From 981e2f584621f33ae501159a979317c79124ece3 Mon Sep 17 00:00:00 2001 From: gac-S_Changer Date: Thu, 28 Nov 2019 14:37:36 +0100 Subject: [PATCH] --- config/config.properties | 34 + config/devices - Copy.properties | 67 + config/devices-modbus.properties | 42 + config/devices.properties | 53 + config/jcae.properties | 11 + config/mail.properties | 9 + config/plugins.properties | 20 + config/settings.properties | 18 + config/setup-modbus.properties | 18 + config/setup.properties | 20 + config/tasks.properties | 2 + config/variables.properties | 2 + devices/20161117_163816.png.properties | 20 + devices/A1.properties | 3 + devices/A2.properties | 3 + devices/A3.properties | 3 + devices/A4.properties | 3 + devices/A5.properties | 3 + devices/B1.properties | 3 + devices/B2.properties | 3 + devices/B3.properties | 3 + devices/B4.properties | 3 + devices/B5.properties | 3 + devices/BasePlate.properties | 1 + devices/C1.properties | 3 + devices/C2.properties | 3 + devices/C3.properties | 3 + devices/C4.properties | 3 + devices/C5.properties | 3 + devices/D1.properties | 3 + devices/D2.properties | 3 + devices/D3.properties | 3 + devices/D4.properties | 3 + devices/D5.properties | 3 + devices/E1.properties | 3 + devices/E2.properties | 3 + devices/E3.properties | 3 + devices/E4.properties | 3 + devices/E5.properties | 3 + devices/F1.properties | 3 + devices/F2.properties | 3 + devices/F3.properties | 3 + devices/F4.properties | 3 + devices/F5.properties | 3 + devices/R1.properties | 3 + devices/R2.properties | 3 + devices/R3.properties | 3 + devices/R4.properties | 3 + devices/R5.properties | 3 + devices/RoomTemperatureBasePlate.properties | 1 + devices/Time.properties | 10 + devices/air_pressure.properties | 5 + devices/cx.properties | 17 + devices/cz.properties | 17 + devices/dewar_level.properties | 6 + devices/dispatcher.properties | 11 + devices/dp1.properties | 11 + devices/fx.properties | 17 + devices/fy.properties | 17 + devices/gripper_cam.properties | 20 + devices/img.properties | 24 + devices/led_ctrl.properties | 8 + devices/led_ctrl_1.properties | 9 + devices/led_ctrl_2.properties | 9 + devices/led_ctrl_3.properties | 9 + devices/led_level.properties | 9 + devices/m1.properties | 13 + devices/m2.properties | 13 + devices/monitoring_cam.properties | 20 + devices/n2_pressure.properties | 5 + devices/p1.properties | 9 + devices/phase_separator.properties | 8 + devices/phase_separator_level.properties | 6 + devices/rim_heater_temp.properties | 6 + devices/robot x.properties | 9 + devices/robot.properties | 8 + devices/robot_j1.properties | 10 + devices/robot_j2.properties | 10 + devices/robot_j3.properties | 10 + devices/robot_j4.properties | 10 + devices/robot_j5.properties | 10 + devices/robot_j6.properties | 10 + devices/robot_modbus.properties | 8 + devices/robot_rx.properties | 10 + devices/robot_ry.properties | 10 + devices/robot_rz.properties | 10 + devices/robot_x.properties | 10 + devices/robot_y.properties | 10 + devices/robot_z.properties | 10 + devices/ry.properties | 17 + devices/smart_magnet.properties | 8 + devices/smc_current.properties | 9 + devices/smc_current_rb.properties | 6 + devices/src1.properties | 24 + devices/src2.properties | 24 + devices/top_cam.properties | 20 + devices/ue.properties | 6 + devices/wago.properties | 8 + plugins/BarcodeReaderPanel.form | 114 ++ plugins/BarcodeReaderPanel.java | 170 ++ plugins/Beeper.java | 72 + plugins/Commands.form | 804 ++++++++ plugins/Commands.java | 928 +++++++++ plugins/Hexiposi.form | 34 + plugins/Hexiposi.java | 78 + plugins/HexiposiPanel.form | 81 + plugins/HexiposiPanel.java | 110 ++ plugins/LN2.form | 34 + plugins/LN2.java | 106 ++ plugins/LaserUE.java | 79 + plugins/LaserUEPanel.form | 59 + plugins/LaserUEPanel.java | 98 + plugins/MXSC-1.10.0 - Back.jar | Bin 0 -> 272446 bytes plugins/MXSC-1.10.0.jar | Bin 0 -> 286289 bytes plugins/MjpegSource2.java | 149 ++ plugins/PuckDetectionPanel.form | 201 ++ plugins/PuckDetectionPanel.java | 281 +++ plugins/Recovery.form | 140 ++ plugins/Recovery.java | 288 +++ plugins/RobotModbus.java | 21 + plugins/RobotPanel.form | 587 ++++++ plugins/RobotPanel.java | 685 +++++++ plugins/RobotTcp.java | 21 + plugins/SmartMagnetConfig.java | 14 + plugins/SmartMagnetPanel.form | 284 +++ plugins/SmartMagnetPanel.java | 320 ++++ plugins/TestZMQ.java | 26 + plugins/WagoPanel.form | 167 ++ plugins/WagoPanel.java | 207 +++ plugins/gui.form | 62 + plugins/gui.java | 96 + script/LN2_Monitoring.scd | 15 + script/LevelMonitoring.scd | 12 + script/calibration/BinarySearchYZ.py | 29 + script/calibration/HillClimbingXZ.py | 45 + script/calibration/ScanRZ.py | 31 + script/calibration/ScanX.py | 87 + script/calibration/ScanY.py | 99 + script/calibration/ScanYZ.py | 93 + script/calibration/ToolCalibration.py | 60 + script/calibration/ToolCalibration2.py | 86 + script/calibration/ToolCalibration3.py | 83 + script/calibration/ToolCalibration6s.py | 79 + script/client/PShellClient.py | 369 ++++ script/client/TellClient.py | 184 ++ script/client/sseclient.py | 163 ++ script/client/tell.py | 79 + script/data/get_samples_info.py | 4 + script/data/pucks.py | 22 + script/data/reports.py | 39 + script/data/samples.py | 348 ++++ script/data/set_samples_info.py | 4 + script/devices/BarcodeReader.py | 83 + script/devices/Gonio.py | 43 + script/devices/Hexiposi.py | 174 ++ script/devices/LaserDistance.py | 17 + script/devices/LedCtrl.py | 46 + script/devices/OneWire.py | 134 ++ script/devices/RobotModbus.py | 46 + script/devices/RobotMotors.py | 62 + script/devices/RobotSC.py | 355 ++++ script/devices/RobotTCP.py | 919 +++++++++ script/devices/SmartMagnet.py | 129 ++ script/devices/Wago.py | 141 ++ script/hexiposi_positon.scd | 11 + script/imgproc/CameraCalibration.py | 156 ++ script/imgproc/CoverDetection.py | 98 + script/imgproc/CoverDetectionCalibration.py | 40 + script/imgproc/CreateMask.py | 29 + script/imgproc/LedDetectionFilter.py | 102 + script/imgproc/LedDetectionProc.py | 106 ++ script/imgproc/Utils.py | 113 ++ script/local.groovy | 3 + script/local.js | 4 + script/local.py | 431 +++++ script/motion/calibrate_tool.py | 32 + script/motion/dry.py | 58 + script/motion/get_aux.py | 21 + script/motion/get_dewar.py | 30 + script/motion/get_gonio.py | 20 + script/motion/homing_hexiposi.py | 18 + script/motion/mount.py | 148 ++ script/motion/move_aux.py | 18 + script/motion/move_cold.py | 22 + script/motion/move_dewar.py | 18 + script/motion/move_gonio.py | 18 + script/motion/move_heater.py | 18 + script/motion/move_home.py | 18 + script/motion/move_park.py | 18 + script/motion/move_scanner.py | 30 + script/motion/put_aux.py | 21 + script/motion/put_dewar.py | 30 + script/motion/put_gonio.py | 23 + script/motion/recover.py | 180 ++ script/motion/robot_recover.py | 16 + script/motion/scan_pin.py | 94 + script/motion/tools.py | 180 ++ script/motion/trash.py | 36 + script/motion/unmount.py | 103 + script/setup/ExposureScan.py | 33 + script/setup/Layout.py | 292 +++ script/tasks/ColdPositionTimeout.py | 23 + script/tasks/LedMonitoring.py | 26 + script/test/CameraCalibration.py | 71 + script/test/CoverDetection.py | 116 ++ script/test/PuckDetection.py | 24 + script/test/PuckDetectionTest.py | 11 + script/test/RobotCartesianScan.py | 28 + script/test/SampleDataInput.py | 1861 ++++++++++++++++++ script/test/SampleDataInput_Dominik.py | 1862 +++++++++++++++++++ script/test/SampleDetection.py | 23 + script/test/TestAlign.py | 9 + script/test/TestBugPcAPI | 4 + script/test/TestBugPcAPI.py | 30 + script/test/TestBugPcAPI2.py | 6 + script/test/TestBugPcAPI3.py | 4 + script/test/TestCalib.py | 30 + script/test/TestCameraStability1.py | 11 + script/test/TestCameraStability2.py | 14 + script/test/TestCameraStability3.py | 9 + script/test/TestCmdSynchronization.py | 32 + script/test/TestCoverDetection.py | 19 + script/test/TestEuclidean.py | 23 + script/test/TestLaserScan.py | 12 + script/test/TestLayout.py | 21 + script/test/TestMicrohawk.py | 10 + script/test/TestRecover.py | 15 + script/test/TestRelays.py | 12 + script/test/TestRemoveBackground.py | 31 + script/test/TestRobot.py | 41 + script/test/TestRobot2.py | 72 + script/test/TestRobotCmds.py | 32 + script/test/TestRobotCmds2.py | 25 + script/test/cycle_time | 4 + script/test/imgtest.py | 47 + script/test/ip | 15 + script/test/mount_profile.py | 144 ++ script/test/onewire.py | 122 ++ script/test/test.py | 24 + script/test/test_hexiposi.py | 8 + script/test/test_segments.py | 16 + script/test/test_swingutils.py | 24 + script/test/then.py | 3 + script/test/transfer_profile.py | 23 + script/test/unmount_profile.py | 98 + script/tools/CheckPuckDetection.py | 6 + script/tools/Math.py | 68 + script/tools/RestartPuckDetection.py | 8 + script/tools/SshExec.py | 61 + script/tools/StopPuckDetection.py | 8 + 250 files changed, 19139 insertions(+) create mode 100644 config/config.properties create mode 100644 config/devices - Copy.properties create mode 100644 config/devices-modbus.properties create mode 100644 config/devices.properties create mode 100644 config/jcae.properties create mode 100644 config/mail.properties create mode 100644 config/plugins.properties create mode 100644 config/settings.properties create mode 100644 config/setup-modbus.properties create mode 100644 config/setup.properties create mode 100644 config/tasks.properties create mode 100644 config/variables.properties create mode 100644 devices/20161117_163816.png.properties create mode 100644 devices/A1.properties create mode 100644 devices/A2.properties create mode 100644 devices/A3.properties create mode 100644 devices/A4.properties create mode 100644 devices/A5.properties create mode 100644 devices/B1.properties create mode 100644 devices/B2.properties create mode 100644 devices/B3.properties create mode 100644 devices/B4.properties create mode 100644 devices/B5.properties create mode 100644 devices/BasePlate.properties create mode 100644 devices/C1.properties create mode 100644 devices/C2.properties create mode 100644 devices/C3.properties create mode 100644 devices/C4.properties create mode 100644 devices/C5.properties create mode 100644 devices/D1.properties create mode 100644 devices/D2.properties create mode 100644 devices/D3.properties create mode 100644 devices/D4.properties create mode 100644 devices/D5.properties create mode 100644 devices/E1.properties create mode 100644 devices/E2.properties create mode 100644 devices/E3.properties create mode 100644 devices/E4.properties create mode 100644 devices/E5.properties create mode 100644 devices/F1.properties create mode 100644 devices/F2.properties create mode 100644 devices/F3.properties create mode 100644 devices/F4.properties create mode 100644 devices/F5.properties create mode 100644 devices/R1.properties create mode 100644 devices/R2.properties create mode 100644 devices/R3.properties create mode 100644 devices/R4.properties create mode 100644 devices/R5.properties create mode 100644 devices/RoomTemperatureBasePlate.properties create mode 100644 devices/Time.properties create mode 100644 devices/air_pressure.properties create mode 100644 devices/cx.properties create mode 100644 devices/cz.properties create mode 100644 devices/dewar_level.properties create mode 100644 devices/dispatcher.properties create mode 100644 devices/dp1.properties create mode 100644 devices/fx.properties create mode 100644 devices/fy.properties create mode 100644 devices/gripper_cam.properties create mode 100644 devices/img.properties create mode 100644 devices/led_ctrl.properties create mode 100644 devices/led_ctrl_1.properties create mode 100644 devices/led_ctrl_2.properties create mode 100644 devices/led_ctrl_3.properties create mode 100644 devices/led_level.properties create mode 100644 devices/m1.properties create mode 100644 devices/m2.properties create mode 100644 devices/monitoring_cam.properties create mode 100644 devices/n2_pressure.properties create mode 100644 devices/p1.properties create mode 100644 devices/phase_separator.properties create mode 100644 devices/phase_separator_level.properties create mode 100644 devices/rim_heater_temp.properties create mode 100644 devices/robot x.properties create mode 100644 devices/robot.properties create mode 100644 devices/robot_j1.properties create mode 100644 devices/robot_j2.properties create mode 100644 devices/robot_j3.properties create mode 100644 devices/robot_j4.properties create mode 100644 devices/robot_j5.properties create mode 100644 devices/robot_j6.properties create mode 100644 devices/robot_modbus.properties create mode 100644 devices/robot_rx.properties create mode 100644 devices/robot_ry.properties create mode 100644 devices/robot_rz.properties create mode 100644 devices/robot_x.properties create mode 100644 devices/robot_y.properties create mode 100644 devices/robot_z.properties create mode 100644 devices/ry.properties create mode 100644 devices/smart_magnet.properties create mode 100644 devices/smc_current.properties create mode 100644 devices/smc_current_rb.properties create mode 100644 devices/src1.properties create mode 100644 devices/src2.properties create mode 100644 devices/top_cam.properties create mode 100644 devices/ue.properties create mode 100644 devices/wago.properties create mode 100644 plugins/BarcodeReaderPanel.form create mode 100644 plugins/BarcodeReaderPanel.java create mode 100644 plugins/Beeper.java create mode 100644 plugins/Commands.form create mode 100644 plugins/Commands.java create mode 100644 plugins/Hexiposi.form create mode 100644 plugins/Hexiposi.java create mode 100644 plugins/HexiposiPanel.form create mode 100644 plugins/HexiposiPanel.java create mode 100644 plugins/LN2.form create mode 100644 plugins/LN2.java create mode 100644 plugins/LaserUE.java create mode 100644 plugins/LaserUEPanel.form create mode 100644 plugins/LaserUEPanel.java create mode 100644 plugins/MXSC-1.10.0 - Back.jar create mode 100644 plugins/MXSC-1.10.0.jar create mode 100644 plugins/MjpegSource2.java create mode 100644 plugins/PuckDetectionPanel.form create mode 100644 plugins/PuckDetectionPanel.java create mode 100644 plugins/Recovery.form create mode 100644 plugins/Recovery.java create mode 100644 plugins/RobotModbus.java create mode 100644 plugins/RobotPanel.form create mode 100644 plugins/RobotPanel.java create mode 100644 plugins/RobotTcp.java create mode 100644 plugins/SmartMagnetConfig.java create mode 100644 plugins/SmartMagnetPanel.form create mode 100644 plugins/SmartMagnetPanel.java create mode 100644 plugins/TestZMQ.java create mode 100644 plugins/WagoPanel.form create mode 100644 plugins/WagoPanel.java create mode 100644 plugins/gui.form create mode 100644 plugins/gui.java create mode 100644 script/LN2_Monitoring.scd create mode 100644 script/LevelMonitoring.scd create mode 100644 script/calibration/BinarySearchYZ.py create mode 100644 script/calibration/HillClimbingXZ.py create mode 100644 script/calibration/ScanRZ.py create mode 100644 script/calibration/ScanX.py create mode 100644 script/calibration/ScanY.py create mode 100644 script/calibration/ScanYZ.py create mode 100644 script/calibration/ToolCalibration.py create mode 100644 script/calibration/ToolCalibration2.py create mode 100644 script/calibration/ToolCalibration3.py create mode 100644 script/calibration/ToolCalibration6s.py create mode 100644 script/client/PShellClient.py create mode 100644 script/client/TellClient.py create mode 100644 script/client/sseclient.py create mode 100644 script/client/tell.py create mode 100644 script/data/get_samples_info.py create mode 100644 script/data/pucks.py create mode 100644 script/data/reports.py create mode 100644 script/data/samples.py create mode 100644 script/data/set_samples_info.py create mode 100644 script/devices/BarcodeReader.py create mode 100644 script/devices/Gonio.py create mode 100644 script/devices/Hexiposi.py create mode 100644 script/devices/LaserDistance.py create mode 100644 script/devices/LedCtrl.py create mode 100644 script/devices/OneWire.py create mode 100644 script/devices/RobotModbus.py create mode 100644 script/devices/RobotMotors.py create mode 100644 script/devices/RobotSC.py create mode 100644 script/devices/RobotTCP.py create mode 100644 script/devices/SmartMagnet.py create mode 100644 script/devices/Wago.py create mode 100644 script/hexiposi_positon.scd create mode 100644 script/imgproc/CameraCalibration.py create mode 100644 script/imgproc/CoverDetection.py create mode 100644 script/imgproc/CoverDetectionCalibration.py create mode 100644 script/imgproc/CreateMask.py create mode 100644 script/imgproc/LedDetectionFilter.py create mode 100644 script/imgproc/LedDetectionProc.py create mode 100644 script/imgproc/Utils.py create mode 100644 script/local.groovy create mode 100644 script/local.js create mode 100644 script/local.py create mode 100644 script/motion/calibrate_tool.py create mode 100644 script/motion/dry.py create mode 100644 script/motion/get_aux.py create mode 100644 script/motion/get_dewar.py create mode 100644 script/motion/get_gonio.py create mode 100644 script/motion/homing_hexiposi.py create mode 100644 script/motion/mount.py create mode 100644 script/motion/move_aux.py create mode 100644 script/motion/move_cold.py create mode 100644 script/motion/move_dewar.py create mode 100644 script/motion/move_gonio.py create mode 100644 script/motion/move_heater.py create mode 100644 script/motion/move_home.py create mode 100644 script/motion/move_park.py create mode 100644 script/motion/move_scanner.py create mode 100644 script/motion/put_aux.py create mode 100644 script/motion/put_dewar.py create mode 100644 script/motion/put_gonio.py create mode 100644 script/motion/recover.py create mode 100644 script/motion/robot_recover.py create mode 100644 script/motion/scan_pin.py create mode 100644 script/motion/tools.py create mode 100644 script/motion/trash.py create mode 100644 script/motion/unmount.py create mode 100644 script/setup/ExposureScan.py create mode 100644 script/setup/Layout.py create mode 100644 script/tasks/ColdPositionTimeout.py create mode 100644 script/tasks/LedMonitoring.py create mode 100644 script/test/CameraCalibration.py create mode 100644 script/test/CoverDetection.py create mode 100644 script/test/PuckDetection.py create mode 100644 script/test/PuckDetectionTest.py create mode 100644 script/test/RobotCartesianScan.py create mode 100644 script/test/SampleDataInput.py create mode 100644 script/test/SampleDataInput_Dominik.py create mode 100644 script/test/SampleDetection.py create mode 100644 script/test/TestAlign.py create mode 100644 script/test/TestBugPcAPI create mode 100644 script/test/TestBugPcAPI.py create mode 100644 script/test/TestBugPcAPI2.py create mode 100644 script/test/TestBugPcAPI3.py create mode 100644 script/test/TestCalib.py create mode 100644 script/test/TestCameraStability1.py create mode 100644 script/test/TestCameraStability2.py create mode 100644 script/test/TestCameraStability3.py create mode 100644 script/test/TestCmdSynchronization.py create mode 100644 script/test/TestCoverDetection.py create mode 100644 script/test/TestEuclidean.py create mode 100644 script/test/TestLaserScan.py create mode 100644 script/test/TestLayout.py create mode 100644 script/test/TestMicrohawk.py create mode 100644 script/test/TestRecover.py create mode 100644 script/test/TestRelays.py create mode 100644 script/test/TestRemoveBackground.py create mode 100644 script/test/TestRobot.py create mode 100644 script/test/TestRobot2.py create mode 100644 script/test/TestRobotCmds.py create mode 100644 script/test/TestRobotCmds2.py create mode 100644 script/test/cycle_time create mode 100644 script/test/imgtest.py create mode 100644 script/test/ip create mode 100644 script/test/mount_profile.py create mode 100644 script/test/onewire.py create mode 100644 script/test/test.py create mode 100644 script/test/test_hexiposi.py create mode 100644 script/test/test_segments.py create mode 100644 script/test/test_swingutils.py create mode 100644 script/test/then.py create mode 100644 script/test/transfer_profile.py create mode 100644 script/test/unmount_profile.py create mode 100644 script/tools/CheckPuckDetection.py create mode 100644 script/tools/Math.py create mode 100644 script/tools/RestartPuckDetection.py create mode 100644 script/tools/SshExec.py create mode 100644 script/tools/StopPuckDetection.py diff --git a/config/config.properties b/config/config.properties new file mode 100644 index 0000000..3bac6fe --- /dev/null +++ b/config/config.properties @@ -0,0 +1,34 @@ +#Thu Nov 28 14:31:51 CET 2019 +autoSaveScanData=true +simulation=false +commandExecutionEvents=false +logDaysToLive=30 +userAuthenticator= +logLevelConsole=Off +scanStreamerPort=-1 +parallelInitialization=false +versionTrackingManual=true +hostName=null +userManagement=false +instanceName=X06SA +dataServerPort=-1 +hideServerMessages=true +serverPort=8080 +versionTrackingEnabled=true +dataPath={data}/{year}_{month}/{date}/{date}_{time}_{name} +serverEnabled=true +dataScanReleaseRecords=false +depthDimension=0 +dataScanPreserveTypes=false +logLevel=Fine +dataScanFlushRecords=true +logPath={logs}/{date}_{time} +dataLayout=default +terminalEnabled=false +notificationLevel=null +terminalPort=3579 +createSessionFiles=true +versionTrackingLogin={context}/svcusr-hlapp_robot +versionTrackingRemote=git@git.psi.ch\:tell/X10SA.git +dataProvider=h5 +saveCommandStatistics=true diff --git a/config/devices - Copy.properties b/config/devices - Copy.properties new file mode 100644 index 0000000..cc3672f --- /dev/null +++ b/config/devices - Copy.properties @@ -0,0 +1,67 @@ +img=ch.psi.pshell.prosilica.Prosilica|25001 "PacketSize=1522;PixelFormat=Mono8;BinningX=1;BinningY=1;RegionX=300;RegionY=200;Width=1000;Height=1000"|||false +gripper_cam=ch.psi.pshell.imaging.MjpegSource|http://129.129.110.114/axis-cgi/mjpg/video.cgi||-1000| +microscan=ch.psi.pshell.serial.TcpDevice|129.129.100.200:2001||| +microscan_cmd=ch.psi.pshell.serial.TcpDevice|129.129.100.200:2003||| +ue=LaserUE|COM4|||false +#robot=RobotTcp|127.0.0.1:1000||| +#onewire=ch.psi.pshell.serial.TcpDevice|129.129.126.83:5000||| +puck_detection=ch.psi.mxsc.PuckDetection|tell-raspberrypi:5556||| +#robot_modbus=ch.psi.pshell.modbus.ModbusTCP|129.129.126.100:502||| +#jf1=ch.psi.pshell.modbus.AnalogInput|robot_modbus 0||100| +#jf2=ch.psi.pshell.modbus.AnalogInput|robot_modbus 1||100| +#jf3=ch.psi.pshell.modbus.AnalogInput|robot_modbus 2||100| +#jf4=ch.psi.pshell.modbus.AnalogInput|robot_modbus 3||100| +#jf5=ch.psi.pshell.modbus.AnalogInput|robot_modbus 4||100| +#jf6=ch.psi.pshell.modbus.AnalogInput|robot_modbus 5||100| +#robot_sts=ch.psi.pshell.modbus.AnalogInputArray|robot_modbus 6 6||100| +#robot_cmd=ch.psi.pshell.modbus.AnalogOutput|robot_modbus 12||| +#robot_args=ch.psi.pshell.modbus.AnalogOutputArray|robot_modbus 47 12||| +#robot_req=ch.psi.pshell.modbus.AnalogOutput|robot_modbus 13||| +#robot_ack=ch.psi.pshell.modbus.AnalogInput|robot_modbus 14||| +#robot_ret=ch.psi.pshell.modbus.AnalogInputArray|robot_modbus 15 12||| +#wago_back=ch.psi.pshell.modbus.ModbusTCP|SF-TEST-WAGO1:502||| +wago=ch.psi.pshell.modbus.ModbusTCP|wago-mxsc-1:502||| +led_ok_1=ch.psi.pshell.modbus.DigitalInput|wago 0||1000| +led_ok_2=ch.psi.pshell.modbus.DigitalInput|wago 1||1000| +led_ok_3=ch.psi.pshell.modbus.DigitalInput|wago 2||1000| +feedback_local_safety=ch.psi.pshell.modbus.DigitalInput|wago 3||1000| +feedback_psys_safety=ch.psi.pshell.modbus.DigitalInput|wago 4||1000| +filling_phase_separator=ch.psi.pshell.modbus.DigitalInput|wago 5||1000| +filling_dewar=ch.psi.pshell.modbus.DigitalInput|wago 6||1000| +dewar_level_high_alarm=ch.psi.pshell.modbus.DigitalInput|wago 7||1000| +guiding_tool_park=ch.psi.pshell.modbus.DigitalInput|wago 8||1000| +air_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 9||1000|false +n2_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 10||1000| +he_chamber_valve_1=ch.psi.pshell.modbus.DigitalInput|wago 15||1000| +he_chamber_valve_2=ch.psi.pshell.modbus.DigitalInput|wago 16||1000| +relays=ch.psi.pshell.modbus.DigitalOutputArray|wago 0 16||1000| +release_local_safety=ch.psi.pshell.modbus.DigitalOutput|wago 0||| +release_psys_safety=ch.psi.pshell.modbus.DigitalOutput|wago 1||| +ln2_main_power=ch.psi.pshell.modbus.DigitalOutput|wago 2||| +rim_heater=ch.psi.pshell.modbus.DigitalOutput|wago 3||| +phase_separator_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 4||| +dewar_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 5|||false +valve_he_chamber=ch.psi.pshell.modbus.DigitalOutput|wago 6||| +gripper_dryer=ch.psi.pshell.modbus.DigitalOutput|wago 7||| +valve_1=ch.psi.pshell.modbus.DigitalOutput|wago 8||| +valve_2=ch.psi.pshell.modbus.DigitalOutput|wago 9||| +valve_3=ch.psi.pshell.modbus.DigitalOutput|wago 10||| +valve_4=ch.psi.pshell.modbus.DigitalOutput|wago 11||| +#spare_do_1=ch.psi.pshell.modbus.DigitalOutput|wago 12||| +#spare_do_2=ch.psi.pshell.modbus.DigitalOutput|wago 13||| +#spare_do_3=ch.psi.pshell.modbus.DigitalOutput|wago 14||| +#spare_do_4=ch.psi.pshell.modbus.DigitalOutput|wago 15||| +phase_separator_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 0||10000| +dewar_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 1||10000| +rim_heater_temp=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 2||10000| +air_pressure=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 3||10000| +n2_pressure=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 4||10000| +#spare_ai_1=ch.psi.pshell.modbus.AnalogInput|wago 5||| +#spare_ai_2=ch.psi.pshell.modbus.AnalogInput|wago 6||| +#spare_ai_3=ch.psi.pshell.modbus.AnalogInput|wago 7||| +led_ctrl_1=ch.psi.pshell.modbus.ProcessVariable|wago 0||| +led_ctrl_2=ch.psi.pshell.modbus.ProcessVariable|wago 1||| +led_ctrl_3=ch.psi.pshell.modbus.ProcessVariable|wago 2||| +#spare_ao_3=ch.psi.pshell.modbus.AnalogOutput|wago 3||| +#cam=ch.psi.pshell.epics.AreaDetector|MX-SAMCAM||| +#img_back=ch.psi.pshell.imaging.CameraSource|cam||-100| diff --git a/config/devices-modbus.properties b/config/devices-modbus.properties new file mode 100644 index 0000000..8fb5a36 --- /dev/null +++ b/config/devices-modbus.properties @@ -0,0 +1,42 @@ +wago=ch.psi.pshell.modbus.ModbusTCP|tell6s-wago:502||| +led_ok_1=ch.psi.pshell.modbus.DigitalInput|wago 0||1000| +led_ok_2=ch.psi.pshell.modbus.DigitalInput|wago 1||1000| +led_ok_3=ch.psi.pshell.modbus.DigitalInput|wago 2||1000| +feedback_local_safety=ch.psi.pshell.modbus.DigitalInput|wago 3||1000| +feedback_psys_safety=ch.psi.pshell.modbus.DigitalInput|wago 4||1000| +filling_dewar=ch.psi.pshell.modbus.DigitalInput|wago 5||1000| +dewar_level_high_alarm=ch.psi.pshell.modbus.DigitalInput|wago 6||1000| +guiding_tool_park=ch.psi.pshell.modbus.DigitalInput|wago 7||1000| +air_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 8||1000|false +n2_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 9||1000| +smc_magnet_status=ch.psi.pshell.modbus.DigitalInput|wago 10||1000| +smc_mounted_1=ch.psi.pshell.modbus.DigitalInput|wago 11||1000| +smc_mounted_2=ch.psi.pshell.modbus.DigitalInput|wago 12||1000| +#spare_di_1=ch.psi.pshell.modbus.DigitalInput|wago 13||| +#spare_di_2=ch.psi.pshell.modbus.DigitalInput|wago 14||| +#spare_di_3=ch.psi.pshell.modbus.DigitalInput|wago 15||| +#spare_di_4=ch.psi.pshell.modbus.DigitalInput|wago 16||| +relays=ch.psi.pshell.modbus.DigitalOutputArray|wago 0 16||1000| +release_local_safety=ch.psi.pshell.modbus.DigitalOutput|wago 0||| +release_psys_safety=ch.psi.pshell.modbus.DigitalOutput|wago 1||| +#spare_do_1=ch.psi.pshell.modbus.DigitalOutput|wago 2||| +#spare_do_2=ch.psi.pshell.modbus.DigitalOutput|wago 3||| +#spare_do_3=ch.psi.pshell.modbus.DigitalOutput|wago 4||| +gripper_dryer=ch.psi.pshell.modbus.DigitalOutput|wago 5||| +smc_sup_det=ch.psi.pshell.modbus.DigitalOutput|wago 6||| +valve_1=ch.psi.pshell.modbus.DigitalOutput|wago 7||| +valve_2=ch.psi.pshell.modbus.DigitalOutput|wago 8||| +valve_3=ch.psi.pshell.modbus.DigitalOutput|wago 9||| +valve_4=ch.psi.pshell.modbus.DigitalOutput|wago 10||| +dewar_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 0||10000| +rim_heater_temp=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 1||10000| +#spare_ai_1=ch.psi.pshell.modbus.AnalogInput|wago 2|||false +#spare_ai_2=ch.psi.pshell.modbus.AnalogInput|wago 3||| +smc_current_rb=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 4||1000| +#spare_ai_3=ch.psi.pshell.modbus.AnalogInput|wago 5||| +#spare_ai_4=ch.psi.pshell.modbus.AnalogInput|wago 6||| +#spare_ai_5=ch.psi.pshell.modbus.AnalogInput|wago 7||| +led_ctrl_1=ch.psi.pshell.modbus.ProcessVariable|wago 0||| +led_ctrl_2=ch.psi.pshell.modbus.ProcessVariable|wago 1||| +led_ctrl_3=ch.psi.pshell.modbus.ProcessVariable|wago 2||| +smc_current=ch.psi.pshell.modbus.ProcessVariable|wago 3||| diff --git a/config/devices.properties b/config/devices.properties new file mode 100644 index 0000000..5c89c68 --- /dev/null +++ b/config/devices.properties @@ -0,0 +1,53 @@ +img=ch.psi.pshell.prosilica.Prosilica|204464 "PacketSize=1504;PixelFormat=Mono8;BinningX=1;BinningY=1;RegionX=290;RegionY=130;Width=1000;Height=1000;MulticastEnable=Off"||-200|false +gripper_cam=ch.psi.pshell.imaging.MjpegSource|http://axis-accc8ea5e463.psi.ch/axis-cgi/mjpg/video.cgi?camera=1 reopen||-200|false +monitoring_cam=ch.psi.pshell.imaging.MjpegSource|http://axis-accc8ea5e463.psi.ch/axis-cgi/mjpg/video.cgi?camera=2 reopen||-200| +#top_cam=ch.psi.pshell.imaging.MjpegSource|http://axis-accc8ea5e463.psi.ch/axis-cgi/mjpg/video.cgi?camera=3 true||-200| +#cam=ch.psi.pshell.epics.AreaDetector|MX-SAMCAM||| +mscan_pin=ch.psi.pshell.serial.TcpDevice|mscan-tell6s-pin:2001||| +mscan_pin_cmd=ch.psi.pshell.serial.TcpDevice|mscan-tell6s-pin:2003||| +mscan_puck=ch.psi.pshell.serial.TcpDevice|mscan-tell6s-puck:2001||| +mscan_puck_cmd=ch.psi.pshell.serial.TcpDevice|mscan-tell6s-puck:2003||| +ue=LaserUE|COM4|||true +puck_detection=ch.psi.mxsc.PuckDetection|tell6s-raspberrypi:5556||| +wago=ch.psi.pshell.modbus.ModbusTCP|tell6s-wago:502||| +led_ok_1=ch.psi.pshell.modbus.DigitalInput|wago 0||1000| +led_ok_2=ch.psi.pshell.modbus.DigitalInput|wago 1||1000| +led_ok_3=ch.psi.pshell.modbus.DigitalInput|wago 2||1000| +feedback_local_safety=ch.psi.pshell.modbus.DigitalInput|wago 3||1000| +feedback_psys_safety=ch.psi.pshell.modbus.DigitalInput|wago 4||1000| +filling_dewar=ch.psi.pshell.modbus.DigitalInput|wago 5||1000| +dewar_level_high_alarm=ch.psi.pshell.modbus.DigitalInput|wago 6||1000| +guiding_tool_park=ch.psi.pshell.modbus.DigitalInput|wago 7||1000| +air_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 8||1000|false +n2_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 9||1000| +smc_magnet_status=ch.psi.pshell.modbus.DigitalInput|wago 10||1000| +smc_mounted_1=ch.psi.pshell.modbus.DigitalInput|wago 11||1000| +smc_mounted_2=ch.psi.pshell.modbus.DigitalInput|wago 12||1000| +#spare_di_1=ch.psi.pshell.modbus.DigitalInput|wago 13||| +#spare_di_2=ch.psi.pshell.modbus.DigitalInput|wago 14||| +#spare_di_3=ch.psi.pshell.modbus.DigitalInput|wago 15||| +#spare_di_4=ch.psi.pshell.modbus.DigitalInput|wago 16||| +relays=ch.psi.pshell.modbus.DigitalOutputArray|wago 0 16||1000| +release_local_safety=ch.psi.pshell.modbus.DigitalOutput|wago 0||| +release_psys_safety=ch.psi.pshell.modbus.DigitalOutput|wago 1||| +#spare_do_1=ch.psi.pshell.modbus.DigitalOutput|wago 2||| +#spare_do_2=ch.psi.pshell.modbus.DigitalOutput|wago 3||| +#spare_do_3=ch.psi.pshell.modbus.DigitalOutput|wago 4||| +gripper_dryer=ch.psi.pshell.modbus.DigitalOutput|wago 5||| +smc_sup_det=ch.psi.pshell.modbus.DigitalOutput|wago 6||| +valve_1=ch.psi.pshell.modbus.DigitalOutput|wago 7||| +valve_2=ch.psi.pshell.modbus.DigitalOutput|wago 8||| +valve_3=ch.psi.pshell.modbus.DigitalOutput|wago 9||| +valve_4=ch.psi.pshell.modbus.DigitalOutput|wago 10||| +dewar_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 0||10000| +rim_heater_temp=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 1||10000| +#spare_ai_1=ch.psi.pshell.modbus.AnalogInput|wago 2|||false +#spare_ai_2=ch.psi.pshell.modbus.AnalogInput|wago 3||| +smc_current_rb=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 4||1000| +#spare_ai_3=ch.psi.pshell.modbus.AnalogInput|wago 5||| +#spare_ai_4=ch.psi.pshell.modbus.AnalogInput|wago 6||| +#spare_ai_5=ch.psi.pshell.modbus.AnalogInput|wago 7||| +led_ctrl_1=ch.psi.pshell.modbus.ProcessVariable|wago 0||| +led_ctrl_2=ch.psi.pshell.modbus.ProcessVariable|wago 1||| +led_ctrl_3=ch.psi.pshell.modbus.ProcessVariable|wago 2||| +smc_current=ch.psi.pshell.modbus.ProcessVariable|wago 3||| diff --git a/config/jcae.properties b/config/jcae.properties new file mode 100644 index 0000000..2bb0691 --- /dev/null +++ b/config/jcae.properties @@ -0,0 +1,11 @@ +#Tue Sep 06 15:10:24 CEST 2016 +ch.psi.jcae.ContextFactory.addressList= +ch.psi.jcae.ContextFactory.serverPort= +ch.psi.jcae.ContextFactory.maxArrayBytes=20000000 +ch.psi.jcae.ChannelFactory.retries=1 +ch.psi.jcae.ChannelFactory.timeout=500 +ch.psi.jcae.impl.DefaultChannelService.retries=2 +ch.psi.jcae.impl.DefaultChannelService.timeout=1000 +ch.psi.jcae.ContextFactory.autoAddressList=true +ch.psi.jcae.ContextFactory.useShellVariables=false +ch.psi.jcae.ContextFactory.addLocalBroadcastInterfaces=false diff --git a/config/mail.properties b/config/mail.properties new file mode 100644 index 0000000..e04b672 --- /dev/null +++ b/config/mail.properties @@ -0,0 +1,9 @@ +#Mon Oct 23 10:53:54 CEST 2017 +auth=None +from= +host= +port=0 +pwd= +smsSuffix=@sms.switch.ch +to= +usr= diff --git a/config/plugins.properties b/config/plugins.properties new file mode 100644 index 0000000..a3380ea --- /dev/null +++ b/config/plugins.properties @@ -0,0 +1,20 @@ +Commands.java=disabled +Recovery.java=disabled +MXSC-1.10.0.jar=enabled +WagoPanel.java=enabled +LaserUEPanel.java=enabled +BarcodeReaderPanel.java=enabled +PuckDetectionPanel.java=enabled +HexiposiPanel.java=enabled +MjpegSource2.java=enabled +LN2.java=disabled +Hexiposi.java=disabled +RobotPanel.java=enabled +SmartMagnetConfig.java=disabled +SmartMagnetPanel.java=enabled +LaserUE.java=enabled +TestZMQ.java=disabled +RobotModbus.java=disabled +RobotTcp.java=disabled +Beeper.java=disabled +gui.java=disabled diff --git a/config/settings.properties b/config/settings.properties new file mode 100644 index 0000000..ae6e8fe --- /dev/null +++ b/config/settings.properties @@ -0,0 +1,18 @@ +#Wed Sep 25 11:32:39 CEST 2019 +barcode_reader_scan_pucks=false +beamline_status_enabled=false +cold_position_timeout=3600 +dry_mount_counter=0 +dry_timestamp=1.569403361248E9 +force_dry_mount_count=8 +force_dry_timeout=0 +imaging_enabled=false +led_level=0.0 +pin_offset=0.0 +puck_types=true +roi_h=1000 +roi_w=1000 +roi_x=288 +roi_y=124 +room_temperature_enabled=false +valve_control=false diff --git a/config/setup-modbus.properties b/config/setup-modbus.properties new file mode 100644 index 0000000..eb292c1 --- /dev/null +++ b/config/setup-modbus.properties @@ -0,0 +1,18 @@ +#Wed Sep 14 15:16:45 CEST 2016 +configFile={config}/config.properties +configFileDevices={config}/devices-modbus.properties +configFilePlugins={config}/plugins.properties +configFileTasks={config}/tasks.properties +configPath={home}/config +contextPath={outp}/context +dataPath={outp}/data +devicesPath={home}/devices +extensionsPath={home}/extensions +imagesPath={outp}/images +libraryPath={script}; {script}/Lib +logPath={outp}/log +pluginsPath={home}/plugins +scriptPath={home}/script +scriptType=py +sessionsPath={outp}/sessions +wwwPath={home}/www diff --git a/config/setup.properties b/config/setup.properties new file mode 100644 index 0000000..7ad15eb --- /dev/null +++ b/config/setup.properties @@ -0,0 +1,20 @@ +#Tue Sep 17 15:06:05 CEST 2019 +configFile={config}/config.properties +configFileDevices={config}/devices.properties +configFilePlugins={config}/plugins.properties +configFileSettings={config}/settings.properties +configFileTasks={config}/tasks.properties +configFileVariables={config}/variables.properties +configPath={home}/config +contextPath={outp}/context +dataPath={outp}/data +devicesPath={home}/devices +extensionsPath={home}/extensions +imagesPath={outp}/images +libraryPath={script}; {script}/Lib +logPath={outp}/log +pluginsPath={home}/plugins +scriptPath={home}/script +scriptType=py +sessionsPath={outp}/sessions +wwwPath={home}/www diff --git a/config/tasks.properties b/config/tasks.properties new file mode 100644 index 0000000..92f138b --- /dev/null +++ b/config/tasks.properties @@ -0,0 +1,2 @@ +tasks/LedMonitoring=120 +tasks/ColdPositionTimeout=300 diff --git a/config/variables.properties b/config/variables.properties new file mode 100644 index 0000000..ff86a2b --- /dev/null +++ b/config/variables.properties @@ -0,0 +1,2 @@ +#Tue Sep 24 12:05:29 CEST 2019 +FileSequentialNumber=24 diff --git a/devices/20161117_163816.png.properties b/devices/20161117_163816.png.properties new file mode 100644 index 0000000..be1fd91 --- /dev/null +++ b/devices/20161117_163816.png.properties @@ -0,0 +1,20 @@ +#Mon Oct 23 15:10:20 CEST 2017 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/A1.properties b/devices/A1.properties new file mode 100644 index 0000000..0d37ef0 --- /dev/null +++ b/devices/A1.properties @@ -0,0 +1,3 @@ +#Thu Jun 06 15:40:21 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/A2.properties b/devices/A2.properties new file mode 100644 index 0000000..ce6347e --- /dev/null +++ b/devices/A2.properties @@ -0,0 +1,3 @@ +#Thu Jun 06 15:47:03 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/A3.properties b/devices/A3.properties new file mode 100644 index 0000000..e34c6cb --- /dev/null +++ b/devices/A3.properties @@ -0,0 +1,3 @@ +#Thu Jun 06 15:40:30 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/A4.properties b/devices/A4.properties new file mode 100644 index 0000000..502a5d0 --- /dev/null +++ b/devices/A4.properties @@ -0,0 +1,3 @@ +#Thu Jun 06 15:40:34 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/A5.properties b/devices/A5.properties new file mode 100644 index 0000000..8b9ee93 --- /dev/null +++ b/devices/A5.properties @@ -0,0 +1,3 @@ +#Thu Jun 06 15:40:38 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/B1.properties b/devices/B1.properties new file mode 100644 index 0000000..22f2102 --- /dev/null +++ b/devices/B1.properties @@ -0,0 +1,3 @@ +#Mon Apr 29 16:18:33 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/B2.properties b/devices/B2.properties new file mode 100644 index 0000000..ea802c8 --- /dev/null +++ b/devices/B2.properties @@ -0,0 +1,3 @@ +#Mon Apr 29 16:40:00 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/B3.properties b/devices/B3.properties new file mode 100644 index 0000000..8b811a9 --- /dev/null +++ b/devices/B3.properties @@ -0,0 +1,3 @@ +#Mon Apr 29 16:40:05 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/B4.properties b/devices/B4.properties new file mode 100644 index 0000000..39c7a01 --- /dev/null +++ b/devices/B4.properties @@ -0,0 +1,3 @@ +#Wed Aug 21 15:20:23 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/B5.properties b/devices/B5.properties new file mode 100644 index 0000000..bb45e5a --- /dev/null +++ b/devices/B5.properties @@ -0,0 +1,3 @@ +#Wed Aug 21 15:20:26 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/BasePlate.properties b/devices/BasePlate.properties new file mode 100644 index 0000000..1e25f83 --- /dev/null +++ b/devices/BasePlate.properties @@ -0,0 +1 @@ +#Fri Feb 10 14:35:38 CET 2017 diff --git a/devices/C1.properties b/devices/C1.properties new file mode 100644 index 0000000..42e8813 --- /dev/null +++ b/devices/C1.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:31 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/C2.properties b/devices/C2.properties new file mode 100644 index 0000000..7e4830e --- /dev/null +++ b/devices/C2.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:34 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/C3.properties b/devices/C3.properties new file mode 100644 index 0000000..5210a65 --- /dev/null +++ b/devices/C3.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:37 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/C4.properties b/devices/C4.properties new file mode 100644 index 0000000..eb44bbb --- /dev/null +++ b/devices/C4.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:41 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/C5.properties b/devices/C5.properties new file mode 100644 index 0000000..354cfeb --- /dev/null +++ b/devices/C5.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:43 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/D1.properties b/devices/D1.properties new file mode 100644 index 0000000..d83b456 --- /dev/null +++ b/devices/D1.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:48 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/D2.properties b/devices/D2.properties new file mode 100644 index 0000000..65e40d6 --- /dev/null +++ b/devices/D2.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:51 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/D3.properties b/devices/D3.properties new file mode 100644 index 0000000..5490caf --- /dev/null +++ b/devices/D3.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:53 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/D4.properties b/devices/D4.properties new file mode 100644 index 0000000..c934ce8 --- /dev/null +++ b/devices/D4.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:55 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/D5.properties b/devices/D5.properties new file mode 100644 index 0000000..0fa5fe0 --- /dev/null +++ b/devices/D5.properties @@ -0,0 +1,3 @@ +#Thu Sep 19 08:23:57 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/E1.properties b/devices/E1.properties new file mode 100644 index 0000000..5399f6c --- /dev/null +++ b/devices/E1.properties @@ -0,0 +1,3 @@ +#Tue Aug 27 11:23:36 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/E2.properties b/devices/E2.properties new file mode 100644 index 0000000..f72d393 --- /dev/null +++ b/devices/E2.properties @@ -0,0 +1,3 @@ +#Tue Aug 27 11:23:40 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/E3.properties b/devices/E3.properties new file mode 100644 index 0000000..8969310 --- /dev/null +++ b/devices/E3.properties @@ -0,0 +1,3 @@ +#Tue Aug 27 11:23:43 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/E4.properties b/devices/E4.properties new file mode 100644 index 0000000..c44f3ec --- /dev/null +++ b/devices/E4.properties @@ -0,0 +1,3 @@ +#Tue Aug 27 11:23:47 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/E5.properties b/devices/E5.properties new file mode 100644 index 0000000..9b88e92 --- /dev/null +++ b/devices/E5.properties @@ -0,0 +1,3 @@ +#Tue Aug 27 11:23:51 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/F1.properties b/devices/F1.properties new file mode 100644 index 0000000..9521147 --- /dev/null +++ b/devices/F1.properties @@ -0,0 +1,3 @@ +#Thu Jun 06 15:46:29 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/F2.properties b/devices/F2.properties new file mode 100644 index 0000000..dce85b2 --- /dev/null +++ b/devices/F2.properties @@ -0,0 +1,3 @@ +#Tue Sep 10 08:18:28 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/F3.properties b/devices/F3.properties new file mode 100644 index 0000000..e7aeabe --- /dev/null +++ b/devices/F3.properties @@ -0,0 +1,3 @@ +#Thu Jun 06 15:47:23 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/F4.properties b/devices/F4.properties new file mode 100644 index 0000000..547817a --- /dev/null +++ b/devices/F4.properties @@ -0,0 +1,3 @@ +#Tue Sep 10 08:18:31 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/F5.properties b/devices/F5.properties new file mode 100644 index 0000000..a73b981 --- /dev/null +++ b/devices/F5.properties @@ -0,0 +1,3 @@ +#Thu Jun 06 15:46:43 CEST 2019 +detection=Mechanical +disabled=false diff --git a/devices/R1.properties b/devices/R1.properties new file mode 100644 index 0000000..fa91122 --- /dev/null +++ b/devices/R1.properties @@ -0,0 +1,3 @@ +#Tue Feb 19 12:07:25 CET 2019 +detection=Both +disabled=false diff --git a/devices/R2.properties b/devices/R2.properties new file mode 100644 index 0000000..fa91122 --- /dev/null +++ b/devices/R2.properties @@ -0,0 +1,3 @@ +#Tue Feb 19 12:07:25 CET 2019 +detection=Both +disabled=false diff --git a/devices/R3.properties b/devices/R3.properties new file mode 100644 index 0000000..fa91122 --- /dev/null +++ b/devices/R3.properties @@ -0,0 +1,3 @@ +#Tue Feb 19 12:07:25 CET 2019 +detection=Both +disabled=false diff --git a/devices/R4.properties b/devices/R4.properties new file mode 100644 index 0000000..fa91122 --- /dev/null +++ b/devices/R4.properties @@ -0,0 +1,3 @@ +#Tue Feb 19 12:07:25 CET 2019 +detection=Both +disabled=false diff --git a/devices/R5.properties b/devices/R5.properties new file mode 100644 index 0000000..fa91122 --- /dev/null +++ b/devices/R5.properties @@ -0,0 +1,3 @@ +#Tue Feb 19 12:07:25 CET 2019 +detection=Both +disabled=false diff --git a/devices/RoomTemperatureBasePlate.properties b/devices/RoomTemperatureBasePlate.properties new file mode 100644 index 0000000..a8e063a --- /dev/null +++ b/devices/RoomTemperatureBasePlate.properties @@ -0,0 +1 @@ +#Tue Feb 19 12:07:25 CET 2019 diff --git a/devices/Time.properties b/devices/Time.properties new file mode 100644 index 0000000..33011f0 --- /dev/null +++ b/devices/Time.properties @@ -0,0 +1,10 @@ +#Wed Jun 27 10:48:14 CEST 2018 +maxValue=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +rotation=false +scale=1.0 +sign_bit=0 +unit=null diff --git a/devices/air_pressure.properties b/devices/air_pressure.properties new file mode 100644 index 0000000..e476b09 --- /dev/null +++ b/devices/air_pressure.properties @@ -0,0 +1,5 @@ +#Thu Mar 01 11:13:34 CET 2018 +offset=0.0 +precision=-1 +scale=1.0 +unit=null diff --git a/devices/cx.properties b/devices/cx.properties new file mode 100644 index 0000000..1720045 --- /dev/null +++ b/devices/cx.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:53 CEST 2018 +defaultSpeed=2.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=mm diff --git a/devices/cz.properties b/devices/cz.properties new file mode 100644 index 0000000..b8877dd --- /dev/null +++ b/devices/cz.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:15 CEST 2018 +defaultSpeed=2.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=mm diff --git a/devices/dewar_level.properties b/devices/dewar_level.properties new file mode 100644 index 0000000..ac55365 --- /dev/null +++ b/devices/dewar_level.properties @@ -0,0 +1,6 @@ +#Tue Jan 22 10:58:09 CET 2019 +offset=0.0 +precision=2 +scale=0.0032 +sign_bit=0 +unit=% diff --git a/devices/dispatcher.properties b/devices/dispatcher.properties new file mode 100644 index 0000000..5a3e672 --- /dev/null +++ b/devices/dispatcher.properties @@ -0,0 +1,11 @@ +#Thu May 03 11:54:38 CEST 2018 +disableCompression=false +keepListeningOnStop=false +mappingIncomplete=null +parallelHandlerProcessing=true +sendAwaitFirstMessage=false +sendBuildChannelConfig=null +sendStrategy=null +sendSyncTimeout=0 +socketType=DEFAULT +validationInconsistency=null diff --git a/devices/dp1.properties b/devices/dp1.properties new file mode 100644 index 0000000..c853c11 --- /dev/null +++ b/devices/dp1.properties @@ -0,0 +1,11 @@ +#Fri Jul 08 10:53:26 CEST 2016 +motor1=0.0|4.0|8.0|0.0 +motor2=0.0|5.0|3.0|NaN +motor3=null +motor4=null +motor5=null +motor6=null +motor7=null +motor8=null +positions=Park|Ready|Out|Clear +precision=-1 diff --git a/devices/fx.properties b/devices/fx.properties new file mode 100644 index 0000000..44a1a35 --- /dev/null +++ b/devices/fx.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:14 CEST 2018 +defaultSpeed=2.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=mm diff --git a/devices/fy.properties b/devices/fy.properties new file mode 100644 index 0000000..44a1a35 --- /dev/null +++ b/devices/fy.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:14 CEST 2018 +defaultSpeed=2.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=mm diff --git a/devices/gripper_cam.properties b/devices/gripper_cam.properties new file mode 100644 index 0000000..6fc903f --- /dev/null +++ b/devices/gripper_cam.properties @@ -0,0 +1,20 @@ +#Thu Jun 28 17:46:46 CEST 2018 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/img.properties b/devices/img.properties new file mode 100644 index 0000000..96f9c93 --- /dev/null +++ b/devices/img.properties @@ -0,0 +1,24 @@ +#Tue Jul 23 10:11:03 CEST 2019 +colormap=Grayscale +colormapAutomatic=false +colormapMax=18.133 +colormapMin=6.4 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=955 +roiWidth=956 +roiX=20 +roiY=24 +rotation=210.3274314256251 +rotationCrop=true +scale=1.0 +spatialCalOffsetX=-478.0 +spatialCalOffsetY=-478.0 +spatialCalScaleX=0.4915561854227953 +spatialCalScaleY=0.49182558383480557 +spatialCalUnits=mm +transpose=false diff --git a/devices/led_ctrl.properties b/devices/led_ctrl.properties new file mode 100644 index 0000000..00dcc48 --- /dev/null +++ b/devices/led_ctrl.properties @@ -0,0 +1,8 @@ +#Tue Jun 20 15:07:30 CEST 2017 +maxValue=0.4 +minValue=0.0 +offset=0.0 +precision=2 +resolution=NaN +scale=3.0E-4 +unit=V diff --git a/devices/led_ctrl_1.properties b/devices/led_ctrl_1.properties new file mode 100644 index 0000000..15ced94 --- /dev/null +++ b/devices/led_ctrl_1.properties @@ -0,0 +1,9 @@ +#Tue Sep 24 17:37:46 CEST 2019 +maxValue=1.0 +minValue=0.0 +offset=0.0 +precision=2 +resolution=NaN +scale=3.0E-4 +sign_bit=0 +unit=V diff --git a/devices/led_ctrl_2.properties b/devices/led_ctrl_2.properties new file mode 100644 index 0000000..15ced94 --- /dev/null +++ b/devices/led_ctrl_2.properties @@ -0,0 +1,9 @@ +#Tue Sep 24 17:37:46 CEST 2019 +maxValue=1.0 +minValue=0.0 +offset=0.0 +precision=2 +resolution=NaN +scale=3.0E-4 +sign_bit=0 +unit=V diff --git a/devices/led_ctrl_3.properties b/devices/led_ctrl_3.properties new file mode 100644 index 0000000..15ced94 --- /dev/null +++ b/devices/led_ctrl_3.properties @@ -0,0 +1,9 @@ +#Tue Sep 24 17:37:46 CEST 2019 +maxValue=1.0 +minValue=0.0 +offset=0.0 +precision=2 +resolution=NaN +scale=3.0E-4 +sign_bit=0 +unit=V diff --git a/devices/led_level.properties b/devices/led_level.properties new file mode 100644 index 0000000..52dee03 --- /dev/null +++ b/devices/led_level.properties @@ -0,0 +1,9 @@ +#Tue Jun 19 16:41:24 CEST 2018 +maxValue=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +scale=1.0 +sign_bit=0 +unit=null diff --git a/devices/m1.properties b/devices/m1.properties new file mode 100644 index 0000000..1cf4553 --- /dev/null +++ b/devices/m1.properties @@ -0,0 +1,13 @@ +#Fri Jun 30 09:37:38 CEST 2017 +defaultSpeed=1.0 +estbilizationDelay=0 +maxSpeed=10.0 +maxValue=10.0 +minSpeed=0.1 +minValue=-10.0 +offset=0.0 +precision=2 +resolution=NaN +rotation=false +scale=1.0 +unit=mm diff --git a/devices/m2.properties b/devices/m2.properties new file mode 100644 index 0000000..1cf4553 --- /dev/null +++ b/devices/m2.properties @@ -0,0 +1,13 @@ +#Fri Jun 30 09:37:38 CEST 2017 +defaultSpeed=1.0 +estbilizationDelay=0 +maxSpeed=10.0 +maxValue=10.0 +minSpeed=0.1 +minValue=-10.0 +offset=0.0 +precision=2 +resolution=NaN +rotation=false +scale=1.0 +unit=mm diff --git a/devices/monitoring_cam.properties b/devices/monitoring_cam.properties new file mode 100644 index 0000000..fa56b35 --- /dev/null +++ b/devices/monitoring_cam.properties @@ -0,0 +1,20 @@ +#Thu Aug 09 11:01:09 CEST 2018 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/n2_pressure.properties b/devices/n2_pressure.properties new file mode 100644 index 0000000..e476b09 --- /dev/null +++ b/devices/n2_pressure.properties @@ -0,0 +1,5 @@ +#Thu Mar 01 11:13:34 CET 2018 +offset=0.0 +precision=-1 +scale=1.0 +unit=null diff --git a/devices/p1.properties b/devices/p1.properties new file mode 100644 index 0000000..07d9ba5 --- /dev/null +++ b/devices/p1.properties @@ -0,0 +1,9 @@ +#Fri Jun 30 09:37:38 CEST 2017 +maxValue=1000.0 +minValue=0.0 +offset=0.0 +precision=-1 +resolution=NaN +rotation=false +scale=1.0 +unit=mm diff --git a/devices/phase_separator.properties b/devices/phase_separator.properties new file mode 100644 index 0000000..122f8e9 --- /dev/null +++ b/devices/phase_separator.properties @@ -0,0 +1,8 @@ +#Wed Feb 28 17:35:59 CET 2018 +maxValue=30000.0 +minValue=0.0 +offset=0.0 +precision=-1 +resolution=NaN +scale=0.1 +unit=% diff --git a/devices/phase_separator_level.properties b/devices/phase_separator_level.properties new file mode 100644 index 0000000..92a5279 --- /dev/null +++ b/devices/phase_separator_level.properties @@ -0,0 +1,6 @@ +#Tue Jun 19 16:41:20 CEST 2018 +offset=-25.81632 +precision=2 +scale=0.003888 +sign_bit=0 +unit=% diff --git a/devices/rim_heater_temp.properties b/devices/rim_heater_temp.properties new file mode 100644 index 0000000..e1c3b95 --- /dev/null +++ b/devices/rim_heater_temp.properties @@ -0,0 +1,6 @@ +#Tue Jun 19 16:41:20 CEST 2018 +offset=-25.81632 +precision=2 +scale=0.003888 +sign_bit=0 +unit=C diff --git a/devices/robot x.properties b/devices/robot x.properties new file mode 100644 index 0000000..02ffbf3 --- /dev/null +++ b/devices/robot x.properties @@ -0,0 +1,9 @@ +#Tue Sep 12 15:00:38 CEST 2017 +maxValue=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +rotation=false +scale=1.0 +unit=null diff --git a/devices/robot.properties b/devices/robot.properties new file mode 100644 index 0000000..97f6ad6 --- /dev/null +++ b/devices/robot.properties @@ -0,0 +1,8 @@ +#Thu Jul 21 08:35:47 CEST 2016 +offsetReadAnalogInput=0 +offsetReadAnalogOutput=0 +offsetReadDigitalInput=0 +offsetReadDigitalOutput=0 +offsetWriteAnalogOutput=0 +offsetWriteDigitalOutput=0 +timeout=1000 diff --git a/devices/robot_j1.properties b/devices/robot_j1.properties new file mode 100644 index 0000000..bc3a381 --- /dev/null +++ b/devices/robot_j1.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=180.0 +minValue=-180.0 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j2.properties b/devices/robot_j2.properties new file mode 100644 index 0000000..6a892bc --- /dev/null +++ b/devices/robot_j2.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=127.5 +minValue=-127.5 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j3.properties b/devices/robot_j3.properties new file mode 100644 index 0000000..07bff75 --- /dev/null +++ b/devices/robot_j3.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=152.5 +minValue=-152.5 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j4.properties b/devices/robot_j4.properties new file mode 100644 index 0000000..41d8586 --- /dev/null +++ b/devices/robot_j4.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=270.0 +minValue=-270.0 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j5.properties b/devices/robot_j5.properties new file mode 100644 index 0000000..dab429f --- /dev/null +++ b/devices/robot_j5.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=132.5 +minValue=-122.5 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j6.properties b/devices/robot_j6.properties new file mode 100644 index 0000000..d688634 --- /dev/null +++ b/devices/robot_j6.properties @@ -0,0 +1,10 @@ +#Fri Aug 24 14:56:42 CEST 2018 +maxValue=400.0 +minValue=-400.0 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_modbus.properties b/devices/robot_modbus.properties new file mode 100644 index 0000000..31a13be --- /dev/null +++ b/devices/robot_modbus.properties @@ -0,0 +1,8 @@ +#Thu Jul 21 12:02:04 CEST 2016 +offsetReadAnalogInput=0 +offsetReadAnalogOutput=0 +offsetReadDigitalInput=0 +offsetReadDigitalOutput=0 +offsetWriteAnalogOutput=0 +offsetWriteDigitalOutput=0 +timeout=1000 diff --git a/devices/robot_rx.properties b/devices/robot_rx.properties new file mode 100644 index 0000000..df63f03 --- /dev/null +++ b/devices/robot_rx.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=180.0 +minValue=-180.0 +offset=0.0 +precision=2 +resolution=0.05 +rotation=true +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_ry.properties b/devices/robot_ry.properties new file mode 100644 index 0000000..a789ebf --- /dev/null +++ b/devices/robot_ry.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=180.0 +minValue=-180.0 +offset=0.0 +precision=-2 +resolution=0.05 +rotation=true +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_rz.properties b/devices/robot_rz.properties new file mode 100644 index 0000000..2b88035 --- /dev/null +++ b/devices/robot_rz.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=360.0 +minValue=-360.0 +offset=0.0 +precision=2 +resolution=0.1 +rotation=true +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_x.properties b/devices/robot_x.properties new file mode 100644 index 0000000..5cdadcc --- /dev/null +++ b/devices/robot_x.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=1000.0 +minValue=-1000.0 +offset=0.0 +precision=2 +resolution=0.05 +rotation=false +scale=1.0 +sign_bit=0 +unit=mm diff --git a/devices/robot_y.properties b/devices/robot_y.properties new file mode 100644 index 0000000..eb8022e --- /dev/null +++ b/devices/robot_y.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=1000.0 +minValue=-1000.0 +offset=0.0 +precision=2 +resolution=0.05 +rotation=false +scale=1.0 +sign_bit=0 +unit=null diff --git a/devices/robot_z.properties b/devices/robot_z.properties new file mode 100644 index 0000000..eb8022e --- /dev/null +++ b/devices/robot_z.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=1000.0 +minValue=-1000.0 +offset=0.0 +precision=2 +resolution=0.05 +rotation=false +scale=1.0 +sign_bit=0 +unit=null diff --git a/devices/ry.properties b/devices/ry.properties new file mode 100644 index 0000000..f43c3d2 --- /dev/null +++ b/devices/ry.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:14 CEST 2018 +defaultSpeed=50.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=deg diff --git a/devices/smart_magnet.properties b/devices/smart_magnet.properties new file mode 100644 index 0000000..29bedad --- /dev/null +++ b/devices/smart_magnet.properties @@ -0,0 +1,8 @@ +#Tue Sep 17 13:46:27 CEST 2019 +holdingCurrent=50.0 +mountCurrent=30.0 +remanenceCurrent=-10.0 +restingCurrent=30.0 +reverseCurrent=-10.0 +reverseTime=0.2 +unmountCurrent=20.0 diff --git a/devices/smc_current.properties b/devices/smc_current.properties new file mode 100644 index 0000000..9d9ba17 --- /dev/null +++ b/devices/smc_current.properties @@ -0,0 +1,9 @@ +#Wed Jan 30 11:33:15 CET 2019 +maxValue=70.0 +minValue=-50.0 +offset=0.0 +precision=2 +resolution=NaN +scale=0.003 +sign_bit=0 +unit=mA diff --git a/devices/smc_current_rb.properties b/devices/smc_current_rb.properties new file mode 100644 index 0000000..7709ada --- /dev/null +++ b/devices/smc_current_rb.properties @@ -0,0 +1,6 @@ +#Tue Jun 19 16:45:06 CEST 2018 +offset=0.0 +precision=2 +scale=0.003 +sign_bit=15 +unit=mA diff --git a/devices/src1.properties b/devices/src1.properties new file mode 100644 index 0000000..a0b5d6d --- /dev/null +++ b/devices/src1.properties @@ -0,0 +1,24 @@ +#Thu Sep 22 14:45:06 CEST 2016 +colormap=Temperature +colormapAutomatic=true +colormapMax=255.0 +colormapMin=0.0 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/src2.properties b/devices/src2.properties new file mode 100644 index 0000000..2bf8406 --- /dev/null +++ b/devices/src2.properties @@ -0,0 +1,24 @@ +#Thu Sep 22 14:45:06 CEST 2016 +colormap=Grayscale +colormapAutomatic=true +colormapMax=255.0 +colormapMin=0.0 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/top_cam.properties b/devices/top_cam.properties new file mode 100644 index 0000000..827552b --- /dev/null +++ b/devices/top_cam.properties @@ -0,0 +1,20 @@ +#Thu Aug 09 11:46:12 CEST 2018 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/ue.properties b/devices/ue.properties new file mode 100644 index 0000000..f241f62 --- /dev/null +++ b/devices/ue.properties @@ -0,0 +1,6 @@ +#Thu Aug 31 16:41:09 CEST 2017 +baudRate=9600 +dataBits=DB_8 +parity=None +port=null +stopBits=SB_1 diff --git a/devices/wago.properties b/devices/wago.properties new file mode 100644 index 0000000..f2650ea --- /dev/null +++ b/devices/wago.properties @@ -0,0 +1,8 @@ +#Wed Feb 28 16:27:51 CET 2018 +offsetReadAnalogInput=0 +offsetReadAnalogOutput=0x200 +offsetReadDigitalInput=0 +offsetReadDigitalOutput=0x200 +offsetWriteAnalogOutput=0 +offsetWriteDigitalOutput=0 +timeout=1000 diff --git a/plugins/BarcodeReaderPanel.form b/plugins/BarcodeReaderPanel.form new file mode 100644 index 0000000..1d2c4af --- /dev/null +++ b/plugins/BarcodeReaderPanel.form @@ -0,0 +1,114 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/BarcodeReaderPanel.java b/plugins/BarcodeReaderPanel.java new file mode 100644 index 0000000..d6dabed --- /dev/null +++ b/plugins/BarcodeReaderPanel.java @@ -0,0 +1,170 @@ +import ch.psi.pshell.core.Context; +import ch.psi.pshell.device.Device; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; +import java.util.concurrent.CompletableFuture; + +/** + * + */ +public class BarcodeReaderPanel extends DevicePanel { + + volatile boolean enabled; + public BarcodeReaderPanel() { + initComponents(); + this.startTimer(100); + } + + + CompletableFuture future; + + + @Override + public void setDevice(Device device){ + super.setDevice(device); + if (device != null){ + deviceStatePanel1.setDevice(device); + deviceValuePanel1.setDevice(device); + } + } + + @Override + public void onTimer(){ + if ((getDevice()!=null) && enabled){ + if ((future==null) || (future.isDone())){ + future = Context.getInstance().evalLineBackgroundAsync(getDevice().getName() + ".get()"); + } + } + } + + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (BarcodeReaderPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + if (ret == null){ + SwingUtils.showMessage(this, "Return", "No code detected", 20000); + } else { + SwingUtils.showMessage(this, "Return", "Detected code: " +ret, 20000); + } + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel3 = new javax.swing.JPanel(); + buttonEnable = new javax.swing.JButton(); + buttonDisable = new javax.swing.JButton(); + buttonRead = new javax.swing.JButton(); + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + deviceValuePanel1 = new ch.psi.pshell.swing.DeviceValuePanel(); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Commands")); + + buttonEnable.setText("Enable"); + buttonEnable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonEnableActionPerformed(evt); + } + }); + + buttonDisable.setText("Disable"); + buttonDisable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonDisableActionPerformed(evt); + } + }); + + buttonRead.setText("Read"); + buttonRead.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReadActionPerformed(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(buttonEnable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonDisable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonRead) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonDisable, buttonEnable, buttonRead}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonEnable) + .addComponent(buttonDisable) + .addComponent(buttonRead)) + .addContainerGap()) + ); + + deviceValuePanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Value")); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) + ); + }// //GEN-END:initComponents + + private void buttonEnableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEnableActionPerformed + execute(getDevice().getName() + ".enable()", false); + enabled = true; + }//GEN-LAST:event_buttonEnableActionPerformed + + private void buttonDisableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDisableActionPerformed + enabled = false; + execute(getDevice().getName() + ".disable()", false); + }//GEN-LAST:event_buttonDisableActionPerformed + + private void buttonReadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReadActionPerformed + enabled = false; + execute(getDevice().getName() + ".read(5.0) ", true); + }//GEN-LAST:event_buttonReadActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonDisable; + private javax.swing.JButton buttonEnable; + private javax.swing.JButton buttonRead; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private ch.psi.pshell.swing.DeviceValuePanel deviceValuePanel1; + private javax.swing.JPanel jPanel3; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/Beeper.java b/plugins/Beeper.java new file mode 100644 index 0000000..c1fea67 --- /dev/null +++ b/plugins/Beeper.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.*; +import com.sun.jna.Function; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.win32.StdCallLibrary; +import com.sun.jna.win32.W32APIFunctionMapper; +import com.sun.jna.win32.W32APITypeMapper; +import java.util.HashMap; +import java.util.Map; + +/** + */ +public class Beeper extends DeviceBase { + + public Beeper(String name) { + super(name); + } + + // JNA Mapping + static Map UNICODE_OPTIONS = new HashMap() { + + { + put("type-mapper", W32APITypeMapper.UNICODE); + put("function-mapper", W32APIFunctionMapper.UNICODE); + } + }; + + interface Kernel32 extends StdCallLibrary { + + public static final String LIBRARY_NAME = "kernel32"; + Kernel32 INSTANCE = (Kernel32) Native.loadLibrary(LIBRARY_NAME, Kernel32.class, UNICODE_OPTIONS); + Kernel32 SYNC_INSTANCE = (Kernel32) Native.synchronizedLibrary(INSTANCE); + + boolean Beep(int FREQUENCY, int DURATION); + + void Sleep(int DURATION); + + int CreateEventW(Pointer securityAttributes, boolean manualReset, boolean initialState, String name); + + int CreateThread(/*Pointer*/int lpThreadAttributes, IntByReference dwStackSize, Function lpStartAddress, Structure lpParameter, int dwCreationFlags, IntByReference lpThreadId); + public static final int STILL_ACTIVE = 259; + + int GetExitCodeThread(int hThread, IntByReference lpExitCode); + + int GetLastError(); + + boolean CloseHandle(int handle); + + } + private final int mEventHandle = Kernel32.INSTANCE.CreateEventW(Pointer.NULL, true, false, null); + + + //Public interface + public int getLastError(){ + return Kernel32.SYNC_INSTANCE.GetLastError(); + } + + public void sleep(int duration){ + Kernel32.SYNC_INSTANCE.Sleep(duration); + } + + public void beep(int frequency, int duration){ + Kernel32.SYNC_INSTANCE.Beep(frequency, duration); + } + +} diff --git a/plugins/Commands.form b/plugins/Commands.form new file mode 100644 index 0000000..26eeaf0 --- /dev/null +++ b/plugins/Commands.form @@ -0,0 +1,804 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/Commands.java b/plugins/Commands.java new file mode 100644 index 0000000..fb37d24 --- /dev/null +++ b/plugins/Commands.java @@ -0,0 +1,928 @@ +/* + * Copyright (c) 2014-2017 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.device.DeviceAdapter; +import ch.psi.pshell.device.GenericDevice; +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import java.awt.Component; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JComponent; +import javax.swing.JSpinner; +import javax.swing.JTextField; + +/** + * + */ +public class Commands extends Panel { + + public Commands() { + initComponents(); + ((JSpinner.DefaultEditor)spinnerSegment.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); + ((JSpinner.DefaultEditor)spinnerPuck.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); + ((JSpinner.DefaultEditor)spinnerSample.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); + + + try{ + spinnerDryTime.setValue(getContext().getScriptManager().getVar("DEFAULT_DRY_HEAT_TIME")); + spinnerDrySpeed.setValue(getContext().getScriptManager().getVar("DEFAULT_DRY_SPEED")); + } catch(Exception ex){ + this.showException(ex); + } + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + GenericDevice basePlate = getDevice("BasePlate"); + if (basePlate != null){ + basePlate.addListener(new DeviceAdapter() { + @Override + public void onValueChanged(Device device, Object value, Object former) { + if (value!=null){ + String segment = ((Object[])value)[0].toString(); + spinnerSegment.setValue(segment); + Integer puck = (Integer) ((Object[])value)[1]; + spinnerPuck.setValue(Integer.valueOf(puck)); + Integer sample = (Integer) ((Object[])value)[2]; + if (sample!=null){ + spinnerSample.setValue(Integer.valueOf(sample)); + } + } + } + }); + } + } + + @Override + public void onStateChange(State state, State former) { + boolean enabled = (state == State.Ready); + for (Component c: SwingUtils.getComponentsByType(this, JComponent.class)){ + c.setEnabled(enabled); + } + spinnerSegment.setEnabled(enabled && !checkAuxiliary.isSelected()); + spinnerPuck.setEnabled(enabled && !checkAuxiliary.isSelected()); + buttonScanPuck.setEnabled(enabled && !checkAuxiliary.isSelected()); + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + //Callback to perform update - in event thread + @Override + protected void doUpdate() { + } + + @Override + public boolean isActive() { + return true; + } + + + void execute(String statement){ + execute(statement, false); + } + + void execute(String statement, boolean background){ + execute(statement, background, false); + } + + void execute(String statement, boolean background, boolean showReturn){ + try { + evalAsync(statement, background).handle((ret, ex) -> { + if (ex != null){ + if (getContext().getGlobal("recovering") == null) { + showException((Exception)ex); + } + } else if (showReturn){ + SwingUtils.showMessage(getTopLevel(), "Return", String.valueOf(ret)); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + void execute(String script, Object args){ + try { + runAsync(script, args).handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jTabbedPane1 = new javax.swing.JTabbedPane(); + tabCommands = new javax.swing.JPanel(); + pnDry = new javax.swing.JPanel(); + jLabel6 = new javax.swing.JLabel(); + spinnerDryTime = new ch.psi.utils.swing.HorizontalSpinner(); + buttonDry = new javax.swing.JButton(); + spinnerDrySpeed = new ch.psi.utils.swing.HorizontalSpinner(); + jLabel7 = new javax.swing.JLabel(); + ckeckParkOnDry = new javax.swing.JCheckBox(); + pnTransfer = new javax.swing.JPanel(); + buttonMount = new javax.swing.JButton(); + jPanel5 = new javax.swing.JPanel(); + jLabel4 = new javax.swing.JLabel(); + checkForce = new javax.swing.JCheckBox(); + spinnerSample = new ch.psi.utils.swing.HorizontalSpinner(); + spinnerPuck = new ch.psi.utils.swing.HorizontalSpinner(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + spinnerSegment = new ch.psi.utils.swing.HorizontalSpinner(); + jLabel3 = new javax.swing.JLabel(); + jLabel5 = new javax.swing.JLabel(); + checkDatamatrix = new javax.swing.JCheckBox(); + buttonUnmount = new javax.swing.JButton(); + buttonScanPin = new javax.swing.JButton(); + buttonScanPuck = new javax.swing.JButton(); + checkAuxiliary = new javax.swing.JCheckBox(); + jPanel1 = new javax.swing.JPanel(); + buttonGripperScan = new javax.swing.JButton(); + buttonTrash = new javax.swing.JButton(); + tabAdvanced = new javax.swing.JPanel(); + pnLowLevel = new javax.swing.JPanel(); + buttonMovePark = new javax.swing.JButton(); + buttonMoveCold = new javax.swing.JButton(); + buttonMoveGonio = new javax.swing.JButton(); + buttonMoveHeater = new javax.swing.JButton(); + buttonGetGonio = new javax.swing.JButton(); + buttonPutGonio = new javax.swing.JButton(); + buttonMoveDewar = new javax.swing.JButton(); + buttonMoveHome = new javax.swing.JButton(); + buttonMoveScanner = new javax.swing.JButton(); + buttonGetDewar = new javax.swing.JButton(); + buttonPutDewar = new javax.swing.JButton(); + buttonMoveAux = new javax.swing.JButton(); + buttonGetAux = new javax.swing.JButton(); + buttonPutAux = new javax.swing.JButton(); + pnDatabase = new javax.swing.JPanel(); + buttonClearSampleDb = new javax.swing.JButton(); + buttonResetPuckIds = new javax.swing.JButton(); + pnMotion = new javax.swing.JPanel(); + buttonRecover = new javax.swing.JButton(); + buttonEnableAll = new javax.swing.JButton(); + + pnDry.setBorder(javax.swing.BorderFactory.createTitledBorder("Drying")); + + jLabel6.setText("Heat time(s):"); + + spinnerDryTime.setModel(new javax.swing.SpinnerNumberModel(35.0d, 1.0d, 50.0d, 1.0d)); + spinnerDryTime.setRequestFocusEnabled(false); + + buttonDry.setText("Dry"); + buttonDry.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonDryActionPerformed(evt); + } + }); + + spinnerDrySpeed.setModel(new javax.swing.SpinnerNumberModel(0.4d, 0.1d, 1.0d, 0.1d)); + + jLabel7.setText("Speed(%):"); + + ckeckParkOnDry.setText("Park on finish"); + + javax.swing.GroupLayout pnDryLayout = new javax.swing.GroupLayout(pnDry); + pnDry.setLayout(pnDryLayout); + pnDryLayout.setHorizontalGroup( + pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDryLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonDry, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ckeckParkOnDry)) + .addGap(18, 25, Short.MAX_VALUE) + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jLabel6) + .addComponent(jLabel7)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(spinnerDrySpeed, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spinnerDryTime, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + pnDryLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonDry, spinnerDrySpeed, spinnerDryTime}); + + pnDryLayout.setVerticalGroup( + pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDryLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDryLayout.createSequentialGroup() + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonDry) + .addComponent(spinnerDryTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(spinnerDrySpeed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel7) + .addComponent(ckeckParkOnDry))) + .addComponent(jLabel6)) + .addContainerGap()) + ); + + pnTransfer.setBorder(javax.swing.BorderFactory.createTitledBorder("Sample Transfer")); + + buttonMount.setText("Mount"); + buttonMount.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMountActionPerformed(evt); + } + }); + + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel4.setText("Force:"); + + checkForce.setSelected(true); + checkForce.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + + spinnerSample.setModel(new javax.swing.SpinnerNumberModel(1, 1, 16, 1)); + + spinnerPuck.setModel(new javax.swing.SpinnerNumberModel(1, 1, 5, 1)); + + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel1.setText("Segment:"); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel2.setText("Puck:"); + + spinnerSegment.setModel(new javax.swing.SpinnerListModel(new String[] {"A", "B", "C", "D", "E", "F"})); + + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel3.setText("Sample:"); + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel5.setText("Read DM:"); + + checkDatamatrix.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + + javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5); + jPanel5.setLayout(jPanel5Layout); + jPanel5Layout.setHorizontalGroup( + jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel5Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel3) + .addComponent(jLabel2) + .addComponent(jLabel1) + .addComponent(jLabel4) + .addComponent(jLabel5)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(spinnerPuck, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(checkForce) + .addComponent(checkDatamatrix) + .addComponent(spinnerSample, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spinnerSegment, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 0, 0)) + ); + + jPanel5Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jLabel1, jLabel2, jLabel3, jLabel4, jLabel5}); + + jPanel5Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {spinnerPuck, spinnerSample, spinnerSegment}); + + jPanel5Layout.setVerticalGroup( + jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel5Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel1) + .addComponent(spinnerSegment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel2) + .addComponent(spinnerPuck, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel3) + .addComponent(spinnerSample, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel4) + .addComponent(checkForce)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel5) + .addComponent(checkDatamatrix))) + ); + + buttonUnmount.setText("Unmount"); + buttonUnmount.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonUnmountActionPerformed(evt); + } + }); + + buttonScanPin.setText("Scan Pin"); + buttonScanPin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonScanPinActionPerformed(evt); + } + }); + + buttonScanPuck.setText("Scan Puck"); + buttonScanPuck.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonScanPuckActionPerformed(evt); + } + }); + + checkAuxiliary.setText("Auxiliary"); + checkAuxiliary.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + checkAuxiliaryActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnTransferLayout = new javax.swing.GroupLayout(pnTransfer); + pnTransfer.setLayout(pnTransferLayout); + pnTransferLayout.setHorizontalGroup( + pnTransferLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnTransferLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnTransferLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonMount, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonUnmount, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonScanPin, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonScanPuck, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(checkAuxiliary)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pnTransferLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonMount, buttonScanPin, buttonUnmount}); + + pnTransferLayout.setVerticalGroup( + pnTransferLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnTransferLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnTransferLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(pnTransferLayout.createSequentialGroup() + .addComponent(buttonMount) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonUnmount) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonScanPin) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonScanPuck) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(checkAuxiliary))) + .addContainerGap()) + ); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Gripper")); + + buttonGripperScan.setText("Scan"); + buttonGripperScan.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonGripperScanActionPerformed(evt); + } + }); + + buttonTrash.setText("Trash"); + buttonTrash.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonTrashActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonGripperScan, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonTrash, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonGripperScan) + .addComponent(buttonTrash)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + javax.swing.GroupLayout tabCommandsLayout = new javax.swing.GroupLayout(tabCommands); + tabCommands.setLayout(tabCommandsLayout); + tabCommandsLayout.setHorizontalGroup( + tabCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabCommandsLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(tabCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pnDry, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnTransfer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + ); + tabCommandsLayout.setVerticalGroup( + tabCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabCommandsLayout.createSequentialGroup() + .addContainerGap() + .addComponent(pnDry, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(pnTransfer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + jTabbedPane1.addTab("Commands", tabCommands); + + pnLowLevel.setBorder(javax.swing.BorderFactory.createTitledBorder("Low-level Motion Commands")); + + buttonMovePark.setText("Move Park"); + buttonMovePark.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveParkActionPerformed(evt); + } + }); + + buttonMoveCold.setText("Move Cold"); + buttonMoveCold.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveColdActionPerformed(evt); + } + }); + + buttonMoveGonio.setText("Move Gonio"); + buttonMoveGonio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveGonioActionPerformed(evt); + } + }); + + buttonMoveHeater.setText("Move Heater"); + buttonMoveHeater.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveHeaterActionPerformed(evt); + } + }); + + buttonGetGonio.setText("Get Gonio"); + buttonGetGonio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonGetGonioActionPerformed(evt); + } + }); + + buttonPutGonio.setText("Put Gonio"); + buttonPutGonio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPutGonioActionPerformed(evt); + } + }); + + buttonMoveDewar.setText("Move Dewar"); + buttonMoveDewar.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveDewarActionPerformed(evt); + } + }); + + buttonMoveHome.setText("Move Home"); + buttonMoveHome.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveHomeActionPerformed(evt); + } + }); + + buttonMoveScanner.setText("Move Scanner"); + buttonMoveScanner.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveScannerActionPerformed(evt); + } + }); + + buttonGetDewar.setText("Get Dewar"); + buttonGetDewar.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonGetDewarActionPerformed(evt); + } + }); + + buttonPutDewar.setText("Put Dewar"); + buttonPutDewar.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPutDewarActionPerformed(evt); + } + }); + + buttonMoveAux.setText("Move Aux"); + buttonMoveAux.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveAuxActionPerformed(evt); + } + }); + + buttonGetAux.setText("Get Aux"); + buttonGetAux.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonGetAuxActionPerformed(evt); + } + }); + + buttonPutAux.setText("Put Aux"); + buttonPutAux.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPutAuxActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnLowLevelLayout = new javax.swing.GroupLayout(pnLowLevel); + pnLowLevel.setLayout(pnLowLevelLayout); + pnLowLevelLayout.setHorizontalGroup( + pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnLowLevelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonMovePark, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveAux) + .addComponent(buttonMoveCold, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveHeater) + .addComponent(buttonGetGonio) + .addComponent(buttonGetDewar, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonGetAux, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 64, Short.MAX_VALUE) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonPutDewar, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonPutGonio, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveGonio, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveHome, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveDewar, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveScanner) + .addComponent(buttonPutAux, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + pnLowLevelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonGetAux, buttonGetDewar, buttonGetGonio, buttonMoveAux, buttonMoveCold, buttonMoveDewar, buttonMoveGonio, buttonMoveHeater, buttonMoveHome, buttonMovePark, buttonMoveScanner, buttonPutAux, buttonPutDewar, buttonPutGonio}); + + pnLowLevelLayout.setVerticalGroup( + pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnLowLevelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonGetDewar) + .addComponent(buttonPutDewar)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonGetAux) + .addComponent(buttonPutAux)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonGetGonio) + .addComponent(buttonPutGonio)) + .addGap(18, 18, 18) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonMoveGonio) + .addComponent(buttonMoveAux)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonMovePark) + .addComponent(buttonMoveHome)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonMoveDewar) + .addComponent(buttonMoveCold)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonMoveHeater) + .addComponent(buttonMoveScanner)) + .addContainerGap()) + ); + + pnDatabase.setBorder(javax.swing.BorderFactory.createTitledBorder("Database")); + + buttonClearSampleDb.setText("Clear Sample Db"); + buttonClearSampleDb.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonClearSampleDbActionPerformed(evt); + } + }); + + buttonResetPuckIds.setText("Reset Puck IDs"); + buttonResetPuckIds.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonResetPuckIdsActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnDatabaseLayout = new javax.swing.GroupLayout(pnDatabase); + pnDatabase.setLayout(pnDatabaseLayout); + pnDatabaseLayout.setHorizontalGroup( + pnDatabaseLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDatabaseLayout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonClearSampleDb) + .addGap(18, 18, Short.MAX_VALUE) + .addComponent(buttonResetPuckIds) + .addContainerGap()) + ); + + pnDatabaseLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonClearSampleDb, buttonResetPuckIds}); + + pnDatabaseLayout.setVerticalGroup( + pnDatabaseLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDatabaseLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnDatabaseLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonClearSampleDb) + .addComponent(buttonResetPuckIds)) + .addContainerGap()) + ); + + pnMotion.setBorder(javax.swing.BorderFactory.createTitledBorder("Motion")); + + buttonRecover.setText("Dewar Recovery"); + buttonRecover.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonRecoverActionPerformed(evt); + } + }); + + buttonEnableAll.setText("Enable Motion"); + buttonEnableAll.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonEnableAllActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnMotionLayout = new javax.swing.GroupLayout(pnMotion); + pnMotion.setLayout(pnMotionLayout); + pnMotionLayout.setHorizontalGroup( + pnMotionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnMotionLayout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonRecover) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonEnableAll) + .addContainerGap()) + ); + + pnMotionLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonEnableAll, buttonRecover}); + + pnMotionLayout.setVerticalGroup( + pnMotionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnMotionLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnMotionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonRecover) + .addComponent(buttonEnableAll)) + .addContainerGap()) + ); + + javax.swing.GroupLayout tabAdvancedLayout = new javax.swing.GroupLayout(tabAdvanced); + tabAdvanced.setLayout(tabAdvancedLayout); + tabAdvancedLayout.setHorizontalGroup( + tabAdvancedLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabAdvancedLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(tabAdvancedLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pnMotion, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnDatabase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnLowLevel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, 0)) + ); + tabAdvancedLayout.setVerticalGroup( + tabAdvancedLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabAdvancedLayout.createSequentialGroup() + .addContainerGap() + .addComponent(pnLowLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(pnDatabase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(pnMotion, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + jTabbedPane1.addTab("Advanced", tabAdvanced); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jTabbedPane1, javax.swing.GroupLayout.Alignment.TRAILING) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + ); + }// //GEN-END:initComponents + + private void buttonEnableAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEnableAllActionPerformed + execute("enable_motion()", true); + }//GEN-LAST:event_buttonEnableAllActionPerformed + + private void buttonMountActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMountActionPerformed + String segment = checkAuxiliary.isSelected() ? "X" : (String) spinnerSegment.getValue(); + int puck = checkAuxiliary.isSelected() ? 1 :(Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + String readDatamatrix = checkDatamatrix.isSelected() ? "True" : "False"; + execute("mount('" + segment + "'," + puck + "," + sample + ", force=" + force + ", read_dm=" + readDatamatrix + ")"); + + }//GEN-LAST:event_buttonMountActionPerformed + + private void buttonMoveAuxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveAuxActionPerformed + execute("move_aux()"); + }//GEN-LAST:event_buttonMoveAuxActionPerformed + + private void buttonUnmountActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonUnmountActionPerformed + String segment = checkAuxiliary.isSelected() ? "X" : (String) spinnerSegment.getValue(); + int puck = checkAuxiliary.isSelected() ? 1 :(Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("unmount('" + segment + "'," + puck + "," + sample + ", force=" + force + ")"); + }//GEN-LAST:event_buttonUnmountActionPerformed + + private void buttonGetDewarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGetDewarActionPerformed + String segment = (String) spinnerSegment.getValue(); + int puck = (Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("get_dewar('" + segment + "'," + puck + "," + sample + ", force=" + force + ")"); + }//GEN-LAST:event_buttonGetDewarActionPerformed + + private void buttonPutDewarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPutDewarActionPerformed + String segment = (String) spinnerSegment.getValue(); + int puck = (Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("put_dewar('" + segment + "'," + puck + "," + sample + ", force=" + force + ")"); + }//GEN-LAST:event_buttonPutDewarActionPerformed + + private void buttonGetGonioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGetGonioActionPerformed + String force = checkForce.isSelected() ? "True" : "False"; + execute("get_gonio(force=" + force + ")"); + }//GEN-LAST:event_buttonGetGonioActionPerformed + + private void buttonPutGonioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPutGonioActionPerformed + String force = checkForce.isSelected() ? "True" : "False"; + execute("put_gonio(force=" + force + ")"); + }//GEN-LAST:event_buttonPutGonioActionPerformed + + private void buttonMoveParkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveParkActionPerformed + execute("move_park()"); + }//GEN-LAST:event_buttonMoveParkActionPerformed + + private void buttonMoveHomeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveHomeActionPerformed + execute("move_home()"); + }//GEN-LAST:event_buttonMoveHomeActionPerformed + + private void buttonMoveGonioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveGonioActionPerformed + execute("move_gonio()"); + }//GEN-LAST:event_buttonMoveGonioActionPerformed + + private void buttonMoveDewarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveDewarActionPerformed + execute("move_dewar()"); + }//GEN-LAST:event_buttonMoveDewarActionPerformed + + private void buttonMoveScannerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveScannerActionPerformed + execute("move_scanner()"); + }//GEN-LAST:event_buttonMoveScannerActionPerformed + + private void buttonMoveHeaterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveHeaterActionPerformed + execute("move_heater()"); + }//GEN-LAST:event_buttonMoveHeaterActionPerformed + + private void buttonDryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDryActionPerformed + double dryTime = (Double) spinnerDryTime.getValue(); + double streamTime = (Double) spinnerDrySpeed.getValue(); + boolean park = ckeckParkOnDry.isSelected(); + + execute("dry(" + dryTime + ", " + streamTime + (park ? ", wait_cold=-1": "") + ")"); + }//GEN-LAST:event_buttonDryActionPerformed + + private void buttonRecoverActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRecoverActionPerformed + execute("robot_recover()"); + }//GEN-LAST:event_buttonRecoverActionPerformed + + private void buttonMoveColdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveColdActionPerformed + execute("move_cold()"); + }//GEN-LAST:event_buttonMoveColdActionPerformed + + private void buttonClearSampleDbActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonClearSampleDbActionPerformed + execute("clear_samples_info()", true); + }//GEN-LAST:event_buttonClearSampleDbActionPerformed + + private void buttonResetPuckIdsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonResetPuckIdsActionPerformed + execute("reset_puck_datamatrix()", true); + }//GEN-LAST:event_buttonResetPuckIdsActionPerformed + + private void buttonScanPinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonScanPinActionPerformed + String segment = checkAuxiliary.isSelected() ? "X" : (String) spinnerSegment.getValue(); + int puck = checkAuxiliary.isSelected() ? 1 :(Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("scan_pin('" + segment + "'," + puck + "," + sample + ", force=" + force + ")", false, true); + }//GEN-LAST:event_buttonScanPinActionPerformed + + private void buttonScanPuckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonScanPuckActionPerformed + String segment = checkAuxiliary.isSelected() ? "X" : (String) spinnerSegment.getValue(); + int puck = checkAuxiliary.isSelected() ? 1 :(Integer) spinnerPuck.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("scan_puck('" + segment + "'," + puck + ", force=" + force + ")", false, true); + }//GEN-LAST:event_buttonScanPuckActionPerformed + + private void buttonGetAuxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGetAuxActionPerformed + int sample = (Integer) spinnerSample.getValue(); + execute("get_aux('" + sample + "')"); + }//GEN-LAST:event_buttonGetAuxActionPerformed + + private void buttonPutAuxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPutAuxActionPerformed + int sample = (Integer) spinnerSample.getValue(); + execute("put_aux('" + sample + "')"); + }//GEN-LAST:event_buttonPutAuxActionPerformed + + private void checkAuxiliaryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkAuxiliaryActionPerformed + onStateChange(getState(), null); + }//GEN-LAST:event_checkAuxiliaryActionPerformed + + private void buttonGripperScanActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGripperScanActionPerformed + execute("scan_gripper()"); + }//GEN-LAST:event_buttonGripperScanActionPerformed + + private void buttonTrashActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonTrashActionPerformed + execute("trash()"); + }//GEN-LAST:event_buttonTrashActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonClearSampleDb; + private javax.swing.JButton buttonDry; + private javax.swing.JButton buttonEnableAll; + private javax.swing.JButton buttonGetAux; + private javax.swing.JButton buttonGetDewar; + private javax.swing.JButton buttonGetGonio; + private javax.swing.JButton buttonGripperScan; + private javax.swing.JButton buttonMount; + private javax.swing.JButton buttonMoveAux; + private javax.swing.JButton buttonMoveCold; + private javax.swing.JButton buttonMoveDewar; + private javax.swing.JButton buttonMoveGonio; + private javax.swing.JButton buttonMoveHeater; + private javax.swing.JButton buttonMoveHome; + private javax.swing.JButton buttonMovePark; + private javax.swing.JButton buttonMoveScanner; + private javax.swing.JButton buttonPutAux; + private javax.swing.JButton buttonPutDewar; + private javax.swing.JButton buttonPutGonio; + private javax.swing.JButton buttonRecover; + private javax.swing.JButton buttonResetPuckIds; + private javax.swing.JButton buttonScanPin; + private javax.swing.JButton buttonScanPuck; + private javax.swing.JButton buttonTrash; + private javax.swing.JButton buttonUnmount; + private javax.swing.JCheckBox checkAuxiliary; + private javax.swing.JCheckBox checkDatamatrix; + private javax.swing.JCheckBox checkForce; + private javax.swing.JCheckBox ckeckParkOnDry; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + 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.JPanel jPanel1; + private javax.swing.JPanel jPanel5; + private javax.swing.JTabbedPane jTabbedPane1; + private javax.swing.JPanel pnDatabase; + private javax.swing.JPanel pnDry; + private javax.swing.JPanel pnLowLevel; + private javax.swing.JPanel pnMotion; + private javax.swing.JPanel pnTransfer; + private javax.swing.JSpinner spinnerDrySpeed; + private javax.swing.JSpinner spinnerDryTime; + private javax.swing.JSpinner spinnerPuck; + private javax.swing.JSpinner spinnerSample; + private javax.swing.JSpinner spinnerSegment; + private javax.swing.JPanel tabAdvanced; + private javax.swing.JPanel tabCommands; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/Hexiposi.form b/plugins/Hexiposi.form new file mode 100644 index 0000000..4687d34 --- /dev/null +++ b/plugins/Hexiposi.form @@ -0,0 +1,34 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/Hexiposi.java b/plugins/Hexiposi.java new file mode 100644 index 0000000..2c55c2c --- /dev/null +++ b/plugins/Hexiposi.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014-2018 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.core.Context; +import ch.psi.pshell.ui.StripChart; +import ch.psi.pshell.ui.App; +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import java.io.File; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class Hexiposi extends Panel { + final StripChart stripChart; + public Hexiposi() { + initComponents(); + stripChart = new StripChart(this.getTopLevel(), false, App.getStripChartFolderArg()); + panel.add(stripChart.getPlotPanel()); + + try { + stripChart.open(new File(Context.getInstance().getSetup().expandPath("{home}/stripchart/hexiposi_positon.scd"))); + stripChart.start(); + } catch (Exception ex) { + showException(ex); + Logger.getLogger(Hexiposi.class.getName()).log(Level.WARNING, null, ex); + } + + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + + } + + @Override + public void onStateChange(State state, State former) { + + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + + //Callback to perform update - in event thread + @Override + protected void doUpdate() { + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + panel = new javax.swing.JPanel(); + + panel.setLayout(new java.awt.BorderLayout()); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel panel; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/HexiposiPanel.form b/plugins/HexiposiPanel.form new file mode 100644 index 0000000..65d0c18 --- /dev/null +++ b/plugins/HexiposiPanel.form @@ -0,0 +1,81 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/HexiposiPanel.java b/plugins/HexiposiPanel.java new file mode 100644 index 0000000..b29a526 --- /dev/null +++ b/plugins/HexiposiPanel.java @@ -0,0 +1,110 @@ + + +import ch.psi.pshell.core.Context; +import ch.psi.pshell.device.Device; +import ch.psi.pshell.swing.DevicePanel; + +/** + * + */ +public class HexiposiPanel extends DevicePanel { + + /** + * Creates new form HexiposiPositionPanel + */ + public HexiposiPanel() { + initComponents(); + } + + @Override + public void setDevice(Device device){ + super.setDevice(device); + discretePositionerPanel.setDevice(device); + } + + @Override + public void setEnabled(boolean enabled){ + super.setEnabled(enabled); + discretePositionerPanel.setEnabled(enabled); + } + + /** + * 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() { + + discretePositionerPanel = new ch.psi.pshell.swing.DiscretePositionerPanel(); + jPanel1 = new javax.swing.JPanel(); + buttonHoming = new javax.swing.JButton(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Initialize")); + + buttonHoming.setText("Homing"); + buttonHoming.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonHomingActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonHoming) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(buttonHoming) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(discretePositionerPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .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) + .addComponent(discretePositionerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// //GEN-END:initComponents + + private void buttonHomingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonHomingActionPerformed + try { + //Context.getInstance().evalLineAsync("hexiposi.move_home()").handle((ret, ex) -> { + Context.getInstance().evalLineAsync("homing_hexiposi()").handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + + }//GEN-LAST:event_buttonHomingActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonHoming; + private ch.psi.pshell.swing.DiscretePositionerPanel discretePositionerPanel; + private javax.swing.JPanel jPanel1; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/LN2.form b/plugins/LN2.form new file mode 100644 index 0000000..4687d34 --- /dev/null +++ b/plugins/LN2.form @@ -0,0 +1,34 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/LN2.java b/plugins/LN2.java new file mode 100644 index 0000000..2300e49 --- /dev/null +++ b/plugins/LN2.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014-2018 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.core.Context; +import ch.psi.pshell.plot.TimePlotBase; +import ch.psi.pshell.ui.StripChart; +import ch.psi.pshell.ui.App; +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import java.awt.Dimension; +import java.io.File; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class LN2 extends Panel { + final StripChart stripChart; + TimePlotBase plot; + public LN2() { + initComponents(); + stripChart = new StripChart(this.getTopLevel(), false, App.getStripChartFolderArg()); + panel.add(stripChart.getPlotPanel()); + + try { + stripChart.open(new File(Context.getInstance().getSetup().expandPath("{home}/stripchart/LN2_Monitoring.scd"))); + stripChart.start(); + } catch (Exception ex) { + showException(ex); + Logger.getLogger(LN2.class.getName()).log(Level.WARNING, null, ex); + } + + plot = (TimePlotBase) SwingUtils.getComponentsByType(stripChart.getPlotPanel(),TimePlotBase.class)[0]; + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + } + + + @Override + public void onStop() { + //saveImage(); + super.onStop(); + } + + @Override + public void onStateChange(State state, State former) { + if ( (state == State.Closing) || + ((state == State.Initializing) && (former != State.Invalid)) + ){ + saveImage(); + } + + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + public void saveImage(){ + getLogger().severe("Saving image"); + try { + String fileName = new File(getContext().getSetup().expandPath("{images}/ln2/{date}_{time}.png")).getCanonicalPath(); + getLogger().severe("File: " + fileName); + plot.saveSnapshot(fileName, "png", new Dimension(1200,800)); + } catch (Exception ex) { + getLogger().log(Level.SEVERE, null, ex); + } + getLogger().severe("Done"); + } + + //Callback to perform update - in event thread + @Override + protected void doUpdate() { + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + panel = new javax.swing.JPanel(); + + panel.setLayout(new java.awt.BorderLayout()); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel panel; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/LaserUE.java b/plugins/LaserUE.java new file mode 100644 index 0000000..37dd6ee --- /dev/null +++ b/plugins/LaserUE.java @@ -0,0 +1,79 @@ + +import ch.psi.pshell.device.Readable; +import ch.psi.pshell.serial.SerialPortDevice; +import ch.psi.pshell.serial.SerialPortDeviceConfig; +import static ch.psi.utils.BitMask.*; +import ch.psi.utils.State; +import java.io.IOException; + +/* + * + */ + +/** + * + */ +public class LaserUE extends SerialPortDevice{ + final Readable readable; + static final double RANGE_MIN = 1.0; + static final double RANGE_MAX = 30.0; + public LaserUE(String name, String port) { + super(name, port, 921600, SerialPortDeviceConfig.DataBits.DB_8, SerialPortDeviceConfig.StopBits.SB_1, SerialPortDeviceConfig.Parity.None); + this.setMode(Mode.FullDuplex); + readable = new Readable() { + @Override + public Object read() throws IOException, InterruptedException { + return take(); + } + @Override + public String getName(){ + return LaserUE.this.getName()+"_readout"; + } + }; + } + + @Override + protected void doInitialize() throws IOException, InterruptedException{ + super.doInitialize(); + //TODO: Start DAQ in ILD1320: http://www.micro-epsilon.com/download/manuals/man--optoNCDT-1320--en.pdf + setState(State.Ready); + write("OUTPUT RS422\n\r"); + } + + public Readable getReadable(){ + return readable; + } + + int value = 0; + int count = 0; + + @Override + protected void onByte(int rx) { + int index = ((rx&BIT7) > 0) ? 2 : (((rx&BIT6) > 0) ? 1 : 0); + if (count==index){ + if (index ==0){ + value = rx & 0x3F; + count = 1; + } else if (index ==1){ + value = ((rx& 0x3F)<<6) + value; + count = 2; + } else if (index ==2){ + value = ((rx& 0x0F)<<12) + value; + double val = ((double)value)/1000; + if ((valRANGE_MAX)){ + val = Double.NaN; + } + setCache(val); + count = 0; + } else { + count = 0; + } + } + else{ + count = 0; + } + } + + + +} diff --git a/plugins/LaserUEPanel.form b/plugins/LaserUEPanel.form new file mode 100644 index 0000000..c9c5f8d --- /dev/null +++ b/plugins/LaserUEPanel.form @@ -0,0 +1,59 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/LaserUEPanel.java b/plugins/LaserUEPanel.java new file mode 100644 index 0000000..017fb77 --- /dev/null +++ b/plugins/LaserUEPanel.java @@ -0,0 +1,98 @@ +import ch.psi.pshell.core.Context; +import ch.psi.pshell.device.Device; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; + +/** + * + */ +public class LaserUEPanel extends DevicePanel { + + public LaserUEPanel() { + initComponents(); + } + + @Override + public void setDevice(Device device){ + super.setDevice(device); + if (device!=null){ + historyChart.addDevice("Laser Distance", device); + } else { + for (Device d: historyChart.getDevices()){ + historyChart.removeDevice(device); + } + } + } + + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (LaserUEPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + if (ret == null){ + SwingUtils.showMessage(this, "Return", "No code detected", 20000); + } else { + SwingUtils.showMessage(this, "Return", "Detected code: " +ret, 20000); + } + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + deviceStatePanel2 = new ch.psi.pshell.swing.DeviceStatePanel(); + try { + historyChart = new ch.psi.pshell.swing.HistoryChart(); + } catch (java.lang.ClassNotFoundException e1) { + e1.printStackTrace(); + } catch (java.lang.InstantiationException e2) { + e2.printStackTrace(); + } catch (java.lang.IllegalAccessException e3) { + e3.printStackTrace(); + } + deviceValuePanel1 = new ch.psi.pshell.swing.DeviceValuePanel(); + + deviceStatePanel2.setDeviceName("ue"); + + deviceValuePanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Value")); + deviceValuePanel1.setDeviceName("ue"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(historyChart, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(deviceStatePanel2, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(historyChart, javax.swing.GroupLayout.DEFAULT_SIZE, 307, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(deviceStatePanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + ); + }// //GEN-END:initComponents + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel2; + private ch.psi.pshell.swing.DeviceValuePanel deviceValuePanel1; + private ch.psi.pshell.swing.HistoryChart historyChart; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/MXSC-1.10.0 - Back.jar b/plugins/MXSC-1.10.0 - Back.jar new file mode 100644 index 0000000000000000000000000000000000000000..04ee83472de5be6b47e6327b1552663210b8e313 GIT binary patch literal 272446 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�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�_B2( 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

Ec4ZX(Lkw2;R zjYdhxNf~C;R_S0SNm>m`v^lE_eHm{lX>Uq0K8F=U*dwC|9ZUD?M@62F63Q|~atJIU z29|%t1-J}7icSxHTbPMRE$d{9NFAuxC8ycz<*xE2d0F1S1smv9FkFGzsQw8PAEq<$ zcvHKMRJ9Aq*I-#yJO;Y~oEyv{XcS9gLPYT=QailL~3U5EJ|3K2d+LCNaZS_@Owsp;nihyhoH+xL^o+70DFt?(yw(l&m#R1jRMO z7)II`k{G**rKU&U#5&oOJq2<+Mlo`37Rps)t}v|+6R!{TVDXI2fSf%}(M?2GNsIIWfz%6C_ zv-8J4$RNL+7_17o&h*XhlYcASc878LkWC<_cz%3|d8ydN_*4XoHzkAI9m=SsTzC$N zRk#OjZ9FW_t{4i6Kr8U>pR_?WLWLuU;(UO`SrNPiwJ%KdXEa^uPZ2ez^tZiaM+*78 zTaFZW8`LsS23FfhQ*CtW{OuX0g;Q+9XxU*Bq%yjt{=$F^V~1-KmMz+0rRj27P91&5 z$v2dI9o6*Ui~K@JC^Su31S$1Y6CPFSPykVbgZZUkMH`)$4hAn>(xK?cy`Yv)4Q7FE zQr)%@raS)<#j`V|0!FSVK!j-JJm^+%Svw}AAN#bBzf$zAlneRgTy7Qkl2}qP+1O4o z&m2@+@{_jbO(jiuDutx6u1$<5L#pD;0CMd1RlwV(8ry3hA?= zsqjaGo|YfSN*+dl8+ea5XNVtUa@OwFSOzb-F>{f&M5ooz9nAV zR0h=MZlJ1~VRzh$9k4bLf9GT%bk-#X(@70!c9n&R0cS_UZUL$!>*j<$adv-}JEYW0C50N!ld0DJRG4^ME;= z(YJ)odR3%aF4qS!mjN-Gj)}aStRp@9)(@%I`q8rxGp; zdh9JxY7_YO+f||JS(Vfk=v~n=`1xl-@OMrg0ks>OPDWwMU!CqQnt&Apw|FOH7ILYLCf zdC^d*RY21f_1mk4h?&}wW4h-xFxO}v6>8PXV=Q9>)Tzl>sLv{6fO8V6Hu zXb^V#uj8+93&T{m&0^ls>WgR3EMDMxDhCWoLM1*giM^37jqucte-%2R8|pRS$2XFy z0@^ozIz2E^SoB~ePms}XlD68YqwOy9r4K-FOCtM(%7(%jb%@SMnb;AHM|F5(99ope zNT4uFCEXk6VtWbFFBZHI*W%W+r?+yUVa7`R!y^9Qb@2wTA&aW zwpWBxfBP_nrtQ?>b=3;cO~}nI6BZdzp68D3)X}FA$LxWawEarkgc9_TI8b&G$4H3( zVNMn-nLs#rR=w~?Oo=?fAI1C#>VA^z?fnR;enyQfp0b4W2z2v^MV@ouk&#;<`--a1 zNp|4HbVbrW5onjE+CD*WpRpDl7hVoSufVn-X_o0qGRs(!$+?i;|d&I3G#rz5tTkT!k+u^iKx0f+Exh)eMD$~Q#;z~E%cQ-;#HCR z2}rlo3?0#Na!L@<^H(u?0mD*JV}1u5FEINtHF2Bz);4uZmrST%w2kw)(agi zmn)o&nJ*Htw2ocWh$5fo^#$Feab&6kU_Z%Tw!8zbfJKfZMNu zPd2>U_`If?{$T%CL42*M^9S*lXyE__0D%2JD2NJ%cBVG}AsTH{z?sOCnZ2*1SOUPhmv$twbX$|97!<&dgZ6$pGp7Z;m^5QFe#gH`CbV7 z7vL|Xw_J`z9FnjNn)ujxXS=TKnBNwDKHu8+0&|4jCSVLjlf>+mU>u`tA^Ga{Uy~TM zCFT|98IXm8n1NnxgPh#u{6BoXV|ylSmn__2$2L2*ZQC}k*tTukwrzH7n^)3Nr^Al< zX6BhW-g)jldw)BBKpp3*wN|aFj9oRx{9(Qx26EVGontg9`tzgwda zR{|lRZ&Os5N&hfpv@z-E=rL`3zeJ6sUIwWw*Fx;DjqvKGyhlxdy}08umT!fLJ&0~x zm&cBoCGLY&0`)jSZrXl~DQ8DiX)w{s&_F=e+RecPHY!Kp`;e*r;(Sb`S~TB6c^$UZhREuwve_Z-OF_l5`i`w*tD$rB9JiAMr9Gib6qWO7dbAWUHiuRV4?q^jsr-JU@!DUNx8(+JM=O+Ah+b#m9ajOGm8 zt)%jPs_HVlE%Q2TJ40kL4X9|K18P+td-0YRmncGOUXk^DEZ5Eo-Bbf87OKNoPl6YG6R<7A)`s_P*&0ME z#;Y=Ai3>~W=~o=tNW%G6 zrr-Il{ry~R^vBPYizdmA*3&@|Zw$Y{4g;h(vEJ>|jXu#9S1s_*Cgd1%&i=K>OLu6L zIyh1^3gQuuJnnUNVNc00X2^*yTU+RL)n#7KBD=E^bge~*WY8(A%q<#N~@7>?@;mXS|VKMcW zuo(Y;`AJn=zSPA3y;qD?KDR;@Li-@!FiGyPZEtL~>|JqVi`=A-BCd$g)Pa)ICQ|ml zTQhMxmG91_^N!>XtUs_v7ZrW^#-HM0mWUxO2sqApo;~7W`Et746Oaet4cZ$3)plKO z&@5j{3e>RGW!djS=CIjraf}Ac;Pz=`LVbT5MlEztqP}_(q3+@6ZG zWKMbThHE_`R@OFUz?#gxBnWO*;xvDep2~gmAWd%fK}#&%h=+)O@F;@&u+G6T)5TL7 z0bOdv!WrUJ__`n%6|nuSEK9zI_?&@yRfeIIL+#6$poR6FUERh5;j-YOAW#N@`;@yQ z+8a)Wd?dbu|JwZkK>w4Dtk{r6>R@=#7qu;nekcga*Q>^!;5>ijF99PbU#)2q@(pV$ zRj~JLI}dk>I^(p$bZg^mgVO?AWq32H%?eYzlS=*0+2!Ns%x#Ppdjjz}()qCkg;j6vaVkSujRyS@ElI>a$zSwKcq^858C%Rd>=aF$8N_^YrzDdupm{#u zdEPgkq82fmC-)4sy7LWfF&m^CoDgh-RzUsA?zoRFsA((!seY|N>;wl)XUt|19oq8( zp)yUP-finE?(A7uInXeDy5Q4*yp~WJ(sWCX33U?qc5yLv$Je6+!hbKhZs1SUgL zWfGD=s&>J=Ysr_b;RM5*qV?^f^Qm&2LfmO+32JGkO-G^Yuz z73F?m5EDc^E8GDShghE0@i8<94Rsjntr$89wK7Z|v#1rpP{7Rsbd4_wBUrXjy+_`K zeTP}IB?q=y)v6z`;tcI~ewI2=Zi*YN!$v|bQmE?Ul3A3)w;#wtxlw!nyIU@p=(Vr@ zcD?be&7*xox33?@v-l=(7(oqx&TpscYW+jUd8`ywOmRhWM!L?+kRTgk?d}0ae4l4m zpK1@&vuU$I)_v*@e-;~MDo?B3^Ad;ZjDaT)wT3z7{#0wiUdgrLYTn0jXyfm6!4Yb5 z$|1Drn*B13{(yP?9R&lmxQQWp7&yLmc>Q#-VySl9w&Ijic#2%T8pESdpY&bUg2i*% z`y$XMSffL1w#+!C-`JQt57-GRtnitxItD(;UB*~z3?+q6vR#ru`d}Bznsvm^Yn45D z#IwBShG0WeU{=hRy-<;BjahG3xz>DjsjjV4R1ZktC-$_>`EpH+58)qqcgUKPiJ&~_ zh}1E}DnF(7^s_WKG(hSMaS=uq$+D6C6$UL3C>y~*Of278!uyH7ATy3fc=mITyt-Yf zBUmc2JT>tMPA1{>JLO;4OxR)hPo=s9-lRC}zzN|IzUeSwyj#3v8Gj707N!ep<(O}> zIYL}q!P4$IQz@ePq_r?DF>tlUQR<1Mrf(OSLwGxa`Zdy%k|?dY6pG!obWwr#R|)OO zSuTNr&XmOSrpOhZr@$Uta#Q39aveGdZl$K1hgYxyO+pErC&@bs_;p`GT2|qnC z91Nbmr<|OZ)W>6R_OO5aBUza-NO1@B3*mdv|2wh#pU761QN>lm`miIAMF~rLEQZ(= z9!7#|)U1Ap?6K0$Q&y^|2QY^g0#GPK2(4=GU3EL$&&9pt>;k|n>Ge9C zs#g!)DX64SH(@9qKd*8>KR+IGpP%=x{J|Z-^FtlJ4GFmzk%lP6Ky>CLZlwpE3JW`# zA34zvoAQQ0%R(}Rp8YVpc8VZw7Q!2TMryAQVGP$O-LzIV(RYGP>Mq#7N6KQv8^BHK zqe^cF_0UnK3lNiXg^+>>3yKD{`q>2M%~@*NEUrG7BzXS^eQ6=x9DjxhoYzcQkQBUX zQGK$-gBSxms5&eU6ZMo}E&VXF2HT)FYvpjs`h`q`O&8QT2d6Bxr(VhRXN&AfN&rLB zX)X!2JOy-*d(Km`b#-)@ufC4#O^F|Gt#u{W4Es@^!>M!HOpV~wrJ1F)9&-*6owaQF zHq<6@FJizxd$c3Hs1no5`%tOvl_6oi8Be7$T$m1D6L{h|p&!E#lZ*I&9`xcQ7thhtRsY%wo){-v}ciXTr6c@z~! zT~$|Ddc@g7Ukou%wJ}N`9l2BVh&jOgG#>`m5&|2YUDHS;O;_C!LPJe=$Qx!? z!x5jbqJs!sAO)0z%pH|^?MNP>HnXy1P!ytkyN=W2wje70x>1)O5Gb-S6k4pXvlGzG z6Dt&0rZ+{dsMEsK+F^7mYcX{h>#DgwZ>&={ttch1oOTYwnoa;;PB$iBuFTwH)u#M& zk~^zZ#o0iM0-a2Y^=erxP9*>aC0WWk>Q2AH2Bat@KU4xP{3gpX`k5B^UR;fRk|pR3 zA+01LuijKqq}#Go4ISNi4zzf$AB;hNzzb^V!z=UAoDA3FaoT8P1IkyPfHHgy9JSo^ z+oNq1N*2SVWw{sbJ*Xhl+mg#lOSf-IQ1hs;Z(3|k;ISM1m)n+Vv{KV1urTavHA|d2 zs84F=CtZs8nyxFx5C@KQ?vNcghh^TrUHKCJ{?(F%>Lji=3GHgRT>9lgd5!kSP2RSszE?ka6E>G3&?J8G~USSt^D1)xaz2 zn^CR{Y@aKEr%XV%VyGQ>1%2R3k2J_r1Pu)+>D++@$fGlX)cL#875m$QoT{zJM6w`j z_`b)U9_zyq))WSB->(7ks`f&=KN%MxKU>qWBZT#B;HQOY61SdN#fL_oUSRE7oaWBs z9!f<(BK(n5u0fxTIrAQ+-=tlRRa-=T7pvdh6-joi+$+!5O#aY+#G$`)A8!rku^S+G zJ6BwMrdjlN-Unuj9Td5-*dj-FU zpCQRG$xaGqyzP{F?Ub^SdcrL+)CMc#!s5ba!{YiCWgzwr*>tN~xaB+1q6$Ut) zD%yMz%m3mC%Kw#sR$qG#+KR472?bSJJN|Mns7$+nlSE$4nzDTTmBY1_XxqK9!+v|o za5I8w;Dc-&D=@IP&u}BuvxR})Ols$L{1t+Bnd5vp-JYM{59$%}-I11BQyKZEEjmsb zdQC;d%dDCST20kBaXE2ZPY@5xDwa`p6J0N{2xoRRlc;nq$si+Oyv<|579Ykuo=_W2 z3I{(~hwV~wj}RiWM5&Cro=Pt)2EgvRmFjigYW=%ASKeBo#Rlk5e;!f3jgB7eT{M8y z+I`G~E{jv|5r3|yp#6e62BZjc;hR*@1LtX+1929D$i_6Jad9b>43AOcvm+2Vc_?rz za1SL~K-yJYm+xgZ5t@_=*1mATSFw>HG{0oNJ?G~iik-TJYxYlm#%FNdblsR|40H7F zno59CECL|>9lkN(gIQ%e?Knx_HP`&eXIF6t%Ve}M3D;}!=q}XYlW4;Y{fn__r=pqW zN9whR_R<`P?ZogjM{-}@u>1>wgAd3^$!F&}BA@$`M0XSuz~_RG*ew1dUzn?*K$rf+ zO7qKSdGJ%1wZgNYU83~y+y_MnS6LR*Y{IULNuYk6Ot)w4Eihh9IZ3ddi{rvXq5T@=%Ac2y40;N zwN8ips~|}{)ntOpEo;-zxZIbQXoy?B5_gTEx=SIgX=^8=y2ebYz%_Kp1ijmG~mEXviec2HSE{+R7;sw1WU z0T-eVb&QM>LRirQ8c79$YYZ2JHN}he5x$=H@66VagXYsQxWpd#zkGnKlZ6*z`LnnVOci!FRF7sAy z?5})2AOfDBN)d%>{sP#wds;$#Ek?Wu#Q|W=xSkusG9l>{Xf_Xn;jYs*K-20V3N7#4 zpmLwYHKo>@Z%SW8uY%ystZBFHN2e zVqMd4t7m8@XdgX!R(COvq_;5TCh{NYvEbb9rG+1`&XB%V?>5Ki%wH@I0`zj^#)P+7 zR1jf$^T&Rb!U$a8LZQc^=GM-JSw^jwP7vu)p{lBa&HN1K-?;hIvxsttvd8EOvee%; zY~0;&DswK`;`E&Mo8z<`ZllE}95fCb(cFBttQ2=KN>j)aOvdE{A|fnESlF|t3;5P| z^c2HNK0Pn0<{H$Nq%3HEBq^$idMQ?Nk>_8?`WIwf-8b@~ruWk4bG-5`{2DFf8!hx3 zErjHMg(S5*QQ-Z=ly}WmG8W5GC`gq)wL#DxA@NWZ17rBhXfP;*9`2wyqRd-w1ae&M zk&zzSLkpVP*VD0}Iz57iE&$oO`jnI_M#mu;#Th_Ctv?VA4;U*3Jv1We?d|{p4}& z8AoG|<~woFfr^7n$=JD7?YBkUV)@v|bb|&9)v(+u{MRV7*d)Qtp-Y3QI-EELRl;(wLA^ad*HsLKrv@o7DpD z_xbU&U=igKnu;-_SZ?H%z_PNk!ozfxHjT3BCxW^_IyHyntnI;E{wGHpDEg3mL3S)N za)K4-8;ekNS1J~>44OL&a?^(d1)jv(8`+-`8++gwoTY77`lF=XAeL6mtihpXvmUbm zRd8u+&MLf9k1gkQkFM-Vq&W$mE=gr{EZ%Ui6sm|!5mhn;)pDPH9f)e^?OOejK2_L3 zY&cNYclsofx?XEUxM5WXnSv(8Ep<3^FO<<3Udo-%3cy~;t+H@wDN##JD}d|X(Bjmv z)lEK2&Nv&86}B^+IN*R3mM(y}ht`cnbG5N8(kHQdZ~b@7;Qn(c4T=L<;Sy@>@fy*p zz|y(W$l2UmTPKYzw8pZ{MAA zjQ$LDyf)|NPkq@}qJHylHKU@dxK@;Rq@n6T z-tbXLzhyLwxN6LU^o00#-m?27W@9;mSrKw2jVp=9^?|q(o}G~#@hhK^^tJ=z=dqWw zu}}|kXO;EUT=9*Yu_#`RjUPS}MtrqoDT!W@&*Ev<>;Og>$#{4iz#3pLcl2v@HGVb| zXU=zOB>ia;u2q62{V8vFt+nNp26`k6ttpfDifHH=v4<=f=TyN{3i_XlSVPq9>Z4eu z+FDdG!j8yc=}gSYcIpzwb#}h^3e=P_oFyirHPxcyfl321G7}&yQ<4GoB!9+Cx;8kZo*EEwG zvdnVeKT&uM`!`6u1(=gU zc$1;OmN zKTzBxxnwo$3dOr1)JyjdDV^c=(7z*(l?WWdpVf2Hzk}IJ?;VD?d>=E#l%J%QpGdw= z(~VrZCE+AtApceqj_NWlw=pNqOApJ!3FBR2rff##{bCr3qij-{_RSqQY%TlVQmtAH(vfgCx zAuWUP>1kHW8h&_W0u&YkXDG|YemNw&!{|N@s;~c`)CZCSkRx9=AHH8}F06l$7!`o6 z!+(1_#H#CP;Hsg0AY_^dW7$y^&WC`~%_CV9x3;ym+<~elrid>QV^-rQG0A4?PLsC0 z{K>Ci=<+#>M(j!}k?B^~@V#F!*q^(ubiK+vBSj!VAKx{9_)47Id!Efh{qT6+a{hL5 zof?BkjHDSSI2g{W4NWrifswreCGNlzBxJ%f;WJzuZ~Dt*8(L51=SyS(uDhpO>y5ZtRoPm&vTBvJ#0fN` zA~0ILRy zSSnYkaHQ*7iy8?rr5sE~3JSmZGTcfL9Dd zT>*3Fi6~@v>pwAj)TjE@AwW>9PahV+6&VISpz*Eaz$|*m2!VMs6Ht2$%PKHC1kI3+ zLWmgF zuM-7k7#y*^#xz^aaKA+U0&D^4wi1kBnZ5RVuceV>>FJrN{UmW*(N=WViFQ@h4QaXF z$xYEg8H;NQSD^*|cn0oJNyk3RD{81tK3I$BwKRxySwO@rsc{IWn?m_+r>%}i$(cT* z#tED~L60eD_l4I1sd9*?9&N!;K!2Gl&;4M}D>5#N6hu{Kl_V$Hu_s;*c|!xD$+?uF zyhgmqp5bSZ^Pv9%K!ic-U%q!N(X} zW{7w@1&MDD45ok5%XtKO^d2nt8N`fehtDhjgD@*U^0=_4%wZ&E4#i@vhSk!n3nA$Yo953)%t<#|97n{; zj+HWJfCvxnH@;>{0q(=XK|UbAi=!y$zmHIhL%X*`7LteQY^w|tl&EF2ZOg%hJA}&n z=ZR}HiXNiV{*Wn_+ji-G!n-)7u1nMvUEDcR-=g;>>J?QUbtOXaC!th&3cGT|`%5qu zb>&F=^fz5V|EMceZ4keZT6jvIdrLS^vi!1dc zAUFat@jvK8#5aGuqV?>BQ>faECfB@zpeq0^(dYKHAPDb@Q3-Dkhn}Eh2-R+we00gq zxE^ky+y3$rzK|m3E8kf9goV%D-l53k|4rV7rPdz?t*5)a_S}5}l`$|mli~Hz8q`4Z zQ4{X1Rhat)2VEPf%Fb<^y>RBqgDw}f;s?DsZDaMjqIAw=CWQ{z#-?4Y=3S!WKR=y4 zB7)*2+#0j2=6wafMobi&^1Y_GlCa^SxJXk)d71nv%TE?EC1I8g z94gHvFM6{xXQ{tTpueD9$H;7oawoGyY2+>^Ee6@6&4~JE-z^5GF*jf<$?l{`PK@Bf zW>>#$WRS}QgHsrzoBg%Cbx31w@w$^FQXpd0$UY(C#?(}+EZ{_PYH{-7N0q~%W63|O z*sBT?n1WbI(7|=okyE?nS5Z&21r=&n49cRN)}}g)m>9v()zS3c zhzonYP7=2@?ho^J6dYP(EZH}OHyGn!)g4U;vv0biOY4gTf!_n3p{MmlUr~984XNp> zG?W0a_SPK0CD>>WyTXhqEj0lbxL8H&YiS@nA0T4wBJ zCHrjf0;395@X!ZrZ)lDX0!!Df5sZYa6r%++Z#gv z+V%H0r6I1I`D==_kLmEwB4GVfb{IHA`~g1BN1VR}XJ|>7KXa8oknH!5_P$0{ywogi zF3&+p^pTMwld8z41z@8@TpkWq`QnyE(4xg=WKbUa;sMkStS6)6O9ObnWxRHnEu+-! z{L=uGW9n)xRh`&MOR{*}_BGXBiK$srkvKXvM>#?F8GGlh*`J!kDX|$#K9Lc9syR)7 zn{vyfp1st9r5Ix7nUVUBSgCcV>QTuE5vEI;ZO0rzntLDr8FFu$4&o!zidPYPp<4B9 z<_iEZl{rRp5R1Rf{<0$n&3&NSn@;W*btE$?wYJ-d`?=1G6nxV7)oEfzVFhsO zR7!5U38?(32SDC_;^CY>2^cjC$rZwXZjI65YW*SCldgI)r*eBLPAb$h-2l5|d<$B4 zSN4!Dk5+r-PUZ5BW}z;6;`^+MRmp8nyutWc9e3X4#9hOJAyxq z?-uhbxxqVFlF;^#CHtvKt*9TD)+L%97q92-RXiY+Ii2ubfjeu!PV%^irFGB^{NQ~7 zzF3PPA?-7#I3NffXvnY~DN%1O-b$jV@1$$9WPi_MJ2)4zzPKLrE=0wbtA(z3cXI)4 z0RXxW{DrS{?9xYT&HYK~C#eT<+CYR{*|ERY)4dQ#w*lj4j6kHv#8Z zK6;CuILRDeAT;6(HMG;)ofOC9IwR4yl^jpR}aBlq~^vo3W*nnLh3rqmW`JuVLrS-KtPP)~0o;8-KISn_nUgKQN= zeaBUaVpFy;oc5%a!y`|7hgHbfCY&fIs+KFRQSL9sa)0s0xby6n8iVK2F~I0su6x#R zcLwMoqqwI!XoO7ICP!)=t3la1W$XUjA_mT)2-}w}&Tx0v$_kXyJ5)Az>LIB!Baj9v1Ds#V3?{Ei9;e>W~tm7J*|x z1nYvPkJG0Qkn<|69;Sq6RIGJ<7D)(6zaTy*j}xY6-T43eh}J=wgh2LdVPN;w;gJ2W z-Hnu;nf*Tks$!J^|CyN@5E2d5sJ5BQTcAw)r>FIktJW0R$W_H61hHeUmnz5X)c0DdAP$t^o zY65Sy33{VBRxrNA?L;iFz&KQ3dtHF+{T=SbTKb$2hd;P;vXhW5+^+eI1ADY;H*d!R z((S@`sTse073y8BPle$luY%D;AClJr2jr3L1f;(I@J@YOx5}=D6YkKyPB4kzWk{0} zL*}S@f92>!XK_kh>OoC+>!H}yod*qpbYT-=NVl@gP;Q-3Xt&O-C=w%O>7v3pZvZo| zvz=S$SnIP)Eqy{8aQSfjuL1Z^lLrPX>4eM<`Zi+w#j0sbk4Z)^=<-MaFN@=MWAdg3 zS-7Z#;F0+~%Xp%rP*=y3PUYvE`_>EJJ?q3~ANNZCOEEj`(k(I9Ni~deOUGBs^OX@I z0DJ*&#;=@lFbGH8KtV_j2UIu_)mRmb_yx$66x7&bxIb zYJMVjDD^cT{*w;c%&&KLant-hY_UN`_)xz9b|x;Tpt}YCQMM+DRYwh@sCmcugG}Un z1me8Xdc}5HIj%szm>60(HHHVj0j2F^R!e}|)ZzwD^%7aaei;r=>I|7L8#;NWb@VC&&* z%-OX4DdJ$HeDmzdEy!R7lOQJ~It3jXgO52ypY)KZil6^F=Xs=w5DR})8T zSe)DFO5?(^Dwv|gYZNh{m0ru z1JLrS7ekAV`zgN(!Mc}=>>_;adswQc=N~6w^d0EwO;_6a5j&vHEOmM?cfSiM9P(7J zT(~9!ZuQc;B2lMo$HienjoP^;v)ae7U#jEw?Q!n)F736t>3fw(8fSdNN`>#oxf`YH z$PlE>PI(RrbpI&xtK8d6?KJvGRJE0&16Dd?-brLwRPlfzQ*fQuRd#6ZlsvpH7NaF+ zcu-Xb$;vf9z_dr)wkD$SJI{-h>RnbYnOD~2>VaEtr6jl)pHn%BL6CNnWRtiaVPxoY z*rQ$ZY>ZJ&flM*DSc0nq1*}|_VF{(K9h)>F+irY9N6n!|V|dx!659xsBir|E*cjaL zw40N+t_GJ@owt*;bY58>X;0Gn58o3AZC-V^5T)`7(*B~V2%!vhKzv1_Jx)x?*a!Iv z%|RIDLo;oYXGa)W9>gEWXA8vVoz~_lmGu$(fr#CD*Ii#Fv1!w87sD`r#k;FhPZNuC z6v)fP=a4wQ~>Qoxsi^Oo4Bq2)B zfEe`sH==MO`2|4EvS_VlBwI4GRW!Nn81B#AEtFG4GQJ=THg^lIDxZu*LK%oQA378I zvt`tTqvep2uo>CsKV&QYTgr2+U$|BO+IZppU$OfyxQ43f*>9Pk`QqTo?~e8@TYwp+2Bt}ZVGn^W5MZ;$>nm(N92A5I3Qnk9F`?d(hG-z2houFp@Po7 zZq6*S?GTSVJp1iB=NW&#U)A@6X%4qDmo?HJ)PQ%q4z zYM4Z`W?sFC3{fCU5wj6xiV8a6Z21q8B|T$5Bk4F4p`0D}Hy4*5>sh&iQhU)(OzHbKC54oHGH#_FQj!Bz<~EkzIxe zP}}5Ng^AyTp=FIb>kVY`*BQtJLB(7!SxpOQ92~IF=dC%+Qormw{)2QDL5O&v*Zqu7 zmdj@f@S>X~G~Ex4%oCp}Ku6~4U9947FgrkjYdd7~u=_-*op~)&~%%SjzR2oO-cn8~@KaQ?pbtCJ~xF(Dt@(l;-=#U_=DOOAcLSst4RwlPcK{;hEq#US0Eb<@FI74vw_Gt*5V`C`9Tco>30cK~P z1iL32%6$7&gimaKP(j&0IzAi!Ms*A-!V=$_6t860uezOu;stz zaUo#8{pR~x&e+T05h%r03g9yyr?#wfYn+ zl}@E@75ExdsKzc6&KoQm2=RFH2g#kMjNe|){^8i0o{e#TKLK9(f6Mquf{&TF$`nzJ zL+;u_j86vC{?7bmxZ~RD{FOS2uOv$a&<5C50@>idgc?BjQa_d`T05E>I<{#G51ldE z<7LKrV~}WRUx`Q=tJWHTm`EIOy3VD&v_kdLSwS)k_E_X2@);ZJE zqTiM)jbms&OVW;66k|Kd@RXTOqDE~Bf{4RokX$bQ45PDmqO|mvBKD124a`u2*7n37 z^%_~ve&uO!eYqRW_493H_U8yHOjtY5HP?{CM4|4P{0_BvKmk#U>6yCwjA3-mU5`$x zSfdG*!iju?zKR>9{$NBP4Hn?k-c1}#1k3Cc4oVyp65buY2W)A8diB&|l6B~@XSzrY zLw>{wf5c~QfP0tin&1|aJ;D6c8l^_K-`)`Qk zwIa(dmB)uiG>)C>tdwhO(~XkUC}OoXHb+Dr!$!Xn%F1M>howD3N5>4yesy9@Hl?$< zmAS@w!d7P;B*w3S!i2>UrpZJ_77Uk*&%ikgGrr2i;)aAn?{l#Pbw*1eAkzIHMe%l6 zrt}0|`?w@iRqqC+FD8JfM+oZ}SDLV@xikH+$EOOM*(Kr1urjcuO|g5iN0RM(IfEi% z>vL(5OfURunvTq6r5Op;n{3%N(i*kV#sOEXpp zmG6dkw$D@nF$-A5m@uc};C!b8S~1Bc%L5%DQy`a<$jCCnB-l?(_i(j3-y`0l+Ef)@ z?dN@566m|o4I9kFkw(e)Uetmii7ao#iiF6o;>xAL{KG zd|n*(2#+Ej4&8_l_DV<-`trY=1NkA*no6_fAQJSI!7E_LzS9)sj{;njuTLnS9A9J? z6U)vxSuzUB*#pr@0mNd6LO6IDXR~=Ba!oScDA<1%mOjYp4r#UrI65Nj&+-S{N&OYP z1@_ewYIe1Sf11q9i!ceTR-sJ%NJHZ<@r*&qDK)X5K}a~k;wKxXoyj>4XZ1%0eE!3o zS|IUO!=LWkw*vZa-@XRE-yAIMz7lE8YrR}mw}j?@piy3GlWID;yVIdP?q6PB+Koi( zG#ZW6c3{dBfV(rOZvz**uXekyyeU3)Z*R9u+}+&VY|PD2tE*_kj;w*_wI zWwA6c1mYywXl*>a{vP8C;Mqgq*R&sh+;{57{$V!EzVJEF+2uljR^0H_y^+T4-N-=# z>9=u4BmAI_xMaR87=pGt^ZH%YWlcdT>EzF|m&K)Dv&MB5D^7B7Kzp|_abV8~RbR}F z9Dm6Fw_EDM?p-qh(V(2&yJ6keiSocX+UsDxwP`GfLwT3%2oqkPXNzBxG@9~ymu(Tc ziyElM)w{WWdpq|>|N0NYt{RE*Th3C`d=# zSFqaVwgQt{j+6dQ(B__dG=C2K33A!W@fTlDvjUuZm$-}Vq;#8&Eq|)?EPFHOTzS@< zZ1Z1RBk)p)p65AyrWYrixc(k!D&Z-1_L{JjVc}}oq8n>;y3!83D5IXw!D>Dk=ouL6 zL5h`1$G=8j*{Rv%M`##bZtJdampmQ!I}giq{Q(-ivTr(A`bHuu)hX(@`MYPrSLHE0 z>N!wpz0+>*8UTSgAw4|?9-Hr~VxW)`J7I7vuytpABcbE7O36|?SmZ^(a7ja6;2CfI zk!g%JwhK(|;+4?y+LSaUmt(DbWeB7Nb0>G5(9D7Z3$0?NJCvjaeZ7+DU%9|XHI-z2 zGI@T>A_~;{)}LGjM$)e$aU*P_rM#ubro}ua0lD2RtV2^5nMIz~R-}bi)^#j1`nzkj z_DGhwUTq6Zq`q|t(9Keh&TsqZeB6EctR|6%q4$wK_1iQ1?0ei-+FFh$&5qRYDUkd} zOo_h?J1mWlZ<+YzBH>!cP*{#fcTe%2S=XQG?>zc8wI6iVw)(nwb5z!I+?l#=x%La* z&|K!V)lPbWW^^)>O;pEd97#j{{tF-9vd#X`%pU0pfFGz7mirKP!?|=r`nX^S!<%+M zjQf_huGOfYt3y>7tB;s!M#M2*3a+y`*B`VfYU6ntruUN>XN?LFoJ-#C9*gHMlrIl) zHVTWh=CR_)HNnY!Bps$nfLx3GZg3lFtQuZeN?;`ebcFxE`32!y0JZ_b9)sX|85vM>xt zPJe1-?)yD~c~YF=@FX7b!m3kJO|;D%zx;zJWjh`ILqb2Y)cQBbrAm>yp{Zr$o#KDM*dZ!ZmNUd+2x zg0AIoG@U}Fp^J~fa+~hh0|OKnonAH^7NJP@I1UX}sTM8i9#EUm{RtYN#2)HjIfCy- z%;3#Hpu@n*)TXxg6v;0Vn?KSob5|^Ax|d^YDP-k@TIuiegq#wPt9JZiLw$Y?(8Txn zfKz|V;1g71|Eb+=$@llA7fPSbHMZTZyj=V1*m8fX-wb+-)~e73BEY%86UFy$V(HcB zD-u!O_`C#8ff8q^w<{N9WfQFL=4B1r<+bB-)3<9S(xLsRvdO~)>MR78^jka&Mo{mc#dKvq^XQtelkI#$=%G+!^gk`r$U3>8B?3$^q0vrzMbq&Q26sq zDyZzik6_}FI7k#<4yiZg+}5g%SSd&UQtujCexofvipSGzXrK8A?|A>_>(@uYT2n)G z#n|}?&*F9Erq%XlbD_4-QDE?tm3#W`DyddZwhB79K;j0MRm+A_Qy)3F1PIW~QFQxO zosU)WoQGC|rummdPHLsc7OP|?H6a6VWbx57weh0xMao~oibl()up*^YpTB#lZq z10AbUy|I;pwkVcaCCB=o43!HwaatH6GD!t)LyUtVW;%$Eb)!aabU{&%2wE%Lor}m1 zVev*fr#a_&j7>U|gOD3R-q&pLbJqq!4~pNh-&i#BMM zto6&5f%2#VtJdwF(26as6>4f~dy9%HH{*kanWcwmwAH<2d?L}Om86~U z)$zTuLC1Bdf)8-4G^FRvMQIs*vl4?3!)wCTkdlgnoSWjZ>Hdw#6>5BVF{4k);MubV z0x)D5+$()nYMfxw%6Rd6@k25MP;-adRgu;b0o}r%Q(G02M@C#keS|IE;bb*ojvnd- z3UtWcwlpT}$mC7W=}0nNnqcb(@2Y7%?MHn>Z}Z(mz*{Dc%cq(NU6zGu8yyXATw9rE z^eO`Gjhg)wTj)L9fJH+=ZGZj+Mq^#FpxMbD6{qo(K+GNSX))+O$K9Qy)!m8*>A(~hcd!K`FySM16Dh17}T^W`>S?zR;pup0t z7__Cv($m%--JGr@$T^(H=LzW->1UB))231`czv-xEL#BWJe*1|RABNm<)sl`IZWlNpoX|ibXU4Z!1!>` zy)(%VI&sf5UU(X;R-wVI82G^QYju=T1tB*p%xu7dh2Xbn*9uo5$T-F}JgEJuK15v( z$-e{P#tF-I&r?+S9@@Kn4i1zOO|iEY@j-1yT=g~7u})B&g4al7mKIw@keG0!48;E9 z?5JuW5>P3)9r=ufj$ih5UgpF&e}8K!9bO&8c0oWdUxtjz25;?xXdIQGd)bmaXYt$` zn1+i<@r@jO+|e0d4Zw4SH{sq@8DC@La~;x*-$$ihGK!aq(U~U@4n=0#ibaitIYsvu z_x@gLDR@hGEsl-I7L0pB&2r+gFK5r$H<+Pen#m$ejHNNyDkwbmW)b7E%xL$&D!Pnf zwLol&?#bhUgQL0cN32oE%)o3xT{uimf;(VGfrf>ln~{llAg-2=EE$RU;0wR&?rmLC%Bb|qED+9czCKTv{o zq@U&jb}4GccEL1ky)PGaNQj;1{6GiF%uY4^HEhC6tVrc9! zsjaDDaDyp}(-JL(Om~y+s#g5M`ILOn>P(3zJ^v(99L_P-%bYbWhYQz}MjM(hpM~R> z!moDzF26Y#Rm4h$Llx+fS48Tdn;~O}UMlmG9N&;-)LEInzno$tFR#yoU19ZFpvi{K zO7hj!TUs?gpishJaxT(}kC?(MGl=oGl^I6b`F8TV%P#JpOw=Rmijta|*$g33+35^M z9S25U#RL+ZiPlOt>x=;4i^SQzg{g7BNLyxdai}sl<(ZM@EqOT`01%~HHlQyINd_bH9G6Dr?<8hqXhUS zm^E})&)lQGh9y>q!VM`YX-7`~ww`9bfa8j*eixZwhry@v0))Z9xyu!ZC%(q$ag2cn zDwy|-Z(i6LM+4b9(#i2LKYlg_&o0qr|( zm+d=VACI$ha<(`7!wuZVX`nkQYN17X$Lq8jbKvW+(UWi2^6Tw>z}PfhGICQW4&=$c zT;%#U1F=B1*7dIe4Qq`@x~NJwE6$`=g#?#@67tnFI;(dpoaAli)W zj=|Bd?GJ`%#(p0XchJMqLZuJ)6x3*H&QW>h|l}ST!sgeYf$GNi2`%q1l zLw9U`g(@oAdkhbAfZXtZ*%23%)X_M$F{7cOF~@MixVyWf4)x^J>T*(9FQt5AnY&W! zM7F`B*(qw4n$zIdE=F$;9R_a-#6X$n*738?>SL+rWy3sic2h}13qkFTEfpV1&HLV3 zAJAqI=<0^-eY~rLoRUDW3wlrlno?!Y5Mlr^V6xztLioj%{lr#ZuAA)mI?MJA&%vciOrMbFIXcUf;B} ziURd>89ZaFRahoCsh^>iEtQoaC$MY)~UGMgPSikETtuySp??V*r3&#{4 z!wmWh_kI3Pn1_-6bThR(;*c9NbbW93!#w@<(Y5=B2XG+oeiulmz9&#>+)hr7QT#0m0dquB@^_B zIXbds?Y>rr)apm8$3bzM)$R=w8Yc+NqeN!%gh4-25r(rv|BjTZCWt zbS8^F5fPC%!!VT6N=-&mAuk7sr9Lwk9os2im52LLvFV{9X@kc@Uw{GwYwxpLP0Ptf zFL^Bw)c3qMv9pV#mP>MZI&G_8Huu^dLWVk}!NI|HC!xAJ{Wgr5tFPJF#q)O9QClS< z%_RP~9TZ;U3CYR0@UUrVX_}1qQBhIQH4TDaZs^MvdxOP5(-I5Ep33=x!<(C%-={r( zAA6>&r%&wpw6EL+l8zP|)sMn4$9Jpxhel^sBWH~~-W9aCfn5{Rt|O6X>=AZe(h;^-V<5)xCUt zzFtiWVTP~;KTM?D=;Bw5eiM(5igF>1wrf$qg1_$}-(bs{Xs;vDPa2K^!mkY;&W-y) z$+NPy9`+Mo{Sff5mu1UM3^h8J>qE8u{e2<;pj?v?Y{NZ0>4r36FA}hkOm18Yp~g9c z%7-Cq;-66MTH@5>HePSrnt?35&g+wXec}#61k`re*POb^*U4GJYqY2yjlXDg9`%@U z4u^)|p^CZ%mLuQW9Z#E_p1xc(Pv#I5`~@B8IcGasgc@bT4z-1xbqJ3=#AQy2&-G-H z9B$POs&*80agdo`L4Eo zP(=#>#`c*7dZ@tXFXUJV8Xc*8i;qtw+xaF30ea_I-DzQ8n~5a-@FNaVpBxt$Ej_Gh zF>*mSbvrw(Ve0E@pgdC-tK^8HK*~&K!Xs#$t%pzE4^FcBY}W#$FN2D~s_8@4dv4;y z_L0G>pFUm9mGRB{1>=a|DS@hoFT$Ob-Jk=ECbDuI7Am>y4X_2Qsr zQQ*7(p}eAks~YF-bY+xlMi`gyPDM$HgPpxEhsQp1!A;tXXM`Pk!YwWm5gNF_mZ{rn zJsyN3Vitgpy-$~0N=lm`Il$VH*O#X(P2$a`*GqzXx~b=}F(jxSuewdJK-pBQaO_$h z)&o7nbOOksn(7YKgYxonPDMB>k`=p_X($I1sG5&EKPxL=HWj`k7G?UjWVKQ zdPbi=F^NiAPm#_m*@{EFWDd)M#%vB|#NLDvF#!gff!d|X1f3Jx%-*&kqH~xJASp}^ zF0R3yWU-#j0of{Btm*fP1RlGt(6e%kCd**p@X$ub9)vvL*0>v*LGO77^>(Men$cx`l~5csOqMy1L0X}1ph0h|A`Ml0-gnl z%H}_wSQ4oJ`(+XS6EGC)KLJC*{u3}1?7sr*7KdrO2}ih-@&VnnVYQQ@f8bDgkY?A) z19f4;2tJ_BGT{9mCjVRGe_iSSLH(oF=&w~8s>2Lg8|)S&AQcoilOBpuW|GRr^deJA znkCH06&v`kQNxC^2HKQBsb^B2q;kT(j=KayR}zf;FI*7iQ&YfZ)BbL8YKVP}g4+V^ zIT$v$?)}%wK#|Y*a>SovNkI9HC2{8-@ed!PBy`)@P{=d63CcXwu*?mGk}H8Ek~dzI zFPBEKpo5+we1%ZS*n&uRV-T3Esn2b(m9POEe5JDVz+Sgsm=nBCk9;O6hP>R0VB0K1 z5^fG-zw%BSC4NLVv8Cw8scxMEvsXOM8_RV{QHG>Bc*Kk)LcuhB07lkU5&`yo_;CMr zi3{`n_gedfkk%5L;$-IN#v+yodP%uCbrV$+76L^YG*>A&g-{4l$$F0@Wr5Tomqh9E z01v%n8Ax_37mEzu1P#)KOITvi6&NgeWdImK_p^9?ytqv-zD>GU?tP zU2vo$CR8-ao@d;aRG=$=0crwpBykEd{WD1ANx%$9tG2uu0+|f49 zIfsS^mAb8G#d=8rf;_KYaODGh48?VH(aHyOM{WguNlW%R8ASB`@4>rKVs9F}-B+?T zIs-RM?NV`3rK(Ai`hTTXrW24P#q=;nL#$UIgI@_+YdTIY^Mzkt&fTsb!tO<~$NLv}i@3YJ1p z*gGTVW&cP-yy7%-ZblJQ^YD}r{SA=iO}I!le!#FlTbYRU%Wp7rK8Ol_IxpVc+AKMN z39?65KJ4Y>W<|2r2TcbQP`mWos6t@pwx7L!W`r`eVcW=*p8fEeup+I9Xe3aQ*O&oc zmm_;>3^89P7g00FPD?PTE*Gz&3B1PB*?uQzVi{gtEpvcIGl(q=W2M0>C`1}Nf--5R z$MY2Ai&)QC;6KT_yf08z#1=Z+g$!x5eVV|6+Qugu)doo(lN6OZ~Lt}H# zMb^hVCRG3xnjvW^Xr#z7{`Q6?48*2~VTrsJ0=ht|k%?wq_WR0%|FirZdML>@QKB8g z^FzE2US^*yHY1ZBMzI+D8l)&(0+%=*HwsNxm1UR|R#`*Bksx>sVS%o%xQtX-&K#Y- zdL>h4h&j*FBX180-*hfKvwXKR&+pay*=gnuv=2Wc{I@OOTq?MKBY1m9v(O)BXQ479 zck(e)Rp34}8TXfbF^Dfrd9ukAui*0QE3qtOCRpf`hSdSLTfTp93Cof8L4(rHer-kp8$I zf`<7*P{bLQaVcXCupaxQn5vQTLo%JVT0*q@K!-?Wi6p+4)|gj0i7Vh=dxs}@>j?U4 z;o%VqTSY%~-;tR$XNVU6<5*;IBvoG-e6i_NhV$k~@9Vj4wW}7wskYBrWR~j%1l2X4 z(xJ#4md|hwV3@wcaIIK@RR$iBi=_Es3H1A7=PNQ5ssV9Qcj*o%_)Z-iKi=06pgV7enILz3_2s^Y>iu_Fp)E)p=rB1_eJjE|pi@==qQJYY!Fe_RH=odI&6z$iq^o zFKK%r<<@;68)&Y9N;?mO!q;NGBbo87q55VNAa0D_u}&toephZ_WRcsr6yd-XFx+KPPqSO?Z<#K`( zKw|llHY)6Mv!_+A6B03Xt@ke*Z*XF7)xE{Hn`wF0QT%>?Da76`l97}`&kZkY@C6Cr$vAkh&mkWiyRfZVv4ytD zFDjw21@Gj)Kl@PZBEessIrt8Mvd|v!%Nk>FjD*eFZH3m3W;jaUX{+|_rq|`0E&m7l z1XkQl)7pZ<^braKu;iOG)ML1EBq?f0F>#|AH>Y{O>;(^ykXp?O`Z%}8-39JA+bSc% zuLHShgiDv>k&k5kNe!?b2i=-=s2o(P>@TF?oU*rS2~DLG4F#GVV)%M8QbQrn6bkae?kwV?D{zXULh!f zX4ZihIc$^rIHi?RuT{F{7pL^0{1~`jOJO{eb+f?#%+$*2eHoqvmdoYtr!Wc=3yW{| z#lV%bLi)1%ZNgspDory7hlIPI2O@4E{#(V7)2ptdWO;&~C^J_e;3#^pCZif_7NIUi z?M+zj4nH*U+VCc==)O;dXjW@|pJyCRA~Sz`eOdKdadi8UWhbzU5gknLZx*8jcQ357Ib6hNVSS~Iu{v>xGH}8l^Ee+bB?)|)7MoJ3y zu`d7uWXwP@H#c7myj%NIO8!zw>VxfZ{%~R~Mk1$EhIb69ZPL)tfM#q~z~paY%C{<1 z@mrm&du{?jtZ|Ew)*B(l;g^LS&DhY`LW(;0*mD;`zz&w0V;AJ?z1z^|9L zDJ|r&Aj45014Pq=2 zf>SYuvuh4~32!jvXZ_@6iYxehyZ|F#TRMrS9+ej0slRbv!dTsLNqSuLTZa1N0f&*7*_6G=lcEunU&C|RvrRa2FW#Fk$Sr5qLLTTBV0B z7#NUh)Rp@lum-Fpz!ZCCuRC@-ZCT)CXQ$9ha$=GD_}yZZCi_(0+hz7ca?L?gt4a@T zhcQ$fj|;u)S=kuoXh}Ql(ByLvI`@0l`{#YW-mOD$shL3M@LgaSMT|;lzOY+`ushvM zUIGaG;?^;Fa^hfII1J6d1zfk`txLI0{QLx4!>A75o&CI0hSVFAKXulm8`4drEWk7d zReAuK7!Iqds(M7Vr>w4OGTu*4O%0>V!RHT(+^you?R|?@mdpPZb2XHmu|Kh_qK(%E zx%C`n$JuExADsr;injpEmK<77W90dA{ko^4&`GxQ>?}l5rB?DeKlqkR$6fp8kH~|{ z)T`=~7ZlmLJs=8j{|ZhgC(IcNGVq2U5203KWo>QCP0ZT}7)Qz_4802a;vvlzCwfF) zXN*9mMX9W;%u0`b*xK(E_e%zr`VadIltMWE`p%;B&f~hp-_|V<3(>~Ps|-;se6p|1 z^_hhDC3FAEH&9M*4uizcW>nrAW-KNQSQR^Hyfq{YX{m}no^w&~}*lUpc zGO@JO=+S2xx8U&w>r=M#hOMnFeri15SDk9^BBT1Y8LJ7F&93tvp}HfbH=mKOlUq9_ z0GEQ0(givaMIdPWt?8$}TUVvK`|el@0)%?v$qUB{!q7@@X6btz8VdV;{*P^G#`tnn zbLEwE4%)|~UKu#LqZb+y*~Yb<8u+Yk%O&V+paNpeqmY!KExbL;RyH;1qy|mIiohC-P!rL6J zw6qlJX_v3>bmMO1fr-ixYJ00%iyh@NE|CEN5s_M2I=U)NMnk=E;qyE~tP(WUTJ2J> z4Rdl4CYfNw`4cKt#c}7YK`TH8o#OZ;?Z!}0FZ9~nH`gkn4_*W>T%H1!}Iz6B8j?e%`3C?vs|tAad(mT`MOfKk+q8pmN{B3uVdqk z$ejV*amvFWt(Xr)Uj0!shbG73Hv^6;#DCv+$w?(%rcmJAx#B6G%BNtB-mmxP9kXBk z&xQRL)})=Gs&3g*Q>KhKMw}ycMYumVe$EJiP|qYh6OZYTc{BESY3;XVQGj?xvxWx0 zyHr{e)x4;f>UTqS$t<(X#6~NQ7Z}}4SU+!f-{Ty(q0`NZ{xv)M$g#z+6fAEvZ<+?7 zRvgmfY0yitZW#R0z0AsH=D94Y(k#Pk$FSjDHTYYGw<W;uX>lh@L(F|szU7Y2 zMjpv9)Rz#){e;a@ULlxwu@EV^%bwLh{Aj#TOY`Y$kZ5o`jZUvOC{RTaF4NM4rV*f5 zv7=1hnrr_{(2{&Mv;43-POvIJ&L&ky1+SZR?ZdG}awm465hLsI=Pwy5XCqt(JUKPk z15U&?kCPx9Zhp@{n*UJAfKqP8CU(5+IRtNpx@^I|*t`>+7O^5Cf3n(?)_a=NO^*(> z@hrQ@)|D}By@~ZE<9lQ>X^)%OAjx#jW$LkDFt{M|J#&0flhrT1Nrp0cabEzhJyKWh z!R4*-Zqrpn?m@>Km}a7hKxU+wqU&PWcl(^%CY1(K1MYWn_T`}hk6mK98PDpQ8;5-7G0}Wb}HOMFI}LuSDkflz(?-PC8uQz zBS5$HrVc5&W3uD_q{h16-Pxen&5Rx+39jZ;(BfwPxyVG+NftBaCpwdaN49!B6t{+_ zivQ4G65!GX2x@pZazgppIj(-(3B1zi`y#HRDKogW`7od2FX)9pkk zQImitN?FIm`!SdyTv4V)a1DT%ZDWQ11z%uB7EW|dZPtmn9SO*9J#DiVV^sG@@VI@V zc71QA04EI^&>OycfwC#4D6;9-zkA+Qj7#inA(+Y_18brwu>UV*Q&S#fpdCMa?0+AL z&`|@Ki9}F2GF!n`4A0KRTa-RzA{58$)r=TW915Ma!)@FV{llFbK%>dz)+QztNv&(F0x%@DaxY?e5g9U5gZ}PHKJj1 z6qz-1=FRRQUty@4Lz2iZYF*@z6Ib^@ppq^ipofjUqi*PIn|L5LLGbN zku#=W$J8yIi)5ht{YRIccD+6UkNTqHtEx1M2h*+-{OW0{Ydk?S#kHcWG(1ZU%KyK5 z_XMR)w#kKu1p$35sJ?S7Q{Q9!CBAQlQld~%4B{39so|Q>u0x%jIL|MT*6=~d8cHTq z;$?x929M|7cyc5blZSogTVa)n78F3;JrH~Ib?SY&9U$}KGPf{_n0TVHUJjYwl>^2F z9yKe0y-$a|&u?F5q*vqd-_(P{hXHTOw=*n$YJR`wY8X`K?$Wp(t(C%a)-HP8n(AI@1H+xvnMh zM?XWb_u+5VrdF0b9Pd}%10F_u$C{=(1Twv3s!$qC&6K}s;`Tu*%7Jc*?5rdh*wnk8;iO>TcsnyH5wTifIO7A0IlJe!4<-Y+Wk?Jui9m3c75> z#%D5DRs3RGe$HeX$x?OnI*F?A6$*7Y&s-@x%Y&m;q49>Pl_IO%CuqXhb=DcL@7$en zH6s>0TvuO`zP*=aY&BCLB7E~(1Dfs35!4mq8x^`dirw9XX-~=C>YaHD^=g;Y(Pv(0)WZ_*OKh zCb%@1dD!iD*tYTb1}B6yajd|y_ZbHI`Xr+)T_(RqhRtM zt}SS*sBX~s$)7Br>f$}!1`^ceJZoY-)G%!KByFXBcU|wv?ZA|yqEPjHzLkF~Q5l7M z7cUmG_G(Kf?@y+ns7vwu$N$EDcoy^Qz9?Ffh8Oy7t|?EF)q7fH&N~lJ2$ld>hVB04 zp4S@A2rwi5fceccI?kDI%_$4)#3(_9X+w;W2iG0orp>PkH$)|mtB~BdV~)?C zNYY~WgYQHHb+Gb*A2E-OsCO z8~S1xODcmV)93?};@-$>^gr5}?gBlArk{lEo9ub|rw6dSwHLZimr0?d1R63j{9Ba4 zDd@v~ONDLNT&K)v6j&jxvYsKMk7PHNG!K-}HI^|g72_JWw?z8X6ziG4pK(m8vG?^$ zG37J9Tj)RLRTqCFZ0mc_9j7q7-?GL{rt6`Z#igmB-sHD`i$b~YLgyB;U0S{y8CyHM zZ&ug%A^Zjlns>gA&N+pId5&v>Nl{AV#8zx0PH-;yGX$3O(rf*EuSW1EM+ZKOtJ$H`l6vnUD@llIfj^Zx$xr?YYcu}4fjbvm4-5+i;6*C zh91_mwtU6fgZfNc*eQG{aI;*r!qkf6^4n8L{fV~lrJMEikdNkOP3nDdb|w2aN4SQuGz^kA3KKqY6d#ok%c(xtPaCvg~N_Ey_l}#j&V_-3cM3>WOR}76TjHu@~cl* zcDOmuZ^Bwac56wz*5mejK;LVti_aswK-)Z#D0ff@k6r?Km-iiwx$8o2F?{}2O=43^ zPyc)N)#>18s_Wco-Yz`BeG4Y4ajk=2$P02uwnQEe>oYfW61Zz%ESv`a+%%|2o8&OI z=s9&UCwIgM>PpEWiR+WZ^tytZH2cTS-m~-t3xdS3oRR4-|EAup#YgtKZQ>2n{yQEpS48zifY%8-)N zLc}&H+`vv_oj%t9s}#(toBpOz1(M2WF_mEZvtLsi8Aa%t#)b$K%G{|Kg7eY$=Sp_W8ItE}kU}$EJ3d?^Ex3~99N^(oX=2?F zB6BuGs*<7K5Xwo{dORQY#Vnn{XWQ1M_~S<6{bBfTQ`DD<>Ika<6=ug{j`3PcaXP<8 zo+L}=FQD_$CC+i*HQwIU53`SwE#2MwhGiVY7w&mx)iI%FO!cc{405mKQ>1RNYgd-B z==@|!aSE_!P!ODP3d8FUoQJpCe-vvS+;{U%1xJ9(xO0SA>1c=5V@i5@`>b?vlAI|mkNAlSQCW&H z^K>d551z+zPg2$7qf}ICkOxsYDVvebMs+7bpl0~jce04zs?WcvrW5jkW;^IAOZv|Q z=jG0oB+hyMH|husQ%H<%^?*}dP(^I9KjWO@{o3v00HX0ez3;h7xFSAj@`kc2WBXgR z%H6)LM)2+%d*7=qaJ>(un>dRM)5hT^_dDv#_FjlVjb&yqr3BY&$duLZ==s`qe!C~~ zA_1dcpIwn4oxuP4X^yDn6b6Q|pnos!tq9$G97WP84^X5$W~_@Yn~AnkNb|KIJT4>X z&gKXU#y6p>y)#UoMzN|supTEe_Nr8n0;bmUW1rnxW#n5e_D)+$XH~T6Z~bhA1D@e) zch^2CbARe8Kn55U&x>2{HiTrG${b{XA|77Ivv}bEc@cQTbRy+4Bs(wh3hUNK&C@pq zxjxS0^di$H#*O9f!`d&x3O`0?Jtjij(~Tsgg9s{Y`^u+^?tlH*hQpmi!In$90!ypqBl@MN7^RSI(8+^S>k1AiPO&tX7-TyR<#g@_j9ri%d&&n%(qk`raS`(+;M_WY8T?Hi%=FWd>Ep zme_Xy%JHEgCD&kx-RKdQ0$8;j&xKzOkM%N;sX1FeEG3^KQoeTSAF>dsY&i8Z_e7M9ISh9^Io@Ibo+w-v$}PS@Y!sE zBhXe`XksI9qm={K)U4n}l9-OL9%VZhtq}{>oW=RZ!RAqny1G4Iso#2 z>_bPz+sg`lfPq~Q03dtwKez%b(+s{W(n1VPb!q?5@iB8Ll#B{T007i~40W_EVQ73o zm)W)f=Rlh0*ey|^bP+GDXbSB&B1|)5c-U1PZNmrg=^51Y)6)PhE|zZ`LbtxszVW|8 zecwnlCi6XPM<#es^|}XpeBRDeB1u$AfrEUVj8OJO>DkszkYE|PEI}rgTZBvvKFP&$FW^mz)DA18>>(#6q#Gr*(eQdUU(+9wz=s|u>mwR z%E=7J(r&!)4h)o+KwSNYHaT8bRM0?b*)tcTC z{SQc_(zHKHN}F|RV1VYu#OB(XZj-%?BqxK8j>`>*SX@Y}W2)NZ&56)2asvsUcaqH% zlu{?Y0C+!K;id43r1260ctu`FzFuh&*Jqk?wX~KG4G;h@O|fcGDr!+)xn!!T|4skj zgQ=FxR+qLTwFb{&ldi77b=f<2`Z1V1*vpsLEy%s6!NJ)$94;Zqtf8S{#s`@Iv@XiY zX}!ap)YRB$LA@aig~4p!nloU@+i9slVt4K=%O|PPZ1Xv(tdYqEn8uk@@YcqL0hRWn z!|bJG`;eqTE%ova)hzD%ZjIc#0P&4=H!GKn?=K-8)BH+6ijb#0D)jrZQ$m zdsBKwh?hZnK-zgEx8yejlIGFTkp=Byaa>4RT3VJr3KQg88_48wqlf>RgJaAn6!EwH z74auwzTS1=d!6@>1~AWe5-AK%Bw8o)AI#2LWhKP;Q#W%!vq%N7uES?@s$LF_&+C)? zR8ytA-EZ8y`oKq#_vvc)-_6a$^78UZ3|=f-tn6&r)ynAv)c7n&LH1oKD(AtycS)a4 zz&3eyX6>45W<0K3BGsv!5S}e%u!QNU=ow=28j_;>d22!S{WrEof037bcZ0F z(y`Ia;PJip?|0t0zuWhm`^P=^o*Vv3Q}rGNGX($uxTmfL)4tWOZaIqV&aLDq#~T6w z}~aG_Kc=oj8PZ;>>SgJ9U9^!bPF%DEf4_D>ce1^+4oE{!CviEtN=mx8Xp9 zzD+`8*Gq3R*KSIa)ro3=&T`Hg`26NLZIhHTtH|($RVB7h<~B4b(#8U9yR(?GmL1Qvu$bgLG9&u{lcf#L7ikKbjQl$v$h$$ z)Q%aRxM;mmLVvrc-RwS=0^G5v|lH_K<4QFEDXK zaKTT=IF0LYjBh=Cm?mYHP_cbJLY&U5#U@Stb^zauDcpeZ*|D!9}4u^HzfaHg;G)v;I+HJ#FN-{z z%}!hlwgaqi3gzSY7>+>X_BH)1d$DIA1#UM8uUfKr>o&W02j0cSjMpiUoT@s^HPhO# zo8An)MHPA8s9^9^lg&=Wm(qWBys~aY^|1FPn;;Ir0Jr0KVZO0ggcuq5-@1Em@_ok) zKw5h1`T?C%x#Cg2Lbf#I7IsVnAAWQE_|!5$s%m9#6@r1kuq76hVTm6o;quzD5(YBB z?Z+BUra>s)l}wdlmE<$U%`No@;1rLAE6rS~SMnrZeulAjAoH$2`U@o@*+BXy$*g=1 zuXa!=A=yTV&a&CNlz5u*2B2Z}SmYh+p2VDZT9&$wT`LMtwa1Mz_?@jLmQRsV>hZ73 zGIxmXy!&|pR-u}*CWXHIQa5OT!ZAsAXCO3-&b`^`?cI=1A*p=I&V4)ZdD$NB2oJ zWlRBgpD*}7GAoZfhWCEIG-4DVPY-@pH&G38Q51SD)}$5wbIhLQN!QdB@i1~PdQh7| zgVxn~CZt8t;g?XWaWhqv^Coyc)>yJC`l`jYNoF92Cm`ZIJbSD>%bd9PP%!5G(@0XV zRZaClGSP^X6rM|)t~gvxDIKSDU?OGxEgUfnJEjRSmNT2O-(mx3<;m<9$quW@2>H{& z19%iE9G^@0I=T|=%i6FdXLLg;Sp7lxv})fnS+eW=ZiUSipeskQE{ ztSM~*Vvw*>EYU9mZ>&qeeUs+%Eh%+j*{9z-iZ~WDHtEIYhcj5HZ7Q7!S%hpiRq~T; zSDt!LVBc{!bnyom;06+e+xw@IqK(L1iOuW@MRJ}9Nq$r=P%A+_;Y_v2cA>^Z9_>l0 z%(AfTvhtVhI-$|CFUb0 zd4b%Pd3ng=aoK6Yna`L=VsPnlk}z|gdDUV!mgUZv=V47h97P0u~}#fTqm>%vt2=lS{N z1%hu0yfJERwA6-`Wc1xcMzT|Bxx=Jj+`;+;rwdQX+eyFw{ zjAl&dTXG--d@DRfgz9r;bvh^R^V^Po4FkOi-!rnh5cK>s^e)(JJ*%~Btafy#%RC<# z<+$qou&;rnMwx=nOrER5(!|)g#x&Ok%j2Y{`Is``geBeyQu{c3!%uUZLOqf7z}+f4 zh{{N~=LB-azW4cD>5zq38?W$<9YhHqYdpxlz z&+Hw_4xBaX(Y)MBj&b%0jnzHQ!fk6%ZwZj;z@T!}`3Zl;H}6UA*I$~ z-cAWiO+tYUfO-*K{?}-;V=S`IH$RYA5Pam@@@>f&@#n*0#^Zim+Vt?Rdi^Ysc(`+P z*u#Ro^TKcbZ0Q2FnER#=Bwq7jpk|h2#tQ&^=toZ)}N*B160B#Jo-|9VYaS&-A(>`JAW`yzT~%ynW&Bm_JvA0dD@G zjKMhe5n)G8ukCA!s^tGVVDI)TzHs=QD|IOIa6G4f%@E>1FVe|H9PioY&fq-NXL= zA8m3l8jr7ZJ|eR_J3Fh;OtA_3Djd<`r?2Vhf$3qeD&+4fB=+j!;=;s7IJaM@g_N2N z5wC7Yg{ zOx7HY|HdCHwnShV=`)UC?8_lvpC*m|0H6U7`~zm{An1zAih$}`(i%o)-J8&?l?Fh_ zaSP%g0NE`FIR3?j{?`urx61#M`uECO#0LHXu(3H^<)D+QX#*Efw)?96^?P^CoCTg3C7bG=qir`&xJ5eXlXC7bVEqFQv!MRe@wPuZeg%3&aKSqO9_lCv&7~5H zwh*MJ;6}^PB~rh3&_Hg-gl(jh-;n`>&tJ6B5;9KXc6Xb_##uL0q+Q%{#{4p0aY!p` zdGJp?6$? zb|F%H0R#f!1O5Oe#>bli4pw^BBg@HaVjsj(iV|BSuSoI3=+UM^xb@)ZXB=3Y>r+OH zuiCv;+W80*L&Fy@+tGS@dJD7j^VegH60{MqGR+wd#%*6djN0D4@4vt6bovb6U3BR? z@zSGyPDqR1-^W~DOg&b1{i-9tjJM{KL0egoJ9PM&5#!C*qG+%27#THiq^f&YJ*y&oTl3jM;u$UX|J;8WLM~nA& z3|e)oB^4{o>4(ero5fzj&Ju7*hAqHAA4G+&WH+Zi5y6ovxj}*_OTsIQKkE{mzT(YA zyH$X>JFU^Mcx_xBI$k@pf27qk^0T(!DB9nynDk`%*(p)Xj~7_2=%*_;(X!R17m{!T z`Sa|pFogsaA8x{+VN<~2Mbe*cK>zl|nm6G-G1M0JzkSPGca|B60)O{iDq3A#Wdg!h zI+tYDEh95g^+vdd_%j8FPi8a!1)*aVQsH*!Kzi|NiQG=52N>~?larICM&Dz533~h* zMp{=_m+ctv-R|N=`xN6SWo&c`)z)<;qhCA zfLIZL2DsiOh`tc}yiU-~|7<1Kz(BfbBXC#jlsq+sVU(r%3O|@M7#>JN>rRx5^RxJN zvokVD_~L#a49R}HJ?{W@WldNK)bzuD08mQ<1PTBE00;mKPiIahj=w~QRR92B zTmS$F0000~Wo&FNaBgRmym>g4-`78WBbn!!a8Srth7{o_GL zp>Cg!lyp7W&0?ec-PwB}2mBwI$|N(!<);Uc2&~Hw(pROfUVaEB^dr3dKuULo?(zdd z09WAh1Jab#^zwrMRY0o0ZwI2|-%8O^QU4ZV_5c615ar2j|41-%)_H9_^Pa=Pi?%Sj zBoVumkvyGrrR{BqBf}AAGdZtKU$=Sq&Aq( zcvjcSaBmd{T%e)*j5F!Sn^v{>wXeHcXS{yTtX zsLb+dDtLT05*B}Oq%T=a`1QQpl>18l@p{dM=ba0yUj_M*6324k^upUf`Y0P%2Lx|# zin!ilibsLO$*N$ge1t)rJNoQk<^XuZb%v}2V3{&Oj=9$svIW zL7k6a5smF8P`09LWj}Y9a|@3jTiK2lHOl_ax_N8Ub$b3dBqJZ~>d}JPTD5oii@};y z_1&0|ulC6t^ToGflXiEFyGg><3vBLfz!`B?m{AEEf=!14NER)4zU$W@pCkK4-mKTE=AqGBYP7i<< zYQeDiTlyGXCO_YN`qedFw>6aNX(Hb$U@-VcJZYvbiRVqh7nQC*;*v00-Zw$)6% z*Po7I(_FR8P-4-gG-<*9JGSHBo@Oa659cOYjpU*GflS%|Z1J~pF5;)2UEN=ebMOFyI-#hf39>6Ke$>Xus_0U?p9m;O?`wfj?fWwo?_pUW<@j64|}z*_Gqf%eX7Rk;_Sd9zEqLFPF>u6 zcM~|KG?|_v9C9EUl)O&%_qaTqxjOx@3DhfIK7(UGwdGQ99kxedo2q>UHS41AlE%JN zu#3dlILYK{=95n-zE;cE6$Vjsy_gGr76Uizc-O<3#6`7O0;}d@6mf3@8Syk>Tgq8Y z*H+b^ZYvh<7fOeahb)ef<%7kJ|7mG4US?T^fBSKR_u1tfGT8M=@0qlPZK?M0HJrW% z*yMZnxiud69i<1_n42fh%|dB4E(YujJ1P;Z@A_N@*fBT`c-K5v%Pp*{gb3J*=9j^c zQM)^+DA6^RCgtyW1%m$gUD~E=!meR0eRVijOS#T{ZyVU91sevc;IMM*U(2Qa5<6TT zS;@{xp)`w`#1LfP?BW6=*GBD5g!9Jqn#O*F_`dd~V3%$cecPz%3bR=uKpfHS4z@br z$Mz3k=VWE8ka|?{a!Nf@fvONl^XbyLFT?Qb;E;YW4zqivghMu39y$>66SDn@;$Kc?OxLj(fH%Yi#_TI{Pd2S^5@f!Sa z-ya{vJy4M)S}2<_=}5x=k!E+H=fhn3YPs!%W~M^?rP;_}v*FfNIV>J?dhqI@b^&|^ zb6?70C3$|BPR*-3udxpzX&qKm>vEZ)1YW(bV61DrI6UyrW!8B+4r1r;f0Xz6H|}*! zev6RxNDnM+!KJj{ymop;B)SX$5Uba@JHa;9zm!b^o8=VyE>E?2+^{#-`yTg{jLVIb`t!Ovj)H#=Xi0@&EB zJ7Eu=FZORfEZ6gYyHkd;n^{j^jpuuIiQVg$MtA|>wOe*7R;Ou^`{w%MAR0o1a^t{$yS3 z|Ll-Pw%QHmzcwIu{GT1lwHnR=vAzAb+w02z3KGwyp`NFGyRf7khO+T+s1$dkbEus7GAA6x$)pUZuk6%qM* ze^|@#Qs;leg<(C5ME->U&=!t>|Kt11Bl#=;(f074YL_ljRADTs`_2xm8g&eE)Nqx9 zMPZ3nv9XNpWTh(5dWViOXK!Wgkk<0V*>Y#$dBFqhY)ABL34ly&>Hl%pDha<~&y%%^ zoM$yCt&Z4o>opP;Kw)MF3Y=E_x*vq*6)<~8p=@_j5j3GRi8<=gT?yr057p}28%@rR zyAGK-gkO+`=~b{FLXc_5r8NyepqE+xWG^fcG3%mq+L)f=zOMO*$B^kQIk)DOUtRHy zlQ|lVqfETDMe&qIMsH+e+0|;C)h1ACC;Mt2@2KT!HZBtbuEPpc&EP+wbenr**&H}q zqMTTIf_h&iU9T&g{g^J>)6FA@H=YNrjLa$Pb!8K?=(|=}a?nDd{9<#q(V+Ex0135{ zDUBMB9{XPbD3tI-WHkSyV++~f?;yoG_u|)B&>$f&KEj*l)8PVx<(9D}dT_R+xOa@< zz8ql`g9vqd{50F8Zp6cMX~ey(Pb%`~6h9iQ(QYJa=Vv7+@jQe3}GyUr1Tr!Gof z==hw@G1rAgJ*)B4AoH+WDY9S43F$fNi85{{zIbEV=hss3%wMIMkKiuu9SAW3yU;+n zd%2Kxf{@G0%@?Vo6Y0G{ANH;m#opx^Dtg7{VDmXhT-SDo+MCq6j^?ZVjg?W8%=5F%r^-ZrGJw^=sPe_=_XBh@ zNoJ%(jCmg+Cc%li=(-KTyE?LN{V}7to^ec)iG`94s^-nPKCz9VCn8e-djV2qpnqn0 z#4GDnT;=u-D}YK;zIy<;4c zUvW>~gwY8;^1n*7&E@e|z`J*ZwyaY4-QhS!;NJa7Dv0 z&*?ehxs&X&uW#tHCgMxja1_3K(BMHfTI=TU2X|z$-o|ZjSZlb#&aiOOx=@}YbrpM- zC$3b3p2mQ4Z|Qd|MQUrf&_^6prM3L94Br7&>fYDdL%$`FSjgo5BSD;M;e8qUvdqkbL#lqihpd zvs$e3^y?Wo%yIRngQ-_mWvQhCEyqeSBVQ+&MGaKi|6sc^n#x}vm6x3-j4gg*W4UeG zfC1rBz~*|b?a*RB=l6Ha*>Q7xwWww#;_1%XV0NzV|-a6br(|hF5AFC%;ByC64zfl30lmW4l{(*K;qP z#$*0QN5^ZKK+B(PI7mJ)`-dk=%Kv%%*q>H!EJ#Hi4h6S^wTi)KF4!lXYZToV=ZTw` zo$;;vF(A!=T)=S0<_7@mx^V(8fha@kkt?}9#G-PdXO3u}iya2Yw+V*!jylVqe(cF8 zpVNZ|lKoh$>|53eB>OJ_-HCk7(YaA>REp%~vhV8`Z)hJe-D|F6Q@&Ev8yL1wy9-Zt0=$(X7+ z1NadSi+^%(eln;kE6?$XH0({2fWuc3Z$AE90dw;`hf$O-K2(-&VFt zHe6<_fjm9tZ0tE^u^(aL@K&c^WMSryo6(yrCBV5 z49^eR`*(5uC68J-FrZGDVMZnJ5+u1Y`PA+X$V%W*-qtHiHoYr0hCEr>j3c`vV&CTcgk1lq`_c zG)-k}pZw(5YU0Uyok%zDQ^>a#i0bQT=5=e8v&*_5`i||kJVILHqzA_Xq+8W|9@p+n zo)c5Y)g`Qqw|gwvn!N<4rgM+b$1DDbwYmdOawrNW6;Uq}_~MWE2#%k79%U+HvY5*1 znSWMHXpm+K+3mXzf3ijkpJClB#uh|W<1g(k` zVL_|RAX{W$=?&V*Vy3vU+ue!@S5A3qJubw&8V#&YK*RS~={+A` z&-GVhfAw(qp2LD`IgO_2^>$wjsiz}PmGG=4G)taK-FmdXI(c)-yJjf=qmTzm851gb z2zJ%pEOmX#J$EQ8vdlC@8IvqlCQ21$qf`EJYCQLoSykOzDmv_^nW4Miu^OELJMj`| zPIftl+{}AzYg`gR;e-c$KL;L(yr%Q8-=HpI;$^J!8rUp98*6#$T!U)owdM3rW@DQ_ zl_Wa<<`A#WRnGZo&?XuzQ}ii4INp57AI0zNH>6`BFEaW4*Gs4aKErA0jl0=MZbsk1 zLY$Y?{YA!Lbs$}qg!wN|HzFP6Zy5sqC~hh)xq})0x~;&Wv^UD41Rrg%Y4Q8cc{ZwK zMb8h@e)B@JG_bXl^2Vk?cyVhUULnPz?psSw%)i@}d6uHzv>!8B%1e^!&2_e{r6W@5 zwWrba)AZx5#)zfP*B(?*2F!Vbv8<_G=E4VCX%r_=N7qRym_29x#dT3O*-0J;<{fRz z!@1?GxvwGvQ}30=bGuC4sJl2n*D4xS{gT%vN3>!$R8z4#A1i?Y-2#3@>SR44$MFd< z$L}-)FY5SVcB#P^!sw299vsclk!Mi{nPazn24cvG~J>EF*(2A1w|4@ zi$1lNz$)&@V3k{GGD|n2xv1{?bE5l&)e1=x;xAS|Fi<})n)!zALjwnRoEj~`rupralVZ*h5m;2Ku44y^%2l4n$#jaiqTo&3QRM?C*VY}Mw; z433_n%3)hXywZKu@v=@12vG++U|j9K?vGK2xkstcV9QXp4quiesE@tk>Od`HC8ar0 zG+wqPl~ld?z#2jRHr;J&e?lr&nKIdBIvOBE(i==<5{x5zu3w(_|XfqE^@lgBlqzK0RuC;zEAfg#uclv=|%|VViYrUN;B%cyaXa& z*6SQEbMvdr8@Sy#JV#=wK$dR-F>dN}$NJzmgKulwD$xya&HNYp>JQDX3^k=XQd|aRR?PbK!b2xy&bbi#ZFBcR3Skv zr`eli+vudqJseqb9_F$jcAv!%%N^mspKW8vtl8Md{Oq)t+<3ta1>Xi{!cD)S=ttVj^u}v!nb7*wO8lvT zXS8z1mLe6mg3o!W&Y{ zOA?yJ0yS*fLAqjmQ~ZR-PJnD_#;|%rBHQR;DrcHmw_iNtemUNNO19b$!%odt7)U}u zK9TQ7Iab>lIi7r4qCoQPuJaNx(qGH6Ol{fD7Z)#o!E$!CaU>ajog3xVd2FTaLoWRe zJDJ(*`f$!)3W$_h=;Vs;ExJ2lq*!hiX99V6>B3H)M`q|AL4T7w(M&m-@$1!!Nw?Xm zSOTm5Qa=d$c6@AYIg5-~yGp7Eg95eB$;aKzW&_C0H20Q`N2iVjc6aB+fh77Z#VNaS zr(bS29|1kq#kz~sMw}_Vqy(-U=`-puJtQ%7yBXASxc(wDgc9~MPQ z)EvE{H-|-SA6+I{%I!8N82txbmU&1IYJ0_fQ@P2dOvdPEwSVqZcre} zbz<8l>=L=Oh$Wsei$pNdt2*xvG+rp5Bt>(rj9{|_=Iim-$LpVoZb@rywy6Fp z7@Y4^%T@zeHXsv82yrTmq(zfr1^li%@Vhm4(2!VA!*^JA7RsFwN_B>Z%V<4nl|?%? zQhM{L8nf}}RvnFjTrimyv(GgfK`dWd_%x0({$wMupmvZTjg*R?>67{9qNHNEH6X~? zKFke(*ZQ(*RF^sKj}4apQeYH4G-Wy5E6hAu-@z<4z1Zh?92IeY5I{&0Y!S|$Br2Pm zV0lNMe4gg}<8iOU3#vU$~=mN<6ZGywYqL!*)V z{#cp_2C4ao>Gsf5e_jrhd&lZH)mwW0dQQM=cZana@4s%>G`ME}cBs&B)52r+jdyzR zXm`U$J7T30DR-+$?IdwMF2iYHC{fr@MLas>LhBPnjU2wXch3(IKZ+=n_wSfI`k`p@ zr)5?;E}Y@)s`p?6~owGiu97dv#4b;kLbKQE_8sYqL@C;40YjRyWFsZ6_LavZ48%qJfao5kIlhT2bC zi^i&jM+c4d0-%*nG^Q;C`?*X*&Tt^fStd3rz%YJ4=N^IjH9!4@rL6)+mm`G{Z zhB-R^Eht-m5oe^n`ZvAna!S8ju`@pza9S=`!XP#}1oa&v$9{!V|sRvJU zkmVuB+eRB+sznRA7OA|v+Orf$;?Al!QfI>2C~S$c12nY`B zweVKRy`w&Qk`Z?{HscsOR42xAb-V3+{q(3GcxoklPNinFzdC!jCRxl2Q_f)|@lOYv zzXmW`Dei`MqB~o0W+E zI$%sgxiosp_*Q=v&?G)lOm5d-c;Zt^Uz`sT@VjC_zu|+d&iy~{q_Z*z7{xMt&J>S-ruwDaN0!uHc#{fXBIRJj6BsLwUYo!n`U%ZH@xMBV&Qd%( zmJed)i|0X$Yzpo>nGb!NeH+sH&Wl{`i%DdBTjT*I)D#4gcnsRkC$^xbj{rI{Z?8yk zjB#Af9>n92i|0NG7c%dqy*M#M7y884AGLA3p*-4sik|hagM44Xxy@9kM$>BgzU!5! z`-Xg1BH;%9q5MUsrVMIxz z<|9l%mC|G3@)O(!MY`2b_QQj5lVFHOa1qRP@RM{$RY*LjzD#Uwx3#}f^ zD1N+y9qFv|yx2zPmC*7RnZcMFQnQ`%Y{9H2Ck>9->Zm-B;Re`%?fue3K&igYJ^sK7j`c!GkN#_X^WwuL2>%)^32uwHIO{U)s#@4Hq(h zN+*GkqTB}hy0zL?KfZH7X|Ldzem(a$5!UJ!s&4*h5y;X6R}WRUt>Q=^$hR$g2Lqy% zKqWv(CC!33`a5yX>$`XmG^jsTGMFT+cC-zsLO>7|kSTT`9bRX2VkCbsLmoiJZ&qNm zPulR2wD)?ih!+F}yaSG3B4`#W!j+0XB z#N8$WU=Cly=NeaiSz$*yF?rIXnZJz*L8q8f|NTzTISr)Z3G`y z6-_{n5t#v`AL*UdY1?|al!YqRa=cXVE>!oh6NqBb2n!2Jex7qzmQ5W zY*6k`nwSuB9po5J(_NsCm)CLjP*o|A9--IzPSN_80tf(5Qc!aXK+g^N8&T8GnkX`}$WzE4kk>y4Lp6M*^L zg6449XZ|N%PIyPzJwPcE%$j%jT=8;4yA$#m1Xn zWp`8KG39vcyCB~WfUb(``?h=xyZpkt+20WjMt9gKvAAR zy1}2JREg84%@!VQ`_G6WvN82Ix@mw0GvY5en4W}|7oz{X4ly};w8?^IT z0itW^V$)G8J^pl8_2<_oKl5}-g&Y?zsWset|1kK#kZw;k7x%s20`#}U2@m(Yl!=1?tT z=et>wH#Ch_K}cKt)GN0d9xAi^X{e7XX=ci|zZsPYheBE=VA33&X% z?l~+h<(2j+2yIBOYtO0bl^f-Xtd-{LARchW#9yy$=bzp&cTgWbDsJa}sD*7r( zLW*k>h|Piy9J*NcCu$AeXJy`J?x|7&t9HV&HO_0~;RC$gCiqyza-?G49*`IV6{9xe@yZ(BZV1`BN9wrpS zT_V-?7LUSlP@cn5toQgqrt{jk)z7ctaBmjMc7mNL-<%5P!C%9Rn1aeC7}XrJlFd^^ z-QkCJBAVTet~rkyjTagD_ajzqaznA{oyYd$h#5t{nY2fQxTXD=a?f>~u)Pe4m0!y4 zTQacQu+o@n^Ambt)tYvar%J^M+l<~Kvl<0{m(`MP`?T0R1KBldMW`1KL{*!ckImFF z*n&lUE!75h__QQm|Fa5B6 zgd9ZgB=f_KX^)K?E#H+_JEr7g+0p$z=cUKH=yct3E6dsMZ``*#IVil;eQj)~FH;S< z=l3g!0M=sGW=ul8aHCuS-%oK|8Va(^US)jMORRevGm@%Ul0Vbll-Ydv|2T_WUPt9h zK@INhC~Gn2)gK@2>OW|IHo_QfCXvjWs&P4ah5(;H9)dEifaI2;vg9AO(Qsjq{wRDK zzk@;S>n}}nZRT)n0_sDaL8eOt0^o-Tc))CW|9B}K-dQc=`Qw!PI*ek@Lz3rPB$^f( zpmxZ#oq&<%rqtzNMpNyRh!a3ixznDbY{tG=7uF>V)1f0^K9Io#gEPKU)Yk7HW~+5T zjW9Zmas@?Q)<50-eZ>-H(Y`}4c0c$`ERf>0ufvSdX;!DzcW?1pvd{Su-G;TB$w$q* z?o|IXj7Y#nuXCqga)T<0K2m)DeYGR{i%zNe5utJ9EIt^;typ=7yikL z+@&@22)5kg;T({P=Lu}1w)(_24skiJp_0+-H5(&0vpzLNH-I77|Lj0#s=d=1DS1B1 zo%U+XDlJ9aW4W8ZVVAB2|FY{u9567s&nj2xHtG&i;O-78mBWRe59zQgZq%O?z+G^N zUx0F6F15KpW>n<7rpxGax&DS*Q!^S(ZIGM5J=#A zmZOoY>4yEbeQ6+F`1yC}vWbyYJ`Zk!Dc24M$@&3}X%Rh^(f)Qf|4Ivm^1Q1ih?%o& z)n;ICda#Ch&->qOh);QRYjA{tBy~*4nyG#h&UA6#^nU$k6g8jz5*wmc;^Nd{Z)xD+ z&SL)oopj*Z1R%oMPYXeoMF@wU(UzpsPP;8K<{Q+Fb0a3Z5_of)iNzjk+~XD(9VsyD zTq_f(@Y04O7YG?gJQ!GOtj$C>f0o2oiJ3K4j*hn&>vIR zgY~4zqR(2$5gQqY?gZZ9YA0)e?F!)xBAQ!&KCgJHa0Zev7d%zECj;L=)6K(2#43k< z;#%&1@WAr+uhrXxZ_{E{X;wR03WKy}J6@(bfwHBrTeh79*;6A=dmxoc*=c!b0GM>B z%E2PpW!jDYzH5=yaL!+sXez(}ip$Kpse3;Nw&!|{h6n;m@`kn8F}usaEpvRE7Z)AP%%;%=<&+%0on^jYpRh4&!dAZ!?o^ zu0ja;jZ>Z96?Rd@A}8YGs8|qLhV9oJ!a}LI7hDGQ)cnH$45I(M<5#-&1P@dY>%EoU z41^fa?V=lVe@aa#%hfU!vW=Pp8%Dnl7MsX|Y}1)a#WaRZ=TSNnYb!=4U@G^eK~7Xr zH)?Bt!fs{gsqzz^MNm$O5O-Ee-~~dyw1)z7R!oF%RB|-)$NM$yOs_INNfNqQGE7`W zB(QJZ;H;Nv|2u$&-P^NTULmUZc_Su_;|wA%cLDc%ZO%_);~{@0jSU4?R|pi$`LU4R z1Tv_CH0zCe(%QDK4JeL}rqw)0M~A82iwM!>Z_=?pFtDz|?L*!i)A-j+M@cruO0xi1 z!2PfD(>{U)@BCOG#Ggmz`ia;N5!3<|*{c&l=?{a5bM&i9By*qRlbf#gdW!=lqbP(Y zj?Rc>9p<=R2v)kk)j}cqD`Ef(LNEuK>XYC+gpe&$arRSmgl|SCJU(_!OUW8kWMAj* z7}bM$5Vw%cN@pVu^J?jq>MWwUZ!fco141;6o9mZeO3>F=nL-?h9Orua_3Ytf+y6TAJHa&M4wRZ;dTX$X@)Eg>OicYz98TVdAE+TuU8egIYJkoes3 zEn3V`+0K|7KKMebLu6v?D5sT?<%x>IkvyHbeg(z}tJkZ=?d;C#yCBmHo(bVoni2xa zMsk1CR|_l`S+}%C4R)N&+=3%x-N6j%H0FM&Byltk3`wDU|2A2Pw0ylk;fWE7=kJ7F z!yed{Z3~+=C*50DAnBomux^PN-XHZ&P(a`GFFk*i8ux?swbI`S8wivA)iJAI1dQVT{oY@y|aK@?^;migGmWPAR!ahoRUGL&vs79khL~rB{It5d+L82 zsl>QOn!*oed?W`%O25t5$UXw70durMP?$Ct(fw-h2b=aKqN|eq>O;u#dqgCo&yQ1H3}AsdBv zWFe$b@188EmjEWY?+t4Sznc9nEg236wq3)S^Wcf)Ja>n7X`2ABdrW$jBqsDF1cCLv zKJP}WNu>B!@J|!iWF%Z<`rFaY;>na>r&d%k;FZi6kjkxi!Ge)SQixO)0BcDpU~p4j z2UAvKC7Ey<{@om8J)CoDC)ceNWz;PLa$X=4omL3Et(*Y#s^Z6#(+%p}Lx$-iC62#& zAO6N^_$US=H0$s$X85`SBrOgqZq3JUX5gp@E{FHd$C;%b!G86RcWldyTk+SX>n2i*+XIOh zcAE(JUkrUyO_K1c?q4@7X5JZ)a0LERy;{;;iwPlolzJ-LutC5|Kk2J<2a#);qY%%v zJYJp){58KXSuEH4?ARToZu0gbrIh<_4Y@pBaW`W}4UDDQ(OIb}+U3yE-an)+E2HZ%yR2rniuD1b)gA>gT464u4hQeL_p2+!y?sd zLBlnUS5FgeP9PTFRRK}`1du*0P(JJqYZ>0~dw1KUZRw}72~X`^P$Q_9 znm=iX^#H=AcpqCPC-?JfT70s9^hX2-$}V$>Di)u6vc1szkz&rTB(>eU-c)Xcp#0nU zc~>HTVQwH%tS%~!ns-|VLeAgcjS_PFMk7a~rEec_zE|kuMs@devw072BliHm5=1&6 z6gn?kIUj?%NBIghwLVPpIpX=AiQ3z#wprix@Ui;^3Mz7k6BBM>K&|c*(F@4|CHBTn zfy-@maThLubg{=}w|Z^NpG#R#=0CuMNagoCR~m6V-ZZ32GGg0Zhzd`AQSF*90GX>l%CwhPg(%Mwk)l%t3P5N=x5EcWotV&9_=C^ zxJ4|wgh=JB^u(rP_S#it4e87UX$=j~OasKY=T#^QW%D;EzwPkYIu(MXBfPk*xe?uQ zTX-1+C$Ek}I8rvbUUl8fTKb!4xR2ktIihEG1M`bI+{Q2JxU~6GfuKg$y!H;aX5M>A zlSn{GSE?3M6m1xe4(B3EiTLRO{nU0cTH~~lk>>(VUNrOe?9XSt;B2oyJDZ^=ES1%@KFY*BG70Lf-)b z%8oi-S2oZz5PIi~Tp+Cz;G9`&R`q$=HX{h2n?4w5ws^gkR5!Y_Fw z@EfKqu~|Ae!{;sCf!QL{uIcObC+jVhO39*<$*jih@5epX0P=FI{~aj_`(@NGdExnG zu{G}I(-LvIR%a9K3ktESp{92NEK4D=8;H4a>%w8Uh$?*jNE8Q>E4q>OOMeau=Nij{Jtg(zo;og->^k&s0{0VsCZ2L>V<4y}`n9 zk1qxDvq5e!z<>tHb8kZkiSe>%^ZtEIbc<3tt+;!c)|(_@Yxe1HH0G&q)l2H5Rz~s_ zYmX`rtULBI_a+jGr<9BpW6rSYj?7rPR|*?aTrXZm!UOL~K1;*J2wtHU`O z-5YO}VP>GHTk&#AU-0AFf-Z zxV7bOmKeG?H%c$e)i*RW#e^O7jVPK-R@ztL^FIdIPEI7YCOYej<#}gvo6+<=*bg+w zZwFQvFDrisrta@R(BM!4Z=+RM7!3}fn68^rfWp=xtBcsQY;zmy^M3hx#TZiB?6uSz zNo!&R*j|j5TPI$8`(kFK0@MYfbBn|EZ>^hyu|$K^BZFoFvBBYp?(%vXkQ(>LmN-?S z>;Vy<&)EoYk|-Cn!hkGSr#&)P3Sne&L*=)i5)t{IT>pf)&xMQB;%f`a=@r|_db2CO ztZ*Lfyg4E*7^aZG^WpAPs}g0g2FZw3W82z9g|g6UkLg^`Ih`Axz&5>skkybJpou@R zY4p<`65ngFNY6$}wSAF!N8YPnqFBD_6MBYSdUglIu34&pspnkZA>SGW+`Ux%+ARNK zIXCS$$6#Ai00BiW`++U_Jpch`Co>oOTpsXyOtq4eCmF;Z6n0rJMoktbNhD8aC0S2b zDI)<};UrUEWz-%WRbuIsH}E4A+iOu`DBk=tKEuRFn4jmX)TdF!pxA{mJ7lv-vw6M@v(-D9Bh~XYYwcaYu*o^1TAsY|CtQgh zsB&2Ru_}xSz3u-mWqdOsP@w0}LdvaUi&HGSa#Qu5j4Y7_mFXyT68r|&uipW-8|aA& zyFZmf03xK|mtDlR)B)kv_u3miUX;8*Q$di&DBX<%z}t|IKSkNs0m3eq15yC1&}fBE zfOrD0-bkv(-F;#K8)2DW1<&>xF3$MdQ)u>AR)1zG8~+WkWtKOOj44u7h%yS-h6#hR z#8Ha{ppr^`l?FYPe=5?*puxmCx1zQ8G7fidM2VbC5D$Xz{jvLQRIH;T#Fhd*UFY%V zo4T0Ob&XuUsbgXpqIt9{tN|qF>W%sna@j@@7*Er~tgYHK zL{u@LKl7i%R{lK4rOW}9D!UTSn2T62<1HhOAnD|Ag*z`NE3K+Ti= zH81KhJhQ0VHlw%1H@{N`w`L2AmRaF%zX3S3~Yj0P$sEP zGCyohDuIm5pZT?iGsp&$iHz)3>4|`P|2zLRr#KQQZRxE*$6bK0URU1s1A3LOn*QiU zH5*&t@$MD|1RVyjMebril*vB|I^e{wg}ke6@>%a?l?=$5%Gch!eJ{E|3m=6T-u;8i z3?T>b%pwU*k}Vf|KFm?6l;zP4G?PevT4D-&KT$8f6kBW=3m-|pP2kOR+kpk77>|qx zD7(s*_Cll3K-|8Ti{()g=QCZ=(^s&J%A=Z?i0cm+Os_ST2){*w@^=>$mZr6Zf5UBc zjXdxms6iUA>&p=`vZj>9CIZtvfPn{v?Bqq8zc|E$zV}mcKk^}jK9h|j(m~B{HS{f7 z3;DZxcTjQfc%_g76^|e)x8rAgPJ1o3~;qzhauT<$M2_#O%wdT2Oa|k2xzoAcR=Rml4f` z*Y5t1MZSj5Z{QaJU)JquQt>k#``~lppB*0o(+k1IV4+yfzhMpvDXY<<&+to3sTla{ zd8K`W!DMXkk#Z_VNzwB+Ltg@bO)|0r2-f7J;5+PqbCVZhGEEUpS7I973+^9GI=C-q zXW`zCDqZN!9LWck0k*V}55_<^vKFU!j}{q)7+gh4jo!%|E48rx?u#LTHUHq^Tml|f zoPPz0E5q7RWNCfy z&O+}~5DMiEi%O{&`-PyA5#1Yl>eP87ajB@8ct;1pys9|=21h|L@%Rb^S$@&KXW5%H zO9nl-E+8vh27>Eh5b+-VVJ6tEmF;f+Umxx2vjLk&56Cj#XhAkoakD4C4uy4&o{L~> zfk+jib)t1gGt_dTU&|v>V z5_!)kT*O;eD%1BT8x4k925y;JavapgPHW>Db?$o#S7>a<%UCLrzenq*B5I@W*lYqP zHZG9HJE2qs)Pe&-+-IdR9p$gEo2d_32oElF-&?-%;9Xsz)o{+yvou^nI#%)RU?5}5 zNvo*WH@?Y*4&~NfiM04%M`HATMs7d+dEz5fB8ta}@s_`;(;W zn4u&2dK{Pp9%Z?nN89H-h%YZIrK%U1Kwt-FJFjJY5UhiIH$xnwjF{Y)Sm5h4m~YW# z=!THrAkXE_J2Jn#RYHlkw84j%*=m`mACNsgDU7w1SP-HQ?t1Mutc92Gj50Ft+S7mw zEy>eO|9%8rUX}TRCh3Y!v|DjCre(f~tYsS^{M^rxk_pw0TbNK22enk-2T)zZXY#!j zXPzDLFz?q?8Pz1!Gct-qaGCi>QyIJ_<;wW!OWbVYU2^pUD!JJY&m-?y&Au{5>-1-tWKpM6SqL{XoFRTIa(KV=QlnSB!h@3MzkxSu z>0Y7pn5cCt1wH`3)MX9-p#(vT2x?y4j3*!O90|ULeHo@9e~JMDhU7DSzz7(=gStn+ zZqt`!jTs#B`C+DNIxOPVuS)U6;zPjA3d;xt_S@+L_zdgy;kR>uXO)|EQ#Vk2S~r>y zUoDw!N_wH|iUF{2z;UYD4LEs=4jZ8HeXcIwEpI?gaKplOuC~i% zU2047SkRHM&3h8y9F;$!>7 z`r(B_hiM_!Kq@*&g>+{@-gaEh^CmVV4d6=+lp+xF5bo!||DwT-?qGxA(OA?G0dVCW z+-#_l2sZ&ByQUl>9S^3|b`~VwVBWj%1c}A5sQe0qZ`Dqmt;%NEiVte@jGnlgY6t6$ zhq1~T(QKLR%!%HIEbkw#$Mf9e)nNt63+$l~+&P4wqka>v3BZ)0Y3|#iE(uJo$m0bD z%NAU~H#6|5PT5~OPTIc(Qis5;F@(9A*tr6zmvDJJs8Pt5uQS)`Z8JfgH*~n!Jezdq z3EX!4i_hmljCvj?qhr)indK`YX1=vavzp_(esY9*zoC4lDUDqWf3n9#2U;56yRAKmv6rY zmz(G&ceM~-aHoqY_tQt!s{#Oiug<2rE1&S+A_lB_5b=#?BP~%{_9hsryp4Q^xdC)zpL6y0eE5Ft6O&T1`l$s@m z$l8Eo%3*sLiMbX5Lt_@#6W6)Bk+B+j(pPOMT=mt4U(`@9PS-}`lR(%OXSZ{- zfJhRD-*L#E&qVToU(#NVu>7SYx~~mHI&$9bl)(LfN8w3|;dT6W=TH~wfL}t8y8&NS zbG|RyYr8eVJhxU+7YrqNVg{2Xd0`@RoK`t|--CESC@&8a(5na9=1woBDkh7%k-c_W zQBX{f%TxfUaQP<}5W@x4U7%XMzcL~6=`3*Cy&H$@mMJbQE8L{0E_N_EOGyDCr<1*_ zNrjyUJk{SD$FD6ivZX@y%pMW4XJkZ1GA?fRmO`WyWn^ZSjI4_6Jws+BTPb^l$R7XW z_xsiFcXPk@|Lt|-dfoHBpXWKx^PKZN=Wx%&rIZWQRISTnzPLx>Al7%9i*`3*#vj8y zYCdKsznLyNzH0b_G{2VwM;BvQgIE|*QSIwXI=Cm3oyQ3-YDKHjB^g>jsvG{YTbycS zcizO=NP9E0xrUkHvz)EVpE%KP7 z1U~cP>pk6Yr|=upLdxxvKWNWeFci)#HI^+c6{t$QZZ5jF^hO{oRsrt`GwbrZdPWiY zon3ON;A9?dVQuN zWU1%~&B=G{G2{99&CYVxj^a!2DYY+b)-6??lZ3q zr}&sWcjVWSBj}0L9xC1YwvfOtv0z8Z5zg;#Yc>BcZGCgHq$;lZ95*F9_eQSz_W}|U zGgt`$Zf+63*G1B{*XJ%`$D+-xN|- zegEWEQa{F*ak7_XCM9dE<`V>&nFMc>@Qc&SgF3xJPd{<&Znf30ouoAK8)-UW(W~%u zaU7F$gpTU+lqUn$9S15`V!GZ>8MPyrx7+h!0qv2G8^7&=-$(Pu-VLOxYr6DF!Ky>! zxOXci)rnBSYj?d)tyc1sXq`NDlG}fv5Jvu(={j?!+qH%i#kDjCEtxcu?I!UDHrDV> zMQQKZ6JQ_wgiAp=TuacrWSJqbaz%f>pY2+%e-0PX7U7V>XL0i@(gv25b(m#?l*GH| zhTrbjWI8=yTy@{GBXZbZRK#*!%7ZaR$}r-s>Q{VjY|eXS;Frz0o0S;%RdDb71*gcS z35BOLr(1M633f2v&@LRCV>iOYQj%(LXCUV46xL4YO62fuJ-u^_j(%~sojmELdrOcn ztyApqEB2s*nR_G@%!GsK?56bd56)CZ;LnUvjcl^qy|iMW+9-3|kcIPA#h#7PEr*wd z^kUsV@Gl2Sy&l6KnBS(}@d|%5Ig@8+Vs>4BHob@4M|Zb=Up{Fh;pr;2Hur?sDOuBx zZ!J7ri7?a)j^EbtiLRry$Uh&?%GI2nJQ^iKe6`-MmECQmGeP6qFt>7C^&`h8vYChv zCY`U(?f;;&+!Vkyp!08em*e-qU$;ZgNBLa0EX?_2f_v3=>J@EIo87shv-+o`4+LMk z#QXU%V_l5f7(Q!6WT_+Yfw0RC%h@-2dJuPf9ZTTG*1_vou7eChbAk1l0Od9-jf!3Vj7z-joJtoTzembqdine-VZfA>7>UIBg z^G&Pdoy1$6WlOGOU5T!VwR)IQb6;-WPyaN5QLC-Y;i4fHSwbkdH0!EfX@}cru6x7kZ1gH6?W>X|Mk2^T^u3X z>wAXS;+so|*9hwNQIhq=D*sj)0m-QL1@ok@;Q_%$taN^jFs?Ck{=s=4!)aMU;jLVq zKF3kMm0r2|uCQ8>*qY2UvZ>$Rj~%188wtMCpsuyz#}GKVZ)I|m z!xZ1z)QD1y0+V#F?@N1rX3q!KCB1(e>TLG_f5dfm z=v2HDRh?CAROVA#5&uP@<{nx~8Ew^a@EOiuoZ5%sw@y^MCYJ>daT`2f1n2K3^$8F3 zzgSCp6rI^orfyphfmf;a0~tC0vsxjWJL8K3V^5)m!_W4V3g z=G5w7w}u#HO=4%zjH=d zoh}+=+5XIWLN>67A61ICuIWq1ARn$E+xX5tGtJ(YS|+j$W{%tjeC~E5!&R3Jy*Ejo zX{Qy2qhhJoMVQ992YM|x*JEHU%(Hj03m8o&mU+pKbLAm4SR3y4n0Dn3DsLqAXV91w ze>`Q!>ug%oMWZY+XNKE=JX8mo;Z1xVHnPfcLWvtG78|$q8>a!`PN*?1d_thmH zE8#bLbORBh#J44B?`{e zOP%&ek@l7lZ~HSG&Kuih$L=g#k%bjy6KBnGx5eKIx$kHdzj#j4v~edPj;~z+{`TBx z+vA>ziXpj6t;uB$y!Dh8GKv&RJ?cjNEwcw)aHDFT(XQKn$ji@P?aQ9 z@Wo=FGB8(*B`EMSpv*LoFS(z`Rf^k4ppta!TVHaSsGc*K!B43Ptef;J2_+$qT^M#f z%Wzs|jA?MY*l_l9aXBcQor5IahzM1CIo8?_7pOBfk`;-(sqQm23yITQ`yiMm{wcMS zcq8D{)F~JK zV|_Tzxo)$sHUhfq$44VQzRP`;pH4BTPIsnd{i$~?h+r41`|(fW33IOjHuulmO1t8S z_BG|wyu>P6Gx=vNT|Cs$LeeVY?<(MfOhdwEBtDa|v$jer_AT1IDujVik6yEh);UlQ zmeZH)I^q+quYRX`{H;y2jYf!q4|eJjR&xIsmV;{F7^d?({fNq4E-CfeXPAnz=|uhe z%#S{o5PQ8%*ymcHZn1QK9^0tdpOS0B1bcBWmNRT5imz;_4-5&m|RZG%G8rh!7a`je_`T4 zDB>(FQOeLr6*|M&6oTqv#B>mgzk10w3=v3aGVQ7;8M>{)LoH~?>dRu z9@cZ`Z96qr?Q`Q`d*{IP6VF~eiOg6qekag@*Kh@XN53^#=Jk-zf%l@K^xb4{M2C{j z@z7FCj|+XT@k1`Xmc~1kb|L8623M_Ro1cRd&5Z*?BB7j~UC$y6b}Z zDzVtlwBa7Z)-Mvpd$49LN&E5hT#D@UV%&;Sa%6pjLB`l#Rqb35=bcAuB_wOJ8&NCD zOujdHkI`rNm}0QJjMAoy`)E>4li+3f1NQdi7x6?r{FH{$8wM*XPw7nW9=| z)~lEox|P(-q8+lx_%k}_j6vH%{=gSRCUbIPLsDZ%)VjWR-2A@%+Ba)gk@Nj&*28oQ zb$F*nwy7+WR|-S2Du;@nzJGm(rE&X)^UMgAzHe}O_YKN&w<|nFzRxPFv!+v%C)v_| z2C)vuG0-hyc^5qm(hE3OA&spxG_%U&a~yFqIn|w|K#g0kF3P-qg>~Q9U+!M9pj9># zn;l=hHzH$JYTP(m5ZZ6c;vsXMD@d#EdDUT|vI6XGy0@SV-}tsr_K<9z#^DY5YuP&( zS!|czwAbxf;uPMVC{E;1b6rIWcIJ1#TU=pDAnvy!SOU~Ko~RWbaB zv$>71W4Pvh9kZO4W!+4o$&NEmNf>mZrCV*6&WK6jS4(Uz6B^i^@Eg6X+xvqnkLb1- zn`4(n?P|wE!i$Ud&TdFse>hKfGW*qqe3`X&nQEh&a9XiMY;5_~?jBOhsfc^nZ#C|I z9mUaVsQPf*vB`$;4xtn#xAAEQYL^B~M<(97&>M0U=DsTgva6t?5F}cO={SA*Xj>n% zwL|GlP7o?7*I8Mh`8tIfn{A8~C&xoPnRH&)XDQ1&(|}<|b8@VAc`$Q|WmGStTaUd@ zkJDu>$K+wvK`i%t_$>AMB;uUG`XwR3OzWV4oZICjd?|&Ibr*x1ICXcN#KUY%o?_rV zp!aw;;zM~;>AB?O_GebN&C54;FXLqdrQD8rx89QHUTNr3_gY|rI=9PHSy0+Y{wi_b zIYkdz!k+YN>U-vrRUd_(J(`ISrCKqLJ9+%O)NOG$a;EWy%*r;4p$i(u#?7M+@|HCT zNv~cgIU?#2IbJS`PJ3Qnl4e@HZDk>+86P?xr`|sMiQR+W`SE1`!NyLUj-GjCXym7v zsyadDvTcJ{Rk?ak;;9~*NqYgD(4L4hIos-r)6d#B-ZI{o7`Ndq%IeZ7;eS!w>OVa< z*&+Osts3!+I5@lO;o@?xeshrF!)zMs8{l_lTRxL1R~v*FC3id~>sG2a62%Q_>Z&=| z5s$4DNIE6-ldgXuDo^1YC!blK6UTL5V-lNmotaiD)?-5f*_Dd%ucu1)sX+=I^*YLqTQTHyKbisj}^bXYzc+kJg&STi3O+ zdFm=lF7^FR`>jGD(c9OSIc&}N;IZSkvJwU?M8(zkU}VlZ7oOhG7_BJIp5+#P5s4WP zGwjyCQGqKRSmHoIoO5PV{`73k`Db2dZG~uYc7=KZz^6p^Mo}635ZnLA5gQpJ_g%_| zyu`%lN(V_A*SO|5DdYb3VmZe&wOl5t*ruQ_Zf!6)X6wTi^Rg;<8idUwvnc z6@M#MmeBE8DnZz~vr;;-oR-fOpZgZodKU?cQ+m!*I^T`0G<}KE)*Rs#j7vj9(|wP1 ztY<~2N`FR=aHgzbRGq^8?i3#5Ud^w|cgo^r=4@%_w^L=+=haM2dLC*-NMxmDeJq*{ zB|afPrFZGOZm8{O`HOZ;)d-D`U6Fa4D`)}D^(`f93c;EQ{u>yK=g z$8CHX-Y!P*RGek2V_a=kr^lz(5$!cx;UQQHXsd0F_0FlrQVk}4Qae9X&}~mE&?v2l z*I(^=@9Jk~^?k9ZH+z$xnEG3APZ6DX6nww+*~37Z%g4?hOxa>J@)JF6em7hxr6Mq! z5w$tmn1qkn-+AjECpnd=FNB=e8!rwe)Q|FCbNmsI(Ihvz^CRp)s>@sx zdphYIWBiA^olTcK&K0q2^Kr9za~Jw%W0t0ljJAE14<~(q_3>oI6J<5pXtQjE4$Zy+ z-Fq*CtK+4^F6HLCHpft=Eb%RWm)`zZvhm^J=Ta_(Pqqb_ZoPcN2;N{`KkKl5jpsBs zGby5OPxJIfuU)>tGMh9p;NQ`b<&M9VcPzLwBIb2_Z`SykRq`iQA2;^uFJ0!LkJ0zN zJjM0`I}IEIr4(tV>YQ!F_?S7)mATvXJ#FTMCO+O`qqzJc1aVM&wE`aE9_^DxL=!QzYa^ z4?baSRjGJ>AY~YHTEcaRxKCr^#ip{V=7&L_tJp@}_to;_+FRVn?kHQnS169VU9(5# zo0!<-_*q`Hjfh!9rj##4#UU?V$FP70zn((Pg+beTZF`t3#mdQ*a9`>ki#&B=1%7R1JO{#o zlqH_9peAv#MSh}Wg9AOf(AZsEo;K5SS%_~DUHw8VUexvT2_gE?KNfzxO=oJz`y7wS zeEyW@@SI*#NEFT0S!}7D%##(d!Jg9`>Pxv(&zTE!D`AWNUeYTMocmV{+T3tGgg#Xa zX&-QK^*l=(zcOc*6*RVg`hgg+Ach%63c->lKUr>IRo9~Tm@2h14>_)T{oR&e!kj_5 zjyT0a#X{p-Wv2Bl^b}L~q6_$5v`bDQtPuPR=>~cqZ@d(qF=Q&s5d!+0WaR4JIq0*VcHC-!-DO zVV|VJOpx2j!b#<9B5-@7h=Z?XRuL{tox5pBU*4Y&j@S*1^`$mArKnL-&aEyxpYN5? z!Bw3+NXu}P@-;5m&hEQy(jsmr8# z5@QLX9S$BG|3B)TTpXR?E^Y|8tB!|ehZ>J6w~EGP^QKo^;_9HNAQAs;6ZWt%73mje>U*l?`9eoFR3Uh=;-olDE>=;{YCiI;_xfh?Ef^KvisSz>8U+;3*$llA<;y-Wqw}lb4 zR4Ed|7%=`@7_h^l_v=dY7XvNLoSf|7rfx1~4z5mSE^r4oQ%@U&8~pHZWdE!CZ_t6O z6Y)MS47LRxhehz$mFAx-f&m3G<>%w`66Qn2W6!&=b`BI(DQp<*(AmGPH2=8^7>ADg zZIY~+D_qOY%ni=0k8nXaSnI&u+?{wW?95zU{}k!YIBb(g1cO=9!~U@LnhXRKH7Mz% zAl?X&Bnq6w_)8l2n&vNm2?8YN=wOAgMvc248?LtrQ2HQ5Sdeh0nh-c87c(atgoP_J zKWgN>jRF_gPlSo%z+l`+$oR|u4=L|r=BeRm2}e!V>3BP23WhogQW%U0i5#Z;f5@nT z=5p#y^gt>X=xXH9IcEX^)G~8`+d-L*=#9@w1ZEo%{>ck9MavUFt?$bhD|}+0&ldC! zvc4N|v^+u7y!WBh#~uUTXJ9XKZE;ZsCS- zbbw}igtZ5*f$I1191O;Q#AdNa$3|_u9HDO38VL1sz?r9!X!-%jG&zKeg&q8_o<@yo zXmWJS1V+yQqt76r?g##Xa&&NWakR68yFkT^`)&EO7l1_y;s%+82!dom#Y?ryvms#O zMPMQ_OF0;l1raM_%aOtPfQ5I2b?p%(O9-{UD(_81h5{RtkN8V16p|&3n$>W}|2P|9 zeLJFyG6Iq%f|{i`S%TLKY!o`e@`{9HiK1pbm;D~m4On7FSV7T{EHTuq)~f^fUjYl} z2rDuck|mCsH5zekM+*4M3HY7|DOU5JLb9~nEo^n*4z7+a7cDH{uCA!jgf7avS^(_| z(5y)4^NDEDx;LHR5X|X-jO%+K-vbaZ*eN7tXEGEMwYn6QzVR2piIl*J3`iuLE@YBC z+yeouL|fX^@MD|O0BsA{%ZNmq0=@pVl=x`8YZUF4VHPq_z zKBB`x)RFg+uve(ng?~bagD53r4hSFAIJW_GIEZTUl%(reCQ9EKfZ_+;6%YmG#0KUN zYTrqXpu<7bl&hrC)u?fdW9V=YWkujE?RnI`!~TK}2T@sa;x`LX<7URu;UJ1jv{7Mg z2j~j?iG>C*) zeLF{mn%2I8h6a%j#eVR3)PBoeMMHx~hk*~1BB*IWKhe-2vSF0}EAKFvujcdrIsLNS zfTp1yAY`r9^ZCHIYWUC6-mf7i&HvVMOr#>G;0kv!lZU(gJ)4G_X0~lS6PE#ziwT&> z(K}Cyj)z*^K%cy~3RuqIr-Z@49qsQc%^yLIOjCw?A)Fjt5ol)9GR5EOTY;=#07RCy zbm|Wnm^ZlCAslSg&CKC;sHHXJh0K+Lj28rJ7|7H7bw*^Gh8e;E?U)~EkaWKpWYy8> z;VcUz3ZfVhyxi0)1uSeJ4S8z50A{oQ9kl)<3!)O$y@{1V&HBOt$%3f4Hf7{&Whixh zgyl&;^H3I7uZxE(zKmNAi2 zC`25J1rc8B$CYGI%US|AC8)bm03wA*1)C&LvnD`ggJ40VP)SNi4{Fw+EF=rUMt{1G zrKnk*@{lZu6iQUH(n8H@P=sVbq>w~bXp|Kw`Ldw4BA1*}Wk?o83Yp6IzB#;876Ii8 zIV23#pjZ$lc4_Ab3<8wo5tNMv6biz^0RPU<{QxC#1a(^z3I$y;iPncGJ<_4fWW)qqLOwKobnOum4;nZ!m@c zqXvDG^h_-RemesKgAqw#U@inm7w+l?HF+9l!|Y-P^9g#e@Qgg&@p^>@hgw_Py=Ogz zKpP9tb{0w7U=cD*3v48KI=WcOBh2g^t)aw)pGdSTM#<|aLCb?EXPT0>WQU{WQGE?% zXn7F%KDgY3bJ!P0dF2&oc@Rmjj!h(t+TPbyXn7Es-xovBhMJdNgO&%8{*~en5r?y& zqxL4$q2)o;0By?0Uk-y1Mnt51~VhY-=ik9JaMQ9q`mK3whxH# zBN6S^jGl-(Lt+B1j!K?@!A3d$ydfxPMaM%;!(6gSv<0@hgKEWqWH0ydA2hJ)$^83H z3N@|FK&1_AHo-Unkr9d3H;RIGxR8o&|1G{~;l&kz@&V%5k#IJjA#lG1LT{Wjdi5T( z04f8R#39!!?5_~i!zEb=iwDi*Ysg@*N}%uXM9Z%$&HvcsQ5b4QYN43cZQwQUBVOAD z%PIdIT@M}h+d`;-`$So~*aw1*6VznnPACEEv(Pw*iYJ@ffmj6U!T?g>mwDi8nt$6K zI-H)9CD{DcMcBi&;bxX*=5`Ps93@U|4g{OO!YBXi4t%gR4=ES5E8{-}P(=VYW*rIV zR-&V@|F>CtzNfPp7c5yYfmB1DBgT8a8z~1D14!k7_rKGdMGZP6Vtt%t21#xhdiIe;~X|AMp~9qo1D_F(zL%+1{e z{(Clsnw#OdmEsQ;j;@jaxiPZ~Ch%yuXgcMqaxHEXh&dn7yEI5z>!gvHI%f9Z@CIsS zY?CCN=^$%2iT^Cdm0%6|zsmlm{EA=HG$(DQGwQ&94nP+RlBN`OR5TR_D@W$T3Ikp3 z6l>JqxdY^(sURnQUupilnvlr9wH`){yDMs?HN)CnLI8OM^a}E}*4$+%ENYVItXV4w zAlU&Da_uv?f=to}dEufC_ki1>=~n58ANqb^U+@{&ya)aA`%3fAFvNm6AskR0k&#TITB|^dr6aA}WB+O;h^iH9XpMZ39t?Kf_|Nw; z$i#x_!tLykTcJL)`L{$;*ueqL9@f9-r+%H_{P$4Pp9enw9q|qu3mk3y`$Q)+M_aS|JGVqhi%$H0pj5 z_m1o+MPzA3CFdNf8WbF8q$FlVRBz-d#m9d$Qp`?L{Rig}6P*M1vzQSc=LEC_5hyx! z$=30-Xr5sAp{b$W+TGd!|2sf{{|fM5O#f-X|3*gU|5?HR3xNMGz~0H?{{zANAIQet z$>={M1i;O|2a?c_mdDKs2*BtC2!Q>MG_bd~Hqmo-G_ZBDH*hqub=Gq;w{SM0v$r+7 z>JHON(s%{M3i~tq#~4Ta4??|ya;CpCAU1(ci6nmUD;WVR2Ni`1a^$jp0dhPVmmng8 z^0^{0f`BJ1?@_MumoM|&H~3AChqr%QcGKLZS6$DG$KKHhE-Y#3o`zqT0D;V8o81mD zKNMj+FkT-nfOtGH=IYlUTK=Sq4Qv&s0*=L#fi!6RU8#J2O^hamuu4ZBrFpN9L~wXb;dezonz3*LWE`|4JD&OY;?nMgu5eop%xbg4u0e&sN~ukQHK&B=RBKk$i# ze*B1k_{~H(v0Y*_-)Db(Rrz|fSwC~L(HFcupO5jF?W!t`KR-Y5t7V#xyr!SNFvt+x zqNp~HTKUO8XY+&*+{k9EfL@Q0-P*8gnH#O@X5nG83FFYyMf1+Ld>0|`e>eD1Ys?;m z2%kiD%yrJxqd?eXrhCm=p>-Syk0NK*l9LYLUWeqM@}lCmJ_tLW4|ljJ99}iZOrmdI z+vrEXg>*=w3_?z|<6RovuwLR7j`4-gaM^u}7N;o63LZ*#uKzCCwjqC~GS)tqRr7bT z)n8uIxJxM9;V9-0JiGKYH$MfnZ18P;)GJ9>BjMm z!Y3UY6!CK@UPu2VhmF!|gMo#0v+sVGBn`5yq!oj2eJ(946A$x2AEdV|`CgS5)VbrK z4Zng>rgMC&Yt_3?zv2J^Je1cAELKNk+semkCkLu>&-Kii2>v78D30~2-uE%e+WyG)P3fa5GKQU5!WktR`E_t zt+xSRbD5OlH(#*tEX5^(l6-D8Q$V&ksz@clj3C*2Z}bl1OW3pnKaR+dPsqYdFh=g0Qc9&Coo5My7?7LF;xRUH30(0W?F~3#mk6o-_d-4=z%^)l4L7 zm6d;Bp}>dT_qx!xW>mh}-y~6JM9h?A-DHiO6hu#a!RNZ?BO^Om5L)@zcPrTG=_#go z$N|DU$TE}0?OIJVjdlev7-iYvQB-}6y3r697gr32&-|6dbe)OeyJ{-;3i73yo&Z&IjOS=sT4MAFi;0kx<-Z*p^urLj&qVRp4c>7qMoufNR% zR=(f>g%iZWF}q5TD85`(_T;jAD3VX(-Mb_D;`+%SUfAw=Z69~Ih~EVZQN36^{G(Yk z(nD5gFxo^wH+U(eq3%wB&J$g5f0q^uG*t>`vRmAjy#SKDK?9#>JL?2?QsvgG=p-O| zz=NvUmVzgIx{N;N?sxl0v&?*7TQu8^Zv63)5~p3_#y&dT)#M!bfLz&H+7v`lhBvxo zRvqS0+hm-NC?=h9&IjUY$%Iac>-pSVJZ!D4BG6Pj zK|xL{!F^;46)sHzf|Uc2cF<_4K3y~map8hruqRCN{V=468_~Ql9Yl1qlJ&=xR5VY& zG!g(V3VcXIZf`l1_+wP5gEHqum|6!awklYnRKMTT`JfCuT*y#4lWp3%5UaUxZI8S6jw3_ZAwrI$-)hSj5#8rh z+z}#LKtMpte9rp$!873`BfkaFfyoj1J*pn)8Jf~-*|x)qB-r`OqiU_XhO`F3im9wi zw57^Ytyej4>u4UOQeD?1-;EwNk3v080~`PIY|iii^G$*Ap2ly%6+5#EK@1R$g`mzo zt3Ky|OvXycoyE?oGBcmVz(n#KpI(g<$e zO!W9$4Mx;Z0FJbc1zU?ym zUnspyo+y5!ubEI9EIXZ_X;ytUo;&=X@G-5_4p2NL!)L5Fikm6$Qvd-DQIZlY`8eQk zeb9i;L?r4zhu2~~BF_t11LCoM`TmaGUg3tA>JrO6@nnR}i27kId{)Dw&3KtEOba?e z#lt9@i6$8ols_?9xq}US*u(=l1wt!qerMe^wW(3@xwG-wAKug6PmfVA1A;{w@wVU? z<$uca0}I#`0s^mjdC3Dgy{%y)uM1~P;Q=s_9iF-m%>M3yx6{}4*OZN2482eGtoE=_ zNI93wo`KjbGI_`CGlxZ5vD@u-6OpODK3vVTWn`eE4$0y9lwsf{rl!8IvA40tGby3T z1!vOeb$B_(Q12R>ni>lJ@vvXyAm#UiyqCY<$P(m+exUi;vNALqN6$?t2ur*-*9=_B z1C2dj`Pq8b+uLT@Q^!GceS6t2eiFuJXbDVBRrPAkMF1w{RlYF4e|Gak9VgzJn~OW~ zs#9OF#Zhhdg4V_!rKDHGpO}zjLROH}nK23#&PlGg%3T;1ju9KVS)FDEH-rioT@zdb z19fwATg*XBESj6MokMHg2~xU^*yAyct}4{+5doW z6;?=PM??|#J}n*_w@&u4)yQ0tT^=yv$$M?W_y&|H{oZQ(#5SJ<*^}Kl@31CQ?r<0O z>~)^D|5VFX>7`>XDo}P|Y(T9{1`+2hs;Yp(Mg@ekC_9E_Mp|E+{ z-pRHGm>E02ySp>nUk2co#dol+5mupi)+yHZKx{QG@a*y(hn}*HxfACtt0p5&h6@mu z3{>(kMO58(d3q!!NRFAIEc$jAfDZ(mdLLlgl9z`sy~!8Yl?Jh9%gBv?)}d}J0CSRu zrVTnt&9%QN7BLv{@AnDzDiM*D9>4$NiLx2m2w?%zK|Y zBs5UWh(${Jun-t}1ha>(xqLmGgcTfD9yb>6n)P0^w;1OqD+G@XoAgyVSTH~VsDe(>4c0bi>GL-EsBTK5_QCgky-ng8$t@GX4Y?LNtyv`FJhgxGtk8f z@$wrca_%;C`Oh8y0@Yw^T|d&%yXgEODuR*3FpxVFiN@-he;!lxl3OM}T1cq>wA^>i z?RLleWXdXkd5NKFY%JqoE2WqK##5^(-`lyy6Nf}U#MW%{Vfo%f8Nc-s?nxRLR`>N0BUmoXnA_*bnW_Am+;#EP@M zJp}QDCJ!FIFm`M%H21uRf(hNSj2>2&nVY;&jK-Kvuc`DrBiNGC*d@uU3 zyURVT?*(12xW@i!0j{X=v5EK3>KxYY=Zxj)-TZiszfT)I`?gF|Vu&Pgc}V+}yCbI! z`EZJ+$tBznQ7pB0)u4jOB6nEcENF00{h;(l5O2(9 zXVDev#^LkD%dentdH8mw3&c$8vatR7A3Vtph4i~hl0|{foC6(PH{sJ)VK`6W+=g4_ zNKb1}&_gOf$%;vf60fs0T8bT@qq#n*&GnP>`JZnqJ@Ik!7)xVWhBa*&0+wL`d&vUW z?%^>=x|m-31lD^=NlwVmUmoT9?>1NmE>Dr}E@lm?_%Xc*ik;izk5wc-^kRI3uuOk2;h?Dm!QY?1=8^H)4Za{Xq52 zj81;Av9`ogtpL+6yjb@u#{!qf6omMzcLyizDe8C?w3s4`YMHbz2+T52H`^}N-_F=* z5c?1Q88f`Ni*!6$#$RUDGm-*uSZETkUatB{YGySOOR3z+WU(KiEBOf_o90Bn0ShR! z&x>-zpVL*=Gl~R9g)0AEWd)MppclZ7HV)($Xq-<|WzpO2LhFrsw$ zctG$>HI1EP3Pqm=0*V{0qSu&zbT%s4uJJ@eQ0swir)=3FvXKXM>mjk3s&8y`^$+ct zk4txW-Jy_7xM@%wnKFj5& zw%pn5W&^jRkgW3I7H{CpK$~)#eT9dKuawkdWt3@te&4E7b{wvl-}wQ^o~^D-#8s!K zr0SH%E%3DqHolGE0JmnPfO8pyEgO5=_;CqQk@kMt_AfmeU&6n>4YXh=UoexPq(fuA z&!Kkh7b;_3f-P5)nFrTTH;)Y}$__m^ZDlPP{VgP{Pa|b*@(Bs~*@_}=Inn#4+>!IA z{fpQ`4fh1wUQBH0csIzc_>Ya139fBX%Vt?z49;$1fmOpZRnajluGN+a6s95$V!!_! z0+Z}NZ1Nlw0;8Hxz#c=J_=K#kZdsiqG#>C-HMP=HgmqZR3KLXIPEzeh(nhnrDt&Cj z-6n4Sz*+$n|hR*6M98%_F76LMiX!6mvk+m(4+C zy_O(2iu|pOb`=%UK z+96Y`*q7*yU+@>do)?`OoND0e&OVpY)2Jbp^XVGY*OIlKp|DOK|4s>}ysgcDxU8Z< z%;W=w`q_FGZOiJGs2JPgaY-qzYu@B23E0)$em)=+o83nnrXN;@USQ;!cc+5L>8w1CCv++tWq zpjCX^1e`dQ z$kQf7m)?b8sN+epqnErEc@C2@UUQ!cfCX?S?~-?=j%_n-zt!Z|=&@R6_bPh*gVtNd zGsDHGsxr{`i&IY>Zl4cBltJ;|DFN|cd4FFU2B!&?$@FSxxVJ~GfD+5&kNP^_XM~n8 zn5#W*ufEN>F8pJ2jKeF@<8KrPF2pY^VsjjRb_MaA;y11xV*2Z>KmH!5(=#(Oxe5cP zJJ=}4`S?x!gg5rTb!Lpqf8?)XE>u@&Zrb)2MOLK5&jlaW$8kUx_3{=obfC+sf`j@E zWXeSN=#}W2i;y$MKO`7V>4+44)fy{;GY&7%{6e3b3D7Q=D@ zq!>-R1BY2;WMq=|etZTP6qLWzH^ig-mS{@t8vHP`Z)WM9s0-v$0}E*%qP<$_8XY{s z6P9j)UGzFG;WeiOYg%jEpCAnMlTf)p5h!IwSFxOz|EcQ#iEw{ zo^7WC$$5QVX6q$6Sn1&b6^n(ZM744^+vT%~GwW5~@XgerM{2b@62imuO1ZSOw8Glzk6Z4#So9_X&`339bS9w~g^5NIAp&1WZunee8(9s7vlZ>`~9*(T)BW)pYhEmsj1$&!`#c+v=IxnJVU|k!7g_h zH|;bcosF3rrxh3($<2K`#b1|Pa7zd6T`_l1sfzzNOWd9E27gF07kKW!%x$f4tiE~qsjajLFOl& zDENO}-g#7_>QTRvmA>X1p z)_T^Hc0Tt!JNJkv)b^c)QPs!`BVZ=eO8Oxl4j5hiyv+wfyx2dtc)gWDE+}zX{qw=N zxq;HvQ;_$=Ew0!Y_)%O^Qm4@IRrUlHy~@mzOmf*}>J;jDwk}T{fA3sB{RsZ2ykDY& zknf?4;*|Di^k3#(tB`U((DTQlZwK+yLPs15w_#-zW;sB25!^GPK(`22j{l`)*=1S@ zd#_FoSi;CIzv1H!WXIMEQu8}uGmAZ2mZ&Y?t-XvqhDve8Zb@mn^u6Vda=-2V%)?83 z?8YjY^x=xJSnf3$*d{TLDJhjNAnmL?Y*@OJ4jQZBh2&zFNalgp5kWpw@SygwKbz@B+R^f zqJ#Z|RF-;g=3bq#vWmfrl=g;yGTZZEr7=)fP_y#=dL@-5h9rpZGh}1qMEfw3dRg3( z-j^y~afVSF5@|N@cv;+8&9769SJ2IJ6w}`?Dso*u|1YE0U+Q^ui#0uCE$@lsaw_HL z+|8@1Tfz90%t=@ZZY#7n-7jZ~T&}~K9?a`V*u~|8o97t;H+J%oACqh5XAlQtLAw?k za(LvDnMO`=cxL7rXV@ca2OwAw;*a{g#@bQBe@78XiHYV;j@LQOma@xvnE|mpMv#cb zo*4-@VelFQKL7O6Q_FUK9jVzS3~PjcCQec5n35+|cj5IkkN4Tnb+p0Ifkj(96`9+O*)MH4}Y( z0;Kw;1#_UDaa!e$x41PoD&xL+LMPM~%USgi?pJimrBp--y;1$brwxS!&Fc60^IL-0w0;7IutrLe2rptb&Kea}Y7r$&aCWWM4 zsCtUp){t-MDUBiT&)hpUMH-F{K$8b@L9h6VZfFnZ)r#blzk+9(I=WG&h zwKFe%9xl0cktc`!A9=H#`@QkGRc>!Tf<=t{nWB1x|LWMDO3XCB4r0QNM-`EjnW_V$ zu?t9F{U-lpXCx&Gg0zRnJ8ES~+<7XKv9(5iyToU40hV$!s0GHBfHMLC`&MmjFs0(0 z&Mr5)FQ;6Ns_5g;?H@N;=6`Q&5+Lj^E73b14G~fEyicR0rKYH+shFgEUD5Xn4I1MX zJ}-Cj-F#J>jgR1xlkUuzS!Zwp@T|)INR}F9qq(1_(cJ_N8saG7-^SVuxE#9j`{3HDzLnK&mGNh#38toW_9F&&NlBSF6y`3<>4_~Q_KdI7 zu@qga`nSO!{8rMdTVlgHX_9QDkZ06EcD29uuqhEIGE;MXf)iej0jEvQW3n~nkV5~2 z{*n;q6Cje{xG=B`UJOsvTDyaFetcUU!HS{Dpkb+5RZkzj=JhpP54^fyEM@nq_cOSy zk#*OqgNb8K5<4Z;{Q@u`haH=Tn=fN1UX47-8u(5YR?+*LH{=Ky5UMV8$A0z$S)tvH z*Z@xGM^ZxQxwu@##+Dgz_UFw6|1}KN0(~$qHwe0ol2wYg_;$o%BR6U3fqX0Gf{5}@ z3KmH*t*T9hsSc`)L00xYBq1`mMeES2ipu1_Pbc5Etk87W9w!_ogIT@aig+n?OFb0^ z77`w<7Uq`Eo&Xc^Y*d@ycdWSIZLBhzElgu5TtuKMJ2`Qjc7@C}#ZhG{*0p?!coiujKUp z$oQp>?NDagDP@WLTD*$L|MHZ+`BwKU4KGu4yN{*8jWfZwgg%rfwazLMTuZ}VQ-+G} zw4LNo!JtND8wzz#Lb|a+i?(iw$VNue>P4;z+6@k-9~Qg}B0VQTtBkcQes-7ec*w-d zIai+<0b{*yHmr|KVYUS1r*~T*0POX7EFX54;i*TDfibuc98jaCJ?38cCY$t(k*yw$ zuc^hFR@qH>s@kV>p~rQU(Cc?8UgWkn8vroUgH!1rL?M?LF!doP-`GU$fyL-rzlD3H+bZ#4-C)vx1U}OzfhG`yLGQb&m;K8zv*rNgiuU9?Vn{Zs6d0>F? zA!m^2bX$=S_}k4(M5;;C@cKoo6`h|8=IzPjC*5b-#demvMA(;;$t`oiMu?P>YD;Qs zHPPSc3T|={1@ZoYnZ#n^EcA*!?gg8Uji6^>Yh|aga-S;(jS zU_1pe6EVR~p8a8hky??0hm43=(5TPm@0hG0K8}bIM$4MV2<$Xllh2P9KUC7F)yHRpdWIOxag)^T+ni7(r|BlxwNWXdeLiT{+It5B*j=y z@b;Z4YL-Pi@7XnLE%2r*0l&nEfzl0W#~+5yDUXt}`9L@0FIvkbrab0qgE7=7K`E^5oWOLcD6$QhiI zERp*~E``T=|ggUi=D$e}` z{#VA_+N{|dWE~i}=z+aBl2+1DR`Roo%Fvg+^}M6D=!nr(FvbR*fae!DQcf659Ct8x zThB#=71W7-PUbRVOX8cZS>is29D8gu@=7k5?U9hX0cFrMC{RhTY(Dv!jJs%OT>yw^ z^o8v2QVf3PrFu5@osDib?hzVg9at@_EKEVh{xCtG(N;2e!Q*OHk!n_uQLIK#IDF{e zp-BW>g%XO~`Athk|3E@mv!fiu%ziXy__`(<cha4aNO zwoy}m${9t!U}LS?&A-2#zd=vk-c6x@Zf29M3$4B@df`pwe|l?~*Y;*A$cQnI-+jtV zFNsehKMB!&0l&SbM}kcVcSFRbfKF2y$74BsQlWz6dJh4*eD9r$c9B1=d38T^bFW)u zN^KFHM1LOw#xiCLS9yDoXOtcwC>J<3A~8(d*9wTQzeiqV8EjXiRR-MlC^Z9pi`3V< zcTdE9)w-&5e*Hx>Q>^jAqRT{K_hsP+_R+6K_iu+Ewx-B z(`k7Mn#9pFLPQH1(>1Hj`U1@5l8Iyv_+h;DSd?L7?DTZ9@TD-K;wM0-iw=i4mx8Q4 zs}L$pud`qyyPBPe5qA=G633D!oxgNnzz(eSBZkV#I0getw>9}7{PiaA;op2SD&0wp zyuJ6kA$)IFUZnDHfb&rrN6>2q*Pqg*H4j|UsVj%wc=~Q@w>*rg)< zD}G|gr;)Fh)^P&G$$`gqSHy2rr={Djs~>>b>Wg7^@qK1hAIbd+EocRt zj(t|EaCYwri+|1#cga%6;h<$^4aJ41g&V{>sL_o^sQ)nNjS@n@ujb{+U?%y96spWN{YL?KkrVHclbHA|10dy#^UR9Xbsaj5tLVTdviS);-1C` zjN}#+3&QgbO1@iahh4lNivtE&G#WkFDpK9LrQttfb#{DZT_-Ti?o4IDDzGLG>7Zdp z6_b3eGp7=}FJLw;294>{$Ih@gn^09%B0>7k;ioZGGwbEN^}?PWhdjcJKxUn?^{VZD zKoIsw@%Q>-nguK}|GAmyNO#L0aUx`&8!GY&cxj$S?SSEK_T{C^8eghFp-phD(}h?<0X4p`G;4u_ zw;Y4Q|Nb|=f-jVvHmz=jwv`|2;Qe;5Q z?**~tzrWQ_#cv!&rQ*qM6#Ej4gf(FxIE}x{@uU2l(PK0;GCES zE2V@t(+zJHM&*OlysWG$S%071aiK%tkWYHjzc(WW9>k`Q=G~wXY-EjPh*$(#t!yY4 zo$H{++P=g*YBBh?GlMZ7B5|ENA~v$4Riv5hhwP2eAjqazVSYIT;JC31;l}1X;X2vW zfs%?EzP0S!`5-X5^McK-bcU&oykd;9lDw~vRrmU{zjrnCk0T{d%GN{wcqS%Of?wS< zRaNO_bocR(`WOda8V`la^1PHJlY5nESkv8dugXZJ{c|axo?^n#A2=Tu;eFGVTD?`8 zq?i;txfz$HR&FmsYm*BJvy&eZd314W$0S0r`3g+x?!0NWI@g2(F6l+TeoSMOw=dH~ zYT%iLFT|5q2YT3v!M_5inxY`FObiIs4%bihhf6;!!A>1+hwp?6~(b1zA~!bGvv5sy}ykr;-O(8W10@jLE-9pv9HH3@s4 z9q8L(mc+OkZ-T+D600bHaRYfsiau5#27D| z${glX5l3uk$Hh(GcNo2!G4!HO3p}ba`~tc=&E7?Mz>1&#afJ|tx({Ci_`sI~iD1`w zsguyZ>ffP@;k{ufftPm=*eDxLp# z6W=VSy6;@V6V~40sYb|Q{d`(-{8;pgokv;v>}M)xw3`B<&TRq{V_2+$ZqH9&~pdxBR7JRJ0F)oo9Of2Pf>%|9t@7@U$dW_-`j#Qt0&|qf+1*W&J)RqNb5FY-J z!)@;`6e3W+HilFGG1Fk?NVM&JZ~tRzaLr|90XaxYhkX4%wZeHGwQKq;}L2Ew8wHcME8YJ);(&+Yo`^`|inI(Ab7D}Cz5=1&1k9B0^Qp59B(k&)l&Qy$3SY&W8Q0?*zQ_Nr*V&-y0bz^}53ViWOah1OTmk z+>BDJNM483s$@0^st}eA9pH7k2g46h>Q!i z2tt^K3=i#>Jws_dvnlwE1ITO-EunvXB*DOg2w2bV~@w$-@0>8}qaRIjekAE!4CQ^4nJF&5cxZ4ffyo+_@vDFE27(6B)ZpQ&SC zp~F_?bHt^md>N4UgW(-sBsN3^yPEp_Yuhso;gfM@)Rx^=<#e%#`@o#dvuS_Z^gcOi zqz_d<6{w=dcG~loL>UN`TX9-~zFMx>O>_pjmX|kSfz5UO8?YTvUNqf$o=Co?Y$Cd+cD_^QjoRGlCpl+2q7zs zJ?~}Y?vfs!+BXVZBmWyy`pNCG2_z*IyAyMYmfA{O=z22`MXsqM^0kwYq(uQzs}2b$ zD!U;}+sO|k^Q!g8r&9AAOJ#N_WmiBtp0D739QCn`#^`UjjvE@Bp!PsWM5S_F>0qVz zgpVLpXy?4!-u#2ViGD?8rK8q$yDO$c-qz?xstcx=5G0pKxQ;E4xk zZA=uqY{n$V1~?x(4}Y^pmkgMzTtl2>Xz$#z^!nTh{or!>XN@7*2=}OxKNz0GD8}d` zH0YHYV=*y|7f1^cfLc1-UC=$<0HZ^xb5@=KK=t5gCct1b3+O&aTrTpdj8iX5b%p`j z{tyoK!J06?qDYHFWXXWH3Siwl9PHUgZC!zCt^lM*1?1*w=xrb1e`!j;qJ@gxRshb; zuAg|Wp#@ED?dA_@r&3LfTjmjMZe+N(g zl0@r(fm{|b>X2A147KpZKZZV>X7R#a4g0&8a%1z&owhc39L8aGVFbDcA^1kgGeFTS zaEhUKNfdlOW7#MuNS{(eJ8*_jb(nYbO8K}*{GCC<_m-+WunTG2Y6|iB=f`GsL2pUa zO2slQrn^;+X)yA4O~U9dsw`{cX^wZPXTp@-9#yH0S6}kdy?~|62ZmR8rL;n&Gn9$I zBS~Flj&;SD2AGwMZ-3rQz~SyJEiL`$fR2di)L2=!sF?EIFZ&DNrTdP{3`hXO(ZT+l z&xI>2aX*qmfe|5q-$9qwBAV1d!uwPZ>=_d^C4~BFoS3`i&H`4OF#@4+C5RQiAw$~P zmTD4MX}N;*%lMQe91}IBiGSivg6<&FD?L0D*j}Rct-5_I*w?ncUUi}hae>}F)-oBKxJ7-fAZ5Vg6Q0BCQ%FL9Jxs!}F$0jW z4Ood{eq4#A$0VeGHq|6)OJyqpR4Q7iHth7`MS>VK&Y@W`L^cabuyc+O+1sflMc2ND zLZNlbdaVNt>6<0HeI9OUKm<6`)syRka1aO_vz?TVL8z1@D_*K3Fzy|0;TOhF8_`HT zIJ&;Wb;KTo-}*tHj;g1*>PFG9#+i=f_^!lgGkl!~W1UV+xun&;LtX z>kW3oF%K%EcjEuya}B{c>joJkQlJ2*54h(SGr=Af)#~f=`$H=yX4td>jlxiTd}anx zfYP%BVztu$tCR&9dE*{EGUhipb)rxYepIsDuJEo`q1Q}1c{?V118O$|lxK)XJnbrYT?6PxXc7F+a5& zwl77sx|;tyPc(wO$eDzA&=|=QuB*fAt>=jh-UbdU%Erk!GwtbU-+{`I@eVWfLj-b= zduz=n6QLw7)CkN1^6`GkwidA>;5wQ3eEtV2P5MWpClTaORb@lRIP@}O+a%Qc_oXJj z?KVgwhHV-E^Kh3crPmrl%2Q;6OLN!D3{q_>LyL7$HFWLS{eg}($IVGbx9HiD(AGwP z^{Df3?&7IAR3U|}qW0a#tlwOyiGzUk{Sw&9vSJT#qw1|5H?{<}DvvrLhOZFEGci@NjeZradId{}c8$)7Y#*zWp_0CguX2h9z z*gtRUMG?-^gyP%Nj$7n5QV@L|-5yzkf1PF4nAFtMfToL*QX8PS;=NgF(;vdI105=^ zfg%^0%D^+JZH%(g0K$C#=zK7^*1|$?7s8m?%DM~^eDm?h6ht?NFd1f=EWNa9%od#$ zM=kuu&z{yUr6f1Pe(2@v@-RG<>9_|4##^a}NI;*0JlzMm%yh=efM>~LHf#sNF27WM0vsiLDn z>)shT58R>Xc*$Tgb3h4iE_Q!8PGK+rLCBlQBOY_q2#6dvR8Szh3zgo4zUovXl4qm+ z9-*@cTfArYYf5n*JUd9P6Y^o8!$2*YIJ?fE;km^GjIatkjdBjDi^S@sHe2T;%Mf9F zrHw!w#vqa$(yWT-n?QpIZ5}o<=#^XK%2Nbi`zV|ziDKV^l>_s< z=jdg_9!mlohs>JKWZKfz1H6RbLATRAF`?8(?WJv>{T@X#{S9uiHth219(=#0&T}9+Ez>YIt%N?e32Dg$q0Ky78vyGAv zw!Ve|v;qr^V=PSTkB_QY`JB9Z^k+mWnkJ+Y*N&_sv*KY_iuf*x1HVLFcr8sSW7NU3 zoPc07zd!Ki$}_ba>A-L}af^%N+N3IT=77S>`$M;;;D%9=g{BQ2(5!1@NrvFS-q709 zC%NDx0hA87l{?ne*A)#s^Q=}fg~{r;m0tDb2EtJm1hQv>`MNLgpK3AErdcnDi5YxhXC=?!wxLyP2CC8XD%pfrZwHIT`_E~ z*j(I4I#@REVzzExXVFJlZFOTs2lR%$!gM@(4sT;GYS^&1)H=6LwLf_C?`Z(SS@m6+ zhbz<5eMSe^MEdva#3Y1iLUb6-q1$j@jh$UydVEak*=4Tot?o8c^lQ7#$xA?z7{;@V zTInzX<4*7@cTzC>zWAiHrRP{4(!}=Adj*!~oXXo@Ulb=xO(qb-`Neezxw+PAEGo5W zW<+Fq-7KpF1B~1}D0BAP^OUyWdEm)c4qJfBCxb%1!bTX}d1*|SFizpm6EV= zS*mlb3;6K*30#Y!wNZ6lF0ndm?c6LhZs?e7caxuWFPqkLgNPw4?IfswKL3I?qTh~_ ze;Tva!49W>bCkh@Wnw{^8V$<3ZDA9#Uc0fS4q_I4Dgv$hSc^>a!M5NaAXf(XwZJjk*v#&48+)J&aK*#$L%ts9Q?pqW)Utts4^pWw={75fuO+ z8FBd!2InZwue5oy7Sb^)CsSM-tQ96)_w}HWAKR|LVF`eiziT@v9lO?w*USHC@{cm5 zenJvQ`C~W8s?JeiLvHy|nE9y{5KDFN$!Oqcy@O-wJHbM+;Poa+*7+lgB(E#=;hafD zvHnSTSu{^M+0vH9-y4ft*A8H}=i;ZaHGKVgA*03pO-MjiW6Q97^Oo-+VYV>IYA^k9d$zB*Ev&|NF8c?s~48EvYi^t{FJeOP74>ZCVI% z&RJ&)KvPDdK|Am0)4;|vZsxP=UXt|G@zrpddcX#v<8z~=NR*Wmju58URC?$`#+NZO ztKhZKAOCEy0vu*1K7PaopPIn0RZoa7dIFJEynW%wYRyWfTz-#^{bInsprl6HbHCF* z?L2ZX;-(Jr`9}Yx5}ggF)_IkQ6G{b>W25Q4>V$kbf_u{k#l_ft$)p!r@pSY4?5oy{ z7dM^Vy3*{*)v{XII-CDPWAes zgrWLL56(stJTJB@Ts2Q*R=w@76jIb#>eEYV={s)U7EV60Y6Ru#@(hRYQ&;HHMD$?I z&u`~l3Y=iY>U^@B8wG15OX@c!pH}US=^?&btKY-2>)kojcks_#J+0(R1xMwDgx zn3CFN3PrGFv-gnV<;1w-+3?SmOeSD}#Y`4&Bg%oFbrh(m%N-AY)MTr-x| zI>KF#&_NJg%l!oJzkg_qOj2Ww8ZT+`2(MQ{9WeUX?Z($OP@oBHfqie@zkA(vNv&JA zb%&|0z$_-YJ(Cq?<8{U|HCgM2^l*Tg+cH2To;%w1cZaaQ(dx9g`d8>n3R6el7Lk8E zQ`4EYk-+;pE$->Mk)MV-lv))XWWeYltSTqsW+iRB^Iq)qeoSpK1)f^==HdWG{vIN~ zNz`1t`6%LKC`>Fd0OZjgaDP@J;Sa$lEX|)9FvdCxe2(GrkhxKA6{w%8e0I%OMXf=t zhVA^^Yt$J)zytj$Ua1fz3LZ5HZk7*hiV$^Rx4+;QUpIg_P?@LA$(mrs&D;XRYI8h5 z&x&_3Q((g6ywOUCzylH_Q(|PpeqSz663reOoZKFJ_4!*FxBN6vMG=Z!txGgHy$e_) zc9x%JG2oA!-uc!NPKdP7jRv{HNw3_)_~8nNhGLu$Go3JB8~+%_`ab|YK*GOps76So zZAHGUnoJfU60kjoZ463=<7W$0<6=#FqDaqH48$nml!Z-{!k7g|pAu6!0a2ZK!VDX! zg;%XRRbDJ`#*$o&>oJ7Sq2R~663CSFPAT#&>6=w#kq3|QTp<-upPR*YSUIVMN?i4J zh(onEo~5r*L~8u6nFCiMc@b(p>lz$TBXW(hDW*ErDX-eVYBH(G$Sa8-64Q|6#WPgS zt!JX2wv+Dv%5>+!D_09w(TaE2N_G`G0RMc8KXp3Oh^PKh_cSx_j0k@@OZ8=Leb&#bA7Aeii~ zfl~Lu40As6uRg1Uw^r5jW$vJF{t$3&B|%D*Bowl;{~|pF3e;7isF3MZEYaAiWC*5b z@@oGztqQ`LO8!_c+Nn~w;LX`nk{`ZwYO(-D31tmCD^}vQ|-Uqvl?~6S7e~a zkkdN77}yD`;R@~&bu z@P$ZvQVhS*g+qZ8C~N?xEg;6BbYxUhAx@^`o{!8*GY;Q7z8|TcXM(9^7Fu2)&Xr&} z2$`Dxc7G#xPv@&Ah{p+=E9OsUWeaYxu{qqC=+;9@6-9v%`|%Z5xe`+3Z0c)D1pH~a z(vpr#^2*`S#TZ^nFEVyl-^?d!Hbj`a&zC8rsVN5?K_(6!=t6DJ+h5V1u|!ca zs;9-EHl%2&9`rL@u}1g0{0{CGb;6|Fb1r^e<_M7NvrUhP6G{DxgzlYeYQfjfLz`Hw z4>b*X#PUP3J{H+xMuK@6IgLQ|kPCQ%^O-qbwlR9HO)lZIw?#)<_-u;q5ET0Ejjp#y zf(ToVq!MRR7^kU4n`~%2qKU8`yE*5Kym&{JM^j^KO`S*W4!IcE-2)MpM~<*V-XqUM zw&xSB5-Y)U?FRPTfYWXU`7JB1S|?w0pNPXSNpJTrHbp(cR5; zG_i^&y(?2Iy%OJJ7%J!4l9cf9#~rJABl{yQmQ{FIlaS^S=?t6WEBd9Er-mw;&qv-j zOxb!k`x^9(1+_<>k-k(X&|sAE_|~BQd}P$rkl`z)lz4SS@@X%ljy%&iJySw2Q?ZcW zn=e1w6*&AZ_ql8KT^ERx67^ojC=%uOo30`4|?#gt*PP@OPa;XM8;>C4puS>KXlx+Y|OQa-lNJ`aa1vDkO#kW-Zy z-~)^1*P6pzWrQ__`UnBH26p8MWK zF=(kw)5P+FAoqVfO{(W|+gv5sT#C{;ObKP(9Q)jhg~VMTwF@8_+|E_ehgqWza~Mq^ zOE?IhiO{^N5TKi0VF`kLc6^)Hiz|q`iZ^8zD&5sJZGpT3Iz#MA>MjA4QTX*IA-WPJ zN6)8~LJr+IX4RH^m4mpuPGL&*JLK^FyRK~UlZevkSIr5$hXM`6d>$5z$H=;kMQhjbf zv@NP^_1?_kt_Z-Kp#IL}YLP=Li&_Ku>b)nUH`hww9m%YL@$2&yB!ULDa$*5W#4)Y` z{`p>WPE+0(_vsK^(_ba%j^ps7^KnV||S!+&+Jst39c?GdOK~@>v)cgssPSUaZc3BEiBwjKIdpH*l8m_Wi zmgAmtFlYa4KoJV0_lDioPu&pHZ=Q0fm@l_)(I9AKyMCL12)*=HFWpVXQtq0tq=tmC#jeiqD%l+L!VcNk^cs61 z`=%}weiYeQO^35Nt0_hb7R;B+&iwFq5OGe%GaAGesA))FESnV}w?Zj))L!V}3I5v= za^=l=0o-6N31^f4hp+d5iX!R4h8tLAR}|NT5(EQ5iAv7kx`1Q}l9S|&l7`H<23A0j z83D;CQ3)eiGA3XMf<(y(LynR&e|7h;@9y_~=l6JyNKfCob;EO?TV2z&^ofPtxIBtp z!gESk&AHMe!qE9Dycj!Q-gr_cwR$J*TdQ;VoK8V|jOcxH#I6E<@qnT~J*6-<{4k^} zcHJsE(wlT*=6Io+Rm{=zu|@%SoWJ6ayhbXv1}%1_KjrnI*6%eBK%f0g5x`5- zR!i7QbFv?;Lbzj>b91_TN_kKquE_R3I&|G0M`oGmqKhg;p&-{6)%4!GX$;QrYVb z$f`DX`5_t{;7|fSh1`&y>;AHgVu>>mpjeDd;MATYAdKDBCYDR2OA|>+?$fO5w)TOW z%AoM-TFcJNcj_ijBYI z?>6S3fuaUydjJ_#3}?1t_PaMFqLEwSx-_sr=l$~wXztUU)n7aqfA^BVj~28J*#JC* z#Lim@Z^#Juannl(mrlOEltnNZ(vSDCkBK%}!cbfV$ z7byukS5SbA>UW-*I@k*^sK^ls`0^M?XT5h9z${2KrdI^4oARAfjW7d=rNe(+YLSX& za#OKtmwq=(=O*3xdSKM(suz;Wq15o#e$5`EsAV=4?`aSd!WTsasV+q7;%+>|Nv&NGuxrbAO7FK# zxg@ji9RVuq<*-`}J6C>*BAPci`p)JlsH$1*?QFt>Gs>g`is6y&Vd&9mNvbD(pbl{? zc-H=1+I{*B080&8h{b0j!E&JzA8n$E&i_}L4=|B7Bl_=eTgivLpn{rba?5dZ#mZmB zGMZ$P(hF0I`}6Bv0<=g!g7E(9kyp8MBo-V63qR3HoX#Rt`KYQ*^w=aB_m4jENM98n z#*$)eaCZT-w7VQ0&fM1kAcP6p>)|43A94DJzPfQWw8?oO8AUmfWI7Jo7g{J=&(JZ# z$WuRmBC!$kx@iCty*ap!tKPel{x0>a1m9GLUBoLI-uD+yv8!a3zVX{^G*zn(*rhvP zF;{HabZ$mv22_6znN3B0uXp(Gdp%7titF=gR#Y3h#Y57Y%Sj;}lZW8_UD#f9ZMB92 zUQ~(q%V&aY#df#YKtTX0+gKtNIQyOdQxL~!E%7wAE9DAEJ9XaoX4+l)Ht%KWMjxGu zZ#evpb!|wdbSnK4s9H2IB)lG@* zH^}ToxG$Lab>&KGUz<+l-d;m zr{3pQRSCjQID&speL)LdDG5gsNQ&Trihd}YDkTPpi>+$Q6{{~byKv@HaECPVD(@}J z7_*&+5zCdlqMDbH#9OfZl~`z(4<(m*OuyJ!3?k;$(b?&Jb=YW5Ofd4Xi_u8IVFrQN zP8+-`E`(QUYaOHc759E`i$93z5;fMUv-NrZy_>F!9}+RJ5!h2u&%NH;Tj!UUf4MW~ z0%UuxOh+2ID(3I5HC7W{YePwY(KPIA)J5(e1}*g0TZa15Dk0i?d+uAKhoM7u zM7+0k#95Pbky>g`fh~FLLEp`hcq?G#vRpA+k=YH`jUS*Ysoq_iO$BUnEZX=wVwRI+ zvyAMndiiLI|dL#w~n=R1?5;I_9Z<@)0>Fb61?NuC9-DXn>c^^?1=bp`B|WbI&YhXdkqLh0J}< zalp!80_}oOx*Csw`Jb+xcOoa$AX{24LVUcRt81^FoQ|O?v+@ifkf&fKm$7T0JE%u20GPch%}kfSn;!V$#lR4uNu5Ftt-c_ zrgHe062s2RLs)jt;RgVJK>{S#7jqB#@`=q}lM}{{!_Pje_sh95U~4pfQP+oum>yWK z(jAYk2I!NcrO#fy=h0T`28>`e-fXznH``xYzuJA)d*rEQ4L0=(>1fSTk9mmFjp6jT zV83~{M7^j^ktz-AX>Bn`Fa!QVTctKqJoT*Q^tT3)y;TEStAs`-|3W4xlf}>}(&*le z{1$0d-P7j)nfv<$aUsz3Y70dTZo2iN*zO9v-=-}$K{Bcipx$_93JH35snAZ#d%wN9 zni8%S?>bOAFx_d4iR{4)2@-!3f^Iu(t*d{Pk=fjth;v>Z!>j8kIR$P!)MSMA4dR4} z)w_nSU&V+%Ggm3O35xgz$7=tj@W6UXGdX?GzU*z|bB(3KVOuDt-9Wz7;bGgB%1?Fp zN+K0vu?^XVkISD%EPkf4< zt%SGb-abn<3lVU$ng>(@R>9oR@J*MB2qs_0wk+Kk-vyqySSB(DRfR<`Gj>OBz5qh{d- zfgTxB47DyTq=4SCYUxZGod3h8t|A!T5hBpS?Y7qA3Srsu8aRn1Rgv)lJ`tU|F1>w; z*IqS=O|XjeCwClfWe^f%r8=ywX3^&;5VsZgsnG6bTT0!T81XxFQ0MELL8J%NfR{?H z!$S9QNaralg*CtT^Z1gXfW!2D|F4a6VknIuEJy(8v?flJgRa0%R@fd!YEe&{Q z4Zw}VnTL$ab=1sfhD;wg$-Q6g;-_YQiL4FUuRUa89okNufM3gRmWKw3LDu?^x@Yg3 zCW~+)B^0Y!?nxA>iip2odtcvojw^0w%@m9aoJt5x@LPOPLGkw6gmkpu{xMy>vD?Rl`?8n52Yx;w*IOJ}7tHU!Wj)nyqr|R?J0zPk`Te^0 zY@Q`v6-yse(@#@m#~pxaq$ zVr*gyk{O7m`^pH5NEV6_FH!*m_PI1tLI!_mumZBNGpRtVWfW<7(!9Bh|CZ9YQy0jp zE_u-nJHFV{!k&>31z@w?(x5FZI*MLgn-(hCW1c!5c#Br@HUhG@(8jmbr(!=Kzg^9W z*;j=QYHiao5fl6QnN-*=ZZPpQUcYq# zXCu(%v(ih6$4KbTL&{m01^PY2?H zXUkn&yN!ud$4_szMW60@`$1wMRAqk;l>D4#sdd(g_|dmBuu$}6683}VF)w-o_boqA zf*35C=@%1Q?|%@Kui7k;eGpdcKU0{t|$A7`{*d&Tv{Gy+n&`L zpD(wfK%fTnd_)sp?>)fQvEu27(Qh}Jc)f!C33Dv00VwovZZ3aqE`M6Ujo;r);y-Kj z95k9^Zdjk9E(7BAI@X&(>~W6fr~HM)*S_;tZ#)JdTd>-#&K$Ti;5V)1K!ZGv!=w3= zvo-t>lzD!@gef8WJJkWi@PHTYbGprRbrIMUyj;V*MP z6LH?t?90|C3UzCnC`fLm?mXyva|I{0u2Qu-XSu)Y6h-iiHr5&cdt(SGyYl10wPT#z^j02toEOU4|TW=cAcC^&*72o-5?MU;fH(x?{fd zff@{<(C3JU*HJy^Ea3q6_!CXfsHPbF?0butIu;Px6fdz+cR9EhW0#_0)B>&^6IjwZcCM6_9sslpYiyMO?75- zq7gLWOSOzZEauoTqA`Z8eD*bxn;w6lO6wQ}`p4X)ji7=$vYrVmsmVx*ZA}88D>Pr& z2DNx+DVpff&E`_=#DhKKGFJqz$EJiSd4B(3y>76!HDk54rfT8^fs08_2b7bL0f4ei5^9dE@6bFEdK<-P^?_AUYVelH7thp1I3 zRvoad`Em{grii0VdX|xQEH!7Wn{IjbWUGoz|5lDktMRPASZ6g?L^yqm z%g3dBf6r>Z%8(A?9^@%u-Q7Y~L1nqn)s5S8K;I_5z^l}d+0WuWUa{?2Pyh^^+a~}~ zAMbSlu!~n4b`{);!#>OK3M^1*$_&VkQ8?1oL>8jLa_?W{LijgFNb{1#8R0U7Ep$1LqG zaBMFOEiuZP`b?#m_uV{xwU~m~Wf-V!Hq+lDzuGnb@HmbFls2C%c$rGqIFc#geK*V} zT9wE$QvjQR_iw=c4;0nB)~BoFM9p;je4On5S_wa>;{C45uImGle^Iq=6#>#MDZW^v z^uTGk*-3?P)@?#3*by)!AY6PV8!x%LQoh-d(M1OvxlkI7^v=m38E&_&DOVugv?Vc8 z)37=~E|_!bc~g80C_-bYiH0t!gI=G+Z#cB&SpY*R0$>Z+MsVVhrp@?Q)vBdP{*wMn zG(f$JL9E>-S--%WlyaV<#x9~4$yG^`CRTWZ3B-Q&?7IUdz^o^gR?MpZ{+c%_Lg~kk z;y%z4W`J5cl7eI|r6_EcQ!7wGX{PxW1&=KkE~I^L{& z_&D$K_7F&?bhnYGM7C(JZ%9CrnOD*KsdRqo^Q<7=zf5=Wz&#a+x_M1Q9Jdktd~LgY%jwpp2qO1w zW7!NlTu?`z`es{U$PaMd0oqbempVQ+8H?lx z1jW1m7wj3U?Kyn)UJ-y~xGTXjp!B3wlaBiquy)g@%2Sum)#Wp{l}{`M!bpBgeXtezZ?rh;x8_7*B0KBn~KxOy3ekffUGQlT;4 zW5e~Ocp`Coviqu5e7^GXWb4Hq_jZz7l5%l>zNSH+eU@b-Pl)^E1r~$ao5v&JEo|FP zAS(E~46eXB^zu}FNUPF846l@I8pi3|>YE1T0<9OoqhR=h!4894as8EAb?l?El! zbvDl`x5@x8l#CEQwI{Tz0mwE5lor+m=ij>vtY$S|ZAu5p`r8gkgX-O2=VV;=-O|8; zGp)E1$68=L5K-#JHR?9bx=?Mpxd3#J5s=vuu!>Ph+9Q@!n%x*%!>7J_rO9g;?>WcG zRv5T;_r~0(AwqxcpdzlQiy`i#sfZr0OXaF<)y^1m>4LOAbi1-k?=nankgydSRR7yG z@a}ae!yW65djQ&3Gp^uv*OUQA1tif?@KC08i=ygm5~4Fr0I)h@t3F9w~q>sDiiI!R#?4M!OYEjhR;WreN;ljh6u#-18z zPJFunugqYri|^e9_5$4yqzK3yQA2@^(Zy&yyP%HZ+nSyum=i1zvNJs~BtK1LZx4adTMTj~C z70rx<;9uRWOhOxs%X90h#H8Uc>eK-N^Rd zG7qj_C|iGN;4dBi3x33~JWiy-cBL4XTaJ7tEhnuH!neMCiPliJm)9=?5NxQ}ddm$o z`XihfUWx*JFeq&}>YDs2T`ADQS=823V!P~Wu%su9D0+~|n_$o>wJUC$W1yJW+A}&n zXA1ONS|xDIiIJg z*g+sfy#pya{DJrz2Wy|B#VF_PA!eV0l3jg7LGPlGg40s>h=A*UCO=t) zw7`9SKsT9S#>C*jYPxHm_Puz(Q#hY8r%#zL5@b55Y8&(==fzp^9Kf~{$a`G0BhUqN z!3Q(BT9#B$ro4bPYqV+N%4CH5l%{n@CVzYSu@gsIr$gzrtoxkK^gzQm_cs(=zlyoS zq0BjoJmSWV30cVJk40IT1R8_ZxyTG4*4{3>VWD!(Rf+0$-=J4Y)BQR&kpa*fY}jz+ zypUX0St@Pu9)Q{EosZ~?W*cW_3%~%7JuzO4`0_e&(3iu|#dsX2+@O+F6=Q~tbsO-o zD(+Q^I0i|7t?(xPeFD{Cgsj7LfCuvfTyd9xRgAN;aUcrd@4)1i)7jlqy_FnX3HVpM zmw6rN9k@XkQD}z`Wl3@@ifl(>kxXp3!*|#DmNR6C6i~8I52!>STwhw?<_Da-4!v!B zdEH7)^1Am7k3Lj`+iK9oUAL$xriPV3bNXHO-eM5QS#A&sUD*oZ@Nxkmz{9A^xFkas zOSe1{VihJMUApTD?r-A^CcO&6nN%VRb;)T%>0GD=506XV0_i8`o{Jek%F34 zfjMTjIuP!{DYMTlPjJBbed02%r(lc%YMc%+RdKGogYZlPG$(8FMM23L+OGluF|7gW z(W@XGHAlC6s@8aBujD3?st6?5ldtZK@ez5;y^g`2;JJl}Ftgj;U9b|zs987T4neY& zaHl6JDmI;I*{b7Vj;At$L4q=TQr<>R8VZgR|$^w{!tGJm>OO{`-3zguX{1y zQpSKT3IN-r)^3GK@{4T@U&&6#|TiRtyQl4>9_n8(mhh^FX+VuW3GXwyfxluRS6{9tyeAZ z%{({IxhV4JJztsB7$SNL>uHM=Xl(ElRKeNBu_{=(${p93c6IgKs@}(1keOWR z=6GsgAd=s<6liiOPlF)zTaE+qX4d0A`Fv#|=_qsjY`IIs+ME^Ts$*~AML-a^miF^7 zgc~~D>*woasD&7^^Nl*>ZwfMu7SX3z;N(wbY2e)*-T771+oh-Q<2SaG+o@wniZ;D( zVp3x)W2epuu(S7ieb|B)NBV8RNFTplO(xc zft;}rdfftvjEDNwRit<~oRn`NFsQp~LM*T?TrqaOn0B~!XvE5PM&kN0rv9J1zP$pW zfdeFjEB6`_8rLmRHLe9Ni?Csaa=`B_X1-hC8~F&w`>K9E6KLyN%fE8_y4ysQ--0i& zfdM3YxojlZa!?W({M^l2#HG}L3lYy&-44V_1I40K!jyQ+xl7l2NrXL4u~luB_mAc8 zDDk^l6RY=q^KB!Tq1MUq7Iogz&)W{Ll*?o(@at?O_ukV21dXEMy#*B5dOuf?l#@1I zP;zbl@L}BcJlE!rg;FY)U$74bBRr%^LJP~tbB8zvK1KyL$X58V&&*plbtDvbUII6?lTONzQ7tQ50cf?oR)Q~I5Vro0nCcBVqRd_j zn2UCIgaUiC5zffpW7p%y<06%p$uviGZEWB@tks*U{;h{0?V(4%DJm$qcIh96N%*yf zP=taHx=ef}H3=veJAR{tu;bS~>|MW{Ax7%5gL>pT{YE;I=H~Ul0Ak=iW~qj1)nO2D zht2J3b?4GAzLv0Etx&rztP}PPTz6N+;qTym6`M%NLSCJhS7%STP~v98Zy~>XvM>0I z4)mQ>h&6oyf=)AR_4Rv2P1#0;5)+1@l@l$=pO&6If+bIaaJJC_gtWx%e| z`napeQW0JQZF(88vOYrr<%}fli*5F_AQSmVPM^%qO=7di4E&5HPMD{3X9<1`1FCb3 z^Z>PwUBE8rR2-{!tnw|Nf*1)7li=-n|1-3(sFE8tYA7ul@g+INhOYCaL_-%lAa%hL z{Ad-;X1eFPJ5wiZ-7oKU?%b_Juh*otK6tIcbH3vj$Y3BmFy3#yd~gA<)tW2UksS8w z8`?D{CSa!F*mK*OA_4@CHi0)`xc1sf&ng#X8{C0ko3g*7z7!-gNdZ+@Y^|gg6hx(j zwZWuU{sEGRvYPuBMs1|=M``VWIyXIP>50)*Am;slh7iRjIy4JhQa)7dxDp329GL!y zY=bmvXz|DV`^%es)vHhF{v`(o5|{0`H2h`N&_`Fbrc;Xf0`jEqm2Zp~NN;HvpYzSq ziIiNF1-@4FEoX*mUX@P1w)|<1X5t~#*UC{ZjQsA8bSuJGz~rI5OZ6dX-w&{ZPSd2V z7ssgu#Oe3~Y--lplzkv5XyQ!o(auM!IhgxvQ+K_5PV&ZvPU z$U$8up<*qT7pnOlCwd)(o{WIU^g8?{R&2ywB(Do|`TSm4exN)LZ~ak;!Nms#_<#2t z^d{=tz;8z5_xIruk|=pnbl-ybT8{Yf@oG1YO);>V7m~Hu0Kl~nI1~r(^geeHRm{PM z6amUcCx{z^51*f|YV`FH3R(iT!;zOl=V>bC2l&I^sBee_;#Rw(ctBP@bJ$w3+}$z= z6a53Gtmi1mbEIcd;jMUQx#P%2V)x;yiTCtRhYQFz_&S5-38PVeP_V4`MqwsTU1SqZF8e; zhJaUBgFV`A>`)5ucdBJx18y+9Fmq<1Gap5?V^4GyV&T_hlualkq}5O z+L_0&bsMFC`CSWOS5xWjUE3F*e-CrX(QrbbtxsF(*5miZ#artMlAEo2%zY)@gbb%X zoxn^5Q`6m@Hz_t*d%>j^OW43_Bm-2SIBS-YkHgX=gU+kpEL;R zdTF2Lr3bI#wo)brR*_ovjnI=eXop7N*93Pyg5`f2MVM+U!``TjAadEv%ehPu9_id+ zyO7zP0?d6%tV1X%F1#ZNJKXz#$TZaiP{Eqo4TMUT-GdB{*-s!o^$)p z5dAs?Ua|ch%X_zJkb#~o>@4FWxg7q0?`TEOniVWz*{MNK_r*pmf21Me*b*B47z`X(o%#Q@$&do;W`MKews*9jzqIQ$^i$ z6D8H16zB-ueQ}aI_fEj5{G=8gKuuN$nhU_9xX&H_^+ohl zV_V)d)`SS{_yYTP?P?s-s7S_*NR#+PXyzf z?~yeF%f0tIs^RMDs&Nc(6#9vu*RMVA$0X7I`vbevx^DSy8Dys>(F?%ZU>{~ij^v9$ z@Np9l9}+X9@8kzml1-Ilz@uL+Ewp@80swabOIHG1dPzZjB$j&HRUx@=UP1#Y=(NN2|UIY6ug#K@%;jP{7R6>uQy4LC? zE`k3NB4q`iWwZ7P)iIsXr2`oNTPtYs1Yv|MMVgWj{8Q#jjwJ5V9al6kZB^PcI2eUH zG_znpgci_qzi&&4^e3Zl(0}FtQ0}L>I()nib{%CdZ_~=lNf8QYG$iLqZ6qV?R~mIg zQNNc(zDpA71;OI&`F8k+!3>>X<#G7B+-zU8N|Fh1FX{!ssykUYx0amWkVn#F8~vP2 zA=^m1j_NpaaQOmCvbF070cogioj->kA`U1&aKJN{_H>+j06z#MB(6YHJM6w zc##Y}q)qz^Ae?~{e9uHEwRxIO&CehZq?eg!tsj^C3} z=XWk|4{^kaoV^H-k6Qh&IF~Ne>h_>>V)p(M#*e>IM42ph=JB4rjv75Pmzo9f4>}{k zGD8>DwYhdQu%~^Nh?d>F$mUIN)S{!DY@4eD57gYfYqN^u&0H|rwN8`OUhU9gbLd8q zUv{-Q{tYaOhpe`d$WS(FujU_^YUSWjSZ1Lx3i#LIq}pESM#mm+?TpOUyW0%3l2t~z z6hnI`y<5I-3E7?DF#<43B&VT3_-tye4@HgSQY4RCN60D_I2#j}TV_y|+`Q*YQ!^$M z5T)OeKjGHrqv%@ZTgU5U9>almfMX+ZVnPGiONze26uY&Wig{8GPY_fGLHfi+&4iyb;zKZo%g7Pgbyhya}!l*eJAR6$~5N(?L~>9RgGf5K|iXF;^Cv zAPhHM7BKw2#bl#ZKX^cTlOg^XR;d$(yJtVXO1Lx(R+7atj5oI<;w@0|Px_qO(NO9_ zn4c`o+el61+`!uISRpo>gfw*UoU|-1v9T8jz7&#?{wJo}7_H&0KFom#Rv82%6TY@L zU#fuKXwXvOjm%clKJD}w^5!>WR%oR;XDVQAi#pU{dOlZX z1zDncgo>^Lh9ryb?k`0|^P`6RSzsPBrIJS zEf}>eQtJof^%e5~%8ta(5wh4kM}1l`!zg$Ip@MQ0?j3n3&4%^amr7y=gp z_^RXGJXh|eJI;FI=T|~Y)hM&!Q zch$gNhzFjRI12wMF7rk=(Q|X)l`ch_jEoK-vh@XO%Wvz8pU?=ed1XKz98KwKWrwNp z3M?ougJ?THK1SSga9@$x4Pq1z**~w4*(58XNR~2_SBH`p>?^%u?w)c47GlH5Vy&Co zP?tY3Z%MS=T)G4!RWr)<&Pf>-zbGt0u@1UfWcC2b;q$1mS3s+J`gj<^@vs*S-`}SC zmt3EJd7$wqLb zd;h(*UcDdp;x+2rqjl4rL`D}RVcXG!l^@L3C;R2zv7@Y6I^I6;w>?x*R&q`s%&5PV zEcuqLOE)Ytos0w7hiH_1e8?dcfpmhhr%*JN@0#r)i@k;XCiy9<`(=kgNpfbSX6r>9 zrG+b?tQJ`rwZOo9+Xyt_u4#JCt90d{Rr4r$Hp?sRY};#7sQoY7_3$I9bp%bVdheb4 z2eNrgbK&7s(ca;l7`jpcU0X6jBZ#cc=xX-@XqOKr==EuMX2D$)hwqfF(X4%X@27p3$cNmyt z$Iy`eB!bCBZ@U(Y$g!nFM_QEHdw+02CkGBdY(o~gzC5wnTEXS=9!Tu4S2Q){!L!5c zP}T}%pGR9_g~;UWTCb9#iQl*O8E`pM5Y@>m(d!R1M9$G<>Da*vk=ep0fxs&AxO9j@ znW6``pvZ;XqU-RlTY?rMb(Mr2(Y64p{R=^8?RX?t?rkIn7?5w{iW6qr-9^laHvBa| zeAo2J=FEP9%huO|o5*A``S`Ss0yn(OWKg083*l@;yelf%SHh8{LyigyyEy~I-rR_y z!;6yJj>H-)IjEvg|9>RQT%IjBkSXxr3;!F8eBq$zzUnF9uyf$*sWe1;*>j-Kb@JQc z-~qJ5&~ntuW8#SNRcJJ=pj~SgwlynixXJOBZdB9S#xf6hklTvr^jqo4>Aj&}jxZHY zA{xE1nz)HXa`~$bLGAehMI*t41OPGQ`1QIE7kz9niuq5hKTwjbDe2(}(_&dRbcCA) zwh?5fCKfv?Zf(OnHQ5!N`YSYpK}GKF(MKZM9=&k0#Kkn%Uovl&+A_IMC$(yf8sNmQN5}nB&aUQPO~Q7k!@~ zfiEt`J)q!0=T?#6t_gUgDqIfVenv>-a4Yve_J20gsf!mG>Hzm*mB_j_qcsLzAH2fW zQ~2grI8!1~NC>k2c8Pr8TLkDF;9o_eoS%uo0*lViocUcY=%}h;!0V1*l8>O35a%HTusj4ld-t zVNk_jG=q_VdxGj<=28`ttxqO`g0Ypp_`yLIgb3atODzVB?jQ?V|1K-9=777cJ19yq z>7j)NT*?$iIwEWX3dyvNo33PYXn0_dG`Av496#_7FG6B7e@FA}(=l3hE?u;-fu13a z0rm)Lci;aFXT%) z1hid*-kLSi{pX6fIGKuYdhL4r=L-5{21;f?@$=XJzh4hO^qjqA;w^_(9I{57ACX|% zNDd3bX}TYbGAHz}QHCG>GydCqC! z6i2qRVy_HgF=zoCuKb^>XiAXj_PWm$8(CEpaWWzD4PCjNWUG%CbtAa)0|l~$BIg7& zG;Ry|`y;$@kt}R_wu5|+^|t4+f6Y$9#J{N9#S=*t*+ZMF@IDMqbUDDQuFM0E9deOYJ*Ypdo&RjlgpoRS=6hWpwvn;ckMW7DBXauvU=k;aM^ z&(>CS#$`edQ5yOX?fY=5aR;G>R`Czy zp`RQh7l2N*;~Nfp0X@mh$e2)&l9C#lnVJGbudjV*C@Db#1D|=_lV_peIoBIm>APMv zvAwdsKJncmy!p{@r(9RQDcFpBeyWHoF8;z!XgJslP~2f(v>VWOy^ab0^b|*WP7WYs zs#`6Jcy|B&`pdg6fIEc#^^8&IzuLh)S50}v)^t`SU*$?0X?3O>ey#n~^t6($uCB1- z_vbl=CFvO%91kBp99?U{%;wcux1}nwcoh{DrGYW(SORwf_P09TXbCv=7WOL0Y-z~U z!x^m_tDSEVbYSXe<0#2ZOQd2lM4nPF%y#N4PN;I9YWtd|9Bn<;5a~UY7M*Y19J{i* zDzqZAo@-p5@6es=j=`{e#qgctP-`l*Yv%_e#NYe)n@f2A-iC+F&|cu|fbYGo)r9@s z^~lS={z`F?mG##ftVUBug!Mwq49_@f+~zX-BK$^5Wp2LkX5XCqoYcCMO#i@F^)4p~ zaSu<2a;J=<0Chl$zfMznk24(xj@>$$3aQLT8WdkVyySZF7Yo{MYpt&s$%&sQ=>XWt?PWWtE0G2SN2~)VB^+X`fR#!xp_T7TR;=NJ2uw&kikhw!ocH z7K^F2v^>Y2e7zE9V~yhPPL)X^UHa@ZJJ@5BlAIQ7+{e{z)mB+&l4`($foR#wRL^mHbH5Dxy?C723> zDg5@95~|rQJivkHhX~b31NO$cN&bdGb%6g;3d`=5fXznJS{moyuN;}1o6ECnPyY@A z$#mPUIWjVm*!t?G#rJo2HMF!&eR^^%h_gE zF9e=7d7@dL9y$FeH#b+W!t1{4=rfU8srCL-z~`^;efL?PKMy2OA9ewL)X>#E3k%-b z+JbeDjg2+(_Ab?fAj_c_R~2{WF(`|crE~WfyA%!6ZLBuG_2tz;zvbqQo|b^9otf%A zhisEdgWtpAa5!9MZf+Qm<$Ss1p=oYTj*u4>l)NY;#Fl6Nn3ik=z{+TbT0mWtRiZD5 zFaRD4VcFlPBYJcjpJfzw{QZ&p9(!!#7clekXZ>qKi^6^zi?Dft1L2qex}|m}-%xZM z%0aV&u^&m;_vi4DGp<5Ed4;@#A>l%bjJJeYc98rN+N*Z&ZKVYZ;!)xm>c# zm*lrZ)G#!R%SGtwo9`QoY#> zqAKm&>B#*2{By#NdhtLEb>frbECIuIpZ`8lI#}sTa|o*Ww*HYuG4vdH!PoLjR}Rfc zDxMc10)oJFXLNFnVww^pMCkZTxDQu^e0WHWVSN9LNo;ADg^v+L{x6ZBA`USJh(3LK z3SBG5W`C~`d!5dXEGye-vr|aDsjQUBtz7FR!6!}@78U(Q83+b4w3zA2ffE_yBzo;=Esb-@Ch?T&=7E`lz8{9+LolRJnTG8o~l@@njwLX-Wx~j`jN)Vj7x} z6ku>v^aud^vs}8lp^;p=Rik~%%F1})0ntqo-U7__x+|%kO8v5Y=-(idEJPrz`AVBI zxqL(+T===U4h<9L{Q2|OT?Q*iy$*zDU%#r|7#5wHoee$4DE#@!F-CJDj?Kl_*W24$ z)6{goIHGSaI*9gstkwzW!oz;@NVJQ|bR?K- z_pE9Xu=dNGU)zrLn z5~|75)Q$d}u1Zc#9mx%|&m^K4yw(aU92OI88X#6m!YPkLC@`O(5_JRxTKZl{pP`F~ z1aP05l@%}jAxPBG*!V=H4;%BVGl(31(t35c=mZn05|I*XVLsPeM0{~o%Y1ih)f`f= z9IEpF*(A{NS)fI7xws@UI+}w6q*9-}b4I+YlAxd<$!B$%?E+L|THw?-dQfw&ORvLg z&cUTI&r+O06-5Ltk2jk`QtQ-4yk`M^Qr9}AD1?V;sY?klFfyjRdUa7(L*pWtXYd(C zK_T)AhW=9A(4T%gqi6|>>~E^oSe=mB7ZU@O1P*&3k5dr`pz@~U_jecJsxu$B5gEw_ zhv>Hy1qBNWi+G>uH`Iv$p8fdGLRXjxRc}!a2LGvhcAZh7c{E%mF+Ol_GtZ)q_BvL3 zW^(dxA&0Kdu|f_bgT4!MYsJ$3TddUKeL&6iq3NiZq3UWcNVeFqFa7_J^yTfHEZkIk z2B7z2kEhqlsF-@fGp4!xArqM)Uv1S<}=*{^{)~O72or%Le9yi&w)UT;xVLajN+Nu3$oMK=Le}My4s;-(e&~< zwX;X##4;#(30kxut;x{~{|SR5qrQ=^Iv$ze{ZaYr*w>xkzMaU@C4_Zm>DCQkh6d)G zsHkaGmNxyEb_6|VzXQ}2aHWEL22p+t+}QOVq4}o;tViF?4U~(dt0yr70d!Qu#*RZ( zQc>LcCzYePr`ERicDFe!>cXC-r>BcZpJ@u^+Cv`@P6PS8`|Z)6d0E$1%SCR#sO0_8pnF_V&Sk(t*R?z>T?uh1#Of@FYL^ zsB!RTSd#h ziqfKnywp`y6)UX%M2^{lPQNc-2zx(FIV1v`ij%(JXH~X-0sH1KwamG4%mN+Ng)fJX zF`OQ)3l9e}=4#rhr57K-B~28n*%xxRJ!x1xNe=dWTaC|;&oUr5s#NR9ln>~R==N*@ zUV+*B&!bpMZ5d>(5_Tt9GsZbgNWAXJ~>79N?jIc;9bP11s2)C^;`OT= zXwP0B`WY>8kg;jWOrFjDa>K5BlhB z;_nV0h8_=h>XJJOZcZM!XU2AbXd#qs&zB?g?hj}&*TiQkO|Q^agWI5RvStQA1a5qM ze4{l;`ZUYlV$f))z}I@vcBpehxA4a02W*jZ+35jXQZ_#6{N^P>s9ZDHnH$>6`5mfo zVH9x=ea0wKn}8XlKXHPMjZINHN#>ff#B!5B3IKH7>2JeOGKb7$JDGB1Rv^zeH5*?( z!>rD^1WLe1NB<5nfEf3ex}{`gDIbNxvL+IJ zc@ur-OQ}jq?&#`b7)ufYwx&w?liaDXDW49|jM$8p-i5;xPR{W8M4;dJ18N;DcI-J> zG8Ew3AFw@l;>7)rzj3hIBzWkk#PGAFtHhiHJj5qAHTBOckSG(OGW}p$)KB3<=f1cq z;xcO}KxRLyt*x~LmERnC?(^{Qv0(Uo-uv^V6SbuiiHy&lJrlbF4gYR@U+!c{Klzc5 zWwYtt$%vNiEqFK08`4F+$#K)YG1H?x(3NvA!|!u0=W#BdEB^cM%$yumSQQXkAAR8^}vE^Hu{6Mly*HI0ppjqZIo zblrbzMHCb}H_#TmhHm#uZ+u{l;zKt)K>6ce&R(9Ld4{Aqn}zVDOCw{^rfTxf7|s9- zouR@ufm#)4OClC=LX6c@Nyjtc*Ir_}<^fdNs1>O?aakcurD}U%f!(EQGyMv5x@w^O z7`c*!C@Ft}pSNQL-2@Cz_%1h#z+9%M&<=kNy7#wyIP>|T{k`?kk2HKuZzyCx7?koq z^)opL0crnBYqLLB9T600c9fg#GISBLq{6P-0U`+d{yiYRxE#Y0>D*tTLv};b2j=!! zN0z3w1+2NuhqedT|Aerg+#7jH{*+DvDvrk)yV1!0@CH#y{ybU^#4L(0t!BvVUiDrg zay*8xmlvnA2=ajB!=Xk5@oLs_SoVjl!vR1cyNIzbz#y6;1Mc`=p?fd-eHSVtS|%*^ zb~Y7lY%(rDsY!8UOT_(ekV3bKuTKuq(EUmQDSQJh(kK`w3{FuZ$d&%K!?I=M2RyRE z$Pdq5YaQh#&sJ}I=>@d)2nAGEgJV-3aoHPp8QGd4sN+7TAH%*N*M6)c|3Swd+^Qb1 zbm{~&e6F_~X8iX|^~KmttG03;w;m2dMqOJDM(sOX7AmTLS4Qp|FRb9PrhK zv#?Xx)^v;=ya-za6p&;8%? zfD2o|?u;o71tc|WBeSg^$|%C?z40Sx08G5a;s0UXOCe|Z)J(j`&Rm3&gR)JlrN2sV z&%P9KF=^}UWcwA8syk?BRMB=O{<`6b%`v{ftCY~nJJ9#Sor!tFi>t)(<~U@Kdjjav zswKL#dex>$ht(u-clG`9R|(+v7aN5AErRIoO8aQl_Pl^C)$oSf|KpDNvYA}VmPDyP z0F$p+YT&x=)LXdGRZXWXyQ^FKhzfSY?fhq_u9 z!E_-?7z#Tsa$v0luh(#$NsR?Fv2}0=fjJ61jMUa-%JqPqjrXHr5=VO>(X|7@7Pqz9 zelP@O_3oSt9^^N$@YNEB?%bDRZq{&fJvBM``!86Fx+DRzx&B%D3a&B646so`r~hVE z9C^a%{C9ZZ&L|PEPY{eXdEYwI{#!n6nxgIl1kSVlb_uwoW@is{NiYKpST7%LKH^kMqHLRVw~Nm23}IhFMH0=Nq_Dd4u#=)*_wN1tR( zjxU~3I$onIKr`5p8{;C?^hsMC88|85wO=V~zWw;e!~wgW2*AeD7g)i|UmTQ>WzAoQ zXv{}GKP7@*#pv7Nnh1e|3=#kN`2qa2?YVWWBYm+|V-$(Vk#w38;zu~easSDi_ZKSH z8Guff|4`zF#>+mdZ4{`H8{d5iIjex%Fu_3exbqU8fS8(`1N6WeYU1D@Xc`|!0q(w(bYR_UnQ5D-tX^i z9|Mu%?o6Kh?0qDZ57oTnNeS5B9twdVIrHtcIXHUX|Ey(%KP*Vz1o2!7xhokuS76og z@VGSWhX~jY4Z2k)P4||f@oQ_IH=vFGkFEEB=lbpb$6r(`O;Kc|$S5JoC>fPVW?9K9 zGn?$KZIh8~Q5sgrUJaYT7_<4)sS^)<}R32TvFRwEWNSlkBhix8E4W1SKW{bd`JennRr$ z-N|~d(8(TDVXFKeY|^hgiOZ9qcIJME>F>L5U~UXq$PbN(3sW!kIHrJ^GW*Y|gpRag zFs?{ZT&g7Ou$-OPNt>x2x(j;M?)2-wcjGNlxWMV-85N@QdQ~TZ8TX57YHF7MDi=|^ zZY{Y+TUlH0CH}VM#QW_70W6)gBsoZ6)LggG@pSvSA)SeijB6Oy?KI`s>lJ!IpP2wL z+#Bv}`xvADAd4HnxAJ5?jdwk ze{#aRo%^&zfL)&l%QFn?X^awd?CbO5^rbP&ua7wpLzS}~lBT_nWr&rfr~5~9l`K>B zG?Px=Q<&RzfEvd&S1OgYCcAPZl$AqHVkO1@$t>;Ijh|It1&aEYop6-eiT!rY`}2ZE zt0hsT0(@Qx#(J#uztT_?dtiKY(08zv&bEteIKomU4OCO~fE$CH(m$l@fm@(mKi;rk zkFx9AO9qa85eQVOq91t_f^Oc2JIXKrGozWf_mMjZTSf1193#T`8OB4?tGm zFtAI-^P`RZ;=-%1;Mb4+hm3>o0`ViQlb}k)jk3b*#F)8)wT(@wqO$tYxuIX+Wy=4R z4V1tBiyy_Z?g93rb9dT(;4OGs)yPq37MPsOaTQC8O_chVusn7BKSQH}P4jab5M8^g zr0X$(UX$-Qx$pnU8$Je}xPcnmEw<}FhgE+Pn9OG6$o~CAr!`q!3!}*OB;6KTNs>c2 zka_~5MFgHiy2q~n0MJEy^6~By?tV@KjL4^w^FZ{RqVX@&xt}hK9GS^$=%ZS}rHDO% z4(6KVWlIo~YK7JkfiiFZcB^i$-;-R%eWXzwfj-hFpr?pyWt{-G4hJ$zdqQwu3<7!h zA0o0*Ak+|jN1FhX0g6Ox+nHtNcSb(Gcw?#8td2zP;XgGJc(EU^?0xb8mI53Wk!?@c zmsPW>zmaPG=h{0i=m@Ta)EyRZ1sD$AK~N7R_bOyvxLsBoqrn+akp5%PL0rV- zM7-NcyC4YAs(Q^1$}jjiJ^e!A^mESQrJ^loH2VF2qZ0~!iMaIG%oCK7W)JjZB4p$-_j-R;1xCKebwJ9at1Gnsdc5b-V4`k~!Uzhpy=%|uS&i5U^z11Inj^j$ySBz-HG{;>~DnsNX8ljQ*x;m~|=DOwm-mk!~Znwm=v ze&C@aYrSv~RZ_503{{(*K+?;LZ6{ea*^vb!yD-BtQ38+?WU-4-Zd$QxnCClTcV#7{p(vgr*-K zDz1BbJ*nu=`2#1e@PA57^ahJwiefYfzjL>u+3r(&!1tix1Hte(Y0l5soLGVyQUsY|NdT)uv_r{L!oFt2o@ijnD~T+QUB!q z?Yvz}P82gN1L@s%G z`MJzjs`B!I;U8HqPx0yr+@0zv&|aM%t#4>R;e8c^)q8j6$Hh{mqr|4mTzKzkz~a6v z(N5ewPIJ;MD2sg+;SOiDedZK`G-TR3IB`Wbu8XdF0U5f0JJvMW6RtU_saz2GpFJFE z$*P_Cw7I3FG*KlzHY0;4EIiyt_^~Ospq?uDmf4LdS7B3#(b{q>KQ!V*&JCp`+mgh8 zBvp_U?K-yudnb0|#*L=tW;&{z3D=&swl`yqAN)ip5|;#E4?tVcay+DF6!SiByd&+B zUMJY}S=p_5*%|t+8T$I3p2;927H+mpRAg+rgf&OfkZm#Tz$l)99GGThgIwGI3Ni^A9Ij4T*VV>>G0iOp0CZKOcz4Rw zXe}9+3}MxB+M-ujVC1jpFl9&91}7gc@6att$z2RbeeDFE`u?j0D19?=zrbO^^Y{fl zQ3yMw!g<-z2@W^Kt7`A|Ow;bwW!O}^6WCOKMKthle|0*tEmguKbsl7?@MHNqPfyQ} z2?+w{A9Zf!1JzqU$kIRNPxf7e!BHv*L>a}jQc+jhrJu{~-EpV{r24T9JVHiw~ z*E08n{2@yfVsKJKhih)v(gZdgLEtH(36ueDzJ2>WB%hzzcMt{z&C#okqKn=b*Vi5> zf7KIxDvs2p+GcBGi6vdX);ChX_A;Kx`2FR|F*0(3fVf=&Spm8qyrZbNkoi~@cvf0k zs%BvDNrX1DpXa}5ZLu;KGAwhY{wKf4Yl`_dCiSs5D&B`^P)|%u$Q(hV@f&ZkF$`7U z)`)1uSu_G@ZNBI1*|V|9$&=s8O}6IH*eJKrCrCHN)%o3F;qOuTcqtE1!R&zm$wz~O zg9mq#s(truKjAR)R_AZirx^&V1@Ho&-|kZGTZNIhCXtqKGQ=v9V88b?H#J%1m6&W* z9XN2{l66}OOPTR*8h-Qp)nPnr_wL=(njNU<5q~Rkbl{E2%IsjprQrzjJe!F}`0MQ7 z$f|A>zi_8w#!0N7N zPRJ?{>nc!}8LtHg1r-;2kZUiFx6g#uI_Yi3Tzz_FXvaIXt3K`E;(eCO#f1W{EVgOO z;P#sTvk)B_UlmT^$ICjR>mT+*FbbMsg;cveN#!}`FHmYlC8g4)Px5h~)Eqej0qD^D z=TnNaAGtbvH@bV7wieB{hVZz>EiU;ogNElGO}vLR=CIRwhSxAUg&XKc)&Z1kzqqX+ zXR+tpdX8gj-Q(@)aqr(VF-wO9RSh~ZQ8mQgFEw83w$(({C9Lme@MN9b-OVFp+eE-v zZWQwZ5r~yEG)^omESS;c_|OXrwPu-VKECtrFyhw*Jt;Mpl|f|e;>3K?44+4~(6Ivy7QH$D zfil9XK_cXmI{zlAR`uc_r|YGaKZjgLzT(^0{@dW5Esd+~9n%}47eRC>-V*H~L8qd* zKL30Fm&MX9f-*qG?(P^zEJg?9)UijgIt>wNEx{XQCu>D38%=dBS+%TjXRR1ikg#5GI=` z0*k=Uu!Cg3`|UU}Ynq(Fxs`{;#?=V3Sov#Fr_&|ohokvzKa)=^pO7^xjFGB z34j;arhwrn$C@()GW_CW=*uJUOe@;gT@$7;mkJ6A5qEZW&Qe7*_9lo!Z>;g1MDU?! z+1Ru}^SK-s$KMD#+Mwgd&FhaD{X4iild^ikszWc7?IjG|T*A-j+ARaUbGuz&y9?XB5Zr?LxpVlmF`^9lMFar>O&K9Wn;ck z2G14nC$EYY8Tq|zA^>rWF5UwS{Zf5f-`uEp44WRKp}P=38vu4W4n$YHnV6oR>J{e5 z9f|!X!Pbm7M$UYqN&gioz?TCNX9UiwI&D4i;uKxNa$U&Cl0Y^nBDaaaYhE=x$7R}; zjeNTAXo^X-&A{KWv3`&rB_Xr!0UPMbEz?So!hFaV|xzI^_XfZaInqk;0cM>KD^I_rbMtb<)l&Y!LPn4HXO95?dLu-axg(v~?y z?U9E(E?5o<_M+on?sv}MTxjQ)~}((OU|)(KWZ6cZxGh}j-5fq-JJtS6T=GD8S%Q- zWig%0YDDfQFZbKi>{};6yFL&yB6qY4@ansF)pHL}b$^LYiRV#^g=S@Ob#-;A$jdw{ zpfFM3QpBl9@0~T(1KspOhrO^fJamN-{_G>0(IznVl_NvnHTW^+cG_~dM*20U zW)$o7w>L}Pn9TH*$l#m38LZ5N51@-eIJc)T{u$HkKQETiNx8JNbjAA0TwsWXL&X;# zg(@bA+9E$*K0X%ND>Kjj?b$9HM=5Srp=4xUNG~@%0|Elx@LOno&CD!4s;u^EtTQWx z_1!H$zxGU%PMZn;Q`a}&BFBLb@Ts1U!G_@DJuluUCOwXtE1L3br``xTJAD26wfL(+ z<0D;N-PpQ*2d8SAwTUbi5HTwpfre4ClctM@DHC^)YA zuC56AXHj<=8n-aX5Dshn;Wv@9CLsiBwb7#Es&8aYQmOWqUFJUza6S0(?4hCIt)XAx zAt>j6`$d0JnVFuzSYmnr1bF2VghkIu;qDWLB3VHoiC!7BfBgAvxK$FhQ5^26}3jJtjn~OX=OmjoOB%@q6?SJz6dY+(5 z7hD+#l)=BenIy9p|8p-&MZ~Zq-c4ml&KU~h9}JR5ptAx-3CdsWF#2KM=3rI5*d#A| z311^Bo54TyQbbb=LWIDElB~+=)`|+s$}AW3s&5`Uch~=GR+iV#wE)S0cV#^uYfDqn zpe1Ez2(-4c6;(TlYq_AYr0D)&bpHMJ@s8biB!|G6Y!t9~sX<#ilgFs#bey=K4KCUu zhTTWWE)anK%Z+U=`9JdU@tOG~>wFe)Z5)88FFv*k4e~|PmbHQ(gmCH@MiQt*T-XU7 zhjnMI(3-KD+E{31>C80AQ#yXI1ttZiCE!&j@9voqs6>QQ$=}M_ zx}@Q~WWSN-+P(cWyyNs>m0q2@`{ks8nHlA7LQ==gwowyb?VbC12m9*0m0iqEMx`gGiXT#DSgL2`hb3H3ndcoDRSkEtCN0=%5DYq`?s~*Swa< zI_jZm)nDpUi8KF`jTRNI0CjUwNQqdl3D}IgqcS}%>%UD@Tw0=!z|^uND5uB-opIVu zuujF?B2X9aZeX?HEL_&AjusXM)YA0k{DW&aFIBTloz+5r=xh`B;9r78+=UZ)Gex)R zbxCXCVg`6@vnVcYvDvxktt;($wkhX#y%R4r4(BsdI)T%bhrrSXe6HUU9UUE75H!xT z*ShecA|)_~%uBtlt^w;?XM+HEGg z&fxEyiF4zZCUCC;MFcxgo3GLgy!E&J!9{+ydX6!g)zLu7W0tNbTwA zY0I@XGVaReD)pm}wz0B$2dtECym(ZG==AeFE(7JSKH;zEVE&53qQzBOxXgZ25-a|R ze&lCErF_|wxnua*BdqrHkx}{$4L!-mixBEG^z>+q;*uBIbcC$;F#h8%-ZKm?Oz3{T z^ke|VmoH!L>z;D41t=+&I&tpr5_e~z^IB|td?_t1?5G?aBDWolHs%yHiOC34vGeU8~fJiUy) z_aUWl_49q1SN}fBm&PrMjvM+1k<5j~#Zpu`4Jwap?R=O~vIM=|@5l4ge}4Y3-vOKv zF#qk=gfFi8-Z_FW7|V(pQ=)y%y6CK#6~# zqDVt#S+Y%68ZwO;kUzNyR2fiKCcHU=5;LgIw_qZ(vmrT|W2<`2mT<`@wgoYB(0`GJ z=}*pZlvlV};ic`I(I|`XO2vG$vL;oph0HMFKTc0WG zFPL&R^FASXxnL;FsA2aByOVV8*MCY8va;^(Y0DdgH)2^Y;@^!UGY6i!c3B;@iWvxfXRsAD_Ca`KbY6YRAtVwHMszCE+}jv% zE607`Nz@A62^G^D91>Cn0vrp`7r0VdWL5Q}?3tsSW-ItR=@LszOUsAnW+rWm1mdMa z1A+`ofe|RNnQPH6mWOk)JP4#~OBSDl;;yZzH&PanA}V1Qr;B`i;+B?{2*?4PKYU1d z-Mq_wIC7?#T(12dfPYX5wj;^L2`1#frGnp4?H$ ziHi2qLA99mYNMPJ^IO1G$bXQLwwdU#uDyOpFlY;jC^{XE%gV|+IVNy9)C36<_=bSU z>Xs?p%sa+AaS13fxnY-u4s)=yKU>J~#mF`_H{UQa8cUt+=*qDStgNhbcVC_`b6rd2 zbX}>U@A_&Wzgl|%* zgj10v6yt&_hTlD$p9*0kL^EPQOj@=So{JYxOFYuzG+vtQ<`Y`}{WN-HeBApby$kt+pbL5blKnL1jgvvGS8!I0iK?uloz%Il;n%2`|=?IhZtRG z$<~lw?Z1Eh#eNT!bUiw@6n2e#{!;JbbMe~Mxp{dZ&ZCl=9d|~EJ7cas)oM@Eg-xRx zBpH%JC&ptpi3smZxe<-!y1zL|kkZ(-{5giA`&X~Fe$lUu;(s)7vqC4=thbQg{I^I& zMD6#dyS1l!3YaW~#C>T!1RWQHn)%8RL7v(tVAx`gn@gTjB+Lt-h9R*OdER4q};O+I7x!Gnhz2Uk5!|veh zCFSsN7bYa%M;^wEG}!TN;)_$L{Yu_>COamZb%zs~7-`!m>Ubr^di4McT>9M!%%v9r`+(*gb z?Ic9ss&3oe7$@cv)=wH82J+e5)D&bD<2oW?`0PXAR>&Yf2Cb(SI?P~o#Tn$a)bj_6x z$R2#HicYF{8F6)5n4d4++*qq!rW0L)Kx0s<_vkG6n3=rZjY;oX13(=XF^4>ZoM$+k zUmm3MMD@|$tqsakciOwVo%_DOr1xER-QrAMFvlg|h@2}aQbo?Dh*>F-Y|w;yd_ zF<8@sU(fWHiAzdWfn7nY1CZOe>4ciBQd|}iMggSvdugs~Mdx$$S@H1liU~#gjinR` z)d+7nMZUf8uDa#rP;GPyeouhE1v*2y`jjMcM!>zLrDau6j>}=DpB1mBu2jDqkPo<~HlepYPqA=zVtk8352@5I0{@(g+uJ-Nc2%GCq2VV26a3 za%xdoD5;GvI{QvY&OHmrMv8Sp`#Ed6wU}rj#ZO}+qx3ieD%tFG^%{BVVTS%zH!P*Q z=*>n~PgI$sqXxRy)Y=M$e=c?Qp0l%aK-D0)t0{0-C!FW&zoIF(R%)Z? zb3PVD{I{7pEn(GG^8#e{z;W(@F!!61T-C6gN?$x+NJLwn%$Fye=Ax(Fj@LCdTK-7= z``7S0reCtUFos%oE^RENxUzfiKThyJ^k9eXePum<#m+q1#pm47wik!!QKy72XbPKh zvQ%YNmC2Lz#9s0f7az(gC@2(z=HEJ7K36L&{C8|j5f8RcCTyUZMDk00G>%<{QVzrzEHn-GFmM+vUowNCC8a@> zGVTwntENiF8cN&ouw@qq9bE zsVls8vGv!T$Lt|hB|o0;L+)dtRkQaJARnV~?;mV8Lnpc{YuP^?MtVOt^lQ!w2TJ9! z!_l(+nwvKWJXXH`b84RnCU+lX`jm0U*E2!wHB$EW_S;z!-{4kiYU+T~qtTzMjP~IN zGpHnT*RMDLGk~r80YZ9M^p}pV>6jE9>+^bjFVqA%+p58FX2NWKE=>x!zfDWZQ6a%} zo^aF1?E#=G1A%O#nNvT_5B?jdO9YG$_;5*%oYS9@lP6nwX!*@gW*WB#gc7T2Yike8 zt=P5Z^&D;dAgg@8>b!2IP+d!l9t+OGV;kf823^)6_#@Tjyny4l`=%v&PRfNI7&!!p zjZ`-?kcM05CP4AAyY?tEhq9MXf-*Ez@8@l8u4&gs3GVu(H#<;K-_mjnl`W$4Gg9Ll zu_tviZ^wxROSxTtdC-SR@^#xZj{0x7ZVt!ek+Q#Y2#T+{|NQ>`l!X?RDeO0INm5B? z4!vw`xcXxs=l&5|06VdTg+gKB;eNrb0Iebi9_2hq`UH_i;mR+wc+{IbD(iX~V3uN? zH?!26!>E)AG>4s?T_WJ)JVp5IHIs-tsfNv;KYsq47D%v&E~||fCks^xJXBRtDXtFH zaNaAzj5^0zXkoYR_uX8UQ?t+YEEO)5>=s`BPGsGK4jds$EX>S@|7F@3y=`6SAnpWL zcC-jqLYf-|0X3?;W&lyD3}y?QoqcpDj6umi!M4YK7^q-kVq$|oR-yBXpfVIsOH19+ z8;T;#W+O56i1{Qd^I;3C)Gp7S}`y z?8`-6YG~Tnf&xK~qV?J0cXbW7{kc1fJ;)`8Xes~`#kY&$gy$08Frbd!NF;E&a7gbs z=6{?yo#?rOs%qW>z;I<$dCKZBhYS;dIN0aw{nQs(<&CQEJx=;>y|g=cR{HtbbZc=@ zlhl`4R-+B5dcM|#5g+=Eswr16o^N^^k8%l(T0k*^=Wk%9-GuO_;>7_%tVZ!NEzMofG2r8; zSG%xXSpXdo`7Ag&=)uH~cV=-)9N`QlS*=Cg2UZJzn?qGa%!O#} zWBZH&QXps!ypNX-AF9xGJImQb871WGKw%k*h>8d1K!#eu5HbA^IOkapE-bt)ClOIv zUmq40esHUDpd#@4s{`;Lp_{gp=6*48)Xe5NyYWr8DQ0UJ(Q z7>{boz?b!-)B^ZX$2)J$bu+;q6@7ea1b*0&pk&~Y7=3A9;c&F%EpEL^(cuKSuXHH) zjq@T!k^!fCwlhCu5^a4XnMAUf*Of0AMV_$U?B9D=?2 zh6b%4EM>R#1f-SKt%JMqDO6_1(+!*^Em3C-7Gnn?iT^3UOSZE7yxOJvzhh<(0R`7L zHwRC)r7{A;$WV10Dj=Yyp{e~?VD<9=-)Ypr)u^mt|Gu{6GB|=a07X)_eueXybpZTw z)$q=tzx3!dYTf<1jY@Q5zwv4nyWh<)RJ5|PDn>U$3_QAY=&;PK(20w!reE=15uNI! ztguQ1lSC|T>+LvsJqlvrz$=RO$xj}C&dYODQC4n!J<*vZuB@yKs!~?(w>8~HzdHXx zm=4&hKfeGVj~Zn|Q1jD=g{7*hDs6~bfC`U{XYXCVe!X6H4=`uA0X!+H(geOfpZbGp zw3L$W9Yr?derIT_T#?XtcM z09Z&#BX1x;G5~ePWt)ocGY0dgkFvYFG;9ASuKJf%+D&OD@x9WRoJB?o9gR+QWF(AS zLqfE@GND;Ac|7c5<+z|Hy8k%CZg3YRl$uhmbK$+Twu!m9mjMJFO*z%?;NTFOmnYy{ z@X0{j&!jVx{osi!cNKv!&L2cMLbhqkCWYh07%CpV zD$K2#zuhPoHB{^)S-mSOD~oz`o#XZzqJ{?Wd?OPRNAHTN*|h6c9CDd{8X#B{N8W~7 zJ(eqET>?CKw&Mdpj2{yc-G6s)0j@Q4Idrmpm5`c_n&5vE*LbFvV%&Y;E0pK&^mN`j-|Gt+2lYTENMps}%$ z95^l8`|!y<&~$VQfP3%>*&|&*Hwck zQIM)z^*VM>LQ>K%Up&>9m_2xGTSH{#hAM!OsJB6uKl9Pxt?zOd|1YgzJzw)VZdWF< z#WO$YH_wwBT^^3G>_b^P6mlpf-aLEutQsrn=lr^TceBkO+zx7oe*hbDw9yzp`z?2y za$@lb%$H=v4aW18IdH7Z==Kb2RJtp}Z@OoXN?mt%L1IFJQ5B7}oPfiA(oxhB*a5N% z6!As9pyWo>;O&t2on3KKb6#jhUQL~qJMOn`<_)i7M{mfX8062-ms?$g!kzu+37|qN z9zccImF3@0Yw0grjbv-fe~|G(eUq;a>Ru!PoPyZnsj!roV zd&YZeXy+9=Z*<9{_ zr8n?PDLgE!58d&BZua9|LDOv@-Ve`;H_P4^uu z$K0frtM!E-oQ5w&Yj)PhB8}?q?j9YJmKJa@2Aa>j+$HAj{xLDp+k>11HRE68;h|eg zhxp;sr%xV$5#Q(8Oq?CvkM7ZlN72|2sqw#z!t6?Z8W$5Ixo#%HALx`)6L6l?3#(>D z<#zn2SMFi&rVX{`iYEa^nOY84Vs1|yH&=!mQ(QO3SZIqDJB*$Oo`NM+0Z_`!uiu#w zSN2<>sij3sUA;Rst)t!#;9+1|S{hME8OpKD_c%`dQhSUdO&{yAmK%+Me;|dFV80pdUq`$V!X?N2nGVM}3L27K*(xI*CLo7kO z;1N;%Q`Co=G?2=+LTATSG4du@k`}>lvz?cz%C_kDWlPwu=JlrGGyNu9ntty-jgXUF zqDH}GP{~BK9PTrmoLR5VsD!q6gU_tc2{i$?ZG(s36di%G+n{D9Tv(F?qv-nnba%h6 zz$E{lWgosC)`-TY|Cc=$)4#7iu4h3dWdP>NDhrxS4Gj%<&QrtxFIhDGoKq+H zo6>*hAK>@Z&yhT<4r=Gf8&4ZREmKS5?SY@%kbA+;!dbtnn!X|ww3{Kpl{1fC>l$w8 zT_55rqoV;UW89TJQ_yfp!`5~wEjc-v-R$Dki4iV-RYM~qzwj?M^Zl!{1IGGi7%Z%Y*tq5i?_YN zi^=S?d+5Rs9-b0llNGg0eX@Gqr2WX-m$S%tBFO+yK(D{C7$|=wmB{u#$qVaN^`-fb zx8sJg@9ozaRJkW5E-oHlX$)-hP~*_Y%Sl8|IS(*$6Wo*{c*dxS=j9kh6Y8{@Pc1tk z@MqbvSGDVU`~T%L9x}?E2TYDiBFS$VL6C&No14tfdSX?i+w*nTk;+#mCJ{~@W8>nk zpCQv=l-JEH@uFlw2O*kvf1XPvegMaH5GTwvhxM6@C!7@sptC@|zpRXMGXFyGPVBi= zt>BVq*oiHxi>6)K_?-sr`q97E=b9kk)gG>i1QdUivta%Xa-o@Ky(b)(CaoG(Y!ka5ZG|JJ_vV;`C3#%F@D*(>XgYP?V_@%(6`ENfD8Yby(A zFY#qBo2ee>{-=k8mOTLf+b#cj*$;>)RHYLlM!bXiUovFm%lA)}YM~}TwTg}mqsF|c z!n~LUoWDNk3l;J8=ws z7d0Uyr6|%AD^4i}#I_gRloB5w-+#*puZ0blzbk?Wz62Fq^` zIkOU;y}o~+nwHF!9Y6fJRZPx+4l0lhVN0Of$bS3wRK?&U;>tJYDBB+8sGU>GK97)% z>&8MPqquK=>Cva@jOn_W?_y!mJqtQZmG*s7O)1R#qV#Ar6Oes2}P6;H)xDM^X00rWSRzrYMzaW!&Jdi zF5aJWUgQcjSqT27kK2)%X7{^iNia93kY(wkEv%M%~PskJim`d8M;=jV(31A~&YgKd0XcZV*zC9xEIR;b0kr~s_UNZP^ z;x=It6K%d`w}80shd5GXKJR~J_XK)ZYLK^J_2)ul*Bk)BLK$6WFjZ=}46@#Kr6hAb zN05{9SMF3~WR9Xl7)8#ujoOOf*1Z)_HMmouPt1op7{Xq*^f8(%cIJuqGR`8j24Gv_ z#*OD*B*&E~bTi%E^`o76BQNO7Kp38lcZ17mg)#Q2lKl~!!RKS@^>gsLPrJNL)WpU=iihui!&adebWxyaowC&BV-p(czk4}Lx)zVR{t z&9OCo*G2sba@i}ddTe{0lW}7f;KNf?K*O;TR&(OyItzgJ~d zm3G5BiL&69zkmOtLeo2|Z);HtU3Z3&a*@j~Lg4@k@WBBuatAe7DyOpBwS9RoQ_kpz z3eypGH{XSi>b{}KO7H<;xz}DDz(xd6e}GBHS8d&lRw-4<&j|^;L?zw;Q&CYSDo_PT z@Pe2o=;N%G+WfP<=pSNeq9&sw)clBUB<#W58s$_~9YG)C=w(B> znUE=o9r#xa0}kt+s_N0U`xq-{%X8UqUUqahL?g;yxvX{e<_6%@6s=_Jn_~D8iPv)6 z3I^mc?eHHmGy@q>rEzzhxZjCWr*3t-lQC*RD2pfnXiGYvI8vKRuJ&n3{xa&+?pCKA_9LEUSA{BZ7199*K8xVP37y129$;rnK@2EswJ<1yPy2u%% zYTdYV`}Qdcs+fR_(q5aVabMM}thwQl;yhuLjK_~UUB&Lp4@CEq;U)e|hPI;Kp6-mX zm>bdC%*@5?y+-1~QQO)gT2HfWp0d`L&;?mluh~(uA6+rPZ8v@Y0rC6WdS34Q@T1f6 zPkNcHzbTt%A;?x&!Nb;%wKs|{6Xfp4q>p=s7UmWJzUl;o0GE>!m6Vk!FX-2d<8j&E z+m$`HLX#2`&!M;sJP^9oMF)g~c&D#Cw{B(}e)@ota_b}F!jG)+fJM89j7*b^K%Pli z#y&Gp$Qz#sDsv2+yeq#6JAp_I;lb_y%SAX&WROOEqdA+yttyI+_xhr@R-zkK%?fxx zht+fmG52TpWfxJklX!*jtu7|A8Fem9B)++&W%GdwdstYQ*0xnWoL@Q?+zyc+f`wop zQTv9+J2&~;0kG`F$!;3kE(`HhRALJ7Wh$owr-w+ESTQ?67>g%7+$|Ynl_>y54-O8Z z8y3K1`S|#ta|oOSPvqx2xI62KJJD4glxpUWiD{-^2U~?sWVo#N(|6U%o23{|G?@CcnF9 zU)zt>rQoN+de!bPUc5k8jsi#rN9B$#YdL!KDDjgE=w2_Y_B36KiHz3L>d*^E+uSa2 z->)>@Q8M%^ywQh-kCYf2p#9xqE3$2rHdvq9VkcavLz3KS>IGJ> z>-sKK#aHeT^YtPxFDVgxi7G|briwIQ9dPSsS79J@W|L$}a-t$%EdO9&`>pEDjWz9& zy0-=p1E0s-()GaF&isCQNX*hQoq+}`>nvC+rQ-QZZZY6~4*#6W&d`t{H!twxM}M^2 zh-VeXOz|j<`SF1Ry@L z>PL2B<{iiuplhDc5$r1x>_f=`M*^?H-b>=@V|FbxN%U8wfbt&fo567|Em5aIHcgL( zu~wj%`RYAY#Exw;|NQ-(Y;Gv0jPyUBgzcKjaC z9p}aqgP2^$_68#ubTf}+n*X_W3d2}XtHhO+fxuL|87+VlH9~yTI1yN_d)iP&Pevsm z{u9Nmws#VN4d^ZhkOT$>yk%f(W69PJ4Dz#!ppCl^iFwn8mQJ~_5MB+11&z z$a@O=hJ~D#Ku*IKopT{8y$9Qvnytd62NN;a-r_e^IgTd{dZ0A>jZw*qtn**_nPl67 zDpew4IsWZR%%HP)NwA$HIKB6BKN>FjykZoONB26CVEfOLGfTNUP8IMC)kG$glZgD0 zj*cpwtF6K*;?}@r|EQSL<&O(87Wum_kp*R*mOy3NPrx7Q0U(;0FmqJ}do*rWCZMyu zHkC}gTz>l4ne+o#h=#+b!`OXnbY#RGIoS#b9*(wS<-S#%Aq3HTKbTg9e`@xMyA%83 zwDJgT-~Y5k*P|+Si!wUf(*SOWiB75lxbW~Ky+q(Fb--z@iX)eB8f>swhsEDvwJ-=P z1#E-rP#-|(Ld|P@7Zp!h3;^L|RU)7` zO}7fflIb(LZ*3vT46L5NbBHDfK^1TP6zDmHe&jy@HobUuunMdT6Dznid0D~WrdFi9 z{?7l1PMT7NYA_oE-Wi;IPW1bIh{mllKYIFPJ}jvGkcGq%glzjbw`Ms5PuFYjh`C97 z=?Isp8nu9JCE?w~J{}PL$!-Y+#R~KfJq&^EB<`u&Wz3Z7Rl7yPD*TeA-j#(W`BbeEQg&XGW%}28L$;Tv|KpjvNoQ9c@^Oti+?^u1 zZ8>Uc_JhG7SPZCJ*lxCh1>}U4{XgXQ48%{)&BcP+N#0~;@}m9REpV_#`>E2ejYi+yBixdA)-_1@?Xisqt%9#d9*|LwfEuSH&`LI%JM7IANh$EukRTw5xQ912jEkLAg zkNr$WiZeUvd<5$%ms?rI$Wf$5uzD0BLql@t-Cws0an-z7l4g;{9?bu$iHXTf!Ibk< zK~hrEJ!34WusLB{#Vzc&HAP#(MDjOR;lmBZa8qHR6kx_HI@UEIyMBQQZeFf+vOttI0)ADroSaKe^KN+Pmb`pR4W?gdh-=}IW zIjAHd<`8T8fu?=YRV9G5;Ij>51P{<%6X-I>#y0GJsrPA)Y!L!Qb$UJV0o;UQs(IbI z&3_)ahPk=iQCFu!H**@dr!ifc%AW(N{mt4)xM`+5_r(isT^Hyo!du4Jv|e%^ zhfl4O*!I`8{-?kPY=f)Y=jYzBwh<{TR0af3d$~1e^j}g zpw7nk3a?P0UB^tZrjt$C*E&AKFz5R)&CGnGY#Hj6R!~wR-HFLGR|Z$b<*WUh@!xvi zRg0|g}##b0kq^Bn-EV|viirv6zK5pA_PuE;x>EkPs__6T-jU&&TzOgmlZSNmx{djU_c*075 zM=p7q&7#$jw1Az|MD02fA}T+R9J_w9{K(?tt3jV;Un|-g-YPpz7o1>QoV#CczvT__ z)7hyGyL4|KBh%Y+a_9b&d)KtC9h>bD)?%o9JvskKCc5^+-=xWBr>$IN={+NaYFAQK zqJ^9zAd;D?YibHYWre8IXwFM>J(eHL_JMXR<^rAbR|2IKUOYYMc?#ict1B$&GnD8h z1gSUY->RX<0kEcb5ZsMtv}&kin?I1@|MN^M+$0l%;M|6wGrA|76$sHuZfntoYTCow zr%=wo>Kqy-v)iTJbDVUN8{1`R{MEcE2BA z8t}h9JLBiNUU=&Ii}6@eOyP~X%^7YzsnFgn4T81LE&IM3Z*zz&t}xF3z+=>+^ODYn z)pe@kDW;G^XWPZKo8HO%pwRN~@zk;tH=GODg)xQveVpg!np3vl{au3P@f9xPFXsI5 zZnx8HRkM`Nx&NK`6!!5fqnLL&(QaD*jm1t*h+Hd1>f@ZB5@DZzak|{rn=06TTX>9z zkEK>f_1$!m9+Ij3rN;RwY3I^gH5`Lc=QI_jkof)SZv9^8rC*zCQ_*NJ`FN=rx?R{u z8yeozabm$MKk2^`#xerHvp!a|T8M6vvhM^67Z`}6f>S65c53t5* z!%>cU(awt%E^8AZp%?UzLD2UD6Op~698w(~0-f$o?ZQivbg2zJ zr~J1&Selw`dcgqvPKE zSgR}*c5<|t?b7&{f!V5z?a^p$-XJZhtB9yBJ$9yw+j6*u-K=0ii3@ueVv^O(n+_3+ zk&)3oRn_!bp*5YZYzvM0gP5JG@TNuR^@H0_qSt`jURg8dcFLa8#+Svdr|l)U*rq)= z-kzTBuwclAEsJcdE>yu^VKHIqHtkH{_)&dneS$Kl1?I+{Wvb3?d^c2Cqn-c*Yck4C zRB*Z);E{G@q6Tqh(?Nl8Ij7CJXimQv^+wcQp1_|Dup(kfuV)@>O{pytT1=e<8%wbxh6KE!?of4TD1bzp z9{b_1nVEX4^P?c@&R4KHiR7Zf>U{g{M}%`uIIxCt{j4y?Y3AMjFdbdG6(Q(oqv5=u z$b~t41Z(p3>sK9MXLy+ry7XXqreDzf5N4H>VH7wt#LZchNRX zep4OoFb0@Yk_DFR5%?=DY##IR@o9%h-~#9kYQY0uRC*u3;0b(DqQzp?7A7NU?R92d zH~k3jnOpfX`qtq(?H<_vFssCiG9*OZCiF0-_%0{s5+XQ6fbr7duUlGLq#`e8d`w6n z-;I4#`!9K=&FX$Vo)wLE*~ILlO0PFfP)e#i;W&O9bq{HQ1)0d~|}XdVP?I3^Qnq*X{UffJ6iJLBD?eI+iv6AuU#Sy{Vb0j5g3|V{H3{ z`_zL%{P-=>b=DxeN_pTbD=%5%cU@|M+M`v1iKv(#ZR9)Digs<$UwS-=2+R1BoL4!X zy8VolRiaU{gbe?8z8=)&<^}sbm7Lw@IU6J|Lq>d`4T(lyu}3Jt`Jq1@FcvxzicL_q|3tM*r*@EBIfG=@%Ew{v$Q}S$XHU2+|Cz1Q+)SgwRPV1% zWVyDUF#?DCtNayXK?e=?Z7oz-c;yG>_M`UN)uH70Z4D#$Wc1>G2I+>P;CAq+vf3$< zZ_(aVTnvFMvNb_xB>5nQ%iUxkE7N+KKCwExS>y9_#;wp0COew@_Q)H{i>5mQ+q6}`UV;(h{NHTFSw z8Fd!%AUEsAp;s;TK_y*J8oBk^+_7Zx9Uoc2L?Cp|8=aUr`Yr=meb6#uB1|E-+lFl} zL6fjBku|{?(S`=X1&r#|Z+v7jOuKU47UapKT#A&s$qSMTXaKB_Ho&7u9TuVn(i-qKjr&U!V z@B;>oaz~pMdJ05RQWD6IB1v@bJ3Bjj=tYA&z-QLOm`GBG>lU~0+V*2(kT`3=E`O^0br49^X7J4KP0Gta%cAIGi4=i)LeGczrE>&UFLW|caUuak|8m< zt*Oa*1j9_`I*cSNEkm0V2tMh4mAaF~?0Zi9PE8R$F1NkeRdz;^omD|VU_^ovwMmk37$gS;K{5{A75t*9VKkSJM2fhJ4N zs5Ch=k~3eus&@bToipc*+V8!(b>r{ex>ZFCprY%~LpRE9-*WG{Veu2TjkJPziT#u# z@XA~DQZ?81_r?x_u;bFNOuqpcM&c#wdOVnFa=1fsn4@(=RBP6?j0fmqE;{NI;7dwK z4bs=DT6Pz;Akev+veHx{{a$1SH>mnC0=-U>^!yU)q^PwDKyNV7W@~EHD(e z1QBx+3y)Tb^2Lg|<)u2Nqt_?=Hx^T$Du>%_E`3ebHQ33~@5TjgE*)c+e0~1sXxV?z zDQO3Mxr39XzD8UODaEV1_uoo0z+mC24}i{vSD9%7*d>Tl;flMru>GkMAg%w;i+@yk zkR$=E$2erfTU%RMWjyV|j&mdddEuu!p0a|UzAcoE?c+WH1r?SI@Fp^Fbt83s{^pYL zn`dfcH5jr`x_{9o!=`Gj*A(z0pb2ZeEC)8~(P!>M=*hnE!SfMjosEyqvML1nhB0xa zfy~N@^Mx~879%T;r!I_fr{T)oBj(S5>UUhIS&qlCnA2>O{NXr z^pNg$Heg7_$b(aatC1SL`F#*IlX}fVg4{R1!edSJt~?z0!qJ;+n%KYdR z`EXQ}@*>fq>8NPcBNofROIX(!c9J8u(aX5n-)q!=E*IO8XSzGJG1JArx3i%ed+f~R zi|U>EmbI%3LsB3yvv+XN07-vmcX#pDpt!-1`1PHf96Ki`&pIH)lBqEErZd5Bk-3yO zef>bm&Z$bm5xO0mPdEoUOZODI2z%O3;b04Quo8k2U%d!6_Bd?v3psG|Ph_y3%uvp$ z;;#Q>T0x1_s?hPL76GFd)Bj}qpG`;>gy?_ zyFX)lS4cQ?z_fhV({N_iOTWPg7i!{8iBV5ikbz2z?$_{txxJ15%#9$M1NkR@cmwjO z*XNtBV-%8XO-f(4eEgdn#)v@ls;6=oPrJO)^BPzU$kNk6pUDGw?aXc3J=-N#`@8T= z9VG%f1=_!~OBdbYO=3>D{U^pCy{``nh2XKT{&^tJ0r>y5*(;dmDCtW0doFkDtISr_ z$YOlJg?KQ)kBnBwsYD>xF-?wARDfV!Zz~0Id^J#4?wU>K^N-`d!YAar_BQxs7YzOd zuQG4d{0#qb?A}i*>mx>pA8B^Wc!->{{)3q5e0k3kofYo?Y&;rLoc;T?gcm3R3>OTV(i4WP0;N*JH zElgR$9#hQ3OUh_y2cHi=Vb3bXqqCSD+P{55?-~?sZ&RLFTl|8}B3tvv^qc`E$5R?{ zu2oNw7$jt-Nt8@Q;d|KUX1~GXBS`B`W#;b7WCQ>Va_%3+T8=^mDCk#7`F&p^IqpPs zB>Fwkxl}zZq^7ZS2u6(?^<>26B=J{`hZtxM!8uAs07){HHchX^avG`0KL)t*nD7dt zS1(!8NsUiOsK|+klEofUxwLUjm0G?9^u?##kr*mxXJbD_pjuHDbNVj+7!-rQGz70% z&iPe1{*0?5DK~OZl_blvc1s)QXb8)72K@X;TFzhInYs_V(PmpQ(}jfDgp4c2Ck@pL z;}_9!_@M$uG&0|D20SjG6G3JraLwF&d9{n2bqyLzsKdTs4cwIMCIi>-m3W6-6;TFv z2pzx`i{Ibn&QP604EkF~?i&67{`$N|L3+oD_HpgnU~-JA3=9(f=z88zZD!H5Wam;; zY$3(ABq!1?S(Fcj==L2SJ;P}1{iBdSStpgl`R>;}Ax-)XV?6aghCbr6om~6+hk1({&!Fdn^u99p)qJO9p=FH408pp8*RL=UHq)t zY!=|Wyhr6{Qh4Gka%}aCm<H z1Gy!o7~6F1ytmxaU+>|UtQemTf~*=^6w^4=_Rx(&;1Il>h^GXh4ox2qKNGvV6uzJs zV_z3Wxx>&j?5^qFEKFV~<9FEF9IL`GDhA!X40Z8KHOMMbf-9iw93gzT zm%Fp)<)!ZE7}FkH+Sn?^Vq9L>2+$mMze=@FXIXx|9vOhzM^N6sB1NrASKNKt^487b z4JKWZY~X?;d27mN^buiUkTM$3JnUuUPOT;fZSdCan13r5*JI7A6d_8rL%-pF8p)ff z@b)cYPCmS~oRqV-6iz-H?z!*?q_43%R8au$$iSfjphxa}K~9ozVVc$edebha|NQ9{ zxae{VX{SQt-bSLma}WBA{IVL3ps|tOR2&?%Oo=0K2K$Z|EPM@*Q{~c53&i=Y^$eEF zZ?9|DN9)!{4sEWd_DR*mm<5;T8_TraXW_HldH{ElkQh+7+Pt_kuRj?j3mxdRfR`6J z`-aN)>Z|$am3X5`{6JxHk(05crLKIu+=^DA`$WBCUD&MMXpRxcwkko!koU{E(U6;~ zpQ97XcU&yXJX6MY`G^wDh!4Ng_^`4^O_biYgZ5R?^wy1BNa#_-4-}jQl4xm)CwsIz zpDC+e`cOX?DYd`szt%%p160@AwAPo+^|=nzW}c5dL@!x0)?Ms&>}{*0I(1b2V4qC7 z!k+*Bu9QV`@b1)H%`vuO&Dq((ed#>oIB|)1o8tm~W4_kK5yi^(+W|%aL`*sDyD8TR4|oqP?wtu) zVON%v>3ybxbk-1_8t^WBx<^oY>I`jeuZ`KN5-qA@@6fvr1bS^e5>{U)PVP-@Y zXg&332q6-Y%SgDqP|U53Zlv`*Y+X9*wlTui;dWeBh*fU$CIlT*NJ#zv8FEfcaen|c z+Wgj}7Gw7PxPfW42xfRRr@R?0P0^&0_=EAM=A>0D9hz{{fv?35xq9`8K(g%9%c0Ebxa$74Izmn4#PD44NT= z0Cv&u??$)&c^J*`d33PBU5D?@mJaWFlVv0Zf;N7`+E24M&=H3VUhfa9fAxcM;jk$i z5zjgzTI1`SAkuRux6JnqgmBi#;s+hKSGheVVL0#j1z2(z(?-*ko-a|dlbJ$ZR&%S1 zsX{lG%%O^4m)HdV`)l%#UI03*1b0*f7NJS!F30Ek54(jQajMRU);YqYUNnY0%()@~G6%|g20)6| zlSlKFt}w`Vb0Txk^;#yY9AQFkuR19??t=a?)9m-DJ_*LP77V3r_L0F0$ z+%MR#dLSZZ zef8USOgf>$QttTW7BL?37k7L$N4ch=b@1pH=Saaa4pQ`9AzV8o&0APg3Br*Gba z9CUs|tpSQ+>e>^U>(O-K67)KQD0}IM5vfq4hnDk1*66Oot(N*;%yFz4VAe*eKlMYs zW4uSpTj-gf=$CFi;PzWA$8RqE_VDM8$z<~SP@-{}&e6fCrMkGed>>0}*@A5f#m=bp zvXC6;krMjt`ISo@zOSUS7ryaolhen>eTVo`$KhiZbIBTd`^}472XBw`eCsupAnnyh zX&;yCxQ$(FjjVV2HX|dsd}!Mg1*uMT><^}An0eFGSuYQSnlXn63PFfa$ zZ`73UGRH4|V##kUxV2Jr>n?M#Idzo0Jdux|?pT0_Orb2JgB4_O`Z^FOd9*cT+c918m^?qfZg@A!}bq|SVcfM8|Qv2s54AsgY#b;bk{VE~1X z7q<`Cx}M3$X1I&)lv1)CBqVYNP;=qPcAdeCG34KUaA{o)o=*BPZDt)#~-sdI2I=@)vMCY8`1KVR6T z1O0o6^_O>%(SPf4xV*hWKe)KN5+|dpis^#F6IFP=YDL|B7Pup&J1Qee!+)dqDO=T^ z_wqQ`oYD}Ma!HXd^K%Ek6g;u^r$aF~Zr>BTZLTLn^ zM+{u-=y*gc#45E*`Q9!(*w=B&X4XuwQyMy{0`gc$q$$l*DpTC*?>UvFqQ|`{G3=K8 z;j_2v7}+``J*N2dU!H#bkN7!c8=d0q6#otEsGop8-S9z=V*Lixghq z{U;XKbFnJKpO$q+Vype2J5<={Bw2b2`rcyWYyK+O@xq}^O92B~BgPtZ2cR4S~V>s9N>-?;0r%ysbekg3b}Z}=f+_?^MrA4#Uh^7b70 z$t8kCfHsz{kSbc9#K^5a(ofF*L=CaD8GidbAx*KnGxoJfyxc+6P%VbP_|w#`Mtej3 z7;Hr`H2&qAOVSJCh`r+mrL*p>5+#@LIXRk>E$VsIlI0T#l!?TV^@U3zHPEpY^w1dm zcUn-XmZoN*cPNIBmnP zr-yfknx5iz73XRZ6Bed;P-L5SLCo!sLYqi1!Szwu@;z^;1y(sd@C16jrwTg*k-9a| z?;XiZ%f2E}zCD|^wsq|Equtgqo@n`m;Xsd=t(61!#snVA?bx%X0p`9>;db(HnycrP zUG2arZpT2X2<-AQ#-*>Z@{GaVLM=XR0g%Y_9F)%&>AFu6$=6g*&2&xeg^aAUC)(Sq z8|HiOl=W~fcl3x1Uze~2F} z{v#r|9n27;==Pl*Da?Lv(O5sT-k;H8?gL%C!OQJ!%1kD}U_W2V{<*WZk)^|A~;L#q&4UpzDT#N?7i&WW-j0|b zp1U*XKM^m@Dz!LS zwO=t*lk2~x!5JdQsyMobeRlfd8r)oO@D>>0pGRXqMU=pJ<jIj1=R zIKNQ(W9Hf9cq7Bf28rN6_sy^5-7RujfcJ1;cVCT7W3PoOmorQ?JTId{gTdXhQH}a& z(Usj5jMR6QIr+MVxdNRX1>f(jR4xj5^xPn0hou|NbP;P-Ur@e9M4D%R(i9E4bna@P zq+_39eS?^bnfu3II25ghK*k#9Hr`aV`~Xw$3c-OOALNphY07wbdtJLt7Ung+qQb)J z%60V{bF-3Bf7GnyayKW6w)NGfwWQ@fpZCGa`!@eDJ(PVr!>XmoxAp zP`*Z^S`*JEklfaMXH+g-AGGB{zEz)=X_-{5n_zXEK8r5cKt5AY7t5=u;Opr&7DN!K zl`Ef2qVyO^%>C;qGmnv_^Za#fgnB&}YKwfR6l*Tc$yUwdigK(H*^V_f`BB?S1>V= zimVo+noj8u@1UT<22S!72Ing8!B=YLQZ@DKrmnog!i4=LhO&Tw-Jx3E2%;gvC8=PCp(ZjxZO-;#yPg)?bQOUye)X5v_ea$6!wleYE(-#T@7FNjxPe zv)JxruRhr_aM?okODMOtcKpiLe*VFY$*Ps%#f3{CwV}kR0CWPw>q!LXdM2@D=qOn} z&OYpBPJH7dY-v)3VKKWmUpM%B1Ws!Bk&toh?xK%OZP%Cg0LH6;EbN&{AT@w6**;dG zXiaIvAMC~Ltq=J|vKtYt>q{Kt{yxzxWVr}r7P6g5=}MP0z@mnXHoAJ{h7Cw@!?`Rb zx96ZS$!}(G1+&hcOfm_YwbJ35tK1atUyXq{yJ!f29QJS3Yb`_-UEoHSM z>tkKRDf30`=?#vu^LiZgnSyy2fh(x5r>vr)a;VM(%8VRVb1dTroTXrIP9!t~HoB2{$t*QrYA`W*3h)=bKd_~?W$baz??%@uY}lMq=ed4NIQB0!wWPmz z)_=WHa^B=&kWhT_>E9OuWEMyU_TkS?b9Da|_5QTA!A_BQ?te=7xY;z>-<&#I>Xbgl zwQ*WvFlLzAT0J)L{qj`6f2N9gbhiTA-P(hK#xPBcsDF3?7aT~eq+(JGtuJkrT-a%! z>lG$meA;;LC*hF2Cc*rv#mXH@%}#6pRokW|i|RJCSjk@4lf-qf8K+ztZ=`cIQbTgA zitx5{YjP-4H$A;?m%3IlcWl5U$FYx+l>yxn4rou$2 zd^LUjwcVus)l3ifgFXJq(SW#}Ma|%iO8ob4+xEfKYOuYt|7^COG?W_V|*dI*3Rpkm$@kPtUR&6`19aQ932uN>QS+iufcfKGmeI=v?UXSSQcP^t$Cd&^&oOY2$ zIALHpQbtz}F8f5j@R$PlrA#+nK`}pKtUW?B!EgQz<+G}3y>qlelH8tWAzs~UcN;L( zZ-0w>q++W`b*+5nB`#p`m9pdBtPy!K8TNb8EzrC|uX%tok^XoGWx^UShL)k0nYj=&e0I(VS@|sF1&qfXW!(dmb#AONdNuWB2W9}t@fRQ%-%uwW}qB$ zh;AAd^@?EOzsrzF6jQ}QGFwA*@MEo%{wMSgfefWRnlN~`qJ^_)a-jfJ|6@Adbpg-=6Kp_ z*Htrt2MBOWalDkp!p^TXb!gfD>wOTGCw2mKk{+A+zv?xZO5b3V5)yMvV9vdSS6lvg zLM15)E)Wbxq7*}Z^UGcQyHK2H4b~Dtx8_>85L-!=%yY=yS}{H18nUUp+^H#?pJ=IL z5mYkKz!b7Sn}ZeIfzd06O>3`hk#(EScs@FwyVib?0{&o&ebvqg`Np+xm1DvlAAZ8} zE4_m}s08#6PdU$YQWnbMMypFm+d?LfkFj2#+^Fq)CZVuVP9fSp@SJ&ukP z9rGUGo$1kJu)`l^;X7Djk}2+;&8c+37P~!Zs}24jA2?C8+ytMmT_3ZgxAQczFrM6+ z^0Lbvk8&(`$DZyu^kbDci$9J(v3%(_Oe9%~j=Ax28)h*&sl}mJ*Y7lZTpkiBHtdbgf{3`;a)zXV^pF0|%H^a~TM_JPDcA~jWqv78fQ4eTH%na$2D(2%K z2x8uZ6f7>m>oLhQ_geq2LyWT{KA2;uT8(AS1ruE!_R#OjAG3fvuQ@&u(3Cto)fHZG zVk|2hj|y|@m=-Dj_$c>3mIwZD^)WOGRoC>Qj~qL{jGEz<_MTk6MsJ6wR>cKwRLT?^ z_T`b^G(d3Rd6~v3uVu3OSNb_1i!A!NyyU~be3@ymFa!(^jNo%PyvWVPWsu_<+w z{4~6R@1K$LRV#~4?5@)tCOZp>uglUlu3>BuK)FYE(HrZChwL!h!2O(kgHO{Y)KljOr|1>c5<(i*)$@jZ)m@nf3ABPgn^2C-%Y( zv>-9>DHGq_;3Tl=%)WxgY85rU$;DmHE=!o z3NKBYR*hbZp(l)NpDU?+bNQAwi)O+mj?mk!b3(34(75{fZ1_oITMjsB&W1DAjYlHq z|2zr==SAyoxj|ca`NeB74+q&RNJpu z8)23|@`#bM1$7Tzmn2~CcvgwEsco-UoBhj9&o*s<-?jRMGJz2mj2wRZQR0l8eHPJl z#^WJ;A>|M~2viZ6gA{+3nI<6SbhFU+4RdbECuZ{AMkPE+t^1#}X$*Y)Tcy`b9}|d7 z+eR(OGwiJRQ>+>dU%3WpLQ&Wt>k%(>8HpvwLC#vwzqKxG7RmeRN=C(08m?^QC74D( zH^>2~*va@xt>>Ex4d4<&O!bNm&Ps{4=OJ{xE7ugDV{+)BtEW5uYQnL~mbTnwa=7+) z`T>>m%1e@8yJOH#yOyd!%jgxQUmMh%YN^PgL3lZ>q6LN1q9A>sY z3{50#|CV**#ozw}M{47iW*@@TsXE$Q^Ji%oZK%>Xr_|ze;!r}Dx&x?}Q=W$9c3d-4 zA-poXF%BtPJOq2CO|)>N#gU{KEYh4#i_w3vcqM)u4B$1o$<|&Y*1l>|F3W)70!^sN zhV9lG{0Sxs{LE<0z~MOjw_NQ-;8uv?SlV?<9`GLz=(4*pUN^7B4 zGaA0)PQYDFPm6d}V}tf#)UIc(jPd*$mdXqJ2J8%J?ajnT^wEZ5UfnAHOB+lcD@~p_ zLop>o%8bqSRc=lU^Qbvs`;QL~OqRPZ^u4&ll)3eD^sp41^y?2fgeF}+zuR_oPG9jg zh>bsUETYbu-|}|Bln;bbnSsXRW$)9Ma-mo*{}+%>XFSB{cQj7;@r<@q`%@G5{UFji zU2DHhwLrPvZm~v;6~#&=mz2utiX!@LPb7}Mqwx{|K*Q^WcQ`6z_XveozVBz0ufv~M zU3cUwiUOxKUy$kJzjbl5R#y9Lw~5^xNUiiIk~2Z?7f7J)h61v?;S7V2EQf0Ly^|v< z8~@Y0*7Fj;#<-eyt2XKnq1e& z7QANmAFF2Q3Rm^>5FqSXw+8suexE(3K*O)vAy6?y^m4l}fKtFh|DTG=5}2yG@@R~h z0k?>tm0qe;D*Xh7)DIP}!yjVpyaHGLp;08vP73JC;i_rJv;zTcqBpWx^j@6*pO>o% zSwqA)LXxyt%qNyP<&)i%(ObVK2K&*96o8NmKGs! zWwP1%%G7{Mk6_%Lgx@zg8SP#`vyNraU{;do_glR>`v+X)YXYZknlmhok?utR{jvw3+)7ERqI{yA+ zWoDCNW3o);#LKCTn4KX_MV*MQ`OH-8zbft+i7=Ey<>M1Rw4%QraNnoZhiHW@_wT43 zY6SCLmLWcs7~zkdQDE+R#{g!=0eTGs9(^T1$^$`-L1NKnb;3uI>Za9+l2poHQ8GVh zk^kV*S5!62%MSH6tuoX#`ZMM~D9#rt3rB@PAMIi3EwQRy#LMA|or;>D;~PfA%<2iY zbecGTa4J6#$s~BXC6-r6aKEi2{5!{$pp?8YsIO#+#T2af_xE+-H$OU^oE44q&PSUi zB~TYB_aJ1JlGkxCgRHlmCr&tiXCcJC)PL$Kee*H@kXEwx@7AjKmOuw$~Akj=|*&g)OKhR1>+WN;3B+p6e!r?1T zC;7=zc-#d{Urf$>$NiOO; zT#L{Nv&)0xxvPAdmduPef@rB{UlLx}9QPTbo;t_vZ8w|JP*Sq6L={Ylml;!nX_=qH z4W;Dc=Yp0GtXWZ)F&xV8OEH}nR&AdY7MX;I4uKMTH8p7KsZ0u3VHTf(2Avq15UFbP zPrB>a0z0)faM=y)QV=@x;Zg~*Dj-~UdQy1m6aYI zSt^4ibL%D260`fZeKE;mezTE^o!16u&Si59x3(C2iL9(-7v>ou&Y#O&wk18p<~ZQ! zT9zCQ#BEs(Ws%!BM+}!;)*ZsN+-wBb1o9e{`)N`)etWO{$IjH(0dO} zVfz+e)}TB?%e8Ypbz`^AaZJ=EN&KDS<)hO6_OdjS|H!TgV+yfO2WBDhcY%llKX7B7 zxMDj?C5vsJ7X&!Xs{#y{{V4&bkz?)Gdmyp{j%49Ut|R!LU!``j=5*3&!(okBL{X|J1<#BT~0H zzd;-t)KMjo8l>v?CXD^jO5>w>_L%1Lb^l<4#zSy!o{$98;h zhvoMQ67sT=Lkkxm6gA82qk2D(@X8EE;2E=0t|Ww~DxsEqO;6vCd4{%;0;ldz5K$!& zhfe;H0!gEx6~ddD(XD>0yAK~jbTnm2s8GQp8ifVtOdv@w z%%o_i9gtB~V?3ZQIhb3BJ~6fx;;88h2~G9tvV}*FWnTW4z*Nb*%CDiD{&8yu9W2gT z^xh0#mQRa7%7l_J^6YTVVuql# zgcK^%bDTwsk8*qJ`#dp9{`RliPmug`)x&^^-`awz$w0P2n-D z4Mp@@`lY&v@kfK?6qO5%_%jlFWzn3!&d6gNu&vFt4R67&q>|JI#Eoa)i*#U~Q9P_& zr(i?eJ+sdHx~{=NaTKJ-8Kjj$ui}~Kx;g`4?Fx`-&hM4iIqddv9eO25JmONz>srs`r%rox=k z@}Pnf-0RpSCTgv|jH(J1)~lLE8K%mE2Nb<_j7~zN1CYl6iG&LYay-?WfR~u4{0JX$l)voU__}otO0DRPrlKins55_E+@vtQ*fn2~42{VIbaR^w6f{ zBp|7V#m{E6EszIK?+gtdr@MYL!0bKNimHkx5lt-^09Pn<)|l|3Eov8bEGXlvA?G3D z;Kci`r|qhHuh+I&jO*QjnDj!K?^KQmxO#4Hmoiqi2BsWdB-5ceiLpo?YZm?c{=t)u z_n*TSRL#!^uMl7H{M*d&S{slZ1^MP^b3AxY8T=GeiojFLlzuGS3TD=goo!&3^Wm_B z{niMBk?elrSO9|7`uPa?x<+nkD^n}CuM_c@)xSxK#*JfGw_f)OlV?j6L!;x)4kE=J zuBS-A3}%*uY$u*AR--&Dj#pcLKQA7C6%eD$wCi=+dcrHGVHP64f1P6hDgBY6)w!VX zCgzk>4OS_D>~a|IVV<@NMemAFNAkLQLRVFXR{2msX9#~W@7xPu<3CHsGg#V#p#qb% zT=+JV&G8?7Qc4ee*Hu#J-M-x-MyUCT*>J_nwV%LbGVjR>JZQHAW zxJIgML7^dZsh;ND>T2UdA;?{XZDsIJ_g045_^v zJNekaf?}8VH^=HsSIHC49b9pjk_E)dq;YnLk&cn4{D&g>=!R-t90-^{6X#Nmf*-{efi`F!o_EL@f}7iW~YQ7$1ZWvUcV{5U&qYcX=bS*7UjR0xPuc$g3IZO*LK8 zpBEZaICN+df;&zUKH~=2c<2!njTw-T>*< zvvYd78sp5-;=ERr-JOCrj+71b+&?KB<&P&*QTFOIN!1kV(tCeYuxoBFv+wZS=g)XS zpo?JH1B!Y@?tZx5=sHX_KF*MDdGxB~I*?V9n;muYaptlPiu z(F4WbZ($%i0QmWguQdr8)ya_iQrUcJ%_%uJA znnz(6iNJ3ODsN=vA)sUnuV>h*fOyiT>up(z%+QuK@XY}PDK3`?9?1%7jBqn_Cc|>u zV{&^TrGV_-oLw%6c^&l_OWSlvHE%2ch`_Di&tuWTx);hab83uj*9yB?xxs4yVa91tfZy&n^?*!r zUT$vTK=-v5(?Tqn3v^nb^z|{j?)5YuiG)RXRQZXo99bnJ7gL?NUzg)i;BgJJY;Uvw zYj_s;LrEIz@c}E=3F6sum^smQvqK_P{hgxNTl@gEt+td*oJOs0H+<*|Hr=Zvh3l7B z!h4Mj8X=g%4spkBNE|1NTYH#>eb)B4f<4G!E{>UkyqTPPXufH@Y!$dSBE&}L!-e^^ z)EX1(SPP-AM<>0ceJg2%uU;w#Q@r4Yo_J|PL8LAy<`^9l3i+=(Q{E%V9_=mTC|c}; zLE{*;hL5(VLy=z_;Yc+(Sah?Qdwsw~eWhMP_jew0OlB7y4%YcyZG-4H-7Rw@DKtq|Z%@J(B+S&ya7ES=^BQ!UE|MDh~)H^&hlCX7ue%++~`& zKMfJi1l$XxM=}=-Sxb`W1a9arRv%>sptYMCcw3@}!2tp=!KJqDkcQI8bggt0u2FQ5JgC0wO9T5Qk6(PY~NxJFL(tKRf1 zIL0%Em9>=Tk3kh#lJ~v!yCimN%Ydkc>+|b}7yNox)IuOkY=*w+M-E|NOHsMA{SO5_)!Ko7aCx0xTeQP75o(a&w zaot6v1d$hWP4`jy`%`A`!c&v%bw?*%EzLr6Gm@XwT?T-l*O&cv>SghQaRjRd1XYJ{mQp=Y55 zH)glznF8sn-IXgYk0dFX6fRcCOJbi`qD)2G-~UQbBo-?@XK!;M6rjlJXo5cv-Le`b zrVhjvG9`3maba!AsjbPTlK8^zc>~6wpt?vX6vL^FpGuzBnORL#B5-sQPV6OUo#xzJNF{Njkxqb*Mdt_?k>U5sXSzF|4R@(q+eRYZr zJTBV>s%RfMF>}7I=D_0Ia*GW|e<>UL4_YBam!J{_ho_?Gl(i%=PG4XO3qf|Bh;7G2 z7U$9sTs}q)ZX_S;%(fhWGtJ-CJ;@wMEZ9*GK>)A5-TJUsLdcOufqg-9$6L}YiAz83 zVB0wYC3=?7Xe^US_>~yX?`Fqk;x>1U* z_ZH_L@Nf|ZGuEEp{OVYe%2|20%ipjR9PlsaU|cA$Vu|RJ>eo7-_^^-e=7>bYop&s_ z{?rt=8Z@Q55Cx04#)K9_jsStvrvLlwLx2%y3^z+scJlCw4CZ94>ZTji(aQ85JVSPb zWrY~&;g0Ki)`Hjp@6`A*d)XMtO#LNS6%DLOT z$5YA4%VkooXaz>8gW@(FonV>-a+ngo7epMCa^Kd8mZ~HXMZV6|(YrU*7uqqiBNkZdNI^;*H91?GKq^H=!t zIyx2UxZ*pl#_E`guYRc8+2KI@N*LpxZkAZUW#o?#ofOn3MoDXt8o9Bz^8=Mg9BIw`-ieH79=cENTa5y(_0~`X=;0Y>N)+quCI|>wS8acog%sx4N>-FwLJxh$BiNBZ(JoQ z1pG#jiyz*I=c>&{$FDV4`2k<5lx?EOn(o&wMQoczK(eQ1j{FT%KY%?5#ejFcuTy{% zF!-<3YP~7yA@yZpGHtwKqa-rHVKN_tu>E&9D^uXs?OMyKOL%r;^YgPqj%$cjx3THs z!S-~3YfFmEs@A$OL5rbRGL)SA3Env`6DaBEXz)NX+rUo*(a1Z^ZTqTDTN7X>jJF?P zi{R5SuA9|mo;;lVaRH*;l-?O4=dqDl$HC5S^wL02U#M&69O|p;yTK@VKHj%{V$B5r z!Xgwpb#V1$n&6bR(tSHAJu|IUbL}hqLz&iFuVuN}sa|?hFH=AP0y4DdjE=G_{Bj?P z7|Yr6kjvGf6=p3RhSxJsYn9B||= z+~LM!#EG&T%KnC#)gqnKzF$7pwle|jgDuUCwR-TK3GC}K$zKOaVYmprC^jPZUUeO2 zN?wcF>3=y+-E9Ny`O#5Uh5BRLtZbu(jWCP;pkLu?!Q?K#pZx*K)%QoaV!XMXt09l8 zw#^UtJi&;n@Ssc!F4Cpzw$eQl!8TOI?ZrVAhijY|obNmFlrmP4<(lUfqchUb|CnwT z#wc_&D~QG6ATfKFgWMC&lOnuQ+0vN-s+D;JT}2I@D;y&oU>QR?;ZTdep!SW=;4b0> z)*+F?AB#(bmDJpiV^kEZtosf^@MprqN;-?J8abswBoA4uAV7??Y|FTy!o zc5&DGrDV^*xUEqmmL4rp{pEhZqZazAQ=aMtGE#g6Z+Z(`otp~g`H)*KB73{?@H^$n zK!JyR#rwccyHej%jX_nD6+EKnvzOsc8XV4iAp7!YTw3x>qrbUB^h@V0NcsL6G zyAF`XJ+Q)8ALU^?{<@HsLyD5gBWA&z8b4J!ZZl}SF^>4=Z3f(P(FeEg#8DR`(ox|_ zhQ%CkCbxUHX6p$U#Izmbf|Fl^>B&j8s;=glXMWzm0Rb6~I%;PApi@E{vR6rXY-M-%`BVHCfmYLJ3E& z?VA|lUjNMtllJM|F+==3ENtCv;l-*oIH%?m(H!=xMyPpFT8;y@&si%&1uYAqN!x`d zRvp`6yB#riL}eWVRh{ig+tdsGq5yM{Gv^Gl0${@q78V6!{DDDj(K~}L;?DSk^BJ!R z3+*kK%+2z6RnyN=41*ZM*W2ZZv#z}wDD$6W96Lel4D7r}`EtXCv%n`dE6(hUfgk>w z;DkR8EkkRe89bj+VyU(1cD2CY-x0R37dEUwXN~HO<)Pwsc8~BjCxt%OKA4mpKw!6QsMWWNs96El!G!OME=EDB1hyG_LEtng z6=~_Z3qojuKiDI%f`nx5kAz@izbShE&7?@z$Cm%sr6LFfu_tuErg70qhSU31=>W^4 zD`c_%;7Dx3#5v&94~X}`rs;eHLK0oS%a!p7f)8&53z+Ess)yYiA?)ypf}t*i+_U~~ z#q>UAb+mEfMR4W@=3{n$Q_;Wh+a62ugv7CETcUvQn6`lMMcyTl=M>35mjhWjif?!; zh$F@2zu^P2V_{D~Z6W2dSknNc3xqcakCIdM{o?V`$@DRlH#kK;l14^piCwj@N2LkQ zU1fEc-of0U+OdJ z6}+4n%$LS!%<9mWf~3dpTOLpQumSw~&Wv+d{#Dryps8zg;Vpvbw)Tu`Jli;WK>@O) zXN&~QV)uU&TJXbaju&C~Txr;k8ms(&gfRHiIT-1r@I#a2xqpq~J+z@5uCM7>s$>wS zjsZo8Q{K5mwh|9SoF9H*7B@Q?71vF8No>u{uDkQyt8eU0C?9?miDaz>B3)kEK^hoX z>iw!oT_g%6!n6t?j$uVIO4c*+aR`Ra;aLtIhtkS1luMEWV(C|h` z!ycT@rolqY_x0H~eeh`Lgwu4U`5wUU6SW2$KTYH;Cz>uEv66p1AtO5NpN*_9`eDNi zOi#`4)Ata}c84?cB?4=0-m=XC9I>h9Ejvn4H1h1;3-CZjsvDDa?ev(c;CF7_N5>n! z!d?;h_aqlm5u-tU*@P7264uq?vRFd~#$-rpbM826Y-AIc1s+%QJXDOPKQA1wr)NSE zW)}FKu6(YKbpd#NKuqfN|ANE&9-!v|rMr!()HYoHxF_*lP4r)LTyi;I86C#dSDAySljTu~0fpW3s%w$G~qLx;Y6uufxug63t~g0b5k4 z+uB@9WMJuP32r^@$Y}q#)GJe1Q@}TnCtknj2hr~>Z0u7UL;2UaU0B6(HneB)my&PT| zrH-Q;g=`wc5Uorss(jS<%X3~|Gzyn$S5j&;! z=_{u{JlesfJ&3&qo>ITdoxYY zjzW$_t(@j;lD-gU5V?;kut&r*hrlw1Ix7{4!4i|&+ETskO8|xFl9Lwl*J@qFA##2N zQG6|Qs_3j7toCfwoQFr6k&|`Yd9G?S#H$4kCvb!oG?}#1C6oS0^8YD>V4Y@RJNoBZ z_bXLe;PcFmg?;DRK5gQuID44W(DHGWf#v{Z?D3LFqbP}R;m8WqY*kdU%V~+#cO18K z8OzvN0F&DT9Azu`VgN}@+>CLeu1$VEVrXP2h4Su2IbD}8J2WgMjuG>T{E#$Fosqm( zXF`p&n2CyU)a!B8@+mi3oJw!)79yI1C&&v48(OxDIZa&eLiy}MEQUw|+Th;dB`D%J z?wlPTsL83x(>tA?Pwp}|w%k;0mGPHRIz%PfN6{`xB22^20E>4>5ABGM3vlQck1hIE z2Ao{m1IFXD?Hc)eSW_qn%doAhN%YzKe38JZ=|lh90ch zXUQ4GtrSUDS>QQNY;!_mSp}4f=28pM-7K!7ZSwbb|^9UIlNc-4#ta&SMQA6$h_o|{~&<(Z;#b3N+=)u~6k`AGF0RzZ8T0uv4_;s7kdX_qZ_oN)eR%H`1t z&_!*jS2}>Z%7kR@iyPvBx=t&~T3;*UZ*}FTtw*mvP=jEuLwfGaEJ`?5PAxiC^p+si z(3IxjK#Z?*(QGdJFxorr_elK8*c}n2Ue2li153wD>bgd*lXj!_Ogy^euZW+Do?5~) z;P(}&#ixHKf~Y{%3%Vv#l$5_IACh{Me}2Azh~P+CbV^?!|HPf3?-01EeT8jR`Xy$$NWNUN_JM>rTX+P0tIva&P3Ko9*-TD9nCuNTz~)AE+ttF$ zUo6!9(`0$Lo)Q5;KG*guuJ@fPHamA1rut<_!ZURm(8JzoLu7k ziQ2rqsm%34!$}@Yr%yxu8L`zycHb;E46PE0vhhFy9&#pHGVcB+7`}SJRSM6plASx@ zOaj4xIXPzr5@_z zq06bi4z{}sE}3UI>bwT}wtZ%yDok2z@1E<*ch11E zDWsbXm@=it_lUGRks_^@m8MmK+?679-YPm{ea;cxf!j;(X20^xgKgC31COP9xWA$3 zgztJuS+Jr`VGMSfF$DjqiM)Jhs4;99O|$b=WXy%o6p(v8a;jE(C)kp{xYn|#jxPHC zXx?(Juek6cgLVK-@UaqXGxZ3fn+OnKSSX{3_1V!`-GzGHE(k-kIN0FUtdG{T1v2X z-{Opt+jx~lm=p!7In3_(`1B2<=XelEFVcp+sPDv$Jd~G>D2ej0?(=t7dNZejOHbE* zLk-G(tA3#Qb`42k(!TlvF=R$z#@S)kHFiCu!jtLWtEXkYWcTbl3Ql`M7MqTq&v7e> zwv57aPK)h)_rBD8m5*D?fXjCzMMfDx2T|;#*nq@SL$FYQgpEW`+k#}05=^X^_QL_f z7+hY?wP3S=2=v8K5D5mGuLVO0m@py{LI5TJ&GH8}Z~K zx-TK&9;0IY2}CNoCoYJf_;0#9K4z4EciiJEx}T!jadmd|V8?Z&>ly_fC*jD~f$Aljz=&Lw>JAYL3W#Y>PCMs2__V|7qxRpRMP;hQ%81X&Lj^w~m zrkB2R{Th1l!Akn6KkuPe%YAJN0fmmAFFH@t*NC`KjJZ`a=q=0pQI{QU^(;4_P^qEjabS4`R2& z-8WE$HaVxB53G`ecAnZ>m3~Wfggn+4U@zK`l#oSKIg#f}( z)X-)x?jrII>Fp3ovyLOxX z7Z$zAF!*&aH^YPn$n4q<^Eq(#RM#_ta0Qxew(YmFoMR`)U}oyoqlY5306@I+{4wO%5VpJOd|5W}qoMoiEdwq!&7iX8 zF}A@ZLk}SG>`HQsgwqhAo3UYU7Xu>7jg}pN8ztLOniN`mm~H`f5ek3Ij}}S1ZFd+^ zHxAaAR4gMkQb=tlBpIzKDum+k{|LvTfIL=tGM$q`eSd_})G3*S!lj$M&@|#BMj{%I zyg=<;{JruBTRM?7IaM`Ya2V_&@>4{G0Eo*-5)IVC2-Ec|lC*vpLYBx!Du22!enx^% zt~c~++pm(rDUaIY{Ob1#i6T~)`Ftto!m`No0$_wX(WpY{a&~j?5$3j z0xi%6qDaeq7xne?e!vEfT}IVUPR+OWkX5hf`=^4vW3NtYRps9R@!?{QSAa7o>=VJJ z8QUj9b|4ICezsZH+7!<;AGok5DV8a{PeuI;(mlspwYD@(FL2n`)f0K613s&z{33}}2UaAcd8=?QKaJA^#2X`%c%prE!?X{>f)e%Lp{Htq}w z%q0Cs0g>ZJ^36-Zu}V zWeYyQ2zaG++UTpgJl}*ud`$>B)k`^~p2F>;y)5)Yt0@;2m+BjZnR%sNgbbA{}-DyV-;uskknp1=Si*%WMJek_dG8VLx{gv1UUK*c9t zmKoX8ExyjU!|BENa*D43=q-I&jNWLLSu=k?C033aKvkQhv7N5=Ic`yiz?!Df(-d5Q z{2#y6NQy$WTae%pG^LYs#EplA40Z>Lu<|f&XDF%NF?Y>E)23kx!ubH7ATMH;n$HMz zLLy{zhK@7_JG-yOTMq6@8fv)XXDVTjnage%!OY98$ZyJGUlWl|BF0RlIo{0(6<&=L zIeKlpknX(FbtqAoWXXx^tb_c_f02IS4YV@buYw0d1Q%881S0=hIN)~b9kbhNKH@wP zF*Ab($o$eq&FZA6(vA+)hNj6D%LCKY9`T6%6^xQOuM4>MyZ7w z+VP}Pq>PRj6^VXSz{Dox-f5#bkt|A9QNEuLXYbUBK;W9ESEiARjmF8-9Mrz`$YtR- zJ89tn17v#6We5jMH;Y)Y4e0Z#KKXH}3CH!Ojv{BUH8R_yE^_bR5!Kg1E1ovL{;epg zY!w{(LQ)u~blun}any9sXOQ=;d$vbga-G7uw)XJ~}` z1`@=eO+#_CdTZO}o2=hWAtm(ttmqoYjEkuJ7IjQ}nit|126q&E+FY1!Sk2}PyL}Qx* zo{HRzgpa8@mE=p2yp)o3vupC1cbZ2{W1I3!%uOZ;1VRZdOU*EdQQn_UqYLT?$(k0~ zgy1$w`$BS=84yMyK(A)7U?Z!OLH?G(M4lo>8p8sb7WPNaSyz{E57m$JRjB;|@7jZt zqVt{K;2k5^)&er@%>ePCi~9utT)`T?y@|#$Vr2wRu!f2|({sI-62ud!k6zTG{7II% z+CKs?UJd_i<%4Y4Re?;uW>6pwuw!xUlvb!LM-{>brI^>B?U(YcxnQxi@!8!*^tDa4 zqC;lpNFvZFsW`T0IDwga-2(bQZ+o$cM3?*I|7yK!`#RIoTr%23#$@Rwjrt5>rAw~z zS0e2?=_U%n!xmBUIyl>W4kQBhs>|@@%6}ts(1&m)X15O%)u2Zk8cr(X`oHZuGYY%} z`lg+Ls;S{LpRHXSH`zbg3BSNL;1X1K7PbFTuA$!B%RxzK(&``#Es`#(99g+G%n->V zq5xqZHww|^kZ9c5JV7D`wwkFK3wL@bWjaKTZoy}+$LcYX9%q@oKT0&9&6+PtP4?4>@`8>gf!B4ylT*}9xmvj=li@i6X5p?$~+6Q(jwF|TeE9i9OaiYJOAsj`OJ>=>Ar&5hgcoErZ=e)GC7 zlmco2No3J?zYa!F)XcZ<)+iN@srHo-Hh7#5SNw1SHo=xe*mY zpK3Ydq_<0YBg-bpx`3TeA>r?vU@AZ(a}tAGe7DX`&Kd zKSMROi_#~%SF9*K@KSqF2h?UPFgIYh&%NlAx}Z^4Y-bw8nr|c^&30s|H?Hlj%gKp(CFHmSNe*v-PSoctc=0}2Jhc8iG6yQi3_l( z2cG0mn3`T$_sPO(V=x8g4|BgM`Fed;C+9)lfWW3TKc`tfyJ!9+M?&&r@pQ2wrFVt0 zYPuw8rLb!%RVt79-Z4_DxO>d7w~u}vkPcOiP9$acNsrAV@*WtLos!EEvorfB|3x@S z!v*F7NwlBwtJ{oNzMLveDe>ji(L+f)$Qcu<37j-I3uL!1WWArAgQ<2wP%G%pWhwCF z%WQPkpBYGnwH#h^JM3S7{uk+8p8O?z6ptXfZHeSbGDH}Jh}ul_wH-&V5F}A2ZhOw$ z{KRyG#{3|RolPZ)xDGZ2qb?17(c3hZan?qV-~(}2Wkp6+0#o_0B$C9axh06-)%|(4 zC{|9-zmk@(QZcJ%RqE7B^78sIpP<{hWWFUHf}G3&3CX`_A6P z_x3?TVpVCX@+{`VUP4pNU7~EMI z=k!k84>UUFl-nMpbvP~zXQNRC4>c(-8Zf?ZLF14 zFh+l0cTzT8>r!u8v{svSHmkR<(WE+KqHMMiAn9ll5Tvs>NPO$C7$=a#?notB2=pO7 z49Mazq)Yz8G7^{87b+kULK>#U^1#NlRqB|I5jMEiuk!iYBLRL{fNO1e`bj*Mnr%Pj zJpGz+nrT1H0ZJf|NFbq%QA|!rX#wKs_I$noE9X9_`WtKjMT_TxwymEYpsLlVYZg@0-T9z+U`-kRU*)@#05Tkm7-78_ia#?b^Ny8PrH(AbHXe zaUhBo78WTibjZ|#-s4*U8Urs?+czSbny6gd)9M{hfG}_kdu@+x-tSx$mEd#p```d) z&;HY3+PyJR%w}}Fh4WQwi;KYS-8>&35%atBLDMB-Zfmw7k~f-7$eElr3_3D zuvs&)=}M(^;)m}y`?Lsku}>ep5P9m?CaIIZqO!8PRURVu7dpL=0}c(F-AEz7`W)G@ ziQ0Hs^~9h7;`wQ8vu4A?-Kv$(ZW9w3A0EjUa*iA;3c9+lO?(TBuk$zC+7)7<^cUiL z@4AvwpAktDbJ-T%1@6zh{zRHKw>q=s%ee{DWO1^sCaU-vUnb=vAo{RlMCs^`}aYkJ1!@A!cu-p$MRcsmmRl1^?_y zap>waB zJa5{I9h`JEG(7ANmXZJv1{svKwZE`uA4>tR+&Z_p)l+O}{sy<>(OA}wsYE_UoHU}~ z{l|zQ0|uK+C}SonDyj%TlZlyG>JUg#NeOScKL*S_;K1WozPi73gT9WAj?vOT;d^IA z!1ZQow|oo+0D{EvjFHjNNWgFarU3k!}8k0;Y=ym+&Gy}P?7ub-Qxt|JT?oT9^B8&;4=xN1M6 zY>qX2|E&uuU;r@x!*^OB$h zEK(g109esvLk(B>mdzdHC{Q*RmzU7`!x5-t07<#Iw~}c#C*z4Qj8p5u>ikC!xb;ij zEiEgs0Do@QngAxz(a|md-XUE#;6Vb5)0yn2EL5B^*t!kI63WCD&dw;)?6%UKP8whY3O9ki5LsT9Cy4ynGfAnb zukbK1S&yIJr^NB%(GbmC2f%fh(0l9E!;L$Km5 zF2mIwG@47UTADJ`U_}KKe`Z|*gv!d+#3{VuT-((Uc~YtBOjxb)gZC#x$Dw#12azb< zsmITBWbNMW0{SQ@-uyPas@00|>tEb}!p+TEaT5iBfvG3Bp|b3vx_0kPE)NaD`vto(-xSRO8UWO zB1H*hRFIW5lg7=+#x3gVG6K0OO{RWD9`*V6&u)nU&(pkk>5*Ary(gPE@f>qv_Ld+t z{f0KPEN_ni6{V^)1+54fP{#waE+jT;Q!5@w}07_qMG-K9tZ${4+H>!{O>Izb9#Fx3wj%OCnI`611A%C zYXfH!5;Y4)3tKZK6K5BDIwNZXC#Psd9Xlii1YUGBv=mxUsOF`QfMKYnh5`(H0@#fv z3FL*0ytI+h$&Lk^l;ZW+kz5lC!)Vb(GruHTxxA*F)|k9j)~X2arKL-Aokhg&SL!GH41IPBbK3(z_9xJXdxC9jcvM_3~_eX0*3oeO!;JxX|& z+Lw=GC^<%l5~jgJ!@or&KQc>fJU3w`nJsTpJA+?hWG?7;7(e^l{-e}J3Q$*S9oaiY zUenpcXE{aalvz%mnR9bCnnhtsWcN_%FCijEGmscYUNYt}q4-Kw9)`*(ZwuZ;$yJ?7Ri<2o)Z`HK0BQ$Vw#p z%w1F%h0`PaS99r8DC(0C_Kicwn`gt7ASU5L*FR;SCIv?1#9CldnM!ceF~J?~;~O%Z z1Gpxc5N~<#1NeVq&V_K(yc+iJe+wS~0Q>(JbN?sKvNa&xm6uWZ*c-dj$BB)1g@8yH z#zBZ6k)(lO2|qA<0p4MTMXitHJxGEQ(>a*)_jIMun_HGUk~)-<=~hCEAtn3URy5}; zY!tL?wqGl%tHbp_c3Zd7J<>sX3btNvd``1IbAM@GWBBfezrn-J39TIG0sq6hlgEno z5HAKN^&As|!*WW@#Y;Iugl|7nfG3N+Z{2lBAAP^`>UjY{{|3g-Njf7ycb6Y^J^@h5Y_Bukkqx z%BQ&5ZtksV=4;6m>b2Hp&o9f!@L2kBSQ#HVMTWcD5ZYj_j(EPU@%g|7tj6UjWJugl z+R!3uVHQdlD8I*+m5pUg{01UqY3v~nDY`;IbP+7fb2id7q%c680LM_dy`{0W*OmdR zZ`YRVF732k%V2KhG!W*v1pvwr$%_Y_sEZI<{@ww$ZU|vty^zo0;Ft?tbUY?wnJn z{(w5Ky7hVE-r~{)%NMexCe3X1LU>3G{WF`pjRRdy%YI*p0nIZ08~&N5pIwHm?_`7o zPKb1wua^-) z2+~m!=8f!W&>_rExx{fW2bxH|O&oTyEa7OM@b)+}(R{J1OGhbi2T#E#)q4M>ptPc| zguM;#nsKhf!>#!NvN?rnPGa|Kv!%G#(gK*zD7W|WP3DU=IHr=ctp77%#`=D~E5=Hht6Ai<`vvl8hTs>nvk+Ay@q zTIrMKjzULOA|<(VGiDr#zY|vJ(x=RmSt<)U<*u7Ak?oYsU9`$4kLSBtwiGsy@oZq5 z5g>m0A+`%4`30j!l|_7Iz&ZHx7%cY<)&h%TlTapkfRW$3wtv!Eel;b!|6&vA>~q?D zs(8fRtDdxOPrYCDNncWq3*?tJhtuMxeCtHDiCYtCkur{E(VfI(&hXrnIaKC_DEAQQ z1|?5qahl~W9W!CT3{9xgPIq0Jg+U6s;L(5?z?lkboJEN!j~|;Q(y=M{@d#_o&wsaE zVqZ_LT9$84c`h{kRXEQNZ2kFQ+4Wo)=smNH`5LemTNG9Xq8slxBImwJ?Pv3SesD+6 zm*Y*7u4;+o+S^7otVm1L23qW(ZFbUV^eUFnr&u-Di(t;VP=_-kNI{dRf>4l&A%Plc{KxU>r~doMbOvXrY}=BR|QXSVHBMeY`C9@&M{M181V zU-v7-G%MXBvci{YDy^;Dx`Ioa1lD+RDeEm**Te?(WcQbIajQW#*~+rkxNk5jv>P=s z#*|>Co%VD2iMtzvuJ3t!_Jo&)uP6JonKE4Vc*>0u-JWr770?RBHl{VV9HL!yZ|nyc z2%>|x_ah)9oKTm>uYa{H?%AUY<8DFPyWsXfJE)gyCT#B2qcit1j-02MBJ--SDMz^> zI>DEa`{wwviJp2(eBOP0O|m8@V_w-gx0yZq3fsTeJczHw>m9oII;bI=1lwYFS>a`m zEgF5i@Gs;sYMF;1WNJV+HwpAQkhnj@z*W3jOAD`ZYYR1dp^BUgw~ER zOVprb_$_Pj{(MZCX~|V&9i_6-5~C$_go*0x^WgTV8EK4RK>aFO{Hi?l&QNOv9f1(2 zQHV(BF_tL*AxRyI=aoeECJ;y)S`MD;h{fF1h7NQrbn!%VdqbqFr>Ccda5vEQP3(rI zPVSD*5`WsO<}mcnM6mgVC+UN8M50g}rpCQpDdep7o)Yrt+7VI{?9XIRbX>+V_5|Tc zHf~J!TxWhD>Dmo?>`eN{!fbjqHWz>F`%b`B(h2R+uFS==60kMp=K8gYt44^bCg`fN z40{H)&XDCqq&)qVf1+;>e82JxGLSNTJ|?oJ+onfOd=?))i6<-{iG=|a;j0=K8ve4>HOBZ41p0PGo zR2F+;?#U=zs8EJz0l9rV%$Py_&i3iZAXTr>ya%hnnI}_0T*_xwgBO_Jk?dGIb9z1` z1fjV*?MZ2I z{;Hd%bqM4uB*{=4-1(%}!!8$L9MJdHNs{Wd;v-vv~*6 zTz$Un;hP$O+Gd5&fcMZ)n<0`M<%;AB$h(|s`}l@fpK=GV;^XH~!j@KR>{iM5osn#0 zafJWgyM4jfvLV9bkg{z|ST#&|A!=_?=H`)U@hq8|!%l9-!Od?6ltWch`$2E=$9~&~ z$ZBWYf8i0EI6VRf(n8eQfjQv9_77#wsOp_OQccBMzCgFT`rWE7wgEORZ*-9!fYX;z zzG_R2u@z2iE2e=vI!ycyLC3KwTi+aoLpG%alI)%Es<)ki0Y{qg=Czz1E}ehJs^{^KBi#GT@rYq~PI8FZ%IU%sKBOveqYUwB7#7}3{M6^j^TQsu6`|?fq0I0LM zbs&_;HQW=^8>_T{D0Sd-5T9dLwsg+ZED~_`vj$LPu9~&0EhO!VPRt7#bg&p!vpO(e zmb_+#?~*XSNwP>!Rht=YyiTMbK_2i)*MMIv5%fmoIp-1^$M1skw^k-3(QSX6M`UUl zF_r(eqk?+p*`H>x{$1YdN`5_F-2GuCMZf9L{)xI*o&Ku+YA`Nd)&Nj!mN${sY{d$d zd!*vckX~tbG>++u0WiZIm5=z@=%^%r$W^>ERx!@i$W0{>}qr; z=PQhfTKO1kC1M=i6Gu$eQ@|+4*~La@3Q!g0lf@F$#h%233-OETag0&=g@Fn=&PQx? z8Sg-c9fNhcPzw_*Qg6tlOeP0_8y+a?Hw%xOElkv=A$xE%O@V=-2lB2`QsTL&jz+aJ z(P+E7X*=;$bCFltFjU_EHg)FH;8>`(9bX2KYYd?p1Pq}?c=CxiR7)qB$T#ZQm>+Ai zvhHL|LM*#7$}xnJ*!)4)y(k@0aWbD2m(F13v~lN5-WPE*vwC<+on zIS;|^0R7fl7l6H9p&Aq?v{kDq8dW2mEKBPb2@@WGv|EUrT8Q?o<>B)A!}gcK4q+}x zjblXl#XBE)DZ&bQI}eJh>6@94J8=iM5NQ5^UxMGE3%6Xa zU|TfkJ!wOh*pdv8Bu-yW)`@aIOGZ~&F}P+sJ)pW@O9F>X@P^?3{OJF|Uu5Jf*w#S! zPXQc~8mIp9^;k5&fq;dxF1)k!`O3EKz0OV&Gw z5}NGw9M}8c-iZCS6u3(c+bTIO%`RiaVUg^Fe{w-7QzB=?Zg?Ca7PY74&$6#n`W+q0 zUykI#n3uigPUhh_*39yxBsoaB<-v!QtM^`jk(Bjy#R^kX9*xX)X|^vT&~4M=>v$7j-(Wy1mfPrn12xV=YjaFfAk>K6AT*K< zyzId9=~GU7_xI1IO!#SgY?*G18?F>)QO^XQ-tTnc19cuoh#~94c!^jol;(RuP$q+| zKnJ{L#?)OLH`2K4@`AS`(kiKE^|8RF+{N84jc>UsriqqfW)B5q;UPz6fGSi30IlYf z4K5rD}e6{e<=%7>Vc6;D!SUb$gYLDf9{yljuxZ@9+HYkCOnj?0D?!q!+$`@$}0=IdH4lgm5et;4QYmAqQ zKE!>D5#>lnCFQ865qH=|a=;zfWUS=MC@i{w(VxO=q`6NHa5eYf-D3KMnbD1%L?$BtKz`g-M9agjP)hb)W zsdiQtw`KxFkGJR}2+!Rk;WA`)DCBjp`BfWUN;e%bR3RB?_=9CZ4qLqMCSJ$!o>7wdTsD zMpG3$9V^b|DnwKGGW~Ub4vSsdGZiX01&5t!GArv9FS1M~pKA?)9Y2rxTf!=*QUvALq5tI=Y`zZ{@*MD}m-vGys)DlC*e z!kTUtf_~k>HbT!z;>#(JD*as2uKDV(rit-)Tl>x&NDya-3JDO|P@<4cZwLcW z1(6|?$U~z_@dUs!vc{&Tc4=pM68~6UZu!~rQ}!aE<4as_f{21e7iiEotE8@Rixn{Ehj1-2reSbjMIoy-W!I( z`E{3|YGk6;&x}DcBIATdndYN19C~8}fmEp#5c^`~ITTy%v8Xsecyz>!5qkgwL1=P_ z&RD9hc5vX=@D7u#mHU83W2MOK8qw_6V0sdH@WH3sa9_Lf>Zw1Blcj!Rg>iACjiGpe z0~9DleLlf?17kEWb!mwtbQC$!$ z$DZveZ!`^TnNL$7`sd;(o;_KnJg_nHZ1)IVZ+lj>ToEZ7jL2-fN0relC8sWqUNWIQ zsBIeG7mJ?FsZGiaZ_JOvM8-c~oh4-xOu>c;2P9mXk2igXu7cen2@3H8RqTxN5N}Oq zd5WS4jk@&n9V3wu|ISmP`^Rh9bd%VN%Tz%3lK1tX9*v?nzoxBT#1U-b&6b~MzR;pb z#glS|)+4|;4EJeUWOXS&WIuqBvZdv<{sd+Xd&^>7M)f5*zu&VVVaz$JfP)2prh#pV zt~gx`KR-eV1qW#YIx6Hi#+-C*vA#OZKQJ&*)*{cZW%@WgQ<~pCXhR~FfW1MYDw5fg zmpmmtVgsgQmO-RIVw|HPSjMEk+lqBK`FMQjtiVBEr6>R!OuW!BqEu1QoG#E_$*77} zB94+e@&NPE#YG6ro>kg?nGPQZ;Tyybs?vLzR-r`cuVQuI#BGEsF;QNMQ;Cxd3r&v7 z++D=^SuhrDr+f0c*;e+;J_Us9e(&-gwyrQ2Fj|LXqLi1IpV!te1UOv3tUCJ4I#81Ry{#ogb1vYccj4eTN4D$TQmg0;Tg8B z$y0_V>X-HqgWXhEAW9j1*l4sXi%+gudU{rUd123j%*7%Ou)VRy1{Szxyuy z?iiWZA0NSua;7hvFt^Nib4hLhEZ??|ElmUTxHu&mX*LTp%crYyijZX|^+I#-<3Vq# z5V=3!dEKwPcW-|Cc9OuYcQM7pWTc2gFqw~d&?J$;v*y%UWG4zdocio5WKi#uHY2cc zgCj^g4fOvSA9?FxUWlQvgj|tCdpxw@mjw1MnzbV)kOY@hrO(r!aqbm!4<0`U*_Hg- zw5B|kV=&T6vGqlK2Pyqw>f*jkR0vj`Uwrb7yPfS@ce2AAi5^_`gJV*%cnE%{Fj{Wg zD?PJCF=M{P9q9^VDPbncDqpP0a`SMGwAZ!L^cVqa!`-=W`v9+5PxuG^ILVRjCI5)k zLp?hb8=Shn$0L22JFKqsX*>UjQ-_nHjJ2N^C$Erjs%y>rC4K@`VK*?vkKa$HB zXUxfC)%{ICr*cmi!`Erq7{S_+QX^qP_%h#DP{V}t%h~(H-1j8xpki}|dp-a?`vAo$ z5#sD;ciifO^uTzaS}n}egx#7N3@^I%Jun0Tf|EML9yfULBlstmh5F1~<+hH50P;y2&IysW&&TX4m?jZN| zB(O2N^da_~uz~_md&(!ZbrwIKcLo1^#81lOpyZ#})fZ+goi@kJwj|6zXGzoz`=eC;Bv;ky-phh_(Aq|#f)K+0 z^E;oglO6d1$_Ge$nmc5tT9)0{Ei7nbYHSs3ihw z&?l)syRbSLjeG+X$-YE<`eei9)emkaoomDcJ5YDwBHUtjUM5B*>$K8V@`Q-b8)z2i zdyQ^T*(qR~GSnwiEaOhz(d6+iZq&@q7|~bN+F`5A8`(osg+>5Rwo&3kyJ>5E1KW0j zhx9qHw6@L?8AJzUV#?6D8b-W=^-#0*vYu>hK4{hn=LMsBLKp=&RT-TU2ouU!M*`F` z#q9b9-#8RDUnVxGxTM)98^Pr^0fflooFy~b^ zYFjJiUE6&>s73<|04Q@o!gH~K0|TP_T!@jOPGWqJ`h4NUPKeCRFrr=IK`*#+seN@5 zfhgMDl;wWk+QI@&mn4^SM?@Df{q`3eu_ena%S|obBZ%-t^}N7u`P`(bWO_Qu(MiWh ziF0azFgRS}tjT#?s7hmJwh z`){SLl99cc?SG0nUzG{_1tD~Pv{Gi~5;t8L&!nbe>LUAoqI$UV0&=Nj_-gR+jBr-@ z66eb?ccR{4F=69=s2eD$KClI^_|b z3QUAd3j2&Uvw{(&@eY>iZ8NRgz?v1s;uYL4nK!EHgnlQ7cPka-HttPCntsJnwOm4O z&yExE?xf2!`O1Q-2-%$?m2;~h6%QeZ=&^bjuJ*26R|e0t3Z+bz@F%XcJkQQ7Lh6y= zmHFT_ZL#oFc~Kj>H_$`qmxXeE?eWSC>2%mLH=y+Sy>E4@nlW|y9#t-l7K;>2UZ-(brWHD zoRkp)RxQN?Vbm~56?Tu?>)%_-$Q{`d=s`|05(JS|xUKTGYh0lX2yivgc61x70kTh} z`rv{0wPqpFw~yy7FDz5w`fP(szq;ThxeDqU@s*?Iy6$aRjBAX7jErees)w_Rc zJW`=<#R;;)Yq_xT2=NRIB?x^E32*wpe_7I5?tB)UnMoX1s|pI!-+OjmeNS4xDpyCj z{-AZZniF*hgFxHSu+%0}Alp7wWNBB~$k*NT6+V)Qaa1d^&Ld@*Ya^!KJ!=@8k&--X zcNje~kxrqWYib`p@`Q|!ajy#NAy#0Q`|x+$sTNd7d7iD;83T>eQ~3G>kGLLWJFI`HD(_^9RRdk6y@v>A_lN>7)fdD2ci-gxf48; zr$(gm?9;LS(fETjw3-e~b{TvU$*->2qZ8L!uvo(43>Z-RjVll!xK+sbVrJ8I`z+LQ z^=_kUTj5kLKAKAJa2sgm2?P@7^4(^#nL2#voW{&7Ap;>>}9*2InKn(_PsT5Smwot@`OgnU*IRq_0 z=CWlvQ z<&S9sL+>$@vpI%u03k=n?6%P|cJ-;w(y3;5J&m!AuG6q6i1kbC&Tn ztBsShDK)pZrOt{t<1{b6auC-^w#_nba*^>tN221P6?0K?2%`ZfBc1h7A5u^-+DLp} zbY7hF)%JLmqp!sg>?3$SXj*n#%0?XuK);KleWKI9$TscgtcE}tQ>KXVrVJzQq2X(= zLX}n9waE(pc~TPdcEtUX&eq#3AFGj+za->cb>uU)te2mR1e?2ZC#TA^M6?D#VZNzv zA6Jyz@vMC(oX-mi^b;W*pIIdwI?2DLwxC1)6+7%$L;k07#Kd;VL#!kF*xh0-BjB>h zhBmfJf9YyfjQL4PJgzW2mYC$t=#?SJz2K3@u@Skh@?yfmB;@9Y4^JNA952FL? zf2{4QcK_xB`=tsYD`Bl)b`b8ZeeuWag9-Xh@$ zR)jN;JV3n^Mm2^?7v9phXItc~t);J}ch~L+Ac1c7heTRUqVF2F2(4%3r`qW;n{J0e zkYYx+S)2SCVGmL7{i9M$VtJRt2-cfQ_4n}07N+Ejr=LRc+)bdG?JM?87_w%QF!B> zO-ijY{&E5WfA1gex2|!4e)p~Bog&bnoPh1q>0ID7(>*PP{xh@@e^?*GIU6Cm=|CNqj(MdqIWagy5? zVz7yX?d{OBDXF!*jjP3rGlhmvsGMo(Cx&0}6owhbgX0_OgziX?3O%7Uz_JG$eZ{cH z&o`nvz@uY{cI+54K4vl8B_4i=T}`di=xDHtUi^wHJj!5NgGCKvs0`>URVT@m4J#1! zm%~YxT-X8qCr#rqSTNCFH0^v1qW{le;a`L3|FMOmzkpg$LiZc*Xr?`~BdQB0;d1+C zMzXs>fe1rErYZ%yFsxX-sC>Czd=Yl*@FHnSX3PcsGLQ;!j5m1Xa^(i75e$f&J zid5}+sIR0D_1?6?JgCn!2AZwdvR#G*g(oy8R&r+PUHJ}<^RwbUb=ZVFb)2o)XV8X; zY}|f33A_$2p%vb044kd^D1U8opYqz;rg-yO@S+r!PED1`qzwuB#fg;{bCqtN=vKtK z7I`=^Q4rpfaInUh*-X#7%GBD%D~?>}3eU;&DKF!{3Jq`WMS}?a8#I4{^Rnv^s zF|A&n*4upQc-0`OsC(B#p^eJuB?@1&(X0aTJKj0HJ(v0nd?qNfI18Qg##b8P#q$*t+Eh9uObRqvC+V{tSDlE(V38 z&^EzV1v_PSgIYsm(b+ea4c@Gw6rjDa-dr8$TJqU_Mo39+Z~9qPc(KW1kX787ofnEq zOQB6A#5F%M$3d}?W_+o5%Ty*Jfv4$+!3KXv0rR?`6DLr30UfV+DBU))Nn)<_88n8A zh14kfQAvJS&KO1@eEd-p^KoJNctBU=BsyeOV47}(iShX5eZb%m_fSS898ZK_NRKOnF3W!JRC(_Kx|EY5OJMJTb^u4IHxbKf4xxIC z-W5055{_Sjd|4z{Sy>0036bb3SB_jeOlrgaU98yRdD+H+(=KGc)5(%#bo1iZab)|4R`7ZVfLPhZw|>iJN&Ez% z)>|dqc$3?(?9e*&BTbj!88>C?s?D!3iLg|%VcET{b(FWJh~UOXzyT)xJu^$IwOQma?a z!47MXFiBA}K|Y?=q;12K!+cn?-Z#XTllj$Kruf>RDkYsLkw7d!lff}`yJ%hH@|qvu zejX|&$#U|!m1t!5@>&i-um8j#shd(U(e&W-X54gMl>`;1h~T61cE-)!DMl26n+7^a zC;mJ(Ve-%~V6u;wuZSKm(SVYS7L+?W0MZ))Zp5k z)*hb>PYXQfofI~w0mwH8-Kzh_S_!mh8lqq8nG(arp(P8!}(d!g`PIXAl(2^!i zEdWQOU+s`rJYV2yr)PPzsGIQjg25j8<>5@1w7BOFYBnnSeH3;WgbcwVsW-fu@^;JI zTkM6U^qqgg=^i^7^neZmvd9PmLiGQI^IsqCY#kUMwWTG&6Ekz5`5iP&oRE+PDFPbN zC9E=Z5J*3nL?BgJGO;HaX=1vQxd;fBo{c{2GQO^^4FsJX2FlML&C4{uWjQOGTbh^G z#V=HBw$A=;J|9oXv7o&O_)T{|Z+ZV-`^|ll<8rWIK;V%UW^Nf0%diK=XlFbqt9b{4 zgW+}NOh8pgk{#(=bWik(U3HI4_*xZQy6>`ouDfx|_%!~(V<^)9mFf=;$JSHs0 zryvkJb>f`PZI4_(34d4%eFmFNDRqr?o(#sMd?GCXm`H^1OrBQtQJYphGRa6Sy@!9z zD!->AB%Glf8@07Mh8Aj$mADK4c}T`6|8>gN%zb_>3fR3Hkcg=n2pn^pr;jehXkY29rk7vw2;T; zOXMvUBxyaPL7FBk+p*+BvG^dwO-^1t=tIH(0``hj6&NlLpe22M1V)R(CoDuTJ4~At zc00_PfKAQ9)8>V-jJt5f?NS+$N3I+&=D|m(IOL|T<(F-85~;E-!9GChsTJ3r@lk`5 z%A*57cJ0zDPj+v=>0;=hc@+nG*yvQ-bY?naQyOt2J4#d#E~#C~v~HRni!lHj$yGws z+=Xl%!;WoGUv3aE4OazMRU7dgYVb;3Hapq6WI*8oAznx~a(#%64Nar(9L=0kC=&eP z!I27~&BKkzo+A_t#>I&a`3kyaBwd2D$z4tSpub}J@picaq8s$bSeScrjl3OpPJKSN zoqQMrui5Q>NQaB=IpEwnbt!j#D5#M_vlP|M)?H^Rpbm%TYtPx>508$5w2wbmzmzI$ zV=9`J$eaMj=^<2CY7iZ0>MSVGt)Y`eV$@WMeDfGK5Y@`kI&&VOII!vvyx*=0mNA=S zqCNYk-9cUIV1u-q^K7O7tmZ9C6RCCiCAdFtgJ4(rwP@RVgNfi^x_8K`Bti z!mllq`r$D|3ioM#i*Tsh?yU8*dRXXJN$PTAh;)v(=$mN~!2Oo;U>cil9j(WvwK~#w z2#i)~aGezn$btx)Bcl~kC6+V8NtQShm-=KQ4KF?z1E7-^qXGdnD^rPjgTfZ8_mYz?p%9klK*cD=^OsS2L@UjfJ6v91WRg%0+@c zA>u6Y_@l8E1Q=ouBxw}UZNX5;e2($3V#10Qn(N9slD6%6#R2idn_;YS+3PG1CGq{I zZE_);auyBtBqVLynMXvR-J-%%iA3yj@?{3u{*L*JP~p~95Q zExebPf}-=UM^|4DZQ(%%kC9p}P{D<5slkX$*NA5aTl!VUgZoZG8TgFy=TernT<(`$ zp_6?}gdRGcM5YM^gBFucQWiG?6_|C!DyR%FcWlnJNBczA5ck(`aD2^@6&O-jkT}lt zb5fzkkNJG2lg6StSACUu{IQaQ8v{$<(za9>4D1Bt!ncDVjfnO50p?kX1Q|L=UDoa( zi8d*S0`!|xwWbM_tZ1b?7dPEJK3n%x#bktT?X21Y?Fh*!z3Ued*4bNd99r9 za{it1mS*#rVDh@t%~Vv&EL^N93YdD3zOlbqPQBhr`djCtA-8^nI22|gbcEYO4*MD3 zs@Wb_Lv9K0oDn)^2=5g0BJhBy`0)C}A*S$qv!2qt@eIvm)b{6+SE3c{aGY9qKyq{w zp-K;--MmP!&Y@UEB0b#Ti)V2vom^vo==Ut_Uf=3NV{61%%r?6sEcZCvY;{fLd8Y}} z(H=lv6%hg+GRh8lL^^mHcF>j5*6nW)!M)9Kf3FTaSTCnpx*aKJ={k@f3J|J?wNbGztv6c%L?S*5Pt;0>8LT0NAf`b z3C4?$i2mLKO_W@OPySx>8^V`ZsT!A2pTNIEwYVP^euH_MXSqt4y|y<7(4453@A7$h z1nU+z2GYh^{SLP~uAiO#e+~OSBe$7f>^?L5uftw@smDKq1Xx}SMBeoMW_F(;KFtFK zcl~ic@}ZvytpxV}!k&&o`bLBZV#dC~KM5IxDf^J{3KoA)u!ukVddJLfPCkPB4I*yg zXRai|2-53E8klGoSCRjC?zxsk6i!vCG&z(1XzP0m_i>!s9tpoFiKQ;d%uX~Sqa;tS z_<1l277opl-jG$Vk6I-_5wHqn0Bau=ga%4AvJ~{7G`!>I?3ug(xxS8mu4cu;@!q|U zPTo*mL_%-cN@mQ3Gx`2f7lP`a7{bNMl-IOjJEEo&CVN!$nf{C5VnHU~xGsbH7aPMU zMB+%*O(F5OA^Vf3-@15;W7=#;GyN^|fds5qL2i}+%4TQS{-T;9Wa~PY2NWx%Wjzz3 zsEC=Lc$uV0DKkhA8-v;Bm)%w--TC&P18)?jxueJ9e^hme#|?Rzk%qwX<8V|A$N0Q_ zIo0qW8eq7MSn2{!og^W`WZ|HixR8@GDuDBIg~Ni-=lc6;JsC^Qd}^p1+fMDn^-5Hn zAPGn2bSSn6WUn}Dm?P&D27_lgy)Vw-aOvuWs+*SgnDFMQ7_UM^cvr7L1t0-?1 zW7!I8g!Q*?X^ralkRO_q_pla_Cz!4bXrlux3^<BPb$$30bkbwpCdBQ*7W5P=UUKIjVq`SE5Z*_ZQI&!$~#3EDeh9~R}V@C z-*nxUk)?G;Kc%`sbu;pe0b>xIBzYBBm}t-TyoKw_wsNCAgef4Mr$@40`(a0lJgqV# z*@nD8qLv_8NPFPPnLeV+$gTly8~@~*9;XQx=a#@4-o18eK|iBrmRV42!yxKn^9p(5 zlG6_$1&_VtydhyLy@4FOAhD6(3|E=X?|`Wi{zMM9>uYx}>2aNcYP1RyTONP1SnwT_ zFvO6M1>56DQ)-9M-s05!)$FtuQug{+w@K=$_q)i>lFp_Xz2l;_K5gCgIO%xce6K$j zKsNIfm4s#piM-@(0ggs$$-w5B>Rv4tO!l!XTs<~I>#;0UJ=RO=v2~4~2C!5}p~63I zv{ZN~&Ksg7W81Vdxb36l+%?ak=<0VQn^(EQPTIJ`=E@Uz=A z4|n(Znz%3&mRZnoSb%0-b{HE`huQK*0ML*sQ>V8tC{!E-uqbP0k*iKJDu$;WtWM@% zg_W5^?E@~h*?>2js%nJ&zKfW?<3RKif7cg>JmVhhKdGqvuY zq{$G^cIC4xYJXtQfC^rkUKF?7}?XJrgwyFl?KF_D&vuzr@f}fR*z#+}AVk8sQ#f}(>i%qJU z%KVCMA-GZjNKuM*NkF?qkmy?HxBMDEm3%Nk?!h`hIRtcwmA)gAR<6umG)?@zUIA&y zB&g%AY9M!obLk%D<(21aCEX@iw{ZZ1TkiFr)S@q(=9{R7szSp+(|lJ232o$wHpv~V zS6r)N`eDrpCz`VjAKbw5Ky=m0In#`D2Q8X|&MLr;JDhXBfPKpq<&m^Nw3ARuh`TcN z1G8)ms$6gKy$#ae3@N&{YE$0eEI*>lxTnWsVUOVFYO+-#T4Exa>LH~n=sH|pC|rJO zq$QKS9O>Sf36nqyLosXze2F{v)X)of2TSzu8b>5BLj>xKxbCH9NQ&CK&WUr5BQ2i zYiNm@eIW_g%_2r}S8NF=iCNoVzN(1f_$Uf4*CFxjiAPY;8MG+%t@$e7(V(ioLhRbe zMPb*BRhU97)`T=+0VUnEo`vBs95GTDr##jZqE+WEJ1c-WXN}DYX^N(zO}Fz~;DMQ= z>NZ`fP0Bk_c3r`c`hJ4j_wdR>`Q;@;!l|5t`r)j?$S9Yh@@;v_2;PTT>BR3pfr$+) zDm7e~z2+alkwu!SvriU9XWXZ#^e}ToKbO7L8vMiYiNJ}O#BhR&wfuU6HtPG!{MUK9 zxRPc31bgDPwaOfA%#jtVK7nWcBOTgLZDhs95!eP-XghdQjG>9srC>4Q1#L@-lp zwz9HD>X1r3sTIyJiMfIRLFP#8`pxe5RX&+INZBe0*NFN{J=!BvPiuKRgOzn-rhLTu7` zCFJ}p)v(Syvx?GV)9y^k=^vAi)(OjjFd)#WX{J$JF4yV|%_%(DJ1Jg&K7;U5E{Jm{ z!U<-2gZMN5^b$$+muYB1lXJ1w^{rW<*J$~S92~S@kd0KR9|ngD>H(VOjAL@oY$@_yvtIPTJ%g(>b{% zYC$}mO&{oDc-^`syv_1V@OEB|%(B(eCLD1&Fzj-0u&MLGX6XI?a* zItNxe#hm{@R}$LU-72e1F1$P?F97jKe=aB`zK;vbWRjsIAVuybfIME*?^6 z%7x4YiLX@MavbIjuF!B}(GqnXWv|g_TaD+f=R)yw=%UeAu`X(w)aE*J+_fduQV+r? ziV5TKZqE<3Ig7I&(dXPU3QGI=!WBacQbp%1;&Nw-tb8!D$1D~^K54QiPgKBHHZkz> zY}%50`b$)P! zl`3|KqBtmkF=d*gdn>Nd1wOYRQTHGcb5CmmW?0O(RMG(jIha&-#H9mA>vav9H0XVN zUMd4G)w00&a6?n5WSzSHE2?}NW;Y;GwR}Cr5yCA`-Ey>xj-pvtyaaJm>_Ma@iGf_B z2inwu>;jwGL7mQlW!cE`Y`08lT{bAH;WmH6c`cvyQtt_oH%bfRjqxoxGF1}>Mi$G_ zw5j=`s8RWu>8-oPtkiPUqri%HMu9L&r0OmKYt zE%FeJnnHq@2F)KzjtFj_*J$&5f7^A4lS3g)S+pw84e#U&KK_dxKD4g=IIYVo)61ff zZTXZ|kGQ*jElK$If{#xlK)6q+SdS>lj`F?5Lwof1=4x}#hFN<_(5k9dT(zpXx9t=! zM(8ccV6FqBE?)V5GsJ$D%)DwtPtdo4d`+7LT1P6|Q~GhBWgR7gOF&?IAIi}LDehK4 zAxFocq{P$B9Lb=h%3?aKB&KO>3Cs$V_MFdaFWFlcv5N60)>f@MCW%Qe(?PsB$FaiDC0>>XJ3?_H-WpVVroOHE(jeYQ z=-kelNp7pcdO6R9JyXIpQ$ih1z39PkH`lDw?{qx5;Z68Sg~4#eQW8s+U&6uws9{8? z;dDGY3`DBf?gFN#IkQv6ZymA_EmXM-rSh)gQ%svDnWr}FW{0E~x%O^++2gO0>}EcE zZ~8+_BhK3=#`XpEA7WEXQ-z)=(i0v@ZV`NdrjZ-1kE%Hjg8Tmxc8bEOl|Ov#dtv+v zJMsUEV=8LpY+`Hn@7dJ9>{7S?s7NJpIiYT{+2s{?$-pHQ1!PG65LZ%`7Kd&I39dk; zWow4=jx*71S#X`f3Q&sEx&ie;-&e3!hIPe!cKe;}a=b3+=l7177cGgA)vtns-EY5w<2py6{3I`Lg z4CU7+FQ705oFr9TmzGp!P0jx#jLN^Gz#DGypun)Wihbu)YX$wr%3}|(%qut95`t@m z-y8`+TK`VF-1+A(ny8>c}5jmCS0oV*6ZLJr8x*E72t!zk02S4SZ2o_y8$_%;JN!&kZ8rH zZAKMUoaogwF5s)BD78`;oVqQ$cgK7MHus}unOc|Pj-6zS>`NJEs+h5;xyD$_{MmQ?{9yd2!M-Wl zdQtk7{+xcLKLr037YBP+X9rtbGw1(ZsZ-Pc_uVZE_MJ@(Dm~O;Bn2%H+Cm>-CS>9y z()kqZzPDDZF;@fbEo)n-{z2h8x0EloKhs_eJ?{Gd?lLknZ?AC>sho~ZcYmLr=0BOd z{QS7T;{72`M?M=|DNW`m|G)TptEjr#rCT>h(1}hUxVyXi#2tdWOK`UU!QI{6-Q696 zySuvw2^`j5|9^H{tF`^zjGJ*eo>5hAy}f!3KaetyoQ{w&2A+_b+JS~E5aWsP=dFBx zL>Uz5FZ>R&O@H{-Wpb#4|197MR%nN36k$kGOX9wLf!n{ zb)ZmKy{)-Ud=o{x*fBIUOU(A}4MuC5%qj4zrecw`BRW#7xAx6Hx z8g`h8#&D@ApcNZ&JkYvpTsFAJ)ZS7{T_`w=xau`e^Bc2*O!Sw+o_dqS)gO^Xjs4Rf zQ|oO2k;a3_sWXH^ip|prMsIS8pyjGryAHKL-`HHADu`SJb3(dZa%J?R4gk!n?}BRStnx5TSUArKUu znTC+&)>mi;!?tYi_uJJ(l5>8{M4Vcp8B34#f?t1cw52mu%#}cOk%CXXb7;fahTia zjqZ{B9YprFOyRDiyL_tGVCjD_;2;6<5TxJc~IdO@88blQES8F1S^SL!$aE3)T_rZlFjHzSm-qgFBxiu+z8xE z^<1N{F_DvF%g+Bn!n&f_W6?66(7kNGy3Dwn?A(a%Cg2Cd9PFn|vm=AT8YKs8|3LeT z89@}-5D*by1whdTj-C-?$K^<1CfWHD?Iz1IaQ&VxJT)svJ1jkXn0=tFiCBnYA^|Bwl2%JT+BO6Gt`p}`pV?5U1NQD zNIP-IY2AK?Oe!uhtTCLmgHtqFjNp$0@P~F->|k!D9fXlf9L^w=^{Qr%!N>y!?OTk6 z79Cr@oK`fcs;t(@xA)LY1`$S~XF97LMgQLZqi`@C)|9JAZhMxrm+E4X^lCC3!$`bG zE@r}-FDiy>glaR|63N4SxtkSWj|FUzZx--)?ikjw4tmvok{u?$vkcq%PA*7cBD3Qg zVG*Ioakeso{EZl0x?Xy0?f_lb43iVFlIN2Dx?@kh?BuzRIB0UUWL|WbemW#2&7=#Z zQx+Y3>ARuq+m;hl>A+vEN?}D$>PmcS+86p230aFwpDfS11ct+JMaibO;epz^zf~gp z{*2;IF!(f9X|U?xQ9bM*49_uOy_^DOV`0OvgENm+&YnWiSi=q-?`LSJ{D)v^@xNsj zbFhhQacWYniOrB=AA=dDp0lf)enUuau8Wzu<4za?iJe~z|E)}& zEWp1^Y~j-bYoA$P=rim81LOa{ylKq_$b`%%r^K$oPKriZcrcqp7eH7m z(E}_24-6*`^!xI#aibYYGaTi@fwEg2(;~t9ne-u0d9U$8YJszUApsS5Yb<7yxY3<@ z-rg^OZT6~pgsNJttc5?6ev!+m8Tti+c44q(8_P=17vSdkRr zGjQXA<`l`&(*N#jd9@f&? z3QwwkxS>1<%(y*R&VjCjZ2M7TIyYM6`n{++D5hiBqR}4}fzV3N2Wjy=WL9f65jnPy zwoXrxqMccE2QuxK9v8dV9%+)9_LGH6$&XjOW#|N?RN<=+F|MuX8kHj}m5e@%DHqd8 zmtixAb6X*SD1{oXujz^jRJ+$^wNj3O@8N8$9gsf~#drT}sE_rwBBA~h3+R8wg7x3k zpqG-Y?VKR8*Bqz)51IHRR4M6`&y$WetmAQI396KkFq~b^n3oa5gKGN5hzqz+xe^sB zwD%VQIHog^3*RE$mAhOH+fBElsV%*3Fx;I%VqPoAl0A)I&Q>pOmqy{!lq@Reo#Yh{ zakTj8)cD>EaV?gzsalmL-oH~g#!7AjYU~-2?(5{Q+t?EWROPXrEqHN9-edr*W~v_S zC~XW52fG@xj*+lC&_>3a3we~J!Do)x=XkYIWR@?&(Iy!F5-8g~Y~Tz>nD4Z)8a#&NZDBojH9u4VhIk*Bf9 zmA1^CM4H{-Jn`mQl#cI;NvX14R>9^yNHYU+Av)*RCcj_d12#NKyJQDToKU%4mw-Q@ zZMOA!r9`P-rM&yuuS7G|0#>by{W`yTr>jHmE%WRwoA@1HLsPzl29Cqs{pv;-`t^uX zx0RZAjZBwwi;Ht(VdOsKJhbR|K7)RY-KbU6qw*ax8i`+Th&!OyiK8iaxsxj2_Mns@N5%o*-I|7iX{@wme`Heas~oddfixwN8=0@eV)lk&L3ae$_f>Q_+RvD>any)Mc- zkFGrxvw8x%>-f6s{2OOUX&>NFdJ5>>dmuz;&h0JgyP`5X!_dj>nx3byx7k&~e4ce` z0m-)0rmE6_tEJvPV_EOkqqXipwc??}h3w)cDFPea+@b~NMRtGA^A*=t&v}c;B&DMX z6XYr#`kH;v0$2Mp##=`rQiN*%aR=X4g#TFGkWs4cWNkMv|EFXYTc!#xn)~HS6+mJl z3&ygp%xFb~Kn4g~aXgZ)K8THy>K4KVjIOCN>K`C)lHna{3Z=;D#OWMU4?3}Y@lZX8 zR5+2#Yz{KmcaREF*IY^CwuJ!6Q_5o?6&^7-YLO^VG|JWVd!-}JYxS1*F|4e6&NU#N zgaAI8?ZlwP9vY%A6Eh>sboU_%41$ltewF?}!pf`6zji>DspJast2K+hX0P z*D6ar%a?>_LB0r$1~gez5sR7b(5N5cwDF5`QDN^TKqL)**@>0IfMS9ak*H;A3qH{b zJ_~VZJIT~~3q3c)sbz0Kpu7885qZhJn;oMZ&s2%<7v>Q5QW4!qanQaDwh1zlj-*$W zaq>3B$g*bHqkvfc4OZr}AjmD1D)w-|%wM1t2DYG=P8h@~0GeT+a?g+soz|Zt@!@1e zWjD#Fk!Jvr9C<~UE9g2O|7BqK?3*}2`N{I$KZh>%|7Cg07WH4o4Y=B#_+M)Uebg(_ z(J3!f=KkoX|0qmLQCNfQe|4xhSUreZ#~Yydpa2dIKofZV%eTQs5{HI0c`XyG>-jLf zb>}IYKmhD~dj(fXyy5E+>v9t~ZWR6F+e{|v5ZQB3Hwcn{-pk2_ zV_ClXsTbfpnlBO4&RZyW!gZ2@^oEfPp?Kx+q3nc-$nbEVUllWZ5|Voacch@#9?8PL zA4OW@xXur>;U&roC=SwQ-&26?e8~jQ@+oWUCNxp+ti=R5lnneGXRZ>aCGfAIC=qMJ za(sFVc^Y=CN$Vwa8q|{KN-d9SMuQdI{8I%Wj&mU0wV7s8tYr%4!oesbXSbTKu`nDD z@|VR~bCb$;SOs7$+M4g=^uN}|si$O2#ZZ>pn^ZRsGvYvhyE9a$R3n#V^5iRGC%pGy zjp-49PmzX<5Wu<=a_sqngWE@-t>+b?MH`2LW*uL3_Q|D zzLCZ}N1r|a@>O+7)P<5ywgG;G1~M%9AdEDpWPiFfgp95z#H0>YeWs&Aa9F3(3;pSs z{rCgUxKUM;RM!8$P6o;8*QRry>5=uH8RPh0#{QKa(K41eCDU7EHO(pM0^<%9!257x zIMGyuVH3l&1*!i}er)7$;7}6}KjL6z((v37R`CF^n=i~VX*yHG= zy1k=|U~;}#z0t$%FKHXA^yDe=S`f@N?z~ZT9!)0mDJ>6iBKY`O zO!)cdt+>TA=x*vG(65y<@a!+R8!z{&b1q$Jz33U8z11)wxPzwLEra@~u?1tf*mv7Q zAGnhDkL~ZX-weALa%?HNnv{B*hESZqqc?Np40=~HcdFIBthSTBADpwZ!^>tja=2e) z`h}jpty0r&4zi0!`+OC@q@CD*eu4kbgW^&Z`SHvr4xImt1LwbS__XK!KfRFp4VT=C z213GJwZymt>I!oH6#a-={W?h$AS}~0>jt8eKDUvJORhlJH-d;zr1vjA2{)H6`7;fn z?JKD)PwRY+hnvqgcWbU+rau2e)Jv6}-L7D0d~86XF`@MxRsRnTY{={iKoAMeSG@fA zWlFMLyfJsGMj2hE4hvanZmyH8J868%swqGJ&DM~(OxWBB5~yaQ7r)%aM9mKAU_KOr z+pN41!zB@Iyc>1XGvZ^@cg!~hOB7eMX4Pp2>#*oU_`0)*V@~OKT$6Q{pmboVy9JMM zX=j(rkXEvmL5uruMqqlm!qZ@gZy>-iR`EpPTkI)x{7|eLO})SmpA0KA9tC50@iFz% zsYg*}MlU2JFW$bkXl81DUe?mvxyinotkMW@Pf>6o8=7VGVqO(V-7K%N0z>sw+Mb%8 zi@{gcw&ep@f?LugW4Grkd{d{*B$u;p&k!gbl4KjS@}+u5WQXHBMu;E{;oz@V%>+JR zmI5m;aG$s6DuuPe8kAlGxI2%W(VOms;s;FfB|#olXGUP*1rm|{O11r#Y0{~NCocpW zd)m!Rraouf>O)dhXWJM=!G9KhI^$TfwtvcNTZBq9Dd+C~3kDzDc!`})7{2~93|#*U zgO=r|?aMoP^TbePXzftLreV7^u$=z0K^B6nNl9KAqeSq+nu^ypC+E_y`{OUfJ9@SX zGRg_kwRor*29vu2+M#wA%Mr8Lq! zb<<@haa(0-Kceh5V!Pr{2MV)LyH~}Oq1Z*{&pjl&#vd2Tl=JsRe2GMQB>a3H6^s@(8|9W5$^QC1LY0<$D?at;O^{|B8ha>%K5dN_NlW zqSsoOsOMXI&zc+C*9hJc=eknHLGiwWyS!IE!hRaDp$X(GuX;w$j^nDrB$-VUtB>wL z!!_4Rz^jSjl&e#;`a-*j)P-=9RqdakV-LWKBs-LKG))g&bC4X3xAqfP#n9%8c7Wzd zwGv6ORj6nEUJXwu{xedLkF=k%eikQcpM^H{|GR6d;A~_mYwK*|^ndm8kxKv8%hRL5 z>9}uXSWPBV+4PWGg@vNj>D!TykD2<#(Rx!i)=kc)&C>s;ULGzM( zrPiKki`8f*$Fdi+LCrjEX7;Nn&HKk*@kj4Fg;b|WM$bHe@b9aa=se071X`>n9o7%H z8%Vr{aNpdBRXNTTZ{llLbtsOP%;wrb;0aAQZb8p|yHekMa!n>nh{v0abO$k-On8k) zri3eqgT<+Bc9X&&XQ`PbSV$?@m_-0<&LwBUxtv8GHJ-xKVq+M^&4zBg@5+W}Kjyqw zjN3Jh!Z9=oFOWErTBtwQC%@h^6T~y4?yC2&DcFWx#vO@c`FV*QqwdI~F=jo7b>3c#Hvd`svS;vO5@fghMe`Q}R;s!xBLnRgx2bSi;uSmlN2@@UplfSfx+ z(pa*`FRG? z$A8DE#P9!uA03+1@Yb`kPWhRi55vebmoY-5pSrjTNJI$ZdDiuPgC)1&lq z*=wnmwtwPnL&E@uowt7hvp~kP__-{Xd0%g88lQWv0&JMp*s=aT)cGi~7uhzgsg~n7 zwgpsaG!wdywC*#0O}xfCGuaSVxUvzq>MGl=l`5)Hc5YYR>&$xDU-w}sp*hsQf*V4O zLpLqM>P_A`7D**$mxrZVAEazxDdZ8f-aW)k>{rgJ|xxU>eCL;Rv($`D=eCDv60e!nb_w zD>?>qe;)zW$irw0{gFWFx2_`+Sju~0O%i)BfqeVUMRq7a;`TLm37Y&gd6ardrNtjz zKz>OiNq*T+kb&@kLzNzd`$N7xKt&Gk>2DfaKSQx&A`)cI>gWyq4Q{xV zuCqSU9&voPbx`4C%r+sTJi&?G6 zW*QZ^hE7FIuiUu9*)O-Dx$+JIJi|u^STK7SHvUAi=Apa-vtQ0>ejZ)>5DhSjvmXy` zD!ub!1U-xX>F8F{9`ONf67ds&eTHr@LooP-)rf*g zn3v_3sXdAFM7c%e2etF$CSmy2e~1KQpFN0ROTVhc+h;}g_rLm`{oWsr0PZhex_rKT z!To`2$S!MB0>%oC6IYR-2?-wxe0Oc^^AYw8hKS@Dh_z-&uDCW4|0jaQq zx=WihE;?l8dBkI1#87ZrJ|`tVo$Q|4T=sd6x;Sj5$bJ8QyuYSCUA8~0&rP+u{>gg2 z%hmZ}7vdtyZ19aK|cJ0Hn;`}DS{XvMeML=F}`7Ew{ zXU|-{m#uImUwV(_{CB;#+wPX(S#9*3{GE-jE0?QV)|BJ=s^q?N(#KAi{v($Ez5Fga zBgV}8t>R8EgK^;PkIGRumqE(&P5b1BT_4Py5dq)({IhrPmtuXtIS^+cTH1F~SeGKmw*rG*OFutbAcEU)U|^`(+b&M?aS2TXAadC~WNfXD9w@xt%Qp&D}b1t}M3 z3x;xaoKo`&rAdor(!PO)^ofTvd*;xuI12^etDg}Sp)@ImwRsbcJC3K=4Vbto>iPA!pCY1LU2glG_lq#f9=!nOO zc;&44v&1Tk4pmp}(&;bpwoDVz=cR=^ z+rvh-&ySuBnEcuPC^ASs+lAA79z(NFY)QjkLT*{g(+-Jbz2w%>j;`>lAh$v0K%HAp zptZqhRya`&Zi(CsKemD)3) zTI?psE5W%X=1fFwT|A6fyc}8)79DI}M(@EZqnwc$TBsxPA&zI*4B{2r!!J(E%CVPM z8g9=Vk(TEgzz<$NLzd?m*uvYz3U*6s<4-2e`o^G8{muC%4%BguTph#PbsC@-)3(cY z!+kRof=X1k_7tPv3(WdYLVo_HQ+gV{`H2R?_JjGeGi#n`V|DdCCta4 z7ae_a1G{6!Zr@Xkc#{eueCV+J|#Uw)y>( zNUfgJO?f=RLH69RE!D28eIfn(^dLVmNm;TQu3@G4m)y%RG_#703gs8g$y zN?N=HzMatKG;LN#pE=JGh`;>E-(*0QiXTM(J<|%6nL3^H^_Y2LwCHxqIrTCIOO9QZ zmD{+8zCNQOu1zL!1u+$L)rGh+MfA#JTm?d$J`g;oxr@`N#N8hl)_=kED~WwZ423%q z=b{A$;0i5}un3I_7i8mJ7)zVP(ubeu2uCaZBn0Y*HiVO25D!nY8kOdT;}9C2?ciz{Lqsp{k=MQvj5j_n&jldfYPt%67GxDG_9O7wZd zhC1}Qk3q(*%JlieOmeN-_|kVAs7cZJ!Q(_~Ioxrwh$}Luw>H5}XK!T1+Ei*>CgJzf zV$rT63vE^=`pTZ2HXpxL)d;r{kLx0ZZaboi7U0<%=8BVrxV;wJJHfJjJif>C{A%Qf zDpl4xJG+Lm^qR1NLX74>c5+XzS?(?>E$rairn1!{FsIHwxr6%KwW!+cgDThAhi*4z z>HM`;t2@Ppr4M1bynE}&Qfu4B()CrR7qQz@%y@bvMd;4+Se&M@m3LFaTTQDu@kgye z*7%vtpl%e#lZSje!?pn<<$5XK^sbFHovlmt18eIz%>sP;qsGoH$Brt_UmLahwJAcH zro37_6u*t*h2?X^wsb#yg1lc`MnoHvE&J4EB21gzlz0zJRzgH|yv9rsuXs`gG zD>lmUox(pnX>Y_H1#A5bCyM1h_Gq_`|#au_t!=HX3W&&AwD|Hq`~S ziR?{vjm8oWQ*{4^w!lV~vO|u^%msdj4o=o+dzi2pOEZ{~WngEu{j9y6CdI0%uSeo`^Rr z{?^b#^)%JJo3=CV zRn?ZiKOiWbWGVfHT#eIw1MQVBuM^VK2|7baN0;`0=!0dgy zhcN=2jq8U)dlox4Z~#w9_C$%mdN-Qj7;m&2yGA!`cBs%#qT`N!sP!1E_Yzvv4WGfv zi59pss?Ho>7Y5ZMH>8rQoNiPaFdLHuz$OIZ+g1PQ&w@!Wt;ieIj%+hc6n0eVndR)e z8tPirj4M(9%i=nC)3QiXTeNMmX=KGw0+{rC3Cs+k+a=a z%cwP>(wZR;xAhO=UY5U?g3YBb9E~k>2iR2^D}F75MT&tNrAwVbIkK83cg?ZfGjuZ| z5E4ZC(e@1^MWSvAZds`y}S;1>gAh= z1zXrOjr(Cp#wyuX-nvpPqpJ!0q2R-6^YXx$JDJ5C=+R{2b-0sFHSfg>_I+SuqEli; zDc&~U6BRlL9X$3kE+UuSU8;B)v5}n8Nb_I}JY=qWos^a!RtetDd#bu8@`x2g>ap)| z8so|53~k`L9GP3@12qYYDUeU*w}2@q)^2C%+PaqAD;PqCt1~QN$ek1nQ`qKO!e#2` zchy5kb85`IzM9F+{R=<5^O(gG%tW@!Zc&F~s9uQNY}B-9uxawF#d~ZdpCHTDw9D`_VPmeDI>;~C6_+X%T{k*^{6m+7T?BP z*Kr{E6`@-&4vf7?myPCV}0xkcRp{X&*0J{*sK?gnY& z=n>L5l{1lvU>DMhZkQr81-^bG&^BI`72P8NJ(}INq;}(MLl$qIjABL=nP_y3KTS?~ z3(_k|iQ)*(X;bxirh$XTr^u6`UMpv?*`^Ceg^bzpBVa?hTlv)N6-epf{UlYOEA5p4 zjQ&{!$=p;WPbil@_zPFHydh}k@zv{nh2GY&Tq!~Et+TGb9J1$wi6$yA+ex5dT5an>@1L9(7 ziyZEQDr0pFGLOv&%yx6?d4Spz0L<0~Bnh83@H=W@Eo@*Py)o~-SGTeX9qoDWp)6N3 zE>RE|NVyM_e+67C-n2<8*k4W8&#Hl*@G5U7qc?Se^e2~RRlE=M|E^j>O@oO(VGS16 zzNdUxcX;OyMrK+|TW~wHHiw%z`I%mx0 z93SBa!c;~lj|KZ6B)L9B$fX^akKkU!J04?JKZWr8%^i{1+0QtV zXlf8^-~IL{NSBa-bzk&nR`0i4(Vz}Y>6Q`C63lcy@AY_k2B!VOTV{~%BtGjt`X7BH zg%hc!e*Lu-#6)z76m{%ymeF!RQ#jwMV=)NO)ZY9ELU>fSy#N9p-E1#{vCd&1OL}!p zs~Is}^t%z+6u(Pjxlpt4B&KGLrTyGY%u+Ea5O;EK?A1Le2e?Oes3zkexZ}NQCokdL zLb;RF2?{UG>o?bS53#KhHS}f~%cE>Q4L{TXg`n03xDm3ZHd*#%Z%qL&w$C}Qd^$4RCxu(Hw8aJRAe`i2v$%=;@ zEpTgN?k;Q(Axnb^* zM2OF~M_`^D&%Iz6INYFz&F_qf$K`bRjYsHr2ZIrwL)Ht&#SvPy_)SNK4}egwIQ`FA z2^=`*^t81T_svIOz&Fv78~>NLvdJETg=k_p9bIK80DscF({NCRagiW>!fyg()L zwFFdExn$I?s0D?nDqC5^R@5fbZ5zm--ZUxm!rDaTqo{YR6Nw+AMrMn>rVK8@HWMN= z!>HkrKVx0wQojw~D#saw=(aDHBsf@6mNW z;5qkgB!*yIK1R6~v71OBG5h2e667s6b^-5RPSh>JL$#QnnV>gXy?3v0UYbbX&9t0+ z%LDRe@R>e{4tkS(w;ItSg@PYNA*1sFg(h{63jkW9RiERPm6FzNuc4G{ep2zX=1gH+ zGX1$B{W5&V?(yfi7AjFAt%?b>mp092VV;&`Tw|tyW6^fVxLgl7IK+3Ut|G%pi*Fdt zWF6+@#}6(fyk+g5R(dwTgh)(npvC2*BCuCnjDiDFWeAY@oTo4aEs9ICG&s@q>rd4u z1L)#|L|m~!`57h?S--eo>m+4DjG!O_MO;1?37gkzSAzYlpJ8>yfI1KvZ3c9Ox*Fc+ zOZZl`olre+)ebHl^0)E|+PmlAQc!6fXgkz>8F zu2--N;)G1978aV^!cr=uYi8vltN9G{bpMXJVf#|;h%4aaIFHl=D z1Fet?5Z%dJX4mb1HiFnAyrR;pI1;_RNmXJ5;9_~G1$%rxN`{(>@}RMJFh$@>B#wGb0uIJ~R5otF1Ii(bm!=NVO_5RIg@81`NO+ z|1m?Ub#kXw#uxI(5Iu-p6{py858(p&LIISXLnH?!J|zlnNkFMIvL049^oX-6a$ElL z5F^0Y(0@R1qoASjs{)b>f^>2{ANem!Wrt7{p76x=^GV1?WA73QYXe;5Zseei60xm$ ze699@l4LY@cDCV6K`N$kY1Sq{y1!ooag7U2_w_4MGW2y;T6VHAoNB2r&n%NP-8vm5| z!dwZ|JhzAV)BH}-OuL7H^^eKGpEM=z2g>B4n*B9*f2VRo0}J3NDs3mdO_vx4}h zFMN2`xlIyF7&xn_m0hqJ0NRWMaZr`W6U(T%1N2M80Dm8=aa_vSY(vON&Vytou`0 zIx~x^C@={NOG{^I&>LSa+>8a3Gs_!QL6&orH(2RnDQlOHlWZh36T?VzjV>Uq{AUEZ zoM&eQ_goN2v=LDyunE7P&f4Dv{Fa1_gS#V(JQ;N*kzSrAO@Ee)B91xCQjF--+>s;x za75X=3=4%r>9)YGp(@kZoWipB7(4Hr^}@;jwUK4Mw%9Xscq{zQs|C*0qZ^|~e_lw} zJ2YI%qb(k2#$v>vEn>LU!h_IqbD1mP&%{SD4PVi0m{FqbB!~3ip47nc%y-dy>+ujK zXApd$_^@8G+FJ{ju(dT4wT`<$^l7yW)Mn~k0KUqQRiGrWDB+P3OdP4%Yx_AK3UwZK z8SV1Y1j?xy?H=}S+-C*A`=iARf&yEtptv8#e|W^fDFxWvF95et)zcVbcVS+ByBHfe zry5;KK>-onoHqMAF)AnOvl8U&h5mBO*M$C5GF|}3RTb=qL%rkE6QkHIS>V$J*F`G> z-UjMMy93Eu7xx|@SNRgMCNGB?=GJB|WG(E!7QL!Drvx*=BAF-UL6s|)VyF<(MeH56 zgJ00Zq_h9N6WIcUb?b?6wSnSFs!(ppk(4qInWZHent=`yT`U6)ERx)Aj{_?}*N zgpqHbgM4t~Od_VXA@{tVcxX=C^cwP1>*twFP~&ZidU!f41+CcN)|Hf7g~VGXxD8uPN5om$3+hLs-Q)PXw`eUwoJb z*1U@R*}tcoRnG2`JEPa-@fD1ItZ*Z-?#%O4%+F-8>Efd<2nVmpnYGAAdA;Kz&>+yPd>o{-3?$nnU&l z?|YdVMC*8<7nE4t6Fa}j{fUr}SMpjQ1~ibYahE(VJX>=T7}vU<(*>-|M8@x0t)DN) zinKBY_BU7dX(xy`CwL?c?Vltj-j$!8m7k(l8!6c8b^<7DFe5Hc901NY?phqbU8{+$ zrmaX2%ktet^a#3~Lb!d%d%5a4IOk*yN^}oIVKYyNW1ZA_R8Zr#rLYw7ogw(wc>L^N zZhd%oa>sq*bQxVK;qb$K_JTPrCm%l)ItTlf5CQS&@%Ppuuew*DZnVa?{}SPjndR~Tlb zox>I}XC~P6qu0d=7f;njNLg7>x4ik&v;W~0T0(mjYA&@$qZ#Ab4;|elY8nqbFTyf0 zqCguS!oA9Y7EBTd(Me28izC_5^=9=Ri@=4j_Y+?m|NKfpdsXMy;%$rU1DU z3Y_?g^cVx#R^}f?gZQ@fwmQ)fSncZ3uGvO76?(m~82sOEE|`%<*1aFThaLLcjqg_f z5&3IQ3-Nb)SqiG(qXo+t38ynepDS9(=n7-!ms%zwfIw_935EC!M;^xchE`lO*tE>4 z3x^MU|MF`I_k*c?j!xhRmhT^&NXU=p5{%E2HhT&Oex*qAU?wKxy%Qft8xA<<{jbc5 zXIW1JHYQ9t`*SecPO{Wzi8flxsA9dkc@Ir3zQd`y!xV#s^(aCy)S}K4pg|{g_KSt~ zPKLQBDDjm0XG33RXl}uhS&%>jB(t@4pDY58gmlsZpFCzryOzm=tdlFl4O?eH&J?Tv ziGe#{O^Bw>3B}_#y`*({I^Vk>>8M4ja(8wPrv%@6KRR>vu%+HXeH{WFy$>IhuZ?Xy zk7-d#P(VnYp#2ck!z*^E+!)|fS|NToeD$VII}aU8rTu;=p^N@1m(5XKRu$*H?2$7W z(35&sUc^vxDuySFRaIR1Irc5>Xly|I#*jWE?bi$)R#-+5*RrOg`g5LQOgc+`2^hMP z@Wi3Bu~$(ghiPzfrtMulhDnCX_CjaQhs}D>syLg!V!b)YU-4w8UKoNJ?8LNmMVt(f z<+0RdR95uz%Vl!iB@u|m?UY!eXKa9Plm@(G`)q7GaRmwtXLI~vdDHM07<|Hf`)md> z(=x9+-OrfMnha{*Gpgn7K0Pby6gG%WAkjR$GJkDt}$Hu7)d~_7-1Z&;F8nN=>u}U#MIauWT*6Vp;w* zTX8)7%j+rGsb^ZfZOKGhueM^@vU~PpD`Hj9<||uRtdx5BjjP+uqeXf za(ft|pzCc#ug|A7$PY?tINzjHQczBCPc1}Tv+sF8LRwyBOkJdl(eyo$1YLW05oNx` zb+osfz?ToW62#X>SRqY{0z)dD#DTwMTI~1zc(7m9QIfu_t1tOA(&P$M_z`UjomT|q z=b)eVz{B@KOB0s-x(fgD2%XtE^&Zv1yP$Jejv1_&zKafz~zGj z7`$bqM%sew`m@3MX!wE@7M7aTG5?h)HcdG|kW?&R? zc$B)Smvk2i7%q*%@P&ft`A~?SHu$GHeEzmD=9E}3N(CUwFy4SE{j2Po&A{Dg4WgVc z%eHdM7dd~LZKpppT~`4tJKmh|O}#5Mz)4?<9c?$1Nj3E;@i!ev_j8g2GQ*hUzTf_2 zyFx|Rdf*NM#$Zb;!`!csm|agsPuI=Q@ApXRVvxnoXuI)oZbP9(8rwowNR=L;g3<2$2byXqHYZ>F?6+G zgIg;Eunh|VZq|)_zDNPkR zmx^%4iXfQ-7j>>=X>#taD0fRFLD>pVod_Q9i?B$b9It*UywTh8#aehG&ZSeYJeh zi+U_a5UN3JZ$RvA1a*k395kN@)HhhE%VNsE*}a9=qG*cr^`Q<}&?e{~`7skd!KaEn z$73wSF$(P%lA_r4$PenKMlheBwJMEx{SeOBuPATVx~5NfHVm0{DM>_PNzMLk3Fd+$ z24X9Z>ks0=o~Ks$b_NC-)V{qhYF|wz4f#%nx|CrgFn1f1)UKSmU*oW?60Q^Ndu0{P2E2cb`z$`I@gL^WSxxbS&+9RW&O*-~ z#W3=qlUJD^`s`iq{kr%c7hg1wZ3b5@`Wk`*Y6b%)+B5bys|BqmTSi% zGP0O$eY+G+-m(Qknmmh{sPu|Jq3n*oTWA%~a0jIc$TBVWAErGrf#YJZ6yClH=tv{3 zg#cHd+$Vy${1sJc{?qQ$dD}HJMhB?p)1B7mt2q&hU5OlKgon?mTBNQ_M z1p>nfqt*E`XoZJ#U-q2TMlYua#v zS z{T*b7ZLtTv<8+GQ#}XFCJO$|0_z?vBooMl|NBfi=`-DQmbMkeHW6d7dAtp5jDYj!3 z*I~zX3UFd$`d<$x0!RL+P?&8vCwSipkQg8KiBhy-^Ouu4n6VYZ0!fJZnnLrMWFepy zBG@8KasA%5;h|soGF*#4TR(dfD!y6y_Ep8#P2=HyvkG)?L+hGocMWPwGyfC;L+Ryh zO6($GDHqknk%n4}{+ka4b!InH@K<*J$*x-G&~u!r-Ic{{sw4wBav{;f4nl7~V19yT z9Ub2&ueb%)(Ce)?pUeWTz(Of>N}0fvY)xV9&0I#RoixNBLFssCIxIRIHy|mJ48czx zz$Lhu|3RUNZpbE<=0^B5Xbth3K-h23QNa~n`rTqGy75V9iuNyf;o*6|=<9vy_uQMT z`xi1G3@gS6`Ir4nSQcY9OJxA#g|#&~-CgMPYtA_LgKD}fJz9d|(O&fqO9BV!)-cfd zb71Gp0oM)z*HXsa<->=F90-4F=WwAgg7B=?sVw#j$sUh7`X2 zHSQ}BT=~bQUkWPUJ1oOexGAsLN2u{xtAr2pn!4X;eZP1|PN<29h_0Bskc5rOViIhH zK;2+qPTDlqrbafr#v!SYmk5mV|y|3;s#XU|G-!-{D17dRd<}( zvZZZ{nVFe6#mp>OY+1~VwwRfjnHel*W@ZM9nZdSFvY^vdb?V!DpYHS3UElN=`U4tI z&WO31vqMfUZ7vz&Y0l>**0qGpEUN~(3z0i2(R%;IH|+5x7^7@y=5;Eagli_)S=m}v8>?^G`I zh9_+2VItX0;O&aj^ymuR@C7|d6|fVI3@N6_-@q-0zt^7WBYP}SJ1kK zCc5CfSFPiQ^;%NpBG=6&FFrdTeGdKZ_e}vh`df=*;`I*I_6u>XXBp!GeU*B$P{x`} zrIC17G1a}jz~vqI=3!{-L~MZz?Zpo^^sCQcLX%oEw$-VH%N+o#)J*F^Gj!z>tYM}{ zNX1{2CUrFzlnn*VY3LmXUSGz-1xS8=4V1h<=Dv>&TYY;)4io4MRlgQIQTH8Df9q9$ zctNhz0R5Xsfx5}?qat4xvB4Vy^_>$4Cl!>;q6%DwS-d)^nXHZ#XWeBV$^>lQJ(^@h zf2cF-z$PUF*Ia{qC*rs0URYC%qL+|>Av67=qEqnq1? z#CENL23#B&dP&cT!)6Vt4?Fs5N8_`G}Or}OOmn*)G_jK z-WC5ieLc!6EOg!EQoEVZX+yCsw<3}O`!bP4%)>@x%TbnYm5*E#$RNmU)nwz@bWyg% z;xW@NGI7Cw?!*T*(4+_3S9zOJLj+q(;z(e2q*OPx8`Ss@_E$DBzylydu zG9T-cG2?ttM!b`8MUylVU2@A_Di5K;7_PDl|B@cnpMM;k2r18+WTY^w<8B2Kg4FHk z_TU$Ou6rN(h;N;(F;H#2=7fTcrr6Lu>0(pFuXF=+`N330Z)!$ON}wJ1w95HNvh5=> zSO#)x18X>_#qsIXX47>$u?a997nPEpwg{sd&wm}APX8hWwz#+7cf<7g($u}_p?a7S z?>rGNr(F1R&G|lsiRdbyirugZ2N%(b-i%46iIZqKy3&SxOV6Eu#K#l_%&ekZ<|d{F zPbXUzcdtU}yY!n7JgCETZ^7*EnFFc#2U@M074on{ zyy{fg6k5QEx=8vue^STu|9 zAm`VuA%)%(vIJj?7v7^R-kHyy@WYqhAMc>O^4lCR_o6>bxMlPp^xUlMxW2+&?ANeC z`(~Toa$Tqnc#qB<&{-?NGSfLzpd<)*5$eaaCd+)aUvPjO22O|2tz*0&;M0zH7oHNT8Zy~Joc*nU0g80EnaxflXDA4gS7eIf z(?0T^itY24!9{EfmYyKdSIhvQ0&@5Sz{UW@HED=v0gA#4igR=ERz4Dnlol$;E%;Wz z>W%p1O-yaE0<>o!G_%sEr{SU@)M{e4t9SE?-TP%f4*jF(jd7<% z`Jswh*upWzxD)Eo4T4?H&~GJ&(kep5q$yD*({r2!`|(3rVTKiQ%9f3C()8ZAu0-R$ zl1Z;%md_u*oB9UkKO^HzJs2|FP)j2IGNioPpy!4N@rfsIs5P=lZ zru~AAaOB&U0427odDss->X(-sB^QXkM)WgbuNA&vwc}mFgGk8qOdpC@)bvbt$o2cE z9Pe3W#W%#pZM8DjoJ$)hh5=rT2a8#vvCW3X^#UVYBX4=ak2+{ZmZ)$Qo%tu=?b3nl z@kl&m;80=mqu8I6f4Y__Oyz4}0T9Io0gHza!!s@K%UaTC=%WsdMBvH!iU$dEBDz~m zgrqTFNL3H0!Z^xJm>|D1t7%4kL64yvc2BiYJmSdC+uuCJtT$n%Fx69y^qeS*Hrtdp z(Q0prAF5x3M9d6T=3C9KA5i$jFmkocRYe`6t7`$>Rq^IdxI1(*?w ziUo{GxYr4NNT0CsyM;j-3(VkICdmO0WrWgjwpQ^Zu~cphm+;$KZ2~an$blVaR@5z2 zOit@7NdYT7Sn=ZM8`lAtP*=uvl~c0A^rAlaXQQgb2oBaHxt#E)7i5Q>dsl~3Oecek z@W%EaeJj=h$CQ<{nAT~dz@@q;F_-m`-d1L+OY#yjE`s;ogY233PvXVi^TrE;O-VoB zKbgx-E)BBcoR=E>q88vK9%Z|GEkMB!@PYR1G@+g_cR=4*8w%mHF&{Xq!r;G~SLDp< zQ`G47+q0ubR8}k=p#><5!iMV-(0$h_7wDH{58Etyf=aJk$!vR^ewj&isf$OHXiMO) z%C^A>{Z^&q388~Xqh45Nk40axJssyP*RE+9IK^QqJ5}#A#C=FLV`FX%19yPR$r%|9 zUw2FDB262y6r{3f5NcW%UU7Ca|Ggij^28|70gy=R9Z;>>zN+@jUm$vIw18K?`u);I zGI)Strs(tM)4%14bIWuTa zgJ)tz)`%?Jbz&u+M*HDVuKCV&|Ce4JfgUK#JhT8+5PhU?rXTXxAY2MXMjC0xrx=HZ zd?QMF%*s`WxqdSkh$ZBngIl@`Xe^2!Y}lEAbZf(e0e(p^@rezxlx38+OEuqI181ZR0M>FPYG=R>y1*BR;tW709c+f3fu`>L7dSM)q<}Y-L z*4&i^w|DCVi7nIlY%K7qYpG^}N{G9ZcvCW!2qXKDw9$^4!r|wB>I98{H&QD~%_Hk# zu&V1^9fI03%5*Eup5s(sf48Z;T^-i|%LZ*%#GS%XK-<6Kcq^w1tLTVH*Hk%IuNV33 z?wwSQZ(zOk{@K3F^pgCL;I87TQMchsmHJ4=mWuyjewz&m6w13s!z$f5OUWJtK5;)~ zSaV18t6yfD4~#IQ)ig9MBKfW0s9U&@i<{IH%=7m|Oh+M7>y)k60vS_L@xl={-p`5^3(H@n~@EG6KaWr;R!9|Wr zH9tap^eS~$k)R{x6T4IKJ8Zx@Zn`aD1dA2SMiX440g21rbbBufvY2lpw7U`Z)s-?0 z+6R$xH?Z-+L>Bc6|1~4##jsMtIya~o%$W^bIB=*;*Ofd5x_*nsx>=lLG^YR!aTo3` zp>I0vBi$A*nV8s!jIt_{Fb^?sTMMvdov~71)O5DZGq~MzqIFio zZE*%*+foGBB%o`b(en0C%|Yn}*6sZ$LyT(RVwpb5arA;OHe7_#Iti(3dhf#|2P3#N z0@g!pN_~s6ynwQK{o+;Gw5{8!KQ1vPirwr+e{UCniqXYJT(9n_drEYo{Y0YO0G;(+ zR3ebsw>mhJ0gHtd?Ltvp^=$hc>6SRhcP!cE4VuSm;cz$Piosu;v4;jx_wRg_3@uWk z^FJ*!^1KI}>RUJ1kA-`)$Vxnsetz#e(7td=9N57B{g;En-7N7&A8(0v%i`L4?R^81 zVbf;zGog())<$h$cHU+-x`Jz|4>VtR47N*sA}xv_<)ET2!;(S6o8@Yc9%1N(LFu)b zxe^#vWOjPxrGa_y>e?OZPwej_{R1=k*1!v$_K=zBf$|ysEPB^k_=}j;5-arZj&!h9 zgom{~exzX3!BCu!J`jmRBP>#0a8i*o25mqvt-(}>CLkPVr2VeoEr$*2cHYBF_NAj7 z5Py4&Sd=IO;j%MQD2ijkkjXa){kBCs{HHPJd!qeVqe|L!xiD5{BtZP)qn+0-b@!t& zuP?!yDgoXKDQ!vMbnYs0U{&O{`RvOh^85nNi}>k|9e?DvvT>sG9EM?@oITGfo@Q;* zbl#@`zP<5tQ8jrc{dbUi?XE^d5;nwaKcIss+#lMHkKP7qfd$q}kFnZcU z=ekAkZPp&%2w*2dfA0`xfQ)OemA30Nb9-EUssxej$5qJip_dk(tG|||XKm|kXig?Y zjz;d6Ui>OlaJG`9*jG80gZWj`?+bAWqo$nqK=hWF&6Iv(f3jDar2B6UIKBiWchm+v zzHk~hUCLuOW}etnyNL)@zo5L;zsg=4%V?6OF|bKWZyv(CXqdB2i=ZAt6?ZbJ@~jTg z0XsI^RTW_OT$f&s$Z1aRm^gLo0(ILmb^YI#QZD)($`uK{QZCvN>*a2<$ypEDDz^B6 z6kiz-`+9iueG$JI$08L(+QthYW!S`XeBr?k=wlAh@nOZdkuzZLAy9Upl;8c>7yoRP z7JE(kti>I(4WV!%$#svP2T6GTGF{U9>y3e~*kKmTUXbzbHA^|8O!8q(8I zi>U^k9;oB>0ZSgrKOEm6_Sr>?>8acEz_;|r3e!B(5|gByTeFNV0)G&(Y>RNU0X67-z@ zKNihz$PTig2sn0NTQB|a>G_pMuL-%0A)+B+h$(U_&^#yEemd_ow2jv3hwS4=OsQCZ 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 z zte>&DmjXwVL%~+z_61Xq;!1boa&ZRb-;HnFQeTn|X=#Lw|tes0y;+ zWMhX8hCz`(H0F4WKNDN;lD5sYngF>4j0*Z7^V%U87MrBgO{$y+NWOq1Jt-b%dXkJp zlN>=@Fs#V|WM9azaxQckMSpVK4^D#5gKHpQTqYYk)HiAxLZ?utUbfjqvxjLF6honQ35lR8$fX2xjc9nhnXtJj*U@4YmzddWqVm_|4t$PSmOpC#Eg4Y4Qt z`l5SrU*H2D_p{AM#>cBvr~kT%H*p>K*Y&umw}*e#IGoNS+?^+{2g4b^k|Bqo1UB*~ zuLAxM;3wnfb>RsR_J!dIUD%;ye9+J9!&C3HO}&cwi? { + try { + while (true) { + try { + doUpdate(); + Thread.sleep(1); + } catch (IOException ex) { + getLogger().log(Level.FINE, null, ex); + } + } + } catch (InterruptedException ex) { + return; + } + }); + monitoredThread.setDaemon(true); + monitoredThread.start(); + } else if (!value && (monitoredThread != null)) { + monitoredThread.interrupt(); + monitoredThread = null; + } + } + + final byte[] START_OF_FRAME = {(byte) 0xFF, (byte) 0xD8}; + final byte[] END_OF_FRAME = {(byte) 0xFF, (byte) 0xD9}; + final int MAX_FRAME_SIZE = 512 * 1024; + + @Override + protected void doUpdate() throws IOException, InterruptedException { + byte[] data = null; + if (stream != null) { + if (flushOnUpdate) { + flush(); + } + try { + data = readData(); + } catch (EOFException ex) { + //Try to reopen stream + doInitialize(); + data = readData(); + } + } + if (data == null) { + pushImage(null); + } else { + BufferedImage img = Utils.newImage(data); + pushImage(img); + } + } + byte[] readData() throws IOException { + if (stream != null) { + stream.mark(MAX_FRAME_SIZE); + int startOfFrame = waitBytes(START_OF_FRAME) - START_OF_FRAME.length; + if (startOfFrame >= 0) { + int endOfFrame = waitBytes(END_OF_FRAME); + if (endOfFrame >= 0) { + stream.reset(); + stream.skip(startOfFrame); + int length = endOfFrame ;//- END_OF_FRAME.length ; + byte[] data = new byte[length]; + stream.read(data, 0, length); + return data; + } + } + } + return null; + } + + int waitBytes(byte[] data) throws IOException { + int index = 0; + int dataPos = 0; + while (true) { + int ret = stream.read(); + if (ret < 0) { + throw new EOFException(); + } + byte value = (byte) ret; + if (value == data[dataPos]) { + dataPos++; + if (dataPos == data.length) { + return (index + 1); + } + } else { + dataPos = 0; + } + index++; + if (index >= MAX_FRAME_SIZE) { + return -1; + } + } + } + + public void flush() throws IOException { + //stream.skip(stream.available()); + //TODO: Skipping won't make the current image to be displayed + stream.close(); + stream = new URL(url).openStream(); + if (!stream.markSupported()) { + stream = new BufferedInputStream(stream); + } + } + +} diff --git a/plugins/PuckDetectionPanel.form b/plugins/PuckDetectionPanel.form new file mode 100644 index 0000000..8045142 --- /dev/null +++ b/plugins/PuckDetectionPanel.form @@ -0,0 +1,201 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + </TableColumnModel> + </Property> + <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> + <TableHeader reorderingAllowed="true" resizingAllowed="true"/> + </Property> + </Properties> + </Component> + </SubComponents> + </Container> + <Component class="javax.swing.JButton" name="buttonConfigure"> + <Properties> + <Property name="text" type="java.lang.String" value="Configure"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonConfigureActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="deviceStatePanel1"> + <Properties> + <Property name="deviceName" type="java.lang.String" value="puck_detection"/> + </Properties> + </Component> + </SubComponents> +</Form> diff --git a/plugins/PuckDetectionPanel.java b/plugins/PuckDetectionPanel.java new file mode 100644 index 0000000..e07dde6 --- /dev/null +++ b/plugins/PuckDetectionPanel.java @@ -0,0 +1,281 @@ +import ch.psi.mxsc.Puck; +import ch.psi.mxsc.PuckDetection; +import ch.psi.mxsc.PuckState; +import ch.psi.mxsc.PuckState.SwitchState; +import ch.psi.pshell.core.Context; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; + +/** + * + */ +public class PuckDetectionPanel extends DevicePanel { + + public PuckDetectionPanel() { + initComponents(); + int row = 0; + for (String segment : new String[]{"A", "B", "C", "D", "E", "F"}){ + for (int puck=1; puck<=5; puck++){ + table.getModel().setValueAt(segment+puck, row++, 0); + } + } + } + + @Override + public PuckDetection getDevice(){ + return (PuckDetection) super.getDevice(); + } + + + @Override + protected void onDeviceCacheChanged(Object value, Object former, long timestamp, boolean arg3) { + for (int row=0; row< 30; row++){ + String name = table.getModel().getValueAt(row, 0).toString(); + //int id = row+1; + try { + Puck puck = getDevice().getPuck(name); + int id = puck.getIndex() + 1; + PuckState state = getDevice().getPuckState(id); + table.getModel().setValueAt(state.online, row, 1); + table.getModel().setValueAt((SwitchState.Off == state.mecSwitch) ? "" : String.valueOf(state.mecSwitch), row, 2); + table.getModel().setValueAt((SwitchState.Off == state.indSwitch) ? "" : String.valueOf(state.indSwitch), row, 3); + table.getModel().setValueAt(puck.getDetection() == null ? "" : puck.getDetection(), row, 4); + table.getModel().setValueAt(puck.getPuckType() == null ? "" : puck.getPuckType(), row, 5); + } catch (Exception ex) { + ex.printStackTrace(); + table.getModel().setValueAt(false, row, 1); + table.getModel().setValueAt(false, row, 2); + table.getModel().setValueAt(false, row, 3); + table.getModel().setValueAt("", row, 4); + table.getModel().setValueAt("", row, 5); + } + } + } + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + SwingUtils.showMessage(this, "Return", String.valueOf(ret)); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jPanel3 = new javax.swing.JPanel(); + buttonPuckDetCheck = new javax.swing.JButton(); + buttonPuckDetStop = new javax.swing.JButton(); + buttonPuckDetStart = new javax.swing.JButton(); + jPanel1 = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + table = new javax.swing.JTable(); + buttonConfigure = new javax.swing.JButton(); + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Raspberry Pi ")); + + buttonPuckDetCheck.setText("Check"); + buttonPuckDetCheck.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetCheckActionPerformed(evt); + } + }); + + buttonPuckDetStop.setText("Stop"); + buttonPuckDetStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetStopActionPerformed(evt); + } + }); + + buttonPuckDetStart.setText("Start"); + buttonPuckDetStart.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetStartActionPerformed(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(buttonPuckDetCheck) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 107, Short.MAX_VALUE) + .addComponent(buttonPuckDetStop) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 108, Short.MAX_VALUE) + .addComponent(buttonPuckDetStart) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonPuckDetCheck, buttonPuckDetStart, buttonPuckDetStop}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonPuckDetCheck) + .addComponent(buttonPuckDetStop) + .addComponent(buttonPuckDetStart)) + .addContainerGap()) + ); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Detection")); + + table.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null} + }, + new String [] { + "Puck", "Online", "Mechanical", "Inductive", "Detection", "Image" + } + ) { + Class[] types = new Class [] { + java.lang.String.class, java.lang.Boolean.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class + }; + boolean[] canEdit = new boolean [] { + false, false, false, false, false, false + }; + + public Class getColumnClass(int columnIndex) { + return types [columnIndex]; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return canEdit [columnIndex]; + } + }); + jScrollPane1.setViewportView(table); + + buttonConfigure.setText("Configure"); + buttonConfigure.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonConfigureActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(buttonConfigure) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 282, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonConfigure) + .addContainerGap()) + ); + + deviceStatePanel1.setDeviceName("puck_detection"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonPuckDetCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetCheckActionPerformed + execute("check_puck_detection()", true); + }//GEN-LAST:event_buttonPuckDetCheckActionPerformed + + private void buttonPuckDetStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetStopActionPerformed + execute("stop_puck_detection()", false); + }//GEN-LAST:event_buttonPuckDetStopActionPerformed + + private void buttonPuckDetStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetStartActionPerformed + execute("start_puck_detection()", false); + }//GEN-LAST:event_buttonPuckDetStartActionPerformed + + private void buttonConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonConfigureActionPerformed + try { + if (table.getSelectedRow()<0){ + throw new Exception("Select a puck"); + } + String name = table.getModel().getValueAt(table.getSelectedRow(), 0).toString(); + Puck puck = getDevice().getPuck(name); + DevicePanel.showConfigEditor(this, puck, true, false); + } catch (Exception ex) { + showException(ex); + } + + }//GEN-LAST:event_buttonConfigureActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonConfigure; + private javax.swing.JButton buttonPuckDetCheck; + private javax.swing.JButton buttonPuckDetStart; + private javax.swing.JButton buttonPuckDetStop; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel3; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JTable table; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/Recovery.form b/plugins/Recovery.form new file mode 100644 index 0000000..fa22373 --- /dev/null +++ b/plugins/Recovery.form @@ -0,0 +1,140 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="ledKnownPosition" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="jLabel6" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> + <Component id="textPosition" max="32767" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="ledValidSegment" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="jLabel7" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="16" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="0" pref="103" max="32767" attributes="0"/> + <Component id="jLabel8" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="textDistance" min="-2" pref="86" max="-2" attributes="0"/> + </Group> + <Component id="textSegment" max="32767" attributes="0"/> + </Group> + </Group> + </Group> + <EmptySpace min="-2" pref="8" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Group type="103" groupAlignment="0" max="-2" attributes="0"> + <Component id="buttonRecover" pref="179" max="32767" attributes="0"/> + <Component id="buttonAbort" max="32767" attributes="0"/> + </Group> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="ledKnownPosition" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="textPosition" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="ledValidSegment" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="jLabel7" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="textSegment" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="jLabel8" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="textDistance" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace pref="61" max="32767" attributes="0"/> + <Component id="buttonRecover" min="-2" max="-2" attributes="0"/> + <EmptySpace type="separate" max="-2" attributes="0"/> + <Component id="buttonAbort" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="24" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledKnownPosition"> + </Component> + <Component class="javax.swing.JLabel" name="jLabel6"> + <Properties> + <Property name="text" type="java.lang.String" value="Known position"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledValidSegment"> + </Component> + <Component class="javax.swing.JLabel" name="jLabel7"> + <Properties> + <Property name="text" type="java.lang.String" value="Valid segment"/> + </Properties> + </Component> + <Component class="javax.swing.JButton" name="buttonRecover"> + <Properties> + <Property name="text" type="java.lang.String" value="Recover"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonRecoverActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonAbort"> + <Properties> + <Property name="text" type="java.lang.String" value="Abort"/> + <Property name="enabled" type="boolean" value="false"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonAbortActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JTextField" name="textPosition"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textSegment"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textDistance"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + <Property name="horizontalAlignment" type="int" value="11"/> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel8"> + <Properties> + <Property name="text" type="java.lang.String" value="Distance:"/> + </Properties> + </Component> + </SubComponents> +</Form> diff --git a/plugins/Recovery.java b/plugins/Recovery.java new file mode 100644 index 0000000..ee1e216 --- /dev/null +++ b/plugins/Recovery.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014-2017 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import java.awt.Color; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.SwingUtilities; + +/** + * + */ +public class Recovery extends Panel { + + public Recovery() { + initComponents(); + startTimer(2500, 200); + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + getContext().setGlobal("recovering", null); + } + + @Override + public void onStateChange(State state, State former) { + if (state==State.Ready){ + SwingUtilities.invokeLater(()->{onTimer();}); + } + textSegment.setEnabled(state == State.Ready); + textDistance.setEnabled(state == State.Ready); + textPosition.setEnabled(state == State.Ready); + updateButton(); + } + + void updateButton(){ + buttonRecover.setEnabled((getContext().getState().isNormal()) && + (textPosition.getText().trim().isEmpty()) && + (!textSegment.getText().trim().isEmpty()) && + !isRecovering() + ); + + } + + boolean isRecovering(){ + return "true".equals(getContext().getGlobal("recovering")); + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + + + @Override + protected void onTimer() { + System.out.println("."); + Device robot = getContext().getDevicePool().getByName("robot", Device.class); + if ((robot==null) || (!robot.getState().isNormal())){ + System.out.println("*"); + ledValidSegment.setColor(Color.BLACK); + textSegment.setText(""); + ledKnownPosition.setColor(Color.BLACK); + textPosition.setText(""); + } else { + if (getState().isNormal()){ + String point = null; + try{ + point = (String) eval("robot.get_current_point()", true); + ledKnownPosition.setColor((point == null) ? Color.RED : Color.GREEN); + textPosition.setText((point == null) ? "": point); + } catch (Exception ex) { + System.out.println(ex); + ledKnownPosition.setColor(Color.BLACK); + textPosition.setText(""); + } + List segment = null; + try{ + segment = (List) eval("get_current_segment()", true); + ledValidSegment.setColor((segment == null) ? Color.RED : Color.GREEN); + textSegment.setText((segment == null) ? "": segment.get(0) + "->" + segment.get(1) + " [" + segment.get(2) + "mm]"); + if ((segment == null)||(point!=null)){ + textDistance.setText(""); + } else { + try{ + Object distance = eval("get_current_distance()", true); + textDistance.setText((distance == null) ? "" : String.format("%1.2f",((Number)distance).doubleValue())); + } catch (Exception ex) { + textDistance.setText(""); + } + } + } catch (Exception ex) { + System.out.println(ex); + ledValidSegment.setColor(Color.BLACK); + textSegment.setText(""); + textDistance.setText(""); + } + try{ + Boolean is_in_dewar = (Boolean) eval("is_in_dewar()", true); + if ((segment==null) && is_in_dewar){ + ledValidSegment.setColor(Color.GREEN); + textSegment.setText("Inside Dewar"); + } + } catch (Exception ex) { + System.out.println(ex); + } + } + } + updateButton(); + } + + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + ledKnownPosition = new ch.psi.pshell.swing.Led(); + jLabel6 = new javax.swing.JLabel(); + ledValidSegment = new ch.psi.pshell.swing.Led(); + jLabel7 = new javax.swing.JLabel(); + buttonRecover = new javax.swing.JButton(); + buttonAbort = new javax.swing.JButton(); + textPosition = new javax.swing.JTextField(); + textSegment = new javax.swing.JTextField(); + textDistance = new javax.swing.JTextField(); + jLabel8 = new javax.swing.JLabel(); + + jLabel6.setText("Known position"); + + jLabel7.setText("Valid segment"); + + buttonRecover.setText("Recover"); + buttonRecover.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonRecoverActionPerformed(evt); + } + }); + + buttonAbort.setText("Abort"); + buttonAbort.setEnabled(false); + buttonAbort.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonAbortActionPerformed(evt); + } + }); + + textPosition.setEditable(false); + + textSegment.setEditable(false); + + textDistance.setEditable(false); + textDistance.setHorizontalAlignment(javax.swing.JTextField.TRAILING); + + jLabel8.setText("Distance:"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(ledKnownPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel6) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(textPosition)) + .addGroup(layout.createSequentialGroup() + .addComponent(ledValidSegment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel7) + .addGap(16, 16, 16) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(0, 103, Short.MAX_VALUE) + .addComponent(jLabel8) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(textDistance, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(textSegment)))) + .addGap(8, 8, 8)) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(buttonRecover, javax.swing.GroupLayout.DEFAULT_SIZE, 179, Short.MAX_VALUE) + .addComponent(buttonAbort, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(ledKnownPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6) + .addComponent(textPosition, 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.BASELINE) + .addComponent(ledValidSegment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel7) + .addComponent(textSegment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel8) + .addComponent(textDistance, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 61, Short.MAX_VALUE) + .addComponent(buttonRecover) + .addGap(18, 18, 18) + .addComponent(buttonAbort) + .addGap(24, 24, 24)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonRecoverActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRecoverActionPerformed + try{ + if (isRecovering()){ + getLogger().warning("Ongoing recovery "); + return; + } + buttonAbort.setEnabled(true); + getContext().setGlobal("recovering", "true"); + Device robot = getContext().getDevicePool().getByName("robot", Device.class); + abort(); + getContext().waitState(State.Ready, 5000); + eval("robot.stop_task()", false); + robot.waitReady(5000); + evalAsync("recover()", false).handle((ret, ex) -> { + if (ex != null){ + if (!getContext().isAborted()){ + showException((Exception)ex); + } + } else { + SwingUtils.showMessage(getTopLevel(), "Return", String.valueOf(ret)); + } + getContext().setGlobal("recovering", null); + buttonAbort.setEnabled(false); + return ret; + }); + } catch (Exception ex) { + showException(ex); + getContext().setGlobal("recovering", null); + buttonAbort.setEnabled(false); + } + }//GEN-LAST:event_buttonRecoverActionPerformed + + private void buttonAbortActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonAbortActionPerformed + try { + abort(); + try{ + eval("robot.disable()", true); + } catch (Exception ex){ + this.showException(ex); + } + try{ + eval("robot.stop_task()", true); + } catch (Exception ex){ + this.showException(ex); + } + try{ + eval("robot.reset_motion()", true); + } catch (Exception ex){ + this.showException(ex); + } + } catch (InterruptedException ex) { + //showException(ex); + } + }//GEN-LAST:event_buttonAbortActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonAbort; + private javax.swing.JButton buttonRecover; + private javax.swing.JLabel jLabel6; + private javax.swing.JLabel jLabel7; + private javax.swing.JLabel jLabel8; + private ch.psi.pshell.swing.Led ledKnownPosition; + private ch.psi.pshell.swing.Led ledValidSegment; + private javax.swing.JTextField textDistance; + private javax.swing.JTextField textPosition; + private javax.swing.JTextField textSegment; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/RobotModbus.java b/plugins/RobotModbus.java new file mode 100644 index 0000000..ca2e149 --- /dev/null +++ b/plugins/RobotModbus.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.*; +import ch.psi.pshell.modbus.*; + +/** + */ +public class RobotModbus extends ModbusTCP { + + public RobotModbus(String name, String server) { + super(name, server); + } + + public Object run() throws Exception{ + Thread.sleep(1000); + return ("Done run"); + } + +} diff --git a/plugins/RobotPanel.form b/plugins/RobotPanel.form new file mode 100644 index 0000000..bf9c0d6 --- /dev/null +++ b/plugins/RobotPanel.form @@ -0,0 +1,587 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jPanel1" max="32767" attributes="0"/> + <Component id="jPanel2" alignment="0" max="32767" attributes="0"/> + <Component id="jPanel3" alignment="0" max="32767" attributes="0"/> + <Component id="panelState" alignment="0" max="32767" attributes="0"/> + <Component id="jPanel4" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jPanel1" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel4" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel2" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel3" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelState" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Container class="javax.swing.JPanel" name="jPanel1"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Power"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jLabel1" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledPowered" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelPowerCtr" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel1" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledPowered" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelPowerCtr" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledPowered"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel1"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Powered:"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelPowerCtr"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="buttonEnable" min="-2" max="-2" attributes="0"/> + <EmptySpace pref="18" max="32767" attributes="0"/> + <Component id="buttonDisable" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Group type="103" alignment="2" groupAlignment="1" max="-2" attributes="0"> + <Component id="buttonDisable" alignment="1" max="32767" attributes="0"/> + <Component id="buttonEnable" alignment="1" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonDisable"> + <Properties> + <Property name="text" type="java.lang.String" value="Disable"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonDisableActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonEnable"> + <Properties> + <Property name="text" type="java.lang.String" value="Enable"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonEnableActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="jPanel2"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Motion"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <Component id="jLabel7" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledMoving" min="-2" max="-2" attributes="0"/> + </Group> + <Component id="jLabel2" alignment="0" min="-2" pref="52" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="14" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" max="-2" attributes="0"> + <Component id="panelMotionCtr" max="32767" attributes="0"/> + <Component id="spinnerSpeed" max="32767" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel7" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledMoving" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelMotionCtr" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="spinnerSpeed" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JLabel" name="jLabel2"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Speed:"/> + </Properties> + </Component> + <Component class="javax.swing.JSpinner" name="spinnerSpeed"> + <Properties> + <Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor"> + <SpinnerModel initial="10" maximum="100" numberType="java.lang.Integer" stepSize="1" type="number"/> + </Property> + </Properties> + <Events> + <EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spinnerSpeedStateChanged"/> + </Events> + <AuxValues> + <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new ch.psi.utils.swing.HorizontalSpinner()"/> + </AuxValues> + </Component> + <Component class="javax.swing.JLabel" name="jLabel7"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Moving:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledMoving"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelMotionCtr"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="0" max="-2" attributes="0"/> + <Component id="butonStop" pref="45" max="32767" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="buttonPause" pref="46" max="32767" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="buttonResume" pref="47" max="32767" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="0" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="butonStop" alignment="2" max="32767" attributes="0"/> + <Component id="buttonPause" alignment="2" max="32767" attributes="0"/> + <Component id="buttonResume" alignment="2" max="32767" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="butonStop"> + <Properties> + <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> + <Connection code="new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Stop.png"))" type="code"/> + </Property> + <Property name="text" type="java.lang.String" value=" "/> + <Property name="horizontalTextPosition" type="int" value="0"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="butonStopActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonResume"> + <Properties> + <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> + <Connection code="new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Play.png"))" type="code"/> + </Property> + <Property name="text" type="java.lang.String" value=" "/> + <Property name="horizontalTextPosition" type="int" value="0"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonResumeActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonPause"> + <Properties> + <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> + <Connection code="new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Pause.png"))" type="code"/> + </Property> + <Property name="text" type="java.lang.String" value=" "/> + <Property name="horizontalTextPosition" type="int" value="0"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonPauseActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="jPanel3"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Status"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel8" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledTask" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="103" alignment="0" groupAlignment="1" attributes="0"> + <Group type="102" attributes="0"> + <Component id="jLabel4" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledEmpty" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="1" attributes="0"> + <Component id="jLabel3" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledSettled" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + <Group type="102" attributes="0"> + <Component id="jLabel9" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledPosition" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="textTask" max="32767" attributes="0"/> + <Component id="textPosition" max="32767" attributes="0"/> + </Group> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel6" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledMode" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="textMode" max="32767" attributes="0"/> + </Group> + </Group> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="buttonAbort" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="1" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel3" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledSettled" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel4" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledEmpty" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="textMode" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledMode" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="jLabel6" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="buttonAbort" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="jLabel8" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledTask" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="textTask" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel9" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledPosition" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="textPosition" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JLabel" name="jLabel3"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Settled:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledSettled"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel4"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Empty:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledEmpty"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textTask"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + <Property name="horizontalAlignment" type="int" value="0"/> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel6"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Mode:"/> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textMode"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + <Property name="horizontalAlignment" type="int" value="0"/> + </Properties> + </Component> + <Component class="javax.swing.JButton" name="buttonAbort"> + <Properties> + <Property name="text" type="java.lang.String" value="Abort"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonAbortActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JLabel" name="jLabel8"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Task:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledTask"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledMode"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textPosition"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + <Property name="horizontalAlignment" type="int" value="0"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledPosition"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel9"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Position:"/> + </Properties> + </Component> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="panelState"> + </Component> + <Container class="javax.swing.JPanel" name="jPanel4"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Tool"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jLabel5" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledOpen" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelPowerCtr1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel5" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledOpen" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelPowerCtr1" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledOpen"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel5"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Open:"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelPowerCtr1"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="buttonOpen" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace pref="18" max="32767" attributes="0"/> + <Component id="buttonClose" linkSize="3" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Group type="103" alignment="2" groupAlignment="1" max="-2" attributes="0"> + <Component id="buttonClose" alignment="1" max="32767" attributes="0"/> + <Component id="buttonOpen" alignment="1" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonClose"> + <Properties> + <Property name="text" type="java.lang.String" value=" Close "/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonCloseActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonOpen"> + <Properties> + <Property name="text" type="java.lang.String" value=" Open "/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonOpenActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + </SubComponents> +</Form> diff --git a/plugins/RobotPanel.java b/plugins/RobotPanel.java new file mode 100644 index 0000000..e841f57 --- /dev/null +++ b/plugins/RobotPanel.java @@ -0,0 +1,685 @@ + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.ui.App; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.pshell.core.Context; +import ch.psi.utils.State; +import java.awt.Color; +import java.util.Map; +import javax.swing.JSpinner; +import javax.swing.JTextField; + +/** + * + */ +public class RobotPanel extends DevicePanel { + + /** + * Creates new form RobotPanel + */ + public RobotPanel() { + initComponents(); + ((JSpinner.DefaultEditor)spinnerSpeed.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); + } + + @Override + public void setDevice(Device device) { + super.setDevice(device); + if (device == null) { + + } + panelState.setDevice(device); + } + + @Override + protected void onDeviceStateChanged(State state, State former) { + boolean enabled = state.isNormal(); + spinnerSpeed.setEnabled(enabled); + buttonAbort.setEnabled(enabled); + if (!enabled){ + buttonEnable.setEnabled(enabled); + buttonDisable.setEnabled(enabled); + butonStop.setEnabled(enabled); + buttonPause.setEnabled(enabled); + buttonResume.setEnabled(enabled); + } + } + + boolean updating; + @Override + protected void onDeviceCacheChanged(Object value, Object former, long timestamp, boolean valueChange) { + updating = true; + try{ + Boolean powered = null; + Boolean empty = null; + Boolean settled = null; + Boolean moving = null; + Boolean open = null; + Integer speed = null; + String task = null; + String mode = null; + String position = null; + + if ((value != null) && (value instanceof Map)) { + Map status = (Map) value; + try { + powered = (Boolean) status.get("powered"); + } catch (Exception ex) { + } + try { + empty = (Boolean) status.get("empty"); + } catch (Exception ex) { + } + try { + settled = (Boolean) status.get("settled"); + } catch (Exception ex) { + } + try { + open = (Boolean) status.get("open"); + } catch (Exception ex) { + } + try { + speed = (Integer) status.get("speed"); + } catch (Exception ex) { + } + try { + position = (String) status.get("pos"); + if (position==null){ + position = ""; + } + } catch (Exception ex) { + } + try { + task = ((status.containsKey("task")) && (status.get("task") == null)) ? "" : ((String) status.get("task")).trim(); + } catch (Exception ex) { + System.out.println(ex); + ex.printStackTrace(); + } + try { + mode = ((String) status.get("mode")).trim(); + //mode = (String) Context.getInstance().evalLineBackground(getDevice().getName() + ".working_mode"); + } catch (Exception ex) { + } + try { + //if (status.get("status").equals("hold")){ + // moving = false; + //} else if (status.get("status").equals("move")){ + // moving = true; + //} + moving = Boolean.FALSE.equals(settled) || Boolean.FALSE.equals(empty); + } catch (Exception ex) { + } + } + + boolean remote = mode.equals("remote"); + boolean enabled = Boolean.TRUE.equals(powered); + buttonEnable.setEnabled((powered != null) && (powered == false)); + buttonDisable.setEnabled(enabled); + + butonStop.setEnabled(remote && Boolean.TRUE.equals(moving)); + buttonPause.setEnabled(remote && enabled && Boolean.TRUE.equals(moving) && Boolean.FALSE.equals(settled)); + buttonResume.setEnabled(remote && enabled && Boolean.TRUE.equals(moving) && Boolean.TRUE.equals(settled)); + + + ledPowered.setColor((powered == null) ? Color.GRAY : (powered ? Color.YELLOW : Color.DARK_GRAY)); + ledEmpty.setColor((empty == null) ? Color.GRAY : (empty ? Color.GREEN : Color.YELLOW)); + ledSettled.setColor((settled == null) ? Color.GRAY : (settled ? Color.GREEN : Color.YELLOW)); + ledOpen.setColor((open == null) ? Color.GRAY : (open ? Color.GREEN : Color.DARK_GRAY)); + ledMoving.setColor((moving == null) ? Color.GRAY : (moving ? Color.YELLOW : Color.DARK_GRAY)); + textTask.setText((task == null) ? "" : task); + ledTask.setColor((task == null) ? Color.GRAY : (task.isEmpty() ? Color.DARK_GRAY : Color.YELLOW)); + textPosition.setText((position == null) ? "" : position); + ledPosition.setColor((position == null) ? Color.GRAY : (position.isEmpty() ? Color.DARK_GRAY : Color.GREEN)); + //buttonAbort.setEnabled(!textTask.getText().isEmpty()); + spinnerSpeed.setEnabled(speed != null); + if (speed == null) { + spinnerSpeed.setValue(0); + } else { + spinnerSpeed.setValue(speed); + } + ledMode.setColor((mode == null) ? Color.BLACK : (remote ? Color.GREEN : Color.YELLOW)); + textMode.setText((mode == null) ? "" : mode); + + } finally{ + updating = false; + } + } + + /** + * 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") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + ledPowered = new ch.psi.pshell.swing.Led(); + jLabel1 = new javax.swing.JLabel(); + panelPowerCtr = new javax.swing.JPanel(); + buttonDisable = new javax.swing.JButton(); + buttonEnable = new javax.swing.JButton(); + jPanel2 = new javax.swing.JPanel(); + jLabel2 = new javax.swing.JLabel(); + spinnerSpeed = new ch.psi.utils.swing.HorizontalSpinner(); + jLabel7 = new javax.swing.JLabel(); + ledMoving = new ch.psi.pshell.swing.Led(); + panelMotionCtr = new javax.swing.JPanel(); + butonStop = new javax.swing.JButton(); + buttonResume = new javax.swing.JButton(); + buttonPause = new javax.swing.JButton(); + jPanel3 = new javax.swing.JPanel(); + jLabel3 = new javax.swing.JLabel(); + ledSettled = new ch.psi.pshell.swing.Led(); + jLabel4 = new javax.swing.JLabel(); + ledEmpty = new ch.psi.pshell.swing.Led(); + textTask = new javax.swing.JTextField(); + jLabel6 = new javax.swing.JLabel(); + textMode = new javax.swing.JTextField(); + buttonAbort = new javax.swing.JButton(); + jLabel8 = new javax.swing.JLabel(); + ledTask = new ch.psi.pshell.swing.Led(); + ledMode = new ch.psi.pshell.swing.Led(); + textPosition = new javax.swing.JTextField(); + ledPosition = new ch.psi.pshell.swing.Led(); + jLabel9 = new javax.swing.JLabel(); + panelState = new ch.psi.pshell.swing.DeviceStatePanel(); + jPanel4 = new javax.swing.JPanel(); + ledOpen = new ch.psi.pshell.swing.Led(); + jLabel5 = new javax.swing.JLabel(); + panelPowerCtr1 = new javax.swing.JPanel(); + buttonClose = new javax.swing.JButton(); + buttonOpen = new javax.swing.JButton(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Power")); + + ledPowered.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel1.setText("Powered:"); + + buttonDisable.setText("Disable"); + buttonDisable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonDisableActionPerformed(evt); + } + }); + + buttonEnable.setText("Enable"); + buttonEnable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonEnableActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelPowerCtrLayout = new javax.swing.GroupLayout(panelPowerCtr); + panelPowerCtr.setLayout(panelPowerCtrLayout); + panelPowerCtrLayout.setHorizontalGroup( + panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtrLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(buttonEnable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 18, Short.MAX_VALUE) + .addComponent(buttonDisable)) + ); + panelPowerCtrLayout.setVerticalGroup( + panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtrLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(buttonDisable, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonEnable)) + .addGap(0, 0, 0)) + ); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledPowered, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelPowerCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel1) + .addComponent(ledPowered, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelPowerCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + + jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Motion")); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel2.setText("Speed:"); + + spinnerSpeed.setModel(new javax.swing.SpinnerNumberModel(10, null, 100, 1)); + spinnerSpeed.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerSpeedStateChanged(evt); + } + }); + + jLabel7.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel7.setText("Moving:"); + + ledMoving.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + butonStop.setIcon(new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Stop.png"))); + butonStop.setText(" "); + butonStop.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + butonStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + butonStopActionPerformed(evt); + } + }); + + buttonResume.setIcon(new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Play.png"))); + buttonResume.setText(" "); + buttonResume.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + buttonResume.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonResumeActionPerformed(evt); + } + }); + + buttonPause.setIcon(new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Pause.png"))); + buttonPause.setText(" "); + buttonPause.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + buttonPause.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPauseActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelMotionCtrLayout = new javax.swing.GroupLayout(panelMotionCtr); + panelMotionCtr.setLayout(panelMotionCtrLayout); + panelMotionCtrLayout.setHorizontalGroup( + panelMotionCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelMotionCtrLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(butonStop, javax.swing.GroupLayout.DEFAULT_SIZE, 45, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonPause, javax.swing.GroupLayout.DEFAULT_SIZE, 46, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonResume, javax.swing.GroupLayout.DEFAULT_SIZE, 47, Short.MAX_VALUE) + .addGap(0, 0, 0)) + ); + panelMotionCtrLayout.setVerticalGroup( + panelMotionCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelMotionCtrLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelMotionCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(butonStop, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonPause, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonResume, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, 0)) + ); + + 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) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel7, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledMoving, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(14, 14, 14) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(panelMotionCtr, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spinnerSpeed)) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel7) + .addComponent(ledMoving, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelMotionCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel2) + .addComponent(spinnerSpeed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Status")); + + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel3.setText("Settled:"); + + ledSettled.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel4.setText("Empty:"); + + ledEmpty.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + textTask.setEditable(false); + textTask.setHorizontalAlignment(javax.swing.JTextField.CENTER); + + jLabel6.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel6.setText("Mode:"); + + textMode.setEditable(false); + textMode.setHorizontalAlignment(javax.swing.JTextField.CENTER); + + buttonAbort.setText("Abort"); + buttonAbort.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonAbortActionPerformed(evt); + } + }); + + jLabel8.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel8.setText("Task:"); + + ledTask.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + ledMode.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + textPosition.setEditable(false); + textPosition.setHorizontalAlignment(javax.swing.JTextField.CENTER); + + ledPosition.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel9.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel9.setText("Position:"); + + 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() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel8, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledTask, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledEmpty, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledSettled, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel9, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(textTask) + .addComponent(textPosition))) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(textMode))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonAbort) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jLabel3, jLabel4, jLabel6, jLabel8, jLabel9}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel3) + .addComponent(ledSettled, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel4) + .addComponent(ledEmpty, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(textMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ledMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6)) + .addGap(2, 2, 2) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(buttonAbort) + .addComponent(jLabel8) + .addComponent(ledTask, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(textTask, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel9) + .addComponent(ledPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(textPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + + jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder("Tool")); + + ledOpen.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel5.setText("Open:"); + + buttonClose.setText(" Close "); + buttonClose.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCloseActionPerformed(evt); + } + }); + + buttonOpen.setText(" Open "); + buttonOpen.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonOpenActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelPowerCtr1Layout = new javax.swing.GroupLayout(panelPowerCtr1); + panelPowerCtr1.setLayout(panelPowerCtr1Layout); + panelPowerCtr1Layout.setHorizontalGroup( + panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtr1Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(buttonOpen) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 18, Short.MAX_VALUE) + .addComponent(buttonClose)) + ); + + panelPowerCtr1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonClose, buttonOpen}); + + panelPowerCtr1Layout.setVerticalGroup( + panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtr1Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(buttonClose, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonOpen)) + .addGap(0, 0, 0)) + ); + + 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(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledOpen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelPowerCtr1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel5) + .addComponent(ledOpen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelPowerCtr1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, 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(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelState, 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) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonEnableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEnableActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".enable()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonEnableActionPerformed + + private void buttonDisableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDisableActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".disable()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonDisableActionPerformed + + private void spinnerSpeedStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerSpeedStateChanged + try{ + if (!updating){ + Context.getInstance().evalLineBackground(getDevice().getName() + ".set_monitor_speed(" + spinnerSpeed.getValue() + ")"); + } + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_spinnerSpeedStateChanged + + private void butonStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_butonStopActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".reset_motion()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_butonStopActionPerformed + + private void buttonPauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPauseActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".stop()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonPauseActionPerformed + + private void buttonResumeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonResumeActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".resume()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonResumeActionPerformed + + private void buttonAbortActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonAbortActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".stop_task()"); + //Context.getInstance().evalLineBackground(getDevice().getName() + ".task_kill('" + textTask.getText() + "')"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonAbortActionPerformed + + private void buttonCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCloseActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".close_tool()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonCloseActionPerformed + + private void buttonOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonOpenActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".open_tool()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonOpenActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton butonStop; + private javax.swing.JButton buttonAbort; + private javax.swing.JButton buttonClose; + private javax.swing.JButton buttonDisable; + private javax.swing.JButton buttonEnable; + private javax.swing.JButton buttonOpen; + private javax.swing.JButton buttonPause; + private javax.swing.JButton buttonResume; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + 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 ch.psi.pshell.swing.Led ledEmpty; + private ch.psi.pshell.swing.Led ledMode; + private ch.psi.pshell.swing.Led ledMoving; + private ch.psi.pshell.swing.Led ledOpen; + private ch.psi.pshell.swing.Led ledPosition; + private ch.psi.pshell.swing.Led ledPowered; + private ch.psi.pshell.swing.Led ledSettled; + private ch.psi.pshell.swing.Led ledTask; + private javax.swing.JPanel panelMotionCtr; + private javax.swing.JPanel panelPowerCtr; + private javax.swing.JPanel panelPowerCtr1; + private ch.psi.pshell.swing.DeviceStatePanel panelState; + private javax.swing.JSpinner spinnerSpeed; + private javax.swing.JTextField textMode; + private javax.swing.JTextField textPosition; + private javax.swing.JTextField textTask; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/RobotTcp.java b/plugins/RobotTcp.java new file mode 100644 index 0000000..d3f4c33 --- /dev/null +++ b/plugins/RobotTcp.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.*; +import ch.psi.pshell.serial.*; + +/** + */ +public class RobotTcp extends TcpDevice { + + public RobotTcp(String name, String server) { + super(name, server); + } + + public Object run() throws Exception{ + Thread.sleep(1000); + return ("Done"); + } + +} diff --git a/plugins/SmartMagnetConfig.java b/plugins/SmartMagnetConfig.java new file mode 100644 index 0000000..2c6213c --- /dev/null +++ b/plugins/SmartMagnetConfig.java @@ -0,0 +1,14 @@ + +import ch.psi.pshell.device.DeviceConfig; + +/** + * + */ +public class SmartMagnetConfig extends DeviceConfig{ + public double holdingCurrent; + public double restingCurrent; + public double mountCurrent; + public double unmountCurrent; + public double remanenceCurrent; + +} diff --git a/plugins/SmartMagnetPanel.form b/plugins/SmartMagnetPanel.form new file mode 100644 index 0000000..432e7bd --- /dev/null +++ b/plugins/SmartMagnetPanel.form @@ -0,0 +1,284 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jPanel1" max="32767" attributes="0"/> + <Component id="panelState" alignment="0" max="32767" attributes="0"/> + <Component id="panelCurrent" max="32767" attributes="0"/> + <Component id="jPanel2" max="32767" attributes="0"/> + <Component id="jPanel3" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jPanel1" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelCurrent" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel2" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel3" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelState" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Container class="javax.swing.JPanel" name="jPanel1"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Status"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel1" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledStatus" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelPowerCtr" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel5" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledMounted" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel10" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelCurrentRb" min="-2" pref="173" max="-2" attributes="0"/> + </Group> + </Group> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel1" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledStatus" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelPowerCtr" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel5" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledMounted" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jLabel10" min="-2" max="-2" attributes="0"/> + <Component id="panelCurrentRb" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledStatus"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel1"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Status:"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelPowerCtr"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <EmptySpace min="0" pref="150" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <EmptySpace min="0" pref="23" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + </Layout> + </Container> + <Component class="javax.swing.JLabel" name="jLabel5"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Mounted:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledMounted"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel10"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Current:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.DeviceValuePanel" name="panelCurrentRb"> + <Properties> + <Property name="deviceName" type="java.lang.String" value="smc_current_rb"/> + </Properties> + </Component> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="panelState"> + </Component> + <Component class="ch.psi.pshell.swing.ProcessVariablePanel" name="panelCurrent"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Current"/> + </Border> + </Property> + <Property name="deviceName" type="java.lang.String" value="smc_current"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="jPanel2"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Supress"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jLabel2" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledSupressed" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + <Component id="buttonSupressOn" linkSize="1" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="buttonSupressOff" linkSize="1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="1" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel2" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledSupressed" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="buttonSupressOn" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="buttonSupressOff" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JLabel" name="jLabel2"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Supressed:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledSupressed"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JButton" name="buttonSupressOn"> + <Properties> + <Property name="text" type="java.lang.String" value="On"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonSupressOnActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonSupressOff"> + <Properties> + <Property name="text" type="java.lang.String" value="Off"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonSupressOffActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="jPanel3"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Configuration"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="buttonConfiguration" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="1" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="buttonConfiguration" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonConfiguration"> + <Properties> + <Property name="text" type="java.lang.String" value="Configuration"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonConfigurationActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> +</Form> diff --git a/plugins/SmartMagnetPanel.java b/plugins/SmartMagnetPanel.java new file mode 100644 index 0000000..589fb82 --- /dev/null +++ b/plugins/SmartMagnetPanel.java @@ -0,0 +1,320 @@ + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.ui.App; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.pshell.core.Context; +import ch.psi.utils.State; +import java.awt.Color; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.script.ScriptException; + +/** + * + */ +public class SmartMagnetPanel extends DevicePanel { + + /** + * Creates new form RobotPanel + */ + public SmartMagnetPanel() { + initComponents(); + } + + @Override + public void setDevice(Device device) { + super.setDevice(device); + if (device == null) { + + } + panelState.setDevice(device); + this.startTimer(1000, 100); + } + + @Override + protected void onDeviceStateChanged(State state, State former) { + switch(state){ + case Paused: + ledSupressed.setColor(Color.ORANGE); + ledStatus.setColor(Color.GREEN); + ledMounted.setColor(Color.RED); + break; + case Ready: + ledSupressed.setColor(Color.BLACK); + ledStatus.setColor(Color.GREEN); + ledMounted.setColor(Color.GREEN); + break; + case Busy: + ledSupressed.setColor(Color.BLACK); + ledStatus.setColor(Color.GREEN); + ledMounted.setColor(Color.ORANGE); + break; + case Fault: + ledSupressed.setColor(Color.RED); + ledStatus.setColor(Color.RED); + ledMounted.setColor(Color.RED); + break; + default: + ledSupressed.setColor(Color.BLACK); + ledStatus.setColor(Color.BLACK); + ledMounted.setColor(Color.BLACK); + break; + } + buttonSupressOn.setEnabled((state==State.Ready) || (state == State.Busy)); + buttonSupressOff.setEnabled(state == State.Paused); + } + + @Override + protected void onDeviceCacheChanged(Object value, Object former, long timestamp, boolean valueChange) { + } + + /** + * 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") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + ledStatus = new ch.psi.pshell.swing.Led(); + jLabel1 = new javax.swing.JLabel(); + panelPowerCtr = new javax.swing.JPanel(); + jLabel5 = new javax.swing.JLabel(); + ledMounted = new ch.psi.pshell.swing.Led(); + jLabel10 = new javax.swing.JLabel(); + panelCurrentRb = new ch.psi.pshell.swing.DeviceValuePanel(); + panelState = new ch.psi.pshell.swing.DeviceStatePanel(); + panelCurrent = new ch.psi.pshell.swing.ProcessVariablePanel(); + jPanel2 = new javax.swing.JPanel(); + jLabel2 = new javax.swing.JLabel(); + ledSupressed = new ch.psi.pshell.swing.Led(); + buttonSupressOn = new javax.swing.JButton(); + buttonSupressOff = new javax.swing.JButton(); + jPanel3 = new javax.swing.JPanel(); + buttonConfiguration = new javax.swing.JButton(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Status")); + + ledStatus.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel1.setText("Status:"); + + javax.swing.GroupLayout panelPowerCtrLayout = new javax.swing.GroupLayout(panelPowerCtr); + panelPowerCtr.setLayout(panelPowerCtrLayout); + panelPowerCtrLayout.setHorizontalGroup( + panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 150, Short.MAX_VALUE) + ); + panelPowerCtrLayout.setVerticalGroup( + panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 23, Short.MAX_VALUE) + ); + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel5.setText("Mounted:"); + + ledMounted.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel10.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel10.setText("Current:"); + + panelCurrentRb.setDeviceName("smc_current_rb"); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledStatus, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelPowerCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledMounted, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel10, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelCurrentRb, javax.swing.GroupLayout.PREFERRED_SIZE, 173, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel1) + .addComponent(ledStatus, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelPowerCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel5) + .addComponent(ledMounted, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel10) + .addComponent(panelCurrentRb, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + panelCurrent.setBorder(javax.swing.BorderFactory.createTitledBorder("Current")); + panelCurrent.setDeviceName("smc_current"); + + jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Supress")); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel2.setText("Supressed:"); + + ledSupressed.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + buttonSupressOn.setText("On"); + buttonSupressOn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonSupressOnActionPerformed(evt); + } + }); + + buttonSupressOff.setText("Off"); + buttonSupressOff.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonSupressOffActionPerformed(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() + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledSupressed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonSupressOn) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonSupressOff) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + jPanel2Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonSupressOff, buttonSupressOn}); + + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel2) + .addComponent(ledSupressed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonSupressOn) + .addComponent(buttonSupressOff)) + .addContainerGap()) + ); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Configuration")); + + buttonConfiguration.setText("Configuration"); + buttonConfiguration.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonConfigurationActionPerformed(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(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonConfiguration) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonConfiguration) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelState, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelCurrent, 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(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelCurrent, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonSupressOnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonSupressOnActionPerformed + try { + Context.getInstance().evalLineBackground("smart_magnet.set_supress(True)"); + } catch (Exception ex) { + Logger.getLogger(SmartMagnetPanel.class.getName()).log(Level.SEVERE, null, ex); + } + }//GEN-LAST:event_buttonSupressOnActionPerformed + + private void buttonSupressOffActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonSupressOffActionPerformed + try { + Context.getInstance().evalLineBackground("smart_magnet.set_supress(False)"); + } catch (Exception ex) { + Logger.getLogger(SmartMagnetPanel.class.getName()).log(Level.SEVERE, null, ex); + } + }//GEN-LAST:event_buttonSupressOffActionPerformed + + private void buttonConfigurationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonConfigurationActionPerformed + try { + this.showConfigEditor(true, false); + } catch (Exception ex) { + Logger.getLogger(SmartMagnetPanel.class.getName()).log(Level.SEVERE, null, ex); + } + }//GEN-LAST:event_buttonConfigurationActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonConfiguration; + private javax.swing.JButton buttonSupressOff; + private javax.swing.JButton buttonSupressOn; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel10; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel5; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private ch.psi.pshell.swing.Led ledMounted; + private ch.psi.pshell.swing.Led ledStatus; + private ch.psi.pshell.swing.Led ledSupressed; + private ch.psi.pshell.swing.ProcessVariablePanel panelCurrent; + private ch.psi.pshell.swing.DeviceValuePanel panelCurrentRb; + private javax.swing.JPanel panelPowerCtr; + private ch.psi.pshell.swing.DeviceStatePanel panelState; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/TestZMQ.java b/plugins/TestZMQ.java new file mode 100644 index 0000000..cec2c40 --- /dev/null +++ b/plugins/TestZMQ.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/** + * + * @author gac-S_Changer + */ +public class TestZMQ { + public static void main(String[] args) { + String server = "raspberrypi:5556"; + org.zeromq.ZMQ.Context context = org.zeromq.ZMQ.context(1); + org.zeromq.ZMQ.Socket subscriber = context.socket(org.zeromq.ZMQ.SUB); + subscriber.connect("tcp://" + server); + subscriber.subscribe("Status".getBytes()); + while (!Thread.currentThread().isInterrupted()) { + String type = subscriber.recvStr(); + String contents = subscriber.recvStr(); + System.out.println(type + " : " + contents); + } + subscriber.close(); + context.term(); + } +} diff --git a/plugins/WagoPanel.form b/plugins/WagoPanel.form new file mode 100644 index 0000000..9864ffa --- /dev/null +++ b/plugins/WagoPanel.form @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="deviceStatePanel1" max="32767" attributes="0"/> + <Component id="panelSafety" max="32767" attributes="0"/> + <Component id="panelRobot1" max="32767" attributes="0"/> + <Component id="panelDewar" alignment="0" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="panelSafety" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelDewar" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelRobot1" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="deviceStatePanel1" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="deviceStatePanel1"> + <Properties> + <Property name="deviceName" type="java.lang.String" value="wago"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelSafety"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Safety"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="buttonReleasePsys" linkSize="2" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="buttonReleaseLocal" linkSize="2" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="buttonReleaseLocal" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="buttonReleasePsys" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonReleasePsys"> + <Properties> + <Property name="text" type="java.lang.String" value="Release PSYS"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonReleasePsysActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonReleaseLocal"> + <Properties> + <Property name="text" type="java.lang.String" value="Release Local"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonReleaseLocalActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="panelRobot1"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Dryer"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="buttonHeater" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="buttonStream" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="buttonHeater" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="buttonStream" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JToggleButton" name="buttonHeater"> + <Properties> + <Property name="text" type="java.lang.String" value="Heater"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonHeaterActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JToggleButton" name="buttonStream"> + <Properties> + <Property name="text" type="java.lang.String" value="Air Stream"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonStreamActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.ProcessVariablePanel" name="panelDewar"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder justification="1" title="Dewar Light"/> + </Border> + </Property> + <Property name="deviceName" type="java.lang.String" value="led_level"/> + <Property name="showAdvanced" type="boolean" value="false"/> + <Property name="showButtons" type="boolean" value="false"/> + <Property name="showLimitButtons" type="boolean" value="false"/> + <Property name="showSlider" type="boolean" value="true"/> + <Property name="showStop" type="boolean" value="false"/> + </Properties> + </Component> + </SubComponents> +</Form> diff --git a/plugins/WagoPanel.java b/plugins/WagoPanel.java new file mode 100644 index 0000000..cacadcd --- /dev/null +++ b/plugins/WagoPanel.java @@ -0,0 +1,207 @@ +import ch.psi.mxsc.Controller; +import ch.psi.pshell.core.Context; +import ch.psi.pshell.swing.DevicePanel; +import java.util.concurrent.CompletableFuture; +import javax.swing.border.TitledBorder; + +/** + * + */ +public class WagoPanel extends DevicePanel { + + public WagoPanel() { + initComponents(); + this.startTimer(10000); + } + + + CompletableFuture future; + + @Override + public void onTimer(){ + if ((getDevice()!=null)){ + updateTitle(); + } + } + + void updateTitle(){ + Boolean roomTemp = (Controller.getInstance().isLedRoomTemp()); + if (roomTemp==null){ + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light"); + } else if (roomTemp==true){ + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light (room temperature)"); + } else { + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light (LN2)"); + } + } + + + void execute(String statement){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (WagoPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + panelSafety = new javax.swing.JPanel(); + buttonReleasePsys = new javax.swing.JButton(); + buttonReleaseLocal = new javax.swing.JButton(); + panelRobot1 = new javax.swing.JPanel(); + buttonHeater = new javax.swing.JToggleButton(); + buttonStream = new javax.swing.JToggleButton(); + panelDewar = new ch.psi.pshell.swing.ProcessVariablePanel(); + + deviceStatePanel1.setDeviceName("wago"); + + panelSafety.setBorder(javax.swing.BorderFactory.createTitledBorder("Safety")); + + buttonReleasePsys.setText("Release PSYS"); + buttonReleasePsys.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReleasePsysActionPerformed(evt); + } + }); + + buttonReleaseLocal.setText("Release Local"); + buttonReleaseLocal.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReleaseLocalActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelSafetyLayout = new javax.swing.GroupLayout(panelSafety); + panelSafety.setLayout(panelSafetyLayout); + panelSafetyLayout.setHorizontalGroup( + panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSafetyLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonReleasePsys) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonReleaseLocal) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + panelSafetyLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonReleaseLocal, buttonReleasePsys}); + + panelSafetyLayout.setVerticalGroup( + panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSafetyLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonReleaseLocal) + .addComponent(buttonReleasePsys)) + .addContainerGap()) + ); + + panelRobot1.setBorder(javax.swing.BorderFactory.createTitledBorder("Dryer")); + + buttonHeater.setText("Heater"); + buttonHeater.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonHeaterActionPerformed(evt); + } + }); + + buttonStream.setText("Air Stream"); + buttonStream.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonStreamActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelRobot1Layout = new javax.swing.GroupLayout(panelRobot1); + panelRobot1.setLayout(panelRobot1Layout); + panelRobot1Layout.setHorizontalGroup( + panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelRobot1Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonHeater) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonStream) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + panelRobot1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonHeater, buttonStream}); + + panelRobot1Layout.setVerticalGroup( + panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelRobot1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonHeater) + .addComponent(buttonStream)) + .addContainerGap()) + ); + + panelDewar.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Dewar Light", javax.swing.border.TitledBorder.LEFT, javax.swing.border.TitledBorder.DEFAULT_POSITION)); + panelDewar.setDeviceName("led_level"); + panelDewar.setShowAdvanced(false); + panelDewar.setShowButtons(false); + panelDewar.setShowLimitButtons(false); + panelDewar.setShowSlider(true); + panelDewar.setShowStop(false); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelSafety, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelRobot1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelDewar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(panelSafety, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelDewar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelRobot1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonReleasePsysActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReleasePsysActionPerformed + execute("release_psys()"); + }//GEN-LAST:event_buttonReleasePsysActionPerformed + + private void buttonReleaseLocalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReleaseLocalActionPerformed + execute("release_local()"); + }//GEN-LAST:event_buttonReleaseLocalActionPerformed + + private void buttonHeaterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonHeaterActionPerformed + execute("set_heater(" + (buttonHeater.isSelected() ? "True": "False") + ")"); + }//GEN-LAST:event_buttonHeaterActionPerformed + + private void buttonStreamActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStreamActionPerformed + execute("set_air_stream(" + (buttonStream.isSelected()? "True": "False")+ ")"); + }//GEN-LAST:event_buttonStreamActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JToggleButton buttonHeater; + private javax.swing.JButton buttonReleaseLocal; + private javax.swing.JButton buttonReleasePsys; + private javax.swing.JToggleButton buttonStream; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private ch.psi.pshell.swing.ProcessVariablePanel panelDewar; + private javax.swing.JPanel panelRobot1; + private javax.swing.JPanel panelSafety; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/gui.form b/plugins/gui.form new file mode 100644 index 0000000..5775937 --- /dev/null +++ b/plugins/gui.form @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="renderer1" min="-2" pref="154" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="82" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="51" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jButton1" min="-2" max="-2" attributes="0"/> + <Component id="linePlotJFree1" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace pref="250" max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="24" max="-2" attributes="0"/> + <Component id="jButton1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="renderer1" min="-2" pref="102" max="-2" attributes="0"/> + <EmptySpace pref="20" max="32767" attributes="0"/> + <Component id="linePlotJFree1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="jButton1"> + <Properties> + <Property name="text" type="java.lang.String" value="Abort"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/> + </Events> + </Component> + <Component class="ch.psi.pshell.imaging.Renderer" name="renderer1"> + </Component> + <Component class="ch.psi.pshell.plot.LinePlotJFree" name="linePlotJFree1"> + </Component> + </SubComponents> +</Form> diff --git a/plugins/gui.java b/plugins/gui.java new file mode 100644 index 0000000..abeb59b --- /dev/null +++ b/plugins/gui.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class gui extends Panel { + + public gui() { + initComponents(); + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + + } + + @Override + public void onStateChange(State state, State former) { + + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + + //Callback to perform update - in event thread + @Override + protected void doUpdate() { + } + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jButton1 = new javax.swing.JButton(); + renderer1 = new ch.psi.pshell.imaging.Renderer(); + linePlotJFree1 = new ch.psi.pshell.plot.LinePlotJFree(); + + jButton1.setText("Abort"); + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(renderer1, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(82, 82, 82)) + .addGroup(layout.createSequentialGroup() + .addGap(51, 51, 51) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jButton1) + .addComponent(linePlotJFree1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(250, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(24, 24, 24) + .addComponent(jButton1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(renderer1, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 20, Short.MAX_VALUE) + .addComponent(linePlotJFree1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + }// </editor-fold>//GEN-END:initComponents + + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + try { + abort(); + } catch (InterruptedException ex) { + Logger.getLogger(gui.class.getName()).log(Level.SEVERE, null, ex); + } + }//GEN-LAST:event_jButton1ActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton jButton1; + private ch.psi.pshell.plot.LinePlotJFree linePlotJFree1; + private ch.psi.pshell.imaging.Renderer renderer1; + // End of variables declaration//GEN-END:variables +} diff --git a/script/LN2_Monitoring.scd b/script/LN2_Monitoring.scd new file mode 100644 index 0000000..d2ab014 --- /dev/null +++ b/script/LN2_Monitoring.scd @@ -0,0 +1,15 @@ +[ + [ [ true, "phase_separator_level", "Device", 1, 1, "102,204,255" ], + [ true, "filling_phase_separator", "Device", 1, 1, "51,255,255" ], + [ true, "filling_dewar", "Device", 1, 1, "0,0,102" ], + [ true, "dewar_level", "Device", 1, 1, "0,51,153" ], + [ true, "rim_heater_temp", "Device", 1, 1, "255,0,51" ] ], + [ [ "1", 0.0, 100.0, null, null, 1000000.0, false, null ], + [ "2", null, null, null, null, null, null, null ], + [ "3", null, null, null, null, null, null, null ], + [ "4", null, null, null, null, null, null, null ], + [ "5", null, null, null, null, null, null, null ] ], + [ [ ] ], + [ [ "", 20000, 100 ], + [ "", "" ] ] +] \ No newline at end of file diff --git a/script/LevelMonitoring.scd b/script/LevelMonitoring.scd new file mode 100644 index 0000000..ae328cc --- /dev/null +++ b/script/LevelMonitoring.scd @@ -0,0 +1,12 @@ +[ + [ [ true, "phase_separator_level", "Device", 1, 1, "255,0,0" ], + [ true, "dewar_level", "Device", 1, 1, "0,0,255" ] ], + [ [ "1", 0.0, 100.0, null, null, 100000.0, false, null ], + [ "2", null, null, null, null, null, null, null ], + [ "3", null, null, null, null, null, null, null ], + [ "4", null, null, null, null, null, null, null ], + [ "5", null, null, null, null, null, null, null ] ], + [ [ ] ], + [ [ "", 20000, 100 ], + [ "", "" ] ] +] \ No newline at end of file diff --git a/script/calibration/BinarySearchYZ.py b/script/calibration/BinarySearchYZ.py new file mode 100644 index 0000000..42db379 --- /dev/null +++ b/script/calibration/BinarySearchYZ.py @@ -0,0 +1,29 @@ +import plotutils +import math + + +#STRATEGY = "Normal" +#STRATEGY = "Boundary" +#STRATEGY = "FullNeighborhood" +RANGE = [-5.0, 5.0] +STEP_SIZE = 0.1 +LATENCY = 0.05 + + +robot.enable() +move_to_laser() + + +robot.set_motors_enabled(True) +current_y = robot_y.getPosition() +current_z = robot_z.getPosition() + + +r = bsearch([robot_y, robot_z], laser_distance,[RANGE[0], RANGE[0]], [RANGE[1], RANGE[1]], [STEP_SIZE,STEP_SIZE], relative = True, maximum=True, strategy = STRATEGY, latency = LATENCY, title = "Binary Search YZ") + + +print r.print() +opt_y, opt_z= r.getOptimalPosition() +offset_y, offset_z = opt_y - current_y, opt_z - current_z + +print "offset_y: ", offset_y, " offset_z: ", offset_z \ No newline at end of file diff --git a/script/calibration/HillClimbingXZ.py b/script/calibration/HillClimbingXZ.py new file mode 100644 index 0000000..2fcab26 --- /dev/null +++ b/script/calibration/HillClimbingXZ.py @@ -0,0 +1,45 @@ +import plotutils +import math + + +#STRATEGY = "Normal" +STRATEGY = "Boundary" +#STRATEGY = "FullNeighborhood" +RANGE = [-5.0, 5.0] +INITIAL_STEP = 1.0 +STEP_SIZE = 0.05 +LATENCY = 0.05 +NOISE_FILTER = 1 + + +robot.enable() +move_to_laser() + + +robot.set_motors_enabled(True) + +current_x = robot_x.getPosition() +current_z = robot_z.getPosition() + + + + +class Distance(Readable): + def read(self): + ret = ue.readable.read() + ret = 0.0 if math.isnan(ret) else ret + return ret + +laser_distance=Distance() +start = time.time() +r = hsearch([robot_x, robot_z],laser_distance, [RANGE[0], RANGE[0]], [RANGE[1], RANGE[1]], [INITIAL_STEP,INITIAL_STEP], [STEP_SIZE,STEP_SIZE], NOISE_FILTER, relative = True, maximum=True, latency = LATENCY, title = "Hill Climbing XZ") + + + +print r.print() +opt_x, opt_z= r.getOptimalPosition() +offset_x, offset_z = opt_x - current_x, opt_z - current_z + +print "offset_x: ", offset_x, " offset_z: ", offset_z + + diff --git a/script/calibration/ScanRZ.py b/script/calibration/ScanRZ.py new file mode 100644 index 0000000..55d3bba --- /dev/null +++ b/script/calibration/ScanRZ.py @@ -0,0 +1,31 @@ +#Imports +import plotutils +from mathutils import fit_gaussian, Gaussian + +#Parameters +RANGE = [-120.0,120.0] +STEP = 5.0 +LATENCY = 0.005 +RELATIVE = False + +#Enabling and checking +#enable_motion() +#system_check() +robot.enable() + + +#Body +robot.set_tool(TOOL_DEFAULT) +move_to_laser() +#robot.set_joint_motors_enabled(True) +robot.set_motors_enabled(True) +robot_rz.move(0.0) +robot.set_motors_enabled(True) +ret = lscan(robot_rz, ue.readable, RANGE[0], RANGE[1], STEP, latency = LATENCY, relative = RELATIVE, range = "auto", title = "Scan2") + + +#Cleanup + + + + diff --git a/script/calibration/ScanX.py b/script/calibration/ScanX.py new file mode 100644 index 0000000..462681b --- /dev/null +++ b/script/calibration/ScanX.py @@ -0,0 +1,87 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + + +d = robot.get_distance_to_pnt("pLaser") +if d<0: + raise Exception ("Error calculating distance to laser: " + str(d)) + +if d>20: + raise Exception ("Should be near the laser position to perform the scan") + +RANGE = [-2.0, 2.0] #[-1.5, 1.5] +STEP = 0.02 +Z_OFFSET = 0 #-1.0 +LATENCY = 0.025 +BORDER_SIZE = 0.15 + +robot.enable() +robot.set_motors_enabled(True) +current_positon = robot_x.getPosition() +robot_z.moveRel(Z_OFFSET) + +robot.setPolling(25) +try: + ret = lscan(robot_x, ue.readable, RANGE[0], RANGE[1], STEP, latency = LATENCY, relative = True) +finally: + robot.setPolling(DEFAULT_ROBOT_POLLING) + +d = ret.getReadable(0) + +first_index = -1 +last_index = -1 +for i in range(len(d)): + if not math.isnan(d[i]): + if first_index<0: + first_index = i + last_index = i + +if first_index == -1 or last_index < first_index: + raise Exception("Invalid range") + + +remove = int(max(BORDER_SIZE, STEP) / STEP) + +_range = [first_index+remove, last_index-remove] +if _range[1] <= _range[0]: + raise Exception("Invalid range: " + str(_range)) + + +center_index = int((_range[0] + _range[1])/2) +center_positon = ret.getPositions(0)[center_index] + + + + +y = ret.getReadable(0)[_range[0] : _range[1]] +x = ret.getPositions(0)[_range[0]: _range[1]] + +#Clear NaNs +first_value=ret.getReadable(0)[first_index] +y = [(first_value if math.isnan(v) else v) for v in y] + + +#x = enforce_monotonic(x) +#(normalization, mean_val, sigma) = fit_gaussian([-v for v in y], x) + + +closest_x = x[y.index(min(y))] +closest_y = y[y.index(min(y))] + + + +if closest_x is None or closest_x <= ret.getPositions(0)[first_index] or closest_x >= ret.getPositions(0)[last_index]: + raise Exception("Invalid Fit") + + + +center_offset = center_positon-closest_y +#center_offset = current_positon-closest_y + + + +p=get_plots()[0] +p.addMarker(closest_y, p.AxisId.X, str(closest_y), Color.GREEN) + +robot.set_motors_enabled(True) +robot_x.move(closest_x) diff --git a/script/calibration/ScanY.py b/script/calibration/ScanY.py new file mode 100644 index 0000000..cf93b9a --- /dev/null +++ b/script/calibration/ScanY.py @@ -0,0 +1,99 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + +FIT = True + +d = robot.get_distance_to_pnt("pLaser") +if d<0: + raise Exception ("Error calculating distance to laser: " + str(d)) + +if d>20: + raise Exception ("Should be near the laser position to perform the scan") + +RANGE = [-7.0, 4.0] #[-1.5, 1.5] +STEP = 0.02 +Z_OFFSET = 0 #-1.0 +LATENCY = 0.025 +BORDER_SIZE = 0.15 + +robot.enable() +robot.set_motors_enabled(True) +current_positon = robot_y.getPosition() +robot_z.moveRel(Z_OFFSET) + + +print "Moving to scan start position: " , RANGE[0] +robot.set_motors_enabled(True) +robot_y.moveRel( RANGE[0]) +robot.set_motors_enabled(True) +print "Starting scan Y" + +RANGE = [0, (RANGE[1] - RANGE[0] )] + +robot.setPolling(25) +try: + ret = lscan(robot_y, ue.readable, RANGE[0], RANGE[1], STEP, latency = LATENCY, relative = True) +finally: + robot.setPolling(DEFAULT_ROBOT_POLLING) + +d = ret.getReadable(0) + +first_index = -1 +last_index = -1 +for i in range(len(d)): + if not math.isnan(d[i]): + if first_index<0: + first_index = i + last_index = i + +if first_index == -1 or last_index < first_index: + raise Exception("Invalid range") + + +remove = int(max(BORDER_SIZE, STEP) / STEP) + +_range = [first_index+remove, last_index-remove] +if _range[1] <= _range[0]: + raise Exception("Invalid range: " + str(_range)) + + +center_index = int((_range[0] + _range[1])/2) +center_positon = ret.getPositions(0)[center_index] + + + + +y = ret.getReadable(0)[_range[0] : _range[1]] +x = ret.getPositions(0)[_range[0]: _range[1]] + +#Clear NaNs +first_value=ret.getReadable(0)[first_index] +y = [(first_value if math.isnan(v) else v) for v in y] + + +if FIT: + x = enforce_monotonic(x) + offset=100 + (normalization, mean_val, sigma) = fit_gaussian([offset-v for v in y], x) + closest_y = mean_val + closest_x = 100 -normalization +else: + closest_y = x[y.index(min(y))] + closest_x = y[y.index(min(y))] + + +if closest_y is None or closest_y <= ret.getPositions(0)[first_index] or closest_y >= ret.getPositions(0)[last_index]: + raise Exception("Invalid Fit") + + + +center_offset = center_positon-closest_y +#center_offset = current_positon-closest_y + + + +p=get_plots()[0] +p.addMarker(closest_y, p.AxisId.X, str(closest_y), Color.GREEN) + +robot.set_motors_enabled(True) +robot_y.move(closest_y) diff --git a/script/calibration/ScanYZ.py b/script/calibration/ScanYZ.py new file mode 100644 index 0000000..bee63e6 --- /dev/null +++ b/script/calibration/ScanYZ.py @@ -0,0 +1,93 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + +SINGLE_PASS = False +if SINGLE_PASS: + STEP_SIZE = 0.2 +else: + STEP_SIZE = 1.0 +STEP_Z_FINAL = 0.1 + +RANGE = [-5.0, 5.0] +LATENCY = 0.05 + +Z_FINAL_OFFSET = 0.0 + + +SINGLE_PASS = True +STEP_SIZE = 0.1 + + +robot.enable() +move_to_laser() + +step_y = STEP_SIZE +step_z = STEP_SIZE +range_y = [RANGE[0], RANGE[1]] +range_z = [RANGE[0], RANGE[1]] + +robot.set_motors_enabled(True) +current_y = robot_y.getPosition() +current_z = robot_z.getPosition() + +print "Current pos y,z" , current_y, ",", current_z +ret = ascan([robot_y, robot_z], ue.readable, [range_y[0], range_z[0]], [range_y[1], range_z[1]], [step_y,step_z], latency = LATENCY, relative = True , zigzag=False, title = "Scan XY") +data = ret.getData(0)[0] +#plot(Convert.transpose(data), title="Data") + +integ = [] +for x in data: integ.append(sum( [ (0.0 if (math.isnan(y)) else y) for y in x])) + +xdata= frange(range_y[0], range_y[1], step_y , False, True) +p = plot(integ, title = "Fit", xdata=xdata)[0] + + +max_x_index = integ.index(max(integ)) +max_x = xdata[max_x_index] +try: + (normalization, mean_val, sigma) = fit_gaussian(integ, xdata) +except: + raise Exception("Invalid Fit") +gaussian = Gaussian(normalization, mean_val, sigma) +xdata= frange(range_y[0], range_y[1], step_y/100.0 , False, True) +plot_function(p, gaussian, "Fit", xdata, show_points = False, show_lines = True, color = Color.BLUE) + +#So +if abs(mean_val - max_x) > 1.0: + raise Exception("Invalid Y detection") +y_offset = mean_val +center_y = current_y + y_offset + +print "Y offset = ", y_offset + +robot_y.move(center_y) +if SINGLE_PASS: + z_scan_data = data[max_x_index] +else: + step_z = STEP_Z_FINAL + ret2 = lscan(robot_z, ue.readable, range_z[0], range_z[1], step_z, latency = LATENCY, relative = True , zigzag=False) + z_scan_data = ret2.getData(0)[0] + +max_z_index= z_scan_data.index(max(z_scan_data)) +last_z_index = 0 +for i in range(len(z_scan_data)): + if not math.isnan(z_scan_data[i]): + last_z_index = i +#Shape is cone: z is inceraseing. For proper detection last Z must be furthest +if abs(max_z_index - last_z_index) * step_z > 1.0: + raise Exception("Invalid Z detection") + +if SINGLE_PASS: + max_z = ret.getPositions(1)[len(data[0]) * max_x_index + last_z_index] +else: + max_z = ret2.getPositions(0)[last_z_index] + +z_offset = max_z - current_z + Z_FINAL_OFFSET + +robot_z.move(max_z + Z_FINAL_OFFSET) + +print "Z offset = ", z_offset + + +#Updating tool: +#update_tool(None, x_offset=x_offset, z_offset=z_offset) diff --git a/script/calibration/ToolCalibration.py b/script/calibration/ToolCalibration.py new file mode 100644 index 0000000..602403b --- /dev/null +++ b/script/calibration/ToolCalibration.py @@ -0,0 +1,60 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + + +robot.assert_tool(TOOL_CALIBRATION) +robot.set_motors_enabled(True) +robot.set_joint_motors_enabled(True) + + +initial_pos = robot.get_cartesian_pos() + +robot.enable() +move_to_laser() + +robot.align() + + +run("calibration/ScanYZ") + +robot.set_motors_enabled(True) + + +first_y = robot_y.take() +first_z = robot_z.take() +first_y = ue.take() +first_j6 = robot_j6.take() +if first_y is None: + raise Exception("Invalid YZ scan values in first scan") + + +robot.set_joint_motors_enabled(True) +if first_j6>0: + robot_j6.moveRel(-180.0, -1) +else: + robot_j6.moveRel(180.0, -1) + + +robot.set_motors_enabled(True) +run("calibration/ScanYZ") + +robot.set_motors_enabled(True) + +second_y = robot_y.take() +second_z = robot_z.take() +second_y = ue.take() +second_j6 = robot_j6.take() +if second_y is None: + raise Exception("Invalid XZ scan values in first scan") + + +#Updates the tool +xoff = (first_x - second_x)/2 +yoff = (first_y - second_y)/2 +t=robot.get_tool_trsf(TOOL_DEFAULT) +t[0]=xoff +t[1]=-yoff +robot.set_tool_trsf(t, TOOL_DEFAULT) + + + diff --git a/script/calibration/ToolCalibration2.py b/script/calibration/ToolCalibration2.py new file mode 100644 index 0000000..e9b71ae --- /dev/null +++ b/script/calibration/ToolCalibration2.py @@ -0,0 +1,86 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + + +#robot.assert_tool(TOOL_CALIBRATION) +#cal_tool = TOOL_DEFAULT +cal_tool = TOOL_CALIBRATION + +robot.set_tool(cal_tool) +robot.enable() +move_to_laser() + + +robot.set_motors_enabled(True) +robot.set_joint_motors_enabled(True) +initial_pos = robot.get_cartesian_pos() + +robot.enable() +move_to_laser() + +#robot.align() + + +run("calibration/ScanY") + +pos1 = robot.get_cartesian_pos() +x1, y1 = closest_x, closest_y + +print "Closest 1: ", [x1, y1] +print "Position 1: ", pos1 + + +pj6 = robot_j6.position +if pj6>0: + robot_j6.move(pj6 - 180.0) +else: + robot_j6.move(pj6 + 180.0) + + +run("calibration/ScanY") + + +x2, y2 = closest_x, closest_y + +print "Closest 2: ", [x2, y2] + + + +off_x = x1 - x2 + +#robot.set_motors_enabled(True) +#robot_x.moveRel(off_x, -1) + +#For composing cannot use tcp_p, need another auxiliary point. tcp_t is also destroyed. +robot.set_pnt(robot.get_cartesian_pos(), "pTemp") +robot.set_trsf([off_x, 0,0,0,0,0]) +c=robot.compose("pTemp", FRAME_TABLE, "tcp_t" ) +robot.set_pnt(c, "pTemp") +robot.movel("pTemp", cal_tool, DESC_SCAN, sync=True) + + +pos2 = robot.get_cartesian_pos() +print pos2 + +print "Position 2: ", pos2 + + + +#Updates the tool +xoff = (pos2[0]-pos1[0])/2 +yoff = (pos2[1]-pos1[1])/2 + +#print "Offset: ", [xoff, yoff] + +t=robot.get_tool_trsf(TOOL_DEFAULT) +t[0]=xoff +t[1]=-yoff +print "Offset: ", [t[0], t[1]] +robot.set_tool_trsf(t, TOOL_DEFAULT) + +robot.set_tool(TOOL_DEFAULT) +d = robot.get_distance_to_pnt("pLaser") +if d<POSITION_TOLERANCE: + print "Moving calibrated tool to laser" +else: + print "Cannot move calibrated tool to laser: toog big offset" diff --git a/script/calibration/ToolCalibration3.py b/script/calibration/ToolCalibration3.py new file mode 100644 index 0000000..969707d --- /dev/null +++ b/script/calibration/ToolCalibration3.py @@ -0,0 +1,83 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + +cal_tool = TOOL_CALIBRATION + +robot.set_tool(cal_tool) + +robot.enable() +move_to_laser() + + +robot.set_motors_enabled(True) +robot.set_joint_motors_enabled(True) +initial_pos = robot.get_cartesian_pos() + +#robot.align() +try: + robot.set_frame(FRAME_TABLE) + run("calibration/ScanX") +finally: + robot.set_default_frame() + +pos1 = robot.get_cartesian_pos() +x1, l1 = closest_x, closest_y + +print "Scan 1 result: ", [x1, l1] +print "Position 1: ", pos1 + + +pj6 = robot_j6.position +if pj6>0: + robot_j6.move(pj6 - 180.0) +else: + robot_j6.move(pj6 + 180.0) + + +try: + robot.set_frame(FRAME_TABLE) + run("calibration/ScanX") +finally: + robot.set_default_frame() + +pos2 =robot.get_cartesian_pos() +x2, l2 = closest_x, closest_y + +print "Scan 2 result: ", [x2, l2] +print "Position 2: ", pos1 + +off_l = l2 - l1 +print "Offset l: ", off_l + +#For composing cannot use tcp_p, need another auxiliary point. tcp_t is also destroyed. +robot.set_pnt(robot.get_cartesian_pos(), "pTemp") +robot.set_trsf([0, -off_l, 0, 0, 0, 0]) +c=robot.compose("pTemp", FRAME_TABLE, "tcp_t" ) +robot.set_pnt(c, "pTemp") +robot.movel("pTemp", cal_tool, DESC_SCAN, sync=True) + + +pos3 = robot.get_cartesian_pos() +print "Position 3: ", pos3 + + +#Updates the tool +t=robot.get_tool_trsf(TOOL_DEFAULT) +print "Former tool: " + str(t) + +xoff = (pos3[0]-pos1[0])/2 +yoff = (pos3[1]-pos1[1])/2 +xrot = math.degrees(math.atan(yoff/t[2])) +yrot = math.degrees(math.atan(xoff/t[2])) +t[0]=xoff +t[1]=-yoff +print "Calibrated tool: " + str(t) +robot.set_tool_trsf(t, TOOL_DEFAULT) + +robot.set_tool(TOOL_DEFAULT) +d = robot.get_distance_to_pnt("pLaser") +if d<POSITION_TOLERANCE: + print "Moving calibrated tool to laser" + #move_to_laser() +else: + print "Cannot move calibrated tool to laser: too big offset" diff --git a/script/calibration/ToolCalibration6s.py b/script/calibration/ToolCalibration6s.py new file mode 100644 index 0000000..7c213a5 --- /dev/null +++ b/script/calibration/ToolCalibration6s.py @@ -0,0 +1,79 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + +cal_tool = TOOL_CALIBRATION + +robot.set_tool(cal_tool) + +robot.enable() +move_to_laser("pPark") + + +robot.set_motors_enabled(True) +robot.set_joint_motors_enabled(True) +initial_pos = robot.get_cartesian_pos() + +#robot.align() +run("calibration/ScanY") + +pos1 = robot.get_cartesian_pos() +l1, y1 = closest_x, closest_y + +print "Scan 1 result: ", [l1, y1] +print "Position 1: ", pos1 + + +pj6 = robot_j6.position +if pj6>0: + robot_j6.move(pj6 - 180.0) +else: + robot_j6.move(pj6 + 180.0) + +run("calibration/ScanY") + +pos2 =robot.get_cartesian_pos() +l2, y2 = closest_x, closest_y + +print "Scan 2 result: ", [l2, y2] +print "Position 2: ", pos1 + +off_l = l2 - l1 +print "Offset l: ", off_l + +#For composing cannot use tcp_p, need another auxiliary point. tcp_t is also destroyed. +robot.set_pnt(robot.get_cartesian_pos(), "pTemp") +robot.set_trsf([-off_l, 0, 0, 0, 0, 0]) +c=robot.compose("pTemp", FRAME_DEFAULT, "tcp_t" ) +robot.set_pnt(c, "pTemp") +robot.movel("pTemp", cal_tool, DESC_SCAN, sync=True) + + +pos3 = robot.get_cartesian_pos() +print "Position 3: ", pos3 + + +#Updates the tool +t=robot.get_tool_trsf(TOOL_DEFAULT) +print "Former tool: " + str(t) + +xoff = (pos3[0]-pos1[0])/2 +yoff = (pos3[1]-pos1[1])/2 +xrot = math.degrees(math.atan(yoff/t[2])) +yrot = math.degrees(math.atan(xoff/t[2])) +t[0]=xoff #X +t[1]=-yoff #Y +#t[3]= xropt #RX +#t[4]= yropt #RY + +print "Calibrated tool: " + str(t) + + +robot.set_tool_trsf(t, TOOL_DEFAULT) + +robot.set_tool(TOOL_DEFAULT) +d = robot.get_distance_to_pnt("pLaser") +if d<POSITION_TOLERANCE: + print "Moving calibrated tool to laser" + #move_to_laser() +else: + print "Cannot move calibrated tool to laser: too big offset" diff --git a/script/client/PShellClient.py b/script/client/PShellClient.py new file mode 100644 index 0000000..a40b1df --- /dev/null +++ b/script/client/PShellClient.py @@ -0,0 +1,369 @@ +import threading +import time +import sys +import requests +import json + +try: + from urllib import quote # Python 2 +except ImportError: + from urllib.parse import quote # Python 3 + +try: + from sseclient import SSEClient +except: + SSEClient = None + + +class PShellClient: + def __init__(self, url): + self.url = url + self.sse_event_loop_thread = None + self.subscribed_events = None + self.event_callback = None + + def _get_response(self, response, is_json=True): + if response.status_code != 200: + raise Exception(response.text) + return json.loads(response.text) if is_json else response.text + + def _get_binary_response(self, response): + if response.status_code != 200: + raise Exception(response.text) + return response.raw.read() + + def get_version(self): + """Return application version. + + Args: + + Returns: + String with application version. + + """ + return self._get_response(requests.get(url=self.url+"/version"), False) + + def get_config(self): + """Return application configuration. + + Args: + + Returns: + Dictionary. + """ + return self._get_response(requests.get(url=self.url+"/config")) + + def get_state(self): + """Return application state. + + Args: + + Returns: + String: Invalid, Initializing,Ready, Paused, Busy, Disabled, Closing, Fault, Offline + """ + return self._get_response(requests.get(url=self.url+"/state")) + + def get_logs(self): + """Return application logs. + + Args: + + Returns: + List of logs. + Format of each log: [date, time, origin, level, description] + + """ + return self._get_response(requests.get(url=self.url+"/logs")) + + def get_history(self, index): + """Access console command history. + + Args: + index(int): Index of history entry (0 is the most recent) + + Returns: + History entry + + """ + return self._get_response(requests.get(url=self.url+"/history/"+str(index)), False) + + def get_script(self, path): + """Return script. + + Args: + path(str): Script path (absolute or relative to script folder) + + Returns: + String with file contents. + + """ + return self._get_response(requests.get(url=self.url+"/script/"+str(path)), False) + + def get_devices(self): + """Return global devices. + + Args: + + Returns: + List of devices. + Format of each device record: [name, type, state, value, age] + + """ + return self._get_response(requests.get(url=self.url+"/devices")) + + def abort(self, command_id=None): + """Abort execution of command + + Args: + command_id(optional, int): id of the command to be aborted. + if None (default), aborts the foreground execution. + + Returns: + + """ + if command_id is None: + requests.get(url=self.url+"/abort") + else: + return requests.get(url=self.url+"/abort/"+str(command_id)) + + def reinit(self): + """Reinitialize the software. + + Args: + + Returns: + + """ + requests.get(url=self.url+"/reinit") + + def stop(self): + """Stop all devices implementing the 'Stoppable' interface. + + Args: + + Returns: + + """ + requests.get(url=self.url+"/stop") + + def update(self): + """Update all global devices. + + Args: + + Returns: + + """ + requests.get(url=self.url+"/update") + + def eval(self,statement): + """Evaluates a statement in the interpreter. + If the statement finishes by '&', it is executed in background. + Otherwise statement is executed in foreground (exclusive). + + Args: + statement(str): input statement + + Returns: + String containing the console return. + If an exception is produces in the interpretor, it is re-thrown here. + """ + statement = quote(statement) + return self._get_response(requests.get(url=self.url+"/eval/"+statement), False) + + def run(self,script, pars=None, background=False): + """Executes script in the interpreter. + + Args: + script(str): name of the script (absolute or relative to the script base folder). Extension may be omitted. + pars(optional, list or dict): if a list is given, it sets sys.argv for the script. + If a dict is given, it sets global variable for the script. + background(optional, bool): if True script is executed in background. + + Returns: + Return value of the script. + If an exception is produces in the interpretor, it is re-thrown here. + """ + return self._get_response(requests.put(url=self.url+"/run", json={"script":script, "pars":pars, "background":background, "async":False })) + + def start_eval(self,statement): + """Starts evaluation of a statement in the interpreter. + If the statement finishes by '&', it is executed in background. + Otherwise statement is executed in foreground (exclusive). + + Args: + statement(str): input statement + + Returns: + Command id (int), which is used to retrieve command execution status/result (get_result). + """ + statement = quote(statement) + return int(self._get_response(requests.get(url=self.url+"/evalAsync/"+statement), False)) + + def start_run(self,script, pars=None, background=False): + """Starts execution of a script in the interpreter. + + Args: + script(str): name of the script (absolute or relative to the script base folder). Extension may be omitted. + pars(optional, list or dict): if a list is given, it sets sys.argv for the script. + If a dict is given, it sets global variable for the script. + background(optional, bool): if True script is executed in background. + + Returns: + Command id (int), which is used to retrieve command execution status/result (get_result). + """ + return int(self._get_response(requests.put(url=self.url+"/run", json={"script":script, "pars":pars, "background":background, "async":True }))) + + def get_result(self, command_id=-1): + """Gets status/result of a command executed asynchronously (start_eval and start_run). + + Args: + command_id(optional, int): command id. If equals to -1 (default) return status/result of the foreground task. + + Returns: + Dictionary with the fields: 'id' (int): command id + 'status' (str): unlaunched, invalid, removed, running, aborted, failed or completed. + 'exception' (str): if status equals 'failed', holds exception string. + 'return' (obj): if status equals 'completed', holds return value of script (start_run) + or console return (start_eval) + """ + return self._get_response(requests.get(url=self.url+"/result/"+str(command_id))) + + def help(self, input = "<builtins>"): + """Returns help or auto-completion strings. + + Args: + input(optional, str): - ":" for control commands + - "<builtins>" for builtin functions + - "devices" for device names + - builtin function name for function help + - else contains entry for auto-completion + + Returns: + List + + """ + return self._get_response(requests.get(url=self.url+"/autocompletion/" + input)) + + def get_contents(self, path=None): + """Returns contents of data path. + + Args: + path(optional, str): Path to data relative to data home path. + - Folder + - File + - File (data root) | internal path + - internal path (on currently open data root) + + Returns: + List of contents + + """ + return self._get_response(requests.get(url=self.url+ "/contents" + ("" if path is None else ( "/"+path))), False) + + def get_data(self, path, type="txt"): + """Returns data on a given path. + + Args: + path(str): Path to data relative to data home path. + - File (data root) | internal path + - internal path (on currently open data root) + type(optional, str): txt, "json", "bin", "bs" + + Returns: + Data accordind to selected format/. + + """ + if type == "json": + return self._get_response(requests.get(url=self.url+ "/data-json/"+path), True) + elif type == "bin": + return self._get_binary_response(requests.get(url=self.url+"/data-bin/"+path, stream=True)) + elif type == "bs": + from collections import OrderedDict + bs = self._get_binary_response(requests.get(url=self.url+"/data-bs/"+path, stream=True)) + index=0 + msg = [] + for i in range(4): + size =int.from_bytes(bs[index:index+4], byteorder='big', signed=False) + index=index+4 + msg.append(bs[index:index+size]) + index=index+size + [main_header, data_header, data, timestamp] = msg + main_header = json.loads(main_header, object_pairs_hook=OrderedDict) + data_header = json.loads(data_header, object_pairs_hook=OrderedDict) + channel = data_header["channels"][0] + channel["encoding"] = "<" if channel.get("encoding", "little") else ">" + from bsread.data.helpers import get_channel_reader + channel_value_reader = get_channel_reader(channel) + return channel_value_reader(data) + + return self._get_response(requests.get(url=self.url+ "/data" + ("" if path is None else ( "/"+path))), False) + + def print_logs(self): + for l in self.get_logs(): + print ("%s %s %-20s %-8s %s" % tuple(l)) + + def print_devices(self): + for l in self.get_devices(): + print ("%-16s %-32s %-10s %-32s %s" % tuple(l)) + + def print_help(self, input = "<builtins>"): + for l in self.help(input): + print (l) + + #Events + def _sse_event_loop_task(self): + try: + while True: + try: + messages = SSEClient(self.url+"/events") + for msg in messages: + if (self.subscribed_events is None) or (msg.event in self.subscribed_events): + try: + value = json.loads(msg.data) + except: + value = str(msg.data) + self.event_callback(msg.event, value) + except IOError as e: + #print(e) + pass + except: + print("Error:", sys.exc_info()[1]) + #raise + finally: + print ("Exit SSE loop task") + self.sse_event_loop_thread = None + + + def start_sse_event_loop_task(self, subscribed_events = None, event_callback = None): + """ + Initializes server event loop task. + Args: + subscribed_events: list of event names to substribe to. If None subscribes to all. + event_callback: callback function. If None, self.on_event is called instead. + + Usage example: + def on_event(name, value): + if name == "state": + print ("State changed: ", value) + elif name == "record": + print ("Received scan record: ", value) + + pc.start_sse_event_loop_task(["state", "record"], on_event) + + """ + self.event_callback = event_callback if event_callback is not None else self.on_event + self.subscribed_events = subscribed_events + if SSEClient is not None: + if self.sse_event_loop_thread is None: + self.sse_event_loop_thread = threading.Thread(target=self._sse_event_loop_task, \ + args = (), \ + kwargs={}, \ + daemon=True) + self.sse_event_loop_thread.start() + else: + raise Exception ("sseclient library is not instlled: server events are not available") + + def on_event(self, name, value): + pass + \ No newline at end of file diff --git a/script/client/TellClient.py b/script/client/TellClient.py new file mode 100644 index 0000000..256dbdd --- /dev/null +++ b/script/client/TellClient.py @@ -0,0 +1,184 @@ +from PShellClient import PShellClient +import json +import time +import sys + + + +class TellClient(PShellClient): + def __init__(self, url): + PShellClient.__init__(self, url) + self.start_sse_event_loop_task(["state", "shell"]) + self.state = self.get_state() + self.debug=False + + def on_event(self, name, value): + if name == "state": + self.state = value + print ("State: ", value) + elif name == "shell": + if self.debug: + print ("> ", value) + + def get_state(self): + self.state = PShellClient.get_state(self) + return self.state + + def wait_ready(self): + count = 0 + #Monitors event but polls every second just n case an event is missed + while (True): + if self.state != "Busy": + break + time.sleep(0.01) + count = count + 1 + if count>=100: + count=0 + self.get_state() + if self.state != "Ready": + raise Exception("Invalid state: " + str(self.state)) + + def set_in_mount_position(self, value): + self.eval("in_mount_position = " + str(value) +"&") + + def is_in_mount_position(self): + return self.eval("in_mount_position&").lower()=="true" + + def get_samples_info(self): + return json.loads(self.eval("get_samples_info()&")) + + def set_samples_info(self, info): + #c.run("data/set_samples_info", pars= [info,], background=True) + self.eval("set_samples_info(" + json.dumps(info) + ")&") + + def start_cmd(self, cmd, *argv): + cmd = cmd + "(" + for a in argv: + cmd = cmd + (("'" + a + "'") if type(a) is str else str(a) ) + ", " + cmd = cmd + ")" + ret = self.start_eval(cmd) + self.get_state() + return ret + + def wait_cmd(self, cmd): + self.wait_ready() + result = self.get_result(cmd) + #print (result) + if result["exception"] is not None: + raise Exception(result["exception"] ) + return result["return"] + + def mount(self, segment, puck, sample, force=False, read_dm=False, auto_unmount=False): + #return self.run("motion/mount", pars= [segment,puck, sample, force, read_dm], background=True) + return self.start_cmd("mount", segment, puck, sample, force, read_dm, auto_unmount) + + def unmount(self, segment = None, puck = None, sample = None, force=False): + return self.start_cmd("unmount", segment, puck, sample, force) + + def scan_pin(self, segment, puck, sample, force=False): + return self.start_cmd("scan_pin", segment, puck, sample, force) + + def scan_puck(self, segment, puck, force=False): + return self.start_cmd("scan_puck", segment, puck, force) + + def dry(self, heat_time=30.0, speed=0.5, wait_cold = 30.0): + return self.start_cmd("dry", heat_time, speed, wait_cold) + + def move_cold(self): + return self.start_cmd("move_cold") + + def trash(self): + return self.start_cmd("trash") + + def abort_cmd(self): + self.abort() + self.eval("robot.stop_task()&") + + def set_gonio_mount_position(homing = False): + if homing: + self.eval("home_fast_table()") + self.eval("set_mount_position()") + + def get_mounted_sample(self): + ret = self.eval("get_setting('mounted_sample_position')&").strip() + return None if len(ret)==0 else ret + + def get_system_check(self): + try: + ret = self.eval("system_check()&") + except Exception as ex: + return ex + return "Ok" + + def get_robot_state(self): + return self.eval("robot.state&") + + + def get_robot_status(self): + status = self.eval("robot.take()&") + return status + + def get_detected_pucks(self): + return self.eval("get_detected_pucks()&") + + def set_pin_offset(self, value): + self.eval("set_pin_offset(" + str(value)+ ")&") + + def get_pin_offset(self): + return self.eval("get_pin_offset()&") + + def print_info(self): + print ("State: " + str(self.get_state())) + print ("Mounted sample: " + str(self.get_mounted_sample())) + print ("System check: " + str(self.get_system_check())) + print ("Robot state: " + str(self.get_robot_state())) + print ("Robot status: " + str(self.get_robot_status())) + print ("Detected pucks: " + str(self.get_detected_pucks())) + print ("Pin offset: " + str(self.get_pin_offset())) + print ("Mount position: " + str(self.is_in_mount_position())) + print ("") + +if __name__ == "__main__": + tell = TellClient("http://Alexandres-MBP.psi.ch:8080") + tell.print_info() + + info = [ + { + "userName": "User", + "dewarName": "Dewar", + "puckName": "Puck", + "puckBarcode": "XXX0001", + "puckType": "Minispine", + "puckAddress": "", + "sampleName": "Sample", + "sampleBarcode": "YYY0001", + "samplePosition": "1", + "sampleStatus": "Present", + "sampleMountCount": "0" , + }, + ] + print (tell.get_samples_info()) + tell.set_samples_info(info) + print (tell.get_samples_info()) + + tell.abort_cmd() + + cmd = tell.move_cold() + print (tell.wait_cmd(cmd)) + + cmd = tell.trash() + print (tell.wait_cmd(cmd)) + + cmd = tell.scan_pin("A", 1, 1) + print (tell.wait_cmd(cmd)) + + cmd = tell.scan_puck("A", 1, 1) + print (tell.wait_cmd(cmd)) + + cmd = tell.mount("A", 1, 1) + print (tell.wait_cmd(cmd)) + + print ("Mounted sample: " + str(tell.get_mounted_sample())) + cmd = tell.unmount() + print (tell.wait_cmd(cmd)) + print ("Mounted sample: " + str(tell.get_mounted_sample())) diff --git a/script/client/sseclient.py b/script/client/sseclient.py new file mode 100644 index 0000000..3c42858 --- /dev/null +++ b/script/client/sseclient.py @@ -0,0 +1,163 @@ +import codecs +import re +import time +import warnings + +import six + +import requests + + +# Technically, we should support streams that mix line endings. This regex, +# however, assumes that a system will provide consistent line endings. +end_of_field = re.compile(r'\r\n\r\n|\r\r|\n\n') + +class SSEClient(object): + def __init__(self, url, last_id=None, retry=3000, session=None, chunk_size=1024, **kwargs): + self.url = url + self.last_id = last_id + self.retry = retry + self.chunk_size = chunk_size + + # Optional support for passing in a requests.Session() + self.session = session + + # Any extra kwargs will be fed into the requests.get call later. + self.requests_kwargs = kwargs + + # The SSE spec requires making requests with Cache-Control: nocache + if 'headers' not in self.requests_kwargs: + self.requests_kwargs['headers'] = {} + self.requests_kwargs['headers']['Cache-Control'] = 'no-cache' + + # The 'Accept' header is not required, but explicit > implicit + self.requests_kwargs['headers']['Accept'] = 'text/event-stream' + + # Keep data here as it streams in + self.buf = u'' + + self._connect() + + def _connect(self): + if self.last_id: + self.requests_kwargs['headers']['Last-Event-ID'] = self.last_id + + # Use session if set. Otherwise fall back to requests module. + requester = self.session or requests + self.resp = requester.get(self.url, stream=True, **self.requests_kwargs) + self.resp_iterator = self.resp.iter_content(chunk_size=self.chunk_size) + + # TODO: Ensure we're handling redirects. Might also stick the 'origin' + # attribute on Events like the Javascript spec requires. + self.resp.raise_for_status() + + def _event_complete(self): + return re.search(end_of_field, self.buf) is not None + + def __iter__(self): + return self + + def __next__(self): + decoder = codecs.getincrementaldecoder( + self.resp.encoding)(errors='replace') + while not self._event_complete(): + try: + next_chunk = next(self.resp_iterator) + if not next_chunk: + raise EOFError() + self.buf += decoder.decode(next_chunk) + + except (StopIteration, requests.RequestException, EOFError) as e: + time.sleep(self.retry / 1000.0) + self._connect() + + # The SSE spec only supports resuming from a whole message, so + # if we have half a message we should throw it out. + head, sep, tail = self.buf.rpartition('\n') + self.buf = head + sep + continue + + # Split the complete event (up to the end_of_field) into event_string, + # and retain anything after the current complete event in self.buf + # for next time. + (event_string, self.buf) = re.split(end_of_field, self.buf, maxsplit=1) + msg = Event.parse(event_string) + + # If the server requests a specific retry delay, we need to honor it. + if msg.retry: + self.retry = msg.retry + + # last_id should only be set if included in the message. It's not + # forgotten if a message omits it. + if msg.id: + self.last_id = msg.id + + return msg + + if six.PY2: + next = __next__ + + +class Event(object): + + sse_line_pattern = re.compile('(?P<name>[^:]*):?( ?(?P<value>.*))?') + + def __init__(self, data='', event='message', id=None, retry=None): + self.data = data + self.event = event + self.id = id + self.retry = retry + + def dump(self): + lines = [] + if self.id: + lines.append('id: %s' % self.id) + + # Only include an event line if it's not the default already. + if self.event != 'message': + lines.append('event: %s' % self.event) + + if self.retry: + lines.append('retry: %s' % self.retry) + + lines.extend('data: %s' % d for d in self.data.split('\n')) + return '\n'.join(lines) + '\n\n' + + @classmethod + def parse(cls, raw): + """ + Given a possibly-multiline string representing an SSE message, parse it + and return a Event object. + """ + msg = cls() + for line in raw.splitlines(): + m = cls.sse_line_pattern.match(line) + if m is None: + # Malformed line. Discard but warn. + warnings.warn('Invalid SSE line: "%s"' % line, SyntaxWarning) + continue + + name = m.group('name') + if name == '': + # line began with a ":", so is a comment. Ignore + continue + value = m.group('value') + + if name == 'data': + # If we already have some data, then join to it with a newline. + # Else this is it. + if msg.data: + msg.data = '%s\n%s' % (msg.data, value) + else: + msg.data = value + elif name == 'event': + msg.event = value + elif name == 'id': + msg.id = value + elif name == 'retry': + msg.retry = int(value) + + return msg + + def __str__(self): + return self.data diff --git a/script/client/tell.py b/script/client/tell.py new file mode 100644 index 0000000..56c70b4 --- /dev/null +++ b/script/client/tell.py @@ -0,0 +1,79 @@ +import sys +import os +import code +import readline +import rlcompleter +import atexit + +from TellClient import TellClient + +tell = TellClient("http://PC12288:8080") + +def info(): + tell.print_info() + +def help(): + print ("Commands: \n\thelp()\n\tinfo()\n\tmount(segment, puck, sample)\n\tunmount() \n\tdry() " \ + "\n\tscan(segment, puck, sample=None) \n\tmove_cold() \n\ttrash() \n\tabort() " \ + "\n\tset_pin_offset(value)") + +def assert_transfer_allowed(): + if not tell.is_in_mount_position(): + raise Exception("Gonio is not in mount position") + +def mount(segment, puck, sample): + assert_transfer_allowed() + cmd = tell.mount(segment, puck, sample, True, True, True) + print (tell.wait_cmd(cmd)) + +def unmount(): + assert_transfer_allowed() + cmd=tell.unmount(force=True) + print (tell.wait_cmd(cmd)) + +def move_cold(): + cmd=tell.move_cold() + print (tell.wait_cmd(cmd)) + +def trash(): + cmd=tell.trash() + print (tell.wait_cmd(cmd)) + +def dry(): + cmd=tell.dry() + print (tell.wait_cmd(cmd)) + +def scan(segment, puck, sample=None): + if sample is None: + cmd=tell.scan_puck(segment, puck, True) + else: + cmd=tell.scan_pin(segment, puck, sample, True) + print (tell.wait_cmd(cmd)) + +def abort(): + tell.abort_cmd() + +def set_pin_offset(value): + tell.set_pin_offset(value) + +info() +help() + +#for line in sys.stdin: +# tell.print_info() +#print ("", end='\r> ') + +historyPath = os.path.expanduser("./.history") +def save_history(historyPath=historyPath): + readline.write_history_file(historyPath) +if os.path.exists(historyPath): + readline.read_history_file(historyPath) +atexit.register(save_history) + +#vars = globals(); vars.update(locals()) +vars =locals() +readline.set_completer(rlcompleter.Completer(vars).complete) +readline.parse_and_bind("tab: complete") + +code.interact(banner = "", local=vars) + diff --git a/script/data/get_samples_info.py b/script/data/get_samples_info.py new file mode 100644 index 0000000..00a5bc3 --- /dev/null +++ b/script/data/get_samples_info.py @@ -0,0 +1,4 @@ + + + +set_return(get_samples_info(as_json=False)) \ No newline at end of file diff --git a/script/data/pucks.py b/script/data/pucks.py new file mode 100644 index 0000000..bdb925b --- /dev/null +++ b/script/data/pucks.py @@ -0,0 +1,22 @@ +def get_puck_names(): + return [str(a)+str(b) for a in BLOCKS for b in range(1,6)] + + +def get_puck_info(): + ret = [] + #for puck in get_puck_names(): + for puck in BasePlate.pucks: + ret.append({"address" : str(puck.name), "status": str(puck.status), "barcode" : str(puck.id)}) + return ret + + +def get_puck_obj(address): + return BasePlate.getChild(address) + + +def get_puck_obj_by_id(puck_id): + for puck in BasePlate.pucks: + if puck.id == puck_id: + return puck + return None + \ No newline at end of file diff --git a/script/data/reports.py b/script/data/reports.py new file mode 100644 index 0000000..629b414 --- /dev/null +++ b/script/data/reports.py @@ -0,0 +1,39 @@ +from statsutils import * + + +def report(start, end): + """ + Data format for start and end: "dd/mm/yy" or "dd/mm/yy hh:mm:ss.mmm" + + """ + cmds = ["mount%", "unmount%", "dry%", "recover%", "trash%", "robot_recover%", "scan%", "homing%"] + + conn = get_stats_connection() + try: + print_stats(cmds, start, end) + + for cmd in cmds: + print_cmd_stats (cmd, start, end) + + + finally: + conn.close() + +def print_recs(cmd,start, end, result=("%%")): + """ + Data format for start and end: "dd/mm/yy" or "dd/mm/yy hh:mm:ss.mmm" + Result: "error", "abort, "success". Defaulr for all + + """ + + conn = get_stats_connection() + try: + print_cmd_records(cmd,start, end, result) + finally: + conn.close() + + +#Print all records: +# + +#report("01/03/19","01/04/19") diff --git a/script/data/samples.py b/script/data/samples.py new file mode 100644 index 0000000..87480df --- /dev/null +++ b/script/data/samples.py @@ -0,0 +1,348 @@ +import json +import re +import org.python.core.PyDictionary as PyDictionary + +SAMPLE_INFO_KEYS = ["userName", "dewarName", "puckName", "puckBarcode", "puckType", "puckAddress", + "sampleName", "samplePosition", "sampleBarcode", "sampleStatus", "sampleMountCount"] +samples_info = [] + + +def set_samples_info(info): + global samples_info + if (is_string(info)): + info = json.loads(info) + if not is_list(info): + raise Exception("Sample info must be a list (given object type is " + str(type(info)) + ")") + #Sanitize list + remove = [] + for sample in info: + try: + if set(sample.keys()) != set(SAMPLE_INFO_KEYS): + raise Exception() + except: + remove.append(sample) + for el in remove: + info.remove(el) + print "Invalid samples info element: " + str(el) + samples_info = info + save_samples_info() + #Trust beamline on assignments, so update puck info + update_puck_table() + + +def clear_samples_info(): + set_samples_info([]) + +def save_samples_info(): + data = get_samples_info(True) + output_file = open( get_context().setup.expandPath("{context}/samples_info.json") , "w") + output_file.write(data) + output_file.close() + get_context().sendEvent("samples_updated", True) + +def restore_samples_info(): + try: + inputfile = open(get_context().setup.expandPath("{context}/samples_info.json"), "r") + info = inputfile.read() + except: + print >> sys.stderr, "Error reading sample info file: " + str(sys.exc_info()[1]) + info = [] + set_samples_info(info) + +def get_samples_info(as_json=True): + global samples_info + return json.dumps(to_list(samples_info)) if as_json else samples_info + +def has_puck_datamatrix(datamatrix): + if samples_info is not None: + for si in samples_info: + if si["puckBarcode"] == datamatrix: + return True + return False + +def add_puck_datamatrix(barcode, address = "", dewar = "Unknown", user = "Unknown", puck = "Unknown", type = "unipuck", sample_prefix = "Sample"): + if has_puck_datamatrix(barcode): + raise Exception("Datamatrix already defined: " + str(barcode)) + for s in range(1,17): + info = \ + { "userName": user, \ + "dewarName": dewar, \ + "puckName": puck, \ + "puckBarcode": address if barcode is None else barcode, \ + "puckType": type, \ + "puckAddress": address,\ + "sampleName": sample_prefix + " " + str(s), \ + "samplePosition": str(s),\ + "sampleStatus": "Unknown", \ + "sampleMountCount": "0", + } + samples_info.append(info) + save_samples_info() + +def remove_puck_datamatrix(barcode): + remove = [] + for si in samples_info: + if si["puckBarcode"] == barcode: + remove.append(si) + for el in remove: samples_info.remove(el) + save_samples_info() + + +barcode_clean_re = re.compile("[^a-zA-Z0-9]") + +def is_same_datamatrix(table, reading): + if table == reading: + return True + table2 = barcode_clean_re.sub("", table.upper()) + reading2 = barcode_clean_re.sub("", reading.upper()) + if table2 == reading2: + log("Assigning aproximative datamatrix " + reading ) + return True + return False + + +def set_puck_datamatrix(puck, datamatrix): + if puck is None: + puck = "" + if datamatrix is None: + datamatrix = "" + if samples_info is not None: + for si in samples_info: + #if si["puckBarcode"] == datamatrix: + if is_same_datamatrix(si["puckBarcode"],datamatrix): + si["puckAddress"] = puck + elif si["puckAddress"] == puck: + si["puckAddress"] = "" + save_samples_info() + +def reset_puck_datamatrix(puck = None): + if samples_info is not None: + for si in samples_info: + if (si["puckAddress"] == puck) or (puck is None): + si["puckAddress"] = "" + save_samples_info() + for p in BasePlate.getChildren(): + if (p.name == puck) or (puck is None): + p.id = None + +def get_puck_datamatrix(): + ret = {} + for si in samples_info: + if si["puckBarcode"] is not None and si["puckBarcode"]!="": + ret[si["puckBarcode"]] = si["puckAddress"] + return ret + +def get_puck_address(barcode): + try: + return get_puck_datamatrix()[barcode] + except: + return None + + +def update_puck_table(): + dms = get_puck_datamatrix() + for barcode in dms.keys(): + address = dms[barcode] + puck = get_puck_obj(address) + if puck is not None: + puck.id = barcode + + +#Sample mount/unmount + +def same_address(puck_add_1, sample_pos_1, puck_add_2, sample_pos_2): + if str(puck_add_1) != str(puck_add_2): + return False + try: + sample_pos_1 = int(sample_pos_1) + except: + return False + try: + sample_pos_2 = int(sample_pos_2) + except: + return False + return sample_pos_1 == sample_pos_2 + + +def update_samples_info_sample_mount(puck_address, sample_position, sample_detected, sample_id): + try: + if (samples_info is not None) and (puck_address is not None): + for si in samples_info: + if same_address( si["puckAddress"], si["samplePosition"], puck_address, sample_position): + if sample_detected: + if si["sampleStatus"] != "Mounted": + si["sampleStatus"] = "Mounted" + try: + mount_count = int(si["sampleMountCount"]) + except: + mount_count = 0 + si["sampleMountCount"] = mount_count + 1 + else: + si["sampleStatus"] = "Unknown" + + if sample_id is not None: + si["sampleBarcode"] = sample_id + + else: + if si["sampleStatus"] == "Mounted": + si["sampleStatus"] = "HasBeenMounted" + save_samples_info() + except: + pass + + +def update_samples_info_sample_unmount(puck_address, sample_position): + try: + if (samples_info is not None) and (puck_address is not None): + for si in samples_info: + if same_address( si["puckAddress"], si["samplePosition"], puck_address, sample_position): + si["sampleStatus"] = "HasBeenMounted" + save_samples_info() + return + except: + pass + +def update_samples_info_sample_scan(puck_address, sample_position, sample_detected, sample_id): + try: + if (samples_info is not None) and (puck_address is not None): + for si in samples_info: + if same_address( si["puckAddress"], si["samplePosition"], puck_address, sample_position): + if sample_detected: + if si["sampleStatus"] == "Unknown": + si["sampleStatus"] = "Present" + else: + if si["sampleStatus"] == "Present": + si["sampleStatus"] = "Unknown" + if sample_id is not None: + si["sampleBarcode"] = sample_id + save_samples_info() + return + except: + pass + + + +test_sample_data = [ \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 5", \ + "sampleBarcode": "", \ + "samplePosition": 5,\ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + ] + \ No newline at end of file diff --git a/script/data/set_samples_info.py b/script/data/set_samples_info.py new file mode 100644 index 0000000..bc7e803 --- /dev/null +++ b/script/data/set_samples_info.py @@ -0,0 +1,4 @@ + + + +set_samples_info(args[0]) \ No newline at end of file diff --git a/script/devices/BarcodeReader.py b/script/devices/BarcodeReader.py new file mode 100644 index 0000000..48b84ca --- /dev/null +++ b/script/devices/BarcodeReader.py @@ -0,0 +1,83 @@ + + +class BarcodeReader(DeviceBase): + + def __init__(self, name, microscan, microscan_cmd): + DeviceBase.__init__(self, name) + self.microscan = microscan + self.microscan_cmd = microscan_cmd + + + def doInitialize(self): + self.disable() + self.readout = None + self.processing = False + self.task_callable=None + + def enable(self): + self.microscan_cmd.write("<H>") + self.setState(State.Ready) + + def disable(self): + self.microscan_cmd.write("<I>") + self.setState(State.Disabled) + + def get(self,timeout=1.0): + self.state.assertReady() + try: + self.setState(State.Busy) + self.microscan.flush() + ret = self.microscan.waitString(int(timeout * 1000)) + if ret is not None: + ret = ret.strip() + self.setCache(ret, None) + return ret + except: + self.setCache(None, None) + return None + finally: + if self.state == State.Busy: + self.setState(State.Ready) + + def doUpdate(self): + self.get() + + + def read(self,timeout=1.0): + if self.processing: + raise Exception("Ongoing read operation") + self.processing = True + try: + initial = self.state + if initial == State.Disabled: + self.enable() + try: + return self.get(timeout) + finally: + if initial == State.Disabled: + self.disable() + finally: + self.processing = False + + def _read_task(self, timeout): + global readout + self.readout = self.read(timeout) + return self.readout + + def start_read(self, timeout=1.0): + self.readout = None + self.task_callable = fork((self._read_task, (timeout,))) + + def get_readout(self): + return self.readout + + def wait_readout(self): + if self.task_callable is not None: + join(self.task_callable) + self.task_callable = None + return self.readout + + +add_device(BarcodeReader("barcode_reader", mscan_pin, mscan_pin_cmd), force = True) +add_device(BarcodeReader("barcode_reader_puck", mscan_puck, mscan_puck_cmd), force = True) + \ No newline at end of file diff --git a/script/devices/Gonio.py b/script/devices/Gonio.py new file mode 100644 index 0000000..0f264f5 --- /dev/null +++ b/script/devices/Gonio.py @@ -0,0 +1,43 @@ + + +def home_fast_table(): + caput ("SAR-EXPMX1:ASYN.AOUT", "enable plc 1") + +def get_fx_pos(): + return caget("SAR-EXPMX:MOT_FX.RBV", 'f') + +def set_fx_pos(pos): + return caput("SAR-EXPMX:MOT_FX.VAL", float(pos)) + + +def get_fy_pos(): + return caget("SAR-EXPMX:MOT_FY.RBV", 'f') + +def set_fy_pos(pos): + return caput("SAR-EXPMX:MOT_FY.VAL", float(pos)) + +def get_ry_pos(): + return caget("SAR-EXPMX:MOT_ROT_Y.RBV", 'f') + +def set_ry_pos(pos): + return caput("SAR-EXPMX:MOT_ROT_Y.VAL", float(pos)) + +def get_cz_pos(): + return caget("SAR-EXPMX:MOT_CZ.RBV", 'f') + +def set_cz_pos(pos): + return caput("SAR-EXPMX:MOT_CZ.VAL", float(pos)) + +def get_cx_pos(): + return caget("SAR-EXPMX:MOT_CX.RBV", 'f') + +def set_cx_pos(pos): + return caput("SAR-EXPMX:MOT_CX.VAL", float(pos)) + + +def set_mount_position(): + set_fx_pos(0.0) + set_fy_pos(0.0) + set_ry_pos(0.0) + set_cz_pos(0.0) + set_cx_pos(0.0) \ No newline at end of file diff --git a/script/devices/Hexiposi.py b/script/devices/Hexiposi.py new file mode 100644 index 0000000..75f6261 --- /dev/null +++ b/script/devices/Hexiposi.py @@ -0,0 +1,174 @@ +import ch.psi.pshell.device.DiscretePositionerBase as DiscretePositionerBase +import requests +import json + +class Hexiposi(DiscretePositionerBase): + def __init__(self, name, url): + DiscretePositionerBase.__init__(self, name, ["A","B","C","D","E","F"]) + self.PORT_SET=8002 + self.PORT_GET=8002 + if not url.startswith("http://"): + url = "http://" + url + if not url.endswith(":"): + url = url + ":" + self.url_set = url + str (self.PORT_SET)+ "/hexiposi/" + self.url_get = url + str (self.PORT_GET)+ "/hexiposi/" + self.moved = True + self.homing_state = State.Disabled + self.rback = self.UNKNOWN_POSITION + self.timeout = 3.0 + self.offline = False + + def doInitialize(self): + super(Hexiposi, self).doInitialize() + self.val = self.doReadReadback() + + def get_response(self, response): + if (response.status_code!=200): + raise Exception (response.text) + return json.loads(response.text) + + def get_status(self): + try: + self.status = self.get_response(requests.get(url=self.url_get+"get", timeout=self.timeout)) + self.estop = self.status["estop"] + self.homed = self.status["homed"] + self.error = self.status["errorCode"] + self.remote = self.status["mode"] == "remote" + self.moving = self.status["errorCode"] + self.pos = self.status["position"] + self.moving = self.status["moving"] + self.offset = self.status["offset"] + self.dpos = self.status["discretePosition"] + if (self.homed==False): rback = self.UNKNOWN_POSITION + elif self.dpos == 1: rback = "A" + elif self.dpos == 2: rback = "B" + elif self.dpos == 4: rback = "C" + elif self.dpos == 8: rback = "D" + elif self.dpos == 16: rback = "E" + elif self.dpos == 32: rback = "F" + else: rback = self.UNKNOWN_POSITION + if (rback == self.UNKNOWN_POSITION) or (rback != self.rback): + self.moved = True + self.rback = rback + self.offline = False + return self.status + except: + self.offline = True + self.updateState() + raise + + def set_deadband(self, value = 0.1): #degrees + ret = self.get_response(requests.get(url=self.url_set+"setDeadband?deadband=" + str(value), timeout=self.timeout)) + if ret["deadbandOutput"] == value: + return value + raise Excepiton("Error setting deadband: " + str(ret)) + + def move_pos(self, pos): + return self.get_response(requests.get(url=self.url_set+"set?pos=" + str(pos), timeout=self.timeout)) + + def move_home(self): + ret = self.get_response(requests.get(url=self.url_set+"set?home=1", timeout=self.timeout)) + try: + self.waitState(self.homing_state,1200) + except: + pass + return ret + + def stop_move(self): + return self.get_response(requests.get(url=self.url_set+"set?stop=1", timeout=self.timeout)) + + def set_offset(self, offset): + return self.get_response(requests.get(url=self.url_set+"setOffset?offset="+str(offset), timeout=self.timeout)) + + def doUpdate(self): + self.get_status() + super(Hexiposi, self).doUpdate() + + + def doStop(self): + self.stop_move() + + def doRead(self): + return str(self.val) + + def doReadReadback(self): + self.get_status() + return self.rback + + def doWrite(self, val): + val = ord(val) - ord('A') +1 + if val<1 or val>6: + raise Exception("Invalid value: " + str(val)) + moving = val != self.val + self.val = val + self.move_pos(self.val) + #Workaround as state does not changes immediatelly + if moving: + #try: + # self.waitState(State.Busy,1200) + #except: + # print sys.exc_info()[1] + start = time.time() + while self.state != State.Busy: + if time.time() - start > 1.5: + print "Timeout waiting Hexiposi busy" + break + self.update() + + def is_in_position(self, pos): + return self.take() == pos + + + def assert_in_position(self, pos): + if not is_in_position(pos): + raise Exception ("Hexiposi is not in position") + + def assert_homed(self): + if self.homed == False: + raise Exception ("Hexiposi is not homed") + + def assert_in_known_position(self): + self.get_status() + if self.rback == 'Unknown': + raise Exception("Hexiposi is in an unknown position, please home.") + + #def isReady(self): + # self.get_status() + # return self.moving == False + + def updateState(self): + if self.isSimulated(): + self.setState(State.Ready) + elif self.offline: + self.setState(State.Offline) + elif self.homed == False: + self.setState(self.homing_state) + elif self.moving: + self.setState(State.Busy) + else: + self.setState(State.Ready) + + + +#http://myriotell:8003/hexiposi/get +dev = Hexiposi("hexiposi", "myriotell6s") + +#If no Rotation Lid is mounted set it to simulated +#dev.setSimulated() + +add_device(dev, True) +hexiposi.polling=1000 +#print dev.url +#print dev.get_status() + +class hexiposi_position(ReadonlyRegisterBase): + def doRead(self): + try: + return float(hexiposi.pos) + except: + return float("nan") + +add_device(hexiposi_position(), True) +hexiposi_position.polling = 1000 +hexiposi.set_deadband(0.7) diff --git a/script/devices/LaserDistance.py b/script/devices/LaserDistance.py new file mode 100644 index 0000000..97efea4 --- /dev/null +++ b/script/devices/LaserDistance.py @@ -0,0 +1,17 @@ +class LaserDistance(ReadonlyRegisterBase): + def __init__(self): + ReadonlyRegisterBase.__init__(self, "laser_distance") + def doRead(self): + ret = ue.readable.read() + ret = 0.0 if math.isnan(ret) else ret + return ret + +class ListenerAI (DeviceListener): + def onValueChanged(self, device, value, former): + laser_distance.setCache( 0.0 if math.isnan(value) else value, None) + +listenerAI = ListenerAI() +ue.addListener(listenerAI) + +laser_distance=LaserDistance() +add_device(laser_distance, True) diff --git a/script/devices/LedCtrl.py b/script/devices/LedCtrl.py new file mode 100644 index 0000000..da4e51d --- /dev/null +++ b/script/devices/LedCtrl.py @@ -0,0 +1,46 @@ +import ch.psi.pshell.device.DiscretePositionerBase as DiscretePositionerBase + + +class LedPositioner(DiscretePositionerBase): + def __init__(self): + DiscretePositionerBase.__init__(self, "led_ctrl", ["On", "Off"]) + self.setState(State.Ready) + self.val = self.doReadReadback() + + def doRead(self): + return self.val + + def doReadReadback(self): + return "On" if get_led_state() else "Off" + + def doWrite(self, val): + self.val = val + if self.val == "On": + set_led_state(True) + else: + set_led_state(False) + + +add_device(LedPositioner(), True) +led_ctrl.polling = 1000 + + + + +import ch.psi.pshell.device.ProcessVariableConfig as ProcessVariableConfig +class LedLevel(ProcessVariableBase): + def __init__(self, name): + ProcessVariableBase.__init__(self, name, ProcessVariableConfig()) + + def doRead(self): + return get_led_level() + + def doWrite(self, val): + return set_led_level(val) + +led_level = LedLevel("led_level") +led_level.config.minValue = 0.0 +led_level.config.maxValue = 100.0 +led_level.config.unit = "%" +add_device(led_level, True) +led_level.polling = 1000 \ No newline at end of file diff --git a/script/devices/OneWire.py b/script/devices/OneWire.py new file mode 100644 index 0000000..20e590f --- /dev/null +++ b/script/devices/OneWire.py @@ -0,0 +1,134 @@ +import traceback +from datetime import datetime + +class Detector(ReadonlyRegisterBase): + def __init__(self, name): + ReadonlyRegisterBase.__init__(self, name) + self.reset() + + def set_inputs(self, inputs): + self.inputs = inputs + if self.take() != inputs.values(): + self.setCache(inputs.values(), None) + if self.getParent()!=None: + self.getParent().updateCache() + if (len(self.take()) == 0): + self.setState(State.Offline) + else: + self.setState(State.Ready) + + def set_input(self, index, val): + self.inputs[index] = val + self.set_inputs(self.inputs) + + def reset(self): + self.id = None + self.sn = None + self.status = None + self.type = None + self.set_inputs({}) + +class Esera(TcpDevice): + def __init__(self, name, server, timeout = 1000, retries = 1): + TcpDevice.__init__(self, name, server) + self.setMode(self.Mode.FullDuplex) + self.detectors = [] + for i in range(30): + self.detectors.append(Detector("Detector " + str(i+1))) + self.setChildren(self.detectors) + self.completed_initializatiod = False + self.debug = False + + def start(self): + self.getLogger().info("Starting controller") + self.write("set,sys,run,1\n") + + def stop(self): + self.getLogger().info("Stopping controller") + self.write("set,sys,run,0\n") + + def list(self): + self.write("get,owb,listall1\n") + + def req_data(self): + self.write("get,sys,data\n") + + def doInitialize(self): + super(Esera, self).doInitialize() + self.init_timestamp = time.time() + try: + self.setState(State.Ready) #So can communicate + for det in self.detectors: + det.reset() + self.list() + time.sleep(1.0) + self.check_started() + self.req_data() + except: + print >> sys.stderr, traceback.format_exc() + self.getLogger().warning(traceback.format_exc()) + raise + + def doUpdate(self): + self.check_started() + self.req_data() + + def updateCache(self): + #print "Update" + cache = [] + for det in self.detectors: + cache.append(det.take()) + self.setCache(cache, None) + + + def check_started(self): + if not self.completed_initializatiod: + init = True + for det in self.detectors: + if det.id == None: + init = False + break + if init: + self.completed_initializatiod = True + print("Completed initialization") + self.getLogger().info("Completed initialization") + self.start() + + def onString(self, msg): + if self.debug: + print datetime.now() , " - " , msg + tokens = msg.split("|") + if len(tokens)>1: + try: + if msg[:3] == "LST": + #LST|1_OWD1|3AF361270000009E|S_0|DS2413| + if tokens[1] > 1: + index = int(tokens[1].split("_")[1][3:]) - 1 + if index < len(self.detectors): + det = self.detectors[index] + det.id = tokens[1] + det.sn= tokens[2] if len(tokens)>2 else None + det.status = int(tokens[3][2:]) if len(tokens)>3 else None + det.type = tokens[4] if len(tokens)>4 else None + if det.status!= 0: + det.set_inputs({}) + else: + for det in self.detectors: + if det.id is not None and msg.startswith(det.id): + det_id = int(tokens[0][len(det.id)+1:]) + det.set_input(det_id, int(tokens[1])) + except: + print >> sys.stderr, traceback.format_exc() + self.getLogger().log(traceback.format_exc()) + + + + + + + +add_device(Esera("onewire", "129.129.126.83:5000"), force = True) +onewire.setPolling(500) +add_device(onewire.detectors[0], force = True) +add_device(onewire.detectors[1], force = True) +add_device(onewire.detectors[2], force = True) diff --git a/script/devices/RobotModbus.py b/script/devices/RobotModbus.py new file mode 100644 index 0000000..cd8abaf --- /dev/null +++ b/script/devices/RobotModbus.py @@ -0,0 +1,46 @@ +class RobotModbus(DeviceBase): + def __init__(self, name): + DeviceBase.__init__(self, name) + robot_req.write(0) + + def execute(self, command, *argv): + if robot_req.read() != 0: + raise Exception("Ongoing command") + if robot_ack.read() != 0: + raise Exception("Robot is not ready") + robot_cmd.write(command) + args = [0] * robot_args.size + index = 0 + for arg in argv: + args[index] = arg + index = index + 1 + if index == robot_args.size: + raise Exception("Invalid number of arguments") + robot_args.write(to_array(args, 'i')) + try: + self.request() + err = robot_ack.take() + if err == 1: + ret = robot_ret.read() + return ret + if err == 2: + raise Exception("Invalid command: " + str(command)) + raise Exception("Unknown error: " + str(err)) + finally: + self.cancel_request() + + def request(self): + robot_req.write(1) + while robot_ack.read() == 0: + time.sleep(0.001) + + def cancel_request(self): + robot_req.write(0) + while robot_ack.read() != 0: + time.sleep(0.001) + + def mount(self, puck, sample): + return self.execute('1', '1', puck, sample) + +add_device(RobotModbus("robot_mb"), force = True) + diff --git a/script/devices/RobotMotors.py b/script/devices/RobotMotors.py new file mode 100644 index 0000000..07ba862 --- /dev/null +++ b/script/devices/RobotMotors.py @@ -0,0 +1,62 @@ + +import ch.psi.pshell.device.PositionerConfig as PositionerConfig + + + +ROBOT_MOTORS = ["x" , "y", "z", "rx", "ry", "rz"] + + +class RobotCartesianMotor (PositionerBase): + def __init__(self, robot, index): + PositionerBase.__init__(self, robot.name + "_" + ROBOT_MOTORS[index], PositionerConfig()) + self.index = index + self.robot = robot + + #ATTENTION: Always initialize cartesian motors before scanning (or call robot.set_motors_enabled(True)) + def doInitialize(self): + self.setCache(self.doRead(), None) + + def doRead(self): + return float("nan") if self.robot.cartesian_destination is None else float(self.robot.cartesian_destination[self.index]) + + def doWrite(self, value): + if self.robot.cartesian_destination is not None: + #print "Move " + ROBOT_MOTORS[self.index] + " to " + str(value) + self.robot.cartesian_destination[self.index] = float(value) + self.robot.set_pnt(robot.cartesian_destination , "tcp_p") + self.robot.movel("tcp_p", self.robot.tool , DESC_SCAN) + + def doReadReadback(self): + return float("nan") if self.robot.cartesian_pos is None else float(self.robot.cartesian_pos[self.index]) + + + + +ROBOT_JOINT_MOTORS = ["j1" , "j2", "j3", "j4", "j5", "j6"] + + +class RobotJointMotor (PositionerBase): + def __init__(self, robot, index): + PositionerBase.__init__(self, robot.name + "_" + ROBOT_JOINT_MOTORS[index], PositionerConfig()) + self.index = index + self.robot = robot + + def doInitialize(self): + self.setpoint = self.doReadReadback() + self.setCache(self.doRead(), None) + + def doRead(self): + return self.setpoint + + def doWrite(self, value): + #print "Move " + ROBOT_JOINT_MOTORS[self.index] + " to " + str(value) + self.setpoint = value + joint = self.robot.herej() + joint[self.index] = value + self.robot.set_jnt(joint, name="tcp_j") + self.robot.movej("tcp_j", self.robot.tool , DESC_SCAN) + + def doReadReadback(self): + return self.robot.herej()[self.index] if self.robot.joint_pos is None else float(self.robot.joint_pos[self.index]) + + \ No newline at end of file diff --git a/script/devices/RobotSC.py b/script/devices/RobotSC.py new file mode 100644 index 0000000..f1e615a --- /dev/null +++ b/script/devices/RobotSC.py @@ -0,0 +1,355 @@ +TOOL_CALIBRATION = "tCalib" +TOOL_SUNA= "tSuna" +TOOL_DEFAULT= TOOL_SUNA + +FRAME_TABLE = "fTable" + +DESC_FAST = "mFast" +DESC_SLOW = "mSlow" +DESC_SCAN = "mScan" +DESC_DEFAULT = DESC_FAST + +AUX_SEGMENT = "X" + + +DEFAULT_ROBOT_POLLING = 500 +TASK_WAIT_ROBOT_POLLING = 50 + + +run("devices/RobotTCP") + + +simulation = False + +joint_forces = False + +class RobotSC(RobotTCP): + def __init__(self, name, server, timeout = 1000, retries = 1): + RobotTCP.__init__(self, name, server, timeout, retries) + self.set_tasks(["getDewar", "putDewar", "putGonio", "getGonio", "recover", "moveDewar", "moveCold", "movePark", "moveGonio","moveHeater", "moveScanner","moveHome", "moveAux"]) + self.set_known_points(["pPark", "pGonioA", "pDewar", "pGonioG", "pScan", "pHeater", "pHeat", "pHeatB", "pLaser","pHelium", "pHome", "pCold", "pAux"]) + self.setPolling(DEFAULT_ROBOT_POLLING) + self.last_command_timestamp = None + self.last_command_position = None + #self.setSimulated() + + def move_dewar(self): + self.start_task('moveDewar') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_dewar() + self.last_command_position = "dewar" + self.last_command_timestamp = time.time() + + def move_cold(self): + self.start_task('moveCold') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_cold() + self.last_command_position = "cold" + self.last_command_timestamp = time.time() + + def move_home(self): + self.start_task('moveHome') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_home() + self.last_command_position = "home" + self.last_command_timestamp = time.time() + + def get_dewar(self, segment, puck, sample): + segment = self.toSegmentNumber(segment) + self.start_task('getDewar',segment, puck, sample, is_room_temp()) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_dewar() + self.last_command_position = "dewar" + self.last_command_timestamp = time.time() + + def put_dewar(self, segment, puck, sample): + segment = self.toSegmentNumber(segment) + self.assert_dewar() + self.start_task('putDewar',segment, puck, sample, is_room_temp()) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + #self.assert_dewar() + self.assert_cold() + self.last_command_position = "dewar" + self.last_command_timestamp = time.time() + + def put_gonio(self): + pin_offset = get_pin_offset() + pin_angle_offset = get_pin_angle_offset() + print "Pin offset = " + str(pin_offset) + self.start_task('putGonio', pin_offset) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_gonio() + self.last_command_position = "gonio" + self.last_command_timestamp = time.time() + + def get_gonio(self): + pin_offset = get_pin_offset() + print "Pin offset = " + str(pin_offset) + self.start_task('getGonio', pin_offset) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_gonio() + self.last_command_position = "gonio" + self.last_command_timestamp = time.time() + + def get_aux(self, sample): + self.assert_aux() + self.start_task('getAuxiliary', sample) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_aux() + self.last_command_position = "aux" + self.last_command_timestamp = time.time() + + def put_aux(self, sample): + self.assert_aux() + self.start_task('putAuxiliary', sample) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_aux() + self.last_command_position = "aux" + self.last_command_timestamp = time.time() + + def move_scanner(self): + self.start_task('moveScanner') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_scanner() + self.last_command_position = "scanner" + self.last_command_timestamp = time.time() + + def move_laser(self): + self.start_task('moveScanner') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_laser() + self.last_command_position = "scanner" + self.last_command_timestamp = time.time() + + #def do_scan(self): + # self.start_task('doScan') + # self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + # self.assert_scan_stop() + + def move_gonio(self): + self.start_task('moveGonio') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_gonio() + self.last_command_position = "gonio" + self.last_command_timestamp = time.time() + + + def move_park(self): + self.start_task('movePark') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_park() + self.last_command_position = "park" + self.last_command_timestamp = time.time() + + def move_heater(self, speed=-1, to_bottom=True): + self.start_task('moveHeater', speed, to_bottom) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + if to_bottom: + self.assert_heater_bottom() + else: + self.assert_heater() + self.last_command_position = "heater" + self.last_command_timestamp = time.time() + + + def robot_recover(self): + self.start_task('recover') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_home() + self.last_command_position = "home" + self.last_command_timestamp = time.time() + + def move_aux(self): + self.start_task('moveAux') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_aux() + self.last_command_position = "aux" + self.last_command_timestamp = time.time() + + def get_calibration_tool(self): + self.start_task('getCalTool') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_scanner() + self.last_command_position = "scanner" + self.last_command_timestamp = time.time() + + def put_calibration_tool(self): + self.start_task('putCalTool') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_scanner() + self.command_timestamps["scanner"] = time.time() + + + + def toSegmentNumber(self, segment): + if is_string(segment): + segment = ord(segment.upper()) - ord('A') +1 + return segment + + + def on_event(self,ev): + #print "EVT: " + ev + pass + def on_change_working_mode(self, working_mode): + if get_device("hexiposi") is not None: + hexiposi.moved = True #Force image processing on first sample + + def doUpdate(self): + #start = time.time() + RobotTCP.doUpdate(self) + global simulation + if not simulation: + if joint_forces: + if self.state != State.Offline: + self.get_joint_forces() + for dev in [jf1, jf2, jf3, jf4,jf5, jf6, jfc]: + dev.update() + #print time.time() -start + + def start_task(self, program, *args, **kwargs): + #TODO: Check safe position + return RobotTCP.start_task(self, program, *args, **kwargs) + + def stop_task(self): + RobotTCP.stop_task(self) + #TODO: Restore safe position + + + def set_remote_mode(self): + robot.set_profile("remote") + + def set_local(self): + robot.set_profile("default") + + def is_park(self): + return self.is_in_point("pPark") + + def is_cold(self): + return self.is_in_point("pCold") + + def is_home(self): + return self.is_in_point("pHome") + + def is_dewar(self): + return self.is_in_point("pDewar") + + def is_heater(self): + return self.is_in_point("pHeat") + + def is_heater_home(self): + return self.is_in_point("pHeater") + + def is_heater_bottom(self): + return self.is_in_point("pHeatB") + + def is_gonio(self): + return self.is_in_point("pGonioA") + + def is_helium(self): + return self.is_in_point("pHelium") + + def is_scanner(self): + return self.is_in_point("pScan") + + def is_aux(self): + return self.is_in_point("pAux") + + def is_laser(self): + return self.is_in_point("pLaser") + + def is_cleared(self): + #return self.is_home() or self.is_park() or self.is_dewar() or self.is_dewar_home() + return self.get_current_point() is not None + + def assert_heater_home(self): + self.assert_in_point("pHeater") + + def assert_cold(self): + self.assert_in_point("pCold") + + def assert_heater(self): + self.assert_in_point("pHeat") + + def assert_heater_bottom(self): + self.assert_in_point("pHeatB") + + def assert_park(self): + self.assert_in_point("pPark") + + def assert_home(self): + self.assert_in_point("pHome") + + def assert_dewar(self): + self.assert_in_point("pDewar") + + def assert_gonio(self): + self.assert_in_point("pGonioA") + + def assert_helium(self): + self.assert_in_point("pHelium") + + def assert_scanner(self): + self.assert_in_point("pScan") + + def assert_aux(self): + self.assert_in_point("pAux") + + def assert_laser(self): + self.assert_in_point("pLaser") + + def assert_cleared(self): + if not self.is_cleared(): + raise Exception("Robot not in cleared position") + + def wait_ready(self): + robot.waitState(State.Ready, 1000) #robot.state.assertReady() + +if simulation: + add_device(RobotSC("robot","localhost:1000"),force = True) +else: + add_device(RobotSC("robot", "TellRobot6S:1000"), force = True) + + +#robot.latency = 0.005 +robot.set_default_desc(DESC_DEFAULT) +robot.default_speed = 20 +robot.set_frame(FRAME_DEFAULT) +robot.set_tool(TOOL_DEFAULT) +robot.setPolling(DEFAULT_ROBOT_POLLING) + +robot.get_current_point() #TODO: REMOVE WHEN CURRENT POINT REPORTED BY POLLING MESSAGE + +class jf1(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[0] +class jf2(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[1] +class jf3(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[2] +class jf4(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[3] +class jf5(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[4] +class jf6(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[5] +class jfc(ReadonlyRegisterBase): + def doRead(self): + if robot.joint_forces == None: + return float('NaN') + if robot.powered == False: + return float('NaN') + return (robot.joint_forces[1]+74)/4 + (robot.joint_forces[2]+30)/4 + (robot.joint_forces[4]-0.8)/0.2 + +if joint_forces: + add_device(jf1(), force = True) + add_device(jf2(), force = True) + add_device(jf3(), force = True) + add_device(jf4(), force = True) + add_device(jf5(), force = True) + add_device(jf6(), force = True) + add_device(jfc(), force = True) \ No newline at end of file diff --git a/script/devices/RobotTCP.py b/script/devices/RobotTCP.py new file mode 100644 index 0000000..4727d68 --- /dev/null +++ b/script/devices/RobotTCP.py @@ -0,0 +1,919 @@ +import threading + +FRAME_DEFAULT = "world" +FLANGE = "flange" + +MAX_NUMBER_PARAMETERS = 20 + +run("devices/RobotMotors") + +class RobotTCP(TcpDevice, Stoppable): + def __init__(self, name, server, timeout = 1000, retries = 1): + TcpDevice.__init__(self, name, server) + self.timeout = timeout + self.retries = retries + self.header = None + self.trailer = "\n" + self.array_separator = '|' + self.cmd_separator = ' ' + self.msg_id = 0 + self.working_mode = "invalid" + self.status = "invalid" + self.powered = None + self.settled = None + self.empty = None + self.working_mode = None + self.status = None + self.lock = threading.Lock() + self.joint_forces = None + self.current_task = None + self.current_task_ret = None + self.high_level_tasks = [] + self.known_points = [] + self.current_points = [] + self.cartesian_destination = None + #self.flange_pos = [None] * 6 + self.cartesian_pos = [None] * 6 + self.joint_pos = [None] * 6 + self.cartesian_motors_enabled = False + self.cartesian_motors = [] + self.joint_motors_enabled = False + self.joint_motors = [] + self.tool = None + self.default_desc = None + self.tool_open = None + #self.tool_trsf = [0.0] * 6 + self.frame = FRAME_DEFAULT + self.polling_interval = 0.01 + self.reset = True + self.default_tolerance = 5 + self.default_speed = 100 + self.latency = 0 + self.last_msg_timestamp = 0 + + self.task_start_retries = 3 + self.exception_on_task_start_failure = True #Tasks may start and be finished when checked + + + def doInitialize(self): + super(RobotTCP, self).doInitialize() + self.reset = True + + def set_tool(self, tool): + self.tool = tool + #self.tool_trsf = self.get_tool_trsf() + self.evaluate("tcp_curtool=" + tool) + if self.cartesian_motors_enabled: + self.update() + self.set_motors_enabled(True) + self.is_tool_open() + + def get_tool(self): + return self.tool + + def set_frame(self, frame): + self.frame = frame + self.evaluate("tcp_curframe=" + frame) + if self.cartesian_motors_enabled: + self.update() + self.set_motors_enabled(True) + self.waitCacheChange(5000) + + def get_frame(self): + return self.frame + + def set_default_frame(self): + self.set_frame(FRAME_DEFAULT) + + def assert_tool(self, tool=None): + if tool is None: + if self.tool is None: + raise Exception("Tool is undefined") + elif self.tool != tool: + raise Exception("Invalid tool: " + self.tool) + + def set_default_desc(self,default_desc): + self.default_desc=default_desc + + def get_default_desc(self): + return self.default_desc + + def set_tasks(self,tasks): + self.high_level_tasks=tasks + + def get_tasks(self): + return self.high_level_tasks + + def set_known_points(self, points): + self.known_points=points + + def get_known_points(self): + return self.known_points + + def get_current_points(self, tolerance = None): + ret = self.is_in_points(*self.known_points, tolerance = tolerance) + current_points = [] + for i in range(len(ret)): + if ret[i] == True: + current_points.append(self.known_points[i]) + return current_points + + def get_current_point(self, tolerance = None): + current_points = self.get_current_points(tolerance) + if (current_points is not None) and ( len(current_points) >0): + return current_points[0] + return None + + def get_current_points_cached(self): + return self.current_points + + def get_current_point_cached(self): + if (self.current_points is not None) and (len (self.current_points) >0): + return self.current_points[0] + return None + + def assert_in_known_point(self, tolerance = None): + if self.get_current_point(tolerance) is None: + raise Exception ("Robot not in known point") + + def _sendReceive(self, msg_id, msg = "", timeout = None): + if self.latency >0: + timespan = time.time() - self.last_msg_timestamp + if timespan<self.latency: + time.sleep(self.latency-timespan) + tx = self.header if (self.header != None) else "" + tx = tx + msg_id + " " + msg + if (len(tx)>150): + raise Exception("Exceeded maximum message size") + self.getLogger().finer("TX = '" + str(tx)+ "'") + if (self.trailer != None): tx = tx + self.trailer + if self.isSimulated(): + return "" + rx = self.sendReceive(tx, msg_id, self.trailer , 0, self.timeout if timeout is None else timeout, self.retries) + self.last_msg_timestamp = time.time() + rx=rx[:-1] #Remove 0A + self.getLogger().finer("RX = '" + str(rx) + "'") + if rx[:3] != msg_id: + if (time.time()-start) >= timeout: + raise Exception("Received invalid message id: " + str(rx[:3]) + " - expecting:" + msg_id ) + if len(rx)<4: + raise Exception("Invalid message size: " + str(len(rx)) ) + if rx[3] == "*": + raise Exception(rx[4:]) + return rx[4:] + + def call(self, msg, timeout = None): + self.lock.acquire() + try: + id = "%03d" % self.msg_id + self.msg_id = (self.msg_id+1)%1000 + return self._sendReceive(id, msg, timeout) + finally: + self.lock.release() + + def execute(self, command, *args, **kwargs): + timeout = None if (kwargs is None) or (not kwargs.has_key("timeout")) else kwargs["timeout"] + msg = str(command) + if len(args)>MAX_NUMBER_PARAMETERS: + raise Exception("Exceeded maximum number of parameters") + for i in range(len(args)): + msg += (self.cmd_separator if (i==0) else self.array_separator) + str(args[i]) + rx = self.call(msg, timeout) + if rx.count(self.array_separator)>0: + return rx.split(self.array_separator) + return rx + + def evaluate(self, cmd, timeout=None): + ret = self.execute('eval', cmd, timeout=timeout) + if is_string(ret): + if ret.strip() != "": raise Exception(ret) + + def get_var(self, name): + return self.execute('get_var', name) + + #Makes app crash + #def get_str(self, name='s'): + # return self.execute('get_str', name) + + def get_arr(self, name, size): + return self.execute('get_arr', name, size) + + def get_bool(self, name = "tcp_b"): + return True if (self.execute('get_bool', name).strip() == '1') else False + + def get_int(self, name ="tcp_n"): + return int(self.get_var(name)) + + def get_float(self, name ="tcp_n"): + return float(self.get_var(name)) + + def get_int_arr(self, size, name="tcp_a"): + # not working. A Jython bug in PyUnicaode? + #return [int(x) for x in self.get_arr("tcp_a", size)] + ret = [] + a=self.get_arr(name, size) + for i in range(size): + ret.append(int(a[i])) + return ret + + def get_float_arr(self, size, name="tcp_a"): + #return [float(x) for x in self.get_arr("tcp_a", size)] + a=self.get_arr(name, size) + ret = []; + for i in range(size): ret.append(float(a[i])); + return ret + + def get_trsf(self, name="tcp_t"): + a = self.execute('get_trf', name) + ret = [] + for i in range(6): ret.append(float(a[i])) + return ret + + def set_trsf(self, l, name="tcp_t"): + self.evaluate(name + "={" + str(l[0]) + ","+ str(l[1]) + ","+ str(l[2]) + ","+ str(l[3]) + ","+ str(l[4]) + ","+ str(l[5]) + "}") + + def get_jnt(self, name="tcp_j"): + a = self.execute('get_jnt', name) + ret = [] + for i in range(6): ret.append(float(a[i])) + return ret + + def set_jnt(self, l, name="tcp_j"): + self.evaluate(name + "={" + str(l[0]) + ","+ str(l[1]) + ","+ str(l[2]) + ","+ str(l[3]) + ","+ str(l[4]) + ","+ str(l[5]) + "}") + + def get_pnt(self, name="tcp_p"): + #a = self.execute('get_pnt', name) + #ret = [] + #for i in range(6): ret.append(float(a[i])) + #return ret + return self.get_trsf(name+".trsf") + + #trsf = (x,y,z,rx,ry,rz) + #TODO: config = (shoulder, elbow, wrist) + def set_pnt(self, trsf, name="tcp_p", config=None): + self.set_trsf(trsf, name+".trsf") + + def get_tool_trsf(self, name=None): + if name is None: + self.assert_tool() + name = self.tool + return self.get_trsf(name+".trsf") + + def set_tool_trsf(self, trsf, name=None): + if name is None: + self.assert_tool() + name = self.tool + self.set_trsf(trsf, name+".trsf") + + def eval_int(self, cmd): + if self.isSimulated(): + return 0 + self.evaluate("tcp_n=" + cmd) + return self.get_int() + + def eval_float(self, cmd): + if self.isSimulated(): + return 0.0 + self.evaluate("tcp_n=" + cmd) + return self.get_float() + + def eval_bool(self, cmd): + if self.isSimulated(): + return False + self.evaluate("tcp_b=" + cmd) + return self.get_bool() + + #def eval_str(self, cmd): + # self.evaluate("s=" + cmd) + # return self.get_str() + + def eval_jnt(self, cmd): + self.evaluate("tcp_j=" + cmd) + return self.get_jnt() + + def eval_trf(self, cmd): + self.evaluate("tcp_t=" + cmd) + return self.get_trsf() + + def eval_pnt(self, cmd): + self.evaluate("tcp_p=" + cmd) + return self.get_pnt() + + + #Robot control + def is_powered(self): + self.powered = self.eval_bool("isPowered()") + return self.powered + + def enable(self): + if not self.is_powered(): + self.evaluate("enablePower()") + time.sleep(1.0) + if not self.is_powered(): + raise Exception("Cannot enable power") + + #waits for power to be actually cut off + def disable(self): + self.evaluate("disablePower()", timeout=5000) + + def get_monitor_speed(self): + self.speed = self.eval_int("getMonitorSpeed()") + return self.speed + + def set_monitor_speed(self, speed): + ret = self.eval_int("setMonitorSpeed(" + str(speed) + ")") + if (ret==-1): raise Exception("The robot is not in remote working mode") + if (ret==-2): raise Exception("The monitor speed is under the control of the operator") + if (ret==-3): raise Exception("The specified speed is not supported") + + def set_default_speed(self): + set_monitor_speed(self.default_speed) + + def is_calibrated(self): + return self.eval_bool("isCalibrated()") + + def save_program(self): + ret = self.execute('save', timeout=5000) + if str(ret) != "0": raise Exception("Error saving program: " + str(ret)) + + def _update_working_mode(self, mode, status): + cur_mode = self.working_mode + if mode==1: + self.working_mode = "manual" + self.status = "hold" if status==6 else "move" + elif mode==2: + self.working_mode = "test" + self.status = "hold" if status==3 else "move" + elif mode==3: + self.working_mode = "local" + self.status = "hold" if status==2 else "move" + elif mode==4: + self.working_mode = "remote" + self.status = "hold" if status==2 else "move" + else: + self.working_mode = "invalid" + self.status = "invalid" + if self.working_mode != cur_mode: + try: + self.on_change_working_mode(self.working_mode) + except: + pass + + def read_working_mode(self): + try: + mode = self.eval_int("workingMode(tcp_a)") + status = int(self.get_var("tcp_a[0]")) + self._update_working_mode(mode, status) + self._update_state() + except: + self.working_mode = "invalid" + self.status = "invalid" + return self.working_mode + + def get_emergency_stop_sts(self): + st = self.eval_int("esStatus()") + if (st== 1): return "active" + if (st== 2): return "activated" + return "off" + + def get_safety_fault_signal(self): + fault = self.eval_bool("safetyFault(s)") + #if (fault): + # return get_str() + return fault + + #Motion control + def stop(self): + self.evaluate("stopMove()") + + def resume(self): + self.evaluate("restartMove()") + + def reset_motion(self, joint=None, timeout=None): + #TODO: in new robot robot.resetMotion() is freezing controller + #self.evaluate("resetMotion()" if (joint is None) else ("resetMotion(" + joint + ")")) + if joint is None: + self.execute('reset', timeout=timeout) + else: + self.execute('reset', str(joint), timeout=timeout) + + def is_empty(self): + self.empty = self.eval_bool("isEmpty()") + self._update_state() + return self.empty + + def is_settled(self): + self.settled = self.eval_bool("isSettled()") + self._update_state() + return self.settled + + def get_move_id(self): + return self.eval_int("getMoveId()") + + def set_move_id(self, id): + return self.evaluate("setMoveId(" + str(id) + " )") + + def get_joint_forces(self): + try: + self.evaluate("getJointForce(tcp_a)") + self.joint_forces = self.get_float_arr(6) + return self.joint_forces + except: + self.joint_forces = None + raise + + def movej(self, joint_or_point, tool=None, desc=None, sync=False): + if desc is None: desc = self.default_desc + if tool is None: tool = self.tool + #If joint_or_point is a list assumes ir is a point + if not is_string(joint_or_point): + robot.set_pnt(joint_or_point , "tcp_p") + joint_or_point = "tcp_p" + + #TODO: in new robot movel and movej is freezing controller + #ret = self.eval_int("movej(" + joint_or_point + ", " + tool + ", " + desc +")") + ret = int(self.execute('movej',joint_or_point, tool, desc)) + + if sync: + self.wait_end_of_move() + return ret + + def movel(self, point, tool=None, desc=None, sync=False): + if desc is None: desc = self.default_desc + if tool is None: tool = self.tool + if not is_string(point): + robot.set_pnt(point , "tcp_p") + point = "tcp_p" + #TODO: in new robot movel and movej is freezing controller + #ret = self.eval_int("movel(" + point + ", " + tool + ", " + desc +")") + ret = int(self.execute('movel',point, tool, desc)) + + if sync: + self.wait_end_of_move() + return ret + + def movec(self, point_interm, point_target, tool=None, desc=None, sync=False): + if desc is None: desc = self.default_desc + if tool is None: tool = self.tool + + #TODO: in new robot movel and movej is freezing controller + #ret = self.eval_int("movec(" + point_interm + ", " + point_target + ", " + tool + ", " + desc +")") + ret = int(self.execute('movec', point_interm, point_target, tool, desc)) + + if sync: + self.wait_end_of_move() + return ret + + def wait_end_of_move(self): + time.sleep(0.05) + self.update() + #time.sleep(0.01) + #self.waitCacheChange(-1) + self.waitReady(-1) + #self.waitState(State.Ready, -1) + + + #Tool - synchronized as can freeze communication + """ + def open_tool(self, tool=None, timeout=3000): + #This function can timeout since it synchronizes move. Checking state before otherwise it can freeze the communication. + self.waitState(State.Ready, -1) + if tool is None: tool = self.tool + return self.evaluate("open(" + tool + " )", timeout=timeout) + + def close_tool(self, tool=None, timeout=3000): + #This function can timeout since it synchronizes move. Checking state before otherwise it can freeze the communication. + self.waitState(State.Ready, -1) + if tool is None: tool = self.tool + return self.evaluate("close(" + tool + " )", timeout=timeout) + """ + #Tool - Not synchronized calls: atention to open/close only when state is Ready + def open_tool(self, tool=None): + if tool is None: tool = self.tool + self.evaluate(tool + ".gripper=true") + self.tool_open = True + + def close_tool(self, tool=None): + if tool is None: tool = self.tool + self.evaluate(tool + ".gripper=false") + self.tool_open = False + + def is_tool_open(self, tool=None): + if tool is None: tool = self.tool + self.tool_open = robot.eval_bool(tool + ".gripper") + return self.tool_open + + + #Arm position + def herej(self): + return self.eval_jnt("herej()") + + def distance_t(self, trsf1, trsf2): + return self.eval_float("distance(" + trsf1 + ", " + trsf2 + ")") + + def distance_p(self, pnt1, pnt2): + return self.eval_float("distance(" + pnt1 + ", " + pnt2 + ")") + + def compose(self, pnt, frame = None, trsf = "tcp_t"): + if frame is None: frame = self.frame + return self.eval_pnt("compose(" + pnt + ", " + frame + ", " + trsf + ")") + + def here(self, tool=None, frame=None): + if tool is None: tool = self.tool + if frame is None: frame = self.frame + return self.eval_pnt("here(" + tool + ", " + frame + ")") + + def joint_to_point(self, tool=None, frame=None, joint="tcp_j"): + if tool is None: tool = self.tool + if frame is None: frame = self.frame + return self.eval_pnt("jointToPoint(" + tool + ", " + frame + ", " + joint +")") + + def point_to_joint(self, tool=None, initial_joint="tcp_j", point="tcp_p"): + if tool is None: tool = self.tool + if self.eval_bool("pointToJoint(" + tool + ", " + initial_joint + ", " + point +", j)"): + return self.get_jnt() + + def position(self, point, frame=None): + if frame is None: frame = self.frame + return self.eval_trf("position(" + point + ", " + frame + ")") + + #Profile + def get_profile(self): + return self.execute('get_profile', timeout=2000) + + def set_profile(self, name, pwd = ""): + self.execute('set_profile', str(name), str(pwd), timeout=5000) + + + #Task control + def task_create(self, program, *args, **kwargs): + program = str(program) + priority = 10 if (kwargs is None) or (not kwargs.has_key("priority")) or (kwargs["priority"] is None) else kwargs["priority"] + name = str(program if (kwargs is None) or (not kwargs.has_key("name")) else kwargs["name"]) + + if self.get_task_status(name)[0] != -1: + raise Exception("Task already exists: " + name) + + if priority<1 or priority > 100: + raise Exception("Invalid priority: " + str(priority)) + + cmd = program + '(' + for i in range(len(args)): + val = args[i] + if type(val) == bool: + if val == True: val = "true" + elif val == False: val = "false" + cmd += str(val) + (',' if (i<(len(args)-1)) else '') + cmd+=')' + + #TODO: in new robot exec taskCreate is freezing controller + #REMOVE if bug is fixed + self.execute('task_create',name, str(priority), program, *args) + #self.evaluate('taskCreate "' + name + '", ' + str(priority) + ', ' + cmd) + + + + def task_suspend(self, name): + self.evaluate('taskSuspend("' + str(name)+ '")') + + #waits until the task is ready for restart + def task_resume(self, name): + self.evaluate('taskResume("' + str(name)+ '",0)', timeout = 2000) + + #waits for the task to be actually killed + def task_kill(self, name): + #self.evaluate('taskKill("' + str(name)+ '")', timeout = 5000) + self.execute('kill', str(name), timeout=5000) + + def get_task_status(self, name): + if self.isSimulated(): + return (-1,"Stopped") + code = self.eval_int('taskStatus("' + str(name)+ '")') + #TODO: String assignments in $exec causes application to freeze + #status = self + if code== -1: status = "Stopped" + elif code== 0: status = "Paused" + elif code== 1: status = "Running" + #else: status = self.execute('get_help', code) + else: status = "Error" + return (code,status) + + def get_tasks_status(self, *pars): + ret = self.execute("task_sts", *pars) + ret = ret[0:len(pars)] + for i in range(len(ret)): + try: + ret[i] = int(ret[i]) + except: + ret[i] = None + return ret + + def _update_state(self): + #self.setState(State.Busy if self.status=="move" else State.Ready) + if self.state==State.Offline: + print "Communication resumed" + if self.reset or (self.state==State.Offline): + self.check_task() + if self.current_task is not None: + print "Ongoing task: " + self.current_task + if (not self.settled) or (self.current_task is not None): self.setState(State.Busy) + elif not self.empty: self.setState(State.Paused) + else: self.setState(State.Ready) + + def doUpdate(self): + try: + start = time.time() + cur_task = self.current_task #Can change in background so cache it + if self.isSimulated(): + sts = [1, 1,"1", 100, "1", "1", 0, 0, \ + 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, \ + ] + else: + sts = self.execute("get_status", cur_task) + self._update_working_mode(int(sts[0]), int(sts[1])) + self.powered = sts[2] == "1" + self.speed = int(sts[3]) + self.empty = sts[4] == "1" + self.settled = sts[5] == "1" + + #TODO: add tool open + if cur_task is not None: + if int(sts[6]) < 0: + log("Task "+ str(cur_task) + " finished with code: " + str(sts[7]), False) + try: + self.current_task, self.current_task_ret = None, int(sts[7]) + except: + self.current_task, self.current_task_ret = None, None + for i in range(6): + self.joint_pos[i] = float(sts[8 + i]) + for i in range(6): + self.cartesian_pos[i] = float(sts[14 + i]) + + ev_index = 20 #7 + ev = sts[ev_index] if len(sts)>ev_index else "" + if len(ev.strip()) >0: + self.getLogger().info(ev) + self.on_event(ev) + + self._update_state() + self.reset = False + self.setCache({"powered": self.powered, + "speed": self.speed, + "empty": self.empty, + "settled": self.settled, + "task": cur_task, + "mode": self.working_mode, + "status": self.status, + "open": self.tool_open, + "pos": self.get_current_point_cached() if self.state==State.Ready else None #TODO: make it calculated in robot by polling funtion + }, None) + + if self.cartesian_motors_enabled: + for m in self.cartesian_motors: + m.readback.update() + + if self.joint_motors_enabled: + for m in self.joint_motors: + m.readback.update() + + except: + if self.state != State.Offline: + print >> sys.stderr, "Update error: " + str(sys.exc_info()[1]) + self.setState(State.Offline) + + #Cartesian space + """ + def get_cartesian_pos(self): + self.assert_tool() + return self.eval_pnt("jointToPoint(" + self.tool + ", " + self.frame + ", herej())") + #self.set_jnt(self.herej()) + #return self.joint_to_point(tool, frame) + """ + + + #TODO: in new robot robot.evaluate("tcp_p=jointToPoint(tSuna, world, herej())") is freezing controller (cannot call herej directly) + #We can consider atomic because tcp_j is only accessed in comTcp + def get_cartesian_pos(self, tool=None, frame=None): + if tool is None: + self.assert_tool() + tool = self.tool + if frame is None: + frame = self.frame + #Do not work + #self.evaluate("tcp_j=herej(); tcp_p=jointToPoint(" + tool + ", " + frame + ", tcp_j)") + #return self.get_pnt() + a = self.execute('get_pos', tool, frame) + ret = [] + for i in range(6): ret.append(float(a[i])) + return ret + + + def get_flange_pos(self, frame=None): + return get_cartesian_pos(FLANGE, frame) + + + def get_cartesian_destination(self, tool=None, frame=None): + if tool is None: + self.assert_tool() + tool = self.tool + if frame is None: + frame = self.frame + return self.here(tool, frame) + + def get_distance_to_pnt(self, name): + #self.here(self.tool, self.frame) #??? + self.set_pnt(self.get_cartesian_pos() ) + return self.distance_p("tcp_p", name) + + def is_in_point(self, p, tolerance = None): #Tolerance in mm + if (tolerance is None) and p in self.known_points: + #If checking a known point with default tolerance, updates the position cache + return p in self.get_current_points() + tolerance = self.default_tolerance if tolerance == None else tolerance + d = self.get_distance_to_pnt(p) + if d<0: + raise Exception ("Error calculating distance to " + p + " : " + str(d)) + return d<tolerance + + def get_distance_to_pnts(self, *pars): + ret = self.execute("dist_pnt", *pars) + ret = ret[0:len(pars)] + for i in range(len(ret)): + try: + ret[i] = float(ret[i]) + except: + ret[i] = None + return ret + + def is_in_points(self, *pars, **kwargs): #Tolerance in mm + tolerance = self.default_tolerance if (kwargs is None) or (not kwargs.has_key("tolerance")) or (kwargs["tolerance"] is None) else kwargs["tolerance"] + ret = self.get_distance_to_pnts(*pars) + for i in range(len(ret)): + if ret[i]<0: + ret[i] = None + else: + ret[i] = ret[i]<tolerance + if (tolerance == self.default_tolerance) and (set(self.known_points).issubset(set(pars))): #Only update cache if tolerance is default + current_points = [] + for i in range(len(ret)): + if ret[i] == True: + current_points.append(self.known_points[i]) + self.current_points = current_points + return ret + + def assert_in_point(self, p, tolerance = None): #Tolerance in mm + if not self.is_in_point(p, tolerance): + raise Exception ("Not in position " + p) + + + #Cartesian peudo-motors + def set_motors_enabled(self, value): + if value !=self.cartesian_motors_enabled: + self.cartesian_motors_enabled = value + if value: + for i in range(6): + self.cartesian_motors.append(RobotCartesianMotor(self, i)) + add_device(self.cartesian_motors[i], True) + self.cartesian_destination = self.get_cartesian_destination() + else: + for m in self.cartesian_motors: + remove_device(m) + self.cartesian_motors = [] + self.cartesian_destination = None + else: + if value: + self.cartesian_destination = self.get_cartesian_destination() + for m in self.cartesian_motors: + m.initialize() + + + #Cartesian peudo-motors + def set_joint_motors_enabled(self, value): + if value !=self.joint_motors_enabled: + self.joint_motors_enabled = value + if value: + for i in range(6): + self.joint_motors.append(RobotJointMotor(self, i)) + add_device(self.joint_motors[i], True) + else: + for m in self.joint_motors: + remove_device(m) + self.joint_motors = [] + else: + if value: + for m in self.joint_motors: + m.initialize() + #Alignment + def align(self, point = None, frame = None, desc = None): + if frame is None: frame = self.frame + self.assert_tool() + if desc is None: desc = self.default_desc + if point is None: + self.set_pnt(self.get_cartesian_pos() ) + else: + self.set_pnt(point) + np=self.eval_trf('align(tcp_p.trsf, ' + frame + '.trsf)') + self.set_pnt(np) + self.movej("tcp_p", self.tool, desc) + #TODO: The first command is not executed (but receive a move id) + self.movej("tcp_p", self.tool, desc, sync = True) + return np + + #High-level, exclusive motion task. + def start_task(self, program, *args, **kwargs): + tasks = [t for t in self.high_level_tasks] + if (self.current_task is not None) and (not self.current_task in tasks): + tasks.append(self.current_task) + if not program in tasks: + tasks.append(program) + #for task in tasks: + # if self.get_task_status(task)[0]>=0: + # raise Exception("Ongoing high-level task: " + task) + ts = self.get_tasks_status(*tasks) + for i in range(len(ts)): + if ts[i] > 0: + raise Exception("Ongoing high-level task: " + tasks[i]) + + self.clear_task_ret() + + for i in range(self.task_start_retries): + self.task_create(program, *args, **kwargs) + (code, status) = self.get_task_status(program) + if code>=0: break + if i < self.task_start_retries-1: + ret = self.get_task_ret(False) + if ret == 0: #Did't start + log("Retrying starting : " + str(program) + str(args) + " - status: " + str(status) + " (" + str(code) + ")", False) + print "Retrying starting : " + str(program) + str(args) + " - status: " + str(status) + " (" + str(code) + ")" + else : + print "Retrying aborted : " + str(program) + str(args) + " - ret: " + str(ret) + " - status: " + str(status) + " (" + str(code) + ")" + break + else: + log("Failed starting : " + str(program) + str(args), False) + print "Failed starting : " + str(program) + str(args) + if self.exception_on_task_start_failure: + raise Exception("Cannot start task: " + program + str(args)) + + log("Task started: " + str(program) + str(args) + " - status: " + str(status) + " (" + str(code) + ")", False) + self.current_task, self.current_task_ret = program, None + self.update() + #self._update_state() + + #TODO: remove + if self.current_task is None: + log("Task finished in first polling : " + str(program) , False) + print "Task finished in first polling : " + str(program) + + return code + + def stop_task(self): + tasks = [t for t in self.high_level_tasks] + if (self.current_task is not None) and (not self.current_task in tasks): + tasks.append(self.current_task) + for task in tasks: + #if self.get_task_status(task)[0]>=0: + self.task_kill(task) + self.reset_motion() + + def get_task_ret(self, cached = True): + return self.current_task_ret if cached else self.eval_int("tcp_ret") + + def clear_task_ret(self): + return self.evaluate("tcp_ret=0") + + def get_task(self): + return self.current_task + + def check_task(self): + if self.current_task is None: + for task in self.high_level_tasks: + if self.get_task_status(task)[0]>=0: + self.current_task, self.current_task_ret = task, None + log("Task detected: " + str(self.current_task), False) + return self.current_task + + def wait_task_finished (self, polling = None): + cur_polling = self.polling + if polling is not None: + self.polling = polling + try: + while self.get_task() != None: + time.sleep(self.polling_interval) + finally: + if polling is not None: + self.polling = cur_polling + ret = self.get_task_ret() + return ret + + def assert_no_task(self): + task = self.check_task() + if task != None: + raise Exception("Ongoing task: " + task) + + def on_event(self,ev): + pass + + def on_change_working_mode(self, working_mode): + pass + \ No newline at end of file diff --git a/script/devices/SmartMagnet.py b/script/devices/SmartMagnet.py new file mode 100644 index 0000000..0736fdf --- /dev/null +++ b/script/devices/SmartMagnet.py @@ -0,0 +1,129 @@ +class SmartMagnet(DeviceBase): + def __init__(self, name): + #DeviceBase.__init__(self, name, get_context().pluginManager.getDynamicClass("SmartMagnetConfig")()) + DeviceBase.__init__(self, name, DeviceConfig({ + "holdingCurrent":0.0, + "restingCurrent":0.0, + "mountCurrent":0.0, + "unmountCurrent":0.0, + "reverseCurrent":0.0, + "reverseTime":0.0, + })) + + def doInitialize(self): + super(SmartMagnet, self).doInitialize() + self.get_current() + + def set_current(self, current): + self.setCache(current, None) + smc_current.write(current) + + def get_current(self): + cur = smc_current.read() + self.setCache(cur, None) + return cur + + def get_current_rb(self): + self.assert_status() + return smc_current_rb.read() + + def get_status(self): + return smc_magnet_status.read() + + def assert_status(self): + pass + #if self.get_status() == False: + # raise Exception("Smart Magnet is in faulty status.") + + def is_mounted(self): + self.assert_status() + m1 = smc_mounted_1.read() + m2 = smc_mounted_2.read() + if m2==m1: + raise Exception("Smart Magnet has invalid detection.") + return m2 + + def set_supress(self, value): + smc_sup_det.write(value) + + def get_supress(self): + return smc_sup_det.read() + + def check_mounted(self, idle_time =1.0, timeout = -1, interval = 0.01): + self.assert_status() + start = time.time() + last = None + while True: + try: + det = self.is_mounted() + except: + det = None + if det != last: + settling_timestamp = time.time() + last = det + else: + if det is not None: + if (time.time()-settling_timestamp > idle_time): + return det + if timeout >= 0: + if (time.time() - start) > timeout: + raise Exception("Timeout waiting for Smart Magnet detection.") + time.sleep(interval) + + + def doUpdate(self): + try: + if self.get_supress(): + self.setState(State.Paused) + elif self.is_mounted(): + self.setState(State.Busy) + else: + self.setState(State.Ready) + except: + self.setState(State.Fault) + + def set_holding_current(self): + self.set_current(self.config.getFieldValue("holdingCurrent")) + + def set_resting_current(self): + self.set_current(self.config.getFieldValue("restingCurrent")) + + def set_mount_current(self): + self.set_current(self.config.getFieldValue("mountCurrent")) + + def set_unmount_current(self): + self.set_current(self.config.getFieldValue("unmountCurrent")) + + def set_reverse_current(self): + self.set_current(self.config.getFieldValue("reverseCurrent")) + + def set_default_current(self): + if self.is_mounted(): + self.set_holding_current() + else: + self.set_resting_current() + + def is_resting_current(self): + is_resting = 2.0 > abs( float(self.get_current()) - float(self.config.getFieldValue("restingCurrent")) ) + return is_resting + + + def apply_reverse(self): + reverse_wait = float(self.config.getFieldValue("reverseTime")) + if reverse_wait >0: + self.set_reverse_current() + time.sleep(reverse_wait) + + #Setting resting current to better detect sample + def apply_resting(self): + if not self.is_resting_current(): + self.set_resting_current() + + + + +add_device(SmartMagnet("smart_magnet"), force = True) + +smart_magnet.polling = 1000 + +smart_magnet.set_default_current() diff --git a/script/devices/Wago.py b/script/devices/Wago.py new file mode 100644 index 0000000..e0921a4 --- /dev/null +++ b/script/devices/Wago.py @@ -0,0 +1,141 @@ +LED_LEVEL_ROOM_TEMPERATURE = 0.4 +LED_LEVEL_LN2 = 1.0 + + +################################################################################################### +# Leds +################################################################################################### + +def set_led_level(level): + level = max(min(float(level),100.0),0.0) + set_setting("led_level", level) + led_ctrl_1.write(led_ctrl_1.config.maxValue * level / 100.0) + led_ctrl_2.write(led_ctrl_2.config.maxValue * level / 100.0) + led_ctrl_3.write(led_ctrl_3.config.maxValue * level / 100.0) + +def get_led_level(): + level = get_setting("led_level") + return float(0 if level is None else level) + +def set_led_state(value): + """ + Turn leds on and off + """ + if value: + set_led_level(100.0) + else: + set_led_level(0.0) + +def get_led_state(): + """ + Returns led state (on/off) + """ + return led_ctrl_1.read() > 0 + +#TODO: The range should be set automatically reading LN2 sensor. +def set_led_range(room_temp = True): + """ + Led range should be limitted in room temperature + """ + max_val = LED_LEVEL_ROOM_TEMPERATURE if room_temp else LED_LEVEL_LN2 + led_ctrl_1.config.maxValue = max_val + led_ctrl_1.config.save() + led_ctrl_2.config.maxValue = max_val + led_ctrl_2.config.save() + led_ctrl_3.config.maxValue = max_val + led_ctrl_3.config.save() + led_ctrl_1.initialize() + led_ctrl_2.initialize() + led_ctrl_3.initialize() + if led_ctrl_1.read() > max_val: + led_ctrl_1.write(max_val) + if led_ctrl_2.read() > max_val: + led_ctrl_2.write(max_val) + if led_ctrl_3.read() > max_val: + led_ctrl_3.write(max_val) + set_led_level(get_led_level()) + + +def is_led_room_temp(): + return led_ctrl_1.config.maxValue <= LED_LEVEL_ROOM_TEMPERATURE + + + + +################################################################################################### +# Safety release +################################################################################################### + +def release_local(): + """ + Release local safety + """ + release_local_safety.write(False) + time.sleep(0.01) + release_local_safety.write(True) + time.sleep(0.01) + release_local_safety.write(False) + +def release_psys(): + """ + Release psys safety + """ + if is_manual_mode(): + raise Exception ("Cannot release PSYS in manual mode") + release_psys_safety.write(False) + time.sleep(0.01) + release_psys_safety.write(True) + time.sleep(0.01) + release_psys_safety.write(False) + + + +################################################################################################### +# Drier +################################################################################################### +MAX_HEATER_TIME = 90000 + +def set_air_stream(state): + """ + """ + valve_1.write(state) + valve_2.write(not state) + + +set_heater_chrono = None + +def monitor_heater_time(): + time.sleep(0.5) + try: + while get_heater(): + if set_heater_chrono.isTimeout(MAX_HEATER_TIME): + set_heater(False) + log("Heater timeout expired: turned off", False) + return + time.sleep(0.1) + except: + print sys.exc_info() + + +def get_heater(): + """ + """ + return gripper_dryer.read() + + +def set_heater(state): + """ + """ + global set_heater_chrono + if get_heater() != state: + gripper_dryer.write(state) + if state: + set_heater_chrono = Chrono() + fork(monitor_heater_time) + + +def get_air_stream(): + """ + """ + return valve_1.read() + diff --git a/script/hexiposi_positon.scd b/script/hexiposi_positon.scd new file mode 100644 index 0000000..471fb41 --- /dev/null +++ b/script/hexiposi_positon.scd @@ -0,0 +1,11 @@ +[ + [ [ true, "hexiposi_position", "Device", 1, 1, null ] ], + [ [ "1", null, null, null, null, null, null, null ], + [ "2", null, null, null, null, null, null, null ], + [ "3", null, null, null, null, null, null, null ], + [ "4", null, null, null, null, null, null, null ], + [ "5", null, null, null, null, null, null, null ] ], + [ [ ] ], + [ [ "", 1000, 100 ], + [ "", "" ] ] +] \ No newline at end of file diff --git a/script/imgproc/CameraCalibration.py b/script/imgproc/CameraCalibration.py new file mode 100644 index 0000000..a89510d --- /dev/null +++ b/script/imgproc/CameraCalibration.py @@ -0,0 +1,156 @@ +import ch.psi.pshell.device.Camera as Camera +import ch.psi.pshell.imaging.RendererMode as RendererMode +import ch.psi.pshell.imaging.Calibration as Calibration +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.pshell.imaging.Pen as Pen +import ch.psi.utils.swing.SwingUtils as SwingUtils +import javax.swing.SwingUtilities as SwingUtilities +#from swingutils.threads.swing import callSwing +#SIMULATION = ch.psi.pshell.imaging.FileSource +""" +img.camera.setColorMode(Camera.ColorMode.Mono) +img.camera.setDataType(Camera.DataType.UInt8) +img.camera.setGrabMode(Camera.GrabMode.Continuous) +img.camera.setTriggerMode(Camera.TriggerMode.Fixed_Rate) +img.camera.setExposure(50.00) +img.camera.setAcquirePeriod(200.00) +img.camera.setGain(0.0) +img.config.rotationCrop=True +""" + +MOVE_HEXIPOSI = not is_manual_mode() +ROTATION_OFFSET = 180.0 + +if MOVE_HEXIPOSI: + release_safety() #enable_motion() + +sensor_width,sensor_height = img.camera.getSensorSize() +img.camera.setROI(0, 0,sensor_width, sensor_height) +img.config.rotation=0 +img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight =0,0,-1,-1 +img.config.setCalibration(None) +img.camera.stop() +img.camera.start() + + +p = show_panel(img) +dlg = SwingUtilities.getWindowAncestor(p) +dlg.setSize(800,800) +frm=SwingUtils.getFrame(p) +dlg.setLocationRelativeTo(frm) + +p.setMode(RendererMode.Fit) +ov_text = Text(Pen(java.awt.Color.GREEN.darker()), "", java.awt.Font("Verdana", java.awt.Font.PLAIN, 24), java.awt.Point(20,20)) +ov_text.setFixed(True) +p.addOverlay(ov_text) + + +try: + #Find image center and Prosilica ROI + ov_text.update("Click on the center of the Dewar...") + p.refresh() + dc = p.waitClick(60000) + print dc + width, height = min(dc.x, sensor_width-dc.x)*2, min(dc.y, sensor_height-dc.y)*2 + width, height = width - width%16, height - height%16 + width, height = min(width,1000), min(height,1000) + print width, height + roi_x = int(dc.x- width/2) + roi_y = int(dc.y- height/2) + roi_w = int(width) + roi_h = int(height) + set_setting("roi_x", roi_x) + set_setting("roi_y", roi_y) + set_setting("roi_w", roi_w) + set_setting("roi_h", roi_h) + img.camera.setROI(roi_x, roi_y, width, height) +except: + img.camera.setROI(int(get_setting("roi_x")), int(get_setting("roi_y")), int(get_setting("roi_w")), int(get_setting("roi_h"))) +finally: + img.camera.stop() + img.camera.start() + + +#Configure source +CC4 = (-129.9, -150) +CD5 = (129.9, -150) +CA5 = (-129.9, 150) +CF4 = (129.9, 150) + +DX = 259.8 +DY = 300.0 + +ROI_X = 470.0 +ROI_Y = 470.0 + +def rotate(x,y, degrees): + rotation = math.radians(degrees) + rw, rh = img.getImage().getWidth(), img.getImage().getHeight() + ox, oy = x - (rw / 2), y - (rh / 2) + x = ox * math.cos(rotation) - oy * math.sin(rotation) + rw / 2; + y = oy * math.cos(rotation) + ox * math.sin(rotation) + rh / 2; + return x,y + + +set_led_state(True) +try: + if MOVE_HEXIPOSI: set_hexiposi("C") + ov_text.update("Click on the center of C4 (19) position...") + p.refresh() + pc4 = p.waitClick(60000) + print pc4 + if MOVE_HEXIPOSI: set_hexiposi("D") + ov_text.update("Click on the center of D5 (13) position...") + p.refresh() + pd5 = p.waitClick(60000) + print pd5 + if MOVE_HEXIPOSI: set_hexiposi("F") + ov_text.update("Click on the center of F4 (04) position...") + p.refresh() + pf4 = p.waitClick(60000) + print pf4 + if MOVE_HEXIPOSI: set_hexiposi("A") + ov_text.update("Click on the center of A5 (28) position...") + p.refresh() + pa5 = p.waitClick(60000) + print pa5 + + + vc1x, vc1y, vc2x, vc2y = (pc4.x + pd5.x )/2.0, (pc4.y + pd5.y )/2.0, (pa5.x + pf4.x )/2.0, (pa5.y + pf4.y )/2.0 + hc1x, hc1y, hc2x, hc2y = (pc4.x + pa5.x )/2.0, (pc4.y + pa5.y )/2.0, (pd5.x + pf4.x )/2.0, (pd5.y + pf4.y )/2.0 + cx, cy = (vc1x + vc2x)/2, (hc1y + hc2y)/2 + + a1 = math.degrees(math.atan((cx-vc1x)/(vc1y-cy))) + a2 = math.degrees(math.atan((cx-vc2x)/(vc2y-cy))) + a = (a1+a2)/2 + + + dy = math.hypot(vc2y - vc1y, vc2x - vc1x) + dx = math.hypot(hc2x - hc1x, hc2y - hc1y) + print dy, dx, cx, cy + sx, sy = DX/dx, DY/dy + + + #Rotating center of puck + rcx, rcy = rotate(cx, cy, -a) + + + + roi_w, roi_h = int(ROI_X / sx), int(ROI_Y / sy) + roi_x, roi_y = int(rcx-roi_w/2), int(rcy-roi_h/2) + + print a, sx, sy, roi_w, roi_h + + img.config.rotation=-a + ROTATION_OFFSET + img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight = roi_x, roi_y, roi_w, roi_h + img.config.setCalibration(Calibration(sx, sy, -roi_w/2, -roi_h/2)) + img.config.save() + + set_return ("Success calibrating the camera") + +finally: + set_led_state(False) + p.removeOverlay(ov_text) + img.refresh() + + \ No newline at end of file diff --git a/script/imgproc/CoverDetection.py b/script/imgproc/CoverDetection.py new file mode 100644 index 0000000..904837a --- /dev/null +++ b/script/imgproc/CoverDetection.py @@ -0,0 +1,98 @@ +################################################################################################### +# Procedure to detect the cover orientation +################################################################################################### +assert_imaging_enabled() + + +#Parameters +FRAMES_INTEGRATION = 3 +STEP_SIZE = 2 +POSITION_NAMES = [ 'A','B','C','D', 'E', 'F'] + +#POSITION_ANGLES = [ 330, 30, 90, 150, 210, 270 ] +POSITION_ANGLES = [ 0, 60, 120, 180, 240, 300 ] +POSITION_TOLERANCE = 3 +MINIMUM_CONFIDENCE = 3 +DEBUG = cover_detection_debug +#REFERENCE_IMG = "ref2" +REFERENCE_IMG = "ref1" +BORDER = 7 + +#Load reference image +ref = load_image(str("{images}/cover/" + REFERENCE_IMG + ".png") , title="Line") + +#Pre-process camera image +#ip = load_image("{images}/cover/Cover_000" + str(index) + ".png", title="Img") +ip = integrate_frames(FRAMES_INTEGRATION) +ip = grayscale(ip, True) +smooth(ip) +#bandpass_filter(ip, 30, 1000) +edges(ip) +auto_threshold(ip, method = "MaxEntropy") +#binary_erode(ip, True) +#binary_dilate(ip, True) +ip.getProcessor().erode(1, 255) +cx,cy = int(ip.width/2), int(ip.height/2) +ip = sub_image(ip, cx-ref.width/2, cy-ref.height/2, ref.width, ref.height) + +if BORDER>0: + sip = sub_image(ip, BORDER,BORDER, ref.width-2*BORDER, ref.height-2*BORDER) + ip = pad_image(sip, BORDER, BORDER, BORDER, BORDER, fill_color=Color.WHITE) + +#Show ROI of pre-processed image +if DEBUG: + image_panel = show_panel(ip.bufferedImage) + + +#Calculate correlation between image and reference, rotating the reference from 0 to 360 +import ch.psi.pshell.imaging.Utils.integrateVertically as integrateVertically +ydata = [] +xdata = range (0,360,STEP_SIZE) +for i in xdata: + r = ref.duplicate() + r.getProcessor().setBackgroundValue(0.0) + r.getProcessor().rotate(float(i)) + op = op_fft(r, ip, "correlate") + bi = op.getBufferedImage() + p = integrateVertically(bi) + ydata.append(sum(p)) + + +#Calculate angle of the highest correlation, and confidence level +peaks = estimate_peak_indexes(ydata, xdata, (min(ydata) + max(ydata))/2, 25.0) +peaks_x = map(lambda x:xdata[x], peaks) +peaks_y = map(lambda x:ydata[x], peaks) +if len(peaks_x) > 1: + #remoce close peaks between 350 deg and 10 deg + if ((peaks_x[0]<10) and (peaks_x[1]>350)) or ((peaks_x[1]<10) and (peaks_x[0]>350)): + peaks.pop(1) + peaks_x.pop(1) + peaks_y.pop(1) + + +confidence = None if len(peaks_x)<2 else int(((float(peaks_y[0])/peaks_y[1])-1) * 1000) +angle = (None if len(peaks_x)==0 else peaks_x[0]) + +#From angle and confidence level estimate hexiposi position +position = None +if angle is not None: + for i in range(len(POSITION_NAMES)): + if abs(POSITION_ANGLES[i] - angle) <= POSITION_TOLERANCE: + position = POSITION_NAMES[i] + +#Plot the correlations values agains angle +if DEBUG: + plot(ydata, xdata=xdata) + +#Output results +if DEBUG: + print "Peaks", peaks + print "Peak indexes: " + str(peaks_x) + print "Peak values: " + str(peaks_y) + print "Angle: " , angle + print "Position: " , position + print "Confidence: " , confidence + +#Set return value +set_return ([position, angle, confidence]) + diff --git a/script/imgproc/CoverDetectionCalibration.py b/script/imgproc/CoverDetectionCalibration.py new file mode 100644 index 0000000..36f6a54 --- /dev/null +++ b/script/imgproc/CoverDetectionCalibration.py @@ -0,0 +1,40 @@ +#Parameters +FRAMES_INTEGRATION = 3 +MINIMUM_CONFIDENCE = 10 +DEBUG = cover_detection_debug +REFERENCE_IMG = "ref1" +ERODE_ITERATIONS = 2 + +#Load reference image +SIZE = [128,128] +BORDER = 7 + +hexiposi.move("A") +#Pre-process camera image +#ip = load_image("{images}/cover/Cover_000" + str(index) + ".png", title="Img") +ip = integrate_frames(FRAMES_INTEGRATION) +ip = grayscale(ip, True) +smooth(ip) +#bandpass_filter(ip, 30, 1000) +edges(ip) + +auto_threshold(ip, method = "MaxEntropy") +#binary_dilate(ip, True, 2) +for i in range(ERODE_ITERATIONS): + ip.getProcessor().erode(1, 255) + +cx,cy = int(ip.width/2), int(ip.height/2) +ip = sub_image(ip, cx-SIZE[0]/2, cy-SIZE[1]/2, SIZE[0], SIZE[1]) + +invert(ip) +ip = grayscale(ip, True) +#smooth(ip) + +if BORDER > 0: + sip = sub_image(ip, BORDER,BORDER, SIZE[0]-2*BORDER, SIZE[1]-2*BORDER) + ip = pad_image(sip, BORDER, BORDER, BORDER, BORDER) +if DEBUG: + image_panel = show_panel(ip.bufferedImage) + +save_image(ip, str("{images}/cover/" + REFERENCE_IMG + ".png") ,"png") + \ No newline at end of file diff --git a/script/imgproc/CreateMask.py b/script/imgproc/CreateMask.py new file mode 100644 index 0000000..98b3498 --- /dev/null +++ b/script/imgproc/CreateMask.py @@ -0,0 +1,29 @@ + +mask_img = new_image(img.getOutput().getWidth(), img.getOutput().getHeight(), image_type="byte", title = "mask_img", fill_color = Color.BLACK) + +mask_radius = 14 +mask_points = [] + + +def to_img_coords(absolute_coords): + return [img.getCalibration().convertToImageX(absolute_coords[0]), img.getCalibration().convertToImageY(absolute_coords[1])] + +for p in _puck_list: + mask_points.append(to_img_coords(p.led_mini)) + mask_points.append(to_img_coords(p.led_uni)) + + + +i = mask_img.getBufferedImage() +for p in mask_points: + #i.setRGB(p[0], p[1], 0xFFFFFF) + for x in range (p[0]-mask_radius, p[0]+mask_radius): + for y in range (p[1]-mask_radius, p[1]+mask_radius): + if math.hypot(x-p[0], y-p[1]) <= mask_radius: + i.setRGB(x,y, 0xFFFFFF) + + +mask_img = load_image(i) +#show_panel( mask_img.getBufferedImage()) + +set_return(mask_img) \ No newline at end of file diff --git a/script/imgproc/LedDetectionFilter.py b/script/imgproc/LedDetectionFilter.py new file mode 100644 index 0000000..a4818d8 --- /dev/null +++ b/script/imgproc/LedDetectionFilter.py @@ -0,0 +1,102 @@ +################################################################################################### +# Example of using ImageJ functionalities through ijutils. +################################################################################################### + +import datetime +from ijutils import * +import java.awt.Color as Color + +import ch.psi.pshell.imaging.Filter as Filter +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.pshell.imaging.Pen as Pen + + +integration_count = 10 +integration_continuous = False +integration_partial = False +frames = [] +roi = get_roi() + + +color_roi = Color(0, 128, 0) + +renderer = show_panel(img) +renderer.clearOverlays() +ov_roi_shape = Ellipse(Pen(color_roi, 0,), java.awt.Point(roi[0], roi[1]), java.awt.Dimension(roi[2], roi[3])) +ov_roi_bound = Rect(Pen(color_roi, 0, Pen.LineStyle.dotted), java.awt.Point(roi[0], roi[1]), java.awt.Dimension(roi[2], roi[3])) +ov_roi_center = Crosshairs(Pen(color_roi, 0), java.awt.Point(roi_center[0],roi_center[1]), java.awt.Dimension(15,15)) + +renderer.addOverlays([ov_roi_shape, ov_roi_bound,ov_roi_center]) + + + + +last_ret = (None, None) +def detect_led(ip): + roi = get_roi() + global roi_center, roi_radius, integration_count, integration_continuous, integration_partial, frames + global count , last_ret + aux = sub_image(ip, roi[0], roi[1], roi[2], roi[3]) + grayscale(aux) + #gaussian_blur(aux) + if (integration_count>1): + frames.append(aux) + if len(frames) >integration_count: + del frames[0] + if not integration_continuous: + if (len(frames)< integration_count): + if last_ret[1] is not None: invert(last_ret[1]) + return last_ret + if (not integration_partial) and len(frames) <integration_count: + return last_ret + aux = integrate(frames) + + #aux = get_channel(aux, "blue") + invert(aux) + #subtract_background(aux) + #Tested ok: Huang, Mean, MaxEntropy, Percentile, Triangle, Yen + auto_threshold(aux, method = "Percentile") + #binary_open(aux) + (results,output) = analyse_particles(aux, 250,1000, + fill_holes = True, exclude_edges = False, print_table=False, + output_image = "outlines", minCirc = 0.3 + , maxCirc = 1.0) + r=results + + + points = "" + npoints = 0 + for row in range (r.counter): + if in_roi(r.getValue("XM",row), r.getValue("YM",row)): + points = points + " (" + str(int(r.getValue("XM", row))+roi[0]) + ", " + str(int(r.getValue("YM", row))+roi[1]) + ")" + npoints = npoints + 1 + print str(npoints) + " - " + points + + last_ret = (results,output) + if not integration_continuous: + frames = [] + + #if npoints!=12: + # save_image(op_image(aux, output,"xor", in_place=False), "{images}/" + str(datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))+".png", "png") + #return (results,aux) + return (results,output) + + + + +ip = None + +class MyFilter(Filter): + def process(self, image, data): + global roi_center, roi_radius, ip + ip = load_image(image) + (results,output) = detect_led(ip) + if output is not None: + invert(output) + output = pad_image(output, roi[0], 0,roi[1], 0) + op_image(ip, output, "xor") + return ip.getBufferedImage() + +#Setting the filter to a source +img.setFilter(MyFilter()) + diff --git a/script/imgproc/LedDetectionProc.py b/script/imgproc/LedDetectionProc.py new file mode 100644 index 0000000..c01673d --- /dev/null +++ b/script/imgproc/LedDetectionProc.py @@ -0,0 +1,106 @@ +################################################################################################### +# Procedure to detect the puck light spots. +################################################################################################### +assert_imaging_enabled() + + +COVER_PRESENT = True +ROOM_TEMP = is_room_temp() +USE_MASK = True + +if get_exec_pars().source == CommandSource.ui: + PLOT = None + RENDERER = None + TEXT = None + +if COVER_PRESENT: + cover_position = hexiposi.readback.take() + if (cover_position is None) or (cover_position == "Unknown"): + raise Exception("Unknown cover position") + else: + block_id = cover_position.upper()[0] +else: + block_id = None +print "Block id: ", block_id + + + +number_frames = 5 if ROOM_TEMP else 10 +number_backgrounds = 5 if ROOM_TEMP else 5 +minimum_size = 78 # r = 5 # 150 +maximum_size = 750 # r = 15 #1500 +min_circ = 0.2 + +threshold_method = "MaxEntropy" if ROOM_TEMP else "Default" #Apparently good for LN2: Default, Intermodes, IsoData, Otsu +threshold_method,threshold_range = "Manual", (0, 215) + +exclude_edges = True +led_latency = 0.5 #0.1 + + + +set_led_state(False) +time.sleep(led_latency) +img.waitNext(2000) + +background = average_frames(number_backgrounds) +#background = integrate_frames(number_backgrounds) + +set_led_state(True) +time.sleep(led_latency) +img.waitNext(2000) +image = average_frames(number_frames) +#image = integrate_frames(number_frames) + +set_led_state(False) + +op_image(image, background, "subtract", float_result=True, in_place=True) +image=grayscale(image) + +if RENDERER is not None and RENDERER.isShowing(): + RENDERER.setImage(None, image.getBufferedImage(), None) +else: + RENDERER = show_panel(image.getBufferedImage()) +RENDERER.clearOverlays() + +if USE_MASK: + mask_img = run("imgproc/CreateMask") + #mask_img=grayscale(mask_img) + #show_panel( mask_img.getBufferedImage()) + op_image(image, mask_img, "and", float_result=False, in_place=True) + RENDERER.setImage(None, image.getBufferedImage(), None) + +invert(image) +if threshold_method == "Manual": + threshold(image, threshold_range[0], threshold_range[1]) +else: + auto_threshold(image, method = threshold_method) #Tested ok: MaxEntropy, Triangle, Yen +(r,output) = analyse_particles(image, minimum_size,maximum_size, + fill_holes = True, exclude_edges = exclude_edges, print_table=False, + output_image = "outlines", minCirc = min_circ + , maxCirc = 1.0) + +points = [] +for row in range (r.counter): + if in_roi(r.getValue("XM",row), r.getValue("YM",row)): + x, y = int(r.getValue("XM", row)), int(r.getValue("YM", row)) + cx, cy = img.getCalibration().convertToAbsoluteX(x), img.getCalibration().convertToAbsoluteY(y) + points.append([cx,cy]) + if RENDERER is not None: + RENDERER.addOverlay(Crosshairs(Pen(java.awt.Color.MAGENTA), java.awt.Point(x,y), java.awt.Dimension(15,15))) + + +clear_detection(block_id) +detect_pucks(points, block_id) +if PLOT is not None: + plot_base_plate(points, p=PLOT) + +ret = get_puck_detection_dict(block_id) + + +if TEXT is not None: + TEXT.setText(str(ret)) + + +set_return(ret) + diff --git a/script/imgproc/Utils.py b/script/imgproc/Utils.py new file mode 100644 index 0000000..addc508 --- /dev/null +++ b/script/imgproc/Utils.py @@ -0,0 +1,113 @@ + +################################################################################################### +# Image processing utilities +################################################################################################### + + +from ijutils import * +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.pshell.imaging.Pen as Pen +import java.awt.Rectangle as Rectangle + +def get_img_cover_pos(): + [position, angle, confidence] = run("imgproc/CoverDetection") + return position + +def assert_img_in_cover_pos(pos = None): + if pos==None: + pos = hexiposi.take() + elif type(pos) is int: + pos = chr( ord('A') + (pos-1)) + elif is_string(pos): + pos = pos.upper() + img_segment = get_img_cover_pos() + if img_segment != pos: + raise Exception ("Image detection of cover does not match position: " + str(img_segment)) + + +def in_roi(x,y): + global roi_center, roi_radius, roi_border + return math.hypot(x-roi_center[0], y-roi_center[1]) < (roi_radius-roi_border) + + +def integrate(ips): + roi = get_roi() + aux = None + for i in range(len(ips)): + if i==0: + aux = new_image(roi[2], roi[3], image_type="float", title = "sum", fill_color = None) + op_image(aux, ips[i], "add", float_result=True, in_place=True) + return aux + +def average (ips): + aux = integrate(ips) + op_const(aux, "divide", len(ips), in_place=True) + return aux + +def grab_frames(samples): + frames = [] + for i in range(samples): + aux = get_image() + frames.append(aux) + return frames + +def average_frames(samples = 1): + return average(grab_frames(samples)) + +def integrate_frames(samples = 1): + return integrate(grab_frames(samples)) + + +roi_center = (600, 600) #(800, 600) +roi_radius = 600 +roi_border = 30 + +def get_roi(): + #roi_center = (img.output.width/2, img.output.height/2) + #roi_radius = min(roi_center[0], roi_center[1]) + #return (roi_center[0] - roi_radius, roi_center[1] - roi_radius, 2* roi_radius, 2*roi_radius) + global roi_center, roi_radius + roi_center = (img.output.width/2, img.output.height/2) + roi_radius = min(roi_center[0], roi_center[1]) + return (0,0,img.output.width, img.output.height) + +def get_image(): + roi = get_roi() + #ip = load_image(img.output) + #ret = ip if (roi is None) else sub_image(ip, roi[0], roi[1], roi[2], roi[3]) + #grayscale(ret, do_scaling=True) + + ret = load_image(Utils.grayscale(img.output, Rectangle(roi[0], roi[1], roi[2], roi[3]) if (roi is not None) else None)) + return ret + +#def detect_pucks(ip): +# """ +# """ +# aux = grayscale(ip, in_place=False) +# threshold(aux,0,50) +# binary_fill_holes(aux) +# return analyse_particles(aux, 10000,50000, +# fill_holes = False, exclude_edges = True,print_table=True, +# output_image = "outlines", minCirc = 0.4, maxCirc = 1.0) +# +#def detect_samples(ip): +# """ +# """ +# aux = grayscale(ip, in_place=False) +# invert(aux) +# subtract_background(aux) +# auto_threshold(aux) +# binary_open(aux) +# return analyse_particles(aux, 250,1000, +# fill_holes = False, exclude_edges = True,print_table=True, + + +r,g,b = [0]*256,[0]*256,[0]*256 +b[0]=0xFF +b[1]=0xFF ; g[1] = 0x80; r[1] = 0x80 +outline_lut1 = (r,g,b) + +r,g,b = [0]*256,[0]*256,[0]*256 +g[0]=0x80;r[0]=0x80; +g[1]=0xFF ; r[1] = 0x80; b[1] = 0x80 +outline_lut2 = (r,g,b) diff --git a/script/local.groovy b/script/local.groovy new file mode 100644 index 0000000..6cd1527 --- /dev/null +++ b/script/local.groovy @@ -0,0 +1,3 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Deployment specific global definitions - executed after startup.groovy +/////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/script/local.js b/script/local.js new file mode 100644 index 0000000..17db863 --- /dev/null +++ b/script/local.js @@ -0,0 +1,4 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Deployment specific global definitions - executed after startup.js +/////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/script/local.py b/script/local.py new file mode 100644 index 0000000..30a8bb8 --- /dev/null +++ b/script/local.py @@ -0,0 +1,431 @@ +################################################################################################### +# Deployment specific global definitions - executed after startup.py +################################################################################################### +import traceback +from ch.psi.pshell.serial import TcpDevice +from ch.psi.pshell.modbus import ModbusTCP +import ch.psi.mxsc.Controller as Controller +import ch.psi.pshell.core.Nameable as Nameable +import ch.psi.utils.Chrono as Chrono +import ch.psi.mxsc.Controller as Controller + + + +run("setup/Layout") +run("data/reports") + + + + +################################################################################################### +# Configuration +################################################################################################### + +IMAGING_ENABLED_PREFERENCE = "imaging_enabled" +PUCK_TYPES_PREFERENCE = "puck_types" +BARCODE_READER_SCAN_PUCKS = "barcode_reader_scan_pucks" +ROOM_TEMPERATURE_ENABLED_PREFERENCE = "room_temperature_enabled" +BEAMLINE_STATUS_ENABLED_PREFERENCE = "beamline_status_enabled" +VALVE_CONTROL_ENABLED_PREFERENCE = "valve_control" + +def is_imaging_enabled(): + setting = get_setting(IMAGING_ENABLED_PREFERENCE) + return not (str(setting).lower() == 'false') + +def set_imaging_enabled(value): + set_setting(IMAGING_ENABLED_PREFERENCE, (True if value else False) ) + +def assert_imaging_enabled(): + if is_imaging_enabled() == False: + raise Exception ("Imaging is disabled") + +#"unipuck", "minispine" or "mixed" +def set_puck_types(value): + set_setting(PUCK_TYPES_PREFERENCE, True if value else False ) + +def get_puck_types(): + setting = get_setting(PUCK_TYPES_PREFERENCE) + if setting == "unipuck" or setting == "minispine": + return setting + return "mixed" + + +def is_barcode_reader_scan_pucks(): + setting = get_setting(BARCODE_READER_SCAN_PUCKS) + return False if setting is None else setting.lower() == "true" + +def set_barcode_reader_scan_pucks(value): + set_setting(BARCODE_READER_SCAN_PUCKS, True if value else False ) + +def is_valve_controlled(): + setting = get_setting(VALVE_CONTROL_ENABLED_PREFERENCE) + return False if setting is None else setting.lower() == "true" + +def set_valve_controlled(value): + set_setting(VALVE_CONTROL_ENABLED_PREFERENCE, True if value else False ) + +def reset_mounted_sample_position(): + set_setting("mounted_sample_position", None) + + +def get_puck_barcode_reader(): + if is_barcode_reader_scan_pucks(): + return barcode_reader + else: + return barcode_reader_puck + +#In order to apply current config +set_imaging_enabled(is_imaging_enabled()) +set_puck_types(get_puck_types()) +set_barcode_reader_scan_pucks(is_barcode_reader_scan_pucks()) +set_valve_controlled(is_valve_controlled()) + + +force_dry_mount_count = get_setting("force_dry_mount_count") +if force_dry_mount_count is None: + set_setting("force_dry_mount_count", 0) + +force_dry_timeout = get_setting("force_dry_timeout") +if force_dry_timeout is None: + set_setting("force_dry_timeout", 0) + + +cold_position_timeout = get_setting("cold_position_timeout") +if cold_position_timeout is None: + set_setting("cold_position_timeout", 0) + + +def is_room_temperature_enabled(): + setting = get_setting(ROOM_TEMPERATURE_ENABLED_PREFERENCE) + return str(setting).lower() == 'true' + +set_setting(ROOM_TEMPERATURE_ENABLED_PREFERENCE, is_room_temperature_enabled()) + + +def is_beamline_status_enabled(): + setting = get_setting(BEAMLINE_STATUS_ENABLED_PREFERENCE) + return str(setting).lower() == 'true' + +set_setting(BEAMLINE_STATUS_ENABLED_PREFERENCE, is_beamline_status_enabled()) + +################################################################################################### +# Scripted devices and pseudo-devices +################################################################################################### + +for script in ["devices/RobotSC", "devices/Wago", "devices/BarcodeReader", "devices/LaserDistance", \ + "devices/LedCtrl", "devices/SmartMagnet", "devices/HexiPosi", "devices/Gonio"]: + try: + run(script) + except: + print >> sys.stderr, traceback.format_exc() + +#if is_imaging_enabled(): +if get_device("img") is not None: + add_device(img.getContrast(), force = True) + add_device(img.getCamera(), force = True) + + +################################################################################################### +# Utility modules +################################################################################################### + +run("data/samples") +run("data/pucks") +run("motion/tools") +run("motion/mount") +run("motion/unmount") +run("motion/get_dewar") +run("motion/put_dewar") +run("motion/get_gonio") +run("motion/put_gonio") +run("motion/move_dewar") +run("motion/move_gonio") +run("motion/move_heater") +run("motion/move_home") +run("motion/move_park") +run("motion/move_cold") +run("motion/move_scanner") +run("motion/move_aux") +run("motion/get_aux") +run("motion/put_aux") +run("motion/dry") +run("motion/trash") +run("motion/homing_hexiposi") +run("motion/calibrate_tool") +run("motion/scan_pin") +run("motion/robot_recover") +run("motion/recover") +run("tools/Math") +if is_imaging_enabled(): + run("imgproc/Utils") + +def system_check(robot_move=True): + if not air_pressure_ok.read(): + raise Exception("Air pressure is not ok") + if not n2_pressure_ok.read(): + raise Exception("N2 pressure is not ok") + hexiposi.assert_in_known_position() + + if robot_move: + if not feedback_local_safety.read(): + raise Exception("Local safety not released") + auto = not is_manual_mode() + if auto: + if not feedback_psys_safety.read(): + raise Exception("Psys safety not released") + if not guiding_tool_park.read(): + raise Exception("Guiding tool not parked") + +def system_check_msg(): + try: + system_check(True) + return "Ok" + except: + return sys.exc_info()[1] + +def get_puck_dev(segment, puck): + if type(segment) is int: + segment = chr( ord('A') + (segment-1)) + + return Controller.getInstance().getPuck(str(segment).upper() + str(puck)) + +def get_puck_elect_detection(segment, puck): + return str(get_puck_dev(segment, puck).detection) + +def get_puck_img_detection(segment, puck): + return str(Controller.getInstance().getPuck(str(segment).upper() + str(puck)).imageDetection) + +def assert_puck_detected(segment, puck): + if (segment == AUX_SEGMENT) and (puck == 1): + return + if get_puck_elect_detection(segment, puck) != "Present": + raise Exception ("Puck " + str(segment).upper() + str(puck) + " not present") + + +def start_puck_detection(): + run("tools/RestartPuckDetection") + +def check_puck_detection(): + return run("tools/CheckPuckDetection") + +def stop_puck_detection(): + run("tools/StopPuckDetection") + + + +def get_detected_pucks(): + ret = [] + for i in range(30): + p = BasePlate.getPucks()[i] + if (str(p.getDetection()) == "Present"): + ret.append(str(p.getName())) + return ret + +def get_pucks_info(): + ret = [] + for i in range(30): + p = BasePlate.getPucks()[i] + name = p.getName() + det = str(p.getDetection()) + barcode = "" if p.getId() is None else p.getId() + + ret.append({"puckAddress": name, "puckState": det, "puckBarcode":barcode}) + return json.dumps(ret) + + +################################################################################################### +# Device initialization +################################################################################################### + +try: + set_heater(False) + set_air_stream(False) +except: + print >> sys.stderr, traceback.format_exc() + + +try: + release_local_safety.write(False) + release_psys_safety.write(False) +except: + print >> sys.stderr, traceback.format_exc() + +try: + hexiposi.polling=500 +except: + print >> sys.stderr, traceback.format_exc() + +try: + robot.setPolling(DEFAULT_ROBOT_POLLING) + robot.set_tool(TOOL_DEFAULT) + robot.set_frame(FRAME_DEFAULT) + robot.set_motors_enabled(True) + robot.set_joint_motors_enabled(True) +except: + print >> sys.stderr, traceback.format_exc() + +if is_imaging_enabled(): + try: + import ch.psi.pshell.device.Camera as Camera + #img.camera.setColorMode(Camera.ColorMode.Mono) + #img.camera.setDataType(Camera.DataType.UInt8) + img.camera.setGrabMode(Camera.GrabMode.Continuous) + img.camera.setTriggerMode(Camera.TriggerMode.Fixed_Rate) + img.camera.setExposure(25.00) + img.camera.setAcquirePeriod(200.00) + img.camera.setGain(0.0) + #img.camera.setROI(200, 0,1200,1200) + """ + img.camera.setROI(300, 200,1000,1000) + img.config.rotation=17 + img.config.rotationCrop=True + img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight = 50,50,900,900 + """ + img.camera.setROI(int(get_setting("roi_x")), int(get_setting("roi_y")), int(get_setting("roi_w")), int(get_setting("roi_h"))) + + img.camera.stop() + img.camera.start() + except: + print >> sys.stderr, traceback.format_exc() + +#TODO: The Smart Magnet keeps moving sample if detecting is enabled +# Detection keeps disabled unless during moount/unmount +try: + smart_magnet.set_supress(True) +except: + print >> sys.stderr, traceback.format_exc() + +#gripper_cam.paused = True +################################################################################################### +# Device monitoring +################################################################################################### + +DEWAR_LEVEL_RT = 5.0 +is_room_temperature = False + +def is_room_temp(): + return is_room_temperature + + +class DewarLevelListener (DeviceListener): + def onValueChanged(self, device, value, former): + global is_room_temperature + if value is not None: + is_room_temperature = value <= DEWAR_LEVEL_RT +dewar_level_listener = DewarLevelListener() + +for l in dewar_level.listeners: + #if isinstance(l, DewarLevelListener): #Class changes... + if Nameable.getShortClassName(l.getClass()) == "DewarLevelListener": + dewar_level.removeListener(l) + +dewar_level.addListener(dewar_level_listener) +dewar_level_listener.onValueChanged(dewar_level, dewar_level.take(), None) + + + + +class HexiposiListener (DeviceListener): + def onValueChanging(self, device, value, former): + robot.assert_cleared() + +hexiposi_listener = HexiposiListener() +hexiposi.addListener(hexiposi_listener) + +################################################################################################### +# Global variables & application state +################################################################################################### + + +context = get_context() + +cover_detection_debug = False + +in_mount_position = False + + +def assert_mount_position(): + print "Source: ", get_exec_pars().source + if not in_mount_position and get_exec_pars().source == CommandSource.server : + raise Exception("Not in mount position") + + +def is_puck_loading(): + return robot.state == State.Ready and robot.take()["pos"] == 'pPark' and \ + feedback_psys_safety.take() == False and \ + not guiding_tool_park.read() + +def set_pin_offset(val): + if abs(val) >5: + raise Exception("Invalid pin offset: " + str(val)) + try: + set_setting("pin_offset",float(val)) + except: + log("Error setting pin offset: " + str(sys.exc_info()[1]), False) + +def get_pin_offset(): + try: + ret = float(get_setting("pin_offset")) + if abs(ret) >5: + raise Exception("Invalid configured pin offset: " + str(ret)) + return ret + except: + log("Error getting pin offset: " + str(sys.exc_info()[1]), False) + return 0.0 + + +def set_pin_angle_offset(val): + if (abs(val) > 180.0) or (abs(val) < -180.0): + raise Exception("Invalid pin angle offset: " + str(val)) + try: + set_setting("pin_angle_offset",float(val)) + except: + log("Error setting pin angle offset: " + str(sys.exc_info()[1]), False) + +def get_pin_angle_offset(): + try: + ret = float(get_setting("pin_angle_offset")) + if (abs(ret) > 180.0) or (abs(ret) < -180.0): + raise Exception("Invalid configured pin angle offset: " + str(ret)) + return ret + except: + log("Error getting pin angle offset: " + str(sys.exc_info()[1]), False) + return 0.0 + +def is_force_dry(): + try: + dry_mount_counter = int(get_setting("dry_mount_counter")) + except: + dry_mount_counter = 0 + + try: + dry_timespan = time.time() - float( get_setting("dry_timestamp")) + except: + dry_timespan = 3600 + + try: + force_dry_mount_count = int(get_setting("force_dry_mount_count")) + if force_dry_mount_count>0 and dry_mount_counter>=force_dry_mount_count: + return True + except: + pass + + try: + force_dry_timeout = float(get_setting("force_dry_timeout")) + if force_dry_timeout>0 and dry_timespan>=force_dry_timeout: + return True + except: + pass + return False + +def onPuckLoadingChange(puck_loading): + set_led_state(puck_loading) + #pass + +update() +add_device(Controller.getInstance().basePlate, True) +restore_samples_info() + + +print "Initialization complete" + \ No newline at end of file diff --git a/script/motion/calibrate_tool.py b/script/motion/calibrate_tool.py new file mode 100644 index 0000000..5357ef0 --- /dev/null +++ b/script/motion/calibrate_tool.py @@ -0,0 +1,32 @@ +def calibrate_tool(): + """ + """ + print "calibrate_tool" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + (detected, dm) = move_scanner() + + if detected: + print "Pin detected, trashing..." + trash() + (detected, dm) = move_scanner() + if detected: + raise Exception("Cannot trash pin") + + robot.open_tool() + robot.get_calibration_tool() + + run("calibration/ToolCalibration3") + + robot.put_calibration_tool() + + robot.save_program() diff --git a/script/motion/dry.py b/script/motion/dry.py new file mode 100644 index 0000000..b77d5dd --- /dev/null +++ b/script/motion/dry.py @@ -0,0 +1,58 @@ +DEFAULT_DRY_HEAT_TIME = 35.0 +DEFAULT_DRY_SPEED = 0.4 +DEFAULT_DRY_WAIT_COLD = 30.0 + +def dry(heat_time=None, speed=None, wait_cold = None): + """ + heat_time (float): in seconds + speed (float): % of nominal speed + wait_cold(float): if negative, move to dewar after drying + Else move to cold and wait (in seconds) before returning. + """ + print "dry" + + if heat_time is None: + heat_time = DEFAULT_DRY_HEAT_TIME + + if speed is None: + speed = DEFAULT_DRY_SPEED + + if wait_cold is None: + wait_cold = DEFAULT_DRY_WAIT_COLD + + if robot.simulated: + time.sleep(10.0) + return + + #Initial chec + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + set_status("Drying") + + #Enabling + enable_motion() + + try: + set_heater(True) + robot.move_heater(speed, False) + time.sleep(heat_time) + robot.move_heater(speed, True) + set_air_stream(True) + robot.move_heater(speed, False) + finally: + set_heater(False) + set_air_stream(False) + + + set_setting("dry_mount_counter", 0) + set_setting("dry_timestamp",time.time()) + + if wait_cold >=0 : + robot.move_cold() + time.sleep(wait_cold) + else: + robot.move_park() \ No newline at end of file diff --git a/script/motion/get_aux.py b/script/motion/get_aux.py new file mode 100644 index 0000000..67bfc7d --- /dev/null +++ b/script/motion/get_aux.py @@ -0,0 +1,21 @@ +def get_aux(sample): + """ + """ + print "get_aux: ",sample + + #Initial checks + assert_valid_sample(sample) + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + hexiposi.assert_homed() + + #Enabling + enable_motion() + + if not robot.is_aux(): + robot.move_aux() + + robot.get_aux(sample) diff --git a/script/motion/get_dewar.py b/script/motion/get_dewar.py new file mode 100644 index 0000000..d0559fc --- /dev/null +++ b/script/motion/get_dewar.py @@ -0,0 +1,30 @@ +def get_dewar(segment, puck, sample, force=False): + """ + """ + print "get_dewar: ", segment, puck, sample, force + + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + hexiposi.assert_homed() + #location = robot.get_current_point() + + + #Enabling + enable_motion() + + set_hexiposi(segment) + + if not force: + visual_check_hexiposi(segment) + + if not robot.is_dewar(): + robot.move_dewar() + + robot.get_dewar(segment, puck, sample) diff --git a/script/motion/get_gonio.py b/script/motion/get_gonio.py new file mode 100644 index 0000000..2123e2a --- /dev/null +++ b/script/motion/get_gonio.py @@ -0,0 +1,20 @@ +def get_gonio(force=False): + """ + """ + print "get_gonio: ", force + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_gonio(): + robot.move_gonio() + + robot.get_gonio() diff --git a/script/motion/homing_hexiposi.py b/script/motion/homing_hexiposi.py new file mode 100644 index 0000000..5c99f9e --- /dev/null +++ b/script/motion/homing_hexiposi.py @@ -0,0 +1,18 @@ +def homing_hexiposi(): + """ + """ + print "homing_hexiposi" + + #Initial checks + robot.assert_no_task() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + #location = robot.get_current_point() + + set_status("Homing hexiposi") + hexiposi.move_home() + hexiposi.waitState(State.Ready,-1) + hexiposi.move_pos(1) + + \ No newline at end of file diff --git a/script/motion/mount.py b/script/motion/mount.py new file mode 100644 index 0000000..035c7ab --- /dev/null +++ b/script/motion/mount.py @@ -0,0 +1,148 @@ +mount_sample_id = None +mount_sample_detected = None + +def mount(segment, puck, sample, force=False, read_dm=False, auto_unmount=False): + """ + """ + global mount_sample_id, mount_sample_detected + print "mount: ", segment, puck, sample, force + + start = time.time() + #time.sleep(2) + is_aux = (segment == AUX_SEGMENT) + + #ZACH + needs_chilling = not is_aux and (not robot.is_cold()) + needs_drying = is_aux and robot.is_cold() + + puck_address = get_puck_address(puck) + if puck_address is None: + puck_obj = get_puck_obj_by_id(puck) + if puck_obj is not None: + puck_address = puck_obj.name + if puck_address is not None: + print "puck address: ", puck_address + segment = puck_address[:1] + puck = int(puck_address[1:]) + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + + if robot.simulated: + time.sleep(3.0) + mount_sample_detected = True + mount_sample_id = "YYY0001" + update_samples_info_sample_mount(get_puck_name(segment, puck), sample, mount_sample_detected, mount_sample_id) + set_setting("mounted_sample_position", get_sample_name(segment, puck, sample)) + return [mount_sample_detected, mount_sample_id] + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + hexiposi.assert_homed() + assert_mount_position() + do_unmount = False + + try: + #ZACH + if needs_chilling: + robot.move_cold() + time.sleep(30.0) + + if smart_magnet.get_supress() == True: + smart_magnet.set_supress(False) + time.sleep(0.2) + #To better dectect sample + #smart_magnet.apply_reverse() + #smart_magnet.apply_resting() + #time.sleep(0.5) + + sample_det = smart_magnet.check_mounted(idle_time=0.25, timeout = 1.0) + Controller.getInstance().logEvent("Sample Detection", str(sample_det)) + if sample_det == True: + if auto_unmount and (get_setting("mounted_sample_position") is not None): + #auto_unmount set to true so detection remains enabled + unmount(force = True, auto_unmount = True) + do_unmount = True + else: + raise Exception("Pin detected on gonio") + set_status("Mounting: " + str(segment) + str(puck) + str(sample)) + Controller.getInstance().logEvent("Mount Sample", str(segment) + str(puck) + str(sample)) + #location = robot.get_current_point() + + #Enabling. If did unmount then it is already enabled. + if not do_unmount: + enable_motion() + + #ZACH + # a room temp pin is being mounted but the gripper is cold + if needs_drying: + dry(wait_cold=-1) # move to park after dry + + if is_aux: + if not robot.is_aux(): + robot.move_aux() + + robot.get_aux(sample) + + else: + set_hexiposi(segment) + + if not force: + visual_check_hexiposi(segment) + + if not robot.is_dewar(): + robot.move_dewar() + + robot.get_dewar(segment, puck, sample) + + + if read_dm: + barcode_reader.start_read(10.0) + robot.move_scanner() + #time.sleep(1.0) + + robot.move_gonio() + + if read_dm: + mount_sample_id = barcode_reader.get_readout() + print "Datamatrix: " , mount_sample_id + else: + mount_sample_id = None + + + robot.put_gonio() + + + try: + dry_mount_count = int(get_setting("dry_mount_counter")) + except: + dry_mount_count = 0 + set_setting("dry_mount_counter", dry_mount_count+1) + + if is_aux: + robot.move_home() + else: + robot.move_cold() + + mount_sample_detected = smart_magnet.check_mounted(idle_time=0.25, timeout = 1.0) + Controller.getInstance().logEvent("Sample Detection", str(mount_sample_detected)) + update_samples_info_sample_mount(get_puck_name(segment, puck), sample, mount_sample_detected, mount_sample_id) + if mount_sample_detected == False: + raise Exception("No pin detected on gonio") + + + if is_force_dry(): + smart_magnet.set_default_current() + print "Auto dry" + log("Starting auto dry", False) + set_exec_pars(then = "dry()") + + set_setting("mounted_sample_position", get_sample_name(segment, puck, sample)) + return [mount_sample_detected, mount_sample_id] + finally: + smart_magnet.set_default_current() + smart_magnet.set_supress(True) + diff --git a/script/motion/move_aux.py b/script/motion/move_aux.py new file mode 100644 index 0000000..94d6468 --- /dev/null +++ b/script/motion/move_aux.py @@ -0,0 +1,18 @@ +def move_aux(): + """ + """ + print "move_aux" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_aux(): + robot.move_aux() \ No newline at end of file diff --git a/script/motion/move_cold.py b/script/motion/move_cold.py new file mode 100644 index 0000000..89c8920 --- /dev/null +++ b/script/motion/move_cold.py @@ -0,0 +1,22 @@ +def move_cold(): + """ + """ + print "move_cold" + + if robot.simulated: + time.sleep(3.0) + return + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_cold(): + robot.move_cold() \ No newline at end of file diff --git a/script/motion/move_dewar.py b/script/motion/move_dewar.py new file mode 100644 index 0000000..3dfcbfe --- /dev/null +++ b/script/motion/move_dewar.py @@ -0,0 +1,18 @@ +def move_dewar(): + """ + """ + print "move_dewar" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_dewar(): + robot.move_dewar() \ No newline at end of file diff --git a/script/motion/move_gonio.py b/script/motion/move_gonio.py new file mode 100644 index 0000000..82397f9 --- /dev/null +++ b/script/motion/move_gonio.py @@ -0,0 +1,18 @@ +def move_gonio(): + """ + """ + print "move_gonio" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_gonio(): + robot.move_gonio() diff --git a/script/motion/move_heater.py b/script/motion/move_heater.py new file mode 100644 index 0000000..000e500 --- /dev/null +++ b/script/motion/move_heater.py @@ -0,0 +1,18 @@ +def move_heater(): + """ + """ + print "move_heater" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_heater(): + robot.move_heater() diff --git a/script/motion/move_home.py b/script/motion/move_home.py new file mode 100644 index 0000000..30592d6 --- /dev/null +++ b/script/motion/move_home.py @@ -0,0 +1,18 @@ +def move_home(): + """ + """ + print "move_home" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_home(): + robot.move_home() diff --git a/script/motion/move_park.py b/script/motion/move_park.py new file mode 100644 index 0000000..e1715c0 --- /dev/null +++ b/script/motion/move_park.py @@ -0,0 +1,18 @@ +def move_park(): + """ + """ + print "move_park" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_park(): + robot.move_park() \ No newline at end of file diff --git a/script/motion/move_scanner.py b/script/motion/move_scanner.py new file mode 100644 index 0000000..b8fe41f --- /dev/null +++ b/script/motion/move_scanner.py @@ -0,0 +1,30 @@ + +def move_scanner(): + """ + """ + print "move_scanner" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + barcode_reader.start_read(10.0) + if not robot.is_scanner(): + robot.move_scanner() + + time.sleep(0.25) + dm = barcode_reader.get_readout() + if dm is None: + detected = is_pin_detected_in_scanner() + else: + detected = True + + print ("Detected: " + str( detected) + " - Datamatrix: " + str(dm)) + + return (detected, dm) diff --git a/script/motion/put_aux.py b/script/motion/put_aux.py new file mode 100644 index 0000000..c41ee81 --- /dev/null +++ b/script/motion/put_aux.py @@ -0,0 +1,21 @@ +def put_aux(sample): + """ + """ + print "put_aux: ",sample + + #Initial checks + assert_valid_sample(sample) + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + hexiposi.assert_homed() + + #Enabling + enable_motion() + + if not robot.is_aux(): + robot.move_aux() + + robot.put_aux(sample) diff --git a/script/motion/put_dewar.py b/script/motion/put_dewar.py new file mode 100644 index 0000000..7d5c74d --- /dev/null +++ b/script/motion/put_dewar.py @@ -0,0 +1,30 @@ +def put_dewar(segment, puck, sample, force=False): + """ + """ + print "put_dewar: ", segment, puck, sample, force + + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + hexiposi.assert_homed() + + #Enabling + enable_motion() + + set_hexiposi(segment) + + if not force: + visual_check_hexiposi(segment) + + #location = robot.get_current_point() + + if not robot.is_dewar(): + robot.move_dewar() + + robot.put_dewar(segment, puck, sample) diff --git a/script/motion/put_gonio.py b/script/motion/put_gonio.py new file mode 100644 index 0000000..c23463f --- /dev/null +++ b/script/motion/put_gonio.py @@ -0,0 +1,23 @@ +def put_gonio(force=False): + """ + """ + print "put_gonio: ", force + + + if robot.simulated: + time.sleep(3.0) + return + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + if not robot.is_gonio(): + robot.move_gonio() + robot.put_gonio() diff --git a/script/motion/recover.py b/script/motion/recover.py new file mode 100644 index 0000000..984e2da --- /dev/null +++ b/script/motion/recover.py @@ -0,0 +1,180 @@ +import org.apache.commons.math3.geometry.euclidean.threed.Segment as Segment +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D as Vector3D +import org.apache.commons.math3.geometry.euclidean.threed.Line as Line3D + +RECOVER_DESC = "mRecovery" +RECOVER_TOOL = TOOL_DEFAULT + +known_segments = [ ("pGonioA", "pGonioG", 10), \ + ("pPark", "pScan", 40), \ + ("pHome", "pPark", 60), \ + ("pScan", "pHeater", 50), \ + ("pHome", "pDewar", 10), \ + ("pHeater", "pHeatB", 10), \ + ("pHome", "pAux", 50), \ + ("pScan", "pGonioA", 100), \ + ] + + +def get_robot_position(): + return robot.get_cartesian_pos() + + +def get_dist_to_line(segment): + tolerance = segment[2] + p1, p2 = robot.get_pnt(segment[0]), robot.get_pnt(segment[1]) + p = get_robot_position() + v = Vector3D(p[0], p[1], p[2]) + v1 = Vector3D(p1[0], p1[1], p1[2]) + v2 = Vector3D(p2[0], p2[1], p2[2]) + l = Line3D(v1, v2, 0.01) + return l.distance(v) + +def get_dist_to_segment(segment): + tolerance = segment[2] + p1, p2 = robot.get_pnt(segment[0]), robot.get_pnt(segment[1]) + p = get_robot_position() + v = Vector3D(p[0], p[1], p[2]) + v1 = Vector3D(p1[0], p1[1], p1[2]) + v2 = Vector3D(p2[0], p2[1], p2[2]) + l = Line3D(v1, v2, 0.01) + d = l.distance(v) + + pj = get_projection_at_line(segment) + + d1, d2 = v1.distance(v), v2.distance(v) + dp1, dp2 = v1.distance(pj), v2.distance(pj) + d12 = v1.distance(v2) + + + if (dp1 + dp2) > (d12 + tolerance): + d = max(d,min(d1,d2)) + return d + +def is_on_segment(segment): + tolerance = segment[2] + d = get_dist_to_segment(segment) + + if d > tolerance: + #print "Current robot position " + str(p) + " not on segment " + str(segment) + " - distance=" + str(d) + return False + #print "Current robot position " + str(p) + " on segment " + str(segment) + " - distance=" + str(d) + return True + +def get_projection_at_line(segment): + tolerance = segment[2] + p1, p2 = robot.get_pnt(segment[0]), robot.get_pnt(segment[1]) + p = get_robot_position() + v = Vector3D(p[0], p[1], p[2]) + v1 = Vector3D(p1[0], p1[1], p1[2]) + v2 = Vector3D(p2[0], p2[1], p2[2]) + l = Line3D(v1, v2, 0.01) + a = l.getAbscissa(v) + lv = l.pointAt(a) + return lv + + +def get_current_segment(): + for segment in known_segments: + if is_on_segment(segment): + return segment + return None + +def get_current_distance(): + for segment in known_segments: + if is_on_segment(segment): + return get_dist_to_segment(segment) + return None + + +def move_to_segment(segment): + tolerance = segment[2] + p = get_robot_position() + v = Vector3D(p[0], p[1], p[2]) + lv = get_projection_at_line(segment) + dlv = lv.distance(v) + if dlv> (tolerance + 0.1): + raise Exception( "Error moving from " + str(p) + " to segment - distance=" + str(dlv)) + d = [lv.x, lv.y, lv.z, p[3], p[4], p[5]] + print "Moving from " + str(p) + " to segment " + str(segment) + " - distance=" + str(dlv) + " - dest=" + str(d) + + try: + robot.movel(d, tool=RECOVER_TOOL, desc=RECOVER_DESC, sync=True) + print "Done" + except: + print sys.exc_info()[1] + +#Moves to first point of the segment ehich is safer, unless in the vicinity of the second +def move_to_safest_point(segment, vicinity_tolerance = 100): + d1, d2 = robot.get_distance_to_pnt(segment[0]), robot.get_distance_to_pnt(segment[1]) + #Always moving to primary point + if False : #(d2<=d1) and (d2 <= vicinity_tolerance): + print "Moving to secondary point " + str(segment[1] + " - d1=" + str(d1) + " d2=" + str(d2) ) + robot.movel(segment[1], tool=RECOVER_TOOL, desc=RECOVER_DESC, sync=True) + else: + print "Moving to primary point " + str(segment[0] + " - d1=" + str(d1) + " d2=" + str(d2) ) + robot.movel(segment[0], tool=RECOVER_TOOL, desc=RECOVER_DESC, sync=True) + print "Done" + #print "Recovered to point " + str(robot.get_curjoint_or_pointrent_point()) + +def is_in_dewar(): + z_hom = robot.get_pnt('pHome')[2] + z_cur=get_robot_position()[2] + if z_cur > (z_hom - 30): + return False + d_dwr = robot.get_distance_to_pnt('pDewar') + if d_dwr > 300: + return False + return True + + +def recover(move_park = True): + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + + if robot.get_current_point() is not None: + raise Exception("Robot is in known location") + + set_status("Recovering") + + #Enabling + enable_motion() + + + is_on_known_segment = False + for segment in known_segments: + if is_on_segment(segment): + #try: + # robot.set_monitor_speed(5) + is_on_known_segment = True + move_to_segment(segment) + move_to_safest_point(segment) + location = robot.get_current_point() + if location is None: + raise Exception("Robot didn't reach known point") + print "Success recovered to point: " + str(location) + if move_park: + robot.move_park() + return "Success recovering to park position" + else: + return "Success recovering to point: " + str(location) + #finally: + # robot.set_default_speed() + if not is_on_known_segment: + print ("Robot is not in known segment") + if is_in_dewar(): + robot.robot_recover() + if move_park: + robot.move_park() + return "Success recovering from dewar to park position" + else: + return "Success recovering from dewar" + else: + raise Exception("Robot is not in known segment nor inside the dewar") + + + + + \ No newline at end of file diff --git a/script/motion/robot_recover.py b/script/motion/robot_recover.py new file mode 100644 index 0000000..c25d712 --- /dev/null +++ b/script/motion/robot_recover.py @@ -0,0 +1,16 @@ +def robot_recover(): + """ + """ + print "robot_recover" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + + set_status("Recovering robot") + + #Enabling + enable_motion() + + robot.robot_recover() diff --git a/script/motion/scan_pin.py b/script/motion/scan_pin.py new file mode 100644 index 0000000..7683694 --- /dev/null +++ b/script/motion/scan_pin.py @@ -0,0 +1,94 @@ +def scan_pin(segment, puck, sample, force=False): + pin_name = get_sample_name(segment, puck, sample) + + print "scan pin", pin_name + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + is_aux = (segment == AUX_SEGMENT) + + if robot.simulated: + time.sleep(0.5) + return "Present" + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + + set_status("Scanning pin: " + str(pin_name)) + + enable_motion() + + if is_aux: + if not robot.is_aux(): + robot.move_aux() + + robot.get_aux(sample) + else: + set_hexiposi(segment) + if not force: + visual_check_hexiposi(segment) + + if not robot.is_dewar(): + robot.move_dewar() + + robot.get_dewar(segment, puck, sample) + + (detected, dm) = move_scanner() + update_samples_info_sample_scan(get_puck_name(segment, puck), sample, detected, dm) + + if is_aux: + robot.move_aux() + robot.put_aux( sample) + else: + robot.move_dewar() + robot.put_dewar(segment, puck, sample) + ret = "Empty" + if detected: + if (dm is None) or (len(dm.strip())==0): + ret = "Present" + else: + ret = str(dm) + return ret + + +def scan_puck(segment, puck, force=False): + if segment == AUX_SEGMENT: + raise Exception("Cannot scan auxiliary puck") + ret = [] + for i in range(16): + ret.append(scan_pin (segment, puck, i+1, force)) + return ret + + +def scan_gripper(): + print "scan gripper" + #Initial checks + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + + set_status("Scanning gripper") + + enable_motion() + + (detected, dm) = move_scanner() + + robot.move_home() + + ret = "Empty" + if detected: + if (dm is None) or (len(dm.strip())==0): + ret = "Present" + else: + ret = str(dm) + return ret diff --git a/script/motion/tools.py b/script/motion/tools.py new file mode 100644 index 0000000..58bb7fc --- /dev/null +++ b/script/motion/tools.py @@ -0,0 +1,180 @@ +POSITION_TOLERANCE = 50 + + +def is_manual_mode(): + """ + return if operating in local mode. TODO: should be based on IO, not on robot flag. + """ + return robot.working_mode == "manual" + +def release_safety(): + """ + Release sefety signals acording to working mode + """ + if air_pressure_ok.take() != True: + raise Exception("Cannot release safety: air preassure not ok") + if n2_pressure_ok.take() != True: + raise Exception("Cannot release safety: n2 pressure not ok") + auto = not is_manual_mode() + if auto: + if feedback_psys_safety.read() == False: + release_psys() + time.sleep(0.5) + if feedback_psys_safety.read() == False: + raise Exception("Cannot enable power: check doors") + + if feedback_local_safety.read() == False: + release_local() + time.sleep(0.5) + if feedback_local_safety.read() == False: + raise Exception("Cannot enable power: check sample changer emergency stop button") + +def enable_motion(): + """ + Check safety and enable arm power if in remote mode + """ + release_safety() + system_check(robot_move=True) + auto = not is_manual_mode() + if auto: + if not robot.state.isNormal(): + raise Exception("Cannot enable power: robot state is " + str(robot.state)) + robot.enable() + +def set_hexiposi(pos, force = False): + """ + Set the hexiposi position in remote mode, or wait for it to be set in manual mode + """ + robot.assert_cleared() + if force == False: + if hexiposi.position == pos: + return + + if is_manual_mode(): + set_status("Move Hexiposi to position " + str(pos) + " ...") + try: + hexiposi.waitInPosition(pos, -1) + finally: + set_status(None) + else: + hexiposi.move(pos) + +#Can be used if cover has following error (no checking readback) +def _set_hexiposi(pos): + hexiposi.moveAsync(pos) + time.sleep(1.0) + hexiposi.waitReady(-1) + + +def visual_check_hexiposi(segment): + if is_imaging_enabled(): + #if is_manual_mode(): ? + if hexiposi.moved: + #Clearing for image processing + if not robot.is_park(): + print "Moving robot to park to clear camera view..." + robot.move_park() + assert_img_in_cover_pos(segment) + hexiposi.moved = False + + + +def wait_end_of_move(): + robot.update() + while (not robot.settled) or (not robot.empty) or (not robot.isReady()) : + time.sleep(0.01) + + +def move_to_home(): + #robot.reset_motion("jHome") + robot.movej("pHome", robot.tool , DESC_SCAN) + wait_end_of_move() + +def move_to_laser(from_point = "pHome"): + robot.reset_motion() + tool = robot.tool + d = robot.get_distance_to_pnt("pLaser") + if d<0: + raise Exception ("Error calculating distance to laser: " + str(d)) + if d<POSITION_TOLERANCE: + print "FROM LASER" + robot.movel("pLaser", robot.tool, DESC_SCAN, sync = True) + return + d = robot.get_distance_to_pnt("pLaserHome") + if d<0: + raise Exception ("Error calculating distance to laser appro: " + str(d)) + if d<POSITION_TOLERANCE: + print "FROM APPRO" + robot.movel("pLaser", robot.tool, DESC_SCAN, sync = True) + return + + d = robot.get_distance_to_pnt(from_point) + if d<0: + raise Exception ("Error calculating distance to " + from_point + ": " + str(d)) + if d<POSITION_TOLERANCE: + print "FROM " + from_point + robot.movej("pLaserHome", robot.tool, DESC_DEFAULT) + robot.movel("pLaser", robot.tool, DESC_SCAN, sync = True) + return + raise Exception ("Must be in home position to start move to laser") + + +def update_tool(tool=None, x_offset=0.0, y_offset=0.0, z_offset=0.0): + #Updating tool: + t=robot.get_tool_trsf(tool) + t[0]=t[0] - x_offset + t[1]=t[1] - y_offset + t[2]=t[2] - z_offset + robot.set_tool_trsf(t, tool) + print "Updated " + (str(robot.tool) if (tool is None) else tool) + ": " + str(t) + robot.save_program() + + +def assert_valid_address(segment, puck, sample): + if (segment == AUX_SEGMENT) and (puck == 1): + return + if is_string(segment): + segment = ord(segment.upper()) - ord('A') +1 + if (segment<=0) or (segment >6): + raise Exception ("Invalid segment: " + str(segment)) + if (puck<=0) or (puck >5): + raise Exception ("Invalid puck: " + str(puck)) + if (sample<=0) or (sample >16): + raise Exception ("Invalid sample: " + str(sample)) + if get_puck_dev(segment, puck).isDisabled(): + raise Exception ("Puck is disabled") + +def assert_valid_sample(sample): + if (sample<=0) or (sample >16): + raise Exception ("Invalid sample: " + str(sample)) + +def get_puck_name(segment, puck): + try: + assert_valid_address(segment, puck, 1) + if type(segment) is int: + segment = chr( ord('A') + (segment-1)) + elif is_string(segment): + segment = segment.upper() + else: + return None + return segment + str(puck) + except: + return None + +def get_sample_name(segment, puck, sample): + puck_name = get_puck_name(segment, puck) + return None if (puck_name is None) else puck_name + str(sample) + + +def is_pin_detected_in_scanner(): + samples = [] + for i in range(10): + samples.append(laser_distance.read()) + time.sleep(0.05) + av = mean(samples) + for s in samples: + if s<=1: + return False + if abs(s-av) > 0.1: + return False + return True \ No newline at end of file diff --git a/script/motion/trash.py b/script/motion/trash.py new file mode 100644 index 0000000..8b37f2c --- /dev/null +++ b/script/motion/trash.py @@ -0,0 +1,36 @@ +def trash(): + """ + """ + print "trash" + + if robot.simulated: + time.sleep(3.0) + return + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + robot.move_heater(to_bottom = False) + robot.move_heater(to_bottom = True) + + try: + for i in range(3): + robot.open_tool() + time.sleep(0.5) + robot.close_tool() + time.sleep(0.5) + finally: + robot.open_tool() + + + robot.move_heater(to_bottom = False) + robot.move_cold() + + \ No newline at end of file diff --git a/script/motion/unmount.py b/script/motion/unmount.py new file mode 100644 index 0000000..0054479 --- /dev/null +++ b/script/motion/unmount.py @@ -0,0 +1,103 @@ +def unmount(segment = None, puck = None, sample = None, force=False, auto_unmount = False): + """ + """ + print "unmount: ", segment, puck, sample, force + + #ZACH + is_aux = (segment == AUX_SEGMENT) + needs_chilling = not is_aux and (not robot.is_cold()) + needs_drying = is_aux and robot.is_cold() + + if (segment is None) or (puck is None) or (sample is None): + pos = get_setting("mounted_sample_position") + if pos is None: + raise Exception("Mounted sample position is not defined") + segment, puck , sample = pos[0:1], int(pos[1]), int(pos[2:]) + print "Mounted sample position: ", segment, puck , sample + + + #Initial checks + if not auto_unmount: + print "assert valid address" + assert_valid_address(segment, puck, sample) + print "asser puck detected" + assert_puck_detected(segment, puck) + + if robot.simulated: + time.sleep(3.0) + update_samples_info_sample_unmount(get_puck_name(segment, puck), sample) + set_setting("mounted_sample_position", None) + return + + print "assert no task" + robot.assert_no_task() + print "reset motion" + robot.reset_motion() + print "wait ready" + robot.wait_ready() + print "assert cleared" + robot.assert_cleared() + #robot.assert_in_known_point() + print "assert homed" + hexiposi.assert_homed() + print "assert mount pos" + assert_mount_position() + + set_status("Unmounting: " + str(segment) + str(puck) + str(sample)) + Controller.getInstance().logEvent("Unmount Sample", str(segment) + str(puck) + str(sample)) + + try: + if smart_magnet.get_supress() == True: + smart_magnet.set_supress(False) + time.sleep(0.2) + + #smart_magnet.apply_reverse() + #smart_magnet.apply_resting() + + if not force: + sample_det = smart_magnet.check_mounted(idle_time=0.5, timeout = 3.0) + Controller.getInstance().logEvent("Sample Detection", str(sample_det)) + if sample_det == False: + raise Exception("No pin detected on gonio") + + #Enabling + enable_motion() + + if not is_aux: + set_hexiposi(segment) + + if not force: + visual_check_hexiposi(segment) + if needs_chilling: + robot.move_cold() + time.sleep(30.) + else: + if needs_drying: + dry(wait_cold=-1) + #location = robot.get_current_point() + + if not robot.is_gonio(): + robot.move_gonio() + + #smart_magnet.set_unmount_current() + + robot.get_gonio() + + smart_magnet.apply_reverse() + smart_magnet.apply_resting() + mount_sample_detected = smart_magnet.check_mounted(idle_time=0.25, timeout = 1.0) + Controller.getInstance().logEvent("Sample Detection", str(mount_sample_detected)) + + if is_aux: + robot.move_aux() + robot.put_aux( sample) + else: + #TODO: Should check if smart magnet detection is off? + update_samples_info_sample_unmount(get_puck_name(segment, puck), sample) + robot.move_dewar() + robot.put_dewar(segment, puck, sample) + set_setting("mounted_sample_position", None) + finally: + if not auto_unmount: + smart_magnet.set_default_current() + smart_magnet.set_supress(True) diff --git a/script/setup/ExposureScan.py b/script/setup/ExposureScan.py new file mode 100644 index 0000000..7a1d438 --- /dev/null +++ b/script/setup/ExposureScan.py @@ -0,0 +1,33 @@ +import java.awt.Rectangle as Rectangle + +import ch.psi.pshell.imaging.Data as Data +class Exposure(Writable): + def write(self,pos): + #cam.setExposure(pos) + img.camera.setExposure(pos) +exposure=Exposure() + + +class Contrast(Readable): + def read(self): + data = img.getData() + #roi = Data(data.getRectSelection(500,300,700,600), False) + #return data.getGradientVariance(False, Rectangle(480,0,600,670)) + return data.getGradientVariance(False, None) +contrast=Contrast() + + +#a= lscan(exposure,img.getContrast(), 0.5, 1.0, 0.01, 0.5) +#a= lscan(exposure,contrast, 0.2, 0.4, 0.01, 0.7) +ret= lscan(exposure,contrast, 10.0, 150.0, 5.0, 0.5) +y, x = ret.getReadable(0), ret.getPositions(0) + +#(n, m, s) = fit(a.getReadable(0), xdata=a.getPositions(0)) +#if m is None: +# m=max(a.getReadable(0)) +m=x[y.index(max(y))] +p=get_plots()[0] +p.addMarker(m, p.AxisId.X, str(m), Color.RED) + +print "Setting exposure = ", m +exposure.write(m) diff --git a/script/setup/Layout.py b/script/setup/Layout.py new file mode 100644 index 0000000..5c584f4 --- /dev/null +++ b/script/setup/Layout.py @@ -0,0 +1,292 @@ +################################################################################################### +#DEFINITIONS +################################################################################################### + +PLATE_SIZE = 480 +BLOCK_ROI_TOLERANCE = 12 #mm +LED_TOLERANCE = 8 #mm Distance between LEDs = 18mm +PUCK_SIZE = 65 + +DET_UNIPUCK = "unipuck" +DET_MINISPINE = "minispine" +DET_ERROR = "error" +DET_EMPTY = "empty" +DET_UNKNOWN = "unknown" + +BLOCKS = ('A', 'B', 'C', 'D', 'E', 'F') + +#Layout table +puck_layout = ( + #Num Elm A0 Index A1 Uni Mini Center Angle Xuni Yuni Xmini=Xc Ymini==Yc + (1 , 'A', 0 , 1, 0.00 , 57.00 , 75.00 , 66.00 , 0.00 , 0.00 , 57.00 , 0.00 , 75.00 ), + (2 , 'A', 0 , 2, 0.00 , 132.00, 150.00, 141.00, 0.00 , 0.00 , 132.00 , 0.00 , 150.00 ), + (3 , 'F', 0 , 5, 19.11, 180.40, 198.40, 189.40, 19.11 , 59.06 , 170.46 , 64.95 , 187.47 ), + (4 , 'F', 0 , 4, 40.89, 180.40, 198.40, 189.40, 40.89 , 118.09 , 136.38 , 129.87 , 149.98 ), + (5 , 'F', 0 , 3, 30.00, 111.90, 129.90, 120.90, 30.00 , 55.95 , 96.91 , 64.95 , 112.50 ), + (6 , 'F', 60 , 1, 0.00 , 57.00 , 75.00 , 66.00 , 60.00 , 49.36 , 28.50 , 64.95 , 37.50 ), + (7 , 'F', 60 , 2, 0.00 , 132.00, 150.00, 141.00, 60.00 , 114.32 , 66.00 , 129.90 , 75.00 ), + (8 , 'E', 60 , 5, 19.11, 180.40, 198.40, 189.40, 79.11 , 177.15 , 34.08 , 194.83 , 37.48 ), + (9 , 'E', 60 , 4, 40.89, 180.40, 198.40, 189.40, 100.89, 177.15 , -34.08 , 194.83 , -37.48 ), + (10, 'E', 60 , 3, 30.00, 111.90, 129.90, 120.90, 90.00 , 111.90 , 0.00 , 129.90 , 0.00 ), + (11, 'E', 120, 1, 0.00 , 57.00 , 75.00 , 66.00 , 120.00, 49.36 , -28.50 , 64.95 , -37.50 ), + (12, 'E', 120, 2, 0.00 , 132.00, 150.00, 141.00, 120.00, 114.32 , -66.00 , 129.90 , -75.00 ), + (13, 'D', 120, 5, 19.11, 180.40, 198.40, 189.40, 139.11, 118.09 , -136.38, 129.87 , -149.98), + (14, 'D', 120, 4, 40.89, 180.40, 198.40, 189.40, 160.89, 59.06 , -170.46, 64.95 , -187.47), + (15, 'D', 120, 3, 30.00, 111.90, 129.90, 120.90, 150.00, 55.95 , -96.91 , 64.95 , -112.50), + (16, 'D', 180, 1, 0.00 , 57.00 , 75.00 , 66.00 , 180.00, 0.00 , -57.00 , 0.00 , -75.00 ), + (17, 'D', 180, 2, 0.00 , 132.00, 150.00, 141.00, 180.00, 0.00 , -132.00, 0.00 , -150.00), + (18, 'C', 180, 5, 19.11, 180.40, 198.40, 189.40, 199.11, -59.06 , -170.46, -64.95 , -187.47), + (19, 'C', 180, 4, 40.89, 180.40, 198.40, 189.40, 220.89, -118.09, -136.38, -129.87, -149.98), + (20, 'C', 180, 3, 30.00, 111.90, 129.90, 120.90, 210.00, -55.95 , -96.91 , -64.95 , -112.50), + (21, 'C', 240, 1, 0.00 , 57.00 , 75.00 , 66.00 , 240.00, -49.36 , -28.50 , -64.95 , -37.50 ), + (22, 'C', 240, 2, 0.00 , 132.00, 150.00, 141.00, 240.00, -114.32, -66.00 , -129.90, -75.00 ), + (23, 'B', 240, 5, 19.11, 180.40, 198.40, 189.40, 259.11, -177.15, -34.08 , -194.83, -37.48 ), + (24, 'B', 240, 4, 40.89, 180.40, 198.40, 189.40, 280.89, -177.15, 34.08 , -194.83, 37.48 ), + (25, 'B', 240, 3, 30.00, 111.90, 129.90, 120.90, 270.00, -111.90, 0.00 , -129.90, 0.00 ), + (26, 'B', 300, 1, 0.00 , 57.00 , 75.00 , 66.00 , 300.00, -49.36 , 28.50 , -64.95 , 37.50 ), + (27, 'B', 300, 2, 0.00 , 132.00, 150.00, 141.00, 300.00, -114.32, 66.00 , -129.90, 75.00 ), + (28, 'A', 300, 5, 19.11, 180.40, 198.40, 189.40, 319.11, -118.09, 136.38 , -129.87, 149.98 ), + (29, 'A', 300, 4, 40.89, 180.40, 198.40, 189.40, 340.89, -59.06 , 170.46 , -64.95 , 187.47 ), + (30, 'A', 300, 3, 30.00, 111.90, 129.90, 120.90, 330.00, -55.95 , 96.91 , -64.95 , 112.5 ), + ) + +################################################################################################### +#Puck class +################################################################################################### +class Puck: + def __init__(self, id, block, index, angle, center, led_uni, led_mini): + self.id = id + self.block = block + self.index = index + self.angle = angle + self.center = center + self.led_uni = led_uni + self.led_mini = led_mini + self.detect = DET_UNKNOWN + + def __str__(self): + return "Number: " + str(self.id) + "\nBlock: " + str(self.block) + "\nIndex: " + str(self.index) + "\nAngle: " + str(self.angle) + \ + "\nCenter: " + str(self.center) + "\nLed Unipuck: " + str(self.led_uni) + "\nLed Minispine: " + str(self.led_mini) + + def get_name(self): + return str(self.block) + str(self.index) + + def match(self, x, y): + if math.hypot(x-self.led_uni[0], y-self.led_uni[1]) <= LED_TOLERANCE: + return DET_UNIPUCK + if math.hypot(x-self.led_mini[0], y-self.led_mini[1]) <= LED_TOLERANCE: + return DET_MINISPINE + return None + + + +_block_ids = [] +_puck_list = [] +_block_list = [] + +for p in(puck_layout): + puck = Puck(p[0], p[1], p[3], p[8], (p[11],p[12]), (p[9],p[10]), (p[11],p[12])) + _puck_list.append(puck) + if puck.block not in (_block_ids): + _block_ids.append(puck.block) + +def get_puck(id): + for p in _puck_list: + if id==p.id: + return p + return None + +def get_pucks(block = None): + ret = [] + for p in _puck_list: + if (block is None) or (block==p.block): + ret.append(p) + return ret + + +################################################################################################### +#Block class +################################################################################################### + +class Block: + def __init__(self, id, angle_range, x_range, y_range): + self.id = id + self.angle_range = angle_range + self.x_range = x_range + self.y_range = y_range + self.roi = (self.x_range[0] - BLOCK_ROI_TOLERANCE, self.y_range[0] - BLOCK_ROI_TOLERANCE, + self.x_range[1] + BLOCK_ROI_TOLERANCE, self.y_range[1] + BLOCK_ROI_TOLERANCE) + + def __str__(self): + return "Id: " + str(self.id) + "\nAngle: " + str(self.angle_range) + "\nX: " + str(self.x_range) + "\nY: " + str(self.y_range) + + +for id in _block_ids: + pucks = get_pucks(id) + angles, x, y = [], [], [] + for p in pucks: + angles.append(p.angle) + x.append(p.led_uni[0]) + x.append(p.led_mini[0]) + y.append(p.led_uni[1]) + y.append(p.led_mini[1]) + el = Block(id,(min(angles), max(angles)), (min(x), max(x)), (min(y), max(y))) + _block_list.append(el) + +def get_block(id): + for e in _block_list: + if id==e.id: + return e + return None + +def get_blocks(): + return _block_list + + + + +################################################################################################### +#Detection utilities +################################################################################################### + + +def _detect_puck(point_list, puck): + puck.detect = DET_ERROR + for point in point_list: + match = puck.match(point[0], point[1]) + if match is not None: + if match==DET_UNIPUCK: + puck.detect = DET_EMPTY if (puck.detect==DET_MINISPINE) else DET_UNIPUCK + elif match==DET_MINISPINE: + puck.detect = DET_EMPTY if (puck.detect==DET_UNIPUCK) else DET_MINISPINE + +def detect_pucks(point_list, id=None): + if (id is None) or (id in BLOCKS): + for puck in get_pucks(id): + _detect_puck(point_list, puck) + else: + puck = get_puck(int(id)) + print puck + _detect_puck(point_list, puck) + + +def clear_detection(block_id=None): + for puck in get_pucks(block_id): + puck.detect = DET_UNKNOWN + return get_puck_detection_dict(block_id) + + +def get_puck_detection(det_type, block_id=None): + ret = [] + for puck in get_pucks(block_id): + if puck.detect == det_type: + ret.append(puck) + return ret + +def get_unipucks(block_id=None): + return get_puck_detection(DET_UNIPUCK, block_id) + +def get_minispines(block_id=None): + return get_puck_detection(DET_MINISPINE, block_id) + +def get_empties(block_id=None): + return get_puck_detection(DET_EMPTY, block_id) + +def get_unknowns(block_id=None): + return get_puck_detection(DET_UNKNOWN, block_id) + +def get_det_errors(block_id=None): + return get_puck_detection(DET_ERROR, block_id) + +def get_puck_detection_dict(block_id): + ret = {} + pucks = [] + for puck in get_unipucks(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Unipuck"] = pucks + pucks = [] + for puck in get_minispines(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Minispine"] = pucks + pucks = [] + for puck in get_det_errors(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Error"] = pucks + pucks = [] + for puck in get_empties(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Empty"] = pucks + pucks = [] + for puck in get_unknowns(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Unknown"] = pucks + return ret + +################################################################################################### +#Plotting +################################################################################################### + +from plotutils import * + +def plot_base_plate(points = None, show_detect = True, title = None, p = None): + colors = (Color.RED, Color.BLUE, Color.MAGENTA, Color(128,0,128), Color(0,128,0), Color(255,128,0)) + if p is None: p = plot(None, title=title)[0] + p.getAxis(p.AxisId.Y).setInverted(True) + plot_circle(p, 0, 0, PLATE_SIZE/2, width = 0, color = Color.GRAY, name = "Plate") + plot_point(p, 0, 0, size = 10, color = Color.GRAY, name = "Center") + #p.setLegendVisible(True) + for block in get_blocks(): + (xmin, xmax) = block.x_range + (ymin, ymax) = block.y_range + (xmin, ymin, xmax, ymax ) = block.roi + index = get_blocks().index(block) + r = plot_rectangle(p, xmin, ymin, xmax, ymax, width =0, color=colors[index], name = block.id) + #In the first time the plot shows, it takes some time for the color to be assigned + #while r.color is None: + # time.sleep(0.001) + + if block.id in ('A', 'F'): + x, y = (xmin + xmax)/2, ymax + 5 + elif block.id in ('C', 'D'): + x, y = (xmin + xmax)/2, ymin - 5 + elif block.id == 'B': + x, y = xmax + 5, (ymin + ymax)/2 + elif block.id == 'E': + x, y = xmin - 5, (ymin + ymax)/2 + + p.addText(x,y, str(block.id), r.color) + + for puck in get_pucks(block.id): + (xu, yu) = puck.led_uni + (xm, ym) = puck.led_mini + plot_point(p, xu, yu, size = 3, color = r.color, name = str(puck.id)+"u") + plot_point(p, xm, ym, size = 7, color = r.color, name = str(puck.id)+"m") + plot_circle(p, xu, yu, LED_TOLERANCE, width = 0, color = r.color, name = str(puck.id)+"uc") + plot_circle(p, xm, ym, LED_TOLERANCE, width = 0, color = r.color, name = str(puck.id)+"mc") + p.addText((xu+xm)/2, (yu+ym)/2, str(puck.id), r.color) + c,w = Color.GRAY,0 + if show_detect: + if puck.detect == DET_UNIPUCK: + c,w = Color.BLACK,1 + elif puck.detect == DET_MINISPINE: + c,w = Color(150, 100, 50),1 + elif puck.detect == DET_ERROR: + c = Color(128,0,0) + plot_circle(p, xm, ym, PUCK_SIZE/2, width = w, color = c , name = str(puck.id)) + if points is not None: + for point in points: + c, w = Color.GRAY, 1 + for puck in get_pucks(): + match = puck.match(point[0], point[1]) + if match is not None: + w=2 + c = Color.DARK_GRAY if match == "minispine" else Color.BLACK + + + plot_cross(p,point[0], point[1], size = 12, width = w, color = c, name = "P"+ str(points.index(point))) + #plot_point(p,point[0], point[1], size = 5, color = Color.BLACK, name = "Pc"+ str(points.index(point))) diff --git a/script/tasks/ColdPositionTimeout.py b/script/tasks/ColdPositionTimeout.py new file mode 100644 index 0000000..b61e0a0 --- /dev/null +++ b/script/tasks/ColdPositionTimeout.py @@ -0,0 +1,23 @@ +cold_position_timeout = int(get_setting("cold_position_timeout")) +if cold_position_timeout > 0: + if robot.last_command_position == "cold": + if (time.time() - robot.last_command_timestamp) > cold_position_timeout: + if robot.is_cold(): + log("Detected cold position timeout", False) + if get_context().state == State.Ready: + if robot.state == State.Ready: + if feedback_psys_safety.take() == True: + #TODO: Chan + get_context().evalLine("dry(wait_cold = -1)") #Dry and park : use get_context().evalLine to change application state + else: + raise Exception("Cannot clear cold position: feedback_psys_safety = False ") + else: + raise Exception("Cannot clear cold position: robot state: " + str(robot.state)) + else: + raise Exception("Cannot clear cold position: system state: " + str(get_context().state)) + + + + + + \ No newline at end of file diff --git a/script/tasks/LedMonitoring.py b/script/tasks/LedMonitoring.py new file mode 100644 index 0000000..5182a77 --- /dev/null +++ b/script/tasks/LedMonitoring.py @@ -0,0 +1,26 @@ +DEWAR_LEVEL_LED = 25.0 + +try: + _level = dewar_level.read() +except: + log("Cannot read Dewar level", False) + _level = 0.0 + +try: + _led_room_temp = is_led_room_temp() +except: + log("Cannot get LED configuration", False) + _led_room_temp = False + +if _level <= DEWAR_LEVEL_LED: + if not _led_room_temp: + log_str="LED Monitoring: Setting LEDs to room temperature range" + log(log_str, False) + print (log_str) + set_led_range(room_temp = True) +else: + if _led_room_temp: + log_str="LED Monitoring: Setting LEDs to LN2 range" + log(log_str, False) + print (log_str) + set_led_range(room_temp = False) diff --git a/script/test/CameraCalibration.py b/script/test/CameraCalibration.py new file mode 100644 index 0000000..02e7d9d --- /dev/null +++ b/script/test/CameraCalibration.py @@ -0,0 +1,71 @@ +import ch.psi.pshell.device.Camera as Camera +import ch.psi.pshell.imaging.RendererMode as RendererMode +from ch.psi.pshell.imaging.Overlays import * + +""" +img.camera.setColorMode(Camera.ColorMode.Mono) +img.camera.setDataType(Camera.DataType.UInt8) +img.camera.setGrabMode(Camera.GrabMode.Continuous) +img.camera.setTriggerMode(Camera.TriggerMode.Fixed_Rate) +img.camera.setExposure(50.00) +img.camera.setAcquirePeriod(200.00) +img.camera.setGain(0.0) +img.config.rotationCrop=True + + +""" +#img.camera.setROI(200, 0,1200,1200) + +img.camera.setROI(0, 0,1600,1200) +img.config.rotation=0 +img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight =0,0,-1,-1 +img.config.setCalibration(None) +img.camera.stop() +img.camera.start() + +#img.camera.setROI(300, 200,1000,1000) +#img.config.rotation=17 +#img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight = 50,50,900,900 + +p = show_panel(img) +p.setMode(RendererMode.Fit) +ov_text = Text(Pen(java.awt.Color.GREEN.darker()), "", java.awt.Font("Verdana", java.awt.Font.PLAIN, 24), java.awt.Point(20,20)) +ov_text.setFixed(True) + + + +p.addOverlay(ov_text) +try: + ov_text.update("Click on upper reference...") + p1 = p.waitClick(60000) + print p1 + ov_text.update("Click on left reference...") + p2 = p.waitClick(60000) + print p2 + ov_text.update("Click on right reference...") + p3 = p.waitClick(60000) + print p3 + + x, y, z = p1.x+p1.y*1j, p2.x+p2.y*1j, p3.x+p3.y*1j + w = z-x + w /= y-x + c = (x-y)*(w-abs(w)**2)/2j/w.imag-x + cx, cy, r = -c.real, -c.imag, abs(c+x) + a = math.degrees(math.atan((cx-p1.x)/(p1.y-cy))) + + print cx, cy, r, a + + #img.camera.setROI(int((1600-cx)/2),int((1200-cy)/2),1000,1000) + img.camera.setROI(int(cx-r),int(cy-r),int(2*r),int(2*r)) + img.config.rotation=-a + #remove rotation border + d=int(r/11) + img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight =d,d, int(2*r-2*d), int(2*r-2*d) + #img.config.setCalibration(None) + img.camera.stop() + img.camera.start() + +finally: + p.removeOverlay(ov_text) + + \ No newline at end of file diff --git a/script/test/CoverDetection.py b/script/test/CoverDetection.py new file mode 100644 index 0000000..24a228b --- /dev/null +++ b/script/test/CoverDetection.py @@ -0,0 +1,116 @@ +################################################################################################### +# Procedure to detect the cover orientation +################################################################################################### +import ch.psi.pshell.imaging.Utils.integrateVertically as integrateVertically +img.backgroundEnabled=False + +REF = (0,96,125) + +line = load_image("{images}/line.png", title="Line") +#line = load_image("{images}/line360.png", title="Line") + +line.getProcessor().setBackgroundValue(0.0) + + +#ip = get_image() +ip = integrate_frames(10) +ip = grayscale(ip, True) + + +smooth(ip) +#bandpass_filter(ip, 30, 1000) +edges(ip) + +#invert(ip) +#auto_threshold(ip, method = "Default") + + +#auto_threshold(ip, method = "Li") +auto_threshold(ip, method = "MaxEntropy") + +""" +for m in AutoThresholder.getMethods(): + print m + aux = ip.duplicate() + auto_threshold(aux, method = m) + binary_fill_holes(aux, dark_background=False) + renderer = show_panel(aux.bufferedImage) + time.sleep(1.0) +""" +#binary_dilate(ip, dark_background=False) +#binary_fill_holes(ip, dark_background=False) +#binary_open(ip, dark_background=Tr) + +renderer = show_panel(ip.bufferedImage) + + + + + + + + +#line = sub_image(line, 325, 325, 512, 512) +#ip = sub_image(ip, 325, 325, 512, 512) +line = sub_image(line, 453, 453, 256, 256) +ip = sub_image(ip, 453, 453, 256, 256) +#op = op_fft(ip, line, "correlate") + + +renderer = show_panel(ip.bufferedImage) + +#renderer = show_panel(op.bufferedImage) +#line.show() +ydata = [] +xdata = range (0,180,1) +for i in xdata: + l = line.duplicate() + l.getProcessor().setBackgroundValue(0.0) + l.getProcessor().rotate(float(i)) + op = op_fft(ip, l, "correlate") + bi = op.getBufferedImage() + p = integrateVertically(bi) + ydata.append(sum(p)) + + #renderer = show_panel(op.bufferedImage) + #time.sleep(0.001) + +def moving_average(arr, n) : + ret = [] + for i in range(len(arr)): + ret.append(mean(arr[max(i-n,0):min(i+n,len(arr)-1)])) + return ret +av = moving_average(ydata, 1) + +p = plot(ydata, xdata=xdata)[0] + +p.addSeries(LinePlotSeries("Moving Average")) +p.getSeries(1).setData(xdata, av) + +peaks = estimate_peak_indexes(ydata, xdata, (min(ydata) + max(ydata))/2, 25.0) +left, right = min(peaks), max(peaks) +if xdata[left]<5 and xdata[right]>(xdata[-1]-5): + #del peaks[0 if ydata[right] > ydata[left] else -1] + peaks.remove(right if ydata[right] > ydata[left] else left) + +peaks = sorted(peaks[:3]) +peaks_x = map(lambda x:xdata[x], peaks) +peaks_y = map(lambda x:ydata[x], peaks) + +print "Peaks", peaks +print "Peak indexes: " + str(peaks_x) +print "Peak values: " + str(peaks_y) + + +for i in range(len(peaks)): + peak = xdata[peaks[i]] + p.addMarker(peak, None, "N="+str(round(peak,2)), Color(80,0,80)) + if ((peaks[i]>160) and (REF[i]<20)): + peaks[i] = peaks[i] - 180.0 + +print "Peaks x: " + str(peaks_x) + + +d = mean(arrabs(arrsub(REF, peaks_x))) + +print "Angle = ", d \ No newline at end of file diff --git a/script/test/PuckDetection.py b/script/test/PuckDetection.py new file mode 100644 index 0000000..003ef68 --- /dev/null +++ b/script/test/PuckDetection.py @@ -0,0 +1,24 @@ +################################################################################################### +# Example of using ImageJ functionalities through ijutils. +################################################################################################### + +from ijutils import * +import java.awt.Color as Color + + +#Image Loading +ip = load_image("{images}/test2.png", title="Image") + + +#Puck Detection +aux = grayscale(ip, in_place=False) +aux.show() +plot(get_histogram(aux)) + +subtract_background(aux) +threshold(aux,0,50); aux.repaintWindow() +binary_fill_holes(aux); aux.repaintWindow() +(results,output_img)=analyse_particles(aux, 10000,50000, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.0, maxCirc = 1.0) +output_img.show() \ No newline at end of file diff --git a/script/test/PuckDetectionTest.py b/script/test/PuckDetectionTest.py new file mode 100644 index 0000000..2995f9a --- /dev/null +++ b/script/test/PuckDetectionTest.py @@ -0,0 +1,11 @@ +import datetime +index = 0 +prefix = str(datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) + +while True: + suffix = "%04d - " % index + print (suffix), + run("imgproc/LedDetectionProc.py") + index=index+1 + save_image(image, "{images}/" +prefix + "_" + suffix +".png", "png") + \ No newline at end of file diff --git a/script/test/RobotCartesianScan.py b/script/test/RobotCartesianScan.py new file mode 100644 index 0000000..4a5225e --- /dev/null +++ b/script/test/RobotCartesianScan.py @@ -0,0 +1,28 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + +robot.enable() +move_to_laser() + +#robot.reset_motion("jLaser") + +#import ch.psi.pshell.device.Timestamp as Timestamp +#sensor = Timestamp() + +#ret = lscan(robot_z, sensor, -50.0, 0.0, 0.5, latency = 0, relative = True) +#ret = lscan(robot_x, sensor, -50.0, 0.0, 0.5, latency = 0, relative = True) + +robot.set_motors_enabled(True) +ret = lscan(robot_x, ue.readable, -1.5, 1.5, 0.1, latency = 0.01, relative = True) + +x,y = ret.getPositions(0), ret.getReadable(0) +y = [100.0-v for v in y] +(norm, mea, sigma) = fit(y, xdata=x) +print "Maximum at " + str(mea) + + + +robot.set_motors_enabled(True) +ret = lscan(robot_rz, ue.readable, 0.0, 40.0, 1.0, latency = 0.01, relative = True, range = "auto") + + diff --git a/script/test/SampleDataInput.py b/script/test/SampleDataInput.py new file mode 100644 index 0000000..1f00cd6 --- /dev/null +++ b/script/test/SampleDataInput.py @@ -0,0 +1,1861 @@ +USER_NAME = "My User" +DEWAR_NAME = "My Dewar" + +test_sample_data = [ \ + +#Puck A1 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "flat_Base_Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "flat_Base_Pin_2", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "regular_Base_Pin_1", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "regular_Base_Pin_2", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck B1 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + \"sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck B2 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck B3 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck B4 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "u"dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck C1 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck C2 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck D1 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck D2 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus""sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "u"dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ +# Puck D3 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ +# Puck D4 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + ] + + +set_samples_info(test_sample_data) \ No newline at end of file diff --git a/script/test/SampleDataInput_Dominik.py b/script/test/SampleDataInput_Dominik.py new file mode 100644 index 0000000..8ff4ae7 --- /dev/null +++ b/script/test/SampleDataInput_Dominik.py @@ -0,0 +1,1862 @@ +USER_NAME = "My User" +DEWAR_NAME = "My Dewar" + +test_sample_data = [ \ + #Puck A1 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "CA00CF1471", \ + "puckType": "unipuck", \ + "puckAddress": "",\ + "sampleName": "flat_Base_Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "CA00CF1471", \ + "puckType": "unipuck", \ + "puckAddress": "",\ + "sampleName": "flat_Base_Pin_2", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "CA00CF1471", \ + "puckType": "unipuck", \ + "puckAddress": "",\ + "sampleName": "regular_Base_Pin_1", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "CA00CF1471", \ + "puckType": "unipuck", \ + "puckAddress": "",\ + "sampleName": "regular_Base_Pin_2", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + # Puck B1 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck B2 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck B3 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck B4 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck C1 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck C2 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck D1 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck D2 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck D3 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck D4 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + ] +set_samples_info(test_sample_data) \ No newline at end of file diff --git a/script/test/SampleDetection.py b/script/test/SampleDetection.py new file mode 100644 index 0000000..4638b7a --- /dev/null +++ b/script/test/SampleDetection.py @@ -0,0 +1,23 @@ +################################################################################################### +# Example of using ImageJ functionalities through ijutils. +################################################################################################### + +from ijutils import * +import java.awt.Color as Color + +#Image Loading +ip = load_image("{images}/test2.png", title="Image") + +aux = grayscale(ip, in_place=False) +aux.show() + +invert(aux); aux.repaintWindow() +#gaussian_blur(aux); aux.repaintWindow() +subtract_background(aux); aux.repaintWindow() +auto_threshold(aux); aux.repaintWindow() +binary_open(aux); aux.repaintWindow() +#binary_fill_holes(aux); aux.repaintWindow() +(results,output_img)=analyse_particles(aux, 250,1000, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.7, maxCirc = 1.0) +output_img.show() diff --git a/script/test/TestAlign.py b/script/test/TestAlign.py new file mode 100644 index 0000000..0cbe1a7 --- /dev/null +++ b/script/test/TestAlign.py @@ -0,0 +1,9 @@ + +v = 2.0 +#while(true): +for i in range(100): + v = v * (-1.0) + robot_j4.initialize() + robot_j4.moveRel(v) + robot.align() + \ No newline at end of file diff --git a/script/test/TestBugPcAPI b/script/test/TestBugPcAPI new file mode 100644 index 0000000..5be0f3e --- /dev/null +++ b/script/test/TestBugPcAPI @@ -0,0 +1,4 @@ +while True: + img.initialize() + img.waitNext(10000) + time.sleep(2.0) \ No newline at end of file diff --git a/script/test/TestBugPcAPI.py b/script/test/TestBugPcAPI.py new file mode 100644 index 0000000..7a3d186 --- /dev/null +++ b/script/test/TestBugPcAPI.py @@ -0,0 +1,30 @@ +import ch.psi.pshell.prosilica.Prosilica as Prosilica +import ch.psi.pshell.device.Camera as Camera + + +add_device(Prosilica("img", 25001, "PacketSize=1522;PixelFormat=Mono8;BinningX=1;BinningY=1;RegionX=300;RegionY=200;Width=1000;Height=1000;MulticastEnable=Off"), True) + +img.camera.setGrabMode(Camera.GrabMode.Continuous) +img.camera.setTriggerMode(Camera.TriggerMode.Fixed_Rate) +img.camera.setExposure(50.00) +img.camera.setAcquirePeriod(200.00) +img.camera.setGain(0.0) +#img.camera.setROI(200, 0,1200,1200) +""" +img.camera.setROI(300, 200,1000,1000) +img.config.rotation=17 +img.config.rotationCrop=True +img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight = 50,50,900,900 +""" +img.camera.setROI(int(get_setting("roi_x")), int(get_setting("roi_y")), int(get_setting("roi_w")), int(get_setting("roi_h"))) + +img.camera.stop() +img.camera.start() + + +show_panel(img) +#while True: +# img.initialize() +# img.waitNext(1000) +# time.sleep(0.1) + diff --git a/script/test/TestBugPcAPI2.py b/script/test/TestBugPcAPI2.py new file mode 100644 index 0000000..5e92b37 --- /dev/null +++ b/script/test/TestBugPcAPI2.py @@ -0,0 +1,6 @@ +import ch.psi.pshell.imaging.MjpegSource as MjpegSource +MjpegSource2 = get_context().pluginManager.getDynamicClass("MjpegSource2") +add_device(MjpegSource("gripper_cam", "http://axis-accc8e9cc87b.psi.ch/axis-cgi/mjpg/video.cgi"), True) +#gripper_cam.polling=1000 +gripper_cam.monitored = True +show_panel(gripper_cam) \ No newline at end of file diff --git a/script/test/TestBugPcAPI3.py b/script/test/TestBugPcAPI3.py new file mode 100644 index 0000000..6acb775 --- /dev/null +++ b/script/test/TestBugPcAPI3.py @@ -0,0 +1,4 @@ +while True: + img.initialize() + img.waitNext(1000) + time.sleep(0.1) \ No newline at end of file diff --git a/script/test/TestCalib.py b/script/test/TestCalib.py new file mode 100644 index 0000000..2cc311b --- /dev/null +++ b/script/test/TestCalib.py @@ -0,0 +1,30 @@ + +print "calibrate_tool" + +#Initial checks +robot.assert_no_task() +robot.reset_motion() +robot.wait_ready() +robot.assert_cleared() +#robot.assert_in_known_point() + +#Enabling +enable_motion() + +(detected, dm) = move_scanner() + +if detected: + print "Pin detected, trashing..." + trash() + (detected, dm) = move_scanner() + if detected: + raise Exception("Cannot trash pin") + +robot.open_tool() +robot.get_calibration_tool() + +run("calibration/ToolCalibration3") + +robot.put_calibration_tool() + +robot.save_program() diff --git a/script/test/TestCameraStability1.py b/script/test/TestCameraStability1.py new file mode 100644 index 0000000..e4660e9 --- /dev/null +++ b/script/test/TestCameraStability1.py @@ -0,0 +1,11 @@ +for i in range(10): + time.sleep(2) + move_home() + time.sleep(1) + move_park() + start = time.time() + while get_img_cover_pos() != 'A': + print ".", + time.sleep(0.001) + print "Time = " , ( time.time() - start) + \ No newline at end of file diff --git a/script/test/TestCameraStability2.py b/script/test/TestCameraStability2.py new file mode 100644 index 0000000..c6ef878 --- /dev/null +++ b/script/test/TestCameraStability2.py @@ -0,0 +1,14 @@ +cover_detection_debug=True +while True: + for pos in ['A', 'B', 'C', 'D', 'E', 'F']: + print "Moving to ", pos + hexiposi.move(pos) + move_home() + move_park() + time.sleep(2.0) + ret = run("imgproc/CoverDetection") + det = ret[0] + print "Detected: ", det + if det != pos: + raise Exception("Position error") + diff --git a/script/test/TestCameraStability3.py b/script/test/TestCameraStability3.py new file mode 100644 index 0000000..bcf1327 --- /dev/null +++ b/script/test/TestCameraStability3.py @@ -0,0 +1,9 @@ +for i in range(10): + time.sleep(1) + move_home() + time.sleep(1) + move_park() + start = time.time() + time.sleep(1.0) + print run("imgproc/LedDetectionProc.py") + \ No newline at end of file diff --git a/script/test/TestCmdSynchronization.py b/script/test/TestCmdSynchronization.py new file mode 100644 index 0000000..098998d --- /dev/null +++ b/script/test/TestCmdSynchronization.py @@ -0,0 +1,32 @@ +import java.util.logging.Level + +def get_pos_str(): + return "point: " + str(robot.get_current_point()) + " - here: " + str(robot.here()) + " - herej: " + str(robot.herej()) + +enable_motion() + +get_context().setLogLevel(java.util.logging.Level.FINER) +try: + while True: + #robot.move_dewar() + #robot.move_park() + + log("Moving dewar", False) + flag = robot.start_task('moveDewar') + print "moveDewar: ", flag + log("Waiting", False) + ret = robot.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + log("Moving dewar finished (" + str(ret) + ") - pos: " + get_pos_str(), False) + robot.assert_dewar() + + + log("Moving park", False) + flag = robot.start_task('movePark') + print "movePark: ", flag + log("Waiting", False) + ret = robot.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + log("Moving park finished (" + str(ret) + ") - pos: " + get_pos_str(), False) + robot.assert_park() + +finally: + get_context().setLogLevel(java.util.logging.Level.INFO) \ No newline at end of file diff --git a/script/test/TestCoverDetection.py b/script/test/TestCoverDetection.py new file mode 100644 index 0000000..e21e2c0 --- /dev/null +++ b/script/test/TestCoverDetection.py @@ -0,0 +1,19 @@ + +ca = [] +aa = [] +pa = [] + +#for i in range(6): + #index = i+1 +for i in ['A', 'B', 'C', 'D', 'E', 'F']: + hexiposi.move(i) + [position, angle, confidence] = run("imgproc/CoverDetection") + print [position, angle, confidence] + pa.append(position) + aa.append(angle) + ca.append(confidence) + +print "---" +print "Position: " ,pa +print "Angle: " ,aa +print "Confidence: " ,ca, " mean: ", mean(ca) \ No newline at end of file diff --git a/script/test/TestEuclidean.py b/script/test/TestEuclidean.py new file mode 100644 index 0000000..4376dc7 --- /dev/null +++ b/script/test/TestEuclidean.py @@ -0,0 +1,23 @@ +import org.apache.commons.math3.geometry.euclidean.threed.Segment as Segment +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D as Vector3D +import org.apache.commons.math3.geometry.euclidean.threed.Line as Line + + +p = Vector3D(0, 0, 3) + +p1 = Vector3D(0,0,0) +p2 = Vector3D(0,1,1 ) +tolerance = 0.001 + +l = Line(p1, p2, tolerance) + + +print l.distance(p) +print p1.distance(p) +print p2.distance(p) +print "---" + +print l.getAbscissa(p) +print l.pointAt(l.getAbscissa(p)) + +#print l.closestPoint(Line(p, p, 0.01)) \ No newline at end of file diff --git a/script/test/TestLaserScan.py b/script/test/TestLaserScan.py new file mode 100644 index 0000000..a977ba0 --- /dev/null +++ b/script/test/TestLaserScan.py @@ -0,0 +1,12 @@ +robot.set_motors_enabled(True) +steps_x = 10 +steps_y = 8 +#ret = ascan([robot_x, robot_z], ue.readable, [-10.0, -10.0], [10.0, 10.0], [10,10], latency = 0.01, relative = True , zigzag=True) +ret = ascan([robot_x, robot_z], ue.readable, [-10.0, -10.0], [10.0, 10.0], [steps_y,steps_x], latency = 0.01, relative = True , zigzag=False) +data = Convert.transpose(Convert.toBidimensional(to_array(ret.getReadable(0),'d'),steps_x+1,steps_y+1)) +plot(data, title="data") + +data = ret.getData(0) +plot(data, title="data2") + + diff --git a/script/test/TestLayout.py b/script/test/TestLayout.py new file mode 100644 index 0000000..7404a8e --- /dev/null +++ b/script/test/TestLayout.py @@ -0,0 +1,21 @@ + + + +points = [(100, 140), (130, 77), (120, 130), (110, 100)] +clear_detection() +detect_pucks(points) +#detect_pucks(points, 'A') +#detect_pucks(points, '4') +plot_base_plate(points) + + + +#plot_detected_leds(points) + + + +block_id = None +print get_unipucks(block_id) +print get_minispines(block_id) +print get_empties(block_id) +print get_det_errors(block_id) \ No newline at end of file diff --git a/script/test/TestMicrohawk.py b/script/test/TestMicrohawk.py new file mode 100644 index 0000000..0ea517e --- /dev/null +++ b/script/test/TestMicrohawk.py @@ -0,0 +1,10 @@ +import ch.psi.pshell.serial.TcpDevice as TcpDevice +import ch.psi.pshell.serial.UdpDevice as UdpDevice + + +microscan = TcpDevice("microscan", "MicroHAWK38C528:2001") +#microscan = UdpDevice("microscan", "MicroHAWK38C528:2001") +microscan.initialize() + + + diff --git a/script/test/TestRecover.py b/script/test/TestRecover.py new file mode 100644 index 0000000..340853f --- /dev/null +++ b/script/test/TestRecover.py @@ -0,0 +1,15 @@ +print "Pos=" + str(robot.get_cartesian_pos()) +for p in robot.get_known_points(): + print p + " = " + str(get_pnt(p)) + +print "-------------" + +for segment in known_segments: + is_on_segment(segment) + +print "-------------" +for segment in known_segments: + try: + move_to_segment(segment) + except: + print sys.exc_info()[1] \ No newline at end of file diff --git a/script/test/TestRelays.py b/script/test/TestRelays.py new file mode 100644 index 0000000..adcd828 --- /dev/null +++ b/script/test/TestRelays.py @@ -0,0 +1,12 @@ +for i in range(500): + relay1.write(True) + time.sleep(1.2) + relay1.write(False) + time.sleep(1.2) +""" +for i in range(5): + relays.write(to_array([True,]*16, 'z')) + time.sleep(0.2) + relays.write(to_array([False,]*16, 'z')) + time.sleep(0.2) +""" \ No newline at end of file diff --git a/script/test/TestRemoveBackground.py b/script/test/TestRemoveBackground.py new file mode 100644 index 0000000..7376f07 --- /dev/null +++ b/script/test/TestRemoveBackground.py @@ -0,0 +1,31 @@ +number_frames = 5 +number_backgrounds = 5 +minimum_size = 78 # r = 5 # 150 +maximum_size = 750 # r = 15 #1500 +min_circ = 0.2 + +threshold_method = "MaxEntropy" +threshold_method,threshold_range = "Manual", (0, 215) + +exclude_edges = True +led_latency = 0.5 #0.1 + +set_led_state(False) +time.sleep(led_latency) +img.waitNext(2000) + +background = average_frames(number_backgrounds) +#background = integrate_frames(number_backgrounds) + +set_led_state(True) +time.sleep(led_latency) +img.waitNext(2000) +image = average_frames(number_frames) +#image = integrate_frames(number_frames) + +set_led_state(False) + +op_image(image, background, "subtract", float_result=True, in_place=True) +image=grayscale(image) + +show_panel(image.getBufferedImage()) \ No newline at end of file diff --git a/script/test/TestRobot.py b/script/test/TestRobot.py new file mode 100644 index 0000000..d64599f --- /dev/null +++ b/script/test/TestRobot.py @@ -0,0 +1,41 @@ +robot.task_create("simulateEvents",3, name = "test", priority = 20) +print robot.get_task_status("test") +print robot.get_task_status("tests") + +robot.task_suspend("test") +print robot.get_task_status("test") +robot.task_resume("test") +print robot.get_task_status("test") + +robot.task_kill("test") +print robot.get_task_status("test") + + +print robot.is_powered() +print robot.get_monitor_speed() +#print robot.set_monitor_speed(20) +#print robot.enable() +print robot.disable() +print robot.is_calibrated() +print robot.read_working_mode() +print robot.get_emergency_stop_sts() +print robot.get_safety_fault_signal() +print robot.stop() +print robot.resume() +print robot.reset_motion() +print robot.is_empty() +print robot.is_settled() +print robot.get_move_id() +print robot.set_move_id(10) +print robot.get_joint_forces() +#print robot.open("gripper") +#print robot.close("gripper") +print robot.herej() +print robot.distance_t("t", "t") +print robot.distance_p("p", "p") +print robot.compose( "p", "world", "t") +print robot.here("gripper", "world") +print robot.joint_to_point("gripper", "world", "j") +print robot.point_to_joint("gripper", "j", "p") +print robot.position("p", "world") +print robot.mount(1, 2) diff --git a/script/test/TestRobot2.py b/script/test/TestRobot2.py new file mode 100644 index 0000000..68398b8 --- /dev/null +++ b/script/test/TestRobot2.py @@ -0,0 +1,72 @@ +import traceback + +robot.task_create("simulateEvents",3, name = "test", priority = 20) + +step = 0 +try: + while(True): + start = time.time() + step = 1 + robot.is_powered() + step = 2 + robot.get_task_status("test") + step = 3 + robot.get_monitor_speed() + step = 4 + #robot.set_monitor_speed(20) + #robot.enable() + step = 5 + #robot.disable() + step = 6 + robot.is_calibrated() + step = 7 + robot.read_working_mode() + step = 8 + robot.get_emergency_stop_sts() + step = 9 + robot.get_safety_fault_signal() + step = 10 + robot.stop() + step = 11 + robot.resume() + step = 12 + robot.reset_motion() + step = 13 + robot.is_empty() + step = 14 + robot.is_settled() + step = 15 + robot.get_move_id() + step = 16 + robot.set_move_id(10) + step = 17 + robot.get_joint_forces() + step = 18 + #robot.open_tool("gripper") + #robot.close_tool("gripper") + robot.herej() + step = 19 + robot.distance_t("t", "t") + step = 20 + robot.distance_p("p", "p") + step = 21 + robot.compose( "p", "world", "t") + step = 22 + robot.here("gripper", "world") + step = 23 + robot.joint_to_point("gripper", "world", "j") + step = 24 + robot.point_to_joint("gripper", "j", "p") + step = 25 + robot.position("p", "world") + step = 26 + robot.mount(1, 2) + #print time.time()-start +except: + print >> sys.stderr, traceback.format_exc() +finally: + print "Step: " + str(step) + try: + robot.task_kill("test") + except: + pass \ No newline at end of file diff --git a/script/test/TestRobotCmds.py b/script/test/TestRobotCmds.py new file mode 100644 index 0000000..4225281 --- /dev/null +++ b/script/test/TestRobotCmds.py @@ -0,0 +1,32 @@ + +import java.lang.System as System + +index = 0 +max_time = 0 +while True: + start = System.currentTimeMillis() + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + cur_time = System.currentTimeMillis() - start + max_time = max(cur_time, max_time) + print index, cur_time, max_time + index = index + 1 + \ No newline at end of file diff --git a/script/test/TestRobotCmds2.py b/script/test/TestRobotCmds2.py new file mode 100644 index 0000000..048e20e --- /dev/null +++ b/script/test/TestRobotCmds2.py @@ -0,0 +1,25 @@ +if robot_req.read() != 0: + raise Exception("Ongoing command") +if robot_ack.read() != 0: + raise Exception("Robot is not ready") +robot_cmd.write(1) +args = [0,0,0,0,0,0] + +robot_args.write(to_array(args, 'i')) + + +robot_req.write(1) +while robot_ack.read() == 0: + time.sleep(0.001) + +err = robot_ack.take() +if err == 1: + ret = robot_ret.read() + print ret +if err == 2: + print ("Invalid command: " + str(command)) +print ("Unknown error: " + str(err)) +robot_req.write(0) +while robot_ack.read() != 0: + time.sleep(0.001) + diff --git a/script/test/cycle_time b/script/test/cycle_time new file mode 100644 index 0000000..79c790e --- /dev/null +++ b/script/test/cycle_time @@ -0,0 +1,4 @@ +start =time.time() +unmount('A',2,5, force=True) +mount('A',2,5, force=True, read_dm=False) +print time.time()-start \ No newline at end of file diff --git a/script/test/imgtest.py b/script/test/imgtest.py new file mode 100644 index 0000000..de442c2 --- /dev/null +++ b/script/test/imgtest.py @@ -0,0 +1,47 @@ +################################################################################################### +# Example of using ImageJ functionalities through ijutils. +################################################################################################### + +from ijutils import * +import java.awt.Color as Color + +import ch.psi.pshell.imaging.Filter as Filter +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.pshell.imaging.Pen as Pen + + + +def detect_pucks(ip): + aux = grayscale(ip, in_place=False) + threshold(aux,0,50) + binary_fill_holes(aux) + return analyse_particles(aux, 10000,50000, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.4, maxCirc = 1.0) + +def detect_samples(ip): + aux = grayscale(ip, in_place=False) + invert(aux) + subtract_background(aux) + auto_threshold(aux) + binary_open(aux) + return analyse_particles(aux, 300,800, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.4 + , maxCirc = 1.0) + + +class MyFilter(Filter): + def process(self, image, data): + ip = load_image(image) + (results_puck,output_puck) = detect_pucks(ip) + (results_samples,output_samples) = detect_samples(ip) + set_lut(output_puck, outline_lut1[0], outline_lut1[1], outline_lut1[2]) + set_lut(output_samples, outline_lut2[0], outline_lut2[1], outline_lut2[2]) + op_image(ip, output_samples, "xor") + op_image(ip, output_puck, "xor") + return ip.getBufferedImage() + +#Setting the filter to a source +img.setFilter(MyFilter()) + diff --git a/script/test/ip b/script/test/ip new file mode 100644 index 0000000..e79bb62 --- /dev/null +++ b/script/test/ip @@ -0,0 +1,15 @@ +from ijutils import * +import java.awt.Color as Color + +ip = load_image(img.getImage()) +grayscale(ip) +#ip=binning(ip,2) +gaussian_blur(ip) +#bandpass_filter(ip,20, 100) +auto_threshold(ip) + +#Particle Analysis +(results,output_img)=analyse_particles(ip, 500,2000, print_table=True) +output_img.show() + +ip.show() \ No newline at end of file diff --git a/script/test/mount_profile.py b/script/test/mount_profile.py new file mode 100644 index 0000000..89ebd80 --- /dev/null +++ b/script/test/mount_profile.py @@ -0,0 +1,144 @@ +mount_sample_id = None +mount_sample_detected = None + +def mount(segment, puck, sample, force=False, read_dm=False, auto_unmount=False): + """ + """ + global mount_sample_id, mount_sample_detected + print "mount: ", segment, puck, sample, force + + start = time.time() + + #time.sleep(2) + is_aux = (segment == AUX_SEGMENT) + + #ZACH + needs_chilling = not is_aux and (not robot.is_cold()) + needs_drying = is_aux and robot.is_cold() + + puck_address = get_puck_address(puck) + if puck_address is None: + puck_obj = get_puck_obj_by_id(puck) + if puck_obj is not None: + puck_address = puck_obj.name + if puck_address is not None: + print "puck address: ", puck_address + segment = puck_address[:1] + puck = int(puck_address[1:]) + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + + if robot.simulated: + time.sleep(3.0) + mount_sample_detected = True + mount_sample_id = "YYY0001" + update_samples_info_sample_mount(get_puck_name(segment, puck), sample, mount_sample_detected, mount_sample_id) + set_setting("mounted_sample_position", get_sample_name(segment, puck, sample)) + return [mount_sample_detected, mount_sample_id] + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + hexiposi.assert_homed() + assert_mount_position() + + print "Pass 1: ", time.time() - start; start = time.time() + try: + #ZACH + if needs_chilling: + robot.move_cold() + time.sleep(30.0) + + if smart_magnet.get_supress() == True: + smart_magnet.set_supress(False) + time.sleep(0.2) + #To better dectect sample + smart_magnet.apply_resting() + time.sleep(0.5) + if smart_magnet.check_mounted(idle_time=0.25, timeout = 1.0) == True: + print "Pass 1b: ", time.time() - start; start = time.time() + if auto_unmount and (get_setting("mounted_sample_position") is not None): + #auto_unmount set to true so detection remains enabled + unmount(force = True, auto_unmount = True) + else: + raise Exception("Pin detected on gonio") + print "Pass 2: ", time.time() - start; start = time.time() + set_status("Mounting: " + str(segment) + str(puck) + str(sample)) + #location = robot.get_current_point() + + #Enabling + enable_motion() + + print "Pass 3: ", time.time() - start; start = time.time() + #ZACH + # a room temp pin is being mounted but the gripper is cold + if needs_drying: + dry(wait_cold=-1) # move to park after dry + + if is_aux: + if not robot.is_aux(): + robot.move_aux() + print "Pass 3b: ", time.time() - start; start = time.time() + robot.get_aux(sample) + + else: + set_hexiposi(segment) + print "Pass 4: ", time.time() - start; start = time.time() + if not force: + visual_check_hexiposi(segment) + + if not robot.is_dewar(): + robot.move_dewar() + print "Pass 4b: ", time.time() - start; start = time.time() + robot.get_dewar(segment, puck, sample) + print "Pass 5: ", time.time() - start; start = time.time() + + if read_dm: + barcode_reader.start_read(10.0) + robot.move_scanner() + #time.sleep(1.0) + + robot.move_gonio() + + if read_dm: + mount_sample_id = barcode_reader.get_readout() + print "Datamatrix: " , mount_sample_id + else: + mount_sample_id = None + print "Pass 6: ", time.time() - start; start = time.time() + + robot.put_gonio() + print "Pass 7: ", time.time() - start; start = time.time() + + try: + dry_mount_count = int(get_setting("dry_mount_counter")) + except: + dry_mount_count = 0 + set_setting("dry_mount_counter", dry_mount_count+1) + + if is_aux: + robot.move_home() + else: + robot.move_cold() + print "Pass 8: ", time.time() - start; start = time.time() + mount_sample_detected = smart_magnet.check_mounted(idle_time=0.25, timeout = 1.0) + update_samples_info_sample_mount(get_puck_name(segment, puck), sample, mount_sample_detected, mount_sample_id) + if mount_sample_detected == False: + raise Exception("No pin detected on gonio") + + + if is_force_dry(): + smart_magnet.set_default_current() + print "Auto dry" + log("Starting auto dry", False) + set_exec_pars(then = "dry()") + print "Pass 9: " , time.time() - start; start = time.time() + set_setting("mounted_sample_position", get_sample_name(segment, puck, sample)) + return [mount_sample_detected, mount_sample_id] + finally: + smart_magnet.set_default_current() + smart_magnet.set_supress(True) + diff --git a/script/test/onewire.py b/script/test/onewire.py new file mode 100644 index 0000000..5141067 --- /dev/null +++ b/script/test/onewire.py @@ -0,0 +1,122 @@ +import traceback + +class Detector(ReadonlyRegisterBase): + def __init__(self, name): + ReadonlyRegisterBase.__init__(self, name) + self.id = None + self.sn = None + self.status = None + self.type = None + self.set_inputs({}) + + def set_inputs(self, inputs): + self.inputs = inputs + self.setCache(inputs.values(), None) + if (len(self.take()) == 0): + self.setState(State.Offline) + else: + self.setState(State.Ready) + + def set_input(self, index, val): + self.inputs[index] = val + self.set_inputs(self.inputs) + +class Esera(TcpDevice): + def __init__(self, name, server, timeout = 1000, retries = 1): + TcpDevice.__init__(self, name, server) + self.setMode(self.Mode.FullDuplex) + self.detectors = [] + self.complete = False + + def start(self): + self.write("set,sys,run,1\n") + + def stop(self): + self.write("set,sys,run,0\n") + + def list(self): + self.write("get,owb,listall1\n") + + def req_data(self): + self.write("get,sys,data\n") + + def doInitialize(self): + super(Esera, self).doInitialize() + try: + self.setState(State.Ready) #So can communicate + #self.stop() + #time.sleep(0.1) + #self.flush() + self.detectors = [] + for i in range(30): + self.detectors.append(Detector("Detector " + str(i+1))) + self.list() + time.sleep(0.5) + self.start() + self.req_data() + except: + print >> sys.stderr, traceback.format_exc() + getLogger().log(traceback.format_exc()) + raise + + def doUpdate(self): + if not self.complete: + init = True + for det in self.detectors: + if det.id == None: + init = False + break + if init: + self.complete = True + self.start() + + self.req_data() + #def onByte(self, rx): + # print rx + + def onString(self, msg): + print msg + tokens = msg.split("|") + if len(tokens)>1: + try: + if msg[:3] == "LST": + #LST|1_OWD1|3AF361270000009E|S_0|DS2413| + if tokens[1] > 1: + index = int(tokens[1].split("_")[1][3:]) - 1 + if index < len(self.detectors): + det = self.detectors[index] + det.id = tokens[1] + det.sn= tokens[2] if len(tokens)>2 else None + det.status = int(tokens[3][2:]) if len(tokens)>3 else None + det.type = tokens[4] if len(tokens)>4 else None + if det.status!= 0: + det.set_inputs({}) + else: + for det in self.detectors: + if det.id is not None and msg.startswith(det.id): + det_id = int(tokens[0][len(det.id)+1:]) + det.set_input(det_id, int(tokens[1])) + except: + print >> sys.stderr, traceback.format_exc() + getLogger().log(traceback.format_exc()) + + + + +#count = 1 +#while (True): +# print onewire.waitString("\n", 1000)# +# +# print count +# count = count + 1 + + + + + + +add_device(Esera("onewire", "129.129.126.83:5000"), force = True) +onewire.setPolling(1000) +add_device(onewire.detectors[0], force = True) +add_device(onewire.detectors[1], force = True) +add_device(onewire.detectors[2], force = True) diff --git a/script/test/test.py b/script/test/test.py new file mode 100644 index 0000000..92fcaca --- /dev/null +++ b/script/test/test.py @@ -0,0 +1,24 @@ +from ijutils import * +import java.awt.Color as Color + + +#ip = load_array(img.getData().getMatrix()) +ip = load_image(img.getOutput()) +#ip = load_image("{images}/test3.png", title="Image") + + +aux = grayscale(ip, in_place=False) +aux.show() + +#convolve(aux, KERNEL_SOBEL); aux.repaintWindow() + +invert(aux); aux.repaintWindow() +subtract_background(aux); aux.repaintWindow() +auto_threshold(aux); aux.repaintWindow() +binary_open(aux); aux.repaintWindow() + +(table, image) = analyse_particles(aux, 250,1000, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.82, maxCirc = 1.0) + +image.show() \ No newline at end of file diff --git a/script/test/test_hexiposi.py b/script/test/test_hexiposi.py new file mode 100644 index 0000000..324a480 --- /dev/null +++ b/script/test/test_hexiposi.py @@ -0,0 +1,8 @@ +index = 1 +while(True): + for pos in ['A', 'B', 'C', 'D', 'E', 'F']: + hexiposi.move(pos) + visual_check_hexiposi(pos) + print "Ok: " + pos + print index + index = index + 1 \ No newline at end of file diff --git a/script/test/test_segments.py b/script/test/test_segments.py new file mode 100644 index 0000000..54a8898 --- /dev/null +++ b/script/test/test_segments.py @@ -0,0 +1,16 @@ +p=robot.get_cartesian_pos() +print "Pos: ", p +print "Cache pos:", robot.cartesian_pos +print "Cache dest: ", robot.cartesian_destination + + +print "Points: ", robot.get_current_points() +for segment in known_segments: + if is_on_segment(segment): + print " On : " + str(segment) + " - Dist:" + str(get_dist_to_segment(segment)) + + + +p2 = robot.get_cartesian_pos() +if arrsub( p2, p) != [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]: + print "Pos: ", p2 \ No newline at end of file diff --git a/script/test/test_swingutils.py b/script/test/test_swingutils.py new file mode 100644 index 0000000..65b354b --- /dev/null +++ b/script/test/test_swingutils.py @@ -0,0 +1,24 @@ +import ch.psi.pshell.imaging.RendererMode as RendererMode +import ch.psi.pshell.imaging.Calibration as Calibration +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.utils.swing.SwingUtils as SwingUtils +import javax.swing.SwingUtilities as SwingUtilities +from swingutils.threads.swing import callSwing + + +p = show_panel(img) +dlg = SwingUtilities.getWindowAncestor(p) +dlg.setSize(800,800) +frm=SwingUtils.getFrame(p) +dlg.setLocationRelativeTo(frm) + +def update_frame(frm): + SwingUtilities.updateComponentTreeUI(frm) + frm.validate() + frm.repaint() +#$callSwing(update_frame, frm) + + +x=0 +for i in range(0,10000000): + x=x+1 \ No newline at end of file diff --git a/script/test/then.py b/script/test/then.py new file mode 100644 index 0000000..fcbe1bb --- /dev/null +++ b/script/test/then.py @@ -0,0 +1,3 @@ +time.sleep(3.0) + +set_exec_pars(then = "time.sleep(5.0)") \ No newline at end of file diff --git a/script/test/transfer_profile.py b/script/test/transfer_profile.py new file mode 100644 index 0000000..00be4cb --- /dev/null +++ b/script/test/transfer_profile.py @@ -0,0 +1,23 @@ + + +measures = [] +#smart_magnet.measures = [] + + +for m in range(1): + print "Step ", m + start = time.time() + #mount('A',3,m+1, force=True, read_dm=False, auto_unmount=True) + #mount('A',5,m+1, force=True, read_dm=False, auto_unmount=True) + + #mount('A',3,1, force=True, read_dm=False, auto_unmount=True) + #unmount('A',3,1, force=True) + #mount('A',3,1, force=True, read_dm=False, auto_unmount=True) + measures.append( time.time()-start) + +print "Total transfer: ", measures +print "Time: ", mean(measures), "+-", stdev(measures) + + +#print "SM cehck: ", smart_magnet.measures +#print "Time: ", mean(smart_magnet.measures), "+-", stdev(smart_magnet.measures) \ No newline at end of file diff --git a/script/test/unmount_profile.py b/script/test/unmount_profile.py new file mode 100644 index 0000000..5adcdb3 --- /dev/null +++ b/script/test/unmount_profile.py @@ -0,0 +1,98 @@ +def unmount(segment = None, puck = None, sample = None, force=False, auto_unmount = False): + """ + """ + print "unmount: ", segment, puck, sample, force + start = time.time() + #ZACH + is_aux = (segment == AUX_SEGMENT) + needs_chilling = not is_aux and (not robot.is_cold()) + needs_drying = is_aux and robot.is_cold() + + if (segment is None) or (puck is None) or (sample is None): + pos = get_setting("mounted_sample_position") + if pos is None: + raise Exception("Mounted sample position is not defined") + segment, puck , sample = pos[0:1], int(pos[1]), int(pos[2:]) + print "Mounted sample position: ", segment, puck , sample + + #Initial checks + print "assert valid address" + assert_valid_address(segment, puck, sample) + print "asser puck detected" + assert_puck_detected(segment, puck) + + if robot.simulated: + time.sleep(3.0) + update_samples_info_sample_unmount(get_puck_name(segment, puck), sample) + set_setting("mounted_sample_position", None) + return + + print "assert no task" + robot.assert_no_task() + print "reset motion" + robot.reset_motion() + print "wait ready" + robot.wait_ready() + print "assert cleared" + robot.assert_cleared() + #robot.assert_in_known_point() + print "assert homed" + hexiposi.assert_homed() + print "assert mount pos" + assert_mount_position() + print "Pass A: " , time.time() - start; start = time.time() + set_status("Umounting: " + str(segment) + str(puck) + str(sample)) + + try: + if smart_magnet.get_supress() == True: + smart_magnet.set_supress(False) + time.sleep(0.2) + + smart_magnet.apply_resting() + + if not force: + if smart_magnet.check_mounted(idle_time=0.5, timeout = 3.0) == False: + raise Exception("No pin detected on gonio") + print "Pass B: " , time.time() - start; start = time.time() + #Enabling + enable_motion() + print "Pass C: " , time.time() - start; start = time.time() + + if not is_aux: + set_hexiposi(segment) + print "Pass D: " , time.time() - start; start = time.time() + if not force: + visual_check_hexiposi(segment) + if needs_chilling: + robot.move_cold() + time.sleep(30.) + else: + if needs_drying: + dry(wait_cold=-1) + #location = robot.get_current_point() + print "Pass E: " , time.time() - start; start = time.time() + if not robot.is_gonio(): + robot.move_gonio() + print "Pass F: " , time.time() - start; start = time.time() + #smart_magnet.set_unmount_current() + + robot.get_gonio() + print "Pass G: " , time.time() - start; start = time.time() + #smart_magnet.apply_reverse() + #smart_magnet.apply_resting() + + if is_aux: + robot.move_aux() + robot.put_aux( sample) + else: + #TODO: Shuld check if smart magnet detection is off? + update_samples_info_sample_unmount(get_puck_name(segment, puck), sample) + robot.move_dewar() + print "Pass H: " , time.time() - start; start = time.time() + robot.put_dewar(segment, puck, sample) + print "Pass I: " , time.time() - start; start = time.time() + set_setting("mounted_sample_position", None) + finally: + if not auto_unmount: + smart_magnet.set_default_current() + smart_magnet.set_supress(True) diff --git a/script/tools/CheckPuckDetection.py b/script/tools/CheckPuckDetection.py new file mode 100644 index 0000000..e39bae2 --- /dev/null +++ b/script/tools/CheckPuckDetection.py @@ -0,0 +1,6 @@ +USR,PWD = "pi", "raspberry" +HOST,PORT = "tell6s-raspberrypi", 22 +CMD= "sudo systemctl status puck_detection.service" + +ret = run("tools/SshExec") +set_return(ret) \ No newline at end of file diff --git a/script/tools/Math.py b/script/tools/Math.py new file mode 100644 index 0000000..c76ce33 --- /dev/null +++ b/script/tools/Math.py @@ -0,0 +1,68 @@ +################################################################################################### +# Math utilities +################################################################################################### + + +from mathutils import estimate_peak_indexes, fit_gaussians, create_fit_point_list, Gaussian +import java.awt.Color as Color + +import mathutils +mathutils.MAX_ITERATIONS = 100000 + +def fit(ydata, xdata = None, draw_plot = True): + if xdata is None: + xdata = frange(0, len(ydata), 1) + max_y= max(ydata) + index_max = ydata.index(max_y) + max_x= xdata[index_max] + #print "Max index:" + str(index_max), + #print " x:" + str(max_x), + #print " y:" + str(max_y) + + if draw_plot: + plots = plot([ydata],["data"],[xdata], title="Fit" ) + p = None if plots is None else plots[0] + + gaussians = fit_gaussians(ydata, xdata, [index_max,]) + if gaussians[0] is None: + if draw_plot and (p is not None): + p.addMarker(max_x, None, "Max="+str(round(max_x,4)), Color.GRAY) + print "Fitting error" + return (None, None, None) + + (norm, mean, sigma) = gaussians[0] + if draw_plot: + fitted_gaussian_function = Gaussian(norm, mean, sigma) + scale_x = [float(min(xdata)), float(max(xdata)) ] + points = max((len(xdata)+1), 100) + resolution = (scale_x[1]-scale_x[0]) / points + fit_y = [] + fit_x = frange(scale_x[0],scale_x[1],resolution, True) + for x in fit_x: + fit_y.append(fitted_gaussian_function.value(x)) + #Server + if p is None: + plot([ydata,fit_y],["data","fit"],[xdata,fit_x], title="Fit") + draw_plot = False + else: + p.addSeries(LinePlotSeries("fit")) + p.getSeries(1).setData(fit_x, fit_y) + + if abs(mean - xdata[index_max]) < abs((scale_x[0] + scale_x[1])/2): + if draw_plot: + p.addMarker(mean, None, "Mean="+str(round(mean,4)), Color.MAGENTA.darker()) + #print "Mean -> " + str(mean) + return (norm, mean, sigma) + else: + if draw_plot: + p.addMarker(max_x, None, "Max="+str(round(max_x,4)), Color.GRAY) + #print "Invalid gaussian fit: " + str(mean) + return (None, None, None) + + +def enforce_monotonic(x): + epsilon = 1e-8 + for i in range(len(x)-1): + if x[i+1]<=x[i]: + x[i+1] = x[i]+ epsilon + return x \ No newline at end of file diff --git a/script/tools/RestartPuckDetection.py b/script/tools/RestartPuckDetection.py new file mode 100644 index 0000000..88df774 --- /dev/null +++ b/script/tools/RestartPuckDetection.py @@ -0,0 +1,8 @@ +USR,PWD = "pi", "raspberry" +HOST,PORT = "tell6s-raspberrypi", 22 +CMD= "sudo systemctl stop puck_detection.service;sudo systemctl start puck_detection.service" + +ret = run("tools/SshExec") +set_return(ret) + +puck_detection.initialize() \ No newline at end of file diff --git a/script/tools/SshExec.py b/script/tools/SshExec.py new file mode 100644 index 0000000..c9e4f50 --- /dev/null +++ b/script/tools/SshExec.py @@ -0,0 +1,61 @@ +import com.jcraft.jsch.Channel as Channel +import com.jcraft.jsch.ChannelShell as ChannelShell +import com.jcraft.jsch.JSch as JSch +import com.jcraft.jsch.JSchException as JSchException +import com.jcraft.jsch.Session as Session +import java.lang.System as System +import java.io.PrintStream as PrintStream + + +#Parameters: +#CMD +#USR +#PWD +#HOST +#PORT + +jsch= JSch() +session=jsch.getSession(USR, HOST, PORT) +session.setPassword(PWD) +session.setConfig("StrictHostKeyChecking", "no") +session.connect() + +#channel=session.openChannel("shell") +#input_stream=channel.getInputStream() +#output_stream = channel.getOutputStream() +#print_stream = PrintStream(output_stream, True) +#print_stream.println("ls") + +channel=session.openChannel("exec") +channel.setCommand(CMD) +channel.setInputStream(None) +channel.setOutputStream(System.out) +channel.setErrStream(System.err) +input_stream=channel.getInputStream() + + +def wait_ret(): + global input_stream + rx = "" + while True: + while (input_stream.available() > 0): + i = input_stream.read() + if i < 0: + break + rx=rx+chr(i) + if channel.closed: + break + time.sleep(0.1) + return rx + + +channel.connect() + +try: + ret = wait_ret() +except: + channel.disconnect() + session.disconnect() + raise + +set_return(ret) \ No newline at end of file diff --git a/script/tools/StopPuckDetection.py b/script/tools/StopPuckDetection.py new file mode 100644 index 0000000..e45a6ae --- /dev/null +++ b/script/tools/StopPuckDetection.py @@ -0,0 +1,8 @@ +USR,PWD = "pi", "raspberry" +HOST,PORT = "tell6s-raspberrypi", 22 +CMD= "sudo systemctl stop puck_detection.service" + +ret = run("tools/SshExec") +set_return(ret) + +