From 9422716dcae88cc6b886a0f706b25543901bd6b7 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Thu, 15 Dec 2022 21:33:42 +0100 Subject: [PATCH 001/209] Redesign of the rowing engine (#84) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Looks like dead code Dead code????? * Improvement of the MovingAverager startup Improvement of the MovingAverager's startup-behaviour, to allow use for the dragcalculation. In this approach, the defaultValue is only used when the array isn't sufficiently filled (less then two pushed values), but after that it is directly released and the average only depends on pushed values. This is especially important for the drag calculation, as the drag calcuation is sufficiently robust in handling errornous values, and drag factors might make big jumps in the beginning (i.e. from the middle setting to a maximum value). * Allow the settings to set a specific priority The nice-level of -20 is arbitrary and very counterproductive, as it dwarfs OS processes including the internal timer. This results in a more noisy measurement, even on a high-speced Pi 4. As the priority is dependent on the hardware/software configuration of the Pi anyway, I made the configuration setting more granular. * Added Concept2 PM5 wiring diagram Added wiring diagram for the PM5 (with 18V generator) * Update server.js * Delete app/engine/averager directory * Creation of the series.js Creation of a series of values, as an abstraction away from the array, with added standard functionality. This is the basis for the more complex functions like the regression series. * Update the server.js to adapt to new architecture Server.js has been adapted to fit the new architecture. It is now in control of the session, directing others how to proceed. * Deleted Timer.js as it has become obselete Deleted Timer.js as it has become obselete * Updated to more abstract Flywheel.js Renamed and rewritten to Flywheel.js. It provides an abstraction from the individual currentDt's and provides a more abstract view of the flywheel and its current state, which can be interrogated by Rower.js * Created an initial testset for Flywheel.js An initial set of tests to check whether Flywheel.js works as expected. * Renaming variables and added new functionality Renamed variables to fit the naming scheme of Rower.js. Added the option to create a RowingData file, hich can be read by RowingData, RowsAndAll and Excel. Also added new fields in the notes of a TCX, including HRR. * Update Pm5Constants.js * Update to the constants Update to the constants, to make them closer to the actual firmware options. Also I added the Row to the name, as Concept2 also seems to do this on their current firmware. * Added additional defensive programming Added additional defensive programming * updated variable names Updated variable names to keep them in sync with RowingStatistics * Added metrics and updated variable names Added new metrics, like projected time and distance, stroke calories Updated variable names to keep them in sync with RowingStatistics * Added metric, states and variable rename Added the dragfactor metric, aded the state for the workoutType, workoutDurationType, workoutState, RowingState and strokeState Renamed most variable to allign them with RowingStatistics * Added metrics, rename variables Added several metrics (driveLength, driveTime, strokeRecoveryTime, strokeDistance, peakDriveForce, averageDriveForce and workPerStroke) Alignment of variable names with RowingStatistics.js * Renamed variables Renamed variables to align them with the RowingStatistics naming convention * Update variable definitions and naming Update to the variable definition of speed: as almost all consumers use the m/s unit, we now use this internally, and only convert to km/h for the bike Alignment with the naming scheme of RowingStatistics * Update based on PM5 spec workoutDurationType was a more complex enum * Complete redesign Complete redesign: * Switched to a Finite State machine to maintain session state * To reduce complexity, it directly inspects Rower.js, instead of awaiting messages to be processed * Small snippets process all data, where updates are grouped based on their update moment * Renaming all variables to clearly identify when they are updated (as determined by the state machine) * Introduced a first version of interval management, as a preperation for future solutions with more complex training scheme's This should help in reducing the code base while making the code easier to understand. * Rename and adoptation to the new architecture Split RowingEngine into two blocks: * Rower (which represents the key metrics from the rower) and * flywheel (which represents the key metrics of the flywheel, formally known as MovingFlankDetector). This should simplify the reading of the code, as Flywheel reports key metrics without the need to many specific configuration parameters. Also added many metrics (including force curve, power curve and handle speed). * Update and rename RowingEngine.test.js to Rower.test.js Update to fit Rower.js better, includes testing with known rowers * Introduction of VO2Max (Beta) Introduction of a Beta-version of VO2-Max, which will be calculated each time a tcx-file is created. It introduces two versions of VO2-Max calculation: * extrapolation-based VO2Max: it extrapolates the power to maxpower based on MaxHR and the relation between HR and power in the session * interpolation based VO2Max: it projects the session onto a 2K, and then calculates the VO2Max based on Concept2's research * Beta version Beta version of the BucketLinearSeries to accomodate VO2Max * Create CurveAligner.js CurveAligner for cleaning up the (power, force and handle velocity) curves * Create Series.test.js Added test-class to series.js, as it is so fundamental to OpenRowingMonitor * Create StreamFilter.js Streamfilter implements a running streamfilter. It is designed to be robust to outliers, and replaces all averaging functions. * Create StreamFilter.test.js Tests the steamfilter * Create OLSLinearSeries.js Creation of the OLSLinearSeries, to allow for drag calculation, VO2Max calculation and projecting calories, distance and time. * Create OLSLinearSeries.test.js Test of the Simple Linear Regression method * Create FullTSQuadraticSeries.js FullTSQuadraticSeries delivers Full Theil-Senn Quadratic regression, which is essential to determine Angular Velocity and Angular Acceleration in a noise-resistant way. These metrics are essential for force curve, power curve, handle velocity curve and stroke detection (as it is triggered by the force on the handle). * Create FullTSQuadraticSeries.test.js Test of the FullTSQuadraticSeries * Create curveMetrics.js Object to manage the specifics of curves * Delete curveMetrics.js * Create curveMetrics.js Object to create curves and the associated curve metrics * Update rowerProfiles.js Update to accomodate the new RowingEngine, and its parameters * Renaming variables Renaming variables to align with the variable renaming in RowingStatistics.js * Rename variables Update variables to align with RowingStatistics naming conventions * Update GpioTimerService.js * Added example CurrentDt curve Added example CurrentDt curve for explanation of good and bad noise. * Testfile for Concept2 RowErg Testfile for Concept2 RowErg, 2000 meters, for validation purposes * Increasing consistency in logging Increased consistency in logging specific messages * Improved logging to facilitate configuration Improved the logging of specific data to facilitate an easier setup for new rowers. * Update backlog.md * Update rower_settings.md * Adaptation to the newly developed physics model Adaptation of the text to the newly developed physics model. * Removed the settings analysis as it isn't needed Removed this tool, as it isn't up-to-date with the current physics model, and logging does a better job in helping the analysis. * Updated to reflect the new approach Updated the setup procedure to: * Adapt it to the new physics model * Adapt it to the new logging-based setup procedure. * Added the Concept2 RowErg Added the Concept2 RowErg configuration * Added the Concept2 as test-object Added the Concept2 as test-object * Added the Concept2 as test-object Added the Concept2 as test-object * Update Rower.test.js * Adaptation to C2 Flywheel Inertia change Adaptation to C2 Flywheel Inertia change * Created to explain the current architecture Created an architecture document to explain the current architecture, as well as the major components in Open Rowing Monitor to maintainers and reviewers of the code. * Create hardware_setup_Concept2_RowErg.md * Added Concept 2 manual Added concept 2 RowErg manual, as some minor updates * Added performance improvement guide Added a guide for improving the performance (Latency) of the Raspberry Pi. * Fixed typos, filled in some blanks Fixed some typos, improved some text for clarity and added some text to complete this description. * Update to reflect new capabilities Update to reflect new capabilities of OpenRowingMonitor and make the text easier to parse for novice users (make it less technical). * Updated with new settings Updated with the new settings available * Update default.config.js * Update to allow for the 64Bit PREEMPT kernel Update of the install script to allow for the 64Bit PREEMPT kernel of Raspberry Pi, which handles low latency much better. * Fixed a typo in a file reference Thanks to @Abasz , dound a typo which i now fixed. * Fixed typo Fixed typo Co-authored-by: Lars Berning <151194+laberning@users.noreply.github.com> * Fixed a typo Fixed a typo Co-authored-by: Lars Berning <151194+laberning@users.noreply.github.com> * Fixed a cut-copy-paste error Fixed a cut-copy-paste error in the infinity symbol * Fixed error in repo-name Fixed an error in the repo-name when moving for the experimental branch to the PR branch * Fixed a copy error in the Repo-name Missed updating the repo-name when moving the code from private experimental branch to a production PR repo * Updated ToDo descriptions Updated ToDo descriptions * Added more detailed ToDo's Added more detailed ToDo's * Better explanation of design issue A much better (and English) and updated explanation of the open design issues in Flywheel.js * Fixed a bug in the strokecount reinitialization Fixed a bug in the stroke count reinitialization (great find by @Abasz), which was inconsistent with the normal init. * Graphic showing systematic error File showing systematic (periodic) deviations in the magnet placement * Added an image of misaligned magnets * Removed non-working code Removed the trimmedMedian function, as its design contains fundamental mathematical errors. The initially proposed way is the only good way of doing it. * Added observation about noise overfitting Added a note about Noise overfitting, based on the Concept2 and the observation of Gordon_Shumway (see https://github.com/laberning/openrowingmonitor/discussions/87) * Added the pigpio library Added the pigpio library * Added an explanation into the GPIO settings Added an explanation of the GPIO settings * Added the settings for the new GPIO library Added the settings to configure the new GPIO library * Replaced onoff with pigpio, added debounce param. Replaced the onoff library (goodbye my old loyal friend) with pigpio, to facilitate much more accurate timing calculations and add more flexibility to the flank detection (including debounce) * Replaced onoff with pigpio Replaced onoff with pigpio library * Replaced onoff with pigpio Replaced onoff with pigpio * Install and config pigpio dependency Added the installation of the pigpio C-library and setting the key parameters. * Added a bit clarification about the setup guide Added a bit better description about the setup guides. * Removed and added spaces.... * Remove an unnecessary space.... * Resolved open design issue in noise filter In the previous design, we were uncertain that the noise filter would handle all cases. With pigpio, we are quite certain it will handle all cases internally, and here we detect any deviations. Please note, startup-behaviour after a cold or warm (re)start still has to be handled as time since the privious pulse tends to be in the minutes, throwing off all timekeeping functions. * Removed obsolete variables Removed two obsolete variables: lastKnownGoodDatapoint and numberOfErrorsAllowed * Removed obsolete variable Removed the now defunct variable numberOfErrorsAllowed * Changes in startup and config Due to changes in the gpio library, the startup behaviour of flywheel.js has changes, as have the Concept2 configuration settings. These changes modify the results of the testcase accordingly. * Updated testcases after update pigpio Due to changes in the gpio library, the startup behaviour of flywheel.js has changed, as have the Concept2 configuration settings. These changes modify the results of the testcase accordingly. * Update testcase to accomodate lib change Update testcase to accomodate lib change * Update due to lib modification Update due to lib modification * Update Rower.test.js * Update Rower.test.js * Update Rower.test.js * Update Rower.test.js * Update due to gpio library change * Update due to removal obsolete parameter Update due to the removal of numberOfErrorsAllowed * Removed obsolute parameter Removed the numberOfErrorsAllowed parameter * Performance improvement A small performance improvement: by moving the evaluation of the flywheel.isPowered(), flywheel.isUnpowered() and flywheel.isDwelling() backwards, we move these potentially expensive operations further in the evaluation. As Javascript is using lazy evaluation, it won't be called unless all other conditions are true. Especially flywheel.isDwelling() checks if the entire flank is above maximumTimeBetweenImpulses, which is expensive (flywheel.isPowered() and flywheel.isUnpowered() are actually quite simple, but are moved along to maintain symmetry). * Fixed a missing bracket Fixed a missing bracket * Allignment with main branch (64Bit support) Alignment with the improvement of the install script of the main branch to support the 64 bit version of the Lite kernel. * removes some obsolete variables * adds a missing async statement Signed-off-by: Lars Berning <151194+laberning@users.noreply.github.com> * pin dependency Signed-off-by: Lars Berning <151194+laberning@users.noreply.github.com> * default setting should not fiddle with nice levels of os, otherwise we require root permissions by default Signed-off-by: Lars Berning <151194+laberning@users.noreply.github.com> * prettyfies a log message Signed-off-by: Lars Berning <151194+laberning@users.noreply.github.com> * unifies VO2max namings Signed-off-by: Lars Berning <151194+laberning@users.noreply.github.com> * Introduced appPriority as setting Added the appPriority setting, to allow a clear entry to set the priority for the main process. * Removed some obscure priority behaviour Removed the obscure approach of using the gpio-priority to set the main app priority. * Added a distinction between stop and pause Based on a bugreport by @Carlito1979 about the pause behaviour, added a distinction between the stopMoving() and pauseMoving() command, as a pause would lead to an undesired stop state. * Added a distinction between stop and pause Based on a bugreport by @Carlito1979 about the pause behaviour, added a distinction between the stopMoving() and pauseMoving() command, as a pause would lead to an undesired stop state. * Improved description of the various states Based on bugs reported, and some internal soul searching, improved the description of states. * Removed a trailing space * Added profiles, put them in alphabetic order Added the Force USA R3 Air Rower, and put the rowers in alphabetic order * Removal of surplus comma * Improvement of pause-behaviour Improvement of the pause behaviour based on feedback from @Carlito1979 * Improved RestingHR behaviour, clarifications Improvement of the resting HR functionality, it will now also trigger when rowing is paused Clarification of "Stopped" sessionState behavior: this is a less than obvious but deliberate approach. * Change to const postExerciseHR Due to Lint error, changed postExerciseHR from "let" to "const" * Create and advertising data builder Since Bleno library does not provide a way to set/tweak appearance data implement a builder that enables to add name and appearance information to the advertisement data. * Expose time of last completed stroke For the CPS and CSC BLE Services the time stamp of the last stoke event is necessary. This is available in the Rower as `drivePhaseStartTime` so expose it * Add 32bit capability to BufferBuilder Since the wheel revolution count in the CSC and CPS measurement service is a 32bin UINT extend the BufferBuilder to be able to handle it. * Add static data and functions used in CSCS and CPS Implement device information service (necessary for garmin to recognise the device as sensor) a wrapper around static read characteristics to ease creation. * Add cycling speed and cadence profile Add necessary services and related characteristics. Implement CscPeripheral interface to be able to properly communicate to the PeripheralManager. * Add cycling power profile Add necessary services and related characteristics. Implement CpsPeripheral interface to be able to properly communicate to the PeripheralManager. * Wire up PeripheralManager with the new profiles Add the new CSCP and CPP profiles to the PeripheralManager. Update comments in settings and front end web view with the new profiles * Add new Rower Profile Zoco Body Fit Add a rowing profile for a Concept2 clone air rower * Update FTMS profile with new services Add device information service to the FTMS peripheral and move to the new advertising data builder. * Improvement of startup behaviour Modification of the startup behaviour: now unrealistic values (i.e. above maximumTimeBetweenImpulses) are ignored. The rower will only start when all values in the flank are above the minmumSpeed (i.e. all currentDt's are below maximumTimeBetweenImpulses). * Improvement of startup behaviour Modification of the startup behaviour: now unrealistic values (i.e. above maximumTimeBetweenImpulses) are ignored. The rower will only start when all values in the flank are above the minmumSpeed (i.e. all currentDt's are below maximumTimeBetweenImpulses). * Improvement of startup behaviour Modification of the startup behaviour: now unrealistic values (i.e. above maximumTimeBetweenImpulses) are ignored. The rower will only start when all values in the flank are above the minmumSpeed (i.e. all currentDt's are below maximumTimeBetweenImpulses). * Improvement of startup behaviour Modification of the startup behaviour: now unrealistic values (i.e. above maximumTimeBetweenImpulses) are ignored. The rower will only start when all values in the flank are above the minmumSpeed (i.e. all currentDt's are below maximumTimeBetweenImpulses). * Finalize Generic Air Rower profile * Change name of displayed name of new profiles * Rename lastStrokeTime to driveLastStartTime * Fixed some small bugs Fixed * the missing pause command * a small typo in the totalmovingtime * Fixed a small bug Fixed a small bug * Improvement of browser performence Improved some startup settings to increase browser performance (disables some security settings as they are not needed at a local system). Please note these settings are NOT RECOMENDED for general purpose browsers, but as we run on a localhost machine only, showing our GUI, this is quite acceptable. * Update due to increased BLE profiles Thanks to @Abasz, we can now use BLE Cycling Power Profile and the Cycling Speed and Cadence Profile. * Added Abasz to the list of great contributors * More expanded explanation of BLE profiles * Update of the testfile to align with new GPIO conf Update of the testfile to reflect the new GPIO-module * Introduction of supporting Linear TS Introduction of the Linear Theil-Senn algorithm to improve the Quadratic Theil-Senn algorithm * Improvement of the Quad. Theil-Senn Algorithm Improvement of the accuracy and robustness of the Quadratic Theil-Senn algorithm, as well as improving (reducing) the CPU load. It employs the Linear Theil-Senn Algorithm to calculate the optimal B and C for the selected A (instead of a marginally related B and C in the older algoithm). * Update of the stroke detection algorithm Update of the stroke detection algorithm: as the Qudratic Theil-Senn algorithm is more robust, we can rely on the sole combination of dragslope being gone and seeing torque. * Updated to reflect more accurate algorithm Updated the testscript to reflect the much more accurate and robust algorithm. * Updated to reflect more improved algorithms Updated test scripts to reflect the improvements in the Quadratic Theil-Senn algorithm and the Flywheel stroke detection algorithm. * Updated to reflect more improved algorithms Updated test scripts to reflect the improvements in the Quadratic Theil-Senn algorithm and the Flywheel stroke detection algorithm. * Removed dead code Removal of dead code * Improvement of Code quality * Improvement of code quality Improvement of code quality * Added space to survive Lint Added space to survive Lint * Addition of the isAboveMinimumSpeed function Addition of the isAboveMinimumSpeed function * Removed unused variable * Add modification for new startup behaviour Add modification for new startup behaviour * Update to fix regression issues Update to fix regression issues * Update Rower.test.js * Update of the C2 testcase Update of the C2 testcase due to GPIO update * Update of the C2 testcase due to GPIO changes Update of the C2 testcase due to changing the testdata due to GPIO changes * fixes some review findings Signed-off-by: Lars Berning <151194+laberning@users.noreply.github.com> Co-authored-by: Lars Berning <151194+laberning@users.noreply.github.com> Co-authored-by: Abász <> Co-authored-by: Abasz <32517724+Abasz@users.noreply.github.com> --- app/ble/BufferBuilder.js | 15 + app/ble/BufferBuilder.test.js | 12 +- app/ble/CpsPeripheral.js | 108 + app/ble/CscPeripheral.js | 108 + app/ble/FtmsPeripheral.js | 19 +- app/ble/PeripheralManager.js | 53 +- app/ble/common/AdvertisingDataBuilder.js | 133 + app/ble/common/AdvertisingDataBuilder.test.js | 117 + app/ble/common/DeviceInformationService.js | 23 + app/ble/common/SensorLocation.js | 30 + app/ble/common/StaticReadCharacteristic.js | 22 + app/ble/cps/CpsControlPointCharacteristic.js | 29 + app/ble/cps/CpsMeasurementCharacteristic.js | 95 + app/ble/cps/CyclingPowerMeterService.js | 66 + app/ble/csc/CscControlPointCharacteristic.js | 29 + app/ble/csc/CscMeasurementCharacteristic.js | 81 + app/ble/csc/CyclingSpeedCadenceService.js | 36 + app/ble/ftms/DeviceInformationService.js | 18 - app/ble/ftms/IndoorBikeDataCharacteristic.js | 18 +- app/ble/ftms/RowerDataCharacteristic.js | 20 +- app/ble/pm5/Pm5Constants.js | 9 +- .../pm5/characteristic/AdditionalStatus.js | 16 +- .../pm5/characteristic/AdditionalStatus2.js | 8 +- .../characteristic/AdditionalStrokeData.js | 16 +- app/ble/pm5/characteristic/GeneralStatus.js | 24 +- app/ble/pm5/characteristic/StrokeData.js | 26 +- app/client/components/DashboardActions.js | 22 +- app/client/components/PerformanceDashboard.js | 24 +- app/client/lib/app.js | 16 +- app/client/store/appState.js | 2 +- app/engine/Flywheel.js | 361 + app/engine/Flywheel.test.js | 356 + app/engine/MovingFlankDetector.js | 193 - app/engine/Rower.js | 369 + app/engine/Rower.test.js | 519 + app/engine/RowingEngine.js | 342 - app/engine/RowingEngine.test.js | 103 - app/engine/RowingStatistics.js | 450 +- app/engine/Timer.js | 36 - app/engine/VO2max.js | 165 + app/engine/WorkoutRecorder.js | 139 +- app/engine/averager/MovingAverager.js | 56 - app/engine/averager/MovingAverager.test.js | 44 - app/engine/averager/MovingIntervalAverager.js | 47 - .../averager/MovingIntervalAverager.test.js | 57 - app/engine/averager/WeightedAverager.js | 43 - app/engine/averager/WeightedAverager.test.js | 45 - app/engine/utils/BucketedLinearSeries.js | 163 + app/engine/utils/CurveAligner.js | 43 + app/engine/utils/FullTSLinearSeries.js | 226 + app/engine/utils/FullTSQuadraticSeries.js | 270 + .../utils/FullTSQuadraticSeries.test.js | 546 + app/engine/utils/OLSLinearSeries.js | 203 + app/engine/utils/OLSLinearSeries.test.js | 268 + app/engine/utils/Series.js | 149 + app/engine/utils/Series.test.js | 163 + app/engine/utils/StreamFilter.js | 56 + app/engine/utils/StreamFilter.test.js | 69 + app/engine/utils/curveMetrics.js | 73 + app/gpio/GpioTimerService.js | 72 +- app/server.js | 194 +- config/default.config.js | 134 +- config/rowerProfiles.js | 237 +- docs/Architecture.md | 179 + docs/Improving_Raspberry_Performance.md | 77 + docs/README.md | 60 +- docs/Rowing_Settings_Analysis_Small.xlsx | Bin 129305 -> 0 bytes docs/attribution.md | 2 + docs/backlog.md | 4 +- docs/hardware_setup_Concept2_RowErg.md | 31 + docs/img/Concept2_Optocoupler.jpg | Bin 0 -> 107303 bytes ...oncept2_RowErg_Construction_tolerances.jpg | Bin 0 -> 421455 bytes docs/img/CurrentDt_curve.jpg | Bin 0 -> 133455 bytes docs/installation.md | 17 +- docs/physics_openrowingmonitor.md | 479 +- docs/rower_settings.md | 351 +- install/install.sh | 3 + install/webbrowserkiosk.sh | 2 +- package-lock.json | 73 +- package.json | 2 +- .../Concept2_RowErg_Session_2000meters.csv | 63000 ++++++++++++++++ 81 files changed, 69890 insertions(+), 1776 deletions(-) create mode 100644 app/ble/CpsPeripheral.js create mode 100644 app/ble/CscPeripheral.js create mode 100644 app/ble/common/AdvertisingDataBuilder.js create mode 100644 app/ble/common/AdvertisingDataBuilder.test.js create mode 100644 app/ble/common/DeviceInformationService.js create mode 100644 app/ble/common/SensorLocation.js create mode 100644 app/ble/common/StaticReadCharacteristic.js create mode 100644 app/ble/cps/CpsControlPointCharacteristic.js create mode 100644 app/ble/cps/CpsMeasurementCharacteristic.js create mode 100644 app/ble/cps/CyclingPowerMeterService.js create mode 100644 app/ble/csc/CscControlPointCharacteristic.js create mode 100644 app/ble/csc/CscMeasurementCharacteristic.js create mode 100644 app/ble/csc/CyclingSpeedCadenceService.js delete mode 100644 app/ble/ftms/DeviceInformationService.js create mode 100644 app/engine/Flywheel.js create mode 100644 app/engine/Flywheel.test.js delete mode 100644 app/engine/MovingFlankDetector.js create mode 100644 app/engine/Rower.js create mode 100644 app/engine/Rower.test.js delete mode 100644 app/engine/RowingEngine.js delete mode 100644 app/engine/RowingEngine.test.js delete mode 100644 app/engine/Timer.js create mode 100644 app/engine/VO2max.js delete mode 100644 app/engine/averager/MovingAverager.js delete mode 100644 app/engine/averager/MovingAverager.test.js delete mode 100644 app/engine/averager/MovingIntervalAverager.js delete mode 100644 app/engine/averager/MovingIntervalAverager.test.js delete mode 100644 app/engine/averager/WeightedAverager.js delete mode 100644 app/engine/averager/WeightedAverager.test.js create mode 100644 app/engine/utils/BucketedLinearSeries.js create mode 100644 app/engine/utils/CurveAligner.js create mode 100644 app/engine/utils/FullTSLinearSeries.js create mode 100644 app/engine/utils/FullTSQuadraticSeries.js create mode 100644 app/engine/utils/FullTSQuadraticSeries.test.js create mode 100644 app/engine/utils/OLSLinearSeries.js create mode 100644 app/engine/utils/OLSLinearSeries.test.js create mode 100644 app/engine/utils/Series.js create mode 100644 app/engine/utils/Series.test.js create mode 100644 app/engine/utils/StreamFilter.js create mode 100644 app/engine/utils/StreamFilter.test.js create mode 100644 app/engine/utils/curveMetrics.js create mode 100644 docs/Architecture.md create mode 100644 docs/Improving_Raspberry_Performance.md delete mode 100644 docs/Rowing_Settings_Analysis_Small.xlsx create mode 100644 docs/hardware_setup_Concept2_RowErg.md create mode 100644 docs/img/Concept2_Optocoupler.jpg create mode 100644 docs/img/Concept2_RowErg_Construction_tolerances.jpg create mode 100644 docs/img/CurrentDt_curve.jpg create mode 100644 recordings/Concept2_RowErg_Session_2000meters.csv diff --git a/app/ble/BufferBuilder.js b/app/ble/BufferBuilder.js index 5ddd624d03..5aebc7f32c 100644 --- a/app/ble/BufferBuilder.js +++ b/app/ble/BufferBuilder.js @@ -47,6 +47,21 @@ export default class BufferBuilder { this._dataArray.push(buffer) } + writeUInt32LE (value) { + const _value = value || 0 + const buffer = Buffer.alloc(4) + if (value > 0xffffffff || value < 0) { + log.warn(new RangeError(`The value of "value" is out of range. It must be >= 0 and <= ${0xffffffff}. Received ${value}`)) + } else { + try { + buffer.writeUint32LE(_value) + } catch (error) { + log.warn(error) + } + } + this._dataArray.push(buffer) + } + getBuffer () { return Buffer.concat(this._dataArray) } diff --git a/app/ble/BufferBuilder.test.js b/app/ble/BufferBuilder.test.js index 186be4281b..72d7f133c5 100644 --- a/app/ble/BufferBuilder.test.js +++ b/app/ble/BufferBuilder.test.js @@ -13,7 +13,8 @@ test('valid max UInts should produce correct buffer', () => { buffer.writeUInt8(255) buffer.writeUInt16LE(65535) buffer.writeUInt24LE(16777215) - assert.equal(buffer.getBuffer(), Buffer.from([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])) + buffer.writeUInt32LE(4294967295) + assert.equal(buffer.getBuffer(), Buffer.from([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])) }) test('valid min UInts should produce correct buffer', () => { @@ -21,7 +22,8 @@ test('valid min UInts should produce correct buffer', () => { buffer.writeUInt8(0) buffer.writeUInt16LE(0) buffer.writeUInt24LE(0) - assert.equal(buffer.getBuffer(), Buffer.from([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])) + buffer.writeUInt32LE(0) + assert.equal(buffer.getBuffer(), Buffer.from([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0])) }) test('negative UInt8 should produce 1 bit buffer of 0x0', () => { @@ -42,6 +44,12 @@ test('negative writeUInt24LE should produce 3 bit buffer of 0x0', () => { assert.equal(buffer.getBuffer(), Buffer.from([0x0, 0x0, 0x0])) }) +test('negative writeUInt32LE should produce 4 bit buffer of 0x0', () => { + const buffer = new BufferBuilder() + buffer.writeUInt32LE(-1) + assert.equal(buffer.getBuffer(), Buffer.from([0x0, 0x0, 0x0, 0x0])) +}) + test('invalid datatype value UInt16LE should produce 2 bit buffer of 0x0', () => { const buffer = new BufferBuilder() buffer.writeUInt16LE(new Map()) diff --git a/app/ble/CpsPeripheral.js b/app/ble/CpsPeripheral.js new file mode 100644 index 0000000000..5d24e47784 --- /dev/null +++ b/app/ble/CpsPeripheral.js @@ -0,0 +1,108 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are required for + a Cycling Power Profile +*/ +import bleno from '@abandonware/bleno' +import config from '../tools/ConfigManager.js' +import log from 'loglevel' +import CyclingPowerService from './cps/CyclingPowerMeterService.js' +import DeviceInformationService from './common/DeviceInformationService.js' +import AdvertisingDataBuilder from './common/AdvertisingDataBuilder.js' + +function createCpsPeripheral () { + const peripheralName = `${config.ftmsRowerPeripheralName} (CPS)` + const cyclingPowerService = new CyclingPowerService((event) => log.debug('CPS Control Point', event)) + + bleno.on('stateChange', (state) => { + triggerAdvertising(state) + }) + + bleno.on('advertisingStart', (error) => { + if (!error) { + bleno.setServices( + [ + cyclingPowerService, + new DeviceInformationService() + ], + (error) => { + if (error) log.error(error) + }) + } + }) + + bleno.on('accept', (clientAddress) => { + log.debug(`ble central connected: ${clientAddress}`) + bleno.updateRssi() + }) + + bleno.on('disconnect', (clientAddress) => { + log.debug(`ble central disconnected: ${clientAddress}`) + }) + + bleno.on('platform', (event) => { + log.debug('platform', event) + }) + bleno.on('addressChange', (event) => { + log.debug('addressChange', event) + }) + bleno.on('mtuChange', (event) => { + log.debug('mtuChange', event) + }) + bleno.on('advertisingStartError', (event) => { + log.debug('advertisingStartError', event) + }) + bleno.on('servicesSetError', (event) => { + log.debug('servicesSetError', event) + }) + bleno.on('rssiUpdate', (event) => { + log.debug('rssiUpdate', event) + }) + + function destroy () { + return new Promise((resolve) => { + bleno.disconnect() + bleno.removeAllListeners() + bleno.stopAdvertising(resolve) + }) + } + + function triggerAdvertising (eventState) { + const activeState = eventState || bleno.state + if (activeState === 'poweredOn') { + const cpsAppearance = 1156 + const advertisingData = new AdvertisingDataBuilder([cyclingPowerService.uuid], cpsAppearance, peripheralName) + + bleno.startAdvertisingWithEIRData( + advertisingData.buildAppearanceData(), + advertisingData.buildScanData(), + (error) => { + if (error) log.error(error) + } + ) + } else { + bleno.stopAdvertising() + } + } + + function notifyData (type, data) { + if (type === 'strokeFinished' || type === 'metricsUpdate') { + cyclingPowerService.notifyData(data) + } + } + + // CPS does not have status characteristic + function notifyStatus (status) { + } + + return { + triggerAdvertising, + notifyData, + notifyStatus, + destroy + } +} + +export { createCpsPeripheral } diff --git a/app/ble/CscPeripheral.js b/app/ble/CscPeripheral.js new file mode 100644 index 0000000000..3c8e99cc79 --- /dev/null +++ b/app/ble/CscPeripheral.js @@ -0,0 +1,108 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are required for + a Cycling Speed and Cadence Profile +*/ +import bleno from '@abandonware/bleno' +import config from '../tools/ConfigManager.js' +import log from 'loglevel' +import DeviceInformationService from './common/DeviceInformationService.js' +import CyclingSpeedCadenceService from './csc/CyclingSpeedCadenceService.js' +import AdvertisingDataBuilder from './common/AdvertisingDataBuilder.js' + +function createCscPeripheral () { + const peripheralName = `${config.ftmsRowerPeripheralName} (CSC)` + const cyclingSpeedCadenceService = new CyclingSpeedCadenceService((event) => log.debug('CSC Control Point', event)) + + bleno.on('stateChange', (state) => { + triggerAdvertising(state) + }) + + bleno.on('advertisingStart', (error) => { + if (!error) { + bleno.setServices( + [ + cyclingSpeedCadenceService, + new DeviceInformationService() + ], + (error) => { + if (error) log.error(error) + }) + } + }) + + bleno.on('accept', (clientAddress) => { + log.debug(`ble central connected: ${clientAddress}`) + bleno.updateRssi() + }) + + bleno.on('disconnect', (clientAddress) => { + log.debug(`ble central disconnected: ${clientAddress}`) + }) + + bleno.on('platform', (event) => { + log.debug('platform', event) + }) + bleno.on('addressChange', (event) => { + log.debug('addressChange', event) + }) + bleno.on('mtuChange', (event) => { + log.debug('mtuChange', event) + }) + bleno.on('advertisingStartError', (event) => { + log.debug('advertisingStartError', event) + }) + bleno.on('servicesSetError', (event) => { + log.debug('servicesSetError', event) + }) + bleno.on('rssiUpdate', (event) => { + log.debug('rssiUpdate', event) + }) + + function destroy () { + return new Promise((resolve) => { + bleno.disconnect() + bleno.removeAllListeners() + bleno.stopAdvertising(resolve) + }) + } + + function triggerAdvertising (eventState) { + const activeState = eventState || bleno.state + if (activeState === 'poweredOn') { + const cscAppearance = 1157 + const advertisingData = new AdvertisingDataBuilder([cyclingSpeedCadenceService.uuid], cscAppearance, peripheralName) + + bleno.startAdvertisingWithEIRData( + advertisingData.buildAppearanceData(), + advertisingData.buildScanData(), + (error) => { + if (error) log.error(error) + } + ) + } else { + bleno.stopAdvertising() + } + } + + function notifyData (type, data) { + if (type === 'strokeFinished' || type === 'metricsUpdate') { + cyclingSpeedCadenceService.notifyData(data) + } + } + + // CSC does not have status characteristic + function notifyStatus (status) { + } + + return { + triggerAdvertising, + notifyData, + notifyStatus, + destroy + } +} + +export { createCscPeripheral } diff --git a/app/ble/FtmsPeripheral.js b/app/ble/FtmsPeripheral.js index 926b8702be..7a54392f9f 100644 --- a/app/ble/FtmsPeripheral.js +++ b/app/ble/FtmsPeripheral.js @@ -13,14 +13,15 @@ */ import bleno from '@abandonware/bleno' import FitnessMachineService from './ftms/FitnessMachineService.js' -// import DeviceInformationService from './ftms/DeviceInformationService.js' import config from '../tools/ConfigManager.js' import log from 'loglevel' +import DeviceInformationService from './common/DeviceInformationService.js' +import AdvertisingDataBuilder from './common/AdvertisingDataBuilder.js' function createFtmsPeripheral (controlCallback, options) { const peripheralName = options?.simulateIndoorBike ? config.ftmsBikePeripheralName : config.ftmsRowerPeripheralName const fitnessMachineService = new FitnessMachineService(options, controlPointCallback) - // const deviceInformationService = new DeviceInformationService() + const deviceInformationService = new DeviceInformationService() bleno.on('stateChange', (state) => { triggerAdvertising(state) @@ -29,8 +30,7 @@ function createFtmsPeripheral (controlCallback, options) { bleno.on('advertisingStart', (error) => { if (!error) { bleno.setServices( - // [fitnessMachineService, deviceInformationService], - [fitnessMachineService], + [fitnessMachineService, deviceInformationService], (error) => { if (error) log.error(error) }) @@ -85,10 +85,13 @@ function createFtmsPeripheral (controlCallback, options) { function triggerAdvertising (eventState) { const activeState = eventState || bleno.state if (activeState === 'poweredOn') { - bleno.startAdvertising( - peripheralName, - // [fitnessMachineService.uuid, deviceInformationService.uuid], - [fitnessMachineService.uuid], + const advertisingBuilder = new AdvertisingDataBuilder([fitnessMachineService.uuid]) + advertisingBuilder.setShortName(peripheralName) + advertisingBuilder.setLongName(peripheralName) + + bleno.startAdvertisingWithEIRData( + advertisingBuilder.buildAppearanceData(), + advertisingBuilder.buildScanData(), (error) => { if (error) log.error(error) } diff --git a/app/ble/PeripheralManager.js b/app/ble/PeripheralManager.js index 12371f6f63..c75861fa24 100644 --- a/app/ble/PeripheralManager.js +++ b/app/ble/PeripheralManager.js @@ -10,8 +10,10 @@ import { createFtmsPeripheral } from './FtmsPeripheral.js' import { createPm5Peripheral } from './Pm5Peripheral.js' import log from 'loglevel' import EventEmitter from 'node:events' +import { createCpsPeripheral } from './CpsPeripheral.js' +import { createCscPeripheral } from './CscPeripheral.js' -const modes = ['FTMS', 'FTMSBIKE', 'PM5'] +const modes = ['FTMS', 'FTMSBIKE', 'PM5', 'CSC', 'CPS'] function createPeripheralManager () { const emitter = new EventEmitter() let peripheral @@ -48,22 +50,39 @@ function createPeripheralManager () { await peripheral.destroy() } - if (newMode === 'PM5') { - log.info('bluetooth profile: Concept2 PM5') - peripheral = createPm5Peripheral(controlCallback) - mode = 'PM5' - } else if (newMode === 'FTMSBIKE') { - log.info('bluetooth profile: FTMS Indoor Bike') - peripheral = createFtmsPeripheral(controlCallback, { - simulateIndoorBike: true - }) - mode = 'FTMSBIKE' - } else { - log.info('bluetooth profile: FTMS Rower') - peripheral = createFtmsPeripheral(controlCallback, { - simulateIndoorBike: false - }) - mode = 'FTMS' + switch (newMode) { + case 'PM5': + log.info('bluetooth profile: Concept2 PM5') + peripheral = createPm5Peripheral(controlCallback) + mode = 'PM5' + break + + case 'FTMSBIKE': + log.info('bluetooth profile: FTMS Indoor Bike') + peripheral = createFtmsPeripheral(controlCallback, { + simulateIndoorBike: true + }) + mode = 'FTMSBIKE' + break + case 'CSC': + log.info('bluetooth profile: Cycling Speed and Cadence') + peripheral = createCscPeripheral() + mode = 'CSC' + break + case 'CPS': + log.info('bluetooth profile: Cycling Power Meter') + peripheral = createCpsPeripheral() + mode = 'CPS' + break + + case 'FTMS': + default: + log.info('bluetooth profile: FTMS Rower') + peripheral = createFtmsPeripheral(controlCallback, { + simulateIndoorBike: false + }) + mode = 'FTMS' + break } peripheral.triggerAdvertising() diff --git a/app/ble/common/AdvertisingDataBuilder.js b/app/ble/common/AdvertisingDataBuilder.js new file mode 100644 index 0000000000..ba3dabf412 --- /dev/null +++ b/app/ble/common/AdvertisingDataBuilder.js @@ -0,0 +1,133 @@ +'use strict' + +export default class AdvertisingDataBuilder { + constructor (serviceUuids, appearance, longName, shortName) { + this.shortName = shortName || longName || 'ORM' + this.longName = longName || 'OpenRowingMonitor' + this.serviceUuids = serviceUuids || [] + this.appearance = appearance + } + + setLongName (name) { + this.longName = name + } + + setShortName (name) { + this.shortName = name + } + + addServiceUuid (serviceUuid) { + this.serviceUuids.push(serviceUuid) + } + + setAppearance (appearance) { + this.appearance = appearance + } + + buildScanData () { + let scanDataLength = 0 + scanDataLength += 2 + this.longName.length + const scanData = Buffer.alloc(scanDataLength) + + const nameBuffer = Buffer.from(this.longName) + + scanData.writeUInt8(1 + nameBuffer.length, 0) + scanData.writeUInt8(0x08, 1) + nameBuffer.copy(scanData, 2) + + return scanData + } + + buildAppearanceData () { + let advertisementDataLength = 3 + + const serviceUuids16bit = [] + const serviceUuids128bit = [] + let i = 0 + + if (this.serviceUuids.length) { + for (i = 0; i < this.serviceUuids.length; i++) { + const serviceUuid = Buffer.from(this.serviceUuids[i].match(/.{1,2}/g).reverse().join(''), 'hex') + + if (serviceUuid.length === 2) { + serviceUuids16bit.push(serviceUuid) + } else if (serviceUuid.length === 16) { + serviceUuids128bit.push(serviceUuid) + } + } + } + + if (serviceUuids16bit.length) { + advertisementDataLength += 2 + 2 * serviceUuids16bit.length + } + + if (serviceUuids128bit.length) { + advertisementDataLength += 2 + 16 * serviceUuids128bit.length + } + + if (this.appearance) { + advertisementDataLength += 4 + } + + let name = this.shortName + + if (advertisementDataLength + 2 + name.length > 31) { + const remainingDataLength = 31 - advertisementDataLength - 2 + name = name.substring(0, remainingDataLength) + } + advertisementDataLength += 2 + name.length + + const advertisementData = Buffer.alloc(advertisementDataLength) + + // flags + advertisementData.writeUInt8(2, 0) + advertisementData.writeUInt8(0x01, 1) + advertisementData.writeUInt8(0x06, 2) + + let advertisementDataOffset = 3 + + if (this.appearance) { + advertisementData.writeUInt8(3, advertisementDataOffset) + advertisementDataOffset++ + advertisementData.writeUInt8(0x19, advertisementDataOffset) + advertisementDataOffset++ + advertisementData.writeUInt16LE(this.appearance, advertisementDataOffset) + advertisementDataOffset += 2 + } + + advertisementData.writeUInt8(name.length + 1, advertisementDataOffset) + advertisementDataOffset++ + advertisementData.writeUInt8(0x08, advertisementDataOffset) + advertisementDataOffset++ + Buffer.from(name).copy(advertisementData, advertisementDataOffset) + advertisementDataOffset += name.length + + if (serviceUuids16bit.length) { + advertisementData.writeUInt8(1 + 2 * serviceUuids16bit.length, advertisementDataOffset) + advertisementDataOffset++ + + advertisementData.writeUInt8(0x03, advertisementDataOffset) + advertisementDataOffset++ + + for (i = 0; i < serviceUuids16bit.length; i++) { + serviceUuids16bit[i].copy(advertisementData, advertisementDataOffset) + advertisementDataOffset += serviceUuids16bit[i].length + } + } + + if (serviceUuids128bit.length) { + advertisementData.writeUInt8(1 + 16 * serviceUuids128bit.length, advertisementDataOffset) + advertisementDataOffset++ + + advertisementData.writeUInt8(0x06, advertisementDataOffset) + advertisementDataOffset++ + + for (i = 0; i < serviceUuids128bit.length; i++) { + serviceUuids128bit[i].copy(advertisementData, advertisementDataOffset) + advertisementDataOffset += serviceUuids128bit[i].length + } + } + + return advertisementData + } +} diff --git a/app/ble/common/AdvertisingDataBuilder.test.js b/app/ble/common/AdvertisingDataBuilder.test.js new file mode 100644 index 0000000000..8fbc991f75 --- /dev/null +++ b/app/ble/common/AdvertisingDataBuilder.test.js @@ -0,0 +1,117 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +*/ +import { test } from 'uvu' +import * as assert from 'uvu/assert' +import log from 'loglevel' +import AdvertisingDataBuilder from './AdvertisingDataBuilder.js' +log.setLevel(log.levels.SILENT) + +test('empty constructor should create default values', () => { + // arrange + const advertisementDataBuilder = new AdvertisingDataBuilder() + + // act + + // assert + assert.type(advertisementDataBuilder.appearance, 'undefined') + assert.equal(advertisementDataBuilder.longName, 'OpenRowingMonitor') + assert.equal(advertisementDataBuilder.shortName, 'ORM', 'if longName is not defined short name should be ORM') + assert.equal(advertisementDataBuilder.serviceUuids.length, 0) +}) + +test('should use long name as short name if latter is not set', () => { + // arrange + const advertisementDataBuilder = new AdvertisingDataBuilder([], undefined, 'testLongName') + + // act + + // assert + assert.equal(advertisementDataBuilder.shortName, advertisementDataBuilder.longName) +}) + +test('should be able to set long name', () => { + // arrange + const advertisementDataBuilder = new AdvertisingDataBuilder() + const name = 'longNameTest' + // act + advertisementDataBuilder.setLongName(name) + + // assert + assert.equal(advertisementDataBuilder.longName, name) +}) + +test('should be able to set short name', () => { + // arrange + const advertisementDataBuilder = new AdvertisingDataBuilder() + + const name = 'shortNameTest' + // act + advertisementDataBuilder.setShortName(name) + + // assert + assert.equal(advertisementDataBuilder.shortName, name) +}) + +test('should be able to set appearance field', () => { + // arrange + const advertisementDataBuilder = new AdvertisingDataBuilder() + + const appearance = 1157 + // act + advertisementDataBuilder.setAppearance(appearance) + + // assert + assert.equal(advertisementDataBuilder.appearance, appearance) +}) + +test('should be able to add service UUID', () => { + // arrange + const advertisementDataBuilder = new AdvertisingDataBuilder() + + // act + advertisementDataBuilder.addServiceUuid('1800') + advertisementDataBuilder.addServiceUuid('1801') + + // assert + assert.equal(advertisementDataBuilder.serviceUuids.length, 2) +}) + +test('should add long name to scan data', () => { + // arrange + const name = 'testLongName' + const advertisementDataBuilder = new AdvertisingDataBuilder(['1800'], undefined, name, 'short') + + // act + const scanData = advertisementDataBuilder.buildScanData() + + // assert + assert.equal(scanData.length, name.length + 2) +}) + +test('should produce correct byte array for advertising data', () => { + // arrange + const advertisementDataBuilder = new AdvertisingDataBuilder(['1816'], 1156, 'ORM') + + // act + const advertisementData = advertisementDataBuilder.buildAppearanceData() + // assert + assert.equal([...advertisementData], [2, 1, 6, 3, 25, 132, 4, 4, 8, 79, 82, 77, 3, 3, 22, 24] + ) +}) + +test('should trim short name if advertising data is longer than 31 byte', () => { + // arrange + const advertisementDataBuilder = new AdvertisingDataBuilder(['1816'], 1156, 'OpenRowingMonitor CSC') + + // act + const advertisementData = advertisementDataBuilder.buildAppearanceData() + + // assert + assert.equal(advertisementData.length, 31) + assert.equal([...advertisementData], [2, 1, 6, 3, 25, 132, 4, 19, 8, 79, 112, 101, 110, 82, 111, 119, 105, 110, 103, 77, 111, 110, 105, 116, 111, 114, 32, 3, 3, 22, 24]) + assert.match(advertisementData.toString(), /OpenRowingMonitor/) +}) + +test.run() diff --git a/app/ble/common/DeviceInformationService.js b/app/ble/common/DeviceInformationService.js new file mode 100644 index 0000000000..100f5c4766 --- /dev/null +++ b/app/ble/common/DeviceInformationService.js @@ -0,0 +1,23 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + todo: Could provide some info on the device here, maybe OS, Node version etc... +*/ +import bleno from '@abandonware/bleno' +import StaticReadCharacteristic from './StaticReadCharacteristic.js' + +export default class DeviceInformationService extends bleno.PrimaryService { + constructor () { + super({ + // uuid of 'Device Information Service' + uuid: '180a', + characteristics: [ + new StaticReadCharacteristic('2A24', 'Model Number', 'ORM2'), + new StaticReadCharacteristic('2A25', 'Serial Number', '1234'), + new StaticReadCharacteristic('2A28', 'Software Revision', '2'), + new StaticReadCharacteristic('2A29', 'Manufacturer Name', 'OpenRowingMonitor') + ] + }) + } +} diff --git a/app/ble/common/SensorLocation.js b/app/ble/common/SensorLocation.js new file mode 100644 index 0000000000..9a86a15ed6 --- /dev/null +++ b/app/ble/common/SensorLocation.js @@ -0,0 +1,30 @@ +'use strict' + +import BufferBuilder from '../BufferBuilder.js' + +export const sensorLocations = +{ + other: 0, + topOfShoe: 1, + inShoe: 2, + hip: 3, + frontWheel: 4, + leftCrank: 5, + rightCrank: 6, + leftPedal: 7, + rightPedal: 8, + frontHub: 9, + rearDropout: 10, + chainstay: 11, + rearWheel: 12, + rearHub: 13, + chest: 14, + spider: 15, + chainRing: 16 +} + +export const SensorLocationAsBuffer = () => { + const sensorLocationBuffer = new BufferBuilder() + sensorLocationBuffer.writeUInt8(sensorLocations.other) + return sensorLocationBuffer.getBuffer() +} diff --git a/app/ble/common/StaticReadCharacteristic.js b/app/ble/common/StaticReadCharacteristic.js new file mode 100644 index 0000000000..ef2248fef6 --- /dev/null +++ b/app/ble/common/StaticReadCharacteristic.js @@ -0,0 +1,22 @@ +'use strict' + +import bleno from '@abandonware/bleno' + +export default class StaticReadCharacteristic extends bleno.Characteristic { + constructor (uuid, description, value) { + super({ + uuid, + properties: ['read'], + value: Buffer.isBuffer(value) ? value : Buffer.from(value), + descriptors: [ + new bleno.Descriptor({ + uuid: '2901', + value: description + }) + ] + }) + this.uuid = uuid + this.description = description + this.value = Buffer.isBuffer(value) ? value : Buffer.from(value) + } +} diff --git a/app/ble/cps/CpsControlPointCharacteristic.js b/app/ble/cps/CpsControlPointCharacteristic.js new file mode 100644 index 0000000000..6b1283d625 --- /dev/null +++ b/app/ble/cps/CpsControlPointCharacteristic.js @@ -0,0 +1,29 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + The connected Central can remotely control some parameters or our rowing monitor via this Control Point + + But for our use case proper implementation is not necessary (its mere existence with an empty handler suffice) +*/ +import bleno from '@abandonware/bleno' + +export default class CyclingPowerControlPointCharacteristic extends bleno.Characteristic { + constructor (controlPointCallback) { + super({ + // Cycling Power Meter Control Point + uuid: '2A66', + value: null, + properties: ['indicate', 'write'] + }) + + this.controlled = false + if (!controlPointCallback) { throw new Error('controlPointCallback required') } + this.controlPointCallback = controlPointCallback + } + + // Central sends a command to the Control Point + // No need to handle any request to have this working + onWriteRequest (data, offset, withoutResponse, callback) { + } +} diff --git a/app/ble/cps/CpsMeasurementCharacteristic.js b/app/ble/cps/CpsMeasurementCharacteristic.js new file mode 100644 index 0000000000..c87fcece50 --- /dev/null +++ b/app/ble/cps/CpsMeasurementCharacteristic.js @@ -0,0 +1,95 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +*/ +import bleno from '@abandonware/bleno' +import log from 'loglevel' +import BufferBuilder from '../BufferBuilder.js' + +export const cpsMeasurementFeaturesFlags = { + pedalPowerBalancePresent: (0x01 << 0), + pedalPowerBalanceReference: (0x01 << 1), + accumulatedTorquePresent: (0x01 << 2), + accumulatedTorqueSource: (0x01 << 3), + accumulatedTorqueSourceWheel: (0x00 << 3), + accumulatedTorqueSourceCrank: (0x01 << 3), + wheelRevolutionDataPresent: (0x01 << 4), + crankRevolutionDataPresent: (0x01 << 5), + extremeForceMagnitudesPresent: (0x01 << 6), + extremeTorqueMagnitudesPresent: (0x01 << 7), + extremeAnglesPresent: (0x01 << 8), + topDeadSpotAnglePresent: (0x01 << 9), + bottomDeadSpotAnglePresent: (0x01 << 10), + accumulatedEnergyPresent: (0x01 << 11), + offsetCompensationIndicator: (0x01 << 12) +} + +export default class CyclingPowerMeasurementCharacteristic extends bleno.Characteristic { + constructor () { + super({ + // Cycling Power Meter Measurement + uuid: '2A63', + value: null, + properties: ['notify'], + descriptors: [ + new bleno.Descriptor({ + uuid: '2901', + value: 'Cycling Power Measurement' + }) + ] + }) + this._updateValueCallback = null + this._subscriberMaxValueSize = null + } + + onSubscribe (maxValueSize, updateValueCallback) { + log.debug(`CyclingPowerMeasurementCharacteristic - central subscribed with maxSize: ${maxValueSize}`) + this._updateValueCallback = updateValueCallback + this._subscriberMaxValueSize = maxValueSize + return this.RESULT_SUCCESS + } + + onUnsubscribe () { + log.debug('CyclingPowerMeasurementCharacteristic - central unsubscribed') + this._updateValueCallback = null + this._subscriberMaxValueSize = null + return this.RESULT_UNLIKELY_ERROR + } + + notify (data) { + // ignore events without the mandatory fields + if (!('cyclePower' in data)) { + log.error('can not deliver bike data without mandatory fields') + return this.RESULT_SUCCESS + } + + if (this._updateValueCallback) { + const bufferBuilder = new BufferBuilder() + + // Features flag + bufferBuilder.writeUInt16LE(cpsMeasurementFeaturesFlags.wheelRevolutionDataPresent | cpsMeasurementFeaturesFlags.crankRevolutionDataPresent) + + // Instantaneous Power + bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) + + // Wheel revolution count (basically the distance in cm) + bufferBuilder.writeUInt32LE(Math.round(Math.round(data.totalLinearDistance * 100))) + + // Wheel revolution time (ushort with 2048 resolution, resetting in every 32sec) + bufferBuilder.writeUInt16LE(Math.round(data.totalMovingTime * 2048) % Math.pow(2, 16)) + + // Total stroke count + bufferBuilder.writeUInt16LE(Math.round(data.totalNumberOfStrokes)) + + // last stroke time time (ushort with 1024 resolution, resetting in every 64sec) + bufferBuilder.writeUInt16LE(Math.round(data.driveLastStartTime * 1024) % Math.pow(2, 16)) + + const buffer = bufferBuilder.getBuffer() + if (buffer.length > this._subscriberMaxValueSize) { + log.warn(`CyclingPowerMeasurementCharacteristic - notification of ${buffer.length} bytes is too large for the subscriber`) + } + this._updateValueCallback(bufferBuilder.getBuffer()) + } + return this.RESULT_SUCCESS + } +} diff --git a/app/ble/cps/CyclingPowerMeterService.js b/app/ble/cps/CyclingPowerMeterService.js new file mode 100644 index 0000000000..ac2c811f32 --- /dev/null +++ b/app/ble/cps/CyclingPowerMeterService.js @@ -0,0 +1,66 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +*/ +import bleno from '@abandonware/bleno' +import BufferBuilder from '../BufferBuilder.js' +import { SensorLocationAsBuffer } from '../common/SensorLocation.js' +import StaticReadCharacteristic from '../common/StaticReadCharacteristic.js' +import CyclingPowerControlPointCharacteristic from './CpsControlPointCharacteristic.js' +import CyclingPowerMeasurementCharacteristic from './CpsMeasurementCharacteristic.js' + +export default class CyclingPowerService extends bleno.PrimaryService { + constructor (controlPointCallback) { + const cpsFeatureBuffer = new BufferBuilder() + cpsFeatureBuffer.writeUInt32LE(featuresFlag) + + const measurementCharacteristic = new CyclingPowerMeasurementCharacteristic() + super({ + // Cycling Power + uuid: '1818', + characteristics: [ + new StaticReadCharacteristic('2A65', 'Cycling Power Feature', cpsFeatureBuffer.getBuffer()), + measurementCharacteristic, + new StaticReadCharacteristic('2A5D', 'Sensor Location', SensorLocationAsBuffer()), + new CyclingPowerControlPointCharacteristic(controlPointCallback) + ] + }) + this.measurementCharacteristic = measurementCharacteristic + } + + notifyData (event) { + this.measurementCharacteristic.notify(event) + } +} + +export const cpsFeaturesFlags = +{ + pedalPowerBalanceSupported: (0x01 << 0), + accumulatedTorqueSupported: (0x01 << 1), + wheelRevolutionDataSupported: (0x01 << 2), + crankRevolutionDataSupported: (0x01 << 3), + extremeMagnitudesSupported: (0x01 << 4), + extremeAnglesSupported: (0x01 << 5), + topAndBottomDeadSpotAnglesSupported: (0x01 << 6), + accumulatedEnergySupported: (0x01 << 7), + offsetCompensationIndicatorSupported: (0x01 << 8), + offsetCompensationSupported: (0x01 << 9), + cyclingPowerMeasurementCharacteristicContentMaskingSupported: (0x01 << 10), + multipleSensorLocationsSupported: (0x01 << 11), + crankLengthAdjustmentSupported: (0x01 << 12), + chainLengthAdjustmentSupported: (0x01 << 13), + chainWeightAdjustmentSupported: (0x01 << 14), + spanLengthAdjustmentSupported: (0x01 << 15), + sensorMeasurementContext: (0x01 << 16), + sensorMeasurementContextForce: (0x00 << 16), + sensorMeasurementContextTorque: (0x01 << 16), + instantaneousMeasurementDirectionSupported: (0x01 << 17), + factoryCalibrationDateSupported: (0x01 << 18), + enhancedOffsetCompensationSupported: (0x01 << 19), + distributeSystemSupportUnspecified: (0x00 << 20), + distributeSystemSupportNotInDistributed: (0x01 << 20), + distributeSystemSupportInDistributed: (0x02 << 20), + distributeSystemSupportRFU: (0x03 << 20) +} + +const featuresFlag = cpsFeaturesFlags.sensorMeasurementContextForce | cpsFeaturesFlags.wheelRevolutionDataSupported | cpsFeaturesFlags.crankRevolutionDataSupported | cpsFeaturesFlags.distributeSystemSupportNotInDistributed diff --git a/app/ble/csc/CscControlPointCharacteristic.js b/app/ble/csc/CscControlPointCharacteristic.js new file mode 100644 index 0000000000..1f9a110b95 --- /dev/null +++ b/app/ble/csc/CscControlPointCharacteristic.js @@ -0,0 +1,29 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + The connected Central can remotely control some parameters or our rowing monitor via this Control Point + + But for our use case proper implementation is not necessary (its mere existence with an empty handler suffice) +*/ +import bleno from '@abandonware/bleno' + +export default class CyclingSpeedCadenceControlPointCharacteristic extends bleno.Characteristic { + constructor (controlPointCallback) { + super({ + // Cycling Speed and Cadence Control Point + uuid: '2A55', + value: null, + properties: ['indicate', 'write'] + }) + + this.controlled = false + if (!controlPointCallback) { throw new Error('controlPointCallback required') } + this.controlPointCallback = controlPointCallback + } + + // Central sends a command to the Control Point + // No need to handle any request to have this working + onWriteRequest (data, offset, withoutResponse, callback) { + } +} diff --git a/app/ble/csc/CscMeasurementCharacteristic.js b/app/ble/csc/CscMeasurementCharacteristic.js new file mode 100644 index 0000000000..60461588c2 --- /dev/null +++ b/app/ble/csc/CscMeasurementCharacteristic.js @@ -0,0 +1,81 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +*/ +import bleno from '@abandonware/bleno' +import log from 'loglevel' +import BufferBuilder from '../BufferBuilder.js' + +export default class CyclingSpeedCadenceMeasurementCharacteristic extends bleno.Characteristic { + constructor () { + super({ + // Cycling Speed and Cadence Measurement + uuid: '2A5B', + value: null, + properties: ['notify'], + descriptors: [ + new bleno.Descriptor({ + uuid: '2901', + value: 'Cycling Speed and Cadence Measurement' + }) + ] + }) + this._updateValueCallback = null + this._subscriberMaxValueSize = null + } + + onSubscribe (maxValueSize, updateValueCallback) { + log.debug(`CyclingSpeedCadenceMeasurementCharacteristic - central subscribed with maxSize: ${maxValueSize}`) + this._updateValueCallback = updateValueCallback + this._subscriberMaxValueSize = maxValueSize + return this.RESULT_SUCCESS + } + + onUnsubscribe () { + log.debug('CyclingSpeedCadenceMeasurementCharacteristic - central unsubscribed') + this._updateValueCallback = null + this._subscriberMaxValueSize = null + return this.RESULT_UNLIKELY_ERROR + } + + notify (data) { + // ignore events without the mandatory fields + if (!('cyclePower' in data)) { + log.error('can not deliver bike data without mandatory fields') + return this.RESULT_SUCCESS + } + + if (this._updateValueCallback) { + const bufferBuilder = new BufferBuilder() + + // Features flag + bufferBuilder.writeUInt8(cscFeaturesFlags.crankRevolutionDataSupported | cscFeaturesFlags.wheelRevolutionDataSupported) + + // Wheel revolution count (basically the distance in cm) + bufferBuilder.writeUInt32LE(Math.round(Math.round(data.totalLinearDistance * 100))) + + // Wheel revolution time (ushort with 1024 resolution, resetting in every 64sec) + bufferBuilder.writeUInt16LE(Math.round(data.totalMovingTime * 1024) % Math.pow(2, 16)) + + // Total stroke count + bufferBuilder.writeUInt16LE(Math.round(data.totalNumberOfStrokes)) + + // last stroke time time (ushort with 1024 resolution, resetting in every 64sec) + bufferBuilder.writeUInt16LE(Math.round(data.driveLastStartTime * 1024) % Math.pow(2, 16)) + + const buffer = bufferBuilder.getBuffer() + if (buffer.length > this._subscriberMaxValueSize) { + log.warn(`CyclingSpeedCadenceMeasurementCharacteristic - notification of ${buffer.length} bytes is too large for the subscriber`) + } + this._updateValueCallback(bufferBuilder.getBuffer()) + } + return this.RESULT_SUCCESS + } +} + +export const cscFeaturesFlags = +{ + wheelRevolutionDataSupported: (0x01 << 0), + crankRevolutionDataSupported: (0x01 << 1), + multipleSensorLocationSupported: (0x01 << 2) +} diff --git a/app/ble/csc/CyclingSpeedCadenceService.js b/app/ble/csc/CyclingSpeedCadenceService.js new file mode 100644 index 0000000000..261b38505f --- /dev/null +++ b/app/ble/csc/CyclingSpeedCadenceService.js @@ -0,0 +1,36 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +*/ +import bleno from '@abandonware/bleno' +import BufferBuilder from '../BufferBuilder.js' +import { SensorLocationAsBuffer } from '../common/SensorLocation.js' +import StaticReadCharacteristic from '../common/StaticReadCharacteristic.js' +import CyclingSpeedCadenceControlPointCharacteristic from './CscControlPointCharacteristic.js' +import CyclingSpeedCadenceMeasurementCharacteristic, { cscFeaturesFlags } from './CscMeasurementCharacteristic.js' + +export default class CyclingSpeedCadenceService extends bleno.PrimaryService { + constructor (controlPointCallback) { + const cscFeatureBuffer = new BufferBuilder() + cscFeatureBuffer.writeUInt16LE(featuresFlag) + + const measurementCharacteristic = new CyclingSpeedCadenceMeasurementCharacteristic() + super({ + // Cycling Speed and Cadence + uuid: '1816', + characteristics: [ + new StaticReadCharacteristic('2A5C', 'Cycling Speed and Cadence Feature', cscFeatureBuffer.getBuffer()), + measurementCharacteristic, + new CyclingSpeedCadenceControlPointCharacteristic(controlPointCallback), + new StaticReadCharacteristic('2A5D', 'Sensor Location', SensorLocationAsBuffer()) + ] + }) + this.measurementCharacteristic = measurementCharacteristic + } + + notifyData (event) { + this.measurementCharacteristic.notify(event) + } +} + +const featuresFlag = cscFeaturesFlags.crankRevolutionDataSupported | cscFeaturesFlags.wheelRevolutionDataSupported diff --git a/app/ble/ftms/DeviceInformationService.js b/app/ble/ftms/DeviceInformationService.js deleted file mode 100644 index 28f2f64803..0000000000 --- a/app/ble/ftms/DeviceInformationService.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - todo: Could provide some info on the device here, maybe OS, Node version etc... -*/ -import bleno from '@abandonware/bleno' - -export default class DeviceInformationService extends bleno.PrimaryService { - constructor (controlPointCallback) { - super({ - // uuid of "Device Information Service" - uuid: '180a', - characteristics: [ - ] - }) - } -} diff --git a/app/ble/ftms/IndoorBikeDataCharacteristic.js b/app/ble/ftms/IndoorBikeDataCharacteristic.js index 141a49cdd5..9a1b71c017 100644 --- a/app/ble/ftms/IndoorBikeDataCharacteristic.js +++ b/app/ble/ftms/IndoorBikeDataCharacteristic.js @@ -50,7 +50,7 @@ export default class IndoorBikeDataCharacteristic extends bleno.Characteristic { notify (data) { // ignore events without the mandatory fields - if (!('speed' in data)) { + if (!('cycleLinearVelocity' in data)) { log.error('can not deliver bike data without mandatory fields') return this.RESULT_SUCCESS } @@ -68,26 +68,26 @@ export default class IndoorBikeDataCharacteristic extends bleno.Characteristic { // see https://www.bluetooth.com/specifications/specs/gatt-specification-supplement-3/ // for some of the data types // Instantaneous Speed in km/h - bufferBuilder.writeUInt16LE(Math.round(data.speed * 100)) + bufferBuilder.writeUInt16LE(data.cycleLinearVelocity * 3.6 * 100) // Instantaneous Cadence in rotations per minute (we use this to communicate the strokes per minute) - bufferBuilder.writeUInt16LE(Math.round(data.strokesPerMinute * 2)) + bufferBuilder.writeUInt16LE(Math.round(data.cycleStrokeRate * 2)) // Total Distance in meters - bufferBuilder.writeUInt24LE(Math.round(data.distanceTotal)) + bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance)) // Instantaneous Power in watts - bufferBuilder.writeUInt16LE(Math.round(data.power)) + bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) // Energy // Total energy in kcal - bufferBuilder.writeUInt16LE(Math.round(data.caloriesTotal)) + bufferBuilder.writeUInt16LE(Math.round(data.totalCalories)) // Energy per hour // The Energy per Hour field represents the average expended energy of a user during a // period of one hour. - bufferBuilder.writeUInt16LE(Math.round(data.caloriesPerHour)) + bufferBuilder.writeUInt16LE(Math.round(data.totalCaloriesPerHour)) // Energy per minute - bufferBuilder.writeUInt8(Math.round(data.caloriesPerMinute)) + bufferBuilder.writeUInt8(Math.round(data.totalCaloriesPerMinute)) // Heart Rate: Beats per minute with a resolution of 1 bufferBuilder.writeUInt8(Math.round(data.heartrate)) // Elapsed Time: Seconds with a resolution of 1 - bufferBuilder.writeUInt16LE(Math.round(data.durationTotal)) + bufferBuilder.writeUInt16LE(Math.round(data.totalMovingTime)) const buffer = bufferBuilder.getBuffer() if (buffer.length > this._subscriberMaxValueSize) { diff --git a/app/ble/ftms/RowerDataCharacteristic.js b/app/ble/ftms/RowerDataCharacteristic.js index 6f9c63aa0d..a3a376266e 100644 --- a/app/ble/ftms/RowerDataCharacteristic.js +++ b/app/ble/ftms/RowerDataCharacteristic.js @@ -43,7 +43,7 @@ export default class RowerDataCharacteristic extends bleno.Characteristic { notify (data) { // ignore events without the mandatory fields - if (!('strokesPerMinute' in data && 'strokesTotal' in data)) { + if (!('cycleStrokeRate' in data && 'totalNumberOfStrokes' in data)) { return this.RESULT_SUCCESS } @@ -62,32 +62,32 @@ export default class RowerDataCharacteristic extends bleno.Characteristic { // see https://www.bluetooth.com/specifications/specs/gatt-specification-supplement-3/ // for some of the data types // Stroke Rate in stroke/minute, value is multiplied by 2 to have a .5 precision - bufferBuilder.writeUInt8(Math.round(data.strokesPerMinute * 2)) + bufferBuilder.writeUInt8(Math.round(data.cycleStrokeRate * 2)) // Stroke Count - bufferBuilder.writeUInt16LE(Math.round(data.strokesTotal)) + bufferBuilder.writeUInt16LE(Math.round(data.totalNumberOfStrokes)) // Total Distance in meters - bufferBuilder.writeUInt24LE(Math.round(data.distanceTotal)) + bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance)) // Instantaneous Pace in seconds/500m // if split is infinite (i.e. while pausing), should use the highest possible number (0xFFFF) // todo: eventhough mathematically correct, setting 0xFFFF (65535s) causes some ugly spikes // in some applications which could shift the axis (i.e. workout diagrams in MyHomeFit) // so instead for now we use 0 here - bufferBuilder.writeUInt16LE(data.split !== Infinity ? Math.round(data.split) : 0) + bufferBuilder.writeUInt16LE(data.cyclePace !== Infinity && data.cyclePace < 65535 ? Math.round(data.cyclePace) : 0xFFFF) // Instantaneous Power in watts - bufferBuilder.writeUInt16LE(Math.round(data.power)) + bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) // Energy in kcal // Total energy in kcal - bufferBuilder.writeUInt16LE(Math.round(data.caloriesTotal)) + bufferBuilder.writeUInt16LE(Math.round(data.totalCalories)) // Energy per hour // The Energy per Hour field represents the average expended energy of a user during a // period of one hour. - bufferBuilder.writeUInt16LE(Math.round(data.caloriesPerHour)) + bufferBuilder.writeUInt16LE(Math.round(data.totalCaloriesPerHour)) // Energy per minute - bufferBuilder.writeUInt8(Math.round(data.caloriesPerMinute)) + bufferBuilder.writeUInt8(Math.round(data.totalCaloriesPerMinute)) // Heart Rate: Beats per minute with a resolution of 1 bufferBuilder.writeUInt8(Math.round(data.heartrate)) // Elapsed Time: Seconds with a resolution of 1 - bufferBuilder.writeUInt16LE(Math.round(data.durationTotal)) + bufferBuilder.writeUInt16LE(Math.round(data.totalMovingTime)) const buffer = bufferBuilder.getBuffer() if (buffer.length > this._subscriberMaxValueSize) { diff --git a/app/ble/pm5/Pm5Constants.js b/app/ble/pm5/Pm5Constants.js index 398701b742..e4c352d4f5 100644 --- a/app/ble/pm5/Pm5Constants.js +++ b/app/ble/pm5/Pm5Constants.js @@ -7,10 +7,11 @@ const constants = { serial: '123456789', model: 'PM5', - name: 'PM5 123456789', - hardwareRevision: '633', - // see https://www.concept2.com/service/monitors/pm5/firmware for available versions - firmwareRevision: '207', + name: 'PM5 123456789 Row', + hardwareRevision: '907', + // See https://www.concept2.com/service/monitors/pm5/firmware for available versions + // please note: hardware versions exclude a software version, and thus might confuse the client + firmwareRevision: '210', manufacturer: 'Concept2', ergMachineType: [0x05] } diff --git a/app/ble/pm5/characteristic/AdditionalStatus.js b/app/ble/pm5/characteristic/AdditionalStatus.js index 0e8dd267c9..2173275976 100644 --- a/app/ble/pm5/characteristic/AdditionalStatus.js +++ b/app/ble/pm5/characteristic/AdditionalStatus.js @@ -38,22 +38,22 @@ export default class AdditionalStatus extends bleno.Characteristic { if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { const bufferBuilder = new BufferBuilder() // elapsedTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(Math.round(data.durationTotal * 100)) + bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) // speed: UInt16LE in 0.001 m/sec - bufferBuilder.writeUInt16LE(Math.round(data.speed * 1000 / 3.6)) + bufferBuilder.writeUInt16LE(Math.round(data.cycleLinearVelocity * 1000)) // strokeRate: UInt8 in strokes/min - bufferBuilder.writeUInt8(Math.round(data.strokesPerMinute)) + bufferBuilder.writeUInt8(Math.round(data.cycleStrokeRate)) // heartrate: UInt8 in bpm, 255 if invalid bufferBuilder.writeUInt8(Math.round(data.heartrate)) // currentPace: UInt16LE in 0.01 sec/500m // if split is infinite (i.e. while pausing), use the highest possible number - bufferBuilder.writeUInt16LE(data.split !== Infinity ? Math.round(data.split * 100) : 0xFFFF) + bufferBuilder.writeUInt16LE(data.cyclePace !== Infinity && data.cyclePace > 0 && data.cyclePace < 655.34 ? data.cyclePace * 100 : 0xFFFF) // averagePace: UInt16LE in 0.01 sec/500m let averagePace = 0 - if (data.distanceTotal && data.distanceTotal !== 0) { - averagePace = data.durationTotal / data.distanceTotal * 500 + if (data.totalLinearDistance && data.totalLinearDistance !== 0) { + averagePace = (data.totalMovingTime / data.totalLinearDistance) * 500 } - bufferBuilder.writeUInt16LE(Math.round(averagePace * 100)) + bufferBuilder.writeUInt16LE(Math.round(Math.min(averagePace * 100, 65535))) // restDistance: UInt16LE bufferBuilder.writeUInt16LE(0) // restTime: UInt24LE in 0.01 sec @@ -62,7 +62,7 @@ export default class AdditionalStatus extends bleno.Characteristic { // the multiplexer uses a slightly different format for the AdditionalStatus // it adds averagePower before the ergMachineType // averagePower: UInt16LE in watts - bufferBuilder.writeUInt16LE(Math.round(data.power)) + bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) } // ergMachineType: 0 TYPE_STATIC_D bufferBuilder.writeUInt8(0) diff --git a/app/ble/pm5/characteristic/AdditionalStatus2.js b/app/ble/pm5/characteristic/AdditionalStatus2.js index 67f54f1650..66ccc66aec 100644 --- a/app/ble/pm5/characteristic/AdditionalStatus2.js +++ b/app/ble/pm5/characteristic/AdditionalStatus2.js @@ -38,17 +38,17 @@ export default class AdditionalStatus2 extends bleno.Characteristic { if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { const bufferBuilder = new BufferBuilder() // elapsedTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(Math.round(data.durationTotal * 100)) + bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) // intervalCount: UInt8 bufferBuilder.writeUInt8(0) if (this._updateValueCallback) { // the multiplexer uses a slightly different format for the AdditionalStatus2 // it skips averagePower before totalCalories // averagePower: UInt16LE in watts - bufferBuilder.writeUInt16LE(Math.round(data.power)) + bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) } - // totalCalories: UInt16LE in cal - bufferBuilder.writeUInt16LE(Math.round(data.caloriesTotal)) + // totalCalories: UInt16LE in kCal + bufferBuilder.writeUInt16LE(Math.round(data.totalCalories)) // splitAveragePace: UInt16LE in 0.01 sec/500m bufferBuilder.writeUInt16LE(0 * 100) // splitAveragePower UInt16LE in watts diff --git a/app/ble/pm5/characteristic/AdditionalStrokeData.js b/app/ble/pm5/characteristic/AdditionalStrokeData.js index 3b6e7bf46a..2a05515806 100644 --- a/app/ble/pm5/characteristic/AdditionalStrokeData.js +++ b/app/ble/pm5/characteristic/AdditionalStrokeData.js @@ -38,22 +38,22 @@ export default class AdditionalStrokeData extends bleno.Characteristic { if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { const bufferBuilder = new BufferBuilder() // elapsedTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(Math.round(data.durationTotal * 100)) + bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) // strokePower: UInt16LE in watts - bufferBuilder.writeUInt16LE(Math.round(data.power)) + bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) // strokeCalories: UInt16LE in cal - bufferBuilder.writeUInt16LE(0) + bufferBuilder.writeUInt16LE(Math.round(data.strokeCalories * 1000)) // strokeCount: UInt16LE - bufferBuilder.writeUInt16LE(Math.round(data.strokesTotal)) + bufferBuilder.writeUInt16LE(Math.round(data.totalNumberOfStrokes)) // projectedWorkTime: UInt24LE in 1 sec - bufferBuilder.writeUInt24LE(0) + bufferBuilder.writeUInt24LE(Math.round(data.cycleProjectedEndTime)) // projectedWorkDistance: UInt24LE in 1 m - bufferBuilder.writeUInt24LE(0) + bufferBuilder.writeUInt24LE(Math.round(data.cycleProjectedEndLinearDistance)) if (!this._updateValueCallback) { // the multiplexer uses a slightly different format for the AdditionalStrokeData // it adds workPerStroke at the end - // workPerStroke: UInt16LE - bufferBuilder.writeUInt16LE(0) + // workPerStroke: UInt16LE in 0.1 Joules + bufferBuilder.writeUInt16LE(Math.round(data.strokeWork * 10)) } if (this._updateValueCallback) { diff --git a/app/ble/pm5/characteristic/GeneralStatus.js b/app/ble/pm5/characteristic/GeneralStatus.js index 2748b41ba7..c0116ee038 100644 --- a/app/ble/pm5/characteristic/GeneralStatus.js +++ b/app/ble/pm5/characteristic/GeneralStatus.js @@ -38,27 +38,27 @@ export default class GeneralStatus extends bleno.Characteristic { if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { const bufferBuilder = new BufferBuilder() // elapsedTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(Math.round(data.durationTotal * 100)) + bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) // distance: UInt24LE in 0.1 m - bufferBuilder.writeUInt24LE(Math.round(data.distanceTotal * 10)) - // workoutType: UInt8 will always use 0 (WORKOUTTYPE_JUSTROW_NOSPLITS) - bufferBuilder.writeUInt8(0) + bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance * 10)) + // workoutType: UInt8 0 WORKOUTTYPE_JUSTROW_NOSPLITS, 2 WORKOUTTYPE_FIXEDDIST_NOSPLITS, 4 WORKOUTTYPE_FIXEDTIME_NOSPLITS + bufferBuilder.writeUInt8(data.sessiontype === 'Distance' ? 2 : (data.sessiontype === 'Time' ? 4 : 0)) // intervalType: UInt8 will always use 255 (NONE) bufferBuilder.writeUInt8(255) // workoutState: UInt8 0 WAITTOBEGIN, 1 WORKOUTROW, 10 WORKOUTEND - bufferBuilder.writeUInt8(data.sessionState === 'rowing' ? 1 : (data.sessionState === 'waitingForStart' ? 0 : 10)) + bufferBuilder.writeUInt8(data.sessionStatus === 'Rowing' ? 1 : (data.sessionStatus === 'WaitingForStart' ? 0 : 10)) // rowingState: UInt8 0 INACTIVE, 1 ACTIVE - bufferBuilder.writeUInt8(data.sessionState === 'rowing' ? 1 : 0) + bufferBuilder.writeUInt8(data.sessionStatus === 'Rowing' ? 1 : 0) // strokeState: UInt8 2 DRIVING, 4 RECOVERY - bufferBuilder.writeUInt8(data.strokeState === 'DRIVING' ? 2 : 4) + bufferBuilder.writeUInt8(data.strokeState === 'WaitingForDrive' ? 0 : (data.strokeState === 'Drive' ? 2 : 4)) // totalWorkDistance: UInt24LE in 1 m - bufferBuilder.writeUInt24LE(Math.round(data.distanceTotal)) + bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance)) // workoutDuration: UInt24LE in 0.01 sec (if type TIME) - bufferBuilder.writeUInt24LE(0 * 100) - // workoutDurationType: UInt8 0 TIME, 1 CALORIES, 2 DISTANCE, 3 WATTS - bufferBuilder.writeUInt8(0) + bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) + // workoutDurationType: UInt8 0 TIME, 0x40 CALORIES, 0x80 DISTANCE, 0xC0 WATTS + bufferBuilder.writeUInt8(data.sessiontype === 'Distance' ? 0x80 : 0) // dragFactor: UInt8 - bufferBuilder.writeUInt8(0) + bufferBuilder.writeUInt8(Math.round(Math.min(data.dragFactor, 255))) if (this._updateValueCallback) { this._updateValueCallback(bufferBuilder.getBuffer()) diff --git a/app/ble/pm5/characteristic/StrokeData.js b/app/ble/pm5/characteristic/StrokeData.js index ededdb224b..4f69bda2e9 100644 --- a/app/ble/pm5/characteristic/StrokeData.js +++ b/app/ble/pm5/characteristic/StrokeData.js @@ -39,28 +39,28 @@ export default class StrokeData extends bleno.Characteristic { if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { const bufferBuilder = new BufferBuilder() // elapsedTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(Math.round(data.durationTotal * 100)) + bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) // distance: UInt24LE in 0.1 m - bufferBuilder.writeUInt24LE(Math.round(data.distanceTotal * 10)) + bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance * 10)) // driveLength: UInt8 in 0.01 m - bufferBuilder.writeUInt8(0 * 100) + bufferBuilder.writeUInt8(Math.round(data.driveLength * 100)) // driveTime: UInt8 in 0.01 s - bufferBuilder.writeUInt8(0 * 100) + bufferBuilder.writeUInt8(Math.round(data.driveDuration * 100)) // strokeRecoveryTime: UInt16LE in 0.01 s - bufferBuilder.writeUInt16LE(0 * 100) + bufferBuilder.writeUInt16LE(Math.round(data.recoveryDuration * 100)) // strokeDistance: UInt16LE in 0.01 s - bufferBuilder.writeUInt16LE(0 * 100) - // peakDriveForce: UInt16LE in 0.1 watts - bufferBuilder.writeUInt16LE(0 * 10) - // averageDriveForce: UInt16LE in 0.1 watts - bufferBuilder.writeUInt16LE(0 * 10) + bufferBuilder.writeUInt16LE(Math.round(data.cycleDistance * 100)) + // peakDriveForce: UInt16LE in 0.1 lbs + bufferBuilder.writeUInt16LE(Math.round(data.drivePeakHandleForce * 0.224809 * 10)) + // averageDriveForce: UInt16LE in 0.1 lbs + bufferBuilder.writeUInt16LE(Math.round(data.driveAverageHandleForce * 0.224809 * 10)) if (this._updateValueCallback) { // workPerStroke is only added if data is not send via multiplexer - // workPerStroke: UInt16LE - bufferBuilder.writeUInt16LE(0) + // workPerStroke: UInt16LE in 0.1 Joules + bufferBuilder.writeUInt16LE(Math.round(data.strokeWork * 10)) } // strokeCount: UInt16LE - bufferBuilder.writeUInt16LE(data.strokesTotal) + bufferBuilder.writeUInt16LE(data.totalNumberOfStrokes) if (this._updateValueCallback) { this._updateValueCallback(bufferBuilder.getBuffer()) } else { diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index 8eb53597a4..109cdfa4f4 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -103,14 +103,20 @@ export class DashboardActions extends AppElement { peripheralMode () { const value = this.appState?.config?.peripheralMode - if (value === 'PM5') { - return 'C2 PM5' - } else if (value === 'FTMSBIKE') { - return 'FTMS Bike' - } else if (value === 'FTMS') { - return 'FTMS Rower' - } else { - return '' + + switch (value) { + case 'PM5': + return 'C2 PM5' + case 'FTMSBIKE': + return 'FTMS Bike' + case 'CSC': + return 'BLE Bike Speed + Cadence' + case 'CPS': + return 'BLE Bike Power' + case 'FTMS': + return 'FTMS Rower' + default: + return '' } } diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index 0d04013f78..a37fcb41fc 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -54,10 +54,10 @@ export class PerformanceDashboard extends AppElement { render () { const metrics = this.calculateFormattedMetrics(this.appState.metrics) return html` - - - - + + + + ${metrics?.heartrate?.value ? html` @@ -68,9 +68,9 @@ export class PerformanceDashboard extends AppElement { : '' } ` - : html``} - - + : html``} + + ` } @@ -79,12 +79,12 @@ export class PerformanceDashboard extends AppElement { // we could split this up to make it more readable and testable calculateFormattedMetrics (metrics) { const fieldFormatter = { - distanceTotal: (value) => value >= 10000 - ? { value: (value / 1000).toFixed(1), unit: 'km' } + totalLinearDistanceFormatted: (value) => value >= 10000 + ? { value: (value / 1000).toFixed(2), unit: 'km' } : { value: Math.round(value), unit: 'm' }, - caloriesTotal: (value) => Math.round(value), - power: (value) => Math.round(value), - strokesPerMinute: (value) => Math.round(value) + totalCalories: (value) => Math.round(value), + cyclePower: (value) => Math.round(value), + cycleStrokeRate: (value) => Math.round(value) } const formattedMetrics = {} diff --git a/app/client/lib/app.js b/app/client/lib/app.js index 90f58019fe..86da9f67b7 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -8,8 +8,8 @@ import NoSleep from 'nosleep.js' import { filterObjectByKeys } from './helper.js' -const rowingMetricsFields = ['strokesTotal', 'distanceTotal', 'caloriesTotal', 'power', 'heartrate', - 'heartrateBatteryLevel', 'splitFormatted', 'strokesPerMinute', 'durationTotalFormatted'] +const rowingMetricsFields = ['totalNumberOfStrokes', 'totalLinearDistanceFormatted', 'totalCalories', 'cyclePower', 'heartrate', + 'heartrateBatteryLevel', 'cyclePaceFormatted', 'cycleStrokeRate', 'totalMovingTimeFormatted'] export function createApp (app) { const urlParameters = new URLSearchParams(window.location.search) @@ -76,9 +76,15 @@ export function createApp (app) { } case 'metrics': { let activeFields = rowingMetricsFields - // if we are in reset state only update heart rate - if (data.strokesTotal === 0) { - activeFields = ['heartrate', 'heartrateBatteryLevel'] + // if we are in reset state only update heart rate and peripheral mode + if (data.totalNumberOfStrokes < 1) { + if (data.totalLinearDistanceFormatted > 0) { + activeFields = ['totalLinearDistanceFormatted', 'heartrate', 'heartrateBatteryLevel'] + } else if (data.totalMovingTimeFormatted !== '00:00') { + activeFields = ['totalMovingTimeFormatted', 'heartrate', 'heartrateBatteryLevel'] + } else { + activeFields = ['heartrate', 'heartrateBatteryLevel'] + } } const filteredData = filterObjectByKeys(data, activeFields) diff --git a/app/client/store/appState.js b/app/client/store/appState.js index 3a93f55ebb..12666d7de6 100644 --- a/app/client/store/appState.js +++ b/app/client/store/appState.js @@ -11,7 +11,7 @@ export const APP_STATE = { // contains all the rowing metrics that are delivered from the backend metrics: {}, config: { - // currently can be FTMS, FTMSBIKE or PM5 + // currently can be FTMS, FTMSBIKE, PM5, CSC, CPS peripheralMode: '', // true if upload to strava is enabled stravaUploadEnabled: false, diff --git a/app/engine/Flywheel.js b/app/engine/Flywheel.js new file mode 100644 index 0000000000..b20b09c1e3 --- /dev/null +++ b/app/engine/Flywheel.js @@ -0,0 +1,361 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This models the flywheel with all of its attributes, which we can also test for being powered + + All times and distances are defined as being before the beginning of the flank, as RowingEngine's metrics + solely depend on times and angular positions before the flank (as they are to be certain to belong to a specific + drive or recovery phase). + + Please note: The array contains a buffer of flankLenght measured currentDt's, BEFORE they are actually processed + + Please note2: This implements Linear regression to obtain the drag factor. We deliberatly DO NOT include the flank data + as we don't know wether they will belong to a Drive or Recovery phase. So we include things which we know for certain that + are part of a specific phase, i.e. dirtyDataPoints[flankLength], which will be eliminated from the flank + + The calculation of angular velocity and acceleration is based on Quadratic Regression, as the second derivative tends to be + quite fragile when small errors are thrown in the mix. The math behind this approach can be found in https://physics.info/motion-equations/ + which is intended for simple linear motion, but the formula are identical when applied to angular distances, velocities and + accelerations. +*/ + +import loglevel from 'loglevel' +import { createStreamFilter } from './utils/StreamFilter.js' +import { createSeries } from './utils/Series.js' +import { createOLSLinearSeries } from './utils/OLSLinearSeries.js' +import { createTSQuadraticSeries } from './utils/FullTSQuadraticSeries.js' +const log = loglevel.getLogger('RowingEngine') + +function createFlywheel (rowerSettings) { + const angularDisplacementPerImpulse = (2.0 * Math.PI) / rowerSettings.numOfImpulsesPerRevolution + const flankLength = Math.max(3, rowerSettings.flankLength) + const minimumDragFactorSamples = Math.floor(rowerSettings.minimumRecoveryTime / rowerSettings.maximumTimeBetweenImpulses) + const minumumTorqueBeforeStroke = rowerSettings.minumumForceBeforeStroke * (rowerSettings.sprocketRadius / 100) + const currentDt = createStreamFilter(rowerSettings.smoothing, rowerSettings.maximumTimeBetweenImpulses) + const _deltaTime = createOLSLinearSeries(flankLength) + const _angularDistance = createTSQuadraticSeries(flankLength) + const _angularVelocityMatrix = [] + const _angularAccelerationMatrix = [] + const drag = createStreamFilter(rowerSettings.dragFactorSmoothing, (rowerSettings.dragFactor / 1000000)) + const recoveryDeltaTime = createOLSLinearSeries() + const strokedetectionMinimalGoodnessOfFit = rowerSettings.minimumStrokeQuality + const minumumRecoverySlope = createStreamFilter(rowerSettings.dragFactorSmoothing, rowerSettings.minumumRecoverySlope) + let _deltaTimeBeforeFlank + let _angularVelocityAtBeginFlank + let _angularVelocityBeforeFlank + let _angularAccelerationAtBeginFlank + let _angularAccelerationBeforeFlank + let _torqueAtBeginFlank + let _torqueBeforeFlank + let inRecoveryPhase + let maintainMetrics + let totalNumberOfImpulses + let totalTimeSpinning + let currentCleanTime + let currentRawTime + let currentAngularDistance + reset() + + function pushValue (dataPoint) { + if (dataPoint > rowerSettings.maximumStrokeTimeBeforePause || dataPoint < 0) { + // This typicaly happends after a pause, we need to fix this as it throws off all time calculations + log.debug(`*** WARNING: currentDt of ${dataPoint} sec isn't between 0 and maximumStrokeTimeBeforePause (${rowerSettings.maximumStrokeTimeBeforePause} sec)`) + dataPoint = currentDt.clean() + } + + if (dataPoint > rowerSettings.maximumTimeBetweenImpulses && maintainMetrics) { + // This shouldn't happen, but let's log it to clarify there is some issue going on here + log.debug(`*** WARNING: currentDt of ${dataPoint} sec is above maximumTimeBetweenImpulses (${rowerSettings.maximumTimeBetweenImpulses} sec)`) + } + + if (dataPoint < rowerSettings.minimumTimeBetweenImpulses && maintainMetrics) { + // This shouldn't happen, but let's log it to clarify there is some issue going on here + log.debug(`*** WARNING: currentDt of ${dataPoint} sec is above minimumTimeBetweenImpulses (${rowerSettings.minimumTimeBetweenImpulses} sec)`) + } + + currentDt.push(dataPoint) + + if (maintainMetrics && (_deltaTime.length() >= flankLength)) { + // If we maintain metrics, update the angular position, spinning time of the flywheel and the associated metrics, + // Also we nend feed the Drag calculation. We need to do this, BEFORE the array shifts, as the valueAtSeriesBeginvalue + // value before the shift is certain to be part of a specific rowing phase (i.e. Drive or Recovery), once the buffer is filled completely + totalNumberOfImpulses += 1 + _deltaTimeBeforeFlank = _deltaTime.yAtSeriesBegin() + totalTimeSpinning += _deltaTimeBeforeFlank + _angularVelocityBeforeFlank = _angularVelocityAtBeginFlank + _angularAccelerationBeforeFlank = _angularAccelerationAtBeginFlank + _torqueBeforeFlank = _torqueAtBeginFlank + + // Feed the drag calculation, as we didn't reset the Semaphore in the previous cycle based on the current flank + if (inRecoveryPhase) { + recoveryDeltaTime.push(totalTimeSpinning, _deltaTimeBeforeFlank) + } + } else { + _deltaTimeBeforeFlank = 0 + _angularVelocityBeforeFlank = 0 + _angularAccelerationBeforeFlank = 0 + _torqueBeforeFlank = 0 + } + + // Let's feed the stroke detection algorithm + // Please note that deltaTime MUST use dirty data to be ale to use the OLS algorithms effictively (Otherwise the Goodness of Fit can't be used as a filter!) + currentRawTime += currentDt.raw() + currentAngularDistance += angularDisplacementPerImpulse + _deltaTime.push(currentRawTime, currentDt.raw()) + + // Next are the metrics that are needed for more advanced metrics, like the foce curve + currentCleanTime += currentDt.clean() + _angularDistance.push(currentCleanTime, currentAngularDistance) + + // Let's update the matrix and calculate the angular velocity and acceleration + if (_angularVelocityMatrix.length >= flankLength) { + // The angularVelocityMatrix has reached its maximum length + _angularVelocityMatrix.shift() + _angularAccelerationMatrix.shift() + } + + // Let's make room for a new set of values for angular velocity and acceleration + _angularVelocityMatrix[_angularVelocityMatrix.length] = createSeries(flankLength) + _angularAccelerationMatrix[_angularAccelerationMatrix.length] = createSeries(flankLength) + + let i = 0 + while (i < _angularVelocityMatrix.length) { + _angularVelocityMatrix[i].push(_angularDistance.firstDerivativeAtPosition(i)) + _angularAccelerationMatrix[i].push(_angularDistance.secondDerivativeAtPosition(i)) + i++ + } + + _angularVelocityAtBeginFlank = _angularVelocityMatrix[0].median() + _angularAccelerationAtBeginFlank = _angularAccelerationMatrix[0].median() + + // And finally calculate the torque + _torqueAtBeginFlank = (rowerSettings.flywheelInertia * _angularAccelerationAtBeginFlank + drag.clean() * Math.pow(_angularVelocityAtBeginFlank, 2)) + } + + function maintainStateOnly () { + maintainMetrics = false + } + + function maintainStateAndMetrics () { + maintainMetrics = true + } + + function markRecoveryPhaseStart () { + inRecoveryPhase = true + recoveryDeltaTime.reset() + } + + function markRecoveryPhaseCompleted () { + // Completion of the recovery phase + inRecoveryPhase = false + + // Calculation of the drag-factor + if (rowerSettings.autoAdjustDragFactor && recoveryDeltaTime.length() > minimumDragFactorSamples && recoveryDeltaTime.slope() > 0 && (!drag.reliable() || recoveryDeltaTime.goodnessOfFit() >= rowerSettings.minimumDragQuality)) { + drag.push(slopeToDrag(recoveryDeltaTime.slope())) + log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, no. samples: ${recoveryDeltaTime.length()}, Goodness of Fit: ${recoveryDeltaTime.goodnessOfFit().toFixed(4)}`) + if (rowerSettings.autoAdjustRecoverySlope) { + // We are allowed to autoadjust stroke detection slope as well, so let's do that + minumumRecoverySlope.push((1 - rowerSettings.autoAdjustRecoverySlopeMargin) * recoveryDeltaTime.slope()) + log.debug(`*** Calculated recovery slope: ${recoveryDeltaTime.slope().toFixed(6)}, Goodness of Fit: ${recoveryDeltaTime.goodnessOfFit().toFixed(4)}`) + } else { + // We aren't allowed to adjust the slope, let's report the slope to help help the user configure it + log.debug(`*** Calculated recovery slope: ${recoveryDeltaTime.slope().toFixed(6)}, Goodness of Fit: ${recoveryDeltaTime.goodnessOfFit().toFixed(4)}, not used as autoAdjustRecoverySlope isn't set to true`) + } + } else { + if (!rowerSettings.autoAdjustDragFactor) { + // autoAdjustDampingConstant = false, thus the update is skipped, but let's log the dragfactor anyway + log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, slope: ${recoveryDeltaTime.slope().toFixed(8)}, not used because autoAdjustDragFactor is not true`) + } else { + log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, not used because reliability was too low. no. samples: ${recoveryDeltaTime.length()}, fit: ${recoveryDeltaTime.goodnessOfFit().toFixed(4)}`) + } + } + } + + function spinningTime () { + // This function returns the time the flywheel is spinning in seconds BEFORE the beginning of the flank + return totalTimeSpinning + } + + function deltaTime () { + return _deltaTimeBeforeFlank + } + + function angularPosition () { + // This function returns the absolute angular position of the flywheel in Radians BEFORE the beginning of the flank + return totalNumberOfImpulses * angularDisplacementPerImpulse + } + + function angularVelocity () { + // This function returns the angular velocity of the flywheel in Radians/sec BEFORE the flank + if (maintainMetrics && (_deltaTime.length() >= flankLength)) { + return Math.max(0, _angularVelocityBeforeFlank) + } else { + return 0 + } + } + + function angularAcceleration () { + // This function returns the angular acceleration of the flywheel in Radians/sec^2 BEFORE the flanl + if (maintainMetrics && (_deltaTime.length() >= flankLength)) { + return _angularAccelerationBeforeFlank + } else { + return 0 + } + } + + function torque () { + if (maintainMetrics && (_deltaTime.length() >= flankLength)) { + return _torqueBeforeFlank + } else { + return 0 + } + } + + function dragFactor () { + // Ths function returns the current dragfactor of the flywheel + return drag.clean() + } + + function isDwelling () { + // Check if the flywheel is spinning down beyond a recovery phase indicating that the rower has stopped rowing + // We conclude this based on + // * A decelerating flywheel as the slope of the CurrentDt's goes up + // * All CurrentDt's in the flank are above the maximum + if (_deltaTime.slope() > 0 && deltaTimesAbove(rowerSettings.maximumTimeBetweenImpulses)) { + return true + } else { + return false + } + } + + function isAboveMinimumSpeed () { + // Check if the flywheel has reached its minimum speed. We conclude this based on all CurrentDt's in the flank are below + // the maximum, indicating a sufficiently fast flywheel + if (deltaTimesEqualorBelow(rowerSettings.maximumTimeBetweenImpulses)) { + return true + } else { + return false + } + } + + function isUnpowered () { + if ((deltaTimeSlopeAbove(minumumRecoverySlope.clean()) || torqueAbsent()) && _deltaTime.length() >= flankLength) { + // We reached the minimum number of increasing currentDt values + return true + } else { + return false + } + } + + function isPowered () { + if ((deltaTimeSlopeBelow(minumumRecoverySlope.clean()) && torquePresent()) || _deltaTime.length() < flankLength) { + return true + } else { + return false + } + } + + function deltaTimesAbove (threshold) { + if (_deltaTime.numberOfYValuesAbove(threshold) === flankLength) { + return true + } else { + return false + } + } + + function deltaTimesEqualorBelow (threshold) { + if (_deltaTime.numberOfYValuesEqualOrBelow(threshold) === flankLength) { + return true + } else { + return false + } + } + + function deltaTimeSlopeBelow (threshold) { + // This is a typical indication that the flywheel is accelerating. We use the slope of successive currentDt's + // A (more) negative slope indicates a powered flywheel. When set to 0, it determines whether the DeltaT's are decreasing + // When set to a value below 0, it will become more stringent. In automatic, a percentage of the current slope (i.e. dragfactor) is used + if (_deltaTime.slope() < threshold && _deltaTime.length() >= flankLength) { + return true + } else { + return false + } + } + + function deltaTimeSlopeAbove (threshold) { + // This is a typical indication that the flywheel is deccelerating. We use the slope of successive currentDt's + // A (more) positive slope indicates a unpowered flywheel. When set to 0, it determines whether the DeltaT's are increasing + // When set to a value below 0, it will become more stringent as it will detect a power inconsistent with the drag + // Typically, a percentage of the current slope (i.e. dragfactor) is use + if (_deltaTime.slope() >= threshold && _deltaTime.goodnessOfFit() >= strokedetectionMinimalGoodnessOfFit && _deltaTime.length() >= flankLength) { + return true + } else { + return false + } + } + + function torquePresent () { + // This is a typical indication that the flywheel is decelerating which might work on some machines: successive currentDt's are increasing + if (_torqueAtBeginFlank > minumumTorqueBeforeStroke) { + return true + } else { + return false + } + } + + function torqueAbsent () { + // This is a typical indication that the flywheel is Accelerating which might work on some machines: successive currentDt's are decreasing + if (_torqueAtBeginFlank < minumumTorqueBeforeStroke) { + return true + } else { + return false + } + } + + function slopeToDrag (slope) { + return ((slope * rowerSettings.flywheelInertia) / angularDisplacementPerImpulse) + } + + function reset () { + maintainMetrics = false + inRecoveryPhase = false + drag.reset() + recoveryDeltaTime.reset() + _deltaTime.reset() + _angularDistance.reset() + totalNumberOfImpulses = 0 + totalTimeSpinning = 0 + currentCleanTime = 0 + currentRawTime = 0 + currentAngularDistance = 0 + _deltaTime.push(0, 0) + _angularDistance.push(0, 0) + _deltaTimeBeforeFlank = 0 + _angularVelocityBeforeFlank = 0 + _angularAccelerationBeforeFlank = 0 + _torqueAtBeginFlank = 0 + _torqueBeforeFlank = 0 + } + + return { + pushValue, + maintainStateOnly, + maintainStateAndMetrics, + markRecoveryPhaseStart, + markRecoveryPhaseCompleted, + spinningTime, + deltaTime, + angularPosition, + angularVelocity, + angularAcceleration, + torque, + dragFactor, + isDwelling, + isAboveMinimumSpeed, + isUnpowered, + isPowered + } +} + +export { createFlywheel } diff --git a/app/engine/Flywheel.test.js b/app/engine/Flywheel.test.js new file mode 100644 index 0000000000..9e2276ca28 --- /dev/null +++ b/app/engine/Flywheel.test.js @@ -0,0 +1,356 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +*/ +import { test } from 'uvu' +import * as assert from 'uvu/assert' +import { deepMerge } from '../tools/Helper.js' +import { replayRowingSession } from '../tools/RowingRecorder.js' +import rowerProfiles from '../../config/rowerProfiles.js' + +import { createFlywheel } from './Flywheel.js' + +const baseConfig = { + numOfImpulsesPerRevolution: 6, + smoothing: 1, + flankLength: 11, + minimumStrokeQuality: 0.30, + minumumRecoverySlope: 0, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.10, + minumumForceBeforeStroke: 50, + minimumRecoveryTime: 2, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.02, + autoAdjustDragFactor: true, + dragFactorSmoothing: 3, + dragFactor: 100, + minimumDragQuality: 0.83, + flywheelInertia: 0.1, + sprocketRadius: 2 +} + +// Test behaviour for no datapoints +test('Correct Flywheel behaviour at initialisation', () => { + const flywheel = createFlywheel(baseConfig) + testDeltaTime(flywheel, 0) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testAngularVelocity(flywheel, 0) + testAngularAcceleration(flywheel, 0) + testTorque(flywheel, 0) + testDragFactor(flywheel, 0.0001) + testIsDwelling(flywheel, false) + testIsUnpowered(flywheel, false) + testIsPowered(flywheel, true) +}) + +// Test behaviour for one datapoint +// ToDo: Add additional test for testing the behaviour after a single datapoint + +// Test behaviour for perfect upgoing flank +// ToDo: Add additional test to test isDwelling, isUnpowered and isPowered with an upgoing flank + +// Test behaviour for perfect downgoing flank +// ToDo: Add additional test to test isDwelling, isUnpowered and isPowered with an downgoing flank + +// Test behaviour for perfect stroke +test('Correct Flywheel behaviour for a noisefree stroke', () => { + const flywheel = createFlywheel(baseConfig) + flywheel.maintainStateAndMetrics() + testDeltaTime(flywheel, 0) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testAngularVelocity(flywheel, 0) + testAngularAcceleration(flywheel, 0) + testTorque(flywheel, 0) + testDragFactor(flywheel, 0.0001) + testIsDwelling(flywheel, false) + testIsUnpowered(flywheel, false) + testIsPowered(flywheel, true) + flywheel.pushValue(0.011221636) + flywheel.pushValue(0.011175504) + flywheel.pushValue(0.01116456) + flywheel.pushValue(0.011130263) + flywheel.pushValue(0.011082613) + flywheel.pushValue(0.011081761) + flywheel.pushValue(0.011062297) + flywheel.pushValue(0.011051853) + flywheel.pushValue(0.010973313) + flywheel.pushValue(0.010919756) + flywheel.pushValue(0.01086431) + flywheel.pushValue(0.010800864) + flywheel.pushValue(0.010956987) + flywheel.pushValue(0.010653396) + flywheel.pushValue(0.010648619) + flywheel.pushValue(0.010536818) + flywheel.pushValue(0.010526151) + flywheel.pushValue(0.010511225) + flywheel.pushValue(0.010386684) + testDeltaTime(flywheel, 0.011051853) + testSpinningTime(flywheel, 0.088970487) + testAngularPosition(flywheel, 9.42477796076938) + testAngularVelocity(flywheel, 95.27559080008358) + testAngularAcceleration(flywheel, 23.690349229418256) + testTorque(flywheel, 3.276778743172323) + testDragFactor(flywheel, 0.0001) + testIsDwelling(flywheel, false) + testIsUnpowered(flywheel, false) + testIsPowered(flywheel, true) + flywheel.pushValue(0.010769) + flywheel.pushValue(0.010707554) + flywheel.pushValue(0.010722165) + flywheel.pushValue(0.01089567) + flywheel.pushValue(0.010917504) + flywheel.pushValue(0.010997969) + flywheel.pushValue(0.011004655) + flywheel.pushValue(0.011013618) + flywheel.pushValue(0.011058193) + flywheel.pushValue(0.010807149) + flywheel.pushValue(0.0110626) + flywheel.pushValue(0.011090787) + flywheel.pushValue(0.011099509) + flywheel.pushValue(0.011131862) + flywheel.pushValue(0.011209919) + testDeltaTime(flywheel, 0.01089567) + testSpinningTime(flywheel, 0.24984299900000007) + testAngularPosition(flywheel, 25.132741228718345) + testAngularVelocity(flywheel, 96.63189639573201) + testAngularAcceleration(flywheel, -28.68758647905641) + testTorque(flywheel, -1.9349863078020926) + testDragFactor(flywheel, 0.0001) + testIsDwelling(flywheel, false) + testIsUnpowered(flywheel, true) + testIsPowered(flywheel, false) + flywheel.pushValue(0.020769) + flywheel.pushValue(0.020707554) + flywheel.pushValue(0.020722165) + flywheel.pushValue(0.02089567) + flywheel.pushValue(0.020917504) + flywheel.pushValue(0.020997969) + flywheel.pushValue(0.021004655) + flywheel.pushValue(0.021013618) + flywheel.pushValue(0.021058193) + flywheel.pushValue(0.020807149) + flywheel.pushValue(0.0210626) + flywheel.pushValue(0.021090787) + flywheel.pushValue(0.021099509) + flywheel.pushValue(0.021131862) + flywheel.pushValue(0.021209919) + testDeltaTime(flywheel, 0.02089567) + testSpinningTime(flywheel, 0.45433115300000004) + testAngularPosition(flywheel, 40.84070449666731) + testAngularVelocity(flywheel, 50.44417826920988) + testAngularAcceleration(flywheel, -25.426721357529768) + testTorque(flywheel, -2.2882106236273945) + testDragFactor(flywheel, 0.0001) + testIsDwelling(flywheel, true) + testIsUnpowered(flywheel, true) + testIsPowered(flywheel, false) +}) + +// Test behaviour for noisy upgoing flank +// ToDo: Add additional test to test isDwelling, isUnpowered and isPowered with an upgoing flank + +// Test behaviour for noisy downgoing flank +// ToDo: Add additional test to test isDwelling, isUnpowered and isPowered with an downgoing flank + +// Test behaviour for noisy stroke +// ToDo: Add additional test to test isDwelling, isUnpowered and isPowered with an upgoing and downgoing flank + +// Test drag factor calculation +// ToDo: Add additional test to test dragfactor calculation + +// Test Dynamic stroke detection +// ToDo: Add additional test to test isDwelling, isUnpowered and isPowered with an upgoing and downgoing flank with dynamic stroke detection + +// Test behaviour for not maintaining metrics +test('Correct Flywheel behaviour at maintainStateOnly', () => { + const flywheel = createFlywheel(baseConfig) + flywheel.maintainStateAndMetrics() + testDeltaTime(flywheel, 0) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testAngularVelocity(flywheel, 0) + testAngularAcceleration(flywheel, 0) + testTorque(flywheel, 0) + testDragFactor(flywheel, 0.0001) + testIsDwelling(flywheel, false) + testIsUnpowered(flywheel, false) + testIsPowered(flywheel, true) + flywheel.maintainStateOnly() + flywheel.pushValue(0.011221636) + flywheel.pushValue(0.011175504) + flywheel.pushValue(0.01116456) + flywheel.pushValue(0.011130263) + flywheel.pushValue(0.011082613) + flywheel.pushValue(0.011081761) + flywheel.pushValue(0.011062297) + flywheel.pushValue(0.011051853) + flywheel.pushValue(0.010973313) + flywheel.pushValue(0.010919756) + flywheel.pushValue(0.01086431) + flywheel.pushValue(0.010800864) + flywheel.pushValue(0.010956987) + flywheel.pushValue(0.010653396) + flywheel.pushValue(0.010648619) + flywheel.pushValue(0.010536818) + flywheel.pushValue(0.010526151) + flywheel.pushValue(0.010511225) + flywheel.pushValue(0.010386684) + testDeltaTime(flywheel, 0) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testAngularVelocity(flywheel, 0) + testAngularAcceleration(flywheel, 0) + testTorque(flywheel, 0) + testDragFactor(flywheel, 0.0001) + testIsDwelling(flywheel, false) + testIsUnpowered(flywheel, false) + testIsPowered(flywheel, true) + flywheel.pushValue(0.010769) + flywheel.pushValue(0.010707554) + flywheel.pushValue(0.010722165) + flywheel.pushValue(0.01089567) + flywheel.pushValue(0.010917504) + flywheel.pushValue(0.010997969) + flywheel.pushValue(0.011004655) + flywheel.pushValue(0.011013618) + flywheel.pushValue(0.011058193) + flywheel.pushValue(0.010807149) + flywheel.pushValue(0.0110626) + flywheel.pushValue(0.011090787) + flywheel.pushValue(0.011099509) + flywheel.pushValue(0.011131862) + flywheel.pushValue(0.011209919) + testDeltaTime(flywheel, 0) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testAngularVelocity(flywheel, 0) + testAngularAcceleration(flywheel, 0) + testTorque(flywheel, 0) + testDragFactor(flywheel, 0.0001) + testIsDwelling(flywheel, false) + testIsUnpowered(flywheel, true) + testIsPowered(flywheel, false) +}) + +test('Correct Flywheel behaviour with a SportsTech WRX700', async () => { + const flywheel = createFlywheel(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700)) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testDragFactor(flywheel, (rowerProfiles.Sportstech_WRX700.dragFactor / 1000000)) + + // Inject 16 strokes + flywheel.maintainStateAndMetrics() + await replayRowingSession(flywheel.pushValue, { filename: 'recordings/WRX700_2magnets.csv', realtime: false, loop: false }) + testSpinningTime(flywheel, 46.302522627) + testAngularPosition(flywheel, 741.4158662471912) + testDragFactor(flywheel, (rowerProfiles.Sportstech_WRX700.dragFactor / 1000000)) +}) + +test('Correct Flywheel behaviour with a DKN R-320', async () => { + const flywheel = createFlywheel(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.DKN_R320)) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testDragFactor(flywheel, (rowerProfiles.DKN_R320.dragFactor / 1000000)) + + // Inject 10 strokes + flywheel.maintainStateAndMetrics() + await replayRowingSession(flywheel.pushValue, { filename: 'recordings/DKNR320.csv', realtime: false, loop: false }) + + testSpinningTime(flywheel, 22.249536391000003) + testAngularPosition(flywheel, 496.37163926718733) + // As dragfactor is static, it should remain the same + testDragFactor(flywheel, (rowerProfiles.DKN_R320.dragFactor / 1000000)) +}) + +test('Correct Flywheel behaviour with a NordicTrack RX800', async () => { + const flywheel = createFlywheel(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.NordicTrack_RX800)) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testDragFactor(flywheel, (rowerProfiles.NordicTrack_RX800.dragFactor / 1000000)) + + // Inject 10 strokes + flywheel.maintainStateAndMetrics() + await replayRowingSession(flywheel.pushValue, { filename: 'recordings/RX800.csv', realtime: false, loop: false }) + + testSpinningTime(flywheel, 22.65622640199999) + testAngularPosition(flywheel, 1446.7034169780998) + // As we don't detect strokes here (this is a function of Rower.js, the dragcalculation shouldn't be triggered + testDragFactor(flywheel, (rowerProfiles.NordicTrack_RX800.dragFactor / 1000000)) +}) + +test('Correct Flywheel behaviour with a full session on a SportsTech WRX700', async () => { + const flywheel = createFlywheel(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700)) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testDragFactor(flywheel, (rowerProfiles.Sportstech_WRX700.dragFactor / 1000000)) + + // Inject 846 strokes + flywheel.maintainStateAndMetrics() + await replayRowingSession(flywheel.pushValue, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false }) + testSpinningTime(flywheel, 2342.741183077012) + testAngularPosition(flywheel, 37337.82868791469) + // The dragfactor should remain static + testDragFactor(flywheel, (rowerProfiles.Sportstech_WRX700.dragFactor / 1000000)) +}) + +test('A full session for a Concept2 RowErg should produce plausible results', async () => { + const flywheel = createFlywheel(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_RowErg)) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testDragFactor(flywheel, (rowerProfiles.Concept2_RowErg.dragFactor / 1000000)) + + flywheel.maintainStateAndMetrics() + await replayRowingSession(flywheel.pushValue, { filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', realtime: false, loop: false }) + testSpinningTime(flywheel, 591.0432650000008) + testAngularPosition(flywheel, 65961.92655232249) + // As we don't detect strokes here (this is a function of Rower.js, the dragcalculation shouldn't be triggered + testDragFactor(flywheel, (rowerProfiles.Concept2_RowErg.dragFactor / 1000000)) +}) + +// Test behaviour after reset +// ToDo: Add additional test to test isDwelling, isUnpowered and isPowered after a reset + +function testDeltaTime (flywheel, expectedValue) { + assert.ok(flywheel.deltaTime() === expectedValue, `deltaTime should be ${expectedValue} sec at ${flywheel.spinningTime()} sec, is ${flywheel.deltaTime()}`) +} + +function testSpinningTime (flywheel, expectedValue) { + assert.ok(flywheel.spinningTime() === expectedValue, `spinningTime should be ${expectedValue} sec at ${flywheel.spinningTime()} sec, is ${flywheel.spinningTime()}`) +} + +function testAngularPosition (flywheel, expectedValue) { + assert.ok(flywheel.angularPosition() === expectedValue, `angularPosition should be ${expectedValue} Radians at ${flywheel.spinningTime()} sec, is ${flywheel.angularPosition()}`) +} + +function testAngularVelocity (flywheel, expectedValue) { + assert.ok(flywheel.angularVelocity() === expectedValue, `angularVelocity should be ${expectedValue} Radians/sec at ${flywheel.spinningTime()} sec, is ${flywheel.angularVelocity()}`) +} + +function testAngularAcceleration (flywheel, expectedValue) { + assert.ok(flywheel.angularAcceleration() === expectedValue, `angularAcceleration should be ${expectedValue} Radians/sec^2 at ${flywheel.spinningTime()} sec, is ${flywheel.angularAcceleration()}`) +} + +function testTorque (flywheel, expectedValue) { + assert.ok(flywheel.torque() === expectedValue, `Torque should be ${expectedValue} N/M at ${flywheel.spinningTime()} sec, is ${flywheel.torque()}`) +} + +function testDragFactor (flywheel, expectedValue) { + assert.ok(flywheel.dragFactor() === expectedValue, `Drag Factor should be ${expectedValue} N*m*s^2 at ${flywheel.spinningTime()} sec, is ${flywheel.dragFactor()}`) +} + +function testIsDwelling (flywheel, expectedValue) { + assert.ok(flywheel.isDwelling() === expectedValue, `isDwelling should be ${expectedValue} at ${flywheel.spinningTime()} sec, is ${flywheel.isDwelling()}`) +} + +function testIsUnpowered (flywheel, expectedValue) { + assert.ok(flywheel.isUnpowered() === expectedValue, `isUnpowered should be ${expectedValue} at ${flywheel.spinningTime()} sec, is ${flywheel.isUnpowered()}`) +} + +function testIsPowered (flywheel, expectedValue) { + assert.ok(flywheel.isPowered() === expectedValue, `isPowered should be ${expectedValue} at ${flywheel.spinningTime()} sec, is ${flywheel.isPowered()}`) +} + +test.run() diff --git a/app/engine/MovingFlankDetector.js b/app/engine/MovingFlankDetector.js deleted file mode 100644 index 3454eb70e0..0000000000 --- a/app/engine/MovingFlankDetector.js +++ /dev/null @@ -1,193 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - A Detector used to test for up-going and down-going flanks - - Please note: The array contains flankLength + 1 measured currentDt's, thus flankLength number of flanks between them - They are arranged that dataPoints[0] is the youngest, and dataPoints[flankLength] the oldest -*/ -import loglevel from 'loglevel' -import { createMovingAverager } from './averager/MovingAverager.js' -const log = loglevel.getLogger('RowingEngine') - -function createMovingFlankDetector (rowerSettings) { - const angularDisplacementPerImpulse = (2.0 * Math.PI) / rowerSettings.numOfImpulsesPerRevolution - const dirtyDataPoints = new Array(rowerSettings.flankLength + 1) - dirtyDataPoints.fill(rowerSettings.maximumTimeBetweenImpulses) - const cleanDataPoints = new Array(rowerSettings.flankLength + 1) - cleanDataPoints.fill(rowerSettings.maximumTimeBetweenImpulses) - const angularVelocity = new Array(rowerSettings.flankLength + 1) - angularVelocity.fill(angularDisplacementPerImpulse / rowerSettings.minimumTimeBetweenImpulses) - const angularAcceleration = new Array(rowerSettings.flankLength + 1) - angularAcceleration.fill(0.1) - const movingAverage = createMovingAverager(rowerSettings.smoothing, rowerSettings.maximumTimeBetweenImpulses) - let numberOfSequentialCorrections = 0 - const maxNumberOfSequentialCorrections = (rowerSettings.smoothing >= 2 ? rowerSettings.smoothing : 2) - - function pushValue (dataPoint) { - // add the new dataPoint to the array, we have to move data points starting at the oldest ones - let i = rowerSettings.flankLength - while (i > 0) { - // older data points are moved toward the higher numbers - dirtyDataPoints[i] = dirtyDataPoints[i - 1] - cleanDataPoints[i] = cleanDataPoints[i - 1] - angularVelocity[i] = angularVelocity[i - 1] - angularAcceleration[i] = angularAcceleration[i - 1] - i = i - 1 - } - dirtyDataPoints[0] = dataPoint - - // reduce noise in the measurements by applying some sanity checks - // noise filter on the value of dataPoint: it should be within sane levels and should not deviate too much from the previous reading - if (dataPoint < rowerSettings.minimumTimeBetweenImpulses || dataPoint > rowerSettings.maximumTimeBetweenImpulses) { - // impulseTime is outside plausible ranges, so we assume it is close to the previous clean one - log.debug(`noise filter corrected currentDt, ${dataPoint} was not between minimumTimeBetweenImpulses and maximumTimeBetweenImpulses, changed to ${cleanDataPoints[1]}`) - dataPoint = cleanDataPoints[1] - } - - // lets test if pushing this value would fit the curve we are looking for - movingAverage.pushValue(dataPoint) - - if (movingAverage.getAverage() > (rowerSettings.maximumDownwardChange * cleanDataPoints[1]) && movingAverage.getAverage() < (rowerSettings.maximumUpwardChange * cleanDataPoints[1])) { - numberOfSequentialCorrections = 0 - } else { - // impulses are outside plausible ranges - if (numberOfSequentialCorrections <= maxNumberOfSequentialCorrections) { - // We haven't made too many corrections, so we assume it is close to the previous one - log.debug(`noise filter corrected currentDt, ${dataPoint} was too much of an accelleration/decelleration with respect to ${movingAverage.getAverage()}, changed to previous value, ${cleanDataPoints[1]}`) - movingAverage.replaceLastPushedValue(cleanDataPoints[1]) - } else { - // We made too many corrections (typically, one currentDt is too long, the next is to short or vice versa), let's allow the algorithm to pick it up otherwise we might get stuck - log.debug(`noise filter wanted to corrected currentDt (${dataPoint} sec), but it had already made ${numberOfSequentialCorrections} corrections, filter temporarily disabled`) - } - numberOfSequentialCorrections = numberOfSequentialCorrections + 1 - } - - // determine the moving average, to reduce noise - cleanDataPoints[0] = movingAverage.getAverage() - - // determine the derived data - if (cleanDataPoints[0] > 0) { - angularVelocity[0] = angularDisplacementPerImpulse / cleanDataPoints[0] - angularAcceleration[0] = (angularVelocity[0] - angularVelocity[1]) / cleanDataPoints[0] - } else { - log.error('Impuls of 0 seconds encountered, this should not be possible (division by 0 prevented)') - angularVelocity[0] = 0 - angularAcceleration[0] = 0 - } - } - - function isFlywheelUnpowered () { - let numberOfErrors = 0 - if (rowerSettings.naturalDeceleration < 0) { - // A valid natural deceleration of the flywheel has been provided, this has to be maintained for a flank length - // to count as an indication for an unpowered flywheel - // Please note that angularAcceleration[] contains flank-information already, so we need to check from - // rowerSettings.flankLength -1 until 0 flanks - let i = rowerSettings.flankLength - 1 - while (i >= 0) { - if (angularAcceleration[i] > rowerSettings.naturalDeceleration) { - // There seems to be some power present, so we detected an error - numberOfErrors = numberOfErrors + 1 - } - i = i - 1 - } - } else { - // No valid natural deceleration has been provided, we rely on pure deceleration for recovery detection - let i = rowerSettings.flankLength - while (i > 0) { - if (cleanDataPoints[i] >= cleanDataPoints[i - 1]) { - // Oldest interval (dataPoints[i]) is larger than the younger one (datapoint[i-1], as the distance is - // fixed, we are accelerating - numberOfErrors = numberOfErrors + 1 - } - i = i - 1 - } - } - if (numberOfErrors > rowerSettings.numberOfErrorsAllowed) { - return false - } else { - return true - } - } - - function isFlywheelPowered () { - let numberOfErrors = 0 - if (rowerSettings.naturalDeceleration < 0) { - // A valid natural deceleration of the flywheel has been provided, this has to be consistently encountered - // for a flank length to count as an indication of a powered flywheel - // Please note that angularAcceleration[] contains flank-information already, so we need to check from - // rowerSettings.flankLength -1 until 0 flanks - let i = rowerSettings.flankLength - 1 - while (i >= 0) { - if (angularAcceleration[i] < rowerSettings.naturalDeceleration) { - // Some deceleration is below the natural deceleration, so we detected an error - numberOfErrors = numberOfErrors + 1 - } - i = i - 1 - } - } else { - // No valid natural deceleration of the flywheel has been provided, we rely on pure acceleration for stroke detection - let i = rowerSettings.flankLength - while (i > 1) { - if (cleanDataPoints[i] < cleanDataPoints[i - 1]) { - // Oldest interval (dataPoints[i]) is shorter than the younger one (datapoint[i-1], as the distance is fixed, we - // discovered a deceleration - numberOfErrors = numberOfErrors + 1 - } - i = i - 1 - } - if (cleanDataPoints[1] <= cleanDataPoints[0]) { - // We handle the last measurement more specifically: at least the youngest measurement must be really accelerating - // This prevents when the currentDt "flatlines" (i.e. error correction kicks in) a ghost-stroke is detected - numberOfErrors = numberOfErrors + 1 - } - } - if (numberOfErrors > rowerSettings.numberOfErrorsAllowed) { - return false - } else { - return true - } - } - - function timeToBeginOfFlank () { - // We expect the curve to bend between dirtyDataPoints[rowerSettings.flankLength] and dirtyDataPoints[rowerSettings.flankLength+1], - // as acceleration FOLLOWS the start of the pulling the handle, we assume it must have started before that - let i = rowerSettings.flankLength - let total = 0.0 - while (i >= 0) { - total += dirtyDataPoints[i] - i = i - 1 - } - return total - } - - function noImpulsesToBeginFlank () { - return rowerSettings.flankLength - } - - function impulseLengthAtBeginFlank () { - // As this is fed into the speed calculation where small changes have big effects, and we typically use it when - // the curve is in a plateau, we return the cleaned data and not the dirty data - // Regardless of the way to determine the acceleration, cleanDataPoints[rowerSettings.flankLength] is always the - // impulse at the beginning of the flank being investigated - return cleanDataPoints[rowerSettings.flankLength] - } - - function accelerationAtBeginOfFlank () { - return angularAcceleration[rowerSettings.flankLength - 1] - } - - return { - pushValue, - isFlywheelUnpowered, - isFlywheelPowered, - timeToBeginOfFlank, - noImpulsesToBeginFlank, - impulseLengthAtBeginFlank, - accelerationAtBeginOfFlank - } -} - -export { createMovingFlankDetector } diff --git a/app/engine/Rower.js b/app/engine/Rower.js new file mode 100644 index 0000000000..82f73e2523 --- /dev/null +++ b/app/engine/Rower.js @@ -0,0 +1,369 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + The Rowing Engine models the physics of a real rowing boat. + It takes impulses from the flywheel of a rowing machine and estimates + parameters such as energy, stroke rates and movement. + + This implementation uses concepts that are described here: + Physics of Rowing by Anu Dudhia: http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics + Also Dave Vernooy has some good explanations here: https://dvernooy.github.io/projects/ergware +*/ + +import loglevel from 'loglevel' +import { createFlywheel } from './Flywheel.js' +import { createCurveMetrics } from './utils/curveMetrics.js' + +const log = loglevel.getLogger('RowingEngine') + +function createRower (rowerSettings) { + const flywheel = createFlywheel(rowerSettings) + const sprocketRadius = rowerSettings.sprocketRadius / 100 + const driveHandleForce = createCurveMetrics(2) + const driveHandleVelocity = createCurveMetrics(3) + const driveHandlePower = createCurveMetrics(1) + let _strokeState = 'WaitingForDrive' + let _totalNumberOfStrokes = -1.0 + let recoveryPhaseStartTime = 0.0 + let _recoveryDuration = 0.0 + let drivePhaseStartTime = 0.0 + let _driveDuration = 0.0 + let drivePhaseStartAngularPosition = 0.0 + let drivePhaseAngularDisplacement = 0.0 + let _driveLinearDistance = 0.0 + let recoveryPhaseStartAngularPosition = 0.0 + let recoveryPhaseAngularDisplacement = 0.0 + let _recoveryLinearDistance = 0.0 + const minimumCycleDuration = rowerSettings.minimumDriveTime + rowerSettings.minimumRecoveryTime + let _cycleDuration = minimumCycleDuration + let _cycleLinearVelocity = 0.0 + let _cyclePower = 0.0 + let totalLinearDistance = 0.0 + let preliminaryTotalLinearDistance = 0.0 + let _driveLength = 0.0 + + // called if the sensor detected an impulse, currentDt is an interval in seconds + function handleRotationImpulse (currentDt) { + // Provide the flywheel with new data + flywheel.pushValue(currentDt) + + // This is the core of the finite state machine that defines all state transitions + switch (true) { + case (_strokeState === 'Stopped'): + // We are in a stopped state, so don't do anything + break + case (_strokeState === 'WaitingForDrive' && flywheel.isPowered() && flywheel.isAboveMinimumSpeed()): + // We change into the "Drive" phase since were waiting for a drive phase, and we see a clear force exerted on the flywheel + // As we are not certain what caused the "WaitingForDrive", we explicitly start the flywheel maintaining metrics again + log.debug(`*** Rowing (re)started with a DRIVE phase at time: ${flywheel.spinningTime().toFixed(4)} sec`) + flywheel.maintainStateAndMetrics() + _strokeState = 'Drive' + startDrivePhase() + break + case (_strokeState === 'WaitingForDrive'): + // We can't change into the "Drive" phase since we are waiting for a drive phase, but there isn't a clear force exerted on the flywheel. So, there is nothing more to do + break + case (_strokeState === 'Drive' && ((flywheel.spinningTime() - drivePhaseStartTime) >= rowerSettings.minimumDriveTime) && flywheel.isUnpowered()): + // We change into the "Recovery" phase since we have been long enough in the Drive phase, and we see a clear lack of power exerted on the flywheel + log.debug(`*** RECOVERY phase started at time: ${flywheel.spinningTime().toFixed(4)} sec`) + _strokeState = 'Recovery' + endDrivePhase() + startRecoveryPhase() + break + case (_strokeState === 'Drive' && flywheel.isUnpowered()): + // We seem to have lost power to the flywheel, but it is too early according to the settings. We stay in the Drive Phase + log.debug(`Time: ${flywheel.spinningTime().toFixed(4)} sec: Delta Time trend is upwards, suggests no power, but waiting for for drive phase length (${(flywheel.spinningTime() - drivePhaseStartTime).toFixed(4)} sec) to exceed minimumDriveTime (${rowerSettings.minimumDriveTime} sec)`) + updateDrivePhase() + break + case (_strokeState === 'Drive'): + // We stay in the "Drive" phase as the decceleration is lacking + updateDrivePhase() + break + case (_strokeState === 'Recovery' && ((flywheel.spinningTime() - drivePhaseStartTime) >= rowerSettings.maximumStrokeTimeBeforePause) && flywheel.isDwelling()): + // The Flywheel is spinning too slowly to create valid CurrentDt's and the last Drive started over maximumStrokeTime ago, we consider it a pause + log.debug(`*** PAUSED rowing at time: ${flywheel.spinningTime().toFixed(4)} sec, rower hasn't moved in ${(flywheel.spinningTime() - drivePhaseStartTime).toFixed(4)} seconds and flywheel is dwelling`) + flywheel.maintainStateOnly() + _strokeState = 'WaitingForDrive' + endRecoveryPhase() + break + case (_strokeState === 'Recovery' && ((flywheel.spinningTime() - recoveryPhaseStartTime) >= rowerSettings.minimumRecoveryTime) && flywheel.isPowered()): + // We change into the "Drive" phase since we have been long enough in the Recovery phase, and we see a clear force + // exerted on the flywheel + log.debug(`*** DRIVE phase started at time: ${flywheel.spinningTime().toFixed(4)} sec`) + _strokeState = 'Drive' + endRecoveryPhase() + startDrivePhase() + break + case (_strokeState === 'Recovery' && flywheel.isPowered()): + // We see a force, but the "Recovery" phase has been too short, we stay in the "Recovery" phase + log.debug(`Time: ${flywheel.spinningTime().toFixed(4)} sec: Delta Time trend is downwards, suggesting power, but waiting for recovery phase length (${(flywheel.spinningTime() - recoveryPhaseStartTime).toFixed(4)} sec) to exceed minimumRecoveryTime (${rowerSettings.minimumRecoveryTime} sec)`) + updateRecoveryPhase() + break + case (_strokeState === 'Recovery'): + // No force on the flywheel, let's continue the "Recovery" phase of the stroke + updateRecoveryPhase() + break + default: + log.error(`Time: ${flywheel.spinningTime().toFixed(4)} sec, state ${_strokeState} found in the Rowing Engine, which is not captured by Finite State Machine`) + } + } + + function startDrivePhase () { + // Next, we start the Drive Phase + _totalNumberOfStrokes++ + drivePhaseStartTime = flywheel.spinningTime() + drivePhaseStartAngularPosition = flywheel.angularPosition() + driveHandleForce.reset() + const forceOnHandle = flywheel.torque() / sprocketRadius + driveHandleForce.push(flywheel.deltaTime(), forceOnHandle) + driveHandleVelocity.reset() + const velocityOfHandle = flywheel.angularVelocity() * sprocketRadius + driveHandleVelocity.push(flywheel.deltaTime(), velocityOfHandle) + driveHandlePower.reset() + const powerOnHandle = flywheel.torque() * flywheel.angularVelocity() + driveHandlePower.push(flywheel.deltaTime(), powerOnHandle) + } + + function updateDrivePhase () { + // Update the key metrics on each impulse + drivePhaseAngularDisplacement = flywheel.angularPosition() - drivePhaseStartAngularPosition + _driveLinearDistance = calculateLinearDistance(drivePhaseAngularDisplacement, (flywheel.spinningTime() - drivePhaseStartTime)) + preliminaryTotalLinearDistance = totalLinearDistance + _driveLinearDistance + const forceOnHandle = flywheel.torque() / sprocketRadius + driveHandleForce.push(flywheel.deltaTime(), forceOnHandle) + const velocityOfHandle = flywheel.angularVelocity() * sprocketRadius + driveHandleVelocity.push(flywheel.deltaTime(), velocityOfHandle) + const powerOnHandle = flywheel.torque() * flywheel.angularVelocity() + driveHandlePower.push(flywheel.deltaTime(), powerOnHandle) + } + + function endDrivePhase () { + // Here, we conclude the Drive Phase + // The FSM guarantees that we have a credible driveDuration and cycletime + _driveDuration = flywheel.spinningTime() - drivePhaseStartTime + _cycleDuration = _recoveryDuration + _driveDuration + drivePhaseAngularDisplacement = flywheel.angularPosition() - drivePhaseStartAngularPosition + _driveLength = drivePhaseAngularDisplacement * sprocketRadius + _driveLinearDistance = calculateLinearDistance(drivePhaseAngularDisplacement, _driveDuration) + totalLinearDistance += _driveLinearDistance + _cyclePower = calculateCyclePower() + _cycleLinearVelocity = calculateLinearVelocity(drivePhaseAngularDisplacement + recoveryPhaseAngularDisplacement, _cycleDuration) + preliminaryTotalLinearDistance = totalLinearDistance + } + + function startRecoveryPhase () { + // Next, we start the Recovery Phase + recoveryPhaseStartTime = flywheel.spinningTime() + recoveryPhaseStartAngularPosition = flywheel.angularPosition() + flywheel.markRecoveryPhaseStart() + } + + function updateRecoveryPhase () { + // Update the key metrics on each impulse + recoveryPhaseAngularDisplacement = flywheel.angularPosition() - recoveryPhaseStartAngularPosition + _recoveryLinearDistance = calculateLinearDistance(recoveryPhaseAngularDisplacement, (flywheel.spinningTime() - recoveryPhaseStartTime)) + preliminaryTotalLinearDistance = totalLinearDistance + _recoveryLinearDistance + } + + function endRecoveryPhase () { + // First, we conclude the recovery phase + // The FSM guarantees that we have a credible recoveryDuration and cycletime + _recoveryDuration = flywheel.spinningTime() - recoveryPhaseStartTime + _cycleDuration = _recoveryDuration + _driveDuration + recoveryPhaseAngularDisplacement = flywheel.angularPosition() - recoveryPhaseStartAngularPosition + _recoveryLinearDistance = calculateLinearDistance(recoveryPhaseAngularDisplacement, _recoveryDuration) + totalLinearDistance += _recoveryLinearDistance + preliminaryTotalLinearDistance = totalLinearDistance + _cycleLinearVelocity = calculateLinearVelocity(drivePhaseAngularDisplacement + recoveryPhaseAngularDisplacement, _cycleDuration) + _cyclePower = calculateCyclePower() + flywheel.markRecoveryPhaseCompleted() + } + + function calculateLinearDistance (baseAngularDisplacement, baseTime) { + if (baseAngularDisplacement >= 0) { + return Math.pow((flywheel.dragFactor() / rowerSettings.magicConstant), 1.0 / 3.0) * baseAngularDisplacement + } else { + log.error(`Time: ${flywheel.spinningTime().toFixed(4)} sec: calculateLinearDistance error: baseAngularDisplacement was not credible, baseTime: ${baseAngularDisplacement}`) + return 0 + } + } + + function calculateLinearVelocity (baseAngularDisplacement, baseTime) { + // Here we calculate the AVERAGE speed for the displays, NOT the topspeed of the stroke + const prevLinearVelocity = _cycleLinearVelocity + if (baseAngularDisplacement > 0 && baseTime > 0) { + // let's prevent division's by zero and make sure data is credible + const baseAngularVelocity = baseAngularDisplacement / baseTime + return Math.pow((flywheel.dragFactor() / rowerSettings.magicConstant), 1.0 / 3.0) * baseAngularVelocity + } else { + log.error(`Time: ${flywheel.spinningTime().toFixed(4)} sec: calculateLinearVelocity error, Angular Displacement = ${baseAngularDisplacement}, baseTime = ${baseTime}`) + return prevLinearVelocity + } + } + + function calculateCyclePower () { + // Here we calculate the AVERAGE power for the displays, NOT the top power of the stroke + const prevCyclePower = _cyclePower + if (_driveDuration >= rowerSettings.minimumDriveTime && _cycleDuration >= minimumCycleDuration) { + // let's prevent division's by zero and make sure data is credible + return flywheel.dragFactor() * Math.pow((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / _cycleDuration, 3.0) + } else { + log.error(`Time: ${flywheel.spinningTime().toFixed(4)} sec: calculateCyclePower error: driveDuration = ${_driveDuration.toFixed(4)} sec, _cycleDuration = ${_cycleDuration.toFixed(4)} sec`) + return prevCyclePower + } + } + + function strokeState () { + return _strokeState + } + + function totalNumberOfStrokes () { + return _totalNumberOfStrokes + } + + function totalMovingTimeSinceStart () { + return flywheel.spinningTime() + } + + function driveLastStartTime () { + return drivePhaseStartTime + } + + function totalLinearDistanceSinceStart () { + return Math.max(preliminaryTotalLinearDistance, totalLinearDistance) + } + + function cycleDuration () { + return _cycleDuration + } + + function cycleLinearDistance () { + return _driveLinearDistance + _recoveryLinearDistance + } + + function cycleLinearVelocity () { + return _cycleLinearVelocity + } + + function cyclePower () { + return _cyclePower + } + + function driveDuration () { + return _driveDuration + } + + function driveLinearDistance () { + return _driveLinearDistance + } + + function driveLength () { + return _driveLength + } + + function driveAverageHandleForce () { + return driveHandleForce.average() + } + + function drivePeakHandleForce () { + return driveHandleForce.peak() + } + + function driveHandleForceCurve () { + return driveHandleForce.curve() + } + + function driveHandleVelocityCurve () { + return driveHandleVelocity.curve() + } + + function driveHandlePowerCurve () { + return driveHandlePower.curve() + } + + function recoveryDuration () { + return _recoveryDuration + } + + function recoveryDragFactor () { + return flywheel.dragFactor() * 1000000 + } + + function instantHandlePower () { + if (_strokeState === 'Drive') { + return flywheel.torque() * flywheel.angularVelocity() + } else { + return 0 + } + } + + function allowMovement () { + log.debug(`*** ALLOW MOVEMENT command by RowingEngine recieved at time: ${flywheel.spinningTime().toFixed(4)} sec`) + _strokeState = 'WaitingForDrive' + } + + function pauseMoving () { + log.debug(`*** PAUSE MOVING command recieved by RowingEngine at time: ${flywheel.spinningTime().toFixed(4)} sec, distance: ${preliminaryTotalLinearDistance.toFixed(2)} meters`) + flywheel.maintainStateOnly() + _strokeState = 'WaitingForDrive' + } + + function stopMoving () { + log.debug(`*** STOP MOVING command recieved by RowingEngine at time: ${flywheel.spinningTime().toFixed(4)} sec, distance: ${preliminaryTotalLinearDistance.toFixed(2)} meters`) + flywheel.maintainStateOnly() + _strokeState = 'Stopped' + } + + function reset () { + _strokeState = 'WaitingForDrive' + flywheel.maintainStateOnly() + _totalNumberOfStrokes = -1.0 + drivePhaseStartTime = 0.0 + drivePhaseStartAngularPosition = 0.0 + _driveDuration = 0.0 + drivePhaseAngularDisplacement = 0.0 + _driveLinearDistance = 0.0 + recoveryPhaseStartTime = 0.0 + _recoveryDuration = 0.0 + recoveryPhaseStartAngularPosition = 0.0 + recoveryPhaseAngularDisplacement = 0.0 + _recoveryLinearDistance = 0.0 + _cycleDuration = 0.0 + _cycleLinearVelocity = 0.0 + totalLinearDistance = 0.0 + preliminaryTotalLinearDistance = 0.0 + _cyclePower = 0.0 + _driveLength = 0.0 + } + + return { + handleRotationImpulse, + allowMovement, + pauseMoving, + stopMoving, + strokeState, + totalNumberOfStrokes, + driveLastStartTime, + totalMovingTimeSinceStart, + totalLinearDistanceSinceStart, + cycleDuration, + cycleLinearDistance, + cycleLinearVelocity, + cyclePower, + driveDuration, + driveLinearDistance, + driveLength, + driveAverageHandleForce, + drivePeakHandleForce, + driveHandleForceCurve, + driveHandleVelocityCurve, + driveHandlePowerCurve, + recoveryDuration, + recoveryDragFactor, + instantHandlePower, + reset + } +} + +export { createRower } diff --git a/app/engine/Rower.test.js b/app/engine/Rower.test.js new file mode 100644 index 0000000000..9e32ab5be7 --- /dev/null +++ b/app/engine/Rower.test.js @@ -0,0 +1,519 @@ +'use strict' +/* + + This test is a test of the Rower object, that tests wether this object fills all fields correctly, given one validated rower, (the + Concept2 RowErg) using a validated cycle of strokes. This thoroughly tests the raw physics of the translation of Angular physics + to Linear physics. The combination with all possible known rowers is tested when testing the above function RowingStatistics, as + these statistics are dependent on these settings as well. +*/ +import { test } from 'uvu' +import * as assert from 'uvu/assert' +import rowerProfiles from '../../config/rowerProfiles.js' +import { replayRowingSession } from '../tools/RowingRecorder.js' +import { deepMerge } from '../tools/Helper.js' + +import { createRower } from './Rower.js' + +const baseConfig = { + numOfImpulsesPerRevolution: 6, + smoothing: 1, + flankLength: 11, + minimumStrokeQuality: 0.30, + minumumRecoverySlope: 0, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.10, + minumumForceBeforeStroke: 50, + minimumRecoveryTime: 0.9, + minimumDriveTime: 0.4, + maximumStrokeTimeBeforePause: 6.0, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.02, + autoAdjustDragFactor: true, + dragFactorSmoothing: 3, + dragFactor: 100, + minimumDragQuality: 0.83, + flywheelInertia: 0.1, + magicConstant: 2.8, + sprocketRadius: 2 +} + +// Test behaviour for no datapoints +test('Correct rower behaviour at initialisation', () => { + const rower = createRower(baseConfig) + testStrokeState(rower, 'WaitingForDrive') + testTotalMovingTimeSinceStart(rower, 0) + testTotalNumberOfStrokes(rower, 0) + testTotalLinearDistanceSinceStart(rower, 0) + testCycleDuration(rower, 1.3) + testCycleLinearDistance(rower, 0) + testCycleLinearVelocity(rower, 0) + testCyclePower(rower, 0) + testDriveDuration(rower, 0) + testDriveLinearDistance(rower, 0) + testDriveLength(rower, 0) + testDriveAverageHandleForce(rower, 0) + testDrivePeakHandleForce(rower, 0) + testRecoveryDuration(rower, 0) + testRecoveryDragFactor(rower, 100) + testInstantHandlePower(rower, 0) +}) + +// Test behaviour for one series of datapoint +// ToDo: add detailed test with a series of datapoints describng a complete stroke + +// Test behaviour for three perfect identical strokes, including settingling behaviour of metrics +test('Correct Rower behaviour for three noisefree strokes with dynamic dragfactor and stroke detection', () => { + const specificConfig = { + numOfImpulsesPerRevolution: 6, + smoothing: 1, + flankLength: 11, + minimumStrokeQuality: 0.30, + minumumRecoverySlope: 0, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.10, + minumumForceBeforeStroke: 50, + minimumDriveTime: 0.1, + minimumRecoveryTime: 0.2, + maximumStrokeTimeBeforePause: 0.2, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.02, + autoAdjustDragFactor: true, + dragFactorSmoothing: 3, + dragFactor: 100, + minimumDragQuality: 0.83, + flywheelInertia: 0.1, + magicConstant: 2.8, + sprocketRadius: 2 + } + + const rower = createRower(specificConfig) + testStrokeState(rower, 'WaitingForDrive') + testTotalMovingTimeSinceStart(rower, 0) + testTotalLinearDistanceSinceStart(rower, 0) + testTotalNumberOfStrokes(rower, 0) + testCycleDuration(rower, 0.30000000000000004) + testCycleLinearDistance(rower, 0) + testCycleLinearVelocity(rower, 0) + testCyclePower(rower, 0) + testDriveDuration(rower, 0) + testDriveLinearDistance(rower, 0) + testDriveLength(rower, 0) + testDriveAverageHandleForce(rower, 0) + testDrivePeakHandleForce(rower, 0) + testRecoveryDuration(rower, 0) + testRecoveryDragFactor(rower, 100) + testInstantHandlePower(rower, 0) + // Drive initial stroke starts here + rower.handleRotationImpulse(0.011221636) + testStrokeState(rower, 'WaitingForDrive') + rower.handleRotationImpulse(0.011175504) + rower.handleRotationImpulse(0.01116456) + rower.handleRotationImpulse(0.011130263) + rower.handleRotationImpulse(0.011082613) + rower.handleRotationImpulse(0.011081761) + rower.handleRotationImpulse(0.011062297) + rower.handleRotationImpulse(0.011051853) + rower.handleRotationImpulse(0.010973313) + rower.handleRotationImpulse(0.010919756) + testStrokeState(rower, 'WaitingForDrive') + rower.handleRotationImpulse(0.01086431) + testStrokeState(rower, 'Drive') + rower.handleRotationImpulse(0.010800864) + testStrokeState(rower, 'Drive') + rower.handleRotationImpulse(0.010956987) + rower.handleRotationImpulse(0.010653396) + rower.handleRotationImpulse(0.010648619) + rower.handleRotationImpulse(0.010536818) + rower.handleRotationImpulse(0.010526151) + rower.handleRotationImpulse(0.010511225) + rower.handleRotationImpulse(0.010386684) + testStrokeState(rower, 'Drive') + testTotalMovingTimeSinceStart(rower, 0.088970487) + testTotalLinearDistanceSinceStart(rower, 0.27588786257094444) + testTotalNumberOfStrokes(rower, 1) + testCycleDuration(rower, 0.30000000000000004) + testCycleLinearDistance(rower, 0.27588786257094444) + testCycleLinearVelocity(rower, 0) // Shouldn't this one be filled after the first drive? + testCyclePower(rower, 0) // Shouldn't this one be filled after the first drive? + testDriveDuration(rower, 0) // Shouldn't this one be filled after the first drive? + testDriveLinearDistance(rower, 0.27588786257094444) + testDriveLength(rower, 0) // Shouldn't this one be filled after the first drive? + testDriveAverageHandleForce(rower, 156.05318736972495) + testDrivePeakHandleForce(rower, 163.83893715861615) + testRecoveryDuration(rower, 0) + testRecoveryDragFactor(rower, 100) + testInstantHandlePower(rower, 312.1970306768984) + // Recovery initial stroke starts here + rower.handleRotationImpulse(0.010769) + rower.handleRotationImpulse(0.010707554) + rower.handleRotationImpulse(0.010722165) + rower.handleRotationImpulse(0.01089567) + rower.handleRotationImpulse(0.010917504) + rower.handleRotationImpulse(0.010997969) + rower.handleRotationImpulse(0.011004655) + rower.handleRotationImpulse(0.011013618) + rower.handleRotationImpulse(0.011058193) + rower.handleRotationImpulse(0.010807149) + rower.handleRotationImpulse(0.0110626) + rower.handleRotationImpulse(0.011090787) + rower.handleRotationImpulse(0.011099509) + rower.handleRotationImpulse(0.011131862) + rower.handleRotationImpulse(0.011209919) + testStrokeState(rower, 'Recovery') + testTotalMovingTimeSinceStart(rower, 0.24984299900000007) + testTotalLinearDistanceSinceStart(rower, 0.7931776048914653) + testTotalNumberOfStrokes(rower, 1) + testCycleDuration(rower, 0.143485717) + testCycleLinearDistance(rower, 0.7931776048914653) + testCycleLinearVelocity(rower, 3.1244766799874912) + testCyclePower(rower, 0) + testDriveDuration(rower, 0.143485717) + testDriveLinearDistance(rower, 0.4483177766777847) + testDriveLength(rower, 0.2722713633111154) + testDriveAverageHandleForce(rower, 168.33379255795953) + testDrivePeakHandleForce(rower, 220.19702843648562) + testRecoveryDuration(rower, 0) + testRecoveryDragFactor(rower, 100) + testInstantHandlePower(rower, 0) + // Drive seconds stroke starts here + rower.handleRotationImpulse(0.011221636) + rower.handleRotationImpulse(0.011175504) + rower.handleRotationImpulse(0.01116456) + rower.handleRotationImpulse(0.011130263) + rower.handleRotationImpulse(0.011082613) + rower.handleRotationImpulse(0.011081761) + rower.handleRotationImpulse(0.011062297) + rower.handleRotationImpulse(0.011051853) + rower.handleRotationImpulse(0.010973313) + rower.handleRotationImpulse(0.010919756) + rower.handleRotationImpulse(0.01086431) + rower.handleRotationImpulse(0.010800864) + rower.handleRotationImpulse(0.010956987) + rower.handleRotationImpulse(0.010653396) + rower.handleRotationImpulse(0.010648619) + rower.handleRotationImpulse(0.010536818) + rower.handleRotationImpulse(0.010526151) + rower.handleRotationImpulse(0.010511225) + rower.handleRotationImpulse(0.010386684) + testStrokeState(rower, 'Drive') + testTotalMovingTimeSinceStart(rower, 0.46020725100000004) + testTotalLinearDistanceSinceStart(rower, 1.519974294345203) + testTotalNumberOfStrokes(rower, 2) + testCycleDuration(rower, 0.404798464) + testCycleLinearDistance(rower, 1.0716565176674184) + testCycleLinearVelocity(rower, 3.1521398371477467) + testCyclePower(rower, 87.69492447163606) + testDriveDuration(rower, 0.143485717) + testDriveLinearDistance(rower, 0.24399292995458496) + testDriveLength(rower, 0.2722713633111154) + testDriveAverageHandleForce(rower, 156.87845718774872) + testDrivePeakHandleForce(rower, 227.37033987102245) + testRecoveryDuration(rower, 0.261312747) + testRecoveryDragFactor(rower, 283.33086731525583) + testInstantHandlePower(rower, 432.851053772137) + // Recovery second stroke starts here + rower.handleRotationImpulse(0.010769) + rower.handleRotationImpulse(0.010707554) + rower.handleRotationImpulse(0.010722165) + rower.handleRotationImpulse(0.01089567) + rower.handleRotationImpulse(0.010917504) + rower.handleRotationImpulse(0.010997969) + rower.handleRotationImpulse(0.011004655) + rower.handleRotationImpulse(0.011013618) + rower.handleRotationImpulse(0.011058193) + rower.handleRotationImpulse(0.010807149) + rower.handleRotationImpulse(0.0110626) + rower.handleRotationImpulse(0.011090787) + rower.handleRotationImpulse(0.011099509) + rower.handleRotationImpulse(0.011131862) + rower.handleRotationImpulse(0.011209919) + testStrokeState(rower, 'Recovery') + testTotalMovingTimeSinceStart(rower, 0.6210797630000001) + testTotalLinearDistanceSinceStart(rower, 2.2519530842089575) + testTotalNumberOfStrokes(rower, 2) + testCycleDuration(rower, 0.37123676400000005) + testCycleLinearDistance(rower, 0.9759717198183395) + testCycleLinearVelocity(rower, 4.469255430992759) + testCyclePower(rower, 249.95599708025222) + testDriveDuration(rower, 0.10992401700000004) + testDriveLinearDistance(rower, 0.48798585990916965) + testDriveLength(rower, 0.20943951023931945) + testDriveAverageHandleForce(rower, 198.7144253754593) + testDrivePeakHandleForce(rower, 294.92974697493514) + testRecoveryDuration(rower, 0.261312747) + testRecoveryDragFactor(rower, 283.33086731525583) + testInstantHandlePower(rower, 0) + // Drive third stroke starts here + rower.handleRotationImpulse(0.011221636) + rower.handleRotationImpulse(0.011175504) + rower.handleRotationImpulse(0.01116456) + rower.handleRotationImpulse(0.011130263) + rower.handleRotationImpulse(0.011082613) + rower.handleRotationImpulse(0.011081761) + rower.handleRotationImpulse(0.011062297) + rower.handleRotationImpulse(0.011051853) + rower.handleRotationImpulse(0.010973313) + rower.handleRotationImpulse(0.010919756) + rower.handleRotationImpulse(0.01086431) + rower.handleRotationImpulse(0.010800864) + rower.handleRotationImpulse(0.010956987) + rower.handleRotationImpulse(0.010653396) + rower.handleRotationImpulse(0.010648619) + rower.handleRotationImpulse(0.010536818) + rower.handleRotationImpulse(0.010526151) + rower.handleRotationImpulse(0.010511225) + rower.handleRotationImpulse(0.010386684) + testStrokeState(rower, 'Drive') + testTotalMovingTimeSinceStart(rower, 0.8314440150000004) + testTotalLinearDistanceSinceStart(rower, 3.17912621803638) + testTotalNumberOfStrokes(rower, 3) + testCycleDuration(rower, 0.3376750640000003) + testCycleLinearDistance(rower, 1.4151589937365927) + testCycleLinearVelocity(rower, 4.479916721710978) + testCyclePower(rower, 251.74905786098182) + testDriveDuration(rower, 0.10992401700000004) + testDriveLinearDistance(rower, 0.3903886879273361) + testDriveLength(rower, 0.20943951023931945) + testDriveAverageHandleForce(rower, 140.7974193430079) + testDrivePeakHandleForce(rower, 227.3703398700472) + testRecoveryDuration(rower, 0.22775104700000026) + testRecoveryDragFactor(rower, 283.33086731525583) + testInstantHandlePower(rower, 432.8510537702822) + // Recovery third stroke starts here + rower.handleRotationImpulse(0.010769) + rower.handleRotationImpulse(0.010707554) + rower.handleRotationImpulse(0.010722165) + rower.handleRotationImpulse(0.01089567) + rower.handleRotationImpulse(0.010917504) + rower.handleRotationImpulse(0.010997969) + rower.handleRotationImpulse(0.011004655) + rower.handleRotationImpulse(0.011013618) + rower.handleRotationImpulse(0.011058193) + rower.handleRotationImpulse(0.010807149) + rower.handleRotationImpulse(0.0110626) + rower.handleRotationImpulse(0.011090787) + rower.handleRotationImpulse(0.011099509) + rower.handleRotationImpulse(0.011131862) + rower.handleRotationImpulse(0.011209919) + testStrokeState(rower, 'Recovery') + testTotalMovingTimeSinceStart(rower, 0.9923165270000005) + testTotalLinearDistanceSinceStart(rower, 3.911105007900135) + testTotalNumberOfStrokes(rower, 3) + testCycleDuration(rower, 0.3712367640000004) + testCycleLinearDistance(rower, 1.122367477791091) + testCycleLinearVelocity(rower, 4.469255430992756) + testCyclePower(rower, 249.95599708025168) + testDriveDuration(rower, 0.14348571700000012) + testDriveLinearDistance(rower, 0.634381617881921) + testDriveLength(rower, 0.2722713633111155) + testDriveAverageHandleForce(rower, 177.72502014311627) + testDrivePeakHandleForce(rower, 294.9297469748562) + testRecoveryDuration(rower, 0.22775104700000026) + testRecoveryDragFactor(rower, 283.33086731525583) + testInstantHandlePower(rower, 0) + // Dwelling state starts here + rower.handleRotationImpulse(0.020769) + rower.handleRotationImpulse(0.020707554) + rower.handleRotationImpulse(0.020722165) + rower.handleRotationImpulse(0.02089567) + rower.handleRotationImpulse(0.020917504) + rower.handleRotationImpulse(0.020997969) + rower.handleRotationImpulse(0.021004655) + rower.handleRotationImpulse(0.021013618) + rower.handleRotationImpulse(0.021058193) + rower.handleRotationImpulse(0.020807149) + rower.handleRotationImpulse(0.0210626) + rower.handleRotationImpulse(0.021090787) + rower.handleRotationImpulse(0.021099509) + rower.handleRotationImpulse(0.021131862) + rower.handleRotationImpulse(0.021209919) + testStrokeState(rower, 'WaitingForDrive') + testTotalMovingTimeSinceStart(rower, 1.1137102920000004) + testTotalNumberOfStrokes(rower, 3) + testTotalLinearDistanceSinceStart(rower, 4.447889453800221) + testCycleDuration(rower, 0.37123676400000005) + testCycleLinearDistance(rower, 1.6591519236911776) + testCycleLinearVelocity(rower, 4.469255430992759) + testCyclePower(rower, 249.95599708025233) + testDriveDuration(rower, 0.14348571700000012) + testDriveLinearDistance(rower, 0.634381617881921) + testDriveLength(rower, 0.2722713633111155) + testDriveAverageHandleForce(rower, 177.72502014311627) + testDrivePeakHandleForce(rower, 294.9297469748562) + testRecoveryDuration(rower, 0.22775104699999993) + testRecoveryDragFactor(rower, 283.33086731525583) + testInstantHandlePower(rower, 0) +}) + +// Test behaviour for noisy upgoing flank +// ToDo: add detailed test with a series of datapoints describng a complete upgoing flank + +// Test behaviour for noisy downgoing flank +// ToDo: add detailed test with a series of datapoints describng a complete downgoing flank + +// Test behaviour for noisy stroke +// ToDo: add detailed test with a series of datapoints describng a complete upgoing and downgoing flank + +// Test drag factor calculation +// ToDo: add a test to test the dragfactor calculation (can be reused from Flywheel.test.js) + +// Test Dynamic stroke detection +// ToDo: add a test to test the dynamic stroke detection (can be reused from Flywheel.test.js) + +// Test behaviour after reset +// ToDo: add detailed test with a series of datapoints followed by a reset + +// Test behaviour with real-life data + +test('sample data for Sportstech WRX700 should produce plausible results', async () => { + const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700)) + testTotalMovingTimeSinceStart(rower, 0) + testTotalLinearDistanceSinceStart(rower, 0) + testTotalNumberOfStrokes(rower, 0) + testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor) + + await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv', realtime: false, loop: false }) + + testTotalMovingTimeSinceStart(rower, 46.302522627) + testTotalLinearDistanceSinceStart(rower, 166.2959671641673) + testTotalNumberOfStrokes(rower, 16) + // As dragFactor is static, it should remain in place + testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('sample data for DKN R-320 should produce plausible results', async () => { + const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.DKN_R320)) + testTotalMovingTimeSinceStart(rower, 0) + testTotalLinearDistanceSinceStart(rower, 0) + testTotalNumberOfStrokes(rower, 0) + testRecoveryDragFactor(rower, rowerProfiles.DKN_R320.dragFactor) + + await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/DKNR320.csv', realtime: false, loop: false }) + + testTotalMovingTimeSinceStart(rower, 21.701535821) + testTotalLinearDistanceSinceStart(rower, 70.11298001986664) + testTotalNumberOfStrokes(rower, 10) + // As dragFactor is static, it should remain in place + testRecoveryDragFactor(rower, rowerProfiles.DKN_R320.dragFactor) +}) + +test('sample data for NordicTrack RX800 should produce plausible results', async () => { + const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.NordicTrack_RX800)) + testTotalMovingTimeSinceStart(rower, 0) + testTotalLinearDistanceSinceStart(rower, 0) + testTotalNumberOfStrokes(rower, 0) + testRecoveryDragFactor(rower, rowerProfiles.NordicTrack_RX800.dragFactor) + + await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/RX800.csv', realtime: false, loop: false }) + + testTotalMovingTimeSinceStart(rower, 17.389910236000024) + testTotalLinearDistanceSinceStart(rower, 62.052936751782944) + testTotalNumberOfStrokes(rower, 8) + // As dragFactor is dynamic, it should have changed + testRecoveryDragFactor(rower, 486.702741763346) +}) + +test('A full session for SportsTech WRX700 should produce plausible results', async () => { + const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700)) + testTotalMovingTimeSinceStart(rower, 0) + testTotalLinearDistanceSinceStart(rower, 0) + testTotalNumberOfStrokes(rower, 0) + testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor) + + await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false }) + + testTotalMovingTimeSinceStart(rower, 2342.241183077012) + testTotalLinearDistanceSinceStart(rower, 8408.914799199298) + testTotalNumberOfStrokes(rower, 846) + // As dragFactor is static, it should remain in place + testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('A full session for a Concept2 RowErg should produce plausible results', async () => { + const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_RowErg)) + testTotalMovingTimeSinceStart(rower, 0) + testTotalLinearDistanceSinceStart(rower, 0) + testTotalNumberOfStrokes(rower, 0) + testRecoveryDragFactor(rower, rowerProfiles.Concept2_RowErg.dragFactor) + + await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', realtime: false, loop: false }) + + testTotalMovingTimeSinceStart(rower, 590.4201840000001) + testTotalLinearDistanceSinceStart(rower, 2030.6574002852396) + testTotalNumberOfStrokes(rower, 206) + // As dragFactor isn't static, it should be updated + testRecoveryDragFactor(rower, 80.81243631988698) +}) + +function testStrokeState (rower, expectedValue) { + assert.ok(rower.strokeState() === expectedValue, `strokeState should be ${expectedValue} at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.strokeState()}`) +} + +function testTotalMovingTimeSinceStart (rower, expectedValue) { + assert.ok(rower.totalMovingTimeSinceStart() === expectedValue, `totalMovingTimeSinceStart should be ${expectedValue} sec at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.totalMovingTimeSinceStart()}`) +} + +function testTotalNumberOfStrokes (rower, expectedValue) { + // Please note there is a stroke 0 + assert.ok(rower.totalNumberOfStrokes() + 1 === expectedValue, `totalNumberOfStrokes should be ${expectedValue} at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.totalNumberOfStrokes() + 1}`) +} + +function testTotalLinearDistanceSinceStart (rower, expectedValue) { + assert.ok(rower.totalLinearDistanceSinceStart() === expectedValue, `totalLinearDistanceSinceStart should be ${expectedValue} meters at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.totalLinearDistanceSinceStart()}`) +} + +function testCycleDuration (rower, expectedValue) { + assert.ok(rower.cycleDuration() === expectedValue, `cycleDuration should be ${expectedValue} sec at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.cycleDuration()}`) +} + +function testCycleLinearDistance (rower, expectedValue) { + assert.ok(rower.cycleLinearDistance() === expectedValue, `cycleLinearDistance should be ${expectedValue} meters at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.cycleLinearDistance()}`) +} + +function testCycleLinearVelocity (rower, expectedValue) { + assert.ok(rower.cycleLinearVelocity() === expectedValue, `cycleLinearVelocity should be ${expectedValue} m/s at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.cycleLinearVelocity()}`) +} + +function testCyclePower (rower, expectedValue) { + assert.ok(rower.cyclePower() === expectedValue, `cyclePower should be ${expectedValue} Watt at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.cyclePower()}`) +} + +function testDriveDuration (rower, expectedValue) { + assert.ok(rower.driveDuration() === expectedValue, `driveDuration should be ${expectedValue} sec at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.driveDuration()}`) +} + +function testDriveLinearDistance (rower, expectedValue) { + assert.ok(rower.driveLinearDistance() === expectedValue, `driveLinearDistance should be ${expectedValue} meters at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.driveLinearDistance()}`) +} + +function testDriveLength (rower, expectedValue) { + assert.ok(rower.driveLength() === expectedValue, `driveLength should be ${expectedValue} meters at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.driveLength()}`) +} + +function testDriveAverageHandleForce (rower, expectedValue) { + assert.ok(rower.driveAverageHandleForce() === expectedValue, `driveAverageHandleForce should be ${expectedValue} N at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.driveAverageHandleForce()}`) +} + +function testDrivePeakHandleForce (rower, expectedValue) { + assert.ok(rower.drivePeakHandleForce() === expectedValue, `drivePeakHandleForce should be ${expectedValue} N at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.drivePeakHandleForce()}`) +} + +function testRecoveryDuration (rower, expectedValue) { + assert.ok(rower.recoveryDuration() === expectedValue, `recoveryDuration should be ${expectedValue} sec at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.recoveryDuration()}`) +} + +function testRecoveryDragFactor (rower, expectedValue) { + assert.ok(rower.recoveryDragFactor() === expectedValue, `recoveryDragFactor should be ${expectedValue} N*m*s^2 at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.recoveryDragFactor()}`) +} + +function testInstantHandlePower (rower, expectedValue) { + assert.ok(rower.instantHandlePower() === expectedValue, `instantHandlePower should be ${expectedValue} Watt at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.instantHandlePower()}`) +} + +/* +function reportAll (rower) { + assert.ok(0, `time: ${rower.totalMovingTimeSinceStart()}, state ${rower.strokeState()}, No Strokes: ${rower.totalNumberOfStrokes()}, Lin Distance: ${rower.totalLinearDistanceSinceStart()}, cycle dur: ${rower.cycleDuration()}, cycle Lin Dist: ${rower.cycleLinearDistance()}, Lin Velocity: ${rower.cycleLinearVelocity()}, Power: ${rower.cyclePower()}, Drive Dur: ${rower.driveDuration()}, Drive Lin. Dist. ${rower.driveLinearDistance()}, Drive Length: ${rower.driveLength()}, Av. Handle Force: ${rower.driveAverageHandleForce()}, Peak Handle Force: ${rower.drivePeakHandleForce()}, Rec. Dur: ${rower.recoveryDuration()}, Dragfactor: ${rower.recoveryDragFactor()}, Inst Handle Power: ${rower.instantHandlePower()}`) +} +*/ + +test.run() diff --git a/app/engine/RowingEngine.js b/app/engine/RowingEngine.js deleted file mode 100644 index d471abdecc..0000000000 --- a/app/engine/RowingEngine.js +++ /dev/null @@ -1,342 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - The Rowing Engine models the physics of a real rowing boat. - It takes impulses from the flywheel of a rowing machine and estimates - parameters such as energy, stroke rates and movement. - - This implementation uses concepts that are described here: - Physics of Rowing by Anu Dudhia: http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics - Also Dave Vernooy has some good explanations here: https://dvernooy.github.io/projects/ergware -*/ -import loglevel from 'loglevel' -import { createMovingAverager } from './averager/MovingAverager.js' -import { createMovingFlankDetector } from './MovingFlankDetector.js' - -const log = loglevel.getLogger('RowingEngine') - -function createRowingEngine (rowerSettings) { - let workoutHandler - const flankDetector = createMovingFlankDetector(rowerSettings) - const angularDisplacementPerImpulse = (2.0 * Math.PI) / rowerSettings.numOfImpulsesPerRevolution - const movingDragAverage = createMovingAverager(rowerSettings.dampingConstantSmoothing, rowerSettings.dragFactor / 1000000) - const dragFactorMaxUpwardChange = 1 + rowerSettings.dampingConstantMaxChange - const dragFactorMaxDownwardChange = 1 - rowerSettings.dampingConstantMaxChange - const minimumCycleLength = rowerSettings.minimumDriveTime + rowerSettings.minimumRecoveryTime - let cyclePhase - let totalTime - let totalNumberOfImpulses - let strokeNumber - let drivePhaseStartTime - let drivePhaseStartAngularDisplacement - let drivePhaseLength - let drivePhaseAngularDisplacement - let driveLinearDistance - let recoveryPhaseStartTime - let recoveryPhaseAngularDisplacement - let recoveryPhaseStartAngularDisplacement - let recoveryPhaseLength - let recoveryStartAngularVelocity - let recoveryEndAngularVelocity - let recoveryLinearDistance - let currentDragFactor - let dragFactor - let cycleLength - let linearCycleVelocity - let totalLinearDistance - let averagedCyclePower - let currentTorque - let previousAngularVelocity - let currentAngularVelocity - // we use the reset function to initialize the variables above - reset() - - // called if the sensor detected an impulse, currentDt is an interval in seconds - function handleRotationImpulse (currentDt) { - // impulses that take longer than maximumImpulseTimeBeforePause seconds are considered a pause - if (currentDt > rowerSettings.maximumImpulseTimeBeforePause) { - workoutHandler.handlePause(currentDt) - return - } - - totalTime += currentDt - totalNumberOfImpulses++ - - // detect where we are in the rowing phase (drive or recovery) - flankDetector.pushValue(currentDt) - - // we implement a finite state machine that goes between "Drive" and "Recovery" phases, - // which allows a phase-change if sufficient time has passed and there is a plausible flank - if (cyclePhase === 'Drive') { - // We currently are in the "Drive" phase, lets determine what the next phase is - if (flankDetector.isFlywheelUnpowered()) { - // The flank detector detects that the flywheel has no power exerted on it - drivePhaseLength = (totalTime - flankDetector.timeToBeginOfFlank()) - drivePhaseStartTime - if (drivePhaseLength >= rowerSettings.minimumDriveTime) { - // We change into the "Recovery" phase since we have been long enough in the Drive phase, and we see a clear lack of power - // exerted on the flywheel - startRecoveryPhase(currentDt) - cyclePhase = 'Recovery' - } else { - // We seem to have lost power to the flywheel, but it is too early according to the settings. We stay in the Drive Phase - log.debug(`Time: ${totalTime.toFixed(4)} sec, impulse ${totalNumberOfImpulses}: flank suggests no power (${flankDetector.accelerationAtBeginOfFlank().toFixed(1)} rad/s2), but waiting for for recoveryPhaseLength (${recoveryPhaseLength.toFixed(4)} sec) to exceed minimumRecoveryTime (${rowerSettings.minimumRecoveryTime} sec)`) - updateDrivePhase(currentDt) - } - } else { - // We stay in the "Drive" phase as the acceleration is lacking - updateDrivePhase(currentDt) - } - } else { - // We currently are in the "Recovery" phase, lets determine what the next phase is - if (flankDetector.isFlywheelPowered()) { - // The flank detector consistently detects some force on the flywheel - recoveryPhaseLength = (totalTime - flankDetector.timeToBeginOfFlank()) - recoveryPhaseStartTime - if (recoveryPhaseLength >= rowerSettings.minimumRecoveryTime) { - // We change into the "Drive" phase if we have been long enough in the "Recovery" phase, and we see a consistent force being - // exerted on the flywheel - startDrivePhase(currentDt) - cyclePhase = 'Drive' - } else { - // We see a force, but the "Recovery" phase has been too short, we stay in the "Recovery" phase - log.debug(`Time: ${totalTime.toFixed(4)} sec, impulse ${totalNumberOfImpulses}: flank suggests power (${flankDetector.accelerationAtBeginOfFlank().toFixed(1)} rad/s2), but waiting for recoveryPhaseLength (${recoveryPhaseLength.toFixed(4)} sec) to exceed minimumRecoveryTime (${rowerSettings.minimumRecoveryTime} sec)`) - updateRecoveryPhase(currentDt) - } - } else { - // No force on the flywheel, let's continue the "Drive" phase - updateRecoveryPhase(currentDt) - } - } - } - - function startDrivePhase (currentDt) { - // First, we conclude the "Recovery" phase - log.debug('*** recovery phase completed') - if (rowerSettings.minimumRecoveryTime <= recoveryPhaseLength && rowerSettings.minimumDriveTime <= drivePhaseLength) { - // We have a plausible cycle time - cycleLength = recoveryPhaseLength + drivePhaseLength - } else { - log.debug(`CycleLength isn't plausible: recoveryPhaseLength ${recoveryPhaseLength.toFixed(4)} sec, drivePhaseLength = ${drivePhaseLength.toFixed(4)} s, maximumImpulseTimeBeforePause ${rowerSettings.maximumImpulseTimeBeforePause} s`) - } - recoveryPhaseAngularDisplacement = ((totalNumberOfImpulses - flankDetector.noImpulsesToBeginFlank()) - recoveryPhaseStartAngularDisplacement) * angularDisplacementPerImpulse - - // Calculation of the drag-factor - if (flankDetector.impulseLengthAtBeginFlank() > 0) { - recoveryEndAngularVelocity = angularDisplacementPerImpulse / flankDetector.impulseLengthAtBeginFlank() - if (recoveryPhaseLength >= rowerSettings.minimumRecoveryTime && recoveryStartAngularVelocity > 0 && recoveryEndAngularVelocity > 0) { - // Prevent division by zero and keep useless data out of our calculations - currentDragFactor = -1 * rowerSettings.flywheelInertia * ((1 / recoveryStartAngularVelocity) - (1 / recoveryEndAngularVelocity)) / recoveryPhaseLength - if (rowerSettings.autoAdjustDragFactor) { - if (currentDragFactor > (movingDragAverage.getAverage() * dragFactorMaxDownwardChange) && currentDragFactor < (movingDragAverage.getAverage() * dragFactorMaxUpwardChange)) { - // If the calculated drag factor is close to what we expect - movingDragAverage.pushValue(currentDragFactor) - dragFactor = movingDragAverage.getAverage() - log.info(`*** Calculated drag factor: ${(currentDragFactor * 1000000).toFixed(2)}`) - } else { - // The calculated drag factor is outside the plausible range - log.info(`Calculated drag factor: ${(currentDragFactor * 1000000).toFixed(2)}, which is too far off the currently used dragfactor of ${movingDragAverage.getAverage() * 1000000}`) - log.debug(`Time: ${totalTime.toFixed(4)} sec, impulse ${totalNumberOfImpulses}: recoveryStartAngularVelocity = ${recoveryStartAngularVelocity.toFixed(2)} rad/sec, recoveryEndAngularVelocity = ${recoveryEndAngularVelocity.toFixed(2)} rad/sec, recoveryPhaseLength = ${recoveryPhaseLength.toFixed(4)} sec`) - if (currentDragFactor < (movingDragAverage.getAverage() * dragFactorMaxDownwardChange)) { - // The current calculated dragfactor makes an abrupt downward change, let's follow the direction, but limit it to the maximum allowed change - movingDragAverage.pushValue(movingDragAverage.getAverage() * dragFactorMaxDownwardChange) - } else { - // The current calculated dragfactor makes an abrupt upward change, let's follow the direction, but limit it to the maximum allowed change - movingDragAverage.pushValue(movingDragAverage.getAverage() * dragFactorMaxUpwardChange) - } - dragFactor = movingDragAverage.getAverage() - log.debug(`*** Applied drag factor: ${dragFactor * 1000000}`) - } - } else { - log.info(`*** Calculated drag factor: ${(currentDragFactor * 1000000).toFixed(2)}`) - } - } else { - log.error(`Time: ${totalTime.toFixed(4)} sec, impulse ${totalNumberOfImpulses}: division by 0 prevented, recoveryPhaseLength = ${recoveryPhaseLength} sec, recoveryStartAngularVelocity = ${recoveryStartAngularVelocity} rad/sec, recoveryEndAngularVelocity = ${recoveryEndAngularVelocity} rad/sec`) - } - } else { - log.error(`Time: ${totalTime.toFixed(4)} sec, impulse ${totalNumberOfImpulses}: division by 0 prevented, impulseLengthAtBeginFlank = ${flankDetector.impulseLengthAtBeginFlank()} sec`) - } - - // Calculate the key metrics - recoveryLinearDistance = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * recoveryPhaseAngularDisplacement - totalLinearDistance += recoveryLinearDistance - currentTorque = calculateTorque(currentDt) - linearCycleVelocity = calculateLinearVelocity() - averagedCyclePower = calculateCyclePower() - - // Next, we start the "Drive" Phase - log.debug(`*** DRIVE phase started at time: ${totalTime.toFixed(4)} sec, impulse number ${totalNumberOfImpulses}`) - strokeNumber++ - drivePhaseStartTime = totalTime - flankDetector.timeToBeginOfFlank() - drivePhaseStartAngularDisplacement = totalNumberOfImpulses - flankDetector.noImpulsesToBeginFlank() - - // Update the metrics - if (workoutHandler) { - workoutHandler.handleRecoveryEnd({ - timeSinceStart: totalTime, - power: averagedCyclePower, - duration: cycleLength, - strokeDistance: driveLinearDistance + recoveryLinearDistance, - durationDrivePhase: drivePhaseLength, - speed: linearCycleVelocity, - distance: totalLinearDistance, - numberOfStrokes: strokeNumber, - instantaneousTorque: currentTorque, - strokeState: 'DRIVING' - }) - } - } - - function updateDrivePhase (currentDt) { - // Update the key metrics on each impulse - drivePhaseAngularDisplacement = ((totalNumberOfImpulses - flankDetector.noImpulsesToBeginFlank()) - drivePhaseStartAngularDisplacement) * angularDisplacementPerImpulse - driveLinearDistance = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * drivePhaseAngularDisplacement - currentTorque = calculateTorque(currentDt) - if (workoutHandler) { - workoutHandler.updateKeyMetrics({ - timeSinceStart: totalTime, - distance: totalLinearDistance + driveLinearDistance, - instantaneousTorque: currentTorque - }) - } - } - - function startRecoveryPhase (currentDt) { - // First, we conclude the "Drive" Phase - log.debug('*** drive phase completed') - if (rowerSettings.minimumRecoveryTime <= recoveryPhaseLength && rowerSettings.minimumDriveTime <= drivePhaseLength) { - // We have a plausible cycle time - cycleLength = recoveryPhaseLength + drivePhaseLength - } else { - log.debug(`CycleLength wasn't plausible: recoveryPhaseLength ${recoveryPhaseLength.toFixed(4)} sec, drivePhaseLength = ${drivePhaseLength.toFixed(4)} s`) - } - drivePhaseAngularDisplacement = ((totalNumberOfImpulses - flankDetector.noImpulsesToBeginFlank()) - drivePhaseStartAngularDisplacement) * angularDisplacementPerImpulse - // driveEndAngularVelocity = angularDisplacementPerImpulse / flankDetector.impulseLengthAtBeginFlank() - driveLinearDistance = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * drivePhaseAngularDisplacement - totalLinearDistance += driveLinearDistance - currentTorque = calculateTorque(currentDt) - // We display the AVERAGE speed in the display, NOT the top speed of the stroke - linearCycleVelocity = calculateLinearVelocity() - averagedCyclePower = calculateCyclePower() - - // Next, we start the "Recovery" Phase - log.debug(`*** RECOVERY phase started at time: ${totalTime.toFixed(4)} sec, impuls number ${totalNumberOfImpulses}`) - recoveryPhaseStartTime = totalTime - flankDetector.timeToBeginOfFlank() - recoveryPhaseStartAngularDisplacement = totalNumberOfImpulses - flankDetector.noImpulsesToBeginFlank() - if (flankDetector.impulseLengthAtBeginFlank() > 0) { - recoveryStartAngularVelocity = angularDisplacementPerImpulse / flankDetector.impulseLengthAtBeginFlank() - } else { - log.error(`Time: ${totalTime.toFixed(4)} sec, impuls ${totalNumberOfImpulses}: division by 0 prevented, flankDetector.impulseLengthAtBeginFlank() is ${flankDetector.impulseLengthAtBeginFlank()} sec`) - } - - // Update the metrics - if (workoutHandler) { - workoutHandler.handleDriveEnd({ - timeSinceStart: totalTime, - power: averagedCyclePower, - duration: cycleLength, - strokeDistance: driveLinearDistance + recoveryLinearDistance, - durationDrivePhase: drivePhaseLength, - speed: linearCycleVelocity, - distance: totalLinearDistance, - instantaneousTorque: currentTorque, - strokeState: 'RECOVERY' - }) - } - } - - function updateRecoveryPhase (currentDt) { - // Update the key metrics on each impulse - recoveryPhaseAngularDisplacement = ((totalNumberOfImpulses - flankDetector.noImpulsesToBeginFlank()) - recoveryPhaseStartAngularDisplacement) * angularDisplacementPerImpulse - recoveryLinearDistance = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * recoveryPhaseAngularDisplacement - currentTorque = calculateTorque(currentDt) - if (workoutHandler) { - workoutHandler.updateKeyMetrics({ - timeSinceStart: totalTime, - distance: totalLinearDistance + recoveryLinearDistance, - instantaneousTorque: currentTorque - }) - } - } - - function calculateLinearVelocity () { - // Here we calculate the AVERAGE speed for the displays, NOT the topspeed of the stroke - let tempLinearVelocity = linearCycleVelocity - if (drivePhaseLength > rowerSettings.minimumDriveTime && cycleLength > minimumCycleLength) { - // There is no division by zero and the data data is plausible - tempLinearVelocity = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * ((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / cycleLength) - } else { - log.error(`Time: ${totalTime.toFixed(4)} sec, impuls ${totalNumberOfImpulses}: cycle length was not plausible, CycleLength = ${cycleLength} sec`) - } - return tempLinearVelocity - } - - function calculateCyclePower () { - // Here we calculate the AVERAGE power for the displays, NOT the top power of the stroke - let cyclePower = averagedCyclePower - if (drivePhaseLength > rowerSettings.minimumDriveTime && cycleLength > minimumCycleLength) { - // There is no division by zero and the data data is plausible - cyclePower = dragFactor * Math.pow((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / cycleLength, 3.0) - } else { - log.error(`Time: ${totalTime.toFixed(4)} sec, impulse ${totalNumberOfImpulses}: cycle length was not plausible, CycleLength = ${cycleLength} sec`) - } - return cyclePower - } - - function calculateTorque (currentDt) { - let torque = currentTorque - if (currentDt > 0) { - previousAngularVelocity = currentAngularVelocity - currentAngularVelocity = angularDisplacementPerImpulse / currentDt - torque = rowerSettings.flywheelInertia * ((currentAngularVelocity - previousAngularVelocity) / currentDt) + dragFactor * Math.pow(currentAngularVelocity, 2) - } - return torque - } - - function reset () { - // to init displacements with plausible defaults we assume, that one rowing cycle transforms to nine meters of distance... - const defaultDisplacementForRowingCycle = 8.0 / Math.pow(((rowerSettings.dragFactor / 1000000) / rowerSettings.magicConstant), 1.0 / 3.0) - - movingDragAverage.reset() - cyclePhase = 'Recovery' - totalTime = 0.0 - totalNumberOfImpulses = 0.0 - strokeNumber = 0.0 - drivePhaseStartTime = 0.0 - drivePhaseStartAngularDisplacement = 0.0 - drivePhaseLength = 2.0 * rowerSettings.minimumDriveTime - // split defaultDisplacementForRowingCycle to aprox 1/3 for the drive phase - drivePhaseAngularDisplacement = (1.0 / 3.0) * defaultDisplacementForRowingCycle - driveLinearDistance = 0.0 - // Make sure that the first CurrentDt will trigger a detected stroke by faking a recovery phase that is long enough - recoveryPhaseStartTime = -2 * rowerSettings.minimumRecoveryTime - // and split defaultDisplacementForRowingCycle to aprox 2/3 for the recovery phase - recoveryPhaseAngularDisplacement = (2.0 / 3.0) * defaultDisplacementForRowingCycle - // set this to the number of impulses required to generate the angular displacement as assumed above - recoveryPhaseStartAngularDisplacement = Math.round(-1.0 * (2.0 / 3.0) * defaultDisplacementForRowingCycle / angularDisplacementPerImpulse) - recoveryPhaseLength = 2.0 * rowerSettings.minimumRecoveryTime - recoveryStartAngularVelocity = angularDisplacementPerImpulse / rowerSettings.minimumTimeBetweenImpulses - recoveryEndAngularVelocity = angularDisplacementPerImpulse / rowerSettings.maximumTimeBetweenImpulses - recoveryLinearDistance = 0.0 - currentDragFactor = rowerSettings.dragFactor / 1000000 - dragFactor = movingDragAverage.getAverage() - cycleLength = minimumCycleLength - linearCycleVelocity = 0.0 - totalLinearDistance = 0.0 - averagedCyclePower = 0.0 - currentTorque = 0.0 - previousAngularVelocity = 0.0 - currentAngularVelocity = 0.0 - } - - function notify (receiver) { - workoutHandler = receiver - } - - return { - handleRotationImpulse, - reset, - notify - } -} - -export { createRowingEngine } diff --git a/app/engine/RowingEngine.test.js b/app/engine/RowingEngine.test.js deleted file mode 100644 index 5c4d2240a5..0000000000 --- a/app/engine/RowingEngine.test.js +++ /dev/null @@ -1,103 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor -*/ -import { test } from 'uvu' -import * as assert from 'uvu/assert' -import loglevel from 'loglevel' - -import rowerProfiles from '../../config/rowerProfiles.js' -import { createRowingEngine } from './RowingEngine.js' -import { replayRowingSession } from '../tools/RowingRecorder.js' -import { deepMerge } from '../tools/Helper.js' - -const log = loglevel.getLogger('RowingEngine.test') -log.setLevel('warn') - -const createWorkoutEvaluator = function () { - const strokes = [] - - function handleDriveEnd (stroke) { - strokes.push(stroke) - log.info(`stroke: ${strokes.length}, power: ${Math.round(stroke.power)}w, duration: ${stroke.duration.toFixed(2)}s, ` + - ` drivePhase: ${stroke.durationDrivePhase.toFixed(2)}s, distance: ${stroke.distance.toFixed(2)}m`) - } - function updateKeyMetrics () {} - function handleRecoveryEnd () {} - function handlePause () {} - function getNumOfStrokes () { - return strokes.length - } - function getMaxStrokePower () { - return strokes.map((stroke) => stroke.power).reduce((acc, power) => Math.max(acc, power)) - } - function getMinStrokePower () { - return strokes.map((stroke) => stroke.power).reduce((acc, power) => Math.max(acc, power)) - } - function getDistanceSum () { - return strokes.map((stroke) => stroke.strokeDistance).reduce((acc, strokeDistance) => acc + strokeDistance) - } - function getDistanceTotal () { - return strokes[strokes.length - 1].distance - } - - return { - handleDriveEnd, - handleRecoveryEnd, - updateKeyMetrics, - handlePause, - getNumOfStrokes, - getMaxStrokePower, - getMinStrokePower, - getDistanceSum, - getDistanceTotal - } -} - -test('sample data for WRX700 should produce plausible results with rower profile', async () => { - const rowingEngine = createRowingEngine(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.WRX700)) - const workoutEvaluator = createWorkoutEvaluator() - rowingEngine.notify(workoutEvaluator) - await replayRowingSession(rowingEngine.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv' }) - assert.is(workoutEvaluator.getNumOfStrokes(), 16, 'number of strokes does not meet expectation') - assertPowerRange(workoutEvaluator, 50, 220) - assertDistanceRange(workoutEvaluator, 165, 168) - assertStrokeDistanceSumMatchesTotal(workoutEvaluator) -}) - -test('sample data for DKNR320 should produce plausible results with rower profile', async () => { - const rowingEngine = createRowingEngine(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.DKNR320)) - const workoutEvaluator = createWorkoutEvaluator() - rowingEngine.notify(workoutEvaluator) - await replayRowingSession(rowingEngine.handleRotationImpulse, { filename: 'recordings/DKNR320.csv' }) - assert.is(workoutEvaluator.getNumOfStrokes(), 10, 'number of strokes does not meet expectation') - assertPowerRange(workoutEvaluator, 75, 200) - assertDistanceRange(workoutEvaluator, 71, 73) - assertStrokeDistanceSumMatchesTotal(workoutEvaluator) -}) - -test('sample data for RX800 should produce plausible results with rower profile', async () => { - const rowingEngine = createRowingEngine(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.RX800)) - const workoutEvaluator = createWorkoutEvaluator() - rowingEngine.notify(workoutEvaluator) - await replayRowingSession(rowingEngine.handleRotationImpulse, { filename: 'recordings/RX800.csv' }) - assert.is(workoutEvaluator.getNumOfStrokes(), 10, 'number of strokes does not meet expectation') - assertPowerRange(workoutEvaluator, 80, 200) - assertDistanceRange(workoutEvaluator, 70, 80) - assertStrokeDistanceSumMatchesTotal(workoutEvaluator) -}) - -function assertPowerRange (evaluator, minPower, maxPower) { - assert.ok(evaluator.getMinStrokePower() > minPower, `minimum stroke power should be above ${minPower}w, but is ${evaluator.getMinStrokePower()}w`) - assert.ok(evaluator.getMaxStrokePower() < maxPower, `maximum stroke power should be below ${maxPower}w, but is ${evaluator.getMaxStrokePower()}w`) -} - -function assertDistanceRange (evaluator, minDistance, maxDistance) { - assert.ok(evaluator.getDistanceSum() >= minDistance && evaluator.getDistanceSum() <= maxDistance, `distance should be between ${minDistance}m and ${maxDistance}m, but is ${evaluator.getDistanceSum().toFixed(2)}m`) -} - -function assertStrokeDistanceSumMatchesTotal (evaluator) { - assert.ok(evaluator.getDistanceSum().toFixed(2) === evaluator.getDistanceTotal().toFixed(2), `sum of distance of all strokes is ${evaluator.getDistanceSum().toFixed(2)}m, but total in last stroke is ${evaluator.getDistanceTotal().toFixed(2)}m`) -} - -test.run() diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index f683ddd705..8249b3d56f 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -5,127 +5,241 @@ This Module calculates the training specific metrics. */ import { EventEmitter } from 'events' -import { createMovingIntervalAverager } from './averager/MovingIntervalAverager.js' -import { createWeightedAverager } from './averager/WeightedAverager.js' +import { createRower } from './Rower.js' +import { createOLSLinearSeries } from './utils/OLSLinearSeries.js' +import { createStreamFilter } from './utils/StreamFilter.js' +import { createCurveAligner } from './utils/CurveAligner.js' import loglevel from 'loglevel' const log = loglevel.getLogger('RowingEngine') -function createRowingStatistics (config) { +function createRowingStatistics (config, session) { const numOfDataPointsForAveraging = config.numOfPhasesForAveragingScreenData - const webUpdateInterval = config.webUpdateInterval - const minimumStrokeTime = config.rowerSettings.minimumRecoveryTime + config.rowerSettings.minimumDriveTime - const maximumStrokeTime = config.maximumStrokeTime - const timeBetweenStrokesBeforePause = maximumStrokeTime * 1000 + const webUpdateInterval = Math.min(config.webUpdateInterval, 2000) + const peripheralUpdateInterval = Math.min(config.peripheralUpdateInterval, 1000) const emitter = new EventEmitter() - const strokeAverager = createWeightedAverager(numOfDataPointsForAveraging) - const powerAverager = createWeightedAverager(numOfDataPointsForAveraging) - const speedAverager = createWeightedAverager(numOfDataPointsForAveraging) - const powerRatioAverager = createWeightedAverager(numOfDataPointsForAveraging) - const caloriesAveragerMinute = createMovingIntervalAverager(60) - const caloriesAveragerHour = createMovingIntervalAverager(60 * 60) - let sessionState = 'waitingForStart' - let rowingPausedTimer + const rower = createRower(config.rowerSettings) + const minimumStrokeTime = config.rowerSettings.minimumRecoveryTime + config.rowerSettings.minimumDriveTime + const maximumStrokeTime = config.rowerSettings.maximumStrokeTimeBeforePause + const cycleDuration = createStreamFilter(numOfDataPointsForAveraging, (minimumStrokeTime + maximumStrokeTime) / 2) + const cycleDistance = createStreamFilter(numOfDataPointsForAveraging, 0) + const cyclePower = createStreamFilter(numOfDataPointsForAveraging, 0) + const cycleLinearVelocity = createStreamFilter(numOfDataPointsForAveraging, 0) + let sessionStatus = 'WaitingForStart' let heartrateResetTimer - let distanceTotal = 0.0 - let durationTotal = 0 - let strokesTotal = 0 - let caloriesTotal = 0.0 + let totalLinearDistance = 0.0 + let totalMovingTime = 0 + let totalNumberOfStrokes = 0 + let driveLastStartTime = 0 + let strokeCalories = 0 + let strokeWork = 0 + const calories = createOLSLinearSeries() + const distanceOverTime = createOLSLinearSeries(Math.min(4, numOfDataPointsForAveraging)) + const driveDuration = createStreamFilter(numOfDataPointsForAveraging, config.rowerSettings.minimumDriveTime) + const driveLength = createStreamFilter(numOfDataPointsForAveraging, 1.1) + const driveDistance = createStreamFilter(numOfDataPointsForAveraging, 3) + const recoveryDuration = createStreamFilter(numOfDataPointsForAveraging, config.rowerSettings.minimumRecoveryTime) + const driveAverageHandleForce = createStreamFilter(numOfDataPointsForAveraging, 0.0) + const drivePeakHandleForce = createStreamFilter(numOfDataPointsForAveraging, 0.0) + const driveHandleForceCurve = createCurveAligner(config.rowerSettings.minumumForceBeforeStroke) + const driveHandleVelocityCurve = createCurveAligner(1.0) + const driveHandlePowerCurve = createCurveAligner(50) + let dragFactor = config.rowerSettings.dragFactor let heartrate = 0 let heartrateBatteryLevel = 0 - let lastStrokeDuration = 0.0 - let instantaneousTorque = 0.0 - let lastStrokeDistance = 0.0 - let lastStrokeSpeed = 0.0 - let lastStrokeState = 'RECOVERY' - let lastWebMetrics = {} - - // send metrics to the web clients periodically (but only if the data has changed) + const postExerciseHR = [] + let instantPower = 0.0 + let lastStrokeState = 'WaitingForDrive' + + // send metrics to the web clients periodically setInterval(emitWebMetrics, webUpdateInterval) - function emitWebMetrics () { - const currentWebMetrics = getMetrics() - if (Object.entries(currentWebMetrics).toString() !== Object.entries(lastWebMetrics).toString()) { - emitter.emit('webMetricsUpdate', currentWebMetrics) - lastWebMetrics = currentWebMetrics - } - } // notify bluetooth peripherall each second (even if data did not change) // todo: the FTMS protocol also supports that peripherals deliver a preferred update interval // we could respect this and set the update rate accordingly - setInterval(emitPeripheralMetrics, 1000) - function emitPeripheralMetrics () { - emitter.emit('peripheralMetricsUpdate', getMetrics()) - } + setInterval(emitPeripheralMetrics, peripheralUpdateInterval) - function handleDriveEnd (stroke) { - // if we do not get a drive for timeBetweenStrokesBeforePause milliseconds we treat this as a rowing pause - if (rowingPausedTimer)clearInterval(rowingPausedTimer) - rowingPausedTimer = setTimeout(() => pauseRowing(), timeBetweenStrokesBeforePause) + function handleRotationImpulse (currentDt) { + // Provide the rower with new data + rower.handleRotationImpulse(currentDt) - // based on: http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html#section11 - const calories = (4 * powerAverager.getAverage() + 350) * (stroke.duration) / 4200 - durationTotal = stroke.timeSinceStart - powerAverager.pushValue(stroke.power) - speedAverager.pushValue(stroke.speed) - if (stroke.duration < timeBetweenStrokesBeforePause && stroke.duration > minimumStrokeTime) { - // stroke duration has to be plausible to be accepted - powerRatioAverager.pushValue(stroke.durationDrivePhase / stroke.duration) - strokeAverager.pushValue(stroke.duration) - caloriesAveragerMinute.pushValue(calories, stroke.duration) - caloriesAveragerHour.pushValue(calories, stroke.duration) - } else { - log.debug(`*** Stroke duration of ${stroke.duration} sec is considered unreliable, skipped update stroke statistics`) + // This is the core of the finite state machine that defines all state transitions + switch (true) { + case (sessionStatus === 'WaitingForStart' && rower.strokeState() === 'Drive'): + sessionStatus = 'Rowing' + startTraining() + updateContinousMetrics() + emitMetrics('recoveryFinished') + break + case (sessionStatus === 'Paused' && rower.strokeState() === 'Drive'): + sessionStatus = 'Rowing' + resumeTraining() + updateContinousMetrics() + emitMetrics('recoveryFinished') + break + case (sessionStatus !== 'Stopped' && rower.strokeState() === 'Stopped'): + sessionStatus = 'Stopped' + // We need to emit the metrics AFTER the sessionstatus changes to anything other than "Rowing", which forces most merics to zero + // This is intended behaviour, as the rower/flywheel indicate the rower has stopped somehow + stopTraining() + break + case (sessionStatus === 'Rowing' && rower.strokeState() === 'WaitingForDrive'): + sessionStatus = 'Paused' + pauseTraining() + break + case (sessionStatus === 'Rowing' && lastStrokeState === 'Recovery' && rower.strokeState() === 'Drive' && intervalTargetReached()): + updateContinousMetrics() + updateCycleMetrics() + handleRecoveryEnd() + emitMetrics('intervalTargetReached') + break + case (sessionStatus === 'Rowing' && lastStrokeState === 'Recovery' && rower.strokeState() === 'Drive'): + updateContinousMetrics() + updateCycleMetrics() + handleRecoveryEnd() + emitMetrics('recoveryFinished') + break + case (sessionStatus === 'Rowing' && lastStrokeState === 'Drive' && rower.strokeState() === 'Recovery' && intervalTargetReached()): + updateContinousMetrics() + updateCycleMetrics() + handleDriveEnd() + emitMetrics('intervalTargetReached') + break + case (sessionStatus === 'Rowing' && lastStrokeState === 'Drive' && rower.strokeState() === 'Recovery'): + updateContinousMetrics() + updateCycleMetrics() + handleDriveEnd() + emitMetrics('driveFinished') + break + case (sessionStatus === 'Rowing' && intervalTargetReached()): + updateContinousMetrics() + emitMetrics('intervalTargetReached') + break + case (sessionStatus === 'Rowing'): + updateContinousMetrics() + break + case (sessionStatus === 'Paused'): + // We are in a paused state, we won't update any metrics + break + case (sessionStatus === 'WaitingForStart'): + // We can't change into the "Rowing" state since we are waiting for a drive phase that didn't come + break + case (sessionStatus === 'Stopped'): + // We are in a stopped state, so we won't update any metrics + break + default: + log.error(`Time: ${rower.totalMovingTimeSinceStart()}, state ${rower.strokeState()} found in the Rowing Statistics, which is not captured by Finite State Machine`) } + lastStrokeState = rower.strokeState() + } - caloriesTotal += calories - lastStrokeDuration = stroke.duration - distanceTotal = stroke.distance - lastStrokeDistance = stroke.strokeDistance - lastStrokeState = stroke.strokeState - lastStrokeSpeed = stroke.speed - instantaneousTorque = stroke.instantaneousTorque - emitter.emit('driveFinished', getMetrics()) + function startTraining () { + rower.allowMovement() } - // initiated by the rowing engine in case an impulse was not considered - // because it was too large - function handlePause (duration) { - sessionState = 'paused' - caloriesAveragerMinute.pushValue(0, duration) - caloriesAveragerHour.pushValue(0, duration) - emitter.emit('rowingPaused') + function allowResumeTraining () { + rower.allowMovement() + sessionStatus = 'WaitingForStart' } - // initiated when the stroke state changes - function handleRecoveryEnd (stroke) { - // todo: we need a better mechanism to communicate strokeState updates - // this is an initial hacky attempt to see if we can use it for the C2-pm5 protocol - if (sessionState !== 'rowing') startTraining() - durationTotal = stroke.timeSinceStart - powerAverager.pushValue(stroke.power) - speedAverager.pushValue(stroke.speed) - if (stroke.duration < timeBetweenStrokesBeforePause && stroke.duration > minimumStrokeTime) { - // stroke duration has to be plausible to be accepted - powerRatioAverager.pushValue(stroke.durationDrivePhase / stroke.duration) - strokeAverager.pushValue(stroke.duration) + function resumeTraining () { + rower.allowMovement() + } + + function stopTraining () { + rower.stopMoving() + lastStrokeState = 'Stopped' + // Emitting the metrics BEFORE the sessionstatus changes to anything other than "Rowing" forces most merics to zero + // As there are more than one way to this method, we FIRST emit the metrics and then set them to zero + // If they need to be forced to zero (as the flywheel seems to have stopped), this status has to be set before the call + emitMetrics('rowingStopped') + sessionStatus = 'Stopped' + postExerciseHR.splice(0, postExerciseHR.length) + measureRecoveryHR() + } + + // clear the metrics in case the user pauses rowing + function pauseTraining () { + log.debug('*** Paused rowing ***') + rower.pauseMoving() + cycleDuration.reset() + cycleDistance.reset() + cyclePower.reset() + cycleLinearVelocity.reset() + lastStrokeState = 'WaitingForDrive' + // We need to emit the metrics BEFORE the sessionstatus changes to anything other than "Rowing", as it forces most merics to zero + emitMetrics('rowingPaused') + sessionStatus = 'Paused' + postExerciseHR.splice(0, postExerciseHR.length) + measureRecoveryHR() + } + + function resetTraining () { + stopTraining() + rower.reset() + calories.reset() + rower.allowMovement() + totalMovingTime = 0 + totalLinearDistance = 0.0 + totalNumberOfStrokes = -1 + driveLastStartTime = 0 + distanceOverTime.reset() + driveDuration.reset() + cycleDuration.reset() + cycleDistance.reset() + cyclePower.reset() + strokeCalories = 0 + strokeWork = 0 + postExerciseHR.splice(0, postExerciseHR.length) + cycleLinearVelocity.reset() + lastStrokeState = 'WaitingForDrive' + emitMetrics('rowingPaused') + sessionStatus = 'WaitingForStart' + } + + // initiated when updating key statistics + function updateContinousMetrics () { + totalMovingTime = rower.totalMovingTimeSinceStart() + totalLinearDistance = rower.totalLinearDistanceSinceStart() + instantPower = rower.instantHandlePower() + } + + function updateCycleMetrics () { + distanceOverTime.push(rower.totalMovingTimeSinceStart(), rower.totalLinearDistanceSinceStart()) + if (rower.cycleDuration() < maximumStrokeTime && rower.cycleDuration() > minimumStrokeTime) { + // stroke duration has to be credible to be accepted + cycleDuration.push(rower.cycleDuration()) + cycleDistance.push(rower.cycleLinearDistance()) + cycleLinearVelocity.push(rower.cycleLinearVelocity()) + cyclePower.push(rower.cyclePower()) } else { - log.debug(`*** Stroke duration of ${stroke.duration} sec is considered unreliable, skipped update stroke statistics`) + log.debug(`*** Stroke duration of ${rower.cycleDuration()} sec is considered unreliable, skipped update cycle statistics`) } - distanceTotal = stroke.distance - strokesTotal = stroke.numberOfStrokes - lastStrokeDistance = stroke.strokeDistance - lastStrokeState = stroke.strokeState - lastStrokeSpeed = stroke.speed - instantaneousTorque = stroke.instantaneousTorque - emitter.emit('recoveryFinished', getMetrics()) } - // initiated when updating key statistics - function updateKeyMetrics (stroke) { - durationTotal = stroke.timeSinceStart - distanceTotal = stroke.distance - instantaneousTorque = stroke.instantaneousTorque + function handleDriveEnd () { + driveDuration.push(rower.driveDuration()) + driveLength.push(rower.driveLength()) + driveDistance.push(rower.driveLinearDistance()) + driveAverageHandleForce.push(rower.driveAverageHandleForce()) + drivePeakHandleForce.push(rower.drivePeakHandleForce()) + driveHandleForceCurve.push(rower.driveHandleForceCurve()) + driveHandleVelocityCurve.push(rower.driveHandleVelocityCurve()) + driveHandlePowerCurve.push(rower.driveHandlePowerCurve()) + } + + // initiated when the stroke state changes + function handleRecoveryEnd () { + totalNumberOfStrokes = rower.totalNumberOfStrokes() + driveLastStartTime = rower.driveLastStartTime() + recoveryDuration.push(rower.recoveryDuration()) + dragFactor = rower.recoveryDragFactor() + + // based on: http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html#section11 + strokeCalories = (4 * cyclePower.clean() + 350) * (cycleDuration.clean()) / 4200 + strokeWork = cyclePower.clean() * cycleDuration.clean() + const totalCalories = calories.yAtSeriesEnd() + strokeCalories + calories.push(totalMovingTime, totalCalories) } // initiated when a new heart rate value is received from heart rate sensor @@ -140,88 +254,110 @@ function createRowingStatistics (config) { heartrateBatteryLevel = value.batteryLevel } - function getMetrics () { - const splitTime = speedAverager.getAverage() !== 0 && lastStrokeSpeed > 0 ? (500.0 / speedAverager.getAverage()) : Infinity - // todo: due to sanitization we currently do not use a consistent time throughout the engine - // We will rework this section to use both absolute and sanitized time in the appropriate places. - // We will also polish up the events for the recovery and drive phase, so we get clean complete strokes from the first stroke onwards. - const averagedStrokeTime = strokeAverager.getAverage() > minimumStrokeTime && strokeAverager.getAverage() < maximumStrokeTime && lastStrokeSpeed > 0 && sessionState === 'rowing' ? strokeAverager.getAverage() : 0 // seconds - return { - sessionState, - durationTotal, - durationTotalFormatted: secondsToTimeString(durationTotal), - strokesTotal, - distanceTotal: distanceTotal > 0 ? distanceTotal : 0, // meters - caloriesTotal, // kcal - caloriesPerMinute: caloriesAveragerMinute.getAverage() > 0 ? caloriesAveragerMinute.getAverage() : 0, - caloriesPerHour: caloriesAveragerHour.getAverage() > 0 ? caloriesAveragerHour.getAverage() : 0, - strokeTime: lastStrokeDuration, // seconds - distance: lastStrokeDistance > 0 && lastStrokeSpeed > 0 && sessionState === 'rowing' ? lastStrokeDistance : 0, // meters - power: powerAverager.getAverage() > 0 && lastStrokeSpeed > 0 && sessionState === 'rowing' ? powerAverager.getAverage() : 0, // watts - split: splitTime, // seconds/500m - splitFormatted: secondsToTimeString(splitTime), - powerRatio: powerRatioAverager.getAverage() > 0 && lastStrokeSpeed > 0 && sessionState === 'rowing' ? powerRatioAverager.getAverage() : 0, - instantaneousTorque, - strokesPerMinute: averagedStrokeTime !== 0 && sessionState === 'rowing' ? (60.0 / averagedStrokeTime) : 0, - speed: speedAverager.getAverage() > 0 && lastStrokeSpeed > 0 && sessionState === 'rowing' ? (speedAverager.getAverage() * 3.6) : 0, // km/h - strokeState: lastStrokeState, - heartrate, - heartrateBatteryLevel + function intervalTargetReached () { + if ((session.targetDistance > 0 && rower.totalLinearDistanceSinceStart() >= session.targetDistance) || (session.targetTime > 0 && rower.totalMovingTimeSinceStart() >= session.targetTime)) { + return true + } else { + return false } } - function startTraining () { - sessionState = 'rowing' + function measureRecoveryHR () { + // This function is called when the rowing session is stopped. postExerciseHR[0] is the last measured excercise HR + // Thus postExerciseHR[1] is Recovery HR after 1 min, etc.. + if (heartrate !== undefined && heartrate > config.userSettings.restingHR && sessionStatus !== 'Rowing') { + log.debug(`*** HRR-${postExerciseHR.length}: ${heartrate}`) + postExerciseHR.push(heartrate) + if ((postExerciseHR.length > 1) && (postExerciseHR.length <= 4)) { + // We skip reporting postExerciseHR[0] and only report measuring postExerciseHR[1], postExerciseHR[2], postExerciseHR[3] + emitter.emit('HRRecoveryUpdate', postExerciseHR) + } + if (postExerciseHR.length < 4) { + // We haven't got three post-exercise HR measurements yet, let's schedule the next measurement + setTimeout(measureRecoveryHR, 60000) + } + } } - function stopTraining () { - sessionState = 'stopped' - if (rowingPausedTimer)clearInterval(rowingPausedTimer) + function emitWebMetrics () { + emitMetrics('webMetricsUpdate') } - function resetTraining () { - stopTraining() - distanceTotal = 0.0 - strokesTotal = 0 - caloriesTotal = 0.0 - durationTotal = 0 - caloriesAveragerMinute.reset() - caloriesAveragerHour.reset() - strokeAverager.reset() - powerAverager.reset() - speedAverager.reset() - powerRatioAverager.reset() - sessionState = 'waitingForStart' + function emitPeripheralMetrics () { + emitMetrics('peripheralMetricsUpdate') } - // clear the metrics in case the user pauses rowing - function pauseRowing () { - strokeAverager.reset() - powerAverager.reset() - speedAverager.reset() - powerRatioAverager.reset() - lastStrokeState = 'RECOVERY' - sessionState = 'paused' - emitter.emit('rowingPaused') + function emitMetrics (emitType = 'webMetricsUpdate') { + emitter.emit(emitType, getMetrics()) } - // converts a timestamp in seconds to a human readable hh:mm:ss format + function getMetrics () { + const cyclePace = cycleLinearVelocity.clean() !== 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? (500.0 / cycleLinearVelocity.clean()) : Infinity + return { + sessiontype: session.targetDistance > 0 ? 'Distance' : (session.targetTime > 0 ? 'Time' : 'JustRow'), + sessionStatus, + strokeState: rower.strokeState(), + totalMovingTime: totalMovingTime > 0 ? totalMovingTime : 0, + driveLastStartTime: driveLastStartTime > 0 ? driveLastStartTime : 0, + totalMovingTimeFormatted: session.targetTime > 0 ? secondsToTimeString(Math.round(Math.max(session.targetTime - totalMovingTime, 0))) : secondsToTimeString(Math.round(totalMovingTime)), + totalNumberOfStrokes: totalNumberOfStrokes > 0 ? totalNumberOfStrokes : 0, + totalLinearDistance: totalLinearDistance > 0 ? totalLinearDistance : 0, // meters + totalLinearDistanceFormatted: session.targetDistance > 0 ? Math.max(session.targetDistance - totalLinearDistance, 0) : totalLinearDistance, + strokeCalories: strokeCalories > 0 ? strokeCalories : 0, // kCal + strokeWork: strokeWork > 0 ? strokeWork : 0, // Joules + totalCalories: calories.yAtSeriesEnd() > 0 ? calories.yAtSeriesEnd() : 0, // kcal + totalCaloriesPerMinute: totalMovingTime > 60 ? caloriesPerPeriod(totalMovingTime - 60, totalMovingTime) : caloriesPerPeriod(0, 60), + totalCaloriesPerHour: totalMovingTime > 3600 ? caloriesPerPeriod(totalMovingTime - 3600, totalMovingTime) : caloriesPerPeriod(0, 3600), + cycleDuration: cycleDuration.clean() > minimumStrokeTime && cycleDuration.clean() < maximumStrokeTime && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cycleDuration.clean() : NaN, // seconds + cycleStrokeRate: cycleDuration.clean() > minimumStrokeTime && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? (60.0 / cycleDuration.clean()) : 0, // strokeRate in SPM + cycleDistance: cycleDistance.raw() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cycleDistance.clean() : 0, // meters + cycleLinearVelocity: cycleLinearVelocity.clean() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cycleLinearVelocity.clean() : 0, // m/s + cyclePace: cycleLinearVelocity.raw() > 0 ? cyclePace : Infinity, // seconds/500m + cyclePaceFormatted: cycleLinearVelocity.raw() > 0 ? secondsToTimeString(Math.round(cyclePace)) : Infinity, + cyclePower: cyclePower.clean() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cyclePower.clean() : 0, // watts + cycleProjectedEndTime: session.targetDistance > 0 ? distanceOverTime.projectY(session.targetDistance) : session.targetTime, + cycleProjectedEndLinearDistance: session.targetTime > 0 ? distanceOverTime.projectX(session.targetTime) : session.targetDistance, + driveDuration: driveDuration.clean() >= config.rowerSettings.minimumDriveTime && totalNumberOfStrokes > 0 && sessionStatus === 'Rowing' ? driveDuration.clean() : NaN, // seconds + driveLength: driveLength.clean() > 0 && sessionStatus === 'Rowing' ? driveLength.clean() : NaN, // meters of chain movement + driveDistance: driveDistance.clean() >= 0 && sessionStatus === 'Rowing' ? driveDistance.clean() : NaN, // meters + driveAverageHandleForce: driveAverageHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveAverageHandleForce.clean() : NaN, + drivePeakHandleForce: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? drivePeakHandleForce.clean() : NaN, + driveHandleForceCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandleForceCurve.lastCompleteCurve() : [NaN], + driveHandleVelocityCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandleVelocityCurve.lastCompleteCurve() : [NaN], + driveHandlePowerCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandlePowerCurve.lastCompleteCurve() : [NaN], + recoveryDuration: recoveryDuration.clean() >= config.rowerSettings.minimumRecoveryTime && totalNumberOfStrokes > 0 && sessionStatus === 'Rowing' ? recoveryDuration.clean() : NaN, // seconds + dragFactor: dragFactor > 0 ? dragFactor : config.rowerSettings.dragFactor, // Dragfactor + instantPower: instantPower > 0 && rower.strokeState() === 'Drive' ? instantPower : 0, + heartrate: heartrate > 30 ? heartrate : undefined, + heartrateBatteryLevel: heartrateBatteryLevel > 0 ? heartrateBatteryLevel : undefined // BE AWARE, changing undefined to NaN kills the GUI!!! + } + } + + // converts a timeStamp in seconds to a human readable hh:mm:ss format function secondsToTimeString (secondsTimeStamp) { if (secondsTimeStamp === Infinity) return '∞' const hours = Math.floor(secondsTimeStamp / 60 / 60) const minutes = Math.floor(secondsTimeStamp / 60) - (hours * 60) const seconds = Math.floor(secondsTimeStamp % 60) - let timeString = hours > 0 ? ` ${hours.toString().padStart(2, '0')}:` : '' - timeString += `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` - return timeString + if (hours > 0) { + return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` + } else { + return `${minutes}:${seconds.toString().padStart(2, '0')}` + } + } + + function caloriesPerPeriod (periodBegin, periodEnd) { + const beginCalories = calories.projectX(periodBegin) + const endCalories = calories.projectX(periodEnd) + return (endCalories - beginCalories) } return Object.assign(emitter, { - handleDriveEnd, - handlePause, handleHeartrateMeasurement, - handleRecoveryEnd, - updateKeyMetrics, + handleRotationImpulse, + pause: pauseTraining, + stop: stopTraining, + resume: allowResumeTraining, reset: resetTraining }) } diff --git a/app/engine/Timer.js b/app/engine/Timer.js deleted file mode 100644 index 3f6cffcfe2..0000000000 --- a/app/engine/Timer.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Stopwatch used to measure multiple time intervals -*/ -function createTimer () { - const timerMap = new Map() - - function start (key) { - timerMap.set(key, 0.0) - } - - function stop (key) { - timerMap.delete(key) - } - - function getValue (key) { - return timerMap.get(key) || 0.0 - } - - function updateTimers (currentDt) { - timerMap.forEach((value, key) => { - timerMap.set(key, value + currentDt) - }) - } - - return { - start, - stop, - getValue, - updateTimers - } -} - -export { createTimer } diff --git a/app/engine/VO2max.js b/app/engine/VO2max.js new file mode 100644 index 0000000000..6d15189c2d --- /dev/null +++ b/app/engine/VO2max.js @@ -0,0 +1,165 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This Module calculates the training specific VO2Max metrics. It is based on formula's found on the web (see function definitions). +*/ + +import { createBucketedLinearSeries } from './utils/BucketedLinearSeries.js' + +import loglevel from 'loglevel' +const log = loglevel.getLogger('RowingEngine') + +function createVO2max (config) { + const bucketedLinearSeries = createBucketedLinearSeries(config) + const minimumValidBrackets = 5.0 + const offset = 90 + + function calculateVO2max (metrics) { + let projectedVO2max = 0 + let interpolatedVO2max = 0 + + if (metrics[0].heartrate !== undefined && metrics[metrics.length - 1].heartrate !== undefined && metrics[metrics.length - 1].heartrate >= config.userSettings.restingHR) { + projectedVO2max = extrapolatedVO2max(metrics) + } + + interpolatedVO2max = calculateInterpolatedVO2max(metrics) + + if (projectedVO2max >= 10 && projectedVO2max <= 60 && interpolatedVO2max >= 10 && interpolatedVO2max <= 60) { + // Both VO2Max calculations have delivered a valid and credible result + log.debug(`--- VO2Max calculation delivered two credible results Extrapolated VO2Max: ${projectedVO2max.toFixed(1)} and Interpolated VO2Max: ${interpolatedVO2max.toFixed(1)}`) + return ((projectedVO2max + interpolatedVO2max) / 2) + } else { + // One of the calculations has delivered an invalid result + if (interpolatedVO2max >= 10 && interpolatedVO2max <= 60) { + // Interpolation has delivered a credible result + log.debug(`--- VO2Max calculation delivered one credible result, the Interpolated VO2Max: ${interpolatedVO2max.toFixed(1)}. The Extrapolated VO2Max: ${projectedVO2max.toFixed(1)} was unreliable`) + return interpolatedVO2max + } else { + // Interpolation hasn't delivered a credible result + if (projectedVO2max >= 10 && projectedVO2max <= 60) { + // Extrapolation did deliver a credible result + log.debug(`--- VO2Max calculation delivered one credible result, the Extrapolated VO2Max: ${projectedVO2max.toFixed(1)}. Interpolated VO2Max: ${interpolatedVO2max.toFixed(1)} was unreliable`) + return projectedVO2max + } else { + // No credible results at all! + log.debug(`--- VO2Max calculation did not deliver any credible results Extrapolated VO2Max: ${projectedVO2max.toFixed(1)}, Interpolated VO2Max: ${interpolatedVO2max.toFixed(1)}`) + return 0 + } + } + } + } + + function extrapolatedVO2max (metrics) { + // This implements the extrapolation-based VO2Max determination + // Which is based on the extrapolated maximum power output based on the correlation between heartrate and power, + // Underlying formula's can be found here: https://sportcoaching.co.nz/how-does-garmin-calculate-vo2-max/ + let ProjectedVO2max + let i = 0 + while (i < metrics.length && metrics[i].totalMovingTime < offset) { + // We skip the first timeperiod as it only depicts the change from a resting HR to a working HR + i++ + } + while (i < metrics.length) { + if (metrics[i].heartrate !== undefined && metrics[i].heartrate >= config.userSettings.restingHR && metrics[i].heartrate <= config.userSettings.maxHR && metrics[i].cyclePower !== undefined && metrics[i].cyclePower >= config.userSettings.minPower && metrics[i].cyclePower <= config.userSettings.maxPower) { + // The data looks credible, lets add it + bucketedLinearSeries.push(metrics[i].heartrate, metrics[i].cyclePower) + } + i++ + } + + // All Datapoints have been added, now we determine the projected power + if (bucketedLinearSeries.numberOfSamples() >= minimumValidBrackets) { + const projectedPower = bucketedLinearSeries.projectX(config.userSettings.maxHR) + if (projectedPower <= config.userSettings.maxPower && projectedPower >= bucketedLinearSeries.maxEncounteredY()) { + ProjectedVO2max = ((14.72 * projectedPower) + 250.39) / config.userSettings.weight + log.debug(`--- VO2Max Goodness of Fit: ${bucketedLinearSeries.goodnessOfFit().toFixed(6)}, projected power ${projectedPower.toFixed(1)} Watt, extrapolated VO2Max: ${ProjectedVO2max.toFixed(1)}`) + } else { + ProjectedVO2max = ((14.72 * bucketedLinearSeries.maxEncounteredY()) + 250.39) / config.userSettings.weight + log.debug(`--- VO2Max maximum encountered power: ${bucketedLinearSeries.maxEncounteredY().toFixed(1)} Watt, extrapolated VO2Max: ${ProjectedVO2max.toFixed(1)}`) + } + } else { + log.debug(`--- VO2Max extrapolation failed as there were not enough valid brackets: ${bucketedLinearSeries.numberOfSamples()}`) + ProjectedVO2max = 0 + } + return ProjectedVO2max + } + + function calculateInterpolatedVO2max (metrics) { + // This is based on research done by concept2, https://www.concept2.com/indoor-rowers/training/calculators/vo2max-calculator, + // which determines the VO2Max based on the 2K speed + const distance = metrics[metrics.length - 1].totalLinearDistance + const time = metrics[metrics.length - 1].totalMovingTime + const projectedTwoKPace = interpolatePace(time, distance, 2000) + const projectedTwoKTimeInMinutes = (4 * projectedTwoKPace) / 60 + let Y = 0 + + log.debug(`--- VO2Max Interpolated 2K pace: ${Math.floor(projectedTwoKPace / 60)}:${(projectedTwoKPace % 60).toFixed(1)}`) + // This implements the table with formulas found at https://www.concept2.com/indoor-rowers/training/calculators/vo2max-calculator + if (config.userSettings.highlyTrained) { + // Highly trained + if (config.userSettings.sex === 'male') { + // Highly trained male + if (config.userSettings.weight > 75) { + // Highly trained male, above 75 Kg + Y = 15.7 - (1.5 * projectedTwoKTimeInMinutes) + } else { + // Highly trained male, equal or below 75 Kg + Y = 15.1 - (1.5 * projectedTwoKTimeInMinutes) + } + } else { + // Highly trained female + if (config.userSettings.weight > 61.36) { + // Highly trained female, above 61.36 Kg + Y = 14.9 - (1.5 * projectedTwoKTimeInMinutes) + } else { + // Highly trained female, equal or below 61.36 Kg + Y = 14.6 - (1.5 * projectedTwoKTimeInMinutes) + } + } + } else { + // Not highly trained + if (config.userSettings.sex === 'male') { + // Not highly trained male + Y = 10.7 - (0.9 * projectedTwoKTimeInMinutes) + } else { + // Not highly trained female + Y = 10.26 - (0.93 * projectedTwoKTimeInMinutes) + } + } + return (Y * 1000) / config.userSettings.weight + } + + function interpolatePace (origintime, origindistance, targetdistance) { + // We interpolate the 2K speed based on Paul's Law: https://paulergs.weebly.com/blog/a-quick-explainer-on-pauls-law + let originpace = 0 + + if (origintime > 0 && origindistance > 0 && targetdistance > 0) { + originpace = (500 * origintime) / origindistance + return (originpace + (config.userSettings.distanceCorrectionFactor * Math.log2(targetdistance / origindistance))) + } else { + return 0 + } + } + + function averageObservedHR () { + bucketedLinearSeries.averageEncounteredX() + } + + function maxObservedHR () { + bucketedLinearSeries.maxEncounteredX() + } + + function reset () { + bucketedLinearSeries.reset() + } + + return { + calculateVO2max, + averageObservedHR, + maxObservedHR, + reset + } +} + +export { createVO2max } diff --git a/app/engine/WorkoutRecorder.js b/app/engine/WorkoutRecorder.js index 192b6efecd..5370a1432f 100644 --- a/app/engine/WorkoutRecorder.js +++ b/app/engine/WorkoutRecorder.js @@ -11,12 +11,14 @@ import zlib from 'zlib' import fs from 'fs/promises' import xml2js from 'xml2js' import config from '../tools/ConfigManager.js' +import { createVO2max } from './VO2max.js' import { promisify } from 'util' const gzip = promisify(zlib.gzip) function createWorkoutRecorder () { let strokes = [] let rotationImpulses = [] + let postExerciseHR = [] let startTime function recordRotationImpulse (impulse) { @@ -53,6 +55,41 @@ function createWorkoutRecorder () { await createFile(rotationImpulses.join('\n'), filename, config.gzipRawDataFiles) } + async function createRowingDataFile () { + const stringifiedStartTime = startTime.toISOString().replace(/T/, '_').replace(/:/g, '-').replace(/\..+/, '') + const directory = `${config.dataDirectory}/recordings/${startTime.getFullYear()}/${(startTime.getMonth() + 1).toString().padStart(2, '0')}` + const filename = `${directory}/${stringifiedStartTime}_rowingData.csv` + let currentstroke + let trackPointTime + let timestamp + let i + + log.info(`saving session as RowingData file ${filename}...`) + + // Required file header, please note this includes a typo and odd spaces as the specification demands it! + let RowingData = ',index, Stroke Number,TimeStamp (sec), ElapsedTime (sec), HRCur (bpm),DistanceMeters, Cadence (stokes/min), Stroke500mPace (sec/500m), Power (watts), StrokeDistance (meters),' + + ' DriveTime (ms), DriveLength (meters), StrokeRecoveryTime (ms),Speed, Horizontal (meters), Calories (kCal), DragFactor, PeakDriveForce (N), AverageDriveForce (N),' + + 'Handle_Force_(N),Handle_Velocity_(m/s),Handle_Power_(W)\n' + + // Add the strokes + i = 0 + while (i < strokes.length) { + currentstroke = strokes[i] + trackPointTime = new Date(startTime.getTime() + currentstroke.totalMovingTime * 1000) + timestamp = trackPointTime.getTime() / 1000 + + RowingData += `${currentstroke.totalNumberOfStrokes.toFixed(0)},${currentstroke.totalNumberOfStrokes.toFixed(0)},${currentstroke.totalNumberOfStrokes.toFixed(0)},${timestamp.toFixed(0)},` + + `${currentstroke.totalMovingTime.toFixed(2)},${(currentstroke.heartrate > 30 ? currentstroke.heartrate.toFixed(0) : NaN)},${currentstroke.totalLinearDistance.toFixed(1)},` + + `${currentstroke.cycleStrokeRate.toFixed(1)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.cyclePace.toFixed(2) : NaN)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.cyclePower.toFixed(0) : NaN)},` + + `${currentstroke.cycleDistance.toFixed(2)},${(currentstroke.driveDuration * 1000).toFixed(0)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.driveLength.toFixed(2) : NaN)},${(currentstroke.recoveryDuration * 1000).toFixed(0)},` + + `${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.cycleLinearVelocity.toFixed(2) : 0)},${currentstroke.totalLinearDistance.toFixed(1)},${currentstroke.totalCalories.toFixed(1)},${currentstroke.dragFactor.toFixed(1)},` + + `${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.drivePeakHandleForce.toFixed(1) : NaN)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.driveAverageHandleForce.toFixed(1) : 0)},"${currentstroke.driveHandleForceCurve}",` + + `"${currentstroke.driveHandleVelocityCurve}","${currentstroke.driveHandlePowerCurve}"\n` + i++ + } + await createFile(RowingData, `${filename}`, false) + } + async function createTcxFile () { const tcxRecord = await activeWorkoutToTcx() if (tcxRecord === undefined) { @@ -76,7 +113,7 @@ function createWorkoutRecorder () { async function activeWorkoutToTcx () { // we need at least two strokes to generate a valid tcx file - if (strokes.length < 2) return + if (strokes.length < 5) return const stringifiedStartTime = startTime.toISOString().replace(/T/, '_').replace(/:/g, '-').replace(/\..+/, '') const filename = `${stringifiedStartTime}_rowing.tcx` @@ -94,8 +131,32 @@ function createWorkoutRecorder () { async function workoutToTcx (workout) { let versionArray = process.env.npm_package_version.split('.') - if (versionArray.length < 3) versionArray = [0, 0, 0] + if (versionArray.length < 3) versionArray = ['0', '0', '0'] const lastStroke = workout.strokes[strokes.length - 1] + const drag = workout.strokes.reduce((sum, s) => sum + s.dragFactor, 0) / strokes.length + + // VO2Max calculation for the remarks section + let VO2maxoutput = 'UNDEFINED' + const VO2max = createVO2max(config) + const VO2maxResult = VO2max.calculateVO2max(strokes) + if (VO2maxResult > 10 && VO2maxResult < 60) { + VO2maxoutput = `${VO2maxResult.toFixed(1)} mL/(kg*min)` + } + + // Addition of HRR data + let hrrAdittion = '' + if (postExerciseHR.length > 1 && (postExerciseHR[0] > (0.7 * config.userSettings.maxHR))) { + // Recovery Heartrate is only defined when the last excercise HR is above 70% of the maximum Heartrate + if (postExerciseHR.length === 2) { + hrrAdittion = `, HRR1: ${postExerciseHR[1] - postExerciseHR[0]} (${postExerciseHR[1]} BPM)` + } + if (postExerciseHR.length === 3) { + hrrAdittion = `, HRR1: ${postExerciseHR[1] - postExerciseHR[0]} (${postExerciseHR[1]} BPM), HRR2: ${postExerciseHR[2] - postExerciseHR[1]} (${postExerciseHR[2]} BPM)` + } + if (postExerciseHR.length >= 4) { + hrrAdittion = `, HRR1: ${postExerciseHR[1] - postExerciseHR[0]} (${postExerciseHR[1]} BPM), HRR2: ${postExerciseHR[2] - postExerciseHR[1]} (${postExerciseHR[2]} BPM), HRR3: ${postExerciseHR[3] - postExerciseHR[2]} (${postExerciseHR[3]} BPM)` + } + } const tcxObject = { TrainingCenterDatabase: { @@ -107,38 +168,37 @@ function createWorkoutRecorder () { Lap: [ { $: { StartTime: workout.startTime.toISOString() }, - TotalTimeSeconds: workout.strokes.reduce((acc, stroke) => acc + stroke.strokeTime, 0).toFixed(1), - DistanceMeters: lastStroke.distanceTotal.toFixed(1), - // tcx uses meters per second as unit for speed - MaximumSpeed: (workout.strokes.map((stroke) => stroke.speed).reduce((acc, speed) => Math.max(acc, speed)) / 3.6).toFixed(2), - Calories: Math.round(lastStroke.caloriesTotal), - /* todo: calculate heart rate metrics... - AverageHeartRateBpm: { Value: 76 }, - MaximumHeartRateBpm: { Value: 76 }, + TotalTimeSeconds: lastStroke.totalMovingTime.toFixed(1), + DistanceMeters: lastStroke.totalLinearDistance.toFixed(1), + MaximumSpeed: (workout.strokes.map((stroke) => stroke.cycleLinearVelocity).reduce((acc, cycleLinearVelocity) => Math.max(acc, cycleLinearVelocity))).toFixed(2), + Calories: Math.round(lastStroke.totalCalories), + /* ToDo Fix issue with IF-statement not being accepted here? + if (lastStroke.heartrate !== undefined && lastStroke.heartrate > 30) { + AverageHeartRateBpm: VO2max.averageObservedHR(), + MaximumHeartRateBpm: VO2max.maxObservedHR, + //AverageHeartRateBpm: { Value: (workout.strokes.reduce((sum, s) => sum + s.heartrate, 0) / workout.strokes.length).toFixed(2) }, + //MaximumHeartRateBpm: { Value: Math.round(workout.strokes.map((stroke) => stroke.power).reduce((acc, heartrate) => Math.max(acc, heartrate))) }, + } */ Intensity: 'Active', - // todo: calculate average SPM - // Cadence: 20, + Cadence: Math.round(workout.strokes.reduce((sum, s) => sum + s.cycleStrokeRate, 0) / (workout.strokes.length - 1)), TriggerMethod: 'Manual', Track: { Trackpoint: (() => { - let trackPointTime = workout.startTime - return workout.strokes.map((stroke) => { - trackPointTime = new Date(trackPointTime.getTime() + stroke.strokeTime * 1000) + const trackPointTime = new Date(workout.startTime.getTime() + stroke.totalMovingTime * 1000) const trackpoint = { Time: trackPointTime.toISOString(), - DistanceMeters: stroke.distanceTotal.toFixed(2), - Cadence: Math.round(stroke.strokesPerMinute), + DistanceMeters: stroke.totalLinearDistance.toFixed(2), + Cadence: Math.round(stroke.cycleStrokeRate), Extensions: { 'ns2:TPX': { - // tcx uses meters per second as unit for speed - 'ns2:Speed': (stroke.speed / 3.6).toFixed(2), - 'ns2:Watts': Math.round(stroke.power) + 'ns2:Speed': stroke.cycleLinearVelocity.toFixed(2), + 'ns2:Watts': Math.round(stroke.cyclePower) } } } - if (stroke.heartrate !== undefined) { + if (stroke.heartrate !== undefined && stroke.heartrate > 30) { trackpoint.HeartRateBpm = { Value: stroke.heartrate } } return trackpoint @@ -147,16 +207,16 @@ function createWorkoutRecorder () { }, Extensions: { 'ns2:LX': { - /* todo: calculate these metrics... - 'ns2:AvgSpeed': 12, - 'ns2:AvgWatts': 133, - */ - 'ns2:MaxWatts': Math.round(workout.strokes.map((stroke) => stroke.power).reduce((acc, power) => Math.max(acc, power))) + 'ns2:Steps': lastStroke.totalNumberOfStrokes.toFixed(0), + // please note, the -1 is needed as we have a stroke 0, with a speed and power of 0. The - 1 corrects this. + 'ns2:AvgSpeed': (workout.strokes.reduce((sum, s) => sum + s.cycleLinearVelocity, 0) / (workout.strokes.length - 1)).toFixed(2), + 'ns2:AvgWatts': (workout.strokes.reduce((sum, s) => sum + s.cyclePower, 0) / (workout.strokes.length - 1)).toFixed(0), + 'ns2:MaxWatts': Math.round(workout.strokes.map((stroke) => stroke.cyclePower).reduce((acc, cyclePower) => Math.max(acc, cyclePower))) } } } ], - Notes: 'Rowing Session' + Notes: `Indoor Rowing, Drag factor: ${drag.toFixed(1)} 10-6 N*m*s2, Estimated VO2Max: ${VO2maxoutput}${hrrAdittion}` } }, Author: { @@ -184,15 +244,24 @@ function createWorkoutRecorder () { await createRecordings() strokes = [] rotationImpulses = [] + postExerciseHR = [] startTime = undefined } async function createFile (content, filename, compress = false) { if (compress) { const gzipContent = await gzip(content) - await fs.writeFile(filename, gzipContent, (err) => { if (err) log.error(err) }) + try { + await fs.writeFile(filename, gzipContent) + } catch (err) { + log.error(err) + } } else { - await fs.writeFile(filename, content, (err) => { if (err) log.error(err) }) + try { + await fs.writeFile(filename, content) + } catch (err) { + log.error(err) + } } } @@ -218,13 +287,21 @@ function createWorkoutRecorder () { if (config.createTcxFiles) { parallelCalls.push(createTcxFile()) } + if (config.createRowingDataFiles) { + parallelCalls.push(createRowingDataFile()) + } await Promise.all(parallelCalls) } + async function updateHRRecovery (hrmetrics) { + postExerciseHR = hrmetrics + createTcxFile() + } + function minimumRecordingTimeHasPassed () { const minimumRecordingTimeInSeconds = 10 const rotationImpulseTimeTotal = rotationImpulses.reduce((acc, impulse) => acc + impulse, 0) - const strokeTimeTotal = strokes.reduce((acc, stroke) => acc + stroke.strokeTime, 0) + const strokeTimeTotal = strokes[strokes.length - 1].totalMovingTime return (Math.max(rotationImpulseTimeTotal, strokeTimeTotal) > minimumRecordingTimeInSeconds) } @@ -233,6 +310,8 @@ function createWorkoutRecorder () { recordRotationImpulse, handlePause, activeWorkoutToTcx, + writeRecordings: createRecordings, + updateHRRecovery, reset } } diff --git a/app/engine/averager/MovingAverager.js b/app/engine/averager/MovingAverager.js deleted file mode 100644 index cbdcf3beb9..0000000000 --- a/app/engine/averager/MovingAverager.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This Averager can calculate the moving average of a continuous flow of data points - - Please note: The array contains flankLength + 1 measured currentDt's, thus flankLength number - of flanks between them. - They are arranged that dataPoints[0] is the youngest, and dataPoints[flankLength] the oldest -*/ -function createMovingAverager (length, initValue) { - let dataPoints - reset() - - function pushValue (dataPoint) { - // add the new dataPoint to the array, we have to move data points starting at the oldest ones - let i = length - 1 - while (i > 0) { - // older data points are moved towards the higher numbers - dataPoints[i] = dataPoints[i - 1] - i = i - 1 - } - dataPoints[0] = dataPoint - } - - function replaceLastPushedValue (dataPoint) { - // replace the newest dataPoint in the array, as it was faulty - dataPoints[0] = dataPoint - } - - function getAverage () { - let i = length - 1 - let arrayTotal = 0.0 - while (i >= 0) { - // summarize the value of the moving average - arrayTotal = arrayTotal + dataPoints[i] - i = i - 1 - } - const arrayAverage = arrayTotal / length - return arrayAverage - } - - function reset () { - dataPoints = new Array(length) - dataPoints.fill(initValue) - } - - return { - pushValue, - replaceLastPushedValue, - getAverage, - reset - } -} - -export { createMovingAverager } diff --git a/app/engine/averager/MovingAverager.test.js b/app/engine/averager/MovingAverager.test.js deleted file mode 100644 index 748d720a9c..0000000000 --- a/app/engine/averager/MovingAverager.test.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor -*/ -import { test } from 'uvu' -import * as assert from 'uvu/assert' - -import { createMovingAverager } from './MovingAverager.js' - -test('average should be initValue on empty dataset', () => { - const movingAverager = createMovingAverager(10, 5.5) - assert.is(movingAverager.getAverage(), 5.5) -}) - -test('an averager of length 1 should return the last added value', () => { - const movingAverager = createMovingAverager(1, 3) - movingAverager.pushValue(9) - assert.is(movingAverager.getAverage(), 9) -}) - -test('an averager of length 2 should return average of last 2 added elements', () => { - const movingAverager = createMovingAverager(2, 3) - movingAverager.pushValue(9) - movingAverager.pushValue(4) - assert.is(movingAverager.getAverage(), 6.5) -}) - -test('elements outside of range should not be considered', () => { - const movingAverager = createMovingAverager(2, 3) - movingAverager.pushValue(9) - movingAverager.pushValue(4) - movingAverager.pushValue(3) - assert.is(movingAverager.getAverage(), 3.5) -}) - -test('replacing the last element should work as expected', () => { - const movingAverager = createMovingAverager(2, 3) - movingAverager.pushValue(9) - movingAverager.pushValue(5) - movingAverager.replaceLastPushedValue(12) - assert.is(movingAverager.getAverage(), 10.5) -}) - -test.run() diff --git a/app/engine/averager/MovingIntervalAverager.js b/app/engine/averager/MovingIntervalAverager.js deleted file mode 100644 index c224ed5175..0000000000 --- a/app/engine/averager/MovingIntervalAverager.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This Averager calculates the average forecast for a moving interval of a continuous flow - of data points for a certain (time) interval -*/ -function createMovingIntervalAverager (movingDuration) { - let dataPoints - let duration - let sum - reset() - - function pushValue (dataValue, dataDuration) { - // add the new data point to the front of the array - dataPoints.unshift({ value: dataValue, duration: dataDuration }) - duration += dataDuration - sum += dataValue - while (duration > movingDuration) { - const removedDataPoint = dataPoints.pop() - duration -= removedDataPoint.duration - sum -= removedDataPoint.value - } - } - - function getAverage () { - if (duration > 0) { - return sum / duration * movingDuration - } else { - return 0 - } - } - - function reset () { - dataPoints = [] - duration = 0.0 - sum = 0.0 - } - - return { - pushValue, - getAverage, - reset - } -} - -export { createMovingIntervalAverager } diff --git a/app/engine/averager/MovingIntervalAverager.test.js b/app/engine/averager/MovingIntervalAverager.test.js deleted file mode 100644 index 35b7013f90..0000000000 --- a/app/engine/averager/MovingIntervalAverager.test.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor -*/ -import { test } from 'uvu' -import * as assert from 'uvu/assert' - -import { createMovingIntervalAverager } from './MovingIntervalAverager.js' - -test('average of a data point with duration of averager is equal to datapoint', () => { - const movingAverager = createMovingIntervalAverager(10) - movingAverager.pushValue(5, 10) - assert.is(movingAverager.getAverage(), 5) -}) - -test('average of a data point with half duration of averager is double to datapoint', () => { - const movingAverager = createMovingIntervalAverager(20) - movingAverager.pushValue(5, 10) - assert.is(movingAverager.getAverage(), 10) -}) - -test('average of two identical data points with half duration of averager is equal to datapoint sum', () => { - const movingAverager = createMovingIntervalAverager(20) - movingAverager.pushValue(5, 10) - movingAverager.pushValue(5, 10) - assert.is(movingAverager.getAverage(), 10) -}) - -test('average does not consider data points that are outside of duration', () => { - const movingAverager = createMovingIntervalAverager(20) - movingAverager.pushValue(10, 10) - movingAverager.pushValue(5, 10) - movingAverager.pushValue(5, 10) - assert.is(movingAverager.getAverage(), 10) -}) - -test('average works with lots of values', () => { - // one hour - const movingAverager = createMovingIntervalAverager(3000) - for (let i = 0; i < 1000; i++) { - movingAverager.pushValue(10, 1) - } - for (let i = 0; i < 1000; i++) { - movingAverager.pushValue(20, 1) - } - for (let i = 0; i < 1000; i++) { - movingAverager.pushValue(30, 2) - } - assert.is(movingAverager.getAverage(), 50000) -}) - -test('average should return 0 on empty dataset', () => { - const movingAverager = createMovingIntervalAverager(10) - assert.is(movingAverager.getAverage(), 0) -}) - -test.run() diff --git a/app/engine/averager/WeightedAverager.js b/app/engine/averager/WeightedAverager.js deleted file mode 100644 index 4b266b96b2..0000000000 --- a/app/engine/averager/WeightedAverager.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This Averager can calculate the weighted average of a continuous flow of data points -*/ -function createWeightedAverager (maxNumOfDataPoints) { - let dataPoints = [] - - function pushValue (dataPoint) { - // add the new data point to the front of the array - dataPoints.unshift(dataPoint) - // ensure that the array does not get longer than maxNumOfDataPoints - if (dataPoints.length > maxNumOfDataPoints) { - dataPoints.pop() - } - } - - function getAverage () { - const numOfDataPoints = dataPoints.length - if (numOfDataPoints > 0) { - const sum = dataPoints - .map((dataPoint, index) => Math.pow(2, numOfDataPoints - index - 1) * dataPoint) - .reduce((acc, dataPoint) => acc + dataPoint, 0) - const weight = Math.pow(2, numOfDataPoints) - 1 - return sum / weight - } else { - return 0 - } - } - - function reset () { - dataPoints = [] - } - - return { - pushValue, - getAverage, - reset - } -} - -export { createWeightedAverager } diff --git a/app/engine/averager/WeightedAverager.test.js b/app/engine/averager/WeightedAverager.test.js deleted file mode 100644 index 28e1583e9b..0000000000 --- a/app/engine/averager/WeightedAverager.test.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor -*/ -import { test } from 'uvu' -import * as assert from 'uvu/assert' - -import { createWeightedAverager } from './WeightedAverager.js' - -test('average should be 0 on empty dataset', () => { - const weightedAverager = createWeightedAverager(10) - assert.is(weightedAverager.getAverage(), 0) -}) - -test('average of one value is value', () => { - const weightedAverager = createWeightedAverager(10) - weightedAverager.pushValue(13.78) - assert.is(weightedAverager.getAverage(), 13.78) -}) - -test('average of a and b is (2*b + a) / 3', () => { - const weightedAverager = createWeightedAverager(10) - weightedAverager.pushValue(5) // a - weightedAverager.pushValue(2) // b - assert.is(weightedAverager.getAverage(), 3) -}) - -test('average should be 0 after reset', () => { - const weightedAverager = createWeightedAverager(10) - weightedAverager.pushValue(5) - weightedAverager.pushValue(2) - weightedAverager.reset() - assert.is(weightedAverager.getAverage(), 0) -}) - -test('average should be a after pushing a after a reset', () => { - const weightedAverager = createWeightedAverager(10) - weightedAverager.pushValue(5) - weightedAverager.pushValue(2) - weightedAverager.reset() - weightedAverager.pushValue(7) - assert.is(weightedAverager.getAverage(), 7) -}) - -test.run() diff --git a/app/engine/utils/BucketedLinearSeries.js b/app/engine/utils/BucketedLinearSeries.js new file mode 100644 index 0000000000..d9352c1ad1 --- /dev/null +++ b/app/engine/utils/BucketedLinearSeries.js @@ -0,0 +1,163 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This Module calculates a bucketed Linear Regression. It assumes a rising line. +*/ + +import { createOLSLinearSeries } from './OLSLinearSeries.js' + +function createBucketedLinearSeries (config) { + const linearSeries = createOLSLinearSeries() + const xCutOffInterval = 5.0 + const yCutOffInterval = 7.0 + const minimumValuesInBracket = 6.0 + + let xBracketStart = 0.0 + let xBracketEnd = 0.0 + let yBracketStart = 0.0 + let yBracketEnd = 0.0 + + let xTotal = 0.0 + let yTotal = 0.0 + let xSum = 0.0 + let ySum = 0.0 + let numberOfValuesInBracket = 0.0 + let numberOfValues = 0.0 + let maxX = 0.0 + let maxY = 0.0 + + function push (x, y) { + maxX = Math.max(maxX, x) + maxY = Math.max(maxY, y) + if ((yBracketStart <= y) && (y <= yBracketEnd) && (xBracketStart <= x) && (x <= xBracketEnd)) { + // We are still in the same bracket + xTotal += x + yTotal += y + xSum += x + ySum += y + numberOfValuesInBracket += 1 + numberOfValues += 1 + } else { + // We are outside the current bracket + if (numberOfValuesInBracket >= minimumValuesInBracket) { + // The latest bracket isn't empty or too shallow, so let's add the average to the dataset + linearSeries.push((xTotal / numberOfValuesInBracket), (yTotal / numberOfValuesInBracket)) + } + + // Let's determine the position of the next bracket + // First, we determine the x Position + if (xBracketStart > x) { + // Looks like we bottomed out below the bracket, so lets make the bracket completely below it + xBracketStart = x - xCutOffInterval + xBracketEnd = x + } else { + // The heartrate probably went up + xBracketStart = x + xBracketEnd = x + xCutOffInterval + } + + // Next, we determine the y position + if (yBracketStart > y) { + // Looks like we bottomed out below the bracket, so lets make the bracket completely below it + yBracketStart = y - yCutOffInterval + yBracketEnd = y + } else { + // The power is most likely to go up + yBracketStart = y + yBracketEnd = y + yCutOffInterval + } + + // Let's fill the first datapoint in the new bracket + xTotal = x + yTotal = y + xSum += x + ySum += y + numberOfValuesInBracket = 1 + numberOfValues += 1 + } + } + + function slope () { + return linearSeries.slope() + } + + function intercept () { + return linearSeries.slope() + } + + function numberOfSamples () { + return linearSeries.length() + } + + function goodnessOfFit () { + // This function returns the R^2 as a goodness of fit indicator + return linearSeries.goodnessOfFit() + } + + function projectX (x) { + return linearSeries.projectX(x) + } + + function projectY (y) { + return linearSeries.projectY(y) + } + + function maxEncounteredX () { + return maxX + } + + function maxEncounteredY () { + return maxY + } + + function averageEncounteredX () { + if (numberOfValues > 0) { + return xSum / numberOfValues + } else { + return 0 + } + } + + function averageEncounteredY () { + if (numberOfValues > 0) { + return ySum / numberOfValues + } else { + return 0 + } + } + + function reset () { + // Nothing to do yet + linearSeries.reset() + xBracketStart = 0.0 + xBracketEnd = 0.0 + yBracketStart = 0.0 + yBracketEnd = 0.0 + xTotal = 0.0 + yTotal = 0.0 + xSum = 0.0 + ySum = 0.0 + numberOfValuesInBracket = 0.0 + numberOfValues = 0.0 + maxX = 0.0 + maxY = 0.0 + } + + return { + push, + slope, + intercept, + numberOfSamples, + goodnessOfFit, + projectX, + projectY, + maxEncounteredX, + maxEncounteredY, + averageEncounteredX, + averageEncounteredY, + reset + } +} + +export { createBucketedLinearSeries } diff --git a/app/engine/utils/CurveAligner.js b/app/engine/utils/CurveAligner.js new file mode 100644 index 0000000000..adff69c346 --- /dev/null +++ b/app/engine/utils/CurveAligner.js @@ -0,0 +1,43 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This keeps an array, for ForceMetrics, and cleans it up +*/ + +function createCurveAligner (minimumValue) { + let _lastCompleteCurve = [] + + function push (curve) { + // First, remove all unneccessary leading zero's + while (curve.length > 5 && (curve[0] < minimumValue || curve[1] < minimumValue || curve[2] < minimumValue || curve[3] < minimumValue || curve[4] < minimumValue)) { + curve.shift() + } + + // Next, we clean up the trailing noise in the tail of the array + while (curve.length > 5 && (curve[curve.length - 1] < minimumValue || curve[curve.length - 2] < minimumValue || curve[curve.length - 3] < minimumValue || curve[curve.length - 4] < minimumValue || curve[curve.length - 5] < minimumValue)) { + curve.pop() + } + _lastCompleteCurve = Array.from(curve) + } + + function lastCompleteCurve () { + if (_lastCompleteCurve.length > 0) { + return _lastCompleteCurve + } else { + return [] + } + } + + function reset () { + _lastCompleteCurve.splice(0, _lastCompleteCurve.length) + } + + return { + push, + lastCompleteCurve, + reset + } +} + +export { createCurveAligner } diff --git a/app/engine/utils/FullTSLinearSeries.js b/app/engine/utils/FullTSLinearSeries.js new file mode 100644 index 0000000000..b0e9c3d4b4 --- /dev/null +++ b/app/engine/utils/FullTSLinearSeries.js @@ -0,0 +1,226 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + The TSLinearSeries is a datatype that represents a Linear Series. It allows + values to be retrieved (like a FiFo buffer, or Queue) but it also includes + a Theil–Sen estimator Linear Regressor to determine the slope of this timeseries. + + At creation its length is determined. After it is filled, the oldest will be pushed + out of the queue) automatically. + + A key constraint is to prevent heavy calculations at the end (due to large + array based curve fitting), which might happen on a Pi zero + + This implementation uses concepts that are described here: + https://en.wikipedia.org/wiki/Theil%E2%80%93Sen_estimator + + The array is ordered such that x[0] is the oldest, and x[x.length-1] is the youngest +*/ + +import { createSeries } from './Series.js' + +import loglevel from 'loglevel' +const log = loglevel.getLogger('RowingEngine') + +function createTSLinearSeries (maxSeriesLength = 0) { + const X = createSeries(maxSeriesLength) + const Y = createSeries(maxSeriesLength) + const slopes = [] + + let _A = 0 + let _B = 0 + let _goodnessOfFit = 0 + + function push (x, y) { + X.push(x) + Y.push(y) + + if (maxSeriesLength > 0 && slopes.length >= maxSeriesLength) { + // The maximum of the array has been reached, we have to create room + // in the 2D array by removing the first row from the table + removeFirstRow() + } + + // Invariant: the indices of the X and Y array now match up with the + // row numbers of the slopes array. So, the slope of (X[0],Y[0]) and (X[1],Y[1] + // will be stored in slopes[0][.]. + + // Calculate the slopes of this new point + if (X.length() > 1) { + // There are at least two points in the X and Y arrays, so let's add the new datapoint + let i = 0 + let result = 0 + while (i < slopes.length) { + result = calculateSlope(i, slopes.length) + slopes[i].push(result) + i++ + } + } + // Add an empty array at the end to store futurs results for the most recent points + slopes.push([]) + + // Calculate the median of the slopes + if (X.length() > 1) { + _A = median() + } else { + _A = 0 + } + _B = Y.average() - (_A * X.average()) + } + + function slope () { + return _A + } + + function intercept () { + return _B + } + + function coefficientA () { + // For testing purposses only! + return _A + } + + function coefficientB () { + // For testing purposses only! + return _B + } + + function length () { + return X.length() + } + + function goodnessOfFit () { + // This function returns the R^2 as a goodness of fit indicator + if (X.length() >= 2) { + return _goodnessOfFit + } else { + return 0 + } + } + + function projectX (x) { + if (X.length() >= 2) { + return (_A * x) + _B + } else { + return 0 + } + } + + function projectY (y) { + if (X.length() >= 2 && _A !== 0) { + return ((y - _B) / _A) + } else { + return 0 + } + } + + function numberOfXValuesAbove (testedValue) { + return X.numberOfValuesAbove(testedValue) + } + + function numberOfXValuesEqualOrBelow (testedValue) { + return X.numberOfValuesEqualOrBelow(testedValue) + } + + function numberOfYValuesAbove (testedValue) { + return Y.numberOfValuesAbove(testedValue) + } + + function numberOfYValuesEqualOrBelow (testedValue) { + return Y.numberOfValuesEqualOrBelow(testedValue) + } + + function xAtSeriesBegin () { + return X.atSeriesBegin() + } + + function xAtSeriesEnd () { + return X.atSeriesEnd() + } + + function yAtSeriesBegin () { + return Y.atSeriesBegin() + } + + function yAtSeriesEnd () { + return Y.atSeriesEnd() + } + + function xSum () { + return X.sum() + } + + function ySum () { + return Y.sum() + } + + function xSeries () { + return X.series() + } + + function ySeries () { + return Y.series() + } + + function removeFirstRow () { + slopes.shift() + } + + function calculateSlope (pointOne, pointTwo) { + if (pointOne !== pointTwo && X.get(pointOne) !== X.get(pointTwo)) { + return ((Y.get(pointTwo) - Y.get(pointOne)) / (X.get(pointTwo) - X.get(pointOne))) + } else { + log.error('TS Linear Regressor, Division by zero prevented!') + return 0 + } + } + + function median () { + if (slopes.length > 1) { + const sortedArray = [...slopes.flat()].sort((a, b) => a - b) + const mid = Math.floor(sortedArray.length / 2) + return (sortedArray.length % 2 !== 0 ? sortedArray[mid] : ((sortedArray[mid - 1] + sortedArray[mid]) / 2)) + } else { + log.eror('TS Linear Regressor, Median calculation on empty dataset attempted!') + return 0 + } + } + + function reset () { + X.reset() + Y.reset() + slopes.splice(0, slopes.length) + _A = 0 + _B = 0 + _goodnessOfFit = 0 + } + + return { + push, + slope, + intercept, + coefficientA, + coefficientB, + length, + goodnessOfFit, + projectX, + projectY, + numberOfXValuesAbove, + numberOfXValuesEqualOrBelow, + numberOfYValuesAbove, + numberOfYValuesEqualOrBelow, + xAtSeriesBegin, + xAtSeriesEnd, + yAtSeriesBegin, + yAtSeriesEnd, + xSum, + ySum, + xSeries, + ySeries, + reset + } +} + +export { createTSLinearSeries } diff --git a/app/engine/utils/FullTSQuadraticSeries.js b/app/engine/utils/FullTSQuadraticSeries.js new file mode 100644 index 0000000000..a5a9ede858 --- /dev/null +++ b/app/engine/utils/FullTSQuadraticSeries.js @@ -0,0 +1,270 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + The TSLinearSeries is a datatype that represents a Quadratic Series. It allows + values to be retrieved (like a FiFo buffer, or Queue) but it also includes + a Theil-Sen Quadratic Regressor to determine the coefficients of this dataseries. + + At creation its length is determined. After it is filled, the oldest will be pushed + out of the queue) automatically. + + A key constraint is to prevent heavy calculations at the end (due to large + array based curve fitting), which might be performed on a Pi zero + + The Theil-Senn implementation uses concepts that are described here: + https://stats.stackexchange.com/questions/317777/theil-sen-estimator-for-polynomial, + + The determination of the coefficients is based on the math descirbed here: + https://www.quora.com/How-do-I-find-a-quadratic-equation-from-points/answer/Robert-Paxson, + https://www.physicsforums.com/threads/quadratic-equation-from-3-points.404174/ +*/ + +import { createSeries } from './Series.js' +import { createTSLinearSeries } from './FullTSLinearSeries.js' + +import loglevel from 'loglevel' +const log = loglevel.getLogger('RowingEngine') + +function createTSQuadraticSeries (maxSeriesLength = 0) { + const X = createSeries(maxSeriesLength) + const Y = createSeries(maxSeriesLength) + const A = [] + let _A = 0 + let _B = 0 + let _C = 0 + + function push (x, y) { + const linearResidu = createTSLinearSeries(maxSeriesLength) + + X.push(x) + Y.push(y) + + if (maxSeriesLength > 0 && A.length >= maxSeriesLength) { + // The maximum of the array has been reached, we have to create room + // in the 2D array by removing the first row from the A-table + A.shift() + } + + // Invariant: the indices of the X and Y array now match up with the + // row numbers of the A array. So, the A of (X[0],Y[0]) and (X[1],Y[1] + // will be stored in A[0][.]. + + // Add an empty array at the end to store futurs results for the most recent points + A.push([]) + + // Calculate the coefficients of this new point + if (X.length() > 2) { + // There are at least two points in the X and Y arrays, so let's add the new datapoint + let i = 0 + while (i < X.length() - 2) { + A[X.length() - 1].push(calculateA(i, X.length() - 1)) + i++ + } + _A = matrixMedian(A) + + i = 0 + linearResidu.reset() + while (i < X.length() - 1) { + linearResidu.push(X.get(i), Y.get(i) - (_A * Math.pow(X.get(i), 2))) + i++ + } + _B = linearResidu.coefficientA() + _C = linearResidu.coefficientB() + } else { + _A = 0 + _B = 0 + _C = 0 + } + } + + function firstDerivativeAtPosition (position) { + if (X.length() > 2 && position < X.length()) { + return ((_A * 2 * X.get(position)) + _B) + } else { + return 0 + } + } + + function secondDerivativeAtPosition (position) { + if (X.length() > 2 && position < X.length()) { + return (_A * 2) + } else { + return 0 + } + } + + function slope (x) { + if (X.length() > 2) { + return ((_A * 2 * x) + _B) + } else { + return 0 + } + } + + function coefficientA () { + // For testing purposses only! + return _A + } + + function coefficientB () { + // For testing purposses only! + return _B + } + + function coefficientC () { + // For testing purposses only! + return _C + } + + function intercept () { + return coefficientC() + } + + function length () { + return X.length() + } + + function goodnessOfFit () { + // This function returns the R^2 as a goodness of fit indicator + // ToDo: calculate the goodness of fit when called + if (X.length() >= 2) { + // return _goodnessOfFit + return 1 + } else { + return 0 + } + } + + function projectX (x) { + const _C = coefficientC() + if (X.length() > 2) { + return ((_A * x * x) + (_B * x) + _C) + } else { + return 0 + } + } + + function numberOfXValuesAbove (testedValue) { + return X.numberOfValuesAbove(testedValue) + } + + function numberOfXValuesEqualOrBelow (testedValue) { + return X.numberOfValuesEqualOrBelow(testedValue) + } + + function numberOfYValuesAbove (testedValue) { + return Y.numberOfValuesAbove(testedValue) + } + + function numberOfYValuesEqualOrBelow (testedValue) { + return Y.numberOfValuesEqualOrBelow(testedValue) + } + + function xAtSeriesBegin () { + return X.atSeriesBegin() + } + + function xAtSeriesEnd () { + return X.atSeriesEnd() + } + + function xAtPosition (position) { + return X.get(position) + } + + function yAtSeriesBegin () { + return Y.atSeriesBegin() + } + + function yAtSeriesEnd () { + return Y.atSeriesEnd() + } + + function yAtPosition (position) { + return Y.get(position) + } + + function xSum () { + return X.sum() + } + + function ySum () { + return Y.sum() + } + + function xSeries () { + return X.series() + } + + function ySeries () { + return Y.series() + } + + function calculateA (pointOne, pointThree) { + if ((pointOne + 1) < pointThree && X.get(pointOne) !== X.get(pointThree)) { + const results = createSeries(maxSeriesLength) + let pointTwo = pointOne + 1 + while (pointOne < pointTwo && pointTwo < pointThree && X.get(pointOne) !== X.get(pointTwo) && X.get(pointTwo) !== X.get(pointThree)) { + // For the underlying math, see https://www.quora.com/How-do-I-find-a-quadratic-equation-from-points/answer/Robert-Paxson + results.push((X.get(pointOne) * (Y.get(pointThree) - Y.get(pointTwo)) + Y.get(pointOne) * (X.get(pointTwo) - X.get(pointThree)) + (X.get(pointThree) * Y.get(pointTwo) - X.get(pointTwo) * Y.get(pointThree))) / ((X.get(pointOne) - X.get(pointTwo)) * (X.get(pointOne) - X.get(pointThree)) * (X.get(pointTwo) - X.get(pointThree)))) + pointTwo += 1 + } + return results.median() + } else { + log.error('TS Quadratic Regressor, Division by zero prevented in CalculateA!') + return 0 + } + } + + function matrixMedian (inputMatrix) { + if (inputMatrix.length > 1) { + const sortedArray = [...inputMatrix.flat()].sort((a, b) => a - b) + const mid = Math.floor(sortedArray.length / 2) + return (sortedArray.length % 2 !== 0 ? sortedArray[mid] : ((sortedArray[mid - 1] + sortedArray[mid]) / 2)) + } else { + log.error('TS Quadratic Regressor, Median calculation on empty matrix attempted!') + return 0 + } + } + + function reset () { + X.reset() + Y.reset() + A.splice(0, A.length) + _A = 0 + _B = 0 + _C = 0 + } + + return { + push, + firstDerivativeAtPosition, + secondDerivativeAtPosition, + slope, + coefficientA, + coefficientB, + coefficientC, + intercept, + length, + goodnessOfFit, + projectX, + numberOfXValuesAbove, + numberOfXValuesEqualOrBelow, + numberOfYValuesAbove, + numberOfYValuesEqualOrBelow, + xAtSeriesBegin, + xAtSeriesEnd, + xAtPosition, + yAtSeriesBegin, + yAtSeriesEnd, + yAtPosition, + xSum, + ySum, + xSeries, + ySeries, + reset + } +} + +export { createTSQuadraticSeries } diff --git a/app/engine/utils/FullTSQuadraticSeries.test.js b/app/engine/utils/FullTSQuadraticSeries.test.js new file mode 100644 index 0000000000..473b5b0484 --- /dev/null +++ b/app/engine/utils/FullTSQuadraticSeries.test.js @@ -0,0 +1,546 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This tests the Quadratic Theil-Senn Regression algorithm. As regression is an estimation and methods have biasses, + we need to accept some slack with respect to real-life examples +*/ +import { test } from 'uvu' +import * as assert from 'uvu/assert' + +import { createTSQuadraticSeries } from './FullTSQuadraticSeries.js' + +test('Quadratic Approximation startup behaviour', () => { + const dataSeries = createTSQuadraticSeries(10) + testCoefficientA(dataSeries, 0) + testCoefficientB(dataSeries, 0) + testCoefficientC(dataSeries, 0) + dataSeries.push(-1, 2) + testCoefficientA(dataSeries, 0) + testCoefficientB(dataSeries, 0) + testCoefficientC(dataSeries, 0) + dataSeries.push(0, 2) + testCoefficientA(dataSeries, 0) + testCoefficientB(dataSeries, 0) + testCoefficientC(dataSeries, 0) + dataSeries.push(1, 6) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, 2) + testCoefficientC(dataSeries, 2) +}) + +test('Quadratic Approximation on a perfect noisefree function y = 2 * Math.pow(x, 2) + 2 * x + 2, 21 datapoints', () => { + // Data based on 2 x^2 + 2 x + 2 + const dataSeries = createTSQuadraticSeries(21) + dataSeries.push(-10, 182) + dataSeries.push(-9, 146) + dataSeries.push(-8, 114) + dataSeries.push(-7, 86) + dataSeries.push(-6, 62) + dataSeries.push(-5, 42) + dataSeries.push(-4, 26) + dataSeries.push(-3, 14) // Pi ;) + dataSeries.push(-2, 6) + dataSeries.push(-1, 2) + dataSeries.push(0, 2) + dataSeries.push(1, 6) + dataSeries.push(2, 14) + dataSeries.push(3, 26) + dataSeries.push(4, 42) + dataSeries.push(5, 62) + dataSeries.push(6, 86) + dataSeries.push(7, 114) + dataSeries.push(8, 146) + dataSeries.push(9, 182) + dataSeries.push(10, 222) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, 2) + testCoefficientC(dataSeries, 2) +}) + +test('Quadratic Approximation on a perfect noisefree function y = 2 * Math.pow(x, 2) + 2 * x + 2, with 10 datapoints and some shifting in the series', () => { + // Data based on 2 x^2 + 2 x + 2, split the dataset in two to see its behaviour when it is around the Vertex + const dataSeries = createTSQuadraticSeries(10) + dataSeries.push(-10, 182) + dataSeries.push(-9, 146) + dataSeries.push(-8, 114) + dataSeries.push(-7, 86) + dataSeries.push(-6, 62) + dataSeries.push(-5, 42) + dataSeries.push(-4, 26) + dataSeries.push(-3, 14) // Pi ;) + dataSeries.push(-2, 6) + dataSeries.push(-1, 2) + dataSeries.push(0, 2) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, 2) + testCoefficientC(dataSeries, 2) + dataSeries.push(1, 6) + dataSeries.push(2, 14) + dataSeries.push(3, 26) + dataSeries.push(4, 42) + dataSeries.push(5, 62) + dataSeries.push(6, 86) + dataSeries.push(7, 114) + dataSeries.push(8, 146) + dataSeries.push(9, 182) + dataSeries.push(10, 222) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, 2) + testCoefficientC(dataSeries, 2) +}) + +test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, noisefree', () => { + // Data based on 4 x^2 + 4 x + 4 + const dataSeries = createTSQuadraticSeries(11) + dataSeries.push(-11, 444) + dataSeries.push(-10, 364) + dataSeries.push(-9, 292) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-8, 228) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-7, 172) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-6, 124) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-5, 84) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-4, 52) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-3, 28) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-2, 12) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-1, 4) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(0, 4) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(1, 12) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(2, 28) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(3, 52) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(4, 84) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(5, 124) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(6, 172) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(7, 228) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(8, 292) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(9, 364) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(10, 444) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) +}) + +test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, with some noise (+/- 1)', () => { + // Data based on 4 x^2 + 4 x + 4 + const dataSeries = createTSQuadraticSeries(11) + dataSeries.push(-11, 443) + dataSeries.push(-10, 365) + dataSeries.push(-9, 291) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, -36) + testCoefficientC(dataSeries, -195) + dataSeries.push(-8, 229) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 3.6666666666666643) // This is quite acceptable as ORM ignores the C + dataSeries.push(-7, 171) + testCoefficientA(dataSeries, 3.666666666666667) + testCoefficientB(dataSeries, -1.8333333333333335) + testCoefficientC(dataSeries, -20.916666666666682) + dataSeries.push(-6, 125) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 3.799999999999997) // This is quite acceptable as ORM ignores the C + dataSeries.push(-5, 83) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-4, 53) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 3.8571428571428577) // This is quite acceptable as ORM ignores the C + dataSeries.push(-3, 27) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-2, 13) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 3.8888888888888893) // This is quite acceptable as ORM ignores the C + dataSeries.push(-1, 3) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(0, 5) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(1, 11) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(2, 29) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(3, 51) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(4, 85) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(5, 123) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(6, 173) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(7, 227) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(8, 293) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(9, 363) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(10, 444) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) +}) + +test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, with some noise (+/- 1) and spikes (+/- 9)', () => { + // Data based on 4 x^2 + 4 x + 4 + const dataSeries = createTSQuadraticSeries(11) + dataSeries.push(-11, 443) + dataSeries.push(-10, 365) + dataSeries.push(-9, 291) + dataSeries.push(-8, 229) + dataSeries.push(-7, 171) + dataSeries.push(-6, 125) + dataSeries.push(-5, 83) + dataSeries.push(-4, 53) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 3.8571428571428577) + dataSeries.push(-3, 37) // FIRST SPIKE +9 + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(-2, 3) // SECOND SPIKE -9 + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4.142857142857142) // Coefficient B seems to take a hit anyway + testCoefficientC(dataSeries, 5.9999999999999964) // We get a 5.9999999999999964 instead of 4, which is quite acceptable (especially since ORM ignores the C) + dataSeries.push(-1, 3) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(0, 5) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(1, 11) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(2, 29) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(3, 51) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(4, 85) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(5, 123) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(6, 173) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(7, 227) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) + dataSeries.push(8, 293) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 3) // This is quite acceptable as ORM ignores the C + dataSeries.push(9, 363) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) // We get a 3 instead of 4, which is quite acceptable (especially since ORM ignores the C) + dataSeries.push(10, 444) + testCoefficientA(dataSeries, 4) + testCoefficientB(dataSeries, 4) + testCoefficientC(dataSeries, 4) +}) + +test('Quadratic TS Estimation should be decent for standard real-life example from MathBits with some noise', () => { + // Data based on https://mathbits.com/MathBits/TISection/Statistics2/quadratic.html + const dataSeries = createTSQuadraticSeries(13) + dataSeries.push(10, 115.6) + dataSeries.push(15, 157.2) + dataSeries.push(20, 189.2) + dataSeries.push(24, 220.8) + dataSeries.push(30, 253.8) + dataSeries.push(34, 269.2) + dataSeries.push(40, 284.8) + dataSeries.push(45, 285.0) + dataSeries.push(48, 277.4) + dataSeries.push(50, 269.2) + dataSeries.push(58, 244.2) + dataSeries.push(60, 231.4) + dataSeries.push(64, 180.4) + testCoefficientA(dataSeries, -0.17785023090944152) // In the example, the TI084 results in -0.1737141137, which we consider acceptably close + testCoefficientB(dataSeries, 15.115602960635863) // In the example, the TI084 results in 14.52117133, which we consider acceptably close + testCoefficientC(dataSeries, -35.639987946994665) // In the example, the TI084 results in -21.89774466, which we consider acceptably close +}) + +test('Quadratic TS Estimation should be decent for standard real-life example from VarsityTutors with some noise', () => { + // Test based on https://www.varsitytutors.com/hotmath/hotmath_help/topics/quadratic-regression + const dataSeries = createTSQuadraticSeries(7) + dataSeries.push(-3, 7.5) + dataSeries.push(-2, 3) + dataSeries.push(-1, 0.5) + dataSeries.push(0, 1) + dataSeries.push(1, 3) + dataSeries.push(2, 6) + dataSeries.push(3, 14) + testCoefficientA(dataSeries, 1.1166666666666667) // The example results in 1.1071 for OLS, which we consider acceptably close + testCoefficientB(dataSeries, 0.966666666666667) // The example results in 1 for OLS, which we consider acceptably close + testCoefficientC(dataSeries, 0.44722222222222213) // The example results in 0.5714 for OLS, which we consider acceptably close +}) + +test('Quadratic TS Estimation should be decent for standard example from VTUPulse with some noise, without the vertex being part of the dataset', () => { + // Test based on https://www.vtupulse.com/machine-learning/quadratic-polynomial-regression-model-solved-example/ + const dataSeries = createTSQuadraticSeries(5) + dataSeries.push(3, 2.5) + dataSeries.push(4, 3.3) + dataSeries.push(5, 3.8) + dataSeries.push(6, 6.5) + dataSeries.push(7, 11.5) + testCoefficientA(dataSeries, 0.9500000000000005) // The example results in 0.7642857 for OLS, which we consider acceptably close given the small sample size + testCoefficientB(dataSeries, -7.483333333333338) // The example results in -5.5128571 for OLS, which we consider acceptably close given the small sample size + testCoefficientC(dataSeries, 17.275000000000006) // The example results in 12.4285714 for OLS, which we consider acceptably close given the small sample size +}) + +test('Quadratic TS Estimation should be decent for standard real-life example from Uni Berlin with some noise without the vertex being part of the dataset', () => { + // Test based on https://www.geo.fu-berlin.de/en/v/soga/Basics-of-statistics/Linear-Regression/Polynomial-Regression/Polynomial-Regression---An-example/index.html + const dataSeries = createTSQuadraticSeries(25) + dataSeries.push(0.001399613, -0.23436656) + dataSeries.push(0.971629779, 0.64689524) + dataSeries.push(0.579119475, -0.92635765) + dataSeries.push(0.335693937, 0.13000706) + dataSeries.push(0.736736086, -0.89294863) + dataSeries.push(0.492572335, 0.33854780) + dataSeries.push(0.737133774, -1.24171910) + dataSeries.push(0.563693769, -0.22523318) + dataSeries.push(0.877603280, -0.12962722) + dataSeries.push(0.141426545, 0.37632006) + dataSeries.push(0.307203910, 0.30299077) + dataSeries.push(0.024509308, -0.21162739) + dataSeries.push(0.843665029, -0.76468719) + dataSeries.push(0.771206067, -0.90455412) + dataSeries.push(0.149670258, 0.77097952) + dataSeries.push(0.359605608, 0.56466366) + dataSeries.push(0.049612895, 0.18897607) + dataSeries.push(0.409898906, 0.32531750) + dataSeries.push(0.935457898, -0.78703491) + dataSeries.push(0.149476207, 0.80585375) + dataSeries.push(0.234315216, 0.62944986) + dataSeries.push(0.455297119, 0.02353327) + dataSeries.push(0.102696671, 0.27621694) + dataSeries.push(0.715372314, -1.20379729) + dataSeries.push(0.681745393, -0.83059624) + testCoefficientA(dataSeries, -3.13052236289358) + testCoefficientB(dataSeries, 1.5907039702198331) + testCoefficientC(dataSeries, 0.12896850914578195) +}) + +test('Quadratic TS Estimation should be decent for standard real-life example from Statology.org with some noise and chaotic X values', () => { + // Test based on https://www.statology.org/quadratic-regression-r/ + const dataSeries = createTSQuadraticSeries(11) + dataSeries.push(6, 14) + dataSeries.push(9, 28) + dataSeries.push(12, 50) + dataSeries.push(14, 70) + dataSeries.push(30, 89) + dataSeries.push(35, 94) + dataSeries.push(40, 90) + dataSeries.push(47, 75) + dataSeries.push(51, 59) + dataSeries.push(55, 44) + dataSeries.push(60, 27) + testCoefficientA(dataSeries, -0.10466531440162272) // The example results in -0.1012 for R after two rounds, which we consider acceptably close + testCoefficientB(dataSeries, 6.98670916642519) // The example results in 6.7444 for R after two rounds, which we consider acceptably close + testCoefficientC(dataSeries, -21.826295759683177) // The example results in 18.2536 for R after two rounds, but for ORM, this factor is irrelevant +}) + +test('Quadratic TS Estimation should be decent for standard real-life example from StatsDirect.com with some noise and chaotic X values', () => { + // Test based on https://www.statsdirect.com/help/regression_and_correlation/polynomial.htm + const dataSeries = createTSQuadraticSeries(10) + dataSeries.push(1290, 1182) + dataSeries.push(1350, 1172) + dataSeries.push(1470, 1264) + dataSeries.push(1600, 1493) + dataSeries.push(1710, 1571) + dataSeries.push(1840, 1711) + dataSeries.push(1980, 1804) + dataSeries.push(2230, 1840) + dataSeries.push(2400, 1956) + dataSeries.push(2930, 1954) + testCoefficientA(dataSeries, -0.0004480669511301859) // The example results in -0.00045 through QR decomposition by Givens rotations, which we consider acceptably close + testCoefficientB(dataSeries, 2.373459636061883) // The example results in 2.39893 for QR decomposition by Givens rotations, which we consider acceptably close + testCoefficientC(dataSeries, -1178.1630473732216) // The example results in -1216.143887 for QR decomposition by Givens rotations, but for ORM, this factor is irrelevant +}) + +test('Quadratic Approximation with a clean function and a reset', () => { + // Data based on 2 x^2 + 2 x + 2 + const dataSeries = createTSQuadraticSeries(10) + dataSeries.push(-10, 182) + dataSeries.push(-9, 146) + dataSeries.push(-8, 114) + dataSeries.push(-7, 86) + dataSeries.push(-6, 62) + dataSeries.push(-5, 42) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, 2) + testCoefficientC(dataSeries, 2) + dataSeries.push(-4, 26) + dataSeries.push(-3, 14) // Pi ;) + dataSeries.push(-2, 6) + dataSeries.push(-1, 2) + dataSeries.push(0, 2) + dataSeries.push(1, 6) + dataSeries.push(2, 14) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, 2) + testCoefficientC(dataSeries, 2) + dataSeries.push(3, 26) + dataSeries.push(4, 42) + dataSeries.push(5, 62) + dataSeries.push(6, 86) + dataSeries.push(7, 114) + dataSeries.push(8, 146) + dataSeries.push(9, 182) + dataSeries.push(10, 222) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, 2) + testCoefficientC(dataSeries, 2) + dataSeries.reset() + testCoefficientA(dataSeries, 0) + testCoefficientB(dataSeries, 0) + testCoefficientC(dataSeries, 0) + dataSeries.push(-1, 2) + testCoefficientA(dataSeries, 0) + testCoefficientB(dataSeries, 0) + testCoefficientC(dataSeries, 0) + dataSeries.push(0, 2) + testCoefficientA(dataSeries, 0) + testCoefficientB(dataSeries, 0) + testCoefficientC(dataSeries, 0) + dataSeries.push(1, 6) + testCoefficientA(dataSeries, 2) + testCoefficientB(dataSeries, 2) + testCoefficientC(dataSeries, 2) +}) + +test('Quadratic TS Estimation should result in a straight line for function y = x', () => { + // As ORM will encounter straight lines (when forces are balanced on the flywheel, there is no acceleration/deceleration), so we need to test this as well + const dataSeries = createTSQuadraticSeries(7) + dataSeries.push(0, 0) + dataSeries.push(1, 1) + dataSeries.push(2, 2) + dataSeries.push(3, 3) + dataSeries.push(4, 4) + dataSeries.push(5, 5) + dataSeries.push(6, 6) + testCoefficientA(dataSeries, 0) + testCoefficientB(dataSeries, 1) + testCoefficientC(dataSeries, 0) +}) + +function testCoefficientA (series, expectedValue) { + assert.ok(series.coefficientA() === expectedValue, `Expected value for coefficientA at X-position ${series.xAtSeriesEnd()} is ${expectedValue}, encountered a ${series.coefficientA()}`) +} + +function testCoefficientB (series, expectedValue) { + assert.ok(series.coefficientB() === expectedValue, `Expected value for coefficientB at X-position ${series.xAtSeriesEnd()} is ${expectedValue}, encountered a ${series.coefficientB()}`) +} + +function testCoefficientC (series, expectedValue) { + assert.ok(series.coefficientC() === expectedValue, `Expected value for coefficientC at X-position ${series.xAtSeriesEnd()} is ${expectedValue}, encountered a ${series.coefficientC()}`) +} + +/* +function testSlope (series, position, expectedValue) { + assert.ok(series.slope(position) === expectedValue, `Expected value for Slope-${position} at X-position ${series.xAtSeriesEnd()} (slope at X-position ${series.xAtPosition(position)}) is ${expectedValue}, encountered a ${series.slope(position)}`) +} + +function reportAll (series) { + assert.ok(series.coefficientA() === 99, `time: ${series.xAtSeriesEnd()}, coefficientA: ${series.coefficientA()}, coefficientB: ${series.coefficientB()}, coefficientC: ${series.coefficientC()}, Slope-10: ${series.slope(10)}, Slope-9: ${series.slope(9)}, Slope-8: ${series.slope(8)}, Slope-7: ${series.slope(7)}, Slope-6: ${series.slope(6)}, Slope-5: ${series.slope(5)}, Slope-4: ${series.slope(4)}, Slope-3: ${series.slope(3)}, Slope-2: ${series.slope(2)}, Slope-1: ${series.slope(1)}, Slope-0: ${series.slope(0)}`) +} +*/ + +test.run() diff --git a/app/engine/utils/OLSLinearSeries.js b/app/engine/utils/OLSLinearSeries.js new file mode 100644 index 0000000000..cc382f6234 --- /dev/null +++ b/app/engine/utils/OLSLinearSeries.js @@ -0,0 +1,203 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + The LinearSeries is a datatype that represents a Linear Series. It allows + values to be retrieved (like a FiFo buffer, or Queue) but it also includes + a Linear Regressor to determine the slope, intercept and R^2 of this timeseries + of x any y coordinates through Simple Linear Regression. + + At creation it can be determined that the Time Series is limited (i.e. after it + is filled, the oldest will be pushed out of the queue) or that the the time series + is unlimited (will only expand). The latter is activated by calling the creation with + an empty argument. + + please note that for unlimited series it is up to the calling function to handle resetting + the Linear Series when needed through the reset() call. + + A key constraint is to prevent heavy calculations at the end (due to large + array based curve fitting) as this function is also used to calculate + drag at the end of the recovery phase, which might happen on a Pi zero + + This implementation uses concepts that are described here: + https://www.colorado.edu/amath/sites/default/files/attached-files/ch12_0.pdf +*/ + +import { createSeries } from './Series.js' + +import loglevel from 'loglevel' +const log = loglevel.getLogger('RowingEngine') + +function createOLSLinearSeries (maxSeriesLength = 0) { + const X = createSeries(maxSeriesLength) + const XX = createSeries(maxSeriesLength) + const Y = createSeries(maxSeriesLength) + const YY = createSeries(maxSeriesLength) + const XY = createSeries(maxSeriesLength) + const trend = createSeries(maxSeriesLength) + let _slope = 0 + let _intercept = 0 + let _goodnessOfFit = 0 + + function push (x, y) { + X.push(x) + XX.push(x * x) + Y.push(y) + YY.push(y * y) + XY.push(x * y) + + // Let's approximate the line through OLS + if (X.length() >= 2 && X.sum() > 0) { + _slope = (X.length() * XY.sum() - X.sum() * Y.sum()) / (X.length() * XX.sum() - X.sum() * X.sum()) + _intercept = (Y.sum() - (_slope * X.sum())) / X.length() + const sse = YY.sum() - (_intercept * Y.sum()) - (_slope * XY.sum()) + const sst = YY.sum() - (Math.pow(Y.sum(), 2) / X.length()) + _goodnessOfFit = 1 - (sse / sst) + trend.push(determineTrend(X.length() - 2, X.length() - 1)) + } else { + _slope = 0 + _intercept = 0 + _goodnessOfFit = 0 + } + } + + function slope () { + return _slope + } + + function intercept () { + return _intercept + } + + function length () { + return X.length() + } + + function goodnessOfFit () { + // This function returns the R^2 as a goodness of fit indicator + if (X.length() >= 2) { + return _goodnessOfFit + } else { + return 0 + } + } + + function projectX (x) { + if (X.length() >= 2) { + return (_slope * x) + _intercept + } else { + return 0 + } + } + + function projectY (y) { + if (X.length() >= 2 && _slope !== 0) { + return ((y - _intercept) / _slope) + } else { + return 0 + } + } + + function numberOfXValuesAbove (testedValue) { + return X.numberOfValuesAbove(testedValue) + } + + function numberOfXValuesEqualOrBelow (testedValue) { + return X.numberOfValuesEqualOrBelow(testedValue) + } + + function numberOfYValuesAbove (testedValue) { + return Y.numberOfValuesAbove(testedValue) + } + + function numberOfYValuesEqualOrBelow (testedValue) { + return Y.numberOfValuesEqualOrBelow(testedValue) + } + + function numberOfUpwardTrend () { + return trend.numberOfValuesAbove(0) + } + + function numberOfFlatOrDownwardTrend () { + return trend.numberOfValuesEqualOrBelow(0) + } + + function xAtSeriesBegin () { + return X.atSeriesBegin() + } + + function xAtSeriesEnd () { + return X.atSeriesEnd() + } + + function yAtSeriesBegin () { + return Y.atSeriesBegin() + } + + function yAtSeriesEnd () { + return Y.atSeriesEnd() + } + + function xSum () { + return X.sum() + } + + function ySum () { + return Y.sum() + } + + function xSeries () { + return X.series() + } + + function ySeries () { + return Y.series() + } + + function determineTrend (pointOne, pointTwo) { + if (pointOne !== pointTwo) { + return (Y.get(pointTwo) - Y.get(pointOne)) + } else { + log.error('OLS Linear Regressor, trend determination, trend can not be applied to one point!') + return 0 + } + } + + function reset () { + X.reset() + XX.reset() + Y.reset() + YY.reset() + XY.reset() + _slope = 0 + _intercept = 0 + _goodnessOfFit = 0 + } + + return { + push, + slope, + intercept, + length, + goodnessOfFit, + projectX, + projectY, + numberOfXValuesAbove, + numberOfXValuesEqualOrBelow, + numberOfYValuesAbove, + numberOfYValuesEqualOrBelow, + numberOfUpwardTrend, + numberOfFlatOrDownwardTrend, + xAtSeriesBegin, + xAtSeriesEnd, + yAtSeriesBegin, + yAtSeriesEnd, + xSum, + ySum, + xSeries, + ySeries, + reset + } +} + +export { createOLSLinearSeries } diff --git a/app/engine/utils/OLSLinearSeries.test.js b/app/engine/utils/OLSLinearSeries.test.js new file mode 100644 index 0000000000..92e6445eb0 --- /dev/null +++ b/app/engine/utils/OLSLinearSeries.test.js @@ -0,0 +1,268 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +*/ +import { test } from 'uvu' +import * as assert from 'uvu/assert' + +import { createOLSLinearSeries } from './OLSLinearSeries.js' + +test('Correct behaviour of a series after initialisation', () => { + const dataSeries = createOLSLinearSeries(3) + testLength(dataSeries, 0) + testXAtSeriesBegin(dataSeries, 0) + testYAtSeriesBegin(dataSeries, 0) + testXAtSeriesEnd(dataSeries, 0) + testYAtSeriesEnd(dataSeries, 0) + testNumberOfXValuesAbove(dataSeries, 0, 0) + testNumberOfYValuesAbove(dataSeries, 0, 0) + testNumberOfXValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfXValuesAbove(dataSeries, 10, 0) + testNumberOfYValuesAbove(dataSeries, 10, 0) + testNumberOfXValuesEqualOrBelow(dataSeries, 10, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 10, 0) + testXSum(dataSeries, 0) + testYSum(dataSeries, 0) + testSlopeEquals(dataSeries, 0) + testInterceptEquals(dataSeries, 0) + testGoodnessOfFitEquals(dataSeries, 0) +}) + +test('Correct behaviour of a series after several puhed values, function y = 3x + 6, noisefree, 1 datapoint', () => { + const dataSeries = createOLSLinearSeries(3) + testLength(dataSeries, 0) + dataSeries.push(5, 9) + testLength(dataSeries, 1) + testXAtSeriesBegin(dataSeries, 5) + testYAtSeriesBegin(dataSeries, 9) + testXAtSeriesEnd(dataSeries, 5) + testYAtSeriesEnd(dataSeries, 9) + testNumberOfXValuesAbove(dataSeries, 0, 1) + testNumberOfYValuesAbove(dataSeries, 0, 1) + testNumberOfXValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfXValuesAbove(dataSeries, 10, 0) + testNumberOfYValuesAbove(dataSeries, 10, 0) + testNumberOfXValuesEqualOrBelow(dataSeries, 10, 1) + testNumberOfYValuesEqualOrBelow(dataSeries, 10, 1) + testXSum(dataSeries, 5) + testYSum(dataSeries, 9) + testSlopeEquals(dataSeries, 0) + testInterceptEquals(dataSeries, 0) + testGoodnessOfFitEquals(dataSeries, 0) +}) + +test('Correct behaviour of a series after several puhed values, function y = 3x + 6, noisefree, 2 datapoints', () => { + const dataSeries = createOLSLinearSeries(3) + dataSeries.push(5, 9) + dataSeries.push(3, 3) + testLength(dataSeries, 2) + testXAtSeriesBegin(dataSeries, 5) + testYAtSeriesBegin(dataSeries, 9) + testXAtSeriesEnd(dataSeries, 3) + testYAtSeriesEnd(dataSeries, 3) + testNumberOfXValuesAbove(dataSeries, 0, 2) + testNumberOfYValuesAbove(dataSeries, 0, 2) + testNumberOfXValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfXValuesAbove(dataSeries, 10, 0) + testNumberOfYValuesAbove(dataSeries, 10, 0) + testNumberOfXValuesEqualOrBelow(dataSeries, 10, 2) + testNumberOfYValuesEqualOrBelow(dataSeries, 10, 2) + testXSum(dataSeries, 8) + testYSum(dataSeries, 12) + testSlopeEquals(dataSeries, 3) + testInterceptEquals(dataSeries, -6) + testGoodnessOfFitEquals(dataSeries, 1) +}) + +test('Correct behaviour of a series after several puhed values, function y = 3x + 6, noisefree, 3 datapoints', () => { + const dataSeries = createOLSLinearSeries(3) + dataSeries.push(5, 9) + dataSeries.push(3, 3) + dataSeries.push(4, 6) + testLength(dataSeries, 3) + testXAtSeriesBegin(dataSeries, 5) + testYAtSeriesBegin(dataSeries, 9) + testXAtSeriesEnd(dataSeries, 4) + testYAtSeriesEnd(dataSeries, 6) + testNumberOfXValuesAbove(dataSeries, 0, 3) + testNumberOfYValuesAbove(dataSeries, 0, 3) + testNumberOfXValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfXValuesAbove(dataSeries, 10, 0) + testNumberOfYValuesAbove(dataSeries, 10, 0) + testNumberOfXValuesEqualOrBelow(dataSeries, 10, 3) + testNumberOfYValuesEqualOrBelow(dataSeries, 10, 3) + testXSum(dataSeries, 12) + testYSum(dataSeries, 18) + testSlopeEquals(dataSeries, 3) + testInterceptEquals(dataSeries, -6) + testGoodnessOfFitEquals(dataSeries, 1) +}) + +test('Correct behaviour of a series after several puhed values, function y = 3x + 6, noisefree, 4 datapoints', () => { + const dataSeries = createOLSLinearSeries(3) + dataSeries.push(5, 9) + dataSeries.push(3, 3) + dataSeries.push(4, 6) + dataSeries.push(6, 12) + testLength(dataSeries, 3) + testXAtSeriesBegin(dataSeries, 3) + testYAtSeriesBegin(dataSeries, 3) + testXAtSeriesEnd(dataSeries, 6) + testYAtSeriesEnd(dataSeries, 12) + testNumberOfXValuesAbove(dataSeries, 0, 3) + testNumberOfYValuesAbove(dataSeries, 0, 3) + testNumberOfXValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfXValuesAbove(dataSeries, 10, 0) + testNumberOfYValuesAbove(dataSeries, 10, 1) + testNumberOfXValuesEqualOrBelow(dataSeries, 10, 3) + testNumberOfYValuesEqualOrBelow(dataSeries, 10, 2) + testXSum(dataSeries, 13) + testYSum(dataSeries, 21) + testSlopeEquals(dataSeries, 3) + testInterceptEquals(dataSeries, -6) + testGoodnessOfFitEquals(dataSeries, 1) +}) + +test('Correct behaviour of a series after several puhed values, function y = 3x + 6, noisefree, 5 datapoints', () => { + const dataSeries = createOLSLinearSeries(3) + dataSeries.push(5, 9) + dataSeries.push(3, 3) + dataSeries.push(4, 6) + dataSeries.push(6, 12) + dataSeries.push(1, -3) + testLength(dataSeries, 3) + testXAtSeriesBegin(dataSeries, 4) + testYAtSeriesBegin(dataSeries, 6) + testXAtSeriesEnd(dataSeries, 1) + testYAtSeriesEnd(dataSeries, -3) + testNumberOfXValuesAbove(dataSeries, 0, 3) + testNumberOfYValuesAbove(dataSeries, 0, 2) + testNumberOfXValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 0, 1) + testNumberOfXValuesAbove(dataSeries, 10, 0) + testNumberOfYValuesAbove(dataSeries, 10, 1) + testNumberOfXValuesEqualOrBelow(dataSeries, 10, 3) + testNumberOfYValuesEqualOrBelow(dataSeries, 10, 2) + testXSum(dataSeries, 11) + testYSum(dataSeries, 15) + testSlopeEquals(dataSeries, 3) + testInterceptEquals(dataSeries, -6) + testGoodnessOfFitEquals(dataSeries, 1) +}) + +test('Correct behaviour of a series after several puhed values, function y = 3x + 6, noisefree, 4 datapoints and a reset', () => { + const dataSeries = createOLSLinearSeries(3) + dataSeries.push(5, 9) + dataSeries.push(3, 3) + dataSeries.push(4, 6) + dataSeries.push(6, 12) + dataSeries.reset() + testLength(dataSeries, 0) + testXAtSeriesBegin(dataSeries, 0) + testYAtSeriesBegin(dataSeries, 0) + testXAtSeriesEnd(dataSeries, 0) + testYAtSeriesEnd(dataSeries, 0) + testNumberOfXValuesAbove(dataSeries, 0, 0) + testNumberOfYValuesAbove(dataSeries, 0, 0) + testNumberOfXValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfXValuesAbove(dataSeries, 10, 0) + testNumberOfYValuesAbove(dataSeries, 10, 0) + testNumberOfXValuesEqualOrBelow(dataSeries, 10, 0) + testNumberOfYValuesEqualOrBelow(dataSeries, 10, 0) + testXSum(dataSeries, 0) + testYSum(dataSeries, 0) + testSlopeEquals(dataSeries, 0) + testInterceptEquals(dataSeries, 0) + testGoodnessOfFitEquals(dataSeries, 0) +}) + +test('Series with 5 elements, with 2 noisy datapoints', () => { + const dataSeries = createOLSLinearSeries(5) + dataSeries.push(5, 9) + dataSeries.push(3, 2) + dataSeries.push(4, 7) + dataSeries.push(6, 12) + dataSeries.push(1, -3) + testSlopeBetween(dataSeries, 2.9, 3.1) + testInterceptBetween(dataSeries, -6.3, -5.8) + testGoodnessOfFitBetween(dataSeries, 0.9, 1.0) +}) + +function testLength (series, expectedValue) { + assert.ok(series.length() === expectedValue, `Expected length should be ${expectedValue}, encountered a ${series.length()}`) +} + +function testXAtSeriesBegin (series, expectedValue) { + assert.ok(series.xAtSeriesBegin() === expectedValue, `Expected xAtSeriesBegin to be ${expectedValue}, encountered a ${series.xAtSeriesBegin()}`) +} + +function testYAtSeriesBegin (series, expectedValue) { + assert.ok(series.yAtSeriesBegin() === expectedValue, `Expected yAtSeriesBegin to be ${expectedValue}, encountered a ${series.yAtSeriesBegin()}`) +} + +function testXAtSeriesEnd (series, expectedValue) { + assert.ok(series.xAtSeriesEnd() === expectedValue, `Expected xAtSeriesEnd to be ${expectedValue}, encountered a ${series.xAtSeriesEnd()}`) +} + +function testYAtSeriesEnd (series, expectedValue) { + assert.ok(series.yAtSeriesEnd() === expectedValue, `Expected yAtSeriesEnd to be ${expectedValue}, encountered a ${series.yAtSeriesEnd()}`) +} + +function testNumberOfXValuesAbove (series, cutoff, expectedValue) { + assert.ok(series.numberOfXValuesAbove(cutoff) === expectedValue, `Expected numberOfXValuesAbove(${cutoff}) to be ${expectedValue}, encountered a ${series.numberOfXValuesAbove(cutoff)}`) +} + +function testNumberOfYValuesAbove (series, cutoff, expectedValue) { + assert.ok(series.numberOfYValuesAbove(cutoff) === expectedValue, `Expected numberOfYValuesAbove(${cutoff}) to be ${expectedValue}, encountered a ${series.numberOfYValuesAbove(cutoff)}`) +} + +function testNumberOfXValuesEqualOrBelow (series, cutoff, expectedValue) { + assert.ok(series.numberOfXValuesEqualOrBelow(cutoff) === expectedValue, `Expected numberOfXValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered a ${series.numberOfXValuesEqualOrBelow(cutoff)}`) +} + +function testNumberOfYValuesEqualOrBelow (series, cutoff, expectedValue) { + assert.ok(series.numberOfYValuesEqualOrBelow(cutoff) === expectedValue, `Expected numberOfYValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered a ${series.numberOfYValuesEqualOrBelow(cutoff)}`) +} + +function testXSum (series, expectedValue) { + assert.ok(series.xSum() === expectedValue, `Expected xSum to be ${expectedValue}, encountered a ${series.xSum()}`) +} + +function testYSum (series, expectedValue) { + assert.ok(series.ySum() === expectedValue, `Expected ySum to be ${expectedValue}, encountered a ${series.ySum()}`) +} + +function testSlopeEquals (series, expectedValue) { + assert.ok(series.slope() === expectedValue, `Expected slope to be ${expectedValue}, encountered a ${series.slope()}`) +} + +function testSlopeBetween (series, expectedValueAbove, expectedValueBelow) { + assert.ok(series.slope() > expectedValueAbove, `Expected slope to be above ${expectedValueAbove}, encountered a ${series.slope()}`) + assert.ok(series.slope() < expectedValueBelow, `Expected slope to be below ${expectedValueBelow}, encountered a ${series.slope()}`) +} + +function testInterceptEquals (series, expectedValue) { + assert.ok(series.intercept() === expectedValue, `Expected intercept to be ${expectedValue}, encountered ${series.intercept()}`) +} + +function testInterceptBetween (series, expectedValueAbove, expectedValueBelow) { + assert.ok(series.intercept() > expectedValueAbove, `Expected intercept to be above ${expectedValueAbove}, encountered ${series.intercept()}`) + assert.ok(series.intercept() < expectedValueBelow, `Expected intercept to be below ${expectedValueBelow}, encountered ${series.intercept()}`) +} + +function testGoodnessOfFitEquals (series, expectedValue) { + assert.ok(series.goodnessOfFit() === expectedValue, `Expected goodnessOfFit to be ${expectedValue}, encountered ${series.goodnessOfFit()}`) +} + +function testGoodnessOfFitBetween (series, expectedValueAbove, expectedValueBelow) { + assert.ok(series.goodnessOfFit() > expectedValueAbove, `Expected goodnessOfFit to be above ${expectedValueAbove}, encountered ${series.goodnessOfFit()}`) + assert.ok(series.goodnessOfFit() < expectedValueBelow, `Expected goodnessOfFit to be below ${expectedValueBelow}, encountered ${series.goodnessOfFit()}`) +} + +test.run() diff --git a/app/engine/utils/Series.js b/app/engine/utils/Series.js new file mode 100644 index 0000000000..2bc189578c --- /dev/null +++ b/app/engine/utils/Series.js @@ -0,0 +1,149 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This creates a series with a maximum number of values + It allows for determining the Average, Median, Number of Positive, number of Negative +*/ + +function createSeries (maxSeriesLength) { + const seriesArray = [] + let seriesSum = 0 + let numPos = 0 + let numNeg = 0 + + function push (value) { + if (maxSeriesLength > 0 && seriesArray.length >= maxSeriesLength) { + // The maximum of the array has been reached, we have to create room by removing the first + // value from the array + seriesSum -= seriesArray[0] + if (seriesArray[0] > 0) { + numPos-- + } else { + numNeg-- + } + seriesArray.shift() + } + seriesArray.push(value) + seriesSum += value + if (value > 0) { + numPos++ + } else { + numNeg++ + } + } + + function length () { + return seriesArray.length + } + + function atSeriesBegin () { + if (seriesArray.length > 0) { + return seriesArray[0] + } else { + return 0 + } + } + + function atSeriesEnd () { + if (seriesArray.length > 0) { + return seriesArray[seriesArray.length - 1] + } else { + return 0 + } + } + + function get (position) { + if (position >= 0 && position < seriesArray.length) { + return seriesArray[position] + } else { + return undefined + } + } + + function numberOfValuesAbove (testedValue) { + if (testedValue === 0) { + return numPos + } else { + let i = seriesArray.length - 1 + let count = 0 + while (i >= 0) { + if (seriesArray[i] > testedValue) { + count++ + } + i-- + } + return count + } + } + + function numberOfValuesEqualOrBelow (testedValue) { + if (testedValue === 0) { + return numNeg + } else { + let i = seriesArray.length - 1 + let count = 0 + while (i >= 0) { + if (seriesArray[i] <= testedValue) { + count++ + } + i-- + } + return count + } + } + + function sum () { + return seriesSum + } + + function average () { + if (seriesArray.length > 0) { + return seriesSum / seriesArray.length + } else { + return 0 + } + } + + function median () { + if (seriesArray.length > 0) { + const mid = Math.floor(seriesArray.length / 2) + const sortedArray = [...seriesArray].sort((a, b) => a - b) + return seriesArray.length % 2 !== 0 ? sortedArray[mid] : (sortedArray[mid - 1] + sortedArray[mid]) / 2 + } else { + return 0 + } + } + + function series () { + if (seriesArray.length > 0) { + return seriesArray + } else { + return [] + } + } + + function reset () { + seriesArray.splice(0, seriesArray.length) + seriesSum = 0 + numPos = 0 + numNeg = 0 + } + + return { + push, + length, + atSeriesBegin, + atSeriesEnd, + get, + numberOfValuesAbove, + numberOfValuesEqualOrBelow, + sum, + average, + median, + series, + reset + } +} + +export { createSeries } diff --git a/app/engine/utils/Series.test.js b/app/engine/utils/Series.test.js new file mode 100644 index 0000000000..8df93334a7 --- /dev/null +++ b/app/engine/utils/Series.test.js @@ -0,0 +1,163 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + As this object is fundamental for most other utility objects, we must test its behaviour quite thoroughly +*/ +import { test } from 'uvu' +import * as assert from 'uvu/assert' + +import { createSeries } from './Series.js' + +test('Series behaviour with an empty series', () => { + const dataSeries = createSeries(3) + testLength(dataSeries, 0) + testatSeriesBegin(dataSeries, 0) + testAtSeriesEnd(dataSeries, 0) + testNumberOfValuesAbove(dataSeries, 0, 0) + testNumberOfValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfValuesAbove(dataSeries, 10, 0) + testNumberOfValuesEqualOrBelow(dataSeries, 10, 0) + testSum(dataSeries, 0) + testAverage(dataSeries, 0) + testMedian(dataSeries, 0) +}) + +test('Series behaviour with a single pushed value. Series = [9]', () => { + const dataSeries = createSeries(3) + dataSeries.push(9) + testLength(dataSeries, 1) + testatSeriesBegin(dataSeries, 9) + testAtSeriesEnd(dataSeries, 9) + testNumberOfValuesAbove(dataSeries, 0, 1) + testNumberOfValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfValuesAbove(dataSeries, 10, 0) + testNumberOfValuesEqualOrBelow(dataSeries, 10, 1) + testSum(dataSeries, 9) + testAverage(dataSeries, 9) + testMedian(dataSeries, 9) +}) + +test('Series behaviour with a second pushed value. Series = [9, 3]', () => { + const dataSeries = createSeries(3) + dataSeries.push(9) + dataSeries.push(3) + testLength(dataSeries, 2) + testatSeriesBegin(dataSeries, 9) + testAtSeriesEnd(dataSeries, 3) + testNumberOfValuesAbove(dataSeries, 0, 2) + testNumberOfValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfValuesAbove(dataSeries, 10, 0) + testNumberOfValuesEqualOrBelow(dataSeries, 10, 2) + testSum(dataSeries, 12) + testAverage(dataSeries, 6) + testMedian(dataSeries, 6) +}) + +test('Series behaviour with a third pushed value. Series = [9, 3, 6]', () => { + const dataSeries = createSeries(3) + dataSeries.push(9) + dataSeries.push(3) + dataSeries.push(6) + testLength(dataSeries, 3) + testatSeriesBegin(dataSeries, 9) + testAtSeriesEnd(dataSeries, 6) + testNumberOfValuesAbove(dataSeries, 0, 3) + testNumberOfValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfValuesAbove(dataSeries, 10, 0) + testNumberOfValuesEqualOrBelow(dataSeries, 10, 3) + testSum(dataSeries, 18) + testAverage(dataSeries, 6) + testMedian(dataSeries, 6) +}) + +test('Series behaviour with a fourth pushed value. Series = [3, 6, 12]', () => { + const dataSeries = createSeries(3) + dataSeries.push(9) + dataSeries.push(3) + dataSeries.push(6) + dataSeries.push(12) + testLength(dataSeries, 3) + testatSeriesBegin(dataSeries, 3) + testAtSeriesEnd(dataSeries, 12) + testNumberOfValuesAbove(dataSeries, 0, 3) + testNumberOfValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfValuesAbove(dataSeries, 10, 1) + testNumberOfValuesEqualOrBelow(dataSeries, 10, 2) + testSum(dataSeries, 21) + testAverage(dataSeries, 7) + testMedian(dataSeries, 6) +}) + +test('Series behaviour with a fifth pushed value. Series = [6, 12, -3]', () => { + const dataSeries = createSeries(3) + dataSeries.push(9) + dataSeries.push(3) + dataSeries.push(6) + dataSeries.push(12) + dataSeries.push(-3) + testLength(dataSeries, 3) + testatSeriesBegin(dataSeries, 6) + testAtSeriesEnd(dataSeries, -3) + testNumberOfValuesAbove(dataSeries, 0, 2) + testNumberOfValuesEqualOrBelow(dataSeries, 0, 1) + testNumberOfValuesAbove(dataSeries, 10, 1) + testNumberOfValuesEqualOrBelow(dataSeries, 10, 2) + testSum(dataSeries, 15) + testAverage(dataSeries, 5) + testMedian(dataSeries, 6) +}) + +test('Series behaviour with a five pushed values followed by a reset, Series = []', () => { + const dataSeries = createSeries(3) + dataSeries.push(9) + dataSeries.push(3) + dataSeries.push(6) + dataSeries.push(12) + dataSeries.push(-3) + dataSeries.reset() + testLength(dataSeries, 0) + testatSeriesBegin(dataSeries, 0) + testAtSeriesEnd(dataSeries, 0) + testNumberOfValuesAbove(dataSeries, 0, 0) + testNumberOfValuesEqualOrBelow(dataSeries, 0, 0) + testNumberOfValuesAbove(dataSeries, 10, 0) + testNumberOfValuesEqualOrBelow(dataSeries, 10, 0) + testSum(dataSeries, 0) + testAverage(dataSeries, 0) + testMedian(dataSeries, 0) +}) + +function testLength (series, expectedValue) { + assert.ok(series.length() === expectedValue, `Expected length should be ${expectedValue}, encountered ${series.length()}`) +} + +function testatSeriesBegin (series, expectedValue) { + assert.ok(series.atSeriesBegin() === expectedValue, `Expected atSeriesBegin to be ${expectedValue}, encountered ${series.atSeriesBegin()}`) +} + +function testAtSeriesEnd (series, expectedValue) { + assert.ok(series.atSeriesEnd() === expectedValue, `Expected atSeriesEnd to be ${expectedValue}, encountered ${series.atSeriesEnd()}`) +} + +function testNumberOfValuesAbove (series, cutoff, expectedValue) { + assert.ok(series.numberOfValuesAbove(cutoff) === expectedValue, `Expected numberOfValuesAbove(${cutoff}) to be ${expectedValue}, encountered ${series.numberOfValuesAbove(cutoff)}`) +} + +function testNumberOfValuesEqualOrBelow (series, cutoff, expectedValue) { + assert.ok(series.numberOfValuesEqualOrBelow(cutoff) === expectedValue, `Expected numberOfValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered ${series.numberOfValuesEqualOrBelow(cutoff)}`) +} + +function testSum (series, expectedValue) { + assert.ok(series.sum() === expectedValue, `Expected sum to be ${expectedValue}, encountered ${series.sum()}`) +} + +function testAverage (series, expectedValue) { + assert.ok(series.average() === expectedValue, `Expected average to be ${expectedValue}, encountered ${series.average()}`) +} + +function testMedian (series, expectedValue) { + assert.ok(series.median() === expectedValue, `Expected median to be ${expectedValue}, encountered ${series.median()}`) +} + +test.run() diff --git a/app/engine/utils/StreamFilter.js b/app/engine/utils/StreamFilter.js new file mode 100644 index 0000000000..f22aea991b --- /dev/null +++ b/app/engine/utils/StreamFilter.js @@ -0,0 +1,56 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This keeps an array, which we can ask for an moving average + + Please note: The array contains maxLength values +*/ + +import { createSeries } from './Series.js' + +function createStreamFilter (maxLength, defaultValue) { + const dataPoints = createSeries(maxLength) + let lastRawDatapoint = defaultValue + let cleanDatapoint = defaultValue + + function push (dataPoint) { + lastRawDatapoint = dataPoint + dataPoints.push(dataPoint) + cleanDatapoint = dataPoints.median() + } + + function raw () { + return lastRawDatapoint + } + + function clean () { + if (dataPoints.length() > 0) { + // The series contains sufficient values to be valid + return cleanDatapoint + } else { + // The array isn't sufficiently filled + return defaultValue + } + } + + function reliable () { + return dataPoints.length() > 0 + } + + function reset () { + dataPoints.reset() + lastRawDatapoint = defaultValue + cleanDatapoint = defaultValue + } + + return { + push, + raw, + clean, + reliable, + reset + } +} + +export { createStreamFilter } diff --git a/app/engine/utils/StreamFilter.test.js b/app/engine/utils/StreamFilter.test.js new file mode 100644 index 0000000000..05c0d4fea4 --- /dev/null +++ b/app/engine/utils/StreamFilter.test.js @@ -0,0 +1,69 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +*/ +import { test } from 'uvu' +import * as assert from 'uvu/assert' + +import { createStreamFilter } from './StreamFilter.js' + +test('average should be initValue on empty dataset', () => { + const datapoints = createStreamFilter(3, 5.5) + testReliable(datapoints, false) + testClean(datapoints, 5.5) +}) + +test('an averager of length 1 should return the last added value', () => { + const datapoints = createStreamFilter(3, 5.5) + datapoints.push(9) + testReliable(datapoints, true) + testClean(datapoints, 9) +}) + +test('a median of length 2 should return average of the 2 added elements', () => { + const datapoints = createStreamFilter(3, 5.5) + datapoints.push(9) + datapoints.push(4) + testReliable(datapoints, true) + testClean(datapoints, 6.5) +}) + +test('a median of three values should deliver the middle element', () => { + const datapoints = createStreamFilter(3, 5.5) + datapoints.push(9) + datapoints.push(4) + datapoints.push(3) + testReliable(datapoints, true) + testClean(datapoints, 4) +}) + +test('elements outside of range should not be considered', () => { + const datapoints = createStreamFilter(3, 5.5) + datapoints.push(9) + datapoints.push(4) + datapoints.push(3) + datapoints.push(1) + testReliable(datapoints, true) + testClean(datapoints, 3) +}) + +test('elements outside of range should not be considered', () => { + const datapoints = createStreamFilter(3, 5.5) + datapoints.push(9) + datapoints.push(4) + datapoints.push(3) + datapoints.push(1) + datapoints.reset() + testReliable(datapoints, false) + testClean(datapoints, 5.5) +}) + +function testClean (series, expectedValue) { + assert.ok(series.clean() === expectedValue, `Expected clean datapoint should be ${expectedValue}, encountered ${series.clean()}`) +} + +function testReliable (series, expectedValue) { + assert.ok(series.reliable() === expectedValue, `Expected clean datapoint should be ${expectedValue}, encountered ${series.reliable()}`) +} + +test.run() diff --git a/app/engine/utils/curveMetrics.js b/app/engine/utils/curveMetrics.js new file mode 100644 index 0000000000..4725ae74c7 --- /dev/null +++ b/app/engine/utils/curveMetrics.js @@ -0,0 +1,73 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This keeps an array, for all in-stroke metrics +*/ +import { createSeries } from './Series.js' + +function createCurveMetrics (precission = 0) { + const _curve = createSeries() + let _max = 0 + let totalInputXTime = 0 + let totaltime = 0 + + function push (deltaTime, inputValue) { + // add the new dataPoint to the array, we have to move datapoints starting at the oldst ones + if (inputValue > 0) { + _curve.push(inputValue.toFixed(precission)) + _max = Math.max(_max, inputValue) + totalInputXTime += deltaTime * inputValue + totaltime += deltaTime + } else { + // Let's skip negative and zero values with 0's as they are not relevant + _curve.push(0) + } + } + + function peak () { + if (_max > 0) { + return _max + } else { + return 0 + } + } + + function average () { + if (totaltime > 0 && totalInputXTime > 0) { + return totalInputXTime / totaltime + } else { + return 0 + } + } + + function curve () { + if (_curve.length() > 0) { + return Array.from(_curve.series()) + } else { + return [] + } + } + + function length () { + return _curve.length() + } + + function reset () { + _curve.reset() + _max = 0 + totalInputXTime = 0 + totaltime = 0 + } + + return { + push, + peak, + average, + curve, + length, + reset + } +} + +export { createCurveMetrics } diff --git a/app/gpio/GpioTimerService.js b/app/gpio/GpioTimerService.js index e73646c5ba..368ab7ca73 100644 --- a/app/gpio/GpioTimerService.js +++ b/app/gpio/GpioTimerService.js @@ -7,7 +7,7 @@ possible to real time. */ import process from 'process' -import { Gpio } from 'onoff' +import pigpio from 'pigpio' import os from 'os' import config from '../tools/ConfigManager.js' import log from 'loglevel' @@ -15,37 +15,49 @@ import log from 'loglevel' log.setLevel(config.loglevel.default) export function createGpioTimerService () { - if (Gpio.accessible) { - if (config.gpioHighPriority) { - // setting top (near-real-time) priority for the Gpio process, as we don't want to miss anything - log.debug('setting priority for the Gpio-service to maximum (-20)') - try { - // setting priority of current process - os.setPriority(-20) - } catch (err) { - log.debug('need root permission to set priority of Gpio-Thread') - } + // Import the settings from the settings file + const triggeredFlank = config.gpioTriggeredFlank + const pollingInterval = config.gpioPollingInterval + const minimumPulseLength = config.gpioMinimumPulseLength + + if (config.gpioPriority) { + // setting top (near-real-time) priority for the Gpio process, as we don't want to miss anything + log.debug(`Gpio-service: Setting priority to ${config.gpioPriority}`) + try { + // setting priority of current process + os.setPriority(config.gpioPriority) + } catch (err) { + log.debug('Gpio-service: FAILED to set priority of Gpio-Thread, are root permissions granted?') } + } + + const Gpio = pigpio.Gpio - // read the sensor data from one of the Gpio pins of Raspberry Pi - const sensor = new Gpio(config.gpioPin, 'in', 'rising') - // use hrtime for time measurement to get a higher time precision - let hrStartTime = process.hrtime() - - // assumes that GPIO-Port 17 is set to pullup and reed is connected to GND - // therefore the value is 1 if the reed sensor is open - sensor.watch((err, value) => { - if (err) { - throw err - } - const hrDelta = process.hrtime(hrStartTime) - hrStartTime = process.hrtime() - const delta = hrDelta[0] + hrDelta[1] / 1e9 - process.send(delta) + // Configure the gpio polling frequency + pigpio.configureClock(pollingInterval, pigpio.CLOCK_PCM) + + // Configure the sensor readings for one of the Gpio pins of Raspberry Pi + const sensor = new Gpio( + config.gpioPin, { + mode: Gpio.INPUT, + pullUpDown: Gpio.PUD_UP, + alert: true }) - } else { - log.info('reading from Gpio is not (yet) supported on this platform') - } -} + // Set a minumum time a level must be stable before an alert event is emitted. + sensor.glitchFilter(minimumPulseLength) + log.debug(`Gpio-service: pin number ${config.gpioPin}, polling interval ${pollingInterval} us, triggered on ${triggeredFlank} flank, minimal pulse time ${minimumPulseLength} us`) + + // set the default value + let previousTick = 0 + + // Define the alert handler + sensor.on('alert', (level, currentTick) => { + if ((triggeredFlank === 'Both') || (triggeredFlank === 'Down' && level === 0) || (triggeredFlank === 'Up' && level === 1)) { + const currentDt = ((currentTick >> 0) - (previousTick >> 0)) / 1e6 + previousTick = currentTick + process.send(currentDt) + } + }) +} createGpioTimerService() diff --git a/app/server.js b/app/server.js index 32ce7621aa..49f87a712a 100644 --- a/app/server.js +++ b/app/server.js @@ -6,11 +6,11 @@ everything together while figuring out the physics and model of the application. todo: refactor this as we progress */ +import os from 'os' import child_process from 'child_process' import { promisify } from 'util' import log from 'loglevel' import config from './tools/ConfigManager.js' -import { createRowingEngine } from './engine/RowingEngine.js' import { createRowingStatistics } from './engine/RowingStatistics.js' import { createWebServer } from './WebServer.js' import { createPeripheralManager } from './ble/PeripheralManager.js' @@ -31,39 +31,83 @@ for (const [loggerName, logLevel] of Object.entries(config.loglevel)) { log.info(`==== Open Rowing Monitor ${process.env.npm_package_version || ''} ====\n`) +if (config.appPriority) { + // setting the (near-real-time?) priority for the main process, to prevent blocking the GPIO thread + const mainPriority = Math.min((config.appPriority), 0) + log.debug(`Setting priority for the main server thread to ${mainPriority}`) + try { + // setting priority of current process + os.setPriority(mainPriority) + } catch (err) { + log.debug('need root permission to set priority of main server thread') + } +} + +// a hook for setting session parameters that the rower has to obey +// Hopefully this will be filled through the WebGUI or through the BLE interface (PM5-BLE can do this...) +// When set, ORM will terminate the session after reaching the target. If not set, it will behave as usual (a "Just row" session). +// When set, the GUI will behave similar to a PM5 in that it counts down from the target to 0 +const session = { + targetDistance: 0, // Target distance in meters + targetTime: 0 // Target time in seconds +} + +log.info(`Session settings: distance limit: ${(session.targetDistance > 0 ? `${session.targetDistance} meters` : 'none')}, time limit: ${(session.targetTime > 0 ? `${session.targetTime} seconds` : 'none')}\n`) + const peripheralManager = createPeripheralManager() peripheralManager.on('control', (event) => { - if (event?.req?.name === 'requestControl') { - event.res = true - } else if (event?.req?.name === 'reset') { - log.debug('reset requested') - resetWorkout() - event.res = true - // todo: we could use these controls once we implement a concept of a rowing session - } else if (event?.req?.name === 'stop') { - log.debug('stop requested') - peripheralManager.notifyStatus({ name: 'stoppedOrPausedByUser' }) - event.res = true - } else if (event?.req?.name === 'pause') { - log.debug('pause requested') - peripheralManager.notifyStatus({ name: 'stoppedOrPausedByUser' }) - event.res = true - } else if (event?.req?.name === 'startOrResume') { - log.debug('startOrResume requested') - peripheralManager.notifyStatus({ name: 'startedOrResumedByUser' }) - event.res = true - } else if (event?.req?.name === 'peripheralMode') { - webServer.notifyClients('config', getConfig()) - event.res = true - } else { - log.info('unhandled Command', event.req) + switch (event?.req?.name) { + case 'requestControl': + event.res = true + break + case 'reset': + log.debug('reset requested') + resetWorkout() + event.res = true + break + // todo: we could use these controls once we implement a concept of a rowing session + case 'stop': + log.debug('stop requested') + stopWorkout() + peripheralManager.notifyStatus({ name: 'stoppedOrPausedByUser' }) + event.res = true + break + case 'pause': + log.debug('pause requested') + pauseWorkout() + peripheralManager.notifyStatus({ name: 'stoppedOrPausedByUser' }) + event.res = true + break + case 'startOrResume': + log.debug('startOrResume requested') + resumeWorkout() + peripheralManager.notifyStatus({ name: 'startedOrResumedByUser' }) + event.res = true + break + case 'peripheralMode': + webServer.notifyClients('config', getConfig()) + event.res = true + break + default: + log.info('unhandled Command', event.req) } }) +function pauseWorkout () { + rowingStatistics.pause() +} + +function stopWorkout () { + rowingStatistics.stop() +} + +function resumeWorkout () { + rowingStatistics.resume() +} + function resetWorkout () { workoutRecorder.reset() - rowingEngine.reset() rowingStatistics.reset() peripheralManager.notifyStatus({ name: 'reset' }) } @@ -73,12 +117,10 @@ gpioTimerService.on('message', handleRotationImpulse) function handleRotationImpulse (dataPoint) { workoutRecorder.recordRotationImpulse(dataPoint) - rowingEngine.handleRotationImpulse(dataPoint) + rowingStatistics.handleRotationImpulse(dataPoint) } -const rowingEngine = createRowingEngine(config.rowerSettings) -const rowingStatistics = createRowingStatistics(config) -rowingEngine.notify(rowingStatistics) +const rowingStatistics = createRowingStatistics(config, session) const workoutRecorder = createWorkoutRecorder() const workoutUploader = createWorkoutUploader(workoutRecorder) @@ -88,15 +130,10 @@ rowingStatistics.on('driveFinished', (metrics) => { }) rowingStatistics.on('recoveryFinished', (metrics) => { - log.info(`stroke: ${metrics.strokesTotal}, dur: ${metrics.strokeTime.toFixed(2)}s, power: ${Math.round(metrics.power)}w` + - `, split: ${metrics.splitFormatted}, ratio: ${metrics.powerRatio.toFixed(2)}, dist: ${metrics.distanceTotal.toFixed(1)}m` + - `, cal: ${metrics.caloriesTotal.toFixed(1)}kcal, SPM: ${metrics.strokesPerMinute.toFixed(1)}, speed: ${metrics.speed.toFixed(2)}km/h` + - `, cal/hour: ${metrics.caloriesPerHour.toFixed(1)}kcal, cal/minute: ${metrics.caloriesPerMinute.toFixed(1)}kcal`) + logMetrics(metrics) webServer.notifyClients('metrics', metrics) peripheralManager.notifyMetrics('strokeFinished', metrics) - if (metrics.sessionState === 'rowing') { - workoutRecorder.recordStroke(metrics) - } + workoutRecorder.recordStroke(metrics) }) rowingStatistics.on('webMetricsUpdate', (metrics) => { @@ -107,8 +144,30 @@ rowingStatistics.on('peripheralMetricsUpdate', (metrics) => { peripheralManager.notifyMetrics('metricsUpdate', metrics) }) -rowingStatistics.on('rowingPaused', () => { +rowingStatistics.on('rowingPaused', (metrics) => { + logMetrics(metrics) + workoutRecorder.recordStroke(metrics) workoutRecorder.handlePause() + webServer.notifyClients('metrics', metrics) + peripheralManager.notifyMetrics('metricsUpdate', metrics) +}) + +rowingStatistics.on('intervalTargetReached', (metrics) => { + // This is called when the RowingStatistics conclude the target is reached + // This isn't the most optimal solution yet, as this interval is the only one set. A logcal extansion would be + // to provide a next intervaltarget. Thus, the use case of a next interval has to be implemented as well + // (i.e. setting a new interval target). For now, this interval is the one and only so we stop. + stopWorkout() +}) + +rowingStatistics.on('rowingStopped', (metrics) => { + // This is called when the rowingmachine is stopped for some reason, could be reaching the end of the session, + // could be user intervention + logMetrics(metrics) + workoutRecorder.recordStroke(metrics) + webServer.notifyClients('metrics', metrics) + peripheralManager.notifyMetrics('metricsUpdate', metrics) + workoutRecorder.writeRecordings() }) if (config.heartrateMonitorBLE) { @@ -136,40 +195,23 @@ workoutUploader.on('resetWorkout', () => { const webServer = createWebServer() webServer.on('messageReceived', async (message, client) => { switch (message.command) { - case 'switchPeripheralMode': { + case 'switchPeripheralMode': peripheralManager.switchPeripheralMode() break - } - case 'reset': { + case 'reset': resetWorkout() break - } - case 'uploadTraining': { + case 'uploadTraining': workoutUploader.upload(client) break - } - case 'shutdown': { - if (getConfig().shutdownEnabled) { - console.info('shutting down device...') - try { - const { stdout, stderr } = await exec(config.shutdownCommand) - if (stderr) { - log.error('can not shutdown: ', stderr) - } - log.info(stdout) - } catch (error) { - log.error('can not shutdown: ', error) - } - } + case 'shutdown': + await shutdown() break - } - case 'stravaAuthorizationCode': { + case 'stravaAuthorizationCode': workoutUploader.stravaAuthorizationCode(message.data) break - } - default: { + default: log.warn('invalid command received:', message) - } } }) @@ -186,10 +228,34 @@ function getConfig () { } } +// This shuts down the pi, use with caution! +async function shutdown () { + stopWorkout() + if (getConfig().shutdownEnabled) { + console.info('shutting down device...') + try { + const { stdout, stderr } = await exec(config.shutdownCommand) + if (stderr) { + log.error('can not shutdown: ', stderr) + } + log.info(stdout) + } catch (error) { + log.error('can not shutdown: ', error) + } + } +} + +function logMetrics (metrics) { + log.info(`stroke: ${metrics.totalNumberOfStrokes}, dist: ${metrics.totalLinearDistance.toFixed(1)}m, speed: ${metrics.cycleLinearVelocity.toFixed(2)}m/s` + + `, pace: ${metrics.cyclePaceFormatted}/500m, power: ${Math.round(metrics.cyclePower)}W, cal: ${metrics.totalCalories.toFixed(1)}kcal` + + `, SPM: ${metrics.cycleStrokeRate.toFixed(1)}, drive dur: ${metrics.driveDuration.toFixed(2)}s, rec. dur: ${metrics.recoveryDuration.toFixed(2)}s` + + `, stroke dur: ${metrics.cycleDuration.toFixed(2)}s`) +} + /* replayRowingSession(handleRotationImpulse, { - filename: 'recordings/WRX700_2magnets.csv', +// filename: 'recordings/2021/04/rx800_2021-04-21_1845_Rowing_30Minutes_Damper8.csv', // 30 minutes, damper 10 realtime: true, - loop: true + loop: false }) */ diff --git a/config/default.config.js b/config/default.config.js index e493e26163..fa16cfa77b 100644 --- a/config/default.config.js +++ b/config/default.config.js @@ -29,13 +29,55 @@ export default { // see: https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md gpioPin: 17, - // Experimental setting: enable this to boost the system level priority of the thread that - // measures the rotation speed of the flywheel. This might improve the precision of the - // measurements (especially on rowers with a fast spinning flywheel) - gpioHighPriority: false, - - // Selects the Bluetooth Low Energy Profile - // Supported modes: FTMS, FTMSBIKE, PM5 + // Enable this to boost or reduce the system level priority of the thread that measures the rotation + // speed of the flywheel. This might improve the precision of the measurements (especially + // on rowers with a fast spinning flywheel). + // This is the Linux NICE level: minimum setting is +19, theoretical maximum setting is -20 + // Setting this below -1 on a non-PREEMPT kernel might cause the app to crash + // Going beyond -7 on a PREEMPT kernel seems to kill the timing of the app + // 0 keeps the systems default value. + // Also note that you will require root permissions if you set anything other than 0 here + gpioPriority: 0, + + // GPIO polling interval: this is the interval at which the GPIO is inspected for state + // changes on the gpioPin, in microseconds (us). + // Valid values are 1 (i.e. 1,000,000 samples per second), 2 (i.e. 500,000 per second), + // 4 (i.e. 250,000 per second), 5 (i.e. 200,000 per second) and 10 (i.e. 100,000 per second). + // A high sample rate will burden your CPU more. Normal value is 5us. + // A raspberry pi 4 can handle a polling interval of 1 us, which results in a 16% CPU load. + gpioPollingInterval: 5, + + // Type of flank: what flank should be detected by the GPIO detection? + // Valid values are 'Up' for the upward flank, 'Down' for the downward flank, 'Both' for both flanks + // In practice, it shouldn't matter much which flank you detect, although in the presence of debounce, + // a specific flank might provide better filtering capabilities. + // Some machines are even capable of using both, but this requires a strong symmetry in the signal. + gpioTriggeredFlank: 'Up', + + // Minumum pulse length in microseconds. This is the minimum pulse length (i.e. a magnet should be + // present) before Open Rowing Monitor considers it a signal valid. Increasing this value reduces ghost readings + // due to bouncing reed switches etc., which typically are detected as very short measurements in the raw logs. + // Making this too long results in missed impulses. Both can be detected in the raw logs easily. + // Normal value is 50 us, but for some rowers, values up to 500 us are known to work. + gpioMinimumPulseLength: 50, + + // Enable this to boost or reduce the system level priority of the thread that processes the flywheel and HR data + // Although this process is not time critical per se, it could get caught up in Linux housekeeping tasks, preventing + // it to process data in a timely manner. + // This is the Linux NICE level: minimum setting is +19, theoretical maximum setting is -20 + // Setting this below -1 on a non-PREEMPT kernel might cause the app to crash + // Going beyond -5 on a PREEMPT kernel seems to kill the timing of the app + // 0 keeps the systems default value. + // Please make sure the app has a less high priority than gpioPriority + // Also note that you will require root permissions if you set anything other than 0 here + appPriority: 0, + + // Selects the Bluetooth Low Energy Profile that is broadcasted to external peripherals and apps. Supported modes: + // - PM5: the Concept2 PM5 emulator (not functionally complete yet) + // - FTMS: the FTMS profile for rowing machines + // - FTMSBIKE: The FTMS profile is used by Smart Bike Trainers (please note: the speed and power are still aimed for rowing, NOT for a bike!) + // - CPS: The BLE Cycling Power Profile simulates a bike for more modern Garmin watches + // - CSC: The BLE Cycling Speed and Cadence Profile simulates a bike for older Garmin watches bluetoothMode: 'FTMS', // Turn this on if you want support for Bluetooth Low Energy heart rate monitors @@ -48,6 +90,31 @@ export default { // - Garmin mini ANT+ (ID 0x1009) heartrateMonitorANT: false, + // Defines the name that is used to announce the FTMS Rower via Bluetooth Low Energy (BLE) + // Some rowing training applications expect that the rowing device is announced with a certain name + ftmsRowerPeripheralName: 'OpenRowingMonitor', + + // Defines the name that is used to announce the FTMS Bike via Bluetooth Low Energy (BLE) + // Most bike training applications are fine with any device name + ftmsBikePeripheralName: 'OpenRowingBike', + + // The interval for updating all web clients (i.e. the monitor) in miliseconds + // Advised is to update at least once per second (1000 ms), to make sure the timer moves nice and smoothly. + // Around 100 ms results in a very smooth update experience for distance as well + // Please note that a smaller value will use more network and cpu ressources + webUpdateInterval: 200, + + // Interval between updates of the bluetooth devices (miliseconds) + // Advised is to update at least once per second, as consumers expect this interval + // Some apps, like EXR like a more frequent interval of 200 ms to better sync the stroke + peripheralUpdateInterval: 1000, + + // The number of stroke phases (i.e. Drive or Recovery) used to smoothen the data displayed on your + // screens (i.e. the monitor, but also bluetooth devices, etc.) and recorded data. A nice smooth experience is found at 6 + // phases, a much more volatile (but more accurate and responsive) is found around 3. The minimum is 2, + // but for recreational rowers that might feel much too restless to be useful + numOfPhasesForAveragingScreenData: 6, + // The directory in which to store user specific content // currently this directory holds the recorded training sessions dataDirectory: 'data', @@ -55,6 +122,9 @@ export default { // Stores the training sessions as TCX files createTcxFiles: true, + // Stores the (in-)stroke data in OpenRowingData CSV files + createRowingDataFiles: true, + // Stores the raw sensor data in CSV files createRawDataFiles: false, @@ -64,34 +134,40 @@ export default { // you will have to unzip the files before uploading gzipTcxFiles: false, - // Apply gzip compression to the ras sensor data recording files (csv.gz) + // Apply gzip compression to the raw sensor data recording files (csv.gz) gzipRawDataFiles: true, - // Defines the name that is used to announce the FTMS Rower via Bluetooth Low Energy (BLE) - // Some rowing training applications expect that the rowing device is announced with a certain name - ftmsRowerPeripheralName: 'OpenRowingMonitor', + // EXPERIMENTAL: Settings used for the VO2 Max calculation that is embedded in the tcx file comments + userSettings: { - // Defines the name that is used to announce the FTMS Bike via Bluetooth Low Energy (BLE) - // Most bike training applications are fine with any device name - ftmsBikePeripheralName: 'OpenRowingBike', + // The resting Heartrate of the user, to filter abnomral HR values + restingHR: 40, - // The interval for updating all web clients (i.e. the monitor) in ms. - // Advised is to update at least once per second, to make sure the timer moves nice and smoothly. - // Around 100 ms results in a very smooth update experience - // Please note that a smaller value will use more network and cpu ressources - webUpdateInterval: 1000, + // The maximum observed heartrate during the last year. If unknown, you can use maxHr = 220 - age + // This is used for filtering abnormal HR values and to project the maximum power a rower produces + maxHR: 190, - // The number of stroke phases (i.e. Drive or Recovery) used to smoothen the data displayed on your - // screens (i.e. the monitor, but also bluetooth devices, etc.). A nice smooth experience is found at 6 - // phases, a much more volatile (but more accurate and responsive) is found around 3. The minimum is 1, - // but for recreational rowers that might feel much too restless to be useful - numOfPhasesForAveragingScreenData: 6, + // The minimum power a rower can produce, used for filtering abnormal power values + minPower: 50, + + // The maximum power a rower can produce, used for filtering abnormal power values + maxPower: 500, - // The time between strokes in seconds before the rower considers it a pause. Default value is set to 10. - // It is not recommended to go below this value, as not recognizing a stroke could result in a pause - // (as a typical stroke is between 2 to 3 seconds for recreational rowers). Increase it when you have - // issues with your stroke detection and the rower is pausing unexpectedly - maximumStrokeTime: 10, + // The effect that doubling the distance has on the maximum achievable average pace. The proposed 5 is based on Paul's law, + // which states that doubling the distance leads to a slowdown in pace of 5 seconds. This value can be adapted if you know + // your PR (this pace) on both a 1000 meters and on 2000 meters, by substracting the pace. + distanceCorrectionFactor: 5, + + // The weight of the rower in kilograms + weight: 80, + + // The sex of the rower, as it is needed for Concept 2's calculation + // This can be "male" or "female" + sex: 'male', + + // See for this definition: https://www.concept2.com/indoor-rowers/training/calculators/vo2max-calculator + highlyTrained: false + }, // The rower specific settings. Either choose a profile from config/rowerProfiles.js or // define the settings individually. If you find good settings for a new rowing device diff --git a/config/rowerProfiles.js b/config/rowerProfiles.js index 6d37351321..74a33f64c4 100644 --- a/config/rowerProfiles.js +++ b/config/rowerProfiles.js @@ -16,36 +16,44 @@ export default { // i.e. the number of magnets if used with a reed sensor numOfImpulsesPerRevolution: 1, + // How big the sprocket is that attaches your belt/chain to your flywheel. This determines both the force on the handle + // as well as the drive length. If all goes well, you end up with average forces around 400 to 800 N and drive lengths around 1.20 to 1.35 m + sprocketRadius: 7.0, + // NOISE FILTER SETTINGS // Filter Settings to reduce noise in the measured data - // Minimum and maximum duration between impulses in seconds during active rowing. Measurements outside of this range - // are replaced by a default value. + // Minimum and maximum duration between impulses in seconds during active rowing. Measurements above the maximum are filtered, so setting these liberaly + // might help here minimumTimeBetweenImpulses: 0.014, maximumTimeBetweenImpulses: 0.5, - // Percentage change between successive intervals before measurements are considered invalid - maximumDownwardChange: 0.25, // effectively the maximum acceleration - maximumUpwardChange: 1.75, // effectively the maximum decceleration - // Smoothing determines the length of the running average for certain volatile measurements, 1 effectively turns it off + + // Smoothing determines the length of the running average for filtering the currentDt, 1 effectively turns it off smoothing: 1, // STROKE DETECTION SETTINGS // Flank length determines the minimum number of consecutive increasing/decreasing measuments that are needed before the stroke detection // considers a drive phase change - // numberOfErrorsAllowed allows for a more noisy approach, but shouldn't be needed - flankLength: 2, - numberOfErrorsAllowed: 0, + flankLength: 3, + + // This is the minimum force that has to be on the handle before ORM considers it a stroke, in Newtons. So this is about 2 Kg or 4.4 Lbs. + minumumForceBeforeStroke: 20, + + // The minimal inclination of the currentDt's before it is considered a recovery. When set to 0, it will look for a pure increase/decrease + minumumRecoverySlope: 0, + + // The minimum quality level of the stroke detection: 1.0 is perfect, 0.1 pretty bad. Normally around 0.33. Setting this too high will stop + // the recovery phase from being detected. + minimumStrokeQuality: 0.34, + + // ORM can automatically calculate the recovery slope and adjust it dynamically. For this to work, autoAdjustDragFactor MUST be set to true + autoAdjustRecoverySlope: false, - // Natural deceleration is used to distinguish between a powered and unpowered flywheel. - // This must be a NEGATIVE number and indicates the level of deceleration required to interpret it as a free spinning - // flywheel. The best way to find the correct value for your rowing machine is a try and error approach. - // You can also set this to zero (or positive), to use the more robust, but not so precise acceleration-based stroke - // detection algorithm. - naturalDeceleration: 0, + // The margin used between the automatically calculated recovery slope and a next recovery. Don't touch unless you know what you are doing. + autoAdjustRecoverySlopeMargin: 0.05, // Error reducing settings for the rowing phase detection (in seconds) - maximumImpulseTimeBeforePause: 3.0, // maximum time between impulses before the rowing engine considers it a pause minimumDriveTime: 0.300, // minimum time of the drive phase - minimumRecoveryTime: 1.200, // minimum time of the recovery phase + minimumRecoveryTime: 0.900, // minimum time of the recovery phase // Needed to determine the drag factor of the rowing machine. This value can be measured in the recovery phase // of the stroke. @@ -64,23 +72,23 @@ export default { // When your machine's power and speed readings are too volatile it is wise to turn it off autoAdjustDragFactor: false, - // The moment of inertia of the flywheel kg*m^2, which is ONLY relevant when autoAdjustDragFactor is set to true or when you - // use Force Curves. Otherwise this value isn't relevant to your rower + // If autoAdjustDragFactor is set to true, it will calculate the drag each recovery phase and update it accordingly to calculate speed, + // distance, etc.. As this calculation that is prone to noise in the measuremnts, it is wise to apply smoothing to prevent this noise + // from throwing off your key metrics. The default value is a running average of the drag factor of 5 strokes + dragFactorSmoothing: 5, + + // When drag is calculated, we also get a quality indication. Based on this quality indication (1.0 is best, 0.1 pretty bad), low quality + // drag factors are rejected to prevent drag poisoning + minimumDragQuality: 0.83, + + // The moment of inertia of the flywheel kg*m^2 // A way to measure it is outlined here: https://dvernooy.github.io/projects/ergware/, "Flywheel moment of inertia" // You could also roughly estimate it by just doing some strokes and the comparing the calculated power values for // plausibility. Note that the power also depends on the drag factor (see above). flywheelInertia: 0.5, - // If autoAdjustDragFactor is set to true, it will calculate the drag each recovery phase and update it accordingly to calculate speed, - // distance, etc.. As this calculation that is prone to noise in the measuremnts, it is wise to apply smoothing to prevent this noise - // from throwing off your key metrics. The default value is a running average of the drag factor of 5 strokes - dampingConstantSmoothing: 5, - - // Another setting for when autoAdjustDragFactor is set to true: the maximum allowed change from the current value. Spikes usually imply - // measurement errors, so this setting determines the maximum change with respect to the current dragfactor. Please note that this filter - // will prevent large changes, but will still move the dragfactor upward/downward to prevent it from being stuck. The value is in maximum - // allowed change. The default value of 0.10 implies that the maximum upward/downward change is an increase of the drag with 10%. - dampingConstantMaxChange: 0.10, + // The time before a stroke is considered paused + maximumStrokeTimeBeforePause: 6.0, // A constant that is commonly used to convert flywheel revolutions to a rowed distance // see here: http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html#section9 @@ -91,99 +99,104 @@ export default { magicConstant: 2.8 }, - // Sportstech WRX700 - WRX700: { - numOfImpulsesPerRevolution: 2, - naturalDeceleration: -5.0, - flywheelInertia: 0.72, - dragFactor: 32000 + // Cheap Clone of Concept2 RowErg Model D + // https://zocobodyfit.ro/produs/aparat-de-vaslit-zoco-body-fit-air-rower-pliabil-ecran-lcd-eficient-si-util-negru/ + Generic_Air_Rower: { + numOfImpulsesPerRevolution: 1, + sprocketRadius: 1.55, + minimumTimeBetweenImpulses: 0.007, + smoothing: 1, + flankLength: 6, + minumumForceBeforeStroke: 2, + minimumStrokeQuality: 0.6, + minimumDriveTime: 0.200, // minimum time of the drive phase + minimumRecoveryTime: 0.600, // minimum time of the recovery phase + dragFactor: 108, + autoAdjustDragFactor: true, + dragFactorSmoothing: 1, + minimumDragQuality: 0.97, + flywheelInertia: 0.073, + maximumStrokeTimeBeforePause: 6.0 + }, + // Concept2 RowErg, Model D, E and RowErg + Concept2_RowErg: { + numOfImpulsesPerRevolution: 6, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.022, + flywheelInertia: 0.10163, + sprocketRadius: 1.5, + flankLength: 12, + minimumStrokeQuality: 0.50, + minumumRecoverySlope: 0.00070, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.035, + minumumForceBeforeStroke: 0, + minimumDriveTime: 0.46, + minimumRecoveryTime: 0.90, + dragFactor: 110, + autoAdjustDragFactor: true, + minimumDragQuality: 0.83, + dragFactorSmoothing: 3 }, // DKN R-320 Air Rower - DKNR320: { + DKN_R320: { numOfImpulsesPerRevolution: 1, flywheelInertia: 0.94, dragFactor: 8522 }, + // Force USA R3 Air Rower + ForceUSA_R3: { + numOfImpulsesPerRevolution: 6, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.022, + flywheelInertia: 0.1015, + flankLength: 10, + dragFactor: 135, + autoAdjustDragFactor: true, + // new engine settings + sprocketRadius: 1.5, + minimumStrokeQuality: 0.50, + minumumRecoverySlope: 0.00070, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.035, + minumumForceBeforeStroke: 20, + minimumDriveTime: 0.46, + minimumRecoveryTime: 0.80, + minimumDragQuality: 0.83, + dragFactorSmoothing: 3, + maximumStrokeTimeBeforePause: 4 + }, + // NordicTrack RX800 Air Rower - RX800: { + NordicTrack_RX800: { numOfImpulsesPerRevolution: 4, - /* Damper setting 10 - minimumTimeBetweenImpulses: 0.018, - maximumTimeBetweenImpulses: 0.0338, - smoothing: 3, - maximumDownwardChange: 0.88, - maximumUpwardChange: 1.11, - flankLength: 9, - numberOfErrorsAllowed: 2, - naturalDeceleration: -11.5, // perfect runs - minimumDriveTime: 0.40, - minimumRecoveryTime: 0.90, - flywheelInertia: 0.146, - dragFactor: 560 - */ - - /* Damper setting 8 - minimumTimeBetweenImpulses: 0.017, - maximumTimeBetweenImpulses: 0.034, - smoothing: 3, - maximumDownwardChange: 0.8, - maximumUpwardChange: 1.15, - flankLength: 9, - numberOfErrorsAllowed: 2, - naturalDeceleration: -10.25, // perfect runs - minimumDriveTime: 0.30, - minimumRecoveryTime: 0.90, - flywheelInertia: 0.131, - dragFactor: 440 - */ - - // Damper setting 6 - minimumTimeBetweenImpulses: 0.00925, - maximumTimeBetweenImpulses: 0.038, - smoothing: 3, - maximumDownwardChange: 0.86, - maximumUpwardChange: 1.13, - flankLength: 9, - numberOfErrorsAllowed: 2, - // naturalDeceleration: -8.5, // perfect runs IIII - naturalDeceleration: -8.6, // perfect runs IIIXI - minimumDriveTime: 0.28, - minimumRecoveryTime: 0.90, - flywheelInertia: 0.189, - dragFactor: 460 - // - - /* Damper setting 4 - minimumTimeBetweenImpulses: 0.00925, - maximumTimeBetweenImpulses: 0.0335, - smoothing: 3, - maximumDownwardChange: 0.890, - maximumUpwardChange: 1.07, - flankLength: 10, - numberOfErrorsAllowed: 2, - naturalDeceleration: -5.5, // perfect runs I - minimumDriveTime: 0.24, - minimumRecoveryTime: 0.90, - flywheelInertia: 0.140, - dragFactor: 255 - */ - - /* Damper setting 2 - minimumTimeBetweenImpulses: 0.00925, - maximumTimeBetweenImpulses: 0.030, - smoothing: 4, - maximumDownwardChange: 0.962, - maximumUpwardChange: 1.07, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.022, + sprocketRadius: 3.0, + autoAdjustDragFactor: true, + minimumDragQuality: 0.83, + dragFactorSmoothing: 3, + flywheelInertia: 0.180, + dragFactor: 225, flankLength: 11, - numberOfErrorsAllowed: 2, - naturalDeceleration: -2.45, // perfect runs - minimumDriveTime: 0.28, - minimumRecoveryTime: 0.90, - flywheelInertia: 0.155, - dragFactor: 155, - magicConstant: 2.8 - */ + minimumStrokeQuality: 0.34, + minumumRecoverySlope: 0.001, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.036, + minumumForceBeforeStroke: 80, + minimumDriveTime: 0.30, + minimumRecoveryTime: 0.90 + }, + + // Sportstech WRX700 + Sportstech_WRX700: { + numOfImpulsesPerRevolution: 2, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.5, + minumumRecoverySlope: 0.125, + flywheelInertia: 0.72, + dragFactor: 32000 } } diff --git a/docs/Architecture.md b/docs/Architecture.md new file mode 100644 index 0000000000..f8dd5c0e7d --- /dev/null +++ b/docs/Architecture.md @@ -0,0 +1,179 @@ +# Open Rowing Monitor architecture + + +In this document, we describe the architectual construction of Open Rowing Monitor. For the reasons behind the physics, please look at [the Physics behind Open Rowing Monitor](Physics_Of_OpenRowingMonitor.md). In this document we describe the main functional blocks in Open Rowing Monitor, and the major design decissions. + +## Platform choice + +We have chosen for Raspberry Pi, instead of Arduino, due to the CPU requirements needed for some machines. The Raspberry Pi can easily be bought by regular users and installation of the OS and applications is pretty straightforward. It also allows for easy connection of hardware through the GPIO interface. + +We have chosen to use Raspian as OS, as it is easily installed by the user, it provides a well maintained platform with many extensions, and it maintains a 64Bit PREEMPT kernel by default. [Ubuntu Core](https://ubuntu.com/core) provides a a leaner 64-bit low-latency kernel and their Snap-based IoT platform is beautiful, but it also requires a much more complex development and deployment toolchain, which would distract from the core application at the moment. + +## Choice for Node.js and JavaScript + +The choice has been made to use JavaScript to build te application, as many of the needed components (like GPIO and Bluetooth Low Energy) components are readily available. The choice for a runtime interpreted language is traditionally at odds with the low latency requirements that is close to physical hardware. The performance of the app depends heavily on the performance of node.js, which itself isn't optimized for low-latency and high frequency environments. However, in practice, we haven't run into any situations where CPU-load has proven to be too much or processing has been frustrated by latency, even when using full Theil-Senn quadratic regression models on larger flanks (which is O(n2)). + +## Main functional components + +We first describe the relation between the main functional components by describing the flow of the key pieces of information: the flywheel and heartrate measurements. We first follow the flow of the flywheel data, which is provided by the interrupt driven `GpioTimerService.js`. The only information retrieved by Open Rowing Monitor is *CurrentDt*: the time between impulses. This data element is transformed in meaningful metrics in the following manner: + +```mermaid +sequenceDiagram + participant clients + participant pigpio + participant GpioTimerService.js + participant server.js + participant RowingStatistics.js + participant Rower.js + participant Flywheel.js + pigpio -)GpioTimerService.js: tick
(interrupt based) + GpioTimerService.js-)server.js: currentDt
(interrupt based) + server.js-)RowingStatistics.js: currentDt
(interrupt based) + RowingStatistics.js->>Rower.js: currentDt
(interrupt based) + Rower.js->>Flywheel.js: currentDt
(interrupt based) + Flywheel.js-->>Rower.js: Angular metrics, Flywheel state
(interrupt based) + Rower.js-->>RowingStatistics.js: Strokes, Linear metrics
(interrupt based) + RowingStatistics.js-)server.js: Metrics Updates
(State/Time based) + server.js-)clients: Metrics Updates
(State/Time based) +``` + +The clients (both the webbased screens and periphal bluetooth devices) are updated based on both a set interval and when the stroke or session state changes. Open Rowing Monitor therefore consists out of two subsystems: an solely interruptdriven part that processes flywheel and heartrate interrupts, and the time/state based needs of the clients. It is the responsibility of `RowingStatistics.js` to manage this: it monitors the timers, session state and guarantees that it can present the clients with the freshest data availble. + +Secondly, the heartrate data follows the same path, but requires significantly less processing: + +```mermaid +sequenceDiagram + participant clients + participant heartrateMonitor + participant server.js + participant RowingStatistics.js + heartrateMonitor-)server.js: heartrate data
(interrupt based) + server.js-)RowingStatistics.js: heartrate data
(interrupt based) + RowingStatistics.js-)server.js: Metrics Updates
(State/Time based) + server.js-)clients: Metrics Updates
(State/Time based) +``` + +### pigpio + +`pigpio` is a wrapper around the [pigpio C library](https://github.com/joan2937/pigpio), which is an extreme high frequency monitor of the pigpio port. As the pigpio npm is just a wrapper around the C library, all time measurement is done by the high cyclic C library, making it extremely accurate. It can be configured to ignore too short pulses (thus providing a basis for debounce) and it reports the `tick` (i.e. the number of microseconds since OS bootup) when it concludes the signal is valid. It reporting is detached from its measurement, and we deliberatly use the *Alert* instead of the *Interrupt* as their documentation indicates that both types of messaging provide an identical accuracy of the `tick`, but *Alerts* do provide the functionality of a debounce filter. As the C-implementation of `pigpio` determines the accuracy of the `tick`, this is the only true time critical element of Open Rowing Monitor. Latency in this process will present itself as noise in the measurements of *CurrentDt*. + +### GpioTimerService.js + +`GpioTimerService.js` is a small independent process, acting as a data handler to the signals from `pigpio`. It translates the *Alerts* with their `tick` into a stream of times between these *Alerts* (which we call *CurrentDt*). The interrupthandler is still triggered to run with extreme low latency as the called `gpio` process will inherit its nice-level, which is extremely time critical. To Open Rowing Monitor it provides a stream of measurements that needed to be handled. + +### Server.js + +`Server.js` orchestrates all information flows and starts/stops processes when needed. It will: + +* Recieve (interrupt based) GPIO timing signals from `GpioTimerService.js` and send them to the `RowingStatistics.js`; +* Recieve (interrupt based) Heartrate measurements and sent them to the `RowingStatistics.js`; +* Recieve the metrics update messages from `RowingStatistics.js` (time-based and state-based updates of metrics) and distribut them to the webclients and blutooth periphials; +* Handle user input (through webinterface and periphials) and instruct `RowingStatistics.js` to act accordingly; +* Handle escalations from `RowingStatistics.js` (like reaching the end of the interval, or seeing the rower has stopped) and instruct the rest of the application, like the `WorkoutRecorder.js` accordingly. + +### RowingStatistics.js + +`RowingStatistics.js` recieves *currentDt* updates, forwards them to `Rower.js` and subsequently inspects `Rower.js` for the resulting strokestate and associated metrics. Based on this inspection, it updates the finite state machine of the sessionstate and the associated metrics (i.e. linear velocity, linear distance, power, etc.). + +#### sessionStates in RowingStatistics.js + +`RowingStatistics.js` maintains the following sessionstates: + +```mermaid +stateDiagram-v2 + [*] --> WaitingForStart + WaitingForStart --> Rowing: strokeState
is 'Drive' + state Rowing { + strokeState=Drive --> strokeState=Recovery + strokeState=Drive --> strokeState=Drive + strokeState=Recovery --> strokeState=Drive + strokeState=Recovery --> strokeState=Recovery + } + Rowing --> Paused: strokeState
is 'WaitingForDrive' + Paused --> Rowing: strokeState
is 'Drive' + Rowing --> Stopped + Stopped --> [*] +``` + +Please note: the 'Stopped' state isn't directly part of the state machine that is defined in `handleRotationImpulse`, it is a direct consequence of emitting the `intervalTargetReached` message to `Server.js`, where `Server.js` concludes there is no next interval left, and thus `stopTraining()` has to be called (which does set the sessionState to 'Stopped'). This is needed as RowingStatistics shouldn't be aware about the existence of next intervals, as it only deals with the current interval. + +#### metrics maintained in RowingStatistics.js + +The goal is to translate the linear rowing metrics into meaningful information for the consumers of data updating both session state and the underlying metrics. As `Rower.js` can only provide a limited set of absolute metrics at a time (as most are stroke state dependent) and is unaware of previous strokes and the context of the interval, `RowingStatistics.js` will consume this data, combine it with other datasources like the heartrate and transform it into a consistent and more stable set of metrics useable for presentation. As `RowingStatistics.js` also is the bridge between the interrupt-driven and time/state driven part of the application, it buffers data as well, providing a complete set of metrics regardless of stroke state. Adittionally, `RowingStatistics.js` also smoothens data across strokes to remove eratic behaviour of metrics due to small measurement errors. + +In a nutshell: + +* `RowingStatistics.js` is the bridge/buffer between the interrupt-drive processing of data and the time/state based reporting of the metrics, +* `RowingStatistics.js` maintains the session state, thus determines whether the rowing machine is 'Rowing', or 'WaitingForDrive', etc., +* `RowingStatistics.js` applies a moving median filter across strokes to make metrics less volatile and thus better suited for presentation, +* `RowingStatistics.js` calculates derived metrics (like Calories) and trands (like Calories per hour), +* `RowingStatistics.js` gaurds interval and session boundaries, and will chop up the metrics-stream accordingly, where Rower.js will just move on without looking at these artifical boundaries. + +In total, this takes full control of the displayed metrics in a specific interval. + +### Rower.js + +`Rower.js` recieves *currentDt* updates, forwards them to `Flywheel.js` and subsequently inspects `Flywheel.js` for the resulting state and angular metrics, transforming it to a strokestate and linear metrics. + +#### strokeStates in Rower.js + +`Rower.js` can have the following strokeStates: + +```mermaid +stateDiagram-v2 + [*] --> WaitingForDrive + WaitingForDrive --> Drive: Flywheel
is powered + Drive --> Recovery: Flywheel
is unpowered + Drive --> Drive: Flywheel
is powered + Recovery --> Drive: Flywheel
is powered + Recovery --> Recovery: Flywheel
is unpowered + Recovery --> WaitingForDrive: Last drive too
long ago + Drive --> Stopped + Recovery --> Stopped + Stopped --> [*] +``` + +Please note: the `Stopped` state is only used for external events (i.e. `RowingStatistics.js` calling the stopMoving() command), which will stop `Rower.js` from processing data. This is a different state than `WaitingForDrive`, which can automatically move into `Drive` by accelerating the flywheel. This is typically used for a forced exact stop of a rowing session (i.e. reaching the end of an interval). + +#### Linear metrics in Rower.js + +`Rower.js` inspects the flywheel behaviour on each impuls and translates the flywheel state into the strokestate (i.e. 'WaitingForDrive', 'Drive', 'Recovery', 'Stopped') through a finite state machine. Based on the angular metrics (i.e.e drag, angular velocity, angular acceleration) it also calculates the updated associated linear metrics (i.e. linear velocity, linear distance, power, etc.). As most metrics can only be calculated at (specific) phase ends, it will only report the metrics it can claculate. Aside temporal metrics (Linear Velocity, Power, etc.) it also maintains several absolute metrics (like total moving time and total linear distance travelled). It only updates metrics that can be updated meaningful, and it will not resend (potentially stale) data that isn't updated. + +### Flywheel.js + +`Flywheel.js` recieves *currentDt* updates and translates that into a state of the flywheel and associated angular metrics. It provides a model of the key parameters of the Flywheel, to provide the rest of OpenRowingMonitor with essential physical metrics and state regarding the flywheel, without the need for considering all kinds of parameterisation. Therefore, `Flywheel.js` will provide all metrics in regular physical quantities, abstracting away from the measurement system and the associated parameters, allowing the rest of OpenRowingMonitor to focus on processing that data. + +It provides the following types of information: + +* the state of the flywheel (i.e. is the flywheel powered, unpowered or even Dwelling) +* temporal metrics (i.e. Angular Velocity, Angular Acceleration, Torque, etc.) +* several absolute metrics (i.e. total elapsed time and total angular distance traveled) +* physical properties of the flywheel, (i.e. the flywheel drag and flywheel inertia) + +## Major design decissions + +### Staying close to *currentDt* + +*currentDt* is defined as the time between impulses, which is the core measurement of any rowing machine. These values tend to range between 0.050 and 0.005 seconds, and are subject to small measurement errors due to vibrations in the rower but also scheduling issues in the Raspberry Pi OS. + +Working with small numbers, and using the impulse time to calculate the angular velocity (i.e. dividing the angular distance travelled through currentDt), or even calculating angular acceleration (i.e. dividing angular velocity through currentDt) tends to enlarge these measurement errors. Therefore, whenever possible, calculations are based on the raw currentDt or Robust Regression methods, rather than numerical derived metrics, to prevent chaotic behaviour of OpenRowingMonitor. + +### Absolute approach in Rower.js + +`Rower.js` could report distance incrementally to `RowingStatistics.js`. However, we chose to report in absolute times and distances, making `Rower.js` in full control of these essential metrics. This way, `Rower.js` can report absolute times and distances, taking full control of the metrics regarding linear movement. This way, these metrics can be calculated temporarily for frequent updates, but calculated definitively when the phase completes. Any derived metrics for specific clients, and smoothing/buffering, is done by `RowingStatistics.js`. + +Adittional benefit of this approach is that it makes transitions in intervals more smooth: `RowingStatistics.js` can intersect stroke without causing any pause in metrics (as RowingEngine.js keeps reporting absolutes, intervals and laps become a view on the same data). + +## Open issues, Known problems and Regrettable design decissions + +### Use of quadratic regression instead of cubic regression + +For the determination of angular velocity and angular acceleration we use quadratic regression over the time versus angular distance function. When using the right algorithm, this has the strong benefit of being robust to noise, at the cost of a O(n2) calculation per new datapoint (where n is the flanklength). Quadratic regression would be fitting if the acceleration would be a constant, as the formulae used would align perfectly with this use. Unfortunatly, the nature of the rowing stroke excludes that assumption as the ideal force curve is a heystack, and thus the force on the flywheel varies in time. As an approximation on a smaller interval, quadratic regression has proven to outperform (i.e. less suspect to noise in the signal) both the numerical approach with noise filtering and the linear regression methods. + +From a pure mathematical perspective, a higher order polynomial would be more appropriate. A cubic regressor, or even better a fourth order polynomal have shown to be better mathematical approximation of the time versus distance function for a Concept2 RowErg. However, there are some current practical objections against using these more complex methods: + +* Higher order polynomials are less stable in nature, and overfitting is a real issue. As this might introduce wild shocks in our metrics, this might be a potential issue for application; +* A key limitation is the available number of datapoints. For the determination of a polynomial of the n-th order, you need at least n+1 datapoints (which in Open Rowing Monitor translates to a `flankLength`). Some rowers, for example the Sportstech WRX700, only deliver 5 to 6 datapoints for the entire drive phase, thus putting explicit limits on the number of datapoints available for such an approximation. +* Calculating a higher order polynomial in a robust way, for example by Theil-Senn regression, is CPU intensive. A quadratic approach requires a O(n2) calculation when a datapoint is added to the flank. Our estimate is that with current known robust polynomial regression methods, a cubic approach requires at least a O(n3) calculation, and a 4th polynomial a O(n4) calculation. With smaller flanks (which determines the n) this has proven to be doable, but for machines which produce a lot of datapoints, and thus have more noise and a typically bigger `flankLength`(like the C2 RowErg and Nordictrack RX-800, both with a 11 `flankLength`), this becomes an issue: we consider completing 103 or even 104 complex calculations within the 5 miliseconds that is available before the next datapoint arrives, impossible. + +This doesn't definitively exclude the use of more complex polynomial regression methods: alternative methods for higher polynomials within a datastream could be as CPU intensive as Theil-Senn Quadratic regression now, and their use could be isolated to specific combination of Raspberry hardware and settings. Thus, this will remain an active area of investigation for future versions. diff --git a/docs/Improving_Raspberry_Performance.md b/docs/Improving_Raspberry_Performance.md new file mode 100644 index 0000000000..363b9e6657 --- /dev/null +++ b/docs/Improving_Raspberry_Performance.md @@ -0,0 +1,77 @@ +# Improving the performance of the Raspberry Pi + +Out of the box, Raspbian is configured to provide a decent experience while conserving energy. However, responding instantly to incoming measurements tends to be so deviating, that we need to do some extra work to get a system working well. + +## Signs your performance is insufficient + +A typical sign is that there is much noise in the data readings from the flywheel, lots of small deviations. This is typically the case when the signals are handled too late. + +## Things you can do at the OS + +Open Rowing Monitor does not exist in isolation, so the first step is to make sure the Operating System (OS) is cut out for the job. + +### Selecting the right kernel + +Normally, a Linux kernel is configured to do non-real-time work, and focusses on doing one task well for a prolonged period of time, reducing overhead. This is great for normal applications that process a lot of data. However, Open Rowing Monitor does not process much data, but does has to respond quickly to incoming signals (especially the impulses from the flywheel). The time it takes to respond to an incoming interrupt is called **latency**. For reducing noise in the readings, it is important that the latency does not vary too much. + +When installing Open Rowing Monitor, please use a low latency or real time kernel. Currently, the Raspbian 64Bit Lite kernel is a Preempt kernel, which aims at low latency. So using this is a great choice for the Operating System. + +### Kernel settings + +Aside from selecting the right OS and kernel, there are some settings that can be set at startup that reduce the latency of the kernel. + +One of these options is to turn off CPU exploit protection. This is a huge security risk as it removes security mitigations in the kernel, but it reduces latency. Given your specific network layout, this could be worth the effort. Add to `/boot/cmdline.txt` the following option, if you consider it responsible in your situation (this introduces a security risk): + +```zsh +mitigations=off +``` + +Another option is to dedicate a CPU to Open Rowing Monitor and run the CPU's in isolation. This avenue isn't explored fully, and the effects on Open Rowing Monitor are unknown, but [this text explains how it should work](https://forums.raspberrypi.com/viewtopic.php?t=228727). + +### CPU Scaling + +Typically, Raspbian is configured to reduce energy consumption, using the *ondemand* CPU governor. For low latency applications, this isn't sufficient. To get the most out of the CPU, we need to use the *performance* governor. + +First, Raspbian will interfere with settings, so we need to kill that functionality: + +```zsh +sudo systemctl disable raspi-config +``` + +Next, we need to istall cpufrequtils to allow control over the CPU governor: + +```zsh +sudo apt-get install cpufrequtils +``` + +Now, you can set the default governor by editing `/etc/default/cpufrequtils` so that it reads: + +```zsh +GOVERNOR="performance" +``` + +After a reboot, you can check the governor by executing: + +```zsh +sudo cpufreq-info +``` + +If all went well, your CPU is now in "Performance" mode. Please note that a Raspberry Pi will run hot and consume a lot more energy. + +### Services you can disable safely + +There are some services running that can be disabled safely. + +#### triggerhappy + +To disable triggerhappy, do the following: + +```zsh +sudo systemctl disable triggerhappy.service +``` + +There are some other services that can be stopped, but where the effects on Open Rowing Monitor are untested, [which can be found here](https://wiki.linuxaudio.org/wiki/raspberrypi). + +## Things you can do in OpenRowingMonitor + +One thing you can do to improve CPU performance is to reduce *flanklength*, which will reduce CPU-load. So running with unneccessary long *flanklength* isn't advised. diff --git a/docs/README.md b/docs/README.md index 7bbb6302ea..6563cf8a79 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,61 +7,71 @@ -A free and open source performance monitor for rowing machines. It upgrades a rowing machine into a smart trainer that can be used with training applications and games. +Open Rowing Monitor is a free and open source performance monitor for rowing machines. It upgrades almost any rowing machine into a smart trainer that can be used with training applications and games. -Open Rowing Monitor is a Node.js application that runs on a Raspberry Pi and measures the rotation of the rower's flywheel (or similar) to calculate rowing specific metrics, such as power, split time, speed, stroke rate, distance and calories. +It is a Node.js application that runs on a Raspberry Pi and measures the rotation of the rower's flywheel (or similar) to calculate rowing specific metrics, such as power, split time, speed, stroke rate, distance and calories. It can share these metrics for controling games and record these metrics for further analysis. -It is currently developed and tested with a Sportstech WRX700 water-rower. But it should run fine with any rowing machine that uses some kind of damping mechanism, as long as you can add something to measure the speed of the flywheel. -It should also work well with DIY rowing machines like the [Openergo](https://openergo.webs.com). +It is currently developed and tested with a Sportstech WRX700 water-rower and a Concept2 air-rower. In the past, it was also tested extensively on a NordicTrack RX-800 hybrid air/magnetic rower. But it should run fine with any rowing machine that uses some kind of damping mechanism, as long as you can add something to measure the speed of the flywheel. It has shown to work well with DIY rowing machines like the [Openergo](https://openergo.webs.com), providing the construction is decent. ## Features -The following items describe most of the current features, more functionality will be added in the future, check the [Development Roadmap](backlog.md) if you are curious. +Open Rowing Monitor aims to provide you with metrics directly, connect to apps and games via bluetooth and allow you to export your data to the analysis tool of your choice. The following items describe most of the current features in more detail. ### Rowing Metrics -Open Rowing Monitor implements a physics model to simulate the typical metrics of a rowing boat based on the pull on the handle. The physics model can be tuned to the specifics of a rower by changing some model parameters. +Open Rowing Monitor implements a physics model to simulate the typical metrics of a rowing boat based on the pull on the handle. The physics model can be tuned to the specifics of a rower by changing some model parameters in the configuration file, where we also provide these settings for machines known to us. -* Stroke detection +Open Rowing Monitor displays the following key metrics on the user interfaces: + +* Distance rowed (meters) +* Training Duration * Power (watts) -* Split time (/500m) -* Strokes per Minute +* Pace (/500m) +* Strokes per Minute (SPM) * Calories used (kcal) -* Training Duration +* Total number of strokes * Heart Rate (supports BLE and ANT+ heart rate monitors, ANT+ requires an ANT+ USB stick) +It calculates and can export many other key rowing metrics, including Drag factor, Drive length (meters), Drive time (milliseconds), Recovery Time (milliseconds), Average handle force (Newton), Peak handle force (Newton) and the associated handle force curve, handle velocity curve and handle power curve. + ### Web Interface -The web interface visualizes the rowing metrics on any device that can run a web browser (i.e. a smartphone that you attach to your rowing machine while training). It uses web sockets to show the rowing status in realtime. It can also be used to reset the training metrics and to select the BLE Rower. +The web interface visualizes the basic rowing metrics on any device that can run a web browser (i.e. a smartphone that you attach to your rowing machine while training). It uses web sockets to show the rowing status in realtime. It can also be used to reset the training metrics and to select the type of bluetooth connection. -If you connect a screen to the Raspberry Pi, then this interface can also be directly shown on the device. The installation script can set up a web browser in kiosk mode that runs on the Raspberry Pi. +If you connect a physical screen directly to the Raspberry Pi, then this interface can also be directly shown on the device. The installation script can set up a web browser in kiosk mode that runs on the Raspberry Pi.
### Bluetooth Low Energy (BLE) -Open Rowing Monitor also implements different Bluetooth Low Energy (BLE) protocols so you can use your rowing machine with different fitness applications. +Open Rowing Monitor also implements different Bluetooth Low Energy (BLE) protocols so you can use your rowing machine with different fitness applications. Some apps use the Fitness Machine Service (FTMS), which is a standardized GATT protocol for different types of fitness machines. Other apps prefer to see a Concept 2 PM5. To help you connect to your app and game of choice, Open Rowing Monitor currently supports the following Bluetooth protocols: -Fitness Machine Service (FTMS) is a standardized GATT protocol for different types of fitness machines. Open Rowing Monitor currently supports the type **FTMS Rower** and simulates the type **FTMS Indoor Bike**. +* **Concept2 PM**: Open Rowing Monitor implements part of the Concept2 PM Bluetooth Smart Communication Interface Definition. This is still work in progress and only implements the most common parts of the spec, so it is not guaranteed to work with all applications that support C2 rowing machines. Our interface currently can only report metrics, but can't recieve commands and session parameters from the app yet. It is known to work with [EXR](https://www.exrgame.com) and all the samples from [The Erg Arcade](https://ergarcade.com), for example you can [row in the clouds](https://ergarcade.github.io/mrdoob-clouds/). -**FTMS Rower:** This is the FTMS profile for rowing machines and supports all rowing specific metrics (such as stroke rate). So far not many training applications for this profile exist, but the market is evolving. I've successfully tested it with [EXR](https://www.exrgame.com), [MyHomeFit](https://myhomefit.de) and [Kinomap](https://www.kinomap.com). +* **FTMS Rower**: This is the FTMS profile for rowing machines and supports all rowing specific metrics (such as stroke rate). So far not many training applications for this profile exist, but the market is evolving. We've successfully tested it with [EXR](https://www.exrgame.com), [MyHomeFit](https://myhomefit.de) and [Kinomap](https://www.kinomap.com). -**FTMS Indoor Bike:** This FTMS profile is used by Smart Bike Trainers and widely adopted by training applications for bike training. It does not support rowing specific metrics. But it can present metrics such as power and distance to the biking application and use cadence for stroke rate. So why not use your virtual rowing bike to row up a mountain in [Zwift](https://www.zwift.com), [Bkool](https://www.bkool.com), [The Sufferfest](https://thesufferfest.com) or similar :-) +* **FTMS Indoor Bike**: This FTMS profile is used by Smart Bike Trainers and widely adopted by training applications for bike training. It does not support rowing specific metrics. But it can present metrics such as power and distance to the biking application and use cadence for stroke rate. So why not use your virtual rowing bike to row up a mountain in [Zwift](https://www.zwift.com), [Bkool](https://www.bkool.com), [The Sufferfest](https://thesufferfest.com) or similar :-) -**Concept2 PM:** Open Rowing Monitor also implements part of the Concept2 PM Bluetooth Smart Communication Interface Definition. This is still work in progress and only implements the most common parts of the spec, so it will not work with all applications that support C2 rowing machines. It currently works with all the samples from [The Erg Arcade](https://ergarcade.com), i.e. you can [row in the clouds](https://ergarcade.github.io/mrdoob-clouds/). This also works very well with [EXR](https://www.exrgame.com). +* **BLE Cycling Power Profile**: This Bluetooth simulates a bike, which allows you to connect the rower to a bike activity on your (mostly Garmin) sportwatch. It will translate the rowing metrics to the appropriate fields. This profile is only supported by specific watches, so it might provide a solution. + +* **BLE Cycling Speed and Cadence Profile**: used for older Garmin Forerunner and Garmin Venu watches and similar types, again simulating a bike activity. Please note to set the wheel circumference to 10mm to make this work well. ### Export of Training Sessions -Open Rowing Monitor can create Training Center XML files (TCX). You can upload these files to training platforms like [Strava](https://www.strava.com), [Garmin Connect](https://connect.garmin.com) or [Trainingpeaks](https://trainingpeaks.com) to track your training sessions. +Open Rowing Monitor is based on the idea that metrics should be easily accessible for further analysis. Therefore, Open Rowing Monitor can create the following files: + +* **Training Center XML files (TCX)**: These are XML-files that contain the most essential metrics of a rowing session. Most training analysis tools will accept a tcx-file. You can upload these files to training platforms like [Strava](https://www.strava.com), [Garmin Connect](https://connect.garmin.com) or [Trainingpeaks](https://trainingpeaks.com) to track your training sessions; -Uploading your sessions to Strava is an integrated feature, for all other platforms this is currently a manual step. The installer can set up a network share that contains all training data so it is easy to grab the files from there and upload them to the training platform of your choice. +* **RowingData** files, which are comma-seperated files with all metrics Open Rowing Monitor can produce. These can be used with [RowingData](https://pypi.org/project/rowingdata/) to display your results locally, or uploaded to [RowsAndAll](https://rowsandall.com/) for a webbased analysis (including dynamic in-stroke metrics). The csv-files can also be processed manually in Excel, allowing your own custom analysis. Please note that for visualising in-stroke metrics in [RowsAndAll](https://rowsandall.com/) (i.e. force, power and handle speed curves), you need their yearly subscription; -Open Rowing Monitor can also store the raw measurements of the flywheel into CSV files. These files are great to start your own exploration of your rowing style and also to learn about the specifics of your rowing machine (some Excel files that can help with this are included in the `docs` folder). +* **Raw flywheel measurements of the flywheel**, also in CSV files. These files are great to start to learn about the specifics of your rowing machine (some Excel visualistion can help with this). + +Uploading your sessions to Strava is an integrated feature, for all other platforms this is currently a manual step. Uploading to [RowsAndAll](https://rowsandall.com/) can be automated through their e-mail interface, see [this description](https://rowsandall.com/rowers/developers/). The Open rowing Monito installer can also set up a network share that contains all training data so it is easy to grab the files from there and manually upload them to the training platform of your choice. ## Installation -You will need a Raspberry Pi Zero W, Raspberry Pi Zero 2 W, Raspberry Pi 3 or a Raspberry Pi 4 with a fresh installation of Raspberry Pi OS Lite for this. Connect to the device with SSH and initiate the following command to install Open Rowing Monitor as an automatically starting system service: +You will need a Raspberry Pi Zero W, Raspberry Pi Zero 2 W, Raspberry Pi 3 or a Raspberry Pi 4 with a fresh installation of Raspberry Pi OS Lite for this (the 64Bit kernel is preferred). Connect to the device with SSH and initiate the following command to install Open Rowing Monitor as an automatically starting system service: ```zsh /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/laberning/openrowingmonitor/HEAD/install/install.sh)" @@ -71,18 +81,16 @@ Also have a look at the [Detailed Installation Instructions](installation.md) fo ## How it all started -I originally started this project, because my rowing machine (Sportstech WRX700) has a very simple computer and I wanted to build something with a clean interface that calculates more realistic metrics. Also, this was a good reason to learn a bit more about Bluetooth and all its specifics. +Lars originally started this project, because his rowing machine (Sportstech WRX700) has a very simple computer and he wanted to build something with a clean interface that calculates more realistic metrics. Also, this was a good reason to learn a bit more about Bluetooth and all its specifics. -The original proof of concept version started as a sketch on an Arduino, but when I started adding things like a web frontend and BLE I moved it to the much more powerful Raspberry Pi. Maybe using a Raspberry Pi for this small IoT-project is a bit of an overkill, but it has the capacity for further features such as syncing training data or rowing games. And it has USB-Ports that I can use to charge my phone while rowing :-) +The original proof of concept version started as a sketch on an Arduino, but the web frontend and BLE needed the much more powerful Raspberry Pi. Maybe using a Raspberry Pi for this small IoT-project is a bit of an overkill, but it has the capacity for further features such as syncing training data or rowing games. And it has USB-Ports that you can use to charge your phone while rowing :-) ## Further information -This project is already in a very usable stage, but some things are still a bit rough on the edges. +This project is already in a very usable stage, but some things are still a bit rough on the edges. More functionality will be added in the future, so check the [Development Roadmap](backlog.md) if you are curious. Contributions are welcome, please read the [Contributing Guidelines](CONTRIBUTING.md) first. Feel free to leave a message in the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) if you have any questions or ideas related to this project. Check the advanced information on the [Physics behind Open Rowing Monitor](physics_openrowingmonitor.md). -I plan to add more features, here is the [Development Roadmap](backlog.md). Contributions are welcome, please read the [Contributing Guidelines](CONTRIBUTING.md) first. - This project uses some great work by others, see the [Attribution here](attribution.md). diff --git a/docs/Rowing_Settings_Analysis_Small.xlsx b/docs/Rowing_Settings_Analysis_Small.xlsx deleted file mode 100644 index c932151de56ee583f1f7cd44867bf7fd0a8d26bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 129305 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%0AV?GV$AIrr ze>Q*yDo_8ZiiB1L{;O(5&v}WGyx*|p8)VA7zC&*pmc)I*7Nc*O0l7xHiAE4W@hJB< z2OHJi2ue_2p!A1kSoCz}srs5J4HSJae#VDfE`IcX^}Hk`Sv$V|=Ka=tfrZ#JoSY_6 zjV5udujjV}q}?x-&t<=dEL!)oq3x`|fQb={S#M_RcG^$9i*JudHl7UBy;>WYZgxpL zfY|(nscK995&R8-AO9d7g|4(lK|?ZcnHej;0CUNaHIB}_Ygc~_qo;Fz221dODhb2H zUsI|b{FM}WwrWTM%^`4$MZ5cqrZWmn0J&-t<3%&$&~T?ofU(xUEn1UT1hG8i-hT_5 zL#9oFrsSzf2DYmti+yuQ;3$#QqSR!b*VTe*mDvHB+F|RPh>o0WbP>Xd$$xPJq${cn z%_&K4KS5%Dsg0o53>v1E#JFV$s-WtTVo@xvLVS}x0H}gSJhS~UGjp~m#p#&HZtF`BQvqWph4OE5RJfn zklpDelus|qSlH-VKo2SKCvfMd-Oq|zXJ?2scC&$d*fBkn|kt!5yFK0B=txNW3 zLX*u=OXBr%^Yu%z$sKf$#`K$(i zpLf5Q*Mh=hnZUvr&+=BO={_=?U-1)W>nF@`F@GtM`fel@`VP*(Q>OH~(wE$@kz8Qs zo%aOI4boxXe&*SAUXXbS*+I#oa?_*21=a2~sCJ{QWOUTY`1LkRvB~bcvtAv|#4VXO z2}hSTEQ=rha4e-nk3UoLvyt)3jtqn=?BM+GD$JNz`xlks{gzAs9z|NRwsWuy;zo&u zmHyL%j$tq-|6bNQ-Lg@UW9dV3;h8LW0F-Q;EzR;J?7y0|P01ak3(qz^}^dKVrL@4Jo0`~7-Bh#RM4%Y6g1 zQ>7!h8#bX@`+$ei%LBa>K_2MeZFxDf6zt&%Nd%Da0c~{RRr-S9)Yl_Sd{qK7aYcDh zg6W*d=s*bu?G*d3(@Y4|)N5|X6B@5M^KHPUvXq~Cf9}&6X9kZfz^xGuCr+@$wkW$3 z6jnO3=Vzj`?_z~2%t614!p*-c9m}Pen{;VmD#H#n|M(}&1gY1x>*zR1O^oN^y@m@n zKFbI|UUNf~uiI^`C1h7l{MT44szp}?jb4t<@c1W-i{d@>34*fbijSeQ)7tay>WT;9 z7hjXB_`=)rKV5~yj&rGN}!mu1i zu=)Tit_1{7IUCHjGSM44bX4r$-BI%d&u_>NTRwTTmlDkaDx8Yepk>wk(6Vc2nei&L<;Qe|G8*V( zE(7~-Ko|R@g}$NnmQKWOPCbvC^K!PmXLwv+VabAhv)N(j7zi52MR`ip+P5YSr$mVB zIn+`<&aDGm-}(4buU4AFU=W4RvgYk0#)r4HSGd8PeEBmL3=@NkmTDI-cYtf_s-YkY zIpIa$UX*0GHxY>*dIej1@6a}Utr>Aekoe6zrVzMhbk&AQieAH(f$jx*EKPg~=tw=t zQMIcE5Tq5trepV6k@HxecM)aYepAg*+^O6%P7bIs$Mhib4rj48=m#)11W_;R{0b3 z3_eN8xvDTNcN&dHuLlu`^EtM>)iuPJ2aUuvxE6M-<5=HbQoh^2NM)+%6B5$PqbPx? z&ou5H!?KS3eCUGcBX-u0 z!f-aR=?$G)nK{Mdwn+o&x$K%58JP`0UD%GR^YlMDFF!ZxeqN9c;%Q$~I0fAq_+Q13U#1Hdj$@4&y! zXShrP`X5;u$U)s=wwlN)e4h;b3Rb&tS?jvHG&7{K(6zOwZQmP-1;~7l{Giy&Zk<|d z)$KJkrCg)!G?5I>O>f=eNW@K-anT=O4_AZRg={e1W?Bh~8c4&Yq22g?R95Q!zh>@8 z!sLt>rM?chKe!EE*;Z5J*MIN8RBk^DhDn`fSPjlSs}Yfguqe@mKr4QSjL@cJ_z+T9 zh&qj?wzglekIHr?cc>MsX$qQkDKs}$up9g33i44V9qy38zUMuIV7qpJOv7yb5spg< zf73c?;+KwYtv)`oo!UO9L;odZ7=ih^y3;*+{|78x{DcA;^lk|TOLk#jbd~Hu&qndL zDeU(~Q5vt87qzgLVdzjFApc=@TJ_a-BEFzqw7Zv$AR5P6$7js-6VV^P!x#%tQKE-` zL&1hml`Lz7DTY(kFgksVx=^pLb-X`}W6}_`bhcL@ae`($BTH348KU+II+-};^#Uk$ zRbTc0!X{<#p#;CC+OPKyn++pfIWQpT!?!aWevc@|0C(ISw26aU_WCb`@5SY>&XIW( ztYQT#H@kX~Gx`9qK|IXYvzBJPF=^?{4o)d84VM1Ok;`vZ!&4;W6i?k@p}kb+?HgZ! zosPa%;-za*T4>8M~TfRC#pu9pVsC$@dUakSIr(+MbxB&6cA& z7Q!r&3*-6D+(Uw)vZ2weDY+@b3&Ds=PHpN34mx)i`!7unJ93+#_O2#nuQrgzzfd>Ux-AZgfn=sUUn_OXdCQlK(VZR z*FTAUg4Z7D4uj?RZcX9VWwG;w@r`qNCDrFPIcDbk8rtw&YD^Da;~cx(m*?vSz@$R} z0=k@v!LHlz?KP2?;b-5UG&r@KJLUU!H3!zg8}E}57-ML+ z&y9%XTKJqc^AX>7c2mb5-|3?4zic?RXts6H$r;YjYQuLqO9 zP^g5&0%}A90&_pszaiR++)7VsP+ZM^gljD3Ss%!KR2P-{Glt^R^b@*12I#_l1{q*1 z>4*NQiqX5^2;BBaDZwms+fKetQ~2^LwGr&tNHp^m0HGIW91k;~~@6pI@=+xebz z69t6w0kXVEif)+Tp)<(J&9yj+)fU645i@In(>X2N;r@}Lu>#JtqET*@c3UqnyWLMW zhlq6Yxtf+@jLe^sYI*N=uy2Y>AQQ8DMRTzgLpum{yK*))BD)^{fC#0v&y;hXwvQ%9AWJ$dk&*Y z9&m&PmGiW9Ox<2cvCue?n;t41X$~VE(<(x256AjczS%{I9V^N((p=3cKW=NT)IItr z9hsBnp?#M95_#%W{l@?KYdX7-S56y^UeL*SzLXH-@uG8t=4`4NJ( zwO9c#Z{q_Ih$A(fQD%*vm<2PHSyAmr^=c+jn*p7@BkRLt8;+ui=h@Vwxj_;-vL7Z- zZ1nDZM-R^6$pBOUb<$B~B1K_Dfh`b$v0X8kwH4+>rQ__BUy`;%S61-w*F%$;Ajgb> zL{FCPygro7-}=af!!0-$#Gr$p-UU}&I?Rel`REuaYb3^WJ}G`5bOStTm9Qsp2$|0c zcN!u--0THn(JJ3QGC=po!=IQ)Au5m+m|7r~nn5EYQ`WnwHoHl{|8)zY<~H_D8n=d{ zy8`H|IV_tS9rU`269SspS9vwiVd|t8%bj__5{+G9Ii>~Eah5kY{4N;T#t}OQ{u-;{ zUEIUz?^g|SPnCK}SYmo{rMS?Rjr{nj6d^FdyKX@|ZSWNZtR!R@GmIuq^T`2b?=@6L z9om$k8k+V`Lup9&8)W|eFrPT;z?!J&*C z+Lu#QxIt$Y36Pmec9VW++Es%}4A8SuMwG*#3llQYokP3?vcuRDjz?hc}8l;Qhs z#~Hy?jxu&S(1y0%nrWI)V3*4K7v8A<8;VaS3CwKiK>|C~N|M}avKj<Zzq~5dy5Zqqi4^a!9DTI5g07F*G(uL=0YzBvD`H^4be)$)4&S;5S#&2O*t>g95SS3^sTrO~ z2Bc*)w!jA%2NwkByus8+qRQttjoEmMb>0=_5)}j#&r4Vg7fI0pf zyorNY1`iD$^kwkBwG*Ks2Z`$ESC3|x;7M34N8gU?E<>sJVlnQ)@r~8jlOR>i{$poI z?y!A??oFZL>BIvPs*;c8ok}D=`A}TkLTdKokmHVp({Vu8|UZ$(}FvAu@R2Y;B66*YsqlT9Dup~^_UU3g{~=? zX;g7WQRcRSjyw^#y%7vVROgQ%g-RLF>$3w|#Gh47DPSufqeD0gqixcfI*A~+r#!LF z***@AUIl#H*M@or&zH0MRTRlXsc_XlkE`)ZITFesT2}?H4djx2DPoh0;BL_6!fyyL zFN3LYk!P-;OaEFtSwIb$|K6R^0|CiaCuz*Co9pTc4Cgm@%As&oaI-|O-V96OK>-@$ zaz9st@mUc1&W9`x>9a0a2lHNT?!}bz7tN7h5J0fSe?6h*I z6*>DMisMT!LcUOic-R)}1Gx}Vq3j&3vbxclysY7yB8VJ$`Z63gscQwftB(3-%7vKF3y%?8e3guRz(~Q z<8t_9qonipQAiR?dmQmY?}@m{2QygE1nBiSrW=v~1IOd@;fc!E3T9h0rFk4Q4#~S) zQS)0YgTpB0AT&zore(3M^lxKH{MYQ+h?B6kr-S+zo%h%+5|iwI~e-WLMIRS!|a<|ECmi2Lp zTca(ekttcLtWY0;jb(U-26oWH6yLj$eP2AQbW7t9QO86=rdpx)I6ZjKKD~5W3KNrV zL|Sk)T=}dE+5`$r>ZR5MJ&avmcV7ST2i5HJ9E^X68F7#VmRsQ@@N%@U(Y0=DMODSGQA3 zErvD}UtDFYP=2k(dZ;=3NKF+iFh@YRb?z|Wf@Ppp9Ye9tVRU>@7rEPNW*~bFlCKWs$p$}8|_S1ZF-M{{6M*eK* z)DP|*4u~fG8YxOf+f>M#Za!YtM(~UZ;2HlUqM601B_6zigKA#3X_T-6Ke!j-9`$QP zIaP&Pw-7!{#jm^(n3s%@&GNog=moo=Mbqu$gW-vh}Q^Huh zbbRrYlYh#`)tqpl;tyTicQt@zl=lk|^Ljoi zmh%k4m}%o?@YFs@dn;-ukK@F>iNf3e{rY67q(3DGY_TdaCe~+BDwQ0x&?g?=OBqF3 ziU}7gU9!wW0CyCno0&KP7DB`A|AKNs&1S*B|Mu3xjDX*M8*V(07OKOx&f|RJus@DG zetSh3DMi`S^h~q9*k|bp8&)G6sPCp-G)SF9gh=42f`YnV@f$i6#b*h~Zx(@U=7-M^ zq||QqY>&&TawGKboZeVBdsB*{Y-}`dpDfsqrFI~;bJlRY#c8(r_3GJ2Nn2M(W?_j@ z4RwLUC0=XY12hf0lJE^&#MTA6A6?8k2ke9ZaCE2jgB}idy?E8>-leqL*$>pAl8m0u zm=eG2>F)G#LptoTx!gFg27#VOZ?Kl%UI>B5=UG3`3y|JV&U$2-d)_a_i;`8J?gf9u zF9CBEMG#@^maonqVTo%v@jxXQy1XCT;}9cBe#9qSa*55*mWs-@LfaSyCLFJwN02}m zl42eRGWlP&k1M(EOj*4#=?T9>wD3{uS?2w(mRgR~mmY3klSzf#+59~Zjz+T8wG!7A zlIL8c?^3R-csQ{wlyA=Jd$XuwmKHyku5Rq2Z=oT4`+~B2HMA-3dO|ixRo_ys&8>bFZv-zN@dv`ju|I>CYBuTJs_{oy-s+xbxIT(XH*@thYQE8WC62T4 zsQBN9ao(=_#7OBEr^0?j3$Gf16L0sI+G&waJlx$hi+$s9wKQyUoK+A?w6Ie&2L3Qx zwE6U4brf>VlHFB$dGPahjp)_y;Bz+nZBgN-`VGDHv0nRhA79t~#&^wEaxJGlEuJ%} zU^77<+Hp^h$Qn{Z*-5>yV~-}MwVc#RK+cGMcnJx9;h;sD0Yv6X4`FzrJqFSP%^sre zR$B76<+27WvkbKzTJs>}l%4tu6ME?(nF|(y{xzL16YzEyvWGp>=exHjFVqlTEnlf6 zz)@i70|bSb>1Jg8D@LJAHr{NH9D~ve_~FecVN(AmSW)oP&>D3vm)Q@0tRZfzZvfa2 zbE{%`kUe^{AN%(3EJEAoTPz_u;QoRlBk8g$m7As#;!GHbePsMLiV9)_ zP(a~u{1Ds~aOmMMS^t^PT7SoT!Z3Qno`SklpC)P)HzboLN`xOJEi7mZ7rCd^=lydd z*_UHQw6#Kvt=)xkSMk}X;?ysV9;^BF%O}_rUQQ&61Qf-j&%kii*ECfrF71n81M7FcvXeCu^|_6LIKo(^32bNZ;=N~r}%Rtwzv~o2j(rX ztJV6Rx2)|tw{a41CCsx{Q9q zp-ky}9(syw3S4`_zDbbqp8V>%(>qn?!9gThn&d{tjv$%d$ zfTySJnxWU&{8duKH-?sY-rFZzlCpxTt&**Gd@` z?4GFGd#D{no$3f4V0^c7E5aRTM>_C>Aey_!V`5+NtIsY%`Pwrst<4NiwMZSL3?Apw zgdul!VrnI%P6+2rDCTsd0|?DhBYLC&+u5?vfQJ4mH28}_|C`KM6j!v4GMj32`@$z4 zv<7l5d@9dYkMX`NdLZpH>SIiUukt8_+msd~s8}UzTT#K}R@~-JcSR0KTv4d{26)p= z0~l&5KXu!GZA4op^yf!eRscqmvH)Q;RZ+T8Nr2IBKgS?*mAivm!8b%bb3s#>VAXnWXCRgC<_8LY#P|yQ8Rmjz$`|Gz_IHA^d%bR+@LrB( z6Qa0ZNjPCesH6P62(P(k&~EhzsrjgnJM}?wBpChsc8Lq6f=S(^eIb}dYco|5YA9yY z+85P*2i0*^5oa9nb2@3q+@WFSKP1`|bv|jo z8rgd4?%_S|3wxL4eAXVI@+&4=u9<Eh-7&$2xin8@U7fuB4 zcIrn8G;u4&Z_`lJSr3a2oD!ExfhAju5e*;s%wV6*sp1}{I?CzgCvv2Zc=Z6();RE< z6eFNYdjfZCc-z@IRC-DkZRC_#@ql18)?eTnDh|_q;(R4hio%peg&f;rpE+G1wn^Fd zyD0s;G`B-N8cmk%Y|XCDZa>|_R5tdp%^&!2W9T!)B$k`C%ZL7_Xv?-Y^r}7A zt@8yu5CFr#3;*Ew@*$zvPaGU-E1_i60CrK~m6SKT0tBSRw`w`rKPj7heZ+2V@HO%Q z)AsFJgw};U;74Effjyx?+!c}9qKNkb|B?6Sdi-d$8zZD7oj)dVT`}V1&P)xCZ(!u# zaxz~?K4hSu!HY5(VRw{{>7IP^;CC{O z{3uz(8BUl6LJw9E!zqEE(-kf?$?K1GSAD0%%8Y#LTnX6P64agP+;pxek_0z9)Y0?N z9Rwbuakh(wEe%roZy`z;Cd!XWlgthaSpowbDIrxLOu#wfDvU}-4n~aF#tWbtXWjJt ztwe9IVKUC@j3x=Ty6WhEh80Axe}Rm8hdk|&LIG_g%z5pGkOIAdCGGP#MEQj!UIS>g zc!;6KmtqtkKb}D8zKvj8C4D`@@sgXvG3K5&$X$FA>o z>-?NSvTl8`fj6fiyx>tZKKmS-KaG{BGg{hCfS1dJ$hhxPO>Xjeu3QVcD_WeITe4iL z|L{Y{?8(h^#Y$iJ4ITME%lX?Rh;8zQxm?RW&+&w+g^(FHY^2&5jjC^UeBL%w4%Bm< zljI`o*FxBQivJMP!qfI^6U3? zzM?5efkvlrR6~tWLS2b!k-s?(8g0<_7~?JHm%~~w^mxuM*I3`jyVcMXsSUo;wSDvP zN0sg%K1PiL`w-d0E5E1EYJmr*C^Y1vO(A!_NG86*PDnY+g*Q*I1{*C6-pD(*7kC^& z=X@=}#=Z(~mhTu*yZM;d;H!Siivs`Nn|uaNTi$uc+s}Xs#_Ikw++fNIE#2qX)<3|4 z+QeOVCrokq?V)s>-;{l^uTRy28l60y8`ZqSmYEgG~u@1K8gvjyY6tZkxYX>)O}kMGA%QFJA1VDfp(FuV^Ufv!c*vx%s+ zyg0a6Jtk-8C$x`h)O)1huKx=kCNGfMyasRT8fOm;8=Un?kI0Ag)4S_uld<39_NzO` zkhLpG^E}0~pndD_b^3^wl1--}Ii5{Vf!%cK5=33;wYS%fh`K>vuL(6;d2QksypWF@hjn)9iOLAo}9F=-X9??FJjJCSIODys`y7*iM^^;Qbw9UQk~=LhS$ z>5Z+F7rWbuCvV7_@aSdMV!5X^YFJBfC=w0`dwu+5v{Y!{S3zu#E?Z}g$antE$|Tso zB!pl!3wgC!I5DOO9O9WZY`NmQZ%Vuh3oUeT-fYLlf`UI8GEA7>>+*K`h0IEzepDmK z%Hl{a@qYiWsc$}>h-dHr`Z*j%y+~7 zBU;3P>-Lv!-W;}9SY#iyC4+2`PA?1y-gVbAQElYmCzNaS*i9n92cNFCC*$3ocUe~n z$%Hwx&C$Py@(`wd_4o)OfxHOR*ZXS71ujl?-+h77{!P6vZ{JSfu~9i8XGPx5%1~Ia*DDq9 zZLl`a_;=?!Y<>zK&rUeesjXiD{cTZRw&0FVZbAxH?m+EMb5=qvR`6o64(wFR z&ACIO)SzdqToifrKy7O*`RP4EU;bqbS-C)EQJt@JpgZ_%>~7+xWAlpY04AAdC&m+; zhFVAGnG1D1j;c8gqhFB%nGZ*1e%9e{rv!mm=u`8Nkq7;aoCyr@i1yZTM5oJznJ_!Pc6KupbedHoxFl>Fd}B&LDUD{*__*}+R{KXxlMfGhKg|z{h;!TTGNZYk zj4|THPd(5qocN_xw~iI))$K%MN@hQvP=2&^sD3cBX~~s5;aqr&neJ#t%P>Yu7L$Or z-^Sej)qJsJ#Q@#TtS1X}r`?X}H@}aDScB~t3$@yeopqp#4BxM6Mpaq$hTj$8a!QkG zvZpMu?RH)=g1^!A^){pQ19VLvmsqE5l#ZYdlLaG20vQerCfXddfyD8} zO?Kr@&c$cn5)xpv*;Nvq=8J|Us`>3M4n(YmHcZe9jGjZb0`Qf-9m^6H z4i4vxTvT%P2SNdkhau_qUs`97XQhfjortH>ae$^Nk1-0E+Y3Vc(R_7=HS z>KpG`epgOrcMzB_+DF1l-KKJlHx)g!thkfz<13t0jvyo8{S7Ha<1I^86W^2QB%rd> za<$-~RHz;KQY;Zqphr=~>o8)a(y$M0mo6MTkqagmkkk_HGhS-OS4E^PemnBDCl81q zvhvJ6cJc;+NMxlc4+{a6+$15}kf@jOby3iY*bZcOXRrWqG-aJ1<6|~YJ;%)Jm(m+^ zgpcms(wkMLg$BZgxC=!bhjuk<8_X(R&L%H0Ulc2zxb*w7X?MWo>8P&ne>P8Q%&}C< z(ll50G@>@1N(*FD(>#<3$15(^tXaxY=F>Li*3)+}i>*qZHebA7=VqoXV9GsmA3r5f z8&OQ^LebThgdNFOBP<+sqGJM&u>QfF^X!;K|SJtj&HwVL)5WJ<4+ygKphj_!sbZ>^?l0Z?H7fyP#bI)7BdsSC zEM-p}4P?EE;BgZ+O2%R24BHW~(zuB~1vf$zJS9+G#wOH~A6tt47jEj8BSs&nGyUJk zR#fa1;va1!coL+^X+%Q5-5{{5;(7K(!9zn=9ZL%RS0wHivQN$N9D#-GuUMeySn)rq zssiZ)iP3-c&wlBBxXslPHwoJAOmCE)RRHR6+-Mdpko@;#rGo>|v~5+`r;{&A-ldA= z9hEsd?eK!JckveP{q=-wsjx|S!GSkV;_RreopS9;LF#0Tn>wzmu8V>Dq1M-RqTE7) zeiD2oK0)0>c5Ss^E}#$qfVo@XTN)q@ZhzD8yPmbaeZ^Bey08(8V1P~?w>w~goWamZ zHJE4^HBcsdDhcv(v3;e0jV{l8ad<@wk+jR=O?*Ul{j7Nyyp&J0Rjm-6zmi{^@Cg>) zsXG4(ox_&F+p)TUn^hp&!L6DREgj;`CX`a_839_EO$TdCP4+e0R}yV|xRY-6j=J$y zd9-C7c3@VjYLx>IKx!)YAEeGb@t)F57k&7_rixHGDK0EomFQLi1pL)}`8wc$JB5FG zr!5I$B`dbL9SO?~uDXY4Nto6MiDx(}mS5GEF+_sN)JN$%z7fDXMnRFWu>9-++zKNR zWouH6gnk7Fm7ljtgn$T4RrTw`Id&rnYKqLF$&?jNyachEwbarv-ckkT+E#g6e=)F1JQ>1+o1>3IL z=2bed_sFeKXW})TeZFX?)KBNi!yi~UVzjAz@`0?XEKu7u{NSd?VcC7!k-BwN_Foq(X^b6f&rpjRzwFpFhgcc0N{Bx=K;wG{2Bdo!CZn`W7rf&%s%sM$l%IUD+7-%tI(h>mtP0iZz zsc#3;i)0ubF9_0Ht!3TVX0SNuavcDaFTEDU(T3GPaXj@x^OgROD{0#Qy^@^a48Eo( z>qsLp$i$(Fb*z<~K*gZb){+nctFVjgw#(Ld*s(%Tq7ST_&Qxx^t=PqQFcQ}!40KYW%s zG+^_}IA2oPsDM}LE20F=0~8kYfcx42Q&x2U&YsLx@R)e1T95!uJ=nm1`;glL!D>r% zRZ%^2T(jA|QuAKF`IA4uR;h9lcJyi=?VQ30s3ety#}KL)Duz@&&JF3d^}~Wd$*NP= zpN&Tmw;3pWvaMvA4@cXC=%7109}(*CZ1KmNYNN0U2jNm?aBE?erVD80K$ncb5j|jl zt);2(l|3}1N0D;cEsA_F_J(x$`m)WGk5o_NQ3^zQah*a{JF1%@B{i#uzS<#cr_lMJ z+n9d?*ApSWYk96J$Iw~LlRqKgW?A)e@CQmo*9T$-CL5}79E+a4BK<=Z>;f~w^$V+9 z5pgWupB)ZD3*={DyUaQprXo~5HjB6b!nz`W7!6;#p5aGp@)H4;wrYUhmbL>zlHTbEGRk) zFIl@EYxq!Pm@wWVrYPLbiwJ(%w~eiCodmJK`%9S=1r|Qoyv})-Ga_-(Un)40e^3;B zE_sIXQ=zo|*%y!Jn4ZsngI{h`togQ*_T5IwOxfc(C}2t2ck}s;>@}PA7y><^&*(y* z$ws4+iJ0=VmTjJ6nKR{4nQ8NBixvN6`IrhqWhIZYw^5Z|BEKNRSoKZAEUXGu9SJ+k zLYrfgD+E+$-vxkD&*)^l+A~1-kkky|0wgdAL{c-5nvNpye67xVJE!p#0UQIwVGN4P z>2LK5lLK6gn?VK%y*&WSMXmf+nG%?_t(-|albisXJx)Xt;m`Ati91HXv7CwgaV&+~ z&W%PlQuq-=W7rDjH=*2)8lc$x9MMHofSRRe|6@I&6zF2BDNCvpgVwb`* zc5VYabqVoQMLk#{Jrw0+}|r( z|6a-E5tk5GvE$&#I=+VKDfnA;1_tD7I)4}AE=iz%W9p!j^58uGkNN!1B^+;>hpjpE zSjXfJWxVjU1S{-jlT%=mQ~4h~WX*n8rcV>FzBUU^{xO#i7;S-h#>&=6YXCMh$^U)Q zvh;_Ilesw$LpWnr;h$;vLm$NT79vF~8< zHbct=CSYC!X}*w1Xdhk1&c--1!cp<`zu|#+5zcR1NMcQManEVENG@XXKrF?)Di{V~ z;gDeg#%BK{o_?g*4XC8^A-XIz5wdB6g~jU*HG+e$VG25D3o0YbFYUM4~o2UPNn1RTuqy4kfkK#m>FwWLgkY-baXr#R_^u%+CgQ%iFza9O6u4{o_b z{}?MA0J*e4V)vg8g+KS?YFy3dtOo(yC}tD?G8MvC^{3_+;T<7bSWsDfkFm50z`(PKp7#go znm@wevN^=swTdTi1f8XWCc_x)vkBaxt}4b;bJE@a#G3XE$&^UE&m@MOBJmEAVx9nyZVZel$N*cb?f!Gew}fLclEB5hfTeTAeDUAsHBu`Nrt<$tMS@Ha2{O3sp$tJ3 zyst=m_Xo04q4tYE2LQ;-7e8sZRqwc%TjkM$b}1HgW`@gNk{biEbB6|jf3Ly#_$v;` zJ>l>_M`!q2%UPWDH}%a;!=D9}t3r||QuA*ibjrc}PrrJ>`#!>Dg-iSB_^{{eIkVDx z=iVVwk6;hbS6~Ey%l;VwNX@KykhRCFv0|lGtA_U>#B!&Ua|oQjHn2f(7|U@809R01 zlkyh;uDdw&N};Hh6SJ1Ham)-`-!3~tP}yh62G~@0GoJhkh9?(;pt<3F4-roWl7=YM zF_b0H9I3(Jsr0)xPFU|j^)not%^AA`CP%W62{5%s!ve7e9|I=%07Ja~|C@dwPlC#} z{B*fH76`uypwi)c7hz06^5YWx|F#{-CZd;}Waa+nBJBdI;2dRJq^;+yu>0)bZm#vP zX&8CzECB> z`3=xbS|s@CAfKFIs9KT?tK;N80!J6b1_`ar|0kbAEXc+a;h=+p7!b}l1(Evy#L#2& zwgS;6*_O@&blDDw=CcD}s(e0`tgaW-d}iuj3O|Y2>Ayx+b+NY4X7Y2kWdn0 zyaZ%XM*Zz?5Bvpzhv@i!-uzcN00Or=N1V;05MZ&ET^Kmf!nqMHsC;=J$$>N8w7qjCRXiLl$B3p92~Ezl3+bdLeomp<9R=Xt*HT{|P|gpY8{H1aRS>VHsIhhrf-Ws5o8|405{lWjO`L~&8Qsb-Fdo=lw03AY}n*V@NCmk>fl^L~N z*2_qMQLwxC!zib+@rVErVpS|SOm*(?--rS+@BJJAHV3hRnEhZ`k+1OQxjcWKi#XE~ z5ggR~@0EFH9EUTBG$7PXf#eo&dOm1-YQAqMNPVI!lipb*ft$J2W8dcnaM|-ZADW!C z0g6AAisWcX(RdcX`UMi*+OJoL`mdi~5~)ny2>qT&Fr*t+DCr!LL2C#2c=CPS52120Foi zc>BNnCzA|U=;zXC6coi*H~yzzE#yM{YGF~Tz4J`h$J}}SZ$6lbWo6Yyd<0n6pD8Vk zCmttiJym49~6|>$6e$Hl4q1 z_V)I;xVXA~y}#S3uJ7mj)$2N7``~oAu)g3-J$-)OkAGR-_ZBKSS^w&;wmu=mON zS_7N>#l!dR>2son*UeWh*Zbo;mg%AzBJln5&g+x&!FgYglM7CfCHv!ac)IUCwdc{& ze(?CV@5SEE$(4Qj-Q&^{pXp@EA{6f-Q$eK5db)|!@de%4D)Sq3aHeSMmy;2OrHrtnHJ9*9L8^*Vj z3Ix0kj|9`juD7n>)cWtQE^pGV%u`Wa1zhdmkr(WciZ)+69WRYHUqlRtt%!K-PG6MD z-x0mug)a}o;lsJS=J6p%m%+K<=L)ZIg+Up9FK%os?x%12U2JscUgP^7@9r*M&-m<4 zH=nx%cT8}eUGSQpCdciUz=kNvI>4%UMGX66(}__QboNNF#(sC^si z&(BaR7ZdbGD1A1AgXK?dT^xrG9v@VpYRz45UZ1`{r%v;QHFFamPSll1ofA`ET@gy{ z`%zyxtq%&{E7%V83rbrKv@R_6m3}gR=Njj7Y7}>|vVJv&D30(P5%p)8EIgVZyl{T+JevlKLi*gIFSOM0iW) zL>v9iXP4VV^%k&0oQPgVmO3AkQ9q(b84#+vOd~sI?TRSP_#IzUbq*h8ldilIOecL& z8JZjiaf9Vn_R^_8kG7j!(X#l#mOOI{5@Z_P_}xT@r*4(5Yn*@mai)7NB#F_thlygt zqc+rKf3d_dM6~JhGMx(EJl9xTcYWY;d~!bTqwjaTNke&d&=p?n{@K-a2uGC@{1T8{ zF!k#@s0luI$Q|z_w^12QhtJ&A-hOWFJ<7*hXK2$9Eqt(1(^j%banWzTe=e$fxj5So za&~<1jw!yh`8>DK&uLlo`s9Gke&*D4e=t4mYPDSCdMo|<@@%zkrbwi@$cMADU#}`@0WCXfga&&*IqzHwGJi zdb3^BdF8)zZ(Dm;J@owzEbgLnnWRam^m%T-a>X(A^6k@&%jMZS<~p$B{w*JIhne%u zKJ9$G={libRx?#A4`!6;evHRoPvlAo{HE8gwbh$nnvUaH7??9cce#7F$MyW@&vVhM zo95S0eo;Ze8_!ocyp-*WSF31P|?Yn~LX!Iu?*(Sh|H(z+c@_vC_nrh|sJlTinjeU@XQ9IB;j z>{+L83_NU^e55OPjpMeuoks2#B=2+u_3^>aLvydhE;h%~$356xi|^{CaU-v{%dhtp zS`kxPIHK1!)IsfKvsb2LNL5cT!OLGm;}&Q0num4i@$m<%XzrrA+y}7 z;mhgmyphh)e@D-XScBrDbFLpoK`_@#c($E)k_9uJJVSf+=W>SIt}+Zwrza-fKIC?^ zj^rdLl!K+Yx7PE7M9aLd8txhM1!F#|y@*VwmQH=Pxv|D3-7an^m>(_8*wiJI-yOM~ zGvP_B6);k=5j1s3QhOk}@tfMMKj_!WN6MNHRUaa~*%&&=%0Y-GAjIyYhbzR!xRc9w zZ%sO~rVpR?pY*TB#0&~N5PWzFx;&H6#HWemBjL29$<}Aej*hyO+ovqF=N+b&GHv|5 zolHS`zIWxlzb;wa7!pBy5m1zCd>?P#j;d@WY4LtKYvp|Vk$>O(2?SDGATNRnDUPY@ zG3K!~H2ZvyUrWiHyRZE111=mfoBj2GuF^^}i|_{_m6mk?mHheNc+b_0Xji#cDphyAoi&QT<$RZi1Ucb?BEl@P{= z$kY&`RRk@k3Q@^Rq}&#Ae7N%PbOQATPgQb#ldz6~+6EyVk0tF6dx8&%#u#R!ZQdjI z@Sgl01GxujVlodfH26PUd@4}#pa{wRPN^6&0QmcMf3^K^;a zEdLT;A8|VTNU?>X-1+#a_vmMA=*{<1+Rr?g*{k$d-p?&(9WQ3>j;!qrUG!m6N8Q0y z?DO*Bkh7h=<0{zWE>jcJJI$LtabP>aW#`pKNmK3dJIO;n?3&@uW-`wn9{Foxp10VC zuW1&WMp}Ja6!|8*mIg*l^PgId_vFgD^?ul5c#t?l9iu|Cm{J|4luyYrNt^p!51mIRBZ@nY z-_5=eRV+t~SS`uE+Va@8e>{Bes&U3+p#yL5g%-}^XX_B!r);dVo^(8{*`33J8ZtE- zwbS>%F?V-#$35)N+T@HP*T^S+ine z$;11;xqG-6eo;(K;Hs)AJ3Wzn1T7JI5rvGRk1DC`Atl9eqS!4Vyf8eu+dQ6JzwQ%K zVFpXtaA*tBd2Vjd&(D~tb2SSnnOVrL2+9`yoQjVLY9iYP-q2fN7t5dzl+kX z3_bCu`1C=o>~{q&8IGu6ddE*S3S1mA8`>HMsszqPy9*jd9PGVi1cVxd;Frgc2i;mW z*k6cYR*a~A9{{JRP6$lLCy+3g5?8eGepVI)k4T4NC0RdZ_6x6MDG2+lZInK&%S&_O zW;)#4JHm|K)s6K5TTPyEU#AE0`XDW6nZ5R{#SLtJv(S#+37UZeqW5$T48hpp#h=>L z`LM=hY)eNUq~n&6w5)1`g%$73IyHv0i@xJm3ZR&IfO(FYYtm|r|NBAZgba(7?%gGd zA8>-I8&kcrcqULRehF2l*H-J*O86D;sOiZ?S*3-(jqL5I#Q7RwZr{gI=9Qi5C7H

R)@&EH;yS* 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 diff --git a/docs/attribution.md b/docs/attribution.md index 5e21640e46..f5a8ec1333 100644 --- a/docs/attribution.md +++ b/docs/attribution.md @@ -15,3 +15,5 @@ Open Rowing Monitor uses some great work by others. Thank you for all the great * The frontend uses some icons from [Font Awesome](https://fontawesome.com/), licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). * Thank you to [Jaap van Ekris](https://github.com/JaapvanEkris) for his contributions to this project. + +* Thanks to [Abasz](https://github.com/Abasz) for his great contributions to the GPIO and BLE implementation diff --git a/docs/backlog.md b/docs/backlog.md index 50a35b1fa4..cdbe1b2e23 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -21,5 +21,5 @@ If you would like to contribute to this project, please read the [Contributing G * add video playback to the Web UI * implement or integrate some rowing games (i.e. a little 2D or 3D, game implemented as Web Component) -* add possibility to define training timers -* add possibility to define workouts (i.e. training intervals with goals) +* add possibility for user to define training timers (Server.js can already handle this) +* add possibility for user to define workouts (i.e. training intervals with goals) diff --git a/docs/hardware_setup_Concept2_RowErg.md b/docs/hardware_setup_Concept2_RowErg.md new file mode 100644 index 0000000000..5db8d28e7f --- /dev/null +++ b/docs/hardware_setup_Concept2_RowErg.md @@ -0,0 +1,31 @@ +# Hardware set up of Open Rowing Monitor on a Concept 2 RowErg + +This guide explains how to set up Open Rowing Monitor for a Concept 2 RowErg. Please note that older Concept 2 models are NOT covered by this as the sensor on the flywheel has changed. + +## Hardware setup + +After the software installation, basically all that's left to do is hook up your sensor to the Raspberry Pi. However, the signal from a Concept 2 RowErg is a 15 Volt sinoid, which would destroy the Raspberry Pi's 3.3 Volts circuits. To isolate the circuits, we add an optocoupler in an non-destructive way, by rerouting the signal. Below is the wiring schematic of the Al-Zard DST-1R4P-P: + +![Optocoupler wiring connecting to the Raspberry Pi](img/Concept2_Optocoupler.jpg) +*Optocoupler wiring to the Raspberry Pi* + +On the left side, both the jack-plug and the jack-bus are 2.5mm, allowing the PM5 jackplug to be inserted and looped through if needed (allowing ORM to work side-by-side of the PM5). On the right, the connections to the Raspberry Pi are made. + +To get a stable reading you should add a pull-up resistor to that pin. I prefer to use the internal resistor of the Raspberry Pi to keep the wiring simple but of course you can also go with an external circuit. + +The internal pull-up can be enabled as described [here](https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md). So its as simple as adding the following to `/boot/config.txt` and then rebooting the device. + +``` Properties +# configure GPIO 17 as input and enable the pull-up resistor +gpio=17=pu,ip +``` + +## Rower Settings + +You should now adjust the rower specific parameters in `config/config.js` to suit your rowing machine. For the Concept 2 RowErg, there is a set of predefined parameters ready to use. So it suffices to add + +``` Properties +rowerSettings: Concept2_RowErg +``` + +to your `config/config.js` file. You can also look at `config/default.config.js` to see what other configuration parameters are available. diff --git a/docs/img/Concept2_Optocoupler.jpg b/docs/img/Concept2_Optocoupler.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c9bec2dff5644842c3c90759b5459235422f211d GIT binary patch literal 107303 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�mP&|gE={SbjXah zU0Vrzf9y3a7rTAw>0so2a7Uu}Og=46og*GtjJhkf<%IuoskoIRGV1hQM(D^x0-pH~ zLzB%Xj@>v;X5P{}%a0>I2z^o!yN!Dhz?$q!RNa^yKNKfwiMB{-a`KfZmQ6Pis4_&h z!F`#KM=uXW8?%)46C7_jFYvCwPu)tz^T#*Wj-EO;Gqz=x{Jzs8B;Pvk-CD$_dGECg zK!F34(xT?_5N4-sqti)?^Bue7r|M@d$&ik_Fc1CgA+sv9 zrDKAG8$MFhROP|7rPB;M&>yv*OzQ4#uG{!iY+zn|h9TZibc3xzo_*1^0+3j!_q9uE zdrmP0zmsNG$ia?xyn6Clnw&S_l0+=2yqOk-SSX+8YIcNvpN570ft3m)o09q=lH0F6 zk_m4gTKOzFpm3Amg>T$5j8qOS%wi}RtOp&4!21p-t|~03wZ^be0v5BgpnrmegMZI6 z1`EKSkvA!i;O;C;?DsLYWx+5QbO9Yr)g-W4 zkdyOcp)bfxIKYudY259`gn40gweG}MWZ}E4%3pmpS%Ib#9D1oIbfo%|0{E_QC*~Pa z(|Y`E$XwQZk0hvRvJ;J5-M$KTnUAvwk44}>HH0B-84k&1y2o@i;sf9Gdxpx{^(nK@ zo9`92PTrsyW`BTCT{Qp}Cc~QNy3sYOHyrcjP?i!tP~j zC*J%K%c+ggg29;m+Us@A&y24)e&COIBKS9IL;W(nwTzfS8X{DLE@li6M2q|->F6^G z11+NMXXS<%=qLC2t~@YgfvAxaQdaILmM>^A^qg-QqciDJ9=e=>wu^8>%r3kYS+!nOd*6Pud(tPoyEBYeBT3XV9}6OX|2il!?@3ogOUU|ptxhIBEemuB8=kks^BiykLBQXQDEK}pVVreD&d!x04(IDm{N3z=HVC##_ zjs60yBTORzIe_O;S8@C$jO|>wexH@UHy3|5d?`=ztJYUU(g)T^>eWbEnH>?m^?|6} z$;}&FhL137-6sd@-ZW`!A}m@xW!leBx3xHL-Gy@dx*nHv+9`dx#2IMT7iiqv<}Zoi z_%Jqu`a_G6=VSW-x)dx68{O2KC`2Pi3s4mK7*SmAulhGJ`(4A|Q~DV1bK(_10_r?H zg&KTLu46YDtZQyZAc8McJjpWu!@oDbKMur^($lBa&z$LwW_cgIylgOH^hB{bVAf`v z&X_O{fCXQyCZf{p>%+EQ#+8dYu6|gXref+7av&j^Bu@rXg7hrN-izDDT^I~T zkYzk9hpT+JxP7K5@tYc|ONgaakX(9Pez1cuA{%}%`DG%eRb4P30;_`_?_%8IBTy_h zmUC1QsNS}kucV?SQXw^^Oh^lB(x$D;ooxT=g3!9<94BD{6_$YQtQLvt`}A(WjWH82 z`T&(VPI$;ve^4;nafS|nv&wD zlN{K45XlaYKgxnVgdeLE&51?*n>)^|tM|JXE%xPeYs1HKs*bkL5W{gE?E^G%TsIO= zQ4^_2X`EafmDC?s@YEGQU;paV-P%)vua-`2zf6b!Ah|r(knP)#tmAU_?t5b>oRpMK z8KPe>B<|vNJ0S0sF`o`gwiP?F71B+|Z=q0{QFE48I_w<~0mhXSUC8n@M}-4=%ECte;3W-BaY9*fPD{y7vKlX>lz#9%p%k5j2SzqRp%! z9O6IL*{G5;fVzU5Wz-mM7AV%Fm3RjTr|UFNW!?z8dM>}mwCAA}r$3Nwu@)@f>M!Ej z!F};Q%zGf%q^YunVn%&o_%WM*49IXOmkGrZ*v+vGc_peD$S z^n!jx+YgV@nj8?!%sitL%qGvge!A^P+2}{~h(N|p-(5kw$C=#L&2~T_(=4K@wg3l? zN`IV+zN~%)SrJt;U|c9a*+9#@g;H|T=9 zyA(;J$s9I1v-?4T z7)RON@R^e!t3e5&4qxnI;NyRBkhJ#&cBxTW-TQ8l!isnoM{U7ZPo zYpfaHI+S!-^AGS%`I_TAzAI4AUaFV)a`jq;8}TR-5V;GJA1+uLM$fatnJAB8hL-i& z*vIikwHePR?v;FfaOI(V=Q+DL>-z4kOx9+zAd31d+=*!R@c_CT3b}xA1W)f#x;d=Y zXY6UyFjZa8Wq~RQN$-X)*-;PriVW}MuaqBqlr`pHz77>|bKuqtB|C;=e%`LZ>eo!} zV3yH;dP0Hb(IbG&)FMuDCy(Wm6?H9ltJ`pH;1{S`w8}~?x?V%1z3%AcmGg5`KS7n< zUpTahF(ciTJ1td@zWE;Oo<{~>r+3bC)Of`1kbDNJ_bp`&EeEn#Mj3EFvw_KQe*8b z70*e1rzSoMhVF(4iqNtUPAz^KM4teQ4c;#~Sko%!Bd}8#e$?aex%;6?K!92LUxU(m zD}14hXOyA$qUX4XR&((SQ4U|WRwv`{t&V?R0K07b<;w84X5dpt{IOIxLY3V zL$fCCcvpwrg<)HG`^}l;4sj{(u(LiD$;d0Gw`a^-N+wZf5N%)~+BZ5ou-5bhBA#pn z$hNqWZSxv1+ka#4y`q}x-nDNO5fudKO^8yZOYg+;00LqZ1f)i#69MTxQIH~4K|pB{ z=`~8PiF6PV=@5EChd=@n0)+Uj=iu81`~SUT?D6f>_h1bM3#VV=y+l2 z^#K&-pt1|%!7QfHm_`l;pg@#4o_zxlBr{NDb&6x&y1g(H{iqLGm04Hn)gi(FhvjSZ zrPjy}OF&J6dDi&bYe#t_O+#To;GMxJ6_(G%b1t8^AZs`9+o4pNHMk{F_sLec=k8y+ zGlGm=3)8zDf9creJ#4y~Uo`MwJ<6=YzszsoJmOOr85#N1aV3;MGU9g_*VFW4xxy+d zY(=im%#hUJl~i8Y-#&W&{BP{9@ua9!Z>Xia<~@EeqNkv~yzIz!P$E30lI4}Y-&w7E z|Dx54x(kk%x6QxmdC$$HWv8r;`^nt}zkAo?;QXX-fECvpav(p=0w%~~XO_Odcnt*R za6LO+QIgXOzCwDeaJw01@}U1Qb>1mo9op>!mO8*pfxGx0MIWe``LV~n? zbg!5H|)GBX0{+AlqA{e~Ru=JQD4j*#5qmoiklrSd!xt>=QbFG#UU z5O+5oZldLgsQ8LUX1&(%RKRIa=8A2-Ij8vg`@1U^54FypN2kPn2(;#1ZoSLQS!gm{ zTsH1{JTtb|>R%MZL%vI4ISib%&;^1v7q#xbJZxYQVS1h66QpQz{ZGI1i{}^-z>tv) zuK9&Jd4XuZ-|9pfH5-wWp#mNFi|1(9KiZXAyyX%8H4AwCEV?{zt!qxMH+1b%BqTaP zSf%bOn@|ow$T^9t4Um(l8Bvk-WC|DWZtqL&i@H<8(p?jG2yms?h=>lvd232w$IEs8 z2PuX@d3Bj8CwEzx6O&tKeO$YT$$vhG)s4D1!@71k@%l{ZOfBP>tz8}ZrKFNxoNUr= z4yvG02J&3w@+oXux*N{rjtvdkHE!Su@U;t`Jj1PVSMmMXbY7vJwz8%zKzt@I7ueYa zB!hGjF5UR@>VJCy2DfVPG7jUodm`1aaQr5y>c60R!zYf2{%&~x0@>UPb8vxV2ipIz zdr}BJ$@t9rS^7WIoHx1tQ!qhNk2&qJFW(2>BKFdZ`0Y~xR-V;?C6%3tcAv2waWL}` z_`=54M%)n)2+r`|0DOTf3p*b$9T?HDT`ol57BFT|31FkDbj1EYgy`+90Ge80jr`$_ zmP1SyMFHU|FezF-Vlj7N?VH_Iduh;*!$9rGn}E`V{xvbW4KE+f|1&TX(KYn8vOM_J+g<;Ss-L^rOG`cuPXW^!`p4-9 z1WX_~F{E(*HEL$2I8H`*-~JxQkGKN^=DwJBo!7oz^@Yk%^+{qy-#on3UOyXi%)HTH zJ3D711KUSZE)*cVkh2H`;uhg^ERp7+9HB_OwQ#gCI z?vQfdO|y=HluL3_n{zVoLMk{B+J%t|u75{M!%oeFS96&Q{5#2v@Y-iBzMQHjq! zoXJg_4T6V3giiBpUZ)alWj%)mzMPH^uEKp0?M9fz2Abw+3^hPoYYFp)CNTCT<%e`h zU82k5_xa8~-%+W&jMB-wfv8{#6KS9eTnAK$wmNiGDT$>UP^`V!B*DvBp-0wZ>9$Xc zaH8*T2YS)ee`jI46=pHhUhA|~+m0n~QLEC_B!n~mzNX(qgwBml0R^{thX_#(diuI> zjn83pB>C;Ff4gAB$Dbg&~}GU`>m`s!FJH&%1vXIi!a_?BAi?MjjMJB zCT$Lt=`^Qc1hC6#b*N?{IuSL$GNbAy(!@VjmwU%v%i(-b{BEUDM*|g)@Z5KB07fI7 zbiS}e`R3F#rADu@F(>Bu!@bX9$zSQgQ2;xNCj+PUhNc|$oZ=3&ENc;03<@_gB35nq zMuHaQg}In5)g{gYaQ_?oAf6;VvmLXL76-v$Fs5{XbHvBn3pVGr7s7#Pzm4$%#enKq zJ53~(CZn#8`axp&WxFgB`E6xCWI%+%8uQ~6VsWNEw>Q1NcZVS)UeWlVHqwTbonEW# z-lvtnLrJ!>zam+zGS&AtIV}VyBE57gUA!bRn0a^H79* zRa*C_x%&Y~xso#_E^fWDD0W8$0le{<2|ePZb6Qqk12(@CLjtPqT2hROt3BlTzjP3i za=ltTkEE}QzgIbJ59>Om>{Gh^wc}Bv3(jKrcB)uC4GLu{>NXweh zI=wxAn*f0?5#s(oebSa2L`0b_2ab8R4~Y%8fAazAwuN5oL?Mpe%|Fk?1ve#QX;P25 zGx6v_5qouW+V$xNiu&GG#;lT7JqA0U3!u`lmMR@5}1xG6q^&%AdYslC}uLuE^jKR z^NwatRSr3}y9cR>)~*qLC5pYR6@3w<1;Dj4N`oMH-AZB=7z@IQQRjIq##H3bV_`hp zlPPX_^}RQ=zBc_>PI`H}TVI;>womgRWWe|sIc((>8|Kyd@!m?~{eM!@liwGm{b^aX zNG{V#ly28N+%_XJ;#rDGsIFY0QTVm6r^GyBZ%pgOLI}BK;7rb{P5m7UxzGM0d~4d4 zJ!JlXfqRdVj7rQF>ZP~6;*nqFzb{0Bt78(-a`t*8Gt(AgQ6+bjY-N4R)!lO2S!FlQ zMA5Q)7xv`#OhH!*){@)exN+Knbm1b2BD_h#D7O(4smZbA|baXq-zId-=+hji_- z*aFkWlP7BK(S;i4O09CsjWyS)dpTN)$2WOpXEP5a%`BnS?*awt>@eh;}oAZCG?8x z+|n^<#5INAHMSd(oA-V4gD0$S{m1^LG5#9Y4q}23H*qp*=0PJ7<{oIY(1fuISRKSA zpX6E#CLSoCEL@?0^#an+piN6Xqgq#*e9Ohj>_s1`{dFN2HLp2vU7DlYTIsHb2={Es z=Y$YPfEW3sBrO$e*iK4!662Dp>K)FsY)?J|@vXQE$Zz0f4qrzSw?$~|Rt;Wk(bxrf z5ebyNG`Le0dfCg5l8#^8dN4ZkN)*96pHsaEC*I&y*CuFNmae0@oyP%oSLyqzFx7c` zaKcB<1j}@a6oZYlY^7-Y$})S1_bAt3O!sr~?FERZEw9QkPL#RbEYmw_wJ5hCLtQLF1;JnQ0PG+4t>@?d1*Yx%{*YG1|WOqH}KeNvnczKI{ zn`y3aw~Y|?So4*?!w_sf*cgN+;TtNSxm#=dX#V`c|BrgVgnGq_KqVZ%6Q+Qd3O?_2 z)#IM;vK!GXvG`8R%Em)+{ovYI;>&I#{n!=>+ZkC+TQ49`f}*=Te3a^V7X zxf|*YhaIpL_v1LzM3KG89SypS@PS<6)1oj0Fg(a84+3_nGIQT-47J0o84%@Iyw=?O z;dD$e#zKd|jZj!%3a(TS?Y@U!E;Z}aLJ!f-95xUnaX`G44v zJILX%A+}T%27bBA|HZ(&?g7Uj_AcGsr$pGthPL5WKv;j4CJ7BHHzJ+?R7}YoxD{^d z_QsT{;L|@Dd-+$cFC=7p?^|Y4`A>nSgOi=yo`=XoGzrt4bLT>DP8HMYu(H)MBTUbQ zJyIr?1s*`h)~6!h4Vn%lyG)`55pJ+tL6X7tp?8V<&}SRFDHsHIS@wgRLrZHt;?uQv z@3gy*UTfnr#vP>4*bOa}BgFe-<*!FHK4X>AHyPhD13Xmnp@T5Qr!@?BtJ5M9PzJW& zfoqslhF5ROLVFF&Mv~&c+%4_<9cwS?`7Ge*o=5x3i;O86sDC|-!9&k*URX>|uJ8z& zXEsRQ0J*rDzoZh4ZFh)1d}IhoV}JjbPM*E=T&z9j!n=rzNdm0)U_kL?HaaS3VU+-CW?{?Y(LOqb<(1~n$@5izLQm< z69?bs2d%@8m2f2Vbr}^NsSlnL>1~x|d+SetJ9_P=dyP2RjXJlXD?TF;TZ@dr0!+iJ zsTHF(MrB9Q7JNeP%;)WAEn`gtq@>Ty%rLgS2&%n^zD`L*J9`me=|0<5A2YO5f>pAV zYNa~seHeUvB{+wV0s=qEcsiJIiMhyn%>3@c1VBHYF8bPc5<78KO{7k;0ZDCp--GyN z3uia-3)u9iNZ+n&6$@Hcf=Fs3SRO84O>IXBWA0Q{9yX!MJ!ztV)f6}mM5zDUcV@<# z@H_!9@^XkJF_K`#S>sAw6)lHzi;H1-ia~bs2lXsF`2-il-7SidV(l8wm&Cb>omz`Y z2=eZlARHVANV9;@azHM+K`ic`S0$O(r=8Q~B{6Id&sL@R^J1&#?iIgGxIUBZc!>ml ztt-|{g1qsplkVnNfHfTQ=XCbmEHb?MO=RXPP(JwfmyQrj(!wJMifAT)|DggE3evI} z^@Li*Jcep&@pd38Sd-NJut6GR6dOh21)7KARAx|ov$5vexO`>hy`$JDXOBoCSCvRw zw`O2{%T9O>pTr#%$^N~TbwcRD%u5oIaC-^BENC|q$!+3=#hcvHLXIc$IcJzZN2aai z0i@|x5&UJI-gN2UqD_T)>%I$d5ZU~Nq*neTV=_Kz3vyae2PDGjC)pU^sgY94xPDVo z8$X6?gOVR$Y%tNy{^*tceAy4OeMfJrf~#z9e(?CVZRQybo#Xz#xNqNfa@Ga_{nBQk z7aiU|OGU&I#v{9~z8KPA#I`n1o7Wn~?+bJ7^$RkFkUG=G?29M;~Vq#Cq=-^dNp}4ZW<`RCtyBeMb4^Fp`q{PD9EXU$IM6WjoS(Ihh z`+@IzotVXf2GsA&g)@XmMEyywg((R{D^y51`Oh@swfS+t4KYD^0BI1nkQfo2<%XB` zP#y%w`jLbNji0=d-@(^tTo5xuwk0GT{P9j*Y05Qtzf`UpW^`y%ZRo%2i-%xYX_w4! zUQ=4ohA~|&+CZ}&s#9wKRRiJ=;xJEs67l_8M^=2Wi2nVPcdWMzacC694ksUj0nvEZ zbv21n6kl5+D)!6%w!FyKL?gD&o~?vl;q2(UeJZIaH)~dcG!g%pSUG`IdO}&d9i#$g zb^l!uNW|LeKd#YBVd*gV)nxuu<2*(Iv519Wxgn82VMrT6l((O_&ad(-Kh&kLcEnkA zj39QSBBx>CO1lpAo2|J*O5_7;al+xjAGINM1Z(u8bisL63_^(ZfMSjBvF9UgKOg8tU-=fr ze>`%RFJX(@JNsfW+mhHD{NTe1mZd=iD~u*H`NvMeEaNuuD{W@9Qbq4Xw~-(q`n#N3 z(7kJ;3cp4YEZnQZ#3)mo?A7!tQx+a-H?KDx{Zuf^w`#VAwdJm@9VP)BoFTgPbXc*Q zkZ@EwFYQ--gXUv$VE+tkrh11(^Ld*W?c%|SG7P)cwFQc!iI41RgO}#G08_-M7hYju zbCRVHKBFA|{4Hlr+?2C~=+jHbwVQC+PZPMU?`XagpLfH9vbdeph2Z3CBeRs^?mfF2 zT);Ih$$hot95kE>H5! z1r7TNTXA^6j2PH%52h$oJiyu|C)Zw9J)T}Ur#PLJ_URw@id*wPrd}kem$u3SOygXh zaj`M+(be%fW7I*z@%X?dk7;Pwa#^wyorM>nyP|(_VLF7{_zuREB%T4g>V4xbd)-fm z&)ZU^waXO&PP3a~Bh|wjXz~##2T`B#o!~-F0iKqv6nwj`kcaMN2PmfD$#SdDSK-10 zPva{W*IDTtC$r&Wh_6Fk@>5mEykXD2*i=OZi_drj-v8MgR(aa{!dXHm@^x<4KO7sgxFz{~Z-6C_s(A#Z*FT}zgZ8^X{Mwd4 z5mh2qTN;OWqbppWbVFM{w9t9A{Y|Lj=}thimT%o_k#C$vnXojZKrFF3+W8xAf~B(b z<5D>*@l4}jtG}s`|X{`z`X*qmbWSNY?)tMSK9_c zq8SL3aH8dR%w@muz@>$R;wGZ*2jwGqf@5qrIy}no-kDz$4%t5Xu)$V_lVJDEh8{_@ z7&Pn*Y0P{6?UyE!SW>()Hew^!LD44ThFZ@>x`-gqeT%3T3WRpiw?r+5s#Zur^nz+_ zAO3?DCOtrTkq0Hd@88S&g>>*5fkl}zsZ$}uN%R!38NM5)M`8g)>g3~?uFH%M8^&a+ z4m|G6m?g5ba5`|<=(&=P9>x5zW!thDJFauj{o&JM2flkOAwpbBqQswJ9#Nista9kV zc|5%j@bPCHR#6E^;v;Z0m;?NLAr^YkFI=K$OFmxvE_V~>p=$Y+YH8tn&)yr(Yuq{0 zdq=vL>O=}ayoIyWkIBPD>^HD=g<@x`LhNk^ zg2ln)5E1|mTH@ko?AoQHSbMR@pYXOe5h8v*lG(lRu*S<);c`mOZNa~EauwSmjrGy` z<`&+KuY#^RXJ^!$VmCH^Q!TsXba6@CKjGzew|&J4KSu3#P{-4Mbg5&Q#cIILzT2vV zV|EPy-_iG}k9W2w&d(*WhP016J#k2ViPyGJk$-g3iwo21<((JJ7SdJ75RccJnA-{M z?XdH`cUr$vLlm4VyNlzqhE!u)k*y6K87C&$y~qr=xijh_g~6C!@Ki<*m|j~T9B1cZ zPeG`~5IhRoqBnKi{+S&9=Y&_3cVYGXVzIimb0g>#lDh(ai8cm+bF50C2*-_F(4<3K zODo%_%dNMcD12XzU{Tn$KP{r*7m-~+bzCANse)>VKLuH#iFdc&2c2{0fjVO9)qF2@ z-S~L^)-OYWY8`1!|Lf<+P*uHKw5vq9N10Bkxl$%3hSR>*KL#9+ZTBH`@M*-i;#Uag zT?RnR2`2G$v&M}Y2GJzU$36eRLd6zn36;qyj*_*{G)!3_%FQtZ!xLueGfFsKkRgl- z=M_o2);PSJ)d`o#uxg!DC^_J+?)c2`y76I`Q0sepi9AY_Hs6V+YLj4MB6h==@#E!` zdtE;I*Eb1(a|ZZ~W#Sd0OvU^4HCM9~PUsuXo)nBN3TI*-?PXO}k^e zt8E4Z>wz8#2g6UJ`kNWv{rz}sJcxfVP(XQjifi3yx~mD4rm5^!Jm8Q_yWVp~g||n$ zr54WJ74b?y!fI-91Dnxm)_OWQBil z`m%UFL&PAO>B+M`P#YHWlD%sm$_<2l0nuh&ar2@i*{aNDorc&tjRVearmWKz`ZApO zg#FZ{r4H)iPQ!L(!}V8N-3TL~UUG>4<|kkvRq1vCkib6!LG%fGYv|4`aC5t!H~@NNf+Si44v0wl$TT2 z{kUdE-k_jZdw_+0W)b}Mdd*&|TBU2C5U8nn-r7XV=4)!a73*Qan;3dDi*!Vlu+fJ? zNW&It5fK{BQ~k4YFoJ5;ko50bs=2mwLBFs;;49xWMracwCMs8bpbyC3Fe2??=xpMv_6pWBPrhBv-Y938b z&+Rt3kozZq9g-_G6irE6TDaJTj5)}W`|+#uR8u_IbmBUb5_4ifqo*dGOJcia3GmhL zBnB44jzis!qsVOxv)+7Mop-*K?Er4%y3ArPod0Q-whkzw4#m=6x|tbP8M4>^a-xXy z<9WS{k>mG(glFi5FaZ2vec(S}B7Y(&bD+L0biQ#vVc|yjG=9U*_Q3tOX+_0fI&*lg z3ndvZPJf~lr^Jkr%`A;dgx#@hS@BS*C(n514CQE>@n!W||49hg8JBy&cC={Lpz-; zfsT^}@IfTe6u|-S<=3rTS|0hc0GNVIKg^osxx3EWwQkb|Uw?6hzNC}o_V=pu0b!5uNg^R5=nk`SUuXfnlW|ir1vL*Z;-2BwJbBJG+-%iCgW0 z-ZqQ7go#$P%X*kd0f3#{o|)ch13@r%SHV~$?UD{2!XL&kR)>mNVEhA)rZKj(YKkqy zDNnTy)}*bT>xd9w6!`kmBnZ5{i_1c>P&G#?D@Ed*_e2Br`B?i!k>obm?!rttZZZk% zoIK5f@3y}NOpwkNf;E_3HYYnoT%m937(c~^414cMm1M|kNKCma zHvH_cddG%-$^}T#K*8fjtou#pY7ggog?8{rjlIw4-D#WXbicq?|)gk8+#*|Pmh*8`2n6`<_8@RH8Wi+&rs zZucH0bakR&WEZRL0Bdz&XZD-D$n~ez`AY>^eJ`7|l()UYIkC37M&+sLUAO{vL11^= zg_MayagL*&6}94{+JZ%{NnbblZTh^unfnTMqakSxjXjJHq`|byf9X!&Is!uyuQK$O ze>Jy(KRkiG*US6mrxOd5(r(J*A-njN_dV9=_TS*ecZjoLTKIv)5FPoh=GDTW+nH;& z6XKZGk0HuczRAzFp!%-Z^T;JZ_5p*D7ao3d@(`iN+!Grsz3iu8RLEM_68=%I9am0E zuBWtuzm(B%tsS8}q~8d_}>2 z-yQ_K8RTLJAR+{jX#AJX)VcI8UBNF`aT^era%qi#WYy*oRbYrTB~E1cd$3n&*M>g% zQ9}QDt?(sUg95xNlTCN73=#2$CgMh;AJbMU?_6rCyYY`H6jJ)}O?5j@Hgl+hDd+3` zbZtM>?bGB7V_}zxPOCE#$fa;$M+pjK+AR5VuMwqTac+FFGn@x!jxNpL2wZTYU~tl` zY#W*%;Eraq_Xl(;3X_KfT1Bhx6|hZZTRQQUK7JJXjfXPkOc36J7!$ADq&o^6c&s#`Hk*$; zI&CTvqcXXBSa!2nLJ}s^gSN=Njl{#GN~+D`RagFu82@+)3~@F?-}PM2WA;SdwUaDk zkQ5|~kzTkK#dlkIsPU&_g1Gpb(vGXual_k_DBm4Obi6=N>Px#ya`2hs*LL+;9;>$c z;5T>;LEW@I${7(|^=5_hPq2JeY6(yMgk!mu9)CKPbz)dUCJ{`e;@eBYq z2$j?qr@6H2b3uU9w>Kt?52jP=)9&x)*bvgvW0$TkD`$R2gszOVWnV{R@X`k4F6Zni zz7;|FRud|fzFoOD>&I1OjcA0z#?~gae9u*hR{=Z30&Fj@1@(O{_0iA z+q0#hpy*%oe@gW|4eR}%Zt53^87TxBZXR#e>$08JBU~Ze@IeI8f;AQ`LPVE_y9F0) zezh}rJ|t5g$XA_cY9RLN<{zYZ=Zp$pxdFGLfdqBk0pm#GSCF>!MDcJQb z-i$u;B(bBhFN@2msVVM2g%?lGJK;jKJJ6)5w^Ek~he@?3Z?jLZ@ zk+X;OIg9|nq-VZbA=(x5DAO?FgmeiOt6|gO-S6*=RDz28Uo zF|wVwvQ=eo^BNh80Xrk5DI$X&e%3hbuV`WI*WrH<$xBO&&8(dw)EwGSZ_9a?!@J?QIO%p)Na{QE86k= z5<}Z*)>YYMjb9hHzwZfr<2nFvFL*PGFUglYGE5DrWZ3z(s6%f~;%X~TmLe2IOdZ+3 z2p4tjpRH1aTT_PYiL@F;4_fy)lfnksrTZf218(V@GF;z4hr0gf+k?7+l*)46qg zSKcKJwexb1+s84*6wx}MB}j$aM|@bEl$YjSMZQRXwU zz=sCM6MdwQ&6mE)w0AxV8<|H&Lu3T$e)=Orps256^7<7I{`KqceFW%z>h-a0S&UOM zmbF8dhs5EQp?ik-(_T1h`$qMf#^9T>3mOc3mdu)aI?^jobY&(_s{Qn$05lapdGli{)&pBeMri}T!#5!Z0F zR5B^*kDzAe%E7`bw0M9kb&$t5e3(o$Je4**#5E*}-1|Q1d9#U^O#%X!MvkLzP&)M1 zY(98MF#fn@uwi7*|DK9^)ey8WoNc>Mot&sE2FMPHJsCpDa+OuHr|EQFG3gk|=Rds< zZ=E~Ab9GV<$t)yGAP;C0$==F(DX6nUNT9JX-U6Lys@kvz(Bvy#1irAqi-@=JgA(Vp zh>&={wov0q=8&Qop9a;Gk5`sroO#>L`a~MVn}@CdMWkCQ@|S5p=Ou{pZ?x%`PA|6l z3a(K_UpTsXET=5B&pGi>zd1y{^SM|NT!AnO^3QU7O!O)KWHjzoh=RGn!Vb0NmvY8{ z(=Oraok5-)cZ*vORz9%%Toq#dJ$ZYHz~_jmu_+HO7+w7k<2oupS>mbpeH4zNS-+rh}q6mVHk^QH%+gS_Q-4$eQ}&3O#ZQ>3QoX+yW@7WQ_p%G<;G z{5>R0iL`H_MVs$F`s>KyjJ5jqSTkf^m`8^uB(WAruOp_UX_p2n;J=VH_rWYLsPaxY zCLP`Bg?nS7A3G*$T6lDQ*!Ih696j0>FA*!@w5_g?mDRjZ;lc2d*?xcR8Sl2acy+Ike%e6f31sZwbCXTzAQVrzL*S=$r27E2PzUZyYizSGcWy zZ1;snEDs>b_ME9aun`X0&!>rkW#Vqa)=}7+#rn#V`!t~9$zDWM>p(^#rZG%Z1J$=B zQ^qBb!hYP%`Y+-8iv*eS?BF16ziw|tjo0@!Mm&`8&%)&c@M|zjn3`xVPii;g4E z;4+&F`M1`~_`WioP7H~Bt<=pkWqTm21(!G&x=i#`Vz36aC9vCUPRu2nQL>1W_NN8f zd`r+PVf+&`4yw~c)#W9UB$`0=5WRo%4JM-O{sqyuwdQ~b} z^(|{B**VBz0aw?_Jri*aw8r%fc#FPSVAs{%IzEg*pSfERbY9E2@@f#|G0AeO04PW= z9M*i_>~8Ik9@i6%mPj@_ZXhexP{i`XG$A&r7_Bf(iM0G(Cwt58P+zq<7QM~@tE&OxIU)wb zD&HDfOku=jv>#>)aF0z}Oqxa9S-5E-5|XB_ev}q-=d%A|iof8*4Agn3c8Sj{LuY%< z%UcJ9&|!TKmkk3`q)*(a3X@a`V#rpn(B;WiCHhTOxWKslO1S3A^P!*Douzz7r6USs zcu|ZLhNZ1g#924~=zQh+ym!}=IHLPraDii04ko*xQ>ac1@qVIo4~VS}`PN>DR2*Mb z+wV6gVl@0wDSu#$UVnpIe6%b3i5Z=T?@ zYCkM`@cSg#aL-_-q^y2iqA1yTYw8GtLlF$|;An(km|4+ANb^9!^d`$!>jj(24*jgh zQGCmA|J?;=J{?@)FmZUmCb?>GC|;$~_l%nHBmirDvYO)$cID>oq5}+c@du zEf9g~ZlfQ6Jg5c=B<_T)oJMX;UaAgu`T15N@!gJv0Uxv%i%tgi^x%yz0Czv*^_1jK z?uI=_=H;WyG?o2T42(C`I7!iBeM5C95ZRdGq0M?b!EzKs)U!Dc>!F$M@Rn5&>s+ zGUyyOD7v_e;?rTrVNcvMekJ7Ep!}lgnpe-ry>pe}p+pXHBGHRrLku*aL@nx=)Ilz9 zx!&=zYv4AcW4f&f$aUl2ZySgRHv!cy_=ORgL>LE&JF(1KY&8bQ$~^DZ{6W#dE%Ecy zaI{%8W5aojDtK{x_ie*)Hy(Vpb;LM-&Nb%ID=qHZVs!)h)hyp@9hncipP8{q`9@|~ zy6j_nv<=@4ca%U_3+(>Po}wx2!q9q#*%7JhqDik(yF*lhC%?z{ttRd0R7gBdoWe)2 zc-zNYKc*zSgnm!{4B#a{js3roQ2(2cVSnlVj}D7`a^GLN)VR}B%y!uVVv`Nm3|^C5 zI5ff>%HIOrvRv7v@(j?74qqX*S;4d<)R+{t4VWHBh<*;I26fiuF^JYCs0Hz20 z^-?nRgK`_7Qz)p}L{UU}s2^D)0M2B69$=;zogC%b2mhxZV|M^ECy9uH-#eO@0%AQU zZ(xT!eM82#0^&sGy+42H^dBItHC`DtB8_gI6wSOwey?dd77rI}z4$c%sF|(I)o&J;9n>Tw`+7 zvP7)2R~Ai2)Qp1Xnvs6-b+%QpWVPv8xyw+G{aPNJ&s^eCOW{j}^mU!`L9plL5PS!c z(E~NXWLF;k;(fo5w}6sS++##TU=K|Ij#~Kf0B5ROr=NT!*iys|w{%EAY!dcA}tNysjPO|+d&I_VB zX)ofM4uO}=pg_pJrxk4sfNSF32HR};b|pZ)4{1~o! z1&}6bKdPVU6*LE13$Fu%b+tBu1sdbD3o=Sn!DZ4lNWZ2_L`^E#ikF6@o$yNExqNrAbU3aIO~EoY2KxAwlC?0l#*uA-}FH z(>7k)KTxobLWMb&$1Oy7FJ|LLoqyW^ot$P*KmqCG`0|`_&u8 zLs6p~HTTLctgZBfTB6{yK(npn6gZZ-?_LQ~(xX6#o*ohpB7SYFEX1T3R`EaK`nAg2 z!<+5!m8&41yD2-Zeu`?WSse4LWI(ywnI}p$kE)u|hBcHptl6g-R!sA#aW^{rrPE>L ziYb-N-h6CpSu-w5w)9M&f7%g8*rEj?u?uC z9{P++xJ)*YR54!8!@6>^hI6&aHv_5y?BvFGR4d38(;Z9g8mMvb3={eD2#skbOd{(Z zMVe@_MD<_HvI{f|9Ri?oh8Hh0KXq_t4qRL>Nit80AtO7@QOy?ys^ldD-54Fpd=ehVxkIQ<}$H3OX;93{jx zP(*nE*-Fo5*8bU+cUc%#w6D2pu^c+-QAn|^d*ia2n&7wxQLnr}m0zw>U2XE*4tpRH zTQ-^+mxZ3muFA->m7H6%Q|oUKg8BV94z+YzniJm;-M`$udXPL|`)m4A2+BTpPU@g4 z;)m{L)o<1ZbxqHTj$CygweVHCZVqMjdNYK?;}D^uzh&`2evqhRl(}~{0ra-gX}n^Y ziI(Hp>cbof$_Y)Taxir?2LdI34=B_0=CM7p{K;uF%}v%znEm^T$5g}*AC?P(usJj@ zWf$kwBM$_v4l&XOL1zz8EJufrW_Yp6&6d#y2EyD&Z?z!(^DU*LrgKQccSO7ULuZ&f z%(H_FMZe@pVge>ZLXa1s_EUyDJQg4A8`FY8IRVI;-d+eZm1U%2`#_#~WBx|gebPVn zlB15A4O3Ww*s&W4?+V`cdi70C4Ui^pj{{5O8=4IC4d@*3JiZcki=;On6Xc(xJUz7m zVS9H`v~M=X=UL>-i-R_Q3k+bu4aXj&)@^?y{-3b}=mmu_@V6?EL|E%H zAG#i&GuQaBxk73lI+pK`F_(xmHL>nawpU$Mo{urn1h>KhRD zRpxijDC#e)$`L8b6C7z`XxMpJ2siIY!_ys9K+ghuw10$&2FWyDO2$KCJu)1}dKSCM zeVjO#`}vzeRaWdLk?=QRQB2GU?{49_e&0QTxmxmnP(1|KVA?H=%Ns40(EW0bbHb$} zCj~CWzIKO%7*az!re>0$fkQF4A!^pzPYn!*O~*%Yd(-&F#{FmPLOfAeh-Y1Lb&OWd za4uuqH>2zt{wIY4aLb(^*gtg`&M+S03Cps;Z^62GYit)?t zrhb$=MSzt09e5O@uTY;)96+Xb7pZDOXMPh7Y}6}dm)Yi9`W_Y(?0u$Vu}mEd7ThJg zU((8QznYT3%$V%R5(BIZp%U;2sb0u@h_w z)Se_GDc=!pnB-h>((aUgW|)DZk?j4BXPzZ-uLEBx9fnK4PBn47r9YoNIRYX+Os1zG zIzeny`rxGn=5-ot9m(MJ3;*&;rTc&Bk{>s{OX-Hc!s~or%Orwp9FVv_1Y2|2AwM`Y z*P@a+Y$-P711hvqo2-%5BAf3kwfLvP!|aaDUZto)npu0V$U3YhW!!EuNHE00gOKq_ z(p*lqv2*$ok9CpgR+i1y1$xhd&<8P(Fq@j!;JL54S#p<@bW3YQ0!D`IX(c zdWwsbDzH8CiJI(YfzKZ^Pa1|79l;LGlS286jy*>YLypJxLw~JJF8Lbv5uRW*=amNH_{q(o zIf;QY7;B<5^4v!A8%$gMiIzscE6Z=)c>4q3n@YXCXY_!voRj5hh4#<*{hMuBMe3_|rwZ$^F^jHq2v;9oX)FG{s?m z`~f~`>NBt2u~ca?me?HnW0M9i?!eR6e$gn^{4vI{h!VvV|AC5dEz6>TX}VPUvK*g}<)I z=GSlD`J5-$zQjo@eFoqMbpPAy-xQSp;}P3{064THxK1Px)8^>EbYmjjeu!UYn4L7l zj{Pg$SO1X#0WC2<3I%rMdw=Ot+7>}4^g}?LRe2WM+9su2mKpre4iNoZTO4+#MLH-m=-0GF&gANe zX8oNW&Bavv_!CtizlXT0VVBSDsu{vI>gkc*ZQ9x=eKR`r?fPjJ!6_6&N(gK7;K?ps9 z0#YO*AW|b;X`v$^y@wJAO-dl4gg}aS|L=Xzm-oEmj(6O1zx>BIA2RZRk+AdZ=UIEL zxz?QX#lzeANNr@7wq`tA)Adeq;MXa)Dz;a>k}*c@#H&*BI=RnmZImPSa> zQMv2YW4eA+BNOPc2hILhMUscaT{0B67mKck1|de4x^VKtPXbEv{!A=c-YGeho#?Py zgG#~_=!^auq({#`2mDg>*V*8%8dc%7M0jvB%q{K~xS~n$<-o)5s83JfYD+p8DfbA@ ztqMUY&_=8^J}T}v`_z`F=ip)*i3dJO&pxVoaw8ktT$9owM>$9+FQwN5yA#X$$OPQ! zNwh2ypjqzaebVlhaAihWU%uC;Mad`;s#f#s%ZWd5<)~-5o?!NoQc8O}JhN->?wD-! z*650Eb#;Q*@Q>5GiXihQTwWgQJwhQLo}dosId??jRK_doEVWE@kgqO<6&_!pcyt3} zayh7~-LdtsuXG!OQp)n%-IY3HLBJ4~P?_NBIVxi1hJ1whahh{XJ?`2M4~-|0y%!!+ zhB8&Y4MqP+U#+h8na55huM)c1{L`fL$)%X}WTeud)2C$}$J>e51g@aUc-7azlt;v9 z84-Fu)o8A0Ms&2oK1fnpdz)-A{wRkey&le$q#)jOT4EnOzuaDILQA3#6vNl-t4k|K z>aGt|P$u$Ew3VqF2xJDST8{p-3wD0%X<#Ky`O#VAK5P+_w}jGOmhu$81rBX#x|1o3 z=rUW$!9KkO&V$5RXAaomx&mDElb#>tkM|!h2wr&lBWRpSh{ft*N_0V#r4ABiy^SFW z_oB6!)C~DyBMCVH_uRD-2^-3{?d@-XgS|L@Eeq2`TfHYhCUk|b2(5DZLytVB4&^QC zVGjZK zsvCq2_f z&hDEWH=NZxWRs`9Zk}klu;#okcQAzZ`PTfRQTtfe{S|dfrxbZFoOet93bqW_iboR< zRbmN(?fQD9gOx|dNQ*r=Z+7SxzxIb!sVwX_`ABV%baDJ03S#m;sA}}v_s#fnH2JU^ zJ$bG5STVw=-;ZypzSb_HpSkARZJTT+{+O53CgZUmPGu1FSQ{{xT1Sz}l)SgT zcHl_ch<6Dd$LXW;5srGz7Y8qiD8IX{pw+HDmX90<^VF$Rf`O6eq&y&@t&q>#VGIgMcAUF^(B~h1{)Mr!@QnvFb#4iS41UDdx{Hx=ky3dTf+mpcIANa@D8## z<<;1{4O0j+Z%~94K$ucZ7@F4yN<7zhFeeOhdY<-p@lXa&Na=HIR=ZtWYKUev=-SNU zWtf6vbqe3$-8Zl;PY3nfiB_d!bC~-Wi|DO$<)tE25bt=%CcMYOt&3oFl)SMUuB;qtj$mFxphkZPJBn~;o&pHRZjQfgt!u_Qk+sH5)Nx&c^zvbsPY$mG>UobCmk za*@i!IixYh@AUF$8Q}4!4+q(?FzO&d=52}*AZ^7*R|NAGqMBiIpR7r1t;YFc=!Ena zwTO;|GG7JV`MfOVEow?coe={NIt_u$;Ue`V57YnI(>(B7${bxho4h|UBJZ7PFk^T4 zC%@65noUp>b=#U1p$n#Lx1^1Q&e6jIkJS<4vs}Enz{me!o^9F1thsQP-!5F-|8}JF zVCeqr*Y%3()qtYBBUJtqUvrNPd0mdRwDIw`b_*nX)_^qun=M|Tr5E3z%EH!Nnd>Wc zaPOuh_mW}v>oCv=_`7YiPldjujt{e-Z(W>mjb2E5!K&8pm_MeWqK9K1E+Vd^R0UiJ zcKnw2f$K=#P4m<%+p6Xr?z`9YkB&3_Syc_3aGO?b7j&hEI$cX>%-^^^>H4W<8Tx6j^n)UcqSCS6X#$8uNOW;i=SIr6DUnlk*F`8T=y`Gh!Fy(TekLhTS^Jg7CV*=vzFZu=GG^e)wyo&^%Fm-M@?F>cNBj4U#Kap{c5o>AHV}?p)r{hu zfj_!CoGcyM!9>qU4?IOb96Fuuhl$KF*dId~V71P(j{8^h%Fd%xG#&f9nF=IbD~U>b zUS3ms!#lkW=G*##z&|omt0vdxR#8MCpw;rnJJ-Ub*nYc!D$gFxf+ADR(57pWG>YdY zgZm_Jd~>%g`BZ2tiQanYOU=F=*(77|YybA50RlKR+*ws=;K{(J9)T)=aIsdAk*?^= zk4xpLj{F0^&>P<$-;f!3!%&73NxTu2pLk76M;eq|i6B2ypWh=(l#wE`m++EPK=_E5 z>hJ41@C}b33*+JgY#ux$F5+R*6UXS!tC|)?o?jM|<_o<&0`!aMfDgAr>3dobg^2On zJnoTJJl1AvT4{gJPGNlW)mgt=qSKPYMb02YoW)2n(9Pm~KzR!WEub5WKL_6&U{Kiy~Up}HHc(pzdRxhAB&wn3@v zR@ah8DAKcw^Xar1ua7;p5j3t3c@so@vkMgriD_qRRMW#8zuCE`iR7P&Zf}1;xct&b zGUK*@T*u^T_DHYyy*gCn?~yZQlC@1}Y#(k5Az zdd5#R+5tp4wv&0azC6ryqR zhNqjK{uX*!`St!S-3aNnKrGqs^PdJO)+gN%ZTFg#=%Ny&s+;ZCLhrN7gq*5(Icm@+ zQZajP5nsY-!m(~RmmW_u2`SC6JpPYuUV-`3c>~ooqYU55x;_m$o^cEw&`dn$hZB0Z zf<1{mIZb!58M0NSn|c>}t*g(gH1kwdUp~cthFp`OlkFiL(D2c}93rUMEWCs#wB-|s z6h0-8D`2N*2{c#7Ou5zULPJ`0aM)#hMQ`_)r1CuyE?FCh!p);zvjbW|SQu|;2Zm?^%{oj*mK zS=Asqx!&qypdDrQ?p=NpuJEI1(M%0{k?^QnJfX-VCh=w5wOaXN=idh&g9Llskn zRLMq3GnL*r##xNb#lMd${vnl*%RE~-Q`q4(vV&#{J)7{-S7t)uuhmt?%r(SjD<~Vb zv#qwLMrCX-23+LflwOPfvWMO6XHLePeLjdQV4gC(pA4x1E0%IE6TbDiZJ`SFf~_|{ zP^u1*G5NgvBYedz%pRuER?*D2#VmURr2s8Pp?rsV#!dmz=`5zJPRg%%VvZ=*sRI9RssP~5i8Vvpu+sET+fKba+=0erzgrfw1fIQs;aAsW%5U zez-NyV3{lu=uVzU{WrWsN6 z7!9QyC40E4klZTv)fl4g$@>Qsr7?X?RMS0XAf*f%x;J_ce$^EssC&V?*j*yLCnr%O z-8Y3tU^tdX@-3YE%yQbFxZ4D(%knkd=ZalcuGJx$gHyeopT^oiglgKm@AzRAPc~;y zK0M_<_IKuiioe$L-1m}(d@Ye3j}2dL+CoZUfGPt&krtjZ-`COes@t0WSvlQ=vVnf` zJ`b+l(=Ps0TDM*NF#1{#G6Jqd3m8Dk((R1Kb|6yj+R1T+c4rqWTLmPI`~<%#b_E{~ z@?UvG1PB(vcUYeqxZ$}Co=)fDjN zpZ~71hxy)#>jh5$l#ic)%b;}}HRjRCRn*}>2LUZaPJ0hGA5Tv?E`-wqvU!;1nbhw# z4N4?@G+u(~$uNO`gokyo<%a7_@~<6_(jixt_fcAoG#h4*y9{SmUMWiMSp2zn>Ivnl zoOQ2Rz~V}IB{3QO2TBG;nh&>BR1ROPfQ1F!4Jzu=(2TBh{Z-jlTv^)mLg(s7-u|&x z2OWAj2_NU6sJ$0kcdG#Y-rD(b`HV^JFN;?e>R?3$hT`S6mqDH>{Ns8`LCt#jU~G!) zk6a6jK|63LRYAz{3ZJ@#HD;?A5Kt6>E;eURR@%aLQE`@N_CuE9=w{H|PfB^*bX(up z)>pG}^Ig)X+L=PLsV(RXDRRT=JmEG2)&${bkYm~c*#-jH7c|zqH$Vo!U0!;&)ridY zy^$~98ImbyoJ^OOr5=Cl#N5! z-h(({H#gQy6a=a|gx2gd_|}N0{#jSrfc*o5g-)rvz2et&^SQWXl%{jdF63*__MfAi zoTeb;OCK&%J|vpw`hFeskF}ce^sLy{*QB>G_}GJ@`WNV*=E$P#6X_@}dUd-GJYHIV zzO`zg=W4zdJnt@ZK%-x?#BlbK2cC*uM+0UOFjj=V`~y0keX`!CW9B@y{nNL``Bsg! zr?g8q0X|&BsY{<98xh~b%>L!LUWRY+j)H-9$=`5ZJ52c@>!ot)S)ix!<98|Xt%+f=L$sIWHvT%O z5nG`T89y`J+s&(W%IXhZt<+9BE=-HE`9!IC>{EK@W?k8w-m>h`n@_1$<+@qttY3Xx zZRBbTxy5*Z?1faMMEt7_8P%XhHz|OlZVfU$pEx_pZ_y(Jg46Me!WP2dkBgS?aKndQ zjskOWP>Sa8C=Z1W=?fw zRj2i;^#aYX40ZOngeGv_Pr22kym?F&4X@Kis5`v38n?2 zJPJ(!=A)-!P{1jTusUk%gncsXcZSO|VrK5R?e!@hDIRW@=s)4SdQSqpyMO=5Z+5RW zk6p?&)UGt2CRn&{rr6uSZYj|I{LgIt89kds46i|>pA0yrw>TX6K7_ltL>02OoFull zjtnruoqmf-Yy)z;6u-Qg2a|L;tBPc{_o;J*df63^za(`k<{UDX zvZ-fxgSnV0RBXG0n75egOAkyg^E_qwy+~e-(VOv}AMeZrq>jGtHF!uLq6juYc<>&_ zF2atvY9rAvivS6LQ?T4xwcIHW3E`tZ39Y9B{B-9~VeP zAD$xx!l{M2jTZ6ziD(r);rRe3mifV?0#o$XEW&yKXzE-=ztTz4zT&KL6iaHlwu5^{ zZ(?}E1!w!#m-Co+MpYH;73|8R*Nn>fVx~UD8l z{yu@U!9v?y?#eKjkJ0J`HZqlM+4A7%Ukr_r!mC#vmUA7A#K|jj;Fe;! zW_{^&gZ>@Ua|d<|IDqAOEEzW#zDoZk-;!uX4BA$upG6>{Wazgm7mb)_f;y-8cx5d1 za07i47@7gVM??0px$A#YisMFprwMWNDgD~IpZt{5d~l}&?e6~eye8oEZV0cPMK|fWcSHL(8!o^tVZ-V@*1jWWqQ#t& z(z~75d?!DUouvyEXpXE*05-!NVR}=h^v?}k4F(;ahIg<}6(dbl9QdRcoV?_$_QPv_ za{p6z$kZ2hj4eY~H3htCKWVnT>(LCWQ^{>0Fa7UTY`?P8P1KE$)yX2VPRvr&9rrh;NOEWTF z`$}d;eo2UQqK!w2_2@w%VAto!=EG3|mj_{{Rnd*vbb&$>vi}B+=o0xER`JhPvh~Cd z#JF78FWf)hS>bF|IEu};5;CU)PL1gd!j_|i`B z(w=2E&9N)I!%L1~$RhOVffV)KIIdgiMk5u| z0j4#TwUzasoFc62q6EMh5f);hN1A#(nJTPwgd{bEB--Y&Dd?tBIAt_{f!i?n=j#~f zx-&P!UvP;3(Q{`_68;CGh;?hIc`TFdXu7O?@Z91Ux_C!bsw(EHGEbVW zVGIXv0eM^JFGs*vrBxzOS@G>a!e`FWN3#B$a2E-3_%f(D^RJ6y zI=6cQu$7qg3zUu)VmSm;DWE55URqZ^SW-3naT%y*XTGw1%@A2zob635Kze_W& zt{DnTE%unHK!W{(SNHw&PXnPl!`0^xvBD^#$XmsB&=b;FW0jMz(QPD~e>Crpq0;hG zob0EcP7a{Tkdr`C2TnA>6L<}txyj74Pka*lH7KU#KkQ+D0 zdX=tpWIvoVs`{!lkx!;up}tpGI(bcwTMt(~bLmFl?>x8GdZh6(EmbLdEHB39g1kXL z#j1uZ_uiuIYZ2P5cXTbfR=qUSFCpp~|;zffXC@fi(e@gL&y}k<$_p(8s;t=DV14nhp2v#QcHP5JR z>vkXAl+gH+(fu66+}15)AP?aU8aN&nqnl7iTYof&GPUDJ4zwu#L+cR!Iz3VQ6NC?{K);GD59NHf@pi?roaA zWIgNR2zkl(gSmn6!3%Q(A&&nGFHQhk{@--tF_Us^GbNfCklPl9{N?y&6b)oG8F{E_ z#lIX=^&BCbuoOH6rn;{*!}*uvyY63(18w}h!vE}D5Y-CVP}_y29`Hs$wtxX6EIYBU z06+T>DpMfWgOLqU4K=Tb>*SWE`X(S(*O>@VLHI;2LS&YfJKF0y}u0K`hRc^gxlHu ze+Cg;)UtL>9aqsNBftxL%=r<%ouwV(I7^IPCue1nNNYxQ5$CgRZr$$TdR>s6*!qq` zD$!L9hjLN!ML?bfuu7NRim z*r=^Db6!-!eq~KMcT}h-J90r>&(!S!vJorcJTMEUeAB-m$C(Ij4w%I>w%r2&$0i6; z-IS+;u0z#!-QJUI4xmH!`Af4e+D*G2fJ5h~*Xoo@^1F=x?D%_Bb+}O+Y1^zK$ZR6P zvm?|G#Xn=`in|=F13mGeJ0!2APu0;6v_VklH5_f~eQCu$#~vY8iZVq6?v+u06AvWshdyuDlJk?N}r;sDrkXc}>pacJu+eJ;Ggq?X5G^kGxo-YAyjyE6!KlO-IYfaxX#w`lz7qRlrCPJjFpES zvIQdU_-vArLV7LMp)b+^X51;y?@{na8niwr>bO+g`+YlBHZk_Tvr|g<(!^rb_rMq5 z_6zR_jTi2$Ib?Y=jx(QbvAy2{z%7sp3J_7$f(mS@YP--~RC7K(HB=kbd^s4C$f1eR&JN0ko7}n=mn#LuH{}yh5asBl|Usu>u@`padEkHDjYpI#>dt^{CAeWmqY+ zZ7C@Luq8-}528Np!jRzgA0uaEeIC|(o`QXOq_@&0)JK5n0A2feox~|2sR8O3TwW`Xn z2OQMs_Spoc1hpOQkpmyPJEm@LVo_6J7kuQ5@^8b=2fqS2UMp>jLRkq&EjOjI?na2% z4t+0`+rP#z_vn*8Yr;1kXt61Hy_mXh=?;g?`@-M%SX?FFds2_wwB5}oeF65!UQump zogtX_sQh=UqHH0uG+5EZqIU z#@V`CiL>JM4dJEvMj)k1R+V7hh?z5rY#8~50E%35&$;Dc6~io_Cx;8# z_ki^%>{a`_Z&$FZ{S0smr9 ze8Q9gnx0fK_>3e5Voc1sGI^Z^~SMkofDnN%rh5TUoUNi2zEtV}S(|vx)@VEieA#c5!ab5dYBG4WQ<~!ow6Oq4tvY$nGfOp1Xx}2WO z!Q#a-LT4x3v0Bo6`);gf8uW+Iw&>pKD!Ag*wBAe_ZgE?Gm;Mt_+X7dd%cYjLjzW$h zpul{f8{N@($k$%;{?E$z`3IS!JH4v~(#h)1`)1ocfhAcC3Aj=->?G5K3cQtdw5ceN zcq6Z-(^Zt^@a3kG(1xFHb5btwep+m~p!`xc_W0*R9t+a}G&t*vojJz199Tc7_O2$8 zD6M0)^(5A(6#Pt_@xtQ<>X|ozf7)6duy;5Y_u9HAIe(jT2%@SUesoanLz23ZicDHi zU?$DEeY_4QU?dpXY!ypA>7DejJ8@$$&3x}sI-)da!eJ7ejpCW3F0W6LHjh?iQHX5~ z=PT>!0bkriHG`Z+x75SQxR2)|?rmLIhU=u9PB5mLG1~Cr`d9H$s5wq5Z#Y784t2<* z>OE|&%&uc;$}Fbz)K!1^Cw$8A6<7w9-3zO@j0K)nZ@uRe%a5U10{5F>8`zZG2i_Ci z^Q@W0AC&6$+Q_AtUx^odS*8i|z_g{4aFgZA3~tT5Dr#y!!zM;B3FIhsIM~|*Syx@z zC)i(Hnq!xV{6nh9wpPq0^3-33II6}NOE}Jj@E2G&@ijA{`Z2&RmFdaX;uWR5fz3{s*Z^gazJ9IZu^c|1)zoL|X zKl9praalpwy#vs*C=bY+0EYXHHpq6!k5YA`*^+ff<0_oM(-fmD90Ziop8Q06z_#-o zad!*iMY^a=dQNP)TYaW=2-(8xkaGs)Qe^p7KBuB)$qUivrUP>Xbd{10?h?>sg92MZ z^Zz8!70aS1cHdJ3~K;8Q-@#Or-RcYCo8Q%zjz(ixK zn;(o$#ZAT6UxuaGg4Xk>VK-_R)}Me{h+w*aQV#GBQdt+}2R*uU{Y8ip0_gP8t;H-& z=+hFD?;KgZxs_&t-nGMHwPrbwi{<-l-T<7f56<@~P(G_J%@HFb|IA)JP;Q+gL)RUE zW({UT1W5|OxQ3)VAmCUL5_HVH#n3nLFNZ<$67!K=sCmcP5I)$W*kN$F!g}Rr=6RrV z{g=a(j+(_r#<0Rjay}##yH@{~H=jQhF_R1T$9_1q`hr)h2eIu&xi!CYrO@CBwV9Ym zRMw8<4>9VV`Kbh$F%bcAod(^>9#KHV+}^E0wj5UVsL3(^*So1KMU0Z-$-V2mdZmO+ zxhrvE=PT9;&@Ki9??W>aAl)?!Q8p9=q4W8Mav4k2l98eHsY3xuT(M3za?W{lqFDs7{S-o* z>ZnW<`Z`LyEo0sg(KzwZdbWi5xaxS%1TJoD7DMKg(0Gp2_{&kWt?_pF&c-fS=Mriilbnz#5H`mnd6I8{VL@1w)X$1^Z6EeVn0$xX=9jX!jnd1Fy z38rCn!?0hyzESdO@A)$o(MsPI0;TJkHNtPc>|CnSmqy&8@&Y}PNZ84uT_{>#yS{P+ zVX3|w&QA9fZq?M-6uJ%}azD-&lRMYI^?r_*eCTt*B*JGuXB)IpDP7b;$8_Ih%CWN2 z3{#66t|?s&H8dB=+W!9MWp%WBrRD&@`oH2rQn$M3T`=N3fZ9?RB??}}iXn_^=|4$@ zD0G8HeEZgN%gt`HAJNw~{jRNV=ynps_M|*5`!jEs3<2}YpHeGgF6v7l2W0Lqda|_(?@l-_tV({2M{nE@o5PZ&L<|I| z!}~c`l1*Mh>ku0t)rfN0L zT3IsABkromp_+eEDeN>}L%NxmGoFxFUaTdb$&5kcr~WVOR@NMv!0T~TanHPC6e8(# z`r-+pey=LO{c1$&!P7zz@Rc5Bc&aB8RgvMPeVEt<*_>9=87CiPUQ{uf=(cA~pb{2G z51uCcYzYjUmyXP1rM%!Yuc}sV4HobxhM*7rD~x~N&I9`JFnC>V3(Copoh^yfvy)- zps`v_vkij|LTGzOUi|^{+$eSAWd_4+F(ltdh2J_)hg|uEnb0If{fL{K+l&wJm3P$y zAk%&&qZU{>w5{*x8fDeiI}9o77L*hlYG=}IDzPD6+=tNUWq&&6W@vT_?=#&=6)RF% zxu30X?CmsU>Yju3qo+5h1BgX2^C{IDtⅇSAjH(CU6Sv@m@DpebT{=`}jiaAc<7B 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 literal 0 HcmV?d00001 diff --git a/docs/img/Concept2_RowErg_Construction_tolerances.jpg b/docs/img/Concept2_RowErg_Construction_tolerances.jpg new file mode 100644 index 0000000000000000000000000000000000000000..87601bf2dfe70548047e96dd3fcd9da5d3c77df3 GIT binary patch literal 421455 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

R_CSoP-#z|mIL`Mkb|t^@KNpI;INv5C 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 literal 0 HcmV?d00001 diff --git a/docs/img/CurrentDt_curve.jpg b/docs/img/CurrentDt_curve.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c199f36cfd75de9ef436c1b38a72dcf2733f206e GIT binary patch literal 133455 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 r2`z^rp^Ppdm^b_v -In this document we explain the physics behind the OpenRowing Monitor, to allow for independent review and software maintenance. This work wouldn't have been possible without some solid physics, described by some people with real knowledge of the subject matter. Please note that any errors in our implementation probably is on us, not them. When appropriate, we link to these sources. When possible, we also link to the source code. +In this document we explain the physics behind the Open Rowing Monitor, to allow for independent review and software maintenance. This work wouldn't have been possible without some solid physics, described by some people with real knowledge of the subject matter. Please note that any errors in our implementation probably is on us, not them. When appropriate, we link to these sources. When possible, we also link to the source code. -## Leading principles +Please note that this text is used as a rationale for design decissions in Open Rowing Monitor. So it is of interest for people maintaining the code (as it explains why we do things the way we do) and for academics to verify of improve our solution. For these academics, we conclude with a section of open design issues. If you are interested in just using Open Rowing Monitor as-is, this might not be the text you are looking for. -The physics engine is the core of Open Rowing Monitor. In our design of the physics engine, we try to: +## Basic concepts -* stay as close to the original data as possible (thus depend on direct measurements as much as possible) instead of depending on derived data. This means that there are two absolute values we try to stay close to as much as possible: the **time between an impulse** and the **Number of Impulses** (their origin and meaning is later explained); +Before we analyze the physics of a rowing engine, we first need to define the basic concepts. First we identify the key physical systems at play, then we define the key phases in the rowing stroke. -* use robust calculations wherever possible (i.e. not depend on a single measurements, extrapolations or derivative functions, etc.) to reduce effects of measurement errors. +### Physical systems in a rower -## Phases, properties and concepts in the rowing cycle - -Before we analyze the physics of a rowing engine, we first need to define the basic concepts. +A rowing machine effectively has two fundamental movements: a **linear** (the rower moving up and down, or a boat moving forward) and a **rotational** where the energy that the rower inputs in the system is absorbed through a flywheel (either a solid one, or a liquid one) [[1]](#1). *A basic view of an indoor rower* -A rowing machine effectively has two fundamental movements: a **linear** (the rower moving up and down, or a boat moving forward) and a **rotational** where the energy that the rower inputs in the system is absorbed through a flywheel (either a solid one, or a liquid one). - The linear and rotational speeds are related: the stronger/faster you pull in the linear direction, the faster the flywheel will rotate. The rotation of the flywheel simulates the effect of a boat in the water: after the stroke, the boat will continue to glide only be dampened by the drag of the boat, so does the flywheel. There are several types of rowers: @@ -32,244 +28,449 @@ There are several types of rowers: * **Magnetic resistance**: where the resistance is constant -There are also hybrid rowers, which combine air resistance and magnetic resistance. The differences in physical behavior can be significant, for example a magnetic rower has a constant resistance while a air/water rower's resistance is dependent on the flywheel's speed. As the key principle is the same for all these rowers (some mass is made to spin and drag brings its speed down), we treat them the same. +There are also hybrid rowers, which combine air resistance and magnetic resistance. The differences in physical behavior can be significant, for example a magnetic rower has a constant resistance while a air/water rower's resistance is dependent on the flywheel's speed. As the key principle is the same for all these rowers (some mass is made to spin and drag brings its speed down), we currently treat them the same. + +### Phases in the rowing stroke + +What seperates rowing from many other sports is its discontinous nature: for example, in Cycling the force constantly shifts between left and right leg, but remains relatively constant throughout the rotation. In rowing, a stroke begins with a powerful *Drive* phase, which is followed by an unpowered *Recovery*. Visually, it can be depicted as follows: + +```mermaid +stateDiagram-v2 + direction LR + Drive --> Recovery + Recovery --> Drive +``` + + +*Basic phases of a rowing stroke* + +On an indoor rower, the rowing cycle will always start with a stroke, followed by a recovery. We define them as follows: + +* The **Drive phase**, where the rower pulls on the handle + +* The **Recovery Phase**, where the rower returns to his starting position + +Combined, we consider a *Drive* followed by a *Recovery* a **Stroke**. In the calculation of several metrics, the requirement is that it should include *a* *Drive* and *a* *Recovery*, but order isn't a strict requirement for some metrics [[2]](#2). We call such combination of a *Drive* and *Recovery* without perticular order a **Cycle**, which allows us to calculate these metrics twice per *stroke*. + +## Leading design principles of the rowing engine + +As described in [the architecture](Architecture.md), the rowing engine is the core of Open Rowing Monitor and consists of three major parts: + +* `engine/Flywheel.js`, which determines rotational metrics, + +* `engine/Rower.js`, which transforms rotational metrics in a rowing state and linear metrics, + +* `engine/RowingStatistics.js`, which manages session state, session metrics and optimizes metrics for presentation. + +Although the physics is well-understood and even well-described publicly (see [[1]](#1),[[2]](#2),[[3]](#3) and [[4]](#4)), applying these formulae in a practical solution for multiple rowers delivering reliable results is quite challenging. Especially small errors, noise, tends to produce visible effects on the recorded metrics. Therefore, in our design of the physics engine, we obey the following principles (see also [the architecture document](Architecture.md)): + +* stay as close to the original data as possible (thus depend on direct measurements as much as possible) instead of heavily depend on derived data. This means that there are two absolute values we try to stay close to as much as possible: the **time between an impulse** and the **Number of Impulses**, where we consider **Number of Impulses** most reliable, and **time between an impulse** reliable but containing noise (the origin and meaning of these metrics, as well the effects of this approach are explained later); + +* use robust calculations wherever possible (i.e. not depend on a single measurements, extrapolations, derivation, etc.) to reduce effects of measurement errors. A typical issue is the role of *CurrentDt*, which is often used as a divisor with small numers as Δt, increasing the effect of measurement errors in most metrics. When we do need to calculate a derived function, we choose to use a robust linear regression method to reduce the impact of noise and than use the function to calculate the derived function; + +* Be as close to the results of the Concept2 when possible and realistic, as they are considered the golden standard in indoor rowing metrics. + +## Relevant rotational metrics + +Typically, measurements are done in the rotational part of the rower, on the flywheel. There is a magnetic reed sensor or optical sensor that will measure time between either magnets or reflective stripes, which gives an **Impulse** each time a magnet or stripe passes. For example, when the flywheel rotates on a NordicTrack RX800, the passing of a magnet on the flywheel triggers a reed-switch, that delivers a pulse to our Raspberry Pi. + +Depending on the **number of impulse providers** (i.e. the number of magnets or stripes), the number of impulses per rotation increases, increasing the resolution of the measurement. As described in [the architecture](Architecture.md), Open Rowing Monitor's `GpioTimerService.js` measures the time between two subsequent impulses and reports as a *currentDt* value. The constant stream of *currentDt* values is the basis for all our angular calculations, which are typically performed in the `pushValue()` function of `engine/Flywheel.js`. + +Open Rowing Monitor needs to keep track of several metrics about the flywheel and its state, including: + +* The **Angular Distance** of the flywheel in Radians (denoted with θ): in essence the distance the flywheel has traveled (i.e. the number of Radians the flywheel has rotated) since the start of the session; + +* The **Time since start** of the flywheel in seconds (denoted with t): in essence the time the flywheel has been spinning since the start of the session; + +* The **Angular Velocity** of the flywheel in Radians \* s-1 (denoted with ω): in essence the number of (partial) rotations of the flywheel per second; + +* The **Angular Acceleration** of the flywheel in Radians \* s-2 (denoted with α): the acceleration/deceleration of the flywheel; + +* The *estimated* **drag factor** of the flywheel: the level af (air/water/magnet) resistence encountered by the flywheel, as a result of a damper setting. + +* The **Torque** of the flywheel in kg \* m2 \* s-2 (denoted with τ): the momentum of force on the flywheel. + +* Detecting power on the flywheel: whether there is a force on the flywheel. + +Being limited to the time between impulses, *currentDt*, as only measurement means we can't measure any of these metrics directly, and that we have to accept some deviations in these measurements as they are reported in discrete intervals. + +Additionally, small mechanical deviations, vibrations in the chassis (due to tiny unbalance in the flywheel) and latency inside the software stack can lead to small deviations the measurement of *currentDt*. Dealing with these deviations is an dominant issue, especially because we have to deal with a wide range machines. Aside from implementing noise reduction, we also focus on using robust calculations: calculations that don't deliver radically different results when a small measurement error is introduced in the measurement of *currentDt*. We typically avoid things like direct deriviations based on single values, as directly deriving over small values of *currentDt* with small errors typically produce huge deviations in the resulting estimate. As an alternative, we use (robust) regression over multiple values, and use the deriviations of the resulting function instead. We do this at the cost of reducing the accuracy of the data, as this approach tends to dampen real occuring peaks in the stroke data. However, this inaccuracy with respect to the perfect theoretical model is needed to prevent estimates to become too unstable for practical use or which can only be used with heavy smoothing later on in the process (typically smoothing across strokes by `engine/RowingStatistics.js`). + +### Determining the "Time since start" of the flywheel + +This can easily be measured by summarising the **time between an impulse**. Noise has little to no impact to this metric as on average the noise cancels out. + +### Determining the "Angular Position" of the flywheel + +As the impulse-givers are evenly spread over the flywheel, this can be robustly measured by counting the total number of impulses, **Number of Impulses**, and multiply it with the **angular displacement** between two **impulses** (i.e. ${2π \over number of impulse providers on the flywheel}$). + +In theory, there are two threats here: + +* Potentially missed impulses due to sticking sensors or too short intervals for the Raspberry Pi to detect them. So far, this hasn't happened. +* Ghost impulses, typically caused by **debounce** effects of the sensor. Up till now, some reports have been seen of this, where the best resolution was a better mechanical construction of magnets and sensors. + +### Determining the "Angular Velocity" and "Angular Acceleration" of the flywheel + +The traditional approach [[1]](#1), [[8]](#8), [[13]](#13) suggeste a numerical approach to Angular Velocity ω: + +> $$ ω = {Δθ \over Δt} $$ + +This formula is dependent on Δt, which is suspect to noise, making this numerical approach to the calculation of ω volatile. From a more robust perspective, we approach ω as the the first derivative of the function between *time since start* and the angular position θ, where we use a robust regression algorithm to determine the function and thus the first derivative. + +The traditional numerical approach [[1]](#1), [[8]](#8), [[13]](#13) Angular Acceleration α would be: + +> $$ α = {Δω \over Δt} $$ + +Again, the presence of Δt would make this alculation of α volatile. From a more robust perspective, we approach α as the the second derivative of the function between *time since start* and the angular position θ, where we use a robust regression algorithm to determine the function and thus the second derivative. + +Summarizing, both Angular Velocity ω and Angular Acceleration α are determined through the same regression algorithm based on the derivatives of the function between *time since start* and the angular position θ, where the first derivative of the function represents the Angular Velocity ω and the second derivative represents the Angular Acceleration α. + +### Determining the "drag factor" of the flywheel + +In the recovery phase, the only force exerted on the flywheel is the (air-/water-/magnetic-)resistance. Thus we can calculate the *drag factor of the flywheel* based on deceleration through the recovery phase [[1]](#1). This calculation is performed in the `markRecoveryPhaseCompleted()` function of `engine/Flywheel.js`. + +A first numerical approach is presented by through [[1]](#1) in formula 7.2a: + +> $$ k = - I \* {Δω \over Δt} * {1 \over Δω^2} $$ + +Where the resulting k should be averaged across the rotations of the flywheel. The downside of this approach is that it introduces Δt in the divider of the drag calculation, making this calculation potentially volatile. Our practical experience based on testing confirms this valatility. An alternative numerical approach is presented by through [[1]](#1) in formula 7.2b: + +> $$ k = -I \* {Δ({1 \over ω}) \over Δt} $$ + +Where this is calculated across the entire recovery phase. Again, the presence of Δt in the divider potentially introduces a type of undesired volatility. Testing has shown that even when Δt is chosen to span the entire recovery phase reliably, reducing the effect of single values of *CurrentDt*, the calculated drag factor is more stable but still is too unstable to be used as is: it typically requires averaging across strokes to prevent drag poisoning. + +To make this calculation more robust, we again turn to regression methods (as suggested by [[7]](#7)). We can transform formula 7.2 to the definition of the slope of a line, by doing the following: + +> $$ { k \over I } = {Δ({1 \over ω}) \over Δt} $$ + +Thus k/I represents the slope of the graph depicted by *time since start* on the *x*-axis and ${1 \over ω}$ on the *y*-axis, during the recovery phase of the stroke. However, this formula can be simplified further, as the angular velocity ω is determined by: + +> $$ ω = {({2π \over Impulses Per Rotation}) \over currentDt} $$ -Typically, measurements are done in the rotational part of the rower, on the flywheel. There is a reed sensor or optical sensor that will measure time between either magnets or reflective stripes, which gives an **Impulse** each time a magnet or stripe passes. Depending on the **number of impulse providers** (i.e. the number of magnets or stripes), the number of impulses per rotation increases, increasing the resolution of the measurement. By measuring the **time between impulses**, deductions about speed and acceleration of the flywheel can be made, and thus the effort of the rower. +thus making: -## What a rowing machine actually measures +> $$ { k \over I } = {Δ({1 \over {({2π \over Impulses Per Rotation}) \over currentDt}}) \over Δt} $$ -As mentioned above, most rowers depend on measuring the **time between impulses**, triggered by some impulse giver (magnet or light) on the flywheel. For example, when the flywheel rotates on a NordicTrack RX800, the passing of a magnet on the flywheel triggers a reed-switch, that delivers a pulse to our Raspberry Pi. We measure the time between two subsequent impulses and call this *currentDt*: the time between two impulses. *currentDt* is the basis for all our calculations. +removing the division, results in + +> $$ { k \over I } = {Δ(currentDt \* {Impulses Per Rotation \over 2π}) \over Δt} $$ + +Since we are multiplying *currentDt* with a constant factor (i.e. ${Impulses Per Rotation \over 2π}$), we can further simplify the formula by moving this multiplication outside the slope-calculation. Effectively, making the formula: + +> $$ {k \* 2π \over I \* Impulses Per Rotation} = {ΔcurrentDt \over Δt} $$ + +As the left-hand of the equation only contains constants and the dragfactor, and the right-hand a division of two delta's, we can use regression to calculate the drag. As the slope of the line *currentDt* over *time since start* is equal to ${k \* 2π \over I \* Impulses Per Rotation}$, the drag thus can be determined through + +> $$ k = slope \* {I \* Impulses Per Rotation \over 2π} $$ + +As this formula shows, the drag factor is effectively determined by the slope of the line created by *time since start* on the *x*-axis and the corresponding *CurrentDt* on the *y*-axis, for each recovery phase. + +This slope can be determined through linear regression (see [[5]](#5) and [[6]](#6)) for the collection of datapoints for a specific recovery phase. This approach also brings this calculation as close as possible to the raw data, and doesn't use individual *currentDt*'s as a divider, which are explicit design goals to reduce data volatility. Although simple linear regression (OLS) isn't robust in nature, its algorithm has proven to be sufficiently robust to be applied, especially when filtering on low R2. On a Concept2, the typical R2 is around 0.96 for steady state rowing. The approach of using r2 has the benefit of completely relying on metrics contained in the algorithm itself for quality control: the algorithm itself signals a bad fit due to too much noise in the calculation. Alternative approaches typically rely on cross-stroke repeatability of the drag calculation, which could ignore drag changes despite a good fit with the data. Practical experiments show that an R2-based filter outperforms any other across-stroke noise dampening filter. + +### Determining the "Torque" of the flywheel + +The torque τ on the flywheel can be determined based on formula 8.1 [[1]](#1): + +> $$ τ = I \* ({Δω \over Δt}) + D $$ + +As ${Δω \over Δt}$ = α and D = k \* ω2 (formula 3.4, [[1]](#1)), we can simplify this further by: + +> $$ τ = I \* α + k \* ω^2 $$ + +As α and ω have been derived in a robust manner, and there are no alternative more robust approaches to determining instant τ that allows for handle force curves, we consider this the best attainable result. Testing shows that the results are quite useable. + +### Detecting force on the flywheel + +One of the key elements of rowing is detecting the stroke phases and thus calculate the associated metrics. From the perspective of Open Rowing Monitor, there only is a stream of *CurrentDt*'s, which should form the basis of this detection: The following picture shows the time between impulses through time: ![Measurements of flywheel](img/physics/flywheelmeasurement.png) *Measurements of flywheel* -Here, it is clear that the flywheel first accelerates and then decelerates, which is typical for rowing. +Open Rowing Monitor combines two types of force detection, which work independently: *basic force detection* and *advanced stroke detection*. Both can detect a stroke accuratly, and the combination has proven its use. -Using *currentDt* means we can't measure anything directly aside from *angular displacement*, and that we have to accept some noise in measurements. For example, as we don't measure torque on the flywheel directly, we can't determine where the flywheel exactly accelerates/decelerates, we can only detect a change in the times between impulses. In essence, we only can conclude that an acceleration has taken place somewhere near a specific impulse, but we can't be certain about where the acceleration exactly has taken place and we can only estimate how big the force must have been. Additionally, small vibrations in the chassis due to tiny unbalance in the flywheel can lead to small deviations in measurements. This kind of noise in our measurement can make many subsequent derived calculation on this measurement too volatile, This is why we explicitly distinguish between *measurements* and *estimates* based on these measurements, to clearly indicate their potential volatility. +In `engine/Flywheel.js`, two functions provide force detection: -Dealing with noise is an dominant issue, especially because we have to deal with many types of machines. Aside from implementing a lot of noise reduction, we also focus on using robust calculations: calculations that don't deliver radically different results when a small measurement error is introduced in the measurement of *currentDt*. We typically avoid things like derived functions when possible, as deriving over small values of *currentDt* typically produce huge deviations in the resulting estimate. We sometimes even do this at the cost of inaccuracy with respect to the perfect theoretical model, as long as the deviation is systematic in one direction, to prevent estimates to become too unstable for practical use. +* `isUnpowered()`: which indicates that the simple or the advanced force detection indicate that a force is absent; -## The rowing cycle and detecting the stroke and recovery phase +* `isPowered()`: which indicates that both the simple or the advanced force detection indicate that a force is present. -On an indoor rower, the rowing cycle will always start with a stroke, followed by a recovery. Looking at a stroke, our monitor gets the following data from its sensor: +The choice for the logical relations between the two types of force detection is based on testing: where a sudden presence of force on a flywheel (i.e. the start of a drive) is quite easily and consistently detected, its abscence has proven to be more difficult. In practice, the beginning of a drive is easily recognised as strong leg muscles excert much force onto the flywheel in a very short period of time. The end of the drive is more difficult to assess, as the dragforce of the flywheel increases with its speed, and the weaker arm muscles have taken over, making the transition to the recovery much harder to detect. In theory, in the end of the drive phase the drag force might be bigger than the force from the arms, resulting in an overall negative torque. + +In the remainder of this paragraph, we describe the underlying physics of these force detection methods. + +#### Basic force detection + +One of the key indicator is the acceleration/decelleration of the flywheel. Looking at a simple visualisation of the rowing stroke, we try to achieve the following: ![Impulses, impulse lengths and rowing cycle phases](img/physics/rowingcycle.png) *Impulses, impulse lengths and rowing cycle phases* -Here, we plot the *currentDt* (time between impulses) against its sequence number. So, a high *currentDt* means a long time between impulses (so a low *angular velocity*), and a low *currentDt* means that there is a short time between impulses (so a high *angular velocity*). As this figure also shows, we split the rowing cycle in two distinct phases: - -* The **Drive phase**, where the rower pulls on the handle +Here we plot the *currentDt* against its sequence number. So, a high *currentDt* means a long time between impulses (so a low *angular velocity*), and a low *currentDt* means that there is a short time between impulses (so a high *angular velocity*). -* The **Recovery Phase**, where the rower returns to his starting position +Here, it is clear that the flywheel first accelerates (i.e. the time between impulses become smaller), suggesting a powered flywheel. Next it decelerates (i.e. the time between impulses become bigger), which suggests an unpowered flywheel. This pattern is typical for the rowing motion. -As the rowing cycle always follows this fixed schema, Open Rowing Monitor models it as a finite state machine (implemented in `handleRotationImpulse` in `engine/RowingEngine.js`). +The simple force detection uses this approach by looking at the slope of *currentDt* over time. Given that the *Angular Displacement* between impulses is fixed, we can deduct some things simply from looking at the subsequent *time between impulses*, *currentDt*. When the *currentDt* shortens, *Angular Velocity* is increasing, and thus the flywheel is accelerating (i.e. we are in the drive phase of the rowing cycle). When times between subsequent impulses become longer, the *Angular Velocity* is decreasing and thus the flywheel is decelerating (i.e. we are the recovery phase of the rowing cycle). As a rough but very robust approximation, a descending (negative) slope indicates a powered flywheel, an (positive) ascending slope indicates an unpowered flywheel. This approach seems to be similar to the implementation used by industry leaders like Concept2. Concept2 are generally considered the golden standard when it comes to metrics, and they state (see [this Concept2 FAQ](https://www.concept2.com/service/software/ergdata/faqs): -![Finite state machine of rowing cycle](img/physics/finitestatemachine.png) -*Finite state machine of rowing cycle* +> Drive time is measured by the amount of time the flywheel is accelerating. Note: It is possible that the athlete may pull on the handle and not accelerate the flywheel due to no energy being put into it and therefore no effective effort. This portion of the handle pull is not measured. -### Basic stroke detection +A more nuanced, but more vulnerable, approach is to compare the slope of this function with the typical slope encountered during the recovery phase of the stroke (which routinely is determined during the drag calculation). When the flywheel is unpowered, the slope will be close to the recovery slope, and otherwise it is powered. This is a more accurate, but more vulnerable, approach, as small deviations could lead to missed strokes. It is noted that practical testing has shown that this works reliably for many machines. -Given that the *Angular Displacement* between impulses is fixed, we can deduct some things simply from looking at the subsequent *time between impulses*, *currentDt*. When the *currentDt* shortens, *Angular Velocity* is increasing, and thus the flywheel is accelerating (i.e. we are in the drive phase of the rowing cycle). When times between subsequent impulses become longer, the *Angular Velocity* is decreasing and thus the flywheel is decelerating (i.e. we are the recovery phase of the rowing cycle). This is the robust implementation of a stroke (implemented in MovingFlankDetector's implementation of isFlywheelPowered and isFlywheelUnpowered for naturalDeceleration = 0 in `engine/MovingFlankDetector.js`), which is similar to the implementation used by industry leaders like Concept2. Concept2 are generally considered the golden standard when it comes to metrics, and they state (see [this Concept2 FAQ](https://www.concept2.com/service/software/ergdata/faqs): 'Drive time is measured by the amount of time the flywheel is accelerating. Note: It is possible that the athlete may pull on the handle and not accelerate the flywheel due to no energy being put into it and therefore no effective effort. This portion of the handle pull is not measured.') +In Open Rowing Monitor, the settings allow for using the more robust ascending/descending approach (by setting *minumumRecoverySlope* to 0), for a more accurate approach (by setting *minumumRecoverySlope* to a static value) or even a dynamic approach (by setting *autoAdjustRecoverySlope* to true) -### Advanced stroke detection +#### Advanced force detection -Looking at the average curve of an actual rowing machine (this example is based on averaging 300 strokes), we see the following: +The more advanced, but more vulnerable approach depends on the calculated torque. When looking at *CurrentDt* and Torque over time, we get the following picture: ![Average curves of a rowing machine](img/physics/currentdtandacceleration.png) *Average currentDt (red) and Acceleration (blue) of a single stroke on a rowing machine* -In this graph, we plot *currentDt* against the time in the stroke, averaged over 300 strokes. As *currentDt* is (reversely) related to angular velocity, we can calculate the angular acceleration/deceleration. In essence, as soon as the acceleration becomes below the 0, the currentDt begins to lengthen again (i.e. the flywheel is decelerating). As indicated earlier, this is the trigger for the robust stroke detection algorithm (i.e. the one used when naturalDeceleration is set to 0): when the *currentDt* starts to lengthen, the drive-phase is considered complete. +In this graph, we plot *currentDt* and Torque against the time in the stroke. As soon as the Torque of the flywheel becomes below the 0, the *currentDt* begins to lengthen again (i.e. the flywheel is decelerating). As indicated earlier, this is the trigger for the basic force detection algorithm (i.e. when *minumumRecoverySlope* is set to 0): when the *currentDt* starts to lengthen, the drive-phase is considered complete. -However, from the acceleration/deceleration curve it is also clear that despite the deceleration, there is still a force present: the deceleration-curve hasn't reached its stable minimum despite crossing 0. This is due to the pull still continuing through the arms: the net force is negative due to a part drive-phase (the arm-movement) delivering weaker forces than the drag-forces of the flywheel. Despite being weaker than the other forces on the flywheel, the rower is still working. In this specific example, at around 0.52 sec the rower's force was weaker than all drag-forces combined. However, only at 0,67 seconds (thus approx. 150 ms later) the net force reaches its stable bottom: the only force present is the drag from the flywheel. Getting closer to this moment is a goal. +However, from the acceleration/deceleration curve it is also clear that despite the deceleration, there is still a force present: the Torque-curve hasn't reached its stable minimum despite crossing 0. This is due to the pull still continuing through the arms: the net force is negative due to a part drive-phase (the arm-movement) delivering weaker forces than the drag-forces of the flywheel. Despite being weaker than the other forces on the flywheel, the rower is still working. In this specific example, at around 0.52 sec the rower's force was weaker than all drag-forces combined. However, only at 0,67 seconds (thus approx. 150 ms later) the net force reaches its stable bottom: the only force present is the drag from the flywheel. Getting closer to this moment is a goal. -By specifying the expected natural deceleration of the flywheel (naturalDeceleration, which in this case is around 8 Rad/S^2) in the configuration of the rower, the stroke starts earlier and ends later (implemented in MovingFlankDetector's implementation of isFlywheelPowered and isFlywheelUnpowered for naturalDeceleration < 0 in `engine/MovingFlankDetector.js`). Please note: as several derived metrics depend on the length of the drive phase or the exact timing of that moment (like the drag factor when calculated dynamically), these are likely to change when this setting is changed. For a more in-depth explanation, see [here for more details](physics_openrowingmonitor.md#a-closer-look-at-the-effects-of-the-various-drive-and-recovery-phase-detection). +We do this by setting a minimum Torque (through setting *minumumForceBeforeStroke*) before a Drive phase can be initiated. -Testing shows that setting a value close to the natural deceleration provides more accurate results very reliably. However, some rowers might contain a lot of noise in their data, making this approach infeasible (hence the fallback option of naturalDeceleration = 0) +#### A note about detection accuracy -This approach is a better approximation than the acceleration/deceleration approach, but still is not perfect. For example, drag-force of the the rower presented in the above graph slowly reduces. This is expected, as the drag-force is speed dependent. For a pure air-rower, the best theoretical approach would be to see if the drag-force is the only force present by calculating the expected drag-force using the current speed and the drag factor (making the stroke detection completely independent on speed). Testing has shown that this approach is too prone to errors, as it requires another derivation with respect to *currentDt*, making it too volatile. Above this, hybrid rower behave differently as well: dependent on the speed, the balance shifts between the speed-dependent air-resistance drag-force and the speed-independent magnetic resistance force. To make the solution robust and broadly applicable, this approach has been abandoned. +Open Rowing Monitor only will get impulses at discrete points in time. As Open Rowing Monitor doesn't measure torque on the flywheel directly, it can't determine where the flywheel exactly accelerates/decelerates as there is no continous measurement. Open Rowing Monitor can only detect a change in the times across several impulses, but it can't detect the exact time of torque change. In essence, at best we only can conclude that the torque has changes somewhere near a specific impulse, but we can't be certain about where the acceleration exactly has taken place and we can only estimate how big the force must have been. -## Key physical metrics during the rowing cycle +## Relevant linear metrics -There are several key metrics that underpin the performance measurement of a rowing stroke. Here, we distinguish the following concepts: +Knowing that *Time since start*, Angular Velocity ω, Angular Acceleration α, flywheel Torque τ and dragfactor k have been determined in a robust manner by `engine/Flywheel.js`, `engine/Rower.js` can now transform these key rotational metrics in linear metrics. This is done in the `handleRotationImpulse()` function of `engine/Rower.js`, where based on the flywheel state, the relevant metrics are calculated. The following metrics need to be determined: -* The **Angular Displacement** of the flywheel in Radians: in essence the distance the flywheel has traveled (i.e. the number of Radians the flywheel has rotated). As the impulse-givers are evenly spread over the flywheel, the **angular displacement** between two **impulses** is 2π/(*number of impulse providers on the flywheel*). This can easily be measured by counting the number of impulses; +* The estimated **power produced** by the rower (in Watts): the power the rower produced during the stroke; -* The **Angular Velocity** of the flywheel in Radians/second: in essence the number of (partial) rotations of the flywheel per second. As the *Angular Displacement* is fixed for a specific rowing machine, the *Angular Velocity* is (*angular displacement between impulses*) / (time between impulses); +* The estimated **Linear Velocity** of the boat (in Meters/Second): the speed at which the boat is expected to travel; -* The **Angular Acceleration** of the flywheel (in Radians/second^2): the acceleration/deceleration of the flywheel; +* The estimated **Linear Distance** of the boat (in Meters): the distance the boat is expected to travel; -* The *estimated* **Linear Distance** of the boat (in Meters): the distance the boat is expected to travel; +* The estimated **Drive length** (in meters): the estimated distance travelled by the handle during the drive phase; -* *estimated* **Linear Velocity** of the boat (in Meters/Second): the speed at which the boat is expected to travel. +* The estimated **speed of the handle** (in m/s): the speed the handle/chain/belt of the rower; -## Measurements during the recovery phase +* The estimated **force on the handle** (in Newtons): the force excerted on the handle/chain/belt of the rower; -Although not the first phase in a cycle, it is an important phase as it deducts specific information about the flywheel properties [[1]](#1). During the recovery-phase, we can *measure* the number of impulses and the length of each impulse. Some things we can easily *estimate* with a decent accuracy based on the data at the end of the recovery phase: +* The estimated **power on the handle** (in Watts): the power on the handle/chain/belt of the rower; -* The length of time between the start and end of the recovery phase +### Power produced -* The angular displacement between the start and end of the recovery - phase +As the only source for adding energy to the rotational part of the rower is the linear part of the rower, the power calculation is the key calculation to translate between rotational and linear metrics. -* The angular velocity at the beginning and end of the recovery phase +We can calculate the energy added to the flywheel through [[1]](#1), formula 8.2: -In the recovery phase, the only force exerted on the flywheel is the (air/water/magnetic)resistance. Thus we can calculate the Drag factor of the Flywheel based on the entire phase. +> $$ ΔE = I \* ({Δω \over Δt}) \* Δθ + k \* ω^2 \* Δθ $$ -As [[1]](#1) describes in formula 7.2, which is also experimentally verified by Nomath on a Concept 2 [[5]](#5): +The power then becomes [[1]](#1), formula 8.3: -> +> $$ P = {ΔE \over Δt} $$ -Or in more readable form: +Combining these formulae, makes -> +> $$ P = I \* ({Δω \over Δt}) \* ω + k \* ω^3 $$ -Looking at the linear speed, we use the following formula [[1]](#1), formula 9.3: +Although this is an easy technical implementable algorithm by calculating a running sum of this function (see [[3]](#3), and more specifically [[4]](#4)). However, the presence of the many small ω's makes the outcome of this calculation quite volatile, even despite the robust underlying calculation for ω. Calculating this across the stroke might be an option, but the presence of Δω would make the power calculation highly dependent on both accurate stroke detection and the accurate determination of instantanous ω. -> +An alternative approach is given in [[1]](#1), [[2]](#2) and [[3]](#3), which describe that power on a Concept 2 is determined through ([[1]](#1) formula 9.1), which proposes: -Or in more readable form: +> $$ \overline{P} = k \* \overline{\omega}^3 $$ -> +Where $\overline{P}$ is the average power and $\overline{\omega}$ is the average angular velocity during the stroke. Here, the average speed can be determined in a robust manner (i.e. ${Δθ \over Δt}$ for sufficiently large Δt). -Looking at the linear speed, we use the following formula [[1]](#1), formula 9.2: +Dave Venrooy indicates that this formula is accurate with a 5% margin [[3]](#3). Testing this on live data confirms this behavior. Academic research on the accuracy of the Concept 2 RowErg PM5's power measurements [[15]](#15) shows that: -> +* It seems that Concept 2 is also using this simplified formula, or something quite similar, in the PM5; -Or in more readable form: +* For stable steady state rowing, the results of this approach are quite reliable; -> +* For unstable rowing, the power calcuation is not reliable. The article seems to suggest that this is caused by ommitting the element of ${I \* ({Δω \over Δt}) \* ω}$, essentially assuming that Δω is near zero across strokes. This is problematic at moments of deliberate acceleration across strokes (like starts and sprints), where Δω can be very significant, and at unstable rowing, where there also can be a sigificant Δω present across strokes. -## Measurements during the drive phase +Still, we currently choose to use $\overline{P}$ = k \* $\overline{ω}$3 for all power calculations, for several reasons: -During the drive-phase, we again can *measure* the number of impulses and the length of each impulse. Some things we can easily *estimate* with a decent accuracy based on the data at the end of the drive phase: +* Despite its flaws, Concept 2's PM5 is widely regarded as the golden standard in rowing. For us, we rather stay close to this golden standard than make a change without the guarantee of delivering more accurate and robust results than Concept 2's PM5; -* The length of time between the start and end of the drive phase +* The simpler algorithm removes any dependence on instantaneous angular velocities ω at the flanks of the stroke from the power calculation and subsequent linear calculations. This makes the power calculation (and thus any subsequent calculations that are based on it) more robust against "unexpected" behavior of the rowing machine. There are several underlying causes for the need to remove this dependence: + * First of all, measurement errors in *CurrentDt* could introduce variations in Δω across the cycle and thus in all dependent linear metrics; + * Secondly, water rowers are known to experience cavitation effects at the end of the Drive Phase when used with sub-optimal technique, leading to extremely volatile results; + * Last, the determination of Δω across a stroke heavily depends on a very repeatable stroke detection that minimizes Δω to 0 during a stable series of stroke in steady state rowing. Such a repeatable stroke detection across the many types of rowing machines in itself is difficult to achieve; -* The angular displacement between the start and end of the drive phase +* As the *flywheelinertia* I is mostly guessed based on its effects on the Power outcome anyway (as most users aren't willing to take their rower apart for callibration purposses), a systematic error wouldn't matter much in most practical applications as it is corrected during the callibration of a monitor: the *flywheelinertia* will simply be modified to get to the correct power in the display. -* The angular velocity at the beginning and end of the drive phase +* It allows the user to removing/disabling all instantaneous angular velocities from linear metric calculations (i.e. only using average angular velocity calculated over the entire phase, which doesn't depend on a single measurement) by setting *autoAdjustDragFactor* to "false". This makes Open Rowing Monitor a viable option for rowers with noisy data or otherwise unstable/unreliable individual measurements; -Looking at the linear speed, we use the following formula [[1]](#1), formula 9.3: +* Given the stability of the measurements, it might be a realistic option for users to remove the filter in the presentation layer completely by setting *numOfPhasesForAveragingScreenData* to 2, making the monitor much more responsive to user actions. -> +Given these advantages and that in practice it won't have a practical implications for users, we have chosen to use the robust implementation. It should be noted that this definition is also robust against missed strokes: a missed drive or recovery phase will lump two strokes together, but as the Average Angular Velocity $\overline{ω}$ will average out across these strokes, it will not be affected in practice. -Or in more readable form: +### Linear Velocity -> +In [[1]](#1) and [[2]](#2), it is described that power on a Concept 2 is determined through (formula 9.1): -Looking at the linear speed, we use the following formula [[1]](#1), formula 9.2: +> $$ \overline{P} = k \* \overline{\omega}^3 = c \* \overline{u}^3 $$ -> +Where c is a constant (2.8 according to [[1]](#1)), $\overline{\omega}$ the average angular velocity and $\overline{u}$ is the average linear velocity, making this formula the essential pivot between rotational and linear velocity and distance. -Or in more readable form: +However, in [[1]](#1) and [[2]](#2), it is suggested that power on a Concept 2 might be determined through (formula 9.4, [[1]](#1)): -> +> $$ \overline{P} = 4.31 \* \overline{u}^{2.75} $$ -## Power calculation +Based on a simple experiment, downloading the exported data of several rowing sessions from Concept 2's logbook, and comparing the reported velocity and power, it can easily be determined that $\overline{P}$ = 2.8 \* $\overline{u}$3 offers a much better fit with the data than $\overline{P}$ = 4.31 \* $\overline{u}$2.75 provides. Therefore, we choose to use formula 9.1. Baed on this, we thus adopt formula 9.1 (from [[1]](#1)) for the calculation of linear velocity u: -In the drive phase, the rower also puts a force on the flywheel, making it accelerate. +> $$ \overline{u} = ({k \over C})^{1/3} * \overline{\omega} $$ -We can calculate the energy added to the flywheel through [[1]](#1), formula 8.2: +As both k and ω can change from cycle to cycle, this calculation should be performed for each cycle. It should be noted that this formula is also robust against missed strokes: a missed drive or recovery phase will lump two strokes together, but as the Average Angular Velocity $\overline{\omega}$ will average out across these strokes. Although undesired behaviour in itself, it will isolate linear velocity calculations from errors in the stroke detection in practice. + +### Linear distance + +[[1]](#1)'s formula 9.3 provides a formula for linear distance: + +> $$ s = ({k \over C})^{1/3} * θ $$ -> +Here, as k can slightly change from cycle to cycle, this calculation should be performed at least once for each cycle. As θ isn't dependent on stroke state and changes constantly, it could be recalculated continously throughout the stroke, providing the user with direct feedback of his stroke. It should be noted that this formula is also robust against missed strokes: a missed drive or recovery phase will lump two strokes together, but as the angular displacement θ is stroke independent, it will not be affected by it at all. Although missing strokes is undesired behaviour, this approach isolates linear distance calculations from errors in the stroke detection in practice. -Or in more readable form for each measured displacement: +### Drive length -> -> +Given the distance travelled by the handle can be calculated from angular distance θ traveled by the sprocket during the Drive Phase. During the drive, the angular distance travelled by the flywheel is identical to the angular distance θ travelled by the flywheel during the drive phase. Thus -Where +> $$ s_{Handle} = \text{number of rotations of the flywheel} \* \text{circumference of the sprocket} $$ -> +As the number of rotations of the flywheel = ${\theta \over 2\pi}$ and the circumference of the sprocket = r * 2π, where r is the radius of the sprocket that is connected to the flywheel, we can translate this formula into: -The power then becomes +> $$ s_{Handle} = {\theta \over 2\pi} * r * 2\pi $$ -> +Which can be simplified into: -Although this is an easy implementable algorithm by calculating a running sum of this function (see [[3]](#3), and more specifically [[4]](#4)). However, the presence of the many Angular Velocities makes the outcome of this calculation quite volatile. The angulate velocity is measured through the formula: +> $$ s_{Handle} = θ * r $$ -> +Where r is the radius of the sprocket in meters and θ the angular distance travelled by the flywheel during the drive. -As *currentDt* tends to be small (typically much smaller than 1, typically between 0,1 and 0,0015 seconds), small errors tend to increase the Angular Velocity significantly, enlarging the effect of an error and potentially causing this volatility. An approach is to use a running average on the presentation layer (in `RowingStatistics.js`). However, when this is bypassed, data shows significant spikes of 20Watts in quite stable cycles due to small changes in the data. +### Handle Velocity -An alternative approach is given by [[3]](#3), which proposes +As the distance travelled by the handle is ${u_{Handle} = θ * r}$, we can decuct: -> +> $$ u_{Handle} = ω \* r $$ -Where P is the average power and ω is the average speed during the stroke. Here, the average speed can be determined in a robust manner (i.e. Angular Displacement of the Drive Phase / DriveLength). +Here, ω can be the instantanous or average angular velocity of the flyhweel in Radians, and r is the radius of the sprocket (in meters). -As Dave Venrooy indicates this is accurate with a 5% margin. Testing this on live data confirms this behavior (tested with a *autoAdjustDragFactor* = true, to maximize noise-effects), with three added observations: +### Handle Force -* The robust algorithm is structurally below the more precise measurement when it comes to total power produced in a 30 minutes or 15 minutes row on a RX800 with any damper setting; +From theory [[12]](#12)) and practical application [[7]](#7), we know the handle force is equal to: -* The robust algorithm is indeed much less volatile: the spikes found in the more precise algorithm are much bigger than the ones found in the robust algorithm +> $$ F_{Handle} = {τ \over r} $$ -* A test with *numOfPhasesForAveragingScreenData* = 1 (practically bypassing the running average in the presentation layer) combined with the robust algorithm shows that the monitor is a bit more responsive but doesn't fluctuate unexpectedly. +Where r is the radius of the sprocket in meters. -As the *flywheelinertia* is mostly guessed based on its effects on the Power outcome anyway (as nobody is willing to take his rower apart for this), the 5% error wouldn't matter much anyway: the *flywheelinertia* will simply become 5% more to get to the same power in the display. Therefore, we choose to use the simpler more robust algorithm, as it has some advantages: +### Handle Power -* In essence the instantaneous angular velocities at the flanks are removed from the power measurement, making it more robust against "unexpected" behavior of the rowers (like the cavitation-like effects found in LiquidFlywheel Rowers). Regardless of settings, only instantaneous angular velocities that affect displayed data are the start and begin of each phase; +From theory [[13]](#13)), we know that the handle Power is -* Setting *autoAdjustDragFactor* to "false" effectively removes/disables all calculations with instantaneous angular velocities (only average velocity is calculated over the entire phase, which typically is not on a single measurement), making Open Rowing Monitor an option for rowers with noisy data or otherwise unstable/unreliable measurements; +> $$ P_{Handle} = τ * ω $$ -* Given the stability of the measurements, it might be a realistic option for users to remove the filter in the presentation layer completely by setting *numOfPhasesForAveragingScreenData* to 1, making the monitor much more responsive to user actions. +## Detecting the stroke phase -Given these advantages and that in practice it won't have a practical implications for users, we have chosen to use the robust implementation. +Knowing that `engine/Flywheel.js` has determined whether there is a force on the flywheel, `engine/Rower.js` can now transform this into the phase of the rowing stroke. On an indoor rower, the rowing cycle will always start with a stroke, followed by a recovery. This results in the follwing phases: -## Additional considerations for the frequency of the metrics calculations +* The **Drive phase**, where the rower pulls on the handle, some force on the flywheel is excerted and the flywheel is accelerating or at least not decelerating in accordance with the drag; -There are some additional options for the frequency of metric calculations: +* The **Recovery Phase**, where the rower returns to his starting position and the flywheel decelerates as the drag on the flywheel is slowing it down; -* An option would be to update the metrics only updated at the end of stroke, which is once every 2 to 3 seconds. This is undesirable as a typical stroke takes around 2.5 seconds to complete and covers around 10 meters. It is very desirable to update typical end-criteria for trainings that change quite quickly (i.e. absolute distance, elapsed time) more frequently than that; +As the rowing cycle always follows this fixed schema, Open Rowing Monitor models it as a finite state machine (implemented in `handleRotationImpulse` in `engine/Rower.js`). -* We additionally update the metrics (when dependent on the stroke dependent parameters, like stroke length) both at the end of the Drive and Recovery Phases, as Marinus van Holst [[2]](#2) suggests that both are valid perspectives on the stroke. This allows for a recalculation of these metrics twice per stroke; +```mermaid +stateDiagram-v2 + direction LR + Drive --> Recovery: Flywheel
isn't powered + Drive --> Drive: Flywheel
is powered + Recovery --> Drive: Flywheel
is powered + Recovery --> Recovery: Flywheel
isn't powered +``` + + +*Finite state machine of rowing cycle* -* To allow for a very frequent update of the monitor, and allow for testing for typical end-criteria for trainings that change quite quickly (i.e. absolute distance, elapsed time), we calculate these for each new *currentDt*; +## A mathematical perspective on key metrics -* As we can only calculate the drag factor at the end of the recovery phase, we can only (retrospectively) apply it to the realized linear distance of that same recovery phase. Therefore, we we need to report absolute time and distance from the `RowingEngine` in `engine/RowingEngine.js`); +### Noise Filtering algorithms applied -## A closer look at the effects of the various Drive and Recovery phase detection +For noise filtering, we use a moving median filter, which has the benefit of removing outliers completely. This is more robust than the moving average, where the effect of outliers is reduced, but not removed. -In this section, we will answer the question whether Concept2 made a big error in their stroke detection, and thus that using *naturalDeceleration* is set to 0 is inferior to actually setting it to a different value. The short answer is that Concept2 has made a perfectly acceptable tradeoff between reliability of the stroke detection and precision of some metrics. +### Linear regression algorithms applied for slope determination -Effectively, Open Rowing Monitor can use two different methods of stroke detection. When *naturalDeceleration* is set to 0, it will detect an acceleration/deceleration directly based on *currentDt*, similar to Concept2. When *naturalDeceleration* is set to a negative number, it will consider that number as the minimum level of deceleration (in Rad/S^2). The later is more volatile, as described above, but some consider this desirable when possible. +There are several different linear regression methods [[9]](#9). We have several requirements on the algorithm: -Our practical experiments show that assuming the recovery-phase started too early doesn't affect measurements per se. In theory, the calculation of speed and power do not depend directly on phase detection, they do depend on the total number of impulses and the drag factor. It is in fact the automatic update of the drag factor that is dependent on the correct detection of the stroke. The drag factor can be pinned down if needed by setting *autoAdjustDragFactor* to "false". If set to true, it might affect measurements of both distance and power, where we will discuss the knock-on effects. +* it has to delviver results in near-real-time scenarios in a datastream; -### Effects on the automatically calculated drag factor +* if possible, it has to be robust to outliers: an outlier shouldn't skew the results too much [[10]](#10). -The most important measurement that is affected by stroke detection errors is the calculation of the drag factor. +Ordinary Least Squares is by far the most efficient and can easily be applied to datastreams. However, it isn't robust. From a robustness perspective, most promissing methods are [least absolute deviations](https://en.wikipedia.org/wiki/Least_absolute_deviations), the [Theil–Sen estimator](https://en.wikipedia.org/wiki/Theil%E2%80%93Sen_estimator) and the [LASSO technique](https://en.wikipedia.org/wiki/Lasso_(statistics)). Most of these methods, except the Theil–Sen estimator, do not have a near-real-time solution. In the description of the linear regression methods, we describe the most promissing ones. -Our robust implementation of the drag factor is: +#### Ordinary Least Squares (OLS) -> +Ordinary Least Squares regression (see [[5]](#5)) and [[6]](#6)) produces results that are generally acceptable and the O(N) performance is well-suited for near-real-time calculations. When implemented in a datastream, the addition of a new datapoint is O(1), and the calculation of a slope also is O(1). When using a high-pass filter on the r2 to disregard any unreliably approximated data, it can also be used to produce reliable results. See `engine/utils/OLSLinearSeries.js` for more information about the implementation. -Looking at the effect of erroneously starting the recovery early and ending it late, it affects two variables: +#### Theil–Sen estimator (Linear TS) -* Recovery length will *systematically* become too long (approx. 200 ms from our experiments) +Although the Theil–Sen estimator has a O(N log(N)) solution available, however we could not find a readily available solution. We did manage to develop a solution that has a O(N) impact during the addition of an additional datapoint in a datastream with a fixed length window, and O(log(N)) impact when determining the slope. -* The Angular Velocity will *systematically* become too high as the flywheel already starts to decelerate at the end of the drive phase, which we mistakenly consider the start of the recovery (in our tests this was approx. 83,2 Rad/sec instead of 82,7 Rad/sec). A similar thing can happen at the begin of the recovery phase when the rower doesn't have an explosive Drive. +#### Incomplete Theil–Sen estimator (Inc Linear TS) -Example calculations based on several tests show that this results in a systematically too high estimate of the drag factor. As these errors are systematic, it is safe to assume these will be fixed by the calibration of the power and distance corrections (i.e. the estimate of the *FlywheelInertia* and the *MagicConstant*). Thus, as long as the user calibrates the rower to provide credible data for his setting of *naturalDeceleration*, there will be no issues. +There also is an Incomplete Theis-Sen estimator for Linear Regression [[11]](#11), which is O(1) for the addition of new datapoints in a datastream with a fixed length window, and O(log(N)) for the determination of the slope. Our tests on real-life data show that in several cases the Incomplete Theil-Sen delivers more robust results than the full Theil-Sen estimator. -Please note that this does imply that changing the *naturalDeceleration* when the *autoAdjustDragFactor* is set to true (thus drag is automatically calculated) will require a recalibration of the power and distance measurements. +#### Quadratic Theil–Sen estimator (Quadratic TS) -### Knock-on Effects on the Power calculation +The Theil–Sen estimator can be expanded to apply to Quadratic functions, where the implementation is O(N2). Based on a Lagrange interpolation, we can calculate the coefficients of the formula quite effectively, resulting in a robust estimation more fitting the data. See `engine/utils/FullTSQuadraticSeries.js` for more information about the background of the implementation. -Question is what the effect of this deviation of the drag factor is on the power calculation. The power is calculated as follows: +### Choices for the specific algorithms -> +#### Regression algorithm used for drag calculation -Here, the drag factor is affected upwards. Here the average speed is determined by measuring the angular displacement and divided by the time, being affected in the following manner: +For the drag-factor calculation (and the closely related recovery slope detection), we observe three things: -* Time spend in the Drive phase is *systematically* too short +* The number of datapoints in the recovery phase isn't known in advance, and is subject to significant change due to variations in recovery time (i.e. sprints), making both the Incomplete Theil–Sen estimator and Theil–Sen estimator incapable of calculating their slopes in the stream as the efficient implementations require a fixed window. This results in a near O(N2) calculation at the start of the *Drive* phase. Given the number of datapoints often encountered (a recoveryphase on a Concept 2 contains around 200 datapoints), this is a significant issue that could disrupt the application. OLS has a O(1) complexity for continous datastreams; -* Angular displacement in the Drive phase will *systematically* be too short +* In non-time critical replays of earlier recorded rowing sessions, both the Incomplete Theil–Sen estimator and Theil–Sen estimator performed worse than OLS: OLS with a high pass filter on r2 resulted in a much more stable dragfactor than the Incomplete Theil–Sen estimator and Theil–Sen estimator did. This suggests that the OLS algorithm combined with a requirement for a sufficiently high r2 handles the outliers sufficiently to prevent drag poisoning. -These effects do not cancel out: in essence the flywheel decelerates at the end of the drive phase, which we mistakenly include in the recovery phase. This means that on average, the average speed is systematically too high: it misses some slower speed at the end of the drive. As all factors of the power calculation are systematically overestimating, the result will be a systematic overestimation. +* Applying Quadratic OLS regression does not improve its results -Again, this is a systematic (overestimation) of the power, which will be systematically corrected by the Inertia setting. +Therefore, we choose to apply the OLS Linear Regression model for the calculation of the dragfactor and the related recovery slope detection. + +#### Regression algorithm used for Angular velocity and Angular Acceleration + +We determine the Angular Velocity ω and Angular Acceleration α based on the relation between θ and time. First of all, we observe that we use both the first derived function (i.e. ω) and the second derived function (i.e. α), making a quadratic or even a cubic regression algorithm more appropriate, as a liniear regressor would make the second derived function trivial. Practical testing has confirmed that Quadratic Theil-Senn outperformed all Linear Regression methods in terms of robustness and responsiveness. Based on extensive testing with multiple simulated rowing machines, Full Quadratic Theil-Senn has proven to deliver the best results and thus is selected to determine ω and α. + +## Open Issues, Known problems and Regrettable design decissions + +### Use of simplified power calculation + +The power calculation is the bridge connecting the linear and rotational energy systems of an ergometer. However, from a robustness perspective, we optimised this formula. The complete formula for power throughout a stroke can be deduced from formulae 8.2 and 8.3 [[1]](#1), which lead to: + +> $$ P = I \* ({Δω \over Δt}) \* ω + k \* ω^3 $$ + +A simplified formula is provided by [[1]](#1) (formula 9.1), [[2]](#2) and [[3]](#3): + +> $$ \overline{P} = k \* \overline{\omega}^3 $$ + +Open Rowing Monitor uses the latter simplified version. As shown by academic research [[15]](#15), this is sufficiently reliable and accurate providing that that ω doesn't vary much across subsequent strokes. When there is a significant acceleration or decelleration of the flywheel across subsequent strokes (at the start, during acceleration in sprints or due to stroke-by-stroke variation), the calculated power starts to deviate from the externally applied power. + +Currently, this is an accepted issue, as the simplified formula has the huge benefit of being much more robust against errors in both the *CurrentDt*/ω measurement and the stroke detection algorithm. As Concept 2 seems to have taken shortcut in a thoroughly matured product [[15]](#15), we are not inclined to change this quickly. Especially as the robustness of both the ω calculation and stroke phase detection varies across types of rowing machines, it is an improvement that should be handled with extreme caution. + +### Use of Quadratic Theil-Senn regression for determining α and ω based on time and θ + +Abandoning the numerical approach for a regression based approach has resulted with a huge improvement in metric robustness. So far, we were able to implement Quadratic Theil-Senn regression and get reliable and robust results. The underlying assumption of this Quadratic approach is that the Angular Accelration α is constant, or at constant by approximation in the flank under measurment. In rowing this probably won't be the case as the force will vary based on the position in the Drive phase (hence the need for a forcecurve). Currently, the use of Quadratic Theil-Senn regression represents a huge improvement from both the traditional numerical approach (as taken by [[1]](#1) and [[4]](#4)) used by earlier approaches of Open Rowing Monitor. As the number of datapoints in a *Flanklength* in the relation to the total number of datapoints in a stroke is small, we consider this is a decent approximation while maintaining an sufficiently efficient algorithm to be able to process all data in the datastream in time. + +We can inmagine there are better suited third polynomal (cubic) approaches available that can robustly calculate α and ω as a function of time, based on the relation between time and θ. However, getting these to work in a datastream with very tight limitations on CPU-time and memory across many configurations is quite challenging. We also observe that in several areas the theoretical best approach did not deliver the best practical result (i.e. a "better" algorithm delivered a more noisy result for α and ω). Therefore, this avenue isn't investigated yet, but will be a continuing area of improvement. + +We also observe specific issues, which could result in overfitting the dataset, nihilating its noise reduction effect. As the following sample of three rotations of a Concept2 flywheel shows, due to production tolerances or deliberate design constructs, there are **systematic** errors in the data due to magnet placement or magnet polarity. This results in systematic issues in the datastream: + + + +Fitting a quadratic curve with at least two full rotations of data (in this case, 12 datapoints) seems to reduce the noise to very acceptable levels. In our view, fitting a third-degree polynomial would result in a better fit with these systematic errors, but resulting in a much less robust signal. + +### Use of Quadratic Theil-Senn regression and a median filter for determining α and ω + +For a specific flank, our quadratic regression algorithm calculates a single α for the entire flank and the individual ω's for each point on that flank. As a datapoint will be part of several flank calculations, we obtain several α's and ω's that are valid approximations for that specific datapoint. To obtain the most stable result, we opt for the median of all valid values for α and ω to calculate the definitive approximation of α and ω for that specific datapoint. Although this approach has proven very robust, and even necessary to prevent noise from disturbing powercurves, it is very conservative. For example, when compared to Concept 2's results, the powercurves have the same shape, but the peak values are considerable lower. + +Reducing extreme values while maintaining the true data volatility is a subject for further improvement. ## References @@ -279,6 +480,26 @@ Again, this is a systematic (overestimation) of the power, which will be systema
[3] Dave Vernooy, "Open Source Ergometer ErgWare" -[4] +[4] Dave Vernooy, ErgWare source code + +[5] Wikipedia, "Simple Linear Regression" + +[6] University of Colorado, "Simple Linear Regression" + +[7] Nomath, "Fan blade Physics and a Peek inside C2's Black Box" + +[8] Glenn Elert, The Physics Hypertextbook, "Rotational Kinematics" + +[9] Wikipedia, "Linear regression" + +[10] Wikipedia, "Robust regression" + +[11] Incomplete Theil-Sen Regression + +[12] Glenn Elert, The Physics Hypertextbook, "Rotational Dynamics" + +[13] Glenn Elert, The Physics Hypertextbook, "Rotational Energy" + +[14] Dave Vernooy, ErgWare source code V0.6 -[5] Fan blade Physics and a Peek inside C2's Black Box, Nomath +[15] Gunnar Treff, Lennart Mentz, Benjamin Mayer and Kay Winkert, "Initial Evaluation of the Concept-2 Rowing Ergometer's Accuracy Using a Motorized Test Rig" diff --git a/docs/rower_settings.md b/docs/rower_settings.md index 53783bde7e..726313280c 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -1,76 +1,355 @@ # Guide for rower specific settings -This guide helps you to adjust the rowing monitor specifically for a new type of rower or even for your specific use, when the default rowers don't suffice. + +This guide helps you to adjust the rowing monitor specifically for a new type of rower or even for your specific use, when the default rowers don't suffice. In this manual, we will guide you through the settings needed to get your machine working. This is a work in progress, and please get in touch through the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) when you run into problems. + +In this manual, we cover the following topics: + +* Why have specific settings in the first place + +* Check that Open Rowing Monitor works + +* Making sure the hardware is connected correctly and works as intended + +* Setting up a more detailed logging for a better insight into Open Rowing Monitor + +* Setting GPIO parameters to get a clean signal (general settings) + +* Critical parameters you must change or review for noise reduction + +* Critical parameters you must change or review for stroke detection + +* What reliable stroke detection should look like in the logs + +* Settings required to get the basic metrics right + +* Settings you COULD change for a new rower + +* Settings you can tweak + +* Sending in a rower profile to us ## Why we need rower specific settings -No rowing machine is the same, and some physical construction parameters are important for the Rowing Monitor to be known to be able to understand your rowing stroke. By far, the easiest way is to select your rower profile from `config/rowerProfiles.js` and put its name in `config.js` (i.e. `rowerSettings: rowerProfiles.WRX700`). The rowers mentioned there are maintained by us for OpenRowingMonitor and are structurally tested with changes typically automatically implemented. +No rowing machine is the same, and some physical construction parameters are important for the Rowing Monitor to be known to be able to understand your rowing stroke. By far, the easiest way to configure your rower is to select your rower profile from `config/rowerProfiles.js` and put its name in `config/config.js` (i.e. `rowerSettings: rowerProfiles.Concept2_RowErg`). The rowers mentioned there are maintained by us for OpenRowingMonitor and we also structurally test OpenRowingMonitor with samples of these machines and updates setings when needed. For you as a user, this has the benefit that updates in our software are automatically implemented, including updating the settings. So if you make a rower profile for your machine, please send the profile and some raw data (explained below) to us as well so we can maintain it for you. If you want something special, or if your rower isn't in there, this guide will help you set it up. Please note that determining these settings is quite labor-intensive, and typically some hard rowing is involved. If you find suitable settings for a new type of rower, please send in the data and settings, so we can add it to OpenRowingMonitor and make other users happy as well. -## Settings you must change for a new rower +## Check that Open Rowing Monitor works + +First check you need to do is to check the status of the Open Rowing Monitor service, which you can do with the command: + + ```zsh + sudo systemctl status openrowingmonitor + ``` + +Which typically results in the following response (with some additional logging): + + ```zsh + ● openrowingmonitor.service - Open Rowing Monitor + Loaded: loaded (/lib/systemd/system/openrowingmonitor.service; enabled; vendor preset: enabled) + Active: active (running) since Sun 2022-09-04 10:27:31 CEST; 12h ago + Main PID: 755 (npm start) + Tasks: 48 (limit: 8986) + CPU: 6min 48.869s + CGroup: /system.slice/openrowingmonitor.service + ├─755 npm start + ├─808 sh /tmp/start-6f31a085.sh + ├─809 node app/server.js + ├─866 /usr/bin/node ./app/gpio/GpioTimerService.js + └─872 /usr/bin/node ./app/ble/CentralService.js + ``` + +Please note that the process identification numbers will differ. + +## Making sure the hardware is connected correctly and works as intended + +Before you physically connect anything to anything else, **check the electric properties of the rower** you are connecting to. Skipping this might destroy your Raspberry Pi as some rowers are known to exceed the Raspberry Pi electrical properties. For example, a Concept 2 RowErg provides 15V signals to the monitor, which will destroy the GPIO-ports. Other rowers provide signals aren't directly detectable by the raspberry Pi. For example, the Concept 2 Model C provides 0.2V pulses, thus staying below the detectable 1.8V treshold that the Raspberry Pi uses. Using a scope or a voltmeter is highly recommended. Please observe that the maximum input a Raspberry Pi GPIO pin can handle is 3.3V and 0.5A, and it will switch at 1.8V (see [this overview of the Raspberry Pi electrical properties](https://raspberrypi.stackexchange.com/questions/3209/what-are-the-min-max-voltage-current-values-the-gpio-pins-can-handle)). In our [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) there are some people who are brilliant with electrical connections, so don't be affraid to ask for help there. When you have a working solution, please report it so that we can include it in the documentation, allowing us to help others. + +Next, when the electric connection has been made, we need to look if the data is recieved well and has sufficient quality to be used. You can change `config/config.js` by + + ```zsh + sudo nano /opt/openrowingmonitor/config/config.js + ``` + +Here, you can change the setting for **createRawDataFiles** by setting: + + ```js + createRawDataFiles: true, + ``` + +You can use the following commands on the command line to restart after a config change (to activate new settings): + + ```zsh + sudo systemctl restart openrowingmonitor + ``` + +After rowing a bit, there should be a csv file created with raw data. Please read this data in Excel (it is in US format, so you might need to adapt it to your local settings), to check if it is sufficiently clean. After loading it into Excel, you can visualise it, and probably see something similar to the following: + + + +When the line goes up, the time between impulses from the flywheel goes up, and thus the flywheel is decellerating. When the line goes down, the time between impulses decreases, and thus the flywheel is accelerating. In the first decellerating flank, we see some noise, which Open Rowing Monitor an deal with perfectly. However, looking at the bottom of the first acceleration flank, we see a series of heavy downward spikes. This could be start-up noise, but it also could be systematic across the rowing session. This is problematic as it throws off both stroke detection and many metrics. Typically, it signals an issue in the mechanical construction of the sensor: the fram and sensor vibrate at high speeds, resulting in much noise. + +A specific issue to watch out for are systemic errors in the magnet placement. For exmple, these 18 pulses from a Concept2 RowErg show a systematic error, that follows a 6 impulse cycle. As the RowErg has 6 magnets, it is very likely that it is caused by magnets not being perfectly aligned (for example due to production tollerances): + + + +In some cases, changing the magnet placing or orientation can fix this completely (see for example [this discussion](https://github.com/laberning/openrowingmonitor/discussions/87)), which yields very good results and near-perfect data. Sometimes, you can't fix this. Open Rowing Monitor can handle this kind of systematic error, as long as the *FlankLength* (described later) is set to at least two full rotations (in this case, 12 magnets). + +Another specific issue to be aware of is *debounce*, which typically is seen as a valid signal followed by a very short spike. This suggests that the sensor picks up the magnet twice. The preferred solution is to fix the physical underlying cause, this is a better alignment of the magnet or replacing the sensor for a more advanced model that only picks up specific signals. However, this might not be practical: some flywheels are extremely well-balanced, and moving magnets might destroy that balance. To prevent that type of error, the **gpioMinimumPulseLength** setting allows you to require a minimal signal length, removing these ghost readings. This is a bit of a try and error process: you'll need to row and increase the value **gpioMinimumPulseLength** further when you see ghost readings, and repeat this process until the noise is acceptable. + +Please fix any mechanical issues before proceeding. + +## Setting up a more detailed logging for a better insight into Open Rowing Monitor + +When installed, OpenRowingMonitor will not flood the log with messages. However, when testing it is great to see what OpenRowingMonitor is doing. So first thing to do is to set the following in the settings: + + ```js + // Available log levels: trace, debug, info, warn, error, silent + loglevel: { + // The default log level + default: 'info', + // The log level of of the rowing engine (stroke detection and physics model) + RowingEngine: 'debug' + }, + ``` + +You can look at the the log output of the OpenRowingMonitor-service by putting the following in the command-line: + + ```zsh + sudo journalctl -u openrowingmonitor + ``` + +This allows you to see the current state of the rower. Typically this will show: + + ```zsh + Sep 12 20:37:45 roeimachine systemd[1]: Started Open Rowing Monitor. + Sep 12 20:38:03 roeimachine npm[751]: > openrowingmonitor@0.8.2 start + Sep 12 20:38:03 roeimachine npm[751]: > node app/server.js + Sep 12 20:38:06 roeimachine npm[802]: ==== Open Rowing Monitor 0.8.2 ==== + Sep 12 20:38:06 roeimachine npm[802]: Setting priority for the main server thread to -5 + Sep 12 20:38:06 roeimachine npm[802]: Session settings: distance limit none meters, time limit none seconds + Sep 12 20:38:06 roeimachine npm[802]: bluetooth profile: Concept2 PM5 + Sep 12 20:38:06 roeimachine npm[802]: webserver running on port 80 + Sep 12 20:38:06 roeimachine npm[862]: Setting priority for the Gpio-service to -7 + Sep 12 20:38:09 roeimachine npm[802]: websocket client connected + ``` + +This shows that Open Rowing Monitor is running, and that bluetooth and the webserver are alive, and that the webclient has connected. We will use this to get some grip on Open Rowing Monitor's settings throughout the process. + +## Critical parameters you must change or review for noise reduction + +Open Rowing Monitor needs to understand normal rower behaviour, so it needs some information about the typical signals it should expect. -The key feature for Open Rowing Monitor is to reliably produce metrics you see on the monitor, share via Bluetooth with games and share with Strava and the like. Typically, these metrics are reported on a per-stroke basis. So, to be able to use these metrics for these goals, you need two key parts of the settings right: +### Setting gpioPriority, gpioPollingInterval, gpioTriggeredFlank, gpioMinimumPulseLength (general settings) -* Stroke detection -* Physical metrics (like distance, power and speed) +When you look at the raw dump of *CurrentDT*, it should provide a nice curve. When this curve is erratic, it could help to increase the priority of the GPIO polling process by changing its nice-level via the *gpioPriority*. On a Rapberyy Pi 4, a nice-level of -1 seems to be the maximum for the normal kernel, on a PREEMPT kernel, everything to -7 seems to work. Going beyond these values typically leads to eratic behaviour of the timing (some kernel timing processes seem to be disrupted). -### Getting stroke detection right +Another option is to change the *gpioPollingInterval*, which determines how accurate the measurements are. Please note that increasing this will increase the CPU load, so setting it to 1us might come at a price. Setting this from the default value of 5us to 1us might increase precission, but it could disrupt the entire process as the CPU might get overloeded. So experimenting with this value is key. -A key element in getting rowing data right is getting the stroke detection right, as we report many metrics on a per-stroke basis. The **Impulse Noise reduction settings** reduce the level of noise on the level of individual impulses. You should change these settings if you experience issues with stroke detection or the stability of the drag factor calculation. The stroke detection consists out of three types of filters: +**gpioTriggeredFlank** and **gpioMinimumPulseLength** are typically used to prevent bounces in the signal: magnets passing could trigger a reed switch twice. The logs provide help here, as the logs indicate abnormal short and long times between impulses (via the minimumTimeBetweenImpulses and maximumTimeBetweenImpulses settings). Please note that during a first stroke, the **CurrentDt** values obviously are longer. -* A smoothing filter, using a running average. The **smoothing** setting determines the length of the running average for the impulses, which removes the height of the peaks, removes noise to a certain level but keeps the stroke detection responsive. Smoothing typically varies between 1 to 4, where 1 effectively turns it off. -* A high-pass/low-pass filter, based on **minimumTimeBetweenImpulses** (the shortest allowable time between impulses) and **maximumTimeBetweenImpulses** (the longest allowed time between impulses). Combined, they remove any obvious errors in the duration between impulses (in seconds) during *active* rowing. Measurements outside of this range are filtered out to prevent the stroke detection algorithm to get distracted. This setting is highly dependent on the physical construction of your rower, so you have to determine it yourself without any hints. The easiest way to determine this is by visualizing your raw recordings in Excel. -* A maximum change filter, which based on the the previous impulse determines the maximum amount of change (percentage) through the **maximumDownwardChange** and **maximumUpwardChange** settings. +### Setting minimumTimeBetweenImpulses and maximumTimeBetweenImpulses -By changing the noise reduction settings, you can remove any obvious errors. You don't need to filter everything: it is just to remove obvious errors that might frustrate the stroke detection, but in the end you can't prevent every piece of noise out there. Begin with the noise filtering, when you are satisfied, you can adjust the rest of the stroke detection settings. +**minimumTimeBetweenImpulses** and **maximumTimeBetweenImpulses** provide a bandwith where values are deemed credible during an active session. The goal here is to help you detect and log any extremely obvious errors. So take a look at the raw datafiles for several damper settings (if available on your rower) and make sure that normal rowing isn't hindered by these settings (i.e. all normal values should fall within *minimumTimeBetweenImpulses* and *maximumTimeBetweenImpulses*). Here, you should rather allow too much noise, than hurt real valid signal, as Open Rowing Monitor can handle a lot of noise by itself. -Another set of settings are the **flankLength** and **numberOfErrorsAllowed** setting, which determine the condition when the stroke detection is sufficiently confident that the stroke has started/ended. In essence, the stroke detection looks for a consecutive increasing/decreasing impulse lengths, and the **flankLength** determines how many consecutive flanks have to be seen before the stroke detection considers a stroke to begin or end. Please note that making the flank longer does *not* change your measurement in any way: the algorithms always rely on the beginning of the flank, not at the current end. Generally, a **flankLength** of 2 to 3 typically works. Sometimes, a measurement is too noisy, which requires some errors in the flanks to be ignored, which can be done through the **numberOfErrorsAllowed** setting. For example, the NordicTrack RX-800 successfully uses a **flankLength** of 9 and a **numberOfErrorsAllowed** of 2, which allows quite some noise but forces quite a long flank. This setting requires a lot of tweaking and rowing. +When using the raw datafiles, realise that the goal is to distinguish good normal strokes from noise. So at startup it is quite accepted that the flywheel starts too slow to produce valid data during the biggest part of the first drive phase. Also at the end of a session the flywheel should spin down out of valid ranges again. Please note, *maximumTimeBetweenImpulses* is also used to detect wether the flywheel is spinning down due to lack of user input. When a *flankLength* of measurements contains sufficient values above *maximumTimeBetweenImpulses*, the flywheel is still decelerating and the *maximumStrokeTimeBeforePause* is structurally exceeded, the rower will pause. So setting the value for *maximumTimeBetweenImpulses* too high might block this behaviour. -At the level of the stroke detection, there is some additional noise filtering, preventing noise to start a drive- or recovery-phase too early. The settings **minimumDriveTime** and **minimumRecoveryTime** determine the minimum times (in seconds) for the drive and recovery phases. Generally, the drive phase lasts at least 0.500 second, and the recovery phase 1.250 second for recreational rowers. +### Review smoothing -For the noise reduction settings and stroke detection settings, you can use the Excel tool. When OpenRowingMonitor records a log (set setting createRawDataFiles to `true`), you can paste the values in the first column of the "Raw Data" tab (please observe that the Raspberry uses a point as separator, and your version of Excel might expect a comma). From there, the Excel file simulates the calculations the OpenRowingMonitor makes, allowing you to play with these settings. +**smoothing** is the ultimate fallback mechanism for rowers with very noisy data. For all known rowers currently maintained by Open Rowing Monitor, **NONE** needed this, so only start working with this when the raw files show you have a very noisy signal, physical measures don't work and you can't get your stroke detection to work with other means (please note that we design the mechanisms here to be robust, so they can take a hit). -Please note that changing the noise filtering and stroke detection settings will affect your calculated dragFactor. So it is best to start with rowing a few strokes to determine settings for noise filtering and stroke detection, and then move on to the other settings. +This is a running median filter, effectively killing any extreme values. By default, it is set to 1 (off). A value of 3 will allow it to completely ignore any single extreme values, which should do the trick for most rowers. -### Getting the metrics right +## Critical parameters you must change or review for stroke detection -There are some parameters you must change to get Open Rowing Monitor to calculate the real physics with a rower. These are: +The key feature for Open Rowing Monitor is to reliably produce metrics you see on the monitor, share via Bluetooth with games and share with Strava and the like. Typically, these metrics are reported on a per-stroke basis, so a key element in getting rowing data right is getting the stroke detection right. It must be noted that we calculate most essential metrics in such a way that missing an individual stroke isn't a big deal, it will not even give hickups when this happens. However, the more advanced metrics (like drive length, stroke length, powercurves) won't provide any useful data when the stroke or stroke phase isn't detected properly. There are several critical parameters that are required for Open Rowing Monitor's stroke detection to work. In this section, we help you set the most critical ones. -* **numOfImpulsesPerRevolution**: this tells Open Rowing Monitor how many impulses per rotation of the flywheel to expect. An inspection of the flywheel could reveal how many magnets it uses (typically a rower has 2 to 4 magnets). Although sometimes it is well-hidden, you can sometimes find it in the manual under the parts-list of your rower. -* **dragFactor**: tells Open Rowing Monitor how much damping and thus resistance your flywheel is offering. This is typically also dependent on your damper-setting (if present). Regardless if you use a static or dynamically calculated drag factor, this setting is needed as the first stroke also needs it to calculate distance, speed and power. Just as a frame of reference: the Concept2 can display this factor from the menu. Please note that the drag factor is much dependent on the physical construction of the flywheel and mechanical properties of the transmission of power to the flywheel. For a new Concept2, the Drag Factor ranges between 80 (Damper setting 1) and 220 (Damper setting 10). The NordicTrack RX-800 ranges from 150 to 450, where the 150 feels much lighter than a 150 on the Concept2. +### setting numOfImpulsesPerRevolution -Here, some rowing and some knowledge about your rowing gets involved. Setting your damping factor is done by rowing a certain number of strokes and then seeing how much you have rowed and at what pace. If you know these metrics by hart, it just requires some rowing and adjusting to get them right. If you aren't that familiar with rowing, a good starting point is that a typical distance covered by a single stroke at 20 strokes per minute (SPM) is around 10 meters. So when you row a minute, you will have 20 strokes recorded and around 200 meters rowed. When possible, we use the [Concept Model D (or RowerErg)](https://www.concept2.com/indoor-rowers/concept2-rowerg) as a "Golden standard": when you know your pace on that machine, you can try to mimic that pace on your machine. Most gym's have one, so trying one can help you a lot in finding the right settings for your machine. +**numOfImpulsesPerRevolution** tells Open Rowing Monitor how many impulses per rotation of the flywheel to expect. An inspection of the flywheel could reveal how many magnets it uses (typically a rower has 2 to 4 magnets). Although sometimes it is well-hidden, you can sometimes find it in the manual under the parts-list of your rower. + +### review sprocketRadius and minumumForceBeforeStroke + +**sprocketRadius** tells Open Rowing Monitor how big the sprocket is that attaches your belt/chain to your flywheel (in centimeters). This setting is used in calculating the handle force for stroke detection. **minumumForceBeforeStroke*** describes the minimum force (in Newtons) should be present on the handle before it will consider moving to a drive phase. The default values will work OK for most rowers, but sometimes it needs to be changed for a specific rower. On most rowers, there always is some noise present at the end of the drive section, and tuning these two parameters might help you remove that noisy tail. + +Their accuracy isn't super-critical. In later sections, we will describe how to optimally tune it as the *sprocketRadius* affects quite some metrics. Here your first goal is to get a working stroke detection. You can change these settings afterwards to something more accurate quite easily, but remember that when the *sprocketRadius* doubles, so should the *minumumForceBeforeStroke*. + +### setting flankLength and minimumStrokeQuality + +These settings are the core of the stroke detection and are the ones that require the most effort to get right. The most cricial settings are the *flankLength* and *minimumStrokeQuality*, where other metrics are much less critical. + +**minimumStrokeQuality** is a setting that defines the minimal goodness of fit of the beforementioned recovery slope with the datapoints. When the slope doesn't fit the data well, this will block moving to the next phase. A value of 0.1 is extrmely relaxed, where 0.95 would be extremely tight. This is set to 0.34 for most rowers, which is a working setting for all maintained rowers to date. The accuracy of this setting isn't super critical for stroke detection to work: for example, on a Concept2 values between 0.28 to 0.42 are known to give reliable stroke detection. Setting this too relaxed will result in earlier phase changes, settng this too strict will delay phase detection. This setting is primarily used to optimise the stroke detection for advanced metrics (like drive time, drive length, force curves), so unless it gets in the way, there is no immediate need to change it. + +The **flankLength** setting determines the condition when the stroke detection is sufficiently confident that the stroke has started/ended. In essence, the stroke detection looks for a consecutive increasing/decreasing impulse lengths, and the **flankLength** determines how many consecutive flanks have to be seen before the stroke detection considers a stroke to begin or end. Generally, a *flankLength* of 3 to 4 typically works. The technical minimum is 3, the maximum is limited by CPU-time. Please note that making the flank longer does *not* change your measurement in any way: the algorithms always rely on the beginning of the flank, not at the current end. If any, increasing the *flanklength* has the side-effect that some calculations are performed with more rigour, making them more precise as they get more data. Please note that the rower itself might limit the *flankLength*: some rowers only have 4 or 5 datapoints in a drive phase, naturally limiting the number of datapoints that can be used for stroke phase detection. + +Please note that a longer *flankLength* also requires more CPU time, where the calculation grows exponentially as *flankLength* becomes longer. On a Raspberry Pi 4B, a *flankLength* of 12 has been succesfully used without issue. What the practical limit on a Rapberry Pi Zero 2 W is, is still a matter of investigation. + +To make life a bit easier, it is possible to replay a recorded raw rowing session. To do this, uncomment and modify the following lines in `server.js`: + + ```js +replayRowingSession(handleRotationImpulse, { + filename: 'recordings/2021/04/rx800_2021-04-21_1845_Rowing_30Minutes_Damper8.csv', // 30 minutes, damper 10 + realtime: false, + loop: false +}) +``` + +After changing the filename to a file that is your raw recording of your rower, you can replay it as often as you want by restarting the service. This will allow you to modify these settings and get feedback in seconds on the effects on Open Rowing Monitor. + +### minimumDriveTime and minimumRecoveryTime + +At the level of the stroke detection, there is some additional noise filtering, preventing noise to start a drive- or recovery-phase too early. The settings **minimumDriveTime** and **minimumRecoveryTime** determine the minimum times (in seconds) for the drive and recovery phases. Generally, the drive phase lasts at least 0.500 second, and the recovery phase 0.900 second for recreational rowers. These settings are good for most rowers, but running in to these filters might indicate that your settings aren't perfect yet. Please note that even on well-tuned machines, sometimes noise can cause this filter to kick in. So finding several of these reports in a session, might indicate that the above settings might need adjustment. + +When this kicks in, you will find this in your log: + + ```zsh + Sep 12 20:46:24 roeimachine npm[839]: Time: 1012.1644 sec: Delta Time trend is upwards, suggests no power, but waiting for drive phase length (0.0107 sec) to exceed mininimumDriveTime (0.40 sec) + ``` + +This typically suggests, as the lack of power occurs at 0.01 seconds into the drive time, that the drive phase is started too early. An other error you might find is the following one: + + ```zsh + Aug 16 22:38:07 roeimachine npm[1003]: Time: 25.5091 sec: Delta Time trend is downwards, suggesting power, but waiting for recoveryDuration suggests no power, but waiting for recovery phase length (0.4572 sec) to exceed minimumRecoveryTime (0.90 sec) + ``` + +This typically suggests, as the issue is so late in the recovery phase, that either the recovery started to late (this typically results in a stream of similar line following this one) or it is noise. + +## What reliable stroke detection should look like in the logs + +When you look in the logs, you hopefully find this: + + ```zsh + Sep 12 20:45:36 roeimachine npm[802]: stroke: 0, dist: 0.0m, speed: 0.00m/s, pace: Infinity/500m, power: 0W, drive length: 1.10 m, SPM: 0.0, drive dur: NaNs, rec. dur: NaNs + Sep 12 20:45:38 roeimachine npm[802]: *** RECOVERY phase started at time: 1.5644 sec + Sep 12 20:45:40 roeimachine npm[802]: *** DRIVE phase started at time: 3.6013 sec + Sep 12 20:45:40 roeimachine npm[802]: *** Calculated drag factor: 105.6459, no. samples: 143, Goodness of Fit: 0.9435 + Sep 12 20:45:40 roeimachine npm[802]: *** Calculated recovery slope: 0.001089, Goodness of Fit: 0.9435 + Sep 12 20:45:40 roeimachine npm[802]: stroke: 1, dist: 7.5m, speed: 1.80m/s, pace: 4:38/500m, power: 17W, drive length: 1.09 m, SPM: 23.2, drive dur: 1.56s, rec. dur: 2.04s + Sep 12 20:45:41 roeimachine npm[802]: *** RECOVERY phase started at time: 4.5018 sec + Sep 12 20:45:43 roeimachine npm[802]: *** DRIVE phase started at time: 6.5907 sec + Sep 12 20:45:43 roeimachine npm[802]: *** Calculated drag factor: 104.1759, no. samples: 196, Goodness of Fit: 0.9675 + Sep 12 20:45:43 roeimachine npm[802]: *** Calculated recovery slope: 0.001074, Goodness of Fit: 0.9675 + Sep 12 20:45:43 roeimachine npm[802]: stroke: 2, dist: 17.1m, speed: 2.93m/s, pace: 2:51/500m, power: 73W, drive length: 1.18 m, SPM: 20.2, drive dur: 1.23s, rec. dur: 2.06s + Sep 12 20:45:44 roeimachine npm[802]: *** RECOVERY phase started at time: 7.3455 sec + Sep 12 20:45:46 roeimachine npm[802]: *** DRIVE phase started at time: 9.5219 sec + Sep 12 20:45:46 roeimachine npm[802]: *** Calculated drag factor: 103.9705, no. samples: 214, Goodness of Fit: 0.9731 + Sep 12 20:45:46 roeimachine npm[802]: *** Calculated recovery slope: 0.001072, Goodness of Fit: 0.9731 + Sep 12 20:45:46 roeimachine npm[802]: stroke: 3, dist: 27.2m, speed: 3.39m/s, pace: 2:28/500m, power: 109W, drive length: 1.23 m, SPM: 20.8, drive dur: 0.83s, rec. dur: 2.13s + Sep 12 20:45:46 roeimachine npm[802]: *** RECOVERY phase started at time: 10.2020 sec + Sep 12 20:45:49 roeimachine npm[802]: *** DRIVE phase started at time: 12.4851 sec + Sep 12 20:45:49 roeimachine npm[802]: *** Calculated drag factor: 103.7254, no. samples: 232, Goodness of Fit: 0.9770 + Sep 12 20:45:49 roeimachine npm[802]: *** Calculated recovery slope: 0.001069, Goodness of Fit: 0.9770 + Sep 12 20:45:49 roeimachine npm[802]: stroke: 4, dist: 37.7m, speed: 3.51m/s, pace: 2:23/500m, power: 121W, drive length: 1.16 m, SPM: 20.6, drive dur: 0.72s, rec. dur: 2.23s + Sep 12 20:45:49 roeimachine npm[802]: *** RECOVERY phase started at time: 13.1464 sec + Sep 12 20:45:52 roeimachine npm[802]: *** DRIVE phase started at time: 15.3739 sec + Sep 12 20:45:52 roeimachine npm[802]: *** Calculated drag factor: 103.9593, no. samples: 226, Goodness of Fit: 0.9775 + Sep 12 20:45:52 roeimachine npm[802]: *** Calculated recovery slope: 0.001072, Goodness of Fit: 0.9775 + Sep 12 20:45:52 roeimachine npm[802]: stroke: 5, dist: 48.0m, speed: 3.56m/s, pace: 2:21/500m, power: 126W, drive length: 1.11 m, SPM: 20.6, drive dur: 0.67s, rec. dur: 2.26s + Sep 12 20:45:52 roeimachine npm[802]: *** RECOVERY phase started at time: 16.1629 sec + Sep 12 20:45:55 roeimachine npm[802]: *** DRIVE phase started at time: 18.3141 sec + Sep 12 20:45:55 roeimachine npm[802]: *** Calculated drag factor: 103.3899, no. samples: 216, Goodness of Fit: 0.9764 + Sep 12 20:45:55 roeimachine npm[802]: *** Calculated recovery slope: 0.001066, Goodness of Fit: 0.9764 + Sep 12 20:45:55 roeimachine npm[802]: stroke: 6, dist: 58.4m, speed: 3.55m/s, pace: 2:21/500m, power: 126W, drive length: 1.22 m, SPM: 20.1, drive dur: 0.73s, rec. dur: 2.19s + Sep 12 20:45:55 roeimachine npm[802]: *** RECOVERY phase started at time: 19.0078 sec + Sep 12 20:45:58 roeimachine npm[802]: *** DRIVE phase started at time: 21.3977 sec + Sep 12 20:45:58 roeimachine npm[802]: *** Calculated drag factor: 102.3463, no. samples: 236, Goodness of Fit: 0.9348 + Sep 12 20:45:58 roeimachine npm[802]: *** Calculated recovery slope: 0.001055, Goodness of Fit: 0.9348 + Sep 12 20:45:58 roeimachine npm[802]: stroke: 7, dist: 69.1m, speed: 3.49m/s, pace: 2:23/500m, power: 119W, drive length: 1.23 m, SPM: 20.2, drive dur: 0.74s, rec. dur: 2.27s + Sep 12 20:45:58 roeimachine npm[802]: *** RECOVERY phase started at time: 21.9592 sec + Sep 12 20:46:00 roeimachine npm[802]: *** DRIVE phase started at time: 24.1939 sec + Sep 12 20:46:00 roeimachine npm[802]: *** Calculated drag factor: 103.4389, no. samples: 225, Goodness of Fit: 0.9705 + Sep 12 20:46:00 roeimachine npm[802]: *** Calculated recovery slope: 0.001066, Goodness of Fit: 0.9705 + Sep 12 20:46:00 roeimachine npm[802]: stroke: 8, dist: 78.9m, speed: 3.50m/s, pace: 2:23/500m, power: 120W, drive length: 1.04 m, SPM: 20.9, drive dur: 0.63s, rec. dur: 2.31s + Sep 12 20:46:01 roeimachine npm[802]: *** RECOVERY phase started at time: 24.8737 sec + Sep 12 20:46:03 roeimachine npm[802]: *** DRIVE phase started at time: 27.1559 sec + Sep 12 20:46:03 roeimachine npm[802]: *** Calculated drag factor: 103.4498, no. samples: 228, Goodness of Fit: 0.9070 + Sep 12 20:46:03 roeimachine npm[802]: *** Calculated recovery slope: 0.001066, Goodness of Fit: 0.9070 + ``` + +When stroke detection works well, and you row consistently on the rower with a consistent catch, the values of "SPM" (Strokes per Minute), "drive dur" (drive duration) and "rec. dur" (recovery duration) will remain relatively stable across strokes. + +## Settings required to get the basic metrics right + +After getting the stroke detection right, we now turn to getting the basic linear metrics (i.e. distance, speed and power) right. There are some parameters you must change to get Open Rowing Monitor to calculate the real physics with a rower. + +### Setting the dragfactor + +**dragFactor** tells Open Rowing Monitor how much damping and thus resistance your flywheel is offering, which is an essential ingredient in calculating Power, Distance, Speed and thus pace. This is typically also dependent on your damper-setting (if present). Regardless if you use a static or dynamically calculated drag factor, this setting is needed as the first stroke also needs it to calculate distance, speed and power. Here, some rowing and some knowledge about your rowing gets involved. Setting your damping factor is done by rowing a certain number of strokes and then seeing how much you have rowed and at what pace. If you know these metrics by hart, it just requires some rowing and adjusting to get them right. If you aren't that familiar with rowing, a good starting point is that a typical distance covered by a single stroke at 20 strokes per minute (SPM) is around 10 meters. So when you row a minute, you will have 20 strokes recorded and around 200 meters rowed. When possible, we use the [Concept Model D (or RowerErg)](https://www.concept2.com/indoor-rowers/concept2-rowerg) as a "Golden standard": when you know your pace on that machine, you can try to mimic that pace on your machine. Most gym's have one, so trying one can help you a lot in finding the right settings for your machine. + +This results in a number, which works and can't be compared to anything else on the planet as that drag factor is highly dependent on the physical construction of the flywheel and mechanical properties of the transmission of power to the flywheel. For example, the Drag Factor for a Concept 2 ranges between 69 (Damper setting 1) and 220 (Damper setting 10). The NordicTrack RX-800 ranges from 150 to 450, where the 150 feels much lighter than a 150 on the Concept2. The Sportstech WRX700 water rower has a drag factor of 32000. + +### Setting the flywheel inertia + +**flywheelInertia** is the moment of inertia of the flywheel (in kg\*m2), which in practice influences the dynamically calculated dragfactor (and thus power, distance, speed and pace), but also the calculated force and power on the handle. A formal way to measure it is outlined in [Flywheel moment of inertia](https://dvernooy.github.io/projects/ergware/). However, the most practical way to set it is by rowing and see if the calculated drag factor approximates the previously set dragfactor needed to get a certain pace. + +The easiest way to test this value is by rowing (or simulating rowing): in the logs, the following lines will appear in debug mode: + + ```zsh + Sep 13 20:25:24 roeimachine npm[839]: *** Calculated drag factor: 103.5829, slope: 0.001064, Goodness of Fit: 0.9809, not used because autoAdjustDragFactor is not true + ``` + +If your flywheel inertia is set correctly, the calculated drag factor will be very close to the drag factor you set manually. Please look at the "Goodness of Fit" before using the data. Due to noise, the dragfactor sometimes can't be calculated accurately, which is reflected in this Goodness of Fit being low. So when comparing the calculated dragfactor with the manually determned dragfactor, use the calculated dragffactors where the Goodness of Fit is highest. + +Please note that this logmessage will change when autoAdjustDragFactor is set to true, but this content will always be reported in debug mode. ## Settings you COULD change for a new rower -In the previous section, we've guided you to set up a real robust working rower, but it will result in more crude data. To improve the accuracy of many measurements, you could switch to a more accurate and dynamic rower. This does require a more sophisticated rower: you need quite a few data points per stroke, with much accuracy, to get this working reliably. And a lot of rowing to get these settings right is involved. +In the previous section, we've guided you to set up a very robust working rower, but it will result in more crude data. To improve the accuracy of many measurements, you could switch to a more accurate and dynamic metric calculation. This does require a more sophisticated rower: you need quite a few data points per stroke, with much accuracy, to get this working reliably. So this setup certainly isn't for every rowing machine out there, although some options might just work. And again a lot of rowing to get these settings right is involved. + +### More accurate static stroke detection -### More accurate stroke detection +When **minumumRecoverySlope** is set to 0, the stroke detection looks for a consecutive increasing/decreasing impulse lengths which is extremely robust. When set to a higher value, it will detect the recovery only when that certain slope is reached or exceeded. This is relevant for more advanced metrics, like drive time, stroke length and the force curve. If your stroke detection roughly works and your logging level is set to debug, you will see lines like this in your log: -The **naturalDeceleration** setting determines the natural deceleration. This setting is used to distinguish between a powered and unpowered flywheel. This must be a negative number and indicates the level of deceleration required to interpret it as a free spinning flywheel. The best way to find the correct value for your rowing machine is a try and error approach. You can also set this to zero (or positive), to use the more robust, but not so precise acceleration-based stroke detection algorithm. Setting it to -0.1 enables the alternative less robust algorithm. By seeing how your stroke detection behaves during a row, you can slowly lower this number until you start missing strokes. + ```zsh + Sep 13 20:25:24 roeimachine npm[839]: *** Calculated drag factor: 103.5829, slope: 0.001064, Goodness of Fit: 0.9809, not used because autoAdjustDragFactor is not true + ``` -Please note that changing this stroke detection will affect your calculated dragFactor. +Here, the reported slope is the calculated slope during the recovery, and the goodness of fit the quality of the data match. A higher value (say above 0.80) suggestst that the data sufficiently. The easiest way to further optimise these settings is to select the lowest damper setting, and copy the lowest reported slope with a credible goodness of fit, with some margin (say 5%), making the minumumRecoverySlope 0.0010108. ### Dynamically adapting the drag factor -In reality, the drag factor of a rowing machine isn't static: it depends on air temperature, moisture, dust, (air)obstructions of the flywheel cage and sometimes even speed of the flywheel. So using a static drag factor is reliable, it isn't accurate. Open Rowing Monitor can automatically calculate the drag factor on-the-fly based on the recovery phase (see [this description of the underlying physics](physics_openrowingmonitor.md)). To do this, you need to set the following settings: +In reality, the drag factor of a rowing machine isn't static: it depends on air temperature, moisture, dust, (air)obstructions of the flywheel cage and sometimes even speed of the flywheel. So using a static drag factor is robust, but it isn't accurate. Open Rowing Monitor can automatically calculate the drag factor on-the-fly based on the recovery phase (see [this description of the underlying physics](physics_openrowingmonitor.md)). To do this, you need to set several settings. + +It must be noted that you have to make sure that your machine's measurements are sufficiently free of noise: noise in the drag calculation can have a strong influence on your speed and distance calculations and thus your results. If your rower produces stable drag factor values, then this could be a good option to dynamically adjust your measurements to the damper setting of your rower as it takes in account environmental conditions. When your machine's power and speed readings are too volatile because of this dynamic calculation, it is wise to turn it off. + +First to change is **autoAdjustDragFactor** to "true", which tells Open Rowing Monitor that the Drag Factor must be calculated automatically. Setting it to true, will allow Open Rowing Monitor to automatically calculate the drag factor based on the already set *flywheelInertia* and the on the measured values in the stroke recovery phase. -* **autoAdjustDragFactor**: the Drag Factor can be calculated automatically. Setting it to true, will allow Open Rowing Monitor to automatically calculate the drag factor based on the **flywheelInertia** and the on the measured values in the stroke recovery phase. -* **flywheelInertia**: The moment of inertia of the flywheel (in kg\*m^2), which in practice influences your power values and distance. A formal way to measure it is outlined in [Flywheel moment of inertia](https://dvernooy.github.io/projects/ergware/). However, the most practical way to set it is by rowing and see what kind of power is displayed on the monitor. Typical ranges are weight dependent (see [this explanation](https://www.rowingmachine-guide.com/tabata-rowing-workouts.html)), and it helps if you know your times on a reliable machine like the Concept2. +Each time the drag is calculated, we also get a quality indication from that same calculation: the "Goodness of Fit". Based on this quality indication (1.0 is best, 0.1 pretty bad), low quality drag factors are rejected to prevent the drag from being poisoned with bad data, throwing off all metrics. **minimumDragQuality** determines the minimum level of quality needed to The easiest way to set this, is by looking at the logs: -Please note that you don't need to use the dynamic drag factor to test your settings. To see the calculated drag factor for your rowing machine, please ensure that the logging level of the RowingEngine is set to 'info' or higher. Then do some strokes on the rower and observe the calculated drag factor in the logging. + ```zsh + Sep 13 20:25:24 roeimachine npm[839]: *** Calculated drag factor: 103.5829, slope: 0.001064, Goodness of Fit: 0.9809, not used because autoAdjustDragFactor is not true + ``` -It must be noted that you have to make sure that your machine's measurements are sufficiently free of noise: noise in the drag calculation can have a strong influence on your speed and distance calculations and thus your results. If your rower produces stable damping values, then this could be a good option to dynamically adjust your measurements to the damper setting of your rower as it takes in account environmental conditions. When your machine's power and speed readings are too volatile it is wise to turn it off +By selecting all these lines, you can see the "Goodness of Fit" for all calculations, see what the typical variation in "Goodness of Fit" is, and when a "Goodness of Fit" signals a deviant drag factor. Based on the logs, you should be able to set a minimumDragQuality. Please note: rejecting a dragfactor isn't much of an issue, as Open Rowing Monitor always retains the latest reliable dragfactor. + +Another measure to prevent sudden drag changes, is **dragFactorSmoothing**: this setting applies a median filter on a series of valid drag factors, further reducing the effect of outliers. Typically this is set to 5 strokes, but it could set to a different value if the drag calculation results in a wildly varying drag factor. + +### Dynamically adapting the recovery slope + +For a more accurate stroke detection, the *minumumRecoverySlope* is a crucial parameter. Open Rowing Monitor can automatically calculate the this recovery slope and adjust it dynamically. For this to work, *autoAdjustDragFactor* **MUST** be set to true, as the recovery slope is dependent on this automatic dragfactor calculation. If you set *autoAdjustDragFactor* to true, this option can be activated by setting *autoAdjustRecoverySlope* to "true". + +Setting *autoAdjustRecoverySlope* to "true" also activates one additional setting **autoAdjustRecoverySlopeMargin**. This is the margin used between the automatically calculated recovery slope and a next recovery slope. 5% (i.e. 0.05) is a pretty good margin and works well for most rowers. + +### sprocketRadius (revisited) + +**sprocketRadius** tells Open Rowing Monitor how big the sprocket is that attaches your belt/chain to your flywheel. Aside from being used in all handle force and speed calculations, it is also used in the drive length calculation. + +```zsh + Sep 12 20:46:00 roeimachine npm[802]: stroke: 8, dist: 78.9m, speed: 3.50m/s, pace: 2:23/500m, power: 120W, drive length: 1.04 m, SPM: 20.9, drive dur: 0.63s, rec. dur: 2.31s +``` + +Another use is found in the RowingData export (if used), where the peak handle force, average handle force, handle force curve, handle velocity curve and handle power curve depend on this. For the configuration we are quite focussed on drive length. Drive length is the length of the drive, in meters. For most people, it is about ${2 \over 3}$ of your own length. So changing it to fit that would be a good approach. Please note that increasing the drive length will reduce the handle force and handle power, so you can't increase this without restraint. Also remember that when the sprocket radius doubles, the *minumumForceBeforeStroke* should also be doubled. ## Settings you can tweak Some people want it all, and we're happy to give to you when your rower and your Raspberry Pi can handle the pain. Some interesting settings: -* **maximumImpulseTimeBeforePause** determines the maximum time between impulses before the rowing engine considers it a pause. * **magicConstant** is a constant that is commonly used to convert flywheel revolutions to a rowed distance and speed (see [the physics of ergometers](http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html#section9)). Concept2 seems to use 2.8, which they admit is an arbitrary number which came close to their expectations of a competetion boat. As this setting only affects speed/distance, this setting typically is used to change the power needed to row a certain distance or reach a certain speed. So changing this can make your rower's metrics act as sluggish as an oil tanker (much power needed for little speed), or more like a smooth eight (less power needed for more speed). So for your rower, you could set your own plausible distance for the effort you put in. Please note that the rowed distance also depends on **flywheelInertia**, so please calibrate that before changing this constant. Another note: increasing this number decreases your rowed meters, but not in a linear fashion. -* **webUpdateInterval**: normally set at 1000 milliseconds, but for a more smoother experience on your monitor you can go as low as 100 ms. This makes the transition of the distance and time quite smooth, but at the price of some more network and CPU-load. -* **numOfPhasesForAveragingScreenData**: we average the data from several stroke phases to prevent the monitor and Bluetooth devices to become fidgety. Typically, we set this value to 6, which means 3 strokes (there are two phases in each stroke). However, some Bluetooth devices do their own calculations. And sometimes you really want the feedback on your individual strokes without any punches hold back. Setting this to 1 will result in a very volatile, but direct feedback mechanism on your stroke. -* **dampingConstantSmoothing** determines the smoothing of the dragfactor across strokes (if autoAdjustDragFactor is set to true). Normally set at 5 strokes, which prevents wild values to throw off all your measurements. If you have rower that produces very little noise in the data, then it could be an option to reduce. If your machine produces noisy data, this is the one to increase before anything else. -* **dampingConstantMaxChange** determines the maximum change between a currently determined dragfactor and the current average of the previous dampingConstantSmoothing strokes (if autoAdjustDragFactor is set to true). This filter reduces spikes in the calculation and thus makes the dragfactor less responsive to changes. The default value of 0.10 implies that the maximum upward/downward change is an increase of the drag with 10%. Please note that this filter still allows changes, it just limits their impact to this percentage. Most rower's dragfactor is relatively constant, however certain hyrid rower's dragfactor changes when the speed changes. To allow for bigger changes within a stroke, increase this setting. When the expected changes are small, set this setting small. When your rower is a hybrid or when you have one configuration for all your damper settings, this should be a bit wider. -* **createRawDataFiles**: This is as raw as it gets, as setting this to `true` makes Open Rowing Monitor dump the raw impulse-lengths to a file (see [how we interpret this data](physics_openrowingmonitor.md)). + +## Sending in a rower profile to us + +Sending in a rower profile helps other users, but also helps yourself as we structurally test and update the knowwn configurations. We need the following things from you to maintain a rower profile: + +* The **profile** itself: these are the settings you used to get the machine working. +* A **raw datafile** (described above) of a session, preferably with your distance and time. This allows us to test if newer versions of OpenRowingMonitor will deliver similar results to you. diff --git a/install/install.sh b/install/install.sh index ec4dbf05e6..79601efd75 100755 --- a/install/install.sh +++ b/install/install.sh @@ -115,6 +115,9 @@ sudo apt-get -y update sudo apt-get -y dist-upgrade sudo systemctl disable bluetooth sudo apt-get -y install bluetooth bluez libbluetooth-dev libudev-dev git +sudo apt-get -y install pigpio +# We disable the pigpio service explicity, as the JS wrapper is alergic to the deamon +sudo systemctl mask pigpiod.service print ARCHITECTURE=$(uname -m) diff --git a/install/webbrowserkiosk.sh b/install/webbrowserkiosk.sh index 057c7322c2..1eb5680b6c 100644 --- a/install/webbrowserkiosk.sh +++ b/install/webbrowserkiosk.sh @@ -12,4 +12,4 @@ openbox-session & # Start Chromium in kiosk mode sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' ~/.config/chromium/'Local State' sed -i 's/"exited_cleanly":false/"exited_cleanly":true/; s/"exit_type":"[^"]\+"/"exit_type":"Normal"/' ~/.config/chromium/Default/Preferences -chromium-browser --disable-infobars --disable-features=AudioServiceSandbox --kiosk --noerrdialogs --disable-session-crashed-bubble --disable-pinch --check-for-update-interval=604800 --app="http://127.0.0.1/?mode=kiosk" +chromium-browser --disable-infobars --disable-features=AudioServiceSandbox --kiosk --noerrdialogs --ignore-certificate-errors --disable-session-crashed-bubble --disable-pinch --enable-low-end-device-mode --disable-site-isolation-trials --renderer-process-limit=2 --check-for-update-interval=604800 --app="http://127.0.0.1/?mode=kiosk" diff --git a/package-lock.json b/package-lock.json index 33e4e08427..995beada5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "lit": "2.1.3", "loglevel": "1.8.0", "nosleep.js": "0.12.0", - "onoff": "6.0.3", + "pigpio": "3.3.1", "serve-static": "1.14.2", "ws": "8.5.0", "xml2js": "0.4.23" @@ -4277,19 +4277,6 @@ "node": ">=6" } }, - "node_modules/epoll": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/epoll/-/epoll-4.0.1.tgz", - "integrity": "sha512-BgCq0nEsk+XI7y9qjrRtt9uXsyFEdvevvq42xl6t/hKZjxLSDZreD9rTZ0pU40V//c3Zzk2PZGuIsn8YJHSJ4g==", - "hasInstallScript": true, - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.14.2" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -6771,7 +6758,8 @@ "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -8003,18 +7991,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/onoff": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/onoff/-/onoff-6.0.3.tgz", - "integrity": "sha512-xtVlwRDzswYM69bzzIui/qzu7QHsFnjsQiCV1iYVA/HXt5xdc9utc97SYAlXzK8wAhIN7+H7MaVqh2vpfdKk9A==", - "dependencies": { - "epoll": "^4.0.1", - "lodash.debounce": "^4.0.8" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/open": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", @@ -8591,6 +8567,19 @@ "node": ">=4" } }, + "node_modules/pigpio": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/pigpio/-/pigpio-3.3.1.tgz", + "integrity": "sha512-z7J55K14IwWkA+oW5JHzWcgwThFAuJ7IzV3A2//yRm4jJ2DTU0DHIy91DB0siOi12rvvlrIhRetEuAo0ztF/vQ==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -14425,15 +14414,6 @@ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true }, - "epoll": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/epoll/-/epoll-4.0.1.tgz", - "integrity": "sha512-BgCq0nEsk+XI7y9qjrRtt9uXsyFEdvevvq42xl6t/hKZjxLSDZreD9rTZ0pU40V//c3Zzk2PZGuIsn8YJHSJ4g==", - "requires": { - "bindings": "^1.5.0", - "nan": "^2.14.2" - } - }, "err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -16310,7 +16290,8 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true }, "lodash.merge": { "version": "4.6.2", @@ -17246,15 +17227,6 @@ "mimic-fn": "^2.1.0" } }, - "onoff": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/onoff/-/onoff-6.0.3.tgz", - "integrity": "sha512-xtVlwRDzswYM69bzzIui/qzu7QHsFnjsQiCV1iYVA/HXt5xdc9utc97SYAlXzK8wAhIN7+H7MaVqh2vpfdKk9A==", - "requires": { - "epoll": "^4.0.1", - "lodash.debounce": "^4.0.8" - } - }, "open": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", @@ -17703,6 +17675,15 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "pigpio": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/pigpio/-/pigpio-3.3.1.tgz", + "integrity": "sha512-z7J55K14IwWkA+oW5JHzWcgwThFAuJ7IzV3A2//yRm4jJ2DTU0DHIy91DB0siOi12rvvlrIhRetEuAo0ztF/vQ==", + "requires": { + "bindings": "^1.5.0", + "nan": "^2.14.2" + } + }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", diff --git a/package.json b/package.json index cd8c906ac7..e59db4080f 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "lit": "2.1.3", "loglevel": "1.8.0", "nosleep.js": "0.12.0", - "onoff": "6.0.3", + "pigpio": "3.3.1", "serve-static": "1.14.2", "ws": "8.5.0", "xml2js": "0.4.23" diff --git a/recordings/Concept2_RowErg_Session_2000meters.csv b/recordings/Concept2_RowErg_Session_2000meters.csv new file mode 100644 index 0000000000..65ee4db3cc --- /dev/null +++ b/recordings/Concept2_RowErg_Session_2000meters.csv @@ -0,0 +1,63000 @@ +0.080654 +0.071426 +0.058965 +0.050558 +0.044207 +0.039636 +0.036263 +0.033684 +0.031432 +0.029379 +0.02732 +0.025791 +0.024678 +0.023824 +0.023014 +0.02225 +0.021168 +0.020272 +0.019798 +0.019262 +0.018968 +0.018483 +0.017651 +0.017126 +0.016796 +0.016591 +0.016371 +0.016203 +0.015614 +0.014994 +0.014842 +0.014784 +0.014693 +0.014631 +0.014228 +0.01376 +0.013578 +0.013772 +0.0137 +0.013413 +0.013058 +0.012863 +0.012946 +0.013001 +0.012801 +0.012791 +0.012484 +0.012308 +0.012315 +0.012352 +0.012402 +0.012389 +0.012078 +0.011917 +0.012071 +0.012101 +0.012058 +0.011934 +0.011807 +0.01167 +0.011628 +0.011647 +0.01175 +0.011807 +0.011684 +0.011561 +0.011508 +0.011647 +0.011778 +0.011875 +0.011648 +0.01155 +0.011624 +0.011752 +0.011875 +0.011957 +0.011872 +0.01168 +0.011617 +0.011781 +0.011981 +0.012034 +0.011695 +0.011626 +0.011754 +0.011869 +0.012014 +0.012084 +0.011848 +0.01175 +0.011846 +0.011932 +0.012037 +0.012141 +0.011916 +0.011829 +0.011917 +0.012069 +0.012128 +0.012154 +0.011962 +0.011885 +0.011943 +0.012052 +0.012183 +0.012265 +0.012061 +0.011952 +0.011994 +0.012113 +0.012247 +0.012336 +0.012088 +0.012018 +0.012072 +0.012225 +0.012362 +0.012418 +0.012139 +0.012031 +0.012128 +0.012258 +0.012389 +0.012465 +0.012274 +0.01213 +0.0122 +0.012302 +0.012446 +0.012521 +0.012293 +0.012216 +0.012254 +0.012386 +0.012533 +0.012597 +0.012361 +0.01229 +0.012382 +0.012416 +0.012591 +0.012653 +0.012416 +0.012314 +0.012397 +0.01253 +0.01267 +0.012723 +0.012495 +0.012419 +0.012446 +0.01259 +0.012718 +0.012779 +0.012575 +0.012465 +0.012551 +0.012696 +0.012821 +0.012827 +0.012635 +0.012526 +0.012576 +0.012719 +0.012855 +0.012935 +0.012715 +0.012598 +0.012661 +0.012791 +0.012928 +0.013012 +0.012739 +0.012667 +0.01275 +0.012905 +0.013004 +0.013133 +0.012793 +0.012692 +0.01278 +0.012973 +0.013062 +0.013163 +0.01289 +0.012781 +0.012865 +0.013 +0.013168 +0.013204 +0.012975 +0.012845 +0.012974 +0.013076 +0.013206 +0.01329 +0.013086 +0.012902 +0.012988 +0.013132 +0.013322 +0.013355 +0.013109 +0.012974 +0.013077 +0.01319 +0.013297 +0.013374 +0.013086 +0.012917 +0.012873 +0.012909 +0.012979 +0.01291 +0.012574 +0.012383 +0.012342 +0.012401 +0.012345 +0.012258 +0.011953 +0.011771 +0.011726 +0.011766 +0.011754 +0.011706 +0.011429 +0.011237 +0.011194 +0.011221 +0.011213 +0.011203 +0.01093 +0.010752 +0.010725 +0.010751 +0.010784 +0.010739 +0.01049 +0.01034 +0.010328 +0.010324 +0.010345 +0.010352 +0.010134 +0.009979 +0.009995 +0.010058 +0.010089 +0.010066 +0.009867 +0.00974 +0.009765 +0.009808 +0.009859 +0.009888 +0.009687 +0.009573 +0.009613 +0.00963 +0.009699 +0.009723 +0.00952 +0.009424 +0.009443 +0.009503 +0.009554 +0.009554 +0.009371 +0.009276 +0.00933 +0.009359 +0.009439 +0.009501 +0.009326 +0.009249 +0.009308 +0.009373 +0.009472 +0.009538 +0.009389 +0.009305 +0.009352 +0.009444 +0.00952 +0.009593 +0.00943 +0.009341 +0.009392 +0.009482 +0.009579 +0.009674 +0.009488 +0.009392 +0.009429 +0.009551 +0.009624 +0.009676 +0.009519 +0.009436 +0.009496 +0.0096 +0.009675 +0.009745 +0.009588 +0.009492 +0.009556 +0.009621 +0.009728 +0.009795 +0.00962 +0.009535 +0.009598 +0.009681 +0.009778 +0.009859 +0.009696 +0.009635 +0.009664 +0.009722 +0.009821 +0.009887 +0.009724 +0.009658 +0.009686 +0.009775 +0.009881 +0.009961 +0.009788 +0.009699 +0.009741 +0.00983 +0.009935 +0.010003 +0.009834 +0.009744 +0.009793 +0.009888 +0.010018 +0.010062 +0.009885 +0.009801 +0.009864 +0.009956 +0.010024 +0.010093 +0.009923 +0.009836 +0.009912 +0.010013 +0.010135 +0.010158 +0.009963 +0.009899 +0.009958 +0.01002 +0.01015 +0.010223 +0.010032 +0.009963 +0.010032 +0.010113 +0.01021 +0.010256 +0.010074 +0.009996 +0.010084 +0.010172 +0.010291 +0.010296 +0.010132 +0.010062 +0.01013 +0.010209 +0.010294 +0.010379 +0.010197 +0.010107 +0.010167 +0.010241 +0.010364 +0.010455 +0.010262 +0.010173 +0.01023 +0.010315 +0.010414 +0.01048 +0.010293 +0.01021 +0.010273 +0.010384 +0.010539 +0.010543 +0.010375 +0.010249 +0.010317 +0.010414 +0.010516 +0.010595 +0.010405 +0.010313 +0.010404 +0.01051 +0.010587 +0.010666 +0.01046 +0.010364 +0.010439 +0.010528 +0.010637 +0.010714 +0.010529 +0.010451 +0.010526 +0.010621 +0.010717 +0.010737 +0.010555 +0.010478 +0.01058 +0.010616 +0.010751 +0.010855 +0.010647 +0.010551 +0.010605 +0.010679 +0.010801 +0.010893 +0.010693 +0.010586 +0.010677 +0.010791 +0.010886 +0.010952 +0.010734 +0.010644 +0.010711 +0.010858 +0.010923 +0.010977 +0.010793 +0.010718 +0.010777 +0.010904 +0.010977 +0.011046 +0.01086 +0.010772 +0.010832 +0.01094 +0.011059 +0.011113 +0.010915 +0.010837 +0.010894 +0.010983 +0.011113 +0.011171 +0.010996 +0.010914 +0.010977 +0.011034 +0.011145 +0.011219 +0.01103 +0.010931 +0.011006 +0.011118 +0.011258 +0.011281 +0.011085 +0.01099 +0.011064 +0.011175 +0.011252 +0.011325 +0.011113 +0.010976 +0.011044 +0.011085 +0.01112 +0.011133 +0.010887 +0.010778 +0.010785 +0.010779 +0.010842 +0.010826 +0.010606 +0.010437 +0.01045 +0.010487 +0.010524 +0.010534 +0.010291 +0.010145 +0.010149 +0.0102 +0.010243 +0.010251 +0.009992 +0.00987 +0.009854 +0.009891 +0.009924 +0.00992 +0.009703 +0.009572 +0.009588 +0.009585 +0.009641 +0.009615 +0.009415 +0.009289 +0.009305 +0.009335 +0.009394 +0.009386 +0.009211 +0.009097 +0.009115 +0.009167 +0.009219 +0.009228 +0.009047 +0.008935 +0.008973 +0.009006 +0.009066 +0.009097 +0.00893 +0.008812 +0.008844 +0.008908 +0.008973 +0.009008 +0.008811 +0.008715 +0.00876 +0.008816 +0.008925 +0.008931 +0.008789 +0.008716 +0.008771 +0.008831 +0.00894 +0.008999 +0.008843 +0.00875 +0.00881 +0.00889 +0.008971 +0.009032 +0.008886 +0.008806 +0.008862 +0.008934 +0.009037 +0.009087 +0.008934 +0.008852 +0.008912 +0.00901 +0.009061 +0.009127 +0.008968 +0.008896 +0.008955 +0.009031 +0.009149 +0.009207 +0.009003 +0.008934 +0.008989 +0.009079 +0.009154 +0.009224 +0.009067 +0.008997 +0.009053 +0.009121 +0.009225 +0.009275 +0.009111 +0.00904 +0.00909 +0.009168 +0.009267 +0.009332 +0.00919 +0.009095 +0.009136 +0.009204 +0.00931 +0.009386 +0.009207 +0.009129 +0.009183 +0.009272 +0.009348 +0.009419 +0.009279 +0.00918 +0.009222 +0.009307 +0.009419 +0.009486 +0.009313 +0.00924 +0.00929 +0.009362 +0.009462 +0.009514 +0.009357 +0.009279 +0.009342 +0.009447 +0.009527 +0.009593 +0.009382 +0.009314 +0.009385 +0.009453 +0.009551 +0.009619 +0.009458 +0.009372 +0.009446 +0.009535 +0.009616 +0.009658 +0.009507 +0.009416 +0.009479 +0.009568 +0.009651 +0.009722 +0.009561 +0.009488 +0.009537 +0.009622 +0.009706 +0.009791 +0.009619 +0.009514 +0.009569 +0.009684 +0.009753 +0.00982 +0.009658 +0.009583 +0.009644 +0.009704 +0.009809 +0.009877 +0.009712 +0.00961 +0.009677 +0.009753 +0.009868 +0.009946 +0.009769 +0.009683 +0.009738 +0.009805 +0.009912 +0.009988 +0.009811 +0.009758 +0.009781 +0.009866 +0.009958 +0.010046 +0.009873 +0.009794 +0.009814 +0.009922 +0.010007 +0.01009 +0.009915 +0.009825 +0.009892 +0.009972 +0.010102 +0.010148 +0.009963 +0.009861 +0.009933 +0.010024 +0.010129 +0.010194 +0.010015 +0.009948 +0.010027 +0.010093 +0.010181 +0.010233 +0.010056 +0.009983 +0.010034 +0.010131 +0.010245 +0.010285 +0.010131 +0.010048 +0.010103 +0.010189 +0.010305 +0.010334 +0.010174 +0.010119 +0.01015 +0.010229 +0.010334 +0.010403 +0.010244 +0.01016 +0.010224 +0.010347 +0.010384 +0.010437 +0.010264 +0.010192 +0.010241 +0.010324 +0.010452 +0.010542 +0.010354 +0.010265 +0.010314 +0.010385 +0.010499 +0.010567 +0.010389 +0.010298 +0.010355 +0.010472 +0.010581 +0.010649 +0.010447 +0.010343 +0.010414 +0.010551 +0.010599 +0.010678 +0.01049 +0.010403 +0.010484 +0.010578 +0.010687 +0.010731 +0.010536 +0.010462 +0.010522 +0.010613 +0.010732 +0.010796 +0.010598 +0.010523 +0.010575 +0.010669 +0.010798 +0.010837 +0.01068 +0.010576 +0.010667 +0.010775 +0.010838 +0.010863 +0.010691 +0.010611 +0.010638 +0.010726 +0.010777 +0.010796 +0.010579 +0.010485 +0.010496 +0.010534 +0.010574 +0.010556 +0.010338 +0.010196 +0.01021 +0.010267 +0.010292 +0.010302 +0.010098 +0.009932 +0.009938 +0.009996 +0.010037 +0.010056 +0.009787 +0.009653 +0.009686 +0.00976 +0.009743 +0.009763 +0.009533 +0.009386 +0.009409 +0.009442 +0.00948 +0.009464 +0.009263 +0.00915 +0.009164 +0.009204 +0.009248 +0.009271 +0.009052 +0.008936 +0.008981 +0.009004 +0.009054 +0.009072 +0.008886 +0.008797 +0.008825 +0.008867 +0.008911 +0.008927 +0.00875 +0.008646 +0.008685 +0.008743 +0.008787 +0.008804 +0.008641 +0.008544 +0.008602 +0.008658 +0.008725 +0.008764 +0.008603 +0.008517 +0.008569 +0.008649 +0.008707 +0.00878 +0.008642 +0.008564 +0.0086 +0.00868 +0.008791 +0.008846 +0.008707 +0.008609 +0.008644 +0.008719 +0.008804 +0.008873 +0.008726 +0.008643 +0.008692 +0.008783 +0.00889 +0.008922 +0.008774 +0.008701 +0.00874 +0.008817 +0.00891 +0.008971 +0.008814 +0.008726 +0.008792 +0.008873 +0.00896 +0.009023 +0.008852 +0.00878 +0.008835 +0.008921 +0.009026 +0.009066 +0.008934 +0.008816 +0.008878 +0.008965 +0.009063 +0.009103 +0.008941 +0.008877 +0.008938 +0.009003 +0.009095 +0.009152 +0.008992 +0.008919 +0.008983 +0.009058 +0.009152 +0.009221 +0.009039 +0.008961 +0.00903 +0.009119 +0.009181 +0.009251 +0.009097 +0.009017 +0.009106 +0.009158 +0.009242 +0.009299 +0.009148 +0.009057 +0.009106 +0.009193 +0.00928 +0.009353 +0.009192 +0.009113 +0.009177 +0.009257 +0.009346 +0.009405 +0.009228 +0.009153 +0.00921 +0.009298 +0.009379 +0.009442 +0.009308 +0.009206 +0.009263 +0.009363 +0.009454 +0.009528 +0.009324 +0.009244 +0.009299 +0.009392 +0.009487 +0.009566 +0.009371 +0.009297 +0.009363 +0.009458 +0.009548 +0.009596 +0.009423 +0.009345 +0.009416 +0.009492 +0.009577 +0.009649 +0.009479 +0.009398 +0.009469 +0.00957 +0.009635 +0.009694 +0.009538 +0.009466 +0.009517 +0.009582 +0.009666 +0.009751 +0.009596 +0.009506 +0.009563 +0.009684 +0.009719 +0.009787 +0.00962 +0.009547 +0.009583 +0.009677 +0.009789 +0.009864 +0.009705 +0.009616 +0.009678 +0.009733 +0.009838 +0.009901 +0.009724 +0.009641 +0.009709 +0.009815 +0.009911 +0.009944 +0.009769 +0.009694 +0.009762 +0.009844 +0.00994 +0.010018 +0.009833 +0.009767 +0.009798 +0.009894 +0.009992 +0.010064 +0.00989 +0.009791 +0.009869 +0.009958 +0.010042 +0.010123 +0.009969 +0.009845 +0.009902 +0.010005 +0.010119 +0.010188 +0.009975 +0.009897 +0.009958 +0.010055 +0.010161 +0.010225 +0.010034 +0.009945 +0.010016 +0.010106 +0.01023 +0.010255 +0.010101 +0.010012 +0.010071 +0.010163 +0.010275 +0.010319 +0.010146 +0.010063 +0.010117 +0.010201 +0.010313 +0.010428 +0.010213 +0.010099 +0.010188 +0.010262 +0.010386 +0.010431 +0.010241 +0.010163 +0.010212 +0.010309 +0.010435 +0.01049 +0.010315 +0.010244 +0.010267 +0.010361 +0.010478 +0.010542 +0.010363 +0.010281 +0.010327 +0.010432 +0.010543 +0.010648 +0.01042 +0.010315 +0.010379 +0.010467 +0.010588 +0.010655 +0.010469 +0.010377 +0.010429 +0.010536 +0.010677 +0.010683 +0.010498 +0.010403 +0.010456 +0.010526 +0.010603 +0.010609 +0.010377 +0.010251 +0.010299 +0.01033 +0.010379 +0.010389 +0.010181 +0.010017 +0.010012 +0.010067 +0.01011 +0.010127 +0.009895 +0.00976 +0.009793 +0.009795 +0.009837 +0.009848 +0.009614 +0.009486 +0.009514 +0.00955 +0.009595 +0.009597 +0.009379 +0.009234 +0.009257 +0.009298 +0.009324 +0.009327 +0.009129 +0.009007 +0.009055 +0.009082 +0.009128 +0.009128 +0.00894 +0.008826 +0.008846 +0.008899 +0.008948 +0.008968 +0.008784 +0.008692 +0.008709 +0.008755 +0.008807 +0.008844 +0.008666 +0.008558 +0.00858 +0.008643 +0.008696 +0.00872 +0.00855 +0.008468 +0.008495 +0.008566 +0.00863 +0.008684 +0.008535 +0.008465 +0.00849 +0.008557 +0.008659 +0.008693 +0.008555 +0.008466 +0.008521 +0.008592 +0.008702 +0.008757 +0.008604 +0.008532 +0.008587 +0.008642 +0.00872 +0.00879 +0.008637 +0.008563 +0.008618 +0.008694 +0.00877 +0.008863 +0.008708 +0.008618 +0.008669 +0.008742 +0.008814 +0.008902 +0.008747 +0.008654 +0.008696 +0.008775 +0.008853 +0.008966 +0.008774 +0.008703 +0.008761 +0.008831 +0.008904 +0.008963 +0.008824 +0.008739 +0.008799 +0.00888 +0.008953 +0.00902 +0.008875 +0.008793 +0.008843 +0.008926 +0.00901 +0.009076 +0.008917 +0.008829 +0.008898 +0.00898 +0.009089 +0.009118 +0.008963 +0.00887 +0.008932 +0.009022 +0.00909 +0.009185 +0.009002 +0.008919 +0.008979 +0.009063 +0.009161 +0.009221 +0.009062 +0.008976 +0.009024 +0.009112 +0.009191 +0.009265 +0.009107 +0.009022 +0.009084 +0.009154 +0.009252 +0.00932 +0.00917 +0.009092 +0.009123 +0.009193 +0.009287 +0.009349 +0.009195 +0.009106 +0.009171 +0.009252 +0.009369 +0.009436 +0.009246 +0.00916 +0.00921 +0.009291 +0.009388 +0.009458 +0.009281 +0.0092 +0.009273 +0.009356 +0.009473 +0.009528 +0.009351 +0.009242 +0.00931 +0.009403 +0.009521 +0.009552 +0.009399 +0.009289 +0.009359 +0.009462 +0.009546 +0.009612 +0.009447 +0.009351 +0.0094 +0.009496 +0.009588 +0.009643 +0.009484 +0.009404 +0.00946 +0.009563 +0.009666 +0.009713 +0.009542 +0.009447 +0.009507 +0.009586 +0.009688 +0.009763 +0.009608 +0.009524 +0.009557 +0.00965 +0.009779 +0.009806 +0.009613 +0.009534 +0.009605 +0.009691 +0.009789 +0.009852 +0.009689 +0.00961 +0.00968 +0.009771 +0.009849 +0.009899 +0.009727 +0.009631 +0.009718 +0.009806 +0.009893 +0.009957 +0.009795 +0.009725 +0.009819 +0.009851 +0.009948 +0.009991 +0.009822 +0.009751 +0.009831 +0.009893 +0.010013 +0.010054 +0.009884 +0.009811 +0.009855 +0.009945 +0.010054 +0.010121 +0.009939 +0.009859 +0.009922 +0.01002 +0.010103 +0.010173 +0.01 +0.009913 +0.009973 +0.010085 +0.01016 +0.010206 +0.010041 +0.009956 +0.010039 +0.010109 +0.010205 +0.010308 +0.010089 +0.010004 +0.010068 +0.010156 +0.010263 +0.010347 +0.010137 +0.010071 +0.010124 +0.010207 +0.010327 +0.010402 +0.010202 +0.010116 +0.010185 +0.010285 +0.01043 +0.010431 +0.010241 +0.010156 +0.010229 +0.010317 +0.010424 +0.010499 +0.010316 +0.010221 +0.010284 +0.010374 +0.010491 +0.010547 +0.010364 +0.010272 +0.010344 +0.010435 +0.010536 +0.010599 +0.010391 +0.010304 +0.010358 +0.010449 +0.010522 +0.010491 +0.010287 +0.010154 +0.010182 +0.010242 +0.010303 +0.010312 +0.010068 +0.009961 +0.009961 +0.010013 +0.010041 +0.010038 +0.009814 +0.009691 +0.00971 +0.009749 +0.009772 +0.009798 +0.009577 +0.00945 +0.009477 +0.009501 +0.009531 +0.00955 +0.009342 +0.009233 +0.009223 +0.009261 +0.009322 +0.009296 +0.009116 +0.008987 +0.009019 +0.009067 +0.009099 +0.009115 +0.008926 +0.008824 +0.008857 +0.008898 +0.008945 +0.008961 +0.008785 +0.008678 +0.008723 +0.008766 +0.008815 +0.008839 +0.00867 +0.00856 +0.008606 +0.008665 +0.008716 +0.008762 +0.008564 +0.008491 +0.008519 +0.00859 +0.008655 +0.008705 +0.008534 +0.008462 +0.008524 +0.008593 +0.008671 +0.008746 +0.008592 +0.008503 +0.008561 +0.008647 +0.008721 +0.008781 +0.008632 +0.008553 +0.008599 +0.008679 +0.00877 +0.008835 +0.00868 +0.008616 +0.008668 +0.008743 +0.008828 +0.008857 +0.00871 +0.008639 +0.008694 +0.008774 +0.008856 +0.008921 +0.008779 +0.008694 +0.008747 +0.008821 +0.008902 +0.008951 +0.008804 +0.008731 +0.008793 +0.008859 +0.008937 +0.009016 +0.00887 +0.008787 +0.008846 +0.008928 +0.009002 +0.009041 +0.008902 +0.008825 +0.008931 +0.008941 +0.009032 +0.009084 +0.008944 +0.00887 +0.008934 +0.009009 +0.009096 +0.009146 +0.009002 +0.00891 +0.008978 +0.009046 +0.009132 +0.009195 +0.009047 +0.008965 +0.009032 +0.009114 +0.00919 +0.009239 +0.009079 +0.009006 +0.009065 +0.009143 +0.009238 +0.009311 +0.009157 +0.009049 +0.00914 +0.009199 +0.009283 +0.009349 +0.009163 +0.009092 +0.009157 +0.00923 +0.009326 +0.009398 +0.009231 +0.009153 +0.009223 +0.009311 +0.009381 +0.009438 +0.009278 +0.009195 +0.009246 +0.009336 +0.009426 +0.009486 +0.00933 +0.009262 +0.009347 +0.009428 +0.009473 +0.009513 +0.009356 +0.009308 +0.009342 +0.009423 +0.009518 +0.009589 +0.009418 +0.009357 +0.009432 +0.009494 +0.009585 +0.009624 +0.009464 +0.009383 +0.009443 +0.009546 +0.009616 +0.009688 +0.009536 +0.00945 +0.009507 +0.009585 +0.009683 +0.009767 +0.009564 +0.009483 +0.009548 +0.009624 +0.009749 +0.009814 +0.009614 +0.009547 +0.009593 +0.009677 +0.009774 +0.009839 +0.009677 +0.00959 +0.009651 +0.009743 +0.009833 +0.009917 +0.009722 +0.009643 +0.009703 +0.009779 +0.009874 +0.009952 +0.009798 +0.009716 +0.009743 +0.009838 +0.009927 +0.009998 +0.009832 +0.009739 +0.00979 +0.009908 +0.009977 +0.010046 +0.009881 +0.009792 +0.009854 +0.009951 +0.010036 +0.010104 +0.009946 +0.009841 +0.009889 +0.009988 +0.010077 +0.010165 +0.009992 +0.009913 +0.009992 +0.010067 +0.010125 +0.0102 +0.010022 +0.009936 +0.010003 +0.010097 +0.010205 +0.01027 +0.010083 +0.009998 +0.010053 +0.010151 +0.010256 +0.010312 +0.010148 +0.010059 +0.010121 +0.010201 +0.01032 +0.010361 +0.010187 +0.010104 +0.010193 +0.01027 +0.010342 +0.010431 +0.010246 +0.010162 +0.010228 +0.010306 +0.010403 +0.010474 +0.010295 +0.010212 +0.010279 +0.010354 +0.010476 +0.010533 +0.010368 +0.010283 +0.010326 +0.010403 +0.010516 +0.010576 +0.010405 +0.010316 +0.010396 +0.010485 +0.010546 +0.010615 +0.010406 +0.010308 +0.010316 +0.01037 +0.010431 +0.010454 +0.010248 +0.010113 +0.010143 +0.010186 +0.010242 +0.010225 +0.00999 +0.009849 +0.009869 +0.009902 +0.009943 +0.009943 +0.009747 +0.009622 +0.009616 +0.009659 +0.009696 +0.009718 +0.009471 +0.009345 +0.009354 +0.00939 +0.009444 +0.009463 +0.009255 +0.009142 +0.009135 +0.009173 +0.009213 +0.00922 +0.009027 +0.008915 +0.008941 +0.00898 +0.009016 +0.009043 +0.008881 +0.008766 +0.008787 +0.008835 +0.008874 +0.008902 +0.008739 +0.008641 +0.008679 +0.008723 +0.00876 +0.008789 +0.008631 +0.008545 +0.008576 +0.008618 +0.008683 +0.008728 +0.00855 +0.008468 +0.008509 +0.00858 +0.008646 +0.008713 +0.008569 +0.008509 +0.008562 +0.008635 +0.008721 +0.00876 +0.008607 +0.008525 +0.008587 +0.008653 +0.00874 +0.008803 +0.008657 +0.008597 +0.008667 +0.008712 +0.008787 +0.008845 +0.0087 +0.008621 +0.008669 +0.008745 +0.008838 +0.008898 +0.008775 +0.008657 +0.008728 +0.008801 +0.008894 +0.008946 +0.008798 +0.00871 +0.008766 +0.008845 +0.00892 +0.008981 +0.008832 +0.008755 +0.00881 +0.008885 +0.008984 +0.009051 +0.008911 +0.008801 +0.008861 +0.008938 +0.009011 +0.009086 +0.008923 +0.008847 +0.008905 +0.008998 +0.009059 +0.009132 +0.008985 +0.00889 +0.008955 +0.009027 +0.009115 +0.009183 +0.00903 +0.008941 +0.008995 +0.009085 +0.009162 +0.009231 +0.009071 +0.008986 +0.009052 +0.009146 +0.00923 +0.009266 +0.009107 +0.00903 +0.009108 +0.009191 +0.009245 +0.009318 +0.009168 +0.009071 +0.009142 +0.009224 +0.009298 +0.009383 +0.00922 +0.009134 +0.009193 +0.009267 +0.009361 +0.009416 +0.009256 +0.009178 +0.009236 +0.009306 +0.009405 +0.009485 +0.009335 +0.009257 +0.009288 +0.009377 +0.009443 +0.009507 +0.00935 +0.009273 +0.009341 +0.00942 +0.009491 +0.009568 +0.009417 +0.00934 +0.009387 +0.009472 +0.009548 +0.009619 +0.009445 +0.009377 +0.009427 +0.009509 +0.009613 +0.009667 +0.009517 +0.009435 +0.009495 +0.00959 +0.009642 +0.009708 +0.00954 +0.009467 +0.00954 +0.009612 +0.009706 +0.009784 +0.009633 +0.009521 +0.00958 +0.009655 +0.009748 +0.009818 +0.009655 +0.009568 +0.009631 +0.00973 +0.009802 +0.009891 +0.009716 +0.009622 +0.00966 +0.009764 +0.009867 +0.009962 +0.009764 +0.009661 +0.009722 +0.009827 +0.009926 +0.009979 +0.009803 +0.009709 +0.009775 +0.009859 +0.009971 +0.010024 +0.009851 +0.009783 +0.009848 +0.009939 +0.010033 +0.01008 +0.009891 +0.009816 +0.009876 +0.009964 +0.010067 +0.010136 +0.009999 +0.009895 +0.009943 +0.010029 +0.01014 +0.010163 +0.009993 +0.009914 +0.009987 +0.01006 +0.010159 +0.010267 +0.010098 +0.009987 +0.010054 +0.010126 +0.010212 +0.010292 +0.010103 +0.010019 +0.010093 +0.010176 +0.010291 +0.010368 +0.010178 +0.010128 +0.010143 +0.010207 +0.010322 +0.01039 +0.010245 +0.010131 +0.010187 +0.010285 +0.010387 +0.010464 +0.010276 +0.010176 +0.010249 +0.010355 +0.010448 +0.010512 +0.010341 +0.010225 +0.0103 +0.010393 +0.010497 +0.01057 +0.010376 +0.010338 +0.010351 +0.010424 +0.010529 +0.010578 +0.010384 +0.010259 +0.010294 +0.010335 +0.010404 +0.010456 +0.010212 +0.010092 +0.010127 +0.010145 +0.01019 +0.010221 +0.009957 +0.009831 +0.009841 +0.009883 +0.009923 +0.00995 +0.009726 +0.009609 +0.009632 +0.009666 +0.009685 +0.009687 +0.009473 +0.009351 +0.00937 +0.009389 +0.009438 +0.009459 +0.009272 +0.009131 +0.009139 +0.00916 +0.009203 +0.009221 +0.009031 +0.008919 +0.008924 +0.008966 +0.009036 +0.009044 +0.008863 +0.008762 +0.008776 +0.008809 +0.008861 +0.008903 +0.008732 +0.008641 +0.008654 +0.00868 +0.008727 +0.008772 +0.008613 +0.008509 +0.008541 +0.008593 +0.00866 +0.008674 +0.008528 +0.008439 +0.008477 +0.008544 +0.008615 +0.008677 +0.008539 +0.008467 +0.008524 +0.008602 +0.00867 +0.008726 +0.008569 +0.008502 +0.008552 +0.008624 +0.008707 +0.008773 +0.008645 +0.008544 +0.008594 +0.008685 +0.008747 +0.008819 +0.008658 +0.008591 +0.008648 +0.008716 +0.008805 +0.008862 +0.008714 +0.008655 +0.008718 +0.00875 +0.008845 +0.008898 +0.008753 +0.008681 +0.008737 +0.008803 +0.008894 +0.00897 +0.00882 +0.008731 +0.008791 +0.008871 +0.008957 +0.009009 +0.008837 +0.008762 +0.00882 +0.008899 +0.008984 +0.009045 +0.008912 +0.008833 +0.008886 +0.008953 +0.009018 +0.009096 +0.008935 +0.008861 +0.008949 +0.008986 +0.009077 +0.009157 +0.008999 +0.008918 +0.008974 +0.009055 +0.009113 +0.009183 +0.009035 +0.008949 +0.009043 +0.009112 +0.00917 +0.009232 +0.009073 +0.009005 +0.009054 +0.009137 +0.009217 +0.009296 +0.009131 +0.009059 +0.009118 +0.009196 +0.009265 +0.009336 +0.009186 +0.009104 +0.009166 +0.009234 +0.009306 +0.009385 +0.009229 +0.009155 +0.009214 +0.009294 +0.009364 +0.009468 +0.009279 +0.009188 +0.009242 +0.009321 +0.00941 +0.009487 +0.009335 +0.009255 +0.009314 +0.009402 +0.009455 +0.00953 +0.009359 +0.00929 +0.009348 +0.009431 +0.009516 +0.0096 +0.009446 +0.009342 +0.009401 +0.009483 +0.009558 +0.009627 +0.009472 +0.009389 +0.009465 +0.009507 +0.009635 +0.009676 +0.009532 +0.009449 +0.009507 +0.009576 +0.009668 +0.009739 +0.009558 +0.009482 +0.009534 +0.009613 +0.009721 +0.00982 +0.009626 +0.009542 +0.009611 +0.00966 +0.009766 +0.009843 +0.00965 +0.009579 +0.009642 +0.009737 +0.009868 +0.009898 +0.009719 +0.009638 +0.009682 +0.009779 +0.009868 +0.009933 +0.009771 +0.00968 +0.009753 +0.009853 +0.009941 +0.010028 +0.009818 +0.009717 +0.009775 +0.009879 +0.009972 +0.01005 +0.009884 +0.009774 +0.009845 +0.009937 +0.010039 +0.010126 +0.009914 +0.009831 +0.009887 +0.009985 +0.010103 +0.010186 +0.009954 +0.009885 +0.009947 +0.010029 +0.010146 +0.010194 +0.010027 +0.009944 +0.010038 +0.0101 +0.010198 +0.010241 +0.010072 +0.009985 +0.010051 +0.010138 +0.010233 +0.010332 +0.010174 +0.010055 +0.010111 +0.010181 +0.010285 +0.010363 +0.010176 +0.010093 +0.01019 +0.010239 +0.010347 +0.010432 +0.01025 +0.010157 +0.010212 +0.010295 +0.0104 +0.010478 +0.010289 +0.010185 +0.010274 +0.01035 +0.010489 +0.010543 +0.010349 +0.010256 +0.010273 +0.01034 +0.010433 +0.010481 +0.010246 +0.01012 +0.010174 +0.010251 +0.010296 +0.010286 +0.010057 +0.00992 +0.009958 +0.009997 +0.01003 +0.010037 +0.009806 +0.009691 +0.009721 +0.00976 +0.009779 +0.00977 +0.009562 +0.009454 +0.009468 +0.009487 +0.009508 +0.009523 +0.009322 +0.009207 +0.009217 +0.009253 +0.009272 +0.009272 +0.009072 +0.008968 +0.009003 +0.009022 +0.009051 +0.009086 +0.008885 +0.008796 +0.00883 +0.008866 +0.008894 +0.008921 +0.008744 +0.008631 +0.008666 +0.008724 +0.008762 +0.008812 +0.008611 +0.008509 +0.00855 +0.008599 +0.008658 +0.008694 +0.008492 +0.008408 +0.008457 +0.008515 +0.008584 +0.008626 +0.008475 +0.008395 +0.008465 +0.008552 +0.008628 +0.008678 +0.008513 +0.008448 +0.008488 +0.008562 +0.008649 +0.008716 +0.008564 +0.008489 +0.00855 +0.008633 +0.008738 +0.008765 +0.008611 +0.00853 +0.008574 +0.008655 +0.008741 +0.008805 +0.008672 +0.00857 +0.008629 +0.008722 +0.008799 +0.008854 +0.0087 +0.008621 +0.008668 +0.008752 +0.008839 +0.008893 +0.008746 +0.008662 +0.008724 +0.008811 +0.008892 +0.008948 +0.008787 +0.008728 +0.008774 +0.008864 +0.008913 +0.008977 +0.008835 +0.008765 +0.008821 +0.008899 +0.008964 +0.009025 +0.00888 +0.008819 +0.008848 +0.008936 +0.009011 +0.009087 +0.008923 +0.008857 +0.008908 +0.008979 +0.009067 +0.009135 +0.008969 +0.008897 +0.008952 +0.009027 +0.009113 +0.009193 +0.009035 +0.008964 +0.00899 +0.009072 +0.009165 +0.009221 +0.009065 +0.00899 +0.00904 +0.009123 +0.009206 +0.009281 +0.009112 +0.009055 +0.009084 +0.009173 +0.009266 +0.00933 +0.009154 +0.009078 +0.00914 +0.009216 +0.009308 +0.009389 +0.009202 +0.009125 +0.009195 +0.009278 +0.009389 +0.009418 +0.009251 +0.009168 +0.009251 +0.009318 +0.009416 +0.009455 +0.009301 +0.009222 +0.009283 +0.009364 +0.009458 +0.009512 +0.00935 +0.009282 +0.009346 +0.009421 +0.009519 +0.009566 +0.009389 +0.009318 +0.009388 +0.009464 +0.009548 +0.009625 +0.009461 +0.009397 +0.009429 +0.009517 +0.009607 +0.009649 +0.009496 +0.009437 +0.009468 +0.009563 +0.009638 +0.009713 +0.00956 +0.009471 +0.009536 +0.009629 +0.009718 +0.009752 +0.009596 +0.009516 +0.009572 +0.009657 +0.009746 +0.00982 +0.009665 +0.009585 +0.009655 +0.009746 +0.00978 +0.009856 +0.009697 +0.009612 +0.009674 +0.009752 +0.009872 +0.00995 +0.009744 +0.009669 +0.009743 +0.0098 +0.009903 +0.009978 +0.009797 +0.00973 +0.009792 +0.009859 +0.00995 +0.010023 +0.009849 +0.009767 +0.009824 +0.009925 +0.010057 +0.010086 +0.009907 +0.009812 +0.009867 +0.009967 +0.010058 +0.010127 +0.009961 +0.009857 +0.009958 +0.010028 +0.010137 +0.010195 +0.010011 +0.009917 +0.009971 +0.010071 +0.010168 +0.01024 +0.010053 +0.009979 +0.010037 +0.010139 +0.010244 +0.01032 +0.010106 +0.010007 +0.010101 +0.010153 +0.010278 +0.010336 +0.010179 +0.010078 +0.010148 +0.010238 +0.010324 +0.010386 +0.010211 +0.010136 +0.01019 +0.010268 +0.010408 +0.010464 +0.010285 +0.010203 +0.010243 +0.010321 +0.010439 +0.010509 +0.010321 +0.01019 +0.010244 +0.010343 +0.010442 +0.010407 +0.010192 +0.010069 +0.010109 +0.010132 +0.010188 +0.0102 +0.00998 +0.009837 +0.009879 +0.009883 +0.009924 +0.009925 +0.009704 +0.009578 +0.009595 +0.009629 +0.009669 +0.009657 +0.00945 +0.00935 +0.009354 +0.009355 +0.009385 +0.009389 +0.009191 +0.009062 +0.00911 +0.009102 +0.009149 +0.009152 +0.008959 +0.008858 +0.008863 +0.008904 +0.008944 +0.008965 +0.008768 +0.008659 +0.008693 +0.00873 +0.008772 +0.008792 +0.008619 +0.008523 +0.008544 +0.008597 +0.008645 +0.008686 +0.008501 +0.008399 +0.008435 +0.00848 +0.008531 +0.008564 +0.008414 +0.008321 +0.008377 +0.008453 +0.008475 +0.008519 +0.008375 +0.008311 +0.008368 +0.008442 +0.00852 +0.008583 +0.008426 +0.008359 +0.008411 +0.008495 +0.008564 +0.00861 +0.008477 +0.008397 +0.00845 +0.008528 +0.008611 +0.008669 +0.008547 +0.008434 +0.008492 +0.008574 +0.008656 +0.008708 +0.008553 +0.008485 +0.008528 +0.008616 +0.008702 +0.008763 +0.008593 +0.008527 +0.008583 +0.008676 +0.008752 +0.0088 +0.008636 +0.008567 +0.008629 +0.008705 +0.008772 +0.008845 +0.008692 +0.00862 +0.008675 +0.008763 +0.00886 +0.008922 +0.00874 +0.008676 +0.008708 +0.008781 +0.008874 +0.008921 +0.008779 +0.008702 +0.008757 +0.008841 +0.008927 +0.008994 +0.008831 +0.008757 +0.008803 +0.008879 +0.00896 +0.009032 +0.008883 +0.008793 +0.008847 +0.008932 +0.009031 +0.009088 +0.008932 +0.008855 +0.008901 +0.008992 +0.009047 +0.00911 +0.008958 +0.008885 +0.008961 +0.009016 +0.009112 +0.009186 +0.009026 +0.008935 +0.008982 +0.009069 +0.009157 +0.009214 +0.009064 +0.008978 +0.009026 +0.009115 +0.009218 +0.009283 +0.009124 +0.009044 +0.009083 +0.009161 +0.009244 +0.009316 +0.009179 +0.00908 +0.009124 +0.009202 +0.0093 +0.009363 +0.009202 +0.009145 +0.009178 +0.009254 +0.00934 +0.00941 +0.009255 +0.009161 +0.009238 +0.009315 +0.0094 +0.009473 +0.009298 +0.009225 +0.009274 +0.009347 +0.009452 +0.00952 +0.009344 +0.009259 +0.009347 +0.00943 +0.009506 +0.009552 +0.009384 +0.009312 +0.009375 +0.009444 +0.009544 +0.009611 +0.009473 +0.009349 +0.009421 +0.009508 +0.009597 +0.009668 +0.0095 +0.009411 +0.009466 +0.009547 +0.009654 +0.009715 +0.00955 +0.009484 +0.009514 +0.009596 +0.009705 +0.009781 +0.009611 +0.009523 +0.009537 +0.00964 +0.00974 +0.009826 +0.009653 +0.009566 +0.009613 +0.0097 +0.009794 +0.009866 +0.009686 +0.009608 +0.009663 +0.009747 +0.009865 +0.009936 +0.009747 +0.009652 +0.009724 +0.009813 +0.009899 +0.009959 +0.009791 +0.009731 +0.009773 +0.00986 +0.009962 +0.010039 +0.009829 +0.009745 +0.009818 +0.009911 +0.009991 +0.010068 +0.009887 +0.009804 +0.00988 +0.009987 +0.010073 +0.010128 +0.009951 +0.009852 +0.009916 +0.010011 +0.010116 +0.010179 +0.009984 +0.009926 +0.010017 +0.010098 +0.010156 +0.01021 +0.010022 +0.009961 +0.010037 +0.010103 +0.010221 +0.010272 +0.010096 +0.010021 +0.01007 +0.01017 +0.010276 +0.010329 +0.010155 +0.010069 +0.010129 +0.010225 +0.010327 +0.010397 +0.010202 +0.010119 +0.010183 +0.010308 +0.010377 +0.010437 +0.010261 +0.010186 +0.010241 +0.010305 +0.010443 +0.010461 +0.01027 +0.01016 +0.010217 +0.010279 +0.010352 +0.010372 +0.010154 +0.010032 +0.010027 +0.010089 +0.010136 +0.01014 +0.009915 +0.009778 +0.0098 +0.009851 +0.009891 +0.009919 +0.009664 +0.009515 +0.00953 +0.00956 +0.009607 +0.009609 +0.009408 +0.009299 +0.009283 +0.009316 +0.009347 +0.009385 +0.009162 +0.009044 +0.00907 +0.00909 +0.009134 +0.009164 +0.008971 +0.00884 +0.008864 +0.008911 +0.008943 +0.008977 +0.008793 +0.008686 +0.008739 +0.008788 +0.008797 +0.008819 +0.008659 +0.008549 +0.008586 +0.008635 +0.008679 +0.00872 +0.008545 +0.008441 +0.008484 +0.008547 +0.008602 +0.008648 +0.008494 +0.008411 +0.008446 +0.0085 +0.008588 +0.008636 +0.008503 +0.008432 +0.00848 +0.008534 +0.008628 +0.008687 +0.008556 +0.008493 +0.008548 +0.008596 +0.008661 +0.008736 +0.008573 +0.008514 +0.008554 +0.008632 +0.008713 +0.008778 +0.008636 +0.008568 +0.008624 +0.008696 +0.008754 +0.008816 +0.008676 +0.008619 +0.008647 +0.008729 +0.008805 +0.008856 +0.008721 +0.008667 +0.008702 +0.008781 +0.008859 +0.008907 +0.008788 +0.00869 +0.008735 +0.008805 +0.008894 +0.008961 +0.008825 +0.008731 +0.0088 +0.008883 +0.008942 +0.009003 +0.008852 +0.008786 +0.008833 +0.008902 +0.009003 +0.009051 +0.008909 +0.008819 +0.00888 +0.008952 +0.009038 +0.009112 +0.008948 +0.008863 +0.008933 +0.009009 +0.00912 +0.00916 +0.008995 +0.008909 +0.008965 +0.009048 +0.009137 +0.009201 +0.00906 +0.008953 +0.00901 +0.009091 +0.00919 +0.009261 +0.009091 +0.009005 +0.009073 +0.009151 +0.009236 +0.009302 +0.009134 +0.009049 +0.009112 +0.00919 +0.009279 +0.009364 +0.009203 +0.009122 +0.009184 +0.009232 +0.009318 +0.009383 +0.009232 +0.009151 +0.009203 +0.009283 +0.009389 +0.009459 +0.009284 +0.009193 +0.009267 +0.009338 +0.009427 +0.009504 +0.009331 +0.009239 +0.009309 +0.009415 +0.00948 +0.009559 +0.009384 +0.009275 +0.009356 +0.009443 +0.009551 +0.009604 +0.00943 +0.009332 +0.009401 +0.009496 +0.009592 +0.009644 +0.00946 +0.009397 +0.009452 +0.009533 +0.009635 +0.009689 +0.00953 +0.009459 +0.009511 +0.009601 +0.009679 +0.00975 +0.009563 +0.009492 +0.009554 +0.009637 +0.00974 +0.00979 +0.009638 +0.009559 +0.009594 +0.009678 +0.009786 +0.009846 +0.009672 +0.009589 +0.009646 +0.009755 +0.009838 +0.009888 +0.00973 +0.009643 +0.009722 +0.009797 +0.009876 +0.009945 +0.009787 +0.009689 +0.009759 +0.009858 +0.009944 +0.009996 +0.00983 +0.00975 +0.009842 +0.009898 +0.009972 +0.010043 +0.009902 +0.009796 +0.009881 +0.009953 +0.010029 +0.010097 +0.009932 +0.009841 +0.009916 +0.009988 +0.010086 +0.010186 +0.009997 +0.009905 +0.009964 +0.010032 +0.010144 +0.010206 +0.010039 +0.009957 +0.010011 +0.010092 +0.01023 +0.010315 +0.010118 +0.009992 +0.010038 +0.010144 +0.010243 +0.010343 +0.010129 +0.010043 +0.010107 +0.010211 +0.01031 +0.010388 +0.010195 +0.010119 +0.010165 +0.010261 +0.010368 +0.010428 +0.010252 +0.010182 +0.010215 +0.010316 +0.010428 +0.010483 +0.010301 +0.010213 +0.010319 +0.010381 +0.010464 +0.010532 +0.01034 +0.010235 +0.010298 +0.010398 +0.010438 +0.010461 +0.010242 +0.010133 +0.010156 +0.010219 +0.010302 +0.010256 +0.010021 +0.009878 +0.00991 +0.009965 +0.009992 +0.010001 +0.00977 +0.009655 +0.009665 +0.009718 +0.009767 +0.009776 +0.00953 +0.009386 +0.009409 +0.009451 +0.009502 +0.009487 +0.009289 +0.009162 +0.009187 +0.00924 +0.009267 +0.009262 +0.009048 +0.008939 +0.008994 +0.009002 +0.009048 +0.009052 +0.008876 +0.008754 +0.00879 +0.008852 +0.008894 +0.008893 +0.008715 +0.008609 +0.008652 +0.00872 +0.00874 +0.00876 +0.008585 +0.008489 +0.008553 +0.008591 +0.008652 +0.008678 +0.008501 +0.0084 +0.008442 +0.008512 +0.008575 +0.008614 +0.008462 +0.008389 +0.008442 +0.008538 +0.008608 +0.008676 +0.008509 +0.00844 +0.008477 +0.008558 +0.008638 +0.008697 +0.008559 +0.008487 +0.008555 +0.008608 +0.008696 +0.008744 +0.008596 +0.008539 +0.008583 +0.008634 +0.008716 +0.008783 +0.008654 +0.008565 +0.008618 +0.008693 +0.008807 +0.008841 +0.008699 +0.008615 +0.008672 +0.008726 +0.008834 +0.008875 +0.008726 +0.008658 +0.008708 +0.008776 +0.008873 +0.008951 +0.008801 +0.008731 +0.008756 +0.008833 +0.0089 +0.008964 +0.008838 +0.008743 +0.008795 +0.008878 +0.008958 +0.009028 +0.008865 +0.008814 +0.008834 +0.008914 +0.009003 +0.009074 +0.008913 +0.008842 +0.008916 +0.008977 +0.009046 +0.009122 +0.008963 +0.008884 +0.008939 +0.009023 +0.009111 +0.00919 +0.008996 +0.008918 +0.008996 +0.00907 +0.009155 +0.009205 +0.00905 +0.008981 +0.009032 +0.009114 +0.009189 +0.00927 +0.009116 +0.009042 +0.009091 +0.009164 +0.009233 +0.009306 +0.009157 +0.009068 +0.009126 +0.009222 +0.009283 +0.009362 +0.009208 +0.009125 +0.009218 +0.009268 +0.009334 +0.009391 +0.009241 +0.009178 +0.009251 +0.009305 +0.009384 +0.009451 +0.009291 +0.009217 +0.009289 +0.009355 +0.009431 +0.009511 +0.009355 +0.009252 +0.00933 +0.00941 +0.009489 +0.009561 +0.009401 +0.009313 +0.009381 +0.00946 +0.009551 +0.009635 +0.009429 +0.009346 +0.009418 +0.009501 +0.009609 +0.009662 +0.009488 +0.009438 +0.009457 +0.009533 +0.009642 +0.009707 +0.009543 +0.009459 +0.009522 +0.009599 +0.009705 +0.009771 +0.009609 +0.009516 +0.009564 +0.009641 +0.009741 +0.009817 +0.009646 +0.009589 +0.00961 +0.009701 +0.009813 +0.009883 +0.009702 +0.009604 +0.009651 +0.009749 +0.009839 +0.009939 +0.009737 +0.009641 +0.009719 +0.00983 +0.009915 +0.009974 +0.0098 +0.009698 +0.009761 +0.009848 +0.009955 +0.010021 +0.009836 +0.009766 +0.009861 +0.009943 +0.010008 +0.010066 +0.009882 +0.009816 +0.009861 +0.009945 +0.010055 +0.01011 +0.009949 +0.009871 +0.009953 +0.010006 +0.010109 +0.010178 +0.01 +0.009914 +0.00998 +0.010052 +0.010174 +0.010245 +0.010051 +0.00996 +0.010044 +0.010149 +0.010232 +0.010271 +0.010107 +0.010009 +0.010116 +0.010174 +0.010255 +0.010347 +0.010146 +0.010063 +0.010139 +0.010215 +0.010322 +0.010412 +0.010212 +0.010121 +0.010203 +0.010271 +0.010383 +0.010462 +0.010263 +0.010175 +0.010245 +0.010344 +0.010479 +0.010506 +0.010335 +0.010209 +0.010293 +0.010381 +0.010507 +0.010544 +0.010349 +0.010263 +0.010372 +0.010462 +0.010553 +0.0106 +0.010392 +0.010298 +0.010353 +0.01041 +0.010477 +0.01049 +0.010294 +0.010173 +0.010201 +0.010251 +0.010297 +0.010328 +0.010067 +0.009925 +0.009954 +0.009998 +0.010047 +0.010049 +0.009832 +0.009705 +0.009703 +0.009735 +0.009785 +0.009783 +0.00957 +0.009464 +0.009468 +0.009511 +0.009558 +0.009539 +0.009318 +0.009208 +0.009227 +0.009253 +0.009284 +0.009311 +0.009119 +0.009022 +0.009019 +0.009065 +0.009101 +0.009119 +0.00892 +0.008814 +0.008846 +0.008887 +0.00893 +0.008959 +0.00879 +0.008687 +0.008707 +0.008764 +0.008815 +0.008838 +0.008654 +0.008566 +0.008604 +0.008649 +0.008707 +0.008744 +0.008587 +0.008498 +0.008548 +0.00862 +0.008686 +0.008766 +0.008592 +0.008509 +0.008569 +0.008639 +0.008717 +0.008769 +0.008622 +0.008543 +0.008611 +0.008692 +0.008774 +0.00883 +0.008684 +0.008602 +0.008638 +0.008727 +0.008802 +0.008866 +0.008716 +0.008655 +0.008686 +0.008767 +0.008861 +0.008923 +0.008783 +0.008683 +0.008739 +0.008824 +0.008935 +0.008951 +0.0088 +0.008726 +0.008795 +0.008887 +0.008948 +0.008995 +0.008853 +0.008776 +0.008824 +0.008898 +0.008989 +0.00905 +0.008914 +0.008847 +0.0089 +0.00897 +0.00905 +0.009115 +0.008935 +0.008867 +0.00892 +0.008999 +0.009087 +0.00916 +0.008997 +0.008926 +0.008994 +0.009038 +0.009133 +0.009188 +0.009043 +0.00897 +0.009011 +0.009102 +0.009189 +0.00926 +0.009086 +0.009006 +0.00907 +0.009136 +0.009228 +0.009306 +0.009124 +0.009077 +0.009111 +0.009197 +0.009283 +0.009359 +0.009185 +0.009094 +0.009157 +0.009245 +0.009336 +0.009428 +0.009217 +0.009143 +0.009202 +0.009291 +0.009388 +0.009452 +0.00927 +0.009198 +0.009255 +0.009353 +0.009419 +0.009481 +0.009316 +0.009246 +0.009308 +0.009377 +0.009489 +0.009559 +0.009379 +0.009293 +0.00935 +0.00944 +0.009529 +0.009579 +0.009435 +0.009352 +0.009424 +0.009484 +0.00961 +0.009619 +0.009463 +0.009391 +0.009438 +0.00953 +0.00963 +0.009676 +0.00952 +0.009449 +0.009514 +0.009598 +0.009688 +0.009731 +0.009567 +0.009484 +0.009546 +0.009626 +0.00972 +0.009803 +0.00962 +0.009551 +0.009625 +0.009717 +0.009802 +0.009824 +0.009657 +0.009572 +0.009657 +0.009726 +0.009812 +0.009909 +0.00974 +0.009644 +0.009713 +0.009787 +0.009863 +0.009929 +0.009771 +0.009683 +0.009744 +0.009831 +0.009952 +0.010014 +0.009837 +0.009755 +0.009799 +0.009877 +0.009981 +0.010077 +0.009882 +0.009774 +0.009834 +0.009963 +0.010062 +0.010119 +0.009927 +0.009839 +0.009885 +0.009982 +0.010088 +0.010149 +0.009973 +0.009883 +0.009983 +0.010059 +0.010157 +0.010222 +0.010018 +0.009937 +0.010006 +0.010087 +0.0102 +0.010279 +0.010103 +0.010016 +0.010058 +0.010154 +0.010266 +0.010304 +0.01013 +0.010036 +0.010142 +0.010186 +0.010288 +0.010381 +0.0102 +0.010093 +0.010182 +0.010261 +0.010342 +0.010434 +0.010233 +0.010149 +0.010222 +0.010309 +0.010416 +0.010493 +0.010315 +0.010242 +0.010278 +0.010336 +0.010457 +0.010539 +0.010363 +0.010269 +0.010328 +0.010405 +0.01052 +0.010587 +0.010394 +0.010308 +0.010381 +0.010472 +0.010591 +0.010649 +0.010434 +0.010316 +0.010378 +0.010431 +0.010499 +0.010496 +0.010285 +0.01019 +0.010226 +0.010244 +0.010305 +0.010267 +0.01004 +0.009905 +0.009933 +0.009985 +0.010015 +0.010015 +0.009798 +0.009678 +0.009698 +0.009732 +0.009774 +0.009755 +0.009538 +0.009425 +0.00943 +0.009466 +0.009501 +0.009494 +0.009283 +0.009183 +0.0092 +0.009261 +0.009264 +0.009247 +0.009039 +0.008937 +0.008983 +0.00899 +0.00903 +0.009043 +0.008858 +0.008759 +0.00879 +0.008835 +0.008869 +0.008885 +0.008688 +0.008598 +0.008617 +0.008665 +0.008708 +0.008735 +0.008555 +0.008464 +0.008519 +0.008555 +0.008602 +0.008623 +0.008465 +0.008377 +0.008429 +0.008463 +0.008517 +0.008571 +0.008418 +0.008368 +0.008407 +0.008495 +0.008545 +0.008624 +0.008464 +0.008389 +0.008441 +0.008514 +0.008597 +0.008659 +0.008528 +0.008447 +0.008506 +0.008557 +0.008651 +0.008698 +0.008556 +0.008488 +0.008539 +0.008601 +0.008689 +0.008761 +0.008621 +0.008564 +0.008589 +0.008655 +0.008747 +0.008779 +0.008637 +0.008561 +0.008619 +0.008693 +0.0088 +0.008847 +0.008683 +0.008624 +0.008679 +0.008747 +0.008819 +0.008887 +0.008725 +0.008658 +0.008711 +0.008794 +0.008872 +0.00893 +0.008796 +0.008705 +0.008771 +0.008844 +0.008932 +0.008985 +0.008833 +0.008764 +0.008789 +0.00887 +0.008959 +0.009022 +0.008865 +0.008794 +0.008863 +0.008932 +0.009022 +0.009069 +0.008919 +0.008836 +0.008886 +0.008974 +0.009058 +0.009115 +0.008965 +0.008898 +0.008947 +0.009027 +0.009122 +0.009175 +0.009002 +0.008929 +0.008992 +0.009086 +0.009169 +0.009203 +0.009047 +0.008988 +0.009037 +0.00912 +0.009203 +0.009256 +0.009111 +0.009016 +0.009075 +0.009164 +0.009249 +0.009325 +0.00916 +0.009088 +0.009129 +0.009212 +0.009312 +0.009349 +0.009201 +0.009117 +0.009178 +0.009263 +0.009344 +0.009407 +0.009274 +0.009206 +0.009223 +0.009301 +0.009402 +0.009438 +0.009318 +0.009197 +0.009267 +0.009362 +0.009437 +0.0095 +0.009347 +0.009256 +0.009311 +0.009403 +0.009502 +0.009554 +0.009398 +0.009318 +0.009372 +0.009461 +0.009554 +0.009612 +0.00944 +0.009358 +0.009419 +0.009529 +0.009596 +0.009654 +0.009493 +0.009402 +0.009476 +0.00955 +0.009637 +0.009734 +0.009532 +0.00945 +0.009507 +0.009604 +0.009689 +0.009761 +0.009599 +0.009505 +0.009569 +0.009661 +0.009742 +0.00981 +0.009644 +0.009558 +0.009612 +0.009691 +0.009802 +0.009905 +0.009703 +0.009617 +0.009662 +0.009734 +0.009847 +0.009913 +0.009733 +0.009655 +0.009707 +0.009824 +0.009897 +0.009966 +0.009801 +0.009718 +0.009766 +0.009837 +0.009943 +0.010013 +0.009845 +0.009756 +0.009826 +0.009903 +0.010002 +0.010095 +0.009914 +0.009839 +0.009864 +0.009957 +0.010031 +0.01011 +0.009926 +0.009846 +0.009918 +0.010022 +0.010128 +0.010186 +0.010007 +0.009891 +0.009962 +0.010061 +0.010154 +0.010222 +0.010054 +0.009948 +0.010023 +0.010146 +0.010232 +0.010281 +0.010098 +0.01002 +0.010097 +0.010153 +0.01025 +0.010325 +0.010189 +0.010067 +0.010126 +0.01023 +0.010324 +0.010361 +0.0102 +0.010118 +0.010178 +0.010285 +0.010368 +0.010429 +0.010261 +0.01017 +0.010227 +0.010321 +0.010437 +0.010492 +0.010292 +0.010203 +0.010317 +0.010305 +0.010385 +0.010421 +0.010191 +0.010061 +0.010124 +0.010145 +0.010185 +0.0102 +0.009973 +0.009836 +0.009849 +0.009876 +0.009908 +0.009911 +0.009683 +0.009557 +0.009562 +0.009616 +0.00964 +0.009642 +0.009444 +0.009296 +0.009304 +0.009344 +0.009372 +0.009403 +0.009156 +0.009035 +0.009039 +0.009087 +0.009144 +0.009134 +0.008953 +0.008812 +0.008821 +0.008864 +0.008903 +0.008929 +0.008727 +0.008618 +0.008655 +0.008706 +0.008767 +0.008773 +0.008598 +0.008497 +0.008533 +0.008571 +0.008638 +0.00865 +0.008486 +0.008389 +0.008432 +0.008504 +0.008548 +0.008563 +0.00839 +0.008308 +0.008353 +0.008423 +0.00847 +0.008521 +0.008369 +0.0083 +0.00836 +0.008417 +0.008498 +0.008553 +0.008417 +0.008334 +0.008394 +0.008457 +0.008537 +0.008592 +0.008467 +0.008384 +0.008426 +0.008515 +0.008596 +0.00864 +0.008491 +0.008425 +0.008476 +0.008573 +0.008628 +0.008687 +0.008523 +0.008462 +0.008528 +0.008607 +0.008703 +0.008731 +0.008581 +0.0085 +0.008556 +0.00865 +0.00873 +0.008763 +0.008614 +0.008561 +0.008599 +0.00868 +0.008761 +0.008833 +0.008679 +0.008598 +0.00865 +0.008729 +0.008812 +0.008865 +0.00874 +0.008661 +0.008717 +0.008768 +0.008851 +0.008903 +0.008783 +0.008688 +0.008728 +0.008812 +0.008898 +0.008966 +0.008819 +0.008743 +0.008793 +0.008852 +0.008942 +0.009005 +0.008862 +0.008782 +0.008824 +0.008904 +0.008991 +0.009075 +0.008913 +0.008842 +0.008888 +0.008941 +0.009039 +0.009105 +0.008972 +0.008872 +0.008918 +0.008983 +0.009081 +0.009164 +0.009023 +0.008919 +0.008978 +0.009045 +0.009124 +0.009188 +0.009042 +0.008951 +0.009014 +0.00909 +0.009174 +0.009256 +0.0091 +0.009029 +0.009079 +0.009135 +0.009227 +0.009292 +0.009129 +0.009051 +0.009114 +0.009193 +0.009301 +0.009359 +0.009188 +0.009108 +0.009169 +0.009233 +0.009313 +0.009381 +0.009251 +0.009136 +0.009194 +0.009278 +0.009377 +0.009458 +0.009293 +0.009213 +0.009265 +0.009326 +0.009427 +0.009476 +0.009319 +0.009243 +0.009295 +0.009378 +0.009478 +0.009563 +0.009414 +0.009313 +0.009354 +0.009416 +0.009514 +0.009583 +0.009422 +0.009339 +0.009391 +0.0095 +0.009587 +0.009656 +0.009479 +0.009387 +0.009443 +0.009527 +0.009613 +0.009685 +0.009529 +0.009449 +0.009491 +0.009572 +0.009672 +0.009734 +0.009569 +0.00949 +0.009563 +0.009668 +0.00973 +0.009797 +0.009632 +0.009523 +0.009587 +0.009669 +0.009768 +0.009843 +0.009674 +0.009584 +0.009658 +0.009744 +0.009847 +0.009907 +0.009709 +0.009624 +0.009691 +0.009779 +0.009871 +0.009942 +0.009781 +0.009685 +0.009758 +0.009864 +0.009973 +0.009996 +0.009813 +0.009718 +0.009785 +0.009911 +0.009966 +0.010031 +0.009891 +0.009801 +0.009861 +0.009949 +0.010044 +0.010084 +0.009919 +0.009835 +0.009887 +0.009971 +0.010087 +0.010172 +0.00999 +0.009911 +0.009961 +0.010038 +0.010142 +0.010223 +0.010036 +0.009942 +0.009992 +0.010078 +0.010189 +0.010253 +0.010107 +0.009992 +0.010038 +0.010144 +0.010252 +0.010321 +0.010128 +0.010055 +0.010109 +0.010205 +0.010298 +0.010367 +0.010182 +0.010093 +0.010164 +0.010252 +0.010368 +0.010445 +0.010271 +0.010144 +0.010206 +0.010292 +0.010403 +0.010472 +0.010282 +0.010201 +0.010283 +0.010376 +0.010479 +0.010501 +0.010311 +0.01022 +0.010282 +0.010337 +0.010404 +0.010458 +0.010216 +0.01009 +0.010148 +0.010172 +0.010212 +0.010229 +0.010013 +0.009884 +0.009873 +0.009884 +0.009927 +0.009953 +0.009704 +0.009577 +0.009596 +0.009613 +0.00963 +0.009631 +0.009419 +0.009286 +0.0093 +0.009332 +0.009374 +0.009364 +0.009158 +0.00903 +0.009049 +0.0091 +0.009097 +0.0091 +0.008898 +0.008798 +0.008817 +0.008882 +0.008907 +0.008919 +0.008719 +0.008644 +0.008652 +0.00869 +0.008721 +0.008746 +0.008578 +0.008477 +0.008514 +0.008565 +0.008608 +0.008651 +0.008467 +0.00838 +0.008408 +0.008462 +0.008496 +0.008524 +0.008356 +0.008282 +0.008327 +0.008391 +0.008446 +0.00848 +0.008352 +0.008276 +0.008353 +0.008414 +0.008468 +0.008506 +0.008371 +0.008297 +0.008353 +0.008443 +0.008501 +0.00856 +0.00842 +0.008356 +0.008414 +0.00849 +0.008561 +0.008616 +0.008454 +0.008394 +0.00844 +0.008511 +0.008596 +0.008659 +0.008505 +0.008435 +0.008508 +0.008579 +0.008666 +0.008702 +0.008563 +0.008484 +0.008545 +0.008601 +0.008683 +0.008738 +0.008592 +0.00853 +0.008569 +0.008649 +0.008738 +0.008815 +0.008634 +0.008564 +0.008619 +0.008699 +0.008775 +0.008842 +0.008709 +0.00862 +0.008658 +0.008743 +0.008815 +0.008875 +0.008731 +0.008661 +0.008713 +0.008794 +0.008872 +0.008942 +0.008817 +0.008729 +0.008767 +0.008815 +0.00891 +0.00897 +0.008826 +0.008753 +0.008799 +0.00888 +0.008964 +0.009049 +0.008873 +0.008812 +0.00885 +0.008915 +0.00901 +0.009062 +0.008915 +0.008844 +0.008902 +0.00896 +0.009061 +0.009129 +0.008968 +0.008907 +0.008953 +0.009016 +0.009124 +0.009177 +0.009007 +0.00894 +0.008982 +0.009048 +0.009151 +0.009208 +0.009057 +0.009001 +0.009058 +0.009097 +0.009197 +0.00927 +0.009101 +0.009022 +0.009083 +0.009143 +0.009249 +0.009318 +0.009153 +0.009089 +0.009146 +0.00921 +0.00929 +0.009355 +0.009205 +0.009129 +0.009196 +0.009248 +0.009344 +0.009403 +0.009244 +0.009209 +0.009229 +0.009291 +0.009395 +0.009456 +0.009288 +0.009215 +0.009274 +0.009353 +0.009446 +0.00952 +0.00935 +0.009279 +0.009329 +0.009394 +0.009494 +0.009554 +0.009395 +0.009309 +0.009364 +0.009455 +0.009569 +0.009628 +0.009461 +0.009361 +0.009405 +0.0095 +0.009593 +0.009666 +0.009493 +0.00941 +0.009451 +0.009547 +0.009653 +0.009714 +0.009554 +0.009469 +0.009516 +0.009607 +0.009691 +0.009758 +0.009574 +0.009494 +0.009568 +0.009666 +0.009766 +0.009832 +0.00967 +0.009587 +0.009607 +0.009689 +0.009787 +0.009854 +0.00969 +0.009602 +0.00966 +0.009774 +0.009857 +0.009902 +0.009747 +0.009652 +0.009717 +0.009814 +0.009895 +0.009968 +0.009807 +0.009711 +0.009761 +0.009855 +0.009953 +0.010016 +0.009841 +0.00977 +0.009856 +0.009915 +0.010027 +0.01006 +0.00988 +0.009805 +0.009856 +0.009943 +0.010078 +0.010114 +0.009946 +0.009893 +0.009915 +0.010027 +0.010117 +0.010163 +0.009993 +0.009909 +0.009967 +0.010049 +0.010167 +0.010241 +0.010053 +0.009973 +0.010043 +0.010149 +0.010216 +0.010259 +0.010093 +0.010034 +0.010074 +0.010151 +0.01027 +0.010339 +0.010169 +0.010076 +0.010128 +0.010213 +0.010319 +0.010393 +0.010199 +0.010111 +0.01019 +0.010284 +0.010392 +0.010463 +0.010257 +0.010155 +0.010237 +0.010345 +0.010468 +0.01047 +0.010264 +0.010188 +0.010264 +0.010355 +0.010383 +0.010418 +0.010193 +0.010081 +0.010122 +0.010188 +0.010248 +0.010229 +0.010017 +0.009867 +0.009906 +0.009938 +0.009966 +0.009988 +0.009741 +0.009624 +0.00967 +0.009699 +0.009714 +0.009731 +0.009521 +0.009415 +0.009402 +0.009422 +0.009459 +0.009467 +0.009273 +0.009155 +0.009145 +0.009181 +0.009187 +0.0092 +0.009002 +0.008897 +0.008915 +0.00895 +0.009005 +0.009016 +0.008823 +0.008718 +0.00875 +0.008782 +0.008813 +0.008844 +0.008655 +0.008565 +0.008598 +0.008663 +0.008713 +0.00874 +0.008537 +0.008453 +0.008492 +0.008553 +0.0086 +0.008634 +0.008469 +0.008406 +0.008439 +0.008489 +0.008567 +0.0086 +0.008456 +0.008384 +0.008445 +0.008523 +0.008587 +0.008653 +0.00851 +0.008439 +0.008467 +0.008561 +0.008652 +0.008705 +0.008539 +0.008473 +0.008536 +0.008614 +0.008724 +0.008731 +0.008577 +0.008511 +0.008569 +0.008646 +0.008744 +0.008797 +0.00863 +0.008564 +0.008616 +0.008706 +0.008765 +0.00883 +0.008673 +0.008604 +0.008665 +0.008743 +0.008826 +0.008881 +0.00874 +0.008648 +0.0087 +0.008779 +0.00886 +0.008922 +0.008772 +0.008701 +0.008771 +0.008856 +0.008911 +0.008992 +0.008812 +0.008728 +0.008797 +0.008863 +0.008952 +0.009017 +0.008868 +0.008788 +0.008851 +0.008931 +0.009005 +0.009067 +0.008916 +0.008836 +0.008876 +0.008958 +0.009054 +0.009107 +0.008965 +0.008888 +0.008935 +0.009007 +0.009088 +0.009168 +0.009023 +0.008943 +0.008971 +0.009052 +0.009138 +0.009237 +0.009058 +0.008973 +0.009029 +0.009113 +0.009187 +0.00924 +0.009091 +0.009021 +0.009072 +0.009162 +0.00924 +0.009292 +0.009138 +0.00906 +0.009117 +0.009198 +0.009286 +0.009365 +0.009192 +0.009119 +0.009172 +0.009273 +0.009364 +0.009385 +0.009232 +0.009143 +0.009208 +0.009306 +0.009389 +0.00946 +0.009288 +0.009202 +0.009263 +0.009356 +0.00943 +0.00949 +0.009331 +0.009256 +0.009327 +0.00939 +0.009487 +0.009551 +0.009383 +0.009296 +0.009376 +0.009437 +0.009529 +0.009609 +0.009455 +0.009374 +0.009399 +0.009483 +0.009579 +0.009645 +0.009488 +0.009405 +0.009472 +0.009565 +0.009633 +0.009685 +0.009533 +0.009443 +0.009497 +0.009585 +0.009688 +0.009749 +0.009586 +0.009524 +0.009565 +0.009637 +0.00974 +0.009793 +0.00963 +0.009554 +0.009617 +0.009719 +0.00981 +0.009849 +0.009681 +0.009605 +0.009645 +0.009731 +0.009831 +0.009905 +0.009721 +0.009644 +0.009717 +0.009788 +0.0099 +0.009984 +0.009788 +0.009688 +0.009759 +0.009836 +0.009942 +0.010008 +0.009835 +0.009741 +0.009807 +0.009905 +0.010031 +0.010068 +0.009876 +0.009796 +0.009867 +0.009946 +0.010035 +0.010121 +0.009955 +0.009838 +0.009902 +0.009998 +0.010089 +0.010164 +0.009994 +0.009898 +0.009964 +0.010053 +0.010172 +0.010232 +0.010027 +0.00995 +0.010005 +0.010094 +0.010223 +0.0103 +0.010108 +0.010007 +0.010072 +0.010162 +0.010289 +0.010303 +0.010123 +0.010055 +0.010109 +0.010203 +0.010313 +0.010374 +0.010211 +0.010137 +0.010173 +0.010261 +0.010355 +0.010424 +0.010245 +0.010172 +0.010216 +0.010306 +0.010432 +0.010518 +0.010332 +0.010203 +0.010274 +0.010357 +0.010476 +0.010534 +0.010369 +0.010297 +0.010315 +0.010415 +0.010535 +0.010577 +0.010412 +0.010327 +0.010372 +0.010504 +0.01058 +0.010602 +0.010384 +0.010263 +0.010279 +0.010334 +0.010407 +0.010449 +0.01022 +0.01009 +0.010134 +0.01014 +0.01017 +0.010155 +0.00993 +0.009808 +0.009812 +0.00989 +0.009912 +0.00989 +0.009679 +0.009557 +0.009555 +0.009596 +0.009647 +0.009658 +0.009452 +0.009315 +0.009329 +0.009373 +0.009409 +0.009425 +0.009208 +0.009096 +0.009103 +0.009147 +0.009231 +0.009212 +0.009015 +0.008902 +0.008933 +0.009 +0.009048 +0.009074 +0.008887 +0.008769 +0.008809 +0.00884 +0.008906 +0.008929 +0.008758 +0.008648 +0.008687 +0.008739 +0.008801 +0.008841 +0.008662 +0.008549 +0.008584 +0.00865 +0.008704 +0.008758 +0.008598 +0.008511 +0.008569 +0.008633 +0.00871 +0.008773 +0.008618 +0.008547 +0.008586 +0.008651 +0.008732 +0.008797 +0.008656 +0.008586 +0.008625 +0.008734 +0.008793 +0.008851 +0.008708 +0.008636 +0.008677 +0.008743 +0.008837 +0.008889 +0.008742 +0.008671 +0.008732 +0.008796 +0.008881 +0.008948 +0.008799 +0.008744 +0.00879 +0.008831 +0.008905 +0.008998 +0.008865 +0.008764 +0.008818 +0.008885 +0.008971 +0.009027 +0.008878 +0.008808 +0.008862 +0.008933 +0.009019 +0.009103 +0.008932 +0.008861 +0.008918 +0.008988 +0.009063 +0.009121 +0.008979 +0.0089 +0.008949 +0.009044 +0.009127 +0.009198 +0.009015 +0.00893 +0.008987 +0.009072 +0.009164 +0.009233 +0.009078 +0.008987 +0.009046 +0.009131 +0.009212 +0.009278 +0.00911 +0.009037 +0.009094 +0.009183 +0.009254 +0.009323 +0.009167 +0.009089 +0.009151 +0.009237 +0.009314 +0.009366 +0.009191 +0.009142 +0.009223 +0.009277 +0.009341 +0.009412 +0.009245 +0.009178 +0.009228 +0.009311 +0.009405 +0.009495 +0.009298 +0.009227 +0.009293 +0.009363 +0.009453 +0.009528 +0.009349 +0.00927 +0.00933 +0.009417 +0.009513 +0.009566 +0.009421 +0.00932 +0.009385 +0.009477 +0.009574 +0.009643 +0.009465 +0.009348 +0.009417 +0.009505 +0.009611 +0.009653 +0.009501 +0.009427 +0.009474 +0.009577 +0.009663 +0.009702 +0.009543 +0.009465 +0.009538 +0.00961 +0.009702 +0.009781 +0.009607 +0.00953 +0.009596 +0.009677 +0.009746 +0.009805 +0.009641 +0.009597 +0.009628 +0.009706 +0.009819 +0.009859 +0.009715 +0.009615 +0.009675 +0.009758 +0.009843 +0.009912 +0.009752 +0.009668 +0.009721 +0.009811 +0.009912 +0.009992 +0.009813 +0.00973 +0.009772 +0.009859 +0.009965 +0.010023 +0.009843 +0.009768 +0.009835 +0.009943 +0.010002 +0.010066 +0.009899 +0.009825 +0.009889 +0.009956 +0.010064 +0.010131 +0.009966 +0.009861 +0.009927 +0.010018 +0.010122 +0.01019 +0.010003 +0.009918 +0.009989 +0.010082 +0.010191 +0.010249 +0.010052 +0.009969 +0.010026 +0.010128 +0.010249 +0.010276 +0.010108 +0.010021 +0.010099 +0.010184 +0.01031 +0.010335 +0.010143 +0.010062 +0.010138 +0.010223 +0.010323 +0.010401 +0.010211 +0.010144 +0.010212 +0.010284 +0.010385 +0.010445 +0.010267 +0.010184 +0.010235 +0.010334 +0.01049 +0.010504 +0.010321 +0.010237 +0.010278 +0.010388 +0.010485 +0.010551 +0.010379 +0.010277 +0.010362 +0.010462 +0.010559 +0.010622 +0.010425 +0.010321 +0.010397 +0.010494 +0.010607 +0.010663 +0.010484 +0.010419 +0.010472 +0.010564 +0.010696 +0.010694 +0.010537 +0.010429 +0.010505 +0.010601 +0.010688 +0.010763 +0.01057 +0.010457 +0.010516 +0.010557 +0.01064 +0.010682 +0.010441 +0.010312 +0.010357 +0.010397 +0.010443 +0.010476 +0.010234 +0.010089 +0.010099 +0.010136 +0.010183 +0.010202 +0.010017 +0.009842 +0.009872 +0.009874 +0.009919 +0.009945 +0.009718 +0.009594 +0.009621 +0.009646 +0.009673 +0.009702 +0.009483 +0.00935 +0.009365 +0.009401 +0.009434 +0.00945 +0.009255 +0.009139 +0.00915 +0.009191 +0.009222 +0.009254 +0.009062 +0.008952 +0.008987 +0.009023 +0.009044 +0.009066 +0.008906 +0.008798 +0.008813 +0.008857 +0.008907 +0.008949 +0.008779 +0.008683 +0.00869 +0.008754 +0.008807 +0.008838 +0.008683 +0.008595 +0.008627 +0.008691 +0.008771 +0.008832 +0.008673 +0.008611 +0.00866 +0.008706 +0.008794 +0.008864 +0.00871 +0.008661 +0.008684 +0.008759 +0.008841 +0.008903 +0.008756 +0.008699 +0.008732 +0.008804 +0.008893 +0.008948 +0.008803 +0.008731 +0.008792 +0.008863 +0.008932 +0.009006 +0.008852 +0.008773 +0.008827 +0.008901 +0.009001 +0.009048 +0.008899 +0.008823 +0.008876 +0.008947 +0.009041 +0.009115 +0.008929 +0.008857 +0.008905 +0.008985 +0.009083 +0.009136 +0.008987 +0.008929 +0.008991 +0.009039 +0.009132 +0.009192 +0.009021 +0.008949 +0.009006 +0.009097 +0.009172 +0.009232 +0.009089 +0.009023 +0.009062 +0.009146 +0.009228 +0.009276 +0.009116 +0.009051 +0.009115 +0.009225 +0.009267 +0.00933 +0.009159 +0.009088 +0.009152 +0.009224 +0.009319 +0.009383 +0.009219 +0.009147 +0.009194 +0.009288 +0.009369 +0.009437 +0.009287 +0.009189 +0.009245 +0.009335 +0.009413 +0.00948 +0.009318 +0.009246 +0.009301 +0.009393 +0.009495 +0.009549 +0.009384 +0.009273 +0.009348 +0.009419 +0.009507 +0.009574 +0.009405 +0.009334 +0.009408 +0.00949 +0.009578 +0.009652 +0.009456 +0.009378 +0.009441 +0.009526 +0.009612 +0.009677 +0.009518 +0.009433 +0.009519 +0.009604 +0.009675 +0.009729 +0.009556 +0.009483 +0.009569 +0.009621 +0.009703 +0.00977 +0.009627 +0.00957 +0.009597 +0.00968 +0.009784 +0.009811 +0.009653 +0.009584 +0.009632 +0.009734 +0.009841 +0.009881 +0.009713 +0.009629 +0.009696 +0.009772 +0.009878 +0.009945 +0.009763 +0.009687 +0.009746 +0.009861 +0.009944 +0.009976 +0.009814 +0.009727 +0.009794 +0.009873 +0.01 +0.010043 +0.009866 +0.00978 +0.009859 +0.009926 +0.010028 +0.010094 +0.009925 +0.009847 +0.00988 +0.009993 +0.010071 +0.010159 +0.009985 +0.009898 +0.009935 +0.010041 +0.010153 +0.010229 +0.010012 +0.009922 +0.009992 +0.010093 +0.010213 +0.010267 +0.01008 +0.01 +0.010036 +0.010131 +0.010241 +0.010302 +0.010119 +0.010051 +0.010103 +0.010215 +0.01033 +0.010351 +0.010168 +0.01009 +0.010148 +0.010246 +0.010356 +0.010441 +0.010252 +0.010171 +0.010205 +0.010309 +0.010401 +0.01045 +0.010272 +0.010204 +0.010266 +0.010346 +0.010475 +0.010547 +0.010349 +0.010271 +0.010319 +0.01039 +0.010511 +0.010567 +0.010401 +0.010319 +0.010358 +0.010457 +0.010577 +0.010659 +0.010462 +0.010341 +0.010406 +0.010523 +0.010632 +0.010683 +0.010504 +0.010418 +0.010471 +0.010571 +0.010697 +0.010759 +0.010532 +0.010446 +0.010506 +0.010599 +0.010675 +0.010654 +0.010436 +0.010291 +0.010358 +0.010374 +0.010423 +0.010441 +0.010224 +0.010073 +0.010076 +0.01011 +0.010166 +0.010184 +0.009922 +0.009805 +0.009816 +0.009865 +0.009923 +0.009917 +0.009701 +0.009578 +0.009597 +0.009614 +0.00965 +0.009664 +0.009443 +0.009326 +0.009339 +0.009382 +0.009426 +0.009446 +0.009239 +0.009115 +0.009123 +0.009182 +0.009253 +0.009246 +0.009037 +0.008923 +0.008953 +0.009038 +0.009064 +0.009078 +0.008906 +0.008802 +0.008812 +0.00887 +0.008926 +0.008957 +0.008769 +0.00867 +0.008702 +0.008764 +0.008814 +0.008849 +0.008682 +0.008579 +0.00862 +0.008678 +0.008742 +0.008783 +0.008623 +0.008543 +0.008604 +0.008684 +0.008738 +0.00882 +0.008667 +0.008592 +0.008645 +0.008708 +0.008777 +0.008857 +0.008704 +0.00863 +0.008677 +0.008756 +0.008841 +0.008894 +0.008749 +0.00868 +0.008737 +0.0088 +0.008883 +0.008947 +0.008795 +0.008716 +0.008776 +0.00886 +0.008935 +0.008988 +0.008845 +0.008791 +0.008818 +0.008887 +0.008962 +0.009029 +0.008885 +0.008805 +0.008861 +0.008958 +0.009045 +0.009099 +0.008919 +0.00885 +0.008901 +0.008978 +0.009067 +0.009134 +0.008973 +0.008901 +0.008963 +0.009048 +0.009132 +0.009173 +0.009029 +0.008948 +0.008995 +0.00908 +0.009166 +0.00925 +0.009069 +0.009011 +0.009049 +0.00913 +0.00923 +0.009273 +0.009106 +0.009037 +0.009091 +0.00917 +0.009263 +0.009326 +0.009159 +0.009087 +0.009148 +0.009219 +0.00931 +0.009383 +0.009208 +0.00913 +0.009188 +0.009278 +0.009376 +0.009434 +0.009263 +0.009184 +0.009263 +0.009322 +0.009395 +0.009458 +0.009304 +0.009231 +0.009286 +0.009383 +0.009476 +0.009536 +0.00935 +0.009272 +0.00933 +0.009422 +0.009511 +0.00957 +0.009414 +0.009331 +0.009399 +0.009469 +0.009565 +0.009605 +0.009455 +0.009375 +0.009424 +0.009521 +0.009639 +0.009674 +0.009489 +0.009414 +0.009461 +0.009562 +0.009662 +0.009721 +0.009556 +0.009482 +0.009534 +0.009625 +0.009716 +0.009761 +0.009599 +0.009524 +0.009594 +0.009659 +0.009754 +0.009828 +0.009656 +0.009565 +0.009647 +0.009719 +0.009801 +0.009885 +0.009718 +0.00964 +0.009668 +0.00975 +0.009856 +0.00993 +0.009782 +0.009681 +0.009762 +0.0098 +0.009902 +0.009962 +0.0098 +0.009714 +0.009765 +0.009867 +0.009966 +0.010052 +0.009883 +0.009775 +0.009815 +0.009919 +0.010009 +0.010077 +0.009907 +0.009826 +0.009933 +0.009988 +0.01007 +0.010115 +0.009963 +0.009868 +0.009923 +0.010017 +0.010122 +0.010193 +0.009994 +0.009933 +0.009995 +0.010083 +0.0102 +0.010236 +0.010051 +0.00998 +0.010033 +0.010122 +0.010231 +0.010286 +0.010109 +0.01003 +0.0101 +0.010216 +0.010273 +0.010327 +0.010157 +0.010087 +0.010145 +0.010241 +0.010333 +0.010409 +0.010219 +0.010131 +0.010231 +0.010269 +0.010386 +0.010452 +0.010277 +0.01021 +0.010262 +0.010326 +0.010441 +0.010514 +0.01032 +0.010229 +0.010301 +0.010444 +0.010522 +0.010565 +0.010365 +0.010279 +0.010358 +0.010445 +0.010546 +0.010621 +0.010425 +0.010367 +0.010427 +0.010516 +0.010652 +0.010669 +0.010463 +0.010393 +0.01045 +0.01056 +0.010684 +0.010718 +0.010543 +0.010455 +0.010524 +0.010657 +0.010685 +0.010752 +0.010562 +0.010477 +0.010528 +0.010583 +0.010599 +0.010619 +0.010414 +0.01028 +0.010287 +0.010343 +0.010391 +0.010401 +0.010176 +0.010034 +0.010017 +0.010065 +0.01009 +0.010107 +0.009898 +0.009745 +0.009783 +0.009822 +0.009842 +0.009874 +0.009614 +0.009484 +0.009478 +0.009516 +0.009551 +0.009568 +0.009398 +0.009251 +0.009237 +0.009277 +0.009319 +0.00933 +0.009141 +0.009029 +0.009051 +0.009093 +0.009133 +0.009165 +0.008992 +0.008883 +0.008886 +0.008942 +0.008979 +0.009014 +0.008847 +0.008743 +0.00879 +0.008817 +0.008879 +0.008899 +0.00873 +0.008645 +0.008664 +0.008704 +0.008764 +0.008814 +0.008667 +0.008559 +0.008606 +0.008663 +0.008735 +0.008804 +0.008663 +0.008587 +0.008636 +0.008687 +0.008786 +0.008831 +0.008685 +0.008619 +0.008669 +0.008743 +0.008842 +0.008903 +0.008753 +0.008687 +0.00872 +0.008786 +0.008869 +0.008912 +0.008779 +0.008698 +0.008762 +0.008844 +0.00893 +0.00897 +0.008821 +0.008777 +0.008805 +0.008883 +0.008955 +0.009024 +0.008868 +0.008807 +0.008865 +0.008928 +0.009014 +0.009089 +0.008902 +0.008836 +0.008891 +0.008975 +0.009068 +0.009148 +0.008961 +0.00889 +0.008943 +0.009049 +0.009113 +0.009156 +0.008995 +0.008927 +0.008981 +0.009062 +0.009148 +0.009231 +0.009048 +0.008978 +0.009036 +0.009117 +0.009197 +0.009266 +0.009108 +0.009027 +0.009083 +0.009172 +0.009265 +0.009327 +0.009146 +0.009073 +0.009155 +0.009221 +0.009288 +0.009349 +0.009183 +0.009128 +0.009192 +0.009284 +0.009355 +0.009418 +0.009242 +0.009156 +0.009222 +0.009295 +0.009391 +0.009456 +0.009317 +0.009215 +0.009265 +0.009362 +0.009438 +0.009508 +0.009349 +0.00926 +0.009315 +0.009403 +0.009502 +0.009595 +0.009394 +0.009307 +0.009364 +0.009447 +0.009551 +0.009612 +0.009432 +0.009375 +0.009421 +0.009497 +0.009606 +0.009667 +0.009476 +0.009401 +0.009475 +0.009555 +0.009638 +0.00971 +0.009538 +0.009453 +0.009513 +0.009617 +0.00971 +0.009751 +0.00959 +0.009539 +0.009598 +0.00964 +0.009727 +0.009792 +0.009636 +0.009555 +0.009626 +0.009715 +0.009811 +0.009848 +0.009683 +0.009601 +0.009661 +0.009749 +0.009848 +0.009918 +0.009755 +0.009677 +0.009719 +0.009807 +0.009889 +0.009953 +0.009783 +0.009706 +0.009771 +0.009892 +0.00997 +0.010017 +0.009868 +0.00975 +0.009818 +0.009876 +0.009989 +0.010061 +0.009881 +0.009817 +0.009887 +0.009955 +0.010043 +0.010117 +0.009943 +0.009849 +0.009914 +0.010004 +0.010106 +0.010178 +0.010016 +0.00992 +0.009958 +0.010066 +0.010191 +0.010218 +0.010036 +0.009947 +0.010016 +0.010143 +0.010217 +0.010283 +0.010111 +0.009987 +0.010057 +0.010173 +0.010264 +0.01033 +0.010155 +0.010072 +0.010137 +0.010237 +0.010325 +0.010377 +0.010191 +0.010105 +0.010179 +0.010282 +0.010391 +0.01047 +0.010259 +0.010163 +0.010234 +0.010336 +0.010413 +0.010491 +0.010305 +0.010208 +0.010288 +0.010383 +0.010467 +0.01054 +0.01036 +0.010283 +0.010355 +0.010428 +0.010543 +0.010596 +0.01042 +0.01034 +0.010381 +0.010496 +0.010608 +0.01069 +0.010455 +0.010368 +0.010432 +0.010536 +0.010651 +0.010725 +0.010547 +0.010441 +0.010487 +0.010596 +0.010675 +0.010739 +0.010555 +0.010455 +0.010511 +0.010585 +0.010635 +0.010641 +0.010409 +0.010287 +0.010329 +0.010375 +0.010405 +0.010422 +0.010252 +0.010089 +0.010062 +0.010103 +0.010122 +0.010145 +0.009921 +0.009795 +0.009818 +0.009854 +0.009889 +0.009908 +0.009675 +0.009559 +0.009573 +0.009575 +0.009606 +0.009624 +0.009417 +0.009299 +0.009318 +0.009336 +0.00936 +0.009385 +0.009201 +0.009087 +0.009126 +0.009129 +0.009175 +0.009188 +0.009009 +0.008907 +0.008938 +0.008962 +0.009012 +0.009033 +0.008858 +0.008762 +0.008778 +0.008817 +0.008873 +0.008916 +0.008739 +0.008644 +0.008672 +0.00871 +0.008757 +0.008797 +0.008647 +0.008555 +0.008591 +0.00865 +0.008715 +0.008769 +0.008624 +0.008572 +0.008625 +0.008712 +0.008745 +0.00883 +0.008648 +0.008578 +0.008639 +0.008714 +0.00879 +0.008863 +0.008727 +0.008638 +0.008696 +0.008782 +0.008852 +0.008889 +0.008748 +0.008683 +0.00873 +0.008808 +0.008891 +0.008955 +0.008818 +0.008738 +0.008799 +0.008874 +0.008948 +0.008978 +0.008838 +0.008786 +0.008833 +0.008884 +0.008981 +0.009033 +0.008923 +0.008814 +0.00886 +0.00894 +0.009036 +0.009083 +0.008941 +0.008867 +0.008925 +0.008989 +0.009084 +0.00915 +0.008982 +0.008909 +0.008964 +0.009047 +0.009127 +0.009182 +0.009044 +0.00896 +0.009008 +0.009093 +0.009197 +0.009262 +0.009076 +0.008994 +0.009044 +0.009128 +0.009228 +0.009287 +0.009142 +0.009042 +0.009104 +0.009189 +0.009281 +0.009344 +0.009164 +0.00909 +0.009149 +0.009232 +0.009317 +0.009375 +0.009227 +0.00915 +0.009209 +0.009296 +0.009377 +0.009421 +0.009269 +0.009196 +0.009273 +0.009331 +0.009405 +0.009461 +0.009315 +0.009255 +0.009301 +0.009382 +0.009478 +0.009522 +0.009366 +0.009283 +0.009357 +0.009411 +0.00951 +0.009598 +0.009425 +0.009341 +0.009418 +0.009486 +0.009555 +0.009615 +0.009466 +0.009375 +0.009435 +0.009545 +0.009626 +0.0097 +0.009518 +0.009415 +0.009478 +0.00957 +0.009665 +0.009721 +0.009569 +0.00949 +0.009544 +0.009624 +0.009724 +0.009783 +0.009606 +0.009528 +0.009589 +0.009668 +0.009782 +0.009844 +0.009684 +0.009591 +0.009649 +0.009706 +0.009809 +0.009887 +0.009727 +0.009649 +0.00968 +0.009765 +0.009883 +0.009934 +0.009777 +0.009685 +0.009725 +0.009824 +0.009914 +0.009985 +0.009826 +0.009728 +0.009789 +0.009907 +0.009995 +0.010049 +0.009874 +0.009775 +0.009826 +0.009921 +0.010022 +0.010086 +0.009916 +0.009834 +0.009946 +0.009991 +0.010083 +0.010141 +0.009951 +0.009908 +0.009929 +0.010023 +0.010135 +0.010194 +0.010011 +0.009948 +0.009987 +0.010076 +0.010203 +0.010232 +0.010078 +0.010001 +0.010057 +0.010139 +0.010256 +0.010297 +0.010122 +0.010046 +0.010111 +0.010233 +0.010276 +0.010346 +0.010163 +0.010111 +0.01017 +0.010239 +0.010369 +0.0104 +0.010217 +0.010149 +0.010212 +0.01029 +0.010404 +0.010471 +0.010309 +0.01021 +0.010248 +0.010349 +0.010455 +0.010533 +0.01034 +0.010241 +0.010319 +0.010475 +0.010524 +0.01057 +0.01037 +0.010288 +0.010366 +0.010456 +0.010567 +0.010632 +0.010444 +0.01037 +0.01045 +0.010529 +0.01063 +0.010675 +0.010492 +0.010407 +0.010492 +0.010562 +0.010682 +0.010758 +0.010565 +0.010473 +0.010545 +0.010663 +0.010705 +0.010791 +0.010547 +0.010493 +0.010544 +0.010599 +0.010667 +0.01069 +0.010483 +0.010376 +0.010386 +0.010423 +0.010465 +0.010496 +0.010276 +0.010146 +0.010147 +0.010166 +0.010217 +0.010215 +0.009999 +0.009875 +0.009883 +0.009939 +0.009981 +0.009999 +0.009775 +0.009643 +0.009612 +0.009649 +0.009698 +0.009694 +0.009504 +0.009393 +0.009407 +0.009415 +0.009452 +0.009474 +0.009271 +0.009157 +0.009179 +0.00921 +0.009255 +0.009274 +0.009101 +0.00899 +0.009002 +0.009045 +0.009079 +0.009106 +0.008932 +0.008829 +0.008879 +0.008907 +0.008951 +0.008981 +0.008823 +0.00871 +0.008739 +0.008772 +0.00883 +0.008873 +0.008705 +0.008619 +0.00866 +0.00872 +0.008785 +0.008844 +0.008697 +0.008616 +0.008674 +0.00872 +0.008815 +0.008871 +0.008725 +0.008653 +0.008695 +0.008774 +0.008874 +0.008939 +0.008789 +0.008721 +0.008745 +0.008824 +0.008892 +0.008956 +0.008817 +0.008741 +0.008791 +0.008877 +0.008951 +0.00901 +0.008859 +0.008797 +0.008843 +0.008922 +0.008993 +0.009093 +0.008903 +0.008823 +0.008886 +0.008965 +0.009031 +0.009106 +0.008953 +0.008875 +0.00893 +0.00902 +0.009103 +0.009182 +0.008993 +0.008928 +0.008967 +0.009049 +0.009148 +0.009195 +0.009046 +0.00897 +0.009034 +0.009104 +0.009187 +0.009271 +0.009091 +0.009007 +0.00907 +0.009144 +0.009236 +0.009329 +0.009134 +0.009058 +0.009112 +0.009203 +0.009281 +0.009353 +0.009187 +0.009111 +0.009196 +0.009267 +0.009324 +0.009379 +0.009228 +0.00916 +0.009206 +0.009295 +0.009395 +0.009459 +0.009273 +0.009201 +0.009264 +0.009342 +0.009429 +0.009497 +0.009328 +0.009249 +0.009306 +0.009405 +0.009499 +0.009533 +0.009385 +0.009294 +0.009352 +0.009449 +0.009543 +0.00962 +0.009423 +0.009354 +0.009418 +0.00949 +0.009591 +0.009623 +0.00947 +0.0094 +0.009463 +0.009533 +0.009632 +0.009699 +0.009529 +0.009457 +0.009513 +0.009601 +0.009673 +0.009743 +0.009569 +0.009493 +0.009561 +0.009632 +0.009734 +0.00981 +0.009643 +0.009586 +0.009605 +0.009691 +0.009762 +0.009833 +0.009697 +0.00958 +0.009656 +0.00974 +0.009831 +0.009892 +0.009726 +0.009645 +0.009699 +0.009791 +0.009886 +0.009949 +0.009778 +0.009705 +0.009757 +0.009835 +0.00994 +0.009996 +0.00983 +0.009753 +0.009819 +0.009917 +0.009986 +0.010058 +0.009885 +0.009794 +0.009837 +0.009942 +0.01004 +0.010114 +0.009933 +0.009841 +0.009918 +0.010009 +0.010104 +0.010171 +0.010011 +0.009879 +0.009952 +0.010037 +0.010139 +0.010222 +0.010046 +0.009932 +0.010014 +0.010118 +0.010224 +0.010252 +0.010068 +0.009998 +0.010067 +0.010167 +0.01026 +0.010325 +0.010139 +0.010044 +0.01011 +0.010212 +0.010305 +0.010374 +0.010192 +0.010111 +0.010187 +0.010303 +0.010348 +0.010415 +0.010238 +0.010149 +0.010214 +0.010319 +0.010462 +0.010499 +0.010313 +0.010208 +0.010267 +0.010354 +0.010462 +0.010529 +0.010361 +0.010261 +0.010323 +0.01044 +0.01054 +0.010602 +0.010415 +0.010305 +0.01037 +0.010475 +0.010575 +0.010652 +0.010468 +0.010362 +0.010434 +0.01054 +0.010684 +0.010693 +0.010501 +0.010436 +0.010494 +0.010579 +0.010692 +0.010753 +0.010581 +0.010472 +0.010547 +0.010648 +0.010745 +0.010806 +0.010595 +0.010522 +0.010604 +0.010643 +0.010717 +0.010754 +0.010515 +0.010387 +0.010422 +0.010488 +0.010536 +0.010548 +0.010361 +0.01018 +0.010182 +0.010197 +0.01025 +0.010275 +0.01005 +0.009905 +0.009942 +0.009985 +0.010027 +0.010047 +0.009845 +0.00966 +0.009697 +0.009726 +0.009766 +0.009783 +0.009551 +0.009428 +0.009463 +0.009502 +0.009548 +0.00955 +0.009343 +0.009231 +0.009249 +0.009274 +0.009321 +0.009334 +0.009143 +0.009038 +0.009092 +0.009127 +0.009176 +0.00919 +0.008987 +0.008883 +0.008912 +0.008967 +0.009013 +0.009068 +0.008846 +0.008754 +0.008815 +0.008859 +0.008912 +0.008938 +0.008772 +0.008656 +0.008713 +0.008789 +0.008844 +0.008915 +0.008731 +0.008646 +0.008715 +0.008808 +0.008875 +0.008947 +0.008795 +0.008705 +0.008754 +0.008826 +0.008913 +0.008972 +0.008825 +0.008738 +0.0088 +0.0089 +0.008974 +0.009035 +0.008871 +0.008804 +0.008834 +0.008921 +0.009017 +0.009064 +0.008918 +0.008841 +0.008897 +0.009015 +0.009102 +0.009114 +0.008953 +0.008884 +0.00893 +0.009011 +0.009105 +0.009155 +0.009007 +0.008944 +0.008994 +0.009056 +0.009148 +0.009209 +0.009056 +0.008988 +0.009022 +0.00911 +0.009205 +0.009268 +0.009106 +0.009034 +0.009082 +0.009156 +0.009252 +0.009318 +0.009162 +0.009101 +0.009112 +0.0092 +0.009286 +0.009361 +0.00922 +0.009123 +0.009176 +0.009246 +0.009344 +0.009404 +0.009248 +0.009198 +0.009213 +0.009294 +0.009397 +0.009455 +0.009306 +0.009229 +0.009276 +0.009342 +0.009437 +0.009512 +0.009338 +0.009262 +0.009321 +0.009418 +0.009518 +0.009557 +0.009392 +0.009312 +0.009383 +0.009442 +0.009532 +0.009594 +0.009441 +0.009354 +0.009415 +0.009523 +0.009604 +0.009663 +0.009498 +0.009415 +0.009451 +0.009535 +0.009643 +0.009697 +0.009538 +0.009461 +0.009523 +0.009615 +0.009709 +0.009772 +0.009624 +0.009482 +0.009545 +0.009645 +0.009741 +0.009814 +0.00966 +0.009555 +0.009616 +0.009684 +0.00979 +0.009858 +0.009683 +0.009593 +0.009668 +0.009759 +0.009875 +0.00992 +0.009758 +0.009651 +0.009706 +0.009802 +0.009887 +0.009961 +0.009791 +0.009727 +0.009796 +0.009864 +0.009956 +0.01002 +0.009825 +0.009756 +0.009818 +0.009896 +0.010008 +0.010052 +0.009898 +0.009823 +0.009883 +0.00997 +0.010075 +0.0101 +0.009934 +0.009872 +0.00991 +0.010003 +0.010108 +0.010186 +0.010009 +0.009928 +0.009988 +0.010107 +0.010139 +0.010208 +0.010036 +0.009958 +0.010023 +0.010119 +0.010211 +0.010268 +0.010093 +0.010067 +0.01007 +0.010154 +0.010269 +0.010342 +0.010152 +0.010069 +0.01013 +0.01022 +0.010332 +0.010393 +0.010206 +0.010113 +0.010199 +0.010303 +0.010404 +0.010447 +0.010268 +0.010173 +0.010233 +0.010321 +0.01043 +0.010497 +0.010298 +0.010227 +0.010299 +0.010398 +0.010504 +0.010554 +0.010359 +0.010275 +0.010352 +0.010427 +0.010535 +0.010615 +0.010439 +0.010348 +0.010422 +0.010523 +0.010603 +0.01065 +0.010465 +0.010374 +0.010463 +0.010553 +0.010644 +0.010741 +0.010522 +0.01045 +0.010501 +0.010591 +0.010704 +0.01078 +0.010581 +0.010492 +0.010593 +0.010676 +0.010769 +0.010823 +0.010602 +0.010512 +0.010574 +0.010681 +0.010716 +0.010737 +0.010472 +0.010355 +0.010403 +0.01045 +0.010499 +0.010461 +0.010235 +0.010105 +0.010115 +0.010153 +0.010195 +0.01021 +0.00997 +0.009828 +0.009845 +0.009868 +0.009903 +0.009916 +0.00968 +0.009555 +0.009599 +0.009625 +0.009674 +0.009632 +0.009413 +0.009275 +0.009301 +0.00934 +0.009368 +0.009379 +0.009196 +0.009069 +0.009097 +0.009104 +0.009151 +0.00917 +0.008981 +0.008882 +0.008903 +0.008947 +0.008995 +0.009017 +0.008848 +0.008733 +0.008772 +0.008806 +0.008858 +0.008885 +0.008716 +0.008641 +0.008673 +0.008703 +0.008775 +0.008777 +0.008623 +0.008554 +0.008576 +0.008646 +0.008707 +0.00875 +0.008602 +0.008531 +0.008598 +0.008665 +0.008735 +0.008804 +0.008653 +0.008581 +0.008628 +0.0087 +0.008783 +0.008846 +0.008696 +0.008628 +0.008671 +0.008743 +0.008841 +0.008899 +0.008769 +0.008672 +0.008727 +0.008795 +0.008867 +0.008958 +0.008776 +0.008724 +0.008756 +0.00884 +0.008908 +0.00898 +0.008827 +0.008759 +0.008818 +0.008907 +0.008969 +0.009029 +0.00887 +0.008799 +0.008857 +0.008927 +0.009009 +0.009088 +0.008928 +0.008858 +0.008912 +0.00899 +0.009095 +0.009118 +0.00896 +0.008888 +0.008941 +0.00902 +0.009108 +0.009183 +0.009016 +0.008955 +0.008995 +0.009076 +0.009163 +0.009205 +0.009056 +0.00898 +0.009041 +0.009119 +0.009196 +0.009288 +0.009126 +0.009039 +0.009092 +0.009175 +0.009251 +0.009302 +0.009159 +0.009091 +0.009148 +0.009208 +0.00931 +0.009348 +0.009198 +0.009127 +0.009174 +0.009265 +0.009357 +0.009421 +0.009249 +0.009167 +0.009223 +0.009305 +0.009407 +0.009467 +0.009295 +0.009221 +0.009287 +0.009355 +0.009448 +0.009509 +0.009354 +0.009287 +0.009331 +0.009425 +0.009527 +0.009563 +0.009405 +0.009301 +0.009362 +0.009451 +0.009544 +0.009607 +0.009448 +0.009383 +0.009423 +0.009515 +0.0096 +0.009645 +0.009487 +0.009413 +0.009465 +0.009553 +0.009653 +0.009734 +0.009553 +0.009472 +0.009531 +0.009601 +0.009681 +0.009765 +0.009603 +0.009539 +0.009575 +0.00966 +0.009757 +0.009793 +0.009636 +0.00955 +0.009614 +0.009698 +0.009792 +0.00986 +0.009703 +0.00961 +0.009683 +0.009757 +0.009849 +0.009917 +0.009747 +0.009662 +0.009711 +0.009803 +0.009913 +0.009981 +0.009806 +0.009734 +0.009789 +0.009873 +0.009937 +0.01001 +0.009834 +0.009756 +0.009839 +0.0099 +0.01002 +0.010082 +0.009902 +0.009799 +0.009868 +0.009957 +0.010056 +0.010133 +0.009941 +0.009868 +0.00995 +0.010022 +0.010125 +0.010192 +0.009978 +0.009908 +0.009971 +0.01009 +0.010184 +0.010211 +0.010041 +0.009983 +0.010048 +0.010128 +0.010236 +0.010297 +0.010073 +0.010003 +0.010076 +0.010162 +0.010276 +0.010334 +0.010155 +0.010076 +0.010139 +0.010214 +0.010324 +0.010395 +0.010216 +0.01014 +0.010215 +0.010283 +0.010375 +0.010444 +0.010287 +0.010186 +0.010221 +0.010317 +0.010453 +0.010522 +0.010329 +0.01026 +0.010294 +0.010357 +0.010464 +0.010553 +0.01036 +0.010294 +0.010347 +0.010429 +0.010545 +0.01062 +0.010418 +0.010327 +0.010414 +0.010498 +0.010596 +0.010682 +0.010523 +0.010392 +0.010442 +0.010532 +0.010657 +0.010718 +0.01052 +0.010443 +0.01053 +0.010655 +0.010696 +0.01074 +0.010551 +0.010458 +0.010519 +0.010571 +0.010624 +0.010649 +0.010442 +0.010297 +0.010325 +0.010381 +0.010413 +0.01042 +0.010199 +0.010113 +0.010123 +0.010114 +0.010149 +0.010148 +0.009906 +0.009786 +0.009806 +0.00985 +0.009872 +0.009896 +0.009681 +0.009543 +0.009563 +0.0096 +0.009618 +0.009604 +0.009407 +0.009293 +0.00932 +0.009345 +0.009407 +0.009392 +0.009191 +0.009094 +0.009113 +0.009184 +0.009192 +0.009198 +0.009021 +0.008925 +0.008959 +0.008992 +0.009052 +0.009055 +0.008879 +0.008775 +0.008803 +0.008858 +0.008906 +0.008923 +0.008752 +0.008658 +0.008691 +0.008735 +0.00881 +0.008824 +0.008648 +0.008565 +0.008619 +0.008689 +0.008725 +0.008773 +0.008621 +0.008578 +0.008622 +0.008684 +0.008751 +0.008838 +0.008662 +0.008601 +0.008642 +0.008718 +0.008809 +0.008859 +0.00871 +0.008642 +0.008702 +0.008776 +0.008867 +0.008935 +0.008763 +0.00868 +0.008733 +0.008822 +0.008893 +0.008955 +0.008809 +0.008735 +0.008788 +0.008868 +0.00897 +0.009024 +0.008878 +0.008781 +0.008811 +0.008892 +0.008987 +0.009051 +0.008889 +0.00882 +0.008914 +0.00896 +0.009041 +0.009091 +0.008948 +0.008863 +0.008911 +0.008994 +0.009082 +0.009147 +0.008993 +0.008941 +0.008966 +0.009039 +0.009136 +0.009199 +0.009036 +0.008954 +0.009013 +0.009117 +0.00921 +0.009234 +0.009075 +0.009023 +0.009047 +0.009138 +0.009222 +0.009285 +0.009139 +0.009054 +0.009109 +0.00919 +0.00928 +0.009356 +0.009191 +0.009118 +0.009141 +0.00923 +0.009329 +0.009394 +0.009222 +0.009144 +0.009202 +0.009282 +0.009372 +0.009465 +0.009303 +0.009226 +0.009231 +0.009309 +0.009423 +0.009479 +0.009326 +0.009231 +0.009291 +0.009401 +0.009477 +0.009549 +0.009392 +0.009299 +0.009333 +0.009417 +0.009521 +0.009578 +0.009421 +0.00936 +0.009388 +0.00947 +0.009576 +0.009628 +0.009469 +0.009388 +0.009446 +0.009564 +0.009637 +0.009667 +0.009521 +0.009444 +0.009503 +0.00956 +0.00966 +0.009733 +0.009564 +0.009478 +0.009549 +0.00964 +0.009738 +0.0098 +0.009631 +0.009519 +0.009591 +0.009679 +0.009773 +0.00983 +0.009667 +0.009582 +0.009654 +0.009744 +0.009844 +0.009931 +0.009698 +0.009616 +0.00969 +0.009774 +0.009876 +0.009948 +0.009767 +0.009706 +0.009748 +0.009837 +0.009935 +0.009974 +0.009806 +0.009728 +0.009791 +0.009887 +0.009976 +0.010045 +0.009889 +0.009797 +0.009862 +0.009935 +0.010024 +0.010098 +0.009944 +0.009845 +0.009883 +0.009975 +0.010078 +0.010145 +0.009974 +0.009883 +0.009957 +0.010054 +0.010131 +0.010201 +0.010022 +0.009935 +0.010006 +0.010084 +0.010189 +0.010257 +0.01009 +0.009995 +0.010042 +0.010149 +0.010244 +0.010316 +0.010152 +0.010076 +0.010104 +0.010188 +0.010286 +0.010356 +0.010186 +0.010078 +0.010159 +0.010258 +0.010367 +0.010453 +0.010227 +0.010133 +0.01019 +0.010308 +0.010411 +0.010459 +0.010297 +0.010205 +0.010286 +0.01038 +0.010465 +0.010504 +0.010346 +0.010269 +0.010337 +0.010397 +0.01049 +0.010584 +0.010413 +0.010317 +0.01038 +0.010467 +0.010556 +0.010628 +0.010457 +0.010392 +0.010407 +0.010542 +0.010632 +0.010695 +0.010519 +0.010409 +0.01046 +0.010578 +0.010673 +0.010744 +0.010584 +0.010485 +0.010541 +0.01062 +0.010725 +0.010799 +0.010636 +0.01051 +0.010579 +0.010682 +0.010781 +0.010817 +0.010619 +0.010487 +0.010516 +0.010584 +0.010647 +0.010661 +0.010425 +0.010304 +0.0103 +0.010332 +0.010348 +0.010346 +0.010119 +0.009982 +0.010027 +0.010009 +0.010039 +0.010055 +0.009844 +0.009711 +0.00973 +0.009721 +0.009758 +0.009752 +0.009542 +0.009423 +0.009416 +0.009454 +0.009496 +0.009498 +0.009288 +0.009159 +0.009175 +0.009187 +0.009219 +0.009244 +0.009042 +0.00894 +0.008964 +0.008988 +0.009056 +0.009067 +0.00887 +0.008769 +0.008791 +0.008828 +0.008891 +0.008912 +0.008739 +0.008644 +0.008692 +0.008704 +0.008757 +0.008798 +0.008613 +0.008526 +0.008562 +0.008607 +0.008658 +0.008705 +0.008562 +0.008459 +0.008497 +0.008552 +0.008608 +0.008666 +0.008513 +0.008444 +0.008488 +0.008583 +0.00865 +0.008701 +0.008563 +0.008488 +0.008534 +0.008616 +0.008684 +0.008732 +0.008597 +0.008523 +0.008576 +0.008649 +0.008741 +0.008784 +0.008657 +0.008583 +0.008632 +0.008699 +0.008785 +0.008835 +0.008679 +0.00862 +0.00868 +0.008741 +0.008836 +0.008875 +0.008732 +0.008661 +0.008736 +0.008784 +0.008859 +0.008924 +0.008804 +0.008696 +0.00875 +0.008826 +0.008936 +0.008978 +0.008814 +0.008747 +0.008802 +0.008869 +0.008958 +0.009033 +0.008869 +0.008794 +0.008853 +0.00892 +0.009025 +0.009085 +0.008919 +0.008836 +0.008891 +0.008965 +0.009057 +0.009115 +0.008959 +0.008895 +0.008964 +0.009068 +0.009111 +0.00916 +0.009019 +0.008915 +0.008979 +0.00905 +0.009145 +0.009211 +0.009049 +0.00898 +0.009031 +0.009122 +0.009213 +0.009257 +0.009111 +0.009014 +0.009073 +0.009158 +0.009253 +0.009312 +0.009158 +0.009082 +0.009127 +0.009208 +0.009301 +0.009368 +0.009235 +0.009112 +0.009164 +0.009251 +0.009337 +0.009434 +0.009266 +0.009151 +0.009217 +0.009307 +0.009391 +0.009455 +0.00929 +0.009208 +0.009264 +0.009375 +0.009453 +0.009513 +0.00935 +0.00927 +0.009307 +0.009398 +0.009498 +0.009549 +0.009387 +0.009307 +0.009374 +0.009506 +0.009545 +0.009601 +0.009437 +0.009345 +0.00942 +0.009499 +0.009603 +0.00965 +0.009487 +0.009395 +0.009461 +0.009546 +0.009637 +0.009706 +0.009541 +0.009451 +0.009533 +0.009599 +0.009694 +0.009754 +0.009601 +0.0095 +0.009559 +0.009651 +0.009748 +0.009851 +0.009624 +0.009548 +0.009609 +0.009697 +0.009822 +0.009861 +0.009676 +0.009611 +0.009688 +0.009741 +0.009838 +0.009897 +0.009729 +0.009668 +0.009731 +0.009814 +0.009909 +0.009976 +0.009771 +0.009696 +0.009764 +0.009841 +0.009942 +0.010016 +0.009865 +0.0098 +0.009823 +0.009927 +0.009996 +0.010041 +0.009874 +0.009789 +0.009861 +0.009958 +0.010053 +0.010113 +0.009944 +0.00987 +0.009919 +0.010015 +0.010093 +0.010172 +0.010004 +0.009904 +0.009965 +0.010072 +0.010153 +0.010225 +0.010057 +0.009986 +0.010053 +0.010093 +0.010199 +0.010278 +0.010137 +0.010016 +0.010055 +0.010168 +0.010264 +0.010324 +0.010149 +0.010057 +0.010116 +0.010212 +0.010333 +0.010415 +0.010216 +0.010107 +0.010174 +0.010269 +0.010373 +0.01044 +0.010253 +0.010178 +0.010299 +0.010337 +0.010431 +0.010469 +0.010295 +0.01022 +0.010307 +0.010364 +0.010481 +0.010533 +0.010372 +0.010298 +0.010354 +0.010441 +0.010532 +0.010587 +0.010408 +0.01032 +0.010377 +0.010457 +0.010571 +0.010588 +0.010366 +0.010248 +0.010311 +0.010312 +0.010363 +0.010353 +0.01014 +0.010024 +0.010048 +0.010073 +0.010154 +0.010076 +0.009858 +0.009739 +0.009744 +0.009785 +0.009833 +0.009833 +0.009627 +0.009495 +0.009498 +0.009536 +0.009574 +0.009561 +0.009357 +0.009218 +0.009248 +0.009297 +0.009374 +0.009336 +0.009111 +0.008999 +0.009017 +0.009076 +0.009111 +0.009128 +0.008939 +0.008821 +0.008842 +0.008891 +0.008955 +0.008947 +0.008765 +0.008664 +0.00869 +0.008741 +0.008792 +0.008823 +0.008638 +0.00854 +0.00857 +0.008622 +0.008683 +0.008702 +0.008526 +0.008429 +0.008492 +0.00852 +0.008564 +0.008604 +0.008442 +0.008346 +0.008383 +0.008458 +0.008531 +0.008569 +0.008405 +0.008323 +0.00838 +0.008452 +0.008535 +0.008591 +0.008457 +0.008363 +0.008412 +0.008492 +0.008588 +0.008644 +0.008501 +0.008433 +0.008471 +0.008537 +0.008618 +0.008685 +0.00853 +0.008461 +0.008518 +0.008593 +0.008689 +0.008731 +0.008569 +0.008519 +0.008551 +0.008624 +0.008708 +0.008787 +0.008615 +0.008551 +0.008592 +0.008673 +0.008748 +0.008826 +0.008672 +0.008592 +0.008646 +0.008719 +0.008796 +0.008865 +0.008722 +0.008638 +0.008696 +0.008778 +0.008862 +0.008899 +0.008758 +0.008688 +0.008741 +0.008835 +0.008891 +0.008944 +0.008809 +0.008726 +0.0088 +0.008868 +0.008948 +0.008987 +0.008848 +0.008769 +0.008826 +0.008908 +0.008987 +0.009038 +0.008894 +0.008824 +0.008873 +0.008943 +0.009042 +0.009095 +0.008945 +0.008868 +0.008932 +0.008991 +0.009094 +0.009159 +0.008993 +0.008946 +0.008973 +0.009032 +0.009122 +0.009184 +0.009038 +0.008961 +0.009028 +0.009086 +0.00918 +0.009239 +0.009081 +0.009016 +0.009066 +0.009126 +0.009226 +0.009286 +0.009133 +0.009045 +0.009113 +0.009178 +0.009278 +0.009353 +0.009196 +0.009114 +0.009171 +0.009223 +0.009348 +0.009383 +0.009213 +0.009134 +0.009192 +0.009283 +0.009377 +0.00944 +0.009292 +0.009215 +0.009268 +0.009313 +0.009417 +0.00947 +0.009309 +0.009238 +0.009295 +0.009382 +0.009493 +0.009563 +0.009376 +0.009299 +0.009346 +0.009415 +0.009514 +0.009589 +0.009416 +0.009373 +0.009388 +0.009495 +0.00956 +0.009625 +0.009472 +0.009378 +0.009437 +0.009527 +0.009617 +0.009693 +0.00954 +0.009448 +0.009486 +0.009573 +0.009674 +0.00973 +0.009566 +0.009485 +0.009542 +0.009638 +0.009747 +0.009793 +0.009624 +0.009529 +0.00959 +0.009705 +0.00977 +0.009825 +0.009648 +0.009618 +0.009659 +0.009731 +0.009828 +0.009895 +0.009698 +0.009621 +0.009684 +0.009771 +0.00988 +0.009948 +0.009774 +0.009679 +0.009741 +0.009833 +0.009919 +0.00999 +0.009824 +0.009721 +0.009803 +0.009909 +0.010006 +0.010073 +0.009865 +0.009764 +0.00983 +0.009926 +0.010041 +0.01009 +0.009901 +0.009847 +0.009905 +0.009992 +0.010095 +0.010131 +0.009959 +0.009892 +0.00994 +0.01003 +0.01014 +0.010203 +0.010018 +0.009944 +0.00999 +0.010089 +0.010198 +0.010265 +0.010103 +0.009981 +0.010039 +0.010141 +0.010241 +0.010302 +0.010125 +0.010069 +0.010095 +0.010179 +0.010297 +0.010354 +0.010185 +0.010116 +0.01017 +0.01023 +0.010352 +0.010414 +0.010226 +0.010145 +0.010211 +0.010303 +0.010436 +0.010484 +0.010334 +0.010226 +0.010232 +0.010333 +0.010439 +0.010511 +0.010324 +0.01024 +0.010335 +0.010428 +0.010525 +0.010589 +0.010381 +0.010292 +0.010367 +0.010452 +0.010564 +0.010651 +0.010433 +0.01034 +0.010401 +0.010486 +0.010577 +0.010599 +0.010422 +0.010244 +0.01029 +0.010354 +0.01038 +0.01038 +0.010168 +0.010035 +0.010044 +0.010093 +0.010131 +0.010149 +0.009915 +0.009787 +0.009794 +0.009835 +0.009855 +0.009845 +0.009637 +0.009509 +0.009507 +0.009543 +0.009602 +0.009607 +0.009385 +0.009265 +0.009274 +0.009324 +0.009338 +0.009326 +0.009141 +0.009006 +0.009024 +0.009051 +0.009109 +0.009133 +0.008933 +0.008806 +0.00883 +0.008869 +0.008909 +0.008929 +0.008739 +0.008639 +0.00866 +0.008709 +0.00877 +0.008804 +0.008619 +0.008515 +0.008544 +0.008598 +0.008631 +0.008663 +0.008493 +0.008414 +0.008439 +0.008481 +0.008548 +0.008572 +0.008414 +0.008347 +0.008368 +0.008436 +0.008512 +0.008557 +0.00841 +0.008335 +0.008404 +0.00847 +0.008539 +0.008605 +0.008473 +0.008382 +0.008431 +0.008509 +0.008592 +0.008643 +0.008507 +0.008436 +0.008489 +0.008559 +0.008653 +0.008709 +0.008554 +0.008494 +0.008513 +0.008583 +0.008673 +0.008733 +0.008591 +0.008521 +0.008583 +0.00867 +0.008725 +0.008782 +0.008634 +0.008554 +0.008608 +0.008681 +0.008765 +0.008834 +0.008677 +0.008605 +0.008661 +0.008744 +0.008827 +0.008883 +0.00874 +0.008653 +0.008695 +0.008771 +0.00886 +0.008944 +0.008788 +0.008686 +0.008739 +0.008813 +0.008905 +0.008973 +0.008813 +0.008743 +0.008793 +0.008866 +0.008965 +0.009013 +0.00887 +0.008784 +0.008847 +0.008916 +0.008998 +0.009052 +0.008903 +0.008843 +0.008885 +0.008955 +0.009053 +0.009124 +0.008959 +0.008895 +0.008952 +0.009024 +0.009118 +0.009142 +0.009017 +0.008914 +0.008967 +0.009051 +0.009133 +0.009201 +0.009056 +0.008982 +0.009037 +0.009098 +0.009194 +0.009255 +0.009094 +0.009021 +0.00906 +0.009141 +0.009241 +0.009316 +0.009157 +0.009074 +0.009139 +0.009193 +0.00928 +0.009351 +0.009193 +0.009137 +0.009155 +0.009244 +0.009323 +0.009409 +0.009253 +0.00914 +0.009214 +0.009291 +0.009381 +0.009448 +0.009285 +0.009218 +0.009271 +0.00935 +0.009434 +0.0095 +0.009331 +0.00925 +0.009311 +0.00938 +0.009486 +0.009569 +0.009399 +0.00931 +0.009376 +0.009455 +0.009553 +0.009578 +0.009416 +0.009343 +0.009401 +0.009496 +0.009622 +0.009648 +0.009488 +0.009398 +0.009456 +0.009532 +0.009624 +0.009687 +0.009528 +0.009461 +0.009506 +0.009583 +0.009687 +0.009751 +0.00957 +0.00951 +0.009558 +0.009635 +0.009738 +0.009824 +0.009672 +0.009548 +0.00959 +0.009677 +0.009777 +0.009849 +0.00967 +0.009588 +0.00967 +0.009734 +0.009848 +0.00992 +0.009737 +0.009636 +0.009701 +0.009788 +0.009885 +0.009953 +0.009781 +0.00968 +0.009762 +0.009854 +0.009957 +0.010001 +0.009841 +0.009763 +0.00983 +0.009934 +0.009963 +0.010051 +0.009892 +0.009786 +0.009842 +0.009942 +0.01004 +0.010109 +0.00994 +0.009845 +0.009908 +0.01002 +0.010118 +0.010169 +0.00997 +0.009895 +0.009951 +0.010054 +0.010157 +0.010219 +0.010044 +0.009971 +0.010041 +0.010145 +0.010198 +0.010237 +0.010086 +0.009996 +0.01005 +0.010157 +0.010264 +0.010305 +0.010136 +0.010056 +0.010119 +0.010207 +0.010308 +0.010379 +0.010203 +0.010129 +0.010182 +0.010265 +0.010356 +0.010438 +0.010243 +0.010152 +0.010228 +0.01035 +0.010441 +0.010485 +0.010305 +0.010214 +0.010309 +0.010336 +0.010458 +0.01053 +0.010351 +0.010279 +0.01032 +0.010416 +0.010527 +0.0106 +0.010404 +0.010312 +0.010376 +0.010472 +0.010575 +0.010633 +0.010386 +0.010272 +0.010303 +0.010343 +0.010414 +0.010484 +0.010241 +0.010105 +0.010132 +0.010147 +0.010237 +0.01017 +0.009962 +0.009841 +0.009837 +0.009873 +0.009925 +0.009936 +0.009732 +0.009594 +0.009594 +0.009629 +0.009644 +0.009666 +0.00945 +0.009315 +0.009337 +0.009361 +0.009397 +0.009424 +0.00921 +0.009114 +0.009091 +0.009124 +0.009155 +0.009187 +0.009009 +0.008889 +0.008913 +0.008962 +0.008987 +0.009016 +0.008836 +0.008737 +0.008747 +0.008797 +0.00884 +0.008888 +0.008706 +0.0086 +0.008642 +0.008684 +0.008731 +0.008753 +0.008593 +0.008483 +0.008515 +0.008568 +0.008625 +0.008687 +0.008515 +0.008408 +0.00844 +0.008516 +0.008582 +0.008627 +0.008473 +0.008397 +0.008443 +0.008524 +0.008624 +0.008646 +0.008521 +0.00844 +0.008502 +0.008569 +0.008657 +0.008709 +0.008542 +0.008486 +0.00854 +0.008602 +0.008676 +0.008754 +0.0086 +0.008531 +0.008587 +0.008671 +0.008769 +0.008817 +0.00865 +0.008563 +0.008615 +0.008692 +0.008782 +0.00885 +0.008688 +0.008619 +0.008676 +0.008748 +0.008831 +0.008921 +0.008737 +0.008646 +0.008704 +0.008785 +0.008868 +0.008929 +0.008797 +0.00871 +0.008759 +0.008829 +0.00892 +0.00897 +0.008825 +0.008752 +0.008805 +0.008911 +0.008968 +0.009022 +0.008874 +0.008819 +0.008842 +0.008917 +0.00901 +0.009068 +0.008925 +0.008833 +0.008894 +0.008982 +0.00906 +0.00914 +0.008977 +0.008906 +0.008935 +0.009011 +0.009106 +0.009167 +0.009006 +0.008925 +0.008992 +0.009081 +0.009156 +0.009238 +0.00908 +0.009016 +0.009017 +0.009105 +0.009184 +0.009259 +0.009112 +0.009045 +0.009071 +0.00917 +0.009259 +0.009315 +0.009159 +0.009089 +0.009119 +0.009206 +0.009305 +0.009358 +0.009195 +0.009117 +0.009171 +0.00928 +0.009356 +0.00942 +0.00925 +0.009175 +0.009223 +0.009311 +0.009426 +0.009445 +0.009283 +0.009208 +0.009256 +0.009363 +0.009439 +0.009508 +0.009377 +0.009258 +0.009325 +0.0094 +0.009497 +0.009547 +0.00939 +0.009328 +0.009369 +0.009455 +0.009551 +0.009606 +0.009442 +0.009362 +0.009428 +0.0095 +0.009587 +0.009679 +0.009524 +0.009438 +0.009459 +0.009543 +0.009639 +0.009706 +0.009535 +0.009451 +0.009511 +0.009594 +0.009704 +0.009775 +0.009592 +0.009496 +0.009578 +0.009671 +0.009747 +0.009805 +0.009631 +0.009557 +0.009627 +0.009711 +0.009813 +0.009847 +0.009688 +0.009614 +0.009696 +0.009777 +0.009833 +0.00992 +0.009745 +0.009663 +0.009717 +0.0098 +0.009904 +0.009945 +0.009781 +0.009707 +0.009766 +0.009869 +0.009949 +0.010019 +0.009843 +0.009752 +0.009824 +0.009895 +0.009994 +0.010073 +0.009903 +0.009829 +0.009887 +0.009986 +0.010104 +0.010085 +0.009935 +0.009848 +0.009916 +0.01002 +0.0101 +0.01016 +0.009998 +0.009909 +0.009974 +0.010077 +0.01016 +0.010234 +0.010058 +0.009965 +0.010017 +0.01012 +0.010214 +0.010279 +0.010104 +0.010014 +0.010078 +0.010178 +0.01029 +0.010363 +0.01016 +0.01007 +0.010113 +0.010221 +0.010326 +0.010407 +0.010201 +0.010105 +0.010176 +0.010278 +0.010379 +0.010465 +0.010269 +0.010163 +0.010235 +0.010329 +0.010427 +0.010495 +0.010312 +0.010229 +0.01031 +0.010401 +0.010511 +0.010582 +0.010345 +0.010262 +0.010333 +0.010432 +0.010535 +0.0106 +0.010437 +0.010373 +0.010401 +0.010488 +0.010557 +0.010617 +0.010423 +0.010317 +0.010328 +0.010394 +0.01048 +0.010468 +0.010256 +0.010127 +0.010148 +0.010175 +0.010224 +0.010266 +0.010017 +0.009906 +0.009878 +0.009907 +0.009932 +0.009937 +0.009724 +0.009602 +0.009597 +0.009622 +0.009686 +0.009694 +0.009461 +0.00934 +0.009347 +0.009358 +0.009392 +0.009412 +0.009206 +0.009091 +0.009113 +0.009125 +0.009156 +0.009182 +0.00899 +0.008901 +0.008905 +0.008924 +0.008956 +0.009001 +0.008824 +0.008707 +0.008738 +0.008779 +0.008822 +0.008839 +0.008671 +0.008571 +0.008609 +0.008637 +0.00869 +0.008726 +0.008557 +0.008464 +0.008487 +0.00855 +0.008588 +0.008626 +0.008461 +0.008378 +0.008413 +0.008463 +0.008533 +0.008584 +0.008458 +0.008368 +0.008407 +0.008463 +0.008568 +0.008622 +0.008466 +0.008414 +0.008437 +0.00852 +0.008593 +0.008652 +0.008507 +0.008449 +0.008502 +0.008572 +0.008657 +0.008719 +0.008557 +0.008474 +0.008537 +0.008608 +0.008695 +0.008743 +0.008598 +0.008524 +0.008583 +0.008653 +0.008745 +0.008819 +0.008671 +0.008574 +0.008614 +0.008685 +0.008775 +0.008844 +0.008689 +0.008615 +0.008683 +0.008748 +0.008821 +0.008893 +0.008745 +0.008665 +0.008712 +0.008787 +0.008868 +0.008932 +0.008793 +0.008738 +0.008758 +0.008843 +0.00891 +0.008982 +0.008831 +0.008751 +0.00881 +0.008885 +0.00899 +0.009025 +0.008862 +0.008803 +0.00886 +0.008942 +0.009005 +0.009066 +0.008913 +0.008847 +0.00889 +0.00898 +0.00906 +0.009127 +0.008967 +0.008899 +0.008957 +0.009028 +0.009103 +0.009171 +0.009004 +0.008954 +0.008985 +0.009064 +0.009145 +0.009206 +0.009072 +0.008999 +0.009066 +0.00911 +0.009194 +0.00928 +0.009092 +0.009032 +0.009073 +0.009157 +0.009271 +0.00932 +0.009151 +0.009073 +0.009137 +0.009215 +0.009298 +0.009368 +0.009187 +0.009116 +0.009176 +0.009255 +0.009375 +0.009418 +0.009252 +0.00916 +0.009225 +0.009317 +0.009406 +0.009485 +0.009281 +0.009213 +0.009277 +0.009363 +0.009482 +0.009495 +0.009328 +0.009266 +0.009317 +0.009402 +0.009489 +0.00956 +0.00939 +0.009315 +0.009389 +0.009457 +0.009556 +0.009606 +0.009434 +0.009364 +0.009418 +0.0095 +0.009582 +0.009665 +0.00951 +0.009449 +0.009484 +0.009554 +0.00964 +0.009683 +0.009532 +0.009459 +0.00951 +0.00961 +0.009708 +0.009747 +0.009583 +0.009511 +0.009565 +0.009649 +0.009748 +0.009806 +0.009664 +0.009561 +0.009612 +0.009721 +0.009788 +0.009858 +0.009686 +0.009603 +0.00967 +0.009783 +0.009855 +0.009904 +0.009745 +0.009669 +0.009734 +0.009786 +0.009891 +0.009967 +0.009796 +0.0097 +0.009762 +0.009856 +0.009953 +0.010027 +0.00986 +0.009768 +0.009805 +0.009924 +0.009987 +0.010057 +0.009899 +0.009801 +0.009867 +0.009975 +0.010087 +0.010152 +0.009968 +0.009841 +0.009897 +0.01 +0.010095 +0.010165 +0.009994 +0.009915 +0.009991 +0.010084 +0.010183 +0.010233 +0.01002 +0.009956 +0.010017 +0.010109 +0.010218 +0.010288 +0.0101 +0.010016 +0.010071 +0.010165 +0.010279 +0.010355 +0.010166 +0.010061 +0.010117 +0.010248 +0.010321 +0.010372 +0.010202 +0.010123 +0.010185 +0.010262 +0.010385 +0.010436 +0.010264 +0.010197 +0.010254 +0.010311 +0.01043 +0.010486 +0.010313 +0.010229 +0.010276 +0.010379 +0.010492 +0.010567 +0.010409 +0.010267 +0.010294 +0.010408 +0.010509 +0.010543 +0.010332 +0.010225 +0.010245 +0.010311 +0.010386 +0.010394 +0.01014 +0.010013 +0.010076 +0.010061 +0.010122 +0.010126 +0.009923 +0.009778 +0.009779 +0.009817 +0.009878 +0.009854 +0.009634 +0.009515 +0.009528 +0.009603 +0.009614 +0.009597 +0.009394 +0.009271 +0.009305 +0.009337 +0.009356 +0.009386 +0.009169 +0.009051 +0.009068 +0.009121 +0.009154 +0.009173 +0.00898 +0.008862 +0.008888 +0.008942 +0.008988 +0.009015 +0.008828 +0.008733 +0.008757 +0.008808 +0.008872 +0.008886 +0.008728 +0.008605 +0.00863 +0.008677 +0.008741 +0.008781 +0.008605 +0.008503 +0.008547 +0.008632 +0.008657 +0.008699 +0.008535 +0.00844 +0.008474 +0.008547 +0.008624 +0.008684 +0.008531 +0.008456 +0.008517 +0.008578 +0.008653 +0.008724 +0.008582 +0.008507 +0.008541 +0.008627 +0.008706 +0.008797 +0.008652 +0.008547 +0.008592 +0.008654 +0.008751 +0.008812 +0.008663 +0.008586 +0.008639 +0.008709 +0.008802 +0.008858 +0.00872 +0.008662 +0.008692 +0.008749 +0.008838 +0.008897 +0.008758 +0.008683 +0.008734 +0.008796 +0.008885 +0.008964 +0.008807 +0.008725 +0.008791 +0.008862 +0.008952 +0.008987 +0.00883 +0.00876 +0.008821 +0.008897 +0.008976 +0.009045 +0.008901 +0.008828 +0.008871 +0.008948 +0.009035 +0.009096 +0.008926 +0.008853 +0.008913 +0.008986 +0.009083 +0.009136 +0.00898 +0.008903 +0.008957 +0.009038 +0.009114 +0.009185 +0.009037 +0.008962 +0.009044 +0.009091 +0.009183 +0.009226 +0.00907 +0.009001 +0.009038 +0.009123 +0.00921 +0.009278 +0.009119 +0.009041 +0.009115 +0.009184 +0.009276 +0.009333 +0.009166 +0.009094 +0.009149 +0.009221 +0.009302 +0.00938 +0.009234 +0.009152 +0.00923 +0.009287 +0.009375 +0.009449 +0.009245 +0.009175 +0.009229 +0.009304 +0.009414 +0.0095 +0.009319 +0.00923 +0.009283 +0.009371 +0.009457 +0.00953 +0.009354 +0.009278 +0.009343 +0.009424 +0.009527 +0.009583 +0.009401 +0.009326 +0.009394 +0.009475 +0.009557 +0.009616 +0.009471 +0.009414 +0.009452 +0.009522 +0.009605 +0.009653 +0.009503 +0.009425 +0.009484 +0.009563 +0.009698 +0.009721 +0.009544 +0.009474 +0.009524 +0.009611 +0.009712 +0.009773 +0.00961 +0.009535 +0.009601 +0.00968 +0.009753 +0.009823 +0.00965 +0.009571 +0.009639 +0.009728 +0.009833 +0.009871 +0.009718 +0.009632 +0.009693 +0.00977 +0.009852 +0.009922 +0.009756 +0.009666 +0.009756 +0.009819 +0.009933 +0.009981 +0.009817 +0.00972 +0.009791 +0.00987 +0.009956 +0.010029 +0.009861 +0.009784 +0.009821 +0.009919 +0.010023 +0.010119 +0.009902 +0.00982 +0.00989 +0.009981 +0.010084 +0.01015 +0.009965 +0.009867 +0.00992 +0.010016 +0.010133 +0.01019 +0.010003 +0.009935 +0.009996 +0.0101 +0.010206 +0.010242 +0.010048 +0.009979 +0.01004 +0.010126 +0.010232 +0.010298 +0.010161 +0.010038 +0.01009 +0.01019 +0.010286 +0.010365 +0.010149 +0.010076 +0.010142 +0.010231 +0.010331 +0.010425 +0.010238 +0.010149 +0.010214 +0.010281 +0.010393 +0.010457 +0.010273 +0.010182 +0.010268 +0.010332 +0.010448 +0.010519 +0.010367 +0.010241 +0.010289 +0.010391 +0.010501 +0.010573 +0.010383 +0.010315 +0.010369 +0.010443 +0.010551 +0.01063 +0.010426 +0.01035 +0.010421 +0.010492 +0.01062 +0.010664 +0.01042 +0.010328 +0.010367 +0.010421 +0.010463 +0.010492 +0.010287 +0.010186 +0.010162 +0.010211 +0.010265 +0.010253 +0.010027 +0.009872 +0.009887 +0.009936 +0.009974 +0.00996 +0.009745 +0.009613 +0.009628 +0.009661 +0.009682 +0.009692 +0.009463 +0.009337 +0.009343 +0.009372 +0.009417 +0.009434 +0.009221 +0.009107 +0.009124 +0.009166 +0.009182 +0.009201 +0.008995 +0.008885 +0.00891 +0.008942 +0.008996 +0.009032 +0.008838 +0.008723 +0.008752 +0.008803 +0.008839 +0.008882 +0.008709 +0.008606 +0.00864 +0.008676 +0.00875 +0.00877 +0.008602 +0.008491 +0.008527 +0.008566 +0.008624 +0.008675 +0.008517 +0.008438 +0.008465 +0.00852 +0.008585 +0.008649 +0.008505 +0.008426 +0.00845 +0.008531 +0.008618 +0.00867 +0.008533 +0.008458 +0.008512 +0.008583 +0.008676 +0.008732 +0.008586 +0.008514 +0.008556 +0.008625 +0.008701 +0.008761 +0.008618 +0.008552 +0.008606 +0.008664 +0.008752 +0.008819 +0.008695 +0.008601 +0.008645 +0.008716 +0.008807 +0.008852 +0.008711 +0.008669 +0.008691 +0.008771 +0.008836 +0.008893 +0.008747 +0.008686 +0.008729 +0.008803 +0.008894 +0.008951 +0.008814 +0.008731 +0.008793 +0.008861 +0.008944 +0.008995 +0.008844 +0.008772 +0.008823 +0.00891 +0.009001 +0.009062 +0.008894 +0.008822 +0.00887 +0.00895 +0.009047 +0.009085 +0.008929 +0.008882 +0.008905 +0.008987 +0.009073 +0.009138 +0.008985 +0.008921 +0.008974 +0.009049 +0.009143 +0.009177 +0.009028 +0.008948 +0.009001 +0.009091 +0.009173 +0.009231 +0.009084 +0.009005 +0.009082 +0.009171 +0.009207 +0.009265 +0.00912 +0.009048 +0.0091 +0.009186 +0.009283 +0.009331 +0.009173 +0.009091 +0.009149 +0.009226 +0.00932 +0.009377 +0.00923 +0.009156 +0.009208 +0.009294 +0.009372 +0.009414 +0.009266 +0.00918 +0.009242 +0.009327 +0.009423 +0.0095 +0.009326 +0.009242 +0.009306 +0.009363 +0.009478 +0.009506 +0.009355 +0.009285 +0.009337 +0.009419 +0.009517 +0.009603 +0.009423 +0.009339 +0.009394 +0.009474 +0.009561 +0.009618 +0.009449 +0.009372 +0.009447 +0.009532 +0.009607 +0.009676 +0.00951 +0.009426 +0.009485 +0.009574 +0.009689 +0.009736 +0.009558 +0.009488 +0.009545 +0.009624 +0.009701 +0.009771 +0.009607 +0.009526 +0.00958 +0.009663 +0.009782 +0.009845 +0.009676 +0.009588 +0.009633 +0.009703 +0.00982 +0.009869 +0.00971 +0.009651 +0.009692 +0.009762 +0.009861 +0.00993 +0.009784 +0.009668 +0.009721 +0.009812 +0.009929 +0.010003 +0.009802 +0.009723 +0.00979 +0.009868 +0.009971 +0.010044 +0.009857 +0.009771 +0.009844 +0.009931 +0.010026 +0.010106 +0.009922 +0.009824 +0.009885 +0.00998 +0.010078 +0.010136 +0.009964 +0.009904 +0.009965 +0.010027 +0.010128 +0.010182 +0.010015 +0.009922 +0.010007 +0.010079 +0.010171 +0.010248 +0.010089 +0.009988 +0.01005 +0.01015 +0.010226 +0.01028 +0.010114 +0.010038 +0.010103 +0.0102 +0.01028 +0.010343 +0.01017 +0.01009 +0.010175 +0.010223 +0.010334 +0.010403 +0.010223 +0.010158 +0.010213 +0.01028 +0.010431 +0.010443 +0.01027 +0.010192 +0.010243 +0.010357 +0.010468 +0.010521 +0.010346 +0.010261 +0.010287 +0.01039 +0.010509 +0.010576 +0.010379 +0.010306 +0.010411 +0.01049 +0.010572 +0.010591 +0.010382 +0.010304 +0.010348 +0.010417 +0.010492 +0.010483 +0.010258 +0.010113 +0.010153 +0.010215 +0.010248 +0.010235 +0.010016 +0.009889 +0.009924 +0.009991 +0.010016 +0.010003 +0.009761 +0.00964 +0.009665 +0.009687 +0.009733 +0.009747 +0.009542 +0.009383 +0.009392 +0.009428 +0.009469 +0.009443 +0.009233 +0.009117 +0.009141 +0.009173 +0.009207 +0.009223 +0.009015 +0.008913 +0.00894 +0.008982 +0.009023 +0.009015 +0.008839 +0.008735 +0.008766 +0.008812 +0.008856 +0.008874 +0.008691 +0.008599 +0.008639 +0.008709 +0.008728 +0.008738 +0.008584 +0.008472 +0.008517 +0.00856 +0.008613 +0.008641 +0.008478 +0.008381 +0.008428 +0.008489 +0.008553 +0.008583 +0.008421 +0.008356 +0.008405 +0.008483 +0.008551 +0.008629 +0.008471 +0.008386 +0.008435 +0.008525 +0.008594 +0.008655 +0.008518 +0.008436 +0.008501 +0.008559 +0.008654 +0.008712 +0.008556 +0.008483 +0.008557 +0.008598 +0.008673 +0.008743 +0.008591 +0.008522 +0.008576 +0.008674 +0.00874 +0.008781 +0.008651 +0.008566 +0.008612 +0.00869 +0.008772 +0.008832 +0.008686 +0.008609 +0.008668 +0.008744 +0.008829 +0.008887 +0.008735 +0.008685 +0.008708 +0.008781 +0.008855 +0.008921 +0.008781 +0.008705 +0.008769 +0.008853 +0.008925 +0.008958 +0.008814 +0.00875 +0.008797 +0.008869 +0.008959 +0.009025 +0.008872 +0.008799 +0.008855 +0.008934 +0.009017 +0.009057 +0.008919 +0.00883 +0.008886 +0.008967 +0.009052 +0.009143 +0.00896 +0.008888 +0.008944 +0.009023 +0.009115 +0.00916 +0.008996 +0.008927 +0.008986 +0.009061 +0.009144 +0.009213 +0.009049 +0.008988 +0.009044 +0.009126 +0.009212 +0.009251 +0.009098 +0.009034 +0.009066 +0.009148 +0.009237 +0.009298 +0.009151 +0.009073 +0.009143 +0.009232 +0.009289 +0.009371 +0.009185 +0.009113 +0.009171 +0.009245 +0.009333 +0.009412 +0.009239 +0.009164 +0.009226 +0.009316 +0.009401 +0.009451 +0.0093 +0.009212 +0.009256 +0.009361 +0.009447 +0.009495 +0.009341 +0.009261 +0.009318 +0.009405 +0.009497 +0.00957 +0.009404 +0.009296 +0.009345 +0.009445 +0.009572 +0.009584 +0.009431 +0.009353 +0.009422 +0.009496 +0.009579 +0.009666 +0.009481 +0.009406 +0.009473 +0.009564 +0.009629 +0.009698 +0.009536 +0.009451 +0.00951 +0.009605 +0.009681 +0.009754 +0.009595 +0.009517 +0.009606 +0.00965 +0.009718 +0.009791 +0.009627 +0.009549 +0.009633 +0.00968 +0.009797 +0.00986 +0.0097 +0.009627 +0.009665 +0.009736 +0.009839 +0.009909 +0.009723 +0.009648 +0.009708 +0.009795 +0.009904 +0.009978 +0.009798 +0.00971 +0.009763 +0.009861 +0.009957 +0.009997 +0.009812 +0.009737 +0.009834 +0.009909 +0.010014 +0.010074 +0.009892 +0.009791 +0.009858 +0.009951 +0.010053 +0.01012 +0.009956 +0.009843 +0.009918 +0.010016 +0.010088 +0.010161 +0.009992 +0.009907 +0.009965 +0.010066 +0.010192 +0.01026 +0.01003 +0.009934 +0.010005 +0.010109 +0.010199 +0.010263 +0.010104 +0.010012 +0.010088 +0.010189 +0.010266 +0.010309 +0.010139 +0.010063 +0.01012 +0.010212 +0.01031 +0.010388 +0.010209 +0.010132 +0.010185 +0.010255 +0.010372 +0.010474 +0.010249 +0.010146 +0.010232 +0.010312 +0.010444 +0.010494 +0.01031 +0.010225 +0.01027 +0.010364 +0.010494 +0.010533 +0.010358 +0.010291 +0.010327 +0.010422 +0.010532 +0.010575 +0.010388 +0.010297 +0.010344 +0.010414 +0.010482 +0.010557 +0.010282 +0.010149 +0.010192 +0.010216 +0.010299 +0.010272 +0.010055 +0.009917 +0.009953 +0.009964 +0.010011 +0.010009 +0.009775 +0.009656 +0.009664 +0.009693 +0.009725 +0.009737 +0.009522 +0.009396 +0.009393 +0.009433 +0.009466 +0.009458 +0.009264 +0.009153 +0.009169 +0.009185 +0.009225 +0.009228 +0.009039 +0.008931 +0.008961 +0.008976 +0.009024 +0.009029 +0.008858 +0.008753 +0.008794 +0.008847 +0.008883 +0.00891 +0.008724 +0.008628 +0.008641 +0.008704 +0.008743 +0.008769 +0.008603 +0.008519 +0.008542 +0.008591 +0.008654 +0.008687 +0.008534 +0.008425 +0.008469 +0.008521 +0.008594 +0.008644 +0.008498 +0.008427 +0.008484 +0.00855 +0.00862 +0.008685 +0.008538 +0.008458 +0.008502 +0.00858 +0.008673 +0.008738 +0.008589 +0.00851 +0.008588 +0.008628 +0.008701 +0.008767 +0.008614 +0.008547 +0.008598 +0.008681 +0.008774 +0.008839 +0.008682 +0.008587 +0.008652 +0.008715 +0.008798 +0.008843 +0.0087 +0.008636 +0.008695 +0.00877 +0.008868 +0.008924 +0.008764 +0.00868 +0.008728 +0.008813 +0.008888 +0.008953 +0.008805 +0.008728 +0.008781 +0.008871 +0.008959 +0.009003 +0.008854 +0.008765 +0.008823 +0.008929 +0.008989 +0.009042 +0.008886 +0.008838 +0.008876 +0.008955 +0.009036 +0.009095 +0.008951 +0.008858 +0.00891 +0.008998 +0.009083 +0.009143 +0.008998 +0.008908 +0.00896 +0.009036 +0.009125 +0.009189 +0.009033 +0.008951 +0.009017 +0.009093 +0.009181 +0.009247 +0.009103 +0.009028 +0.009052 +0.009129 +0.009214 +0.009283 +0.009137 +0.009056 +0.0091 +0.009186 +0.009295 +0.009342 +0.009191 +0.009105 +0.009144 +0.009221 +0.009324 +0.009374 +0.009219 +0.009145 +0.009211 +0.009304 +0.00938 +0.009447 +0.009271 +0.00919 +0.009244 +0.009324 +0.009453 +0.009474 +0.009319 +0.009238 +0.009287 +0.009381 +0.009467 +0.009528 +0.00937 +0.009288 +0.009334 +0.009438 +0.009536 +0.0096 +0.009425 +0.009337 +0.009385 +0.0095 +0.009567 +0.009624 +0.009461 +0.009377 +0.009457 +0.009545 +0.009628 +0.009697 +0.009537 +0.009452 +0.009477 +0.009564 +0.009658 +0.009725 +0.009571 +0.009473 +0.009532 +0.009627 +0.009737 +0.009783 +0.009616 +0.009534 +0.009592 +0.009689 +0.009769 +0.009845 +0.009667 +0.009592 +0.009642 +0.009727 +0.009829 +0.00988 +0.00972 +0.009638 +0.009724 +0.009822 +0.009885 +0.009932 +0.009752 +0.009681 +0.009734 +0.009825 +0.009932 +0.009993 +0.009824 +0.00976 +0.00981 +0.00989 +0.009968 +0.010041 +0.009862 +0.009782 +0.009851 +0.009916 +0.010049 +0.010125 +0.009928 +0.009849 +0.009913 +0.009997 +0.010106 +0.010128 +0.009966 +0.009882 +0.009953 +0.010024 +0.010133 +0.010203 +0.010021 +0.009944 +0.010004 +0.010095 +0.010185 +0.010265 +0.010094 +0.00999 +0.010046 +0.010149 +0.010244 +0.010307 +0.010142 +0.010038 +0.010133 +0.010209 +0.010344 +0.010385 +0.010171 +0.010072 +0.010148 +0.010255 +0.010352 +0.010409 +0.010234 +0.010154 +0.010227 +0.010332 +0.010413 +0.010452 +0.010292 +0.010218 +0.010254 +0.010361 +0.010444 +0.010542 +0.010368 +0.010263 +0.010324 +0.010415 +0.010533 +0.010599 +0.010374 +0.010288 +0.010371 +0.010464 +0.010565 +0.010639 +0.010475 +0.010377 +0.010387 +0.010497 +0.010595 +0.010663 +0.010461 +0.010319 +0.010346 +0.010395 +0.010455 +0.010457 +0.010224 +0.010093 +0.010117 +0.010141 +0.010202 +0.010216 +0.010007 +0.009812 +0.009819 +0.009861 +0.009915 +0.009922 +0.009693 +0.009566 +0.00958 +0.009613 +0.009625 +0.00964 +0.009418 +0.009289 +0.009306 +0.009315 +0.009375 +0.009404 +0.009189 +0.009061 +0.009066 +0.009108 +0.009125 +0.00915 +0.008964 +0.008845 +0.008888 +0.008903 +0.008945 +0.008983 +0.008808 +0.008709 +0.008721 +0.008774 +0.00881 +0.008851 +0.008669 +0.008565 +0.008601 +0.008678 +0.008705 +0.008742 +0.008591 +0.008482 +0.008516 +0.008574 +0.008645 +0.008662 +0.008515 +0.008437 +0.008474 +0.008541 +0.008625 +0.008687 +0.008553 +0.008504 +0.008522 +0.00859 +0.008668 +0.008721 +0.008576 +0.00851 +0.008556 +0.008629 +0.008717 +0.008776 +0.008626 +0.008551 +0.008606 +0.008672 +0.008776 +0.00883 +0.008667 +0.008596 +0.008647 +0.008724 +0.008806 +0.008865 +0.008727 +0.008648 +0.00871 +0.00877 +0.008846 +0.008923 +0.00878 +0.008677 +0.008729 +0.008807 +0.008903 +0.008977 +0.008818 +0.008743 +0.008774 +0.008855 +0.008943 +0.009002 +0.00885 +0.008765 +0.008819 +0.008918 +0.00901 +0.009068 +0.008906 +0.008839 +0.008873 +0.008943 +0.009034 +0.009099 +0.008941 +0.008868 +0.008943 +0.009014 +0.009107 +0.009133 +0.008981 +0.008908 +0.008968 +0.009039 +0.009135 +0.009191 +0.009038 +0.008986 +0.009023 +0.009083 +0.009189 +0.009229 +0.009082 +0.009011 +0.009056 +0.00913 +0.009225 +0.009304 +0.00914 +0.009067 +0.00913 +0.00919 +0.009271 +0.009337 +0.009179 +0.009127 +0.009155 +0.00922 +0.009317 +0.009382 +0.009246 +0.00916 +0.009214 +0.009271 +0.009375 +0.009441 +0.00929 +0.009201 +0.009232 +0.009321 +0.009439 +0.009497 +0.009331 +0.00925 +0.009315 +0.009368 +0.009474 +0.009539 +0.009365 +0.009287 +0.009346 +0.009437 +0.009577 +0.009595 +0.00941 +0.009352 +0.009399 +0.009477 +0.009566 +0.009631 +0.009465 +0.009387 +0.009448 +0.009527 +0.009619 +0.009711 +0.009516 +0.009431 +0.009492 +0.009593 +0.009674 +0.009746 +0.00959 +0.009495 +0.009538 +0.009617 +0.00973 +0.009783 +0.009617 +0.009543 +0.009624 +0.009731 +0.009783 +0.009842 +0.009686 +0.009567 +0.009632 +0.009721 +0.009828 +0.009891 +0.009707 +0.009638 +0.009702 +0.009786 +0.009879 +0.009949 +0.009771 +0.009687 +0.009755 +0.009835 +0.009942 +0.010019 +0.009839 +0.009727 +0.009792 +0.009889 +0.010026 +0.010042 +0.009869 +0.009781 +0.009864 +0.009989 +0.010034 +0.010098 +0.00993 +0.009817 +0.009888 +0.009992 +0.010081 +0.010161 +0.009995 +0.009885 +0.009953 +0.010052 +0.01014 +0.010204 +0.01003 +0.009947 +0.010009 +0.010115 +0.01022 +0.010291 +0.01007 +0.009991 +0.010051 +0.010135 +0.010255 +0.010313 +0.01018 +0.010058 +0.010109 +0.010194 +0.010298 +0.010355 +0.010183 +0.010109 +0.010157 +0.010259 +0.010365 +0.010418 +0.010242 +0.010163 +0.010212 +0.010307 +0.010421 +0.010515 +0.010333 +0.010211 +0.010261 +0.010344 +0.010465 +0.01052 +0.010351 +0.010269 +0.010333 +0.010425 +0.010542 +0.010589 +0.010407 +0.010312 +0.010362 +0.010464 +0.010584 +0.010634 +0.010459 +0.010376 +0.010426 +0.010527 +0.010654 +0.010721 +0.010524 +0.010436 +0.010483 +0.010588 +0.0107 +0.010714 +0.010544 +0.010448 +0.010484 +0.010542 +0.010638 +0.010635 +0.010429 +0.010306 +0.010316 +0.010346 +0.010377 +0.010367 +0.010146 +0.009996 +0.010007 +0.010062 +0.010095 +0.010084 +0.009861 +0.009737 +0.009758 +0.009757 +0.009803 +0.009787 +0.009581 +0.009484 +0.009457 +0.009499 +0.009544 +0.009538 +0.009334 +0.009219 +0.009231 +0.009266 +0.009302 +0.009319 +0.009126 +0.009011 +0.009034 +0.009067 +0.009116 +0.009136 +0.008961 +0.008841 +0.008869 +0.008926 +0.008971 +0.009031 +0.008807 +0.008707 +0.008724 +0.008799 +0.008826 +0.008849 +0.008681 +0.008585 +0.00863 +0.008676 +0.008735 +0.00879 +0.008622 +0.008542 +0.008572 +0.008642 +0.008711 +0.008756 +0.008619 +0.008552 +0.008597 +0.008665 +0.008774 +0.008826 +0.008676 +0.008591 +0.008656 +0.008719 +0.008821 +0.008847 +0.008694 +0.008631 +0.008683 +0.008789 +0.00886 +0.008886 +0.008749 +0.008679 +0.008727 +0.008806 +0.008893 +0.008947 +0.008803 +0.008727 +0.008787 +0.008881 +0.008935 +0.008997 +0.008845 +0.008769 +0.008826 +0.008898 +0.008986 +0.009039 +0.008909 +0.008825 +0.008909 +0.008951 +0.009035 +0.009073 +0.00893 +0.008873 +0.008905 +0.008987 +0.009089 +0.009148 +0.008971 +0.008898 +0.008972 +0.009046 +0.009143 +0.009184 +0.009034 +0.008956 +0.009009 +0.009097 +0.00917 +0.009242 +0.009094 +0.00902 +0.009072 +0.009137 +0.009237 +0.00929 +0.00916 +0.009038 +0.009086 +0.009177 +0.009268 +0.009335 +0.009178 +0.009105 +0.009169 +0.009236 +0.009332 +0.009369 +0.009217 +0.009141 +0.009197 +0.009285 +0.009377 +0.009429 +0.009282 +0.009191 +0.009255 +0.009328 +0.009425 +0.009485 +0.00932 +0.009248 +0.009317 +0.009404 +0.009481 +0.009538 +0.009366 +0.009283 +0.009341 +0.009423 +0.009518 +0.00958 +0.009418 +0.009335 +0.009412 +0.009498 +0.009581 +0.009629 +0.009466 +0.009384 +0.009443 +0.009531 +0.009622 +0.00968 +0.009543 +0.009452 +0.009501 +0.009593 +0.009681 +0.009756 +0.009555 +0.009476 +0.009535 +0.009619 +0.009726 +0.009789 +0.009624 +0.009553 +0.009599 +0.00968 +0.009771 +0.009827 +0.009666 +0.009611 +0.00963 +0.009721 +0.00982 +0.009892 +0.009719 +0.009638 +0.009701 +0.009784 +0.009881 +0.00995 +0.009783 +0.009707 +0.009749 +0.009811 +0.009921 +0.009998 +0.009824 +0.009753 +0.009793 +0.009881 +0.009969 +0.010049 +0.009895 +0.009784 +0.009834 +0.009941 +0.010026 +0.010098 +0.009935 +0.009839 +0.009892 +0.010013 +0.01011 +0.010156 +0.009986 +0.009896 +0.009976 +0.010024 +0.010122 +0.01019 +0.010024 +0.009939 +0.010018 +0.010106 +0.010227 +0.010272 +0.010055 +0.009984 +0.010043 +0.010138 +0.010252 +0.010305 +0.010129 +0.010061 +0.010104 +0.010199 +0.010311 +0.010361 +0.010186 +0.010097 +0.010186 +0.010277 +0.010389 +0.010391 +0.010225 +0.010165 +0.010202 +0.010298 +0.010417 +0.010471 +0.010294 +0.010237 +0.010288 +0.010347 +0.010464 +0.010522 +0.010343 +0.010272 +0.010315 +0.010409 +0.01055 +0.010596 +0.010411 +0.010329 +0.010384 +0.01049 +0.010556 +0.010618 +0.010446 +0.010371 +0.010429 +0.010543 +0.010653 +0.010698 +0.010502 +0.010418 +0.010474 +0.010584 +0.01066 +0.010721 +0.0105 +0.010399 +0.010418 +0.010463 +0.010505 +0.010534 +0.010309 +0.010159 +0.010178 +0.010217 +0.010312 +0.010274 +0.010006 +0.009877 +0.009913 +0.00991 +0.009939 +0.00996 +0.009744 +0.009616 +0.009628 +0.009664 +0.009671 +0.009682 +0.009469 +0.009353 +0.009345 +0.009372 +0.009413 +0.009425 +0.009218 +0.009104 +0.009103 +0.009142 +0.009178 +0.009202 +0.009027 +0.008896 +0.008906 +0.008938 +0.008992 +0.009024 +0.00883 +0.008747 +0.008741 +0.008793 +0.008829 +0.008864 +0.008687 +0.008587 +0.008607 +0.008651 +0.008724 +0.008748 +0.008559 +0.008465 +0.008502 +0.008554 +0.008598 +0.008647 +0.008493 +0.008404 +0.00845 +0.008519 +0.008592 +0.008689 +0.008509 +0.008429 +0.008473 +0.008551 +0.008633 +0.008687 +0.008542 +0.008462 +0.008544 +0.008604 +0.008688 +0.008746 +0.008598 +0.00851 +0.008558 +0.008646 +0.00872 +0.008777 +0.008636 +0.008572 +0.008602 +0.00869 +0.008784 +0.008844 +0.008713 +0.00861 +0.008657 +0.008725 +0.008837 +0.008864 +0.008716 +0.008646 +0.008696 +0.008791 +0.008868 +0.008927 +0.008776 +0.008708 +0.008743 +0.008828 +0.008921 +0.008953 +0.008807 +0.008747 +0.008813 +0.00886 +0.00895 +0.009014 +0.008861 +0.00879 +0.008835 +0.008915 +0.008998 +0.009062 +0.008912 +0.008838 +0.008927 +0.008969 +0.009038 +0.0091 +0.008955 +0.008876 +0.008926 +0.008997 +0.009103 +0.009154 +0.00901 +0.008941 +0.00899 +0.009056 +0.00914 +0.009209 +0.00904 +0.008966 +0.009025 +0.009106 +0.009189 +0.00925 +0.009101 +0.009023 +0.009079 +0.009148 +0.009233 +0.009294 +0.009144 +0.00907 +0.009147 +0.009231 +0.009288 +0.009334 +0.009178 +0.009106 +0.009157 +0.009241 +0.00933 +0.009398 +0.009237 +0.009168 +0.009238 +0.009314 +0.009388 +0.009429 +0.009273 +0.009195 +0.009254 +0.009345 +0.009426 +0.009504 +0.009358 +0.009267 +0.009317 +0.009398 +0.009492 +0.009559 +0.009378 +0.009285 +0.009347 +0.009437 +0.009561 +0.009574 +0.00942 +0.009348 +0.009403 +0.00948 +0.009575 +0.009649 +0.009482 +0.009408 +0.009475 +0.009543 +0.009638 +0.009687 +0.009525 +0.009441 +0.009504 +0.009589 +0.009673 +0.009761 +0.009595 +0.009529 +0.009581 +0.009643 +0.009715 +0.009774 +0.009624 +0.009544 +0.009615 +0.009707 +0.009765 +0.009833 +0.009672 +0.009594 +0.009653 +0.009732 +0.009846 +0.009897 +0.009744 +0.009666 +0.009708 +0.009775 +0.009882 +0.009947 +0.009774 +0.009692 +0.009756 +0.00988 +0.009968 +0.010004 +0.009827 +0.009751 +0.009797 +0.00988 +0.009982 +0.01006 +0.009904 +0.009785 +0.009854 +0.009928 +0.010026 +0.010116 +0.009936 +0.009846 +0.009912 +0.010002 +0.010096 +0.010184 +0.009996 +0.00988 +0.009954 +0.010057 +0.010193 +0.010225 +0.010042 +0.009933 +0.01 +0.010107 +0.01021 +0.010253 +0.010087 +0.009998 +0.010059 +0.01017 +0.010266 +0.010298 +0.01015 +0.010065 +0.010125 +0.010227 +0.010296 +0.010364 +0.0102 +0.010101 +0.010163 +0.010255 +0.01039 +0.01048 +0.010247 +0.010153 +0.010233 +0.010309 +0.0104 +0.010464 +0.010291 +0.010227 +0.010264 +0.010364 +0.010478 +0.010532 +0.010353 +0.010267 +0.010326 +0.010421 +0.010546 +0.010603 +0.010417 +0.010307 +0.010378 +0.010465 +0.01056 +0.010654 +0.010397 +0.010291 +0.010321 +0.010367 +0.01046 +0.010442 +0.010212 +0.010084 +0.010099 +0.010124 +0.010183 +0.010172 +0.009955 +0.009831 +0.009823 +0.009852 +0.009895 +0.009917 +0.009689 +0.009569 +0.009568 +0.009601 +0.009629 +0.009654 +0.009467 +0.009307 +0.009308 +0.009332 +0.009378 +0.009413 +0.009205 +0.009084 +0.009119 +0.009109 +0.009143 +0.009169 +0.008988 +0.008868 +0.008882 +0.008926 +0.008977 +0.009011 +0.00885 +0.008737 +0.008751 +0.008786 +0.008834 +0.008867 +0.008695 +0.008593 +0.008626 +0.008673 +0.008751 +0.008764 +0.008591 +0.008496 +0.008527 +0.008585 +0.008623 +0.008665 +0.008518 +0.00844 +0.008476 +0.008562 +0.008606 +0.008655 +0.008521 +0.008454 +0.00851 +0.008569 +0.008653 +0.008709 +0.008573 +0.008497 +0.008547 +0.008622 +0.00871 +0.008756 +0.00861 +0.008545 +0.0086 +0.00869 +0.008745 +0.008789 +0.008669 +0.008576 +0.008633 +0.008718 +0.008798 +0.008862 +0.008696 +0.008643 +0.008674 +0.008746 +0.00884 +0.008886 +0.008736 +0.008671 +0.008723 +0.008801 +0.008896 +0.008952 +0.008788 +0.008712 +0.008775 +0.008837 +0.008925 +0.008991 +0.008851 +0.008779 +0.00883 +0.008883 +0.008973 +0.009029 +0.008883 +0.008816 +0.008854 +0.008931 +0.009027 +0.009076 +0.008935 +0.00885 +0.008908 +0.008982 +0.009071 +0.009142 +0.008972 +0.008892 +0.008954 +0.009031 +0.009114 +0.009189 +0.009041 +0.008938 +0.008998 +0.009081 +0.009168 +0.009261 +0.009075 +0.00898 +0.009036 +0.009118 +0.009219 +0.009293 +0.009133 +0.009034 +0.009088 +0.009164 +0.009261 +0.009327 +0.00916 +0.00908 +0.00914 +0.009229 +0.009315 +0.009384 +0.009223 +0.009118 +0.009181 +0.00927 +0.009357 +0.009421 +0.009265 +0.009196 +0.009277 +0.009342 +0.009407 +0.009459 +0.0093 +0.009215 +0.009269 +0.009361 +0.009454 +0.009541 +0.009372 +0.009266 +0.009331 +0.009404 +0.0095 +0.009573 +0.009393 +0.009321 +0.00938 +0.009487 +0.009569 +0.009629 +0.009453 +0.009365 +0.009424 +0.009517 +0.009614 +0.009697 +0.009492 +0.009441 +0.009474 +0.009569 +0.009673 +0.009712 +0.009538 +0.009471 +0.009528 +0.009606 +0.009712 +0.009775 +0.009595 +0.009516 +0.009576 +0.009655 +0.00976 +0.009824 +0.009653 +0.009578 +0.009644 +0.009729 +0.009811 +0.009869 +0.009713 +0.009646 +0.009674 +0.00975 +0.009852 +0.009939 +0.00976 +0.009679 +0.00974 +0.009829 +0.009896 +0.009965 +0.009806 +0.00971 +0.009779 +0.009867 +0.009992 +0.010037 +0.009865 +0.009779 +0.009837 +0.009909 +0.010009 +0.010079 +0.009901 +0.009837 +0.009916 +0.009971 +0.010054 +0.010119 +0.009953 +0.009882 +0.009951 +0.010013 +0.010134 +0.010205 +0.010014 +0.009921 +0.009962 +0.010068 +0.010177 +0.01024 +0.010061 +0.009973 +0.010043 +0.01013 +0.010236 +0.010298 +0.010115 +0.010027 +0.010091 +0.010226 +0.010284 +0.010352 +0.010177 +0.010072 +0.010142 +0.010221 +0.010341 +0.010415 +0.010204 +0.010132 +0.010214 +0.010303 +0.010403 +0.010464 +0.010252 +0.010183 +0.010247 +0.010336 +0.010441 +0.010528 +0.010346 +0.010248 +0.010316 +0.010438 +0.010498 +0.010534 +0.010362 +0.010288 +0.01037 +0.01045 +0.010544 +0.010616 +0.010437 +0.010359 +0.01041 +0.01049 +0.010608 +0.010674 +0.010476 +0.010365 +0.010406 +0.010477 +0.010534 +0.010557 +0.01033 +0.0102 +0.010256 +0.010323 +0.010365 +0.010322 +0.010142 +0.009964 +0.009992 +0.010028 +0.010064 +0.010083 +0.009851 +0.00971 +0.009726 +0.009753 +0.009782 +0.00979 +0.009557 +0.009437 +0.009463 +0.009512 +0.009541 +0.009542 +0.009341 +0.00919 +0.009217 +0.009264 +0.009295 +0.009334 +0.009099 +0.008978 +0.009016 +0.009068 +0.009133 +0.009112 +0.008918 +0.008803 +0.008844 +0.008883 +0.008932 +0.008966 +0.008773 +0.008678 +0.008732 +0.008775 +0.008811 +0.008836 +0.008666 +0.008559 +0.008595 +0.008638 +0.008703 +0.008724 +0.008572 +0.00849 +0.008534 +0.00861 +0.008657 +0.008681 +0.008527 +0.008467 +0.008517 +0.008606 +0.008674 +0.008755 +0.008596 +0.008516 +0.008568 +0.008643 +0.00872 +0.008769 +0.008627 +0.008553 +0.008612 +0.008689 +0.008769 +0.00883 +0.008684 +0.008609 +0.008661 +0.008744 +0.008814 +0.008859 +0.008718 +0.008649 +0.008726 +0.008783 +0.008855 +0.008924 +0.008764 +0.008685 +0.008742 +0.008816 +0.008898 +0.008966 +0.008838 +0.008729 +0.008783 +0.008875 +0.008958 +0.009015 +0.008859 +0.008776 +0.008829 +0.00891 +0.009 +0.009043 +0.008896 +0.00883 +0.008878 +0.008963 +0.009048 +0.009114 +0.008984 +0.00889 +0.008938 +0.008989 +0.009084 +0.009148 +0.008994 +0.008917 +0.008972 +0.009059 +0.009136 +0.009203 +0.009052 +0.00897 +0.009013 +0.009097 +0.009192 +0.009243 +0.009101 +0.00903 +0.009067 +0.00914 +0.009236 +0.0093 +0.009135 +0.009058 +0.009112 +0.009205 +0.009324 +0.009355 +0.009191 +0.009108 +0.009168 +0.009231 +0.009323 +0.009379 +0.009232 +0.009141 +0.009207 +0.009303 +0.009402 +0.009454 +0.00929 +0.009214 +0.009247 +0.009323 +0.009423 +0.009485 +0.00933 +0.009256 +0.009306 +0.009394 +0.009478 +0.009548 +0.009393 +0.009313 +0.009345 +0.009425 +0.009525 +0.009601 +0.009438 +0.009365 +0.009395 +0.009486 +0.009567 +0.009634 +0.009477 +0.009379 +0.009455 +0.009554 +0.009648 +0.009699 +0.00953 +0.009438 +0.009502 +0.009578 +0.009683 +0.009732 +0.009576 +0.009493 +0.009551 +0.009672 +0.009737 +0.009786 +0.009612 +0.009537 +0.009604 +0.00968 +0.009797 +0.00989 +0.009654 +0.009582 +0.009652 +0.009728 +0.009828 +0.009895 +0.009723 +0.009647 +0.009727 +0.009808 +0.009888 +0.009938 +0.009781 +0.009679 +0.009738 +0.009847 +0.009956 +0.010042 +0.009828 +0.009746 +0.009809 +0.009903 +0.009979 +0.010035 +0.009875 +0.009788 +0.009869 +0.009964 +0.01003 +0.010095 +0.009919 +0.009849 +0.009905 +0.009983 +0.010099 +0.01016 +0.01 +0.00992 +0.009965 +0.010028 +0.010152 +0.010226 +0.010065 +0.00993 +0.009995 +0.010095 +0.010219 +0.010266 +0.010093 +0.010004 +0.010037 +0.010143 +0.010248 +0.01034 +0.010131 +0.010043 +0.010113 +0.010202 +0.010307 +0.010374 +0.010186 +0.010105 +0.010178 +0.010246 +0.010382 +0.010451 +0.010274 +0.010163 +0.010202 +0.010299 +0.010404 +0.010497 +0.010285 +0.010222 +0.010292 +0.010371 +0.010458 +0.01053 +0.010341 +0.010262 +0.010332 +0.010408 +0.010544 +0.010613 +0.010412 +0.010323 +0.010393 +0.01045 +0.010562 +0.010649 +0.010498 +0.010397 +0.010419 +0.010508 +0.010603 +0.010678 +0.010487 +0.010388 +0.010417 +0.010475 +0.010533 +0.010576 +0.01037 +0.010211 +0.010239 +0.010286 +0.010322 +0.010319 +0.010094 +0.009962 +0.009973 +0.010009 +0.010061 +0.010058 +0.009846 +0.009729 +0.009725 +0.00974 +0.009779 +0.009795 +0.009595 +0.009459 +0.009473 +0.009529 +0.00958 +0.009559 +0.009351 +0.009217 +0.00923 +0.009266 +0.009318 +0.009325 +0.009135 +0.009033 +0.009056 +0.009091 +0.009131 +0.009164 +0.008965 +0.008842 +0.008884 +0.008919 +0.008999 +0.00902 +0.008813 +0.008697 +0.00873 +0.008779 +0.008826 +0.008857 +0.008693 +0.008598 +0.008634 +0.008684 +0.008739 +0.008788 +0.008635 +0.008547 +0.00859 +0.00865 +0.008723 +0.008793 +0.008654 +0.008571 +0.00862 +0.008696 +0.008777 +0.00885 +0.008699 +0.00862 +0.008677 +0.008771 +0.008805 +0.00887 +0.008748 +0.008649 +0.008709 +0.00878 +0.008861 +0.008926 +0.008785 +0.008699 +0.008758 +0.008838 +0.008918 +0.008996 +0.008817 +0.00875 +0.008794 +0.008871 +0.008967 +0.009017 +0.008868 +0.008795 +0.00885 +0.00892 +0.009014 +0.009076 +0.008924 +0.008876 +0.008897 +0.00897 +0.009058 +0.009102 +0.008963 +0.008908 +0.008931 +0.009006 +0.009105 +0.009155 +0.009008 +0.008938 +0.008979 +0.009077 +0.009164 +0.009211 +0.009055 +0.008975 +0.009036 +0.009103 +0.009198 +0.009256 +0.009107 +0.009038 +0.009098 +0.009173 +0.009269 +0.009325 +0.009128 +0.009059 +0.009118 +0.009198 +0.0093 +0.009355 +0.009213 +0.009121 +0.009164 +0.009246 +0.009345 +0.009409 +0.009249 +0.009161 +0.009229 +0.009299 +0.009399 +0.009466 +0.009294 +0.009213 +0.009266 +0.009356 +0.009448 +0.009495 +0.009356 +0.009284 +0.009343 +0.009406 +0.009493 +0.009537 +0.009378 +0.009308 +0.009361 +0.009445 +0.009548 +0.009616 +0.009433 +0.009366 +0.009414 +0.009517 +0.0096 +0.009645 +0.009483 +0.0094 +0.009471 +0.009541 +0.009634 +0.009716 +0.009554 +0.00947 +0.009524 +0.009613 +0.009724 +0.009723 +0.009593 +0.00949 +0.00955 +0.009652 +0.00973 +0.009808 +0.009663 +0.009563 +0.00962 +0.009704 +0.009778 +0.009845 +0.009682 +0.009602 +0.009662 +0.009749 +0.009875 +0.009916 +0.009747 +0.009669 +0.009713 +0.009782 +0.009893 +0.00997 +0.009817 +0.009707 +0.009749 +0.009842 +0.009968 +0.009999 +0.009827 +0.009748 +0.009808 +0.009898 +0.010001 +0.010071 +0.009896 +0.009805 +0.009871 +0.009945 +0.01005 +0.010124 +0.009937 +0.009853 +0.009934 +0.010012 +0.010129 +0.010185 +0.010002 +0.009929 +0.009939 +0.010044 +0.010141 +0.010217 +0.010044 +0.009988 +0.010014 +0.010133 +0.010219 +0.010259 +0.010096 +0.010001 +0.010067 +0.010164 +0.010258 +0.010331 +0.010177 +0.010075 +0.010132 +0.010242 +0.010305 +0.010369 +0.010203 +0.010129 +0.01019 +0.01025 +0.010366 +0.010426 +0.010277 +0.010171 +0.01024 +0.010348 +0.010409 +0.010473 +0.010309 +0.01021 +0.010272 +0.010401 +0.010492 +0.010553 +0.010378 +0.010271 +0.010315 +0.010433 +0.010525 +0.010594 +0.010438 +0.01034 +0.010425 +0.010487 +0.010554 +0.010642 +0.010463 +0.010383 +0.010437 +0.010546 +0.010648 +0.010719 +0.010525 +0.010429 +0.010493 +0.010592 +0.010664 +0.010731 +0.010548 +0.010436 +0.010484 +0.010541 +0.010573 +0.010587 +0.010382 +0.010281 +0.010295 +0.010291 +0.010387 +0.010351 +0.010149 +0.009994 +0.009997 +0.010031 +0.010071 +0.010076 +0.009866 +0.009728 +0.009725 +0.009783 +0.009819 +0.009828 +0.009606 +0.009479 +0.009461 +0.009503 +0.009549 +0.009558 +0.009342 +0.009221 +0.009232 +0.009312 +0.009305 +0.009312 +0.009115 +0.008997 +0.009035 +0.009031 +0.00909 +0.009119 +0.008934 +0.00884 +0.00886 +0.008896 +0.008948 +0.008973 +0.008805 +0.008699 +0.008721 +0.00876 +0.00883 +0.008858 +0.008703 +0.008597 +0.008626 +0.008669 +0.008713 +0.008766 +0.008597 +0.008533 +0.008556 +0.008608 +0.008669 +0.008737 +0.008607 +0.008528 +0.008575 +0.008675 +0.008719 +0.008769 +0.008628 +0.008554 +0.008617 +0.008678 +0.008766 +0.008842 +0.008693 +0.008614 +0.008664 +0.008746 +0.008821 +0.008856 +0.008718 +0.008651 +0.008703 +0.008774 +0.008882 +0.00893 +0.008793 +0.008689 +0.008741 +0.008835 +0.008893 +0.008956 +0.008801 +0.008736 +0.008794 +0.008871 +0.008993 +0.009017 +0.008872 +0.008777 +0.008833 +0.008909 +0.009 +0.009058 +0.008908 +0.008833 +0.008893 +0.008957 +0.009053 +0.009129 +0.008966 +0.008874 +0.008931 +0.00901 +0.00913 +0.009144 +0.009016 +0.008904 +0.008968 +0.009075 +0.009148 +0.009207 +0.009054 +0.008971 +0.009002 +0.009095 +0.009197 +0.009242 +0.009092 +0.009016 +0.009071 +0.009167 +0.009254 +0.009321 +0.009144 +0.00906 +0.009117 +0.009199 +0.009276 +0.009343 +0.009185 +0.009141 +0.009179 +0.009243 +0.009325 +0.009399 +0.00925 +0.009141 +0.009197 +0.00929 +0.009388 +0.009456 +0.009296 +0.00922 +0.009255 +0.00935 +0.009438 +0.009494 +0.009331 +0.009251 +0.009312 +0.009384 +0.009482 +0.009567 +0.009394 +0.009304 +0.009349 +0.009446 +0.009574 +0.009593 +0.009415 +0.009337 +0.009407 +0.009496 +0.009612 +0.009648 +0.009479 +0.009383 +0.009449 +0.009544 +0.009628 +0.009691 +0.009539 +0.009437 +0.009497 +0.009589 +0.009675 +0.009743 +0.009576 +0.0095 +0.009561 +0.009642 +0.009751 +0.009813 +0.009623 +0.009545 +0.009617 +0.009711 +0.00977 +0.009831 +0.009653 +0.009598 +0.009685 +0.009757 +0.009843 +0.009903 +0.009713 +0.009631 +0.009703 +0.009785 +0.009882 +0.009967 +0.009766 +0.00969 +0.009756 +0.009844 +0.009933 +0.01 +0.009828 +0.009745 +0.009816 +0.009915 +0.010043 +0.010032 +0.009863 +0.009786 +0.009836 +0.009944 +0.010028 +0.010101 +0.00997 +0.009856 +0.00991 +0.010015 +0.010074 +0.010145 +0.009987 +0.009894 +0.009946 +0.010045 +0.010152 +0.01022 +0.010045 +0.009957 +0.010014 +0.010097 +0.01019 +0.010294 +0.010094 +0.009993 +0.010047 +0.010135 +0.010232 +0.010306 +0.01014 +0.010062 +0.010103 +0.010206 +0.010321 +0.010387 +0.010208 +0.010098 +0.010161 +0.010243 +0.010366 +0.010413 +0.010237 +0.010172 +0.010234 +0.010335 +0.010433 +0.010502 +0.010294 +0.010192 +0.010282 +0.010344 +0.010471 +0.010517 +0.010343 +0.010265 +0.010328 +0.010413 +0.010524 +0.010586 +0.010408 +0.010327 +0.010404 +0.010474 +0.010578 +0.010632 +0.010456 +0.010381 +0.010426 +0.010518 +0.010651 +0.010749 +0.010542 +0.010424 +0.010468 +0.010558 +0.010696 +0.010691 +0.010508 +0.010412 +0.010452 +0.010489 +0.010558 +0.010592 +0.010336 +0.010197 +0.010223 +0.010237 +0.010297 +0.0103 +0.010064 +0.009943 +0.009937 +0.009977 +0.01002 +0.010024 +0.009828 +0.009657 +0.009672 +0.009712 +0.009744 +0.009733 +0.009538 +0.00942 +0.009414 +0.009435 +0.00947 +0.009503 +0.009306 +0.009183 +0.009192 +0.009228 +0.009261 +0.009261 +0.009084 +0.008964 +0.008988 +0.00903 +0.009079 +0.009094 +0.008928 +0.00882 +0.008859 +0.008895 +0.008922 +0.008945 +0.008783 +0.008679 +0.008716 +0.008737 +0.0088 +0.00884 +0.008686 +0.008571 +0.008595 +0.008648 +0.008699 +0.008732 +0.008578 +0.008494 +0.008531 +0.008585 +0.00866 +0.008716 +0.008548 +0.008478 +0.008535 +0.008591 +0.008688 +0.008747 +0.008594 +0.008542 +0.008594 +0.008673 +0.008726 +0.008783 +0.008621 +0.008566 +0.008608 +0.00869 +0.008774 +0.00883 +0.008678 +0.008621 +0.008675 +0.008749 +0.008827 +0.008886 +0.008736 +0.008651 +0.008702 +0.008784 +0.008865 +0.008935 +0.00879 +0.008693 +0.008749 +0.00882 +0.008912 +0.008972 +0.008848 +0.008738 +0.008795 +0.008865 +0.00898 +0.009017 +0.008869 +0.008787 +0.008843 +0.008914 +0.009 +0.009071 +0.008922 +0.00884 +0.008894 +0.008956 +0.00907 +0.009133 +0.008966 +0.008899 +0.008941 +0.009004 +0.009096 +0.009164 +0.009003 +0.008933 +0.008985 +0.009072 +0.009172 +0.009203 +0.009038 +0.008966 +0.009031 +0.009109 +0.009222 +0.009253 +0.009101 +0.009033 +0.009082 +0.009147 +0.009251 +0.009304 +0.009142 +0.009071 +0.009126 +0.009195 +0.009296 +0.00937 +0.009206 +0.009127 +0.009184 +0.009238 +0.009337 +0.009408 +0.009246 +0.009194 +0.009221 +0.009287 +0.009392 +0.009458 +0.009306 +0.009214 +0.00926 +0.009339 +0.009437 +0.009495 +0.009341 +0.009263 +0.009318 +0.009401 +0.009495 +0.009547 +0.009391 +0.009328 +0.009357 +0.009432 +0.009533 +0.009611 +0.009433 +0.009374 +0.009435 +0.00951 +0.009633 +0.009638 +0.009466 +0.009391 +0.009451 +0.009537 +0.00964 +0.009713 +0.009551 +0.009462 +0.00952 +0.00959 +0.009692 +0.009743 +0.009581 +0.009499 +0.00955 +0.00966 +0.009759 +0.009816 +0.009637 +0.009568 +0.009595 +0.0097 +0.009795 +0.00986 +0.009714 +0.009603 +0.009651 +0.00974 +0.00983 +0.009898 +0.009719 +0.009641 +0.00972 +0.009805 +0.009897 +0.009977 +0.009809 +0.009688 +0.009763 +0.00984 +0.009943 +0.010015 +0.009826 +0.00975 +0.009815 +0.009914 +0.010017 +0.010079 +0.00988 +0.00983 +0.009861 +0.009945 +0.010038 +0.010102 +0.009974 +0.009856 +0.00992 +0.010016 +0.010103 +0.010145 +0.009989 +0.009907 +0.00996 +0.010062 +0.010153 +0.010212 +0.010045 +0.009951 +0.010012 +0.010099 +0.010206 +0.010277 +0.010106 +0.010032 +0.010127 +0.010144 +0.010248 +0.010312 +0.010142 +0.010057 +0.010116 +0.010229 +0.010312 +0.01038 +0.01021 +0.010131 +0.010158 +0.010261 +0.010369 +0.010442 +0.010248 +0.010167 +0.010238 +0.010333 +0.010439 +0.010487 +0.0103 +0.01021 +0.0103 +0.010379 +0.010469 +0.010534 +0.010339 +0.010269 +0.010322 +0.010423 +0.010539 +0.010584 +0.010413 +0.010336 +0.010402 +0.010495 +0.010583 +0.010638 +0.010458 +0.010407 +0.010446 +0.010513 +0.01064 +0.010691 +0.010509 +0.010399 +0.01046 +0.010479 +0.010556 +0.010525 +0.010324 +0.01021 +0.010236 +0.010288 +0.010335 +0.010317 +0.010107 +0.009966 +0.009975 +0.010012 +0.010034 +0.010047 +0.009836 +0.009688 +0.009703 +0.009732 +0.009768 +0.009774 +0.009547 +0.00944 +0.009431 +0.009462 +0.009523 +0.009529 +0.009323 +0.009196 +0.009185 +0.009219 +0.009258 +0.009285 +0.009084 +0.008978 +0.009008 +0.009043 +0.009095 +0.009114 +0.008914 +0.008805 +0.008836 +0.008884 +0.00892 +0.00895 +0.008767 +0.008686 +0.00871 +0.008762 +0.008817 +0.008835 +0.008654 +0.008556 +0.008597 +0.008648 +0.008721 +0.008726 +0.008568 +0.008487 +0.008546 +0.008608 +0.008664 +0.008717 +0.008572 +0.008496 +0.008547 +0.00861 +0.008701 +0.008765 +0.008617 +0.008535 +0.008612 +0.008677 +0.008757 +0.008816 +0.008669 +0.008587 +0.008629 +0.008718 +0.008793 +0.008846 +0.008703 +0.008648 +0.008694 +0.008782 +0.008831 +0.008892 +0.008759 +0.008666 +0.00873 +0.008791 +0.008879 +0.008948 +0.008796 +0.008732 +0.008773 +0.008844 +0.008926 +0.008991 +0.008842 +0.008802 +0.008804 +0.008885 +0.008982 +0.009038 +0.008901 +0.008824 +0.008882 +0.008925 +0.00902 +0.009097 +0.008937 +0.008876 +0.008905 +0.008976 +0.009073 +0.009131 +0.009 +0.008913 +0.008959 +0.009044 +0.009111 +0.009157 +0.009021 +0.008953 +0.008998 +0.009076 +0.009185 +0.009248 +0.009086 +0.009006 +0.009064 +0.009114 +0.009206 +0.009285 +0.009111 +0.009038 +0.009091 +0.009175 +0.009304 +0.009362 +0.009167 +0.009089 +0.009145 +0.009217 +0.009313 +0.009371 +0.00921 +0.009137 +0.009193 +0.009261 +0.009361 +0.009421 +0.00926 +0.009182 +0.009242 +0.00932 +0.009418 +0.009489 +0.009315 +0.00923 +0.009303 +0.009358 +0.009456 +0.009523 +0.009366 +0.00931 +0.009343 +0.009426 +0.009528 +0.009564 +0.00942 +0.009331 +0.00937 +0.009456 +0.00956 +0.009608 +0.00945 +0.009394 +0.009429 +0.009531 +0.00962 +0.009678 +0.009523 +0.00943 +0.009468 +0.009559 +0.009659 +0.009733 +0.009557 +0.009467 +0.009553 +0.009646 +0.009754 +0.009772 +0.009597 +0.009509 +0.009594 +0.009655 +0.009752 +0.009818 +0.009658 +0.009571 +0.009636 +0.009743 +0.009832 +0.009884 +0.009703 +0.009602 +0.009675 +0.009768 +0.00986 +0.00993 +0.009772 +0.009693 +0.009746 +0.009828 +0.009928 +0.009997 +0.009798 +0.009711 +0.009775 +0.009858 +0.009989 +0.010027 +0.009871 +0.009772 +0.009816 +0.00992 +0.010021 +0.010082 +0.009915 +0.009828 +0.00989 +0.009996 +0.01006 +0.010141 +0.009952 +0.009879 +0.009953 +0.010025 +0.010128 +0.010203 +0.010057 +0.009951 +0.009993 +0.010064 +0.010163 +0.010239 +0.010065 +0.009979 +0.010042 +0.010149 +0.010225 +0.010315 +0.010126 +0.010036 +0.010082 +0.010179 +0.010282 +0.010355 +0.010176 +0.010077 +0.010157 +0.010238 +0.010357 +0.010422 +0.010235 +0.010165 +0.010214 +0.010273 +0.010376 +0.010447 +0.010269 +0.010183 +0.010257 +0.010362 +0.010464 +0.010518 +0.010324 +0.010235 +0.010301 +0.010398 +0.0105 +0.010575 +0.010385 +0.010293 +0.010364 +0.010465 +0.01056 +0.010612 +0.010446 +0.010387 +0.010423 +0.010529 +0.010614 +0.010639 +0.010458 +0.010361 +0.010406 +0.01047 +0.010514 +0.010539 +0.010336 +0.010227 +0.010237 +0.010251 +0.010301 +0.010295 +0.010075 +0.009942 +0.009954 +0.010007 +0.010036 +0.010044 +0.009831 +0.009711 +0.009713 +0.009719 +0.009748 +0.009754 +0.009553 +0.009444 +0.009434 +0.009479 +0.009522 +0.009519 +0.009313 +0.009188 +0.00919 +0.009235 +0.009275 +0.009283 +0.009088 +0.008972 +0.009024 +0.009051 +0.009088 +0.009123 +0.008918 +0.008806 +0.008844 +0.008892 +0.008948 +0.00897 +0.008786 +0.008688 +0.008706 +0.008753 +0.008804 +0.008824 +0.008658 +0.008579 +0.008595 +0.008644 +0.008695 +0.008735 +0.008571 +0.008487 +0.008536 +0.008589 +0.008648 +0.008715 +0.008554 +0.008474 +0.008535 +0.008598 +0.008696 +0.008742 +0.0086 +0.008527 +0.008581 +0.008675 +0.008742 +0.008776 +0.008625 +0.008557 +0.008613 +0.008697 +0.008767 +0.008834 +0.008686 +0.00861 +0.008684 +0.008745 +0.008821 +0.008869 +0.008727 +0.008646 +0.008706 +0.008805 +0.008854 +0.00893 +0.008773 +0.008712 +0.008763 +0.008839 +0.008906 +0.008958 +0.008823 +0.00875 +0.008826 +0.008859 +0.008967 +0.009022 +0.008854 +0.00879 +0.008834 +0.008913 +0.008998 +0.00907 +0.00891 +0.008836 +0.008894 +0.008961 +0.00905 +0.009118 +0.008961 +0.008878 +0.008932 +0.009019 +0.009093 +0.00916 +0.009005 +0.008929 +0.008979 +0.009056 +0.00917 +0.009235 +0.009068 +0.008961 +0.00902 +0.009097 +0.009202 +0.009261 +0.009082 +0.009016 +0.009077 +0.009149 +0.009252 +0.009315 +0.009138 +0.009067 +0.009117 +0.009193 +0.009277 +0.009352 +0.009192 +0.00912 +0.009182 +0.009259 +0.009363 +0.009399 +0.009229 +0.009159 +0.009213 +0.009325 +0.009378 +0.009439 +0.009273 +0.009207 +0.009288 +0.009352 +0.009469 +0.009492 +0.009317 +0.009239 +0.009303 +0.009395 +0.009481 +0.009542 +0.009412 +0.009326 +0.009368 +0.009458 +0.009538 +0.009578 +0.009427 +0.009349 +0.009398 +0.009491 +0.009607 +0.009666 +0.009495 +0.009393 +0.009445 +0.009531 +0.009624 +0.009694 +0.009529 +0.009446 +0.009543 +0.009597 +0.009684 +0.00975 +0.009571 +0.009499 +0.009554 +0.009626 +0.009719 +0.009805 +0.009636 +0.009567 +0.009628 +0.00972 +0.009782 +0.009838 +0.009682 +0.009613 +0.009663 +0.009758 +0.009825 +0.009876 +0.009729 +0.009643 +0.009706 +0.009794 +0.009886 +0.009949 +0.009787 +0.0097 +0.009749 +0.009845 +0.009949 +0.010002 +0.009835 +0.009756 +0.009798 +0.00989 +0.010011 +0.010055 +0.009884 +0.00982 +0.009877 +0.009976 +0.010034 +0.010094 +0.009951 +0.009836 +0.009903 +0.009989 +0.010095 +0.010169 +0.009993 +0.009914 +0.009956 +0.01004 +0.01014 +0.010218 +0.010021 +0.009949 +0.010031 +0.010107 +0.010228 +0.010297 +0.010096 +0.009984 +0.010059 +0.010163 +0.010291 +0.010305 +0.010118 +0.010068 +0.010134 +0.010248 +0.010306 +0.010363 +0.010176 +0.010097 +0.010163 +0.010264 +0.010382 +0.010419 +0.010251 +0.010155 +0.010219 +0.010317 +0.010408 +0.010493 +0.010311 +0.010229 +0.0103 +0.01039 +0.010499 +0.010523 +0.010336 +0.010252 +0.010319 +0.010419 +0.010525 +0.010631 +0.010422 +0.010327 +0.010369 +0.010466 +0.010554 +0.010618 +0.01043 +0.010306 +0.01037 +0.01043 +0.010493 +0.010539 +0.010309 +0.010171 +0.010185 +0.010212 +0.010272 +0.010295 +0.010092 +0.009894 +0.009912 +0.009945 +0.009988 +0.009999 +0.009774 +0.009665 +0.009676 +0.009701 +0.009737 +0.009758 +0.009516 +0.009403 +0.009424 +0.009438 +0.00949 +0.009512 +0.009307 +0.009198 +0.009203 +0.009263 +0.009283 +0.009298 +0.009106 +0.009001 +0.009044 +0.009064 +0.009084 +0.009111 +0.008939 +0.008858 +0.008875 +0.008912 +0.008962 +0.008991 +0.008796 +0.008707 +0.00874 +0.008772 +0.008827 +0.008859 +0.008692 +0.008592 +0.008634 +0.008688 +0.008735 +0.008782 +0.0086 +0.008528 +0.008561 +0.008617 +0.008688 +0.00875 +0.008626 +0.008543 +0.008579 +0.008651 +0.00874 +0.008781 +0.008649 +0.008562 +0.008623 +0.008701 +0.008781 +0.008845 +0.008689 +0.008622 +0.00867 +0.008741 +0.008828 +0.008888 +0.008735 +0.008658 +0.008722 +0.00879 +0.008879 +0.008945 +0.008802 +0.008732 +0.008746 +0.008827 +0.008909 +0.009003 +0.008821 +0.008746 +0.008789 +0.008873 +0.008995 +0.009023 +0.00888 +0.008804 +0.008844 +0.008914 +0.009005 +0.009078 +0.008923 +0.008842 +0.008894 +0.008975 +0.009054 +0.00913 +0.008983 +0.00889 +0.008946 +0.009015 +0.00911 +0.009168 +0.009012 +0.008938 +0.008984 +0.009093 +0.009154 +0.00922 +0.009059 +0.008983 +0.009034 +0.009103 +0.009222 +0.009258 +0.009099 +0.009022 +0.009073 +0.009182 +0.009255 +0.009316 +0.009162 +0.009088 +0.009115 +0.009198 +0.009298 +0.00936 +0.009193 +0.009141 +0.009166 +0.009253 +0.009352 +0.009413 +0.009285 +0.009168 +0.009207 +0.009294 +0.009387 +0.009465 +0.009291 +0.009228 +0.009262 +0.009374 +0.009455 +0.009504 +0.009355 +0.009253 +0.009312 +0.009405 +0.009483 +0.009574 +0.009408 +0.009326 +0.009372 +0.009454 +0.009546 +0.009612 +0.009434 +0.009357 +0.009422 +0.009526 +0.009604 +0.009664 +0.009494 +0.009396 +0.009473 +0.009547 +0.009641 +0.009712 +0.009529 +0.00945 +0.009534 +0.009609 +0.009702 +0.009771 +0.009592 +0.0095 +0.009568 +0.009652 +0.009756 +0.009802 +0.009634 +0.009561 +0.009625 +0.009715 +0.009813 +0.009896 +0.009665 +0.009595 +0.009663 +0.00976 +0.00984 +0.009899 +0.00973 +0.009656 +0.009709 +0.009797 +0.00991 +0.009952 +0.009798 +0.009717 +0.009764 +0.009847 +0.009961 +0.010023 +0.009849 +0.009754 +0.009822 +0.009908 +0.009997 +0.010065 +0.009929 +0.009824 +0.009877 +0.009966 +0.010057 +0.010103 +0.009961 +0.009851 +0.009904 +0.009997 +0.010098 +0.010184 +0.010013 +0.009931 +0.009981 +0.010051 +0.010151 +0.010227 +0.010045 +0.009962 +0.010031 +0.010103 +0.01021 +0.010282 +0.010101 +0.010015 +0.010073 +0.010196 +0.010291 +0.010319 +0.010157 +0.01006 +0.010127 +0.010232 +0.010307 +0.010386 +0.010191 +0.010111 +0.010191 +0.010289 +0.010391 +0.010457 +0.010253 +0.010161 +0.010233 +0.010324 +0.010417 +0.010498 +0.010307 +0.010214 +0.010296 +0.010393 +0.010516 +0.010532 +0.010354 +0.010267 +0.01034 +0.010427 +0.010541 +0.010632 +0.010403 +0.010322 +0.010396 +0.010482 +0.010583 +0.010674 +0.010471 +0.010391 +0.010469 +0.010546 +0.010638 +0.010693 +0.010491 +0.010397 +0.010458 +0.010543 +0.01064 +0.010578 +0.010376 +0.010254 +0.010266 +0.010326 +0.010372 +0.010362 +0.010151 +0.010009 +0.010028 +0.010103 +0.010114 +0.010123 +0.00989 +0.00976 +0.009763 +0.009806 +0.00983 +0.009832 +0.009624 +0.009501 +0.009497 +0.009538 +0.009576 +0.009599 +0.009374 +0.009254 +0.009247 +0.009296 +0.009331 +0.00934 +0.009159 +0.009025 +0.009061 +0.009095 +0.009138 +0.009162 +0.008966 +0.008866 +0.008898 +0.008953 +0.009008 +0.009018 +0.008839 +0.008728 +0.008751 +0.008817 +0.008855 +0.008866 +0.008696 +0.008606 +0.008635 +0.008715 +0.008752 +0.008777 +0.0086 +0.008541 +0.008546 +0.008615 +0.008674 +0.008717 +0.008575 +0.008501 +0.008551 +0.008632 +0.008726 +0.008775 +0.008629 +0.00855 +0.0086 +0.008673 +0.008739 +0.008809 +0.008654 +0.008577 +0.008645 +0.008732 +0.008795 +0.008855 +0.008711 +0.008635 +0.008712 +0.008761 +0.008836 +0.008896 +0.008753 +0.008681 +0.008747 +0.008837 +0.008877 +0.008945 +0.008787 +0.008715 +0.008775 +0.008854 +0.008936 +0.008989 +0.008859 +0.008781 +0.008831 +0.008906 +0.008992 +0.009026 +0.008886 +0.008819 +0.008864 +0.00894 +0.00903 +0.009095 +0.008962 +0.008865 +0.008922 +0.008992 +0.00908 +0.009126 +0.008978 +0.008902 +0.008957 +0.009054 +0.009116 +0.009176 +0.009045 +0.008967 +0.009011 +0.009093 +0.009187 +0.00924 +0.009067 +0.008994 +0.009042 +0.009127 +0.009219 +0.009303 +0.009118 +0.009039 +0.009102 +0.009188 +0.009312 +0.009321 +0.009157 +0.009077 +0.009145 +0.009234 +0.00932 +0.009393 +0.009228 +0.009128 +0.009189 +0.009272 +0.009372 +0.009424 +0.009257 +0.009198 +0.009258 +0.009345 +0.009432 +0.009487 +0.009309 +0.009226 +0.009284 +0.009364 +0.009451 +0.009534 +0.009372 +0.009309 +0.009349 +0.009446 +0.009528 +0.009572 +0.009396 +0.009317 +0.009374 +0.009469 +0.009554 +0.009622 +0.009488 +0.009406 +0.009449 +0.009529 +0.009619 +0.009664 +0.009496 +0.00942 +0.009472 +0.00957 +0.00969 +0.009729 +0.009558 +0.009483 +0.009543 +0.009649 +0.009706 +0.009755 +0.009602 +0.00952 +0.009611 +0.009674 +0.009766 +0.009835 +0.009651 +0.00958 +0.009643 +0.009714 +0.009801 +0.009886 +0.009709 +0.009637 +0.009704 +0.009793 +0.00986 +0.009924 +0.009768 +0.009668 +0.009734 +0.009818 +0.009936 +0.010014 +0.009811 +0.009729 +0.009795 +0.009864 +0.009965 +0.010046 +0.009859 +0.009775 +0.009824 +0.009935 +0.010051 +0.010099 +0.009916 +0.009837 +0.009873 +0.009959 +0.010065 +0.010133 +0.009967 +0.009887 +0.009948 +0.01005 +0.01015 +0.010218 +0.010048 +0.009897 +0.009978 +0.010072 +0.010173 +0.010242 +0.010069 +0.009985 +0.010048 +0.010136 +0.010236 +0.010307 +0.010116 +0.010032 +0.0101 +0.010191 +0.010293 +0.010385 +0.010162 +0.01008 +0.010149 +0.010239 +0.010333 +0.010421 +0.010259 +0.01015 +0.010224 +0.010284 +0.01038 +0.01046 +0.010276 +0.010184 +0.010257 +0.010335 +0.010456 +0.010533 +0.010343 +0.010254 +0.01031 +0.010383 +0.0105 +0.010568 +0.010384 +0.010306 +0.010371 +0.010458 +0.01058 +0.010645 +0.010473 +0.010349 +0.010386 +0.010473 +0.010612 +0.010625 +0.010405 +0.010302 +0.010344 +0.010405 +0.010474 +0.010464 +0.010237 +0.010096 +0.010121 +0.01015 +0.010204 +0.010197 +0.009982 +0.00985 +0.009852 +0.009895 +0.009921 +0.009919 +0.009699 +0.009573 +0.009595 +0.009639 +0.009663 +0.009671 +0.009455 +0.009353 +0.009337 +0.00936 +0.009412 +0.009424 +0.009217 +0.009089 +0.009125 +0.009156 +0.009194 +0.009209 +0.00902 +0.008897 +0.008912 +0.008968 +0.009022 +0.009058 +0.008868 +0.008764 +0.008792 +0.008837 +0.008883 +0.008924 +0.008761 +0.008629 +0.008657 +0.008697 +0.00876 +0.008806 +0.008628 +0.008544 +0.008576 +0.008637 +0.008686 +0.008724 +0.008572 +0.00849 +0.008533 +0.008602 +0.008697 +0.008768 +0.008604 +0.008527 +0.008586 +0.008652 +0.008739 +0.00878 +0.00864 +0.008566 +0.008618 +0.008702 +0.008791 +0.008857 +0.008687 +0.008621 +0.008666 +0.008745 +0.008834 +0.008874 +0.008731 +0.008657 +0.008737 +0.008781 +0.008864 +0.008933 +0.008775 +0.008714 +0.008749 +0.008838 +0.008904 +0.008972 +0.00883 +0.00875 +0.008802 +0.008874 +0.008971 +0.009025 +0.008867 +0.0088 +0.008849 +0.008953 +0.009038 +0.00907 +0.008897 +0.008837 +0.008896 +0.008967 +0.009056 +0.009121 +0.008968 +0.00889 +0.008939 +0.009017 +0.009102 +0.009166 +0.009002 +0.008947 +0.008982 +0.009062 +0.009172 +0.009224 +0.009057 +0.008976 +0.009037 +0.009116 +0.009196 +0.009265 +0.009108 +0.009054 +0.009073 +0.009155 +0.009255 +0.009317 +0.00915 +0.009069 +0.009119 +0.009209 +0.009301 +0.009356 +0.009194 +0.009129 +0.009208 +0.00926 +0.009359 +0.009404 +0.009231 +0.009158 +0.00922 +0.009283 +0.009393 +0.009468 +0.009293 +0.009223 +0.00929 +0.009374 +0.009485 +0.009499 +0.009334 +0.009245 +0.009313 +0.00941 +0.009488 +0.00955 +0.0094 +0.009312 +0.009361 +0.009439 +0.00954 +0.009606 +0.009435 +0.009389 +0.00941 +0.009504 +0.009618 +0.009665 +0.009476 +0.009403 +0.009453 +0.009547 +0.009648 +0.00971 +0.009571 +0.009466 +0.00952 +0.009606 +0.009701 +0.009758 +0.009571 +0.009501 +0.009574 +0.009651 +0.009733 +0.009802 +0.009647 +0.009571 +0.009629 +0.009724 +0.009789 +0.009842 +0.009687 +0.009583 +0.009662 +0.009756 +0.009845 +0.009915 +0.009754 +0.009679 +0.009761 +0.009809 +0.009873 +0.009943 +0.009771 +0.009715 +0.009775 +0.009837 +0.009975 +0.010039 +0.009843 +0.009765 +0.009815 +0.009887 +0.010001 +0.010058 +0.009884 +0.009814 +0.009884 +0.009938 +0.010051 +0.010121 +0.009944 +0.009863 +0.009914 +0.010044 +0.010118 +0.010163 +0.009994 +0.00991 +0.009973 +0.010058 +0.010156 +0.010235 +0.010056 +0.009953 +0.010053 +0.010114 +0.010225 +0.010296 +0.010092 +0.01 +0.010074 +0.010154 +0.01025 +0.010344 +0.010154 +0.010072 +0.010141 +0.01025 +0.01038 +0.010366 +0.010192 +0.010109 +0.010183 +0.010276 +0.010365 +0.010446 +0.010279 +0.010182 +0.010243 +0.010345 +0.010421 +0.010507 +0.010298 +0.010216 +0.010282 +0.01038 +0.010501 +0.010567 +0.010386 +0.01029 +0.01033 +0.010434 +0.010576 +0.010598 +0.010411 +0.010329 +0.010396 +0.0105 +0.010621 +0.010621 +0.010446 +0.010331 +0.010396 +0.010461 +0.010503 +0.01053 +0.01034 +0.010184 +0.010208 +0.010256 +0.010299 +0.010294 +0.010085 +0.009959 +0.00998 +0.010049 +0.010089 +0.01007 +0.009823 +0.0097 +0.009718 +0.009759 +0.009794 +0.009788 +0.009599 +0.009486 +0.009477 +0.009505 +0.009542 +0.009521 +0.009322 +0.009226 +0.009221 +0.009259 +0.009301 +0.009303 +0.009125 +0.009011 +0.009038 +0.009062 +0.009098 +0.009108 +0.008928 +0.008856 +0.008854 +0.008892 +0.008939 +0.008951 +0.008784 +0.008684 +0.008714 +0.008752 +0.008804 +0.008817 +0.008667 +0.008563 +0.008588 +0.008633 +0.008683 +0.008735 +0.00855 +0.00847 +0.008515 +0.008579 +0.008627 +0.008682 +0.008538 +0.00847 +0.008532 +0.008591 +0.008694 +0.008751 +0.008615 +0.008493 +0.008555 +0.008643 +0.008709 +0.008768 +0.00862 +0.008538 +0.008602 +0.008697 +0.008763 +0.008824 +0.008674 +0.008595 +0.00863 +0.008715 +0.008813 +0.008855 +0.008707 +0.008637 +0.00869 +0.008793 +0.008852 +0.008913 +0.008766 +0.008681 +0.008719 +0.008803 +0.008902 +0.008963 +0.008786 +0.008716 +0.008769 +0.008845 +0.008963 +0.008992 +0.008832 +0.008763 +0.008812 +0.008888 +0.008977 +0.009049 +0.008883 +0.008808 +0.008881 +0.008933 +0.009023 +0.009091 +0.008939 +0.008853 +0.008903 +0.008974 +0.009072 +0.009136 +0.008992 +0.008918 +0.008983 +0.009048 +0.009102 +0.009166 +0.009009 +0.008931 +0.009001 +0.009061 +0.009182 +0.009243 +0.009067 +0.008996 +0.009045 +0.009126 +0.00919 +0.009259 +0.009119 +0.009021 +0.009087 +0.00916 +0.009248 +0.009332 +0.009167 +0.009091 +0.009131 +0.009205 +0.009297 +0.009365 +0.009225 +0.009121 +0.009166 +0.009253 +0.009338 +0.009411 +0.009253 +0.009162 +0.009224 +0.009299 +0.009412 +0.009452 +0.009293 +0.009212 +0.009263 +0.009362 +0.009437 +0.009494 +0.009348 +0.009267 +0.009315 +0.009391 +0.009483 +0.00954 +0.009377 +0.0093 +0.009373 +0.009462 +0.009532 +0.009611 +0.009423 +0.009342 +0.009413 +0.009482 +0.009575 +0.009659 +0.009494 +0.009406 +0.00947 +0.009546 +0.009664 +0.009721 +0.00953 +0.009452 +0.009507 +0.009594 +0.009675 +0.009737 +0.009603 +0.009485 +0.009564 +0.009658 +0.009749 +0.009823 +0.009608 +0.009538 +0.00959 +0.009705 +0.009764 +0.009822 +0.009669 +0.009609 +0.009656 +0.009746 +0.009837 +0.009889 +0.009717 +0.009645 +0.009691 +0.009777 +0.009878 +0.009963 +0.009775 +0.009692 +0.009758 +0.009832 +0.009921 +0.009992 +0.009838 +0.009746 +0.009806 +0.009872 +0.009969 +0.010048 +0.009863 +0.009784 +0.009841 +0.009921 +0.010026 +0.010101 +0.009926 +0.009856 +0.009895 +0.009997 +0.010099 +0.010134 +0.00997 +0.009867 +0.009933 +0.010039 +0.010141 +0.010215 +0.010044 +0.009956 +0.010008 +0.01007 +0.010174 +0.010234 +0.010064 +0.009975 +0.010044 +0.010165 +0.010263 +0.010299 +0.010105 +0.010023 +0.010091 +0.010184 +0.010293 +0.010338 +0.010189 +0.010112 +0.010158 +0.010247 +0.010346 +0.010387 +0.010206 +0.010137 +0.010233 +0.010321 +0.010392 +0.010434 +0.010255 +0.010181 +0.010238 +0.010331 +0.010443 +0.010499 +0.010334 +0.010242 +0.010312 +0.010411 +0.010501 +0.010551 +0.01037 +0.01029 +0.010348 +0.010437 +0.010559 +0.010639 +0.010433 +0.010347 +0.010414 +0.010462 +0.010541 +0.010604 +0.010344 +0.010232 +0.010301 +0.010343 +0.010409 +0.01043 +0.0102 +0.010056 +0.010084 +0.010127 +0.010191 +0.010204 +0.009968 +0.00983 +0.009834 +0.009873 +0.009921 +0.009945 +0.009695 +0.009559 +0.009592 +0.009653 +0.009719 +0.009673 +0.009449 +0.009312 +0.009356 +0.009379 +0.009414 +0.009423 +0.009226 +0.009089 +0.009111 +0.00916 +0.009203 +0.009217 +0.009025 +0.008901 +0.008922 +0.008976 +0.00903 +0.009064 +0.008874 +0.008747 +0.008788 +0.00883 +0.008892 +0.008918 +0.008733 +0.008649 +0.008675 +0.008713 +0.00878 +0.008809 +0.008635 +0.008542 +0.008574 +0.008632 +0.008698 +0.00873 +0.008573 +0.008489 +0.008536 +0.008613 +0.008707 +0.008772 +0.008613 +0.00854 +0.00857 +0.008651 +0.008722 +0.008794 +0.008648 +0.008573 +0.008612 +0.008691 +0.008786 +0.008855 +0.008714 +0.008616 +0.008656 +0.008735 +0.008818 +0.008883 +0.008735 +0.008654 +0.00872 +0.008814 +0.008883 +0.008923 +0.008768 +0.008699 +0.008746 +0.008829 +0.00891 +0.008966 +0.008822 +0.008754 +0.008816 +0.008878 +0.008952 +0.009018 +0.008857 +0.008787 +0.008837 +0.008918 +0.009024 +0.009081 +0.008911 +0.008833 +0.008887 +0.008964 +0.009061 +0.009095 +0.008946 +0.008878 +0.008917 +0.009005 +0.009104 +0.009147 +0.008994 +0.008926 +0.008979 +0.009044 +0.009136 +0.009197 +0.009047 +0.008964 +0.009028 +0.009117 +0.009187 +0.00924 +0.009081 +0.00901 +0.009093 +0.009145 +0.009224 +0.009285 +0.009165 +0.009063 +0.009105 +0.009188 +0.009279 +0.00934 +0.009166 +0.009089 +0.009158 +0.00923 +0.009334 +0.009398 +0.009212 +0.00914 +0.009191 +0.009279 +0.009364 +0.009426 +0.00928 +0.009197 +0.009256 +0.009352 +0.009438 +0.009505 +0.009313 +0.009225 +0.009275 +0.009363 +0.009467 +0.009535 +0.009364 +0.009299 +0.009352 +0.009435 +0.009523 +0.009566 +0.00941 +0.009327 +0.009389 +0.009457 +0.009558 +0.009619 +0.009461 +0.009374 +0.009438 +0.009532 +0.009604 +0.009664 +0.009515 +0.009447 +0.009509 +0.009571 +0.009658 +0.009718 +0.009544 +0.009471 +0.00953 +0.009637 +0.009705 +0.009755 +0.009606 +0.009538 +0.009579 +0.009675 +0.009775 +0.009814 +0.009643 +0.009561 +0.009622 +0.009705 +0.009825 +0.009865 +0.009695 +0.009601 +0.009681 +0.009776 +0.009884 +0.009906 +0.009733 +0.009672 +0.009738 +0.00982 +0.009893 +0.009964 +0.009796 +0.009718 +0.009765 +0.009856 +0.009947 +0.010048 +0.009863 +0.00977 +0.00983 +0.009905 +0.010009 +0.010056 +0.009899 +0.0098 +0.009853 +0.009957 +0.010085 +0.010172 +0.009946 +0.009888 +0.009896 +0.009996 +0.010097 +0.010162 +0.009987 +0.009916 +0.009956 +0.010049 +0.010165 +0.010213 +0.010057 +0.00996 +0.010018 +0.01011 +0.010228 +0.010289 +0.010101 +0.010012 +0.010073 +0.010148 +0.010262 +0.010333 +0.010168 +0.010051 +0.010126 +0.010221 +0.010356 +0.010353 +0.010174 +0.010109 +0.010162 +0.010262 +0.01036 +0.010446 +0.010264 +0.010182 +0.010227 +0.010316 +0.010402 +0.01047 +0.010298 +0.010209 +0.010295 +0.010363 +0.010463 +0.010528 +0.01038 +0.010258 +0.010304 +0.010415 +0.010526 +0.010607 +0.010447 +0.010313 +0.010359 +0.010458 +0.010571 +0.010637 +0.010454 +0.010373 +0.010441 +0.010524 +0.010621 +0.010664 +0.010443 +0.010334 +0.010362 +0.010416 +0.010504 +0.01054 +0.010305 +0.010173 +0.010224 +0.010257 +0.010258 +0.01028 +0.010064 +0.009938 +0.009974 +0.009969 +0.01003 +0.010033 +0.009819 +0.009706 +0.009688 +0.009723 +0.009785 +0.009797 +0.00958 +0.00946 +0.009472 +0.00949 +0.009535 +0.009562 +0.009348 +0.009219 +0.009254 +0.009286 +0.009357 +0.009342 +0.009146 +0.009049 +0.009057 +0.009093 +0.009132 +0.009163 +0.008982 +0.00887 +0.008891 +0.008925 +0.009002 +0.009018 +0.008844 +0.00874 +0.008755 +0.008791 +0.008846 +0.008893 +0.008698 +0.008596 +0.008628 +0.00868 +0.008734 +0.008786 +0.008645 +0.008549 +0.008611 +0.008665 +0.008698 +0.008754 +0.008621 +0.008553 +0.008601 +0.008679 +0.008747 +0.008836 +0.008674 +0.008605 +0.008658 +0.008727 +0.008797 +0.008846 +0.008716 +0.008632 +0.008687 +0.008768 +0.008858 +0.008908 +0.008754 +0.008686 +0.008732 +0.008793 +0.008882 +0.008953 +0.008818 +0.008738 +0.008773 +0.008848 +0.008988 +0.008995 +0.008851 +0.008763 +0.008804 +0.008892 +0.008979 +0.009041 +0.008886 +0.008823 +0.008859 +0.008935 +0.00904 +0.009097 +0.008944 +0.008864 +0.008904 +0.008976 +0.009061 +0.009136 +0.00898 +0.008895 +0.008947 +0.009053 +0.009154 +0.009199 +0.009021 +0.008941 +0.00898 +0.009067 +0.009178 +0.009209 +0.00906 +0.009005 +0.009033 +0.009116 +0.009212 +0.009278 +0.00911 +0.009031 +0.009089 +0.00916 +0.009257 +0.009321 +0.009158 +0.009095 +0.009129 +0.009222 +0.009297 +0.009359 +0.009216 +0.009131 +0.009199 +0.009253 +0.009345 +0.009414 +0.009261 +0.009186 +0.009213 +0.009328 +0.009393 +0.009441 +0.009289 +0.009209 +0.00927 +0.009361 +0.009455 +0.009528 +0.009356 +0.009269 +0.009316 +0.009392 +0.009483 +0.00954 +0.009388 +0.009305 +0.009356 +0.009455 +0.009566 +0.009623 +0.009432 +0.009342 +0.009404 +0.009486 +0.009581 +0.009647 +0.009481 +0.009408 +0.009458 +0.009544 +0.009662 +0.009688 +0.00953 +0.009453 +0.009502 +0.009581 +0.009687 +0.009781 +0.009578 +0.009486 +0.009562 +0.009636 +0.009721 +0.009793 +0.009629 +0.009562 +0.009601 +0.009713 +0.009777 +0.009845 +0.009674 +0.009577 +0.009647 +0.009733 +0.009823 +0.009886 +0.009726 +0.009638 +0.009709 +0.009808 +0.00989 +0.009939 +0.009755 +0.009677 +0.00974 +0.009831 +0.009929 +0.009991 +0.009814 +0.009739 +0.009823 +0.009892 +0.009975 +0.010019 +0.009892 +0.009781 +0.00983 +0.009924 +0.010036 +0.010088 +0.009918 +0.009842 +0.009886 +0.00998 +0.010074 +0.010144 +0.009967 +0.009892 +0.009967 +0.010026 +0.010129 +0.010198 +0.010022 +0.009926 +0.009992 +0.0101 +0.010193 +0.010257 +0.010071 +0.009989 +0.010056 +0.010141 +0.010213 +0.010293 +0.010107 +0.010023 +0.010107 +0.0102 +0.010301 +0.01034 +0.010186 +0.010065 +0.010137 +0.010226 +0.010333 +0.010417 +0.010234 +0.010121 +0.010196 +0.010302 +0.010426 +0.010433 +0.010263 +0.010171 +0.010246 +0.010334 +0.010463 +0.010519 +0.010312 +0.010229 +0.0103 +0.010395 +0.010495 +0.010554 +0.010383 +0.010303 +0.010373 +0.010453 +0.010531 +0.010602 +0.010418 +0.010334 +0.010401 +0.010508 +0.010644 +0.010677 +0.010419 +0.010338 +0.010396 +0.01047 +0.010508 +0.010532 +0.010329 +0.010202 +0.010239 +0.010286 +0.010335 +0.010321 +0.010075 +0.009952 +0.009975 +0.010011 +0.010052 +0.010036 +0.009835 +0.009709 +0.009726 +0.009764 +0.009799 +0.009777 +0.009544 +0.009429 +0.009455 +0.009474 +0.009499 +0.009507 +0.00931 +0.00921 +0.009221 +0.009248 +0.009286 +0.009283 +0.009088 +0.008985 +0.009016 +0.009058 +0.009087 +0.009141 +0.00894 +0.008843 +0.008875 +0.008921 +0.008947 +0.008968 +0.008803 +0.008708 +0.008753 +0.00878 +0.008832 +0.008837 +0.008667 +0.008603 +0.008614 +0.008663 +0.00871 +0.008749 +0.008575 +0.008496 +0.008547 +0.008598 +0.008658 +0.008698 +0.00856 +0.008471 +0.00853 +0.008597 +0.008679 +0.008739 +0.008589 +0.008519 +0.008558 +0.008641 +0.008727 +0.008798 +0.008657 +0.008568 +0.008606 +0.008678 +0.008759 +0.008821 +0.008678 +0.008592 +0.008654 +0.008746 +0.008826 +0.00887 +0.008723 +0.008651 +0.008696 +0.008783 +0.008845 +0.008909 +0.008762 +0.008691 +0.008744 +0.00882 +0.008901 +0.008963 +0.008817 +0.00873 +0.008772 +0.008853 +0.008941 +0.009039 +0.008848 +0.008779 +0.008821 +0.008894 +0.008977 +0.009048 +0.008891 +0.008818 +0.00888 +0.008944 +0.009027 +0.009117 +0.00896 +0.008865 +0.008921 +0.009002 +0.009061 +0.00913 +0.008981 +0.008927 +0.008952 +0.009031 +0.009122 +0.009187 +0.009043 +0.008965 +0.009013 +0.009121 +0.009154 +0.009246 +0.009052 +0.008986 +0.00905 +0.009117 +0.00921 +0.00927 +0.009122 +0.009038 +0.009094 +0.009182 +0.00926 +0.009323 +0.009169 +0.009089 +0.00914 +0.00922 +0.009316 +0.009368 +0.009211 +0.00914 +0.009185 +0.009259 +0.009347 +0.009428 +0.009286 +0.00919 +0.009241 +0.00931 +0.009415 +0.009461 +0.009291 +0.009211 +0.009273 +0.009359 +0.009443 +0.009516 +0.00938 +0.009286 +0.009335 +0.009419 +0.009491 +0.009543 +0.009387 +0.009311 +0.009363 +0.009451 +0.009544 +0.009613 +0.009461 +0.009382 +0.009442 +0.009543 +0.009579 +0.009629 +0.009476 +0.0094 +0.009459 +0.009577 +0.009628 +0.009708 +0.009533 +0.009455 +0.009525 +0.009596 +0.009685 +0.009752 +0.00959 +0.009492 +0.009557 +0.009655 +0.009737 +0.009804 +0.009646 +0.009546 +0.009608 +0.009698 +0.009803 +0.009887 +0.009678 +0.009605 +0.009651 +0.009731 +0.009835 +0.009894 +0.009726 +0.009654 +0.009698 +0.009784 +0.009922 +0.009969 +0.009782 +0.009696 +0.009736 +0.009835 +0.009944 +0.009995 +0.009826 +0.009739 +0.009826 +0.009901 +0.01 +0.010063 +0.009901 +0.009824 +0.009836 +0.009916 +0.010018 +0.01011 +0.009923 +0.00983 +0.009902 +0.009988 +0.010094 +0.010149 +0.009974 +0.009889 +0.009948 +0.010043 +0.010159 +0.010194 +0.010031 +0.009938 +0.010002 +0.010095 +0.01018 +0.010257 +0.010084 +0.010032 +0.010077 +0.010147 +0.010254 +0.010282 +0.010113 +0.010021 +0.010099 +0.010199 +0.010299 +0.010354 +0.010212 +0.010109 +0.010146 +0.010237 +0.010333 +0.010404 +0.010234 +0.010135 +0.010187 +0.010323 +0.010417 +0.010474 +0.010294 +0.0102 +0.010272 +0.010329 +0.010431 +0.010503 +0.010327 +0.010238 +0.010322 +0.010425 +0.010522 +0.010561 +0.010375 +0.010289 +0.010344 +0.010479 +0.010543 +0.010607 +0.01042 +0.010319 +0.010384 +0.010478 +0.010538 +0.010584 +0.01036 +0.010227 +0.010277 +0.010367 +0.010397 +0.01038 +0.010157 +0.01001 +0.010049 +0.010075 +0.010129 +0.010146 +0.009909 +0.009771 +0.0098 +0.009835 +0.009874 +0.009895 +0.009672 +0.009524 +0.009543 +0.009599 +0.009639 +0.009646 +0.009451 +0.009304 +0.009314 +0.009378 +0.009413 +0.009446 +0.0092 +0.009086 +0.009113 +0.009165 +0.009224 +0.009237 +0.009046 +0.008951 +0.008946 +0.009001 +0.009049 +0.009077 +0.00888 +0.008777 +0.008817 +0.008871 +0.008939 +0.008958 +0.008775 +0.008665 +0.00869 +0.008755 +0.008808 +0.008843 +0.008666 +0.008585 +0.008623 +0.008725 +0.008746 +0.008798 +0.00863 +0.008551 +0.008612 +0.008683 +0.008753 +0.008811 +0.008676 +0.008599 +0.008637 +0.008727 +0.008809 +0.008857 +0.008709 +0.008645 +0.008677 +0.008767 +0.008852 +0.008913 +0.008769 +0.008677 +0.008739 +0.008808 +0.008909 +0.008952 +0.008804 +0.00875 +0.00879 +0.00885 +0.008935 +0.009006 +0.008841 +0.008772 +0.008831 +0.008907 +0.008994 +0.009034 +0.008883 +0.008806 +0.008903 +0.00893 +0.009023 +0.009086 +0.008929 +0.008858 +0.008912 +0.009004 +0.009084 +0.009129 +0.008986 +0.008902 +0.008952 +0.009029 +0.009121 +0.009207 +0.009033 +0.008959 +0.009 +0.009082 +0.009177 +0.009229 +0.009061 +0.008984 +0.009049 +0.00912 +0.009215 +0.009289 +0.009116 +0.009026 +0.009109 +0.009164 +0.009251 +0.009315 +0.009161 +0.009082 +0.009141 +0.009219 +0.009315 +0.009382 +0.009209 +0.009127 +0.009196 +0.009287 +0.009344 +0.009402 +0.00924 +0.00918 +0.009232 +0.009341 +0.009422 +0.009471 +0.009282 +0.009217 +0.009269 +0.009351 +0.009443 +0.009507 +0.009346 +0.00927 +0.009317 +0.009428 +0.009502 +0.009565 +0.009392 +0.009312 +0.009365 +0.009447 +0.009549 +0.00963 +0.009444 +0.009366 +0.009428 +0.009514 +0.009602 +0.009656 +0.009475 +0.009398 +0.009485 +0.009524 +0.00963 +0.009718 +0.009532 +0.009438 +0.009519 +0.009597 +0.009689 +0.009763 +0.009577 +0.009497 +0.009553 +0.009639 +0.009751 +0.009813 +0.009633 +0.009574 +0.009628 +0.009693 +0.009772 +0.009846 +0.009676 +0.009605 +0.009662 +0.009749 +0.009844 +0.009901 +0.009753 +0.00964 +0.009696 +0.009782 +0.009892 +0.009933 +0.009778 +0.009715 +0.009762 +0.009858 +0.009941 +0.009987 +0.009824 +0.009743 +0.009805 +0.009924 +0.009981 +0.010052 +0.00991 +0.009796 +0.009858 +0.009928 +0.010021 +0.010094 +0.009933 +0.009834 +0.009921 +0.009985 +0.01008 +0.010162 +0.009968 +0.00989 +0.009949 +0.010033 +0.010141 +0.010209 +0.010031 +0.009962 +0.009999 +0.010105 +0.010233 +0.010245 +0.010072 +0.009972 +0.010043 +0.010178 +0.010257 +0.010313 +0.010141 +0.010034 +0.010092 +0.010192 +0.010297 +0.010347 +0.010178 +0.010079 +0.010151 +0.01028 +0.010361 +0.010403 +0.010232 +0.010133 +0.010202 +0.010308 +0.010421 +0.010477 +0.010297 +0.010196 +0.01026 +0.010361 +0.010437 +0.010495 +0.010337 +0.010228 +0.010299 +0.0104 +0.010514 +0.010591 +0.010408 +0.010308 +0.010355 +0.010445 +0.010539 +0.010616 +0.010441 +0.010348 +0.010403 +0.010513 +0.01064 +0.010692 +0.010487 +0.010377 +0.010463 +0.010549 +0.010646 +0.010703 +0.010514 +0.010414 +0.01043 +0.010492 +0.01054 +0.010562 +0.010355 +0.010225 +0.010239 +0.010306 +0.01036 +0.010334 +0.010103 +0.009959 +0.009978 +0.010021 +0.010061 +0.010096 +0.00986 +0.009753 +0.00972 +0.009757 +0.009789 +0.009784 +0.009582 +0.009451 +0.009475 +0.009497 +0.009568 +0.009542 +0.009345 +0.009231 +0.009231 +0.009265 +0.009305 +0.009329 +0.009134 +0.009021 +0.009052 +0.009085 +0.009132 +0.009145 +0.008969 +0.008885 +0.008896 +0.008919 +0.008966 +0.008992 +0.008853 +0.008716 +0.008755 +0.008798 +0.008856 +0.008861 +0.008706 +0.0086 +0.008632 +0.008676 +0.008732 +0.008775 +0.008614 +0.008527 +0.008566 +0.008642 +0.008697 +0.008749 +0.008596 +0.008528 +0.008574 +0.008648 +0.008736 +0.008791 +0.008662 +0.008573 +0.008626 +0.008695 +0.008777 +0.008837 +0.008677 +0.008625 +0.00865 +0.008726 +0.008796 +0.008869 +0.008717 +0.008656 +0.008718 +0.008791 +0.008881 +0.008931 +0.008776 +0.00869 +0.008747 +0.008838 +0.008896 +0.008969 +0.00881 +0.008736 +0.008793 +0.008865 +0.00898 +0.009021 +0.008854 +0.008785 +0.008822 +0.008906 +0.009 +0.00906 +0.008918 +0.008845 +0.008876 +0.008948 +0.009038 +0.009107 +0.008947 +0.008872 +0.008922 +0.008995 +0.009088 +0.009165 +0.009032 +0.008916 +0.008962 +0.009046 +0.009127 +0.009192 +0.009038 +0.008965 +0.009036 +0.009095 +0.009209 +0.009234 +0.009083 +0.00901 +0.009058 +0.009128 +0.009218 +0.009287 +0.009126 +0.009048 +0.009101 +0.009179 +0.009288 +0.009349 +0.009183 +0.0091 +0.00914 +0.009231 +0.00931 +0.009375 +0.009221 +0.009138 +0.009194 +0.00928 +0.009373 +0.009465 +0.009276 +0.00918 +0.009233 +0.009334 +0.009402 +0.009468 +0.009323 +0.009241 +0.009306 +0.009375 +0.009456 +0.009523 +0.009354 +0.009272 +0.009328 +0.009397 +0.009507 +0.009585 +0.009431 +0.009335 +0.009385 +0.009472 +0.009548 +0.009614 +0.009457 +0.009381 +0.009442 +0.009511 +0.009618 +0.009669 +0.009507 +0.009441 +0.009479 +0.009545 +0.00965 +0.009694 +0.009547 +0.009457 +0.009515 +0.009609 +0.009701 +0.009782 +0.009599 +0.009518 +0.009584 +0.009642 +0.009751 +0.009822 +0.00964 +0.009556 +0.009634 +0.009717 +0.009844 +0.009855 +0.00969 +0.009603 +0.009654 +0.009758 +0.00984 +0.009926 +0.009776 +0.009657 +0.009708 +0.00981 +0.009893 +0.009961 +0.009794 +0.009707 +0.00976 +0.009851 +0.009952 +0.010027 +0.009855 +0.009752 +0.00981 +0.009893 +0.010014 +0.010092 +0.009911 +0.009785 +0.009859 +0.009965 +0.01007 +0.010112 +0.00992 +0.009852 +0.009902 +0.010008 +0.010098 +0.010159 +0.009986 +0.009905 +0.00997 +0.01005 +0.010151 +0.010221 +0.010049 +0.009946 +0.010012 +0.010101 +0.010213 +0.010278 +0.010123 +0.010015 +0.010053 +0.010168 +0.010233 +0.010317 +0.010128 +0.010048 +0.010141 +0.010219 +0.0103 +0.010376 +0.010177 +0.010102 +0.01017 +0.010246 +0.010361 +0.010452 +0.010257 +0.010168 +0.010224 +0.010302 +0.010404 +0.010474 +0.010299 +0.010237 +0.010264 +0.010366 +0.010471 +0.010569 +0.010333 +0.010229 +0.010311 +0.010404 +0.01052 +0.010596 +0.010398 +0.010303 +0.010366 +0.010456 +0.010566 +0.01064 +0.010448 +0.010353 +0.010447 +0.010523 +0.01062 +0.010675 +0.010468 +0.010373 +0.010363 +0.010418 +0.010488 +0.010506 +0.010299 +0.010201 +0.010177 +0.010233 +0.010285 +0.010276 +0.010065 +0.009921 +0.009936 +0.009977 +0.010029 +0.010034 +0.009794 +0.009663 +0.009673 +0.009697 +0.009752 +0.009748 +0.009542 +0.009426 +0.009451 +0.00948 +0.009476 +0.009467 +0.009273 +0.009156 +0.009166 +0.009199 +0.009238 +0.009267 +0.009089 +0.008963 +0.008983 +0.009016 +0.009054 +0.009067 +0.008899 +0.008788 +0.008816 +0.008876 +0.008911 +0.008929 +0.008758 +0.008669 +0.008677 +0.008725 +0.008782 +0.008815 +0.008668 +0.008572 +0.008568 +0.008635 +0.008687 +0.008721 +0.008555 +0.008468 +0.008507 +0.008573 +0.008642 +0.0087 +0.008546 +0.00849 +0.008534 +0.008612 +0.008687 +0.008749 +0.008588 +0.008508 +0.008573 +0.008637 +0.008723 +0.00878 +0.008653 +0.008557 +0.00861 +0.00869 +0.008766 +0.008855 +0.008684 +0.008596 +0.008682 +0.008715 +0.008806 +0.008873 +0.008716 +0.008649 +0.008705 +0.008782 +0.008865 +0.008906 +0.008776 +0.008684 +0.008724 +0.008809 +0.008892 +0.008954 +0.008831 +0.008753 +0.008793 +0.008867 +0.008965 +0.009009 +0.008842 +0.008767 +0.008832 +0.008912 +0.009021 +0.009053 +0.008881 +0.008816 +0.008868 +0.008972 +0.009033 +0.009081 +0.00894 +0.008869 +0.008913 +0.008991 +0.009091 +0.009148 +0.008978 +0.008916 +0.008953 +0.009036 +0.009126 +0.009189 +0.009029 +0.008961 +0.009019 +0.009098 +0.009189 +0.009247 +0.009068 +0.009022 +0.009056 +0.009122 +0.009206 +0.009267 +0.009118 +0.009053 +0.009112 +0.009193 +0.009284 +0.009341 +0.009151 +0.009087 +0.009132 +0.009204 +0.009309 +0.009386 +0.009226 +0.009131 +0.009197 +0.009267 +0.009368 +0.009424 +0.009265 +0.009179 +0.009229 +0.009318 +0.009438 +0.009489 +0.009295 +0.009213 +0.00928 +0.009375 +0.009455 +0.009504 +0.009351 +0.009283 +0.009339 +0.009412 +0.009518 +0.009559 +0.009394 +0.00932 +0.009385 +0.00946 +0.009543 +0.009642 +0.00944 +0.009366 +0.009432 +0.009509 +0.009593 +0.00965 +0.009496 +0.00945 +0.009474 +0.009567 +0.009631 +0.009685 +0.009526 +0.009448 +0.009514 +0.009605 +0.009694 +0.009758 +0.009602 +0.009526 +0.009578 +0.009653 +0.009744 +0.00979 +0.009625 +0.009556 +0.009613 +0.009704 +0.009798 +0.00986 +0.009688 +0.009609 +0.009655 +0.009779 +0.009832 +0.009884 +0.009738 +0.009657 +0.009715 +0.009792 +0.009888 +0.009964 +0.009781 +0.009691 +0.009757 +0.009837 +0.009936 +0.010013 +0.009823 +0.009758 +0.009829 +0.009913 +0.00998 +0.010046 +0.009883 +0.009797 +0.00985 +0.009938 +0.010077 +0.010125 +0.009932 +0.009848 +0.009895 +0.00999 +0.010075 +0.010149 +0.009991 +0.009894 +0.009946 +0.010064 +0.01015 +0.010211 +0.010034 +0.009958 +0.009988 +0.010088 +0.010196 +0.010254 +0.010094 +0.00999 +0.01005 +0.010136 +0.010247 +0.010339 +0.01012 +0.010034 +0.010095 +0.010201 +0.010318 +0.010353 +0.010168 +0.010099 +0.010152 +0.010241 +0.010354 +0.010399 +0.010248 +0.010166 +0.01021 +0.010332 +0.010393 +0.010441 +0.010269 +0.010196 +0.010245 +0.010343 +0.010452 +0.010543 +0.01038 +0.010212 +0.010277 +0.010365 +0.010477 +0.010503 +0.01031 +0.0102 +0.010199 +0.010249 +0.010309 +0.010344 +0.010115 +0.00998 +0.010007 +0.010039 +0.010119 +0.010122 +0.009889 +0.009731 +0.009747 +0.00979 +0.009844 +0.00986 +0.009661 +0.009521 +0.009521 +0.009581 +0.009594 +0.00961 +0.009374 +0.00925 +0.009271 +0.009318 +0.009355 +0.009382 +0.00917 +0.009032 +0.009051 +0.009107 +0.009145 +0.009169 +0.008975 +0.008863 +0.00888 +0.008932 +0.008994 +0.009 +0.008802 +0.008694 +0.008721 +0.008786 +0.00884 +0.008843 +0.00866 +0.008558 +0.0086 +0.008678 +0.008705 +0.008727 +0.008555 +0.008468 +0.008475 +0.008538 +0.008611 +0.00864 +0.008489 +0.008415 +0.008442 +0.008508 +0.008585 +0.008654 +0.008508 +0.008429 +0.008474 +0.008554 +0.008629 +0.008699 +0.008563 +0.008489 +0.008546 +0.008601 +0.008666 +0.008724 +0.008579 +0.008512 +0.008567 +0.008624 +0.008722 +0.008791 +0.008651 +0.008572 +0.00861 +0.008684 +0.008753 +0.008833 +0.008665 +0.0086 +0.008646 +0.008724 +0.0088 +0.008866 +0.008714 +0.00864 +0.008699 +0.008755 +0.008844 +0.008919 +0.008766 +0.008737 +0.008755 +0.00881 +0.008889 +0.008939 +0.008796 +0.008731 +0.008773 +0.008849 +0.008941 +0.009006 +0.008848 +0.008785 +0.008838 +0.008911 +0.00898 +0.009043 +0.008881 +0.008812 +0.008865 +0.008945 +0.009025 +0.009087 +0.008943 +0.008856 +0.008908 +0.008991 +0.009082 +0.009161 +0.00899 +0.008931 +0.008948 +0.009027 +0.009129 +0.00919 +0.009019 +0.008937 +0.009004 +0.009083 +0.00916 +0.009227 +0.00907 +0.008984 +0.009058 +0.009143 +0.009232 +0.009277 +0.009117 +0.009031 +0.009087 +0.009168 +0.009264 +0.009311 +0.009161 +0.009085 +0.009138 +0.009245 +0.009301 +0.009364 +0.009203 +0.009135 +0.009184 +0.009261 +0.009359 +0.009437 +0.009262 +0.009164 +0.009222 +0.009312 +0.009404 +0.009462 +0.009306 +0.009222 +0.009288 +0.009379 +0.009464 +0.009509 +0.009334 +0.009267 +0.009333 +0.009401 +0.009502 +0.009568 +0.009423 +0.009324 +0.009376 +0.009455 +0.009542 +0.009611 +0.009428 +0.009352 +0.009426 +0.009506 +0.009601 +0.009665 +0.009481 +0.009407 +0.009454 +0.009571 +0.00964 +0.009687 +0.009545 +0.009449 +0.009529 +0.009634 +0.009707 +0.009741 +0.009584 +0.009495 +0.009587 +0.009641 +0.009732 +0.009791 +0.009648 +0.009574 +0.00962 +0.009701 +0.009788 +0.009839 +0.009673 +0.009596 +0.009647 +0.009749 +0.009834 +0.009919 +0.009733 +0.009677 +0.0097 +0.009777 +0.009884 +0.009945 +0.009775 +0.00971 +0.009782 +0.009865 +0.009987 +0.009981 +0.009812 +0.009732 +0.009795 +0.009884 +0.009993 +0.010074 +0.009897 +0.009813 +0.009839 +0.009942 +0.010033 +0.010103 +0.009931 +0.009836 +0.009914 +0.010017 +0.010104 +0.010158 +0.009988 +0.009875 +0.009943 +0.010043 +0.010152 +0.010239 +0.010032 +0.009948 +0.009986 +0.010086 +0.010183 +0.010248 +0.01007 +0.010003 +0.010046 +0.01014 +0.010266 +0.010301 +0.010125 +0.010047 +0.010099 +0.010194 +0.010301 +0.010354 +0.010183 +0.010102 +0.010166 +0.010258 +0.010345 +0.010439 +0.010231 +0.010132 +0.010192 +0.01028 +0.01044 +0.010476 +0.010285 +0.010207 +0.010252 +0.010329 +0.010453 +0.010488 +0.010316 +0.01022 +0.010267 +0.010328 +0.010413 +0.010421 +0.010204 +0.010074 +0.010122 +0.010176 +0.010214 +0.010245 +0.010029 +0.009896 +0.009876 +0.009896 +0.00994 +0.009949 +0.009726 +0.009596 +0.009636 +0.009649 +0.009686 +0.009685 +0.009486 +0.009351 +0.009366 +0.009423 +0.009472 +0.009438 +0.009253 +0.009129 +0.009139 +0.009181 +0.009226 +0.00922 +0.009032 +0.008942 +0.00896 +0.009032 +0.009041 +0.009053 +0.008876 +0.008775 +0.008799 +0.008834 +0.008887 +0.008909 +0.008731 +0.008632 +0.008654 +0.008718 +0.008757 +0.008795 +0.008613 +0.008528 +0.008558 +0.008592 +0.008673 +0.008671 +0.00851 +0.008427 +0.008479 +0.008528 +0.008598 +0.008645 +0.008505 +0.008435 +0.008514 +0.008556 +0.008601 +0.008665 +0.008524 +0.008457 +0.008498 +0.008577 +0.008664 +0.008744 +0.00858 +0.008508 +0.008559 +0.008637 +0.0087 +0.008756 +0.008616 +0.008531 +0.008591 +0.008673 +0.008764 +0.008803 +0.008655 +0.008591 +0.008643 +0.008714 +0.008779 +0.00885 +0.008725 +0.008648 +0.008685 +0.008762 +0.008868 +0.008876 +0.00874 +0.00866 +0.008719 +0.008804 +0.008881 +0.008931 +0.008794 +0.008735 +0.008783 +0.008846 +0.008928 +0.00899 +0.008827 +0.00875 +0.008814 +0.008881 +0.008968 +0.009033 +0.008883 +0.008809 +0.008864 +0.008945 +0.009035 +0.009104 +0.0089 +0.008837 +0.00889 +0.008969 +0.009064 +0.009119 +0.008962 +0.008894 +0.008943 +0.009015 +0.009114 +0.009174 +0.00901 +0.008934 +0.009015 +0.00906 +0.009149 +0.009213 +0.009061 +0.008981 +0.009027 +0.009111 +0.009193 +0.009264 +0.0091 +0.009024 +0.00911 +0.009174 +0.009256 +0.009303 +0.009152 +0.009072 +0.009107 +0.009191 +0.009288 +0.009367 +0.009188 +0.009117 +0.009185 +0.009269 +0.009349 +0.009403 +0.009245 +0.00916 +0.009207 +0.009293 +0.009372 +0.00944 +0.009298 +0.009218 +0.00925 +0.00934 +0.009439 +0.009514 +0.009341 +0.009236 +0.009292 +0.009386 +0.009482 +0.009544 +0.009392 +0.009296 +0.009366 +0.009442 +0.009519 +0.009588 +0.009417 +0.009331 +0.009403 +0.009486 +0.009597 +0.009649 +0.009508 +0.009379 +0.009436 +0.009531 +0.009611 +0.009675 +0.00951 +0.009445 +0.009534 +0.009591 +0.009683 +0.009737 +0.009553 +0.009484 +0.00953 +0.009616 +0.009733 +0.009774 +0.009606 +0.009573 +0.009602 +0.009687 +0.009776 +0.009827 +0.009644 +0.009568 +0.009635 +0.009712 +0.009821 +0.009879 +0.009715 +0.009647 +0.009704 +0.009798 +0.0099 +0.009897 +0.009749 +0.009673 +0.009739 +0.00981 +0.009905 +0.00998 +0.009817 +0.009723 +0.009777 +0.009873 +0.009967 +0.010032 +0.009865 +0.009774 +0.009845 +0.009929 +0.010009 +0.010077 +0.009912 +0.009815 +0.009885 +0.009966 +0.010077 +0.010179 +0.009954 +0.009879 +0.009922 +0.01001 +0.010121 +0.010182 +0.010001 +0.009938 +0.009966 +0.010072 +0.010197 +0.010251 +0.010064 +0.009969 +0.01004 +0.010107 +0.010222 +0.010275 +0.010101 +0.010033 +0.010094 +0.010185 +0.010295 +0.01036 +0.01017 +0.010052 +0.010114 +0.010214 +0.010337 +0.010387 +0.010201 +0.010129 +0.010188 +0.010271 +0.010375 +0.010437 +0.010262 +0.010181 +0.010253 +0.01034 +0.010453 +0.010481 +0.010301 +0.010219 +0.010286 +0.010372 +0.010485 +0.010557 +0.010383 +0.010259 +0.010291 +0.010336 +0.010405 +0.010424 +0.010217 +0.010114 +0.010127 +0.010194 +0.010244 +0.010228 +0.009998 +0.009857 +0.009871 +0.009919 +0.00995 +0.009961 +0.009756 +0.009639 +0.009659 +0.009697 +0.009739 +0.009736 +0.009517 +0.009405 +0.009434 +0.00949 +0.009512 +0.009484 +0.00929 +0.009183 +0.009214 +0.009256 +0.009278 +0.009305 +0.009099 +0.008995 +0.009022 +0.009061 +0.009101 +0.009114 +0.008936 +0.008821 +0.008853 +0.008899 +0.008942 +0.008966 +0.008784 +0.0087 +0.008721 +0.008766 +0.008829 +0.008866 +0.008704 +0.0086 +0.008612 +0.008665 +0.008726 +0.008761 +0.008613 +0.008522 +0.008567 +0.008628 +0.008696 +0.008762 +0.008605 +0.008544 +0.008604 +0.008649 +0.008725 +0.00879 +0.008644 +0.008561 +0.008619 +0.00869 +0.008773 +0.008844 +0.008708 +0.008621 +0.008675 +0.008746 +0.008815 +0.008904 +0.008727 +0.008653 +0.008697 +0.008781 +0.008866 +0.008943 +0.008789 +0.008705 +0.008763 +0.008847 +0.008902 +0.008957 +0.008806 +0.008737 +0.008793 +0.008911 +0.008952 +0.009003 +0.008856 +0.00879 +0.008839 +0.00891 +0.008997 +0.009058 +0.00891 +0.008837 +0.008903 +0.00899 +0.009061 +0.009102 +0.008936 +0.008868 +0.00893 +0.009001 +0.009095 +0.009163 +0.009011 +0.008908 +0.008962 +0.009045 +0.009136 +0.009194 +0.009039 +0.008964 +0.009016 +0.009098 +0.009186 +0.00925 +0.0091 +0.009003 +0.00907 +0.009142 +0.009228 +0.009298 +0.009135 +0.009084 +0.009101 +0.009179 +0.009279 +0.00935 +0.009193 +0.009099 +0.009149 +0.009229 +0.009318 +0.009391 +0.00922 +0.009136 +0.009192 +0.009274 +0.009387 +0.009446 +0.009279 +0.009183 +0.009249 +0.009326 +0.009407 +0.009485 +0.009308 +0.00923 +0.009302 +0.009392 +0.009513 +0.009527 +0.009357 +0.009273 +0.009345 +0.009415 +0.009503 +0.009574 +0.009409 +0.009332 +0.009373 +0.009469 +0.009578 +0.009612 +0.00946 +0.009368 +0.009431 +0.009516 +0.009619 +0.009675 +0.009514 +0.009434 +0.009463 +0.009561 +0.009665 +0.009718 +0.009552 +0.009473 +0.009555 +0.009649 +0.009714 +0.009773 +0.00959 +0.009495 +0.009568 +0.009654 +0.009748 +0.009827 +0.009651 +0.009549 +0.009626 +0.009693 +0.009796 +0.009871 +0.009691 +0.009616 +0.009685 +0.009774 +0.009866 +0.009929 +0.009731 +0.009647 +0.009711 +0.00981 +0.009924 +0.00998 +0.009779 +0.00973 +0.009793 +0.009869 +0.009944 +0.009987 +0.009832 +0.009746 +0.009811 +0.0099 +0.010011 +0.01006 +0.009889 +0.009809 +0.009861 +0.009951 +0.010051 +0.010118 +0.009942 +0.009867 +0.009926 +0.010004 +0.010102 +0.010179 +0.010018 +0.009894 +0.009956 +0.010048 +0.010158 +0.010251 +0.010052 +0.009959 +0.010007 +0.010084 +0.010196 +0.010262 +0.010086 +0.010005 +0.01008 +0.010163 +0.010267 +0.010337 +0.010141 +0.01004 +0.010112 +0.010197 +0.010306 +0.010385 +0.010235 +0.010102 +0.010151 +0.010241 +0.010348 +0.010429 +0.01023 +0.010156 +0.010258 +0.010326 +0.010412 +0.01047 +0.010278 +0.010201 +0.010273 +0.010353 +0.010458 +0.010544 +0.010358 +0.010267 +0.01034 +0.01041 +0.010477 +0.010557 +0.010383 +0.010285 +0.010271 +0.010327 +0.010371 +0.010385 +0.01018 +0.010051 +0.010081 +0.010121 +0.010188 +0.01017 +0.009981 +0.009837 +0.00985 +0.009879 +0.009911 +0.009937 +0.009731 +0.009606 +0.009606 +0.009655 +0.009704 +0.009711 +0.009498 +0.009391 +0.009392 +0.009426 +0.009445 +0.00948 +0.009252 +0.009152 +0.00917 +0.009199 +0.009249 +0.009296 +0.009086 +0.008981 +0.009004 +0.009028 +0.009076 +0.009099 +0.008926 +0.008815 +0.00884 +0.008901 +0.008943 +0.008975 +0.008794 +0.008698 +0.008719 +0.008748 +0.00881 +0.008836 +0.008691 +0.008577 +0.00861 +0.008643 +0.008707 +0.008763 +0.008586 +0.008501 +0.008545 +0.008608 +0.008674 +0.008734 +0.008593 +0.008543 +0.008578 +0.008651 +0.008713 +0.008781 +0.008629 +0.008557 +0.008615 +0.008678 +0.00876 +0.008832 +0.008693 +0.008611 +0.008666 +0.008741 +0.008818 +0.008882 +0.008713 +0.008634 +0.008692 +0.008759 +0.008843 +0.008919 +0.008819 +0.008691 +0.008749 +0.008815 +0.008898 +0.008943 +0.008804 +0.008727 +0.008783 +0.008862 +0.008942 +0.009001 +0.00885 +0.008784 +0.00883 +0.008899 +0.008998 +0.009042 +0.008905 +0.008825 +0.008881 +0.008975 +0.009046 +0.009096 +0.008936 +0.008865 +0.008907 +0.008993 +0.009074 +0.009142 +0.009007 +0.008901 +0.008959 +0.009044 +0.009141 +0.009194 +0.009022 +0.008957 +0.008998 +0.009081 +0.009175 +0.009236 +0.009072 +0.009 +0.009075 +0.009147 +0.009229 +0.009283 +0.009123 +0.009061 +0.009108 +0.009156 +0.009251 +0.009316 +0.009164 +0.009075 +0.009143 +0.009238 +0.009326 +0.009382 +0.009224 +0.009126 +0.009178 +0.009259 +0.009363 +0.009418 +0.009258 +0.009184 +0.009253 +0.009325 +0.009413 +0.009482 +0.009311 +0.009204 +0.009279 +0.009366 +0.009486 +0.009518 +0.009348 +0.009289 +0.009313 +0.009403 +0.009488 +0.009555 +0.009395 +0.009311 +0.009372 +0.00946 +0.009559 +0.009625 +0.009448 +0.009376 +0.009416 +0.009501 +0.0096 +0.009653 +0.009491 +0.009415 +0.009475 +0.009573 +0.009667 +0.009727 +0.009562 +0.00946 +0.009502 +0.00959 +0.009685 +0.009755 +0.009585 +0.00949 +0.009577 +0.009677 +0.009753 +0.009796 +0.009635 +0.009545 +0.009602 +0.0097 +0.009783 +0.009847 +0.009713 +0.009614 +0.009676 +0.009762 +0.009844 +0.009883 +0.009732 +0.009647 +0.009738 +0.009796 +0.009891 +0.00994 +0.009774 +0.009704 +0.009758 +0.00986 +0.009934 +0.009991 +0.009827 +0.009769 +0.009815 +0.009904 +0.009979 +0.010048 +0.009881 +0.009791 +0.009856 +0.009931 +0.010046 +0.010139 +0.009933 +0.009858 +0.009922 +0.010016 +0.010094 +0.010128 +0.009963 +0.009895 +0.009942 +0.010039 +0.010166 +0.010229 +0.010054 +0.009948 +0.009984 +0.01008 +0.010183 +0.010259 +0.010073 +0.009993 +0.010054 +0.010141 +0.010247 +0.010322 +0.010126 +0.010043 +0.010113 +0.0102 +0.010312 +0.010384 +0.0102 +0.010099 +0.010144 +0.010228 +0.010341 +0.01041 +0.010225 +0.010157 +0.010231 +0.010338 +0.010389 +0.010454 +0.010268 +0.010187 +0.010262 +0.010339 +0.010458 +0.010551 +0.010339 +0.010251 +0.010326 +0.010392 +0.010492 +0.010569 +0.0104 +0.010334 +0.010371 +0.010405 +0.010501 +0.010558 +0.010334 +0.010223 +0.01025 +0.010295 +0.010369 +0.010395 +0.010163 +0.009999 +0.010028 +0.010051 +0.010112 +0.010118 +0.009879 +0.009761 +0.009777 +0.009812 +0.009878 +0.009863 +0.009633 +0.009511 +0.009533 +0.009594 +0.009598 +0.009628 +0.00938 +0.009276 +0.009295 +0.00932 +0.009367 +0.009377 +0.009158 +0.009046 +0.009063 +0.009114 +0.009156 +0.009172 +0.008981 +0.008863 +0.008877 +0.008928 +0.008983 +0.009009 +0.008818 +0.008724 +0.008735 +0.008791 +0.008855 +0.008896 +0.008706 +0.008606 +0.008613 +0.008661 +0.008722 +0.008779 +0.008583 +0.00848 +0.008531 +0.008596 +0.00866 +0.008698 +0.008536 +0.008447 +0.008486 +0.008557 +0.008636 +0.008713 +0.008564 +0.008478 +0.008525 +0.0086 +0.008686 +0.00874 +0.008601 +0.008519 +0.00857 +0.008646 +0.008733 +0.008806 +0.008664 +0.008566 +0.008614 +0.008675 +0.008764 +0.008829 +0.008682 +0.008622 +0.008656 +0.008726 +0.008815 +0.008885 +0.008742 +0.008669 +0.008712 +0.008762 +0.00886 +0.008916 +0.008761 +0.008692 +0.008746 +0.008813 +0.008913 +0.008979 +0.008813 +0.008744 +0.008796 +0.008878 +0.008964 +0.008995 +0.008848 +0.008773 +0.008836 +0.008918 +0.00899 +0.009046 +0.008894 +0.008851 +0.008865 +0.008946 +0.009042 +0.009091 +0.008945 +0.00887 +0.008934 +0.00901 +0.009094 +0.009155 +0.008983 +0.008911 +0.008961 +0.009048 +0.009135 +0.009189 +0.009042 +0.008987 +0.009049 +0.009116 +0.009173 +0.009214 +0.009064 +0.008998 +0.009044 +0.009132 +0.009219 +0.009296 +0.00912 +0.009054 +0.009109 +0.009172 +0.009271 +0.009334 +0.00917 +0.009095 +0.009142 +0.009242 +0.009333 +0.009378 +0.009227 +0.009131 +0.009189 +0.009273 +0.009377 +0.009448 +0.009265 +0.009178 +0.009256 +0.009342 +0.009426 +0.009456 +0.009294 +0.009225 +0.009282 +0.009356 +0.00945 +0.009528 +0.009347 +0.009281 +0.009343 +0.009421 +0.009502 +0.009567 +0.009401 +0.009324 +0.009373 +0.009472 +0.009566 +0.009609 +0.00945 +0.009381 +0.009456 +0.009505 +0.009597 +0.009647 +0.009494 +0.009448 +0.00947 +0.009557 +0.009662 +0.009685 +0.009535 +0.009467 +0.009517 +0.009614 +0.009697 +0.009777 +0.009603 +0.009514 +0.009574 +0.009653 +0.009734 +0.009807 +0.009629 +0.00955 +0.009624 +0.009736 +0.00982 +0.009837 +0.009676 +0.009597 +0.009658 +0.009753 +0.009843 +0.009927 +0.009731 +0.009665 +0.009721 +0.009797 +0.009889 +0.00995 +0.009793 +0.009703 +0.009761 +0.009843 +0.009957 +0.010023 +0.009842 +0.00976 +0.009801 +0.009888 +0.010006 +0.010097 +0.009883 +0.009797 +0.009843 +0.009937 +0.010044 +0.010097 +0.009929 +0.009847 +0.009917 +0.009998 +0.010104 +0.010176 +0.009998 +0.009891 +0.009957 +0.010041 +0.010145 +0.010222 +0.010026 +0.009946 +0.01002 +0.01011 +0.010209 +0.010281 +0.010103 +0.009987 +0.010074 +0.010133 +0.010235 +0.010308 +0.010137 +0.010046 +0.010125 +0.010201 +0.010291 +0.010361 +0.010186 +0.010088 +0.010167 +0.010264 +0.010337 +0.010417 +0.010229 +0.010142 +0.010225 +0.010285 +0.010404 +0.010481 +0.010333 +0.010231 +0.010251 +0.010328 +0.010446 +0.010546 +0.01032 +0.010238 +0.010304 +0.010385 +0.010486 +0.010564 +0.010333 +0.010195 +0.010231 +0.010291 +0.010327 +0.010337 +0.010121 +0.009983 +0.009997 +0.010052 +0.010106 +0.01011 +0.009862 +0.009717 +0.009738 +0.009783 +0.009789 +0.009804 +0.00959 +0.009497 +0.009488 +0.009498 +0.009538 +0.009568 +0.009334 +0.00921 +0.00923 +0.009252 +0.009302 +0.009332 +0.009115 +0.008995 +0.009009 +0.009052 +0.009088 +0.009114 +0.008929 +0.008813 +0.008833 +0.008895 +0.00894 +0.008971 +0.00878 +0.00865 +0.008677 +0.008722 +0.008776 +0.008815 +0.008626 +0.008556 +0.008568 +0.008615 +0.008666 +0.008702 +0.008532 +0.008428 +0.008463 +0.00852 +0.008594 +0.00863 +0.008487 +0.008395 +0.008447 +0.008509 +0.008583 +0.008655 +0.008509 +0.008427 +0.008487 +0.008551 +0.008647 +0.008713 +0.008545 +0.008476 +0.008508 +0.008589 +0.008677 +0.008728 +0.00858 +0.008504 +0.008563 +0.008637 +0.008724 +0.008796 +0.008645 +0.008565 +0.008616 +0.008683 +0.008765 +0.008825 +0.008664 +0.008631 +0.008641 +0.008715 +0.008803 +0.008867 +0.008706 +0.008646 +0.008696 +0.008778 +0.008871 +0.008918 +0.008757 +0.008679 +0.008744 +0.008823 +0.008882 +0.008948 +0.008804 +0.008732 +0.008778 +0.008855 +0.008943 +0.009009 +0.008854 +0.008789 +0.008837 +0.008903 +0.00898 +0.009041 +0.008888 +0.008815 +0.008868 +0.00895 +0.009024 +0.009112 +0.008954 +0.008878 +0.008945 +0.00899 +0.009065 +0.009119 +0.008991 +0.008905 +0.008946 +0.009034 +0.009129 +0.009174 +0.009026 +0.008945 +0.008997 +0.009085 +0.009165 +0.009229 +0.00907 +0.008994 +0.009066 +0.009146 +0.009226 +0.009273 +0.009117 +0.009035 +0.009087 +0.009174 +0.009259 +0.00934 +0.009184 +0.009091 +0.009151 +0.009225 +0.009315 +0.009387 +0.009191 +0.009118 +0.00918 +0.00925 +0.009356 +0.009432 +0.009244 +0.009172 +0.009233 +0.009326 +0.009401 +0.009465 +0.009307 +0.009219 +0.009282 +0.009374 +0.009455 +0.009517 +0.009342 +0.009267 +0.009348 +0.009417 +0.009494 +0.009543 +0.009398 +0.009328 +0.009377 +0.00945 +0.00955 +0.009611 +0.009431 +0.009358 +0.009423 +0.009498 +0.009602 +0.009656 +0.009478 +0.009402 +0.009479 +0.009541 +0.009632 +0.009688 +0.009548 +0.009454 +0.009546 +0.009616 +0.009721 +0.009775 +0.009557 +0.009484 +0.00954 +0.009643 +0.009728 +0.009798 +0.00965 +0.009569 +0.009626 +0.009697 +0.009778 +0.009834 +0.009671 +0.009594 +0.009648 +0.009739 +0.009843 +0.009897 +0.009732 +0.009648 +0.009699 +0.009781 +0.009897 +0.009958 +0.009812 +0.009708 +0.00976 +0.009846 +0.009917 +0.009994 +0.009807 +0.009741 +0.009799 +0.009883 +0.009978 +0.010073 +0.009899 +0.009796 +0.009833 +0.00993 +0.010025 +0.010096 +0.009923 +0.00983 +0.00992 +0.010008 +0.010098 +0.010162 +0.009982 +0.009896 +0.00995 +0.010026 +0.010113 +0.010202 +0.010048 +0.009915 +0.00999 +0.010085 +0.010179 +0.010248 +0.010075 +0.009987 +0.010051 +0.010169 +0.010261 +0.010283 +0.010116 +0.01003 +0.010095 +0.010187 +0.010287 +0.010354 +0.0102 +0.010105 +0.010191 +0.010245 +0.01032 +0.010379 +0.010213 +0.010135 +0.010204 +0.010295 +0.010402 +0.010458 +0.010285 +0.010199 +0.010241 +0.010328 +0.010444 +0.01051 +0.010314 +0.010231 +0.010278 +0.010356 +0.010456 +0.010474 +0.01027 +0.010131 +0.010193 +0.010211 +0.010249 +0.010278 +0.010035 +0.009901 +0.009926 +0.009951 +0.010006 +0.010041 +0.009762 +0.009649 +0.009675 +0.009723 +0.00976 +0.00977 +0.009529 +0.009409 +0.009438 +0.009462 +0.009512 +0.009524 +0.009327 +0.009196 +0.009208 +0.009248 +0.009322 +0.009282 +0.009098 +0.008953 +0.008982 +0.009039 +0.009095 +0.009094 +0.008908 +0.008799 +0.008826 +0.00887 +0.008945 +0.008955 +0.00877 +0.008667 +0.008709 +0.008758 +0.008815 +0.008832 +0.008642 +0.008544 +0.008577 +0.008642 +0.008689 +0.008727 +0.008551 +0.00847 +0.008528 +0.008592 +0.008628 +0.008661 +0.008499 +0.008438 +0.008479 +0.00854 +0.008628 +0.008689 +0.008556 +0.008464 +0.008512 +0.008594 +0.008666 +0.008739 +0.008586 +0.008511 +0.008561 +0.008632 +0.008721 +0.008794 +0.008638 +0.008555 +0.008605 +0.00867 +0.008759 +0.008826 +0.008678 +0.008615 +0.00866 +0.00872 +0.008815 +0.008892 +0.008717 +0.008646 +0.00871 +0.008745 +0.008838 +0.008896 +0.008738 +0.008679 +0.008732 +0.008819 +0.008906 +0.008963 +0.008816 +0.00873 +0.00877 +0.008848 +0.00893 +0.008993 +0.008844 +0.008781 +0.008822 +0.0089 +0.008989 +0.009051 +0.008914 +0.008804 +0.008862 +0.008925 +0.009032 +0.009093 +0.008952 +0.008866 +0.008935 +0.008981 +0.009061 +0.009122 +0.008973 +0.008896 +0.008948 +0.009025 +0.009133 +0.009194 +0.009038 +0.008959 +0.009005 +0.009064 +0.009162 +0.009222 +0.009063 +0.008997 +0.009048 +0.009135 +0.009254 +0.009253 +0.009097 +0.009028 +0.009084 +0.00917 +0.009249 +0.009319 +0.00917 +0.009095 +0.009135 +0.009203 +0.009302 +0.00936 +0.009204 +0.009135 +0.009177 +0.009259 +0.009364 +0.009428 +0.009271 +0.009178 +0.009236 +0.009289 +0.009395 +0.009461 +0.009311 +0.009232 +0.009266 +0.009364 +0.009458 +0.009515 +0.009353 +0.009262 +0.009307 +0.009398 +0.009484 +0.009543 +0.009393 +0.009315 +0.009366 +0.009473 +0.00956 +0.009609 +0.009438 +0.009368 +0.009389 +0.009483 +0.009592 +0.009643 +0.009496 +0.009422 +0.009462 +0.009577 +0.009636 +0.009687 +0.009522 +0.009436 +0.009531 +0.00959 +0.009684 +0.009766 +0.009587 +0.009491 +0.00956 +0.009637 +0.009728 +0.009798 +0.009627 +0.009537 +0.009603 +0.009698 +0.009801 +0.009863 +0.009684 +0.00959 +0.009649 +0.009736 +0.009835 +0.009926 +0.009713 +0.009644 +0.009714 +0.009793 +0.009901 +0.009944 +0.009777 +0.009686 +0.009719 +0.009829 +0.009934 +0.009989 +0.00982 +0.009739 +0.0098 +0.009889 +0.009977 +0.010052 +0.009875 +0.009785 +0.009862 +0.009944 +0.010037 +0.010094 +0.009945 +0.009841 +0.009883 +0.009965 +0.010062 +0.010154 +0.009987 +0.009899 +0.009964 +0.010066 +0.010114 +0.010188 +0.010011 +0.009925 +0.00999 +0.010095 +0.010176 +0.010246 +0.010077 +0.009982 +0.010046 +0.01014 +0.010236 +0.010301 +0.010134 +0.010082 +0.010115 +0.01018 +0.010267 +0.010339 +0.010173 +0.010074 +0.010134 +0.010243 +0.010334 +0.010425 +0.010259 +0.010135 +0.010179 +0.010291 +0.010381 +0.010451 +0.010276 +0.010174 +0.010264 +0.01037 +0.010454 +0.010526 +0.010319 +0.010249 +0.010324 +0.010379 +0.010467 +0.010558 +0.010338 +0.010232 +0.010285 +0.01035 +0.010403 +0.010413 +0.010204 +0.010081 +0.010103 +0.010164 +0.0102 +0.010195 +0.009969 +0.009824 +0.009831 +0.009873 +0.009912 +0.009926 +0.009734 +0.009581 +0.009625 +0.009641 +0.009658 +0.00967 +0.009453 +0.009345 +0.009382 +0.009382 +0.009432 +0.009445 +0.009228 +0.009113 +0.009139 +0.00916 +0.009206 +0.009231 +0.009034 +0.008921 +0.008958 +0.008998 +0.00903 +0.009049 +0.008865 +0.008747 +0.008777 +0.008822 +0.008872 +0.0089 +0.008739 +0.008604 +0.008631 +0.008683 +0.008732 +0.008775 +0.008603 +0.008501 +0.00856 +0.008595 +0.008643 +0.008696 +0.008542 +0.008452 +0.008489 +0.008555 +0.008633 +0.008677 +0.008539 +0.008478 +0.00852 +0.008586 +0.008683 +0.008747 +0.008585 +0.008512 +0.008571 +0.008629 +0.008728 +0.008809 +0.008606 +0.008546 +0.008594 +0.008669 +0.008761 +0.008808 +0.008666 +0.008593 +0.008651 +0.008722 +0.008798 +0.008869 +0.008713 +0.008654 +0.008701 +0.008773 +0.008835 +0.008895 +0.008755 +0.008681 +0.008739 +0.008799 +0.00889 +0.008948 +0.00881 +0.00874 +0.00879 +0.008888 +0.008932 +0.008982 +0.008857 +0.008757 +0.008811 +0.008887 +0.008967 +0.009048 +0.008905 +0.008816 +0.008872 +0.008948 +0.00904 +0.009082 +0.008922 +0.008859 +0.008892 +0.008979 +0.009086 +0.009138 +0.008978 +0.008905 +0.008955 +0.009026 +0.009121 +0.00918 +0.009027 +0.008969 +0.008988 +0.009065 +0.009154 +0.009215 +0.009086 +0.008979 +0.009031 +0.00912 +0.009217 +0.009268 +0.009126 +0.009052 +0.009071 +0.009161 +0.00926 +0.00932 +0.00916 +0.009072 +0.009131 +0.009209 +0.009311 +0.009383 +0.009211 +0.009135 +0.009172 +0.009264 +0.009367 +0.009413 +0.009242 +0.009161 +0.009215 +0.00932 +0.009401 +0.00948 +0.009302 +0.009226 +0.009255 +0.00934 +0.009444 +0.009483 +0.009345 +0.00927 +0.009306 +0.009406 +0.009487 +0.009563 +0.009391 +0.009301 +0.009375 +0.009435 +0.009548 +0.009624 +0.00945 +0.009379 +0.009407 +0.009492 +0.009585 +0.009641 +0.009488 +0.009384 +0.009462 +0.009555 +0.009668 +0.009689 +0.009531 +0.009437 +0.009501 +0.00959 +0.009689 +0.009743 +0.009575 +0.009505 +0.009539 +0.009636 +0.009737 +0.009801 +0.009631 +0.009557 +0.009615 +0.009722 +0.009806 +0.00986 +0.009646 +0.009579 +0.009646 +0.009726 +0.009828 +0.009891 +0.009722 +0.009648 +0.009727 +0.009796 +0.009888 +0.009931 +0.00977 +0.009689 +0.009744 +0.00984 +0.009923 +0.01001 +0.009844 +0.009744 +0.009818 +0.009902 +0.009989 +0.010062 +0.009853 +0.009763 +0.009874 +0.009935 +0.010011 +0.010087 +0.009914 +0.009841 +0.00989 +0.009974 +0.01009 +0.010154 +0.009992 +0.009905 +0.009943 +0.01002 +0.010137 +0.010193 +0.010016 +0.009945 +0.009983 +0.010104 +0.010213 +0.010278 +0.010103 +0.009976 +0.01003 +0.010119 +0.010232 +0.010322 +0.010104 +0.010026 +0.010105 +0.010197 +0.010304 +0.010358 +0.010156 +0.01008 +0.010143 +0.010217 +0.010332 +0.010421 +0.01022 +0.010137 +0.010203 +0.010293 +0.010399 +0.01046 +0.010312 +0.010183 +0.010241 +0.010351 +0.010435 +0.010499 +0.010305 +0.010223 +0.010279 +0.010327 +0.010405 +0.010442 +0.010218 +0.010085 +0.010121 +0.010146 +0.0102 +0.010203 +0.009976 +0.00983 +0.009857 +0.009917 +0.009958 +0.009949 +0.009728 +0.009636 +0.009582 +0.009625 +0.009673 +0.00968 +0.009479 +0.009341 +0.009366 +0.009418 +0.009452 +0.009455 +0.009244 +0.009111 +0.009139 +0.009183 +0.00923 +0.00923 +0.009028 +0.008917 +0.00893 +0.008979 +0.009022 +0.009041 +0.008847 +0.008738 +0.008773 +0.008839 +0.008896 +0.008884 +0.008694 +0.008615 +0.008615 +0.008681 +0.00872 +0.008749 +0.008573 +0.008489 +0.008512 +0.008572 +0.008624 +0.00866 +0.008488 +0.008392 +0.008438 +0.008496 +0.00856 +0.008602 +0.008454 +0.008374 +0.00843 +0.008483 +0.008582 +0.008618 +0.008489 +0.008412 +0.008452 +0.008547 +0.008615 +0.008663 +0.008528 +0.008455 +0.008519 +0.008584 +0.008641 +0.008702 +0.008567 +0.008482 +0.008534 +0.008614 +0.008697 +0.008766 +0.008618 +0.008542 +0.008592 +0.00868 +0.008732 +0.008798 +0.008637 +0.008573 +0.008623 +0.008714 +0.008794 +0.008857 +0.008691 +0.008619 +0.008692 +0.008744 +0.008817 +0.008881 +0.008728 +0.008661 +0.008722 +0.008807 +0.008891 +0.008938 +0.008772 +0.008695 +0.008757 +0.008832 +0.008914 +0.008973 +0.008837 +0.008749 +0.008802 +0.008874 +0.008963 +0.009025 +0.008866 +0.008798 +0.00885 +0.008924 +0.00901 +0.009078 +0.008957 +0.00884 +0.008881 +0.008956 +0.00904 +0.00911 +0.008959 +0.008874 +0.008938 +0.009024 +0.009128 +0.009165 +0.009009 +0.008925 +0.008964 +0.009051 +0.009146 +0.00919 +0.009043 +0.008978 +0.009043 +0.009122 +0.009207 +0.009265 +0.009106 +0.009012 +0.009056 +0.009143 +0.009265 +0.009291 +0.009167 +0.009053 +0.00911 +0.009198 +0.009268 +0.009335 +0.009186 +0.0091 +0.009154 +0.009249 +0.009339 +0.00941 +0.009246 +0.009159 +0.009207 +0.009276 +0.009368 +0.009437 +0.009278 +0.009193 +0.009265 +0.009357 +0.009446 +0.009507 +0.009336 +0.009266 +0.009294 +0.009353 +0.009463 +0.009543 +0.009369 +0.009275 +0.009344 +0.009444 +0.009516 +0.009584 +0.009419 +0.00933 +0.00939 +0.009465 +0.009582 +0.009644 +0.009471 +0.009383 +0.009443 +0.009536 +0.009616 +0.009688 +0.009503 +0.009426 +0.00949 +0.009617 +0.009686 +0.009723 +0.009548 +0.009467 +0.009541 +0.009615 +0.009702 +0.009772 +0.009613 +0.009534 +0.009591 +0.009683 +0.009767 +0.009812 +0.009673 +0.009566 +0.009619 +0.009721 +0.00982 +0.009866 +0.009707 +0.009623 +0.00968 +0.009765 +0.009866 +0.009953 +0.009746 +0.009668 +0.009733 +0.009825 +0.009906 +0.009971 +0.009793 +0.009744 +0.009763 +0.009852 +0.009961 +0.010038 +0.00986 +0.00978 +0.009834 +0.009901 +0.01001 +0.010069 +0.00989 +0.009813 +0.009885 +0.009963 +0.010068 +0.01013 +0.009975 +0.009899 +0.009905 +0.009998 +0.010105 +0.010182 +0.009996 +0.009914 +0.009977 +0.010071 +0.010165 +0.010234 +0.010047 +0.009956 +0.010028 +0.01011 +0.01022 +0.010305 +0.010116 +0.010008 +0.010071 +0.010172 +0.01027 +0.010332 +0.010149 +0.010096 +0.010149 +0.010223 +0.010344 +0.010353 +0.010192 +0.010103 +0.010165 +0.01027 +0.010359 +0.010446 +0.010285 +0.01017 +0.010223 +0.010311 +0.010368 +0.01042 +0.010234 +0.010085 +0.010144 +0.010195 +0.010261 +0.010266 +0.010033 +0.009911 +0.009945 +0.009999 +0.010011 +0.010015 +0.009843 +0.009682 +0.009677 +0.009723 +0.009762 +0.009748 +0.009535 +0.009408 +0.00942 +0.009474 +0.00949 +0.009503 +0.009278 +0.009156 +0.00917 +0.009204 +0.009237 +0.009257 +0.009059 +0.008944 +0.008956 +0.009011 +0.009049 +0.009082 +0.008862 +0.008755 +0.008774 +0.008824 +0.008884 +0.008919 +0.008728 +0.008615 +0.008658 +0.008694 +0.008748 +0.008767 +0.008589 +0.008493 +0.008522 +0.008583 +0.00864 +0.008671 +0.008506 +0.008416 +0.008451 +0.008509 +0.008587 +0.008619 +0.00846 +0.008376 +0.008438 +0.008505 +0.008611 +0.008631 +0.008486 +0.008424 +0.008476 +0.008554 +0.008624 +0.008684 +0.008524 +0.008484 +0.008504 +0.008582 +0.008667 +0.008726 +0.00858 +0.008497 +0.008559 +0.008625 +0.008713 +0.008776 +0.008631 +0.00855 +0.0086 +0.008675 +0.008755 +0.008842 +0.008662 +0.008598 +0.008643 +0.00874 +0.008827 +0.008839 +0.008698 +0.008624 +0.00869 +0.008755 +0.008841 +0.00891 +0.008767 +0.008684 +0.008725 +0.008802 +0.008887 +0.008947 +0.008798 +0.008733 +0.008772 +0.008849 +0.008948 +0.009008 +0.008845 +0.008761 +0.008816 +0.008893 +0.00897 +0.009042 +0.008886 +0.008835 +0.008862 +0.00895 +0.009042 +0.009087 +0.008935 +0.008856 +0.008896 +0.008973 +0.009068 +0.009123 +0.00897 +0.008908 +0.008959 +0.009014 +0.009112 +0.00918 +0.009021 +0.00894 +0.008997 +0.009078 +0.009162 +0.00923 +0.009089 +0.00899 +0.009034 +0.009116 +0.009214 +0.009294 +0.009105 +0.009022 +0.009077 +0.009165 +0.009303 +0.009309 +0.009161 +0.009083 +0.009124 +0.009196 +0.009288 +0.009363 +0.009198 +0.009121 +0.009192 +0.009264 +0.009346 +0.009409 +0.009253 +0.009161 +0.009207 +0.009298 +0.009401 +0.009463 +0.00932 +0.009236 +0.009318 +0.009342 +0.009432 +0.009499 +0.009333 +0.00926 +0.009302 +0.009413 +0.009502 +0.009554 +0.009396 +0.009315 +0.009371 +0.009432 +0.009531 +0.009609 +0.009426 +0.00935 +0.009413 +0.009494 +0.009582 +0.009648 +0.009484 +0.009411 +0.009448 +0.009551 +0.009672 +0.009702 +0.009537 +0.009445 +0.00949 +0.009585 +0.009669 +0.009742 +0.009573 +0.009504 +0.009559 +0.009636 +0.009757 +0.009801 +0.009633 +0.009548 +0.009595 +0.009677 +0.00978 +0.009839 +0.009659 +0.009594 +0.009665 +0.009751 +0.009838 +0.009902 +0.009753 +0.009628 +0.009713 +0.009763 +0.009866 +0.009958 +0.009753 +0.009678 +0.009744 +0.009822 +0.009924 +0.00999 +0.009815 +0.009735 +0.009812 +0.00991 +0.009998 +0.010023 +0.00987 +0.009773 +0.009835 +0.009933 +0.010019 +0.010086 +0.009945 +0.009872 +0.009928 +0.009983 +0.010062 +0.010139 +0.009962 +0.009868 +0.009929 +0.010023 +0.010125 +0.010209 +0.010033 +0.009951 +0.01 +0.01007 +0.01017 +0.010241 +0.01006 +0.009983 +0.010038 +0.010128 +0.010227 +0.010292 +0.010124 +0.010039 +0.010112 +0.010204 +0.010279 +0.010339 +0.010164 +0.010089 +0.010173 +0.010224 +0.010337 +0.010385 +0.010214 +0.010138 +0.010191 +0.010292 +0.010411 +0.010481 +0.01025 +0.01018 +0.010236 +0.010336 +0.010438 +0.01048 +0.010297 +0.010223 +0.010278 +0.010358 +0.010366 +0.010356 +0.010153 +0.010033 +0.010063 +0.01012 +0.01018 +0.010196 +0.009951 +0.009815 +0.009838 +0.009868 +0.009882 +0.009895 +0.009687 +0.009579 +0.009596 +0.009611 +0.009643 +0.009656 +0.009459 +0.009324 +0.009345 +0.009386 +0.009424 +0.009472 +0.009238 +0.009119 +0.009129 +0.009157 +0.009212 +0.009216 +0.009031 +0.008929 +0.008956 +0.008991 +0.009053 +0.009087 +0.00888 +0.008786 +0.008812 +0.008845 +0.008897 +0.008909 +0.008749 +0.008657 +0.00868 +0.008721 +0.008777 +0.008797 +0.008629 +0.008545 +0.008575 +0.008648 +0.008683 +0.008726 +0.008554 +0.008465 +0.008521 +0.008583 +0.008626 +0.00868 +0.008543 +0.008467 +0.008531 +0.008594 +0.008681 +0.00874 +0.008589 +0.00853 +0.008568 +0.008645 +0.008715 +0.008777 +0.008623 +0.008552 +0.008608 +0.008686 +0.008765 +0.00882 +0.008681 +0.008601 +0.00868 +0.008738 +0.008812 +0.008849 +0.008715 +0.008657 +0.008689 +0.008777 +0.008854 +0.008905 +0.008748 +0.008679 +0.008738 +0.008813 +0.008892 +0.00896 +0.008805 +0.008723 +0.008783 +0.008865 +0.008957 +0.008996 +0.008839 +0.00878 +0.008822 +0.008899 +0.008982 +0.009047 +0.008912 +0.00884 +0.008875 +0.008944 +0.009029 +0.009092 +0.008924 +0.008875 +0.008901 +0.008989 +0.009067 +0.009136 +0.008977 +0.008908 +0.008956 +0.009029 +0.009128 +0.00918 +0.009023 +0.008951 +0.009003 +0.009079 +0.009176 +0.009254 +0.009066 +0.008987 +0.009042 +0.009122 +0.009247 +0.009274 +0.009104 +0.009041 +0.00909 +0.009175 +0.009275 +0.009329 +0.009154 +0.009083 +0.009128 +0.009217 +0.009309 +0.009369 +0.009202 +0.009126 +0.009196 +0.00928 +0.009375 +0.00944 +0.009233 +0.009162 +0.009227 +0.009302 +0.009395 +0.009459 +0.009312 +0.00927 +0.009312 +0.009356 +0.00944 +0.00949 +0.009334 +0.00926 +0.009306 +0.009395 +0.009501 +0.009553 +0.009399 +0.009322 +0.009374 +0.00944 +0.009547 +0.009584 +0.009439 +0.009361 +0.009424 +0.009516 +0.009599 +0.009658 +0.009485 +0.009403 +0.009472 +0.009555 +0.009643 +0.00968 +0.009537 +0.009488 +0.009513 +0.009601 +0.009695 +0.009732 +0.009583 +0.009504 +0.009546 +0.009641 +0.009748 +0.009779 +0.009626 +0.009542 +0.009607 +0.009695 +0.009788 +0.009844 +0.009685 +0.009616 +0.009659 +0.00974 +0.009832 +0.009912 +0.009739 +0.009635 +0.009694 +0.00978 +0.009887 +0.009978 +0.009776 +0.009701 +0.009758 +0.009824 +0.009924 +0.009994 +0.009829 +0.009732 +0.009808 +0.009873 +0.009978 +0.01005 +0.009871 +0.009791 +0.009854 +0.009943 +0.010037 +0.010108 +0.009948 +0.009872 +0.009873 +0.009973 +0.010076 +0.010147 +0.009973 +0.009877 +0.00995 +0.010054 +0.010149 +0.010206 +0.010034 +0.009922 +0.009987 +0.010088 +0.010188 +0.010267 +0.010071 +0.009972 +0.010038 +0.010144 +0.010234 +0.010298 +0.010123 +0.010055 +0.010128 +0.010175 +0.010294 +0.010351 +0.010163 +0.010073 +0.010135 +0.010249 +0.010351 +0.010401 +0.010223 +0.010147 +0.010208 +0.0103 +0.010391 +0.010439 +0.010269 +0.010191 +0.010242 +0.01034 +0.010464 +0.010504 +0.010314 +0.010221 +0.010308 +0.010298 +0.01039 +0.01037 +0.010177 +0.010058 +0.010095 +0.010133 +0.010173 +0.010194 +0.009971 +0.009838 +0.009852 +0.009886 +0.009932 +0.009955 +0.009725 +0.009596 +0.009596 +0.009644 +0.009673 +0.009684 +0.009469 +0.009337 +0.009368 +0.009423 +0.00945 +0.00948 +0.009232 +0.009122 +0.00913 +0.009156 +0.009205 +0.009197 +0.009011 +0.008913 +0.008921 +0.008965 +0.009006 +0.009035 +0.008834 +0.008735 +0.00876 +0.008814 +0.008856 +0.008889 +0.008712 +0.008601 +0.008626 +0.008674 +0.008724 +0.008745 +0.008564 +0.00848 +0.008511 +0.008585 +0.008636 +0.008647 +0.00848 +0.008405 +0.008453 +0.008525 +0.00856 +0.008611 +0.008466 +0.008399 +0.008458 +0.008542 +0.008611 +0.008657 +0.008518 +0.00846 +0.008486 +0.008563 +0.008642 +0.008712 +0.008559 +0.008484 +0.008555 +0.008629 +0.008696 +0.008743 +0.008599 +0.008526 +0.008601 +0.008669 +0.008726 +0.008774 +0.008643 +0.008584 +0.008642 +0.008725 +0.008813 +0.008823 +0.008673 +0.008605 +0.008656 +0.008742 +0.008812 +0.00888 +0.008727 +0.008654 +0.008714 +0.008779 +0.008875 +0.008927 +0.008776 +0.008706 +0.008756 +0.008819 +0.008923 +0.008991 +0.008833 +0.008764 +0.008788 +0.008871 +0.008949 +0.009005 +0.008867 +0.00879 +0.00884 +0.008925 +0.009034 +0.009066 +0.008902 +0.00883 +0.00888 +0.008958 +0.009043 +0.009115 +0.008948 +0.008878 +0.008948 +0.009011 +0.009105 +0.009163 +0.009005 +0.008907 +0.008971 +0.009057 +0.009149 +0.009226 +0.009064 +0.00895 +0.009005 +0.009088 +0.009184 +0.009246 +0.009083 +0.009012 +0.009067 +0.009141 +0.009238 +0.009299 +0.00914 +0.009051 +0.009112 +0.009185 +0.009278 +0.009341 +0.009189 +0.009098 +0.009167 +0.009247 +0.009339 +0.0094 +0.009235 +0.009144 +0.009226 +0.009276 +0.009363 +0.009421 +0.009278 +0.009198 +0.009251 +0.009344 +0.009437 +0.009497 +0.009312 +0.009228 +0.009292 +0.009367 +0.009461 +0.009539 +0.009362 +0.009288 +0.00935 +0.009429 +0.009518 +0.009586 +0.009412 +0.00933 +0.009383 +0.009477 +0.009594 +0.009653 +0.009445 +0.009372 +0.009442 +0.009517 +0.009628 +0.009666 +0.009501 +0.009429 +0.009491 +0.009575 +0.009675 +0.009723 +0.009543 +0.009476 +0.009534 +0.009607 +0.009708 +0.009774 +0.009616 +0.00953 +0.009594 +0.009667 +0.009753 +0.00982 +0.009655 +0.009591 +0.009613 +0.009713 +0.009807 +0.009855 +0.009698 +0.009613 +0.009687 +0.009783 +0.009839 +0.0099 +0.009752 +0.009675 +0.009731 +0.009823 +0.009922 +0.00995 +0.009796 +0.009705 +0.009771 +0.009859 +0.009963 +0.010008 +0.009843 +0.009765 +0.00985 +0.009922 +0.009991 +0.010059 +0.009893 +0.009815 +0.009865 +0.009958 +0.010063 +0.010109 +0.009951 +0.009865 +0.009917 +0.01 +0.010117 +0.010174 +0.009998 +0.009932 +0.009984 +0.010056 +0.010158 +0.010222 +0.010039 +0.009954 +0.01002 +0.010142 +0.010234 +0.01028 +0.010119 +0.009981 +0.010064 +0.010147 +0.010254 +0.010331 +0.010136 +0.010065 +0.010152 +0.010219 +0.010324 +0.010389 +0.010177 +0.010102 +0.010173 +0.010255 +0.01038 +0.010442 +0.010246 +0.010146 +0.010224 +0.010327 +0.010453 +0.010473 +0.010285 +0.010215 +0.010325 +0.010377 +0.010448 +0.010523 +0.010331 +0.010237 +0.010302 +0.010372 +0.010463 +0.010517 +0.01027 +0.010139 +0.010158 +0.010194 +0.010254 +0.01023 +0.01 +0.009876 +0.009914 +0.009921 +0.009968 +0.009953 +0.009744 +0.009574 +0.009582 +0.009617 +0.009662 +0.0097 +0.009421 +0.009295 +0.009315 +0.009339 +0.009376 +0.009384 +0.009165 +0.009039 +0.009066 +0.009116 +0.009153 +0.009152 +0.008959 +0.008834 +0.008857 +0.008903 +0.00895 +0.008959 +0.008778 +0.008673 +0.008713 +0.008785 +0.008805 +0.00881 +0.008619 +0.008524 +0.008563 +0.008612 +0.008662 +0.008706 +0.008514 +0.008422 +0.008459 +0.008515 +0.00857 +0.008593 +0.008423 +0.008329 +0.008369 +0.008433 +0.008501 +0.008552 +0.008402 +0.008307 +0.008359 +0.008443 +0.008516 +0.008571 +0.008438 +0.008364 +0.008423 +0.008483 +0.00855 +0.008625 +0.008466 +0.0084 +0.008445 +0.008511 +0.0086 +0.008661 +0.008515 +0.008451 +0.008477 +0.008566 +0.008653 +0.008709 +0.008565 +0.008493 +0.008533 +0.008598 +0.008684 +0.008757 +0.008608 +0.008518 +0.008579 +0.008637 +0.008724 +0.008788 +0.008648 +0.008585 +0.008631 +0.008691 +0.00878 +0.008824 +0.008677 +0.008612 +0.008662 +0.00873 +0.008818 +0.008874 +0.008726 +0.008655 +0.00872 +0.008774 +0.008855 +0.008924 +0.008777 +0.008695 +0.008753 +0.008842 +0.008903 +0.008964 +0.008813 +0.008741 +0.008791 +0.008861 +0.00896 +0.009025 +0.008889 +0.008793 +0.008833 +0.008914 +0.009014 +0.009046 +0.008893 +0.008819 +0.008878 +0.008956 +0.009045 +0.009099 +0.008947 +0.008869 +0.00893 +0.009001 +0.009092 +0.009145 +0.008998 +0.008929 +0.008971 +0.009048 +0.009149 +0.009204 +0.009034 +0.008958 +0.009019 +0.009106 +0.009207 +0.00923 +0.009073 +0.009001 +0.009053 +0.009147 +0.009259 +0.00928 +0.009129 +0.009042 +0.009106 +0.009188 +0.009279 +0.009337 +0.009175 +0.009102 +0.009156 +0.009237 +0.009333 +0.00939 +0.009211 +0.009134 +0.009202 +0.009282 +0.009368 +0.009434 +0.00929 +0.009218 +0.009242 +0.009319 +0.009412 +0.009454 +0.009315 +0.009228 +0.009295 +0.009402 +0.009468 +0.009508 +0.009353 +0.009275 +0.009327 +0.009414 +0.009516 +0.009573 +0.00941 +0.009342 +0.00941 +0.009474 +0.009564 +0.009607 +0.009454 +0.009367 +0.009431 +0.009542 +0.009638 +0.009655 +0.009505 +0.009426 +0.009488 +0.009568 +0.00964 +0.009706 +0.009548 +0.009464 +0.009524 +0.009621 +0.009696 +0.009767 +0.009602 +0.009512 +0.009575 +0.00966 +0.009771 +0.00982 +0.009647 +0.009576 +0.009634 +0.009699 +0.009807 +0.009889 +0.009703 +0.009603 +0.00968 +0.009737 +0.009844 +0.009932 +0.009755 +0.009674 +0.009719 +0.009812 +0.009891 +0.009962 +0.009787 +0.0097 +0.009778 +0.009861 +0.009943 +0.010026 +0.009839 +0.009753 +0.009829 +0.009904 +0.010003 +0.010073 +0.009914 +0.009851 +0.009865 +0.00993 +0.010032 +0.01011 +0.009959 +0.009849 +0.009901 +0.01001 +0.010098 +0.010183 +0.010008 +0.009897 +0.009958 +0.010059 +0.010147 +0.010213 +0.010053 +0.009946 +0.010024 +0.010127 +0.010218 +0.010268 +0.01009 +0.010011 +0.010093 +0.010141 +0.010233 +0.010304 +0.010139 +0.010048 +0.01013 +0.010217 +0.0103 +0.010358 +0.010195 +0.010106 +0.010167 +0.01028 +0.010355 +0.01039 +0.010213 +0.010127 +0.010161 +0.010224 +0.010294 +0.010301 +0.010116 +0.009997 +0.010023 +0.010043 +0.010098 +0.010124 +0.009861 +0.009728 +0.009749 +0.009797 +0.009835 +0.009869 +0.009613 +0.009491 +0.009483 +0.009512 +0.009562 +0.009561 +0.00936 +0.009261 +0.009249 +0.009281 +0.009315 +0.009328 +0.009124 +0.009005 +0.00902 +0.009055 +0.009084 +0.009109 +0.008916 +0.008845 +0.008824 +0.008851 +0.008887 +0.008915 +0.00875 +0.008647 +0.008667 +0.008715 +0.008769 +0.008807 +0.008623 +0.008525 +0.008555 +0.008579 +0.008633 +0.008674 +0.008501 +0.008422 +0.008447 +0.008506 +0.008554 +0.008599 +0.008451 +0.008378 +0.008418 +0.008472 +0.008535 +0.008595 +0.008477 +0.008392 +0.00845 +0.00849 +0.008573 +0.008645 +0.00851 +0.008432 +0.008478 +0.008556 +0.008625 +0.008675 +0.008535 +0.00847 +0.008508 +0.008588 +0.008666 +0.008727 +0.008598 +0.008516 +0.008579 +0.008634 +0.008722 +0.008761 +0.008625 +0.008564 +0.008601 +0.008677 +0.00875 +0.008839 +0.008675 +0.008588 +0.008635 +0.008726 +0.008793 +0.008862 +0.008701 +0.008639 +0.008694 +0.008769 +0.00886 +0.008916 +0.008754 +0.008674 +0.008728 +0.008811 +0.008886 +0.00896 +0.008796 +0.008734 +0.008786 +0.00886 +0.008947 +0.009002 +0.008839 +0.008762 +0.008821 +0.008908 +0.008999 +0.009029 +0.008878 +0.008801 +0.008862 +0.008959 +0.009038 +0.009091 +0.008933 +0.008846 +0.008902 +0.008977 +0.00908 +0.009132 +0.008973 +0.008913 +0.008962 +0.009047 +0.009127 +0.009188 +0.009022 +0.008932 +0.008997 +0.009065 +0.009159 +0.009225 +0.009098 +0.009007 +0.009047 +0.00911 +0.009193 +0.009262 +0.009102 +0.00903 +0.009089 +0.009172 +0.009283 +0.009316 +0.009169 +0.009087 +0.009126 +0.009206 +0.009301 +0.00937 +0.009218 +0.009121 +0.009177 +0.009258 +0.009367 +0.009427 +0.009261 +0.009158 +0.009219 +0.009307 +0.009417 +0.009494 +0.009277 +0.0092 +0.009264 +0.009357 +0.009463 +0.009512 +0.00935 +0.009257 +0.009304 +0.009397 +0.009492 +0.009546 +0.009389 +0.009311 +0.009388 +0.009466 +0.00955 +0.009614 +0.009447 +0.009337 +0.009402 +0.009481 +0.009581 +0.009657 +0.009501 +0.009428 +0.009458 +0.009537 +0.009635 +0.009683 +0.009527 +0.009442 +0.009501 +0.009594 +0.009685 +0.009761 +0.009569 +0.009525 +0.009547 +0.009638 +0.009735 +0.009797 +0.009624 +0.009552 +0.009603 +0.0097 +0.009809 +0.009842 +0.009662 +0.00959 +0.009649 +0.009776 +0.009827 +0.009876 +0.009731 +0.009654 +0.009731 +0.009785 +0.009875 +0.009937 +0.009758 +0.009684 +0.00975 +0.00983 +0.009926 +0.009997 +0.009832 +0.009747 +0.009802 +0.009895 +0.009975 +0.010049 +0.009879 +0.009796 +0.009866 +0.009928 +0.010051 +0.010111 +0.009907 +0.00983 +0.009888 +0.00999 +0.010074 +0.010187 +0.009988 +0.009888 +0.00993 +0.010032 +0.010128 +0.010193 +0.010024 +0.009942 +0.010011 +0.010102 +0.010203 +0.010248 +0.010076 +0.009974 +0.010037 +0.010133 +0.01024 +0.010351 +0.010117 +0.010025 +0.01009 +0.010178 +0.010291 +0.010337 +0.010172 +0.010098 +0.010171 +0.010247 +0.01036 +0.01038 +0.01021 +0.010143 +0.010197 +0.010286 +0.010397 +0.010467 +0.010281 +0.010194 +0.010234 +0.010315 +0.010395 +0.010442 +0.010239 +0.01011 +0.010096 +0.010172 +0.010232 +0.010226 +0.009995 +0.009856 +0.009891 +0.009926 +0.00998 +0.009955 +0.009752 +0.009624 +0.009618 +0.009659 +0.00968 +0.009668 +0.009443 +0.00932 +0.009326 +0.009363 +0.009398 +0.009415 +0.009193 +0.009068 +0.00909 +0.009129 +0.009181 +0.00919 +0.008957 +0.008845 +0.008868 +0.008924 +0.008945 +0.00896 +0.008777 +0.008674 +0.008694 +0.008748 +0.008804 +0.008824 +0.00865 +0.00856 +0.008589 +0.008638 +0.008681 +0.008697 +0.008528 +0.008432 +0.00846 +0.00853 +0.008576 +0.008609 +0.008461 +0.008371 +0.008417 +0.008485 +0.008522 +0.008564 +0.008404 +0.008325 +0.008381 +0.008448 +0.00853 +0.008606 +0.008464 +0.008368 +0.008419 +0.008496 +0.008579 +0.008651 +0.008483 +0.008414 +0.008461 +0.008538 +0.008621 +0.008691 +0.00854 +0.008466 +0.008502 +0.008581 +0.008663 +0.008724 +0.008582 +0.00851 +0.008572 +0.008624 +0.008708 +0.008785 +0.00863 +0.00855 +0.00863 +0.008648 +0.008735 +0.008808 +0.008651 +0.00858 +0.008641 +0.008712 +0.008812 +0.008866 +0.008716 +0.008632 +0.008684 +0.008744 +0.008839 +0.00889 +0.008744 +0.008678 +0.008731 +0.008795 +0.008883 +0.008949 +0.00881 +0.008733 +0.008758 +0.008838 +0.008911 +0.008989 +0.008849 +0.008764 +0.008825 +0.008898 +0.008963 +0.009033 +0.008881 +0.00881 +0.008863 +0.00893 +0.009015 +0.009087 +0.008934 +0.008869 +0.008915 +0.00898 +0.009047 +0.009122 +0.008962 +0.008889 +0.008936 +0.009031 +0.009129 +0.009199 +0.009002 +0.008928 +0.008984 +0.009072 +0.009154 +0.009214 +0.009063 +0.008991 +0.009047 +0.009128 +0.009187 +0.009264 +0.009107 +0.009031 +0.009088 +0.009164 +0.009242 +0.009315 +0.00917 +0.009089 +0.009131 +0.009213 +0.009272 +0.009353 +0.009202 +0.009118 +0.009203 +0.009253 +0.009351 +0.009396 +0.009247 +0.009175 +0.009215 +0.009298 +0.009385 +0.00943 +0.009292 +0.009205 +0.009277 +0.00935 +0.009442 +0.009506 +0.009325 +0.009249 +0.009307 +0.009396 +0.009482 +0.009541 +0.009391 +0.009303 +0.009374 +0.009461 +0.009559 +0.009602 +0.009416 +0.00933 +0.009396 +0.009512 +0.009571 +0.009626 +0.009486 +0.009418 +0.009462 +0.00954 +0.009631 +0.009677 +0.009519 +0.009435 +0.009496 +0.009582 +0.009671 +0.009749 +0.009568 +0.009492 +0.009552 +0.009632 +0.009723 +0.009792 +0.009628 +0.009573 +0.009602 +0.009688 +0.009757 +0.009828 +0.009669 +0.009576 +0.009632 +0.00973 +0.009826 +0.0099 +0.009741 +0.009648 +0.009703 +0.009766 +0.009877 +0.009936 +0.009755 +0.009681 +0.009728 +0.009845 +0.009935 +0.009993 +0.009819 +0.009748 +0.009807 +0.009886 +0.009952 +0.010021 +0.009867 +0.009786 +0.009827 +0.009918 +0.010022 +0.01009 +0.00991 +0.009821 +0.009891 +0.009974 +0.010102 +0.010155 +0.009954 +0.009874 +0.009959 +0.010013 +0.010118 +0.010193 +0.010004 +0.009939 +0.010012 +0.010113 +0.010204 +0.010246 +0.010034 +0.009955 +0.010032 +0.010111 +0.010221 +0.010299 +0.010117 +0.010028 +0.010104 +0.010198 +0.010262 +0.010338 +0.010158 +0.010071 +0.010138 +0.010234 +0.010327 +0.0104 +0.010215 +0.010128 +0.010189 +0.010287 +0.010427 +0.010424 +0.010244 +0.010186 +0.010181 +0.010259 +0.010324 +0.010349 +0.010132 +0.009991 +0.01002 +0.010074 +0.01012 +0.010143 +0.009914 +0.009769 +0.009787 +0.009804 +0.00984 +0.009855 +0.009634 +0.009521 +0.009526 +0.009587 +0.009604 +0.009609 +0.009406 +0.009291 +0.009301 +0.009311 +0.009343 +0.009351 +0.009154 +0.009061 +0.009055 +0.009083 +0.009132 +0.009139 +0.00894 +0.008841 +0.008865 +0.008914 +0.008936 +0.008972 +0.008779 +0.008679 +0.008691 +0.008749 +0.008786 +0.008809 +0.008641 +0.008543 +0.008572 +0.008622 +0.008692 +0.008716 +0.008556 +0.008439 +0.008477 +0.008511 +0.00857 +0.008616 +0.008443 +0.008367 +0.00841 +0.008478 +0.008534 +0.008581 +0.008445 +0.008374 +0.008428 +0.008499 +0.008587 +0.008611 +0.008472 +0.0084 +0.008457 +0.008521 +0.008603 +0.008671 +0.008536 +0.008454 +0.008509 +0.008583 +0.008663 +0.008725 +0.008552 +0.008483 +0.008527 +0.008612 +0.008701 +0.008765 +0.008596 +0.008548 +0.008581 +0.008655 +0.008734 +0.008794 +0.008648 +0.008577 +0.008625 +0.008707 +0.00879 +0.008858 +0.008679 +0.008618 +0.008661 +0.008738 +0.008825 +0.008887 +0.008728 +0.008661 +0.008732 +0.00881 +0.00891 +0.008919 +0.008779 +0.008687 +0.008754 +0.008832 +0.008913 +0.008968 +0.008821 +0.008745 +0.00882 +0.008882 +0.008976 +0.009022 +0.00887 +0.008781 +0.008842 +0.008923 +0.008997 +0.009068 +0.008914 +0.00883 +0.008888 +0.008967 +0.009046 +0.009117 +0.008965 +0.008886 +0.008965 +0.009006 +0.009096 +0.009154 +0.009 +0.00893 +0.008979 +0.009051 +0.009141 +0.009204 +0.009044 +0.008966 +0.009054 +0.009098 +0.009189 +0.009262 +0.009102 +0.009008 +0.009061 +0.00915 +0.009237 +0.009296 +0.009156 +0.00905 +0.009117 +0.009197 +0.009304 +0.009381 +0.009195 +0.009095 +0.009138 +0.009235 +0.00934 +0.009384 +0.009224 +0.009145 +0.009225 +0.009292 +0.009379 +0.009452 +0.009277 +0.009181 +0.009241 +0.009336 +0.009419 +0.009484 +0.009345 +0.009235 +0.009293 +0.009379 +0.009475 +0.009533 +0.009367 +0.009286 +0.009377 +0.009441 +0.009533 +0.009588 +0.009413 +0.009326 +0.009395 +0.009463 +0.00956 +0.009628 +0.009457 +0.009381 +0.009461 +0.009541 +0.009628 +0.009696 +0.009514 +0.009416 +0.009482 +0.009563 +0.009661 +0.009731 +0.009559 +0.009481 +0.009535 +0.009627 +0.009744 +0.009785 +0.009603 +0.009517 +0.009577 +0.009685 +0.009783 +0.009816 +0.009657 +0.009589 +0.009622 +0.009707 +0.009816 +0.009865 +0.009707 +0.009646 +0.009691 +0.00978 +0.009872 +0.009903 +0.009749 +0.009672 +0.009726 +0.009814 +0.009907 +0.010001 +0.009849 +0.009733 +0.00979 +0.009857 +0.009941 +0.010017 +0.00985 +0.009758 +0.009842 +0.009901 +0.010031 +0.010071 +0.009892 +0.009808 +0.009879 +0.009954 +0.010064 +0.010138 +0.00997 +0.009881 +0.009913 +0.010015 +0.010107 +0.010175 +0.010009 +0.00994 +0.009982 +0.010083 +0.0102 +0.010216 +0.010054 +0.009951 +0.010005 +0.010115 +0.010202 +0.010273 +0.010111 +0.010014 +0.010089 +0.010186 +0.010273 +0.010329 +0.01014 +0.010055 +0.010119 +0.010217 +0.010319 +0.010376 +0.010209 +0.010125 +0.010213 +0.010263 +0.010358 +0.010423 +0.010259 +0.010171 +0.010206 +0.010302 +0.010409 +0.010418 +0.010218 +0.010087 +0.010103 +0.01016 +0.010231 +0.010229 +0.010016 +0.009902 +0.009914 +0.009934 +0.009985 +0.009951 +0.009738 +0.009613 +0.009626 +0.009682 +0.009681 +0.009686 +0.009485 +0.009353 +0.009362 +0.009391 +0.009448 +0.009424 +0.009207 +0.009086 +0.009112 +0.009135 +0.009176 +0.009187 +0.008991 +0.008867 +0.008882 +0.008928 +0.008964 +0.008993 +0.008802 +0.008698 +0.008717 +0.008768 +0.00882 +0.008836 +0.008681 +0.008548 +0.008573 +0.008617 +0.008673 +0.008701 +0.008531 +0.00844 +0.00847 +0.008527 +0.008593 +0.008596 +0.008428 +0.008341 +0.008372 +0.00843 +0.008489 +0.008553 +0.008395 +0.008307 +0.008368 +0.008431 +0.008506 +0.008564 +0.00842 +0.008339 +0.008387 +0.008458 +0.008539 +0.008616 +0.008472 +0.008388 +0.008456 +0.008508 +0.008586 +0.00865 +0.008489 +0.008416 +0.00847 +0.008546 +0.008619 +0.008684 +0.00856 +0.00847 +0.008515 +0.008586 +0.008677 +0.00874 +0.008587 +0.00851 +0.008556 +0.008637 +0.00871 +0.008798 +0.008632 +0.008556 +0.008596 +0.008677 +0.008777 +0.008829 +0.008659 +0.008597 +0.008634 +0.008739 +0.008814 +0.008859 +0.008717 +0.008646 +0.008694 +0.008752 +0.008839 +0.008919 +0.00875 +0.008685 +0.008732 +0.008801 +0.008877 +0.008946 +0.008809 +0.008724 +0.008777 +0.008843 +0.008947 +0.009006 +0.008847 +0.008783 +0.008836 +0.008918 +0.008969 +0.009039 +0.008882 +0.008809 +0.008864 +0.008938 +0.00904 +0.009082 +0.00895 +0.008858 +0.00891 +0.008991 +0.009053 +0.009123 +0.008975 +0.0089 +0.008954 +0.009025 +0.009134 +0.00919 +0.009032 +0.008949 +0.009005 +0.009066 +0.009147 +0.009229 +0.009073 +0.009012 +0.009046 +0.009133 +0.009192 +0.009262 +0.009113 +0.00902 +0.009079 +0.009167 +0.009249 +0.009312 +0.00916 +0.009102 +0.009146 +0.009221 +0.009301 +0.009351 +0.009192 +0.009139 +0.009171 +0.009244 +0.009349 +0.009431 +0.009253 +0.009182 +0.009252 +0.009318 +0.009416 +0.00946 +0.00927 +0.009196 +0.009257 +0.009346 +0.009441 +0.009517 +0.009358 +0.009274 +0.009329 +0.009388 +0.009491 +0.009534 +0.009384 +0.009307 +0.009355 +0.009446 +0.009541 +0.009606 +0.009442 +0.009362 +0.009418 +0.009484 +0.009586 +0.009658 +0.009517 +0.00943 +0.009461 +0.009537 +0.009639 +0.00969 +0.00953 +0.009444 +0.0095 +0.009586 +0.009689 +0.009763 +0.009602 +0.009505 +0.009553 +0.009633 +0.009717 +0.009778 +0.009631 +0.009543 +0.009598 +0.009691 +0.009791 +0.009849 +0.009686 +0.009599 +0.00967 +0.009753 +0.009827 +0.009879 +0.009718 +0.009664 +0.009697 +0.009783 +0.009879 +0.009953 +0.009773 +0.009683 +0.009756 +0.009821 +0.009938 +0.010022 +0.009824 +0.00973 +0.009805 +0.009878 +0.009978 +0.010053 +0.009861 +0.009793 +0.009863 +0.009959 +0.010084 +0.010086 +0.009898 +0.009822 +0.009884 +0.009987 +0.010063 +0.010171 +0.009964 +0.009877 +0.009941 +0.010043 +0.010137 +0.010182 +0.01003 +0.009922 +0.009998 +0.010107 +0.010192 +0.010236 +0.010076 +0.009977 +0.010048 +0.010138 +0.010242 +0.010333 +0.010107 +0.010019 +0.01011 +0.010193 +0.010274 +0.010343 +0.010169 +0.010082 +0.010145 +0.010237 +0.010345 +0.010406 +0.010215 +0.010121 +0.010154 +0.010216 +0.010311 +0.010297 +0.010075 +0.009954 +0.010011 +0.010039 +0.010082 +0.010093 +0.009892 +0.00978 +0.00973 +0.009767 +0.009823 +0.009819 +0.009616 +0.00949 +0.0095 +0.009521 +0.009566 +0.009572 +0.009348 +0.009229 +0.00925 +0.009278 +0.009327 +0.009342 +0.009134 +0.009012 +0.009018 +0.009061 +0.009088 +0.0091 +0.008911 +0.008796 +0.008822 +0.008866 +0.008914 +0.008943 +0.008771 +0.008631 +0.008659 +0.008704 +0.008759 +0.008788 +0.008602 +0.008507 +0.008556 +0.008588 +0.008641 +0.008672 +0.008501 +0.008404 +0.008444 +0.008492 +0.008558 +0.008582 +0.008421 +0.008342 +0.008406 +0.008459 +0.008504 +0.008557 +0.008408 +0.008337 +0.008394 +0.008471 +0.008544 +0.008629 +0.008448 +0.008384 +0.008446 +0.008502 +0.008591 +0.008629 +0.008496 +0.008422 +0.008486 +0.008542 +0.008627 +0.008682 +0.008545 +0.008467 +0.008514 +0.008607 +0.008684 +0.008727 +0.00858 +0.00852 +0.008555 +0.008635 +0.008714 +0.008785 +0.008646 +0.008544 +0.008615 +0.008682 +0.008798 +0.008822 +0.008654 +0.008583 +0.00864 +0.008719 +0.0088 +0.008859 +0.008708 +0.008663 +0.008696 +0.00877 +0.008855 +0.008914 +0.008747 +0.008679 +0.008765 +0.008795 +0.008887 +0.008954 +0.008807 +0.008718 +0.008767 +0.008855 +0.008928 +0.008996 +0.008848 +0.008766 +0.008846 +0.008915 +0.008985 +0.009041 +0.008891 +0.008802 +0.008862 +0.008931 +0.009024 +0.009099 +0.008926 +0.00885 +0.008913 +0.009001 +0.009073 +0.009132 +0.00899 +0.008893 +0.008972 +0.00902 +0.009113 +0.009173 +0.009018 +0.008952 +0.008993 +0.009072 +0.009167 +0.009231 +0.009101 +0.008985 +0.00904 +0.009118 +0.009203 +0.009283 +0.00912 +0.009024 +0.009085 +0.009176 +0.009268 +0.009309 +0.009164 +0.009064 +0.009133 +0.00922 +0.009319 +0.00938 +0.009214 +0.009126 +0.009177 +0.00925 +0.009352 +0.009405 +0.009247 +0.009167 +0.009246 +0.00935 +0.009415 +0.009479 +0.009282 +0.009194 +0.009262 +0.009353 +0.009436 +0.009506 +0.009362 +0.009252 +0.009317 +0.009413 +0.009484 +0.009544 +0.009394 +0.009303 +0.009372 +0.009446 +0.009565 +0.009619 +0.009431 +0.009358 +0.009406 +0.009494 +0.009596 +0.009659 +0.009511 +0.0094 +0.009466 +0.009549 +0.009664 +0.009702 +0.009506 +0.00944 +0.009519 +0.009587 +0.009678 +0.009748 +0.009572 +0.009503 +0.00955 +0.009641 +0.009726 +0.009793 +0.00964 +0.009541 +0.009605 +0.009713 +0.009796 +0.009837 +0.009677 +0.009601 +0.009681 +0.009728 +0.009824 +0.009882 +0.009721 +0.009643 +0.009706 +0.009801 +0.009889 +0.009932 +0.00977 +0.009697 +0.009753 +0.009825 +0.009929 +0.01001 +0.009826 +0.009752 +0.009807 +0.009875 +0.009973 +0.010043 +0.009873 +0.009785 +0.009857 +0.009956 +0.010039 +0.010104 +0.009919 +0.009839 +0.009897 +0.009968 +0.010075 +0.010156 +0.00996 +0.009882 +0.009957 +0.010053 +0.010145 +0.010211 +0.010038 +0.009916 +0.010019 +0.010075 +0.010172 +0.010245 +0.010082 +0.00997 +0.010037 +0.010131 +0.010276 +0.010329 +0.010092 +0.01002 +0.010089 +0.010208 +0.010295 +0.01034 +0.010177 +0.010072 +0.010142 +0.010241 +0.010328 +0.010399 +0.010247 +0.01014 +0.01021 +0.010308 +0.010389 +0.010438 +0.010273 +0.010164 +0.010231 +0.01032 +0.010426 +0.010461 +0.010217 +0.010115 +0.010115 +0.010157 +0.010219 +0.010237 +0.010033 +0.009893 +0.009901 +0.009926 +0.009975 +0.009946 +0.009728 +0.009607 +0.009613 +0.009656 +0.009694 +0.009709 +0.00949 +0.009354 +0.00937 +0.009395 +0.00944 +0.009461 +0.00925 +0.00915 +0.009139 +0.009175 +0.009194 +0.009212 +0.009025 +0.008892 +0.008917 +0.008957 +0.009003 +0.009023 +0.008846 +0.008741 +0.008748 +0.00882 +0.008836 +0.008861 +0.008672 +0.008572 +0.008614 +0.008652 +0.008707 +0.008752 +0.008581 +0.008475 +0.008496 +0.00855 +0.008607 +0.00864 +0.00847 +0.008365 +0.008394 +0.008465 +0.008545 +0.00858 +0.008422 +0.008348 +0.008395 +0.008466 +0.008547 +0.008603 +0.008468 +0.008388 +0.008438 +0.008515 +0.008605 +0.008673 +0.008484 +0.008423 +0.008474 +0.008545 +0.008629 +0.008696 +0.008536 +0.008464 +0.008533 +0.008612 +0.008697 +0.008765 +0.008583 +0.008503 +0.008552 +0.008627 +0.008721 +0.00878 +0.008634 +0.008567 +0.008625 +0.008661 +0.00875 +0.008815 +0.008667 +0.008591 +0.008638 +0.00873 +0.0088 +0.008861 +0.008728 +0.008656 +0.008691 +0.008759 +0.008855 +0.008904 +0.008758 +0.008684 +0.008742 +0.00883 +0.008934 +0.008965 +0.008801 +0.008727 +0.008779 +0.008842 +0.008927 +0.008998 +0.008843 +0.008765 +0.008819 +0.008896 +0.008985 +0.00904 +0.008892 +0.008821 +0.008864 +0.008934 +0.009029 +0.009099 +0.008934 +0.00887 +0.008931 +0.008985 +0.00907 +0.009132 +0.008983 +0.008922 +0.008964 +0.009025 +0.009107 +0.009193 +0.009024 +0.008954 +0.009017 +0.009078 +0.009164 +0.009216 +0.009063 +0.008992 +0.009046 +0.00911 +0.00921 +0.009284 +0.009138 +0.009037 +0.009104 +0.009167 +0.009246 +0.009311 +0.00917 +0.009076 +0.009129 +0.009222 +0.009333 +0.009404 +0.009211 +0.009131 +0.009181 +0.009245 +0.009343 +0.009402 +0.009254 +0.00917 +0.009243 +0.009305 +0.009403 +0.009465 +0.009301 +0.009213 +0.009292 +0.00933 +0.009444 +0.009512 +0.009356 +0.009273 +0.009332 +0.009407 +0.009486 +0.009562 +0.009393 +0.009325 +0.009377 +0.009434 +0.009545 +0.009607 +0.009451 +0.009371 +0.009414 +0.009497 +0.009588 +0.009642 +0.009482 +0.009409 +0.009468 +0.00954 +0.009633 +0.009697 +0.009551 +0.009458 +0.009504 +0.009592 +0.009686 +0.009759 +0.009597 +0.009499 +0.009559 +0.009654 +0.009771 +0.009787 +0.009614 +0.009539 +0.009601 +0.009701 +0.009799 +0.009866 +0.009693 +0.009596 +0.009643 +0.00974 +0.009823 +0.009896 +0.009725 +0.00966 +0.009715 +0.009798 +0.009905 +0.009946 +0.009756 +0.009692 +0.009744 +0.009834 +0.009943 +0.010032 +0.009828 +0.009753 +0.009788 +0.009872 +0.009983 +0.010032 +0.009885 +0.009794 +0.009863 +0.009956 +0.010049 +0.010088 +0.009916 +0.009833 +0.009896 +0.009983 +0.010075 +0.010156 +0.009995 +0.009904 +0.00997 +0.010032 +0.010125 +0.010193 +0.010046 +0.009951 +0.009991 +0.010078 +0.010179 +0.010257 +0.010067 +0.009993 +0.010048 +0.010132 +0.010245 +0.010311 +0.010146 +0.010075 +0.010083 +0.010179 +0.010283 +0.010351 +0.01017 +0.010076 +0.010153 +0.010263 +0.01037 +0.010416 +0.010232 +0.010163 +0.010194 +0.010265 +0.010359 +0.010421 +0.010235 +0.010124 +0.010161 +0.010216 +0.010283 +0.010283 +0.010075 +0.009921 +0.00995 +0.00998 +0.010075 +0.010032 +0.009805 +0.009688 +0.009703 +0.009731 +0.009766 +0.009788 +0.009578 +0.00946 +0.009454 +0.00949 +0.009521 +0.009535 +0.009301 +0.009176 +0.00919 +0.009227 +0.009263 +0.00929 +0.009076 +0.008978 +0.008976 +0.009011 +0.009035 +0.00906 +0.008871 +0.008763 +0.008787 +0.008814 +0.008856 +0.0089 +0.008728 +0.008619 +0.008639 +0.008687 +0.008716 +0.008744 +0.008575 +0.008488 +0.008511 +0.008569 +0.008592 +0.008617 +0.008466 +0.008377 +0.008418 +0.008451 +0.008508 +0.008555 +0.008388 +0.0083 +0.008335 +0.008395 +0.008467 +0.008527 +0.008384 +0.008313 +0.008353 +0.008428 +0.008503 +0.00856 +0.008422 +0.008344 +0.008405 +0.008479 +0.008555 +0.008621 +0.008477 +0.008398 +0.008461 +0.008534 +0.008582 +0.008644 +0.008496 +0.008433 +0.008487 +0.008554 +0.008632 +0.008706 +0.00856 +0.008512 +0.008514 +0.008597 +0.008665 +0.008726 +0.008588 +0.008518 +0.008565 +0.008633 +0.008738 +0.00879 +0.008644 +0.008567 +0.008625 +0.008673 +0.008758 +0.008827 +0.008679 +0.008629 +0.008659 +0.008726 +0.008793 +0.008868 +0.008725 +0.008653 +0.0087 +0.008758 +0.008856 +0.008917 +0.008762 +0.008693 +0.008759 +0.008817 +0.008891 +0.008963 +0.008807 +0.008731 +0.008776 +0.008863 +0.008935 +0.009008 +0.008879 +0.008797 +0.008836 +0.008911 +0.008985 +0.009064 +0.008908 +0.008811 +0.008858 +0.008935 +0.00903 +0.009119 +0.008944 +0.008871 +0.008926 +0.009005 +0.009073 +0.009132 +0.008988 +0.008901 +0.008957 +0.009071 +0.009115 +0.009178 +0.009023 +0.008953 +0.009002 +0.009082 +0.009177 +0.009231 +0.009079 +0.009011 +0.009068 +0.009172 +0.009219 +0.009267 +0.009107 +0.009033 +0.009105 +0.009178 +0.009272 +0.009332 +0.009178 +0.009096 +0.009149 +0.009232 +0.009305 +0.009355 +0.009202 +0.009131 +0.009187 +0.009259 +0.009366 +0.009408 +0.009255 +0.009192 +0.009233 +0.009312 +0.009399 +0.009474 +0.009337 +0.009231 +0.00929 +0.009368 +0.009448 +0.009518 +0.009352 +0.009265 +0.009317 +0.009419 +0.009491 +0.009552 +0.009409 +0.009325 +0.009384 +0.009467 +0.009548 +0.009603 +0.009442 +0.00936 +0.009413 +0.009485 +0.009619 +0.009663 +0.009498 +0.009427 +0.00949 +0.009572 +0.009629 +0.009687 +0.009531 +0.009459 +0.009525 +0.009587 +0.009682 +0.009757 +0.009579 +0.009504 +0.009597 +0.009629 +0.009738 +0.009805 +0.009633 +0.009565 +0.009621 +0.009692 +0.009785 +0.009858 +0.009685 +0.009595 +0.009646 +0.009751 +0.009864 +0.009941 +0.009736 +0.009643 +0.0097 +0.009796 +0.009887 +0.009944 +0.009768 +0.009696 +0.009754 +0.009854 +0.009961 +0.010015 +0.009842 +0.009739 +0.009787 +0.009881 +0.00999 +0.010043 +0.009889 +0.009787 +0.009858 +0.009937 +0.010036 +0.010104 +0.009956 +0.009837 +0.009894 +0.010003 +0.010101 +0.010173 +0.009973 +0.009874 +0.00995 +0.010028 +0.010133 +0.010202 +0.01003 +0.009957 +0.010016 +0.010096 +0.010188 +0.010246 +0.010064 +0.009982 +0.010041 +0.010138 +0.01024 +0.01032 +0.010136 +0.010077 +0.010096 +0.010173 +0.010284 +0.010368 +0.010178 +0.010105 +0.010186 +0.010218 +0.010309 +0.010376 +0.010195 +0.010086 +0.010118 +0.010184 +0.010244 +0.010269 +0.010056 +0.009912 +0.009922 +0.009969 +0.010015 +0.010011 +0.009803 +0.009672 +0.0097 +0.009715 +0.009754 +0.009746 +0.009549 +0.009399 +0.009412 +0.009439 +0.009484 +0.009492 +0.009299 +0.009179 +0.009179 +0.009212 +0.00925 +0.00926 +0.009053 +0.008937 +0.008963 +0.008988 +0.009028 +0.009063 +0.008871 +0.008752 +0.008773 +0.008825 +0.008877 +0.008913 +0.008709 +0.008608 +0.008646 +0.00867 +0.008728 +0.008758 +0.008592 +0.008476 +0.008513 +0.008547 +0.008602 +0.008643 +0.008476 +0.008375 +0.008414 +0.008469 +0.008517 +0.008576 +0.008416 +0.008336 +0.008358 +0.008424 +0.008496 +0.008554 +0.008415 +0.008344 +0.008391 +0.008465 +0.008576 +0.008605 +0.00846 +0.00838 +0.008433 +0.008508 +0.008579 +0.008628 +0.008487 +0.008427 +0.008472 +0.008538 +0.008623 +0.008686 +0.008527 +0.008463 +0.008525 +0.008589 +0.008664 +0.008731 +0.008585 +0.008521 +0.008575 +0.008635 +0.008709 +0.008759 +0.008622 +0.008544 +0.008597 +0.008697 +0.008761 +0.008815 +0.008663 +0.008602 +0.00866 +0.008723 +0.008798 +0.00886 +0.008707 +0.008627 +0.008683 +0.008756 +0.008845 +0.008912 +0.008762 +0.008693 +0.008736 +0.008812 +0.008891 +0.008939 +0.008782 +0.008717 +0.008775 +0.008841 +0.008944 +0.008986 +0.008844 +0.00878 +0.008833 +0.00888 +0.008973 +0.009025 +0.008885 +0.00882 +0.00886 +0.008947 +0.009037 +0.009107 +0.00891 +0.008845 +0.008901 +0.00897 +0.009063 +0.009123 +0.008978 +0.008909 +0.00896 +0.009049 +0.009115 +0.009172 +0.00901 +0.008933 +0.008987 +0.009065 +0.009152 +0.009243 +0.009078 +0.008998 +0.00903 +0.009111 +0.0092 +0.009267 +0.009099 +0.009027 +0.009084 +0.009158 +0.009268 +0.009325 +0.009148 +0.009074 +0.009126 +0.009218 +0.009294 +0.009357 +0.009211 +0.009124 +0.009181 +0.009266 +0.009357 +0.009401 +0.009239 +0.009167 +0.009243 +0.00933 +0.009381 +0.009449 +0.009292 +0.009214 +0.009274 +0.009345 +0.009446 +0.009514 +0.009321 +0.00925 +0.00932 +0.009393 +0.009488 +0.009547 +0.00938 +0.009298 +0.009354 +0.009451 +0.00953 +0.009597 +0.00944 +0.009365 +0.009411 +0.009495 +0.009604 +0.009668 +0.009474 +0.009384 +0.009446 +0.009522 +0.009644 +0.009706 +0.009516 +0.009456 +0.00951 +0.009596 +0.009685 +0.009729 +0.009566 +0.009484 +0.009556 +0.009625 +0.009718 +0.009811 +0.009632 +0.009549 +0.009611 +0.00969 +0.009768 +0.009829 +0.009675 +0.009616 +0.009652 +0.00974 +0.009806 +0.009881 +0.009724 +0.009626 +0.009691 +0.009807 +0.009864 +0.009928 +0.00978 +0.009701 +0.009752 +0.009817 +0.009922 +0.009984 +0.00982 +0.009732 +0.009777 +0.009873 +0.010004 +0.010054 +0.009876 +0.009807 +0.009857 +0.009967 +0.01 +0.010074 +0.009894 +0.009841 +0.009892 +0.009966 +0.01007 +0.010136 +0.009971 +0.009876 +0.009942 +0.010012 +0.010132 +0.010222 +0.010027 +0.009938 +0.009991 +0.010074 +0.010173 +0.010246 +0.010057 +0.009971 +0.01007 +0.010169 +0.010267 +0.010284 +0.010134 +0.009998 +0.010078 +0.010176 +0.010263 +0.010352 +0.010162 +0.010069 +0.010143 +0.010232 +0.01033 +0.010396 +0.010215 +0.010118 +0.010189 +0.010282 +0.010363 +0.010377 +0.010173 +0.01005 +0.010089 +0.01012 +0.010186 +0.010232 +0.010011 +0.009842 +0.009871 +0.009931 +0.009945 +0.009954 +0.009731 +0.009597 +0.009617 +0.009652 +0.009699 +0.009713 +0.009486 +0.009351 +0.009374 +0.009399 +0.009445 +0.009456 +0.009245 +0.009115 +0.009131 +0.00919 +0.00922 +0.009214 +0.009027 +0.008904 +0.008943 +0.008957 +0.008992 +0.009015 +0.008822 +0.00873 +0.008751 +0.008785 +0.008831 +0.008842 +0.008664 +0.008553 +0.008583 +0.008631 +0.008683 +0.008704 +0.008557 +0.008432 +0.008466 +0.008517 +0.008578 +0.008593 +0.008414 +0.008332 +0.008362 +0.008417 +0.008484 +0.008541 +0.008378 +0.008303 +0.00832 +0.008387 +0.00847 +0.008529 +0.008383 +0.008313 +0.008353 +0.008442 +0.008527 +0.008573 +0.008428 +0.008362 +0.008415 +0.008474 +0.008545 +0.008609 +0.008467 +0.00839 +0.008448 +0.008517 +0.008591 +0.008656 +0.008511 +0.008454 +0.00849 +0.008556 +0.008634 +0.008704 +0.008582 +0.0085 +0.008543 +0.008603 +0.008668 +0.008731 +0.008597 +0.008514 +0.00857 +0.008642 +0.008728 +0.008798 +0.008636 +0.008579 +0.008621 +0.008696 +0.008776 +0.008827 +0.008683 +0.008603 +0.008662 +0.008725 +0.008809 +0.008878 +0.008745 +0.008657 +0.008709 +0.008782 +0.008867 +0.00894 +0.008759 +0.008696 +0.008741 +0.008808 +0.008905 +0.008971 +0.008801 +0.008732 +0.008792 +0.008858 +0.008949 +0.00901 +0.008861 +0.008779 +0.008827 +0.008928 +0.009002 +0.009062 +0.008892 +0.008823 +0.008877 +0.008954 +0.009046 +0.009102 +0.008933 +0.008872 +0.008937 +0.009029 +0.009107 +0.009141 +0.008974 +0.008907 +0.00898 +0.009033 +0.009117 +0.009182 +0.00903 +0.008951 +0.009019 +0.009099 +0.009182 +0.009237 +0.009073 +0.009006 +0.009048 +0.009129 +0.009225 +0.009278 +0.009126 +0.009043 +0.0091 +0.009191 +0.009264 +0.009336 +0.009173 +0.009122 +0.009139 +0.009214 +0.009302 +0.009366 +0.009221 +0.009149 +0.009183 +0.009274 +0.009359 +0.009425 +0.009257 +0.009191 +0.009233 +0.009309 +0.009431 +0.00948 +0.009295 +0.009232 +0.00928 +0.009373 +0.009455 +0.009521 +0.009351 +0.009268 +0.00935 +0.009434 +0.009541 +0.009557 +0.009374 +0.009316 +0.009371 +0.009459 +0.009544 +0.009607 +0.009473 +0.009348 +0.009414 +0.00951 +0.009588 +0.00966 +0.009495 +0.009419 +0.009472 +0.009551 +0.009673 +0.009711 +0.009532 +0.00946 +0.009518 +0.00959 +0.009703 +0.00976 +0.009623 +0.009526 +0.009552 +0.009646 +0.009748 +0.009797 +0.009626 +0.009552 +0.009614 +0.009691 +0.00979 +0.009859 +0.009682 +0.009616 +0.009676 +0.009758 +0.00983 +0.009894 +0.009738 +0.009647 +0.009704 +0.009798 +0.009896 +0.009966 +0.009796 +0.009724 +0.009787 +0.009839 +0.009912 +0.009992 +0.009823 +0.009747 +0.009814 +0.009879 +0.009984 +0.010046 +0.009879 +0.009793 +0.009869 +0.009936 +0.010044 +0.010109 +0.009943 +0.00987 +0.009889 +0.009985 +0.010094 +0.010159 +0.00997 +0.009888 +0.009963 +0.010094 +0.010147 +0.010198 +0.010032 +0.009924 +0.010001 +0.010072 +0.010187 +0.010263 +0.010076 +0.009986 +0.010055 +0.010139 +0.010244 +0.010317 +0.010121 +0.01004 +0.010116 +0.0102 +0.010316 +0.010357 +0.010175 +0.01009 +0.010162 +0.010257 +0.010331 +0.010372 +0.010201 +0.010095 +0.010136 +0.010168 +0.010231 +0.010224 +0.010025 +0.009905 +0.009907 +0.009945 +0.010017 +0.010006 +0.00979 +0.009644 +0.009662 +0.009668 +0.009717 +0.009728 +0.009512 +0.0094 +0.009399 +0.009424 +0.009476 +0.009503 +0.009294 +0.009145 +0.009148 +0.009183 +0.009222 +0.00926 +0.009066 +0.008942 +0.008959 +0.008983 +0.009017 +0.009041 +0.008861 +0.008754 +0.00876 +0.008807 +0.008865 +0.008898 +0.008715 +0.008616 +0.008631 +0.008654 +0.008717 +0.00874 +0.008576 +0.008478 +0.008511 +0.008558 +0.008622 +0.008625 +0.008467 +0.008368 +0.008396 +0.008447 +0.008502 +0.008547 +0.008393 +0.008314 +0.008346 +0.008412 +0.008481 +0.008523 +0.008377 +0.008309 +0.008359 +0.008425 +0.00851 +0.008556 +0.008426 +0.00836 +0.008411 +0.008476 +0.008562 +0.008588 +0.008454 +0.008391 +0.008442 +0.008534 +0.008598 +0.008638 +0.008497 +0.008446 +0.008489 +0.008566 +0.008629 +0.008686 +0.008544 +0.008475 +0.00854 +0.008588 +0.00868 +0.008724 +0.008587 +0.008515 +0.008571 +0.008652 +0.008726 +0.00879 +0.008641 +0.008567 +0.008601 +0.008681 +0.008767 +0.008813 +0.00867 +0.008613 +0.008682 +0.008729 +0.008802 +0.00886 +0.008713 +0.008642 +0.008718 +0.008761 +0.008849 +0.008917 +0.008769 +0.008699 +0.008742 +0.008808 +0.008887 +0.00895 +0.008811 +0.008727 +0.008782 +0.008853 +0.008946 +0.00903 +0.00886 +0.008788 +0.008836 +0.008893 +0.008982 +0.009045 +0.008902 +0.008834 +0.008859 +0.008957 +0.00902 +0.009088 +0.008942 +0.008857 +0.00891 +0.009005 +0.00907 +0.00914 +0.008981 +0.008917 +0.008962 +0.009039 +0.009129 +0.009179 +0.009032 +0.008951 +0.009006 +0.009082 +0.009163 +0.009244 +0.009085 +0.009006 +0.009054 +0.009135 +0.009234 +0.009281 +0.009106 +0.009034 +0.009088 +0.009173 +0.009266 +0.009328 +0.009172 +0.009098 +0.009155 +0.009212 +0.009303 +0.009356 +0.009204 +0.009136 +0.009199 +0.00927 +0.00935 +0.009418 +0.009253 +0.009166 +0.009228 +0.009309 +0.009398 +0.009466 +0.009321 +0.009266 +0.009304 +0.009357 +0.009445 +0.009494 +0.009333 +0.009256 +0.009318 +0.0094 +0.009502 +0.009551 +0.009409 +0.009364 +0.009382 +0.009436 +0.009541 +0.009594 +0.009433 +0.009355 +0.009417 +0.009495 +0.009612 +0.009681 +0.0095 +0.009423 +0.009467 +0.009545 +0.009663 +0.009683 +0.009529 +0.00944 +0.009526 +0.009596 +0.009692 +0.009743 +0.00959 +0.009494 +0.009547 +0.009646 +0.009737 +0.009807 +0.009652 +0.009563 +0.009599 +0.009688 +0.009787 +0.009846 +0.009675 +0.009602 +0.009645 +0.009756 +0.009865 +0.009924 +0.00976 +0.009647 +0.009687 +0.009773 +0.009874 +0.009939 +0.009799 +0.00967 +0.009766 +0.009852 +0.009942 +0.010012 +0.009823 +0.009733 +0.009796 +0.009881 +0.009976 +0.010053 +0.009869 +0.00979 +0.009856 +0.009937 +0.010034 +0.010102 +0.009927 +0.009879 +0.009893 +0.009999 +0.010097 +0.010132 +0.009974 +0.009881 +0.009943 +0.01007 +0.01012 +0.010191 +0.010032 +0.009963 +0.010007 +0.010104 +0.010178 +0.010233 +0.010078 +0.009976 +0.010039 +0.010136 +0.010252 +0.010318 +0.010135 +0.010055 +0.010142 +0.010159 +0.010281 +0.010336 +0.010155 +0.010076 +0.010117 +0.010204 +0.010282 +0.010305 +0.010117 +0.00995 +0.00998 +0.010035 +0.010104 +0.010118 +0.009882 +0.009761 +0.009793 +0.00983 +0.009857 +0.009845 +0.00963 +0.009507 +0.009521 +0.009594 +0.009584 +0.009606 +0.009408 +0.009252 +0.009275 +0.009303 +0.009334 +0.009355 +0.00914 +0.009024 +0.009042 +0.009103 +0.009121 +0.009137 +0.008949 +0.008829 +0.008844 +0.008894 +0.008938 +0.008964 +0.008769 +0.008668 +0.008699 +0.008748 +0.00878 +0.008811 +0.008644 +0.008539 +0.008549 +0.008607 +0.00865 +0.008682 +0.008527 +0.008431 +0.008453 +0.008505 +0.008571 +0.008576 +0.008418 +0.008333 +0.008365 +0.008436 +0.008505 +0.008554 +0.008407 +0.008323 +0.008373 +0.008457 +0.008524 +0.008572 +0.00843 +0.008356 +0.008403 +0.008474 +0.008564 +0.008631 +0.008493 +0.008398 +0.008444 +0.00852 +0.008598 +0.008662 +0.008512 +0.008433 +0.008505 +0.008572 +0.008652 +0.008713 +0.008563 +0.008484 +0.008552 +0.008602 +0.008686 +0.00874 +0.008597 +0.008532 +0.008583 +0.008657 +0.008739 +0.008799 +0.00865 +0.008563 +0.008613 +0.008694 +0.00878 +0.008859 +0.008684 +0.00861 +0.008657 +0.008733 +0.008821 +0.008878 +0.008728 +0.008654 +0.008706 +0.008788 +0.008877 +0.008925 +0.008779 +0.008699 +0.008745 +0.008829 +0.008904 +0.008964 +0.008823 +0.008748 +0.008792 +0.008868 +0.008961 +0.009025 +0.008873 +0.008793 +0.008851 +0.008931 +0.009005 +0.009052 +0.008907 +0.008824 +0.008879 +0.008957 +0.009056 +0.00911 +0.008961 +0.008872 +0.00893 +0.008988 +0.009114 +0.009145 +0.008985 +0.008925 +0.00898 +0.009038 +0.009137 +0.009195 +0.009038 +0.008958 +0.009024 +0.009081 +0.009181 +0.009252 +0.009104 +0.009054 +0.009074 +0.009135 +0.009217 +0.009282 +0.009141 +0.009047 +0.009093 +0.009173 +0.009278 +0.009333 +0.009194 +0.009122 +0.009171 +0.009231 +0.009313 +0.009373 +0.009218 +0.009135 +0.009197 +0.009271 +0.009375 +0.009455 +0.009278 +0.009206 +0.009264 +0.00934 +0.009429 +0.009465 +0.009304 +0.009223 +0.009287 +0.00938 +0.009452 +0.009547 +0.00936 +0.00929 +0.009346 +0.009407 +0.009519 +0.009563 +0.009418 +0.009344 +0.009393 +0.009458 +0.009559 +0.009627 +0.009454 +0.009376 +0.009446 +0.009505 +0.009625 +0.009689 +0.009534 +0.009447 +0.009477 +0.009551 +0.009644 +0.009715 +0.00955 +0.009467 +0.00952 +0.009647 +0.009715 +0.009773 +0.009613 +0.009529 +0.009556 +0.009658 +0.009733 +0.009805 +0.009662 +0.009573 +0.009617 +0.00971 +0.009811 +0.009873 +0.009697 +0.009621 +0.009694 +0.009778 +0.009852 +0.009926 +0.00975 +0.009654 +0.009714 +0.009805 +0.009902 +0.009977 +0.009783 +0.009733 +0.009777 +0.009873 +0.009963 +0.010022 +0.00983 +0.00975 +0.009828 +0.009901 +0.010003 +0.010065 +0.009907 +0.009824 +0.009883 +0.009972 +0.010099 +0.010084 +0.009933 +0.009874 +0.0099 +0.010006 +0.010096 +0.010161 +0.010004 +0.009901 +0.009965 +0.010063 +0.01016 +0.010221 +0.010054 +0.009964 +0.010033 +0.010108 +0.010209 +0.010262 +0.010099 +0.010004 +0.01006 +0.010163 +0.010286 +0.010372 +0.010144 +0.010062 +0.010093 +0.010204 +0.010328 +0.010358 +0.010188 +0.010105 +0.010161 +0.010259 +0.010362 +0.010427 +0.010249 +0.010151 +0.010207 +0.010294 +0.010403 +0.010439 +0.010214 +0.010101 +0.010117 +0.010162 +0.010234 +0.010269 +0.010026 +0.009878 +0.009912 +0.009925 +0.009978 +0.00995 +0.009758 +0.009625 +0.009609 +0.009654 +0.009702 +0.009725 +0.009508 +0.009375 +0.009389 +0.009411 +0.009453 +0.009475 +0.00926 +0.009137 +0.009157 +0.009201 +0.009232 +0.009251 +0.009061 +0.008958 +0.00897 +0.008986 +0.009034 +0.009059 +0.008876 +0.008772 +0.008792 +0.008842 +0.008884 +0.008902 +0.008739 +0.008613 +0.008643 +0.008684 +0.00874 +0.008776 +0.008607 +0.008507 +0.00853 +0.008589 +0.008638 +0.008654 +0.008493 +0.008406 +0.008432 +0.00849 +0.008564 +0.008614 +0.008471 +0.008367 +0.008404 +0.008474 +0.008548 +0.008611 +0.008474 +0.008397 +0.008446 +0.008512 +0.0086 +0.008667 +0.008508 +0.008459 +0.008481 +0.008554 +0.008637 +0.008701 +0.00854 +0.008473 +0.008529 +0.008613 +0.008695 +0.00875 +0.008615 +0.008525 +0.008578 +0.008634 +0.008722 +0.008812 +0.008657 +0.00856 +0.008624 +0.008673 +0.008793 +0.008822 +0.008674 +0.008598 +0.008657 +0.008718 +0.00881 +0.008873 +0.008731 +0.008662 +0.008713 +0.008778 +0.008851 +0.008913 +0.008764 +0.008696 +0.008743 +0.008815 +0.008902 +0.008978 +0.008826 +0.008749 +0.008803 +0.008879 +0.008964 +0.008993 +0.00885 +0.008773 +0.008822 +0.008908 +0.00899 +0.00907 +0.008893 +0.008823 +0.008876 +0.008948 +0.009037 +0.009092 +0.008947 +0.008873 +0.008934 +0.009008 +0.009086 +0.009148 +0.008982 +0.008911 +0.008964 +0.009042 +0.00913 +0.009184 +0.009046 +0.008987 +0.009046 +0.009096 +0.009185 +0.009219 +0.009069 +0.009001 +0.009047 +0.00912 +0.009225 +0.009308 +0.009115 +0.00904 +0.009104 +0.009187 +0.009269 +0.009329 +0.009171 +0.009089 +0.009146 +0.009237 +0.009322 +0.009369 +0.00922 +0.009133 +0.009196 +0.009283 +0.009374 +0.009448 +0.009253 +0.009191 +0.009242 +0.009321 +0.009426 +0.009452 +0.0093 +0.009229 +0.009291 +0.009368 +0.00948 +0.009517 +0.009362 +0.009279 +0.009341 +0.009422 +0.009488 +0.009554 +0.009395 +0.009322 +0.009378 +0.009466 +0.009555 +0.009612 +0.009453 +0.009389 +0.009439 +0.009502 +0.009594 +0.009679 +0.009488 +0.009422 +0.00948 +0.009567 +0.009643 +0.009699 +0.009541 +0.009468 +0.009519 +0.009595 +0.009702 +0.009769 +0.009604 +0.009525 +0.00958 +0.009649 +0.009736 +0.009809 +0.00964 +0.009551 +0.009626 +0.009719 +0.009816 +0.009849 +0.009679 +0.009598 +0.009664 +0.009775 +0.009836 +0.009899 +0.009746 +0.00966 +0.009704 +0.009806 +0.009888 +0.009957 +0.0098 +0.009691 +0.009755 +0.009847 +0.009952 +0.010021 +0.009856 +0.009761 +0.009802 +0.009903 +0.009997 +0.010093 +0.00988 +0.009789 +0.009852 +0.009957 +0.010064 +0.010119 +0.009939 +0.00985 +0.009898 +0.009992 +0.0101 +0.010149 +0.009989 +0.009924 +0.009965 +0.010058 +0.010157 +0.010193 +0.010023 +0.009948 +0.010009 +0.010095 +0.010219 +0.010259 +0.010122 +0.009994 +0.010053 +0.01014 +0.010243 +0.010319 +0.010137 +0.010047 +0.010116 +0.010209 +0.010291 +0.01037 +0.01018 +0.010096 +0.010171 +0.010239 +0.010359 +0.010431 +0.010274 +0.010152 +0.010207 +0.010293 +0.010401 +0.010481 +0.010316 +0.010202 +0.010262 +0.010381 +0.010469 +0.010529 +0.010326 +0.01021 +0.010291 +0.010362 +0.010447 +0.010516 +0.010245 +0.01012 +0.010164 +0.010226 +0.01029 +0.010302 +0.010086 +0.009941 +0.009984 +0.010028 +0.010078 +0.010072 +0.009855 +0.009762 +0.009746 +0.009799 +0.009839 +0.009882 +0.009642 +0.009535 +0.009542 +0.0096 +0.009616 +0.00963 +0.009434 +0.009304 +0.009334 +0.009379 +0.009433 +0.009451 +0.009239 +0.00913 +0.00914 +0.009188 +0.009233 +0.009235 +0.009048 +0.008932 +0.008972 +0.009047 +0.009093 +0.00908 +0.008882 +0.008782 +0.008808 +0.008875 +0.008935 +0.008946 +0.008766 +0.008664 +0.008697 +0.008761 +0.008824 +0.008835 +0.008651 +0.008567 +0.008605 +0.008669 +0.008734 +0.008783 +0.008603 +0.008534 +0.0086 +0.008677 +0.008753 +0.008807 +0.008654 +0.008565 +0.008643 +0.008694 +0.008783 +0.008837 +0.008687 +0.008616 +0.008671 +0.008742 +0.00883 +0.008908 +0.008734 +0.008653 +0.008708 +0.00879 +0.008877 +0.008939 +0.008799 +0.008697 +0.008751 +0.008834 +0.008918 +0.008993 +0.008812 +0.008743 +0.008792 +0.008868 +0.008978 +0.009039 +0.008896 +0.008814 +0.008847 +0.008921 +0.008989 +0.009053 +0.008911 +0.008835 +0.00889 +0.008968 +0.009038 +0.009108 +0.008986 +0.008876 +0.008923 +0.008998 +0.009105 +0.009161 +0.009005 +0.008938 +0.008985 +0.009049 +0.009133 +0.009203 +0.009038 +0.008963 +0.009024 +0.009108 +0.009219 +0.009266 +0.009106 +0.009024 +0.009083 +0.009138 +0.009213 +0.009277 +0.009123 +0.009058 +0.009105 +0.009191 +0.009285 +0.009345 +0.009182 +0.009104 +0.009163 +0.009227 +0.009329 +0.009399 +0.009235 +0.009151 +0.009214 +0.009289 +0.009362 +0.009435 +0.009279 +0.009221 +0.009267 +0.009325 +0.009415 +0.00948 +0.009331 +0.009273 +0.009291 +0.009377 +0.009481 +0.009508 +0.009358 +0.009293 +0.009336 +0.009427 +0.009526 +0.009568 +0.009408 +0.009325 +0.009396 +0.009469 +0.009561 +0.009644 +0.009462 +0.009392 +0.009451 +0.009533 +0.009643 +0.009657 +0.009507 +0.009417 +0.00948 +0.009576 +0.009647 +0.009753 +0.009581 +0.009471 +0.009529 +0.009611 +0.009693 +0.009761 +0.009603 +0.009525 +0.00958 +0.00967 +0.009762 +0.009821 +0.009646 +0.009578 +0.009606 +0.009704 +0.009819 +0.00989 +0.009748 +0.009631 +0.009684 +0.009743 +0.009845 +0.009915 +0.009741 +0.009659 +0.009722 +0.009833 +0.009909 +0.009991 +0.0098 +0.009711 +0.009767 +0.009848 +0.00995 +0.010021 +0.00985 +0.009753 +0.009839 +0.009926 +0.010016 +0.010074 +0.009906 +0.009835 +0.009865 +0.009958 +0.01006 +0.010113 +0.009935 +0.009846 +0.009906 +0.010008 +0.0101 +0.010161 +0.010009 +0.009904 +0.009969 +0.010068 +0.010173 +0.010218 +0.010043 +0.009955 +0.010015 +0.010112 +0.01021 +0.010259 +0.01009 +0.01003 +0.010125 +0.010177 +0.01025 +0.010311 +0.010158 +0.010051 +0.010118 +0.010192 +0.010314 +0.010368 +0.010208 +0.010128 +0.010164 +0.010253 +0.010363 +0.01042 +0.010241 +0.010167 +0.010204 +0.010323 +0.010447 +0.010486 +0.010306 +0.010204 +0.010294 +0.010374 +0.010455 +0.010524 +0.010336 +0.010259 +0.010321 +0.010412 +0.010509 +0.01056 +0.010363 +0.010276 +0.010299 +0.010366 +0.010429 +0.010479 +0.010224 +0.010086 +0.010109 +0.010155 +0.0102 +0.010199 +0.009987 +0.009861 +0.009877 +0.009909 +0.009964 +0.009956 +0.009701 +0.009584 +0.009603 +0.009647 +0.009689 +0.009703 +0.009488 +0.009372 +0.009386 +0.009414 +0.009463 +0.00946 +0.009277 +0.009167 +0.009183 +0.009239 +0.009254 +0.009257 +0.009074 +0.00897 +0.009 +0.009029 +0.009083 +0.009104 +0.008938 +0.008867 +0.008864 +0.008896 +0.008939 +0.008954 +0.008791 +0.008696 +0.008722 +0.008765 +0.008824 +0.00887 +0.008672 +0.008583 +0.008618 +0.008665 +0.008713 +0.008756 +0.008591 +0.008509 +0.00855 +0.008618 +0.00868 +0.008731 +0.00857 +0.008502 +0.008552 +0.008617 +0.008715 +0.008777 +0.008638 +0.008548 +0.008606 +0.008673 +0.008751 +0.008814 +0.008652 +0.008575 +0.008631 +0.008714 +0.008787 +0.008847 +0.008706 +0.00863 +0.008691 +0.008764 +0.008853 +0.008901 +0.008748 +0.008663 +0.008721 +0.008812 +0.008874 +0.008937 +0.0088 +0.008705 +0.008761 +0.008842 +0.008942 +0.009005 +0.008821 +0.008739 +0.008813 +0.008906 +0.008972 +0.009033 +0.008881 +0.008809 +0.008839 +0.008917 +0.009013 +0.009077 +0.008925 +0.00884 +0.008902 +0.008989 +0.009073 +0.009134 +0.00898 +0.008898 +0.008926 +0.009015 +0.009103 +0.009151 +0.008999 +0.008936 +0.009013 +0.0091 +0.009146 +0.009203 +0.009058 +0.008975 +0.009036 +0.009118 +0.009191 +0.009265 +0.009109 +0.00903 +0.009086 +0.009149 +0.009241 +0.009308 +0.009157 +0.009068 +0.009117 +0.009204 +0.009303 +0.009363 +0.009203 +0.009133 +0.009168 +0.009239 +0.009341 +0.009414 +0.009263 +0.009148 +0.009201 +0.009287 +0.009381 +0.009452 +0.009281 +0.009201 +0.009279 +0.009336 +0.009437 +0.009504 +0.009345 +0.009268 +0.009299 +0.009391 +0.00947 +0.009551 +0.009395 +0.009282 +0.009347 +0.009455 +0.009549 +0.009595 +0.009429 +0.009358 +0.009414 +0.009502 +0.009562 +0.009623 +0.009464 +0.009396 +0.009453 +0.009535 +0.009625 +0.009694 +0.009532 +0.009443 +0.009488 +0.009568 +0.009668 +0.009749 +0.009583 +0.009496 +0.009548 +0.009625 +0.009721 +0.00979 +0.009619 +0.009529 +0.009587 +0.009688 +0.009814 +0.009872 +0.009663 +0.009601 +0.009615 +0.009716 +0.009807 +0.009868 +0.009705 +0.009635 +0.009703 +0.009789 +0.009891 +0.009937 +0.00975 +0.009677 +0.009724 +0.009817 +0.009927 +0.009996 +0.009808 +0.009735 +0.00979 +0.009853 +0.009973 +0.010038 +0.009899 +0.00978 +0.00983 +0.009938 +0.010035 +0.010094 +0.009901 +0.009812 +0.009884 +0.009959 +0.01006 +0.010147 +0.009973 +0.009893 +0.009953 +0.01003 +0.010108 +0.010187 +0.009999 +0.009921 +0.009984 +0.010085 +0.010167 +0.010238 +0.010057 +0.010008 +0.010035 +0.010114 +0.010213 +0.010285 +0.01012 +0.010044 +0.010107 +0.010166 +0.010267 +0.010329 +0.010159 +0.010067 +0.010124 +0.010235 +0.010338 +0.010403 +0.010229 +0.010127 +0.010169 +0.010277 +0.01038 +0.010434 +0.010259 +0.010208 +0.010248 +0.010318 +0.010415 +0.010491 +0.010318 +0.010216 +0.010283 +0.010392 +0.010501 +0.010524 +0.010363 +0.010237 +0.010283 +0.010358 +0.010403 +0.010433 +0.010206 +0.010087 +0.010122 +0.010159 +0.010199 +0.010214 +0.009994 +0.009855 +0.00988 +0.009956 +0.00997 +0.009935 +0.009726 +0.009601 +0.009622 +0.00965 +0.009689 +0.009702 +0.009487 +0.009372 +0.009388 +0.009436 +0.009479 +0.009475 +0.009277 +0.009139 +0.00917 +0.009208 +0.009247 +0.009256 +0.009056 +0.008953 +0.008991 +0.009026 +0.00906 +0.009094 +0.00892 +0.008777 +0.008824 +0.00885 +0.00889 +0.008922 +0.008747 +0.008645 +0.008681 +0.008737 +0.00877 +0.008803 +0.008636 +0.008542 +0.008573 +0.008627 +0.008684 +0.008726 +0.008562 +0.008465 +0.008506 +0.008552 +0.008623 +0.008675 +0.008518 +0.008448 +0.008498 +0.008584 +0.008672 +0.008746 +0.008565 +0.008489 +0.008529 +0.008603 +0.008707 +0.008742 +0.008596 +0.008525 +0.008587 +0.008648 +0.008741 +0.008796 +0.008648 +0.008567 +0.008622 +0.008703 +0.008782 +0.008847 +0.008693 +0.008625 +0.008691 +0.008747 +0.008821 +0.008882 +0.00876 +0.008652 +0.008712 +0.008789 +0.008884 +0.008913 +0.00878 +0.008711 +0.00876 +0.008842 +0.008925 +0.008966 +0.008811 +0.008743 +0.008795 +0.008868 +0.008965 +0.009013 +0.008864 +0.008794 +0.008846 +0.008918 +0.009004 +0.009067 +0.008919 +0.008834 +0.008885 +0.008974 +0.009065 +0.009104 +0.008959 +0.00889 +0.008955 +0.009001 +0.009082 +0.009144 +0.008999 +0.00893 +0.008983 +0.009059 +0.009156 +0.009217 +0.00903 +0.00896 +0.009021 +0.009094 +0.009183 +0.009249 +0.009104 +0.009023 +0.009075 +0.009159 +0.009246 +0.009278 +0.009133 +0.00904 +0.009104 +0.009193 +0.009296 +0.009376 +0.009196 +0.009091 +0.009147 +0.009226 +0.009327 +0.009379 +0.009216 +0.009146 +0.009207 +0.009298 +0.009391 +0.009452 +0.009264 +0.009191 +0.00925 +0.009327 +0.009406 +0.009483 +0.009327 +0.009253 +0.009309 +0.009394 +0.009478 +0.009529 +0.009356 +0.009294 +0.00936 +0.009412 +0.009512 +0.009599 +0.009398 +0.009329 +0.009384 +0.00947 +0.009565 +0.009618 +0.009454 +0.009371 +0.009441 +0.009532 +0.009624 +0.009677 +0.009509 +0.009421 +0.009495 +0.009559 +0.009656 +0.00972 +0.009568 +0.009482 +0.009538 +0.009632 +0.009742 +0.009764 +0.009583 +0.009506 +0.009569 +0.009665 +0.00978 +0.009806 +0.009646 +0.00956 +0.009624 +0.009713 +0.009811 +0.009869 +0.009708 +0.00963 +0.009687 +0.009752 +0.009854 +0.009907 +0.009745 +0.009668 +0.009725 +0.009803 +0.00991 +0.009999 +0.009837 +0.009716 +0.009767 +0.009836 +0.009945 +0.010018 +0.009839 +0.009781 +0.00981 +0.009925 +0.010013 +0.01008 +0.00989 +0.00981 +0.009862 +0.009957 +0.010052 +0.010114 +0.009945 +0.009841 +0.009912 +0.010006 +0.010106 +0.010171 +0.010009 +0.009954 +0.009965 +0.010053 +0.01015 +0.010227 +0.010032 +0.009945 +0.010012 +0.01011 +0.010223 +0.010255 +0.010105 +0.010031 +0.010075 +0.010176 +0.010266 +0.010297 +0.010142 +0.010051 +0.010113 +0.010211 +0.010306 +0.01037 +0.010197 +0.010127 +0.010198 +0.010249 +0.010372 +0.01041 +0.010243 +0.010151 +0.010216 +0.010304 +0.010411 +0.010485 +0.010303 +0.010212 +0.010272 +0.010366 +0.010483 +0.010538 +0.010368 +0.010274 +0.010303 +0.010406 +0.010494 +0.010548 +0.010348 +0.01024 +0.010285 +0.010303 +0.010369 +0.010374 +0.010179 +0.009997 +0.010033 +0.010056 +0.010109 +0.010118 +0.009895 +0.009769 +0.009773 +0.009808 +0.009852 +0.00986 +0.009635 +0.009516 +0.009514 +0.009546 +0.009601 +0.009607 +0.009378 +0.009254 +0.009273 +0.009317 +0.009355 +0.009345 +0.009142 +0.00903 +0.009056 +0.009091 +0.009155 +0.009129 +0.008952 +0.008829 +0.008853 +0.008897 +0.008952 +0.008972 +0.008807 +0.008706 +0.008728 +0.008762 +0.008814 +0.008849 +0.008655 +0.008553 +0.008592 +0.008636 +0.008691 +0.008737 +0.00856 +0.008471 +0.00851 +0.008536 +0.008595 +0.008638 +0.008482 +0.008394 +0.008435 +0.008503 +0.008589 +0.008674 +0.008492 +0.008417 +0.008454 +0.008539 +0.008607 +0.00867 +0.008527 +0.008461 +0.008498 +0.008591 +0.00868 +0.008719 +0.008579 +0.008506 +0.008552 +0.008611 +0.008695 +0.008765 +0.008629 +0.008564 +0.008624 +0.008658 +0.008727 +0.008797 +0.008655 +0.008584 +0.008647 +0.008701 +0.008786 +0.008841 +0.008706 +0.008648 +0.008686 +0.008757 +0.008829 +0.008894 +0.008745 +0.008666 +0.008717 +0.008798 +0.008877 +0.008957 +0.00881 +0.008718 +0.008766 +0.008847 +0.008937 +0.008996 +0.008839 +0.008747 +0.008806 +0.008899 +0.008973 +0.009019 +0.008859 +0.00879 +0.008855 +0.008927 +0.009015 +0.00908 +0.008927 +0.008844 +0.008904 +0.008992 +0.009072 +0.009113 +0.008964 +0.008894 +0.008936 +0.009017 +0.009114 +0.009156 +0.009015 +0.008947 +0.009003 +0.009107 +0.009169 +0.009199 +0.009036 +0.00897 +0.00903 +0.009136 +0.009191 +0.009246 +0.009107 +0.009036 +0.009085 +0.00917 +0.009253 +0.009288 +0.009142 +0.009064 +0.009117 +0.009202 +0.009295 +0.009355 +0.009196 +0.009117 +0.009169 +0.009238 +0.009335 +0.009406 +0.009267 +0.009176 +0.00921 +0.009306 +0.009399 +0.009435 +0.009284 +0.009192 +0.009274 +0.009336 +0.009432 +0.009483 +0.009334 +0.00926 +0.009326 +0.009407 +0.009493 +0.009528 +0.009371 +0.009298 +0.009339 +0.00943 +0.009527 +0.0096 +0.009443 +0.009359 +0.009426 +0.009537 +0.009567 +0.009614 +0.009449 +0.009379 +0.009443 +0.00954 +0.009605 +0.00969 +0.009522 +0.009446 +0.009493 +0.009582 +0.00967 +0.009734 +0.009573 +0.009496 +0.009552 +0.009632 +0.009728 +0.009772 +0.009612 +0.009532 +0.009583 +0.009667 +0.009788 +0.009886 +0.00967 +0.0096 +0.009635 +0.009697 +0.009814 +0.009862 +0.0097 +0.009624 +0.009686 +0.00977 +0.00987 +0.009941 +0.009761 +0.009671 +0.009737 +0.009817 +0.009913 +0.009991 +0.009818 +0.009737 +0.00979 +0.009856 +0.00996 +0.010034 +0.009875 +0.0098 +0.009815 +0.009921 +0.010026 +0.010116 +0.009903 +0.009804 +0.009868 +0.009965 +0.010063 +0.010122 +0.009968 +0.009874 +0.009931 +0.010026 +0.010104 +0.010186 +0.010007 +0.009927 +0.00998 +0.010075 +0.010188 +0.010245 +0.010056 +0.009989 +0.010057 +0.010107 +0.010204 +0.010269 +0.010108 +0.010034 +0.010119 +0.010178 +0.010264 +0.010313 +0.010153 +0.010066 +0.010128 +0.010217 +0.010339 +0.010407 +0.010219 +0.010135 +0.010185 +0.010257 +0.010376 +0.010435 +0.010252 +0.010181 +0.010276 +0.010324 +0.010409 +0.010481 +0.010288 +0.010205 +0.01025 +0.010336 +0.01046 +0.010428 +0.010206 +0.010073 +0.010105 +0.010147 +0.010207 +0.010225 +0.009992 +0.009875 +0.009906 +0.009933 +0.009988 +0.009975 +0.009733 +0.009607 +0.009636 +0.009708 +0.009751 +0.009695 +0.009478 +0.009358 +0.009383 +0.009415 +0.009462 +0.009478 +0.00925 +0.009127 +0.009156 +0.009205 +0.009252 +0.00926 +0.009062 +0.00892 +0.008948 +0.009 +0.00905 +0.009065 +0.008878 +0.00877 +0.008806 +0.008857 +0.008913 +0.008938 +0.008767 +0.008637 +0.008653 +0.008709 +0.008781 +0.008781 +0.008613 +0.008513 +0.008538 +0.008606 +0.008656 +0.008689 +0.008509 +0.008427 +0.008455 +0.008517 +0.008589 +0.008642 +0.008476 +0.008393 +0.008444 +0.008499 +0.008585 +0.008644 +0.008502 +0.008425 +0.008467 +0.008534 +0.00864 +0.00872 +0.008564 +0.008466 +0.008512 +0.008575 +0.008661 +0.008747 +0.008576 +0.008499 +0.008547 +0.008633 +0.008711 +0.008769 +0.008628 +0.008545 +0.008599 +0.008677 +0.008763 +0.008836 +0.008661 +0.008589 +0.008652 +0.008724 +0.00881 +0.008873 +0.008707 +0.008624 +0.008682 +0.008766 +0.008871 +0.008904 +0.008745 +0.008671 +0.008723 +0.008804 +0.008887 +0.008952 +0.008824 +0.008724 +0.008781 +0.00884 +0.008932 +0.008998 +0.008848 +0.008768 +0.008816 +0.008889 +0.008979 +0.009037 +0.008892 +0.008803 +0.008862 +0.008946 +0.009029 +0.009099 +0.008939 +0.00887 +0.008929 +0.008995 +0.009059 +0.009111 +0.00897 +0.008894 +0.008954 +0.009046 +0.009124 +0.009193 +0.009036 +0.008938 +0.008979 +0.009065 +0.009162 +0.009214 +0.009068 +0.008997 +0.009044 +0.009117 +0.009214 +0.009266 +0.009112 +0.009034 +0.009078 +0.009155 +0.00926 +0.009346 +0.009194 +0.009081 +0.009163 +0.009192 +0.00929 +0.009359 +0.009197 +0.009114 +0.009168 +0.009263 +0.009362 +0.009408 +0.009266 +0.00917 +0.009225 +0.009309 +0.009398 +0.009447 +0.009292 +0.009218 +0.009259 +0.009347 +0.009449 +0.009498 +0.009347 +0.009268 +0.009333 +0.009433 +0.009479 +0.009552 +0.009389 +0.009333 +0.009343 +0.009433 +0.009528 +0.009605 +0.00943 +0.009348 +0.009414 +0.009507 +0.009602 +0.009664 +0.00949 +0.009392 +0.009449 +0.009538 +0.00964 +0.009693 +0.009534 +0.009454 +0.0095 +0.009595 +0.009693 +0.009779 +0.009579 +0.009479 +0.009547 +0.009634 +0.009745 +0.009823 +0.009638 +0.00954 +0.0096 +0.00968 +0.009781 +0.009843 +0.009669 +0.00959 +0.009662 +0.009754 +0.00984 +0.009911 +0.009702 +0.009635 +0.009705 +0.009791 +0.009877 +0.009945 +0.009797 +0.009737 +0.009748 +0.009832 +0.009931 +0.009969 +0.009821 +0.009734 +0.009792 +0.00992 +0.00998 +0.010029 +0.009865 +0.009769 +0.009841 +0.009938 +0.01002 +0.010103 +0.009941 +0.009854 +0.009912 +0.009995 +0.010072 +0.010146 +0.009971 +0.009894 +0.009979 +0.010049 +0.01013 +0.010199 +0.010029 +0.009948 +0.009993 +0.010066 +0.010177 +0.010239 +0.010077 +0.009989 +0.01004 +0.010136 +0.010248 +0.010298 +0.010121 +0.010037 +0.010095 +0.010189 +0.010301 +0.010367 +0.010184 +0.010084 +0.010164 +0.010272 +0.010326 +0.010383 +0.010234 +0.010135 +0.010205 +0.010304 +0.010408 +0.010449 +0.01026 +0.010179 +0.010237 +0.01034 +0.010452 +0.010517 +0.010326 +0.010229 +0.010283 +0.010359 +0.010409 +0.010443 +0.010216 +0.010092 +0.010163 +0.010226 +0.010249 +0.010238 +0.010032 +0.009889 +0.009955 +0.009955 +0.009998 +0.010016 +0.009798 +0.009669 +0.009684 +0.009716 +0.009762 +0.00978 +0.009548 +0.009427 +0.009445 +0.009508 +0.009545 +0.009556 +0.009348 +0.00921 +0.009221 +0.009283 +0.00933 +0.009355 +0.009116 +0.009008 +0.009028 +0.009075 +0.009129 +0.00914 +0.008945 +0.008852 +0.008857 +0.008916 +0.008956 +0.008981 +0.008795 +0.008699 +0.008714 +0.008776 +0.00882 +0.008849 +0.008671 +0.008561 +0.008596 +0.008656 +0.008719 +0.008751 +0.008575 +0.008488 +0.008533 +0.008605 +0.008648 +0.008682 +0.00852 +0.008452 +0.008509 +0.008591 +0.008675 +0.008732 +0.008588 +0.008502 +0.008569 +0.008611 +0.008707 +0.008763 +0.00861 +0.008542 +0.008599 +0.008669 +0.008745 +0.008816 +0.00866 +0.008582 +0.008634 +0.008716 +0.008787 +0.008859 +0.008714 +0.008649 +0.008721 +0.008765 +0.008846 +0.008896 +0.00874 +0.008666 +0.008715 +0.008791 +0.00887 +0.008949 +0.008786 +0.008715 +0.008786 +0.008863 +0.008917 +0.008983 +0.008838 +0.008763 +0.008811 +0.008883 +0.008973 +0.009025 +0.008891 +0.008826 +0.00886 +0.008936 +0.009026 +0.009076 +0.008947 +0.008849 +0.008894 +0.008964 +0.009058 +0.00914 +0.008961 +0.00889 +0.008939 +0.009026 +0.009105 +0.009164 +0.009019 +0.008938 +0.008987 +0.00908 +0.00917 +0.009203 +0.009052 +0.008982 +0.009042 +0.009115 +0.009198 +0.009262 +0.009106 +0.009034 +0.009097 +0.009185 +0.009281 +0.009284 +0.00914 +0.00906 +0.009122 +0.009201 +0.009304 +0.009359 +0.009202 +0.009126 +0.009174 +0.009255 +0.009348 +0.009381 +0.009228 +0.009151 +0.009213 +0.009298 +0.009401 +0.009445 +0.009285 +0.009205 +0.009269 +0.009345 +0.009431 +0.0095 +0.009342 +0.009283 +0.009317 +0.0094 +0.009476 +0.009528 +0.009382 +0.009282 +0.009349 +0.009452 +0.009523 +0.009593 +0.009442 +0.009357 +0.009413 +0.009496 +0.009574 +0.009626 +0.009468 +0.009397 +0.009434 +0.009527 +0.009622 +0.009686 +0.009526 +0.009438 +0.009513 +0.009609 +0.009704 +0.009721 +0.009549 +0.009484 +0.009553 +0.009618 +0.009711 +0.009786 +0.009618 +0.009534 +0.009593 +0.00967 +0.009766 +0.009846 +0.009671 +0.009585 +0.009638 +0.009724 +0.009814 +0.009879 +0.009719 +0.009627 +0.009678 +0.009796 +0.009891 +0.009979 +0.00976 +0.009676 +0.009754 +0.009796 +0.009908 +0.009959 +0.009807 +0.00974 +0.009767 +0.009865 +0.009972 +0.01003 +0.009857 +0.009772 +0.009824 +0.009919 +0.010036 +0.010097 +0.00991 +0.009808 +0.009889 +0.009964 +0.01007 +0.010137 +0.00999 +0.009888 +0.009935 +0.010022 +0.010119 +0.01021 +0.009992 +0.0099 +0.009974 +0.010047 +0.010171 +0.010241 +0.010047 +0.009964 +0.010037 +0.010106 +0.010221 +0.010289 +0.010112 +0.010019 +0.010103 +0.010188 +0.010263 +0.010333 +0.010164 +0.010112 +0.010124 +0.010212 +0.010302 +0.010399 +0.010222 +0.010125 +0.010216 +0.010279 +0.010353 +0.010422 +0.010254 +0.010156 +0.010245 +0.010319 +0.010425 +0.010487 +0.010295 +0.010192 +0.010242 +0.010342 +0.010398 +0.010434 +0.010233 +0.01009 +0.01011 +0.01018 +0.010239 +0.010207 +0.009984 +0.009866 +0.009883 +0.009924 +0.010005 +0.009996 +0.009752 +0.009626 +0.009622 +0.009674 +0.009705 +0.009707 +0.009495 +0.009366 +0.009395 +0.009446 +0.009474 +0.009483 +0.00927 +0.009151 +0.009165 +0.009207 +0.009256 +0.009273 +0.009091 +0.008939 +0.008952 +0.008994 +0.009041 +0.009067 +0.008863 +0.00876 +0.008791 +0.008848 +0.008903 +0.008904 +0.008732 +0.008623 +0.008648 +0.008685 +0.00874 +0.008757 +0.008583 +0.008491 +0.008519 +0.008572 +0.008626 +0.008664 +0.008492 +0.008401 +0.008441 +0.008508 +0.008587 +0.008623 +0.008464 +0.008371 +0.008428 +0.008505 +0.008588 +0.008635 +0.008501 +0.008422 +0.00847 +0.00854 +0.008622 +0.008696 +0.008536 +0.008464 +0.008516 +0.008606 +0.008678 +0.008723 +0.008578 +0.008507 +0.008551 +0.00863 +0.008724 +0.00877 +0.008633 +0.008551 +0.00862 +0.008699 +0.008791 +0.008825 +0.00865 +0.008578 +0.008667 +0.008707 +0.008786 +0.00885 +0.0087 +0.008631 +0.00869 +0.008769 +0.008864 +0.008904 +0.008761 +0.008668 +0.008729 +0.008797 +0.008883 +0.008954 +0.008798 +0.008717 +0.008773 +0.00886 +0.008936 +0.008991 +0.008848 +0.008771 +0.008841 +0.008892 +0.00897 +0.009036 +0.008895 +0.008815 +0.008868 +0.008937 +0.009018 +0.009084 +0.008925 +0.008848 +0.008908 +0.008981 +0.009081 +0.009138 +0.008994 +0.008894 +0.00895 +0.009026 +0.00911 +0.009174 +0.009023 +0.008949 +0.009002 +0.009065 +0.00918 +0.009239 +0.009099 +0.008985 +0.009043 +0.009109 +0.009196 +0.009266 +0.0091 +0.009027 +0.009107 +0.00916 +0.009243 +0.009307 +0.00916 +0.009075 +0.009128 +0.009219 +0.009298 +0.009362 +0.009217 +0.009136 +0.009183 +0.009252 +0.00935 +0.009408 +0.009249 +0.009171 +0.009224 +0.009332 +0.009416 +0.00945 +0.009292 +0.009213 +0.009278 +0.009334 +0.00943 +0.009501 +0.009336 +0.009262 +0.00932 +0.009401 +0.009485 +0.00955 +0.009394 +0.009301 +0.009355 +0.009438 +0.009537 +0.009604 +0.009444 +0.009362 +0.009421 +0.009487 +0.009594 +0.009665 +0.009499 +0.009392 +0.009462 +0.009536 +0.009626 +0.009688 +0.009527 +0.009444 +0.009524 +0.009579 +0.009675 +0.009753 +0.009575 +0.009489 +0.00955 +0.00963 +0.009733 +0.009799 +0.009646 +0.00956 +0.009591 +0.009692 +0.009779 +0.009832 +0.009677 +0.009599 +0.009666 +0.009737 +0.00983 +0.009896 +0.009743 +0.009644 +0.009679 +0.009769 +0.009876 +0.00993 +0.009768 +0.009679 +0.00974 +0.009834 +0.009935 +0.009988 +0.009811 +0.009745 +0.009785 +0.009872 +0.010003 +0.010068 +0.009867 +0.009782 +0.009842 +0.009969 +0.01002 +0.010078 +0.009902 +0.009831 +0.0099 +0.009981 +0.010124 +0.010127 +0.009964 +0.009875 +0.009946 +0.010023 +0.010118 +0.010201 +0.010017 +0.009947 +0.010012 +0.010094 +0.010165 +0.010245 +0.010067 +0.009986 +0.010039 +0.010131 +0.010266 +0.010293 +0.010122 +0.010036 +0.010095 +0.010166 +0.010273 +0.010341 +0.010181 +0.010083 +0.010133 +0.010258 +0.010351 +0.010402 +0.010227 +0.010116 +0.010181 +0.010284 +0.010375 +0.010437 +0.010297 +0.010184 +0.01024 +0.010339 +0.01045 +0.010484 +0.010297 +0.010167 +0.010217 +0.010302 +0.010338 +0.01035 +0.010146 +0.010009 +0.010027 +0.010078 +0.010116 +0.010116 +0.009906 +0.009769 +0.00978 +0.009821 +0.009856 +0.009864 +0.009652 +0.009529 +0.009538 +0.009566 +0.009625 +0.009638 +0.009417 +0.009277 +0.009287 +0.009345 +0.009367 +0.00937 +0.009176 +0.009063 +0.009102 +0.009116 +0.009158 +0.009173 +0.008968 +0.008871 +0.008887 +0.008932 +0.008963 +0.008989 +0.008834 +0.008724 +0.008743 +0.008781 +0.008821 +0.00885 +0.008658 +0.008572 +0.008594 +0.008665 +0.008692 +0.00872 +0.008539 +0.008441 +0.00848 +0.008532 +0.008598 +0.008611 +0.008464 +0.008372 +0.008415 +0.008475 +0.008547 +0.008591 +0.008462 +0.008386 +0.008429 +0.008491 +0.008576 +0.008646 +0.008487 +0.00842 +0.008458 +0.008545 +0.008624 +0.008696 +0.008532 +0.008471 +0.008532 +0.008588 +0.008653 +0.008704 +0.008567 +0.008497 +0.008555 +0.008615 +0.00872 +0.008786 +0.00863 +0.008567 +0.008593 +0.008668 +0.008734 +0.008795 +0.008654 +0.008587 +0.008634 +0.008719 +0.008785 +0.008853 +0.008703 +0.008627 +0.008689 +0.008743 +0.008837 +0.008904 +0.008756 +0.008711 +0.008776 +0.008796 +0.008859 +0.008926 +0.008787 +0.008708 +0.008764 +0.008846 +0.008916 +0.008988 +0.008855 +0.008778 +0.008811 +0.008887 +0.008978 +0.009016 +0.008874 +0.008804 +0.008858 +0.008938 +0.00902 +0.009077 +0.008925 +0.008845 +0.008903 +0.008978 +0.009054 +0.00912 +0.008975 +0.008901 +0.008983 +0.009042 +0.009108 +0.009149 +0.009008 +0.008929 +0.008983 +0.009062 +0.009159 +0.009207 +0.009074 +0.008998 +0.009043 +0.009119 +0.009209 +0.009257 +0.009092 +0.009016 +0.009082 +0.009161 +0.009243 +0.009312 +0.009157 +0.009076 +0.009141 +0.009215 +0.009286 +0.00934 +0.009194 +0.009116 +0.009205 +0.009252 +0.009339 +0.00939 +0.009238 +0.009168 +0.00921 +0.00929 +0.009383 +0.009443 +0.009287 +0.009209 +0.009286 +0.009361 +0.009435 +0.009497 +0.009325 +0.009249 +0.00931 +0.00941 +0.009464 +0.009541 +0.009399 +0.009302 +0.009372 +0.009461 +0.009543 +0.009609 +0.009411 +0.009362 +0.009381 +0.009472 +0.009568 +0.009627 +0.009473 +0.009397 +0.009449 +0.009539 +0.009632 +0.0097 +0.009518 +0.009443 +0.009507 +0.009572 +0.009671 +0.009744 +0.009561 +0.009491 +0.009559 +0.009617 +0.009726 +0.009805 +0.009643 +0.009572 +0.009593 +0.009657 +0.009757 +0.009858 +0.009649 +0.009587 +0.009623 +0.009747 +0.009829 +0.009895 +0.009728 +0.009639 +0.009677 +0.00977 +0.00986 +0.009928 +0.009766 +0.009691 +0.009727 +0.009818 +0.009926 +0.009984 +0.00981 +0.009727 +0.009808 +0.009893 +0.00998 +0.010032 +0.009855 +0.009772 +0.009833 +0.009935 +0.010015 +0.010087 +0.009904 +0.00983 +0.009904 +0.009986 +0.010078 +0.010143 +0.009943 +0.009862 +0.009935 +0.01001 +0.010109 +0.0102 +0.010006 +0.009926 +0.010001 +0.010097 +0.010197 +0.01022 +0.010049 +0.009968 +0.010053 +0.010135 +0.010232 +0.01028 +0.010105 +0.010024 +0.010085 +0.010185 +0.010265 +0.010347 +0.010176 +0.010087 +0.010171 +0.010226 +0.010307 +0.010381 +0.010205 +0.010119 +0.010185 +0.010281 +0.010422 +0.010469 +0.010234 +0.010143 +0.010205 +0.010304 +0.010378 +0.010418 +0.010217 +0.010077 +0.010111 +0.010149 +0.010211 +0.010233 +0.010008 +0.009857 +0.009876 +0.00994 +0.00998 +0.009991 +0.009744 +0.009611 +0.009616 +0.009667 +0.009708 +0.009713 +0.009502 +0.009392 +0.009409 +0.009407 +0.009442 +0.009458 +0.009251 +0.00912 +0.009145 +0.009184 +0.009237 +0.009258 +0.009044 +0.008919 +0.008926 +0.008979 +0.009028 +0.009055 +0.008865 +0.008737 +0.008776 +0.008832 +0.008888 +0.008895 +0.008724 +0.008604 +0.008622 +0.008685 +0.008733 +0.008785 +0.008586 +0.008477 +0.00851 +0.008563 +0.00862 +0.008657 +0.008484 +0.008387 +0.008434 +0.008495 +0.008556 +0.008602 +0.00845 +0.008385 +0.008419 +0.008495 +0.008558 +0.008625 +0.008475 +0.008401 +0.008447 +0.008509 +0.008595 +0.008686 +0.008528 +0.008453 +0.008505 +0.00858 +0.008677 +0.008713 +0.008548 +0.008476 +0.008529 +0.008604 +0.008699 +0.008751 +0.0086 +0.008532 +0.008582 +0.008671 +0.008735 +0.00879 +0.008642 +0.008573 +0.008636 +0.008718 +0.008782 +0.008837 +0.008682 +0.008608 +0.008663 +0.008736 +0.00883 +0.008879 +0.00873 +0.008661 +0.008718 +0.008821 +0.008887 +0.008928 +0.00876 +0.008685 +0.008748 +0.008831 +0.008907 +0.008992 +0.008812 +0.008759 +0.0088 +0.008876 +0.008967 +0.009011 +0.00886 +0.008786 +0.008836 +0.008917 +0.008996 +0.009067 +0.008909 +0.008829 +0.008882 +0.008953 +0.009044 +0.009102 +0.008959 +0.008902 +0.008946 +0.009 +0.0091 +0.00916 +0.009008 +0.008932 +0.00897 +0.009036 +0.009138 +0.009212 +0.009029 +0.008959 +0.009024 +0.00909 +0.009184 +0.009254 +0.00909 +0.009003 +0.009059 +0.00914 +0.009227 +0.009291 +0.009144 +0.009064 +0.009117 +0.009193 +0.009285 +0.009369 +0.00917 +0.009094 +0.009143 +0.009228 +0.009331 +0.009399 +0.009229 +0.009155 +0.009203 +0.009269 +0.009381 +0.009442 +0.009255 +0.009184 +0.00924 +0.009339 +0.009428 +0.009491 +0.009322 +0.009245 +0.009299 +0.009372 +0.009454 +0.009518 +0.009366 +0.009289 +0.009361 +0.009428 +0.009496 +0.009562 +0.009412 +0.009335 +0.009391 +0.009454 +0.009564 +0.009615 +0.00946 +0.00939 +0.00944 +0.009538 +0.009595 +0.00967 +0.009501 +0.009422 +0.009486 +0.009547 +0.009664 +0.00974 +0.009559 +0.009475 +0.009533 +0.009607 +0.009742 +0.009752 +0.009594 +0.009511 +0.009568 +0.00966 +0.009779 +0.009803 +0.009644 +0.009567 +0.009609 +0.009714 +0.009804 +0.009866 +0.009716 +0.009627 +0.009662 +0.009749 +0.009855 +0.009914 +0.009734 +0.009657 +0.009717 +0.009814 +0.009932 +0.009993 +0.009824 +0.009687 +0.009755 +0.009854 +0.009946 +0.010018 +0.009831 +0.009776 +0.009844 +0.009906 +0.010002 +0.010071 +0.00988 +0.009799 +0.009868 +0.009946 +0.010062 +0.010122 +0.009931 +0.009848 +0.009919 +0.01 +0.010098 +0.010168 +0.010003 +0.00995 +0.009976 +0.010059 +0.010146 +0.010205 +0.010041 +0.009954 +0.010007 +0.010109 +0.010197 +0.010304 +0.010107 +0.010007 +0.01007 +0.010148 +0.01026 +0.01031 +0.010142 +0.010052 +0.01011 +0.010212 +0.010292 +0.010367 +0.010208 +0.010125 +0.010188 +0.010251 +0.010356 +0.010423 +0.010268 +0.010154 +0.010208 +0.010312 +0.010382 +0.010448 +0.010261 +0.010176 +0.010179 +0.010253 +0.010292 +0.010287 +0.010073 +0.009932 +0.009949 +0.009986 +0.010036 +0.010026 +0.009822 +0.00968 +0.009704 +0.00974 +0.009783 +0.009798 +0.009554 +0.009463 +0.009433 +0.009467 +0.009515 +0.009504 +0.009304 +0.009189 +0.00919 +0.009222 +0.009261 +0.009266 +0.009085 +0.008961 +0.008993 +0.009017 +0.009047 +0.009064 +0.008868 +0.008766 +0.008788 +0.008823 +0.008856 +0.008894 +0.008738 +0.00864 +0.008681 +0.008695 +0.008736 +0.008762 +0.008579 +0.00852 +0.008518 +0.008566 +0.008614 +0.008666 +0.008484 +0.008391 +0.00842 +0.008479 +0.00852 +0.008572 +0.008409 +0.008321 +0.008361 +0.008412 +0.008493 +0.008541 +0.008393 +0.008306 +0.008364 +0.008416 +0.008504 +0.008564 +0.00843 +0.008363 +0.008408 +0.008476 +0.008552 +0.008608 +0.008464 +0.008395 +0.008434 +0.008528 +0.008586 +0.008644 +0.008496 +0.00843 +0.008485 +0.008551 +0.008641 +0.008693 +0.008554 +0.008477 +0.008529 +0.008594 +0.008683 +0.008759 +0.008586 +0.008531 +0.008579 +0.008636 +0.008712 +0.008787 +0.008647 +0.00858 +0.008602 +0.008684 +0.008754 +0.008822 +0.008695 +0.00861 +0.008664 +0.008734 +0.008843 +0.008845 +0.008714 +0.008647 +0.008692 +0.008779 +0.008851 +0.008919 +0.008762 +0.008688 +0.008746 +0.00881 +0.008892 +0.008955 +0.008819 +0.00873 +0.008786 +0.008881 +0.008965 +0.009033 +0.008864 +0.008779 +0.008813 +0.008894 +0.008984 +0.009043 +0.00889 +0.008819 +0.008896 +0.008958 +0.009048 +0.009097 +0.008934 +0.008867 +0.008903 +0.009 +0.009073 +0.009136 +0.009002 +0.008921 +0.008977 +0.009052 +0.009138 +0.009186 +0.009016 +0.008955 +0.009001 +0.009111 +0.00917 +0.009238 +0.009075 +0.009009 +0.00905 +0.009121 +0.00921 +0.009276 +0.009117 +0.009038 +0.009098 +0.009184 +0.009269 +0.00935 +0.009162 +0.009087 +0.009137 +0.009221 +0.009325 +0.009364 +0.009215 +0.009144 +0.009196 +0.009289 +0.009374 +0.009436 +0.009278 +0.009176 +0.009225 +0.009297 +0.009404 +0.009468 +0.009336 +0.009234 +0.009289 +0.009374 +0.009458 +0.009499 +0.009351 +0.009264 +0.009331 +0.009418 +0.009499 +0.009557 +0.009403 +0.009321 +0.009371 +0.009455 +0.009556 +0.009597 +0.009451 +0.009372 +0.009433 +0.00956 +0.00961 +0.009645 +0.009484 +0.009404 +0.009467 +0.009543 +0.009657 +0.009715 +0.009546 +0.009471 +0.009537 +0.009611 +0.009708 +0.009739 +0.009582 +0.009494 +0.009558 +0.009649 +0.009737 +0.009802 +0.009645 +0.009561 +0.009613 +0.009706 +0.009803 +0.009898 +0.009673 +0.009588 +0.009668 +0.009755 +0.009828 +0.009898 +0.009725 +0.009658 +0.009716 +0.009785 +0.009893 +0.009964 +0.009808 +0.009714 +0.009759 +0.009828 +0.009935 +0.010001 +0.009826 +0.009743 +0.009804 +0.009902 +0.010008 +0.010074 +0.009914 +0.009807 +0.009844 +0.009943 +0.010021 +0.010096 +0.009914 +0.009843 +0.009905 +0.009982 +0.010089 +0.010165 +0.009975 +0.009894 +0.009957 +0.010049 +0.010158 +0.010219 +0.010032 +0.009927 +0.010002 +0.010091 +0.010189 +0.010254 +0.010077 +0.010033 +0.01007 +0.010149 +0.010242 +0.010303 +0.010128 +0.010024 +0.010087 +0.010173 +0.010258 +0.010306 +0.010118 +0.009985 +0.010028 +0.010056 +0.010138 +0.010172 +0.00994 +0.009819 +0.009834 +0.009868 +0.009932 +0.009938 +0.009707 +0.009579 +0.009581 +0.009656 +0.009671 +0.009681 +0.009468 +0.009353 +0.00937 +0.00941 +0.009411 +0.009445 +0.009226 +0.009108 +0.009121 +0.009161 +0.0092 +0.009229 +0.009046 +0.00891 +0.008925 +0.008963 +0.008994 +0.009026 +0.008834 +0.008727 +0.008743 +0.008782 +0.008828 +0.008869 +0.008703 +0.008584 +0.008595 +0.008632 +0.008686 +0.00873 +0.008559 +0.00845 +0.008484 +0.008561 +0.008582 +0.008606 +0.008445 +0.008355 +0.008385 +0.008432 +0.008495 +0.008542 +0.008384 +0.008298 +0.008354 +0.008409 +0.00848 +0.008532 +0.00839 +0.008316 +0.008364 +0.008429 +0.008514 +0.008572 +0.00845 +0.008372 +0.008411 +0.00847 +0.008559 +0.00862 +0.008465 +0.008387 +0.008444 +0.008518 +0.008589 +0.008654 +0.008522 +0.00844 +0.008492 +0.008559 +0.008644 +0.008703 +0.00857 +0.008471 +0.008536 +0.008605 +0.008689 +0.008753 +0.008602 +0.008519 +0.008562 +0.008646 +0.008731 +0.008811 +0.008641 +0.008558 +0.00863 +0.008685 +0.008781 +0.008834 +0.008685 +0.008613 +0.008661 +0.008722 +0.008809 +0.008874 +0.008727 +0.008653 +0.008703 +0.008779 +0.008856 +0.008921 +0.008765 +0.0087 +0.008744 +0.008814 +0.008916 +0.008973 +0.008811 +0.008755 +0.008811 +0.008887 +0.008973 +0.009 +0.008862 +0.008768 +0.008829 +0.008925 +0.008982 +0.009056 +0.008911 +0.008821 +0.008869 +0.008948 +0.009047 +0.009107 +0.008947 +0.008878 +0.008918 +0.008999 +0.009103 +0.009164 +0.009 +0.00891 +0.008965 +0.009044 +0.009129 +0.009192 +0.009037 +0.00898 +0.009034 +0.009102 +0.00919 +0.009236 +0.009084 +0.009005 +0.009039 +0.00914 +0.009227 +0.009272 +0.00913 +0.009063 +0.009106 +0.009183 +0.009266 +0.009336 +0.009171 +0.009086 +0.009148 +0.009222 +0.00932 +0.009399 +0.009235 +0.009138 +0.009198 +0.009282 +0.009385 +0.00943 +0.009254 +0.009172 +0.009229 +0.009335 +0.009429 +0.009488 +0.009317 +0.009231 +0.009304 +0.009359 +0.009458 +0.009517 +0.009354 +0.009264 +0.009333 +0.00941 +0.009506 +0.009587 +0.009401 +0.009323 +0.009383 +0.009464 +0.009557 +0.009639 +0.009468 +0.009389 +0.009426 +0.009527 +0.009585 +0.009654 +0.009496 +0.009415 +0.009477 +0.009578 +0.009673 +0.00972 +0.009532 +0.009463 +0.00952 +0.0096 +0.009706 +0.009748 +0.0096 +0.00954 +0.009586 +0.009666 +0.009759 +0.009808 +0.009628 +0.009555 +0.009617 +0.009727 +0.009806 +0.009853 +0.009678 +0.009627 +0.009663 +0.009747 +0.009837 +0.009914 +0.009738 +0.009652 +0.009718 +0.009821 +0.009909 +0.009949 +0.009789 +0.009701 +0.009767 +0.00986 +0.009944 +0.010009 +0.009847 +0.009768 +0.009824 +0.009901 +0.010003 +0.010083 +0.00987 +0.009789 +0.009854 +0.009935 +0.010083 +0.010124 +0.009943 +0.009861 +0.009898 +0.009988 +0.010099 +0.010159 +0.00998 +0.00991 +0.009959 +0.010038 +0.010154 +0.010203 +0.010033 +0.00995 +0.010007 +0.010099 +0.01021 +0.010301 +0.010111 +0.009982 +0.010042 +0.010144 +0.010251 +0.010314 +0.010127 +0.010085 +0.010112 +0.010208 +0.010313 +0.010375 +0.010161 +0.010075 +0.010137 +0.010228 +0.010306 +0.010349 +0.010133 +0.009997 +0.01004 +0.010091 +0.010124 +0.010137 +0.009918 +0.00982 +0.009811 +0.009847 +0.009871 +0.00989 +0.009678 +0.009536 +0.009563 +0.009612 +0.00965 +0.009666 +0.009461 +0.009337 +0.009348 +0.009378 +0.009437 +0.009434 +0.009228 +0.009118 +0.009159 +0.009164 +0.009224 +0.009253 +0.009044 +0.008932 +0.008961 +0.009007 +0.009064 +0.00905 +0.008878 +0.008759 +0.008793 +0.008856 +0.0089 +0.008924 +0.008748 +0.008646 +0.008673 +0.008725 +0.008801 +0.008811 +0.008635 +0.008536 +0.008589 +0.008628 +0.008678 +0.008717 +0.008548 +0.008451 +0.008495 +0.008561 +0.008623 +0.008668 +0.008515 +0.008444 +0.008509 +0.008573 +0.008636 +0.008677 +0.008542 +0.008487 +0.008518 +0.00858 +0.008666 +0.008737 +0.0086 +0.008518 +0.008573 +0.008655 +0.008727 +0.00877 +0.00862 +0.008558 +0.008597 +0.008676 +0.008776 +0.008824 +0.00867 +0.008595 +0.00865 +0.008744 +0.008809 +0.008865 +0.008715 +0.008664 +0.008708 +0.008771 +0.008843 +0.008909 +0.008752 +0.008683 +0.008761 +0.008803 +0.008895 +0.008951 +0.008794 +0.00873 +0.008808 +0.00886 +0.008952 +0.009011 +0.008848 +0.008761 +0.00882 +0.008902 +0.008981 +0.009042 +0.0089 +0.008812 +0.008867 +0.008943 +0.009041 +0.009114 +0.008946 +0.008854 +0.00891 +0.008984 +0.009073 +0.009153 +0.008984 +0.008899 +0.008982 +0.009026 +0.009116 +0.009174 +0.009039 +0.008939 +0.00901 +0.009098 +0.009174 +0.009237 +0.009078 +0.008986 +0.009036 +0.00912 +0.009223 +0.009268 +0.009118 +0.009047 +0.009112 +0.009216 +0.009291 +0.009313 +0.00914 +0.009067 +0.009127 +0.009218 +0.0093 +0.009373 +0.009225 +0.009129 +0.009182 +0.009271 +0.009346 +0.009412 +0.009257 +0.009168 +0.00923 +0.009315 +0.009424 +0.009483 +0.009308 +0.009226 +0.009265 +0.009345 +0.009443 +0.00951 +0.009384 +0.009257 +0.009336 +0.00944 +0.009499 +0.009565 +0.009392 +0.009292 +0.00936 +0.009443 +0.009531 +0.009606 +0.009469 +0.009349 +0.009416 +0.009515 +0.009584 +0.009653 +0.009488 +0.009398 +0.009452 +0.009551 +0.009663 +0.009708 +0.009527 +0.009459 +0.009545 +0.009608 +0.009682 +0.009735 +0.009565 +0.009534 +0.009562 +0.009652 +0.009741 +0.0098 +0.009613 +0.009543 +0.009622 +0.009692 +0.009776 +0.009854 +0.00968 +0.009594 +0.009658 +0.009737 +0.009832 +0.009901 +0.009729 +0.009644 +0.009711 +0.009814 +0.009922 +0.009943 +0.009767 +0.009686 +0.009747 +0.009845 +0.009923 +0.010025 +0.009832 +0.009745 +0.009806 +0.009896 +0.009979 +0.010039 +0.009878 +0.009799 +0.009857 +0.009927 +0.010055 +0.010107 +0.009929 +0.00985 +0.009887 +0.009977 +0.010091 +0.010183 +0.009983 +0.009896 +0.009934 +0.010024 +0.010131 +0.010182 +0.010025 +0.009948 +0.009987 +0.01009 +0.010202 +0.010261 +0.010095 +0.009997 +0.01004 +0.010138 +0.010242 +0.010338 +0.010116 +0.010027 +0.010101 +0.01019 +0.010311 +0.01037 +0.010207 +0.010078 +0.010165 +0.010223 +0.010332 +0.010405 +0.010227 +0.010151 +0.01022 +0.010299 +0.010406 +0.010462 +0.010267 +0.01018 +0.010254 +0.010342 +0.010446 +0.010501 +0.010302 +0.010217 +0.010273 +0.010336 +0.010395 +0.010429 +0.010233 +0.010093 +0.010102 +0.01015 +0.01021 +0.010181 +0.009971 +0.009836 +0.009873 +0.009897 +0.009967 +0.009972 +0.009746 +0.009623 +0.009633 +0.009659 +0.009701 +0.009705 +0.009504 +0.009384 +0.009406 +0.009451 +0.009479 +0.00949 +0.009285 +0.00917 +0.00922 +0.00925 +0.009268 +0.009291 +0.009102 +0.009003 +0.009029 +0.009059 +0.009098 +0.009125 +0.008929 +0.008834 +0.008871 +0.008921 +0.008973 +0.008991 +0.008812 +0.008705 +0.008736 +0.008789 +0.00883 +0.008859 +0.008682 +0.008595 +0.008628 +0.008678 +0.008738 +0.008769 +0.008615 +0.008504 +0.008547 +0.008605 +0.008662 +0.008704 +0.008551 +0.008468 +0.008521 +0.008611 +0.008681 +0.008728 +0.008591 +0.00852 +0.00856 +0.008631 +0.008716 +0.008777 +0.008625 +0.008557 +0.008636 +0.008684 +0.008771 +0.008806 +0.008665 +0.008589 +0.008642 +0.008731 +0.008805 +0.008888 +0.008737 +0.00864 +0.008692 +0.00877 +0.008854 +0.008909 +0.008763 +0.00867 +0.008729 +0.0088 +0.008904 +0.008942 +0.008796 +0.008724 +0.008775 +0.008858 +0.008923 +0.008999 +0.008841 +0.008773 +0.008827 +0.008893 +0.009002 +0.009052 +0.008881 +0.008814 +0.008868 +0.008964 +0.009041 +0.009078 +0.008935 +0.008858 +0.008906 +0.008986 +0.009073 +0.009141 +0.008984 +0.008909 +0.008936 +0.009026 +0.009134 +0.009177 +0.00902 +0.00895 +0.008989 +0.009092 +0.009179 +0.009239 +0.009074 +0.008995 +0.009042 +0.00911 +0.009203 +0.009273 +0.009117 +0.009075 +0.009078 +0.009166 +0.009248 +0.009314 +0.009184 +0.009071 +0.009121 +0.009211 +0.009306 +0.009373 +0.009216 +0.009151 +0.009183 +0.009252 +0.009357 +0.009402 +0.009248 +0.009168 +0.009218 +0.009308 +0.009409 +0.009479 +0.009302 +0.009223 +0.009274 +0.009358 +0.009473 +0.009494 +0.00933 +0.009246 +0.009306 +0.009414 +0.009486 +0.009548 +0.009402 +0.009311 +0.009359 +0.009443 +0.009553 +0.00961 +0.009446 +0.009372 +0.009423 +0.009508 +0.009583 +0.009637 +0.009479 +0.009403 +0.009455 +0.009543 +0.009643 +0.009708 +0.009571 +0.009462 +0.009501 +0.009574 +0.009679 +0.009748 +0.009574 +0.009503 +0.009544 +0.009639 +0.009737 +0.009786 +0.009632 +0.009534 +0.009599 +0.009709 +0.009778 +0.009866 +0.009694 +0.009594 +0.009632 +0.009729 +0.009824 +0.009888 +0.009728 +0.009645 +0.009753 +0.009808 +0.009896 +0.009933 +0.009759 +0.009679 +0.009731 +0.009825 +0.009931 +0.009996 +0.009813 +0.009772 +0.00979 +0.009878 +0.009981 +0.010041 +0.009871 +0.009783 +0.009849 +0.009935 +0.010048 +0.010095 +0.009926 +0.00983 +0.009902 +0.010003 +0.010101 +0.010138 +0.009952 +0.009919 +0.009953 +0.010033 +0.010114 +0.010192 +0.010019 +0.009927 +0.009992 +0.010082 +0.010203 +0.010258 +0.01008 +0.009987 +0.010048 +0.010122 +0.010223 +0.010291 +0.010121 +0.010037 +0.010086 +0.010189 +0.01032 +0.010359 +0.010152 +0.010065 +0.01015 +0.010229 +0.010346 +0.010435 +0.010235 +0.010115 +0.010186 +0.010276 +0.010382 +0.010463 +0.010263 +0.010214 +0.010262 +0.010344 +0.010432 +0.010476 +0.010268 +0.010175 +0.010209 +0.010263 +0.010332 +0.010397 +0.010173 +0.010011 +0.010048 +0.010077 +0.010135 +0.010139 +0.009952 +0.009813 +0.009831 +0.009853 +0.00989 +0.009868 +0.009664 +0.009542 +0.009555 +0.009579 +0.009603 +0.00963 +0.00942 +0.009296 +0.009317 +0.009331 +0.009351 +0.009371 +0.009178 +0.009094 +0.009086 +0.009109 +0.009155 +0.009161 +0.008981 +0.008874 +0.008897 +0.008933 +0.008985 +0.009018 +0.008819 +0.008722 +0.008752 +0.008801 +0.008845 +0.008863 +0.008684 +0.00859 +0.008622 +0.008669 +0.008709 +0.008738 +0.008583 +0.008489 +0.008524 +0.008566 +0.008624 +0.008658 +0.008495 +0.00839 +0.00843 +0.008484 +0.008544 +0.00861 +0.008456 +0.008375 +0.008426 +0.008497 +0.008572 +0.008637 +0.008502 +0.008421 +0.008455 +0.008528 +0.008624 +0.00868 +0.00854 +0.008446 +0.008511 +0.008577 +0.008658 +0.008731 +0.008573 +0.008491 +0.008552 +0.008625 +0.008722 +0.008801 +0.008613 +0.008547 +0.00858 +0.008661 +0.008755 +0.008803 +0.008669 +0.008578 +0.008629 +0.008721 +0.008795 +0.008859 +0.008701 +0.008624 +0.008704 +0.008744 +0.008818 +0.008888 +0.008743 +0.008674 +0.00873 +0.008789 +0.008879 +0.008933 +0.00879 +0.008709 +0.008771 +0.008858 +0.00894 +0.008979 +0.008835 +0.008769 +0.008819 +0.008892 +0.008983 +0.009011 +0.00887 +0.008792 +0.008843 +0.008936 +0.009015 +0.009095 +0.008927 +0.008858 +0.008904 +0.008976 +0.009047 +0.009117 +0.008959 +0.008888 +0.008948 +0.009026 +0.009103 +0.009166 +0.009021 +0.008952 +0.008993 +0.009059 +0.009137 +0.009212 +0.009057 +0.008992 +0.009051 +0.009118 +0.009222 +0.009239 +0.009094 +0.009018 +0.009068 +0.009154 +0.009228 +0.00932 +0.009175 +0.009079 +0.009146 +0.009203 +0.00928 +0.009344 +0.00919 +0.009106 +0.009164 +0.009252 +0.009359 +0.009428 +0.009235 +0.009155 +0.009219 +0.009289 +0.009378 +0.009445 +0.009288 +0.009211 +0.00927 +0.009372 +0.009438 +0.009489 +0.009328 +0.009248 +0.009307 +0.009373 +0.009472 +0.009555 +0.009394 +0.009312 +0.009372 +0.009448 +0.009523 +0.009583 +0.009425 +0.009366 +0.009397 +0.009467 +0.00959 +0.009639 +0.009488 +0.009405 +0.00946 +0.009523 +0.009616 +0.009677 +0.009516 +0.00944 +0.00952 +0.009558 +0.009673 +0.009718 +0.009562 +0.009498 +0.00955 +0.009624 +0.009724 +0.0098 +0.009633 +0.009537 +0.009588 +0.00969 +0.009787 +0.009824 +0.009658 +0.009574 +0.009637 +0.009762 +0.009824 +0.009878 +0.009714 +0.009613 +0.009693 +0.009774 +0.009859 +0.009927 +0.009772 +0.009669 +0.009731 +0.00983 +0.009912 +0.009981 +0.009813 +0.009724 +0.009788 +0.00988 +0.009983 +0.010085 +0.00985 +0.009758 +0.009823 +0.009917 +0.010024 +0.010081 +0.009931 +0.00982 +0.009887 +0.009979 +0.010089 +0.01011 +0.009947 +0.009875 +0.009919 +0.010028 +0.010119 +0.010194 +0.010022 +0.009933 +0.009986 +0.010066 +0.010154 +0.010233 +0.01009 +0.009962 +0.010037 +0.010115 +0.01021 +0.010282 +0.010104 +0.01001 +0.010085 +0.010187 +0.010264 +0.010342 +0.010163 +0.010083 +0.010123 +0.01021 +0.010307 +0.010401 +0.010204 +0.010109 +0.010196 +0.010277 +0.010364 +0.010431 +0.01024 +0.010109 +0.010126 +0.010182 +0.010211 +0.010226 +0.01004 +0.009917 +0.009912 +0.009963 +0.010005 +0.010027 +0.009807 +0.009666 +0.009686 +0.00972 +0.009749 +0.009789 +0.009583 +0.009435 +0.00944 +0.009472 +0.009518 +0.009521 +0.009319 +0.009198 +0.009208 +0.009284 +0.009284 +0.009289 +0.009097 +0.008967 +0.008976 +0.009004 +0.009052 +0.009074 +0.008894 +0.008788 +0.008812 +0.00885 +0.008885 +0.008911 +0.008733 +0.008623 +0.008644 +0.008685 +0.008741 +0.008769 +0.008611 +0.008501 +0.008536 +0.008569 +0.008623 +0.008661 +0.008498 +0.008421 +0.008443 +0.008475 +0.008532 +0.008584 +0.008428 +0.008359 +0.008378 +0.008425 +0.008495 +0.008556 +0.008412 +0.008348 +0.008389 +0.008459 +0.008552 +0.008603 +0.008468 +0.008376 +0.008429 +0.008497 +0.008584 +0.008631 +0.008491 +0.008426 +0.008475 +0.008543 +0.008626 +0.008694 +0.008551 +0.008487 +0.008512 +0.008587 +0.008662 +0.008724 +0.008584 +0.008512 +0.008575 +0.008656 +0.008727 +0.008751 +0.008615 +0.008547 +0.008602 +0.008668 +0.008745 +0.008817 +0.008668 +0.008596 +0.008648 +0.008735 +0.008809 +0.008859 +0.008709 +0.008633 +0.008682 +0.008756 +0.008849 +0.008921 +0.008776 +0.008676 +0.008739 +0.008812 +0.008893 +0.008955 +0.008784 +0.008715 +0.008767 +0.008844 +0.00893 +0.008996 +0.008845 +0.008761 +0.008817 +0.00889 +0.008984 +0.009028 +0.008876 +0.008814 +0.008876 +0.008938 +0.00903 +0.009103 +0.008944 +0.008861 +0.008913 +0.00899 +0.00909 +0.009118 +0.00899 +0.008882 +0.008934 +0.009039 +0.009117 +0.009178 +0.009027 +0.00895 +0.008997 +0.009068 +0.009163 +0.009211 +0.009059 +0.008992 +0.009035 +0.009105 +0.009201 +0.009271 +0.009108 +0.009033 +0.009095 +0.009173 +0.00925 +0.009317 +0.009174 +0.009109 +0.009128 +0.009194 +0.009285 +0.009352 +0.00923 +0.009112 +0.009169 +0.00926 +0.009355 +0.009413 +0.009256 +0.009167 +0.009201 +0.009299 +0.009393 +0.009445 +0.009291 +0.009215 +0.009265 +0.009346 +0.009443 +0.009497 +0.009339 +0.009254 +0.009318 +0.009405 +0.009489 +0.009558 +0.009421 +0.00934 +0.009341 +0.009424 +0.009519 +0.009611 +0.009427 +0.009335 +0.009415 +0.009498 +0.009598 +0.009648 +0.009497 +0.009387 +0.009446 +0.009528 +0.009626 +0.009685 +0.009523 +0.009449 +0.009519 +0.009605 +0.009704 +0.009752 +0.009567 +0.009482 +0.009539 +0.009658 +0.009728 +0.009775 +0.009615 +0.009534 +0.009596 +0.009678 +0.00978 +0.009847 +0.009657 +0.009583 +0.009653 +0.009743 +0.009841 +0.009901 +0.009736 +0.009616 +0.009685 +0.009778 +0.009865 +0.009936 +0.009778 +0.009685 +0.009743 +0.009839 +0.009933 +0.010011 +0.0098 +0.009725 +0.009783 +0.009879 +0.009985 +0.010049 +0.009875 +0.009792 +0.009828 +0.009924 +0.010024 +0.010074 +0.009914 +0.009839 +0.009904 +0.00999 +0.010097 +0.010117 +0.009962 +0.009888 +0.00994 +0.010019 +0.010128 +0.010219 +0.010064 +0.009944 +0.009977 +0.010074 +0.010159 +0.010233 +0.010053 +0.009982 +0.010044 +0.010122 +0.010228 +0.010293 +0.01011 +0.010021 +0.010086 +0.010177 +0.010285 +0.010364 +0.010183 +0.010097 +0.010135 +0.01023 +0.010328 +0.0104 +0.010245 +0.010133 +0.010176 +0.010304 +0.010355 +0.010411 +0.010187 +0.010065 +0.010092 +0.010139 +0.010218 +0.010243 +0.010016 +0.009885 +0.009906 +0.009927 +0.009984 +0.009984 +0.009773 +0.009651 +0.009637 +0.00969 +0.009741 +0.009727 +0.009502 +0.009376 +0.00938 +0.009445 +0.009455 +0.009456 +0.00925 +0.009131 +0.009155 +0.009197 +0.009236 +0.009237 +0.009047 +0.008924 +0.008941 +0.008987 +0.009038 +0.009044 +0.008859 +0.008754 +0.008787 +0.008826 +0.008889 +0.008884 +0.008713 +0.008605 +0.008637 +0.008687 +0.008721 +0.00876 +0.008601 +0.00852 +0.00852 +0.008562 +0.008609 +0.008642 +0.008468 +0.008376 +0.008411 +0.008457 +0.008527 +0.008569 +0.008406 +0.00832 +0.008366 +0.00842 +0.0085 +0.00856 +0.008436 +0.008336 +0.008386 +0.008459 +0.008541 +0.008608 +0.008461 +0.008384 +0.008422 +0.008497 +0.008583 +0.008642 +0.008517 +0.008428 +0.008464 +0.008544 +0.008631 +0.008688 +0.008547 +0.008475 +0.008501 +0.008606 +0.008663 +0.008735 +0.008571 +0.008508 +0.008554 +0.008617 +0.008696 +0.008776 +0.00862 +0.008553 +0.0086 +0.008671 +0.008765 +0.008814 +0.008675 +0.008599 +0.00865 +0.008709 +0.0088 +0.008883 +0.008739 +0.008628 +0.008679 +0.008748 +0.008842 +0.008911 +0.008769 +0.008685 +0.008736 +0.008804 +0.008884 +0.008938 +0.0088 +0.008715 +0.008774 +0.00885 +0.008939 +0.009015 +0.00885 +0.00878 +0.008822 +0.008892 +0.008969 +0.009036 +0.008882 +0.008805 +0.008866 +0.008963 +0.009044 +0.009074 +0.008939 +0.008844 +0.008899 +0.008985 +0.009062 +0.009125 +0.008978 +0.008905 +0.008961 +0.00904 +0.009121 +0.009163 +0.009015 +0.008934 +0.008992 +0.009081 +0.009151 +0.00924 +0.009082 +0.008994 +0.009058 +0.009111 +0.0092 +0.009266 +0.009111 +0.009059 +0.009101 +0.009156 +0.009237 +0.009309 +0.009156 +0.009073 +0.009134 +0.009209 +0.009297 +0.009362 +0.009204 +0.009136 +0.009188 +0.009264 +0.009358 +0.009399 +0.009237 +0.009163 +0.00923 +0.009302 +0.009389 +0.009466 +0.009308 +0.009228 +0.009273 +0.009357 +0.009461 +0.0095 +0.009328 +0.009257 +0.009312 +0.009403 +0.009498 +0.00959 +0.00938 +0.009307 +0.009354 +0.009431 +0.009534 +0.009583 +0.009431 +0.009356 +0.009437 +0.00949 +0.009581 +0.00965 +0.009476 +0.009396 +0.009453 +0.009531 +0.009632 +0.009711 +0.009567 +0.00949 +0.009511 +0.009565 +0.009669 +0.009734 +0.009572 +0.0095 +0.009539 +0.009661 +0.009751 +0.0098 +0.009639 +0.009545 +0.009586 +0.009684 +0.009773 +0.009839 +0.009672 +0.009602 +0.009645 +0.009731 +0.009836 +0.00989 +0.009723 +0.00964 +0.00971 +0.009816 +0.009904 +0.009937 +0.009772 +0.009673 +0.009743 +0.00983 +0.00992 +0.009996 +0.009812 +0.00974 +0.00981 +0.0099 +0.009997 +0.010061 +0.009866 +0.009769 +0.009839 +0.009923 +0.010028 +0.010098 +0.009921 +0.009834 +0.009923 +0.010008 +0.010133 +0.010138 +0.009957 +0.009862 +0.009933 +0.010034 +0.010133 +0.010207 +0.010012 +0.009926 +0.009989 +0.010089 +0.010221 +0.010224 +0.010072 +0.009981 +0.010055 +0.010159 +0.010242 +0.01028 +0.01013 +0.010028 +0.010092 +0.010192 +0.010298 +0.010388 +0.010179 +0.010083 +0.010153 +0.010238 +0.010335 +0.010373 +0.010192 +0.010101 +0.010158 +0.010228 +0.010288 +0.010318 +0.010103 +0.009989 +0.010001 +0.010071 +0.010088 +0.010126 +0.009901 +0.009771 +0.009814 +0.009842 +0.009858 +0.009866 +0.009648 +0.009559 +0.009539 +0.009576 +0.009597 +0.009632 +0.009419 +0.009288 +0.0093 +0.00934 +0.009354 +0.009351 +0.009153 +0.00905 +0.00906 +0.009111 +0.009146 +0.009165 +0.008947 +0.008843 +0.008871 +0.008918 +0.008942 +0.008969 +0.00878 +0.008683 +0.008724 +0.008777 +0.008825 +0.008819 +0.008632 +0.008534 +0.008571 +0.008627 +0.008673 +0.008677 +0.008521 +0.008454 +0.00847 +0.008514 +0.008563 +0.008585 +0.008415 +0.00833 +0.008371 +0.008438 +0.008479 +0.008526 +0.008383 +0.008315 +0.008363 +0.008431 +0.008511 +0.008571 +0.008421 +0.008349 +0.008402 +0.008468 +0.008586 +0.008631 +0.008463 +0.008376 +0.008431 +0.00852 +0.008584 +0.008649 +0.008501 +0.00843 +0.008478 +0.00856 +0.008652 +0.008705 +0.008555 +0.008476 +0.008524 +0.008604 +0.008691 +0.00873 +0.008594 +0.00851 +0.008573 +0.008652 +0.008731 +0.008786 +0.008636 +0.00857 +0.008616 +0.008703 +0.008765 +0.008809 +0.008666 +0.008606 +0.008669 +0.008714 +0.008805 +0.008867 +0.008725 +0.008643 +0.008699 +0.00877 +0.00888 +0.008917 +0.008769 +0.008703 +0.00874 +0.008806 +0.008881 +0.008957 +0.008808 +0.008728 +0.0088 +0.008855 +0.008945 +0.009025 +0.008866 +0.008807 +0.008846 +0.008899 +0.008975 +0.009033 +0.008896 +0.008829 +0.00886 +0.008941 +0.009035 +0.009091 +0.008945 +0.008861 +0.008919 +0.00899 +0.009077 +0.009149 +0.008982 +0.008907 +0.008973 +0.009052 +0.009115 +0.009178 +0.009039 +0.008947 +0.009006 +0.009086 +0.009169 +0.009265 +0.009087 +0.009004 +0.00905 +0.009128 +0.009219 +0.009273 +0.009122 +0.009047 +0.009095 +0.009161 +0.009263 +0.009341 +0.009165 +0.00909 +0.009149 +0.009222 +0.009302 +0.009358 +0.009207 +0.00913 +0.009189 +0.009275 +0.009345 +0.009416 +0.009261 +0.009179 +0.009269 +0.009321 +0.009402 +0.009456 +0.009308 +0.009247 +0.009279 +0.009345 +0.009445 +0.00951 +0.009357 +0.009265 +0.009331 +0.009404 +0.009503 +0.009583 +0.009407 +0.00932 +0.009375 +0.009447 +0.009534 +0.009602 +0.009446 +0.00936 +0.009426 +0.009508 +0.009606 +0.00969 +0.009483 +0.0094 +0.009446 +0.009554 +0.009648 +0.009706 +0.009544 +0.009479 +0.009516 +0.00959 +0.009729 +0.009749 +0.00958 +0.009498 +0.009551 +0.009646 +0.009741 +0.009825 +0.009642 +0.009551 +0.009612 +0.009688 +0.009784 +0.00986 +0.009692 +0.009631 +0.009669 +0.009749 +0.009844 +0.00991 +0.009735 +0.009625 +0.009695 +0.009804 +0.009882 +0.009961 +0.009783 +0.009701 +0.009779 +0.009839 +0.009939 +0.009991 +0.009825 +0.009744 +0.009805 +0.009909 +0.010005 +0.01005 +0.009872 +0.0098 +0.009891 +0.009949 +0.010033 +0.010084 +0.009942 +0.009869 +0.009935 +0.009988 +0.010086 +0.010132 +0.009967 +0.009895 +0.00994 +0.01004 +0.010142 +0.010213 +0.010027 +0.009944 +0.010008 +0.01008 +0.010191 +0.010267 +0.010084 +0.009994 +0.01007 +0.010186 +0.010244 +0.010297 +0.010118 +0.010045 +0.010112 +0.010169 +0.010272 +0.01037 +0.010155 +0.010049 +0.010075 +0.010123 +0.010184 +0.010212 +0.01002 +0.009899 +0.009928 +0.009995 +0.010047 +0.010039 +0.009831 +0.009683 +0.009702 +0.009745 +0.009783 +0.009838 +0.009582 +0.009455 +0.009475 +0.009503 +0.009545 +0.009555 +0.009349 +0.009243 +0.009265 +0.009276 +0.009316 +0.009347 +0.009133 +0.009021 +0.009045 +0.009068 +0.00911 +0.009141 +0.008951 +0.008843 +0.008861 +0.00893 +0.008966 +0.008985 +0.008807 +0.008691 +0.008747 +0.008768 +0.008803 +0.008826 +0.00867 +0.008565 +0.008604 +0.008647 +0.008683 +0.008722 +0.008549 +0.008439 +0.008471 +0.008538 +0.008563 +0.008606 +0.008457 +0.008376 +0.008401 +0.008458 +0.00853 +0.008573 +0.008435 +0.008372 +0.008409 +0.00847 +0.008561 +0.008625 +0.008489 +0.008427 +0.008466 +0.008512 +0.008586 +0.008659 +0.008528 +0.008437 +0.008485 +0.008553 +0.00865 +0.008713 +0.008559 +0.008492 +0.008544 +0.008601 +0.008683 +0.008741 +0.008603 +0.00854 +0.008576 +0.008653 +0.008723 +0.008781 +0.008633 +0.008567 +0.008612 +0.0087 +0.00877 +0.008842 +0.00871 +0.008623 +0.008667 +0.008746 +0.008816 +0.008872 +0.008734 +0.00867 +0.008695 +0.008775 +0.008859 +0.008915 +0.00877 +0.008716 +0.008754 +0.008831 +0.008913 +0.008963 +0.008811 +0.008734 +0.008795 +0.008858 +0.008947 +0.009017 +0.008873 +0.008796 +0.00884 +0.008933 +0.00902 +0.009063 +0.008889 +0.008814 +0.00887 +0.00895 +0.00906 +0.009095 +0.008938 +0.008873 +0.008939 +0.009 +0.009083 +0.009146 +0.008987 +0.008915 +0.008973 +0.009056 +0.009141 +0.009185 +0.009037 +0.008952 +0.009005 +0.009101 +0.009176 +0.009237 +0.009089 +0.009026 +0.009094 +0.009157 +0.009228 +0.009267 +0.009119 +0.009047 +0.009102 +0.009181 +0.009268 +0.009337 +0.009175 +0.009106 +0.009145 +0.009216 +0.009316 +0.009374 +0.009226 +0.009138 +0.009194 +0.009298 +0.009381 +0.009425 +0.009267 +0.009185 +0.009234 +0.009318 +0.009414 +0.009494 +0.009331 +0.009234 +0.009291 +0.009387 +0.009471 +0.009509 +0.009345 +0.009271 +0.009327 +0.009406 +0.0095 +0.009585 +0.009452 +0.009327 +0.009395 +0.009472 +0.009537 +0.009605 +0.009444 +0.009361 +0.009416 +0.009526 +0.009602 +0.009657 +0.009506 +0.009428 +0.009513 +0.009544 +0.009645 +0.009699 +0.009554 +0.009502 +0.00953 +0.009612 +0.009698 +0.009747 +0.009585 +0.009518 +0.009562 +0.009648 +0.009747 +0.009833 +0.009654 +0.009561 +0.009637 +0.009703 +0.009788 +0.009858 +0.009684 +0.009605 +0.009681 +0.009759 +0.009875 +0.009894 +0.009725 +0.009662 +0.009714 +0.009805 +0.009895 +0.009984 +0.009801 +0.009707 +0.009756 +0.00985 +0.009933 +0.010004 +0.00985 +0.009748 +0.009817 +0.009913 +0.010018 +0.010071 +0.009895 +0.009798 +0.009851 +0.009943 +0.010048 +0.010151 +0.009937 +0.009868 +0.009901 +0.009997 +0.010101 +0.01016 +0.009984 +0.009899 +0.009983 +0.010036 +0.010169 +0.010223 +0.010039 +0.009947 +0.010005 +0.010094 +0.010209 +0.010268 +0.010079 +0.010015 +0.010085 +0.010165 +0.010264 +0.010326 +0.010158 +0.010037 +0.010099 +0.010202 +0.010294 +0.010368 +0.010187 +0.010097 +0.010164 +0.010249 +0.010336 +0.010431 +0.010201 +0.010112 +0.010178 +0.010211 +0.010262 +0.010295 +0.010064 +0.009936 +0.009966 +0.010001 +0.010055 +0.010065 +0.009865 +0.009765 +0.009746 +0.009753 +0.009801 +0.009823 +0.009583 +0.009466 +0.009483 +0.00952 +0.009564 +0.009583 +0.009378 +0.009245 +0.009269 +0.009284 +0.00932 +0.00933 +0.009132 +0.009025 +0.00903 +0.00907 +0.009121 +0.009121 +0.008938 +0.008825 +0.008854 +0.008902 +0.008944 +0.008944 +0.008759 +0.008677 +0.008694 +0.008725 +0.008796 +0.008784 +0.008619 +0.008523 +0.008557 +0.008595 +0.00866 +0.008677 +0.008521 +0.00843 +0.00847 +0.008503 +0.008543 +0.008586 +0.008418 +0.008336 +0.008378 +0.008434 +0.008481 +0.008537 +0.008392 +0.008321 +0.008386 +0.008455 +0.008502 +0.008559 +0.008423 +0.008347 +0.008404 +0.00847 +0.008547 +0.008605 +0.008497 +0.008375 +0.008436 +0.008515 +0.008594 +0.008649 +0.008505 +0.008432 +0.008476 +0.008553 +0.008641 +0.008713 +0.008552 +0.008477 +0.008521 +0.008601 +0.008698 +0.008729 +0.008595 +0.008523 +0.008585 +0.008645 +0.008723 +0.008782 +0.008642 +0.008562 +0.008604 +0.008675 +0.008756 +0.008829 +0.008677 +0.008618 +0.00866 +0.008715 +0.008803 +0.008864 +0.008723 +0.008642 +0.008693 +0.008765 +0.00886 +0.008917 +0.008764 +0.008706 +0.008741 +0.00881 +0.008896 +0.00895 +0.008828 +0.008754 +0.008777 +0.008858 +0.00896 +0.008988 +0.008865 +0.00878 +0.008828 +0.008912 +0.008989 +0.009034 +0.008886 +0.008819 +0.008879 +0.008941 +0.009046 +0.009093 +0.008935 +0.008861 +0.008915 +0.008981 +0.009075 +0.009141 +0.008986 +0.00891 +0.008967 +0.009062 +0.009165 +0.009197 +0.009017 +0.008947 +0.008999 +0.009071 +0.00919 +0.00921 +0.00907 +0.009014 +0.009056 +0.009144 +0.009226 +0.009278 +0.009102 +0.009035 +0.009102 +0.009173 +0.009257 +0.00933 +0.009156 +0.009086 +0.009142 +0.009231 +0.009308 +0.009359 +0.009217 +0.009148 +0.009216 +0.009264 +0.009371 +0.00943 +0.009242 +0.00918 +0.009227 +0.009336 +0.009409 +0.009454 +0.009297 +0.009226 +0.009292 +0.009365 +0.009458 +0.009525 +0.009332 +0.009272 +0.009334 +0.009416 +0.009498 +0.009561 +0.009394 +0.009313 +0.009365 +0.009462 +0.009581 +0.00961 +0.009437 +0.009361 +0.009431 +0.009513 +0.009611 +0.009648 +0.009485 +0.009413 +0.009484 +0.009542 +0.009648 +0.00969 +0.009541 +0.00948 +0.00953 +0.009615 +0.009703 +0.009746 +0.009583 +0.009499 +0.009567 +0.009635 +0.009731 +0.009832 +0.009671 +0.009586 +0.00962 +0.009719 +0.009766 +0.009839 +0.009675 +0.009593 +0.009656 +0.009758 +0.009825 +0.009902 +0.009737 +0.009644 +0.009708 +0.009798 +0.00989 +0.009952 +0.009808 +0.009707 +0.009765 +0.009838 +0.009932 +0.010001 +0.009827 +0.009757 +0.009835 +0.009906 +0.010011 +0.010058 +0.009913 +0.009796 +0.009827 +0.009929 +0.010039 +0.010087 +0.009915 +0.009845 +0.009906 +0.010005 +0.010102 +0.010154 +0.00998 +0.009892 +0.009954 +0.010042 +0.010151 +0.010231 +0.010022 +0.009943 +0.01 +0.010125 +0.010197 +0.01025 +0.010079 +0.009991 +0.010071 +0.010185 +0.010247 +0.010315 +0.010104 +0.010032 +0.010105 +0.010184 +0.010292 +0.010364 +0.010181 +0.010091 +0.010163 +0.010239 +0.010342 +0.010423 +0.010227 +0.010133 +0.010217 +0.010306 +0.010379 +0.010371 +0.010165 +0.010059 +0.010077 +0.010127 +0.0102 +0.010252 +0.010008 +0.009865 +0.009886 +0.009911 +0.009955 +0.009946 +0.009731 +0.009604 +0.00961 +0.009672 +0.009688 +0.009697 +0.009483 +0.009348 +0.009368 +0.009401 +0.009443 +0.009462 +0.009267 +0.009162 +0.00914 +0.009172 +0.00921 +0.009229 +0.009038 +0.008904 +0.008928 +0.008973 +0.009043 +0.009044 +0.008848 +0.008742 +0.008749 +0.008807 +0.008846 +0.008875 +0.008694 +0.008589 +0.00863 +0.008665 +0.008722 +0.008756 +0.008587 +0.008471 +0.0085 +0.008562 +0.008614 +0.008666 +0.008475 +0.008381 +0.008394 +0.008457 +0.008523 +0.008558 +0.008394 +0.008308 +0.008355 +0.008417 +0.008498 +0.008547 +0.008407 +0.008321 +0.008374 +0.008452 +0.008537 +0.008587 +0.008437 +0.008374 +0.00841 +0.008482 +0.008566 +0.008634 +0.008477 +0.00841 +0.008459 +0.00854 +0.008638 +0.008694 +0.008523 +0.008452 +0.008495 +0.00858 +0.008651 +0.008712 +0.008568 +0.008486 +0.008544 +0.008608 +0.008692 +0.008762 +0.008603 +0.008548 +0.008575 +0.00866 +0.008747 +0.008794 +0.008654 +0.008595 +0.00863 +0.008697 +0.008788 +0.00885 +0.008694 +0.008619 +0.008674 +0.008753 +0.00885 +0.008882 +0.008732 +0.00867 +0.008723 +0.008792 +0.008885 +0.008923 +0.008778 +0.008702 +0.008753 +0.008821 +0.008924 +0.008975 +0.008837 +0.008762 +0.008816 +0.00887 +0.00896 +0.009028 +0.008871 +0.00879 +0.008848 +0.008921 +0.009012 +0.009077 +0.008931 +0.008849 +0.008924 +0.008965 +0.009044 +0.009094 +0.008945 +0.008883 +0.008921 +0.00902 +0.009116 +0.009144 +0.008995 +0.008921 +0.008989 +0.009051 +0.009135 +0.009212 +0.009046 +0.008978 +0.00903 +0.009116 +0.009176 +0.009251 +0.009095 +0.009021 +0.009065 +0.009146 +0.009232 +0.009326 +0.009172 +0.009058 +0.009105 +0.009192 +0.009266 +0.009336 +0.009177 +0.0091 +0.009161 +0.009238 +0.009329 +0.009392 +0.009224 +0.009142 +0.009202 +0.009289 +0.009369 +0.009444 +0.009287 +0.009196 +0.009271 +0.009336 +0.009421 +0.009477 +0.009318 +0.009239 +0.009317 +0.009386 +0.009471 +0.009551 +0.009374 +0.009297 +0.009342 +0.009406 +0.009505 +0.009582 +0.009409 +0.009332 +0.009409 +0.00947 +0.009581 +0.009647 +0.009465 +0.009383 +0.009435 +0.009505 +0.009607 +0.009668 +0.009521 +0.009436 +0.009494 +0.00957 +0.009673 +0.009745 +0.009545 +0.009473 +0.009509 +0.009641 +0.009701 +0.009778 +0.009616 +0.009539 +0.009565 +0.009654 +0.009761 +0.009811 +0.009648 +0.009567 +0.009626 +0.00973 +0.009829 +0.009885 +0.009705 +0.009607 +0.009674 +0.009763 +0.009854 +0.009922 +0.009771 +0.009679 +0.009723 +0.009799 +0.0099 +0.00997 +0.009797 +0.009732 +0.009764 +0.009859 +0.00997 +0.010038 +0.009859 +0.009749 +0.009816 +0.009906 +0.009998 +0.01007 +0.009896 +0.009818 +0.009894 +0.009984 +0.010079 +0.010112 +0.009941 +0.009866 +0.009944 +0.009997 +0.010086 +0.010161 +0.009999 +0.009911 +0.009968 +0.01006 +0.010197 +0.010212 +0.01004 +0.009961 +0.010027 +0.010125 +0.010208 +0.010266 +0.010093 +0.010022 +0.010062 +0.010148 +0.010273 +0.010334 +0.010168 +0.01008 +0.010148 +0.010225 +0.010312 +0.010316 +0.010159 +0.010081 +0.01011 +0.01019 +0.01025 +0.010291 +0.010075 +0.009956 +0.009973 +0.010018 +0.010056 +0.010062 +0.009865 +0.009733 +0.009755 +0.009786 +0.009819 +0.009825 +0.009602 +0.00948 +0.009509 +0.009544 +0.0096 +0.009566 +0.009351 +0.009244 +0.009237 +0.009276 +0.009304 +0.009312 +0.009125 +0.008992 +0.009023 +0.00906 +0.009105 +0.009116 +0.008918 +0.008805 +0.008832 +0.008864 +0.008918 +0.00893 +0.008753 +0.008653 +0.008711 +0.008747 +0.008791 +0.008818 +0.008648 +0.00857 +0.008587 +0.008626 +0.008665 +0.008694 +0.008537 +0.008467 +0.008496 +0.00853 +0.008586 +0.008622 +0.008463 +0.008379 +0.008428 +0.008479 +0.008543 +0.008591 +0.008464 +0.00838 +0.008438 +0.008491 +0.008567 +0.008636 +0.00848 +0.00841 +0.008453 +0.008529 +0.008615 +0.008696 +0.008545 +0.008479 +0.008507 +0.008588 +0.008644 +0.008703 +0.008566 +0.00849 +0.008539 +0.008639 +0.008702 +0.008752 +0.008608 +0.008537 +0.008595 +0.00868 +0.008732 +0.00881 +0.008648 +0.008588 +0.008632 +0.008722 +0.008795 +0.008831 +0.008701 +0.008626 +0.008674 +0.008748 +0.008838 +0.008902 +0.008782 +0.008664 +0.008719 +0.008785 +0.00887 +0.008938 +0.008771 +0.00871 +0.008761 +0.008839 +0.008936 +0.008976 +0.008835 +0.008751 +0.008801 +0.008877 +0.008967 +0.009034 +0.008863 +0.008808 +0.008857 +0.008922 +0.009015 +0.00909 +0.008917 +0.008838 +0.008892 +0.008983 +0.009079 +0.009106 +0.008971 +0.008877 +0.008934 +0.009029 +0.009105 +0.009165 +0.009005 +0.008914 +0.008973 +0.009053 +0.009159 +0.009199 +0.009049 +0.008985 +0.009041 +0.00912 +0.009198 +0.009265 +0.009095 +0.009003 +0.009072 +0.00914 +0.009233 +0.009302 +0.009161 +0.009084 +0.00912 +0.009198 +0.009276 +0.009334 +0.0092 +0.009094 +0.009157 +0.009241 +0.009353 +0.009405 +0.009231 +0.009155 +0.009199 +0.009283 +0.00938 +0.009446 +0.009269 +0.009198 +0.00928 +0.009355 +0.009437 +0.009503 +0.009316 +0.009241 +0.009294 +0.009382 +0.009505 +0.009531 +0.009375 +0.009279 +0.009345 +0.009441 +0.009527 +0.009604 +0.00941 +0.00933 +0.009388 +0.00947 +0.009591 +0.009633 +0.009459 +0.0094 +0.00945 +0.009524 +0.009619 +0.009682 +0.009513 +0.00943 +0.009504 +0.009583 +0.009674 +0.009727 +0.009578 +0.009496 +0.009539 +0.00961 +0.00971 +0.009771 +0.009607 +0.009523 +0.009584 +0.009702 +0.009764 +0.00982 +0.009646 +0.009574 +0.00963 +0.009751 +0.009823 +0.009881 +0.009709 +0.009625 +0.009676 +0.009766 +0.009864 +0.009918 +0.009759 +0.009692 +0.009776 +0.009829 +0.009925 +0.009948 +0.009793 +0.009726 +0.009763 +0.009861 +0.009964 +0.010023 +0.009871 +0.009805 +0.009837 +0.009919 +0.010004 +0.010074 +0.0099 +0.009814 +0.009876 +0.009951 +0.010065 +0.010135 +0.009947 +0.009864 +0.009937 +0.010032 +0.010135 +0.010182 +0.009997 +0.009951 +0.009971 +0.010052 +0.010158 +0.010234 +0.010047 +0.009966 +0.010027 +0.010117 +0.010239 +0.010304 +0.010124 +0.010004 +0.01007 +0.010166 +0.010263 +0.010331 +0.010158 +0.010079 +0.010142 +0.010238 +0.010374 +0.010383 +0.010188 +0.010096 +0.010166 +0.01029 +0.010385 +0.010407 +0.010234 +0.010131 +0.010193 +0.010273 +0.010323 +0.010363 +0.010147 +0.010008 +0.010056 +0.010119 +0.010129 +0.010148 +0.009924 +0.009796 +0.009817 +0.009861 +0.009887 +0.009914 +0.009693 +0.009596 +0.009585 +0.009605 +0.009633 +0.009625 +0.009447 +0.00931 +0.009321 +0.00937 +0.009412 +0.009407 +0.009208 +0.009091 +0.009114 +0.009149 +0.009198 +0.009187 +0.009 +0.00889 +0.008926 +0.008981 +0.009009 +0.009017 +0.008821 +0.008723 +0.008756 +0.008811 +0.008876 +0.008881 +0.008681 +0.008597 +0.008638 +0.008688 +0.00874 +0.008749 +0.00857 +0.008492 +0.008514 +0.008566 +0.008616 +0.008653 +0.008479 +0.008394 +0.008438 +0.008503 +0.008555 +0.008603 +0.008444 +0.008365 +0.008427 +0.0085 +0.00857 +0.008648 +0.008501 +0.008399 +0.00846 +0.008545 +0.008645 +0.008665 +0.008522 +0.008439 +0.008488 +0.008579 +0.008668 +0.008728 +0.008578 +0.008504 +0.008545 +0.008629 +0.008691 +0.008757 +0.008609 +0.008535 +0.008595 +0.008677 +0.008747 +0.008797 +0.00866 +0.008597 +0.008623 +0.008708 +0.008776 +0.008843 +0.0087 +0.008625 +0.008711 +0.00878 +0.008833 +0.008897 +0.008719 +0.008658 +0.008716 +0.008784 +0.008872 +0.008933 +0.00879 +0.008721 +0.008769 +0.008857 +0.00893 +0.00898 +0.008816 +0.008751 +0.008798 +0.008877 +0.00897 +0.009032 +0.008869 +0.008801 +0.008851 +0.008924 +0.009009 +0.00908 +0.008927 +0.008867 +0.008888 +0.008969 +0.009068 +0.009127 +0.00896 +0.008874 +0.00893 +0.009016 +0.009107 +0.009161 +0.009 +0.008935 +0.008997 +0.009074 +0.009153 +0.009216 +0.00904 +0.008966 +0.009034 +0.009099 +0.009194 +0.009258 +0.009101 +0.009016 +0.009065 +0.009155 +0.009263 +0.009311 +0.009134 +0.00905 +0.009118 +0.009198 +0.009297 +0.009392 +0.009175 +0.009107 +0.009147 +0.009232 +0.009334 +0.009389 +0.009226 +0.009157 +0.009219 +0.009313 +0.00939 +0.009459 +0.009266 +0.009183 +0.009252 +0.009329 +0.009424 +0.009489 +0.009327 +0.009291 +0.009332 +0.009391 +0.009471 +0.009523 +0.009356 +0.009283 +0.009333 +0.009426 +0.009553 +0.009588 +0.00941 +0.00934 +0.009392 +0.009468 +0.009574 +0.009621 +0.009467 +0.009388 +0.009443 +0.009544 +0.009627 +0.00968 +0.00951 +0.00943 +0.0095 +0.009587 +0.009695 +0.009733 +0.00955 +0.009481 +0.009538 +0.009632 +0.009711 +0.00976 +0.009611 +0.009527 +0.00958 +0.009673 +0.009763 +0.009822 +0.009655 +0.00957 +0.00963 +0.009713 +0.009816 +0.009876 +0.009709 +0.009632 +0.009694 +0.009767 +0.009866 +0.009949 +0.009773 +0.009658 +0.009712 +0.009821 +0.009901 +0.00997 +0.009809 +0.009737 +0.009794 +0.009854 +0.009955 +0.010025 +0.009851 +0.009763 +0.009821 +0.009929 +0.01002 +0.010091 +0.009901 +0.009817 +0.00987 +0.00996 +0.010053 +0.010131 +0.009972 +0.009889 +0.009908 +0.009999 +0.010104 +0.010172 +0.010024 +0.009899 +0.009967 +0.010073 +0.010178 +0.010238 +0.010042 +0.009955 +0.010021 +0.010129 +0.010208 +0.010264 +0.010111 +0.010034 +0.010087 +0.010182 +0.010268 +0.01031 +0.01015 +0.010083 +0.010146 +0.010202 +0.010307 +0.010368 +0.010199 +0.010102 +0.01019 +0.010284 +0.01037 +0.010426 +0.010252 +0.010173 +0.01024 +0.010316 +0.010411 +0.010471 +0.010285 +0.010185 +0.010235 +0.010315 +0.010396 +0.010416 +0.010187 +0.010057 +0.010096 +0.01013 +0.010197 +0.010158 +0.009946 +0.009821 +0.009865 +0.009884 +0.009903 +0.009951 +0.009685 +0.009573 +0.009596 +0.009633 +0.009667 +0.009688 +0.009484 +0.009348 +0.009368 +0.009395 +0.009421 +0.009431 +0.009231 +0.009121 +0.009138 +0.009189 +0.00923 +0.009244 +0.009073 +0.008921 +0.008947 +0.008979 +0.009026 +0.009048 +0.008875 +0.008777 +0.008823 +0.00886 +0.008905 +0.008914 +0.00875 +0.008645 +0.008686 +0.008731 +0.008781 +0.008807 +0.008645 +0.008562 +0.008585 +0.008639 +0.008673 +0.008714 +0.008544 +0.008463 +0.008521 +0.008571 +0.008654 +0.008698 +0.008528 +0.008478 +0.008514 +0.008591 +0.008669 +0.0087 +0.008563 +0.008501 +0.008539 +0.008621 +0.008718 +0.008769 +0.00861 +0.008533 +0.008595 +0.00867 +0.00875 +0.008806 +0.008667 +0.008582 +0.008636 +0.008724 +0.008814 +0.008852 +0.008697 +0.008639 +0.008681 +0.008783 +0.008855 +0.008881 +0.008731 +0.008672 +0.00876 +0.008795 +0.008872 +0.008929 +0.008786 +0.008704 +0.008763 +0.008839 +0.008928 +0.008981 +0.008836 +0.008765 +0.008806 +0.008886 +0.008969 +0.009037 +0.008902 +0.0088 +0.008857 +0.008922 +0.009014 +0.009099 +0.00893 +0.00886 +0.008901 +0.008961 +0.009057 +0.009115 +0.00896 +0.00889 +0.008949 +0.009027 +0.009127 +0.009167 +0.009015 +0.008927 +0.008981 +0.00906 +0.009146 +0.009219 +0.009066 +0.008987 +0.009047 +0.009113 +0.009205 +0.009265 +0.009108 +0.009009 +0.009069 +0.009162 +0.009254 +0.009328 +0.009151 +0.009053 +0.009114 +0.009192 +0.009296 +0.009357 +0.009175 +0.009103 +0.009186 +0.009243 +0.009352 +0.009417 +0.009241 +0.009153 +0.009209 +0.009286 +0.009377 +0.00945 +0.009293 +0.009201 +0.009272 +0.009361 +0.009434 +0.009503 +0.009345 +0.009249 +0.009321 +0.009391 +0.009472 +0.009523 +0.009385 +0.009296 +0.009343 +0.009429 +0.009532 +0.009591 +0.009422 +0.009333 +0.009403 +0.009481 +0.009595 +0.00966 +0.00947 +0.009386 +0.009448 +0.009521 +0.009623 +0.009688 +0.00951 +0.009434 +0.009525 +0.009604 +0.00972 +0.00974 +0.009555 +0.009467 +0.009535 +0.009615 +0.009717 +0.009776 +0.009606 +0.009529 +0.009588 +0.009681 +0.009777 +0.009861 +0.009657 +0.009574 +0.009634 +0.00973 +0.009844 +0.00987 +0.009705 +0.009637 +0.009678 +0.009768 +0.009876 +0.009927 +0.009796 +0.009686 +0.009747 +0.009832 +0.009905 +0.009986 +0.009818 +0.009707 +0.009778 +0.009851 +0.009966 +0.010054 +0.009865 +0.009786 +0.009854 +0.009925 +0.010003 +0.010072 +0.009899 +0.009807 +0.009889 +0.009965 +0.010065 +0.010146 +0.009966 +0.009906 +0.009928 +0.010016 +0.01011 +0.01019 +0.010025 +0.00992 +0.009968 +0.0101 +0.010145 +0.010221 +0.010065 +0.009955 +0.010037 +0.010149 +0.010239 +0.010301 +0.010115 +0.01002 +0.010072 +0.010171 +0.010268 +0.010334 +0.010166 +0.010076 +0.010184 +0.010218 +0.010312 +0.010371 +0.010209 +0.010122 +0.010181 +0.010294 +0.010393 +0.01044 +0.010255 +0.010175 +0.010233 +0.010324 +0.010428 +0.010496 +0.010331 +0.010245 +0.010298 +0.010371 +0.010477 +0.010526 +0.010345 +0.010245 +0.010322 +0.010377 +0.010428 +0.010443 +0.010203 +0.010081 +0.010124 +0.010138 +0.010188 +0.010203 +0.009982 +0.009856 +0.009895 +0.009894 +0.009933 +0.009949 +0.009719 +0.009595 +0.009617 +0.009643 +0.009678 +0.009695 +0.009483 +0.009359 +0.00935 +0.009392 +0.009447 +0.00943 +0.009212 +0.009097 +0.009135 +0.009163 +0.009199 +0.009207 +0.009014 +0.008913 +0.008911 +0.008958 +0.009003 +0.009015 +0.008838 +0.008732 +0.008766 +0.008801 +0.008842 +0.008877 +0.008693 +0.008598 +0.008622 +0.008685 +0.008715 +0.008753 +0.008578 +0.008504 +0.00854 +0.008582 +0.008608 +0.008641 +0.008483 +0.008404 +0.008456 +0.008506 +0.008571 +0.008624 +0.008487 +0.00841 +0.00846 +0.008529 +0.008593 +0.00867 +0.008519 +0.008455 +0.008503 +0.008564 +0.008648 +0.008724 +0.008569 +0.00849 +0.00855 +0.008615 +0.00869 +0.008746 +0.008604 +0.008541 +0.008596 +0.008653 +0.008746 +0.00878 +0.008641 +0.008574 +0.008621 +0.008708 +0.008785 +0.008851 +0.008677 +0.00861 +0.008671 +0.008733 +0.008832 +0.008877 +0.008736 +0.008654 +0.008709 +0.008793 +0.008869 +0.008919 +0.008782 +0.00871 +0.008753 +0.008851 +0.008929 +0.008983 +0.008829 +0.008767 +0.008789 +0.008857 +0.008948 +0.009013 +0.008862 +0.008799 +0.008849 +0.008931 +0.009004 +0.00907 +0.008903 +0.008832 +0.008875 +0.008956 +0.009054 +0.009102 +0.008955 +0.008883 +0.008941 +0.009003 +0.009081 +0.009166 +0.008996 +0.008929 +0.008979 +0.009052 +0.009171 +0.009201 +0.009043 +0.008994 +0.009013 +0.009088 +0.009175 +0.009239 +0.009085 +0.009016 +0.009065 +0.009136 +0.009251 +0.009306 +0.009141 +0.00906 +0.009113 +0.009175 +0.009272 +0.009343 +0.009176 +0.009102 +0.009164 +0.009233 +0.00933 +0.009392 +0.009233 +0.009167 +0.009207 +0.009274 +0.00936 +0.009432 +0.009296 +0.009216 +0.009244 +0.00932 +0.009424 +0.009467 +0.009318 +0.009238 +0.009281 +0.009363 +0.009484 +0.009551 +0.009381 +0.009293 +0.009361 +0.009409 +0.009507 +0.009581 +0.009403 +0.009334 +0.009386 +0.00947 +0.009599 +0.009624 +0.009449 +0.009369 +0.009427 +0.009524 +0.009605 +0.0097 +0.009509 +0.009432 +0.009469 +0.00956 +0.009664 +0.00972 +0.009557 +0.00948 +0.009533 +0.009613 +0.009726 +0.00978 +0.009609 +0.009521 +0.009562 +0.009666 +0.009749 +0.009822 +0.009684 +0.009562 +0.009629 +0.009721 +0.009813 +0.009881 +0.009698 +0.009596 +0.009671 +0.009775 +0.00984 +0.009921 +0.009743 +0.009642 +0.009722 +0.009813 +0.009909 +0.009969 +0.009802 +0.009718 +0.009767 +0.009882 +0.009969 +0.010023 +0.00984 +0.009776 +0.009847 +0.009908 +0.009989 +0.01005 +0.009905 +0.009825 +0.009876 +0.009964 +0.010063 +0.010098 +0.009941 +0.009855 +0.009906 +0.010005 +0.01011 +0.010172 +0.009999 +0.009919 +0.009964 +0.010049 +0.01017 +0.010234 +0.010049 +0.009977 +0.010048 +0.010135 +0.010193 +0.010255 +0.010107 +0.010004 +0.010052 +0.010148 +0.010274 +0.010343 +0.010157 +0.010067 +0.010108 +0.01022 +0.010306 +0.010358 +0.010194 +0.010108 +0.010197 +0.010278 +0.010379 +0.01045 +0.010238 +0.010146 +0.010221 +0.010348 +0.010421 +0.010475 +0.010276 +0.010206 +0.010273 +0.010375 +0.010432 +0.010493 +0.010293 +0.010182 +0.010239 +0.010276 +0.010323 +0.010345 +0.010125 +0.009983 +0.010005 +0.010051 +0.010106 +0.010104 +0.009891 +0.00979 +0.009783 +0.009818 +0.009867 +0.00988 +0.009618 +0.009494 +0.009512 +0.009554 +0.0096 +0.009605 +0.009418 +0.009276 +0.009279 +0.009316 +0.009366 +0.009364 +0.009177 +0.009056 +0.009073 +0.009106 +0.009155 +0.009163 +0.008965 +0.008862 +0.00888 +0.008918 +0.008969 +0.00898 +0.008816 +0.008729 +0.00876 +0.008771 +0.008818 +0.008837 +0.008661 +0.008571 +0.008587 +0.008636 +0.008686 +0.00873 +0.00856 +0.008453 +0.008489 +0.008531 +0.008589 +0.00863 +0.008476 +0.008383 +0.008423 +0.008488 +0.008563 +0.008625 +0.008469 +0.008395 +0.008438 +0.008522 +0.008586 +0.008656 +0.008509 +0.008449 +0.008481 +0.008565 +0.008641 +0.00869 +0.008556 +0.008477 +0.008516 +0.008591 +0.008679 +0.008728 +0.008585 +0.008525 +0.008574 +0.008651 +0.008731 +0.008792 +0.008638 +0.008567 +0.008605 +0.008687 +0.008768 +0.008809 +0.008688 +0.008609 +0.00866 +0.008731 +0.008811 +0.008873 +0.008733 +0.008634 +0.008691 +0.008759 +0.008875 +0.008908 +0.008763 +0.008699 +0.008748 +0.008821 +0.008912 +0.008944 +0.008806 +0.008726 +0.008784 +0.008856 +0.008951 +0.009008 +0.008847 +0.008784 +0.008821 +0.008899 +0.008989 +0.009052 +0.008908 +0.008818 +0.008875 +0.00897 +0.00908 +0.009099 +0.008932 +0.008853 +0.00891 +0.008995 +0.00908 +0.009148 +0.008975 +0.008913 +0.008973 +0.00905 +0.009147 +0.009194 +0.009017 +0.008948 +0.009001 +0.009072 +0.009166 +0.009252 +0.009073 +0.009 +0.00906 +0.009136 +0.009231 +0.009273 +0.009129 +0.009057 +0.009113 +0.009174 +0.009265 +0.009335 +0.009159 +0.009093 +0.009143 +0.009212 +0.009345 +0.00936 +0.009204 +0.009134 +0.009195 +0.009286 +0.00937 +0.009438 +0.009256 +0.009176 +0.009242 +0.009302 +0.009398 +0.009462 +0.009316 +0.009245 +0.009291 +0.009377 +0.009485 +0.009545 +0.009339 +0.009252 +0.00931 +0.009399 +0.009494 +0.009556 +0.009394 +0.009322 +0.009373 +0.009463 +0.009561 +0.0096 +0.00945 +0.009367 +0.009426 +0.009506 +0.009615 +0.009668 +0.009503 +0.009401 +0.009471 +0.009546 +0.00964 +0.009718 +0.009549 +0.009485 +0.009501 +0.009584 +0.009717 +0.009741 +0.009588 +0.009507 +0.009568 +0.009655 +0.009754 +0.009809 +0.009634 +0.009551 +0.009605 +0.009694 +0.009789 +0.009847 +0.00969 +0.009619 +0.009678 +0.009756 +0.009862 +0.009893 +0.009723 +0.009654 +0.009718 +0.009823 +0.009878 +0.009946 +0.009789 +0.009708 +0.009784 +0.009842 +0.009916 +0.009994 +0.009823 +0.009741 +0.009817 +0.009899 +0.009983 +0.010063 +0.009876 +0.009797 +0.009858 +0.009935 +0.010037 +0.010117 +0.009952 +0.009866 +0.00992 +0.010003 +0.010118 +0.010136 +0.009961 +0.009884 +0.009948 +0.010042 +0.010159 +0.010247 +0.010037 +0.009944 +0.009992 +0.010086 +0.010184 +0.010252 +0.010086 +0.010003 +0.010047 +0.010149 +0.010247 +0.010301 +0.010137 +0.010038 +0.010105 +0.010204 +0.010328 +0.010411 +0.010172 +0.010078 +0.010139 +0.010243 +0.010342 +0.010405 +0.010233 +0.010175 +0.010218 +0.010311 +0.010408 +0.010446 +0.010277 +0.010176 +0.010242 +0.010322 +0.010418 +0.01042 +0.010204 +0.010087 +0.010119 +0.010153 +0.010228 +0.010269 +0.009998 +0.009878 +0.009871 +0.009915 +0.009947 +0.009955 +0.009724 +0.009599 +0.009597 +0.00964 +0.009702 +0.00969 +0.009476 +0.009357 +0.009376 +0.009394 +0.009435 +0.009456 +0.009244 +0.009113 +0.009143 +0.009166 +0.009224 +0.009254 +0.009052 +0.008951 +0.008958 +0.00898 +0.009014 +0.009048 +0.008877 +0.008749 +0.008774 +0.008825 +0.008886 +0.008908 +0.00873 +0.008624 +0.008658 +0.008699 +0.008758 +0.008796 +0.008611 +0.008507 +0.008545 +0.008608 +0.008643 +0.008672 +0.008503 +0.008405 +0.008455 +0.008503 +0.008572 +0.008621 +0.008483 +0.008386 +0.008432 +0.008491 +0.008576 +0.008627 +0.008491 +0.008432 +0.008453 +0.008536 +0.008607 +0.008666 +0.00854 +0.00847 +0.00851 +0.008584 +0.008669 +0.008731 +0.008558 +0.008493 +0.008545 +0.008616 +0.008699 +0.008774 +0.008616 +0.008542 +0.008587 +0.008669 +0.008754 +0.008832 +0.008673 +0.008576 +0.008622 +0.008701 +0.008798 +0.008859 +0.008695 +0.008618 +0.008706 +0.008743 +0.008831 +0.008887 +0.008747 +0.008661 +0.008723 +0.008818 +0.008892 +0.008942 +0.008791 +0.008706 +0.008754 +0.008837 +0.008926 +0.008982 +0.008829 +0.008758 +0.008813 +0.008901 +0.008992 +0.009029 +0.008863 +0.008792 +0.008845 +0.008933 +0.009003 +0.009079 +0.008938 +0.008854 +0.008905 +0.00898 +0.009055 +0.009106 +0.008961 +0.008895 +0.008944 +0.009018 +0.009098 +0.009172 +0.009018 +0.00893 +0.008987 +0.009059 +0.009142 +0.009218 +0.009064 +0.009005 +0.009059 +0.009121 +0.009199 +0.009259 +0.009092 +0.009015 +0.009062 +0.009152 +0.009239 +0.009307 +0.009151 +0.009088 +0.009142 +0.009216 +0.00929 +0.00935 +0.009192 +0.009106 +0.009165 +0.009241 +0.009328 +0.009418 +0.009266 +0.009171 +0.009226 +0.009304 +0.009393 +0.009457 +0.009268 +0.00919 +0.00925 +0.009349 +0.00945 +0.009483 +0.009326 +0.009256 +0.009307 +0.009389 +0.009485 +0.009543 +0.009384 +0.009314 +0.009366 +0.009435 +0.009519 +0.009592 +0.00942 +0.009343 +0.009412 +0.009481 +0.009584 +0.009661 +0.00949 +0.009428 +0.009459 +0.009525 +0.009599 +0.009675 +0.009522 +0.009433 +0.009519 +0.009597 +0.00966 +0.009729 +0.009565 +0.009485 +0.009543 +0.009618 +0.009727 +0.009796 +0.009631 +0.009558 +0.0096 +0.009665 +0.009774 +0.009833 +0.009667 +0.009579 +0.009631 +0.009757 +0.009842 +0.009893 +0.009724 +0.009634 +0.009703 +0.009755 +0.009862 +0.009938 +0.009769 +0.009675 +0.009748 +0.009817 +0.009915 +0.009983 +0.009818 +0.009728 +0.009779 +0.009884 +0.009968 +0.01005 +0.009879 +0.009781 +0.00982 +0.009929 +0.01004 +0.010096 +0.009915 +0.00982 +0.009881 +0.009993 +0.010083 +0.010134 +0.009961 +0.009855 +0.009924 +0.010017 +0.01013 +0.010184 +0.010005 +0.009937 +0.009985 +0.010067 +0.010176 +0.010228 +0.010069 +0.009978 +0.010032 +0.010129 +0.010258 +0.010312 +0.010116 +0.010011 +0.010068 +0.010193 +0.010279 +0.010316 +0.010164 +0.010096 +0.010151 +0.010232 +0.010335 +0.010372 +0.010207 +0.010121 +0.010187 +0.010269 +0.010374 +0.010441 +0.010264 +0.01018 +0.010236 +0.010314 +0.010408 +0.010481 +0.010298 +0.010156 +0.010176 +0.010214 +0.010283 +0.010307 +0.010115 +0.009968 +0.009986 +0.010041 +0.010116 +0.010099 +0.009886 +0.009743 +0.009744 +0.009782 +0.009813 +0.009832 +0.009618 +0.009493 +0.009512 +0.009542 +0.009585 +0.009577 +0.009371 +0.009238 +0.00925 +0.009315 +0.009322 +0.009344 +0.009143 +0.009025 +0.009042 +0.00907 +0.009115 +0.009143 +0.008945 +0.008837 +0.008853 +0.008895 +0.008959 +0.008969 +0.008789 +0.008669 +0.008719 +0.008734 +0.008798 +0.008818 +0.008653 +0.008558 +0.008589 +0.008635 +0.008687 +0.008727 +0.008555 +0.008466 +0.008477 +0.008519 +0.008571 +0.008617 +0.008463 +0.008384 +0.00841 +0.00847 +0.008543 +0.008599 +0.008451 +0.008378 +0.008426 +0.008499 +0.00857 +0.008629 +0.008496 +0.00843 +0.008472 +0.00855 +0.00861 +0.008661 +0.008523 +0.008463 +0.008507 +0.008574 +0.008663 +0.008724 +0.0086 +0.008507 +0.00857 +0.008616 +0.008685 +0.008752 +0.008617 +0.008553 +0.008596 +0.008661 +0.008744 +0.008816 +0.00867 +0.008595 +0.008643 +0.008705 +0.008767 +0.008845 +0.008694 +0.008623 +0.008685 +0.008764 +0.008829 +0.008898 +0.008747 +0.008668 +0.008719 +0.008796 +0.00888 +0.008965 +0.008788 +0.008712 +0.00877 +0.008859 +0.008928 +0.008972 +0.008827 +0.008754 +0.00881 +0.008877 +0.008967 +0.009028 +0.008888 +0.008826 +0.008857 +0.00894 +0.009015 +0.009058 +0.008916 +0.008842 +0.008892 +0.008972 +0.009068 +0.009139 +0.008956 +0.008889 +0.008942 +0.009048 +0.009102 +0.009152 +0.008997 +0.008928 +0.008989 +0.009072 +0.009162 +0.009225 +0.00907 +0.00897 +0.009028 +0.009113 +0.009192 +0.009257 +0.009098 +0.009047 +0.009079 +0.00916 +0.00926 +0.009299 +0.009148 +0.009068 +0.009117 +0.009197 +0.009279 +0.009364 +0.009219 +0.009125 +0.009148 +0.009233 +0.009331 +0.009397 +0.009242 +0.009155 +0.009225 +0.0093 +0.009402 +0.00945 +0.009288 +0.009186 +0.00925 +0.009343 +0.009431 +0.009494 +0.009354 +0.00925 +0.009323 +0.009392 +0.009501 +0.009537 +0.009361 +0.009283 +0.009351 +0.009469 +0.009542 +0.009574 +0.009428 +0.009335 +0.009401 +0.009469 +0.009572 +0.009635 +0.009473 +0.009402 +0.009443 +0.009539 +0.009632 +0.009698 +0.009524 +0.00943 +0.009488 +0.009575 +0.009668 +0.009733 +0.009568 +0.009496 +0.009554 +0.009641 +0.00974 +0.009806 +0.009616 +0.009518 +0.009597 +0.009663 +0.009764 +0.009835 +0.009657 +0.009579 +0.009642 +0.009721 +0.009813 +0.009883 +0.009704 +0.009627 +0.009695 +0.009789 +0.009878 +0.009931 +0.009761 +0.009675 +0.009745 +0.009818 +0.009905 +0.00999 +0.009817 +0.00978 +0.009792 +0.009878 +0.00996 +0.010009 +0.009857 +0.009773 +0.009827 +0.00993 +0.010037 +0.010065 +0.009911 +0.009817 +0.00989 +0.00999 +0.010051 +0.010125 +0.009959 +0.009888 +0.009947 +0.010041 +0.0101 +0.010176 +0.010004 +0.009924 +0.010015 +0.010067 +0.010166 +0.010243 +0.010069 +0.009988 +0.010043 +0.010114 +0.010211 +0.010275 +0.010095 +0.010022 +0.010083 +0.010166 +0.01028 +0.01033 +0.010156 +0.010071 +0.010126 +0.010221 +0.010346 +0.010402 +0.010217 +0.010116 +0.010192 +0.010307 +0.010363 +0.010421 +0.010238 +0.010172 +0.01024 +0.010327 +0.010442 +0.010512 +0.010253 +0.010177 +0.010219 +0.010277 +0.010333 +0.010337 +0.010131 +0.010019 +0.010027 +0.010082 +0.010117 +0.010101 +0.009876 +0.009733 +0.009763 +0.009801 +0.009837 +0.009892 +0.009619 +0.009497 +0.009512 +0.009541 +0.00958 +0.00957 +0.009366 +0.009255 +0.009276 +0.009282 +0.00933 +0.009334 +0.009111 +0.009001 +0.009027 +0.009048 +0.009085 +0.0091 +0.008911 +0.008814 +0.00883 +0.008878 +0.008903 +0.008917 +0.00873 +0.008637 +0.008687 +0.008716 +0.008762 +0.008758 +0.008589 +0.008509 +0.00855 +0.008597 +0.008645 +0.008675 +0.008502 +0.008403 +0.008437 +0.008499 +0.008537 +0.008575 +0.00842 +0.008346 +0.008378 +0.008437 +0.008503 +0.008555 +0.008413 +0.008337 +0.008393 +0.008456 +0.008531 +0.008597 +0.008454 +0.008394 +0.008454 +0.008485 +0.00857 +0.008631 +0.008503 +0.008413 +0.008467 +0.008527 +0.008618 +0.00868 +0.008534 +0.008464 +0.008516 +0.008584 +0.008657 +0.008714 +0.008577 +0.008507 +0.008554 +0.008622 +0.008704 +0.008778 +0.008624 +0.008554 +0.008598 +0.008685 +0.008732 +0.008803 +0.008663 +0.008601 +0.00863 +0.008705 +0.008786 +0.008843 +0.008697 +0.008643 +0.008676 +0.008746 +0.008837 +0.008885 +0.008743 +0.008677 +0.008731 +0.008808 +0.008888 +0.008958 +0.008779 +0.00871 +0.008766 +0.008835 +0.008927 +0.00898 +0.008834 +0.008765 +0.008821 +0.008898 +0.008984 +0.009059 +0.00887 +0.008795 +0.008845 +0.00892 +0.009008 +0.009075 +0.008918 +0.008839 +0.008929 +0.008961 +0.009056 +0.00912 +0.00896 +0.008883 +0.008938 +0.009024 +0.009115 +0.009178 +0.009016 +0.008928 +0.008992 +0.009056 +0.009159 +0.009209 +0.009052 +0.008978 +0.009044 +0.009153 +0.009223 +0.009251 +0.009089 +0.009011 +0.009071 +0.009157 +0.009237 +0.009301 +0.009149 +0.009077 +0.009111 +0.009202 +0.009284 +0.009347 +0.009196 +0.009114 +0.009164 +0.009247 +0.009346 +0.009422 +0.009244 +0.009173 +0.009195 +0.009287 +0.009383 +0.009449 +0.009319 +0.009211 +0.009249 +0.009377 +0.009428 +0.009495 +0.009324 +0.009244 +0.009296 +0.009383 +0.009474 +0.009538 +0.009385 +0.009307 +0.009342 +0.009436 +0.009518 +0.009582 +0.009427 +0.009334 +0.009407 +0.009487 +0.009592 +0.009655 +0.009486 +0.009389 +0.009461 +0.009546 +0.00961 +0.009672 +0.009494 +0.009434 +0.009523 +0.009592 +0.009682 +0.009747 +0.00956 +0.00947 +0.00954 +0.009623 +0.009712 +0.009794 +0.00961 +0.00953 +0.009588 +0.009678 +0.009778 +0.009825 +0.009663 +0.009576 +0.009644 +0.00973 +0.009861 +0.009906 +0.009695 +0.009612 +0.009676 +0.00977 +0.009867 +0.009931 +0.009769 +0.009685 +0.009753 +0.009833 +0.00993 +0.009958 +0.009802 +0.009725 +0.009781 +0.009861 +0.009962 +0.010047 +0.009874 +0.009794 +0.009841 +0.009923 +0.010005 +0.010082 +0.009942 +0.009805 +0.009876 +0.009961 +0.010059 +0.010124 +0.009948 +0.009874 +0.009942 +0.010028 +0.010113 +0.010191 +0.010018 +0.009931 +0.009986 +0.010063 +0.010165 +0.010241 +0.010068 +0.009958 +0.010031 +0.010131 +0.010236 +0.010304 +0.010127 +0.010039 +0.01007 +0.010175 +0.010253 +0.010322 +0.010151 +0.010058 +0.010124 +0.010226 +0.010322 +0.010392 +0.010208 +0.010103 +0.010168 +0.010267 +0.010357 +0.010367 +0.010166 +0.010044 +0.010064 +0.010114 +0.010188 +0.010204 +0.009974 +0.009847 +0.009904 +0.009938 +0.009949 +0.009971 +0.00972 +0.009595 +0.009609 +0.009663 +0.009711 +0.009717 +0.009517 +0.009384 +0.009398 +0.009438 +0.009459 +0.009481 +0.009261 +0.009138 +0.009167 +0.009204 +0.009239 +0.009263 +0.009062 +0.008934 +0.008957 +0.009012 +0.009059 +0.009103 +0.008877 +0.008758 +0.008799 +0.008858 +0.008912 +0.008917 +0.008738 +0.008635 +0.008669 +0.008721 +0.008772 +0.008814 +0.008627 +0.008538 +0.00857 +0.008642 +0.008664 +0.00869 +0.008528 +0.008436 +0.008463 +0.008526 +0.008596 +0.008623 +0.008481 +0.008397 +0.008443 +0.008522 +0.008607 +0.008629 +0.008466 +0.008404 +0.00846 +0.008525 +0.008608 +0.008669 +0.008548 +0.008453 +0.008493 +0.008572 +0.008659 +0.008722 +0.008571 +0.00849 +0.008555 +0.00861 +0.008715 +0.008771 +0.008632 +0.008538 +0.008579 +0.008666 +0.008742 +0.008802 +0.008657 +0.008587 +0.008643 +0.008743 +0.008807 +0.008833 +0.008694 +0.008619 +0.00867 +0.008746 +0.008821 +0.008885 +0.008743 +0.008693 +0.008709 +0.008789 +0.008866 +0.008934 +0.008781 +0.008714 +0.008757 +0.008831 +0.008931 +0.008988 +0.008839 +0.008765 +0.008816 +0.00887 +0.008961 +0.009019 +0.008877 +0.008823 +0.008851 +0.008938 +0.009 +0.009076 +0.008926 +0.008844 +0.008895 +0.008969 +0.009052 +0.009113 +0.00895 +0.00889 +0.00893 +0.009025 +0.009111 +0.009156 +0.008999 +0.008924 +0.008984 +0.009054 +0.009146 +0.009206 +0.009056 +0.008979 +0.009039 +0.009126 +0.009217 +0.009267 +0.009081 +0.009005 +0.009065 +0.009169 +0.009237 +0.009287 +0.00915 +0.009076 +0.009122 +0.009203 +0.009293 +0.009335 +0.009175 +0.009107 +0.009166 +0.009239 +0.009345 +0.009392 +0.00924 +0.009149 +0.009207 +0.009293 +0.009382 +0.009441 +0.009282 +0.009206 +0.0093 +0.009344 +0.009424 +0.009472 +0.009314 +0.009245 +0.009312 +0.009376 +0.009471 +0.009529 +0.009375 +0.009295 +0.009365 +0.009441 +0.009511 +0.009586 +0.009409 +0.009335 +0.009403 +0.009481 +0.009564 +0.009634 +0.009476 +0.00938 +0.009437 +0.009533 +0.009639 +0.009691 +0.009503 +0.009418 +0.009507 +0.009583 +0.009654 +0.009726 +0.009557 +0.009497 +0.00952 +0.009609 +0.009721 +0.009781 +0.009623 +0.009547 +0.009594 +0.009652 +0.009766 +0.00983 +0.009648 +0.009569 +0.009626 +0.009715 +0.009829 +0.009894 +0.009748 +0.009658 +0.009672 +0.009734 +0.00984 +0.009919 +0.009741 +0.009683 +0.009735 +0.009801 +0.009909 +0.009961 +0.009802 +0.009717 +0.009767 +0.009872 +0.009973 +0.010041 +0.009886 +0.009767 +0.009814 +0.009915 +0.01001 +0.010067 +0.009904 +0.009821 +0.009926 +0.009972 +0.010062 +0.010141 +0.009946 +0.009843 +0.009911 +0.010004 +0.010108 +0.010185 +0.009988 +0.009916 +0.009984 +0.010058 +0.010171 +0.010214 +0.01005 +0.009981 +0.010023 +0.01014 +0.010237 +0.010269 +0.010088 +0.010012 +0.010086 +0.010191 +0.010251 +0.010305 +0.010165 +0.010095 +0.010131 +0.010217 +0.010317 +0.010356 +0.010188 +0.010108 +0.01017 +0.010279 +0.01037 +0.010428 +0.010248 +0.010168 +0.01023 +0.0103 +0.010402 +0.010466 +0.010271 +0.010163 +0.010179 +0.010239 +0.01026 +0.010263 +0.010053 +0.009938 +0.009939 +0.010003 +0.010079 +0.010033 +0.009822 +0.009675 +0.009679 +0.00972 +0.009764 +0.009778 +0.009566 +0.009439 +0.009446 +0.009489 +0.009535 +0.009528 +0.009336 +0.009211 +0.009229 +0.00926 +0.009299 +0.009349 +0.009146 +0.009013 +0.009009 +0.009044 +0.009094 +0.009121 +0.008939 +0.008824 +0.008846 +0.008925 +0.008935 +0.008969 +0.008781 +0.008681 +0.008694 +0.008741 +0.008804 +0.008828 +0.008662 +0.008559 +0.008584 +0.008623 +0.008679 +0.00872 +0.008551 +0.008451 +0.008476 +0.008539 +0.008593 +0.008667 +0.008474 +0.008397 +0.008427 +0.008476 +0.008553 +0.008612 +0.008471 +0.008392 +0.008454 +0.00852 +0.008612 +0.008653 +0.008524 +0.008441 +0.008497 +0.008566 +0.008631 +0.008693 +0.00856 +0.008484 +0.008536 +0.008598 +0.008675 +0.008759 +0.0086 +0.008531 +0.008583 +0.008659 +0.008746 +0.00878 +0.008627 +0.008585 +0.008619 +0.008684 +0.008779 +0.008816 +0.008675 +0.008612 +0.008652 +0.008727 +0.008802 +0.008886 +0.008723 +0.008651 +0.00871 +0.008774 +0.008874 +0.00894 +0.008783 +0.008688 +0.008742 +0.00882 +0.008901 +0.008958 +0.008814 +0.008745 +0.008803 +0.008904 +0.008954 +0.009006 +0.00886 +0.008772 +0.008837 +0.008901 +0.008986 +0.009058 +0.008901 +0.008817 +0.008877 +0.008956 +0.009037 +0.009102 +0.008949 +0.008873 +0.008921 +0.009001 +0.009097 +0.009157 +0.009003 +0.008922 +0.008958 +0.009041 +0.009136 +0.009197 +0.009051 +0.008965 +0.009003 +0.009086 +0.009187 +0.009246 +0.009091 +0.009001 +0.009076 +0.009132 +0.00921 +0.009277 +0.009116 +0.009042 +0.00909 +0.009179 +0.009282 +0.009332 +0.009186 +0.009098 +0.009152 +0.00923 +0.009312 +0.009385 +0.009218 +0.009153 +0.009198 +0.009282 +0.009392 +0.00941 +0.009253 +0.009182 +0.009234 +0.009327 +0.00941 +0.009483 +0.009331 +0.009254 +0.009268 +0.009364 +0.009451 +0.009515 +0.009353 +0.009284 +0.009331 +0.009437 +0.009526 +0.009575 +0.009401 +0.009327 +0.00937 +0.009462 +0.009549 +0.009618 +0.00947 +0.009386 +0.009438 +0.009488 +0.009589 +0.009658 +0.009493 +0.009409 +0.009478 +0.009566 +0.00966 +0.009731 +0.009555 +0.009447 +0.009514 +0.009612 +0.009697 +0.00977 +0.009591 +0.009517 +0.009577 +0.00967 +0.009765 +0.009812 +0.00963 +0.009558 +0.009635 +0.009727 +0.009784 +0.009843 +0.009707 +0.009602 +0.009655 +0.009741 +0.009845 +0.009909 +0.009733 +0.009656 +0.009722 +0.009809 +0.009912 +0.00997 +0.00978 +0.00971 +0.009764 +0.009847 +0.009941 +0.010015 +0.009843 +0.009772 +0.009824 +0.009919 +0.010032 +0.010041 +0.009878 +0.009792 +0.009852 +0.009965 +0.010055 +0.010123 +0.009944 +0.009854 +0.009914 +0.009997 +0.010083 +0.01014 +0.009996 +0.00991 +0.00998 +0.010048 +0.010141 +0.010212 +0.01004 +0.009947 +0.010002 +0.010107 +0.010211 +0.010322 +0.010092 +0.01 +0.010039 +0.010142 +0.010252 +0.010315 +0.010155 +0.010047 +0.010095 +0.010198 +0.01033 +0.010374 +0.010199 +0.010091 +0.010157 +0.01025 +0.010357 +0.010409 +0.010224 +0.010175 +0.010207 +0.010294 +0.010398 +0.01045 +0.010222 +0.010075 +0.0101 +0.010153 +0.010243 +0.010265 +0.010033 +0.009925 +0.009938 +0.009983 +0.010014 +0.01002 +0.009811 +0.009681 +0.009693 +0.009735 +0.009746 +0.009771 +0.009553 +0.009415 +0.009434 +0.009457 +0.009504 +0.009544 +0.009335 +0.009229 +0.009202 +0.009248 +0.009273 +0.00928 +0.009096 +0.008968 +0.008987 +0.009033 +0.009079 +0.009107 +0.008919 +0.00881 +0.008832 +0.008874 +0.008925 +0.008962 +0.008782 +0.008675 +0.008709 +0.008745 +0.00879 +0.00883 +0.008654 +0.008548 +0.008569 +0.008626 +0.008677 +0.008738 +0.008541 +0.008451 +0.008471 +0.008525 +0.008613 +0.008607 +0.008452 +0.008369 +0.008414 +0.00847 +0.008548 +0.008605 +0.008486 +0.008389 +0.00845 +0.008521 +0.008588 +0.008653 +0.008492 +0.008427 +0.008471 +0.008546 +0.008626 +0.008695 +0.008545 +0.008485 +0.008518 +0.008594 +0.008695 +0.008739 +0.008582 +0.008505 +0.008557 +0.008635 +0.008721 +0.008803 +0.00867 +0.008561 +0.008605 +0.008664 +0.008753 +0.008821 +0.008672 +0.008595 +0.008645 +0.008723 +0.008817 +0.008878 +0.00873 +0.008651 +0.008698 +0.00875 +0.00885 +0.008903 +0.008756 +0.008691 +0.00874 +0.008835 +0.008896 +0.008948 +0.008798 +0.008725 +0.008783 +0.008848 +0.008935 +0.009004 +0.008864 +0.008783 +0.008836 +0.008905 +0.008984 +0.009037 +0.008889 +0.008812 +0.008867 +0.008936 +0.009032 +0.009093 +0.008947 +0.00887 +0.008932 +0.009001 +0.009065 +0.009135 +0.008978 +0.008929 +0.008957 +0.009042 +0.0091 +0.009185 +0.009036 +0.008949 +0.009011 +0.009087 +0.009156 +0.009216 +0.009066 +0.008996 +0.009042 +0.009131 +0.009203 +0.009278 +0.009116 +0.009039 +0.009096 +0.009165 +0.009258 +0.009329 +0.00916 +0.009091 +0.009146 +0.00923 +0.009321 +0.009378 +0.009189 +0.009117 +0.0092 +0.009255 +0.00935 +0.009416 +0.009264 +0.009188 +0.00923 +0.009304 +0.009396 +0.009453 +0.009294 +0.009212 +0.009279 +0.009355 +0.009457 +0.009505 +0.009336 +0.00927 +0.009325 +0.0094 +0.009493 +0.009555 +0.009399 +0.00935 +0.009392 +0.00945 +0.009537 +0.009595 +0.00944 +0.009365 +0.009405 +0.009487 +0.009591 +0.009659 +0.009502 +0.009422 +0.00947 +0.009536 +0.009658 +0.009691 +0.009527 +0.009448 +0.009498 +0.009601 +0.009701 +0.009766 +0.009583 +0.00951 +0.009554 +0.009663 +0.009748 +0.009783 +0.009615 +0.009551 +0.009598 +0.009696 +0.00978 +0.009847 +0.009678 +0.009587 +0.009661 +0.009739 +0.009838 +0.009911 +0.009745 +0.009628 +0.009719 +0.009794 +0.009863 +0.009947 +0.009779 +0.009685 +0.00976 +0.009849 +0.009948 +0.010055 +0.009805 +0.009723 +0.009782 +0.009874 +0.009988 +0.010033 +0.009867 +0.009794 +0.00985 +0.009938 +0.01004 +0.010095 +0.00992 +0.009848 +0.009893 +0.010011 +0.010098 +0.01014 +0.00997 +0.009885 +0.009946 +0.010032 +0.010129 +0.010209 +0.010071 +0.009945 +0.010011 +0.010095 +0.010165 +0.010244 +0.010059 +0.009982 +0.010053 +0.010129 +0.010262 +0.010325 +0.010142 +0.010033 +0.010095 +0.01017 +0.010291 +0.010355 +0.010165 +0.0101 +0.010158 +0.010219 +0.010339 +0.010415 +0.01024 +0.010171 +0.010189 +0.010273 +0.010412 +0.010488 +0.010278 +0.010189 +0.010238 +0.010337 +0.010431 +0.010491 +0.010303 +0.01019 +0.010251 +0.010303 +0.010345 +0.010364 +0.010165 +0.010029 +0.010055 +0.010095 +0.010143 +0.010152 +0.009933 +0.009811 +0.009806 +0.009827 +0.009857 +0.009875 +0.009668 +0.009538 +0.009551 +0.009599 +0.009636 +0.009633 +0.009405 +0.009297 +0.009303 +0.009337 +0.009381 +0.009403 +0.009182 +0.009083 +0.009101 +0.009133 +0.009165 +0.009177 +0.008971 +0.008873 +0.008901 +0.008944 +0.009006 +0.008992 +0.008812 +0.008711 +0.008739 +0.008789 +0.008827 +0.008857 +0.008677 +0.0086 +0.008617 +0.008659 +0.008719 +0.008755 +0.00857 +0.008474 +0.008511 +0.008547 +0.008608 +0.008642 +0.008504 +0.008385 +0.008436 +0.008502 +0.008568 +0.008618 +0.008465 +0.008391 +0.008445 +0.008532 +0.008598 +0.008644 +0.008488 +0.008422 +0.008482 +0.008564 +0.008645 +0.008697 +0.008559 +0.008473 +0.008513 +0.008604 +0.008676 +0.008732 +0.008579 +0.008523 +0.008569 +0.008634 +0.008725 +0.008783 +0.008627 +0.008563 +0.008608 +0.008684 +0.008778 +0.008807 +0.008692 +0.008622 +0.008689 +0.008719 +0.008794 +0.008861 +0.008742 +0.008634 +0.00869 +0.008755 +0.008864 +0.008923 +0.008769 +0.008701 +0.008747 +0.008811 +0.008895 +0.008956 +0.0088 +0.00873 +0.008789 +0.008865 +0.008937 +0.009003 +0.008861 +0.008774 +0.00883 +0.008903 +0.008989 +0.009051 +0.008899 +0.008828 +0.008894 +0.008991 +0.009027 +0.009082 +0.008933 +0.008863 +0.008927 +0.008985 +0.009073 +0.009142 +0.008993 +0.008927 +0.008969 +0.009057 +0.009133 +0.009176 +0.009026 +0.008947 +0.009004 +0.009075 +0.009176 +0.009246 +0.009086 +0.009014 +0.009071 +0.009134 +0.009206 +0.009277 +0.009142 +0.009049 +0.009085 +0.009181 +0.009247 +0.009325 +0.009197 +0.009083 +0.009136 +0.009226 +0.009301 +0.009371 +0.009221 +0.009142 +0.009197 +0.009284 +0.009356 +0.009412 +0.009256 +0.009186 +0.009232 +0.009315 +0.009406 +0.009484 +0.009313 +0.009244 +0.009293 +0.009391 +0.009458 +0.0095 +0.009341 +0.009266 +0.009338 +0.00942 +0.009499 +0.009586 +0.009391 +0.009308 +0.00937 +0.009459 +0.009551 +0.009614 +0.009466 +0.009378 +0.009441 +0.009489 +0.009601 +0.009656 +0.009494 +0.009416 +0.009463 +0.009543 +0.009664 +0.00973 +0.009589 +0.009471 +0.009516 +0.009589 +0.00969 +0.009756 +0.009589 +0.009501 +0.009577 +0.009668 +0.009747 +0.009825 +0.009642 +0.009563 +0.009624 +0.009685 +0.009784 +0.009853 +0.009693 +0.009601 +0.009655 +0.009756 +0.009841 +0.009907 +0.009745 +0.00967 +0.009732 +0.009792 +0.009883 +0.009962 +0.0098 +0.009712 +0.009743 +0.009838 +0.009941 +0.01 +0.009833 +0.009781 +0.009806 +0.009902 +0.010016 +0.01006 +0.009887 +0.009793 +0.00984 +0.009936 +0.010055 +0.010098 +0.00993 +0.009852 +0.009913 +0.010031 +0.01009 +0.010146 +0.009976 +0.009921 +0.009952 +0.010045 +0.010155 +0.01023 +0.010015 +0.009939 +0.01001 +0.010089 +0.010199 +0.010269 +0.010091 +0.010002 +0.01008 +0.010152 +0.010244 +0.010302 +0.010123 +0.010047 +0.010112 +0.010217 +0.010329 +0.010371 +0.010185 +0.010098 +0.010166 +0.010249 +0.010353 +0.010402 +0.010218 +0.010141 +0.010221 +0.010289 +0.010397 +0.01048 +0.010274 +0.010171 +0.010233 +0.010329 +0.010395 +0.010445 +0.010213 +0.010063 +0.010088 +0.010149 +0.010205 +0.010237 +0.01003 +0.009857 +0.009896 +0.009954 +0.009991 +0.009981 +0.00977 +0.009602 +0.00963 +0.009674 +0.009718 +0.00973 +0.009504 +0.009366 +0.009395 +0.009425 +0.00947 +0.009474 +0.009261 +0.009133 +0.009147 +0.009196 +0.009244 +0.009239 +0.009034 +0.008916 +0.008966 +0.008973 +0.009018 +0.00904 +0.008853 +0.008753 +0.008784 +0.008843 +0.008895 +0.008936 +0.008717 +0.008615 +0.008658 +0.008705 +0.008766 +0.008786 +0.008611 +0.008518 +0.008552 +0.008612 +0.008667 +0.008688 +0.008506 +0.00842 +0.008454 +0.008516 +0.008587 +0.008638 +0.008494 +0.008404 +0.008447 +0.008513 +0.008589 +0.008641 +0.008509 +0.00842 +0.008473 +0.00855 +0.008638 +0.008708 +0.008555 +0.008478 +0.008517 +0.008597 +0.008674 +0.008741 +0.008587 +0.008506 +0.008558 +0.008647 +0.008735 +0.008797 +0.008646 +0.008565 +0.0086 +0.008677 +0.00877 +0.008839 +0.008697 +0.008611 +0.008644 +0.008714 +0.008828 +0.00886 +0.0087 +0.008637 +0.008689 +0.008767 +0.008846 +0.008907 +0.008772 +0.008698 +0.008754 +0.008819 +0.008894 +0.00895 +0.008801 +0.008734 +0.008779 +0.008855 +0.008935 +0.009013 +0.008864 +0.008782 +0.008832 +0.008904 +0.009015 +0.009039 +0.008885 +0.008812 +0.008863 +0.008941 +0.009058 +0.009095 +0.008922 +0.008862 +0.008905 +0.008982 +0.00908 +0.009129 +0.008981 +0.008904 +0.008969 +0.009049 +0.00913 +0.009198 +0.009017 +0.008941 +0.008995 +0.00908 +0.009163 +0.009227 +0.009074 +0.009014 +0.009087 +0.009132 +0.00922 +0.009272 +0.009101 +0.009036 +0.009086 +0.00916 +0.009283 +0.009318 +0.00915 +0.009079 +0.009142 +0.00922 +0.009305 +0.009375 +0.009197 +0.009126 +0.009183 +0.009268 +0.009361 +0.009426 +0.009255 +0.009167 +0.009232 +0.009322 +0.009407 +0.009492 +0.009287 +0.009221 +0.009281 +0.009361 +0.009461 +0.0095 +0.009331 +0.009268 +0.009324 +0.009403 +0.009491 +0.009563 +0.009392 +0.0093 +0.009375 +0.009441 +0.009546 +0.009611 +0.009445 +0.009367 +0.009418 +0.009508 +0.009607 +0.009649 +0.009494 +0.009423 +0.009476 +0.009541 +0.009658 +0.009681 +0.009534 +0.009462 +0.009518 +0.009603 +0.009691 +0.009733 +0.009578 +0.009502 +0.009574 +0.009642 +0.009735 +0.00981 +0.009639 +0.009563 +0.009609 +0.009694 +0.009772 +0.009844 +0.009676 +0.009592 +0.00966 +0.009781 +0.009841 +0.009882 +0.009705 +0.009628 +0.009738 +0.009768 +0.009885 +0.009956 +0.009784 +0.009705 +0.00976 +0.009831 +0.009939 +0.009997 +0.00983 +0.009741 +0.009791 +0.009897 +0.010001 +0.010063 +0.009888 +0.009787 +0.009839 +0.009934 +0.010053 +0.010124 +0.009912 +0.009823 +0.009894 +0.009991 +0.010081 +0.010173 +0.009964 +0.009882 +0.009947 +0.010039 +0.010146 +0.010227 +0.010016 +0.009941 +0.009997 +0.01008 +0.010196 +0.010245 +0.010073 +0.009994 +0.010061 +0.010161 +0.010256 +0.010311 +0.010134 +0.010024 +0.010083 +0.010167 +0.010295 +0.010369 +0.01019 +0.010104 +0.010183 +0.010238 +0.010325 +0.010397 +0.010215 +0.010139 +0.010206 +0.010283 +0.010396 +0.010462 +0.010275 +0.010191 +0.01024 +0.010326 +0.010415 +0.010483 +0.010305 +0.010147 +0.010145 +0.010184 +0.010249 +0.010261 +0.010044 +0.009916 +0.009935 +0.010005 +0.010047 +0.010045 +0.009831 +0.009669 +0.009667 +0.009713 +0.009765 +0.009773 +0.009568 +0.009425 +0.009429 +0.009461 +0.009512 +0.009525 +0.009305 +0.009173 +0.009187 +0.009245 +0.009285 +0.00931 +0.009072 +0.008946 +0.008967 +0.008998 +0.009053 +0.00908 +0.008899 +0.008778 +0.008798 +0.008856 +0.008895 +0.00893 +0.008751 +0.00865 +0.008662 +0.008709 +0.008778 +0.00881 +0.008638 +0.008545 +0.00858 +0.008612 +0.008667 +0.008704 +0.008542 +0.008456 +0.008494 +0.008524 +0.008578 +0.008636 +0.008508 +0.008401 +0.00843 +0.008501 +0.008578 +0.008625 +0.008479 +0.008402 +0.008465 +0.008528 +0.008606 +0.008667 +0.008525 +0.008451 +0.0085 +0.008573 +0.008658 +0.008712 +0.008574 +0.008498 +0.008548 +0.008617 +0.008707 +0.008772 +0.008616 +0.008556 +0.008577 +0.008657 +0.008739 +0.008789 +0.00865 +0.008584 +0.008644 +0.008694 +0.008788 +0.008851 +0.008705 +0.008643 +0.008675 +0.008733 +0.008825 +0.008888 +0.008738 +0.008661 +0.008713 +0.008794 +0.008874 +0.008934 +0.008792 +0.008713 +0.008755 +0.008831 +0.008926 +0.009004 +0.008837 +0.008751 +0.008807 +0.008879 +0.008957 +0.009023 +0.008874 +0.00879 +0.008853 +0.008921 +0.009 +0.009084 +0.008924 +0.008853 +0.008898 +0.008982 +0.009043 +0.009106 +0.008981 +0.008877 +0.008932 +0.009012 +0.009099 +0.009174 +0.009015 +0.008937 +0.008992 +0.009094 +0.009164 +0.009186 +0.009025 +0.008961 +0.009015 +0.009106 +0.009191 +0.00925 +0.009104 +0.009021 +0.009069 +0.009162 +0.009223 +0.0093 +0.00914 +0.009071 +0.009131 +0.009204 +0.009289 +0.009338 +0.009189 +0.009111 +0.009165 +0.009244 +0.009324 +0.009404 +0.009268 +0.00918 +0.009207 +0.009288 +0.009381 +0.009422 +0.009268 +0.009193 +0.009253 +0.009341 +0.009417 +0.009486 +0.009338 +0.009245 +0.009289 +0.009379 +0.009467 +0.009537 +0.009374 +0.00931 +0.009364 +0.00943 +0.009524 +0.009582 +0.00941 +0.00933 +0.009389 +0.0095 +0.009576 +0.009629 +0.009472 +0.009388 +0.009474 +0.00951 +0.009599 +0.009672 +0.009504 +0.009422 +0.00949 +0.009574 +0.009682 +0.00974 +0.009579 +0.009488 +0.009526 +0.009618 +0.009704 +0.009765 +0.009602 +0.009528 +0.009579 +0.00967 +0.009767 +0.009855 +0.009652 +0.009568 +0.009609 +0.009713 +0.009817 +0.009886 +0.009734 +0.009628 +0.009665 +0.009755 +0.009867 +0.009918 +0.009746 +0.00966 +0.009736 +0.009832 +0.009926 +0.009988 +0.009804 +0.0097 +0.009769 +0.009852 +0.009953 +0.010025 +0.009865 +0.009801 +0.009818 +0.009902 +0.010002 +0.010066 +0.009894 +0.009796 +0.009872 +0.009975 +0.010076 +0.010122 +0.009961 +0.009859 +0.009922 +0.010015 +0.010093 +0.010176 +0.010009 +0.009952 +0.009979 +0.010077 +0.010162 +0.010206 +0.010048 +0.009963 +0.010053 +0.010097 +0.010228 +0.010276 +0.010099 +0.010016 +0.01007 +0.010147 +0.010255 +0.010311 +0.010153 +0.010069 +0.010117 +0.010209 +0.010319 +0.01038 +0.010199 +0.010117 +0.010167 +0.010268 +0.010373 +0.010446 +0.01026 +0.010155 +0.010249 +0.010332 +0.010396 +0.010451 +0.01029 +0.010178 +0.010245 +0.010301 +0.010381 +0.010378 +0.01015 +0.010042 +0.010083 +0.010138 +0.010184 +0.010202 +0.009994 +0.009854 +0.009891 +0.009918 +0.009957 +0.009983 +0.00976 +0.009631 +0.009672 +0.009719 +0.009764 +0.009731 +0.009512 +0.009405 +0.009426 +0.009496 +0.009489 +0.009505 +0.009319 +0.009196 +0.009223 +0.009254 +0.009273 +0.009283 +0.009094 +0.008993 +0.009004 +0.009046 +0.009094 +0.009117 +0.008925 +0.008819 +0.008853 +0.008882 +0.008912 +0.008946 +0.008759 +0.008687 +0.008699 +0.008749 +0.008786 +0.008798 +0.008631 +0.008539 +0.008571 +0.008622 +0.008672 +0.008694 +0.008533 +0.008457 +0.0085 +0.008545 +0.008625 +0.008669 +0.008507 +0.00842 +0.0085 +0.00856 +0.008623 +0.008682 +0.008541 +0.008461 +0.008514 +0.008607 +0.008686 +0.008745 +0.008622 +0.008504 +0.008555 +0.00862 +0.008711 +0.008768 +0.008623 +0.008552 +0.008594 +0.008681 +0.00876 +0.00882 +0.008674 +0.008603 +0.008639 +0.008722 +0.008814 +0.008866 +0.00874 +0.008642 +0.008691 +0.008778 +0.008833 +0.0089 +0.008751 +0.008677 +0.008726 +0.008815 +0.008899 +0.008993 +0.008796 +0.008751 +0.008771 +0.008835 +0.008935 +0.008982 +0.00884 +0.008767 +0.008823 +0.008891 +0.008987 +0.009058 +0.008895 +0.008817 +0.00887 +0.00895 +0.00901 +0.00908 +0.008934 +0.00885 +0.008906 +0.008987 +0.009073 +0.009133 +0.008977 +0.008907 +0.008961 +0.009056 +0.009106 +0.009173 +0.009014 +0.008958 +0.00902 +0.009079 +0.009153 +0.00922 +0.009066 +0.008985 +0.009045 +0.009123 +0.009201 +0.009275 +0.00912 +0.009041 +0.009098 +0.009175 +0.009257 +0.009306 +0.009155 +0.009084 +0.009122 +0.009213 +0.009293 +0.009382 +0.009248 +0.009137 +0.009186 +0.009259 +0.009332 +0.009407 +0.009239 +0.009187 +0.009211 +0.009311 +0.009377 +0.009454 +0.009294 +0.009215 +0.009286 +0.009355 +0.00945 +0.00951 +0.009334 +0.009279 +0.009323 +0.009394 +0.009499 +0.009545 +0.009386 +0.009317 +0.009377 +0.00947 +0.009532 +0.009604 +0.009439 +0.009349 +0.009427 +0.009482 +0.009583 +0.009657 +0.009477 +0.009406 +0.009457 +0.009527 +0.009642 +0.009692 +0.009538 +0.009452 +0.009502 +0.009635 +0.00968 +0.009741 +0.009584 +0.009496 +0.009537 +0.009635 +0.00973 +0.009832 +0.009651 +0.009545 +0.009591 +0.009682 +0.009797 +0.009844 +0.009675 +0.009589 +0.009633 +0.009736 +0.009825 +0.009901 +0.009728 +0.00964 +0.009729 +0.009796 +0.009884 +0.009947 +0.00976 +0.009678 +0.009749 +0.009839 +0.009929 +0.010013 +0.009841 +0.009766 +0.009779 +0.009864 +0.009996 +0.010032 +0.009863 +0.009781 +0.009846 +0.009965 +0.010047 +0.010097 +0.009926 +0.009822 +0.009884 +0.009987 +0.010085 +0.010138 +0.009989 +0.009898 +0.009958 +0.010053 +0.010126 +0.010183 +0.010021 +0.009942 +0.01003 +0.010085 +0.010176 +0.010237 +0.010063 +0.010012 +0.01003 +0.010121 +0.010233 +0.010297 +0.010131 +0.01006 +0.010093 +0.010177 +0.010298 +0.010349 +0.010169 +0.010086 +0.010138 +0.010235 +0.010368 +0.010417 +0.010234 +0.010153 +0.010212 +0.010292 +0.010371 +0.010445 +0.010245 +0.010157 +0.010207 +0.010288 +0.010345 +0.010365 +0.010172 +0.010031 +0.010064 +0.010123 +0.010191 +0.010181 +0.009967 +0.009801 +0.009828 +0.009888 +0.00992 +0.009922 +0.00971 +0.009571 +0.009611 +0.009661 +0.009688 +0.009694 +0.009439 +0.009316 +0.009343 +0.009383 +0.009434 +0.009425 +0.009242 +0.009125 +0.009149 +0.009183 +0.009224 +0.009216 +0.009024 +0.008906 +0.008938 +0.008981 +0.009046 +0.00908 +0.008844 +0.008744 +0.008777 +0.00884 +0.008879 +0.008907 +0.008719 +0.008629 +0.008682 +0.008757 +0.008764 +0.008782 +0.008594 +0.008502 +0.008546 +0.008601 +0.008646 +0.008678 +0.008514 +0.008407 +0.008459 +0.008535 +0.008589 +0.008627 +0.008464 +0.008389 +0.008421 +0.008504 +0.008582 +0.00863 +0.00849 +0.008419 +0.008463 +0.00853 +0.008623 +0.008685 +0.008542 +0.008468 +0.008531 +0.008573 +0.008667 +0.008726 +0.008572 +0.008513 +0.008552 +0.008619 +0.008704 +0.008781 +0.008625 +0.00854 +0.008597 +0.008681 +0.008739 +0.008799 +0.008678 +0.008609 +0.008655 +0.008715 +0.008785 +0.008845 +0.008699 +0.008641 +0.008677 +0.00875 +0.008826 +0.008923 +0.008779 +0.008696 +0.008729 +0.008797 +0.008873 +0.008936 +0.008806 +0.008708 +0.008761 +0.008855 +0.008936 +0.008975 +0.008831 +0.008762 +0.008817 +0.008884 +0.008977 +0.00903 +0.00888 +0.008804 +0.00887 +0.008941 +0.009025 +0.009071 +0.008923 +0.008848 +0.008902 +0.008985 +0.009083 +0.009139 +0.008967 +0.008898 +0.00895 +0.009025 +0.009123 +0.009149 +0.009007 +0.008944 +0.008997 +0.009065 +0.009152 +0.009216 +0.009052 +0.008971 +0.009045 +0.009118 +0.009225 +0.009254 +0.009105 +0.009027 +0.009077 +0.009177 +0.00926 +0.009299 +0.009154 +0.009078 +0.009157 +0.009206 +0.009287 +0.009342 +0.009193 +0.009135 +0.009182 +0.009253 +0.009358 +0.009401 +0.009238 +0.00916 +0.009218 +0.009293 +0.00938 +0.00946 +0.009303 +0.009216 +0.009274 +0.009388 +0.00943 +0.00948 +0.009332 +0.009247 +0.009305 +0.009397 +0.009495 +0.009568 +0.009369 +0.009308 +0.009349 +0.009436 +0.009532 +0.009588 +0.009434 +0.009361 +0.009424 +0.009488 +0.00957 +0.009634 +0.009465 +0.009386 +0.009464 +0.009533 +0.009627 +0.009713 +0.009533 +0.009451 +0.009504 +0.009584 +0.009664 +0.009731 +0.009575 +0.00952 +0.009556 +0.009627 +0.009709 +0.009783 +0.009623 +0.009529 +0.00959 +0.009675 +0.00979 +0.009833 +0.009668 +0.009606 +0.009663 +0.009717 +0.009822 +0.009871 +0.009715 +0.009639 +0.009677 +0.009776 +0.009891 +0.009951 +0.009774 +0.009686 +0.009737 +0.009855 +0.009918 +0.009967 +0.009804 +0.009717 +0.009806 +0.009886 +0.009978 +0.01005 +0.009869 +0.009758 +0.009835 +0.009915 +0.010011 +0.01011 +0.009911 +0.009817 +0.009882 +0.009967 +0.010069 +0.010135 +0.009958 +0.009874 +0.00994 +0.010058 +0.010179 +0.010167 +0.009998 +0.009915 +0.009967 +0.01008 +0.010163 +0.010237 +0.010099 +0.009984 +0.010035 +0.010135 +0.010202 +0.010274 +0.010111 +0.010014 +0.010084 +0.010189 +0.010266 +0.010336 +0.010167 +0.010066 +0.010132 +0.01022 +0.010343 +0.01045 +0.010208 +0.010125 +0.010174 +0.010261 +0.010365 +0.01041 +0.010229 +0.010133 +0.010158 +0.010215 +0.010291 +0.010298 +0.010089 +0.009961 +0.009973 +0.01002 +0.010065 +0.010076 +0.009868 +0.009736 +0.009731 +0.009776 +0.009805 +0.009825 +0.009617 +0.009488 +0.00953 +0.009528 +0.009569 +0.009593 +0.009389 +0.009258 +0.009282 +0.009299 +0.009345 +0.00936 +0.009197 +0.00904 +0.009082 +0.009123 +0.009163 +0.009194 +0.008996 +0.008874 +0.008898 +0.008944 +0.008985 +0.009015 +0.008847 +0.008734 +0.008758 +0.008803 +0.008856 +0.008905 +0.00873 +0.008611 +0.008634 +0.008685 +0.008733 +0.008776 +0.008629 +0.008521 +0.008535 +0.008592 +0.008648 +0.008685 +0.008548 +0.00845 +0.008471 +0.008544 +0.008617 +0.008677 +0.008536 +0.008466 +0.008507 +0.008561 +0.008644 +0.008718 +0.008555 +0.008485 +0.008543 +0.008614 +0.008723 +0.008784 +0.008607 +0.008541 +0.008585 +0.008659 +0.008742 +0.008776 +0.008639 +0.008569 +0.008631 +0.008701 +0.008774 +0.008847 +0.008697 +0.008634 +0.008673 +0.008739 +0.00881 +0.008883 +0.008738 +0.00867 +0.008717 +0.008795 +0.008869 +0.008921 +0.008781 +0.008706 +0.008755 +0.008856 +0.008913 +0.008975 +0.00883 +0.008753 +0.008807 +0.00888 +0.008975 +0.009002 +0.008867 +0.008783 +0.008837 +0.008916 +0.009009 +0.009066 +0.00891 +0.008842 +0.008888 +0.00896 +0.009052 +0.009113 +0.008956 +0.008875 +0.008931 +0.009001 +0.009097 +0.009176 +0.009015 +0.008961 +0.008973 +0.009048 +0.009132 +0.009192 +0.009047 +0.008962 +0.009017 +0.009108 +0.009232 +0.00924 +0.00909 +0.009023 +0.009052 +0.009135 +0.009229 +0.009292 +0.009131 +0.009065 +0.009121 +0.009195 +0.009277 +0.00934 +0.00918 +0.0091 +0.009146 +0.009243 +0.009352 +0.009414 +0.009254 +0.009151 +0.009189 +0.009273 +0.009371 +0.009438 +0.009267 +0.009196 +0.009229 +0.009335 +0.009443 +0.009488 +0.009331 +0.009241 +0.009292 +0.009373 +0.009462 +0.009535 +0.009359 +0.009283 +0.00934 +0.009426 +0.009516 +0.009579 +0.009415 +0.009367 +0.009401 +0.009468 +0.009559 +0.009638 +0.009474 +0.009361 +0.009427 +0.009522 +0.00961 +0.009672 +0.009507 +0.009425 +0.009487 +0.009566 +0.009681 +0.009726 +0.009555 +0.009469 +0.009521 +0.009621 +0.00971 +0.009782 +0.009595 +0.009532 +0.009594 +0.009702 +0.009786 +0.009808 +0.009628 +0.00956 +0.009629 +0.009729 +0.009795 +0.009874 +0.009687 +0.009606 +0.009671 +0.009763 +0.009846 +0.009916 +0.009766 +0.009655 +0.009729 +0.009837 +0.009918 +0.009955 +0.009804 +0.009708 +0.009772 +0.009867 +0.009965 +0.010055 +0.009851 +0.009773 +0.009826 +0.009908 +0.009992 +0.010066 +0.009909 +0.009811 +0.009858 +0.009945 +0.010064 +0.010114 +0.009946 +0.009863 +0.009916 +0.010009 +0.010117 +0.010176 +0.009999 +0.009936 +0.009968 +0.01005 +0.010162 +0.010237 +0.010094 +0.009945 +0.01 +0.010107 +0.010204 +0.010285 +0.010126 +0.010014 +0.010063 +0.010166 +0.010255 +0.010325 +0.010142 +0.010048 +0.010131 +0.010219 +0.010331 +0.010401 +0.0102 +0.010095 +0.010174 +0.010249 +0.010364 +0.01045 +0.01027 +0.01018 +0.010215 +0.010332 +0.010406 +0.010476 +0.010298 +0.010211 +0.010283 +0.010392 +0.010471 +0.010538 +0.010329 +0.010241 +0.010315 +0.010387 +0.010458 +0.010514 +0.010299 +0.010159 +0.010194 +0.01025 +0.01029 +0.01032 +0.010086 +0.00998 +0.009969 +0.010003 +0.010056 +0.010111 +0.009838 +0.009718 +0.009742 +0.009791 +0.00984 +0.009845 +0.009645 +0.009528 +0.009532 +0.009571 +0.009604 +0.009618 +0.009403 +0.00928 +0.0093 +0.009352 +0.009402 +0.009417 +0.009213 +0.009094 +0.009107 +0.009168 +0.009181 +0.009192 +0.009007 +0.008897 +0.008924 +0.008992 +0.009058 +0.009055 +0.008862 +0.008755 +0.008772 +0.008835 +0.008875 +0.008903 +0.008725 +0.008629 +0.008669 +0.008707 +0.008775 +0.008792 +0.008625 +0.008531 +0.008575 +0.008629 +0.00871 +0.00875 +0.0086 +0.008535 +0.008573 +0.008637 +0.008702 +0.008764 +0.008622 +0.008547 +0.008593 +0.00866 +0.008757 +0.008844 +0.00867 +0.008597 +0.008652 +0.008717 +0.008803 +0.008853 +0.008702 +0.008628 +0.008681 +0.008757 +0.008858 +0.0089 +0.008748 +0.008681 +0.008728 +0.008808 +0.008897 +0.00896 +0.00882 +0.008759 +0.008759 +0.008851 +0.008934 +0.008999 +0.008825 +0.008761 +0.008807 +0.008892 +0.008974 +0.009037 +0.008885 +0.008813 +0.008871 +0.008947 +0.009028 +0.009088 +0.008924 +0.008853 +0.0089 +0.008977 +0.009067 +0.009139 +0.008988 +0.008893 +0.008953 +0.009033 +0.009146 +0.009167 +0.009004 +0.008952 +0.008992 +0.009069 +0.009165 +0.009227 +0.009066 +0.008975 +0.009036 +0.009115 +0.009215 +0.009269 +0.009106 +0.00904 +0.009091 +0.009174 +0.00926 +0.009313 +0.009148 +0.009064 +0.009136 +0.009213 +0.009294 +0.009367 +0.009213 +0.009152 +0.009187 +0.009238 +0.009331 +0.009394 +0.009246 +0.009182 +0.00922 +0.009303 +0.009403 +0.009471 +0.00929 +0.009223 +0.00926 +0.00934 +0.009447 +0.009498 +0.009331 +0.009261 +0.009328 +0.009417 +0.009504 +0.00957 +0.009379 +0.009297 +0.009363 +0.00944 +0.009567 +0.009593 +0.00943 +0.009343 +0.009408 +0.009497 +0.009586 +0.009655 +0.009485 +0.009387 +0.009451 +0.009539 +0.009639 +0.009708 +0.009526 +0.009453 +0.009509 +0.009592 +0.009672 +0.009735 +0.009566 +0.009507 +0.009562 +0.009655 +0.009744 +0.00981 +0.00966 +0.009536 +0.00959 +0.00967 +0.009767 +0.009834 +0.0097 +0.009595 +0.009664 +0.00975 +0.009839 +0.009876 +0.009711 +0.009633 +0.009689 +0.009787 +0.009872 +0.009941 +0.009772 +0.009685 +0.009751 +0.009851 +0.009929 +0.009992 +0.009831 +0.009762 +0.009834 +0.009881 +0.009982 +0.010016 +0.009862 +0.009782 +0.009845 +0.009925 +0.010042 +0.010114 +0.00993 +0.009852 +0.009886 +0.009969 +0.010081 +0.010137 +0.009967 +0.009883 +0.009943 +0.010031 +0.010146 +0.010202 +0.010019 +0.009943 +0.01 +0.010113 +0.010174 +0.010248 +0.010078 +0.010021 +0.010019 +0.010126 +0.010232 +0.010298 +0.01012 +0.010027 +0.01011 +0.010206 +0.010302 +0.010358 +0.010157 +0.010075 +0.010145 +0.01023 +0.010344 +0.010407 +0.010225 +0.010133 +0.010199 +0.010322 +0.0104 +0.010438 +0.010266 +0.010182 +0.010257 +0.010364 +0.010438 +0.010508 +0.010319 +0.010236 +0.010308 +0.010387 +0.010489 +0.010556 +0.010403 +0.010257 +0.010304 +0.010344 +0.010407 +0.010416 +0.010218 +0.010096 +0.010115 +0.010162 +0.010229 +0.010225 +0.009965 +0.009854 +0.009878 +0.00992 +0.009963 +0.009973 +0.009794 +0.009634 +0.009643 +0.009693 +0.009726 +0.009739 +0.009539 +0.009408 +0.009434 +0.009483 +0.009534 +0.009531 +0.009327 +0.009212 +0.009216 +0.009262 +0.009307 +0.009315 +0.009126 +0.009023 +0.009064 +0.009133 +0.009132 +0.00915 +0.008972 +0.008856 +0.008897 +0.008938 +0.008988 +0.009035 +0.008842 +0.008746 +0.008777 +0.008837 +0.008876 +0.008908 +0.008736 +0.008649 +0.008678 +0.00873 +0.008793 +0.008833 +0.008656 +0.008582 +0.008627 +0.008685 +0.008732 +0.008788 +0.008635 +0.008587 +0.008626 +0.008691 +0.008756 +0.008833 +0.008689 +0.00861 +0.008655 +0.008738 +0.008817 +0.008864 +0.008732 +0.008638 +0.008703 +0.00877 +0.008854 +0.00892 +0.008762 +0.008686 +0.008743 +0.008825 +0.008909 +0.008956 +0.008811 +0.008739 +0.008813 +0.008867 +0.008961 +0.009007 +0.008873 +0.008772 +0.008821 +0.008907 +0.00898 +0.009054 +0.008885 +0.008821 +0.008893 +0.008957 +0.009037 +0.009102 +0.008971 +0.008853 +0.008907 +0.008993 +0.00908 +0.009128 +0.008985 +0.008917 +0.008959 +0.009041 +0.009135 +0.009192 +0.009028 +0.008957 +0.009017 +0.009107 +0.009205 +0.009237 +0.009062 +0.008998 +0.009061 +0.009124 +0.009212 +0.009273 +0.009122 +0.009042 +0.0091 +0.009195 +0.009284 +0.009333 +0.009159 +0.009096 +0.00914 +0.009216 +0.009311 +0.009368 +0.009205 +0.009147 +0.00921 +0.009286 +0.009371 +0.009427 +0.009268 +0.009199 +0.009219 +0.009306 +0.009405 +0.009468 +0.009296 +0.009238 +0.009271 +0.009372 +0.009447 +0.009512 +0.009356 +0.009273 +0.009324 +0.009421 +0.009516 +0.009559 +0.009389 +0.009322 +0.009362 +0.00946 +0.009563 +0.009612 +0.009443 +0.009363 +0.00943 +0.009542 +0.009612 +0.009663 +0.009478 +0.009401 +0.009475 +0.009561 +0.009638 +0.009704 +0.00956 +0.009462 +0.00951 +0.009607 +0.009691 +0.009744 +0.009593 +0.009502 +0.00957 +0.009661 +0.009743 +0.009793 +0.00963 +0.009552 +0.009599 +0.009694 +0.009795 +0.009885 +0.009695 +0.009604 +0.009679 +0.009752 +0.009839 +0.009885 +0.009722 +0.009644 +0.009714 +0.00979 +0.00991 +0.009959 +0.009791 +0.009712 +0.009766 +0.009831 +0.009928 +0.010007 +0.009823 +0.009747 +0.00981 +0.009883 +0.009989 +0.010065 +0.009892 +0.009825 +0.009847 +0.009924 +0.010047 +0.010103 +0.009928 +0.009839 +0.009915 +0.009987 +0.010084 +0.010155 +0.009987 +0.009929 +0.009941 +0.010043 +0.010133 +0.01021 +0.01005 +0.009941 +0.009987 +0.010094 +0.010183 +0.010259 +0.010093 +0.010004 +0.010087 +0.010151 +0.010242 +0.010316 +0.010125 +0.010046 +0.010089 +0.010187 +0.010287 +0.010351 +0.010179 +0.010093 +0.010154 +0.010253 +0.01036 +0.010402 +0.010223 +0.01014 +0.010209 +0.010318 +0.010415 +0.010451 +0.010283 +0.010199 +0.010296 +0.010345 +0.010434 +0.010518 +0.010345 +0.01026 +0.010312 +0.010418 +0.01049 +0.010554 +0.01037 +0.010302 +0.010346 +0.010468 +0.010584 +0.010638 +0.010443 +0.010344 +0.010375 +0.010466 +0.010559 +0.010589 +0.010388 +0.010242 +0.01027 +0.010336 +0.010409 +0.010382 +0.010146 +0.010008 +0.010035 +0.010077 +0.010141 +0.010211 +0.009921 +0.009793 +0.009789 +0.009842 +0.009894 +0.009904 +0.009689 +0.009537 +0.009584 +0.009635 +0.009676 +0.009673 +0.009467 +0.009315 +0.00933 +0.009379 +0.009435 +0.009483 +0.00926 +0.00912 +0.009129 +0.009179 +0.009243 +0.009254 +0.009063 +0.008939 +0.008977 +0.009025 +0.009096 +0.009118 +0.008914 +0.008793 +0.008825 +0.008883 +0.008935 +0.008969 +0.00879 +0.008677 +0.008715 +0.008781 +0.008845 +0.008877 +0.008693 +0.008592 +0.008617 +0.00871 +0.008758 +0.008796 +0.008646 +0.008538 +0.008587 +0.008665 +0.008746 +0.008813 +0.00867 +0.008581 +0.008629 +0.008703 +0.008801 +0.008854 +0.008709 +0.008645 +0.008682 +0.00875 +0.008836 +0.008904 +0.00874 +0.008667 +0.008723 +0.008798 +0.008876 +0.008956 +0.008796 +0.008724 +0.008792 +0.00884 +0.008916 +0.00898 +0.008822 +0.008785 +0.008816 +0.008878 +0.00898 +0.009041 +0.008872 +0.008792 +0.008855 +0.008928 +0.009009 +0.009085 +0.008918 +0.008834 +0.008904 +0.008995 +0.009067 +0.009128 +0.008972 +0.008878 +0.008935 +0.00902 +0.009108 +0.009182 +0.009031 +0.008925 +0.008986 +0.009061 +0.009148 +0.009219 +0.009048 +0.008988 +0.009032 +0.009106 +0.009197 +0.009272 +0.009119 +0.00901 +0.009074 +0.009161 +0.009232 +0.00932 +0.009146 +0.009068 +0.009121 +0.009213 +0.009309 +0.009359 +0.009198 +0.009111 +0.009173 +0.009281 +0.009333 +0.009392 +0.009226 +0.009161 +0.009231 +0.00931 +0.009387 +0.009455 +0.00931 +0.009187 +0.009247 +0.009337 +0.00943 +0.00949 +0.009336 +0.009236 +0.009305 +0.009392 +0.009488 +0.009542 +0.009374 +0.009304 +0.009348 +0.009436 +0.009547 +0.009619 +0.009441 +0.009337 +0.009392 +0.00948 +0.009568 +0.009641 +0.00946 +0.009397 +0.009469 +0.009548 +0.009624 +0.009711 +0.0095 +0.009434 +0.009495 +0.009574 +0.009654 +0.009725 +0.009579 +0.00948 +0.009552 +0.00964 +0.009721 +0.009784 +0.009631 +0.009551 +0.009624 +0.00969 +0.009773 +0.009816 +0.009662 +0.009578 +0.009636 +0.009732 +0.009823 +0.009889 +0.009721 +0.00965 +0.0097 +0.009773 +0.00986 +0.00992 +0.009754 +0.009683 +0.009741 +0.009819 +0.009935 +0.010005 +0.009822 +0.009732 +0.009793 +0.009885 +0.009982 +0.010027 +0.00984 +0.009773 +0.009842 +0.009939 +0.010006 +0.010077 +0.009904 +0.00982 +0.009882 +0.009979 +0.01007 +0.010151 +0.009982 +0.009865 +0.009924 +0.010025 +0.01011 +0.010189 +0.010023 +0.009919 +0.009996 +0.010097 +0.010207 +0.010256 +0.010054 +0.009942 +0.010024 +0.010125 +0.010215 +0.010291 +0.010141 +0.010021 +0.010071 +0.010173 +0.010271 +0.010326 +0.010169 +0.010077 +0.010134 +0.01025 +0.010345 +0.010375 +0.010209 +0.010122 +0.010186 +0.010279 +0.010385 +0.01049 +0.010279 +0.01018 +0.010235 +0.010308 +0.010426 +0.010493 +0.010301 +0.010234 +0.010307 +0.010396 +0.010497 +0.010551 +0.010368 +0.010283 +0.01032 +0.010411 +0.01053 +0.010608 +0.010433 +0.010329 +0.01039 +0.010488 +0.010586 +0.010674 +0.010431 +0.010335 +0.010383 +0.010449 +0.010505 +0.010493 +0.010265 +0.010125 +0.010153 +0.010197 +0.010248 +0.010214 +0.009998 +0.009865 +0.009889 +0.009936 +0.009955 +0.009964 +0.009751 +0.009639 +0.009633 +0.009675 +0.009727 +0.009708 +0.009489 +0.009382 +0.009413 +0.009441 +0.009452 +0.009471 +0.009254 +0.009153 +0.009187 +0.009221 +0.009255 +0.009256 +0.009061 +0.008957 +0.008996 +0.009027 +0.009068 +0.009081 +0.008929 +0.008813 +0.008842 +0.0089 +0.008932 +0.008943 +0.008773 +0.008683 +0.008708 +0.008758 +0.008813 +0.008856 +0.00868 +0.008579 +0.008598 +0.008654 +0.008702 +0.00876 +0.008573 +0.008489 +0.008535 +0.008596 +0.008655 +0.008713 +0.008566 +0.008481 +0.008533 +0.008613 +0.008684 +0.008747 +0.008598 +0.008512 +0.008576 +0.008647 +0.008744 +0.0088 +0.008655 +0.008561 +0.008609 +0.008697 +0.008782 +0.008856 +0.008679 +0.008603 +0.008652 +0.008729 +0.008818 +0.008892 +0.008743 +0.008656 +0.008713 +0.008786 +0.008858 +0.008906 +0.008766 +0.008687 +0.008745 +0.008822 +0.008913 +0.008977 +0.008804 +0.00873 +0.008781 +0.00886 +0.00896 +0.009011 +0.008855 +0.008789 +0.008858 +0.008944 +0.009003 +0.009047 +0.008893 +0.00882 +0.008875 +0.008957 +0.009044 +0.009098 +0.008964 +0.008892 +0.008925 +0.009003 +0.009079 +0.009136 +0.008989 +0.008918 +0.00896 +0.009042 +0.009123 +0.009215 +0.009044 +0.008966 +0.009027 +0.009094 +0.009165 +0.009233 +0.009087 +0.009028 +0.009066 +0.009154 +0.009205 +0.009271 +0.009125 +0.009039 +0.009098 +0.009176 +0.009265 +0.009337 +0.009173 +0.009103 +0.009159 +0.009235 +0.009312 +0.009374 +0.009215 +0.009135 +0.00918 +0.009257 +0.009366 +0.009445 +0.009281 +0.009194 +0.009253 +0.009342 +0.009431 +0.009471 +0.009294 +0.009221 +0.009287 +0.009357 +0.00944 +0.009512 +0.00936 +0.009283 +0.009332 +0.009406 +0.009512 +0.00958 +0.009395 +0.009333 +0.009382 +0.009452 +0.009551 +0.009615 +0.009453 +0.009371 +0.009437 +0.009496 +0.009597 +0.009678 +0.009531 +0.009444 +0.009476 +0.009543 +0.009634 +0.009702 +0.009569 +0.009453 +0.0095 +0.009617 +0.009698 +0.009762 +0.009603 +0.009511 +0.009556 +0.009656 +0.00975 +0.009805 +0.009635 +0.009563 +0.0096 +0.009683 +0.009804 +0.009851 +0.009689 +0.009613 +0.009693 +0.009786 +0.009838 +0.009916 +0.009737 +0.009633 +0.009704 +0.009791 +0.009919 +0.009953 +0.00977 +0.0097 +0.009781 +0.009854 +0.009953 +0.010014 +0.009821 +0.009748 +0.009812 +0.009904 +0.009988 +0.010057 +0.009876 +0.009794 +0.009855 +0.009965 +0.010095 +0.010091 +0.009926 +0.009841 +0.0099 +0.01002 +0.010094 +0.010146 +0.009984 +0.00989 +0.009956 +0.010054 +0.010138 +0.010214 +0.010054 +0.009959 +0.010017 +0.010103 +0.010201 +0.010233 +0.010081 +0.010002 +0.010057 +0.01015 +0.010288 +0.010364 +0.01013 +0.010075 +0.010074 +0.010181 +0.010292 +0.010352 +0.010179 +0.010115 +0.010143 +0.010247 +0.010356 +0.010412 +0.010233 +0.010148 +0.010211 +0.010301 +0.010434 +0.010483 +0.010277 +0.010201 +0.01025 +0.010343 +0.010472 +0.010556 +0.010348 +0.010252 +0.010315 +0.010448 +0.010504 +0.010518 +0.010358 +0.01025 +0.010307 +0.010377 +0.010415 +0.010429 +0.010224 +0.0101 +0.010125 +0.010165 +0.010208 +0.010209 +0.009991 +0.009862 +0.009892 +0.009908 +0.009944 +0.00995 +0.00973 +0.009611 +0.00965 +0.009673 +0.009673 +0.009697 +0.00951 +0.009363 +0.009357 +0.009397 +0.009435 +0.00944 +0.009234 +0.009126 +0.009153 +0.0092 +0.009243 +0.009246 +0.009036 +0.008933 +0.008942 +0.008991 +0.009024 +0.009045 +0.008869 +0.008774 +0.008793 +0.008833 +0.008881 +0.008922 +0.00874 +0.008623 +0.008658 +0.008707 +0.008748 +0.008792 +0.00863 +0.00853 +0.008567 +0.008603 +0.008655 +0.008691 +0.008537 +0.008442 +0.008492 +0.008546 +0.008621 +0.008679 +0.00851 +0.00844 +0.008493 +0.008553 +0.00861 +0.00869 +0.008545 +0.008467 +0.008516 +0.0086 +0.008695 +0.008745 +0.008577 +0.008502 +0.008562 +0.008636 +0.008718 +0.008785 +0.008624 +0.00856 +0.008623 +0.008687 +0.008761 +0.008823 +0.008662 +0.008595 +0.008648 +0.008728 +0.008801 +0.008861 +0.008725 +0.00865 +0.008717 +0.008772 +0.008864 +0.008895 +0.008753 +0.008681 +0.008737 +0.008836 +0.00891 +0.008937 +0.008787 +0.008724 +0.008776 +0.008852 +0.008934 +0.008995 +0.00885 +0.008776 +0.008845 +0.008902 +0.008985 +0.009048 +0.008887 +0.00882 +0.008859 +0.008937 +0.009027 +0.009092 +0.008932 +0.008853 +0.008918 +0.009002 +0.009093 +0.009149 +0.00899 +0.008918 +0.008957 +0.009026 +0.009123 +0.009181 +0.009016 +0.008948 +0.009012 +0.00908 +0.009184 +0.009227 +0.009068 +0.008987 +0.009049 +0.009121 +0.009203 +0.00928 +0.00912 +0.009032 +0.009098 +0.009161 +0.009257 +0.009329 +0.009168 +0.009082 +0.009135 +0.009223 +0.009337 +0.009401 +0.009206 +0.009105 +0.009173 +0.009254 +0.009379 +0.009405 +0.009239 +0.009182 +0.009235 +0.009322 +0.009415 +0.009466 +0.009291 +0.009213 +0.009278 +0.00936 +0.009442 +0.009517 +0.009341 +0.009269 +0.009319 +0.009403 +0.009492 +0.009552 +0.009395 +0.009338 +0.009388 +0.009452 +0.009547 +0.009609 +0.009435 +0.00935 +0.00941 +0.009515 +0.009586 +0.009642 +0.009486 +0.009417 +0.009478 +0.009557 +0.009657 +0.009688 +0.009525 +0.009445 +0.009513 +0.009601 +0.009686 +0.009754 +0.009611 +0.009514 +0.009574 +0.009665 +0.00976 +0.009766 +0.009609 +0.009534 +0.009603 +0.009699 +0.009785 +0.009847 +0.009682 +0.009613 +0.009644 +0.009741 +0.009812 +0.009902 +0.00974 +0.009654 +0.009718 +0.009797 +0.009874 +0.009948 +0.009774 +0.009696 +0.009757 +0.009828 +0.009943 +0.010047 +0.009843 +0.009769 +0.009779 +0.009862 +0.009981 +0.010029 +0.009864 +0.009793 +0.009845 +0.009941 +0.010049 +0.010094 +0.009925 +0.009833 +0.009896 +0.009986 +0.010085 +0.010165 +0.009993 +0.009888 +0.009955 +0.010036 +0.010132 +0.010203 +0.010046 +0.009955 +0.009984 +0.01009 +0.010232 +0.010254 +0.010049 +0.009977 +0.010049 +0.010128 +0.010231 +0.010304 +0.010136 +0.010057 +0.010117 +0.010195 +0.010294 +0.010342 +0.010167 +0.010078 +0.010147 +0.010251 +0.010345 +0.010398 +0.01023 +0.010178 +0.01019 +0.010288 +0.010379 +0.010457 +0.010284 +0.010202 +0.010264 +0.010348 +0.010431 +0.010509 +0.010327 +0.010236 +0.0103 +0.010392 +0.010501 +0.010586 +0.010395 +0.010283 +0.010323 +0.010421 +0.010506 +0.010521 +0.010305 +0.010155 +0.010207 +0.010281 +0.010322 +0.010295 +0.010083 +0.009924 +0.009955 +0.010015 +0.010034 +0.010053 +0.009814 +0.009697 +0.009716 +0.009741 +0.009791 +0.009802 +0.009583 +0.009442 +0.009452 +0.00951 +0.009554 +0.009573 +0.009341 +0.0092 +0.009207 +0.009264 +0.009305 +0.00934 +0.009103 +0.008976 +0.008984 +0.009053 +0.009104 +0.009113 +0.008911 +0.00881 +0.008815 +0.008851 +0.008907 +0.008933 +0.008738 +0.008645 +0.00866 +0.008725 +0.008761 +0.008791 +0.008611 +0.008508 +0.008534 +0.008586 +0.008651 +0.00867 +0.008509 +0.008412 +0.008451 +0.008509 +0.008594 +0.008588 +0.008427 +0.008349 +0.008401 +0.008477 +0.008549 +0.008623 +0.008475 +0.008409 +0.008449 +0.00852 +0.008579 +0.008649 +0.008506 +0.008431 +0.008495 +0.008556 +0.008629 +0.008696 +0.008554 +0.008473 +0.008523 +0.008601 +0.008681 +0.008732 +0.008595 +0.00853 +0.00858 +0.008683 +0.008732 +0.008789 +0.008665 +0.008547 +0.008604 +0.008675 +0.00876 +0.008821 +0.008682 +0.008592 +0.008667 +0.008739 +0.008826 +0.008876 +0.008729 +0.008649 +0.008694 +0.008764 +0.008855 +0.008916 +0.008768 +0.0087 +0.008752 +0.00881 +0.008896 +0.008956 +0.008816 +0.008747 +0.008799 +0.00886 +0.008934 +0.009019 +0.008868 +0.008802 +0.008817 +0.008891 +0.008994 +0.009045 +0.008898 +0.008821 +0.008873 +0.008953 +0.009056 +0.009116 +0.008952 +0.008872 +0.008907 +0.008992 +0.009075 +0.009146 +0.008992 +0.008903 +0.008958 +0.009046 +0.009132 +0.009216 +0.009045 +0.008947 +0.008995 +0.009079 +0.009171 +0.00924 +0.009093 +0.009025 +0.009057 +0.009126 +0.009217 +0.009282 +0.009121 +0.009045 +0.009089 +0.009183 +0.009279 +0.00934 +0.009185 +0.009107 +0.009141 +0.009226 +0.009313 +0.00936 +0.00921 +0.009138 +0.0092 +0.009297 +0.009361 +0.00943 +0.009268 +0.00919 +0.009234 +0.009306 +0.009399 +0.009477 +0.009305 +0.00922 +0.009283 +0.009384 +0.009481 +0.009523 +0.009367 +0.009279 +0.009305 +0.009418 +0.009491 +0.009556 +0.00941 +0.009332 +0.009373 +0.00945 +0.00955 +0.009646 +0.009462 +0.00939 +0.009399 +0.009494 +0.009606 +0.009668 +0.009505 +0.009406 +0.009473 +0.009551 +0.009637 +0.00972 +0.009541 +0.009453 +0.009535 +0.00962 +0.009709 +0.009768 +0.009588 +0.009501 +0.009562 +0.009652 +0.009737 +0.009803 +0.009641 +0.009581 +0.009636 +0.009689 +0.009785 +0.009876 +0.009676 +0.009598 +0.009657 +0.009753 +0.009862 +0.0099 +0.009734 +0.00966 +0.009715 +0.009794 +0.0099 +0.009954 +0.009786 +0.009719 +0.009772 +0.009864 +0.00995 +0.009996 +0.009827 +0.009747 +0.009802 +0.009933 +0.009983 +0.010075 +0.009893 +0.009804 +0.00988 +0.009949 +0.010025 +0.010103 +0.009921 +0.009844 +0.009925 +0.009983 +0.010094 +0.010168 +0.00999 +0.009891 +0.009959 +0.01004 +0.010147 +0.010229 +0.010044 +0.009955 +0.010002 +0.010105 +0.010238 +0.010245 +0.010067 +0.009983 +0.010055 +0.010178 +0.010266 +0.01034 +0.01014 +0.010022 +0.010099 +0.0102 +0.010298 +0.010349 +0.010183 +0.010095 +0.010162 +0.010258 +0.01035 +0.010405 +0.01025 +0.010141 +0.010212 +0.010328 +0.010449 +0.010493 +0.01026 +0.010176 +0.010254 +0.010349 +0.010427 +0.01048 +0.01029 +0.010179 +0.010246 +0.010297 +0.010339 +0.010341 +0.010125 +0.010002 +0.010004 +0.010053 +0.010099 +0.010124 +0.009893 +0.009746 +0.009765 +0.009798 +0.009839 +0.009884 +0.009624 +0.009502 +0.009535 +0.009545 +0.009581 +0.009578 +0.009358 +0.00925 +0.009252 +0.009284 +0.009325 +0.009341 +0.009134 +0.009011 +0.009037 +0.009058 +0.009098 +0.009107 +0.008905 +0.008798 +0.008822 +0.008861 +0.008887 +0.008914 +0.008733 +0.008653 +0.008682 +0.008718 +0.008743 +0.008752 +0.008586 +0.00849 +0.008528 +0.008561 +0.008601 +0.008636 +0.008483 +0.008385 +0.008404 +0.008449 +0.008508 +0.008549 +0.008382 +0.008296 +0.008333 +0.008383 +0.00845 +0.008515 +0.008367 +0.008294 +0.008333 +0.008392 +0.008471 +0.008536 +0.00839 +0.008329 +0.008373 +0.008457 +0.008528 +0.008578 +0.008432 +0.008359 +0.00842 +0.008482 +0.008552 +0.008615 +0.008474 +0.008401 +0.008447 +0.008535 +0.008602 +0.008661 +0.008513 +0.008447 +0.008523 +0.00859 +0.008632 +0.008707 +0.008551 +0.00849 +0.008549 +0.008621 +0.008691 +0.008737 +0.008608 +0.008534 +0.008603 +0.008654 +0.008731 +0.008778 +0.008636 +0.008576 +0.008629 +0.00869 +0.008771 +0.00885 +0.008693 +0.008614 +0.008672 +0.008741 +0.008825 +0.008889 +0.008741 +0.008663 +0.008722 +0.008791 +0.008867 +0.008933 +0.008769 +0.008705 +0.008757 +0.008818 +0.008917 +0.008983 +0.008848 +0.008792 +0.008815 +0.008864 +0.008935 +0.009006 +0.008863 +0.008777 +0.008836 +0.008917 +0.009006 +0.00908 +0.008917 +0.008846 +0.008897 +0.008962 +0.009038 +0.0091 +0.008951 +0.008873 +0.008934 +0.009017 +0.009087 +0.009157 +0.008997 +0.008918 +0.008972 +0.009057 +0.009153 +0.00922 +0.009041 +0.008976 +0.009039 +0.009095 +0.009176 +0.009237 +0.009081 +0.009017 +0.009067 +0.009136 +0.009227 +0.009302 +0.009131 +0.00907 +0.009128 +0.009192 +0.009261 +0.009339 +0.009177 +0.009103 +0.009155 +0.009247 +0.009316 +0.009397 +0.009251 +0.009171 +0.009237 +0.009281 +0.009359 +0.009408 +0.009262 +0.009189 +0.00924 +0.009338 +0.009433 +0.00948 +0.009318 +0.009233 +0.009291 +0.00937 +0.009466 +0.009546 +0.009357 +0.009289 +0.009364 +0.00944 +0.009512 +0.009573 +0.00941 +0.009322 +0.009383 +0.00947 +0.009576 +0.009644 +0.009471 +0.009384 +0.009448 +0.009527 +0.009584 +0.009655 +0.009503 +0.009428 +0.009474 +0.009554 +0.009667 +0.009733 +0.009569 +0.009491 +0.00954 +0.009628 +0.009696 +0.009756 +0.009593 +0.009512 +0.009576 +0.009654 +0.009757 +0.009827 +0.009676 +0.009586 +0.009615 +0.009695 +0.009796 +0.00987 +0.00971 +0.009628 +0.009663 +0.009768 +0.009864 +0.009909 +0.009749 +0.009656 +0.009712 +0.009814 +0.009914 +0.009979 +0.009811 +0.009699 +0.009765 +0.009859 +0.00995 +0.010018 +0.009843 +0.00977 +0.009868 +0.009916 +0.010034 +0.010055 +0.009871 +0.009797 +0.009858 +0.009954 +0.010062 +0.01014 +0.009924 +0.009865 +0.009911 +0.010002 +0.010112 +0.010159 +0.009992 +0.009915 +0.009983 +0.010087 +0.010174 +0.0102 +0.010038 +0.009958 +0.01002 +0.010149 +0.010192 +0.010264 +0.010085 +0.010021 +0.010091 +0.010154 +0.010251 +0.010315 +0.010147 +0.010052 +0.010124 +0.010213 +0.010341 +0.010392 +0.010195 +0.010112 +0.010165 +0.010251 +0.010357 +0.010424 +0.010227 +0.01012 +0.010198 +0.010286 +0.010352 +0.010338 +0.010108 +0.009986 +0.010017 +0.010083 +0.010117 +0.010119 +0.009912 +0.009778 +0.009781 +0.009803 +0.009846 +0.009849 +0.009654 +0.009493 +0.00949 +0.00955 +0.009591 +0.009589 +0.009369 +0.009227 +0.009223 +0.009276 +0.009314 +0.00934 +0.009105 +0.00897 +0.008982 +0.009024 +0.009067 +0.009075 +0.008865 +0.00875 +0.008777 +0.008814 +0.008856 +0.008876 +0.008688 +0.008584 +0.0086 +0.008655 +0.00869 +0.008716 +0.008531 +0.008439 +0.008474 +0.008515 +0.008569 +0.008593 +0.008427 +0.008325 +0.008365 +0.008411 +0.008477 +0.008482 +0.00831 +0.008216 +0.00826 +0.008328 +0.008384 +0.008436 +0.00827 +0.00819 +0.008239 +0.00832 +0.008403 +0.008419 +0.008274 +0.008223 +0.008263 +0.008338 +0.008424 +0.008469 +0.008338 +0.008263 +0.008313 +0.008377 +0.008463 +0.008524 +0.008371 +0.008305 +0.008355 +0.008435 +0.008544 +0.008562 +0.008407 +0.008359 +0.008382 +0.008464 +0.008543 +0.008615 +0.008448 +0.008391 +0.008438 +0.008515 +0.008596 +0.008659 +0.008506 +0.008415 +0.008475 +0.008548 +0.008627 +0.00869 +0.008549 +0.008465 +0.008527 +0.00859 +0.008686 +0.008731 +0.008584 +0.008516 +0.008566 +0.008659 +0.008735 +0.008769 +0.008636 +0.008564 +0.0086 +0.008695 +0.008754 +0.00881 +0.008664 +0.008585 +0.008644 +0.008716 +0.008822 +0.008868 +0.008719 +0.008657 +0.0087 +0.008765 +0.008848 +0.008917 +0.00876 +0.008685 +0.008737 +0.008809 +0.008891 +0.008964 +0.008812 +0.008753 +0.008815 +0.008855 +0.008928 +0.008993 +0.008842 +0.008772 +0.008822 +0.008916 +0.008973 +0.009046 +0.008885 +0.008821 +0.008889 +0.008945 +0.009019 +0.009084 +0.008931 +0.008861 +0.00891 +0.008998 +0.009067 +0.009146 +0.009 +0.008913 +0.008959 +0.009044 +0.009118 +0.009198 +0.00904 +0.008935 +0.008994 +0.009076 +0.009158 +0.009234 +0.009078 +0.008985 +0.009041 +0.009138 +0.009191 +0.009277 +0.009126 +0.009035 +0.009104 +0.009189 +0.009258 +0.009318 +0.00916 +0.009086 +0.00914 +0.009215 +0.009308 +0.009364 +0.009216 +0.00915 +0.009202 +0.00931 +0.009336 +0.009425 +0.009233 +0.009165 +0.009229 +0.009301 +0.0094 +0.009481 +0.009318 +0.009234 +0.009279 +0.00937 +0.009428 +0.009497 +0.009351 +0.009255 +0.009324 +0.009423 +0.009492 +0.009565 +0.009397 +0.009314 +0.009362 +0.009442 +0.009549 +0.00962 +0.009465 +0.009353 +0.009427 +0.0095 +0.009606 +0.009651 +0.009481 +0.009399 +0.009462 +0.009526 +0.009626 +0.009717 +0.009549 +0.009464 +0.009533 +0.009613 +0.009681 +0.009742 +0.009586 +0.009494 +0.009553 +0.00965 +0.00973 +0.009811 +0.009659 +0.009575 +0.009648 +0.009693 +0.00976 +0.009831 +0.009671 +0.009596 +0.009674 +0.009721 +0.009845 +0.009911 +0.009738 +0.009663 +0.009702 +0.009768 +0.009882 +0.009956 +0.009768 +0.00969 +0.009755 +0.009844 +0.009938 +0.010002 +0.009825 +0.009742 +0.009804 +0.009911 +0.009993 +0.01004 +0.00988 +0.009789 +0.009847 +0.00993 +0.010038 +0.010113 +0.009914 +0.00983 +0.0099 +0.009999 +0.010105 +0.010172 +0.009975 +0.009876 +0.009941 +0.010037 +0.010153 +0.010192 +0.010021 +0.009954 +0.010011 +0.010108 +0.010232 +0.010253 +0.010053 +0.009961 +0.01004 +0.010141 +0.010229 +0.010305 +0.010149 +0.010046 +0.010147 +0.010195 +0.010261 +0.010333 +0.010173 +0.010075 +0.010147 +0.010253 +0.010336 +0.010398 +0.010204 +0.010111 +0.01015 +0.010227 +0.010298 +0.010351 +0.010094 +0.009968 +0.009998 +0.01005 +0.010069 +0.010084 +0.009875 +0.009752 +0.009757 +0.009818 +0.009848 +0.009869 +0.009631 +0.0095 +0.009519 +0.00956 +0.009587 +0.009601 +0.009392 +0.009274 +0.009284 +0.00931 +0.009342 +0.009348 +0.009131 +0.009017 +0.009037 +0.009091 +0.009116 +0.009109 +0.008932 +0.008795 +0.008819 +0.008861 +0.008881 +0.008898 +0.00872 +0.008602 +0.008638 +0.008687 +0.008738 +0.008746 +0.00857 +0.008477 +0.008504 +0.008554 +0.008604 +0.008631 +0.008449 +0.008358 +0.008394 +0.008466 +0.0085 +0.008515 +0.008359 +0.008273 +0.008333 +0.008378 +0.008419 +0.008446 +0.008299 +0.008231 +0.008295 +0.008352 +0.008425 +0.008472 +0.008315 +0.008257 +0.008305 +0.008368 +0.008452 +0.008515 +0.008378 +0.008297 +0.00834 +0.008417 +0.008501 +0.008564 +0.008411 +0.008336 +0.008388 +0.00846 +0.008541 +0.008619 +0.008465 +0.008396 +0.00845 +0.008499 +0.008581 +0.008644 +0.008498 +0.00842 +0.00847 +0.008552 +0.008637 +0.008695 +0.008537 +0.008471 +0.008521 +0.008581 +0.008665 +0.008722 +0.008582 +0.008508 +0.008557 +0.008632 +0.008724 +0.008783 +0.008632 +0.00856 +0.008612 +0.008677 +0.008749 +0.008816 +0.008674 +0.008617 +0.008642 +0.00871 +0.00879 +0.008869 +0.008723 +0.008644 +0.008697 +0.008768 +0.008851 +0.008909 +0.008733 +0.008672 +0.008733 +0.008803 +0.008894 +0.008956 +0.008795 +0.008723 +0.008781 +0.008856 +0.008925 +0.008997 +0.00885 +0.008768 +0.008835 +0.008909 +0.008998 +0.00906 +0.008893 +0.008825 +0.008848 +0.008928 +0.009021 +0.009078 +0.008929 +0.008865 +0.008925 +0.009001 +0.009079 +0.009123 +0.008973 +0.008894 +0.008949 +0.009034 +0.009114 +0.009172 +0.009029 +0.008946 +0.008995 +0.009081 +0.009171 +0.009216 +0.009071 +0.008992 +0.009049 +0.009162 +0.009218 +0.009263 +0.009098 +0.009045 +0.009084 +0.009159 +0.009252 +0.009308 +0.009165 +0.009085 +0.009141 +0.009235 +0.009315 +0.009349 +0.009197 +0.009117 +0.009174 +0.009263 +0.009354 +0.009401 +0.009267 +0.009187 +0.009238 +0.009314 +0.009395 +0.009446 +0.009317 +0.009208 +0.00926 +0.009344 +0.009448 +0.009506 +0.009358 +0.009256 +0.00931 +0.009396 +0.009476 +0.009548 +0.009396 +0.009303 +0.009377 +0.009472 +0.009548 +0.009595 +0.009438 +0.009352 +0.009406 +0.009488 +0.009596 +0.009637 +0.009478 +0.00943 +0.009487 +0.009581 +0.009635 +0.009671 +0.009519 +0.009439 +0.009503 +0.009592 +0.009697 +0.009755 +0.009569 +0.009486 +0.009551 +0.00963 +0.009734 +0.0098 +0.009631 +0.009547 +0.009615 +0.009717 +0.009791 +0.009839 +0.009683 +0.00959 +0.009643 +0.009735 +0.009836 +0.009937 +0.009718 +0.009645 +0.00971 +0.009793 +0.009864 +0.009934 +0.009768 +0.009689 +0.009743 +0.009823 +0.009953 +0.010005 +0.009833 +0.009756 +0.009801 +0.009876 +0.009983 +0.010037 +0.00986 +0.009794 +0.009855 +0.009931 +0.010027 +0.010091 +0.009959 +0.009834 +0.009905 +0.009977 +0.010067 +0.01016 +0.009974 +0.009879 +0.00995 +0.010028 +0.010122 +0.010207 +0.010012 +0.009927 +0.010017 +0.010095 +0.010203 +0.010267 +0.010051 +0.009982 +0.010048 +0.010133 +0.010225 +0.010296 +0.010123 +0.010069 +0.010092 +0.010171 +0.01028 +0.010376 +0.010157 +0.010078 +0.010142 +0.010259 +0.010329 +0.0104 +0.010221 +0.010123 +0.010197 +0.010281 +0.01036 +0.010441 +0.010253 +0.010134 +0.010154 +0.010193 +0.01025 +0.010266 +0.010064 +0.009954 +0.009967 +0.009993 +0.010055 +0.010036 +0.00983 +0.009684 +0.009705 +0.009716 +0.009754 +0.00977 +0.009552 +0.009423 +0.009449 +0.009482 +0.009523 +0.009519 +0.00932 +0.00918 +0.009181 +0.009216 +0.009255 +0.009275 +0.009087 +0.008953 +0.008975 +0.009015 +0.009068 +0.00905 +0.008861 +0.008751 +0.008777 +0.008819 +0.008863 +0.008894 +0.008719 +0.008631 +0.008609 +0.008655 +0.008716 +0.008736 +0.008573 +0.008473 +0.008502 +0.008542 +0.008612 +0.008646 +0.008466 +0.008372 +0.008387 +0.008441 +0.008481 +0.008533 +0.008375 +0.008295 +0.008339 +0.008393 +0.008461 +0.008501 +0.008355 +0.008285 +0.008334 +0.008388 +0.008466 +0.008519 +0.008393 +0.00832 +0.008363 +0.008431 +0.008514 +0.008569 +0.008429 +0.008365 +0.008412 +0.008477 +0.008563 +0.008627 +0.008473 +0.008402 +0.008453 +0.008542 +0.008611 +0.00865 +0.008517 +0.008441 +0.008522 +0.008575 +0.008636 +0.008698 +0.008592 +0.008475 +0.008544 +0.008608 +0.00869 +0.008742 +0.008588 +0.008521 +0.008574 +0.008657 +0.008735 +0.008789 +0.00864 +0.008586 +0.008629 +0.008707 +0.008793 +0.008832 +0.008671 +0.008607 +0.008664 +0.008741 +0.008813 +0.008889 +0.00874 +0.008671 +0.008708 +0.008775 +0.008851 +0.008922 +0.008769 +0.008703 +0.008747 +0.008822 +0.008931 +0.008974 +0.008824 +0.008742 +0.008786 +0.008867 +0.00895 +0.009021 +0.008867 +0.008783 +0.008848 +0.008911 +0.009003 +0.009058 +0.00891 +0.008828 +0.008881 +0.008963 +0.009051 +0.00913 +0.008958 +0.008882 +0.008927 +0.008994 +0.009086 +0.009151 +0.00899 +0.008934 +0.008987 +0.009034 +0.009132 +0.009203 +0.009054 +0.008971 +0.009029 +0.009091 +0.009173 +0.009249 +0.00909 +0.009013 +0.009049 +0.009132 +0.009249 +0.009298 +0.009139 +0.009068 +0.009128 +0.009219 +0.009256 +0.009315 +0.009165 +0.009089 +0.009168 +0.009221 +0.009317 +0.00939 +0.009217 +0.009152 +0.009191 +0.009275 +0.009369 +0.009425 +0.009291 +0.009196 +0.009256 +0.009326 +0.009412 +0.009477 +0.009312 +0.009239 +0.009286 +0.009367 +0.009482 +0.009551 +0.009391 +0.00928 +0.009339 +0.009402 +0.009503 +0.009566 +0.009401 +0.009322 +0.009383 +0.009453 +0.009557 +0.00963 +0.00947 +0.009369 +0.009426 +0.00952 +0.00961 +0.009678 +0.00952 +0.009426 +0.009463 +0.009568 +0.009644 +0.009714 +0.009553 +0.00947 +0.009558 +0.009612 +0.00969 +0.009765 +0.009629 +0.009515 +0.009563 +0.009659 +0.009743 +0.009811 +0.009644 +0.009556 +0.009613 +0.009707 +0.009832 +0.009878 +0.009697 +0.009623 +0.009669 +0.009745 +0.009852 +0.009905 +0.009736 +0.009682 +0.009728 +0.009817 +0.009913 +0.009975 +0.009811 +0.009705 +0.009749 +0.009839 +0.009985 +0.009991 +0.009825 +0.009757 +0.009807 +0.009906 +0.010003 +0.010061 +0.009897 +0.009808 +0.009889 +0.009963 +0.010038 +0.010113 +0.009928 +0.009849 +0.009925 +0.009993 +0.01011 +0.01017 +0.009987 +0.00992 +0.009985 +0.010076 +0.010178 +0.010198 +0.01002 +0.009971 +0.010007 +0.010088 +0.010209 +0.01028 +0.010085 +0.010014 +0.010061 +0.010169 +0.010255 +0.010308 +0.010139 +0.010041 +0.010114 +0.010232 +0.010323 +0.010385 +0.010201 +0.010094 +0.010156 +0.010259 +0.010395 +0.010414 +0.010233 +0.010151 +0.010212 +0.010313 +0.0104 +0.010437 +0.010266 +0.010153 +0.010197 +0.01027 +0.010327 +0.010312 +0.010112 +0.009978 +0.009995 +0.01005 +0.010092 +0.010089 +0.009878 +0.009743 +0.009787 +0.009826 +0.009851 +0.009884 +0.009625 +0.009485 +0.009507 +0.00954 +0.009584 +0.009592 +0.009383 +0.009257 +0.00926 +0.009301 +0.009337 +0.009355 +0.00914 +0.009025 +0.009046 +0.009058 +0.00912 +0.009139 +0.008921 +0.008803 +0.008826 +0.008866 +0.008897 +0.008917 +0.008741 +0.008639 +0.008696 +0.008727 +0.008749 +0.008759 +0.008592 +0.008487 +0.008522 +0.008559 +0.008608 +0.008643 +0.008473 +0.00839 +0.008411 +0.008465 +0.008514 +0.008542 +0.008386 +0.00831 +0.008336 +0.008398 +0.008461 +0.008505 +0.008372 +0.008296 +0.008345 +0.008397 +0.008471 +0.008543 +0.008401 +0.008334 +0.008392 +0.00843 +0.008521 +0.008627 +0.008425 +0.00837 +0.008411 +0.008476 +0.008559 +0.008622 +0.008467 +0.008393 +0.008448 +0.008537 +0.008612 +0.008663 +0.008533 +0.008456 +0.008507 +0.008583 +0.008651 +0.008717 +0.00856 +0.008485 +0.008546 +0.008608 +0.008684 +0.008761 +0.008622 +0.008564 +0.008587 +0.008661 +0.008735 +0.008777 +0.008661 +0.008569 +0.008615 +0.008692 +0.0088 +0.008826 +0.008687 +0.008615 +0.008674 +0.008743 +0.008823 +0.008884 +0.008736 +0.008659 +0.008706 +0.008802 +0.008875 +0.008922 +0.008783 +0.008701 +0.008751 +0.008835 +0.008915 +0.008991 +0.008834 +0.008737 +0.008792 +0.008877 +0.008967 +0.009031 +0.008852 +0.008786 +0.008843 +0.008913 +0.008992 +0.009051 +0.008917 +0.008837 +0.008893 +0.008983 +0.009056 +0.00914 +0.008937 +0.008873 +0.008931 +0.008996 +0.009096 +0.009148 +0.008991 +0.008921 +0.008976 +0.009078 +0.009155 +0.009191 +0.009029 +0.008959 +0.00902 +0.009104 +0.00919 +0.00926 +0.009099 +0.009033 +0.00905 +0.009135 +0.009231 +0.009286 +0.009127 +0.009058 +0.00911 +0.009211 +0.0093 +0.009353 +0.009173 +0.009095 +0.009154 +0.009233 +0.009317 +0.009392 +0.009231 +0.009184 +0.009215 +0.009307 +0.009371 +0.009432 +0.009258 +0.009176 +0.009241 +0.009325 +0.00942 +0.009478 +0.009317 +0.009238 +0.009301 +0.00938 +0.009474 +0.009523 +0.00936 +0.00929 +0.009329 +0.009425 +0.009521 +0.009591 +0.009405 +0.009337 +0.009402 +0.009497 +0.009587 +0.009606 +0.009442 +0.009372 +0.009437 +0.009537 +0.009624 +0.009685 +0.0095 +0.009421 +0.009478 +0.00957 +0.009659 +0.009733 +0.00956 +0.009478 +0.009537 +0.009623 +0.009718 +0.009756 +0.009596 +0.009519 +0.009576 +0.009658 +0.009762 +0.009838 +0.009685 +0.009572 +0.009634 +0.009712 +0.009808 +0.009846 +0.009694 +0.009607 +0.009677 +0.009771 +0.00985 +0.009916 +0.009735 +0.00966 +0.009739 +0.00982 +0.009895 +0.009978 +0.009789 +0.009715 +0.009786 +0.009859 +0.00995 +0.010022 +0.009852 +0.009791 +0.009814 +0.009896 +0.010001 +0.010069 +0.009919 +0.009835 +0.009859 +0.009959 +0.01005 +0.01011 +0.009945 +0.009859 +0.00991 +0.010013 +0.010104 +0.010192 +0.010044 +0.009899 +0.00995 +0.010054 +0.010156 +0.010223 +0.010045 +0.009961 +0.010068 +0.010126 +0.010207 +0.010266 +0.010078 +0.010002 +0.010063 +0.010155 +0.010268 +0.010337 +0.010155 +0.010075 +0.010115 +0.010221 +0.010331 +0.010353 +0.010187 +0.010113 +0.010167 +0.01026 +0.010364 +0.010417 +0.010251 +0.010167 +0.010244 +0.010334 +0.010407 +0.010472 +0.010285 +0.010205 +0.010264 +0.010313 +0.010407 +0.010433 +0.010203 +0.010075 +0.010145 +0.010175 +0.010225 +0.010248 +0.01003 +0.009887 +0.009919 +0.009934 +0.009982 +0.010003 +0.009759 +0.009631 +0.009655 +0.009702 +0.009794 +0.009753 +0.009522 +0.009386 +0.009402 +0.009446 +0.009483 +0.009482 +0.009278 +0.009155 +0.009164 +0.009209 +0.009267 +0.009252 +0.009076 +0.008944 +0.008959 +0.009006 +0.009052 +0.009077 +0.008886 +0.00877 +0.008793 +0.008832 +0.008889 +0.008906 +0.008724 +0.008635 +0.008663 +0.008693 +0.008755 +0.008787 +0.008602 +0.008514 +0.008553 +0.008575 +0.00864 +0.00867 +0.008496 +0.008407 +0.008462 +0.008506 +0.008574 +0.008613 +0.008461 +0.008382 +0.008421 +0.008497 +0.008573 +0.008635 +0.008483 +0.008423 +0.008459 +0.008539 +0.008607 +0.008679 +0.008543 +0.008471 +0.008495 +0.008568 +0.00865 +0.008718 +0.008574 +0.008507 +0.008551 +0.008626 +0.008734 +0.008739 +0.008607 +0.008537 +0.008591 +0.008674 +0.008731 +0.008803 +0.008661 +0.008588 +0.008655 +0.008712 +0.008786 +0.008843 +0.008694 +0.008625 +0.008669 +0.008745 +0.008839 +0.008904 +0.008762 +0.008674 +0.008719 +0.008806 +0.008877 +0.008945 +0.008776 +0.008702 +0.008758 +0.008831 +0.008915 +0.00901 +0.008824 +0.008744 +0.008797 +0.008879 +0.008966 +0.009024 +0.008869 +0.008807 +0.008843 +0.008931 +0.009026 +0.009087 +0.008916 +0.008838 +0.008897 +0.008981 +0.009083 +0.009107 +0.008948 +0.008881 +0.008942 +0.009034 +0.009116 +0.009163 +0.009009 +0.008917 +0.008974 +0.009054 +0.009156 +0.009225 +0.00904 +0.008967 +0.009017 +0.009106 +0.009198 +0.009266 +0.009096 +0.00902 +0.009082 +0.009147 +0.00924 +0.009315 +0.009155 +0.009086 +0.009124 +0.009192 +0.009285 +0.009345 +0.009197 +0.009125 +0.009155 +0.009245 +0.009343 +0.009399 +0.009229 +0.009163 +0.009201 +0.009295 +0.009393 +0.009441 +0.009275 +0.009208 +0.009263 +0.00934 +0.009443 +0.009499 +0.009313 +0.009241 +0.009311 +0.009397 +0.009506 +0.009541 +0.009363 +0.00928 +0.009337 +0.009436 +0.009523 +0.009595 +0.009432 +0.009342 +0.009401 +0.009475 +0.009577 +0.009631 +0.009458 +0.009383 +0.009439 +0.009529 +0.009622 +0.009685 +0.009524 +0.009444 +0.009507 +0.00958 +0.009676 +0.009723 +0.009578 +0.009493 +0.009538 +0.009619 +0.00971 +0.009774 +0.009622 +0.009545 +0.009592 +0.009683 +0.00978 +0.009803 +0.009646 +0.009566 +0.009635 +0.009731 +0.009806 +0.009879 +0.009715 +0.009626 +0.009676 +0.009765 +0.009865 +0.009928 +0.009759 +0.009688 +0.009786 +0.009822 +0.009936 +0.009954 +0.00979 +0.009718 +0.009762 +0.009859 +0.009975 +0.010024 +0.009857 +0.009801 +0.009836 +0.009906 +0.010009 +0.010074 +0.009895 +0.009809 +0.009881 +0.009966 +0.010087 +0.010154 +0.009959 +0.00986 +0.009929 +0.010036 +0.010135 +0.010166 +0.009993 +0.009927 +0.009979 +0.010067 +0.010172 +0.010243 +0.01004 +0.009963 +0.010036 +0.010107 +0.010223 +0.010278 +0.010118 +0.010028 +0.010082 +0.010179 +0.010275 +0.010314 +0.010151 +0.010063 +0.010122 +0.010226 +0.010369 +0.010379 +0.010192 +0.01011 +0.010171 +0.010273 +0.010392 +0.010425 +0.010262 +0.010179 +0.010239 +0.010324 +0.010411 +0.010484 +0.010306 +0.010211 +0.010266 +0.010384 +0.010509 +0.010554 +0.010375 +0.010262 +0.010317 +0.010413 +0.010538 +0.010562 +0.010344 +0.010234 +0.010248 +0.010298 +0.010378 +0.010402 +0.010205 +0.010025 +0.010061 +0.010089 +0.010151 +0.010151 +0.009912 +0.009784 +0.009779 +0.009822 +0.009866 +0.009879 +0.009648 +0.009527 +0.009526 +0.009574 +0.009616 +0.009638 +0.009434 +0.009276 +0.009279 +0.009311 +0.009351 +0.00938 +0.009175 +0.009072 +0.009085 +0.009122 +0.009158 +0.009179 +0.008985 +0.008864 +0.008889 +0.008929 +0.008981 +0.009005 +0.008831 +0.008732 +0.008758 +0.008786 +0.008844 +0.008884 +0.008707 +0.008593 +0.008636 +0.008673 +0.008763 +0.008771 +0.008602 +0.008482 +0.008513 +0.008568 +0.008626 +0.008668 +0.008511 +0.008426 +0.00846 +0.00853 +0.008613 +0.008665 +0.008507 +0.008434 +0.008464 +0.008544 +0.008624 +0.008686 +0.008546 +0.008466 +0.008516 +0.008589 +0.008688 +0.008741 +0.008591 +0.008531 +0.008569 +0.008651 +0.008725 +0.008756 +0.008615 +0.008548 +0.008623 +0.00867 +0.008752 +0.008815 +0.008678 +0.008604 +0.008657 +0.008718 +0.008805 +0.008853 +0.008728 +0.008645 +0.008697 +0.008762 +0.008843 +0.008911 +0.008755 +0.008681 +0.008737 +0.008809 +0.00889 +0.008957 +0.008811 +0.008743 +0.008814 +0.008856 +0.008944 +0.008986 +0.008836 +0.00877 +0.008815 +0.008905 +0.008975 +0.009044 +0.008881 +0.008819 +0.008877 +0.008949 +0.009038 +0.009095 +0.00893 +0.008854 +0.008903 +0.008993 +0.009066 +0.009132 +0.00898 +0.008915 +0.008963 +0.009043 +0.009132 +0.009202 +0.009026 +0.008929 +0.008985 +0.009067 +0.009164 +0.009225 +0.009066 +0.009002 +0.009054 +0.00913 +0.009216 +0.009282 +0.009099 +0.009022 +0.009085 +0.00917 +0.009253 +0.009329 +0.009173 +0.009084 +0.009125 +0.009208 +0.009299 +0.009358 +0.009209 +0.009123 +0.009186 +0.009307 +0.00939 +0.009403 +0.009247 +0.009161 +0.009218 +0.009294 +0.009389 +0.009453 +0.009302 +0.009205 +0.009283 +0.009377 +0.009452 +0.009517 +0.009357 +0.00925 +0.009309 +0.009393 +0.009488 +0.009554 +0.009386 +0.009331 +0.009356 +0.00945 +0.009547 +0.009617 +0.009463 +0.009344 +0.009396 +0.009515 +0.009575 +0.009663 +0.009484 +0.009395 +0.009465 +0.009534 +0.009637 +0.009705 +0.009541 +0.009437 +0.009501 +0.009589 +0.00969 +0.00976 +0.00958 +0.009485 +0.009552 +0.009645 +0.00974 +0.009787 +0.009629 +0.009556 +0.009645 +0.009694 +0.00978 +0.009842 +0.009651 +0.009613 +0.009637 +0.009725 +0.009831 +0.009885 +0.009722 +0.009661 +0.009708 +0.009792 +0.009903 +0.009938 +0.009756 +0.009681 +0.009737 +0.009828 +0.009924 +0.009998 +0.009818 +0.00974 +0.0098 +0.009916 +0.009991 +0.010029 +0.009863 +0.009779 +0.009855 +0.009942 +0.010014 +0.010096 +0.009914 +0.009832 +0.009909 +0.009974 +0.010078 +0.010146 +0.009972 +0.009898 +0.009971 +0.010024 +0.010116 +0.010179 +0.010037 +0.009927 +0.009983 +0.010091 +0.010222 +0.010279 +0.010069 +0.00997 +0.01002 +0.010133 +0.010226 +0.010291 +0.010122 +0.010016 +0.010094 +0.010208 +0.010298 +0.010348 +0.010174 +0.010068 +0.010139 +0.010238 +0.010349 +0.01039 +0.010218 +0.010154 +0.010205 +0.010295 +0.010402 +0.010473 +0.010251 +0.010195 +0.010221 +0.010327 +0.010425 +0.010509 +0.01033 +0.010246 +0.0103 +0.010404 +0.010473 +0.010541 +0.010364 +0.010279 +0.010358 +0.010431 +0.010544 +0.010597 +0.01042 +0.010319 +0.010364 +0.010456 +0.010534 +0.010608 +0.010338 +0.010184 +0.010204 +0.010294 +0.010325 +0.010335 +0.010109 +0.009973 +0.010021 +0.010066 +0.010102 +0.010091 +0.009852 +0.009726 +0.009736 +0.009784 +0.009839 +0.009828 +0.00961 +0.009492 +0.009514 +0.009549 +0.009586 +0.009587 +0.009379 +0.009237 +0.009247 +0.009295 +0.009332 +0.009348 +0.009139 +0.009044 +0.009044 +0.009099 +0.00914 +0.009161 +0.008973 +0.00885 +0.008883 +0.008936 +0.009006 +0.00901 +0.008808 +0.00872 +0.00874 +0.008804 +0.008841 +0.008877 +0.008697 +0.008594 +0.008637 +0.008692 +0.008781 +0.008783 +0.00859 +0.008492 +0.008539 +0.008604 +0.008669 +0.008712 +0.008536 +0.008469 +0.00851 +0.008602 +0.008686 +0.008728 +0.008573 +0.008493 +0.008543 +0.00862 +0.008701 +0.008764 +0.008628 +0.00853 +0.008603 +0.008677 +0.008767 +0.008811 +0.008668 +0.008585 +0.00863 +0.008735 +0.008813 +0.008851 +0.008688 +0.008624 +0.008673 +0.008749 +0.008848 +0.008887 +0.008745 +0.008673 +0.008713 +0.008801 +0.008885 +0.008933 +0.00879 +0.00873 +0.008758 +0.008843 +0.008921 +0.008991 +0.008838 +0.008758 +0.008806 +0.008876 +0.00897 +0.009033 +0.008882 +0.008827 +0.008878 +0.008937 +0.009006 +0.009086 +0.00891 +0.008843 +0.008892 +0.008966 +0.009059 +0.009116 +0.008977 +0.008908 +0.008952 +0.009034 +0.009097 +0.009162 +0.009001 +0.008924 +0.008983 +0.009067 +0.009137 +0.009207 +0.009065 +0.008985 +0.009033 +0.00911 +0.009202 +0.009286 +0.009102 +0.009016 +0.009066 +0.009167 +0.009247 +0.009317 +0.009133 +0.009057 +0.009123 +0.009194 +0.009289 +0.009362 +0.009182 +0.009125 +0.009178 +0.009255 +0.009332 +0.009383 +0.009243 +0.009149 +0.009209 +0.009292 +0.009376 +0.009441 +0.009293 +0.009203 +0.009286 +0.009337 +0.009424 +0.009473 +0.009325 +0.009256 +0.0093 +0.0094 +0.009495 +0.009529 +0.00937 +0.009299 +0.009346 +0.009426 +0.009514 +0.009594 +0.00942 +0.009379 +0.009416 +0.009497 +0.009564 +0.009621 +0.009465 +0.009377 +0.009433 +0.009532 +0.009627 +0.009717 +0.009513 +0.00944 +0.009499 +0.009582 +0.00966 +0.009719 +0.009555 +0.009485 +0.009529 +0.009619 +0.009739 +0.00979 +0.009623 +0.009543 +0.009594 +0.009661 +0.009765 +0.009838 +0.009656 +0.009567 +0.009627 +0.009718 +0.009828 +0.009895 +0.009735 +0.009656 +0.009679 +0.00977 +0.009846 +0.009918 +0.009748 +0.009678 +0.00972 +0.009816 +0.009909 +0.009985 +0.009809 +0.009713 +0.009779 +0.009874 +0.009964 +0.010035 +0.009874 +0.00977 +0.009824 +0.009925 +0.010006 +0.010076 +0.009901 +0.009826 +0.009919 +0.009967 +0.010072 +0.010133 +0.009967 +0.009858 +0.009916 +0.010013 +0.010118 +0.010167 +0.010011 +0.009924 +0.009973 +0.010089 +0.010188 +0.010214 +0.010047 +0.009976 +0.010021 +0.010115 +0.010222 +0.01028 +0.010115 +0.010034 +0.010102 +0.010216 +0.010246 +0.010325 +0.010144 +0.010067 +0.010123 +0.010226 +0.010321 +0.010403 +0.010213 +0.010138 +0.01018 +0.010254 +0.010368 +0.010438 +0.010254 +0.010164 +0.010227 +0.010321 +0.010426 +0.010501 +0.010306 +0.010214 +0.010294 +0.010415 +0.010473 +0.010552 +0.010351 +0.010261 +0.010336 +0.010425 +0.010528 +0.010598 +0.01039 +0.01031 +0.010381 +0.010447 +0.010522 +0.010523 +0.010299 +0.010169 +0.010225 +0.010257 +0.010293 +0.010325 +0.010091 +0.009935 +0.00997 +0.010022 +0.010063 +0.010037 +0.009784 +0.009661 +0.009693 +0.009713 +0.009783 +0.009788 +0.009556 +0.00942 +0.00944 +0.009455 +0.009494 +0.009499 +0.009293 +0.009155 +0.009189 +0.009216 +0.009259 +0.009271 +0.009054 +0.008944 +0.008954 +0.009001 +0.009059 +0.009076 +0.008901 +0.008761 +0.008801 +0.008847 +0.008897 +0.008916 +0.008726 +0.008628 +0.008661 +0.008723 +0.008762 +0.008795 +0.008634 +0.008534 +0.008572 +0.008616 +0.008669 +0.008686 +0.00852 +0.00843 +0.008476 +0.008529 +0.008596 +0.008644 +0.008493 +0.0084 +0.008449 +0.008532 +0.008611 +0.008667 +0.008493 +0.008435 +0.00847 +0.008547 +0.008636 +0.008718 +0.00854 +0.00847 +0.008529 +0.008593 +0.008675 +0.008746 +0.00859 +0.008512 +0.008565 +0.008656 +0.008737 +0.008794 +0.008624 +0.00856 +0.008607 +0.008681 +0.008767 +0.008829 +0.00869 +0.008603 +0.008668 +0.008743 +0.008843 +0.008867 +0.008718 +0.008625 +0.00869 +0.008768 +0.008844 +0.008912 +0.008781 +0.008686 +0.008735 +0.008812 +0.008908 +0.008957 +0.008807 +0.008728 +0.008794 +0.008861 +0.008945 +0.009013 +0.008862 +0.008774 +0.008824 +0.008906 +0.008984 +0.009044 +0.008891 +0.008822 +0.008913 +0.008952 +0.00903 +0.00909 +0.008952 +0.00887 +0.00891 +0.008987 +0.009074 +0.009147 +0.008978 +0.008906 +0.00897 +0.009038 +0.009133 +0.009207 +0.009049 +0.00896 +0.008992 +0.009084 +0.009178 +0.009225 +0.009074 +0.009001 +0.009053 +0.009128 +0.009238 +0.009303 +0.009153 +0.009041 +0.009101 +0.009157 +0.009251 +0.009322 +0.009159 +0.009081 +0.009149 +0.009234 +0.009322 +0.009392 +0.00922 +0.009127 +0.009175 +0.009268 +0.009352 +0.009413 +0.009265 +0.009175 +0.009239 +0.009332 +0.009421 +0.00947 +0.009306 +0.009227 +0.009286 +0.009393 +0.009444 +0.009492 +0.009354 +0.009303 +0.009314 +0.009399 +0.009491 +0.009565 +0.009396 +0.009316 +0.009385 +0.009454 +0.009556 +0.009624 +0.009459 +0.009357 +0.009411 +0.009511 +0.009591 +0.009657 +0.009499 +0.009404 +0.009464 +0.009549 +0.009668 +0.009754 +0.009547 +0.009447 +0.009515 +0.009595 +0.009694 +0.009756 +0.00959 +0.009503 +0.009563 +0.009656 +0.009759 +0.009805 +0.009632 +0.009543 +0.009622 +0.009697 +0.009776 +0.009856 +0.00967 +0.009615 +0.009674 +0.009751 +0.00985 +0.009897 +0.009734 +0.009681 +0.009702 +0.009783 +0.009885 +0.009948 +0.009781 +0.0097 +0.009752 +0.009849 +0.009937 +0.009999 +0.009841 +0.00975 +0.009821 +0.009917 +0.009998 +0.010043 +0.009887 +0.009792 +0.009853 +0.009936 +0.010037 +0.010116 +0.009947 +0.009868 +0.009949 +0.010014 +0.010104 +0.010123 +0.009965 +0.009893 +0.009936 +0.010032 +0.010154 +0.010213 +0.010033 +0.009961 +0.01 +0.010094 +0.010201 +0.010269 +0.010094 +0.010007 +0.010045 +0.010148 +0.010249 +0.010312 +0.010132 +0.010041 +0.010113 +0.010235 +0.010308 +0.010369 +0.010203 +0.01008 +0.010151 +0.01024 +0.010346 +0.010416 +0.010235 +0.01017 +0.010233 +0.010317 +0.010407 +0.010452 +0.010274 +0.010188 +0.010261 +0.010352 +0.010438 +0.010496 +0.010304 +0.010196 +0.010243 +0.010313 +0.010344 +0.010335 +0.010135 +0.010003 +0.010063 +0.010067 +0.010102 +0.010095 +0.009886 +0.009749 +0.009769 +0.009796 +0.00983 +0.009836 +0.009633 +0.009495 +0.009493 +0.009528 +0.009562 +0.009574 +0.009369 +0.009256 +0.009254 +0.009302 +0.009345 +0.009357 +0.009183 +0.00903 +0.00903 +0.009065 +0.009102 +0.00913 +0.00893 +0.008846 +0.00884 +0.008885 +0.008924 +0.008955 +0.008783 +0.008671 +0.008698 +0.008745 +0.008794 +0.008829 +0.008649 +0.008566 +0.008579 +0.008614 +0.008663 +0.008702 +0.008527 +0.008438 +0.008469 +0.00852 +0.008595 +0.008624 +0.008459 +0.00837 +0.00841 +0.00846 +0.008534 +0.008575 +0.008438 +0.008373 +0.008424 +0.008487 +0.008574 +0.008643 +0.00849 +0.008419 +0.00846 +0.008544 +0.008595 +0.00866 +0.008521 +0.008464 +0.008503 +0.008572 +0.008661 +0.008702 +0.008559 +0.008487 +0.008551 +0.008629 +0.008711 +0.008766 +0.008594 +0.008545 +0.008578 +0.008663 +0.008743 +0.008809 +0.008659 +0.00859 +0.008637 +0.0087 +0.008786 +0.008839 +0.008688 +0.008617 +0.008675 +0.008736 +0.008828 +0.00889 +0.00874 +0.008667 +0.008723 +0.008787 +0.008881 +0.008933 +0.008781 +0.008718 +0.008798 +0.008844 +0.008914 +0.008963 +0.008845 +0.008744 +0.008798 +0.008867 +0.008958 +0.009031 +0.008873 +0.0088 +0.008856 +0.008935 +0.009003 +0.009065 +0.008915 +0.008835 +0.008886 +0.008965 +0.009056 +0.009113 +0.008967 +0.008903 +0.008947 +0.009018 +0.009091 +0.009161 +0.009023 +0.008936 +0.008967 +0.009046 +0.009138 +0.009206 +0.009056 +0.008983 +0.009029 +0.009131 +0.009176 +0.009256 +0.009092 +0.009016 +0.009065 +0.009143 +0.009263 +0.009305 +0.009147 +0.009076 +0.009118 +0.009201 +0.009275 +0.009339 +0.009181 +0.0091 +0.009166 +0.009258 +0.009348 +0.009398 +0.009234 +0.009159 +0.009215 +0.009299 +0.009361 +0.00943 +0.009283 +0.009192 +0.009254 +0.009346 +0.009416 +0.009481 +0.009324 +0.009251 +0.009301 +0.009404 +0.009475 +0.009526 +0.009367 +0.00929 +0.009349 +0.009425 +0.009523 +0.009592 +0.009451 +0.00936 +0.009384 +0.009457 +0.009552 +0.009641 +0.009478 +0.009398 +0.009456 +0.009536 +0.009617 +0.009665 +0.009513 +0.009424 +0.009485 +0.009576 +0.009673 +0.009739 +0.009577 +0.009489 +0.009544 +0.009603 +0.009714 +0.009768 +0.009605 +0.009535 +0.009606 +0.00969 +0.009779 +0.00985 +0.009652 +0.009579 +0.009621 +0.009701 +0.00981 +0.009878 +0.009707 +0.009626 +0.009687 +0.009759 +0.009863 +0.009932 +0.009752 +0.009666 +0.009732 +0.009817 +0.009912 +0.00999 +0.009812 +0.009716 +0.009781 +0.009871 +0.010006 +0.010022 +0.009846 +0.009752 +0.009817 +0.009921 +0.010027 +0.0101 +0.009922 +0.009832 +0.009869 +0.009957 +0.010061 +0.010135 +0.009972 +0.009854 +0.009915 +0.01001 +0.010112 +0.010179 +0.010004 +0.009913 +0.009978 +0.010064 +0.010175 +0.010283 +0.010047 +0.009954 +0.010017 +0.010108 +0.010223 +0.010276 +0.0101 +0.010024 +0.010096 +0.010183 +0.010285 +0.010304 +0.010144 +0.010068 +0.010156 +0.010209 +0.01031 +0.010389 +0.010208 +0.010132 +0.010179 +0.010268 +0.010362 +0.010449 +0.010272 +0.010152 +0.010209 +0.010298 +0.010428 +0.010502 +0.010322 +0.010227 +0.010302 +0.010322 +0.010428 +0.010463 +0.010255 +0.010133 +0.010159 +0.010209 +0.010274 +0.010274 +0.010043 +0.009915 +0.009935 +0.009964 +0.010019 +0.010032 +0.009822 +0.009696 +0.009701 +0.009747 +0.00974 +0.009749 +0.009549 +0.009413 +0.009424 +0.009454 +0.009517 +0.009564 +0.009311 +0.009187 +0.009207 +0.009221 +0.009272 +0.00929 +0.009093 +0.008973 +0.008982 +0.009028 +0.009071 +0.009097 +0.008911 +0.008795 +0.008814 +0.008854 +0.008927 +0.008954 +0.008781 +0.008649 +0.008683 +0.008724 +0.008776 +0.008803 +0.008628 +0.008523 +0.008554 +0.0086 +0.008653 +0.008707 +0.008516 +0.008416 +0.008453 +0.008514 +0.008584 +0.008614 +0.008442 +0.008359 +0.008408 +0.008472 +0.008544 +0.008605 +0.008461 +0.008372 +0.008438 +0.008521 +0.008599 +0.00868 +0.008497 +0.008424 +0.00848 +0.008545 +0.008619 +0.008681 +0.00854 +0.008459 +0.008534 +0.008592 +0.008677 +0.008736 +0.008589 +0.008514 +0.00855 +0.008627 +0.008714 +0.008786 +0.008621 +0.008557 +0.008591 +0.008685 +0.008769 +0.008842 +0.008677 +0.0086 +0.008646 +0.008716 +0.008825 +0.00885 +0.00871 +0.008631 +0.008684 +0.008769 +0.008863 +0.008898 +0.008753 +0.008682 +0.008721 +0.0088 +0.008894 +0.008957 +0.008801 +0.008727 +0.0088 +0.008843 +0.008937 +0.009 +0.008846 +0.00877 +0.008816 +0.008896 +0.00898 +0.009044 +0.008904 +0.00883 +0.008903 +0.008944 +0.00902 +0.009071 +0.008921 +0.008855 +0.008911 +0.00898 +0.009097 +0.009132 +0.008972 +0.00891 +0.008961 +0.009034 +0.009104 +0.009174 +0.009027 +0.008939 +0.009002 +0.009074 +0.009162 +0.009234 +0.009079 +0.009003 +0.009044 +0.009115 +0.009201 +0.009277 +0.009139 +0.00903 +0.009085 +0.009161 +0.009248 +0.009322 +0.009155 +0.00908 +0.009154 +0.009217 +0.009308 +0.009351 +0.009204 +0.009118 +0.009175 +0.009258 +0.009345 +0.009414 +0.00925 +0.00917 +0.009225 +0.009296 +0.00941 +0.009457 +0.009298 +0.009234 +0.009292 +0.009378 +0.009442 +0.009507 +0.009334 +0.009253 +0.009319 +0.009393 +0.009488 +0.009565 +0.009382 +0.009321 +0.009379 +0.009447 +0.009529 +0.009595 +0.009441 +0.009351 +0.009405 +0.009503 +0.009584 +0.009665 +0.009504 +0.00941 +0.009448 +0.009534 +0.009637 +0.009723 +0.009537 +0.009444 +0.009495 +0.009597 +0.009699 +0.009725 +0.009582 +0.009517 +0.00956 +0.009627 +0.00972 +0.009797 +0.009617 +0.009545 +0.0096 +0.009682 +0.009801 +0.009861 +0.009677 +0.009593 +0.009638 +0.009729 +0.009828 +0.009889 +0.009722 +0.009666 +0.009694 +0.009791 +0.009887 +0.009945 +0.00978 +0.009693 +0.009732 +0.009828 +0.009917 +0.009983 +0.009818 +0.009733 +0.00979 +0.009878 +0.009983 +0.010042 +0.009862 +0.009792 +0.009839 +0.009929 +0.010046 +0.010096 +0.009915 +0.009837 +0.009908 +0.009998 +0.010071 +0.010133 +0.009962 +0.009883 +0.009935 +0.010027 +0.010148 +0.010206 +0.010004 +0.009927 +0.009986 +0.010078 +0.010183 +0.010245 +0.010067 +0.009986 +0.010064 +0.010144 +0.010222 +0.010295 +0.010114 +0.010026 +0.010099 +0.010211 +0.010318 +0.01033 +0.010153 +0.010091 +0.010156 +0.010215 +0.010331 +0.010405 +0.010205 +0.010126 +0.010191 +0.010279 +0.01041 +0.010476 +0.010274 +0.010178 +0.010242 +0.010336 +0.010433 +0.010503 +0.010311 +0.010226 +0.010315 +0.010417 +0.01051 +0.010512 +0.010322 +0.010188 +0.01022 +0.010263 +0.010323 +0.010343 +0.010121 +0.010004 +0.010002 +0.010061 +0.010104 +0.010106 +0.009893 +0.00975 +0.009773 +0.009813 +0.009874 +0.00989 +0.009668 +0.009524 +0.009535 +0.009576 +0.009626 +0.009662 +0.009447 +0.009305 +0.009332 +0.009376 +0.009452 +0.009432 +0.009224 +0.009112 +0.009138 +0.009167 +0.009216 +0.009248 +0.009051 +0.008937 +0.008962 +0.008999 +0.009039 +0.009071 +0.008889 +0.008773 +0.008803 +0.008843 +0.008899 +0.008943 +0.008755 +0.00864 +0.008668 +0.008738 +0.008769 +0.008788 +0.008624 +0.008525 +0.008563 +0.008618 +0.008696 +0.00872 +0.008576 +0.008471 +0.008508 +0.008573 +0.008658 +0.008705 +0.00857 +0.008499 +0.008547 +0.008621 +0.008705 +0.008776 +0.00861 +0.008541 +0.008578 +0.008659 +0.008738 +0.008799 +0.008657 +0.008588 +0.008649 +0.008712 +0.008771 +0.008848 +0.0087 +0.00863 +0.008675 +0.008731 +0.008824 +0.008906 +0.008733 +0.00866 +0.008715 +0.00879 +0.008907 +0.008931 +0.008791 +0.008708 +0.00876 +0.008823 +0.008917 +0.008966 +0.008819 +0.008756 +0.008798 +0.008872 +0.008975 +0.00904 +0.008904 +0.008809 +0.008861 +0.008908 +0.008989 +0.009055 +0.008909 +0.008831 +0.0089 +0.008973 +0.009047 +0.009109 +0.008953 +0.008886 +0.008926 +0.009004 +0.009103 +0.009155 +0.009005 +0.008924 +0.008988 +0.009065 +0.009144 +0.009209 +0.009053 +0.008968 +0.009023 +0.009107 +0.009219 +0.009253 +0.009086 +0.009025 +0.009096 +0.009152 +0.009226 +0.009297 +0.009127 +0.009056 +0.009109 +0.009184 +0.009292 +0.009345 +0.009182 +0.009124 +0.009168 +0.009231 +0.009321 +0.009392 +0.009227 +0.009147 +0.009212 +0.009287 +0.009373 +0.009456 +0.009288 +0.009232 +0.009266 +0.009327 +0.009398 +0.009467 +0.009322 +0.009261 +0.009292 +0.009372 +0.009468 +0.009542 +0.009367 +0.009289 +0.009345 +0.009431 +0.009512 +0.009576 +0.009411 +0.009337 +0.009392 +0.009462 +0.009577 +0.009652 +0.009469 +0.009385 +0.009459 +0.009538 +0.009636 +0.009659 +0.009493 +0.00942 +0.009483 +0.009564 +0.009659 +0.009746 +0.00956 +0.009466 +0.009529 +0.009624 +0.009718 +0.009771 +0.009606 +0.009527 +0.009579 +0.009664 +0.009766 +0.009818 +0.009654 +0.009586 +0.009616 +0.009714 +0.009812 +0.009899 +0.009757 +0.009616 +0.009661 +0.009751 +0.009851 +0.009919 +0.00975 +0.009665 +0.009722 +0.009841 +0.009907 +0.009986 +0.009796 +0.009714 +0.009772 +0.00986 +0.009951 +0.01002 +0.009837 +0.009751 +0.009847 +0.009933 +0.010019 +0.010079 +0.009906 +0.009831 +0.009869 +0.009963 +0.01004 +0.010113 +0.009939 +0.009851 +0.009926 +0.010013 +0.010101 +0.010167 +0.010011 +0.009902 +0.009959 +0.010064 +0.010171 +0.01022 +0.010053 +0.00997 +0.010013 +0.010121 +0.010208 +0.010272 +0.010095 +0.010019 +0.010129 +0.010174 +0.010243 +0.010307 +0.010137 +0.010057 +0.010117 +0.010196 +0.010322 +0.010374 +0.010211 +0.010135 +0.010166 +0.010287 +0.010359 +0.010416 +0.010242 +0.010163 +0.010213 +0.010315 +0.01043 +0.010513 +0.010313 +0.010226 +0.010283 +0.010379 +0.010447 +0.010515 +0.010342 +0.010261 +0.01034 +0.010429 +0.010516 +0.01055 +0.010337 +0.010229 +0.010247 +0.010288 +0.010354 +0.010422 +0.010154 +0.010054 +0.010061 +0.010089 +0.010137 +0.01013 +0.009902 +0.00979 +0.009806 +0.009868 +0.009894 +0.009876 +0.009663 +0.00954 +0.009558 +0.009583 +0.009628 +0.009661 +0.009426 +0.0093 +0.009332 +0.00935 +0.009381 +0.009388 +0.009201 +0.009075 +0.009086 +0.009135 +0.009166 +0.009186 +0.009016 +0.0089 +0.008913 +0.008944 +0.008998 +0.009012 +0.008848 +0.008739 +0.008731 +0.008784 +0.008834 +0.008868 +0.008687 +0.008597 +0.008615 +0.008666 +0.008711 +0.008749 +0.008585 +0.008485 +0.008517 +0.008574 +0.008642 +0.00867 +0.0085 +0.008423 +0.008464 +0.008522 +0.008593 +0.00866 +0.008506 +0.008433 +0.00849 +0.008571 +0.008652 +0.008723 +0.008544 +0.00846 +0.008529 +0.008591 +0.008678 +0.008728 +0.008586 +0.008508 +0.00857 +0.008649 +0.008729 +0.008791 +0.008639 +0.008561 +0.008611 +0.008684 +0.008762 +0.008812 +0.008674 +0.008613 +0.008684 +0.008733 +0.00882 +0.008873 +0.008704 +0.008635 +0.008694 +0.008781 +0.008866 +0.008903 +0.008756 +0.008699 +0.008748 +0.008827 +0.008903 +0.008963 +0.0088 +0.008733 +0.008777 +0.008854 +0.008945 +0.008995 +0.008848 +0.008798 +0.008852 +0.008908 +0.008996 +0.009069 +0.008878 +0.008813 +0.008866 +0.008943 +0.009031 +0.009104 +0.008945 +0.008872 +0.008938 +0.008987 +0.009074 +0.009138 +0.008975 +0.008915 +0.008955 +0.009045 +0.009132 +0.00919 +0.009026 +0.008951 +0.009012 +0.009086 +0.009166 +0.009235 +0.009071 +0.008996 +0.009054 +0.009139 +0.009237 +0.00929 +0.009122 +0.009033 +0.009091 +0.009172 +0.009268 +0.00937 +0.009166 +0.009077 +0.00913 +0.009222 +0.009331 +0.009377 +0.009208 +0.009129 +0.009183 +0.009262 +0.009348 +0.009426 +0.009244 +0.009177 +0.009256 +0.00934 +0.00942 +0.00948 +0.009294 +0.009212 +0.009265 +0.00936 +0.009444 +0.009509 +0.00935 +0.009287 +0.009381 +0.009422 +0.009522 +0.009545 +0.009369 +0.009311 +0.009352 +0.00946 +0.009543 +0.009605 +0.009443 +0.009368 +0.009434 +0.009498 +0.009594 +0.009655 +0.009479 +0.009414 +0.009474 +0.009569 +0.009664 +0.009721 +0.009542 +0.009444 +0.009502 +0.009602 +0.009719 +0.009763 +0.009571 +0.009507 +0.009572 +0.009663 +0.009749 +0.009811 +0.009621 +0.009544 +0.009599 +0.00969 +0.009791 +0.009843 +0.00972 +0.009617 +0.00966 +0.00975 +0.009848 +0.009884 +0.009719 +0.009647 +0.009709 +0.009796 +0.009903 +0.009945 +0.009813 +0.009693 +0.009746 +0.009828 +0.009926 +0.010011 +0.009822 +0.009755 +0.00981 +0.009902 +0.009982 +0.010059 +0.009871 +0.009793 +0.009852 +0.009945 +0.010055 +0.010108 +0.009939 +0.009854 +0.009916 +0.009981 +0.010086 +0.010152 +0.009986 +0.009926 +0.009956 +0.010034 +0.010135 +0.010209 +0.01005 +0.009939 +0.009992 +0.010108 +0.010194 +0.010243 +0.010083 +0.009982 +0.010055 +0.010173 +0.010258 +0.010313 +0.010134 +0.010034 +0.010092 +0.01019 +0.010294 +0.010356 +0.010175 +0.010109 +0.010212 +0.010276 +0.010345 +0.010384 +0.010213 +0.010136 +0.0102 +0.010293 +0.010398 +0.010456 +0.010286 +0.010195 +0.010252 +0.010348 +0.010459 +0.010509 +0.010328 +0.010259 +0.010326 +0.010375 +0.010465 +0.010509 +0.010299 +0.010178 +0.010227 +0.010232 +0.010283 +0.010319 +0.010088 +0.009958 +0.009978 +0.009998 +0.010036 +0.010014 +0.009804 +0.009683 +0.009687 +0.009724 +0.009783 +0.009765 +0.00956 +0.009427 +0.009438 +0.009469 +0.009503 +0.009533 +0.009315 +0.009184 +0.009213 +0.009243 +0.009292 +0.009269 +0.009072 +0.008949 +0.008968 +0.009016 +0.009045 +0.009088 +0.008903 +0.00879 +0.008804 +0.008846 +0.008893 +0.008908 +0.008737 +0.008633 +0.00868 +0.0087 +0.008754 +0.008792 +0.00861 +0.008516 +0.008541 +0.008598 +0.008643 +0.008676 +0.008521 +0.008417 +0.008467 +0.008517 +0.00857 +0.008599 +0.008438 +0.008354 +0.00841 +0.008465 +0.008555 +0.008626 +0.008458 +0.008387 +0.008438 +0.008523 +0.008602 +0.008653 +0.008494 +0.008434 +0.008478 +0.008555 +0.00863 +0.008692 +0.00854 +0.008475 +0.008542 +0.0086 +0.008686 +0.008738 +0.008595 +0.008525 +0.00859 +0.008631 +0.008708 +0.00879 +0.008629 +0.008556 +0.008602 +0.008683 +0.008762 +0.008825 +0.008692 +0.008593 +0.00865 +0.00872 +0.008806 +0.00887 +0.008724 +0.008663 +0.008685 +0.008768 +0.008854 +0.008905 +0.008754 +0.008689 +0.008734 +0.008812 +0.008904 +0.008974 +0.00885 +0.008749 +0.008791 +0.008865 +0.008931 +0.008993 +0.008845 +0.008771 +0.008826 +0.008896 +0.008991 +0.009056 +0.008902 +0.008832 +0.008872 +0.008943 +0.00904 +0.009085 +0.008938 +0.008863 +0.008915 +0.00899 +0.009084 +0.009161 +0.008989 +0.008913 +0.008969 +0.009046 +0.009146 +0.009181 +0.009019 +0.008942 +0.008996 +0.009093 +0.009164 +0.009228 +0.009073 +0.009003 +0.009047 +0.009122 +0.009224 +0.009278 +0.009127 +0.009064 +0.009096 +0.009181 +0.00926 +0.00933 +0.009163 +0.009087 +0.00914 +0.009212 +0.009313 +0.009376 +0.009219 +0.009164 +0.009225 +0.009271 +0.009337 +0.009411 +0.009257 +0.009179 +0.009228 +0.009308 +0.009411 +0.00946 +0.009307 +0.009244 +0.009295 +0.00936 +0.009451 +0.009519 +0.009374 +0.009261 +0.009324 +0.009387 +0.009502 +0.009581 +0.009405 +0.009321 +0.009386 +0.009461 +0.009574 +0.009613 +0.009427 +0.009353 +0.009412 +0.009494 +0.009594 +0.009664 +0.009495 +0.009436 +0.009456 +0.009561 +0.009641 +0.009707 +0.009556 +0.009473 +0.009505 +0.009595 +0.009692 +0.009755 +0.009584 +0.00951 +0.009551 +0.009636 +0.009757 +0.009808 +0.009657 +0.009567 +0.009623 +0.00973 +0.009784 +0.009839 +0.009675 +0.009601 +0.009659 +0.009735 +0.009839 +0.009947 +0.009724 +0.009642 +0.009712 +0.00979 +0.009887 +0.009963 +0.00977 +0.009696 +0.009765 +0.009844 +0.009948 +0.010023 +0.009825 +0.009745 +0.009806 +0.009897 +0.010028 +0.010079 +0.009864 +0.009785 +0.009845 +0.009968 +0.01004 +0.010086 +0.009934 +0.009848 +0.009909 +0.009991 +0.010089 +0.010153 +0.009985 +0.009895 +0.009963 +0.010057 +0.010131 +0.010208 +0.010014 +0.009951 +0.010006 +0.010076 +0.010209 +0.010308 +0.010103 +0.01 +0.010045 +0.010135 +0.010251 +0.010305 +0.010125 +0.010053 +0.010087 +0.010193 +0.010318 +0.010405 +0.01018 +0.010089 +0.01014 +0.010235 +0.010347 +0.010406 +0.010228 +0.01016 +0.010224 +0.010312 +0.010421 +0.010485 +0.010293 +0.010178 +0.010241 +0.010333 +0.010463 +0.010479 +0.010309 +0.01021 +0.010247 +0.010285 +0.010343 +0.010335 +0.010132 +0.01 +0.01001 +0.010076 +0.010098 +0.010124 +0.009899 +0.009754 +0.009766 +0.009806 +0.009852 +0.009865 +0.009658 +0.009566 +0.00955 +0.009554 +0.00958 +0.009611 +0.009405 +0.009272 +0.009307 +0.00931 +0.009362 +0.009389 +0.009174 +0.009062 +0.009059 +0.009075 +0.009125 +0.009146 +0.008953 +0.008842 +0.00887 +0.008893 +0.008945 +0.008981 +0.008795 +0.008692 +0.008716 +0.008762 +0.00882 +0.008862 +0.008659 +0.008564 +0.0086 +0.008637 +0.008685 +0.008709 +0.008552 +0.008451 +0.00851 +0.008529 +0.008581 +0.008632 +0.008479 +0.008406 +0.008439 +0.008507 +0.008553 +0.008611 +0.008476 +0.008414 +0.008448 +0.008518 +0.008606 +0.008668 +0.008532 +0.008455 +0.008511 +0.008586 +0.008684 +0.008687 +0.008551 +0.008477 +0.008541 +0.008611 +0.008692 +0.008751 +0.008599 +0.008534 +0.008585 +0.008659 +0.008747 +0.008793 +0.008638 +0.008573 +0.008626 +0.008709 +0.00881 +0.008839 +0.00868 +0.008608 +0.008674 +0.008739 +0.008818 +0.008882 +0.008726 +0.008667 +0.008724 +0.008807 +0.008874 +0.008929 +0.008771 +0.0087 +0.008758 +0.008826 +0.008904 +0.008974 +0.008822 +0.008738 +0.008804 +0.00889 +0.008983 +0.009022 +0.008863 +0.008781 +0.008832 +0.00891 +0.009009 +0.009064 +0.008906 +0.008827 +0.008892 +0.008968 +0.00906 +0.009126 +0.00897 +0.008892 +0.008918 +0.008994 +0.009085 +0.009149 +0.009006 +0.008909 +0.00897 +0.009051 +0.00914 +0.009198 +0.009042 +0.008968 +0.009019 +0.009094 +0.009211 +0.009251 +0.009095 +0.009002 +0.00906 +0.009135 +0.009229 +0.009293 +0.00914 +0.009044 +0.009111 +0.00919 +0.009307 +0.009357 +0.009186 +0.009086 +0.009153 +0.009227 +0.009322 +0.009377 +0.009243 +0.009139 +0.009198 +0.009284 +0.00939 +0.009437 +0.009275 +0.009178 +0.009241 +0.009316 +0.009419 +0.009482 +0.009302 +0.009235 +0.0093 +0.00938 +0.009478 +0.009541 +0.00938 +0.009305 +0.00934 +0.009403 +0.009496 +0.009574 +0.009406 +0.009338 +0.009399 +0.009482 +0.009573 +0.009628 +0.009442 +0.009371 +0.009413 +0.009507 +0.00961 +0.009663 +0.009497 +0.009444 +0.009517 +0.009568 +0.009665 +0.00972 +0.00953 +0.00946 +0.009523 +0.009628 +0.009722 +0.009763 +0.009587 +0.009513 +0.009582 +0.009658 +0.009746 +0.009799 +0.009648 +0.009559 +0.009618 +0.009736 +0.009801 +0.009853 +0.009696 +0.009605 +0.009671 +0.009765 +0.00984 +0.009917 +0.009755 +0.009665 +0.009724 +0.009806 +0.009898 +0.009998 +0.009788 +0.009696 +0.00976 +0.009876 +0.009957 +0.010009 +0.009839 +0.009777 +0.009817 +0.009888 +0.009999 +0.010057 +0.009889 +0.009803 +0.009859 +0.009954 +0.010075 +0.010133 +0.00995 +0.009864 +0.009906 +0.00999 +0.010095 +0.010167 +0.010012 +0.009906 +0.009961 +0.010063 +0.01017 +0.010229 +0.010062 +0.009936 +0.010003 +0.010097 +0.010194 +0.010266 +0.010084 +0.009998 +0.010071 +0.010154 +0.010243 +0.010322 +0.010137 +0.010054 +0.010119 +0.010215 +0.010321 +0.010365 +0.0102 +0.010139 +0.010156 +0.010247 +0.010351 +0.010426 +0.010244 +0.010153 +0.010227 +0.010353 +0.010384 +0.010458 +0.010299 +0.010194 +0.010245 +0.010332 +0.010422 +0.010478 +0.010268 +0.010128 +0.010142 +0.010193 +0.010256 +0.010253 +0.010031 +0.009903 +0.009958 +0.009997 +0.010013 +0.010006 +0.00978 +0.00967 +0.009681 +0.009717 +0.009774 +0.00978 +0.009596 +0.009441 +0.009449 +0.009488 +0.009509 +0.009526 +0.009313 +0.009184 +0.009207 +0.009247 +0.009277 +0.009303 +0.009107 +0.008969 +0.008987 +0.009038 +0.009087 +0.009108 +0.008893 +0.008802 +0.008791 +0.008841 +0.008899 +0.008918 +0.008739 +0.008633 +0.008654 +0.008703 +0.008752 +0.008802 +0.008603 +0.008506 +0.00853 +0.008602 +0.008652 +0.008666 +0.008502 +0.008399 +0.008432 +0.008494 +0.00857 +0.008596 +0.008444 +0.008354 +0.008404 +0.008487 +0.008582 +0.008613 +0.008445 +0.008384 +0.008436 +0.008512 +0.008574 +0.008636 +0.008494 +0.008431 +0.00847 +0.008558 +0.008639 +0.008698 +0.008535 +0.008466 +0.00852 +0.008581 +0.00867 +0.008729 +0.008594 +0.008515 +0.008572 +0.008654 +0.008723 +0.008798 +0.008628 +0.008548 +0.008611 +0.008694 +0.00875 +0.008812 +0.008672 +0.008591 +0.008646 +0.008711 +0.008826 +0.008852 +0.008715 +0.008636 +0.008685 +0.008771 +0.008845 +0.00891 +0.008761 +0.008701 +0.008733 +0.008802 +0.008895 +0.008953 +0.008802 +0.008725 +0.008778 +0.008858 +0.008936 +0.009008 +0.008864 +0.008811 +0.008823 +0.008882 +0.008984 +0.009035 +0.008885 +0.008812 +0.008858 +0.008941 +0.009055 +0.009089 +0.008942 +0.008866 +0.008908 +0.008974 +0.009068 +0.009137 +0.008973 +0.008903 +0.00896 +0.00903 +0.009133 +0.009193 +0.00904 +0.008947 +0.008995 +0.009069 +0.009158 +0.009256 +0.009087 +0.008982 +0.009033 +0.009115 +0.009225 +0.00928 +0.009119 +0.009048 +0.009092 +0.009151 +0.009257 +0.009318 +0.009153 +0.009073 +0.009134 +0.009216 +0.009294 +0.009374 +0.009215 +0.009124 +0.009179 +0.009266 +0.009349 +0.009414 +0.009258 +0.009192 +0.00926 +0.009308 +0.009392 +0.009465 +0.009296 +0.009215 +0.009258 +0.009347 +0.009443 +0.009514 +0.009347 +0.009268 +0.00932 +0.009413 +0.009492 +0.009553 +0.009383 +0.009307 +0.009361 +0.009455 +0.009539 +0.009606 +0.009458 +0.009359 +0.009405 +0.009498 +0.0096 +0.009668 +0.009475 +0.009402 +0.009458 +0.009541 +0.009661 +0.009697 +0.009524 +0.009462 +0.009491 +0.009587 +0.009688 +0.009745 +0.009581 +0.009503 +0.009555 +0.009639 +0.009731 +0.009803 +0.009632 +0.009538 +0.009609 +0.009683 +0.009782 +0.009862 +0.009688 +0.009618 +0.009642 +0.009734 +0.009832 +0.009889 +0.00974 +0.009628 +0.009721 +0.009784 +0.00988 +0.009935 +0.009769 +0.009686 +0.009745 +0.009854 +0.009947 +0.010006 +0.009818 +0.009727 +0.009788 +0.009881 +0.009981 +0.010037 +0.009873 +0.009799 +0.00989 +0.009954 +0.010044 +0.010078 +0.009907 +0.009832 +0.009884 +0.00998 +0.010086 +0.01014 +0.009969 +0.009903 +0.009967 +0.010037 +0.010139 +0.010179 +0.010015 +0.009935 +0.009996 +0.010083 +0.010179 +0.010273 +0.010079 +0.01 +0.010059 +0.010162 +0.010227 +0.010297 +0.010111 +0.010022 +0.010091 +0.010179 +0.010302 +0.01036 +0.010177 +0.01009 +0.010146 +0.010222 +0.010331 +0.01041 +0.010224 +0.010122 +0.010218 +0.010301 +0.010406 +0.010473 +0.01027 +0.010173 +0.01025 +0.010363 +0.010457 +0.010485 +0.010311 +0.010257 +0.010342 +0.01039 +0.010498 +0.010556 +0.010352 +0.010259 +0.010332 +0.010403 +0.010489 +0.010539 +0.010301 +0.010162 +0.010189 +0.010266 +0.010274 +0.010297 +0.010065 +0.00992 +0.009942 +0.00999 +0.010083 +0.010035 +0.0098 +0.009676 +0.009684 +0.009728 +0.009781 +0.009751 +0.009541 +0.009405 +0.009437 +0.009469 +0.009503 +0.009511 +0.009302 +0.00917 +0.009188 +0.009215 +0.009281 +0.009278 +0.009075 +0.008962 +0.00898 +0.009013 +0.009054 +0.009076 +0.0089 +0.008776 +0.008774 +0.008826 +0.008887 +0.008912 +0.008736 +0.008618 +0.008649 +0.008712 +0.008784 +0.008773 +0.0086 +0.008501 +0.008525 +0.008584 +0.00864 +0.008671 +0.008496 +0.008398 +0.008456 +0.008505 +0.008568 +0.008593 +0.008437 +0.00835 +0.008394 +0.008469 +0.008552 +0.00862 +0.008472 +0.008401 +0.008419 +0.008497 +0.00859 +0.00865 +0.00849 +0.008421 +0.008471 +0.008548 +0.008624 +0.008691 +0.008542 +0.008465 +0.008512 +0.008586 +0.008692 +0.008737 +0.008593 +0.008519 +0.008555 +0.008629 +0.008713 +0.008782 +0.008635 +0.008563 +0.00859 +0.008676 +0.008775 +0.008845 +0.00867 +0.008594 +0.008662 +0.008713 +0.008795 +0.008853 +0.008705 +0.008634 +0.008689 +0.008756 +0.00886 +0.008924 +0.00876 +0.008691 +0.008739 +0.008798 +0.008884 +0.008947 +0.008805 +0.008721 +0.008784 +0.008841 +0.008947 +0.008994 +0.008841 +0.008771 +0.008825 +0.008916 +0.008984 +0.009029 +0.008891 +0.008811 +0.008871 +0.008978 +0.009015 +0.009077 +0.008936 +0.008848 +0.008903 +0.008982 +0.009063 +0.009132 +0.008978 +0.008904 +0.008954 +0.009039 +0.009123 +0.00918 +0.009024 +0.008947 +0.009005 +0.009065 +0.009159 +0.009239 +0.009077 +0.009013 +0.009038 +0.00912 +0.009205 +0.009256 +0.009123 +0.009031 +0.009085 +0.009189 +0.00925 +0.009314 +0.009155 +0.009078 +0.009134 +0.009218 +0.009309 +0.009362 +0.009207 +0.009127 +0.009179 +0.009251 +0.009353 +0.009424 +0.009254 +0.009163 +0.009234 +0.00932 +0.009435 +0.009447 +0.009284 +0.009205 +0.009271 +0.009351 +0.009442 +0.009504 +0.009351 +0.009259 +0.009337 +0.009391 +0.009492 +0.009555 +0.009387 +0.009313 +0.009364 +0.009444 +0.00955 +0.009602 +0.009436 +0.009366 +0.009424 +0.009487 +0.009576 +0.009652 +0.009505 +0.009417 +0.009453 +0.009559 +0.009613 +0.009705 +0.009541 +0.009459 +0.009491 +0.009589 +0.009677 +0.009742 +0.009591 +0.009489 +0.009551 +0.009647 +0.009742 +0.009808 +0.00964 +0.009543 +0.009594 +0.009691 +0.009787 +0.009847 +0.009671 +0.009591 +0.009673 +0.009771 +0.009836 +0.009894 +0.009722 +0.009655 +0.009683 +0.009776 +0.009875 +0.009944 +0.009757 +0.009687 +0.009767 +0.009838 +0.00995 +0.010002 +0.009807 +0.009733 +0.009801 +0.009887 +0.009978 +0.010043 +0.009877 +0.009784 +0.009847 +0.009939 +0.010068 +0.01008 +0.009909 +0.009841 +0.009888 +0.009991 +0.010105 +0.01013 +0.009974 +0.009877 +0.009942 +0.010036 +0.010125 +0.010196 +0.010045 +0.009952 +0.010005 +0.010084 +0.010177 +0.010243 +0.010075 +0.009991 +0.010031 +0.010135 +0.010247 +0.01035 +0.010118 +0.010033 +0.010082 +0.010177 +0.010278 +0.010342 +0.010171 +0.010104 +0.010133 +0.010235 +0.010359 +0.010412 +0.01023 +0.010119 +0.010188 +0.010283 +0.010395 +0.010458 +0.010263 +0.010198 +0.010251 +0.010329 +0.010423 +0.010474 +0.010253 +0.010092 +0.010115 +0.010167 +0.010239 +0.01025 +0.010028 +0.009905 +0.009924 +0.009956 +0.010003 +0.009993 +0.009779 +0.009656 +0.009643 +0.009712 +0.009752 +0.009743 +0.009525 +0.009392 +0.009403 +0.009443 +0.00947 +0.009499 +0.009291 +0.009187 +0.009161 +0.009206 +0.009259 +0.009228 +0.009039 +0.008916 +0.008932 +0.008985 +0.009017 +0.00904 +0.008857 +0.008761 +0.008773 +0.008816 +0.008866 +0.008873 +0.0087 +0.008591 +0.008632 +0.008663 +0.008723 +0.008755 +0.008592 +0.008484 +0.008503 +0.00856 +0.008611 +0.008643 +0.008451 +0.008352 +0.008389 +0.008439 +0.008503 +0.008569 +0.008388 +0.008304 +0.008363 +0.008421 +0.008502 +0.008559 +0.008407 +0.008334 +0.008384 +0.008455 +0.008538 +0.008589 +0.008449 +0.008395 +0.008446 +0.008509 +0.008585 +0.00865 +0.008492 +0.00841 +0.008473 +0.008536 +0.008646 +0.00869 +0.00853 +0.00846 +0.008521 +0.008595 +0.00868 +0.008743 +0.008583 +0.008533 +0.00854 +0.008622 +0.008695 +0.008767 +0.00861 +0.008555 +0.008595 +0.008673 +0.00875 +0.008811 +0.008675 +0.008591 +0.008635 +0.008717 +0.008805 +0.008855 +0.008711 +0.00864 +0.008706 +0.008788 +0.008867 +0.008891 +0.008739 +0.008674 +0.008722 +0.008799 +0.008882 +0.008934 +0.008806 +0.008727 +0.008793 +0.008845 +0.008939 +0.008999 +0.008841 +0.008775 +0.008815 +0.008887 +0.008986 +0.009045 +0.008897 +0.008821 +0.008877 +0.008936 +0.009017 +0.009083 +0.008932 +0.008874 +0.00892 +0.008973 +0.00906 +0.009143 +0.008984 +0.008915 +0.008958 +0.009027 +0.009109 +0.009168 +0.009016 +0.008941 +0.009017 +0.00906 +0.009156 +0.009238 +0.009087 +0.009001 +0.009054 +0.009126 +0.009196 +0.009258 +0.009112 +0.009024 +0.009077 +0.00917 +0.009256 +0.00935 +0.009156 +0.009074 +0.009141 +0.009199 +0.009326 +0.009344 +0.009195 +0.009124 +0.009183 +0.009253 +0.009348 +0.00942 +0.009251 +0.009174 +0.009229 +0.00929 +0.009394 +0.009461 +0.009302 +0.009226 +0.009286 +0.009361 +0.00943 +0.00951 +0.009347 +0.009263 +0.009339 +0.009374 +0.009487 +0.009559 +0.009397 +0.009324 +0.009377 +0.009456 +0.009532 +0.009586 +0.009424 +0.009348 +0.009396 +0.009483 +0.009581 +0.009669 +0.0095 +0.009412 +0.009471 +0.00954 +0.009623 +0.009695 +0.009527 +0.009442 +0.009491 +0.009611 +0.009728 +0.009757 +0.009575 +0.009496 +0.009531 +0.009635 +0.009713 +0.009784 +0.009624 +0.009548 +0.009609 +0.009694 +0.009797 +0.009848 +0.009675 +0.00958 +0.009636 +0.009725 +0.009834 +0.009888 +0.009715 +0.009648 +0.00972 +0.009789 +0.009892 +0.009953 +0.00979 +0.009676 +0.009719 +0.009828 +0.009923 +0.009969 +0.009821 +0.009766 +0.009801 +0.009891 +0.010005 +0.010035 +0.009851 +0.009773 +0.009839 +0.00993 +0.010037 +0.01009 +0.009917 +0.009837 +0.009896 +0.009972 +0.010072 +0.010153 +0.009963 +0.009882 +0.009953 +0.010067 +0.010174 +0.010184 +0.009994 +0.00992 +0.009994 +0.010065 +0.010167 +0.010255 +0.010073 +0.009982 +0.010064 +0.010157 +0.01022 +0.010294 +0.010119 +0.010031 +0.010085 +0.010183 +0.01029 +0.010365 +0.010182 +0.010079 +0.010132 +0.010203 +0.010316 +0.010322 +0.010088 +0.010003 +0.009997 +0.010056 +0.010121 +0.010112 +0.00989 +0.009773 +0.009797 +0.009822 +0.00989 +0.00988 +0.009658 +0.009546 +0.009554 +0.009601 +0.009634 +0.009619 +0.009409 +0.009287 +0.009308 +0.009338 +0.009375 +0.00941 +0.009207 +0.009099 +0.009081 +0.009126 +0.009159 +0.009186 +0.00897 +0.008846 +0.008879 +0.008932 +0.008975 +0.009 +0.008825 +0.008709 +0.008725 +0.00878 +0.008822 +0.008827 +0.008648 +0.008543 +0.008579 +0.00862 +0.008682 +0.008694 +0.008523 +0.008412 +0.008445 +0.008503 +0.008552 +0.008604 +0.008419 +0.008314 +0.008346 +0.008414 +0.008476 +0.008535 +0.008373 +0.008287 +0.008324 +0.008403 +0.008473 +0.008536 +0.008396 +0.008322 +0.008366 +0.008435 +0.008527 +0.008585 +0.008441 +0.008352 +0.00841 +0.008473 +0.008558 +0.008626 +0.008474 +0.008399 +0.00845 +0.008529 +0.008616 +0.008703 +0.008521 +0.008449 +0.008482 +0.008558 +0.008647 +0.008703 +0.008558 +0.008473 +0.008553 +0.008611 +0.008684 +0.008744 +0.008616 +0.008536 +0.008579 +0.008665 +0.008727 +0.008785 +0.008643 +0.008575 +0.008616 +0.008689 +0.008776 +0.008837 +0.008684 +0.008614 +0.008673 +0.008748 +0.008851 +0.008891 +0.008717 +0.008651 +0.008703 +0.008793 +0.008872 +0.008917 +0.008773 +0.0087 +0.008754 +0.008829 +0.008915 +0.008971 +0.008817 +0.008738 +0.008795 +0.008868 +0.008966 +0.009025 +0.008856 +0.008785 +0.008842 +0.008921 +0.008998 +0.009061 +0.008911 +0.008841 +0.008915 +0.008951 +0.009054 +0.009104 +0.008949 +0.00887 +0.008918 +0.009 +0.009089 +0.009163 +0.008992 +0.008921 +0.008977 +0.009053 +0.009146 +0.009204 +0.009034 +0.008964 +0.009011 +0.009099 +0.00918 +0.009244 +0.009084 +0.009016 +0.009062 +0.009155 +0.009248 +0.009317 +0.009139 +0.00904 +0.009091 +0.009179 +0.00927 +0.009363 +0.009163 +0.009094 +0.009173 +0.009251 +0.009327 +0.009387 +0.009212 +0.009136 +0.009187 +0.009281 +0.009361 +0.009424 +0.009275 +0.009201 +0.009267 +0.009345 +0.009428 +0.009473 +0.009303 +0.009235 +0.009303 +0.009393 +0.009452 +0.009513 +0.009356 +0.009289 +0.009364 +0.00943 +0.00954 +0.009559 +0.009394 +0.009314 +0.009377 +0.009464 +0.009557 +0.00963 +0.009455 +0.009395 +0.009456 +0.00953 +0.009617 +0.009656 +0.009505 +0.009417 +0.009474 +0.009565 +0.009658 +0.009766 +0.009545 +0.009477 +0.00953 +0.009617 +0.009717 +0.009742 +0.009592 +0.009528 +0.009583 +0.009657 +0.009753 +0.009805 +0.009648 +0.009564 +0.009628 +0.009708 +0.0098 +0.009886 +0.009701 +0.009618 +0.00969 +0.009763 +0.009844 +0.00992 +0.009756 +0.009694 +0.009714 +0.009819 +0.009894 +0.009961 +0.009799 +0.009713 +0.009776 +0.00985 +0.009953 +0.010013 +0.009851 +0.009753 +0.009812 +0.009919 +0.010001 +0.010069 +0.00991 +0.00982 +0.009857 +0.009953 +0.010051 +0.010117 +0.009945 +0.009868 +0.009963 +0.010004 +0.010098 +0.010172 +0.01003 +0.009893 +0.009955 +0.010051 +0.010158 +0.010213 +0.010031 +0.009962 +0.010014 +0.010131 +0.010231 +0.010267 +0.01008 +0.010012 +0.010061 +0.010154 +0.010267 +0.010311 +0.010147 +0.010069 +0.010149 +0.010268 +0.010307 +0.010341 +0.010181 +0.010103 +0.010174 +0.010282 +0.010354 +0.010434 +0.010223 +0.010144 +0.01021 +0.010267 +0.010348 +0.010379 +0.010145 +0.010013 +0.01006 +0.010107 +0.010168 +0.010169 +0.009936 +0.009785 +0.009796 +0.009866 +0.009898 +0.009872 +0.009643 +0.009531 +0.009537 +0.009576 +0.009622 +0.009618 +0.009427 +0.009259 +0.009277 +0.009325 +0.009353 +0.009362 +0.009164 +0.009032 +0.009048 +0.009095 +0.009142 +0.009143 +0.008943 +0.008832 +0.008852 +0.008904 +0.008949 +0.008971 +0.008801 +0.008688 +0.008695 +0.008737 +0.008792 +0.008813 +0.008636 +0.008531 +0.008555 +0.008617 +0.008665 +0.008688 +0.008514 +0.008426 +0.008454 +0.008499 +0.008555 +0.008591 +0.008414 +0.008326 +0.008371 +0.00843 +0.008497 +0.00855 +0.008396 +0.008311 +0.008368 +0.008427 +0.008514 +0.008575 +0.008446 +0.008342 +0.008386 +0.008473 +0.008544 +0.00861 +0.00846 +0.008394 +0.00845 +0.008525 +0.008584 +0.008647 +0.008502 +0.008434 +0.00848 +0.008548 +0.008638 +0.008702 +0.008553 +0.008474 +0.008544 +0.008621 +0.008692 +0.008728 +0.008596 +0.008517 +0.00856 +0.008646 +0.008727 +0.008803 +0.00863 +0.008553 +0.008607 +0.008695 +0.008778 +0.008851 +0.008662 +0.008598 +0.008654 +0.008719 +0.008812 +0.008872 +0.008713 +0.008642 +0.008699 +0.008789 +0.008855 +0.008919 +0.008772 +0.008697 +0.008739 +0.008814 +0.008903 +0.008956 +0.008819 +0.008741 +0.008785 +0.008887 +0.008961 +0.008998 +0.008842 +0.008772 +0.00882 +0.008912 +0.008993 +0.009075 +0.008916 +0.008822 +0.008865 +0.008944 +0.009038 +0.009089 +0.008936 +0.008867 +0.008901 +0.008993 +0.009081 +0.009159 +0.009 +0.008917 +0.008971 +0.009045 +0.009112 +0.009188 +0.009031 +0.008979 +0.009003 +0.009081 +0.009173 +0.009234 +0.009091 +0.009007 +0.009052 +0.009126 +0.009216 +0.009289 +0.009115 +0.009038 +0.009079 +0.009159 +0.009256 +0.009333 +0.009169 +0.009085 +0.009159 +0.009224 +0.009314 +0.00938 +0.009217 +0.009138 +0.009197 +0.009267 +0.009378 +0.009444 +0.009246 +0.009192 +0.009226 +0.00931 +0.009409 +0.009459 +0.009305 +0.009242 +0.009285 +0.00935 +0.009453 +0.009511 +0.009355 +0.009273 +0.009336 +0.009402 +0.009502 +0.009574 +0.009392 +0.009333 +0.009383 +0.009448 +0.009546 +0.00961 +0.009454 +0.009406 +0.009421 +0.009503 +0.009594 +0.009665 +0.009514 +0.009412 +0.009451 +0.009544 +0.009639 +0.009701 +0.009537 +0.009466 +0.009506 +0.009596 +0.009708 +0.009757 +0.00961 +0.009514 +0.009554 +0.009644 +0.009743 +0.009802 +0.009636 +0.009547 +0.009618 +0.009735 +0.009798 +0.009862 +0.009684 +0.00959 +0.009662 +0.009757 +0.009849 +0.009897 +0.009718 +0.009644 +0.009711 +0.009792 +0.0099 +0.009966 +0.009776 +0.009699 +0.009753 +0.009851 +0.009934 +0.009994 +0.009837 +0.00974 +0.009805 +0.009907 +0.010024 +0.010084 +0.009867 +0.009788 +0.009854 +0.009937 +0.010036 +0.010097 +0.009925 +0.009871 +0.009906 +0.009999 +0.010084 +0.010136 +0.009971 +0.009898 +0.009949 +0.010035 +0.010158 +0.010204 +0.01003 +0.009965 +0.010018 +0.010083 +0.010197 +0.010271 +0.01011 +0.010002 +0.010026 +0.010127 +0.01024 +0.010305 +0.010138 +0.010056 +0.010086 +0.010189 +0.010298 +0.010369 +0.01018 +0.010088 +0.010158 +0.010242 +0.010331 +0.010417 +0.010208 +0.010101 +0.010152 +0.0102 +0.01025 +0.010279 +0.01009 +0.009982 +0.009973 +0.01001 +0.010049 +0.010046 +0.00982 +0.009691 +0.009708 +0.00975 +0.009774 +0.009786 +0.009591 +0.009462 +0.009451 +0.009488 +0.009543 +0.00955 +0.009343 +0.009227 +0.009233 +0.009265 +0.009319 +0.009312 +0.009127 +0.009008 +0.009041 +0.009101 +0.009128 +0.009113 +0.008922 +0.008817 +0.00887 +0.008878 +0.008926 +0.008947 +0.008789 +0.008674 +0.008709 +0.008762 +0.008817 +0.008834 +0.008663 +0.008574 +0.008602 +0.008649 +0.008699 +0.008738 +0.008564 +0.008484 +0.008533 +0.008579 +0.008633 +0.008672 +0.008514 +0.008436 +0.008498 +0.008531 +0.008595 +0.008647 +0.008507 +0.008444 +0.008497 +0.008579 +0.008644 +0.008704 +0.008548 +0.008475 +0.008529 +0.008615 +0.008683 +0.008748 +0.00861 +0.008528 +0.008576 +0.008653 +0.008739 +0.008795 +0.00864 +0.008569 +0.008624 +0.008687 +0.008784 +0.008856 +0.008708 +0.008648 +0.008683 +0.008737 +0.008799 +0.008862 +0.008725 +0.008645 +0.008697 +0.008786 +0.008874 +0.00893 +0.008762 +0.008699 +0.008745 +0.008819 +0.008902 +0.008976 +0.008815 +0.008742 +0.008794 +0.008874 +0.008954 +0.00901 +0.00887 +0.008788 +0.008835 +0.008914 +0.009009 +0.009087 +0.008905 +0.008846 +0.008883 +0.008959 +0.009049 +0.009088 +0.008941 +0.008868 +0.008927 +0.008994 +0.009086 +0.009155 +0.008994 +0.008916 +0.008978 +0.009068 +0.009137 +0.009189 +0.009043 +0.008961 +0.009015 +0.009095 +0.00918 +0.009239 +0.009082 +0.009011 +0.009089 +0.009181 +0.009242 +0.009288 +0.009116 +0.009055 +0.0091 +0.009173 +0.009267 +0.009329 +0.009178 +0.009105 +0.009162 +0.009251 +0.009329 +0.009379 +0.009218 +0.00913 +0.009195 +0.009275 +0.009372 +0.009421 +0.009278 +0.009209 +0.009248 +0.009334 +0.009431 +0.009491 +0.009333 +0.009225 +0.009283 +0.009367 +0.009466 +0.009528 +0.009369 +0.009274 +0.009332 +0.009413 +0.009504 +0.00957 +0.009417 +0.009327 +0.009385 +0.009484 +0.009561 +0.009614 +0.009464 +0.009368 +0.00943 +0.009522 +0.009608 +0.009673 +0.009509 +0.009448 +0.009526 +0.009584 +0.00965 +0.009696 +0.009536 +0.00946 +0.00953 +0.009609 +0.00973 +0.009766 +0.009592 +0.009529 +0.009589 +0.009655 +0.00974 +0.009818 +0.00964 +0.009564 +0.009633 +0.009703 +0.009805 +0.009892 +0.00971 +0.009622 +0.009674 +0.009752 +0.009885 +0.009917 +0.00972 +0.009647 +0.009711 +0.009815 +0.009911 +0.009976 +0.009812 +0.009721 +0.009756 +0.009848 +0.009943 +0.01001 +0.009834 +0.009756 +0.009813 +0.00989 +0.010005 +0.010069 +0.0099 +0.009811 +0.009867 +0.009961 +0.010071 +0.010161 +0.009963 +0.009834 +0.009924 +0.009987 +0.010099 +0.010158 +0.009983 +0.009912 +0.009965 +0.010044 +0.010172 +0.010242 +0.010021 +0.00995 +0.010014 +0.010104 +0.010209 +0.010274 +0.010096 +0.010012 +0.010084 +0.010163 +0.010257 +0.010327 +0.010165 +0.010059 +0.010094 +0.010189 +0.010302 +0.010391 +0.010196 +0.010108 +0.010186 +0.01024 +0.010355 +0.01043 +0.010237 +0.010167 +0.01022 +0.010325 +0.010423 +0.010483 +0.010283 +0.010202 +0.010267 +0.010357 +0.010467 +0.010538 +0.010373 +0.010275 +0.010315 +0.010391 +0.010496 +0.010539 +0.010303 +0.010215 +0.010216 +0.010275 +0.010357 +0.010389 +0.010151 +0.010029 +0.010055 +0.010093 +0.010157 +0.010158 +0.009933 +0.009811 +0.009828 +0.009878 +0.009928 +0.009921 +0.009702 +0.009578 +0.009587 +0.00967 +0.009677 +0.009688 +0.009475 +0.009358 +0.009388 +0.009415 +0.009472 +0.00947 +0.009254 +0.009138 +0.009155 +0.009205 +0.00924 +0.009281 +0.009093 +0.008954 +0.008983 +0.009032 +0.009064 +0.009103 +0.008907 +0.008804 +0.008823 +0.008875 +0.008921 +0.008959 +0.008809 +0.008681 +0.008693 +0.008741 +0.008781 +0.008819 +0.00865 +0.008545 +0.00858 +0.008648 +0.008707 +0.008739 +0.008584 +0.008499 +0.008535 +0.008607 +0.008687 +0.008744 +0.008596 +0.008516 +0.008586 +0.008642 +0.008736 +0.00878 +0.008638 +0.008571 +0.008611 +0.008687 +0.00876 +0.00885 +0.008684 +0.008632 +0.00865 +0.008714 +0.008817 +0.008871 +0.00871 +0.008643 +0.0087 +0.008767 +0.008853 +0.008921 +0.008765 +0.008708 +0.008741 +0.008829 +0.008902 +0.008967 +0.008798 +0.008726 +0.008771 +0.008857 +0.008956 +0.009013 +0.008847 +0.008776 +0.00883 +0.008937 +0.009028 +0.009052 +0.00888 +0.008813 +0.008888 +0.008941 +0.009026 +0.009091 +0.008938 +0.008862 +0.008911 +0.009005 +0.009101 +0.009148 +0.008992 +0.008904 +0.008955 +0.009035 +0.009123 +0.009193 +0.009028 +0.008953 +0.009017 +0.009104 +0.009188 +0.009243 +0.009085 +0.009013 +0.009048 +0.009124 +0.00921 +0.00927 +0.009117 +0.009047 +0.009127 +0.009184 +0.00928 +0.009327 +0.009161 +0.009087 +0.00913 +0.009211 +0.009311 +0.00938 +0.009204 +0.009139 +0.009203 +0.009286 +0.00937 +0.009436 +0.009263 +0.009174 +0.009233 +0.009316 +0.009429 +0.009476 +0.009301 +0.009209 +0.009274 +0.009369 +0.009455 +0.009518 +0.009347 +0.009295 +0.009321 +0.009403 +0.009507 +0.009569 +0.009389 +0.009323 +0.009374 +0.009462 +0.009554 +0.009624 +0.009452 +0.009366 +0.00943 +0.00952 +0.00961 +0.009667 +0.009491 +0.009442 +0.009472 +0.009538 +0.009643 +0.0097 +0.009549 +0.009454 +0.009518 +0.009621 +0.00971 +0.009748 +0.009587 +0.009502 +0.009572 +0.009658 +0.009742 +0.009805 +0.00965 +0.009572 +0.009619 +0.009709 +0.009791 +0.009846 +0.009691 +0.00961 +0.009668 +0.009783 +0.009827 +0.00991 +0.00976 +0.009654 +0.009717 +0.009783 +0.009884 +0.009954 +0.009776 +0.009702 +0.009763 +0.009852 +0.009938 +0.010014 +0.009832 +0.009742 +0.00982 +0.009893 +0.009996 +0.010064 +0.0099 +0.009816 +0.009848 +0.009947 +0.010082 +0.010106 +0.009927 +0.009832 +0.009904 +0.010027 +0.01008 +0.010159 +0.010004 +0.009882 +0.009952 +0.010056 +0.010142 +0.010211 +0.01004 +0.009954 +0.009999 +0.010125 +0.010202 +0.010268 +0.010073 +0.009994 +0.010061 +0.010153 +0.010249 +0.010347 +0.010126 +0.010044 +0.010113 +0.010205 +0.010308 +0.010346 +0.010201 +0.010095 +0.01015 +0.010244 +0.01035 +0.010435 +0.010249 +0.010162 +0.010216 +0.010294 +0.0104 +0.010468 +0.010275 +0.010198 +0.010244 +0.010371 +0.010485 +0.010564 +0.010351 +0.010246 +0.010285 +0.010389 +0.01051 +0.010562 +0.010394 +0.010301 +0.010376 +0.010447 +0.010566 +0.010617 +0.010434 +0.010363 +0.010404 +0.010493 +0.010584 +0.010642 +0.010413 +0.010301 +0.010307 +0.010356 +0.010413 +0.010451 +0.010216 +0.01007 +0.010068 +0.010086 +0.010141 +0.010112 +0.009899 +0.009773 +0.009766 +0.0098 +0.009856 +0.009857 +0.00965 +0.009503 +0.009514 +0.009542 +0.009556 +0.009571 +0.009363 +0.009228 +0.00924 +0.009255 +0.009297 +0.009332 +0.00913 +0.009026 +0.009016 +0.009034 +0.00906 +0.009097 +0.008901 +0.00878 +0.008797 +0.008843 +0.008895 +0.00891 +0.008737 +0.008633 +0.008652 +0.008692 +0.008739 +0.008786 +0.008601 +0.008505 +0.008531 +0.008582 +0.008623 +0.008642 +0.008485 +0.008383 +0.008416 +0.008455 +0.008527 +0.008562 +0.00843 +0.008325 +0.008357 +0.008413 +0.008485 +0.00854 +0.008388 +0.008332 +0.008353 +0.008443 +0.008505 +0.008566 +0.008425 +0.008364 +0.008418 +0.008486 +0.008568 +0.008626 +0.008471 +0.008397 +0.00845 +0.008523 +0.008597 +0.008654 +0.008518 +0.008433 +0.008494 +0.008567 +0.008653 +0.008726 +0.008565 +0.008483 +0.008528 +0.008621 +0.00868 +0.008746 +0.008613 +0.008531 +0.008585 +0.008657 +0.008718 +0.008783 +0.008646 +0.008563 +0.008614 +0.008689 +0.008784 +0.008834 +0.008686 +0.008636 +0.008672 +0.008734 +0.008811 +0.008881 +0.008727 +0.008661 +0.008709 +0.008778 +0.008886 +0.008949 +0.008761 +0.008698 +0.008753 +0.008829 +0.008913 +0.008953 +0.008809 +0.008746 +0.008794 +0.008864 +0.008949 +0.009006 +0.008876 +0.008796 +0.008857 +0.008917 +0.009003 +0.009047 +0.008903 +0.008833 +0.008871 +0.008958 +0.009035 +0.009099 +0.008966 +0.008885 +0.008963 +0.009021 +0.009093 +0.009138 +0.00898 +0.008912 +0.008964 +0.009034 +0.009138 +0.009196 +0.009031 +0.008958 +0.009018 +0.009103 +0.009184 +0.00924 +0.009099 +0.009012 +0.009056 +0.009134 +0.009224 +0.009284 +0.00913 +0.009065 +0.009104 +0.009188 +0.009289 +0.009346 +0.009202 +0.009089 +0.009144 +0.009229 +0.009327 +0.009425 +0.0092 +0.009131 +0.0092 +0.009276 +0.009368 +0.009422 +0.009268 +0.009179 +0.009244 +0.009347 +0.009433 +0.009453 +0.009318 +0.009229 +0.009299 +0.009373 +0.00946 +0.00952 +0.009366 +0.009294 +0.009361 +0.009449 +0.009505 +0.009545 +0.009402 +0.009327 +0.009392 +0.009458 +0.00957 +0.009614 +0.009458 +0.009378 +0.009445 +0.009517 +0.009596 +0.009666 +0.009506 +0.009431 +0.009474 +0.00956 +0.00965 +0.009699 +0.009547 +0.009458 +0.009538 +0.009619 +0.009723 +0.009808 +0.009595 +0.009511 +0.009583 +0.009645 +0.009751 +0.009803 +0.009644 +0.009569 +0.009634 +0.009704 +0.009808 +0.009863 +0.009701 +0.009626 +0.009678 +0.009744 +0.009847 +0.00992 +0.009739 +0.009659 +0.009719 +0.009813 +0.009917 +0.009982 +0.009823 +0.009724 +0.009767 +0.009839 +0.009929 +0.010013 +0.009829 +0.009745 +0.009815 +0.00991 +0.010022 +0.010073 +0.009905 +0.009799 +0.009858 +0.009957 +0.010054 +0.010111 +0.009934 +0.009862 +0.009933 +0.010022 +0.010115 +0.010162 +0.009983 +0.00992 +0.009994 +0.010041 +0.010133 +0.010216 +0.010065 +0.009958 +0.010026 +0.010118 +0.010204 +0.010251 +0.010082 +0.010006 +0.01007 +0.010163 +0.010256 +0.010317 +0.01014 +0.010053 +0.010112 +0.010201 +0.010319 +0.010376 +0.010203 +0.010112 +0.010207 +0.010266 +0.010354 +0.010418 +0.010236 +0.010162 +0.010229 +0.010284 +0.010393 +0.010457 +0.010255 +0.010127 +0.010145 +0.010205 +0.010259 +0.010285 +0.010075 +0.009936 +0.009961 +0.010006 +0.010042 +0.010028 +0.009831 +0.009666 +0.009678 +0.009716 +0.009761 +0.00979 +0.009548 +0.009404 +0.00941 +0.009442 +0.009483 +0.009526 +0.009278 +0.009172 +0.009167 +0.009208 +0.009249 +0.009275 +0.009063 +0.008944 +0.008959 +0.008992 +0.009034 +0.009069 +0.008865 +0.008763 +0.008779 +0.008831 +0.008884 +0.008908 +0.008726 +0.008614 +0.008658 +0.008681 +0.008728 +0.008752 +0.008587 +0.008486 +0.008518 +0.008577 +0.00862 +0.008662 +0.008483 +0.008383 +0.008408 +0.008465 +0.008522 +0.008559 +0.008404 +0.008318 +0.008346 +0.008403 +0.008501 +0.008527 +0.008379 +0.008301 +0.008352 +0.008423 +0.00851 +0.008564 +0.008422 +0.008377 +0.008419 +0.008467 +0.008532 +0.008594 +0.008449 +0.008393 +0.008435 +0.008504 +0.008592 +0.008651 +0.008524 +0.008441 +0.008495 +0.008556 +0.008619 +0.008678 +0.008545 +0.008477 +0.008528 +0.008589 +0.008672 +0.008743 +0.008595 +0.008529 +0.008575 +0.008641 +0.008705 +0.008776 +0.008639 +0.008573 +0.0086 +0.008675 +0.008765 +0.008833 +0.008683 +0.008598 +0.008656 +0.008725 +0.00881 +0.008851 +0.008708 +0.008642 +0.008695 +0.008771 +0.008851 +0.008912 +0.008755 +0.008681 +0.008742 +0.008805 +0.008893 +0.00895 +0.008805 +0.008731 +0.008774 +0.008863 +0.00895 +0.009051 +0.008869 +0.008778 +0.008816 +0.008884 +0.008975 +0.009066 +0.008879 +0.008809 +0.008872 +0.008936 +0.009033 +0.009097 +0.008941 +0.008863 +0.008909 +0.008994 +0.009081 +0.009133 +0.008987 +0.008906 +0.008972 +0.009033 +0.009127 +0.009182 +0.009021 +0.008957 +0.009003 +0.009107 +0.009172 +0.009223 +0.009066 +0.008993 +0.009065 +0.00912 +0.009206 +0.009273 +0.009122 +0.009034 +0.009095 +0.009175 +0.009272 +0.009323 +0.009183 +0.009093 +0.00914 +0.009221 +0.009303 +0.009364 +0.009204 +0.00913 +0.009187 +0.009263 +0.009357 +0.009428 +0.009297 +0.009189 +0.009228 +0.009292 +0.009391 +0.009451 +0.009298 +0.00922 +0.009286 +0.009367 +0.009492 +0.009509 +0.009342 +0.009264 +0.009318 +0.009398 +0.009485 +0.009555 +0.009399 +0.009319 +0.009372 +0.009458 +0.009564 +0.009625 +0.009437 +0.009364 +0.009419 +0.009521 +0.009577 +0.009668 +0.009471 +0.009412 +0.009467 +0.009526 +0.009643 +0.009702 +0.009535 +0.009441 +0.009508 +0.009598 +0.009684 +0.009758 +0.009589 +0.009508 +0.009554 +0.009643 +0.009733 +0.009796 +0.009643 +0.009545 +0.009604 +0.009688 +0.009802 +0.0099 +0.009691 +0.009583 +0.009637 +0.009756 +0.009829 +0.009887 +0.00972 +0.009645 +0.009694 +0.009789 +0.00991 +0.009951 +0.009784 +0.009682 +0.009745 +0.009833 +0.009933 +0.01 +0.009817 +0.009733 +0.00981 +0.009901 +0.01 +0.010059 +0.009885 +0.009796 +0.009837 +0.009934 +0.010022 +0.01009 +0.009924 +0.009852 +0.009909 +0.009987 +0.010087 +0.010131 +0.009957 +0.009884 +0.009942 +0.010034 +0.010148 +0.010203 +0.010038 +0.00994 +0.010005 +0.010104 +0.010164 +0.010228 +0.010074 +0.01001 +0.01006 +0.010125 +0.010215 +0.01029 +0.010122 +0.010041 +0.010083 +0.010194 +0.010282 +0.010347 +0.010179 +0.010089 +0.010136 +0.010243 +0.010333 +0.010404 +0.010246 +0.010123 +0.010188 +0.010278 +0.010386 +0.010437 +0.010232 +0.010113 +0.010175 +0.010202 +0.01023 +0.010277 +0.010061 +0.009962 +0.009984 +0.010013 +0.01006 +0.010043 +0.009834 +0.009699 +0.009713 +0.009741 +0.009787 +0.009804 +0.009593 +0.009468 +0.009484 +0.009497 +0.009537 +0.00955 +0.009332 +0.009209 +0.009218 +0.009247 +0.00932 +0.009324 +0.009114 +0.009011 +0.008999 +0.009038 +0.009084 +0.009102 +0.008924 +0.008818 +0.008837 +0.00888 +0.008935 +0.008951 +0.008774 +0.008669 +0.008702 +0.008732 +0.008792 +0.008822 +0.008655 +0.00855 +0.008589 +0.008644 +0.008678 +0.008701 +0.008539 +0.008451 +0.008484 +0.008547 +0.00858 +0.008622 +0.008463 +0.008386 +0.008435 +0.008496 +0.008567 +0.008617 +0.008466 +0.00839 +0.008431 +0.008515 +0.008597 +0.008647 +0.008517 +0.008445 +0.00849 +0.008562 +0.008642 +0.008706 +0.008547 +0.008467 +0.008528 +0.008601 +0.008674 +0.008738 +0.008596 +0.00852 +0.008587 +0.008643 +0.008718 +0.008775 +0.008639 +0.008562 +0.008617 +0.008717 +0.008771 +0.008823 +0.008667 +0.008613 +0.008664 +0.008724 +0.008807 +0.008868 +0.008727 +0.008652 +0.008697 +0.008765 +0.00886 +0.008916 +0.008766 +0.008711 +0.008751 +0.00881 +0.008896 +0.008966 +0.008834 +0.008743 +0.008778 +0.008854 +0.008939 +0.009009 +0.008859 +0.008781 +0.008843 +0.008911 +0.009009 +0.009041 +0.008892 +0.008827 +0.008867 +0.008944 +0.009037 +0.009096 +0.008951 +0.008873 +0.008935 +0.009005 +0.009066 +0.00915 +0.008978 +0.00891 +0.008962 +0.009045 +0.009142 +0.009188 +0.009058 +0.00895 +0.009012 +0.009092 +0.00918 +0.009223 +0.009064 +0.008999 +0.009045 +0.009129 +0.009223 +0.00928 +0.009123 +0.009058 +0.009115 +0.009173 +0.009273 +0.009327 +0.009155 +0.009083 +0.009142 +0.009235 +0.009317 +0.009368 +0.009231 +0.009155 +0.009225 +0.009262 +0.009357 +0.00942 +0.009252 +0.009176 +0.009232 +0.009313 +0.009412 +0.009453 +0.009314 +0.009237 +0.009286 +0.00937 +0.009459 +0.009505 +0.009341 +0.009265 +0.00934 +0.009414 +0.009499 +0.009567 +0.009416 +0.009326 +0.00937 +0.00947 +0.009578 +0.009609 +0.009431 +0.009355 +0.009421 +0.009501 +0.009625 +0.009647 +0.009478 +0.00941 +0.009454 +0.009549 +0.009653 +0.009699 +0.009546 +0.009476 +0.009534 +0.009608 +0.009703 +0.009747 +0.009582 +0.009503 +0.009571 +0.009644 +0.009738 +0.009812 +0.009661 +0.00959 +0.009617 +0.009712 +0.00977 +0.009847 +0.009684 +0.009598 +0.009684 +0.009739 +0.009827 +0.009899 +0.009751 +0.009659 +0.009719 +0.009795 +0.009881 +0.009954 +0.009786 +0.009689 +0.009756 +0.009849 +0.009944 +0.010015 +0.009848 +0.009766 +0.009843 +0.009894 +0.009967 +0.010029 +0.009879 +0.009802 +0.009852 +0.009943 +0.010062 +0.01012 +0.009943 +0.009844 +0.009893 +0.009984 +0.010099 +0.010156 +0.009979 +0.009896 +0.009954 +0.010057 +0.010168 +0.010222 +0.01002 +0.009937 +0.010007 +0.010131 +0.0102 +0.010255 +0.010077 +0.009983 +0.010054 +0.010142 +0.010256 +0.010331 +0.010124 +0.010037 +0.010112 +0.010186 +0.010291 +0.010362 +0.010178 +0.010095 +0.010175 +0.010263 +0.010353 +0.010421 +0.010221 +0.010137 +0.010213 +0.010314 +0.010435 +0.01045 +0.010272 +0.010203 +0.010305 +0.010333 +0.010439 +0.010499 +0.010302 +0.010213 +0.01027 +0.010348 +0.010399 +0.010419 +0.010218 +0.010101 +0.01011 +0.010173 +0.010214 +0.010222 +0.009995 +0.009861 +0.009894 +0.009952 +0.009981 +0.010014 +0.009742 +0.009598 +0.009624 +0.009662 +0.009702 +0.009718 +0.009469 +0.009366 +0.009381 +0.009422 +0.009453 +0.009454 +0.009224 +0.00911 +0.009143 +0.009161 +0.009204 +0.009223 +0.009011 +0.008907 +0.008939 +0.008971 +0.009006 +0.009022 +0.008843 +0.008738 +0.008791 +0.008802 +0.008837 +0.008867 +0.008686 +0.008591 +0.008616 +0.008667 +0.008715 +0.008754 +0.008555 +0.008457 +0.008505 +0.008555 +0.008601 +0.008637 +0.008488 +0.008384 +0.008419 +0.00848 +0.008545 +0.008579 +0.008437 +0.008362 +0.008408 +0.008483 +0.008556 +0.00864 +0.008491 +0.008427 +0.008451 +0.008509 +0.00859 +0.008647 +0.008504 +0.008435 +0.00848 +0.008561 +0.008653 +0.008709 +0.008572 +0.008485 +0.008543 +0.008594 +0.008685 +0.008745 +0.008595 +0.008521 +0.00857 +0.008651 +0.008746 +0.008811 +0.008651 +0.00857 +0.008618 +0.008688 +0.008769 +0.008828 +0.008703 +0.008606 +0.008654 +0.008758 +0.008797 +0.008872 +0.008715 +0.008648 +0.0087 +0.008784 +0.008856 +0.008919 +0.008767 +0.008705 +0.008745 +0.008818 +0.008915 +0.00897 +0.008807 +0.008742 +0.008794 +0.00886 +0.008961 +0.00902 +0.00885 +0.008782 +0.008834 +0.008914 +0.009037 +0.009077 +0.008899 +0.00881 +0.008867 +0.008953 +0.009057 +0.00909 +0.008935 +0.008873 +0.008917 +0.008999 +0.009102 +0.009163 +0.008993 +0.008907 +0.008973 +0.009037 +0.009128 +0.009195 +0.009032 +0.008954 +0.009025 +0.009108 +0.009187 +0.009242 +0.009085 +0.008997 +0.009078 +0.009141 +0.009207 +0.009263 +0.009119 +0.009039 +0.009107 +0.00921 +0.009284 +0.00933 +0.009166 +0.00909 +0.009139 +0.009222 +0.009311 +0.00938 +0.009209 +0.009145 +0.009205 +0.00928 +0.009372 +0.009443 +0.009258 +0.009173 +0.00924 +0.009319 +0.009409 +0.009468 +0.009306 +0.00923 +0.009313 +0.009363 +0.009446 +0.009516 +0.009349 +0.009282 +0.009345 +0.009415 +0.00952 +0.009567 +0.009389 +0.00932 +0.009374 +0.009461 +0.009554 +0.00962 +0.009447 +0.00937 +0.009439 +0.009499 +0.009615 +0.009675 +0.009493 +0.009411 +0.009468 +0.009565 +0.009686 +0.009696 +0.009539 +0.009463 +0.009514 +0.009622 +0.009706 +0.009751 +0.009598 +0.009525 +0.009561 +0.009647 +0.009742 +0.0098 +0.009632 +0.009567 +0.009619 +0.009722 +0.009814 +0.009851 +0.009692 +0.009611 +0.009665 +0.009741 +0.009842 +0.009918 +0.009771 +0.009678 +0.00972 +0.009789 +0.009885 +0.009954 +0.009789 +0.009694 +0.009763 +0.009838 +0.00995 +0.010022 +0.009829 +0.009768 +0.009822 +0.009888 +0.009993 +0.010068 +0.009885 +0.009803 +0.009859 +0.009957 +0.010055 +0.010126 +0.009953 +0.009879 +0.009908 +0.009987 +0.010075 +0.010159 +0.009991 +0.009888 +0.009966 +0.01007 +0.010174 +0.010218 +0.010039 +0.009936 +0.010005 +0.010101 +0.010194 +0.010263 +0.010098 +0.010025 +0.010072 +0.010165 +0.01027 +0.010296 +0.010127 +0.010042 +0.01015 +0.010196 +0.010291 +0.010363 +0.010201 +0.010141 +0.010162 +0.010255 +0.010341 +0.010402 +0.01023 +0.010154 +0.010213 +0.010292 +0.010433 +0.010482 +0.0103 +0.010225 +0.010256 +0.01034 +0.010459 +0.010521 +0.010337 +0.010243 +0.010325 +0.010412 +0.010471 +0.010486 +0.010277 +0.010141 +0.010158 +0.010224 +0.010277 +0.010275 +0.010044 +0.00993 +0.009953 +0.009973 +0.010035 +0.010028 +0.009773 +0.009657 +0.009666 +0.009699 +0.009745 +0.009753 +0.009533 +0.009404 +0.00942 +0.009467 +0.009518 +0.009463 +0.009238 +0.009121 +0.009139 +0.009176 +0.009222 +0.009218 +0.009027 +0.008897 +0.008914 +0.008954 +0.008994 +0.009003 +0.008816 +0.008707 +0.008714 +0.008765 +0.008821 +0.008851 +0.008645 +0.008535 +0.008566 +0.008606 +0.008661 +0.008688 +0.008509 +0.008424 +0.008451 +0.008481 +0.008552 +0.008568 +0.008393 +0.0083 +0.008325 +0.008388 +0.008456 +0.008503 +0.008333 +0.008248 +0.008299 +0.008369 +0.008435 +0.008493 +0.008357 +0.008275 +0.008333 +0.008387 +0.008481 +0.008531 +0.008382 +0.008319 +0.008365 +0.008437 +0.008512 +0.008581 +0.008444 +0.008388 +0.008415 +0.00847 +0.008545 +0.00861 +0.008486 +0.008404 +0.00844 +0.00851 +0.008598 +0.00866 +0.008535 +0.008447 +0.008506 +0.008557 +0.008632 +0.008708 +0.008554 +0.008476 +0.008531 +0.008615 +0.008687 +0.008746 +0.008595 +0.00854 +0.008582 +0.00866 +0.00872 +0.00879 +0.008663 +0.008582 +0.008609 +0.008681 +0.008764 +0.008832 +0.008691 +0.008607 +0.008681 +0.008735 +0.008824 +0.008868 +0.008725 +0.00866 +0.008702 +0.00878 +0.008861 +0.008926 +0.008773 +0.008703 +0.008772 +0.008834 +0.008915 +0.008954 +0.008814 +0.008739 +0.00879 +0.008872 +0.008965 +0.009034 +0.008857 +0.00878 +0.008835 +0.008916 +0.009007 +0.00905 +0.008896 +0.008826 +0.008906 +0.008948 +0.00904 +0.009102 +0.008945 +0.008873 +0.008918 +0.009019 +0.009098 +0.00915 +0.009 +0.008913 +0.008964 +0.009046 +0.009133 +0.009189 +0.009036 +0.008966 +0.009024 +0.009128 +0.009213 +0.00923 +0.00906 +0.008996 +0.009057 +0.009138 +0.009215 +0.009277 +0.009121 +0.009059 +0.009121 +0.009199 +0.009276 +0.009336 +0.009171 +0.009081 +0.009145 +0.00923 +0.009323 +0.009373 +0.009214 +0.009157 +0.009204 +0.00928 +0.009384 +0.009438 +0.009277 +0.009172 +0.009225 +0.009326 +0.009415 +0.00947 +0.009296 +0.00924 +0.009302 +0.009384 +0.009462 +0.009523 +0.009339 +0.009267 +0.009325 +0.009421 +0.009511 +0.009562 +0.009421 +0.009343 +0.009385 +0.009469 +0.009566 +0.009605 +0.009437 +0.009369 +0.009447 +0.009528 +0.009597 +0.009645 +0.009507 +0.00943 +0.009507 +0.009557 +0.009641 +0.009697 +0.009534 +0.009456 +0.00953 +0.009608 +0.00971 +0.009762 +0.00959 +0.009511 +0.009569 +0.009663 +0.009741 +0.009807 +0.009648 +0.009555 +0.009622 +0.009729 +0.009819 +0.009875 +0.009681 +0.009591 +0.00966 +0.00975 +0.009844 +0.009911 +0.009768 +0.009653 +0.009714 +0.009794 +0.009904 +0.009954 +0.009791 +0.009719 +0.009768 +0.009849 +0.009953 +0.010016 +0.009832 +0.009763 +0.009809 +0.009888 +0.010006 +0.010075 +0.009937 +0.009792 +0.009846 +0.009943 +0.010045 +0.010133 +0.009942 +0.009841 +0.009913 +0.00999 +0.010096 +0.010176 +0.009985 +0.009899 +0.009975 +0.010055 +0.010162 +0.010245 +0.010051 +0.009938 +0.01001 +0.010092 +0.010197 +0.010265 +0.010094 +0.010038 +0.010058 +0.010194 +0.010255 +0.010295 +0.010129 +0.010043 +0.010108 +0.010202 +0.010293 +0.010371 +0.010191 +0.01011 +0.01019 +0.010277 +0.010349 +0.010411 +0.010251 +0.010147 +0.010205 +0.010313 +0.010407 +0.010449 +0.010288 +0.010209 +0.010212 +0.010251 +0.0103 +0.010337 +0.010109 +0.009969 +0.010008 +0.010051 +0.010096 +0.010112 +0.009892 +0.009753 +0.009764 +0.009798 +0.00983 +0.009846 +0.009632 +0.009496 +0.009529 +0.009553 +0.009584 +0.009586 +0.00938 +0.009234 +0.009248 +0.009286 +0.009327 +0.009332 +0.009107 +0.008984 +0.00902 +0.009059 +0.00911 +0.009083 +0.008891 +0.008783 +0.008793 +0.008837 +0.008875 +0.008903 +0.008707 +0.008607 +0.008653 +0.008698 +0.00873 +0.008746 +0.008579 +0.008474 +0.008492 +0.008544 +0.008588 +0.008613 +0.008452 +0.008365 +0.008392 +0.008473 +0.008507 +0.008518 +0.008362 +0.008281 +0.008324 +0.008384 +0.008419 +0.008486 +0.008318 +0.008248 +0.008316 +0.008389 +0.008455 +0.008503 +0.008367 +0.008289 +0.008344 +0.008418 +0.008501 +0.008546 +0.008411 +0.008337 +0.008383 +0.008476 +0.008551 +0.008594 +0.008453 +0.008382 +0.008445 +0.008524 +0.008574 +0.008636 +0.008488 +0.008418 +0.008478 +0.008547 +0.008646 +0.008688 +0.008531 +0.008451 +0.008511 +0.008593 +0.008669 +0.008726 +0.008571 +0.008512 +0.008556 +0.008647 +0.00872 +0.008805 +0.008624 +0.008536 +0.008598 +0.008663 +0.008754 +0.008807 +0.008673 +0.008595 +0.008666 +0.008717 +0.008822 +0.008852 +0.00871 +0.008634 +0.008684 +0.008749 +0.008827 +0.008897 +0.008741 +0.008682 +0.008738 +0.008809 +0.008896 +0.00896 +0.008812 +0.008724 +0.008766 +0.008846 +0.008925 +0.008989 +0.008844 +0.008773 +0.008807 +0.00889 +0.008981 +0.00906 +0.008923 +0.008818 +0.008851 +0.00892 +0.009034 +0.009079 +0.008917 +0.008846 +0.0089 +0.008999 +0.009086 +0.009141 +0.008976 +0.008904 +0.008941 +0.009011 +0.009113 +0.009161 +0.009013 +0.008941 +0.008993 +0.009084 +0.009171 +0.009238 +0.00907 +0.00899 +0.009034 +0.009116 +0.009227 +0.009246 +0.009103 +0.009025 +0.00908 +0.009184 +0.009273 +0.009316 +0.00916 +0.009073 +0.009121 +0.009195 +0.009297 +0.009358 +0.009195 +0.009132 +0.009206 +0.009245 +0.009341 +0.0094 +0.00924 +0.009162 +0.009221 +0.009288 +0.009387 +0.009471 +0.0093 +0.009256 +0.009281 +0.009333 +0.009431 +0.00949 +0.009338 +0.009246 +0.009301 +0.009401 +0.009486 +0.009569 +0.009397 +0.009322 +0.009365 +0.009427 +0.009534 +0.009597 +0.009427 +0.00937 +0.009391 +0.009484 +0.009585 +0.009661 +0.009488 +0.009405 +0.009446 +0.009554 +0.009665 +0.009672 +0.009505 +0.009433 +0.009501 +0.009582 +0.00969 +0.009755 +0.009586 +0.009483 +0.009541 +0.009633 +0.009726 +0.009787 +0.009623 +0.00953 +0.009604 +0.009691 +0.009799 +0.009852 +0.009671 +0.009568 +0.009639 +0.009721 +0.009834 +0.009914 +0.009718 +0.009642 +0.009721 +0.009783 +0.009881 +0.009931 +0.009744 +0.009677 +0.009743 +0.009815 +0.009924 +0.009994 +0.009818 +0.009745 +0.009803 +0.009891 +0.009982 +0.010031 +0.009852 +0.009773 +0.009849 +0.009923 +0.010015 +0.010102 +0.009939 +0.00987 +0.009888 +0.009974 +0.01006 +0.010143 +0.009962 +0.009863 +0.009929 +0.010033 +0.01012 +0.010199 +0.010029 +0.009942 +0.01 +0.010068 +0.010164 +0.010233 +0.010066 +0.009972 +0.01003 +0.010153 +0.010245 +0.010307 +0.01013 +0.010051 +0.0101 +0.010156 +0.01026 +0.010329 +0.010165 +0.010064 +0.010153 +0.010259 +0.010347 +0.010394 +0.010214 +0.010109 +0.010183 +0.010277 +0.010381 +0.01048 +0.010232 +0.010146 +0.010205 +0.01029 +0.010354 +0.010369 +0.010158 +0.010019 +0.010063 +0.010128 +0.010207 +0.010139 +0.009928 +0.009783 +0.009815 +0.009852 +0.009884 +0.009929 +0.009663 +0.009534 +0.009537 +0.009612 +0.00962 +0.009628 +0.009425 +0.009274 +0.009302 +0.009335 +0.009367 +0.009368 +0.009166 +0.009043 +0.00906 +0.009098 +0.009137 +0.009145 +0.008969 +0.008806 +0.008833 +0.008875 +0.008915 +0.008938 +0.008743 +0.00863 +0.008662 +0.008726 +0.008766 +0.008767 +0.008597 +0.008487 +0.008525 +0.008571 +0.008636 +0.008646 +0.008478 +0.008382 +0.008418 +0.008471 +0.008526 +0.008549 +0.008376 +0.008287 +0.008323 +0.008394 +0.008449 +0.008494 +0.008314 +0.008229 +0.008272 +0.008344 +0.008417 +0.008482 +0.008308 +0.008238 +0.0083 +0.008366 +0.008443 +0.008508 +0.00838 +0.008278 +0.008321 +0.0084 +0.008493 +0.008546 +0.008411 +0.008327 +0.008381 +0.008447 +0.008534 +0.008601 +0.008436 +0.008368 +0.008417 +0.008501 +0.008594 +0.008648 +0.008483 +0.008417 +0.008473 +0.008528 +0.008619 +0.008672 +0.00852 +0.008449 +0.008506 +0.008575 +0.008656 +0.008721 +0.008572 +0.008502 +0.008591 +0.008619 +0.00869 +0.008754 +0.008611 +0.008539 +0.008589 +0.008655 +0.00875 +0.008804 +0.008655 +0.008585 +0.00865 +0.008732 +0.008805 +0.008836 +0.008692 +0.00862 +0.008674 +0.008755 +0.00883 +0.008907 +0.008737 +0.008668 +0.00872 +0.008802 +0.008882 +0.008936 +0.008776 +0.008712 +0.008772 +0.008834 +0.008915 +0.008983 +0.008831 +0.008757 +0.008808 +0.008904 +0.008973 +0.009022 +0.008881 +0.008807 +0.008876 +0.008919 +0.009006 +0.009055 +0.008925 +0.008844 +0.008899 +0.008985 +0.009067 +0.009143 +0.008951 +0.008879 +0.008936 +0.009007 +0.009099 +0.009156 +0.00902 +0.008936 +0.008999 +0.009089 +0.009151 +0.009197 +0.009051 +0.008973 +0.009023 +0.009101 +0.009198 +0.009264 +0.009117 +0.009017 +0.009081 +0.009168 +0.009254 +0.009292 +0.009139 +0.009059 +0.009115 +0.009192 +0.009281 +0.009368 +0.009188 +0.009108 +0.009179 +0.009264 +0.009335 +0.009384 +0.009237 +0.00916 +0.00921 +0.009287 +0.00938 +0.009432 +0.009281 +0.009215 +0.009283 +0.009379 +0.009431 +0.00947 +0.009325 +0.009241 +0.0093 +0.009379 +0.00946 +0.00955 +0.009382 +0.009302 +0.009366 +0.009448 +0.009539 +0.009572 +0.009416 +0.009327 +0.00939 +0.009476 +0.009556 +0.009643 +0.009482 +0.009411 +0.009454 +0.009535 +0.009606 +0.009701 +0.009514 +0.009419 +0.009481 +0.009559 +0.009678 +0.009767 +0.009557 +0.009489 +0.00954 +0.009607 +0.009707 +0.009769 +0.009602 +0.009523 +0.009584 +0.009655 +0.009786 +0.009851 +0.009663 +0.009581 +0.009645 +0.00971 +0.009799 +0.009875 +0.009703 +0.009661 +0.009704 +0.009763 +0.009845 +0.009917 +0.009748 +0.009659 +0.009737 +0.009817 +0.0099 +0.009988 +0.00982 +0.009729 +0.009784 +0.009857 +0.009959 +0.010018 +0.009859 +0.009759 +0.009818 +0.00993 +0.010023 +0.010092 +0.009919 +0.009818 +0.00986 +0.009964 +0.010073 +0.010165 +0.00994 +0.00986 +0.009906 +0.010012 +0.010118 +0.010176 +0.010024 +0.009907 +0.009971 +0.010062 +0.010176 +0.010233 +0.010045 +0.00997 +0.010019 +0.010116 +0.010221 +0.010273 +0.010098 +0.010027 +0.010073 +0.010164 +0.0103 +0.010359 +0.01017 +0.010049 +0.010124 +0.010202 +0.010314 +0.010371 +0.010202 +0.010138 +0.010186 +0.010278 +0.010361 +0.010434 +0.010245 +0.010153 +0.010208 +0.010287 +0.010386 +0.010435 +0.01022 +0.010091 +0.010114 +0.010151 +0.010206 +0.010215 +0.009983 +0.009858 +0.009904 +0.009953 +0.009946 +0.009938 +0.009706 +0.009587 +0.009586 +0.009633 +0.009674 +0.00968 +0.009463 +0.009313 +0.009352 +0.009385 +0.009415 +0.009422 +0.009199 +0.009075 +0.009088 +0.009157 +0.009154 +0.009176 +0.008982 +0.008854 +0.008878 +0.008927 +0.008972 +0.008996 +0.008787 +0.008686 +0.00868 +0.008737 +0.008787 +0.008816 +0.008641 +0.008531 +0.008568 +0.008618 +0.008681 +0.008683 +0.008515 +0.008406 +0.008437 +0.008494 +0.008553 +0.008573 +0.00841 +0.008321 +0.008344 +0.008414 +0.00848 +0.008526 +0.008339 +0.008255 +0.008302 +0.008371 +0.00847 +0.008519 +0.00835 +0.008264 +0.008346 +0.008422 +0.008488 +0.008541 +0.008397 +0.00833 +0.008366 +0.008447 +0.00852 +0.008572 +0.008437 +0.008366 +0.008414 +0.008497 +0.008575 +0.008637 +0.008487 +0.008424 +0.008458 +0.008518 +0.008613 +0.008673 +0.008541 +0.008447 +0.008502 +0.008573 +0.008687 +0.008718 +0.008565 +0.008495 +0.008545 +0.008618 +0.008709 +0.008752 +0.008597 +0.008539 +0.008576 +0.008663 +0.008732 +0.008814 +0.008666 +0.00858 +0.008642 +0.008709 +0.008772 +0.008838 +0.008696 +0.008615 +0.008672 +0.008749 +0.008832 +0.008893 +0.00875 +0.008687 +0.008733 +0.008822 +0.008875 +0.008912 +0.00877 +0.008701 +0.008764 +0.008826 +0.008928 +0.00897 +0.008831 +0.008754 +0.008796 +0.008877 +0.008962 +0.009017 +0.008876 +0.008804 +0.008852 +0.008945 +0.009026 +0.009065 +0.008913 +0.008842 +0.008891 +0.008961 +0.009051 +0.009116 +0.008967 +0.00892 +0.008932 +0.009001 +0.009101 +0.00916 +0.009008 +0.008922 +0.008974 +0.00906 +0.009145 +0.009206 +0.009051 +0.008975 +0.009022 +0.009105 +0.009204 +0.009265 +0.009091 +0.009015 +0.009073 +0.009161 +0.009228 +0.009299 +0.009134 +0.009056 +0.009118 +0.009201 +0.00932 +0.009359 +0.009178 +0.009122 +0.009149 +0.009239 +0.009323 +0.009383 +0.009232 +0.009156 +0.009206 +0.009289 +0.009395 +0.009444 +0.009273 +0.009195 +0.009256 +0.00933 +0.009429 +0.009497 +0.00932 +0.009247 +0.009305 +0.009385 +0.00948 +0.009547 +0.009382 +0.009308 +0.009353 +0.009425 +0.009506 +0.009576 +0.009436 +0.009325 +0.009381 +0.009475 +0.009583 +0.009647 +0.009447 +0.009385 +0.00944 +0.009527 +0.009621 +0.009672 +0.009506 +0.009434 +0.009484 +0.009583 +0.009681 +0.009741 +0.009549 +0.009479 +0.009535 +0.00964 +0.009738 +0.009758 +0.009588 +0.009533 +0.009597 +0.009673 +0.009775 +0.009828 +0.009639 +0.009577 +0.00962 +0.009719 +0.009797 +0.009867 +0.009729 +0.009639 +0.009693 +0.009785 +0.009864 +0.009906 +0.009748 +0.00966 +0.009722 +0.009813 +0.009917 +0.010027 +0.009814 +0.009724 +0.009782 +0.009866 +0.009972 +0.009992 +0.009838 +0.009766 +0.009821 +0.009935 +0.010016 +0.010061 +0.009897 +0.009819 +0.009869 +0.009958 +0.010057 +0.010143 +0.009942 +0.009867 +0.00995 +0.010011 +0.010106 +0.010185 +0.010032 +0.00992 +0.009973 +0.010039 +0.010162 +0.010234 +0.010056 +0.00998 +0.010027 +0.010104 +0.010217 +0.010309 +0.010082 +0.010001 +0.010067 +0.01015 +0.010271 +0.010354 +0.01017 +0.01008 +0.010132 +0.010217 +0.010341 +0.010364 +0.010187 +0.010147 +0.010167 +0.010253 +0.010406 +0.010455 +0.010249 +0.010144 +0.01022 +0.01031 +0.010401 +0.010457 +0.010266 +0.010158 +0.010194 +0.010275 +0.010319 +0.010341 +0.010132 +0.009995 +0.010005 +0.010056 +0.010115 +0.01011 +0.009903 +0.009796 +0.009825 +0.009832 +0.009868 +0.009882 +0.009664 +0.009577 +0.00955 +0.00959 +0.009634 +0.009654 +0.009446 +0.009341 +0.009351 +0.009368 +0.00942 +0.009415 +0.009219 +0.009108 +0.009119 +0.009151 +0.009195 +0.009221 +0.009024 +0.008926 +0.008943 +0.008975 +0.009049 +0.009022 +0.008839 +0.008733 +0.008759 +0.008803 +0.00885 +0.008875 +0.008706 +0.008622 +0.008635 +0.008686 +0.008728 +0.00876 +0.008569 +0.008482 +0.008517 +0.008558 +0.008615 +0.008674 +0.008487 +0.008397 +0.008455 +0.00851 +0.008576 +0.008628 +0.008473 +0.008404 +0.008446 +0.008547 +0.008611 +0.008648 +0.008502 +0.008431 +0.008488 +0.008577 +0.008647 +0.008708 +0.008562 +0.008476 +0.008534 +0.0086 +0.008691 +0.008734 +0.008593 +0.008518 +0.008583 +0.008655 +0.008729 +0.008799 +0.008655 +0.008565 +0.008619 +0.008693 +0.008785 +0.008826 +0.008685 +0.00861 +0.008696 +0.008747 +0.008822 +0.00889 +0.00871 +0.008649 +0.008696 +0.008774 +0.008848 +0.008923 +0.00877 +0.008701 +0.008752 +0.00884 +0.008912 +0.00896 +0.008815 +0.008732 +0.008792 +0.008861 +0.008956 +0.009009 +0.008857 +0.008795 +0.008838 +0.00892 +0.009007 +0.00907 +0.00892 +0.008831 +0.008869 +0.008939 +0.009036 +0.009119 +0.008943 +0.008867 +0.008916 +0.009014 +0.009092 +0.00916 +0.008982 +0.008906 +0.008966 +0.009047 +0.009137 +0.009183 +0.009032 +0.008969 +0.009026 +0.0091 +0.009187 +0.009251 +0.009061 +0.009 +0.009058 +0.009142 +0.009251 +0.009283 +0.009125 +0.009033 +0.0091 +0.009181 +0.009267 +0.00933 +0.009168 +0.009093 +0.009151 +0.009223 +0.009324 +0.009376 +0.009224 +0.00914 +0.009198 +0.009287 +0.00936 +0.009427 +0.009258 +0.009179 +0.009241 +0.00931 +0.009413 +0.009484 +0.00933 +0.009258 +0.009281 +0.009366 +0.009454 +0.009509 +0.009355 +0.009264 +0.009326 +0.00942 +0.009503 +0.009587 +0.009392 +0.00933 +0.009382 +0.009461 +0.009566 +0.009601 +0.009439 +0.009382 +0.009443 +0.009514 +0.009613 +0.009677 +0.00949 +0.009411 +0.009475 +0.009575 +0.009665 +0.009721 +0.009518 +0.009451 +0.009516 +0.009627 +0.009707 +0.00977 +0.009579 +0.00951 +0.009566 +0.009653 +0.009739 +0.009798 +0.009656 +0.009551 +0.009627 +0.009722 +0.009811 +0.009844 +0.009686 +0.009598 +0.00966 +0.009746 +0.00985 +0.009934 +0.009745 +0.009661 +0.009714 +0.009828 +0.009888 +0.009931 +0.009773 +0.009706 +0.009763 +0.009856 +0.009934 +0.010009 +0.00985 +0.009762 +0.009819 +0.009881 +0.009986 +0.010059 +0.009878 +0.009792 +0.009869 +0.009943 +0.010048 +0.01013 +0.009966 +0.009881 +0.009906 +0.009973 +0.010082 +0.010157 +0.010001 +0.009886 +0.009951 +0.010063 +0.010167 +0.010209 +0.010047 +0.009937 +0.010004 +0.010098 +0.010192 +0.010253 +0.010084 +0.009987 +0.010078 +0.010168 +0.010257 +0.010317 +0.010131 +0.010063 +0.010114 +0.010187 +0.010284 +0.010349 +0.010203 +0.010107 +0.010167 +0.01027 +0.010348 +0.010404 +0.010236 +0.010134 +0.010211 +0.010306 +0.010407 +0.010493 +0.010301 +0.0102 +0.010266 +0.010356 +0.010441 +0.010513 +0.010345 +0.010262 +0.010359 +0.010387 +0.010518 +0.01056 +0.010381 +0.010274 +0.010309 +0.010399 +0.010448 +0.010473 +0.010246 +0.010128 +0.010184 +0.010225 +0.010268 +0.010245 +0.010016 +0.009869 +0.009895 +0.009937 +0.009961 +0.009976 +0.009749 +0.009611 +0.009632 +0.009681 +0.009715 +0.009747 +0.009467 +0.009344 +0.009366 +0.009404 +0.009444 +0.009445 +0.00923 +0.009113 +0.009123 +0.009161 +0.009198 +0.009202 +0.008994 +0.008885 +0.008907 +0.008954 +0.009005 +0.009011 +0.008811 +0.008707 +0.008727 +0.008783 +0.008817 +0.008837 +0.008652 +0.008561 +0.008611 +0.008652 +0.008692 +0.008718 +0.00851 +0.008423 +0.008462 +0.008507 +0.008562 +0.008593 +0.008421 +0.008324 +0.008379 +0.008455 +0.008504 +0.008537 +0.008379 +0.0083 +0.008344 +0.00842 +0.008496 +0.00855 +0.008412 +0.008338 +0.008388 +0.008462 +0.008556 +0.008602 +0.008463 +0.00839 +0.008443 +0.008495 +0.008574 +0.008631 +0.008485 +0.008418 +0.008466 +0.00854 +0.008635 +0.00869 +0.008535 +0.008466 +0.00851 +0.008591 +0.008673 +0.008746 +0.00858 +0.008507 +0.008577 +0.008623 +0.008716 +0.008763 +0.008611 +0.008546 +0.008599 +0.008677 +0.00876 +0.008814 +0.008675 +0.008614 +0.008648 +0.008706 +0.008793 +0.008855 +0.008706 +0.008636 +0.008685 +0.008762 +0.008854 +0.008914 +0.008759 +0.008674 +0.00873 +0.008808 +0.008882 +0.008954 +0.00881 +0.008711 +0.008779 +0.008849 +0.008925 +0.009003 +0.008865 +0.008764 +0.008815 +0.008887 +0.008989 +0.009063 +0.008892 +0.008803 +0.008858 +0.008934 +0.009032 +0.009099 +0.008939 +0.008857 +0.008921 +0.00898 +0.009062 +0.009122 +0.008974 +0.008886 +0.008942 +0.009035 +0.009123 +0.009188 +0.009037 +0.008935 +0.008984 +0.009069 +0.009164 +0.009223 +0.009059 +0.008989 +0.009045 +0.009165 +0.009244 +0.009262 +0.009103 +0.009022 +0.00908 +0.009162 +0.009242 +0.009313 +0.009154 +0.009064 +0.009137 +0.009229 +0.009314 +0.009363 +0.009208 +0.009119 +0.009164 +0.009252 +0.009351 +0.009401 +0.009252 +0.009172 +0.009214 +0.009298 +0.009395 +0.009466 +0.009321 +0.009208 +0.009259 +0.009353 +0.009455 +0.009501 +0.00934 +0.009251 +0.009324 +0.009405 +0.009488 +0.009547 +0.009389 +0.009296 +0.009361 +0.009448 +0.009545 +0.009608 +0.009443 +0.009353 +0.009393 +0.009492 +0.009592 +0.009636 +0.009483 +0.009403 +0.009467 +0.009563 +0.00962 +0.009685 +0.00952 +0.009447 +0.009504 +0.009583 +0.009691 +0.009746 +0.009587 +0.00949 +0.009551 +0.009639 +0.009724 +0.009811 +0.009616 +0.009525 +0.0096 +0.009686 +0.00978 +0.00985 +0.009691 +0.009579 +0.009642 +0.009753 +0.009842 +0.009907 +0.009705 +0.009616 +0.009692 +0.009798 +0.009887 +0.009949 +0.009759 +0.009689 +0.00974 +0.00982 +0.009935 +0.009983 +0.009819 +0.009739 +0.009813 +0.009913 +0.009985 +0.010019 +0.009856 +0.009785 +0.009838 +0.009927 +0.010032 +0.010105 +0.009994 +0.00983 +0.009888 +0.009983 +0.010057 +0.010129 +0.009962 +0.009884 +0.009943 +0.010039 +0.010126 +0.010215 +0.010017 +0.009941 +0.010008 +0.010064 +0.010171 +0.010249 +0.010074 +0.009974 +0.010051 +0.010119 +0.010228 +0.010302 +0.010125 +0.010065 +0.010083 +0.010204 +0.010268 +0.010346 +0.010169 +0.010081 +0.01015 +0.010237 +0.010336 +0.010398 +0.010222 +0.010125 +0.010195 +0.010295 +0.010407 +0.010468 +0.010249 +0.010141 +0.010206 +0.01031 +0.010376 +0.010389 +0.010175 +0.010025 +0.010065 +0.01015 +0.010193 +0.010137 +0.009911 +0.00978 +0.009797 +0.009835 +0.009861 +0.009869 +0.009641 +0.00951 +0.009536 +0.009585 +0.009568 +0.009575 +0.009364 +0.009217 +0.009236 +0.009277 +0.009306 +0.009317 +0.009114 +0.008982 +0.008998 +0.009027 +0.009064 +0.00906 +0.008888 +0.00874 +0.00876 +0.008803 +0.008868 +0.008866 +0.008683 +0.008568 +0.008598 +0.008656 +0.008692 +0.008702 +0.00853 +0.00843 +0.008463 +0.008517 +0.008576 +0.008589 +0.008426 +0.008325 +0.008371 +0.008419 +0.008477 +0.008503 +0.008322 +0.008235 +0.008273 +0.008341 +0.008398 +0.008459 +0.008279 +0.008191 +0.008249 +0.008324 +0.008391 +0.008453 +0.008307 +0.008204 +0.008274 +0.008331 +0.008417 +0.008468 +0.008334 +0.008266 +0.008309 +0.008395 +0.008479 +0.008529 +0.008381 +0.008308 +0.008352 +0.008417 +0.008504 +0.008562 +0.008418 +0.008348 +0.008392 +0.008481 +0.008567 +0.00864 +0.008483 +0.008386 +0.008441 +0.008497 +0.008582 +0.008648 +0.008498 +0.008425 +0.00851 +0.008541 +0.008634 +0.008696 +0.008555 +0.008476 +0.008527 +0.008602 +0.008666 +0.008724 +0.008589 +0.008514 +0.008556 +0.008628 +0.00871 +0.008791 +0.008635 +0.00856 +0.008618 +0.008685 +0.008795 +0.008821 +0.00868 +0.008603 +0.008652 +0.008726 +0.008829 +0.008871 +0.008712 +0.00865 +0.00869 +0.008771 +0.008855 +0.008915 +0.008755 +0.008691 +0.008744 +0.008808 +0.008907 +0.008968 +0.008807 +0.008734 +0.008788 +0.008863 +0.008935 +0.009004 +0.008846 +0.008784 +0.008845 +0.008921 +0.008988 +0.009055 +0.008889 +0.008807 +0.008873 +0.008949 +0.009028 +0.009096 +0.008935 +0.008861 +0.008917 +0.009003 +0.009097 +0.009149 +0.00899 +0.008896 +0.008954 +0.009032 +0.009129 +0.009178 +0.009019 +0.008962 +0.009009 +0.009089 +0.009173 +0.009255 +0.009104 +0.009001 +0.009045 +0.009114 +0.009212 +0.009283 +0.009125 +0.009032 +0.009097 +0.009185 +0.009271 +0.009336 +0.009171 +0.009076 +0.009132 +0.00922 +0.009314 +0.009368 +0.009205 +0.009143 +0.009185 +0.00929 +0.009378 +0.009431 +0.009251 +0.009169 +0.009232 +0.009336 +0.009424 +0.009455 +0.009296 +0.009218 +0.009285 +0.009387 +0.009466 +0.009539 +0.009357 +0.00925 +0.009314 +0.009412 +0.009496 +0.009551 +0.009398 +0.009311 +0.009381 +0.009457 +0.009555 +0.009609 +0.009438 +0.009366 +0.009406 +0.009506 +0.009608 +0.009686 +0.009527 +0.009407 +0.009463 +0.009546 +0.009639 +0.00972 +0.009523 +0.00945 +0.00952 +0.009622 +0.009702 +0.009759 +0.009578 +0.009502 +0.00956 +0.00966 +0.009746 +0.009797 +0.00965 +0.00955 +0.009609 +0.00971 +0.009807 +0.009842 +0.009687 +0.009608 +0.009699 +0.009742 +0.009851 +0.009886 +0.009726 +0.00966 +0.009705 +0.00981 +0.00991 +0.009937 +0.009774 +0.00971 +0.00975 +0.009837 +0.009942 +0.009996 +0.009832 +0.009757 +0.009833 +0.009913 +0.009984 +0.010042 +0.009874 +0.009793 +0.009862 +0.009974 +0.010049 +0.010098 +0.009925 +0.009887 +0.009916 +0.009972 +0.010083 +0.010152 +0.009972 +0.009888 +0.009955 +0.010042 +0.01015 +0.010217 +0.010047 +0.009954 +0.009997 +0.010093 +0.010191 +0.01026 +0.010086 +0.009992 +0.010058 +0.010152 +0.010295 +0.010329 +0.010133 +0.010029 +0.010095 +0.010203 +0.010317 +0.010345 +0.010181 +0.010081 +0.010165 +0.010272 +0.010358 +0.010403 +0.010205 +0.010104 +0.010157 +0.010233 +0.010276 +0.010293 +0.010091 +0.009987 +0.009999 +0.010037 +0.010102 +0.010123 +0.009857 +0.00972 +0.009735 +0.009783 +0.009822 +0.009817 +0.009609 +0.009503 +0.009463 +0.009506 +0.009544 +0.009531 +0.009322 +0.009198 +0.009215 +0.009248 +0.009284 +0.009296 +0.009081 +0.00895 +0.008973 +0.009001 +0.009033 +0.009042 +0.008858 +0.00875 +0.008793 +0.008797 +0.008836 +0.008853 +0.008675 +0.008586 +0.008584 +0.00864 +0.008684 +0.008706 +0.008531 +0.008439 +0.008471 +0.008519 +0.008574 +0.0086 +0.008433 +0.008331 +0.008368 +0.008407 +0.008461 +0.008485 +0.008322 +0.00824 +0.008277 +0.00833 +0.008394 +0.008446 +0.008296 +0.008229 +0.008254 +0.008319 +0.008392 +0.008417 +0.008292 +0.008235 +0.008274 +0.008344 +0.008424 +0.008478 +0.008339 +0.008263 +0.008324 +0.008389 +0.008472 +0.008522 +0.008389 +0.008312 +0.00836 +0.00844 +0.008526 +0.008569 +0.008425 +0.008356 +0.008398 +0.008474 +0.008562 +0.00862 +0.00848 +0.008414 +0.008437 +0.008512 +0.008615 +0.008656 +0.008534 +0.008425 +0.008478 +0.008558 +0.008639 +0.008699 +0.008547 +0.008479 +0.00853 +0.008603 +0.008698 +0.008761 +0.008594 +0.008514 +0.008567 +0.008648 +0.008725 +0.008783 +0.008647 +0.008557 +0.00861 +0.008682 +0.008782 +0.008861 +0.008712 +0.008613 +0.008655 +0.008717 +0.008812 +0.008884 +0.008718 +0.008668 +0.008701 +0.008771 +0.008858 +0.008929 +0.008785 +0.008701 +0.00875 +0.008811 +0.008901 +0.008962 +0.008811 +0.008742 +0.008785 +0.008855 +0.008951 +0.009028 +0.008865 +0.008793 +0.008849 +0.008921 +0.009018 +0.009044 +0.008886 +0.008815 +0.008873 +0.008955 +0.009038 +0.009106 +0.008957 +0.008888 +0.008942 +0.008995 +0.009081 +0.009133 +0.008987 +0.008909 +0.008969 +0.009046 +0.009121 +0.009211 +0.009048 +0.008969 +0.009023 +0.009096 +0.009171 +0.009216 +0.00909 +0.009018 +0.009077 +0.009135 +0.009238 +0.009272 +0.009119 +0.009055 +0.009098 +0.009176 +0.009272 +0.00933 +0.009169 +0.009099 +0.009147 +0.009231 +0.009324 +0.009387 +0.009218 +0.009138 +0.009199 +0.009284 +0.009357 +0.00943 +0.009273 +0.009188 +0.009237 +0.009336 +0.009433 +0.009499 +0.009302 +0.009221 +0.00928 +0.009391 +0.009453 +0.009507 +0.009358 +0.009281 +0.00933 +0.009427 +0.009502 +0.009576 +0.009408 +0.009324 +0.009388 +0.009456 +0.009555 +0.009629 +0.00945 +0.009369 +0.009433 +0.009534 +0.009594 +0.009666 +0.009506 +0.009444 +0.00949 +0.009548 +0.00964 +0.009715 +0.009567 +0.009499 +0.009526 +0.009608 +0.009686 +0.009751 +0.009591 +0.009515 +0.00957 +0.009648 +0.009765 +0.009814 +0.009661 +0.009581 +0.00962 +0.009686 +0.009793 +0.009862 +0.009689 +0.009611 +0.009683 +0.009784 +0.009864 +0.009905 +0.009743 +0.009662 +0.009719 +0.009785 +0.009886 +0.009987 +0.009774 +0.009703 +0.009766 +0.009849 +0.009956 +0.010026 +0.009849 +0.009748 +0.009814 +0.009901 +0.009991 +0.010059 +0.009898 +0.009795 +0.009858 +0.009971 +0.01009 +0.010166 +0.009926 +0.009836 +0.009895 +0.010008 +0.010087 +0.010155 +0.009987 +0.009909 +0.009978 +0.010063 +0.010161 +0.010195 +0.010028 +0.00995 +0.010007 +0.010105 +0.010205 +0.010267 +0.010114 +0.010018 +0.010075 +0.010155 +0.010245 +0.010333 +0.01014 +0.010041 +0.010123 +0.01018 +0.01032 +0.010383 +0.010193 +0.010115 +0.010163 +0.01023 +0.010331 +0.010387 +0.010196 +0.010096 +0.010108 +0.010193 +0.010245 +0.010257 +0.010058 +0.009911 +0.009926 +0.009968 +0.010015 +0.010003 +0.009816 +0.00968 +0.009733 +0.009721 +0.009746 +0.009767 +0.009549 +0.009419 +0.009414 +0.009442 +0.009486 +0.009497 +0.009311 +0.00918 +0.009193 +0.009225 +0.009247 +0.009266 +0.009068 +0.008949 +0.008985 +0.008997 +0.009038 +0.009069 +0.008899 +0.008765 +0.008782 +0.008828 +0.008878 +0.008921 +0.008719 +0.008616 +0.008642 +0.008689 +0.008749 +0.008783 +0.008612 +0.008513 +0.008534 +0.008582 +0.008625 +0.008671 +0.008502 +0.008412 +0.008436 +0.008498 +0.008542 +0.00859 +0.008435 +0.008365 +0.008392 +0.008429 +0.008503 +0.008557 +0.008409 +0.008336 +0.008395 +0.00845 +0.008566 +0.008591 +0.00845 +0.008373 +0.008438 +0.008505 +0.008562 +0.008632 +0.008502 +0.008426 +0.008464 +0.008539 +0.008615 +0.008684 +0.008537 +0.008458 +0.008512 +0.008597 +0.008662 +0.008717 +0.008584 +0.008506 +0.00855 +0.008625 +0.008711 +0.008778 +0.008617 +0.008549 +0.008594 +0.008714 +0.008767 +0.008798 +0.008645 +0.008587 +0.008638 +0.008711 +0.00879 +0.008846 +0.008715 +0.008631 +0.008698 +0.008762 +0.008851 +0.008895 +0.008739 +0.00868 +0.008726 +0.008795 +0.008888 +0.008946 +0.008795 +0.008716 +0.008774 +0.008853 +0.008936 +0.008988 +0.008842 +0.008778 +0.008831 +0.008881 +0.008964 +0.009039 +0.008879 +0.00881 +0.008844 +0.00894 +0.009035 +0.009085 +0.008933 +0.008852 +0.008921 +0.00897 +0.009055 +0.009124 +0.008967 +0.008894 +0.008937 +0.009039 +0.009137 +0.009173 +0.00903 +0.00894 +0.008978 +0.009067 +0.009157 +0.009236 +0.009069 +0.008972 +0.00902 +0.009129 +0.009236 +0.009264 +0.009107 +0.009031 +0.009074 +0.009145 +0.00924 +0.009307 +0.009147 +0.009069 +0.009118 +0.009226 +0.009311 +0.00937 +0.009213 +0.009126 +0.009155 +0.009246 +0.009336 +0.009405 +0.009238 +0.009158 +0.009224 +0.009325 +0.009388 +0.009436 +0.009298 +0.009205 +0.009266 +0.009357 +0.00943 +0.009502 +0.009328 +0.009267 +0.009325 +0.009387 +0.009483 +0.009547 +0.009388 +0.009303 +0.009345 +0.009445 +0.009537 +0.009591 +0.009442 +0.009362 +0.009398 +0.009491 +0.009591 +0.009676 +0.009484 +0.009381 +0.009436 +0.009545 +0.009621 +0.009688 +0.009537 +0.009456 +0.009514 +0.009575 +0.009678 +0.009729 +0.009568 +0.009491 +0.009541 +0.009636 +0.009747 +0.009811 +0.009625 +0.009527 +0.009592 +0.009674 +0.009771 +0.009843 +0.009663 +0.009569 +0.009658 +0.009748 +0.009864 +0.009897 +0.009713 +0.009622 +0.009685 +0.009776 +0.00987 +0.009936 +0.009789 +0.009664 +0.009751 +0.00985 +0.009938 +0.009992 +0.009807 +0.00973 +0.009778 +0.009887 +0.009966 +0.01003 +0.009869 +0.009787 +0.009854 +0.009939 +0.010044 +0.010114 +0.009908 +0.009814 +0.00988 +0.009961 +0.01008 +0.01013 +0.00996 +0.009884 +0.009931 +0.010055 +0.010119 +0.010182 +0.010011 +0.009932 +0.009995 +0.010084 +0.010177 +0.010235 +0.010066 +0.009984 +0.010032 +0.010111 +0.010219 +0.010308 +0.010161 +0.010046 +0.010092 +0.01021 +0.010254 +0.010336 +0.010154 +0.010068 +0.010137 +0.010214 +0.010333 +0.010412 +0.010231 +0.01014 +0.010204 +0.01027 +0.010373 +0.010445 +0.010257 +0.010174 +0.010247 +0.01035 +0.010451 +0.01052 +0.010355 +0.01023 +0.010272 +0.010367 +0.010465 +0.010556 +0.010315 +0.010237 +0.010301 +0.010327 +0.010381 +0.010425 +0.010158 +0.010031 +0.010063 +0.010093 +0.01014 +0.010151 +0.009945 +0.009797 +0.009816 +0.009831 +0.009864 +0.009847 +0.009633 +0.009546 +0.009529 +0.00954 +0.009563 +0.009588 +0.009392 +0.009256 +0.009298 +0.009303 +0.009308 +0.009309 +0.009125 +0.009013 +0.009034 +0.00906 +0.009097 +0.009095 +0.008917 +0.008807 +0.00883 +0.008865 +0.0089 +0.008935 +0.008747 +0.008648 +0.008674 +0.00872 +0.008787 +0.008794 +0.008606 +0.008501 +0.008533 +0.008572 +0.008633 +0.00864 +0.008487 +0.008395 +0.00843 +0.008505 +0.008527 +0.008556 +0.008387 +0.008312 +0.008352 +0.008414 +0.008476 +0.008514 +0.00837 +0.008315 +0.008356 +0.008424 +0.008517 +0.008571 +0.008415 +0.008338 +0.008389 +0.008473 +0.00856 +0.008597 +0.008469 +0.008365 +0.008431 +0.008519 +0.008602 +0.008653 +0.0085 +0.008443 +0.008468 +0.008545 +0.008633 +0.008687 +0.008545 +0.008466 +0.008529 +0.008589 +0.00869 +0.008723 +0.008587 +0.008509 +0.008558 +0.008641 +0.008716 +0.008771 +0.008627 +0.008559 +0.008613 +0.00871 +0.008769 +0.008811 +0.008664 +0.008601 +0.00866 +0.008713 +0.008794 +0.008861 +0.008719 +0.008642 +0.008705 +0.008773 +0.008843 +0.008905 +0.008759 +0.008686 +0.008732 +0.008805 +0.008884 +0.008963 +0.008802 +0.008732 +0.0088 +0.008867 +0.008934 +0.008992 +0.008847 +0.008781 +0.008835 +0.008892 +0.008967 +0.009032 +0.008896 +0.008831 +0.008897 +0.008943 +0.009028 +0.009075 +0.008932 +0.008852 +0.008911 +0.008986 +0.009064 +0.009136 +0.008986 +0.008911 +0.008958 +0.009046 +0.009115 +0.009166 +0.009027 +0.008941 +0.009 +0.009076 +0.009171 +0.009251 +0.00909 +0.008982 +0.009024 +0.009119 +0.009209 +0.009262 +0.009118 +0.009046 +0.009117 +0.009174 +0.009268 +0.009308 +0.009149 +0.009075 +0.009134 +0.009207 +0.009296 +0.009374 +0.00921 +0.009131 +0.00919 +0.009279 +0.00935 +0.009392 +0.009258 +0.009167 +0.009219 +0.009314 +0.009407 +0.009484 +0.0093 +0.009214 +0.009274 +0.009361 +0.009457 +0.009508 +0.009331 +0.009281 +0.009312 +0.009399 +0.009489 +0.009561 +0.009382 +0.00931 +0.009376 +0.009449 +0.009548 +0.009606 +0.009424 +0.009349 +0.009408 +0.009508 +0.009589 +0.009646 +0.009507 +0.009418 +0.009505 +0.009535 +0.009639 +0.009669 +0.009518 +0.009447 +0.009506 +0.009592 +0.009689 +0.009745 +0.00958 +0.009509 +0.00956 +0.009644 +0.009751 +0.00978 +0.009616 +0.009549 +0.009598 +0.009688 +0.009778 +0.009843 +0.009681 +0.009606 +0.009684 +0.009766 +0.009842 +0.009873 +0.009727 +0.009619 +0.009693 +0.009785 +0.009869 +0.009938 +0.009789 +0.0097 +0.009761 +0.009857 +0.009911 +0.009982 +0.009823 +0.009727 +0.00979 +0.009884 +0.009975 +0.010063 +0.009893 +0.009796 +0.00985 +0.009922 +0.01004 +0.010124 +0.009907 +0.009822 +0.009882 +0.009994 +0.010113 +0.010146 +0.009971 +0.009898 +0.00993 +0.010022 +0.010132 +0.010182 +0.010023 +0.009934 +0.00999 +0.010108 +0.010201 +0.010257 +0.010068 +0.009977 +0.010035 +0.010126 +0.010247 +0.010316 +0.010142 +0.010026 +0.010092 +0.01018 +0.010306 +0.010355 +0.010185 +0.010071 +0.010134 +0.010229 +0.010336 +0.010401 +0.010233 +0.010148 +0.010212 +0.010302 +0.010357 +0.010425 +0.010237 +0.010135 +0.010181 +0.010219 +0.010277 +0.01033 +0.010112 +0.01001 +0.009986 +0.009991 +0.010052 +0.010045 +0.00983 +0.009701 +0.009704 +0.009778 +0.009776 +0.00979 +0.00958 +0.009447 +0.009428 +0.00947 +0.009495 +0.00951 +0.009305 +0.009187 +0.009187 +0.009223 +0.009267 +0.00927 +0.009076 +0.008975 +0.008976 +0.009036 +0.009084 +0.009054 +0.008874 +0.008781 +0.008784 +0.008827 +0.008865 +0.008893 +0.008722 +0.008612 +0.008641 +0.00868 +0.008733 +0.008754 +0.008587 +0.008508 +0.008526 +0.008555 +0.008602 +0.008644 +0.008469 +0.00838 +0.008407 +0.008454 +0.008504 +0.008553 +0.008412 +0.008311 +0.008376 +0.008397 +0.008453 +0.00851 +0.008364 +0.008288 +0.008345 +0.008401 +0.008481 +0.008553 +0.008404 +0.008343 +0.008386 +0.00847 +0.00853 +0.008581 +0.008439 +0.008371 +0.008423 +0.008493 +0.008578 +0.008634 +0.008504 +0.008423 +0.008477 +0.008545 +0.008624 +0.008671 +0.00853 +0.008462 +0.008527 +0.008572 +0.008655 +0.008727 +0.008557 +0.008531 +0.008552 +0.008611 +0.008694 +0.008759 +0.008606 +0.008541 +0.008596 +0.008663 +0.008744 +0.008819 +0.008677 +0.008592 +0.008641 +0.008717 +0.008784 +0.008841 +0.0087 +0.008631 +0.008681 +0.008751 +0.008835 +0.008898 +0.008778 +0.008695 +0.008723 +0.0088 +0.008861 +0.008929 +0.008788 +0.008715 +0.008786 +0.008834 +0.008918 +0.008977 +0.008831 +0.008764 +0.008806 +0.00888 +0.008968 +0.00903 +0.008883 +0.008798 +0.008862 +0.008935 +0.009028 +0.009075 +0.008922 +0.008845 +0.008895 +0.008983 +0.00908 +0.009137 +0.008961 +0.008879 +0.008935 +0.00902 +0.009129 +0.00916 +0.009005 +0.008942 +0.009002 +0.009061 +0.009153 +0.009209 +0.009055 +0.008982 +0.00905 +0.009121 +0.009211 +0.009247 +0.009107 +0.009021 +0.009077 +0.009166 +0.009241 +0.009303 +0.009161 +0.009077 +0.009165 +0.009218 +0.009309 +0.009338 +0.00918 +0.009113 +0.009164 +0.009246 +0.009338 +0.009405 +0.009231 +0.009159 +0.009239 +0.009283 +0.009388 +0.009449 +0.009287 +0.00921 +0.009267 +0.009351 +0.009449 +0.009498 +0.009334 +0.009247 +0.009307 +0.009402 +0.009489 +0.009571 +0.009384 +0.009299 +0.009345 +0.009457 +0.009544 +0.009581 +0.009415 +0.009342 +0.009398 +0.009484 +0.009577 +0.009644 +0.009479 +0.009406 +0.00947 +0.009541 +0.009628 +0.009687 +0.009516 +0.009436 +0.009498 +0.009581 +0.009664 +0.009751 +0.009575 +0.009534 +0.009567 +0.009637 +0.009721 +0.009767 +0.009618 +0.009551 +0.009582 +0.009674 +0.009771 +0.00983 +0.00966 +0.009587 +0.009641 +0.009728 +0.009828 +0.009888 +0.009716 +0.00964 +0.009696 +0.009781 +0.00987 +0.00993 +0.009762 +0.009692 +0.009745 +0.009858 +0.009919 +0.009973 +0.009799 +0.009735 +0.009813 +0.009861 +0.009972 +0.010064 +0.009845 +0.009772 +0.009832 +0.009929 +0.010021 +0.01011 +0.009913 +0.009835 +0.009887 +0.00997 +0.010068 +0.010137 +0.00996 +0.009864 +0.009944 +0.010029 +0.010188 +0.010218 +0.010003 +0.009907 +0.009968 +0.010072 +0.010159 +0.010233 +0.010065 +0.009959 +0.010037 +0.010134 +0.010222 +0.010292 +0.010115 +0.010032 +0.010082 +0.010183 +0.010284 +0.010357 +0.010159 +0.010069 +0.010133 +0.010239 +0.010344 +0.010418 +0.0102 +0.010132 +0.010191 +0.010286 +0.010378 +0.010424 +0.010246 +0.010148 +0.010207 +0.010289 +0.010357 +0.010371 +0.010161 +0.01002 +0.010047 +0.01011 +0.010112 +0.010128 +0.009893 +0.00975 +0.009772 +0.009812 +0.009839 +0.00985 +0.009624 +0.009519 +0.009513 +0.009533 +0.009584 +0.009593 +0.009366 +0.009227 +0.009253 +0.009305 +0.009326 +0.009334 +0.009127 +0.00901 +0.009027 +0.009062 +0.009113 +0.009121 +0.008921 +0.008797 +0.00884 +0.008891 +0.008913 +0.008942 +0.00875 +0.008644 +0.00867 +0.008727 +0.00878 +0.008815 +0.008605 +0.008503 +0.008555 +0.008606 +0.008657 +0.008665 +0.008489 +0.008391 +0.008437 +0.00848 +0.008538 +0.008565 +0.00839 +0.008312 +0.00835 +0.008424 +0.008463 +0.0085 +0.008326 +0.008257 +0.008297 +0.008375 +0.008449 +0.008502 +0.008361 +0.008284 +0.008362 +0.008405 +0.008515 +0.008552 +0.008397 +0.008309 +0.008365 +0.008439 +0.008528 +0.008578 +0.008438 +0.008385 +0.008412 +0.008496 +0.008579 +0.008639 +0.008485 +0.008412 +0.008453 +0.008531 +0.008603 +0.008674 +0.008521 +0.008457 +0.008515 +0.008568 +0.008675 +0.008722 +0.00857 +0.008501 +0.008552 +0.008626 +0.008728 +0.008738 +0.008593 +0.008529 +0.008587 +0.008662 +0.008729 +0.008791 +0.008654 +0.008585 +0.008642 +0.008691 +0.008792 +0.008843 +0.008697 +0.008622 +0.008679 +0.008756 +0.008823 +0.008896 +0.00874 +0.008667 +0.00871 +0.0088 +0.008877 +0.008934 +0.00879 +0.008716 +0.008802 +0.00885 +0.008919 +0.008981 +0.008812 +0.008742 +0.008797 +0.008868 +0.008956 +0.009025 +0.008866 +0.008795 +0.00886 +0.00894 +0.009021 +0.00906 +0.008911 +0.008836 +0.008884 +0.008968 +0.009052 +0.009103 +0.00896 +0.008893 +0.008949 +0.009025 +0.009111 +0.009173 +0.009021 +0.008926 +0.008968 +0.009044 +0.009136 +0.009223 +0.009045 +0.00897 +0.009032 +0.009119 +0.009191 +0.009252 +0.009093 +0.00901 +0.009064 +0.009145 +0.009238 +0.009287 +0.009143 +0.009083 +0.009124 +0.009211 +0.009302 +0.009356 +0.009181 +0.009098 +0.00916 +0.009246 +0.00935 +0.009388 +0.009212 +0.009142 +0.009207 +0.009297 +0.009403 +0.009425 +0.009285 +0.009198 +0.009244 +0.009335 +0.009427 +0.009483 +0.009324 +0.009249 +0.009307 +0.009383 +0.009483 +0.009525 +0.009372 +0.009301 +0.009358 +0.009445 +0.009525 +0.009577 +0.009445 +0.009341 +0.009392 +0.009465 +0.00956 +0.009635 +0.009453 +0.009376 +0.009456 +0.009567 +0.009609 +0.009669 +0.009514 +0.009434 +0.009484 +0.00958 +0.009651 +0.009731 +0.009581 +0.009493 +0.009545 +0.009637 +0.009711 +0.009777 +0.009599 +0.009526 +0.009606 +0.009681 +0.009759 +0.009824 +0.009665 +0.009586 +0.009638 +0.009703 +0.009809 +0.009873 +0.009702 +0.009641 +0.009676 +0.009751 +0.00986 +0.009935 +0.009762 +0.009666 +0.009727 +0.009812 +0.009924 +0.009984 +0.009826 +0.009729 +0.009765 +0.009865 +0.010001 +0.010013 +0.009841 +0.00978 +0.009818 +0.009915 +0.009998 +0.010076 +0.009928 +0.009801 +0.009872 +0.009968 +0.010063 +0.010126 +0.00995 +0.009867 +0.009923 +0.010044 +0.010133 +0.010187 +0.009985 +0.009917 +0.009969 +0.010058 +0.010166 +0.010258 +0.010048 +0.009949 +0.010034 +0.010119 +0.010261 +0.010243 +0.010087 +0.010012 +0.010065 +0.010159 +0.010263 +0.010342 +0.010163 +0.010085 +0.010126 +0.010208 +0.010316 +0.010377 +0.010192 +0.010115 +0.010185 +0.010243 +0.010373 +0.010429 +0.010244 +0.010092 +0.010102 +0.010152 +0.010206 +0.010227 +0.010023 +0.009916 +0.009891 +0.009936 +0.009983 +0.009978 +0.009776 +0.009627 +0.009634 +0.009673 +0.009712 +0.009739 +0.009519 +0.009383 +0.00937 +0.009404 +0.00944 +0.009454 +0.009242 +0.009128 +0.00914 +0.009207 +0.009209 +0.009215 +0.009019 +0.008896 +0.008918 +0.00894 +0.008987 +0.009034 +0.008831 +0.008708 +0.008741 +0.008798 +0.008829 +0.008861 +0.008687 +0.008587 +0.00859 +0.008646 +0.008695 +0.008726 +0.008559 +0.008467 +0.008487 +0.008522 +0.008575 +0.008615 +0.008453 +0.008369 +0.008412 +0.00842 +0.008471 +0.008516 +0.008369 +0.008284 +0.00832 +0.008375 +0.008444 +0.008509 +0.008359 +0.008293 +0.008332 +0.008396 +0.008482 +0.008538 +0.008403 +0.008327 +0.008388 +0.008455 +0.00852 +0.008582 +0.00843 +0.008363 +0.008416 +0.008484 +0.008562 +0.008621 +0.008485 +0.008433 +0.008465 +0.008543 +0.008638 +0.008646 +0.008511 +0.008446 +0.008515 +0.008564 +0.00865 +0.008697 +0.008558 +0.008499 +0.00856 +0.008629 +0.008699 +0.008752 +0.008598 +0.008531 +0.008579 +0.008656 +0.008739 +0.008795 +0.008651 +0.008583 +0.008636 +0.008708 +0.008793 +0.008854 +0.00871 +0.008615 +0.008666 +0.008731 +0.008818 +0.008896 +0.008739 +0.008656 +0.008702 +0.008791 +0.008866 +0.008935 +0.008784 +0.00871 +0.008755 +0.00883 +0.008928 +0.008986 +0.008839 +0.008743 +0.0088 +0.00888 +0.008958 +0.009034 +0.008865 +0.008787 +0.008867 +0.008919 +0.009031 +0.009079 +0.008917 +0.008833 +0.008879 +0.008959 +0.009055 +0.009103 +0.008975 +0.008877 +0.008933 +0.009007 +0.009108 +0.009172 +0.009008 +0.008922 +0.00898 +0.009053 +0.009145 +0.009199 +0.009053 +0.008967 +0.009024 +0.009109 +0.009196 +0.009261 +0.009104 +0.009025 +0.009091 +0.009143 +0.009229 +0.009286 +0.009133 +0.009059 +0.009113 +0.0092 +0.009296 +0.009364 +0.009187 +0.009101 +0.009165 +0.009241 +0.009322 +0.009397 +0.009225 +0.00914 +0.00921 +0.009312 +0.009391 +0.009441 +0.009284 +0.009189 +0.009247 +0.009334 +0.009423 +0.009518 +0.009328 +0.009246 +0.009282 +0.009367 +0.009474 +0.009528 +0.009365 +0.009291 +0.009346 +0.00943 +0.009537 +0.00959 +0.009421 +0.009322 +0.009402 +0.009476 +0.009558 +0.009634 +0.009462 +0.00938 +0.009448 +0.009525 +0.009634 +0.00969 +0.00951 +0.009445 +0.0095 +0.009563 +0.009651 +0.009738 +0.009554 +0.009471 +0.009529 +0.00963 +0.009723 +0.009767 +0.009603 +0.009531 +0.009576 +0.009666 +0.009773 +0.009822 +0.009651 +0.009588 +0.00965 +0.009729 +0.009832 +0.009857 +0.009699 +0.009614 +0.009677 +0.009785 +0.009868 +0.009912 +0.009749 +0.009675 +0.00974 +0.009847 +0.009883 +0.00996 +0.009794 +0.00971 +0.009776 +0.009861 +0.009953 +0.010031 +0.009861 +0.009765 +0.009816 +0.009906 +0.010006 +0.010079 +0.009913 +0.009833 +0.009879 +0.009956 +0.010067 +0.010154 +0.009934 +0.009846 +0.009907 +0.010008 +0.01011 +0.010171 +0.010034 +0.009918 +0.009958 +0.010054 +0.010163 +0.010224 +0.010045 +0.00996 +0.010028 +0.010119 +0.010238 +0.010273 +0.010096 +0.010013 +0.010058 +0.010157 +0.010271 +0.010344 +0.010187 +0.010041 +0.010121 +0.010218 +0.010329 +0.010358 +0.010186 +0.010115 +0.010166 +0.01026 +0.010358 +0.010415 +0.01024 +0.010144 +0.010188 +0.010234 +0.010269 +0.01029 +0.010084 +0.009941 +0.009966 +0.01001 +0.010065 +0.010076 +0.009844 +0.009746 +0.009739 +0.009762 +0.009745 +0.009757 +0.009558 +0.009429 +0.00946 +0.009491 +0.009506 +0.009513 +0.009317 +0.009196 +0.009209 +0.009239 +0.009275 +0.009286 +0.009084 +0.008984 +0.009 +0.009043 +0.009056 +0.009069 +0.00888 +0.008777 +0.008809 +0.008845 +0.008906 +0.008889 +0.008719 +0.008626 +0.008681 +0.008706 +0.008735 +0.008748 +0.008583 +0.008504 +0.008525 +0.008575 +0.008626 +0.00865 +0.008489 +0.008397 +0.008438 +0.008484 +0.008535 +0.008553 +0.008403 +0.008313 +0.008364 +0.008412 +0.008469 +0.008518 +0.008367 +0.0083 +0.008347 +0.008441 +0.008502 +0.008543 +0.008401 +0.00832 +0.008368 +0.008447 +0.008551 +0.008576 +0.008429 +0.008356 +0.008408 +0.008498 +0.008592 +0.008649 +0.008491 +0.00842 +0.008474 +0.00852 +0.008609 +0.008671 +0.008523 +0.008452 +0.008503 +0.008582 +0.008664 +0.008736 +0.008579 +0.008518 +0.008566 +0.008637 +0.008684 +0.008743 +0.008602 +0.008533 +0.008593 +0.008657 +0.008737 +0.008807 +0.008674 +0.008594 +0.008643 +0.008717 +0.008787 +0.008839 +0.00869 +0.008627 +0.008674 +0.008748 +0.008842 +0.00889 +0.008751 +0.008682 +0.008733 +0.0088 +0.008879 +0.00893 +0.008787 +0.008736 +0.008775 +0.008834 +0.008911 +0.008974 +0.008833 +0.008765 +0.008814 +0.008892 +0.008973 +0.00902 +0.008874 +0.008795 +0.008855 +0.008936 +0.009012 +0.009078 +0.008909 +0.008853 +0.008907 +0.008987 +0.009092 +0.009129 +0.008955 +0.008872 +0.008932 +0.009014 +0.009101 +0.009188 +0.009001 +0.008936 +0.009003 +0.009069 +0.00916 +0.009214 +0.00904 +0.008969 +0.009023 +0.009098 +0.009193 +0.009259 +0.009114 +0.009024 +0.009086 +0.009168 +0.009253 +0.009307 +0.00914 +0.009054 +0.009112 +0.009193 +0.009291 +0.009346 +0.009184 +0.009131 +0.0092 +0.009278 +0.009341 +0.009389 +0.009217 +0.009147 +0.009226 +0.009282 +0.009377 +0.009439 +0.009277 +0.009219 +0.009277 +0.009361 +0.00944 +0.009488 +0.009321 +0.009236 +0.009299 +0.009392 +0.009481 +0.009544 +0.009378 +0.009308 +0.009361 +0.009448 +0.009539 +0.009606 +0.009416 +0.009332 +0.009384 +0.009478 +0.009575 +0.009626 +0.009483 +0.0094 +0.009462 +0.009532 +0.009629 +0.009675 +0.009509 +0.00943 +0.009499 +0.00957 +0.009698 +0.009729 +0.009578 +0.009497 +0.009544 +0.00964 +0.009714 +0.009768 +0.009613 +0.009553 +0.009604 +0.009663 +0.009747 +0.009837 +0.00968 +0.009586 +0.009644 +0.009732 +0.00982 +0.009871 +0.009691 +0.009631 +0.009686 +0.009761 +0.009886 +0.009943 +0.009769 +0.009695 +0.009741 +0.009814 +0.009915 +0.009969 +0.009802 +0.00972 +0.009784 +0.009911 +0.00999 +0.010051 +0.009853 +0.009773 +0.009824 +0.009904 +0.010009 +0.010089 +0.009896 +0.009812 +0.009898 +0.009988 +0.010077 +0.010143 +0.009955 +0.009858 +0.009926 +0.010013 +0.010126 +0.010188 +0.009999 +0.009927 +0.009996 +0.010089 +0.010222 +0.010228 +0.010034 +0.009959 +0.010045 +0.01011 +0.010207 +0.010282 +0.010108 +0.010018 +0.010068 +0.01017 +0.010258 +0.010343 +0.010169 +0.010066 +0.010131 +0.010244 +0.010317 +0.010395 +0.010204 +0.010099 +0.01016 +0.010247 +0.010339 +0.010383 +0.01012 +0.009997 +0.010046 +0.010087 +0.010142 +0.01015 +0.009915 +0.009792 +0.009814 +0.009851 +0.009893 +0.009894 +0.00968 +0.009567 +0.009601 +0.009611 +0.009641 +0.009648 +0.009431 +0.009296 +0.009327 +0.009353 +0.009395 +0.009416 +0.009202 +0.009111 +0.009113 +0.009143 +0.009164 +0.009179 +0.008986 +0.008866 +0.008896 +0.008959 +0.008977 +0.009017 +0.008807 +0.008697 +0.008723 +0.00878 +0.008812 +0.008845 +0.008648 +0.008552 +0.008586 +0.008642 +0.008687 +0.008713 +0.008555 +0.008444 +0.008479 +0.008535 +0.008591 +0.008618 +0.008454 +0.008338 +0.008378 +0.00844 +0.00851 +0.008562 +0.008393 +0.008313 +0.008361 +0.008445 +0.008534 +0.008569 +0.008426 +0.008358 +0.008404 +0.00847 +0.00855 +0.008618 +0.008475 +0.008397 +0.008455 +0.008521 +0.008599 +0.008659 +0.008517 +0.008432 +0.008487 +0.008566 +0.00865 +0.008745 +0.008565 +0.008487 +0.008527 +0.008591 +0.008681 +0.008745 +0.008609 +0.008513 +0.008574 +0.008645 +0.008723 +0.008783 +0.008665 +0.008567 +0.008603 +0.008687 +0.00877 +0.008832 +0.008676 +0.008612 +0.008656 +0.008729 +0.008834 +0.008887 +0.008729 +0.008658 +0.008701 +0.008775 +0.008883 +0.008906 +0.008762 +0.008681 +0.008736 +0.008826 +0.008907 +0.008976 +0.008821 +0.008753 +0.008794 +0.008848 +0.008942 +0.009 +0.008852 +0.008792 +0.008832 +0.008896 +0.008991 +0.00906 +0.008907 +0.008827 +0.008874 +0.008947 +0.009036 +0.009096 +0.008948 +0.008878 +0.008959 +0.008992 +0.009076 +0.00913 +0.008987 +0.008918 +0.008971 +0.009046 +0.009122 +0.009191 +0.009025 +0.008957 +0.009025 +0.009084 +0.009171 +0.009231 +0.009085 +0.009002 +0.009058 +0.009134 +0.009228 +0.009273 +0.00914 +0.00906 +0.009105 +0.009187 +0.009294 +0.009339 +0.009181 +0.009081 +0.009135 +0.009215 +0.009323 +0.009363 +0.009212 +0.009126 +0.009217 +0.009266 +0.009352 +0.009426 +0.009257 +0.009187 +0.009238 +0.009316 +0.009411 +0.00946 +0.009315 +0.009232 +0.009279 +0.009371 +0.009456 +0.009518 +0.009364 +0.009283 +0.00937 +0.009445 +0.009511 +0.009534 +0.009379 +0.009319 +0.009371 +0.009455 +0.009554 +0.009611 +0.009452 +0.009372 +0.009442 +0.009499 +0.009604 +0.009653 +0.009486 +0.009415 +0.009475 +0.009564 +0.009651 +0.009707 +0.009549 +0.00947 +0.009526 +0.009624 +0.009703 +0.009776 +0.009572 +0.009501 +0.009571 +0.009637 +0.009739 +0.009817 +0.009645 +0.009574 +0.009617 +0.009697 +0.009796 +0.009874 +0.009674 +0.0096 +0.009649 +0.00973 +0.009859 +0.009926 +0.009747 +0.00966 +0.009723 +0.009777 +0.009886 +0.009956 +0.009807 +0.009711 +0.009753 +0.009832 +0.009935 +0.010013 +0.009841 +0.009741 +0.009802 +0.009888 +0.009992 +0.010058 +0.009886 +0.009802 +0.009849 +0.009969 +0.010036 +0.010105 +0.009941 +0.009841 +0.009903 +0.010005 +0.010105 +0.010177 +0.009987 +0.00991 +0.009977 +0.010033 +0.010139 +0.010191 +0.01003 +0.009941 +0.010005 +0.01013 +0.010215 +0.010236 +0.010076 +0.009991 +0.010052 +0.010145 +0.010247 +0.010306 +0.010148 +0.010069 +0.010124 +0.010204 +0.010286 +0.010348 +0.01018 +0.0101 +0.010209 +0.010228 +0.01031 +0.010383 +0.010177 +0.01008 +0.010083 +0.010124 +0.010177 +0.010218 +0.009992 +0.009865 +0.009858 +0.009914 +0.009974 +0.009969 +0.009754 +0.009597 +0.009604 +0.009649 +0.009671 +0.009691 +0.009484 +0.009342 +0.009347 +0.009391 +0.009437 +0.009479 +0.009245 +0.009105 +0.009116 +0.00915 +0.009198 +0.009216 +0.009029 +0.008894 +0.008914 +0.008944 +0.009016 +0.009014 +0.008825 +0.008715 +0.008734 +0.008783 +0.008824 +0.008856 +0.008698 +0.008585 +0.008596 +0.008636 +0.008703 +0.008723 +0.008556 +0.008459 +0.008485 +0.008549 +0.008609 +0.008628 +0.008472 +0.008371 +0.008382 +0.008441 +0.008496 +0.008544 +0.008392 +0.008317 +0.008347 +0.008407 +0.008486 +0.008556 +0.00842 +0.008341 +0.008393 +0.008453 +0.008517 +0.008591 +0.008443 +0.008366 +0.008422 +0.008494 +0.008578 +0.008625 +0.008488 +0.008419 +0.008472 +0.008563 +0.008613 +0.008664 +0.008523 +0.008455 +0.008527 +0.008575 +0.008666 +0.00871 +0.008572 +0.008505 +0.008551 +0.008619 +0.008702 +0.008751 +0.008611 +0.008545 +0.008591 +0.008659 +0.008756 +0.008826 +0.008655 +0.008578 +0.008631 +0.008706 +0.008787 +0.00886 +0.008698 +0.008632 +0.008696 +0.008759 +0.008841 +0.008893 +0.008744 +0.008666 +0.008718 +0.008809 +0.008876 +0.008938 +0.008779 +0.008706 +0.008765 +0.008843 +0.008935 +0.008992 +0.008847 +0.008748 +0.008803 +0.008884 +0.008961 +0.009025 +0.00887 +0.008809 +0.008866 +0.008937 +0.009011 +0.009082 +0.008951 +0.008846 +0.008888 +0.008966 +0.009042 +0.009119 +0.008964 +0.008882 +0.00895 +0.009043 +0.009114 +0.00916 +0.00901 +0.008933 +0.008978 +0.009057 +0.009143 +0.00921 +0.009058 +0.008988 +0.009037 +0.009124 +0.009192 +0.009266 +0.009099 +0.009022 +0.009085 +0.009163 +0.009265 +0.00931 +0.009136 +0.009053 +0.00912 +0.009224 +0.009279 +0.009349 +0.009197 +0.009107 +0.009165 +0.009247 +0.009335 +0.009396 +0.009241 +0.009178 +0.009222 +0.009303 +0.009396 +0.009439 +0.009278 +0.00921 +0.009261 +0.009329 +0.009426 +0.009497 +0.009351 +0.009291 +0.009314 +0.009392 +0.009494 +0.009533 +0.009375 +0.009288 +0.009341 +0.009434 +0.009515 +0.009578 +0.009444 +0.009353 +0.00942 +0.009499 +0.009592 +0.00962 +0.009475 +0.009394 +0.009436 +0.009521 +0.009634 +0.009679 +0.009517 +0.009434 +0.009503 +0.009622 +0.009671 +0.009733 +0.009568 +0.009482 +0.009546 +0.009654 +0.009708 +0.00978 +0.009609 +0.009531 +0.009592 +0.009683 +0.009767 +0.009837 +0.009678 +0.009578 +0.009652 +0.009735 +0.009809 +0.009883 +0.009716 +0.00963 +0.009693 +0.009778 +0.009877 +0.009972 +0.009762 +0.009669 +0.009751 +0.00981 +0.009923 +0.009985 +0.009809 +0.009745 +0.009769 +0.009863 +0.009979 +0.010028 +0.009862 +0.009803 +0.009831 +0.009916 +0.01003 +0.010077 +0.009905 +0.00982 +0.009883 +0.009978 +0.01008 +0.010159 +0.010006 +0.00988 +0.009909 +0.010007 +0.010109 +0.010186 +0.009996 +0.009912 +0.009993 +0.010093 +0.01019 +0.01025 +0.010041 +0.009962 +0.010033 +0.010114 +0.010223 +0.010297 +0.010106 +0.010015 +0.010087 +0.010172 +0.010275 +0.010343 +0.010167 +0.010109 +0.01013 +0.010232 +0.010353 +0.010385 +0.010171 +0.010085 +0.010143 +0.010226 +0.01028 +0.010297 +0.010093 +0.009941 +0.009986 +0.010062 +0.010085 +0.010091 +0.00986 +0.009722 +0.00975 +0.009792 +0.009813 +0.00983 +0.009621 +0.009485 +0.0095 +0.009543 +0.009574 +0.009568 +0.009337 +0.009225 +0.009227 +0.009269 +0.009304 +0.009315 +0.009115 +0.008999 +0.009008 +0.009044 +0.009076 +0.009085 +0.008889 +0.008769 +0.008815 +0.008834 +0.008886 +0.008915 +0.008734 +0.00863 +0.00865 +0.008711 +0.008734 +0.008745 +0.008571 +0.008474 +0.008523 +0.00857 +0.008601 +0.00861 +0.00845 +0.008362 +0.008396 +0.00844 +0.008498 +0.008522 +0.008365 +0.008276 +0.00832 +0.008389 +0.008457 +0.008484 +0.008327 +0.008268 +0.008309 +0.008383 +0.008458 +0.008519 +0.008371 +0.008296 +0.008342 +0.008416 +0.008512 +0.008584 +0.008413 +0.008336 +0.008407 +0.008464 +0.008539 +0.008584 +0.008449 +0.008373 +0.008434 +0.008519 +0.008585 +0.00865 +0.008501 +0.008419 +0.008469 +0.008552 +0.008637 +0.008688 +0.008538 +0.008469 +0.008514 +0.008576 +0.008675 +0.008736 +0.008587 +0.008519 +0.008574 +0.008638 +0.0087 +0.008773 +0.00863 +0.008573 +0.008608 +0.008673 +0.008741 +0.008811 +0.008666 +0.008608 +0.008655 +0.008727 +0.008814 +0.008863 +0.008701 +0.008633 +0.00869 +0.008756 +0.008838 +0.008906 +0.00876 +0.008684 +0.008741 +0.008831 +0.008894 +0.008939 +0.008797 +0.008726 +0.008773 +0.008841 +0.008939 +0.008995 +0.008864 +0.008782 +0.008821 +0.0089 +0.008986 +0.009035 +0.008875 +0.008805 +0.008856 +0.008936 +0.009017 +0.009084 +0.008933 +0.008852 +0.00892 +0.008999 +0.009089 +0.009121 +0.008971 +0.008907 +0.008949 +0.009026 +0.009111 +0.009176 +0.009016 +0.008945 +0.009015 +0.0091 +0.009203 +0.009217 +0.009047 +0.00899 +0.009026 +0.009123 +0.009192 +0.009266 +0.009113 +0.009025 +0.009097 +0.009175 +0.009268 +0.009321 +0.009147 +0.009087 +0.009122 +0.009211 +0.009309 +0.009364 +0.009195 +0.009118 +0.009193 +0.00928 +0.009351 +0.009418 +0.009249 +0.009186 +0.009216 +0.009302 +0.009393 +0.009447 +0.0093 +0.009203 +0.009277 +0.009365 +0.009447 +0.009507 +0.009326 +0.00926 +0.009317 +0.009397 +0.009506 +0.009534 +0.009392 +0.009313 +0.009362 +0.009443 +0.009533 +0.009605 +0.00943 +0.009368 +0.009432 +0.009515 +0.009601 +0.009645 +0.00947 +0.009394 +0.009454 +0.009546 +0.009633 +0.00972 +0.009518 +0.009441 +0.009498 +0.009595 +0.009677 +0.009752 +0.009588 +0.00949 +0.009562 +0.009636 +0.009732 +0.009788 +0.009624 +0.009551 +0.009593 +0.009686 +0.009801 +0.009866 +0.009696 +0.009583 +0.009636 +0.009734 +0.009825 +0.009891 +0.009723 +0.009639 +0.0097 +0.009799 +0.009873 +0.00994 +0.009766 +0.009688 +0.009767 +0.009823 +0.009925 +0.010004 +0.009832 +0.00973 +0.009801 +0.00988 +0.009974 +0.010044 +0.009876 +0.009825 +0.00984 +0.009949 +0.010009 +0.010087 +0.009937 +0.00984 +0.009883 +0.009983 +0.010071 +0.010138 +0.009972 +0.009885 +0.009939 +0.010047 +0.010134 +0.010208 +0.01004 +0.009931 +0.00998 +0.010091 +0.010171 +0.010241 +0.010062 +0.009987 +0.010082 +0.010122 +0.010243 +0.010305 +0.01013 +0.01002 +0.010081 +0.010175 +0.010285 +0.010336 +0.010171 +0.010086 +0.010148 +0.010254 +0.010375 +0.010396 +0.010202 +0.010112 +0.010176 +0.010254 +0.010345 +0.010365 +0.010149 +0.010025 +0.010068 +0.010143 +0.010174 +0.010133 +0.00992 +0.009774 +0.00981 +0.009859 +0.009881 +0.009909 +0.009689 +0.009563 +0.009579 +0.009619 +0.009647 +0.00967 +0.009449 +0.009318 +0.009323 +0.009375 +0.009399 +0.00942 +0.009212 +0.009075 +0.00909 +0.009134 +0.009174 +0.009213 +0.008999 +0.008861 +0.00888 +0.008938 +0.008965 +0.008995 +0.008794 +0.008691 +0.008732 +0.008751 +0.0088 +0.008831 +0.008655 +0.008538 +0.008572 +0.008635 +0.008681 +0.008688 +0.008521 +0.008428 +0.008451 +0.008503 +0.008561 +0.008592 +0.008423 +0.008327 +0.008376 +0.008433 +0.008519 +0.008531 +0.008359 +0.008269 +0.008322 +0.00839 +0.00848 +0.008522 +0.008377 +0.008308 +0.008367 +0.008443 +0.008521 +0.008581 +0.008421 +0.008353 +0.0084 +0.008477 +0.008552 +0.008605 +0.008468 +0.008389 +0.008458 +0.008517 +0.008608 +0.008664 +0.008515 +0.008429 +0.008487 +0.008563 +0.008663 +0.008687 +0.008551 +0.008488 +0.008524 +0.008615 +0.008681 +0.008744 +0.008596 +0.008528 +0.00856 +0.008634 +0.008723 +0.008782 +0.00864 +0.008567 +0.008611 +0.008695 +0.008779 +0.008839 +0.008684 +0.008603 +0.00866 +0.008735 +0.008805 +0.008872 +0.008719 +0.008657 +0.008716 +0.008791 +0.008869 +0.008916 +0.00877 +0.008712 +0.008779 +0.008799 +0.008889 +0.008952 +0.008804 +0.008725 +0.008789 +0.008865 +0.008948 +0.009008 +0.008859 +0.008786 +0.008831 +0.008898 +0.009004 +0.00905 +0.008903 +0.008827 +0.008881 +0.008954 +0.009039 +0.009111 +0.008954 +0.008892 +0.008915 +0.008994 +0.009076 +0.009143 +0.009 +0.008922 +0.008997 +0.009048 +0.009118 +0.00918 +0.009031 +0.008959 +0.009011 +0.009086 +0.009183 +0.009247 +0.009083 +0.009013 +0.009072 +0.009129 +0.009214 +0.009287 +0.009122 +0.009042 +0.009096 +0.009193 +0.0093 +0.009347 +0.009182 +0.009096 +0.009154 +0.00923 +0.009309 +0.009368 +0.009211 +0.009139 +0.009186 +0.00927 +0.009371 +0.009435 +0.009278 +0.009203 +0.009256 +0.009311 +0.009401 +0.00949 +0.009294 +0.009224 +0.009287 +0.009355 +0.00946 +0.009538 +0.009373 +0.009319 +0.00935 +0.00942 +0.009484 +0.009552 +0.0094 +0.009311 +0.009373 +0.009456 +0.009566 +0.009634 +0.00946 +0.009391 +0.009424 +0.009509 +0.009604 +0.009652 +0.009495 +0.009418 +0.009467 +0.009554 +0.009643 +0.009717 +0.009552 +0.009473 +0.009525 +0.009635 +0.009723 +0.009756 +0.009598 +0.009541 +0.009558 +0.009648 +0.009735 +0.009815 +0.009646 +0.009553 +0.009627 +0.009713 +0.009818 +0.009861 +0.009713 +0.009597 +0.009663 +0.009758 +0.009846 +0.009911 +0.009738 +0.009656 +0.009715 +0.009823 +0.009925 +0.010007 +0.009777 +0.009697 +0.009754 +0.009843 +0.009956 +0.010017 +0.009826 +0.009773 +0.009823 +0.009919 +0.010018 +0.010057 +0.009873 +0.009804 +0.009865 +0.009943 +0.010043 +0.01011 +0.009954 +0.009853 +0.009923 +0.010011 +0.010093 +0.010163 +0.010014 +0.009908 +0.009956 +0.010039 +0.010146 +0.010245 +0.010042 +0.009959 +0.010026 +0.010083 +0.0102 +0.010263 +0.010085 +0.009998 +0.010064 +0.01015 +0.010277 +0.010351 +0.010144 +0.010052 +0.010093 +0.010196 +0.010295 +0.010367 +0.010192 +0.010145 +0.010174 +0.010257 +0.010357 +0.01042 +0.010241 +0.010125 +0.010187 +0.010287 +0.010371 +0.01043 +0.010211 +0.01009 +0.010111 +0.010154 +0.010228 +0.010238 +0.010017 +0.009891 +0.009897 +0.009909 +0.009993 +0.009974 +0.009752 +0.009625 +0.009638 +0.009685 +0.009721 +0.009684 +0.009474 +0.009353 +0.009372 +0.009405 +0.009426 +0.009453 +0.009225 +0.009101 +0.009118 +0.009152 +0.009184 +0.009207 +0.00901 +0.008886 +0.00891 +0.00896 +0.00898 +0.009003 +0.008817 +0.008705 +0.008723 +0.008758 +0.008819 +0.008846 +0.008689 +0.008553 +0.008586 +0.008629 +0.008692 +0.0087 +0.008528 +0.008428 +0.008456 +0.00852 +0.00856 +0.008595 +0.008434 +0.008343 +0.008379 +0.008449 +0.008505 +0.00854 +0.00837 +0.00829 +0.008339 +0.008401 +0.00848 +0.008545 +0.008404 +0.008325 +0.008375 +0.00844 +0.008537 +0.008613 +0.008454 +0.008356 +0.008399 +0.008479 +0.008566 +0.008626 +0.008475 +0.008404 +0.008459 +0.00853 +0.008612 +0.008677 +0.008537 +0.008447 +0.008496 +0.008569 +0.008666 +0.008728 +0.008559 +0.008484 +0.008533 +0.008609 +0.008691 +0.008762 +0.008616 +0.00854 +0.008576 +0.008672 +0.00875 +0.008811 +0.008639 +0.00857 +0.008617 +0.008693 +0.008785 +0.008836 +0.0087 +0.00863 +0.008682 +0.008735 +0.008818 +0.008889 +0.008732 +0.00867 +0.008708 +0.008786 +0.008868 +0.008939 +0.008802 +0.008712 +0.008764 +0.008823 +0.008907 +0.008964 +0.008825 +0.00875 +0.008799 +0.008898 +0.008977 +0.009007 +0.008858 +0.008799 +0.008861 +0.008929 +0.009 +0.009062 +0.008914 +0.00884 +0.008882 +0.008962 +0.009044 +0.009115 +0.008956 +0.00889 +0.00894 +0.00901 +0.009093 +0.009156 +0.009 +0.008923 +0.008984 +0.009043 +0.009144 +0.009212 +0.009058 +0.009009 +0.009026 +0.009104 +0.009191 +0.009235 +0.009089 +0.008999 +0.009069 +0.009145 +0.009238 +0.009301 +0.009135 +0.009069 +0.009109 +0.009189 +0.009276 +0.009338 +0.009178 +0.009104 +0.009169 +0.009238 +0.009325 +0.0094 +0.009223 +0.009155 +0.009208 +0.009296 +0.009398 +0.009422 +0.009268 +0.009185 +0.009251 +0.009341 +0.009415 +0.009485 +0.009317 +0.009253 +0.009301 +0.009367 +0.009468 +0.009538 +0.009374 +0.009308 +0.009337 +0.00941 +0.009514 +0.009571 +0.009416 +0.009339 +0.009402 +0.009462 +0.00956 +0.009634 +0.009472 +0.00941 +0.00943 +0.009499 +0.009617 +0.009679 +0.009517 +0.009432 +0.009488 +0.009563 +0.009652 +0.009715 +0.009554 +0.009466 +0.00953 +0.009611 +0.009731 +0.009784 +0.009604 +0.009531 +0.009556 +0.009655 +0.009761 +0.009806 +0.009637 +0.009564 +0.009636 +0.009763 +0.009809 +0.009874 +0.009699 +0.009601 +0.009674 +0.009743 +0.009848 +0.009931 +0.009754 +0.009654 +0.009733 +0.009818 +0.009925 +0.009977 +0.00978 +0.009698 +0.009767 +0.009853 +0.00994 +0.010016 +0.009838 +0.00977 +0.009837 +0.009928 +0.010053 +0.010051 +0.009899 +0.009784 +0.009854 +0.009963 +0.010038 +0.010108 +0.009955 +0.00988 +0.009926 +0.010025 +0.010094 +0.010148 +0.009988 +0.009901 +0.009962 +0.010055 +0.010154 +0.010233 +0.010064 +0.00997 +0.010016 +0.010093 +0.010203 +0.010304 +0.010087 +0.009998 +0.010049 +0.010149 +0.010286 +0.010335 +0.010146 +0.010062 +0.010097 +0.0102 +0.010313 +0.010376 +0.0102 +0.0101 +0.010145 +0.010257 +0.010358 +0.010384 +0.010168 +0.010049 +0.010073 +0.010109 +0.010173 +0.010218 +0.010005 +0.009836 +0.009859 +0.009893 +0.009945 +0.009964 +0.009704 +0.009569 +0.009587 +0.00962 +0.009668 +0.009682 +0.009464 +0.009353 +0.009358 +0.009386 +0.009426 +0.009418 +0.009219 +0.00909 +0.009102 +0.009148 +0.00918 +0.009203 +0.009008 +0.008877 +0.008923 +0.008939 +0.008978 +0.009 +0.00881 +0.008696 +0.008717 +0.008762 +0.008811 +0.008868 +0.008657 +0.00854 +0.008569 +0.008618 +0.008671 +0.008701 +0.008529 +0.008414 +0.008445 +0.008497 +0.008556 +0.008573 +0.008424 +0.008324 +0.008343 +0.008395 +0.008458 +0.008507 +0.008346 +0.008278 +0.008298 +0.008357 +0.008427 +0.008498 +0.00835 +0.008285 +0.008337 +0.008381 +0.008461 +0.008532 +0.008388 +0.008328 +0.008364 +0.008426 +0.008508 +0.008573 +0.008439 +0.008354 +0.008417 +0.008485 +0.008551 +0.008616 +0.008465 +0.008405 +0.008446 +0.008512 +0.008596 +0.00867 +0.008523 +0.00847 +0.008507 +0.00856 +0.008645 +0.008689 +0.008551 +0.008484 +0.00853 +0.008592 +0.008693 +0.008742 +0.008597 +0.008527 +0.008601 +0.008647 +0.008735 +0.008789 +0.008634 +0.008561 +0.008618 +0.008693 +0.008767 +0.008833 +0.008686 +0.008616 +0.008664 +0.008728 +0.008837 +0.0089 +0.008742 +0.008644 +0.00869 +0.008778 +0.008856 +0.008952 +0.008759 +0.008692 +0.008744 +0.008818 +0.008904 +0.008977 +0.008818 +0.008743 +0.008795 +0.008866 +0.008954 +0.009008 +0.008855 +0.008791 +0.008832 +0.008907 +0.008996 +0.009077 +0.008906 +0.008833 +0.008878 +0.008958 +0.009075 +0.009094 +0.008945 +0.008865 +0.008913 +0.009009 +0.009106 +0.009179 +0.008991 +0.008922 +0.008959 +0.009031 +0.009135 +0.009183 +0.009039 +0.008962 +0.009016 +0.009092 +0.009197 +0.009257 +0.009086 +0.00901 +0.009058 +0.009123 +0.009218 +0.009278 +0.009131 +0.009071 +0.009117 +0.009186 +0.009286 +0.009336 +0.009181 +0.009106 +0.009143 +0.009215 +0.009315 +0.00939 +0.009204 +0.00914 +0.009188 +0.009293 +0.009383 +0.009438 +0.009272 +0.00919 +0.009242 +0.009321 +0.009396 +0.009469 +0.00931 +0.009217 +0.009287 +0.009394 +0.0095 +0.009547 +0.009362 +0.00928 +0.009312 +0.009407 +0.009494 +0.009563 +0.009404 +0.009326 +0.009375 +0.009484 +0.0096 +0.009616 +0.009453 +0.009374 +0.009416 +0.009504 +0.009601 +0.00967 +0.009494 +0.009417 +0.009486 +0.009579 +0.00966 +0.009724 +0.00956 +0.009485 +0.009519 +0.009601 +0.009703 +0.009762 +0.009588 +0.009498 +0.009579 +0.009669 +0.009751 +0.009814 +0.009642 +0.009553 +0.009623 +0.009703 +0.009795 +0.009858 +0.009686 +0.009627 +0.009669 +0.009761 +0.009864 +0.009907 +0.009723 +0.009652 +0.009722 +0.009838 +0.009886 +0.009943 +0.009801 +0.00972 +0.009796 +0.00985 +0.009946 +0.009991 +0.009822 +0.009747 +0.009815 +0.009895 +0.009986 +0.010082 +0.009899 +0.009813 +0.00988 +0.009949 +0.010032 +0.010111 +0.009925 +0.009845 +0.009915 +0.010002 +0.010154 +0.010165 +0.009993 +0.009903 +0.009961 +0.010032 +0.010137 +0.010211 +0.01003 +0.009943 +0.010001 +0.010124 +0.010224 +0.010275 +0.010096 +0.009992 +0.010071 +0.010149 +0.010238 +0.010306 +0.010142 +0.010036 +0.010128 +0.010227 +0.010334 +0.010395 +0.010174 +0.010076 +0.010149 +0.010259 +0.010351 +0.010398 +0.010211 +0.010111 +0.010191 +0.010219 +0.010267 +0.010287 +0.010065 +0.009931 +0.009958 +0.009996 +0.010034 +0.010037 +0.009808 +0.009664 +0.009688 +0.0097 +0.009734 +0.00976 +0.009534 +0.00944 +0.009454 +0.009445 +0.009462 +0.009475 +0.009279 +0.00916 +0.009169 +0.009204 +0.009231 +0.009245 +0.009046 +0.008946 +0.008946 +0.008992 +0.009016 +0.009031 +0.008837 +0.008739 +0.008768 +0.008794 +0.008838 +0.008866 +0.00868 +0.008583 +0.008616 +0.008668 +0.008714 +0.008747 +0.008538 +0.008447 +0.008499 +0.008526 +0.008574 +0.008592 +0.008425 +0.008341 +0.008382 +0.008426 +0.008474 +0.008505 +0.008359 +0.008251 +0.008292 +0.00835 +0.008403 +0.008448 +0.008302 +0.008234 +0.008278 +0.008345 +0.008413 +0.008493 +0.008349 +0.008279 +0.008308 +0.008381 +0.008478 +0.008533 +0.008366 +0.008291 +0.008342 +0.008425 +0.008518 +0.008567 +0.008423 +0.008353 +0.00841 +0.008455 +0.008546 +0.008606 +0.008464 +0.008392 +0.008433 +0.008517 +0.008591 +0.008661 +0.008497 +0.008441 +0.008485 +0.008555 +0.008626 +0.008685 +0.008544 +0.008475 +0.00853 +0.008601 +0.00869 +0.008732 +0.008591 +0.008521 +0.008571 +0.008648 +0.008717 +0.008767 +0.008645 +0.008553 +0.008601 +0.008674 +0.008762 +0.008825 +0.008672 +0.008612 +0.008665 +0.008736 +0.008818 +0.008852 +0.008716 +0.008639 +0.008692 +0.008769 +0.008851 +0.008912 +0.008759 +0.008702 +0.008765 +0.008841 +0.008896 +0.008937 +0.008791 +0.008724 +0.008784 +0.008851 +0.008937 +0.009 +0.008849 +0.008776 +0.008836 +0.008923 +0.008988 +0.009048 +0.008879 +0.008808 +0.008865 +0.008942 +0.00904 +0.009113 +0.008924 +0.008861 +0.008927 +0.009003 +0.009082 +0.009146 +0.008991 +0.008917 +0.008939 +0.009048 +0.009109 +0.009173 +0.009036 +0.008953 +0.008991 +0.009081 +0.009156 +0.009227 +0.009069 +0.009002 +0.009036 +0.00912 +0.009224 +0.009274 +0.009129 +0.009053 +0.009085 +0.00917 +0.009263 +0.009331 +0.009169 +0.009078 +0.009131 +0.009218 +0.009338 +0.009367 +0.00921 +0.009123 +0.009185 +0.009275 +0.009348 +0.009407 +0.009256 +0.009175 +0.009219 +0.009308 +0.009409 +0.009458 +0.009314 +0.009226 +0.009274 +0.009358 +0.009449 +0.009514 +0.009348 +0.00926 +0.009334 +0.009394 +0.009492 +0.009562 +0.009415 +0.009338 +0.009369 +0.009445 +0.009539 +0.009602 +0.009446 +0.009373 +0.009408 +0.009502 +0.009602 +0.009655 +0.009494 +0.009397 +0.009454 +0.009547 +0.009643 +0.009702 +0.009525 +0.009455 +0.00951 +0.009606 +0.009722 +0.009765 +0.009567 +0.009498 +0.009556 +0.009674 +0.009735 +0.009787 +0.009622 +0.009541 +0.009625 +0.0097 +0.009798 +0.009853 +0.009664 +0.009593 +0.009652 +0.009735 +0.009829 +0.009888 +0.009734 +0.009651 +0.009733 +0.00983 +0.009875 +0.009932 +0.00978 +0.009683 +0.009746 +0.009837 +0.009937 +0.010027 +0.009839 +0.009735 +0.009796 +0.009895 +0.009974 +0.010035 +0.009871 +0.009791 +0.009847 +0.009927 +0.010056 +0.010097 +0.009939 +0.00986 +0.009894 +0.00997 +0.010088 +0.010136 +0.009977 +0.009893 +0.009941 +0.010039 +0.010146 +0.010233 +0.010068 +0.009931 +0.009972 +0.010099 +0.010171 +0.010241 +0.010064 +0.009978 +0.01007 +0.010153 +0.010248 +0.010316 +0.010113 +0.010021 +0.010094 +0.010181 +0.010284 +0.010362 +0.010165 +0.010107 +0.010165 +0.010258 +0.010332 +0.010372 +0.010212 +0.010108 +0.010128 +0.010171 +0.010238 +0.010296 +0.010081 +0.009926 +0.00996 +0.01001 +0.010061 +0.010056 +0.009838 +0.009703 +0.009732 +0.009758 +0.00979 +0.009813 +0.009576 +0.009462 +0.009462 +0.009492 +0.009533 +0.009533 +0.009323 +0.009211 +0.00922 +0.009278 +0.009285 +0.009287 +0.009068 +0.008964 +0.008986 +0.009011 +0.009063 +0.009059 +0.008867 +0.008765 +0.008804 +0.008845 +0.008881 +0.008891 +0.008705 +0.008612 +0.008644 +0.008682 +0.008739 +0.008759 +0.008591 +0.008504 +0.008541 +0.00859 +0.00864 +0.008677 +0.008509 +0.008426 +0.008447 +0.008486 +0.008531 +0.008572 +0.008431 +0.008351 +0.008403 +0.00846 +0.008528 +0.008574 +0.008428 +0.008353 +0.008406 +0.008462 +0.008549 +0.008607 +0.008468 +0.008392 +0.008432 +0.008537 +0.008613 +0.00865 +0.008506 +0.00844 +0.008474 +0.008548 +0.008632 +0.008693 +0.008562 +0.00849 +0.008539 +0.008584 +0.008684 +0.008737 +0.0086 +0.008528 +0.008578 +0.008629 +0.008718 +0.008766 +0.008629 +0.008566 +0.008604 +0.008675 +0.008773 +0.00884 +0.008681 +0.008607 +0.008667 +0.008738 +0.008799 +0.008871 +0.008714 +0.008638 +0.008694 +0.008776 +0.00885 +0.008934 +0.00877 +0.008684 +0.008729 +0.008825 +0.008879 +0.008963 +0.008807 +0.008732 +0.008804 +0.008867 +0.008949 +0.009004 +0.00885 +0.008775 +0.008818 +0.0089 +0.008986 +0.009039 +0.0089 +0.008825 +0.008886 +0.008957 +0.009051 +0.009101 +0.008929 +0.008857 +0.008914 +0.009004 +0.009095 +0.009127 +0.008977 +0.008912 +0.008965 +0.009072 +0.009125 +0.009173 +0.00902 +0.008943 +0.008999 +0.009083 +0.009169 +0.009221 +0.009076 +0.009022 +0.009052 +0.009138 +0.009228 +0.009275 +0.009113 +0.009037 +0.009097 +0.009167 +0.009255 +0.009328 +0.009175 +0.009125 +0.009154 +0.009217 +0.009307 +0.009359 +0.009208 +0.009126 +0.00918 +0.009264 +0.009352 +0.009407 +0.009276 +0.009189 +0.009241 +0.009324 +0.009421 +0.009454 +0.009315 +0.009225 +0.009271 +0.009351 +0.009449 +0.009504 +0.009339 +0.009257 +0.00933 +0.009425 +0.009542 +0.009544 +0.009392 +0.009313 +0.009364 +0.009452 +0.009548 +0.0096 +0.009446 +0.009356 +0.009412 +0.009514 +0.009589 +0.009653 +0.009495 +0.009412 +0.009484 +0.009556 +0.009642 +0.009721 +0.009526 +0.009457 +0.009504 +0.009588 +0.009685 +0.00976 +0.009617 +0.009509 +0.009588 +0.009644 +0.009723 +0.009788 +0.009626 +0.009545 +0.009611 +0.009677 +0.009786 +0.009878 +0.009689 +0.009604 +0.009666 +0.009738 +0.009834 +0.009891 +0.009735 +0.009644 +0.009691 +0.009801 +0.00989 +0.009965 +0.009789 +0.009714 +0.009769 +0.009817 +0.009921 +0.009986 +0.009852 +0.00973 +0.009784 +0.009902 +0.01001 +0.010063 +0.009886 +0.009777 +0.009834 +0.009934 +0.010038 +0.010089 +0.009915 +0.009847 +0.00991 +0.010008 +0.010105 +0.010154 +0.00996 +0.009881 +0.009949 +0.010064 +0.010128 +0.010189 +0.010016 +0.009939 +0.009993 +0.010118 +0.010177 +0.010245 +0.01007 +0.009995 +0.010053 +0.010162 +0.010231 +0.010308 +0.010119 +0.01003 +0.010105 +0.010186 +0.010279 +0.010368 +0.010172 +0.010092 +0.010177 +0.010264 +0.010362 +0.010389 +0.010212 +0.010133 +0.010197 +0.010284 +0.010396 +0.010489 +0.01027 +0.010172 +0.010226 +0.01029 +0.010368 +0.010402 +0.010163 +0.010036 +0.010097 +0.010142 +0.01019 +0.010194 +0.009971 +0.009821 +0.009832 +0.00987 +0.009916 +0.009938 +0.009711 +0.009579 +0.009576 +0.009624 +0.009663 +0.009651 +0.009436 +0.009298 +0.009316 +0.009371 +0.009393 +0.009399 +0.009208 +0.009063 +0.009082 +0.009126 +0.009168 +0.009182 +0.008971 +0.00887 +0.008867 +0.008916 +0.008962 +0.00898 +0.008787 +0.008681 +0.008712 +0.008763 +0.008833 +0.008823 +0.008638 +0.008535 +0.00857 +0.008634 +0.008677 +0.008706 +0.008528 +0.008455 +0.008461 +0.00854 +0.008578 +0.008607 +0.008436 +0.00835 +0.008395 +0.008453 +0.008525 +0.008563 +0.008415 +0.008335 +0.008397 +0.008455 +0.008538 +0.00859 +0.008449 +0.008381 +0.008422 +0.008514 +0.008585 +0.008633 +0.00849 +0.008421 +0.008454 +0.008546 +0.008613 +0.008683 +0.008542 +0.008457 +0.008509 +0.008583 +0.008671 +0.008725 +0.008573 +0.008503 +0.008567 +0.008651 +0.008716 +0.008767 +0.008607 +0.008537 +0.008593 +0.008673 +0.008752 +0.008803 +0.008657 +0.00859 +0.008665 +0.008735 +0.008804 +0.008851 +0.008691 +0.008626 +0.008679 +0.008749 +0.008836 +0.00891 +0.008738 +0.008668 +0.008731 +0.008817 +0.008902 +0.008951 +0.008822 +0.008702 +0.00876 +0.008835 +0.008929 +0.00898 +0.008831 +0.008765 +0.00881 +0.008893 +0.008994 +0.009048 +0.008905 +0.008817 +0.008843 +0.00892 +0.009012 +0.009067 +0.008923 +0.008838 +0.008904 +0.008991 +0.009067 +0.009143 +0.008981 +0.008906 +0.008942 +0.009013 +0.009114 +0.009164 +0.009036 +0.008933 +0.008988 +0.009068 +0.009155 +0.009231 +0.009071 +0.008987 +0.009024 +0.009112 +0.009233 +0.009267 +0.009097 +0.009024 +0.009074 +0.009159 +0.009252 +0.009311 +0.009165 +0.009094 +0.009129 +0.009194 +0.009287 +0.009345 +0.009194 +0.009114 +0.009177 +0.009251 +0.009341 +0.009425 +0.009249 +0.00917 +0.009206 +0.00929 +0.009387 +0.009448 +0.009295 +0.009229 +0.00928 +0.009364 +0.009431 +0.009504 +0.00934 +0.009257 +0.009295 +0.00938 +0.009494 +0.009536 +0.009379 +0.009308 +0.009362 +0.009436 +0.009536 +0.009611 +0.009442 +0.009335 +0.009403 +0.009476 +0.009579 +0.009649 +0.009468 +0.009391 +0.009464 +0.009549 +0.009677 +0.009693 +0.009527 +0.009425 +0.009513 +0.009576 +0.009662 +0.009726 +0.009574 +0.009496 +0.009545 +0.009635 +0.009751 +0.009799 +0.009604 +0.009535 +0.009588 +0.009678 +0.00978 +0.00983 +0.009666 +0.009592 +0.00964 +0.009741 +0.009844 +0.009897 +0.009736 +0.009619 +0.009676 +0.009776 +0.009874 +0.009933 +0.00976 +0.009666 +0.009765 +0.009836 +0.009917 +0.009989 +0.009816 +0.009725 +0.0098 +0.00988 +0.009966 +0.01004 +0.009861 +0.009787 +0.009848 +0.009939 +0.010002 +0.010079 +0.009943 +0.009855 +0.00989 +0.009956 +0.01006 +0.01015 +0.00998 +0.009882 +0.009924 +0.010024 +0.010119 +0.010176 +0.010016 +0.009923 +0.009979 +0.010085 +0.010201 +0.010242 +0.010108 +0.009959 +0.010021 +0.010122 +0.01022 +0.010286 +0.010112 +0.010026 +0.010137 +0.010212 +0.010273 +0.010335 +0.010137 +0.010069 +0.01012 +0.010228 +0.010344 +0.010387 +0.010207 +0.010146 +0.0102 +0.010292 +0.010399 +0.010424 +0.010242 +0.010155 +0.010219 +0.010283 +0.010357 +0.010383 +0.010172 +0.010035 +0.010079 +0.01014 +0.010161 +0.010167 +0.009922 +0.009767 +0.009806 +0.009835 +0.009887 +0.009889 +0.009651 +0.009508 +0.009535 +0.00956 +0.009599 +0.0096 +0.00938 +0.009255 +0.009257 +0.009299 +0.009327 +0.009324 +0.00912 +0.008982 +0.008995 +0.009042 +0.009079 +0.009104 +0.008901 +0.00877 +0.008783 +0.008815 +0.008862 +0.008885 +0.008692 +0.008571 +0.008612 +0.008663 +0.008709 +0.008734 +0.008568 +0.008452 +0.008497 +0.00855 +0.008575 +0.008597 +0.008429 +0.008336 +0.008369 +0.00842 +0.008474 +0.008517 +0.00835 +0.008264 +0.008294 +0.008362 +0.008427 +0.008455 +0.008282 +0.008202 +0.008255 +0.00833 +0.008411 +0.008462 +0.008331 +0.008247 +0.008295 +0.008363 +0.008442 +0.008502 +0.008362 +0.008284 +0.008335 +0.008408 +0.008496 +0.008566 +0.008406 +0.008334 +0.008372 +0.008448 +0.008529 +0.008599 +0.008446 +0.008366 +0.008425 +0.008502 +0.008599 +0.008652 +0.00849 +0.008419 +0.008463 +0.008528 +0.008618 +0.008663 +0.008524 +0.008446 +0.008537 +0.008574 +0.008653 +0.008723 +0.008568 +0.008509 +0.00854 +0.008626 +0.008699 +0.008758 +0.008624 +0.00854 +0.008582 +0.008666 +0.008753 +0.008806 +0.008663 +0.008592 +0.008654 +0.008723 +0.008806 +0.008859 +0.008688 +0.008621 +0.008673 +0.008755 +0.008838 +0.008889 +0.008764 +0.008676 +0.008725 +0.008789 +0.008879 +0.008931 +0.008783 +0.008713 +0.008769 +0.008832 +0.008929 +0.008995 +0.008838 +0.008773 +0.008816 +0.008896 +0.008953 +0.009029 +0.008881 +0.008806 +0.008876 +0.008921 +0.009005 +0.009069 +0.00892 +0.008867 +0.008913 +0.008981 +0.009059 +0.009114 +0.00895 +0.008879 +0.008945 +0.009031 +0.0091 +0.009168 +0.009011 +0.008941 +0.009 +0.009089 +0.009142 +0.009208 +0.009059 +0.008979 +0.009024 +0.009102 +0.009198 +0.009284 +0.009119 +0.009034 +0.009085 +0.009171 +0.00924 +0.009311 +0.009139 +0.009058 +0.009118 +0.009201 +0.009282 +0.009345 +0.009203 +0.009131 +0.009187 +0.009299 +0.009317 +0.009391 +0.009236 +0.009149 +0.009207 +0.009293 +0.009383 +0.009449 +0.009302 +0.009235 +0.009299 +0.00937 +0.009411 +0.009476 +0.009326 +0.009242 +0.009301 +0.009389 +0.009503 +0.009546 +0.009382 +0.009316 +0.009374 +0.00944 +0.009518 +0.00958 +0.009425 +0.009337 +0.009402 +0.009483 +0.009589 +0.009659 +0.009492 +0.0094 +0.009453 +0.009522 +0.00962 +0.009726 +0.009511 +0.009432 +0.009486 +0.009581 +0.009696 +0.009745 +0.009576 +0.009499 +0.009538 +0.009617 +0.009714 +0.00978 +0.009612 +0.009547 +0.009589 +0.009682 +0.009766 +0.009839 +0.009662 +0.00957 +0.009649 +0.009723 +0.009824 +0.009891 +0.009726 +0.00967 +0.009687 +0.009766 +0.009867 +0.009927 +0.009767 +0.009678 +0.009744 +0.009829 +0.009929 +0.009989 +0.009835 +0.009712 +0.009782 +0.009872 +0.009968 +0.010036 +0.009862 +0.009781 +0.009837 +0.009947 +0.01004 +0.010093 +0.009902 +0.009828 +0.009915 +0.009976 +0.010064 +0.010121 +0.009974 +0.009888 +0.009941 +0.010031 +0.010133 +0.010166 +0.010001 +0.009926 +0.009979 +0.010077 +0.010172 +0.010243 +0.010079 +0.009989 +0.010046 +0.01013 +0.010213 +0.010289 +0.010112 +0.01002 +0.010085 +0.010209 +0.010275 +0.010329 +0.010124 +0.010036 +0.010083 +0.010142 +0.010149 +0.010174 +0.009984 +0.009861 +0.00989 +0.009914 +0.009967 +0.009962 +0.009765 +0.009619 +0.009633 +0.009676 +0.009698 +0.009711 +0.009504 +0.009391 +0.009379 +0.00941 +0.009446 +0.009472 +0.009261 +0.009122 +0.009132 +0.009161 +0.009204 +0.009212 +0.009031 +0.008939 +0.008936 +0.008942 +0.008984 +0.009003 +0.008817 +0.008714 +0.008736 +0.008776 +0.008815 +0.00884 +0.008669 +0.008583 +0.008605 +0.008635 +0.008684 +0.008701 +0.008538 +0.008443 +0.008478 +0.008525 +0.008583 +0.008587 +0.00842 +0.008331 +0.008373 +0.008423 +0.008457 +0.008491 +0.008333 +0.008258 +0.008291 +0.008361 +0.008396 +0.008449 +0.008309 +0.008253 +0.008304 +0.008366 +0.008434 +0.008503 +0.008351 +0.008274 +0.00832 +0.008393 +0.00848 +0.008529 +0.008388 +0.008313 +0.008387 +0.008472 +0.008546 +0.008576 +0.008449 +0.008347 +0.008398 +0.00848 +0.008553 +0.008616 +0.008469 +0.008406 +0.008446 +0.008537 +0.008625 +0.008679 +0.008533 +0.008445 +0.008489 +0.008556 +0.008637 +0.008701 +0.008557 +0.008482 +0.008533 +0.008629 +0.008698 +0.00876 +0.008609 +0.008543 +0.008605 +0.008658 +0.008718 +0.008784 +0.008634 +0.008573 +0.008641 +0.008689 +0.008784 +0.008845 +0.008698 +0.008622 +0.008668 +0.008737 +0.008817 +0.00887 +0.008732 +0.008662 +0.008704 +0.008794 +0.00888 +0.00893 +0.008768 +0.008695 +0.008752 +0.008819 +0.008908 +0.008974 +0.008824 +0.008774 +0.008803 +0.008879 +0.008969 +0.009014 +0.008854 +0.008786 +0.008852 +0.008909 +0.008998 +0.00906 +0.008895 +0.008829 +0.008888 +0.008962 +0.009064 +0.009129 +0.008942 +0.008872 +0.008926 +0.009001 +0.009088 +0.00915 +0.008997 +0.008914 +0.008974 +0.009059 +0.009167 +0.009241 +0.009037 +0.008958 +0.009008 +0.009084 +0.009179 +0.009236 +0.009086 +0.009 +0.009091 +0.009133 +0.009242 +0.009305 +0.009138 +0.009043 +0.009106 +0.009178 +0.009268 +0.009331 +0.009188 +0.009084 +0.009153 +0.009247 +0.009341 +0.009397 +0.00924 +0.009145 +0.009219 +0.009282 +0.009383 +0.009413 +0.00925 +0.009178 +0.009244 +0.00934 +0.009437 +0.009489 +0.00932 +0.009231 +0.009287 +0.009366 +0.009454 +0.009525 +0.009362 +0.00928 +0.00934 +0.009444 +0.009527 +0.009586 +0.009415 +0.009321 +0.009376 +0.00947 +0.009561 +0.009652 +0.009447 +0.009364 +0.009445 +0.009545 +0.009623 +0.009668 +0.009491 +0.009424 +0.009468 +0.009555 +0.00966 +0.009713 +0.009549 +0.009471 +0.009548 +0.009626 +0.009717 +0.009785 +0.009588 +0.009509 +0.009578 +0.009655 +0.009755 +0.009826 +0.009649 +0.009608 +0.009636 +0.00971 +0.009807 +0.009846 +0.009705 +0.009613 +0.009666 +0.009761 +0.009843 +0.00991 +0.009751 +0.009674 +0.009728 +0.009813 +0.009918 +0.009949 +0.009788 +0.009713 +0.009767 +0.009854 +0.009955 +0.010022 +0.009863 +0.009776 +0.009845 +0.009934 +0.009979 +0.010045 +0.009879 +0.009809 +0.009858 +0.009954 +0.010082 +0.010121 +0.009952 +0.009863 +0.009927 +0.009993 +0.010086 +0.010166 +0.009983 +0.009907 +0.009984 +0.010056 +0.010148 +0.010224 +0.010038 +0.009957 +0.01002 +0.010121 +0.010251 +0.010251 +0.010067 +0.010015 +0.010074 +0.010145 +0.010259 +0.010325 +0.010136 +0.010062 +0.010102 +0.010185 +0.01028 +0.010343 +0.010147 +0.010005 +0.010035 +0.010081 +0.010144 +0.010182 +0.009952 +0.009824 +0.009845 +0.00987 +0.009916 +0.009951 +0.009733 +0.009584 +0.009556 +0.009596 +0.00964 +0.009666 +0.009427 +0.009308 +0.009323 +0.009337 +0.009406 +0.009408 +0.009181 +0.009053 +0.00907 +0.009109 +0.009132 +0.009161 +0.008965 +0.008842 +0.008853 +0.00889 +0.008948 +0.008965 +0.008754 +0.008655 +0.008666 +0.008738 +0.008768 +0.008787 +0.008624 +0.008504 +0.008527 +0.008577 +0.008626 +0.008675 +0.008506 +0.008387 +0.008408 +0.00846 +0.008526 +0.008554 +0.008389 +0.008291 +0.008324 +0.008371 +0.008434 +0.008484 +0.008332 +0.008242 +0.008273 +0.008334 +0.008402 +0.00846 +0.008319 +0.008246 +0.00829 +0.008385 +0.008433 +0.008492 +0.008349 +0.008289 +0.008347 +0.008412 +0.008471 +0.008532 +0.008397 +0.008321 +0.008375 +0.008442 +0.008526 +0.008572 +0.008432 +0.008397 +0.008425 +0.008497 +0.008565 +0.008625 +0.008484 +0.008424 +0.008456 +0.00853 +0.008608 +0.008662 +0.008527 +0.008446 +0.008524 +0.008594 +0.008656 +0.0087 +0.008556 +0.008488 +0.008554 +0.008609 +0.008713 +0.008749 +0.008606 +0.00854 +0.008584 +0.008667 +0.008749 +0.008805 +0.008643 +0.008582 +0.008624 +0.008701 +0.008791 +0.008835 +0.008698 +0.008629 +0.008675 +0.008752 +0.008841 +0.008906 +0.008748 +0.008697 +0.008714 +0.00878 +0.008859 +0.008926 +0.008781 +0.008705 +0.008755 +0.008833 +0.008931 +0.008996 +0.008831 +0.008745 +0.008801 +0.008863 +0.008961 +0.009029 +0.00887 +0.008794 +0.00885 +0.008929 +0.009017 +0.009081 +0.008933 +0.008833 +0.008883 +0.008964 +0.00905 +0.009141 +0.008964 +0.008885 +0.008928 +0.009018 +0.009114 +0.009168 +0.009006 +0.008911 +0.008976 +0.009048 +0.009139 +0.009238 +0.009041 +0.008961 +0.009026 +0.00912 +0.009211 +0.009257 +0.009103 +0.009013 +0.009052 +0.009146 +0.009235 +0.009297 +0.009137 +0.009059 +0.009131 +0.009241 +0.00929 +0.009339 +0.009182 +0.009092 +0.009161 +0.009229 +0.009325 +0.009391 +0.009225 +0.009145 +0.009215 +0.009308 +0.009389 +0.009456 +0.009285 +0.009178 +0.009241 +0.009332 +0.009432 +0.009482 +0.009319 +0.009248 +0.009309 +0.009394 +0.009493 +0.009553 +0.009391 +0.009266 +0.009326 +0.009418 +0.009511 +0.009589 +0.009425 +0.009332 +0.009409 +0.009484 +0.009577 +0.009639 +0.009453 +0.00937 +0.009433 +0.009521 +0.009604 +0.00968 +0.009519 +0.009427 +0.009506 +0.00959 +0.009688 +0.009723 +0.009548 +0.009475 +0.009561 +0.009614 +0.009704 +0.009758 +0.009606 +0.009548 +0.00959 +0.009677 +0.009804 +0.0098 +0.00964 +0.00957 +0.00962 +0.009711 +0.009815 +0.009871 +0.009715 +0.009644 +0.009697 +0.00978 +0.00985 +0.009925 +0.009747 +0.009668 +0.009733 +0.009828 +0.009956 +0.00997 +0.009805 +0.009722 +0.009784 +0.009866 +0.009946 +0.010019 +0.009853 +0.009768 +0.009824 +0.009912 +0.010013 +0.010095 +0.009923 +0.009825 +0.009878 +0.009966 +0.010064 +0.01012 +0.009953 +0.00986 +0.009916 +0.010025 +0.010139 +0.010228 +0.010002 +0.009915 +0.009959 +0.010052 +0.010168 +0.01022 +0.010045 +0.009964 +0.010026 +0.010135 +0.01025 +0.010293 +0.010091 +0.010012 +0.01006 +0.010163 +0.010271 +0.010328 +0.010167 +0.01007 +0.010118 +0.0102 +0.010303 +0.010382 +0.010178 +0.010051 +0.010076 +0.010134 +0.010202 +0.010226 +0.010013 +0.009863 +0.009878 +0.00992 +0.009964 +0.00996 +0.009756 +0.009626 +0.00963 +0.009662 +0.00968 +0.009694 +0.009478 +0.009332 +0.009341 +0.009367 +0.009409 +0.009416 +0.009207 +0.009096 +0.009111 +0.009161 +0.009155 +0.009164 +0.008965 +0.008845 +0.008868 +0.0089 +0.008925 +0.008943 +0.008771 +0.008661 +0.008688 +0.008729 +0.008764 +0.008785 +0.008625 +0.008515 +0.00854 +0.008575 +0.008634 +0.008665 +0.008504 +0.008404 +0.008448 +0.008489 +0.008545 +0.008583 +0.008423 +0.008337 +0.00836 +0.008388 +0.008441 +0.008492 +0.008341 +0.00826 +0.008288 +0.00835 +0.008452 +0.008485 +0.008328 +0.008262 +0.008303 +0.008362 +0.008459 +0.0085 +0.008374 +0.008291 +0.008337 +0.008413 +0.008499 +0.008561 +0.008412 +0.008343 +0.008401 +0.008455 +0.008531 +0.008591 +0.00845 +0.008402 +0.008436 +0.008497 +0.00857 +0.008638 +0.008499 +0.008434 +0.00849 +0.008553 +0.008627 +0.008664 +0.008557 +0.008451 +0.008511 +0.008577 +0.008664 +0.008716 +0.008585 +0.008515 +0.008558 +0.00864 +0.008717 +0.008764 +0.008613 +0.00855 +0.008594 +0.008667 +0.008751 +0.008818 +0.008681 +0.008615 +0.008648 +0.008717 +0.008811 +0.008853 +0.0087 +0.008627 +0.008679 +0.008758 +0.008839 +0.008897 +0.008739 +0.008713 +0.008734 +0.00881 +0.008896 +0.008953 +0.008789 +0.00871 +0.008768 +0.008846 +0.008923 +0.008994 +0.008839 +0.008756 +0.008832 +0.008907 +0.008993 +0.009072 +0.008879 +0.008798 +0.008844 +0.008936 +0.009028 +0.009066 +0.008929 +0.00884 +0.008905 +0.008978 +0.009065 +0.009137 +0.008969 +0.008896 +0.008944 +0.009027 +0.009101 +0.009173 +0.009037 +0.008933 +0.008994 +0.009075 +0.009166 +0.00923 +0.009065 +0.008983 +0.009045 +0.009138 +0.009198 +0.009256 +0.009119 +0.009026 +0.00908 +0.009176 +0.009254 +0.009309 +0.009146 +0.009064 +0.009127 +0.009214 +0.009298 +0.009363 +0.009216 +0.009118 +0.009169 +0.009254 +0.009342 +0.009399 +0.009247 +0.009165 +0.009218 +0.009299 +0.009404 +0.009478 +0.00933 +0.009196 +0.009247 +0.009347 +0.00943 +0.009504 +0.009324 +0.009253 +0.009335 +0.0094 +0.009486 +0.009547 +0.009401 +0.009291 +0.009343 +0.009444 +0.009532 +0.009587 +0.00943 +0.009342 +0.009412 +0.009498 +0.009603 +0.009656 +0.009487 +0.00939 +0.00947 +0.009535 +0.00962 +0.00968 +0.009521 +0.009443 +0.009496 +0.009596 +0.009687 +0.009749 +0.009561 +0.009505 +0.009537 +0.009619 +0.009717 +0.009789 +0.009608 +0.009538 +0.009611 +0.009696 +0.009793 +0.00984 +0.009655 +0.009576 +0.009639 +0.009729 +0.009859 +0.009875 +0.009707 +0.009625 +0.00971 +0.009798 +0.009886 +0.009911 +0.009766 +0.009671 +0.009735 +0.009829 +0.009924 +0.009999 +0.009802 +0.009743 +0.0098 +0.009875 +0.009969 +0.010023 +0.009861 +0.009784 +0.009831 +0.009913 +0.010029 +0.010109 +0.009945 +0.009832 +0.009886 +0.009964 +0.010068 +0.01015 +0.009946 +0.009873 +0.009932 +0.01002 +0.010129 +0.010208 +0.010024 +0.00993 +0.009979 +0.01006 +0.010159 +0.010242 +0.010056 +0.009965 +0.010048 +0.010119 +0.01025 +0.010313 +0.010141 +0.010024 +0.010071 +0.01016 +0.010278 +0.010343 +0.010145 +0.010082 +0.010163 +0.010219 +0.010312 +0.010362 +0.010156 +0.010042 +0.010078 +0.01012 +0.010186 +0.010189 +0.009973 +0.009851 +0.009857 +0.009883 +0.00993 +0.009941 +0.009716 +0.009577 +0.009609 +0.009615 +0.009644 +0.009673 +0.009453 +0.009323 +0.00931 +0.009342 +0.009388 +0.00943 +0.009191 +0.009068 +0.009083 +0.009133 +0.009164 +0.009191 +0.008983 +0.008868 +0.008867 +0.008915 +0.00895 +0.008975 +0.008801 +0.008681 +0.008697 +0.008754 +0.008811 +0.008845 +0.008674 +0.008547 +0.008572 +0.0086 +0.008654 +0.008697 +0.00852 +0.008426 +0.00846 +0.008512 +0.008544 +0.008588 +0.008441 +0.008327 +0.008356 +0.008405 +0.008467 +0.008515 +0.008357 +0.008279 +0.008317 +0.008372 +0.008444 +0.008492 +0.008353 +0.008278 +0.008322 +0.008401 +0.008476 +0.008553 +0.008397 +0.008317 +0.008375 +0.008466 +0.008516 +0.008579 +0.008415 +0.008354 +0.008411 +0.008481 +0.008555 +0.008615 +0.008471 +0.008409 +0.008453 +0.008528 +0.00862 +0.008666 +0.008515 +0.008443 +0.008496 +0.008586 +0.008637 +0.008704 +0.008563 +0.008478 +0.008536 +0.008609 +0.008725 +0.008765 +0.0086 +0.008532 +0.008565 +0.008643 +0.008738 +0.008798 +0.008637 +0.008566 +0.008616 +0.008703 +0.008785 +0.008851 +0.008687 +0.00862 +0.008657 +0.008737 +0.008816 +0.008878 +0.008734 +0.008655 +0.008698 +0.00878 +0.00888 +0.008931 +0.008775 +0.008714 +0.008752 +0.008854 +0.008917 +0.008964 +0.008809 +0.008722 +0.008793 +0.008871 +0.008948 +0.00903 +0.008875 +0.008781 +0.008835 +0.008921 +0.009006 +0.009068 +0.008916 +0.008855 +0.008875 +0.008959 +0.009049 +0.009103 +0.008949 +0.008873 +0.008927 +0.009008 +0.009093 +0.009162 +0.009011 +0.008967 +0.008973 +0.009036 +0.009132 +0.009181 +0.009048 +0.008959 +0.009009 +0.009103 +0.009193 +0.009269 +0.009094 +0.009026 +0.009049 +0.009129 +0.009222 +0.009291 +0.00913 +0.009051 +0.009108 +0.009194 +0.009271 +0.009363 +0.009195 +0.009109 +0.009139 +0.009225 +0.009345 +0.009395 +0.009215 +0.009148 +0.009188 +0.009285 +0.009374 +0.009448 +0.009283 +0.009201 +0.009235 +0.009312 +0.009422 +0.009484 +0.00931 +0.009234 +0.009295 +0.00938 +0.00947 +0.009551 +0.00936 +0.009283 +0.009336 +0.009411 +0.009509 +0.009572 +0.009418 +0.00936 +0.009397 +0.009469 +0.009575 +0.009629 +0.00949 +0.009363 +0.009416 +0.009514 +0.009598 +0.00967 +0.009501 +0.009426 +0.009476 +0.009573 +0.009688 +0.009722 +0.009555 +0.009469 +0.009519 +0.009614 +0.009706 +0.009762 +0.009598 +0.009522 +0.009589 +0.009705 +0.009784 +0.009823 +0.009635 +0.009559 +0.009624 +0.009702 +0.009828 +0.009848 +0.009708 +0.009629 +0.009685 +0.009774 +0.009856 +0.009905 +0.009747 +0.009666 +0.009715 +0.009808 +0.009898 +0.009961 +0.009825 +0.009724 +0.009785 +0.009879 +0.009961 +0.010042 +0.009828 +0.009747 +0.009814 +0.009908 +0.010006 +0.010063 +0.009892 +0.009845 +0.009874 +0.009946 +0.010061 +0.010121 +0.00994 +0.009866 +0.009924 +0.01 +0.010122 +0.010169 +0.009994 +0.009912 +0.009955 +0.010056 +0.010166 +0.010239 +0.010087 +0.009969 +0.010012 +0.010102 +0.010206 +0.010281 +0.010089 +0.009998 +0.010078 +0.010163 +0.010294 +0.010317 +0.010146 +0.010055 +0.010117 +0.0102 +0.010273 +0.010346 +0.010126 +0.010022 +0.010034 +0.010084 +0.010163 +0.010181 +0.009955 +0.009824 +0.009864 +0.009898 +0.009926 +0.009896 +0.009695 +0.009576 +0.009568 +0.009612 +0.009669 +0.009664 +0.009449 +0.009335 +0.009332 +0.009364 +0.009397 +0.009434 +0.009219 +0.009085 +0.0091 +0.009133 +0.009175 +0.009193 +0.008988 +0.008864 +0.008877 +0.008926 +0.008963 +0.009016 +0.008796 +0.008682 +0.008702 +0.008762 +0.008812 +0.008832 +0.00864 +0.008537 +0.008569 +0.008605 +0.008664 +0.008697 +0.008525 +0.008418 +0.008449 +0.008512 +0.008555 +0.008587 +0.008419 +0.008314 +0.008347 +0.008392 +0.008459 +0.008505 +0.008351 +0.008258 +0.008303 +0.008371 +0.008486 +0.008521 +0.008364 +0.008291 +0.008325 +0.008396 +0.008483 +0.008559 +0.008383 +0.008326 +0.008374 +0.008441 +0.008525 +0.008591 +0.008437 +0.008368 +0.008421 +0.008491 +0.008571 +0.008626 +0.008488 +0.008415 +0.008468 +0.008534 +0.008615 +0.008682 +0.008542 +0.008448 +0.008507 +0.008581 +0.00868 +0.008709 +0.008565 +0.00849 +0.008543 +0.008636 +0.008698 +0.008749 +0.008609 +0.008564 +0.008581 +0.008653 +0.00874 +0.008798 +0.008647 +0.008588 +0.008649 +0.008711 +0.008795 +0.008843 +0.008695 +0.00862 +0.008673 +0.008752 +0.008827 +0.008884 +0.008744 +0.008674 +0.008755 +0.008825 +0.008883 +0.008916 +0.008771 +0.0087 +0.008758 +0.008833 +0.008912 +0.008978 +0.008825 +0.00876 +0.008826 +0.008897 +0.008968 +0.009026 +0.008863 +0.008794 +0.008844 +0.008916 +0.009018 +0.009067 +0.008906 +0.008836 +0.008897 +0.008985 +0.009069 +0.009133 +0.008988 +0.008903 +0.008933 +0.009002 +0.009115 +0.009147 +0.008998 +0.008918 +0.008972 +0.009077 +0.009156 +0.009212 +0.009058 +0.008984 +0.009016 +0.0091 +0.009196 +0.009249 +0.009091 +0.009018 +0.009066 +0.009163 +0.009253 +0.00932 +0.009141 +0.009071 +0.009116 +0.009204 +0.009317 +0.009345 +0.009178 +0.009092 +0.009156 +0.00927 +0.009344 +0.009398 +0.009243 +0.009162 +0.009202 +0.009286 +0.009382 +0.009433 +0.009277 +0.00922 +0.009247 +0.009348 +0.009436 +0.009503 +0.00933 +0.009242 +0.009312 +0.009376 +0.009472 +0.009541 +0.009382 +0.009314 +0.009357 +0.009445 +0.00953 +0.009591 +0.009431 +0.009327 +0.009422 +0.009474 +0.00957 +0.00962 +0.009472 +0.009379 +0.009442 +0.009527 +0.009631 +0.009688 +0.009513 +0.009447 +0.009488 +0.009579 +0.00968 +0.00974 +0.009563 +0.009486 +0.009548 +0.009664 +0.009733 +0.009771 +0.009603 +0.009529 +0.009588 +0.009683 +0.009785 +0.009852 +0.009681 +0.009567 +0.00963 +0.009723 +0.009812 +0.009875 +0.009705 +0.009628 +0.009691 +0.009803 +0.00988 +0.009923 +0.009756 +0.009659 +0.009736 +0.009824 +0.009922 +0.010015 +0.009813 +0.009743 +0.009789 +0.009871 +0.009975 +0.010011 +0.009849 +0.009774 +0.009822 +0.009916 +0.010026 +0.010095 +0.009923 +0.009839 +0.00989 +0.009961 +0.01006 +0.010117 +0.009948 +0.009881 +0.009928 +0.010012 +0.010143 +0.010209 +0.010055 +0.009923 +0.009978 +0.010047 +0.010176 +0.010215 +0.010041 +0.009973 +0.010048 +0.010103 +0.010213 +0.010287 +0.010103 +0.010011 +0.010082 +0.010168 +0.010273 +0.010347 +0.010179 +0.010069 +0.010127 +0.010213 +0.010322 +0.010395 +0.010242 +0.010135 +0.010165 +0.010247 +0.010335 +0.010408 +0.010188 +0.010037 +0.010057 +0.010103 +0.010173 +0.010171 +0.009949 +0.00982 +0.009861 +0.009886 +0.009937 +0.009941 +0.009722 +0.009591 +0.009598 +0.009632 +0.009676 +0.009683 +0.009462 +0.009331 +0.009348 +0.009404 +0.009436 +0.009416 +0.009203 +0.009089 +0.009104 +0.009141 +0.009212 +0.009197 +0.009 +0.00887 +0.008885 +0.008935 +0.008981 +0.009 +0.008805 +0.008708 +0.00872 +0.008763 +0.008818 +0.008849 +0.00867 +0.008557 +0.008584 +0.008628 +0.008689 +0.008709 +0.008541 +0.008448 +0.00848 +0.008501 +0.008556 +0.008595 +0.008425 +0.008349 +0.008368 +0.008412 +0.008478 +0.008544 +0.008358 +0.008272 +0.008316 +0.008385 +0.008453 +0.008517 +0.008394 +0.0083 +0.008354 +0.008423 +0.008499 +0.008546 +0.008406 +0.008337 +0.008394 +0.008459 +0.00853 +0.008598 +0.008463 +0.008417 +0.008456 +0.008516 +0.008574 +0.00862 +0.008484 +0.008423 +0.008468 +0.008542 +0.008621 +0.008684 +0.00855 +0.00847 +0.008516 +0.00858 +0.008662 +0.008725 +0.008579 +0.008507 +0.008556 +0.008634 +0.008712 +0.008783 +0.008626 +0.008551 +0.0086 +0.008669 +0.008756 +0.008823 +0.008695 +0.008596 +0.008638 +0.008713 +0.008819 +0.008856 +0.008716 +0.008633 +0.008675 +0.008761 +0.008836 +0.008899 +0.008752 +0.008683 +0.008726 +0.008801 +0.008894 +0.008953 +0.008813 +0.008736 +0.008772 +0.008837 +0.00893 +0.008993 +0.008844 +0.008759 +0.008806 +0.0089 +0.009002 +0.009063 +0.008889 +0.008815 +0.008854 +0.008929 +0.009034 +0.009095 +0.00892 +0.008846 +0.0089 +0.008973 +0.009071 +0.009154 +0.00898 +0.008904 +0.008959 +0.009015 +0.009109 +0.009171 +0.009023 +0.00894 +0.008985 +0.009084 +0.009158 +0.009219 +0.009072 +0.008991 +0.009065 +0.009136 +0.009198 +0.009245 +0.009107 +0.00903 +0.009083 +0.009176 +0.009283 +0.009314 +0.009151 +0.009067 +0.009131 +0.009215 +0.009294 +0.009355 +0.009209 +0.009115 +0.009181 +0.009273 +0.009355 +0.009393 +0.009248 +0.009169 +0.00922 +0.009303 +0.009401 +0.00947 +0.009321 +0.009215 +0.009262 +0.009353 +0.009442 +0.009487 +0.00933 +0.009257 +0.009323 +0.0094 +0.009484 +0.009549 +0.009393 +0.009312 +0.009368 +0.009457 +0.009525 +0.009582 +0.00944 +0.009349 +0.009408 +0.009496 +0.009582 +0.009644 +0.00948 +0.009406 +0.009488 +0.009539 +0.009633 +0.009692 +0.009518 +0.009448 +0.009507 +0.009589 +0.009677 +0.009738 +0.00957 +0.009492 +0.009551 +0.009624 +0.009731 +0.009801 +0.009629 +0.009544 +0.009621 +0.009672 +0.009779 +0.009849 +0.009673 +0.00958 +0.009641 +0.009733 +0.009868 +0.009892 +0.009725 +0.009638 +0.009696 +0.009784 +0.009851 +0.00993 +0.009772 +0.009673 +0.009731 +0.00983 +0.009932 +0.010011 +0.009832 +0.009731 +0.00978 +0.009872 +0.009982 +0.01005 +0.009858 +0.009775 +0.00983 +0.00993 +0.010055 +0.01012 +0.009926 +0.009814 +0.009873 +0.009971 +0.010083 +0.010137 +0.009977 +0.009882 +0.009938 +0.010042 +0.010146 +0.010183 +0.010004 +0.009925 +0.009988 +0.010075 +0.010174 +0.010241 +0.01007 +0.009983 +0.010061 +0.010153 +0.010217 +0.01029 +0.010138 +0.010032 +0.010079 +0.010159 +0.010275 +0.010352 +0.010179 +0.010088 +0.01018 +0.010219 +0.010305 +0.010373 +0.010179 +0.010088 +0.01013 +0.010188 +0.010247 +0.010282 +0.010079 +0.009951 +0.009938 +0.009991 +0.010033 +0.010025 +0.009828 +0.009688 +0.009753 +0.009724 +0.009764 +0.009772 +0.009559 +0.009439 +0.009423 +0.009459 +0.009496 +0.009503 +0.009302 +0.009178 +0.009185 +0.009228 +0.009263 +0.009277 +0.009068 +0.008943 +0.008969 +0.008997 +0.009021 +0.009039 +0.008855 +0.008739 +0.008763 +0.008822 +0.008858 +0.008898 +0.008692 +0.008583 +0.008608 +0.008643 +0.008692 +0.008712 +0.008549 +0.008453 +0.008484 +0.008524 +0.008582 +0.008614 +0.008457 +0.008354 +0.00838 +0.008425 +0.008471 +0.008509 +0.00836 +0.00828 +0.008315 +0.008361 +0.008429 +0.008496 +0.00834 +0.008268 +0.008328 +0.008383 +0.00848 +0.008522 +0.008359 +0.008297 +0.008344 +0.008421 +0.008521 +0.008539 +0.008421 +0.008351 +0.008404 +0.008472 +0.008548 +0.008604 +0.008443 +0.008378 +0.008432 +0.008511 +0.008582 +0.008646 +0.008491 +0.008448 +0.00851 +0.008556 +0.008639 +0.008684 +0.008533 +0.008471 +0.008522 +0.008597 +0.00869 +0.008718 +0.008574 +0.008499 +0.008574 +0.008649 +0.008728 +0.008799 +0.008627 +0.008547 +0.008595 +0.008671 +0.008752 +0.008815 +0.008669 +0.008593 +0.008664 +0.008732 +0.008823 +0.008871 +0.008726 +0.008644 +0.008681 +0.008765 +0.00884 +0.008905 +0.008759 +0.008697 +0.00875 +0.008838 +0.008898 +0.008949 +0.008804 +0.008733 +0.008789 +0.008833 +0.008932 +0.008997 +0.008872 +0.008771 +0.008832 +0.008901 +0.008972 +0.00904 +0.008893 +0.008813 +0.00887 +0.008932 +0.00904 +0.009089 +0.008933 +0.008866 +0.008926 +0.008989 +0.009075 +0.009149 +0.009 +0.008915 +0.008966 +0.009017 +0.009105 +0.009176 +0.009029 +0.008946 +0.009016 +0.00909 +0.009164 +0.009225 +0.00908 +0.008993 +0.009045 +0.009111 +0.009213 +0.009279 +0.009116 +0.009041 +0.009118 +0.009181 +0.00926 +0.00932 +0.00916 +0.009079 +0.009142 +0.009213 +0.009337 +0.009349 +0.009203 +0.00913 +0.009227 +0.009269 +0.009342 +0.00941 +0.009245 +0.009169 +0.009218 +0.009304 +0.009408 +0.009466 +0.009308 +0.009243 +0.00931 +0.009347 +0.009445 +0.009508 +0.009341 +0.009256 +0.009323 +0.009398 +0.009491 +0.009573 +0.009411 +0.009358 +0.009383 +0.00943 +0.009529 +0.009592 +0.009439 +0.009356 +0.009404 +0.009508 +0.009591 +0.009666 +0.009513 +0.00942 +0.009452 +0.009537 +0.009639 +0.009691 +0.009527 +0.009455 +0.009511 +0.009596 +0.009707 +0.009761 +0.009598 +0.009527 +0.00955 +0.009668 +0.009713 +0.009784 +0.009617 +0.00953 +0.009614 +0.009689 +0.009808 +0.009889 +0.009674 +0.009579 +0.009647 +0.009732 +0.009832 +0.009902 +0.009728 +0.009638 +0.009712 +0.009801 +0.009893 +0.009952 +0.00977 +0.009696 +0.009743 +0.009844 +0.009948 +0.01003 +0.009807 +0.009725 +0.009803 +0.009901 +0.009989 +0.010031 +0.009868 +0.009791 +0.009854 +0.009931 +0.010036 +0.010087 +0.009931 +0.009858 +0.009917 +0.009996 +0.010081 +0.010136 +0.009966 +0.009892 +0.009939 +0.010027 +0.01015 +0.010214 +0.010069 +0.009942 +0.009994 +0.010068 +0.010178 +0.010241 +0.010068 +0.009984 +0.010048 +0.010128 +0.010239 +0.010326 +0.010129 +0.010058 +0.010108 +0.010159 +0.010255 +0.010319 +0.010115 +0.010005 +0.010044 +0.010075 +0.010162 +0.010199 +0.009972 +0.009837 +0.009844 +0.009921 +0.00994 +0.009975 +0.009709 +0.009585 +0.009604 +0.009656 +0.009694 +0.009715 +0.009482 +0.009341 +0.009372 +0.009388 +0.009422 +0.00944 +0.009233 +0.009103 +0.009112 +0.009153 +0.009184 +0.009208 +0.009011 +0.008894 +0.008899 +0.00893 +0.008987 +0.009024 +0.008834 +0.008686 +0.008699 +0.008747 +0.008816 +0.008822 +0.008634 +0.00853 +0.008556 +0.008596 +0.008646 +0.008684 +0.008521 +0.008407 +0.008422 +0.008467 +0.008531 +0.008553 +0.008392 +0.008298 +0.008325 +0.008371 +0.008438 +0.008504 +0.008341 +0.00825 +0.008276 +0.008341 +0.008416 +0.008494 +0.008321 +0.008254 +0.008289 +0.008369 +0.008451 +0.008509 +0.008401 +0.008296 +0.008353 +0.008412 +0.008482 +0.008545 +0.008408 +0.008335 +0.008382 +0.008451 +0.008533 +0.008595 +0.008448 +0.008394 +0.008439 +0.008507 +0.008572 +0.008639 +0.008491 +0.008418 +0.008468 +0.008548 +0.00864 +0.008696 +0.008532 +0.008451 +0.00851 +0.008578 +0.008673 +0.008713 +0.008575 +0.008503 +0.008551 +0.008636 +0.008705 +0.008767 +0.008623 +0.008545 +0.008603 +0.008685 +0.008756 +0.00881 +0.008679 +0.008589 +0.008633 +0.008707 +0.008796 +0.008853 +0.008699 +0.008631 +0.008685 +0.008794 +0.008864 +0.008915 +0.008733 +0.008659 +0.008716 +0.008795 +0.008878 +0.008935 +0.008793 +0.008716 +0.008783 +0.008858 +0.00894 +0.009003 +0.008832 +0.008752 +0.008806 +0.00888 +0.00897 +0.00904 +0.008875 +0.008802 +0.008875 +0.008948 +0.009027 +0.009076 +0.008936 +0.008857 +0.008913 +0.00897 +0.009049 +0.009144 +0.00896 +0.008891 +0.008938 +0.009014 +0.009114 +0.009173 +0.009013 +0.008931 +0.008997 +0.009082 +0.009155 +0.009224 +0.009071 +0.008974 +0.009031 +0.009108 +0.009201 +0.009264 +0.009114 +0.00903 +0.009083 +0.00917 +0.009261 +0.009342 +0.009161 +0.009065 +0.009109 +0.009202 +0.009299 +0.009372 +0.009191 +0.00911 +0.009186 +0.009253 +0.009344 +0.009413 +0.009249 +0.009155 +0.009219 +0.009296 +0.009387 +0.009451 +0.009302 +0.009211 +0.00927 +0.009357 +0.009453 +0.009511 +0.009345 +0.00925 +0.009335 +0.009385 +0.009473 +0.009532 +0.009373 +0.009311 +0.009349 +0.009431 +0.009562 +0.009611 +0.009426 +0.009345 +0.009408 +0.009486 +0.009577 +0.009649 +0.009462 +0.009425 +0.009451 +0.009537 +0.009645 +0.009696 +0.009525 +0.00944 +0.009493 +0.009585 +0.009709 +0.009747 +0.009556 +0.009477 +0.009542 +0.009649 +0.009733 +0.009774 +0.009621 +0.00954 +0.009606 +0.009675 +0.009778 +0.009825 +0.009675 +0.009605 +0.009649 +0.009731 +0.009827 +0.009869 +0.009707 +0.009638 +0.009694 +0.009783 +0.009865 +0.009945 +0.00982 +0.009695 +0.009752 +0.009814 +0.009906 +0.009968 +0.009788 +0.009739 +0.00979 +0.009864 +0.009978 +0.010072 +0.009879 +0.009782 +0.009846 +0.009905 +0.010007 +0.010091 +0.009904 +0.009825 +0.009885 +0.009975 +0.010096 +0.010158 +0.009964 +0.009876 +0.009933 +0.010035 +0.010159 +0.010182 +0.010004 +0.009902 +0.009981 +0.010089 +0.010184 +0.010245 +0.010057 +0.009961 +0.010034 +0.010123 +0.010221 +0.010285 +0.01011 +0.010028 +0.0101 +0.0102 +0.010292 +0.010334 +0.010155 +0.010063 +0.010136 +0.010219 +0.010333 +0.010376 +0.010182 +0.010077 +0.010106 +0.010173 +0.010192 +0.010211 +0.010008 +0.009889 +0.009899 +0.009937 +0.009984 +0.010046 +0.009776 +0.009646 +0.009657 +0.009668 +0.009714 +0.00973 +0.009513 +0.009392 +0.009393 +0.009411 +0.009471 +0.009493 +0.009304 +0.009141 +0.009151 +0.009158 +0.009207 +0.009223 +0.009054 +0.008896 +0.008918 +0.00894 +0.00899 +0.009018 +0.008836 +0.008712 +0.008732 +0.008749 +0.008805 +0.008823 +0.008644 +0.008556 +0.008569 +0.008612 +0.008657 +0.008706 +0.008527 +0.008429 +0.008458 +0.008495 +0.00855 +0.008569 +0.008397 +0.008303 +0.008344 +0.008379 +0.008436 +0.008477 +0.008326 +0.008252 +0.008286 +0.008334 +0.008387 +0.00845 +0.008301 +0.008239 +0.008286 +0.008351 +0.008425 +0.008497 +0.008337 +0.008278 +0.00832 +0.008402 +0.008467 +0.008531 +0.008379 +0.008311 +0.008375 +0.008443 +0.00854 +0.008589 +0.008423 +0.008342 +0.0084 +0.008476 +0.008558 +0.008603 +0.008466 +0.008399 +0.008449 +0.008543 +0.008598 +0.008656 +0.008511 +0.008441 +0.008486 +0.008564 +0.008639 +0.008699 +0.008558 +0.008482 +0.008535 +0.008601 +0.008692 +0.008737 +0.008597 +0.008524 +0.008589 +0.008667 +0.008736 +0.008784 +0.008634 +0.008564 +0.008616 +0.008685 +0.008777 +0.008817 +0.008687 +0.008613 +0.008665 +0.008733 +0.008826 +0.008896 +0.008725 +0.008656 +0.008707 +0.008772 +0.008858 +0.008932 +0.008768 +0.008701 +0.008744 +0.008837 +0.008899 +0.008965 +0.008821 +0.00875 +0.008815 +0.008861 +0.008943 +0.009007 +0.008857 +0.008813 +0.008851 +0.008914 +0.008984 +0.009053 +0.008895 +0.008824 +0.008881 +0.008948 +0.009035 +0.009107 +0.008949 +0.008872 +0.00894 +0.009024 +0.00909 +0.009146 +0.008988 +0.008912 +0.008959 +0.009046 +0.00913 +0.009208 +0.009062 +0.008954 +0.009027 +0.009102 +0.009169 +0.009239 +0.009079 +0.009015 +0.009049 +0.009123 +0.009211 +0.009286 +0.009137 +0.009051 +0.009121 +0.009206 +0.009265 +0.009325 +0.009173 +0.00909 +0.009151 +0.009226 +0.009317 +0.009388 +0.009216 +0.009148 +0.009214 +0.009323 +0.009355 +0.009412 +0.009247 +0.009176 +0.009243 +0.009316 +0.009403 +0.009483 +0.009331 +0.009238 +0.009298 +0.009383 +0.009444 +0.009512 +0.009359 +0.009269 +0.009328 +0.009414 +0.009501 +0.009581 +0.009403 +0.009339 +0.009392 +0.009454 +0.009556 +0.009634 +0.009474 +0.009372 +0.009417 +0.009495 +0.009597 +0.009663 +0.009496 +0.00943 +0.009481 +0.009553 +0.009643 +0.009733 +0.009539 +0.009459 +0.009526 +0.009598 +0.009697 +0.009766 +0.00961 +0.009532 +0.009584 +0.009648 +0.009737 +0.009804 +0.009647 +0.009572 +0.009642 +0.009692 +0.009796 +0.009872 +0.009718 +0.009611 +0.009648 +0.009736 +0.009846 +0.009896 +0.009736 +0.009661 +0.009696 +0.00981 +0.009912 +0.009974 +0.009796 +0.009706 +0.009753 +0.009853 +0.009941 +0.010005 +0.009837 +0.009749 +0.009819 +0.009941 +0.010021 +0.010058 +0.009879 +0.009785 +0.009865 +0.009972 +0.010024 +0.010101 +0.009915 +0.009851 +0.00992 +0.010016 +0.010115 +0.010167 +0.009982 +0.009894 +0.009958 +0.010047 +0.010152 +0.010205 +0.010037 +0.009952 +0.010025 +0.010122 +0.010239 +0.010243 +0.010073 +0.009987 +0.010049 +0.010156 +0.010237 +0.010318 +0.010181 +0.010061 +0.010114 +0.010196 +0.010286 +0.010357 +0.010193 +0.010093 +0.010156 +0.010247 +0.010332 +0.010416 +0.010214 +0.010095 +0.010107 +0.010172 +0.01022 +0.010243 +0.010031 +0.009935 +0.009911 +0.009945 +0.01002 +0.010006 +0.009789 +0.009627 +0.009637 +0.009711 +0.009718 +0.009729 +0.009518 +0.009394 +0.009408 +0.009444 +0.009483 +0.009492 +0.009278 +0.009158 +0.009154 +0.00919 +0.009239 +0.00925 +0.009053 +0.008945 +0.008965 +0.009008 +0.009062 +0.009032 +0.008834 +0.008735 +0.008755 +0.008799 +0.008842 +0.008873 +0.008699 +0.008597 +0.008641 +0.008665 +0.008728 +0.00875 +0.008571 +0.008462 +0.008493 +0.00853 +0.008594 +0.00863 +0.008455 +0.008361 +0.008399 +0.008457 +0.008507 +0.008546 +0.008388 +0.008306 +0.008348 +0.008401 +0.008448 +0.008513 +0.008366 +0.008298 +0.00835 +0.008403 +0.008489 +0.008534 +0.008416 +0.008334 +0.00839 +0.008456 +0.008539 +0.008597 +0.00845 +0.008387 +0.00844 +0.008495 +0.008588 +0.008639 +0.008487 +0.008418 +0.008476 +0.008544 +0.008612 +0.008683 +0.008543 +0.008469 +0.008543 +0.008608 +0.008662 +0.008708 +0.008566 +0.008523 +0.008546 +0.00862 +0.008705 +0.00876 +0.008619 +0.008546 +0.008596 +0.008674 +0.008759 +0.00881 +0.008666 +0.008588 +0.008637 +0.008715 +0.008798 +0.008858 +0.008702 +0.008634 +0.008687 +0.008752 +0.008854 +0.008915 +0.008759 +0.008694 +0.008713 +0.008787 +0.008877 +0.008939 +0.008792 +0.008715 +0.008773 +0.008848 +0.008937 +0.008983 +0.008839 +0.008761 +0.008806 +0.00889 +0.008975 +0.009042 +0.008882 +0.008804 +0.008859 +0.00893 +0.00903 +0.009086 +0.008941 +0.00885 +0.008889 +0.00898 +0.009091 +0.009147 +0.008959 +0.008881 +0.008931 +0.009014 +0.009126 +0.009163 +0.009019 +0.008939 +0.008989 +0.00906 +0.009153 +0.009221 +0.009056 +0.00898 +0.009031 +0.009112 +0.009212 +0.009279 +0.009125 +0.009019 +0.009071 +0.00916 +0.009245 +0.009306 +0.009151 +0.009079 +0.009139 +0.009221 +0.009322 +0.009326 +0.009182 +0.009105 +0.009164 +0.009254 +0.009344 +0.009408 +0.009255 +0.009169 +0.00922 +0.009286 +0.009381 +0.00945 +0.009286 +0.009202 +0.009277 +0.009357 +0.009437 +0.0095 +0.009359 +0.00925 +0.009304 +0.009384 +0.009483 +0.009572 +0.009383 +0.009291 +0.009361 +0.009468 +0.009532 +0.009589 +0.009437 +0.009336 +0.009397 +0.009477 +0.009574 +0.009643 +0.009474 +0.009391 +0.009459 +0.009538 +0.009634 +0.009718 +0.009527 +0.009435 +0.009492 +0.009586 +0.009678 +0.009732 +0.009569 +0.009506 +0.009573 +0.00962 +0.009724 +0.009794 +0.009606 +0.00957 +0.00958 +0.009674 +0.009773 +0.009817 +0.009655 +0.009592 +0.009637 +0.00973 +0.009853 +0.009893 +0.009725 +0.009629 +0.009688 +0.009782 +0.009873 +0.00994 +0.009753 +0.009678 +0.009741 +0.009873 +0.009941 +0.009984 +0.009786 +0.009722 +0.009794 +0.009864 +0.009969 +0.010062 +0.009872 +0.009778 +0.009843 +0.009931 +0.010032 +0.010069 +0.009904 +0.00982 +0.00989 +0.009978 +0.010067 +0.010144 +0.009982 +0.009889 +0.009941 +0.010041 +0.010142 +0.010203 +0.009986 +0.009909 +0.009977 +0.010084 +0.010166 +0.010235 +0.010074 +0.009973 +0.010035 +0.010132 +0.010234 +0.010293 +0.010117 +0.01003 +0.010085 +0.010187 +0.01028 +0.010349 +0.010169 +0.010073 +0.010135 +0.010231 +0.010342 +0.010439 +0.010226 +0.010129 +0.010187 +0.010269 +0.010383 +0.010439 +0.010261 +0.010176 +0.010221 +0.010312 +0.010415 +0.010442 +0.010229 +0.010112 +0.010127 +0.01017 +0.010235 +0.010239 +0.010013 +0.009883 +0.009909 +0.009926 +0.009978 +0.009972 +0.009759 +0.009593 +0.009593 +0.009643 +0.009726 +0.00969 +0.009467 +0.009354 +0.009374 +0.009399 +0.009443 +0.009451 +0.009222 +0.009088 +0.009106 +0.009141 +0.009185 +0.009214 +0.009018 +0.008874 +0.00888 +0.008924 +0.008973 +0.008996 +0.0088 +0.008686 +0.008714 +0.008772 +0.008803 +0.008828 +0.008642 +0.008528 +0.008555 +0.008593 +0.008676 +0.008674 +0.008506 +0.008395 +0.008422 +0.00848 +0.008534 +0.00858 +0.008404 +0.008312 +0.008324 +0.008378 +0.008448 +0.008492 +0.008324 +0.008231 +0.008274 +0.008331 +0.008433 +0.008479 +0.008337 +0.008253 +0.008327 +0.008379 +0.008429 +0.008488 +0.008357 +0.008289 +0.008342 +0.008399 +0.008481 +0.008561 +0.008436 +0.008336 +0.008387 +0.00846 +0.008531 +0.008577 +0.008441 +0.008382 +0.00841 +0.008494 +0.008592 +0.008643 +0.008516 +0.008416 +0.00847 +0.008534 +0.008601 +0.008669 +0.008529 +0.008469 +0.00853 +0.008601 +0.008659 +0.008705 +0.008562 +0.008503 +0.008543 +0.008618 +0.008699 +0.008762 +0.008614 +0.008541 +0.008602 +0.008664 +0.008762 +0.008804 +0.008663 +0.008584 +0.008635 +0.008715 +0.008798 +0.008846 +0.008708 +0.008639 +0.008676 +0.00875 +0.008846 +0.008915 +0.008763 +0.008687 +0.008718 +0.008795 +0.008895 +0.008934 +0.00879 +0.00871 +0.008762 +0.008855 +0.008935 +0.008995 +0.008826 +0.008762 +0.008812 +0.008884 +0.008969 +0.009039 +0.008878 +0.008817 +0.00886 +0.008943 +0.009027 +0.009086 +0.008931 +0.008839 +0.008897 +0.008977 +0.009081 +0.009146 +0.008961 +0.008881 +0.008953 +0.009029 +0.009126 +0.009194 +0.009002 +0.008925 +0.008981 +0.009062 +0.009154 +0.009218 +0.009056 +0.008976 +0.009054 +0.009123 +0.009215 +0.009274 +0.00911 +0.009007 +0.009071 +0.009163 +0.009242 +0.009305 +0.009157 +0.009073 +0.009175 +0.009219 +0.009296 +0.009348 +0.009187 +0.009109 +0.009161 +0.009243 +0.009366 +0.0094 +0.009234 +0.009161 +0.009238 +0.009304 +0.009392 +0.009458 +0.009288 +0.009198 +0.009253 +0.009345 +0.009435 +0.009497 +0.009354 +0.00926 +0.009298 +0.009396 +0.009485 +0.009588 +0.009372 +0.00929 +0.009337 +0.009436 +0.009552 +0.009599 +0.009432 +0.009351 +0.009391 +0.00949 +0.009577 +0.009644 +0.009478 +0.009381 +0.009454 +0.009546 +0.009643 +0.009703 +0.009534 +0.009422 +0.009493 +0.009576 +0.00967 +0.009736 +0.009568 +0.009518 +0.009553 +0.009624 +0.009733 +0.009773 +0.009616 +0.009524 +0.009588 +0.009678 +0.009771 +0.009855 +0.009657 +0.009586 +0.009639 +0.009721 +0.009841 +0.009878 +0.00972 +0.009636 +0.009686 +0.00977 +0.009895 +0.009925 +0.009752 +0.009679 +0.009744 +0.009866 +0.009916 +0.009967 +0.009802 +0.009735 +0.009801 +0.009879 +0.009964 +0.01003 +0.009851 +0.009775 +0.009842 +0.009915 +0.01001 +0.010101 +0.009904 +0.009827 +0.009911 +0.009991 +0.010063 +0.010126 +0.009957 +0.009871 +0.009928 +0.010021 +0.01016 +0.010183 +0.010004 +0.009931 +0.00998 +0.010076 +0.010167 +0.010241 +0.010059 +0.009963 +0.010024 +0.010123 +0.010223 +0.01029 +0.010145 +0.010034 +0.010076 +0.010157 +0.010261 +0.01034 +0.010163 +0.010078 +0.010131 +0.010228 +0.010346 +0.010446 +0.010188 +0.010106 +0.010174 +0.010278 +0.010361 +0.010411 +0.01024 +0.010172 +0.010177 +0.010258 +0.010312 +0.010306 +0.010103 +0.009962 +0.009986 +0.010054 +0.010064 +0.010074 +0.009846 +0.009719 +0.009742 +0.009771 +0.009775 +0.009775 +0.009561 +0.00947 +0.009465 +0.009465 +0.009494 +0.009503 +0.009317 +0.009184 +0.009196 +0.009206 +0.009242 +0.009239 +0.009042 +0.008936 +0.00894 +0.008966 +0.009004 +0.009023 +0.008838 +0.008724 +0.008753 +0.00879 +0.008799 +0.008822 +0.008655 +0.00855 +0.00858 +0.008625 +0.008673 +0.008729 +0.008535 +0.008445 +0.008453 +0.008502 +0.008531 +0.008564 +0.0084 +0.008312 +0.008356 +0.008395 +0.008443 +0.008485 +0.008347 +0.008249 +0.008292 +0.008341 +0.008415 +0.008444 +0.008294 +0.00823 +0.008284 +0.008347 +0.008419 +0.008502 +0.008341 +0.008267 +0.008317 +0.008395 +0.008473 +0.008555 +0.008374 +0.008306 +0.008366 +0.008439 +0.00852 +0.008564 +0.00842 +0.00835 +0.008401 +0.008476 +0.008555 +0.008617 +0.008477 +0.008392 +0.008452 +0.008521 +0.0086 +0.008665 +0.008501 +0.008449 +0.008485 +0.008557 +0.008638 +0.008705 +0.008557 +0.00848 +0.008531 +0.008604 +0.008713 +0.008751 +0.008602 +0.008521 +0.00858 +0.008633 +0.008729 +0.008782 +0.008635 +0.008568 +0.00861 +0.008681 +0.008776 +0.008836 +0.008693 +0.008615 +0.008668 +0.008757 +0.008803 +0.008863 +0.008727 +0.008644 +0.0087 +0.008771 +0.008859 +0.008916 +0.008773 +0.008721 +0.008764 +0.008854 +0.00889 +0.008952 +0.008797 +0.008732 +0.008788 +0.008856 +0.008943 +0.00901 +0.008868 +0.008795 +0.008844 +0.008925 +0.008996 +0.009042 +0.008897 +0.008828 +0.00888 +0.008942 +0.009057 +0.009091 +0.008941 +0.008875 +0.008934 +0.009006 +0.009088 +0.00914 +0.008995 +0.008938 +0.008983 +0.009034 +0.009111 +0.009183 +0.009037 +0.008956 +0.00902 +0.009096 +0.00919 +0.009225 +0.009075 +0.009001 +0.009061 +0.009128 +0.009221 +0.009283 +0.009125 +0.009052 +0.009122 +0.009191 +0.009273 +0.009328 +0.009166 +0.009089 +0.009142 +0.00923 +0.009341 +0.00938 +0.009211 +0.009151 +0.009207 +0.009286 +0.00936 +0.009406 +0.009257 +0.009188 +0.009237 +0.00931 +0.009413 +0.009475 +0.009305 +0.009243 +0.009305 +0.009387 +0.009448 +0.009515 +0.009341 +0.009261 +0.00934 +0.009411 +0.009495 +0.009575 +0.009411 +0.009376 +0.009386 +0.009475 +0.009537 +0.009603 +0.009458 +0.009357 +0.009417 +0.009503 +0.009608 +0.00968 +0.009506 +0.009432 +0.009487 +0.009546 +0.009665 +0.009693 +0.009537 +0.009466 +0.00952 +0.009596 +0.009713 +0.009772 +0.009602 +0.009522 +0.009581 +0.009668 +0.009746 +0.009793 +0.009624 +0.009557 +0.009623 +0.009698 +0.009793 +0.009863 +0.009693 +0.009602 +0.009656 +0.009757 +0.009844 +0.009906 +0.009749 +0.009665 +0.009727 +0.009804 +0.009884 +0.009952 +0.009793 +0.009696 +0.009757 +0.009857 +0.009954 +0.010051 +0.009836 +0.009737 +0.009805 +0.009894 +0.009993 +0.01005 +0.009875 +0.009812 +0.009874 +0.009945 +0.010053 +0.010115 +0.009926 +0.009849 +0.00991 +0.009993 +0.010098 +0.010156 +0.009985 +0.009909 +0.009955 +0.010045 +0.010163 +0.010214 +0.010069 +0.009943 +0.010017 +0.010084 +0.010181 +0.010254 +0.01008 +0.010007 +0.010055 +0.010149 +0.010256 +0.01032 +0.010129 +0.010052 +0.010101 +0.010196 +0.01031 +0.010357 +0.010183 +0.010097 +0.010157 +0.010249 +0.010363 +0.010408 +0.010235 +0.010135 +0.010203 +0.010322 +0.010385 +0.010377 +0.010187 +0.010056 +0.010091 +0.010136 +0.010196 +0.010227 +0.00999 +0.009878 +0.009894 +0.00992 +0.009975 +0.009978 +0.009738 +0.009624 +0.009626 +0.009677 +0.009729 +0.00972 +0.009504 +0.009374 +0.00939 +0.009429 +0.009474 +0.009487 +0.009279 +0.009164 +0.009148 +0.009194 +0.009231 +0.009243 +0.009054 +0.008933 +0.008944 +0.008997 +0.00904 +0.009057 +0.008885 +0.008751 +0.008768 +0.008821 +0.008872 +0.008885 +0.008709 +0.008601 +0.008634 +0.008678 +0.008734 +0.008768 +0.008573 +0.008473 +0.008503 +0.008561 +0.008617 +0.008664 +0.008459 +0.008371 +0.008402 +0.008473 +0.008518 +0.008561 +0.008404 +0.008312 +0.008366 +0.008425 +0.008506 +0.008568 +0.00842 +0.008341 +0.008398 +0.008456 +0.008545 +0.008612 +0.008469 +0.008395 +0.008428 +0.008506 +0.008583 +0.008656 +0.008501 +0.008421 +0.008481 +0.008548 +0.008659 +0.008704 +0.008553 +0.008481 +0.008509 +0.008581 +0.00869 +0.008743 +0.008585 +0.008506 +0.008557 +0.008623 +0.008722 +0.008793 +0.008633 +0.008562 +0.008613 +0.00868 +0.008749 +0.008804 +0.008668 +0.008597 +0.008648 +0.008713 +0.008814 +0.008873 +0.008727 +0.008652 +0.008704 +0.008787 +0.008855 +0.008902 +0.008746 +0.008682 +0.00873 +0.008806 +0.008885 +0.00897 +0.008811 +0.008728 +0.008776 +0.008855 +0.008926 +0.009 +0.008846 +0.008779 +0.008819 +0.008908 +0.008977 +0.009043 +0.008889 +0.008815 +0.008875 +0.008943 +0.009023 +0.009096 +0.008944 +0.00888 +0.008929 +0.00899 +0.009077 +0.009119 +0.008971 +0.008903 +0.00895 +0.009034 +0.009131 +0.009183 +0.00904 +0.008944 +0.008996 +0.00909 +0.009171 +0.009225 +0.00906 +0.008979 +0.009055 +0.009133 +0.009215 +0.009267 +0.009125 +0.009032 +0.009084 +0.009187 +0.009278 +0.009336 +0.009154 +0.009102 +0.009134 +0.009215 +0.009303 +0.009351 +0.009204 +0.009126 +0.009174 +0.009268 +0.009373 +0.009407 +0.00925 +0.009168 +0.00924 +0.009315 +0.00939 +0.009458 +0.009292 +0.009214 +0.009266 +0.009381 +0.009449 +0.009497 +0.009354 +0.009278 +0.009358 +0.009389 +0.009487 +0.009537 +0.009415 +0.009315 +0.009363 +0.009455 +0.009549 +0.009589 +0.009429 +0.009366 +0.009409 +0.00949 +0.009588 +0.009636 +0.009499 +0.009408 +0.009468 +0.009547 +0.009638 +0.009695 +0.009522 +0.009448 +0.009507 +0.009597 +0.009717 +0.009754 +0.009589 +0.0095 +0.00956 +0.009651 +0.009721 +0.009795 +0.009618 +0.009527 +0.0096 +0.009693 +0.009784 +0.009861 +0.009687 +0.009607 +0.009657 +0.009724 +0.00983 +0.009881 +0.009717 +0.009646 +0.009705 +0.009774 +0.009906 +0.009972 +0.009814 +0.009687 +0.009747 +0.009808 +0.009918 +0.009989 +0.009815 +0.009737 +0.009841 +0.009865 +0.00997 +0.010046 +0.00986 +0.009783 +0.009847 +0.009927 +0.010034 +0.010104 +0.009923 +0.009848 +0.009884 +0.00998 +0.010079 +0.010142 +0.009986 +0.009916 +0.009977 +0.010028 +0.010116 +0.010194 +0.010035 +0.009915 +0.009989 +0.010086 +0.010177 +0.010254 +0.010071 +0.009978 +0.01004 +0.01014 +0.010243 +0.010305 +0.010117 +0.010026 +0.010102 +0.010191 +0.010282 +0.010344 +0.010182 +0.010096 +0.010179 +0.010241 +0.010352 +0.010407 +0.010201 +0.010118 +0.010187 +0.010288 +0.010377 +0.010426 +0.010258 +0.010149 +0.010215 +0.010269 +0.010299 +0.010325 +0.010107 +0.009969 +0.009994 +0.010041 +0.010067 +0.010092 +0.009877 +0.009755 +0.009758 +0.009791 +0.009834 +0.009797 +0.009574 +0.009452 +0.009501 +0.009493 +0.009511 +0.009528 +0.009325 +0.009203 +0.009212 +0.009244 +0.009274 +0.009285 +0.009081 +0.008974 +0.00899 +0.009034 +0.009047 +0.009066 +0.008874 +0.008769 +0.0088 +0.008833 +0.008863 +0.008892 +0.008713 +0.008634 +0.008656 +0.008696 +0.008723 +0.00875 +0.008582 +0.0085 +0.008547 +0.008568 +0.008619 +0.008643 +0.008483 +0.008391 +0.008433 +0.008478 +0.008535 +0.008548 +0.008403 +0.008307 +0.00835 +0.008407 +0.00846 +0.008503 +0.008356 +0.008297 +0.008339 +0.008402 +0.008476 +0.008556 +0.00841 +0.008338 +0.008362 +0.008425 +0.008512 +0.008575 +0.008428 +0.008354 +0.008408 +0.008487 +0.008584 +0.008643 +0.008476 +0.008391 +0.008452 +0.008518 +0.008599 +0.008667 +0.008512 +0.008436 +0.00851 +0.008574 +0.008663 +0.008725 +0.008562 +0.008498 +0.008524 +0.008602 +0.008691 +0.008752 +0.008626 +0.00857 +0.008563 +0.008637 +0.008727 +0.008799 +0.008651 +0.008576 +0.008627 +0.008691 +0.008772 +0.008835 +0.008682 +0.008615 +0.008672 +0.00873 +0.008822 +0.008887 +0.008743 +0.008668 +0.008715 +0.008777 +0.008864 +0.00893 +0.008772 +0.008704 +0.008751 +0.008833 +0.008931 +0.009003 +0.008807 +0.00874 +0.008804 +0.008861 +0.008955 +0.009009 +0.008852 +0.008788 +0.008846 +0.008916 +0.009002 +0.009086 +0.008901 +0.008829 +0.008881 +0.008963 +0.009048 +0.009106 +0.008957 +0.008874 +0.008928 +0.009013 +0.009101 +0.009164 +0.008989 +0.008922 +0.008984 +0.009072 +0.009132 +0.00919 +0.009031 +0.008969 +0.009039 +0.009088 +0.009182 +0.009263 +0.00909 +0.009002 +0.009059 +0.009145 +0.009227 +0.009298 +0.009137 +0.009052 +0.009107 +0.009184 +0.009281 +0.009363 +0.009182 +0.009104 +0.009155 +0.009237 +0.009332 +0.009391 +0.009253 +0.009144 +0.009195 +0.009276 +0.009368 +0.009457 +0.009261 +0.009185 +0.009255 +0.009336 +0.009423 +0.009479 +0.009316 +0.00924 +0.009289 +0.009381 +0.009474 +0.009558 +0.009358 +0.009279 +0.009353 +0.009427 +0.009516 +0.009578 +0.009408 +0.009337 +0.0094 +0.009493 +0.009568 +0.009617 +0.009446 +0.009377 +0.00944 +0.009511 +0.009612 +0.009672 +0.009511 +0.009422 +0.009503 +0.009579 +0.009668 +0.009718 +0.00955 +0.009473 +0.009528 +0.009644 +0.00969 +0.009746 +0.009609 +0.009525 +0.009595 +0.009688 +0.009786 +0.009853 +0.009644 +0.009552 +0.009607 +0.009698 +0.009799 +0.009856 +0.009702 +0.009639 +0.009694 +0.009769 +0.009876 +0.009896 +0.009736 +0.009663 +0.00971 +0.009802 +0.009902 +0.009981 +0.009821 +0.009721 +0.009783 +0.009861 +0.009944 +0.010016 +0.009872 +0.009764 +0.009811 +0.009901 +0.010028 +0.010083 +0.009892 +0.009809 +0.009876 +0.009954 +0.010041 +0.010116 +0.009938 +0.009864 +0.009917 +0.009998 +0.010128 +0.010185 +0.010016 +0.009902 +0.009956 +0.010056 +0.010153 +0.010218 +0.010049 +0.00998 +0.010032 +0.010119 +0.010212 +0.010274 +0.010107 +0.009998 +0.010057 +0.01016 +0.010253 +0.010319 +0.010146 +0.010064 +0.010135 +0.010231 +0.010319 +0.010374 +0.010189 +0.010101 +0.010163 +0.010264 +0.010369 +0.010417 +0.010264 +0.010168 +0.01024 +0.010268 +0.01033 +0.010327 +0.010128 +0.009994 +0.010031 +0.010109 +0.010125 +0.010137 +0.009901 +0.009752 +0.00978 +0.009807 +0.009852 +0.009858 +0.009644 +0.009519 +0.009516 +0.009544 +0.009573 +0.00957 +0.009376 +0.00923 +0.00926 +0.009302 +0.009349 +0.009375 +0.00914 +0.009018 +0.009028 +0.00906 +0.009116 +0.009113 +0.008921 +0.008811 +0.008854 +0.008866 +0.008915 +0.008946 +0.008747 +0.00864 +0.008667 +0.008711 +0.00876 +0.008771 +0.008607 +0.0085 +0.008535 +0.008577 +0.008646 +0.008663 +0.008497 +0.008397 +0.008435 +0.008497 +0.008541 +0.00856 +0.008371 +0.008287 +0.008328 +0.008396 +0.008444 +0.008485 +0.008338 +0.008254 +0.008298 +0.008374 +0.008441 +0.0085 +0.008351 +0.008286 +0.008341 +0.008397 +0.008494 +0.008538 +0.008407 +0.008322 +0.008368 +0.008443 +0.008531 +0.008583 +0.008435 +0.008372 +0.008416 +0.008512 +0.008575 +0.008633 +0.008476 +0.008416 +0.008451 +0.008523 +0.008604 +0.00867 +0.008525 +0.008452 +0.008515 +0.008569 +0.008669 +0.008722 +0.008565 +0.00848 +0.008542 +0.008614 +0.00869 +0.008756 +0.008601 +0.008527 +0.008581 +0.008664 +0.008749 +0.008805 +0.008662 +0.008586 +0.008642 +0.008707 +0.008773 +0.008829 +0.008688 +0.008616 +0.008671 +0.008733 +0.008828 +0.00891 +0.008743 +0.00867 +0.008719 +0.008785 +0.008864 +0.008925 +0.008799 +0.008705 +0.00875 +0.008819 +0.008919 +0.008988 +0.008827 +0.008758 +0.008797 +0.008867 +0.008963 +0.009027 +0.008882 +0.008812 +0.008831 +0.008912 +0.008992 +0.009062 +0.008922 +0.008831 +0.008891 +0.00897 +0.009047 +0.009112 +0.008958 +0.008887 +0.008932 +0.009021 +0.009092 +0.009162 +0.00901 +0.008938 +0.008976 +0.009043 +0.009132 +0.009205 +0.009049 +0.008968 +0.009027 +0.009123 +0.009212 +0.009259 +0.009085 +0.009003 +0.009057 +0.009137 +0.009228 +0.009291 +0.00914 +0.009076 +0.009135 +0.009201 +0.009275 +0.009338 +0.009179 +0.009104 +0.009155 +0.009229 +0.009318 +0.009397 +0.009235 +0.009159 +0.009219 +0.009304 +0.009364 +0.009433 +0.009278 +0.009205 +0.009264 +0.009317 +0.009434 +0.009457 +0.009316 +0.009244 +0.009298 +0.009394 +0.009469 +0.00953 +0.009364 +0.009293 +0.00934 +0.009433 +0.009507 +0.009578 +0.009412 +0.009333 +0.009403 +0.009471 +0.009563 +0.009639 +0.009461 +0.009376 +0.009442 +0.009539 +0.009637 +0.009671 +0.009497 +0.00942 +0.009485 +0.009565 +0.009659 +0.009726 +0.009584 +0.009483 +0.00954 +0.009607 +0.009709 +0.009772 +0.009621 +0.009521 +0.009568 +0.009656 +0.009762 +0.009831 +0.009668 +0.009592 +0.009627 +0.009712 +0.009794 +0.009873 +0.009737 +0.009613 +0.009659 +0.009755 +0.009857 +0.009945 +0.009767 +0.00967 +0.009732 +0.0098 +0.009901 +0.009975 +0.009791 +0.009707 +0.009774 +0.009876 +0.009974 +0.010032 +0.009858 +0.009753 +0.009815 +0.009912 +0.009999 +0.010073 +0.009911 +0.009842 +0.009885 +0.009968 +0.010059 +0.010109 +0.009939 +0.009854 +0.009911 +0.01003 +0.010115 +0.010161 +0.009998 +0.009917 +0.00999 +0.010071 +0.010175 +0.010208 +0.010046 +0.009963 +0.010009 +0.010107 +0.01021 +0.010273 +0.010098 +0.010029 +0.010118 +0.010187 +0.010258 +0.010298 +0.01013 +0.010062 +0.010108 +0.010212 +0.010324 +0.01038 +0.010215 +0.010128 +0.010151 +0.010231 +0.01034 +0.010379 +0.010181 +0.010066 +0.010084 +0.010144 +0.010223 +0.010254 +0.010023 +0.009866 +0.009894 +0.009921 +0.009975 +0.010012 +0.009793 +0.009611 +0.009613 +0.009676 +0.009734 +0.00972 +0.00948 +0.009365 +0.009372 +0.009408 +0.009444 +0.009465 +0.009248 +0.009117 +0.009137 +0.009176 +0.009218 +0.009232 +0.009015 +0.008901 +0.008909 +0.00896 +0.008986 +0.009013 +0.008835 +0.008721 +0.008764 +0.008806 +0.00884 +0.008856 +0.00867 +0.00857 +0.008603 +0.008638 +0.008695 +0.008737 +0.00856 +0.008452 +0.008481 +0.008545 +0.008624 +0.008623 +0.008457 +0.00835 +0.008385 +0.008434 +0.008505 +0.008542 +0.008386 +0.008294 +0.008347 +0.008398 +0.008487 +0.008547 +0.008407 +0.008331 +0.008374 +0.008431 +0.008495 +0.008568 +0.008422 +0.008368 +0.008395 +0.00847 +0.008556 +0.008632 +0.008479 +0.008405 +0.008457 +0.008515 +0.008594 +0.008657 +0.00853 +0.008429 +0.008491 +0.008551 +0.008645 +0.00872 +0.008566 +0.00849 +0.008542 +0.008596 +0.0087 +0.008737 +0.008598 +0.008545 +0.008566 +0.008642 +0.008719 +0.00878 +0.008647 +0.008577 +0.008631 +0.00871 +0.008783 +0.008826 +0.008669 +0.008606 +0.008656 +0.008726 +0.008812 +0.008883 +0.008717 +0.008667 +0.008718 +0.008789 +0.008865 +0.008928 +0.008772 +0.008695 +0.008741 +0.008816 +0.00891 +0.008985 +0.008826 +0.008733 +0.008791 +0.008873 +0.008954 +0.009027 +0.008852 +0.00877 +0.008839 +0.00893 +0.008991 +0.009046 +0.008904 +0.008813 +0.008884 +0.008973 +0.009047 +0.009107 +0.008952 +0.008866 +0.008914 +0.008996 +0.009093 +0.009138 +0.008983 +0.008904 +0.008985 +0.009089 +0.009166 +0.009185 +0.009036 +0.008959 +0.008997 +0.009093 +0.009165 +0.009237 +0.009095 +0.009018 +0.009047 +0.009157 +0.009219 +0.009281 +0.009124 +0.009051 +0.009084 +0.009181 +0.00928 +0.009334 +0.009186 +0.00911 +0.009145 +0.009225 +0.009319 +0.00939 +0.00923 +0.009166 +0.00918 +0.009268 +0.009365 +0.009421 +0.009287 +0.009185 +0.009237 +0.009326 +0.009414 +0.00947 +0.009311 +0.009232 +0.009299 +0.009367 +0.009463 +0.009507 +0.009372 +0.009288 +0.00933 +0.009418 +0.009507 +0.009568 +0.009401 +0.00931 +0.009387 +0.009483 +0.009569 +0.009617 +0.009453 +0.009363 +0.009435 +0.009532 +0.009599 +0.009659 +0.009502 +0.009406 +0.009465 +0.009561 +0.009644 +0.009728 +0.009556 +0.009482 +0.009514 +0.009607 +0.0097 +0.009758 +0.009588 +0.009517 +0.009562 +0.009651 +0.009771 +0.009844 +0.009653 +0.009551 +0.009608 +0.009696 +0.009798 +0.009862 +0.009685 +0.009617 +0.009675 +0.009753 +0.009851 +0.009902 +0.009731 +0.009653 +0.009725 +0.009796 +0.009893 +0.009971 +0.009784 +0.009701 +0.009763 +0.009864 +0.009939 +0.010008 +0.009831 +0.009785 +0.009842 +0.009894 +0.009982 +0.010056 +0.009898 +0.009793 +0.009875 +0.00995 +0.010047 +0.010103 +0.009937 +0.00986 +0.009906 +0.010004 +0.010097 +0.010163 +0.009989 +0.009916 +0.009958 +0.010048 +0.010151 +0.010213 +0.010036 +0.009957 +0.010039 +0.010102 +0.010196 +0.010257 +0.010103 +0.010026 +0.010043 +0.010145 +0.010254 +0.010308 +0.010134 +0.01005 +0.01013 +0.010195 +0.010318 +0.010389 +0.010179 +0.010099 +0.010139 +0.01022 +0.010342 +0.010364 +0.010148 +0.010036 +0.010046 +0.010107 +0.010171 +0.010194 +0.009919 +0.009786 +0.009801 +0.009816 +0.009866 +0.009857 +0.009642 +0.009525 +0.009513 +0.009543 +0.009582 +0.009587 +0.009353 +0.009221 +0.009235 +0.009266 +0.009298 +0.009322 +0.009117 +0.008994 +0.009007 +0.009035 +0.009061 +0.009072 +0.008887 +0.008774 +0.008796 +0.008803 +0.008863 +0.008867 +0.008694 +0.008596 +0.008592 +0.008634 +0.00869 +0.008716 +0.008541 +0.00844 +0.008467 +0.008511 +0.008577 +0.008597 +0.00843 +0.008322 +0.00835 +0.008399 +0.008461 +0.008493 +0.008319 +0.008225 +0.008254 +0.0083 +0.008368 +0.008419 +0.008251 +0.008174 +0.008182 +0.008243 +0.008321 +0.008363 +0.008221 +0.008152 +0.008186 +0.00829 +0.008341 +0.008396 +0.008274 +0.008198 +0.00825 +0.008309 +0.008378 +0.008437 +0.008306 +0.008231 +0.008281 +0.008351 +0.008429 +0.008485 +0.008344 +0.008284 +0.008336 +0.008407 +0.008468 +0.008526 +0.008384 +0.008336 +0.00839 +0.008431 +0.008508 +0.008557 +0.00842 +0.008357 +0.008414 +0.008483 +0.00857 +0.00864 +0.008452 +0.00839 +0.008452 +0.008513 +0.008591 +0.008657 +0.008512 +0.008436 +0.008494 +0.008579 +0.008654 +0.008704 +0.008546 +0.008486 +0.008525 +0.008607 +0.008684 +0.008749 +0.00862 +0.00854 +0.008589 +0.008643 +0.008732 +0.008791 +0.008649 +0.008557 +0.008611 +0.008689 +0.008772 +0.008822 +0.008688 +0.008611 +0.008664 +0.008745 +0.008828 +0.008889 +0.008732 +0.00865 +0.008704 +0.008769 +0.008864 +0.00892 +0.008775 +0.008692 +0.008739 +0.008846 +0.008921 +0.009004 +0.008822 +0.00874 +0.008797 +0.008867 +0.008939 +0.008996 +0.008851 +0.008782 +0.008848 +0.008899 +0.00899 +0.009056 +0.008901 +0.008828 +0.008876 +0.008957 +0.009041 +0.009104 +0.008955 +0.008871 +0.008934 +0.008992 +0.009094 +0.009144 +0.00899 +0.008913 +0.008973 +0.00908 +0.009134 +0.009191 +0.009036 +0.008946 +0.009032 +0.009117 +0.009163 +0.009232 +0.00908 +0.008998 +0.009062 +0.00914 +0.009224 +0.009288 +0.009133 +0.009055 +0.009111 +0.009178 +0.009275 +0.009321 +0.009176 +0.009102 +0.009156 +0.009227 +0.009322 +0.009389 +0.009251 +0.00915 +0.009198 +0.009286 +0.009347 +0.009421 +0.009262 +0.009182 +0.00927 +0.009324 +0.009407 +0.009468 +0.009315 +0.009232 +0.009289 +0.00938 +0.009448 +0.009522 +0.009361 +0.009286 +0.009334 +0.009405 +0.009521 +0.009564 +0.009409 +0.009342 +0.009401 +0.009507 +0.00955 +0.009602 +0.009441 +0.00936 +0.009429 +0.009501 +0.009597 +0.009673 +0.009506 +0.009436 +0.009487 +0.009552 +0.009649 +0.00971 +0.009547 +0.009461 +0.009514 +0.009617 +0.009702 +0.009765 +0.009619 +0.009522 +0.009561 +0.00965 +0.009755 +0.00984 +0.009636 +0.009551 +0.009627 +0.009697 +0.009822 +0.009864 +0.009695 +0.009621 +0.009651 +0.009743 +0.009843 +0.009909 +0.009735 +0.009652 +0.009714 +0.009822 +0.009908 +0.009975 +0.009788 +0.009695 +0.00977 +0.009834 +0.009944 +0.010023 +0.00985 +0.009774 +0.009817 +0.009918 +0.009998 +0.010089 +0.009865 +0.00978 +0.009852 +0.009943 +0.010042 +0.010114 +0.009953 +0.009838 +0.009909 +0.010005 +0.010085 +0.01016 +0.00999 +0.009905 +0.009962 +0.010056 +0.010157 +0.010218 +0.010022 +0.009938 +0.010012 +0.010046 +0.010119 +0.010134 +0.009932 +0.009802 +0.009871 +0.009909 +0.009954 +0.009948 +0.00973 +0.009598 +0.009625 +0.009663 +0.009695 +0.009714 +0.009488 +0.009352 +0.009379 +0.009439 +0.009447 +0.009446 +0.009243 +0.009117 +0.009136 +0.009179 +0.009211 +0.009246 +0.009034 +0.008892 +0.008917 +0.008961 +0.008995 +0.009014 +0.008819 +0.00873 +0.008738 +0.008776 +0.00882 +0.008845 +0.008669 +0.008557 +0.008591 +0.008659 +0.008696 +0.008708 +0.008533 +0.008443 +0.008467 +0.008524 +0.008575 +0.008605 +0.008434 +0.008328 +0.008384 +0.008437 +0.008515 +0.008508 +0.008333 +0.008247 +0.008299 +0.008361 +0.008434 +0.008467 +0.008317 +0.008248 +0.008308 +0.008406 +0.008458 +0.008515 +0.008364 +0.008284 +0.008332 +0.008412 +0.008485 +0.008545 +0.008408 +0.008327 +0.008383 +0.008461 +0.008551 +0.008609 +0.008454 +0.008367 +0.008427 +0.0085 +0.008603 +0.008641 +0.008497 +0.008423 +0.008449 +0.008531 +0.008609 +0.008679 +0.008532 +0.008466 +0.008509 +0.008579 +0.00867 +0.00873 +0.008559 +0.008503 +0.008559 +0.008624 +0.008709 +0.008774 +0.008623 +0.008542 +0.008597 +0.008668 +0.008756 +0.008816 +0.008653 +0.008596 +0.008642 +0.00874 +0.008806 +0.008846 +0.008712 +0.008647 +0.008676 +0.008745 +0.008827 +0.008892 +0.008752 +0.00866 +0.008722 +0.008799 +0.008885 +0.008952 +0.008796 +0.008728 +0.008764 +0.008838 +0.00893 +0.008988 +0.008836 +0.008757 +0.008823 +0.008894 +0.008975 +0.009033 +0.008882 +0.008832 +0.008858 +0.008927 +0.009005 +0.009065 +0.008924 +0.008852 +0.008922 +0.008975 +0.00907 +0.009118 +0.008969 +0.008898 +0.008937 +0.009013 +0.009104 +0.00918 +0.009012 +0.008934 +0.008991 +0.009076 +0.009154 +0.009225 +0.009061 +0.008989 +0.009022 +0.009113 +0.009204 +0.009292 +0.009102 +0.009022 +0.009069 +0.009164 +0.009255 +0.009313 +0.009162 +0.009087 +0.00912 +0.0092 +0.009282 +0.009355 +0.009188 +0.009109 +0.00918 +0.009246 +0.009346 +0.009414 +0.00926 +0.009163 +0.009207 +0.0093 +0.009385 +0.009443 +0.009292 +0.009206 +0.009294 +0.00938 +0.009437 +0.009491 +0.009331 +0.009256 +0.009295 +0.00938 +0.009479 +0.009538 +0.009376 +0.009312 +0.009376 +0.009436 +0.009522 +0.009598 +0.009419 +0.009345 +0.009406 +0.009479 +0.009588 +0.009642 +0.00948 +0.009414 +0.009442 +0.00954 +0.009645 +0.009711 +0.009521 +0.009442 +0.009493 +0.009571 +0.009669 +0.009736 +0.009573 +0.009504 +0.009534 +0.009621 +0.009731 +0.009784 +0.009618 +0.009539 +0.009599 +0.009678 +0.009777 +0.009844 +0.009686 +0.009577 +0.00965 +0.009724 +0.009816 +0.00988 +0.009734 +0.009651 +0.009691 +0.009766 +0.009867 +0.009973 +0.00976 +0.009669 +0.009732 +0.009817 +0.009916 +0.009985 +0.00981 +0.009732 +0.009795 +0.00988 +0.009988 +0.010032 +0.009868 +0.009778 +0.009829 +0.009932 +0.010025 +0.010082 +0.009916 +0.009834 +0.009922 +0.009986 +0.010073 +0.010113 +0.009955 +0.009876 +0.009934 +0.010046 +0.010114 +0.010182 +0.010016 +0.009943 +0.009987 +0.010063 +0.010179 +0.010232 +0.01006 +0.00999 +0.010027 +0.010116 +0.010239 +0.010313 +0.010125 +0.010041 +0.010097 +0.010203 +0.010258 +0.01032 +0.010153 +0.010073 +0.010141 +0.010217 +0.010316 +0.01041 +0.01017 +0.010049 +0.010081 +0.010132 +0.010192 +0.010206 +0.009997 +0.009872 +0.009887 +0.009936 +0.00998 +0.009964 +0.009745 +0.009597 +0.009612 +0.009639 +0.009684 +0.00974 +0.00947 +0.009338 +0.009357 +0.00939 +0.009435 +0.009428 +0.009213 +0.009094 +0.009107 +0.009147 +0.009171 +0.009196 +0.008987 +0.008877 +0.008905 +0.008934 +0.008978 +0.008989 +0.008798 +0.008694 +0.008704 +0.008743 +0.008793 +0.008823 +0.008646 +0.008558 +0.008593 +0.008656 +0.008681 +0.008713 +0.008533 +0.008427 +0.00846 +0.008503 +0.008562 +0.008601 +0.008444 +0.008338 +0.008377 +0.008433 +0.008504 +0.008533 +0.008377 +0.008294 +0.008321 +0.008376 +0.008447 +0.008519 +0.008371 +0.0083 +0.008338 +0.008422 +0.008497 +0.008559 +0.008416 +0.008347 +0.008414 +0.008464 +0.008528 +0.008581 +0.008445 +0.00839 +0.008433 +0.008486 +0.008571 +0.008632 +0.008494 +0.008413 +0.008471 +0.008546 +0.008621 +0.008683 +0.008536 +0.008476 +0.008529 +0.008602 +0.008653 +0.008721 +0.008577 +0.008501 +0.008559 +0.00862 +0.00871 +0.008769 +0.008624 +0.008564 +0.008614 +0.008673 +0.008759 +0.008795 +0.008653 +0.008596 +0.008642 +0.00872 +0.008782 +0.00885 +0.008702 +0.008631 +0.00871 +0.008768 +0.008848 +0.00891 +0.008767 +0.008668 +0.008724 +0.008802 +0.008886 +0.008946 +0.008791 +0.00872 +0.008776 +0.008853 +0.008941 +0.009001 +0.008872 +0.008759 +0.008805 +0.008877 +0.008973 +0.009036 +0.008882 +0.008798 +0.008862 +0.008973 +0.00904 +0.009079 +0.008931 +0.008853 +0.008894 +0.008976 +0.009074 +0.009115 +0.008968 +0.008895 +0.008939 +0.009038 +0.009125 +0.009187 +0.009024 +0.008939 +0.00899 +0.009077 +0.009191 +0.009225 +0.009052 +0.008966 +0.009023 +0.009135 +0.00921 +0.009261 +0.009118 +0.009038 +0.009071 +0.009161 +0.009253 +0.009312 +0.009146 +0.009076 +0.009126 +0.009221 +0.009309 +0.009371 +0.0092 +0.009123 +0.009171 +0.009251 +0.009343 +0.009407 +0.009252 +0.009189 +0.00923 +0.009308 +0.009394 +0.009471 +0.00929 +0.009197 +0.009257 +0.009342 +0.009443 +0.009495 +0.009339 +0.009258 +0.009318 +0.009411 +0.009499 +0.009564 +0.009383 +0.009289 +0.009361 +0.009438 +0.009535 +0.009602 +0.009433 +0.009345 +0.009425 +0.009515 +0.009622 +0.009634 +0.009467 +0.009379 +0.009449 +0.009569 +0.009623 +0.009688 +0.009538 +0.009438 +0.009487 +0.009585 +0.009678 +0.009743 +0.009574 +0.009499 +0.009548 +0.009638 +0.009736 +0.009814 +0.009633 +0.009544 +0.009581 +0.009682 +0.009785 +0.009859 +0.0097 +0.009573 +0.009636 +0.009723 +0.009834 +0.009909 +0.009719 +0.009648 +0.009699 +0.009773 +0.009876 +0.009946 +0.009762 +0.009685 +0.009743 +0.009843 +0.009938 +0.009997 +0.0098 +0.009733 +0.009793 +0.009892 +0.009983 +0.010031 +0.009874 +0.00982 +0.00986 +0.009937 +0.010024 +0.010067 +0.009918 +0.009826 +0.009889 +0.009982 +0.010064 +0.010144 +0.009972 +0.009893 +0.009964 +0.010043 +0.010127 +0.01019 +0.010012 +0.009937 +0.009993 +0.010068 +0.010188 +0.010242 +0.010077 +0.010007 +0.010084 +0.01014 +0.010223 +0.010288 +0.010112 +0.010008 +0.010084 +0.010188 +0.010283 +0.010359 +0.010191 +0.010078 +0.010137 +0.010235 +0.010336 +0.010395 +0.010218 +0.010126 +0.0102 +0.010288 +0.01042 +0.010454 +0.010239 +0.01015 +0.010212 +0.010287 +0.010356 +0.010404 +0.010148 +0.010028 +0.010035 +0.010111 +0.010145 +0.01013 +0.009907 +0.009784 +0.009796 +0.009832 +0.009871 +0.00986 +0.009651 +0.009518 +0.009525 +0.00956 +0.009571 +0.00958 +0.009366 +0.00925 +0.009254 +0.009294 +0.00934 +0.009339 +0.009139 +0.009016 +0.009039 +0.009088 +0.009111 +0.009113 +0.008884 +0.008786 +0.008813 +0.008863 +0.008897 +0.008919 +0.008749 +0.008639 +0.008666 +0.008721 +0.00875 +0.008765 +0.008591 +0.008497 +0.008534 +0.008578 +0.008624 +0.008663 +0.008485 +0.008397 +0.008441 +0.008491 +0.008532 +0.008547 +0.008395 +0.008311 +0.008378 +0.00843 +0.008482 +0.008528 +0.008377 +0.00831 +0.008366 +0.008437 +0.008503 +0.008577 +0.008428 +0.008349 +0.008401 +0.008473 +0.008557 +0.008635 +0.008465 +0.008397 +0.00844 +0.008517 +0.008599 +0.008666 +0.008504 +0.008435 +0.008496 +0.008558 +0.008644 +0.008701 +0.008572 +0.008491 +0.008552 +0.008597 +0.008679 +0.008754 +0.008588 +0.008517 +0.008574 +0.008641 +0.00873 +0.008801 +0.008647 +0.008563 +0.008607 +0.008684 +0.00877 +0.008827 +0.008697 +0.00862 +0.008645 +0.00873 +0.008812 +0.008883 +0.008739 +0.008668 +0.008698 +0.008771 +0.008854 +0.008925 +0.008787 +0.008706 +0.008738 +0.008802 +0.008899 +0.008967 +0.008833 +0.008739 +0.008789 +0.00888 +0.008936 +0.008994 +0.008846 +0.008791 +0.008824 +0.008904 +0.009003 +0.009057 +0.00892 +0.00884 +0.008894 +0.008945 +0.009036 +0.00911 +0.008939 +0.008866 +0.008918 +0.008995 +0.009108 +0.009179 +0.008992 +0.008919 +0.008972 +0.009035 +0.009134 +0.009184 +0.009027 +0.008957 +0.009002 +0.009089 +0.009174 +0.009247 +0.009098 +0.009017 +0.009075 +0.009127 +0.00922 +0.009277 +0.009124 +0.00904 +0.009101 +0.009185 +0.009263 +0.009334 +0.009196 +0.009114 +0.009193 +0.009207 +0.009311 +0.009381 +0.009204 +0.009135 +0.009181 +0.009265 +0.009366 +0.009428 +0.009275 +0.009202 +0.009263 +0.009308 +0.009403 +0.009476 +0.009311 +0.009221 +0.009282 +0.00936 +0.00946 +0.009539 +0.009377 +0.009287 +0.00933 +0.009419 +0.009511 +0.009593 +0.009391 +0.009309 +0.009368 +0.009467 +0.009574 +0.009617 +0.009454 +0.009389 +0.009413 +0.009504 +0.009605 +0.00966 +0.009498 +0.009417 +0.00947 +0.00955 +0.009653 +0.009739 +0.009559 +0.009466 +0.00953 +0.009595 +0.009703 +0.00976 +0.009598 +0.009536 +0.009563 +0.009649 +0.009754 +0.009823 +0.009651 +0.00955 +0.009629 +0.009698 +0.009784 +0.009847 +0.009688 +0.009595 +0.009657 +0.009771 +0.009872 +0.009926 +0.009746 +0.009662 +0.009692 +0.0098 +0.0099 +0.009956 +0.009778 +0.009703 +0.009793 +0.009895 +0.009948 +0.009999 +0.009838 +0.00973 +0.009808 +0.009889 +0.009986 +0.010081 +0.009869 +0.009807 +0.009882 +0.009956 +0.010052 +0.01012 +0.009914 +0.009841 +0.00991 +0.00999 +0.010093 +0.010165 +0.009988 +0.009914 +0.009972 +0.010073 +0.010193 +0.010202 +0.010007 +0.009931 +0.010002 +0.010093 +0.010188 +0.010276 +0.010103 +0.010008 +0.010072 +0.010148 +0.010233 +0.010306 +0.010139 +0.010042 +0.010106 +0.0102 +0.010316 +0.010388 +0.010205 +0.010102 +0.010149 +0.010259 +0.010374 +0.010405 +0.0102 +0.010112 +0.010185 +0.010246 +0.0103 +0.010306 +0.010086 +0.009967 +0.010009 +0.010031 +0.010081 +0.010096 +0.009899 +0.009758 +0.009787 +0.009792 +0.009833 +0.009851 +0.009628 +0.0095 +0.009526 +0.009551 +0.009601 +0.009599 +0.009382 +0.009287 +0.009269 +0.009288 +0.009323 +0.009331 +0.009133 +0.009 +0.009015 +0.009069 +0.009115 +0.009109 +0.008911 +0.008806 +0.008817 +0.008851 +0.008893 +0.008915 +0.008721 +0.008624 +0.008672 +0.008704 +0.008738 +0.008754 +0.008589 +0.008481 +0.008523 +0.008563 +0.008608 +0.008651 +0.008477 +0.008369 +0.008403 +0.008467 +0.0085 +0.008541 +0.008387 +0.008294 +0.008332 +0.008397 +0.008448 +0.008494 +0.008355 +0.008281 +0.008335 +0.008408 +0.008496 +0.00854 +0.008393 +0.008315 +0.008372 +0.008446 +0.008517 +0.008577 +0.008436 +0.008361 +0.008415 +0.00849 +0.008578 +0.008662 +0.008469 +0.008398 +0.008442 +0.008525 +0.008606 +0.008668 +0.008514 +0.008444 +0.008516 +0.008578 +0.008667 +0.008703 +0.008565 +0.008489 +0.008534 +0.008614 +0.008683 +0.008748 +0.008603 +0.008535 +0.008581 +0.008656 +0.008729 +0.008803 +0.008657 +0.008581 +0.008637 +0.008716 +0.008802 +0.00886 +0.008674 +0.008605 +0.008654 +0.008737 +0.008819 +0.008869 +0.008736 +0.008677 +0.008712 +0.00879 +0.008874 +0.008918 +0.008773 +0.008698 +0.008755 +0.008824 +0.00891 +0.008965 +0.008829 +0.008761 +0.008804 +0.008885 +0.008958 +0.009004 +0.008859 +0.008797 +0.008858 +0.008934 +0.008994 +0.009058 +0.008921 +0.008819 +0.008883 +0.008953 +0.009041 +0.009114 +0.008945 +0.008873 +0.00893 +0.009004 +0.009098 +0.009158 +0.009009 +0.00893 +0.008968 +0.009048 +0.009149 +0.009202 +0.009037 +0.008967 +0.009011 +0.009098 +0.009187 +0.009253 +0.009121 +0.009015 +0.009064 +0.009135 +0.00923 +0.0093 +0.009142 +0.009045 +0.009102 +0.009191 +0.009273 +0.00934 +0.009192 +0.009097 +0.009157 +0.009247 +0.009329 +0.009387 +0.009221 +0.009153 +0.009204 +0.009276 +0.009377 +0.009435 +0.009272 +0.009198 +0.009254 +0.009365 +0.009431 +0.009476 +0.009301 +0.009233 +0.009291 +0.009374 +0.009483 +0.00956 +0.009356 +0.009278 +0.009341 +0.009434 +0.009508 +0.009561 +0.009409 +0.009332 +0.009401 +0.009485 +0.009575 +0.009641 +0.009447 +0.009385 +0.009438 +0.009517 +0.009618 +0.009679 +0.009538 +0.009424 +0.009479 +0.009573 +0.009657 +0.009729 +0.009534 +0.009465 +0.009535 +0.009621 +0.009702 +0.009764 +0.009606 +0.009537 +0.00959 +0.009674 +0.009765 +0.009803 +0.009647 +0.009568 +0.009616 +0.009717 +0.009795 +0.009873 +0.009724 +0.009643 +0.009719 +0.009761 +0.009864 +0.00988 +0.009735 +0.009657 +0.00971 +0.009805 +0.009897 +0.009983 +0.009809 +0.009731 +0.009776 +0.00985 +0.009958 +0.010006 +0.009842 +0.009766 +0.00982 +0.0099 +0.010027 +0.010078 +0.009903 +0.009815 +0.009885 +0.009986 +0.010047 +0.010103 +0.009935 +0.009884 +0.009908 +0.009993 +0.010098 +0.010173 +0.009987 +0.009904 +0.009981 +0.010054 +0.010165 +0.01023 +0.010048 +0.009952 +0.01002 +0.010116 +0.010212 +0.01028 +0.010087 +0.010013 +0.01007 +0.010169 +0.010302 +0.010327 +0.010128 +0.010049 +0.010118 +0.010216 +0.01034 +0.010358 +0.010194 +0.010104 +0.010166 +0.010265 +0.010364 +0.010429 +0.010241 +0.010131 +0.010204 +0.010295 +0.010369 +0.010397 +0.010182 +0.010045 +0.010064 +0.010128 +0.010174 +0.010196 +0.009943 +0.009784 +0.009815 +0.009842 +0.009887 +0.009888 +0.009673 +0.009545 +0.009533 +0.009573 +0.00959 +0.009596 +0.009376 +0.009243 +0.009257 +0.009284 +0.009322 +0.009344 +0.009112 +0.008991 +0.009011 +0.009042 +0.009059 +0.009068 +0.008877 +0.00876 +0.008803 +0.008811 +0.00885 +0.008877 +0.008705 +0.008601 +0.008615 +0.008668 +0.008704 +0.008737 +0.008571 +0.008448 +0.008484 +0.008532 +0.008582 +0.008609 +0.008454 +0.008349 +0.00838 +0.008433 +0.008502 +0.0085 +0.008335 +0.008247 +0.008285 +0.008344 +0.008412 +0.008456 +0.008302 +0.008247 +0.008281 +0.008349 +0.008431 +0.008467 +0.008317 +0.00826 +0.008297 +0.008372 +0.008449 +0.008508 +0.008364 +0.008297 +0.008365 +0.008435 +0.008507 +0.008563 +0.008415 +0.008333 +0.008385 +0.008458 +0.008549 +0.008593 +0.008457 +0.008386 +0.008437 +0.008523 +0.00859 +0.008651 +0.008506 +0.008453 +0.008461 +0.008536 +0.008614 +0.008682 +0.008563 +0.008456 +0.008507 +0.008586 +0.00868 +0.00873 +0.008591 +0.008517 +0.008566 +0.008621 +0.008711 +0.008775 +0.008621 +0.008538 +0.008599 +0.008684 +0.008754 +0.008834 +0.008685 +0.008606 +0.008657 +0.008708 +0.008801 +0.008868 +0.008732 +0.00863 +0.008682 +0.008751 +0.008839 +0.008917 +0.008768 +0.008706 +0.008733 +0.008814 +0.008873 +0.008939 +0.008801 +0.008714 +0.008777 +0.008849 +0.008933 +0.009 +0.008856 +0.008791 +0.008834 +0.008904 +0.008969 +0.009035 +0.008887 +0.0088 +0.008864 +0.008944 +0.009045 +0.009083 +0.008937 +0.008857 +0.008914 +0.008997 +0.009064 +0.009124 +0.008973 +0.008926 +0.008938 +0.00902 +0.009112 +0.009173 +0.009028 +0.008953 +0.009014 +0.009077 +0.009157 +0.00923 +0.009067 +0.008988 +0.009039 +0.009123 +0.009206 +0.009265 +0.009125 +0.009055 +0.009123 +0.009199 +0.009245 +0.009292 +0.009149 +0.009081 +0.009124 +0.009203 +0.009298 +0.009358 +0.009209 +0.009139 +0.009189 +0.009265 +0.009345 +0.009413 +0.009246 +0.009175 +0.00923 +0.009309 +0.009384 +0.009456 +0.009312 +0.009225 +0.009278 +0.009371 +0.009458 +0.009522 +0.009329 +0.009252 +0.009313 +0.009392 +0.00948 +0.009545 +0.009403 +0.009322 +0.009372 +0.009444 +0.009537 +0.009607 +0.009438 +0.009352 +0.009405 +0.009481 +0.009584 +0.009666 +0.009486 +0.009413 +0.009478 +0.009533 +0.009628 +0.009698 +0.00953 +0.009482 +0.009493 +0.009579 +0.009687 +0.009739 +0.009606 +0.009494 +0.009538 +0.009644 +0.009724 +0.009795 +0.00963 +0.009556 +0.009601 +0.009682 +0.009789 +0.009844 +0.009675 +0.009612 +0.009642 +0.009734 +0.009832 +0.009891 +0.009739 +0.00965 +0.009701 +0.009817 +0.009869 +0.009933 +0.009762 +0.00968 +0.009755 +0.009841 +0.009964 +0.009997 +0.009818 +0.009728 +0.009798 +0.009877 +0.009974 +0.010049 +0.009856 +0.009787 +0.009867 +0.009944 +0.010043 +0.010106 +0.00991 +0.00983 +0.00989 +0.009989 +0.010135 +0.010125 +0.00996 +0.00988 +0.009943 +0.010052 +0.010133 +0.010187 +0.010026 +0.009958 +0.009979 +0.010091 +0.010169 +0.010249 +0.01008 +0.009979 +0.010062 +0.010149 +0.010244 +0.01029 +0.010123 +0.010027 +0.010092 +0.010185 +0.010301 +0.01039 +0.01016 +0.010121 +0.010122 +0.010226 +0.010328 +0.010399 +0.010222 +0.010112 +0.010177 +0.010266 +0.010358 +0.010394 +0.010181 +0.010032 +0.01006 +0.010103 +0.010178 +0.010168 +0.009936 +0.009811 +0.009829 +0.009853 +0.009915 +0.009927 +0.009685 +0.009522 +0.009536 +0.009577 +0.009661 +0.00961 +0.009397 +0.009269 +0.009291 +0.009315 +0.009375 +0.009372 +0.00915 +0.009022 +0.009041 +0.009084 +0.009128 +0.009123 +0.008942 +0.008812 +0.008821 +0.008869 +0.008929 +0.008935 +0.00874 +0.008634 +0.008665 +0.008727 +0.008744 +0.008771 +0.008583 +0.008487 +0.008518 +0.008566 +0.008641 +0.008649 +0.008465 +0.008355 +0.008388 +0.008441 +0.008499 +0.008523 +0.008352 +0.008256 +0.008294 +0.008352 +0.00841 +0.00846 +0.008313 +0.0082 +0.008249 +0.008322 +0.00839 +0.008452 +0.008307 +0.008245 +0.0083 +0.008364 +0.008425 +0.008482 +0.008351 +0.00829 +0.008328 +0.008392 +0.008473 +0.008533 +0.008414 +0.008311 +0.008359 +0.008435 +0.008517 +0.008574 +0.008435 +0.008368 +0.008428 +0.008476 +0.008557 +0.008628 +0.008487 +0.008402 +0.008448 +0.008517 +0.008599 +0.008658 +0.008522 +0.008446 +0.008525 +0.008596 +0.008649 +0.008684 +0.008547 +0.008484 +0.008532 +0.008601 +0.008681 +0.008753 +0.0086 +0.008534 +0.008595 +0.008669 +0.008735 +0.008784 +0.008645 +0.00857 +0.00862 +0.008689 +0.008786 +0.008835 +0.008676 +0.008605 +0.00868 +0.008742 +0.008832 +0.008884 +0.008737 +0.008679 +0.008703 +0.008771 +0.00887 +0.008924 +0.008773 +0.008691 +0.008755 +0.008835 +0.008927 +0.008972 +0.008808 +0.008746 +0.008784 +0.008865 +0.008952 +0.009023 +0.008854 +0.00878 +0.008843 +0.008944 +0.009013 +0.009069 +0.008904 +0.008827 +0.008875 +0.008958 +0.009047 +0.009134 +0.008938 +0.008869 +0.008926 +0.009013 +0.009107 +0.009176 +0.008975 +0.008911 +0.00897 +0.00904 +0.009136 +0.009193 +0.009032 +0.008964 +0.009025 +0.009118 +0.009201 +0.009251 +0.009088 +0.008995 +0.009053 +0.009127 +0.009229 +0.00929 +0.009128 +0.009065 +0.009133 +0.009223 +0.009283 +0.009331 +0.009162 +0.009088 +0.009146 +0.009229 +0.009335 +0.009387 +0.00921 +0.009139 +0.009206 +0.009296 +0.009383 +0.009446 +0.00926 +0.009189 +0.009236 +0.009324 +0.009408 +0.009474 +0.009315 +0.009237 +0.009298 +0.00939 +0.009486 +0.009558 +0.009366 +0.009269 +0.009321 +0.009412 +0.009505 +0.009569 +0.009404 +0.009328 +0.009404 +0.00951 +0.00956 +0.009616 +0.009439 +0.009373 +0.009435 +0.009515 +0.009609 +0.009662 +0.00952 +0.009422 +0.009483 +0.009585 +0.00965 +0.009707 +0.009554 +0.009479 +0.009558 +0.009603 +0.009724 +0.009746 +0.009591 +0.009531 +0.009579 +0.009667 +0.009768 +0.009794 +0.009638 +0.009568 +0.009627 +0.009711 +0.009798 +0.009865 +0.009695 +0.00961 +0.009682 +0.009748 +0.009846 +0.009928 +0.009742 +0.009664 +0.009734 +0.009846 +0.009916 +0.009951 +0.009778 +0.009702 +0.009789 +0.00984 +0.009939 +0.010016 +0.00984 +0.009759 +0.009842 +0.009903 +0.010005 +0.010065 +0.009893 +0.009811 +0.009847 +0.009966 +0.010046 +0.010115 +0.009955 +0.009866 +0.00991 +0.010011 +0.010107 +0.010202 +0.009977 +0.009888 +0.009949 +0.010055 +0.010157 +0.010251 +0.01005 +0.009942 +0.010007 +0.010097 +0.010208 +0.010269 +0.010079 +0.010015 +0.010073 +0.010149 +0.010276 +0.010334 +0.010119 +0.010036 +0.010087 +0.010167 +0.010265 +0.0103 +0.010072 +0.009904 +0.00995 +0.010013 +0.010052 +0.010051 +0.009824 +0.009671 +0.009729 +0.00972 +0.009761 +0.009786 +0.009546 +0.009413 +0.009435 +0.009485 +0.009493 +0.009503 +0.009295 +0.009162 +0.009172 +0.009215 +0.009249 +0.009251 +0.009053 +0.008935 +0.008977 +0.009026 +0.009015 +0.009024 +0.008835 +0.00872 +0.008754 +0.00879 +0.008836 +0.008866 +0.008671 +0.008562 +0.008603 +0.008656 +0.008693 +0.008708 +0.008531 +0.00843 +0.008458 +0.008512 +0.008571 +0.008586 +0.008415 +0.008309 +0.008352 +0.008409 +0.008463 +0.008475 +0.008313 +0.008233 +0.008277 +0.008316 +0.008395 +0.008416 +0.00826 +0.008192 +0.008229 +0.008311 +0.008392 +0.008457 +0.008295 +0.008233 +0.008273 +0.008355 +0.008423 +0.008479 +0.008345 +0.008267 +0.008322 +0.00839 +0.008481 +0.00853 +0.008394 +0.008308 +0.008366 +0.008419 +0.008498 +0.008569 +0.008434 +0.008374 +0.008422 +0.008472 +0.008556 +0.008622 +0.008472 +0.008429 +0.008432 +0.008507 +0.008587 +0.008652 +0.008503 +0.008438 +0.008486 +0.008561 +0.008641 +0.008702 +0.008558 +0.008482 +0.008537 +0.008602 +0.008683 +0.008736 +0.008591 +0.00853 +0.008568 +0.008644 +0.008733 +0.008794 +0.008662 +0.008583 +0.008619 +0.008696 +0.008759 +0.008823 +0.00868 +0.008597 +0.008656 +0.008727 +0.008817 +0.008881 +0.008723 +0.008673 +0.008714 +0.008781 +0.00885 +0.008909 +0.008789 +0.008688 +0.008748 +0.008819 +0.008894 +0.008969 +0.008818 +0.008742 +0.008787 +0.008872 +0.008966 +0.009026 +0.008849 +0.008774 +0.008825 +0.008906 +0.008996 +0.009061 +0.008916 +0.008834 +0.008888 +0.008956 +0.009037 +0.009087 +0.008941 +0.008862 +0.008918 +0.009006 +0.009081 +0.009146 +0.009034 +0.008931 +0.008968 +0.009043 +0.009137 +0.009168 +0.009023 +0.008957 +0.009013 +0.00912 +0.009188 +0.009226 +0.009083 +0.009012 +0.009068 +0.009133 +0.009221 +0.009266 +0.009127 +0.009037 +0.009101 +0.00918 +0.00927 +0.009326 +0.009187 +0.009103 +0.009153 +0.009239 +0.009326 +0.009352 +0.009213 +0.009136 +0.009188 +0.009267 +0.009362 +0.009432 +0.009316 +0.009197 +0.009243 +0.009318 +0.009423 +0.009457 +0.009291 +0.009219 +0.009282 +0.009371 +0.009448 +0.009526 +0.009376 +0.009301 +0.009334 +0.009426 +0.009492 +0.009555 +0.009405 +0.009315 +0.009375 +0.009465 +0.009557 +0.009613 +0.009448 +0.009375 +0.009439 +0.009536 +0.00959 +0.00966 +0.009496 +0.009417 +0.009478 +0.009555 +0.009647 +0.009725 +0.009547 +0.009461 +0.009528 +0.009594 +0.009699 +0.009773 +0.009624 +0.009507 +0.00957 +0.009647 +0.009742 +0.009808 +0.009648 +0.009562 +0.009609 +0.009707 +0.009804 +0.009893 +0.009687 +0.0096 +0.009657 +0.009748 +0.009852 +0.009909 +0.009737 +0.009663 +0.009712 +0.009796 +0.009907 +0.009954 +0.009791 +0.009716 +0.009758 +0.009867 +0.009962 +0.010012 +0.009826 +0.009744 +0.009811 +0.009893 +0.010001 +0.010069 +0.009933 +0.009806 +0.009843 +0.009938 +0.010042 +0.010113 +0.009925 +0.009857 +0.009917 +0.010006 +0.010095 +0.01017 +0.009974 +0.009896 +0.009965 +0.010044 +0.010145 +0.010227 +0.010035 +0.009948 +0.01001 +0.010103 +0.010198 +0.010262 +0.01009 +0.010025 +0.01006 +0.010158 +0.010243 +0.010307 +0.010134 +0.010049 +0.01011 +0.010168 +0.010258 +0.010288 +0.010092 +0.009949 +0.009976 +0.010022 +0.010102 +0.010088 +0.009883 +0.009747 +0.009765 +0.009799 +0.009839 +0.009848 +0.00962 +0.009492 +0.009502 +0.009582 +0.00957 +0.009574 +0.00936 +0.009229 +0.009252 +0.009279 +0.009317 +0.009337 +0.009128 +0.008998 +0.009005 +0.00907 +0.009099 +0.00912 +0.008915 +0.008785 +0.008812 +0.008851 +0.008897 +0.008914 +0.008728 +0.008622 +0.008639 +0.008693 +0.008737 +0.008772 +0.008594 +0.008495 +0.008504 +0.008552 +0.008605 +0.008636 +0.008469 +0.008363 +0.008392 +0.008442 +0.008514 +0.008533 +0.008361 +0.008267 +0.008306 +0.008356 +0.008428 +0.00847 +0.008332 +0.008229 +0.00827 +0.008352 +0.008416 +0.008489 +0.008337 +0.008275 +0.008308 +0.008381 +0.008464 +0.008523 +0.008397 +0.008317 +0.008355 +0.008427 +0.008503 +0.008563 +0.008434 +0.008343 +0.008393 +0.008472 +0.008549 +0.008608 +0.008465 +0.008387 +0.008436 +0.008514 +0.008588 +0.008662 +0.008516 +0.008455 +0.008509 +0.008543 +0.008621 +0.008683 +0.008547 +0.008472 +0.008514 +0.008594 +0.008686 +0.008749 +0.008618 +0.008514 +0.008571 +0.008625 +0.008715 +0.008787 +0.008633 +0.008559 +0.008605 +0.008678 +0.008761 +0.008826 +0.008681 +0.0086 +0.008658 +0.008721 +0.008813 +0.008871 +0.008725 +0.008647 +0.008696 +0.008762 +0.008852 +0.008919 +0.008758 +0.00869 +0.008742 +0.00883 +0.008921 +0.008969 +0.0088 +0.008723 +0.008777 +0.008857 +0.008941 +0.009005 +0.008847 +0.008775 +0.008828 +0.00891 +0.008987 +0.009066 +0.008899 +0.008812 +0.008871 +0.008944 +0.009029 +0.009098 +0.008945 +0.008861 +0.008915 +0.009001 +0.009084 +0.009134 +0.008982 +0.008911 +0.008983 +0.00905 +0.009119 +0.009171 +0.009022 +0.00897 +0.00903 +0.00909 +0.009172 +0.009237 +0.00907 +0.008979 +0.009046 +0.009131 +0.009219 +0.009278 +0.009128 +0.009031 +0.009113 +0.009184 +0.009264 +0.00933 +0.009165 +0.009073 +0.009136 +0.00922 +0.009322 +0.009385 +0.009233 +0.00912 +0.009189 +0.009273 +0.009358 +0.00942 +0.009256 +0.009184 +0.009226 +0.00931 +0.009395 +0.009466 +0.009301 +0.009212 +0.009291 +0.009371 +0.009464 +0.009518 +0.009349 +0.009249 +0.009323 +0.009408 +0.009498 +0.009559 +0.009394 +0.009318 +0.009391 +0.009469 +0.009533 +0.009593 +0.009425 +0.009368 +0.00943 +0.0095 +0.009598 +0.009677 +0.009493 +0.009401 +0.009467 +0.009536 +0.009641 +0.009711 +0.009535 +0.009463 +0.009513 +0.009606 +0.009695 +0.009747 +0.009591 +0.009498 +0.009562 +0.009658 +0.009758 +0.009824 +0.009627 +0.009544 +0.009601 +0.009689 +0.009806 +0.009835 +0.009683 +0.009605 +0.009655 +0.009751 +0.009858 +0.009893 +0.009725 +0.009653 +0.009704 +0.009806 +0.009884 +0.009947 +0.009779 +0.009705 +0.009758 +0.009834 +0.009933 +0.010002 +0.009863 +0.009764 +0.009822 +0.009882 +0.01 +0.010039 +0.009867 +0.009784 +0.009853 +0.009929 +0.010042 +0.010124 +0.009937 +0.009856 +0.009909 +0.009987 +0.010078 +0.010143 +0.009974 +0.009888 +0.009966 +0.010035 +0.01014 +0.010201 +0.010033 +0.00997 +0.010009 +0.01008 +0.010179 +0.010248 +0.01009 +0.010031 +0.010028 +0.010142 +0.01023 +0.010301 +0.010135 +0.010026 +0.010104 +0.010201 +0.010289 +0.010368 +0.010168 +0.01005 +0.010107 +0.01018 +0.010235 +0.010257 +0.010041 +0.009916 +0.009951 +0.010021 +0.010097 +0.010047 +0.009823 +0.009686 +0.009716 +0.009745 +0.009788 +0.00978 +0.00956 +0.009441 +0.009456 +0.009505 +0.009533 +0.009521 +0.009316 +0.009211 +0.009195 +0.009236 +0.009269 +0.009265 +0.009073 +0.008973 +0.008989 +0.009025 +0.009064 +0.009071 +0.008888 +0.008757 +0.008784 +0.008821 +0.008865 +0.008886 +0.008702 +0.008609 +0.008653 +0.008725 +0.008733 +0.008749 +0.00856 +0.008477 +0.008506 +0.008555 +0.008603 +0.008629 +0.008447 +0.008362 +0.008411 +0.008452 +0.008503 +0.008531 +0.00837 +0.008263 +0.008312 +0.008381 +0.008436 +0.008499 +0.008343 +0.008257 +0.008301 +0.008372 +0.008451 +0.008521 +0.008379 +0.008296 +0.008331 +0.008413 +0.008491 +0.008553 +0.008411 +0.008331 +0.00838 +0.008461 +0.008553 +0.008611 +0.008457 +0.00838 +0.008442 +0.008488 +0.008583 +0.008639 +0.008488 +0.008421 +0.008469 +0.008552 +0.008631 +0.008714 +0.00856 +0.008457 +0.008527 +0.008595 +0.008654 +0.00871 +0.008566 +0.0085 +0.00856 +0.008631 +0.008703 +0.008767 +0.008632 +0.008556 +0.008608 +0.00869 +0.008751 +0.008804 +0.008656 +0.008591 +0.008639 +0.008713 +0.008798 +0.008862 +0.008711 +0.008649 +0.008699 +0.008779 +0.008871 +0.008878 +0.008739 +0.008666 +0.008721 +0.008821 +0.00888 +0.008941 +0.008794 +0.008736 +0.00878 +0.008852 +0.008948 +0.008987 +0.00883 +0.008759 +0.008824 +0.008887 +0.008973 +0.009037 +0.008882 +0.008812 +0.008873 +0.008951 +0.009028 +0.00908 +0.008931 +0.008861 +0.008925 +0.008976 +0.009057 +0.009117 +0.008983 +0.00891 +0.008951 +0.009031 +0.009151 +0.009169 +0.008997 +0.008934 +0.008997 +0.009062 +0.009167 +0.009228 +0.009065 +0.008981 +0.009032 +0.009122 +0.009199 +0.009264 +0.009107 +0.009034 +0.009089 +0.009167 +0.00927 +0.009347 +0.009157 +0.009062 +0.009119 +0.009206 +0.009297 +0.00936 +0.009191 +0.009117 +0.009195 +0.009287 +0.009354 +0.009415 +0.009246 +0.009152 +0.009214 +0.009313 +0.009388 +0.009453 +0.009301 +0.009215 +0.009275 +0.009363 +0.009444 +0.009511 +0.00934 +0.00925 +0.00934 +0.009408 +0.009492 +0.009545 +0.009374 +0.009301 +0.009368 +0.009454 +0.00954 +0.009605 +0.009422 +0.00934 +0.009421 +0.009485 +0.009583 +0.009658 +0.009476 +0.009407 +0.009469 +0.009553 +0.009647 +0.009701 +0.009526 +0.009445 +0.009497 +0.009591 +0.009689 +0.009765 +0.009565 +0.009499 +0.009553 +0.009676 +0.009739 +0.009769 +0.009617 +0.009542 +0.00959 +0.009681 +0.009782 +0.009828 +0.00968 +0.009614 +0.009666 +0.009745 +0.009839 +0.009876 +0.009715 +0.009631 +0.009696 +0.009787 +0.00986 +0.009962 +0.009812 +0.009719 +0.009743 +0.009824 +0.009907 +0.009985 +0.009816 +0.009742 +0.009788 +0.009874 +0.009981 +0.010061 +0.00988 +0.009787 +0.00985 +0.009932 +0.010016 +0.010082 +0.009915 +0.009828 +0.009885 +0.01 +0.010098 +0.010154 +0.009984 +0.009906 +0.009953 +0.010009 +0.010122 +0.010177 +0.010017 +0.00992 +0.009983 +0.010085 +0.010203 +0.010238 +0.010068 +0.009975 +0.010031 +0.010132 +0.010253 +0.010293 +0.010121 +0.010049 +0.01008 +0.01018 +0.010298 +0.010329 +0.010145 +0.01005 +0.010138 +0.010202 +0.010213 +0.010228 +0.010026 +0.009897 +0.009932 +0.009961 +0.010005 +0.010032 +0.009818 +0.009672 +0.009705 +0.009728 +0.009778 +0.009803 +0.009566 +0.009462 +0.009476 +0.009501 +0.009537 +0.009541 +0.009343 +0.009211 +0.009232 +0.009281 +0.009314 +0.009352 +0.009116 +0.009023 +0.009017 +0.009046 +0.009095 +0.009088 +0.008907 +0.0088 +0.008828 +0.008871 +0.00891 +0.008936 +0.008747 +0.008656 +0.008689 +0.008721 +0.008763 +0.008787 +0.008622 +0.008516 +0.008555 +0.008598 +0.008659 +0.008678 +0.008503 +0.008421 +0.008459 +0.00852 +0.008564 +0.008571 +0.008407 +0.008333 +0.00839 +0.008453 +0.008496 +0.008547 +0.008399 +0.008331 +0.008397 +0.008473 +0.008538 +0.008592 +0.008449 +0.00837 +0.008431 +0.008482 +0.008577 +0.008631 +0.008497 +0.008416 +0.008469 +0.008555 +0.008636 +0.008677 +0.008527 +0.00846 +0.00851 +0.008607 +0.008659 +0.008714 +0.00856 +0.008501 +0.008568 +0.00864 +0.008763 +0.008746 +0.00861 +0.008535 +0.008586 +0.008658 +0.008745 +0.008805 +0.008659 +0.00861 +0.008653 +0.008699 +0.00879 +0.008854 +0.008702 +0.008629 +0.008682 +0.008753 +0.008836 +0.008897 +0.008755 +0.008698 +0.008758 +0.008801 +0.008865 +0.008934 +0.008785 +0.008716 +0.008764 +0.008834 +0.008926 +0.009014 +0.008841 +0.008769 +0.008824 +0.00889 +0.008961 +0.009035 +0.008878 +0.008801 +0.00885 +0.008937 +0.009012 +0.009074 +0.00893 +0.008859 +0.008906 +0.008984 +0.009066 +0.009125 +0.008989 +0.008905 +0.008925 +0.00901 +0.009091 +0.009176 +0.009014 +0.008947 +0.009004 +0.00907 +0.009146 +0.009209 +0.009058 +0.008974 +0.009025 +0.009123 +0.009187 +0.009259 +0.009114 +0.009048 +0.009085 +0.009167 +0.009249 +0.009308 +0.009138 +0.009067 +0.009119 +0.009229 +0.009296 +0.009346 +0.009197 +0.00914 +0.009175 +0.00925 +0.009323 +0.009389 +0.009236 +0.009156 +0.009208 +0.009302 +0.009379 +0.009447 +0.009317 +0.009213 +0.009266 +0.009349 +0.009429 +0.009484 +0.009324 +0.009253 +0.009316 +0.009384 +0.009494 +0.009561 +0.009421 +0.009308 +0.009343 +0.009427 +0.009509 +0.00959 +0.00943 +0.009336 +0.009415 +0.009482 +0.009567 +0.009627 +0.009469 +0.00939 +0.009447 +0.009543 +0.009621 +0.009687 +0.009533 +0.009445 +0.009513 +0.009579 +0.009672 +0.009733 +0.009574 +0.009487 +0.009569 +0.009634 +0.009717 +0.009778 +0.009612 +0.009562 +0.009587 +0.009671 +0.009795 +0.009824 +0.009663 +0.009577 +0.009638 +0.009723 +0.009825 +0.0099 +0.009722 +0.009645 +0.009689 +0.009764 +0.009868 +0.009938 +0.009759 +0.009668 +0.009743 +0.009836 +0.009975 +0.009983 +0.009812 +0.00971 +0.009778 +0.009876 +0.009973 +0.010026 +0.009863 +0.009788 +0.009831 +0.009939 +0.01003 +0.010085 +0.009914 +0.009812 +0.009882 +0.009969 +0.01008 +0.010128 +0.009963 +0.009878 +0.009949 +0.010036 +0.010138 +0.010205 +0.010001 +0.009918 +0.00997 +0.010067 +0.010168 +0.010249 +0.010072 +0.009992 +0.010045 +0.010112 +0.010213 +0.010279 +0.010103 +0.010041 +0.010085 +0.010171 +0.010284 +0.010342 +0.010159 +0.010104 +0.010117 +0.010222 +0.010334 +0.010408 +0.010244 +0.010128 +0.010167 +0.010268 +0.010414 +0.010422 +0.010259 +0.010172 +0.010239 +0.010327 +0.010441 +0.010498 +0.0103 +0.010205 +0.010256 +0.010334 +0.010395 +0.010426 +0.010182 +0.010052 +0.010096 +0.010135 +0.01019 +0.010204 +0.009985 +0.00984 +0.009824 +0.009851 +0.009903 +0.009895 +0.009686 +0.00957 +0.009561 +0.00961 +0.009659 +0.009656 +0.009432 +0.009308 +0.009322 +0.009358 +0.009395 +0.009388 +0.009177 +0.009062 +0.009078 +0.009136 +0.00917 +0.009177 +0.00898 +0.008859 +0.008872 +0.008916 +0.008962 +0.008996 +0.008792 +0.008675 +0.008698 +0.008755 +0.008811 +0.008832 +0.008662 +0.00854 +0.008573 +0.008611 +0.00866 +0.008681 +0.00852 +0.008414 +0.008456 +0.008499 +0.008574 +0.0086 +0.008415 +0.008332 +0.008367 +0.008417 +0.008476 +0.008522 +0.008359 +0.008285 +0.008339 +0.008422 +0.008496 +0.008564 +0.008406 +0.008331 +0.008371 +0.008446 +0.008527 +0.008573 +0.008427 +0.008366 +0.008437 +0.008483 +0.008568 +0.008624 +0.008503 +0.00842 +0.008464 +0.008544 +0.00862 +0.008659 +0.008518 +0.008451 +0.008499 +0.008568 +0.008658 +0.008714 +0.008581 +0.008501 +0.008556 +0.008628 +0.008731 +0.008783 +0.008583 +0.00852 +0.008577 +0.008652 +0.008735 +0.008795 +0.008641 +0.008591 +0.008634 +0.00871 +0.008793 +0.008857 +0.008685 +0.008614 +0.008678 +0.008738 +0.008823 +0.008889 +0.008752 +0.008676 +0.008726 +0.008793 +0.008868 +0.008926 +0.008779 +0.008709 +0.008779 +0.00885 +0.008907 +0.008974 +0.008844 +0.008758 +0.008813 +0.00887 +0.008947 +0.009017 +0.008864 +0.008792 +0.008847 +0.008936 +0.009004 +0.009068 +0.00892 +0.008853 +0.0089 +0.008973 +0.00905 +0.009102 +0.008952 +0.008882 +0.008938 +0.009014 +0.009097 +0.009168 +0.009025 +0.008959 +0.008981 +0.009059 +0.009133 +0.009192 +0.009065 +0.008957 +0.00902 +0.009109 +0.009181 +0.009248 +0.009097 +0.009042 +0.009075 +0.00916 +0.009243 +0.009284 +0.009134 +0.009062 +0.009113 +0.009189 +0.009277 +0.009355 +0.009185 +0.009126 +0.009181 +0.009258 +0.009356 +0.009374 +0.009221 +0.009145 +0.00919 +0.009293 +0.009359 +0.009448 +0.009285 +0.009211 +0.009268 +0.009348 +0.009427 +0.009479 +0.009313 +0.009242 +0.009288 +0.009404 +0.009466 +0.00953 +0.009373 +0.009301 +0.009362 +0.009424 +0.009508 +0.009582 +0.009431 +0.009357 +0.009382 +0.009456 +0.009563 +0.009626 +0.009482 +0.009396 +0.009445 +0.009521 +0.009601 +0.00968 +0.009512 +0.009438 +0.009477 +0.009553 +0.009659 +0.009731 +0.009577 +0.009509 +0.009539 +0.009626 +0.009706 +0.00976 +0.009601 +0.009526 +0.009589 +0.009695 +0.009746 +0.009851 +0.009647 +0.009576 +0.009637 +0.009705 +0.0098 +0.00987 +0.009703 +0.009617 +0.009691 +0.009763 +0.009845 +0.009926 +0.009745 +0.009665 +0.009727 +0.009809 +0.009907 +0.009976 +0.009805 +0.00972 +0.009777 +0.009873 +0.009985 +0.010034 +0.009843 +0.009751 +0.009836 +0.00991 +0.009995 +0.010076 +0.009919 +0.009812 +0.009873 +0.009958 +0.010074 +0.01012 +0.009933 +0.009855 +0.009918 +0.010011 +0.010133 +0.010189 +0.00999 +0.009919 +0.009972 +0.010055 +0.010166 +0.010245 +0.010057 +0.009951 +0.010013 +0.010129 +0.010237 +0.010286 +0.010086 +0.010009 +0.010064 +0.010157 +0.01026 +0.01034 +0.010145 +0.010067 +0.010151 +0.010223 +0.010303 +0.010369 +0.010194 +0.010112 +0.01017 +0.010255 +0.010375 +0.010473 +0.010289 +0.010146 +0.010198 +0.01026 +0.010349 +0.010381 +0.010151 +0.010023 +0.010084 +0.010116 +0.010163 +0.010188 +0.009953 +0.009798 +0.009821 +0.009855 +0.009904 +0.009959 +0.009693 +0.009565 +0.009577 +0.009615 +0.00966 +0.009668 +0.009444 +0.009339 +0.009359 +0.009357 +0.009391 +0.009417 +0.009209 +0.009062 +0.009079 +0.009124 +0.009169 +0.009163 +0.008962 +0.008838 +0.008859 +0.0089 +0.008943 +0.00897 +0.00877 +0.008647 +0.008681 +0.008722 +0.008777 +0.008797 +0.008621 +0.008515 +0.00854 +0.008604 +0.00866 +0.008709 +0.008508 +0.008399 +0.008424 +0.008482 +0.008524 +0.008554 +0.008379 +0.008291 +0.008334 +0.008391 +0.008456 +0.008506 +0.008349 +0.008272 +0.008308 +0.008365 +0.008454 +0.008501 +0.008359 +0.008286 +0.008339 +0.0084 +0.008499 +0.008571 +0.008416 +0.008342 +0.008392 +0.008465 +0.008543 +0.008605 +0.008439 +0.008365 +0.008416 +0.008502 +0.008579 +0.008628 +0.008485 +0.008418 +0.008477 +0.008541 +0.008616 +0.008671 +0.008545 +0.008475 +0.008506 +0.008612 +0.008663 +0.00871 +0.008567 +0.008502 +0.008545 +0.00862 +0.008705 +0.008769 +0.008615 +0.008548 +0.008603 +0.008688 +0.008786 +0.008811 +0.00865 +0.008582 +0.00863 +0.008711 +0.008788 +0.008852 +0.008701 +0.008638 +0.008685 +0.008756 +0.008852 +0.008913 +0.008741 +0.008666 +0.008722 +0.008795 +0.008904 +0.008937 +0.008781 +0.008706 +0.008759 +0.008838 +0.008927 +0.009 +0.008852 +0.008774 +0.008851 +0.0089 +0.008962 +0.009017 +0.008877 +0.008798 +0.008857 +0.008929 +0.00903 +0.009093 +0.00894 +0.008855 +0.008903 +0.008985 +0.009043 +0.009112 +0.008973 +0.008881 +0.008945 +0.009034 +0.009103 +0.009166 +0.009012 +0.008943 +0.008986 +0.009063 +0.00915 +0.009223 +0.009088 +0.008986 +0.009054 +0.009122 +0.009186 +0.009259 +0.009101 +0.009027 +0.009074 +0.009158 +0.009249 +0.009303 +0.009159 +0.009068 +0.009132 +0.009222 +0.009294 +0.009351 +0.009193 +0.009112 +0.00916 +0.009248 +0.009346 +0.009405 +0.009247 +0.009162 +0.009242 +0.009329 +0.009399 +0.009436 +0.009272 +0.009202 +0.009258 +0.009344 +0.009438 +0.009499 +0.009345 +0.009263 +0.009322 +0.009396 +0.00949 +0.009557 +0.009371 +0.009292 +0.009351 +0.009432 +0.009536 +0.009595 +0.009433 +0.009359 +0.009413 +0.009478 +0.009573 +0.009646 +0.009505 +0.009391 +0.009451 +0.009522 +0.009629 +0.009694 +0.009523 +0.009453 +0.009497 +0.009577 +0.009667 +0.009734 +0.009576 +0.009482 +0.009546 +0.009642 +0.009749 +0.009776 +0.009627 +0.009542 +0.009584 +0.009679 +0.009765 +0.009831 +0.009668 +0.009592 +0.009677 +0.009714 +0.009824 +0.009888 +0.009718 +0.009648 +0.009694 +0.009755 +0.009904 +0.009922 +0.009751 +0.009679 +0.009725 +0.009831 +0.009936 +0.009996 +0.009821 +0.00974 +0.009783 +0.00987 +0.009963 +0.010035 +0.009853 +0.009766 +0.009847 +0.009965 +0.010074 +0.010083 +0.0099 +0.009804 +0.009888 +0.009963 +0.010059 +0.010138 +0.009957 +0.009884 +0.009955 +0.010034 +0.010133 +0.010191 +0.009994 +0.009918 +0.009974 +0.010079 +0.010167 +0.010229 +0.01008 +0.009997 +0.010049 +0.010143 +0.010255 +0.010283 +0.010095 +0.010008 +0.010077 +0.010187 +0.010271 +0.010354 +0.010182 +0.010079 +0.010148 +0.010222 +0.010331 +0.010345 +0.010174 +0.010051 +0.010096 +0.010135 +0.010218 +0.010228 +0.010014 +0.009896 +0.009902 +0.009927 +0.009965 +0.009981 +0.009801 +0.00963 +0.009632 +0.009686 +0.009732 +0.00971 +0.009502 +0.009372 +0.00939 +0.0094 +0.009444 +0.009481 +0.009258 +0.009138 +0.009152 +0.00919 +0.009196 +0.009221 +0.009034 +0.008898 +0.008908 +0.00895 +0.00899 +0.009017 +0.008829 +0.008723 +0.008742 +0.008812 +0.00881 +0.00883 +0.008663 +0.008559 +0.00859 +0.008632 +0.008693 +0.008703 +0.008544 +0.008436 +0.008466 +0.008525 +0.008573 +0.008586 +0.008428 +0.008342 +0.008367 +0.008412 +0.008467 +0.008513 +0.008357 +0.008271 +0.008309 +0.008371 +0.008436 +0.008497 +0.008342 +0.008277 +0.008338 +0.008391 +0.008465 +0.008522 +0.008372 +0.008305 +0.008361 +0.008429 +0.008504 +0.008574 +0.00845 +0.008341 +0.008397 +0.008475 +0.008546 +0.008604 +0.008463 +0.008391 +0.008441 +0.008513 +0.008593 +0.008653 +0.008507 +0.00844 +0.008487 +0.008561 +0.008652 +0.008689 +0.008554 +0.008482 +0.008548 +0.008594 +0.008677 +0.008742 +0.008597 +0.008531 +0.008575 +0.008632 +0.008715 +0.008779 +0.008628 +0.008569 +0.008626 +0.008673 +0.008755 +0.008827 +0.008696 +0.008607 +0.008666 +0.008718 +0.008809 +0.00887 +0.008719 +0.008653 +0.008693 +0.008761 +0.008856 +0.008922 +0.008799 +0.008714 +0.008744 +0.008815 +0.008909 +0.008941 +0.008803 +0.008729 +0.008775 +0.008855 +0.008942 +0.009023 +0.008861 +0.008795 +0.008835 +0.008903 +0.00898 +0.00904 +0.008892 +0.008812 +0.008875 +0.008943 +0.009028 +0.009101 +0.008941 +0.008863 +0.008919 +0.008999 +0.009102 +0.009151 +0.008984 +0.008907 +0.008966 +0.009044 +0.009159 +0.009165 +0.009018 +0.008949 +0.009002 +0.009081 +0.009176 +0.009233 +0.009079 +0.008996 +0.009068 +0.00913 +0.009225 +0.009264 +0.009119 +0.009036 +0.009095 +0.009181 +0.009261 +0.009324 +0.009171 +0.009097 +0.009183 +0.009231 +0.009314 +0.009354 +0.009199 +0.009133 +0.00918 +0.009266 +0.00938 +0.009412 +0.00925 +0.009179 +0.009253 +0.009314 +0.00941 +0.009463 +0.009294 +0.009226 +0.009278 +0.009362 +0.009437 +0.00951 +0.009377 +0.009274 +0.00933 +0.009421 +0.009514 +0.009575 +0.009384 +0.009309 +0.009367 +0.009452 +0.009565 +0.00959 +0.009437 +0.009365 +0.009422 +0.009507 +0.009589 +0.009652 +0.009488 +0.00941 +0.009474 +0.009557 +0.009643 +0.009711 +0.009542 +0.009454 +0.009516 +0.009595 +0.009683 +0.009759 +0.009596 +0.009536 +0.009572 +0.009676 +0.00973 +0.009779 +0.009633 +0.009546 +0.009602 +0.009701 +0.009778 +0.009852 +0.009701 +0.009597 +0.009673 +0.009753 +0.009831 +0.009895 +0.00973 +0.009654 +0.009725 +0.00978 +0.009912 +0.009944 +0.009773 +0.009714 +0.009775 +0.009872 +0.009917 +0.009994 +0.009821 +0.009774 +0.009794 +0.009874 +0.009984 +0.010056 +0.009894 +0.00981 +0.009857 +0.009929 +0.010038 +0.010106 +0.009922 +0.009837 +0.009914 +0.00999 +0.010114 +0.010176 +0.009986 +0.009879 +0.009951 +0.010047 +0.010181 +0.010193 +0.010013 +0.009932 +0.010007 +0.01011 +0.010233 +0.01025 +0.010061 +0.009978 +0.010047 +0.01015 +0.010229 +0.010299 +0.01014 +0.010057 +0.010119 +0.01021 +0.010299 +0.010343 +0.010174 +0.010086 +0.010142 +0.01023 +0.01036 +0.010379 +0.010149 +0.010038 +0.010051 +0.010088 +0.010156 +0.010183 +0.009963 +0.00985 +0.009852 +0.009867 +0.009909 +0.009899 +0.009689 +0.00956 +0.009564 +0.009597 +0.009639 +0.009658 +0.009439 +0.00932 +0.009332 +0.009348 +0.009374 +0.009406 +0.009196 +0.009105 +0.009072 +0.009101 +0.009145 +0.009183 +0.008997 +0.008872 +0.00888 +0.008914 +0.00895 +0.008969 +0.008798 +0.008685 +0.008696 +0.00874 +0.008786 +0.008839 +0.008656 +0.008551 +0.008576 +0.008619 +0.008666 +0.008683 +0.008522 +0.008418 +0.008451 +0.008501 +0.008558 +0.008601 +0.008454 +0.008333 +0.008364 +0.008411 +0.008472 +0.008512 +0.008348 +0.00827 +0.008307 +0.008378 +0.00845 +0.008511 +0.008361 +0.008305 +0.008339 +0.008417 +0.008496 +0.008547 +0.008392 +0.00832 +0.008385 +0.008439 +0.008527 +0.008588 +0.008446 +0.008367 +0.008438 +0.008508 +0.008585 +0.00866 +0.008495 +0.008414 +0.008449 +0.008529 +0.008631 +0.008677 +0.008534 +0.008453 +0.008511 +0.008566 +0.008649 +0.00871 +0.008571 +0.0085 +0.008545 +0.008623 +0.008701 +0.008755 +0.008613 +0.008546 +0.008603 +0.008658 +0.008732 +0.008814 +0.008655 +0.008589 +0.008634 +0.008708 +0.008815 +0.008853 +0.008699 +0.008629 +0.008684 +0.008759 +0.008819 +0.008903 +0.008747 +0.008672 +0.008711 +0.008793 +0.008872 +0.008942 +0.008784 +0.008721 +0.008776 +0.008853 +0.008919 +0.008975 +0.008834 +0.008748 +0.008804 +0.008884 +0.008962 +0.009031 +0.008876 +0.008815 +0.008884 +0.008961 +0.009016 +0.009053 +0.008911 +0.008835 +0.00889 +0.008964 +0.009052 +0.009118 +0.008963 +0.008892 +0.008964 +0.009038 +0.00911 +0.009162 +0.009004 +0.008926 +0.008973 +0.009056 +0.009177 +0.009199 +0.009055 +0.008987 +0.009045 +0.009122 +0.009204 +0.009267 +0.009112 +0.00902 +0.009077 +0.009133 +0.009241 +0.009301 +0.009133 +0.009062 +0.00912 +0.009208 +0.009286 +0.009357 +0.009198 +0.009102 +0.00916 +0.009238 +0.009352 +0.009399 +0.009228 +0.009164 +0.009212 +0.009292 +0.009392 +0.00945 +0.009281 +0.009203 +0.009268 +0.009382 +0.009453 +0.009482 +0.009307 +0.009267 +0.009298 +0.009375 +0.009472 +0.009543 +0.009359 +0.009296 +0.009363 +0.009428 +0.009526 +0.00959 +0.00942 +0.009336 +0.009402 +0.009492 +0.009574 +0.009642 +0.009487 +0.009393 +0.009445 +0.009531 +0.009631 +0.009685 +0.009514 +0.009433 +0.009521 +0.009595 +0.009687 +0.009754 +0.00956 +0.009478 +0.009528 +0.009619 +0.009733 +0.009776 +0.009604 +0.009533 +0.009595 +0.009694 +0.00978 +0.009847 +0.009647 +0.009573 +0.009647 +0.009724 +0.009814 +0.009884 +0.009723 +0.009625 +0.009699 +0.009792 +0.009919 +0.009919 +0.009739 +0.009671 +0.009731 +0.009828 +0.009909 +0.00998 +0.009847 +0.009728 +0.009789 +0.00989 +0.009961 +0.010022 +0.009878 +0.009768 +0.009831 +0.009921 +0.010027 +0.010087 +0.009912 +0.00984 +0.009893 +0.009971 +0.010073 +0.010157 +0.009962 +0.009868 +0.00994 +0.010009 +0.010129 +0.010177 +0.010009 +0.009941 +0.009967 +0.010074 +0.01018 +0.010239 +0.01006 +0.009985 +0.010032 +0.01015 +0.010228 +0.010287 +0.010106 +0.010019 +0.010087 +0.010174 +0.010288 +0.010367 +0.010203 +0.010063 +0.010124 +0.010215 +0.010313 +0.010397 +0.010216 +0.010115 +0.010184 +0.010291 +0.010352 +0.010376 +0.010164 +0.010046 +0.010083 +0.010109 +0.010172 +0.010187 +0.00998 +0.009841 +0.009845 +0.009887 +0.009922 +0.009907 +0.009693 +0.009563 +0.00958 +0.009651 +0.009665 +0.009671 +0.009453 +0.009325 +0.009342 +0.009385 +0.009391 +0.009407 +0.009215 +0.00908 +0.009082 +0.009132 +0.009157 +0.009195 +0.009003 +0.00887 +0.008877 +0.008923 +0.008962 +0.008969 +0.008783 +0.008676 +0.008694 +0.00874 +0.008783 +0.008832 +0.008657 +0.008564 +0.008559 +0.008624 +0.008646 +0.008664 +0.008504 +0.008405 +0.008426 +0.008478 +0.008542 +0.00856 +0.00841 +0.008311 +0.008354 +0.008404 +0.008467 +0.008513 +0.008344 +0.008263 +0.008305 +0.008382 +0.00845 +0.008508 +0.008368 +0.008299 +0.008348 +0.00842 +0.008507 +0.008567 +0.008436 +0.008353 +0.008374 +0.008451 +0.008534 +0.008592 +0.008453 +0.008384 +0.008428 +0.008511 +0.008597 +0.008641 +0.008499 +0.008435 +0.00847 +0.008557 +0.008619 +0.008679 +0.008541 +0.008471 +0.008519 +0.00858 +0.008658 +0.008722 +0.00858 +0.008503 +0.008567 +0.008621 +0.008721 +0.008779 +0.008647 +0.008544 +0.008604 +0.00867 +0.008746 +0.008821 +0.008685 +0.008582 +0.008641 +0.008717 +0.008791 +0.008862 +0.008715 +0.00865 +0.0087 +0.008766 +0.008847 +0.008905 +0.008746 +0.008677 +0.008727 +0.008798 +0.008879 +0.00896 +0.008796 +0.008733 +0.008787 +0.008858 +0.008962 +0.00899 +0.008831 +0.008755 +0.008812 +0.008896 +0.008988 +0.009032 +0.008888 +0.00884 +0.008865 +0.008942 +0.009029 +0.009075 +0.008926 +0.008844 +0.008912 +0.008984 +0.009068 +0.009128 +0.008976 +0.008902 +0.008959 +0.009045 +0.009118 +0.009163 +0.009021 +0.008947 +0.009022 +0.009095 +0.009151 +0.009197 +0.009059 +0.008985 +0.009058 +0.009128 +0.009211 +0.009255 +0.009107 +0.00903 +0.009091 +0.009157 +0.009249 +0.009311 +0.009157 +0.009075 +0.009145 +0.00923 +0.009309 +0.009349 +0.009203 +0.009124 +0.009161 +0.009255 +0.009348 +0.009425 +0.00926 +0.009161 +0.009225 +0.009309 +0.0094 +0.009454 +0.009285 +0.00921 +0.009271 +0.009343 +0.009427 +0.009509 +0.009358 +0.009257 +0.009326 +0.009407 +0.009482 +0.009542 +0.009389 +0.0093 +0.009358 +0.00945 +0.009522 +0.009592 +0.009437 +0.00937 +0.009452 +0.009503 +0.009577 +0.009622 +0.009477 +0.009392 +0.00945 +0.009539 +0.009624 +0.00969 +0.009536 +0.009463 +0.009512 +0.00959 +0.009698 +0.009733 +0.009558 +0.009484 +0.009542 +0.009631 +0.009739 +0.009807 +0.009624 +0.009547 +0.00961 +0.009673 +0.009763 +0.009841 +0.009681 +0.009611 +0.009649 +0.009715 +0.009825 +0.00991 +0.009701 +0.009624 +0.009687 +0.009776 +0.009871 +0.009938 +0.009774 +0.009701 +0.009742 +0.009829 +0.009916 +0.009987 +0.009823 +0.009724 +0.00979 +0.00989 +0.009975 +0.010044 +0.009879 +0.009795 +0.009865 +0.009915 +0.010016 +0.010086 +0.009906 +0.009827 +0.009907 +0.009981 +0.010075 +0.010141 +0.009962 +0.009876 +0.009933 +0.010019 +0.010132 +0.01019 +0.010006 +0.009937 +0.009982 +0.010078 +0.010195 +0.010242 +0.010055 +0.009976 +0.010047 +0.010169 +0.01022 +0.010278 +0.010108 +0.010023 +0.010092 +0.010196 +0.010293 +0.010355 +0.010146 +0.010066 +0.010138 +0.010224 +0.010317 +0.010407 +0.010211 +0.010135 +0.010223 +0.010276 +0.010372 +0.010433 +0.010236 +0.010146 +0.010209 +0.010288 +0.010336 +0.010314 +0.010134 +0.010001 +0.010009 +0.010054 +0.010106 +0.010085 +0.009865 +0.009737 +0.009772 +0.00979 +0.009835 +0.009833 +0.009617 +0.009476 +0.009489 +0.00953 +0.009567 +0.009565 +0.00935 +0.009232 +0.009238 +0.009291 +0.009342 +0.009335 +0.009158 +0.008993 +0.009019 +0.009051 +0.009089 +0.009106 +0.008897 +0.008811 +0.008842 +0.00889 +0.008936 +0.008937 +0.008761 +0.008672 +0.008675 +0.00873 +0.008785 +0.008799 +0.008637 +0.008545 +0.008563 +0.008618 +0.008665 +0.0087 +0.008513 +0.008428 +0.00846 +0.008523 +0.008587 +0.008611 +0.008428 +0.008364 +0.008388 +0.008453 +0.008536 +0.008545 +0.0084 +0.008332 +0.008395 +0.008452 +0.008535 +0.008594 +0.008452 +0.008383 +0.008433 +0.008504 +0.008573 +0.00863 +0.008492 +0.008421 +0.008465 +0.008539 +0.008618 +0.008685 +0.008524 +0.008455 +0.008518 +0.008608 +0.008693 +0.008721 +0.008579 +0.008499 +0.00855 +0.008633 +0.008712 +0.008795 +0.008625 +0.008544 +0.008597 +0.008668 +0.008761 +0.0088 +0.008656 +0.008586 +0.008638 +0.008721 +0.0088 +0.008846 +0.008715 +0.008628 +0.008685 +0.008761 +0.008851 +0.008898 +0.008749 +0.008682 +0.008744 +0.008823 +0.008879 +0.008945 +0.008785 +0.008717 +0.008781 +0.008854 +0.008936 +0.008994 +0.008849 +0.008752 +0.008808 +0.008894 +0.008967 +0.009032 +0.008878 +0.00881 +0.008856 +0.008942 +0.009045 +0.009087 +0.008913 +0.008847 +0.0089 +0.008981 +0.009057 +0.009128 +0.00898 +0.008928 +0.008949 +0.009033 +0.00911 +0.009172 +0.009014 +0.008928 +0.008987 +0.009074 +0.009161 +0.009218 +0.009071 +0.008991 +0.009039 +0.009118 +0.009216 +0.009265 +0.009091 +0.009026 +0.009083 +0.009158 +0.009256 +0.009315 +0.009159 +0.009063 +0.009121 +0.00921 +0.009323 +0.009361 +0.009187 +0.009117 +0.009197 +0.009249 +0.009341 +0.009402 +0.009236 +0.009166 +0.00921 +0.009301 +0.009398 +0.009447 +0.009291 +0.009217 +0.009267 +0.009351 +0.009454 +0.009511 +0.009323 +0.009254 +0.009316 +0.009392 +0.009482 +0.009542 +0.009392 +0.009337 +0.009364 +0.009453 +0.009539 +0.009589 +0.009427 +0.009368 +0.009393 +0.009481 +0.009573 +0.00963 +0.009475 +0.009411 +0.009462 +0.009551 +0.009654 +0.009672 +0.00952 +0.009446 +0.009492 +0.009578 +0.009674 +0.009737 +0.009577 +0.009509 +0.009565 +0.009678 +0.00972 +0.009777 +0.009612 +0.009532 +0.009592 +0.009678 +0.009768 +0.009889 +0.00966 +0.009584 +0.009648 +0.009728 +0.009805 +0.009875 +0.009714 +0.009629 +0.009711 +0.00978 +0.009865 +0.009933 +0.009773 +0.009674 +0.009732 +0.009827 +0.009929 +0.010009 +0.009803 +0.009752 +0.009788 +0.009874 +0.009976 +0.01004 +0.009859 +0.009779 +0.009831 +0.009932 +0.010029 +0.010079 +0.009924 +0.009831 +0.009881 +0.009973 +0.010084 +0.010137 +0.00996 +0.009871 +0.009935 +0.010027 +0.010131 +0.010216 +0.010045 +0.009911 +0.009983 +0.010074 +0.010166 +0.010244 +0.010056 +0.009975 +0.010041 +0.01013 +0.010243 +0.010307 +0.010107 +0.010016 +0.01009 +0.010159 +0.010269 +0.01035 +0.010159 +0.010073 From 51400f2c02b93b639bc48f0267e063a8a929fed4 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 10 Jan 2023 11:14:37 +0100 Subject: [PATCH 002/209] Fixed a bug in tick rollover Fixed a bug in the tick rollover (which seems to happen every 60 minutes of processtime). --- app/gpio/GpioTimerService.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/gpio/GpioTimerService.js b/app/gpio/GpioTimerService.js index 368ab7ca73..093a89529e 100644 --- a/app/gpio/GpioTimerService.js +++ b/app/gpio/GpioTimerService.js @@ -52,9 +52,17 @@ export function createGpioTimerService () { let previousTick = 0 // Define the alert handler - sensor.on('alert', (level, currentTick) => { + sensor.on('alert', (level, rawCurrentTick) => { if ((triggeredFlank === 'Both') || (triggeredFlank === 'Down' && level === 0) || (triggeredFlank === 'Up' && level === 1)) { - const currentDt = ((currentTick >> 0) - (previousTick >> 0)) / 1e6 + const currentTick = (rawCurrentTick >> 0) / 1e6 + let currentDt + if (currentTick > previousTick) { + currentDt = currentTick - previousTick + } else { + // We had a rollover of the tick, so the current tick misses 4,294,967,295 us + log.debug('Gpio-service: tick rollover detected and corrected') + currentDt = (currentTick + 4294.967295) - previousTick + } previousTick = currentTick process.send(currentDt) } From 6623aa2f86e42cb1a7224bc19bc86863a198ea08 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 10 Jan 2023 11:27:13 +0100 Subject: [PATCH 003/209] Several bugfixes and improvements Bugfix: Fixed a bug where a new year or month would crash the workoutrecorder due to a missing data directory Several improvements: * Added possibility of only creating RowingData file * Improved HRR data when restarting a workout --- app/engine/WorkoutRecorder.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/engine/WorkoutRecorder.js b/app/engine/WorkoutRecorder.js index 5370a1432f..05e59849d5 100644 --- a/app/engine/WorkoutRecorder.js +++ b/app/engine/WorkoutRecorder.js @@ -87,6 +87,14 @@ function createWorkoutRecorder () { `"${currentstroke.driveHandleVelocityCurve}","${currentstroke.driveHandlePowerCurve}"\n` i++ } + + try { + await fs.mkdir(directory, { recursive: true }) + } catch (error) { + if (error.code !== 'EEXIST') { + log.error(`can not create directory ${directory}`, error) + } + } await createFile(RowingData, `${filename}`, false) } @@ -270,7 +278,7 @@ function createWorkoutRecorder () { } async function createRecordings () { - if (!config.createRawDataFiles && !config.createTcxFiles) { + if (!config.createRawDataFiles && !config.createTcxFiles && !config.createRowingDataFiles) { return } @@ -279,6 +287,8 @@ function createWorkoutRecorder () { return } + postExerciseHR = [] + const parallelCalls = [] if (config.createRawDataFiles) { From 062faa0190d132c59e877c759bc2e8d9f7dff3e3 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 10 Jan 2023 11:34:00 +0100 Subject: [PATCH 004/209] A bit more defensive programming A bit more defensive programming as one bad (NaN) measurement of CurrentDt will kill all metrics for the entire session. --- app/engine/Flywheel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/engine/Flywheel.js b/app/engine/Flywheel.js index b20b09c1e3..565db81ac1 100644 --- a/app/engine/Flywheel.js +++ b/app/engine/Flywheel.js @@ -58,7 +58,7 @@ function createFlywheel (rowerSettings) { reset() function pushValue (dataPoint) { - if (dataPoint > rowerSettings.maximumStrokeTimeBeforePause || dataPoint < 0) { + if (isNaN(dataPoint) || dataPoint < 0 || dataPoint > rowerSettings.maximumStrokeTimeBeforePause) { // This typicaly happends after a pause, we need to fix this as it throws off all time calculations log.debug(`*** WARNING: currentDt of ${dataPoint} sec isn't between 0 and maximumStrokeTimeBeforePause (${rowerSettings.maximumStrokeTimeBeforePause} sec)`) dataPoint = currentDt.clean() From 35ff3489a567577b6dcca2dc0eb6d7211098eb85 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 10 Jan 2023 11:44:37 +0100 Subject: [PATCH 005/209] Fixed a typo in function name To add insult to injury: by a typo in the error logging function, the app would crash if there was a recoverable error --- app/engine/utils/FullTSLinearSeries.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/engine/utils/FullTSLinearSeries.js b/app/engine/utils/FullTSLinearSeries.js index b0e9c3d4b4..1eab396f0e 100644 --- a/app/engine/utils/FullTSLinearSeries.js +++ b/app/engine/utils/FullTSLinearSeries.js @@ -183,7 +183,7 @@ function createTSLinearSeries (maxSeriesLength = 0) { const mid = Math.floor(sortedArray.length / 2) return (sortedArray.length % 2 !== 0 ? sortedArray[mid] : ((sortedArray[mid - 1] + sortedArray[mid]) / 2)) } else { - log.eror('TS Linear Regressor, Median calculation on empty dataset attempted!') + log.error('TS Linear Regressor, Median calculation on empty dataset attempted!') return 0 } } From 733720fa44b8840e997d8daf7bfb585c918a58b8 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 10 Jan 2023 11:56:37 +0100 Subject: [PATCH 006/209] Expansion of the Interval type Addittion of the interval type, as a preperation of the more complex workout schedules --- app/ble/pm5/characteristic/GeneralStatus.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/ble/pm5/characteristic/GeneralStatus.js b/app/ble/pm5/characteristic/GeneralStatus.js index c0116ee038..b4b7a5aa6a 100644 --- a/app/ble/pm5/characteristic/GeneralStatus.js +++ b/app/ble/pm5/characteristic/GeneralStatus.js @@ -41,10 +41,11 @@ export default class GeneralStatus extends bleno.Characteristic { bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) // distance: UInt24LE in 0.1 m bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance * 10)) - // workoutType: UInt8 0 WORKOUTTYPE_JUSTROW_NOSPLITS, 2 WORKOUTTYPE_FIXEDDIST_NOSPLITS, 4 WORKOUTTYPE_FIXEDTIME_NOSPLITS + // workoutType: UInt8: 0 WORKOUTTYPE_JUSTROW_NOSPLITS, 2 WORKOUTTYPE_FIXEDDIST_NOSPLITS, 4 WORKOUTTYPE_FIXEDTIME_NOSPLITS bufferBuilder.writeUInt8(data.sessiontype === 'Distance' ? 2 : (data.sessiontype === 'Time' ? 4 : 0)) - // intervalType: UInt8 will always use 255 (NONE) - bufferBuilder.writeUInt8(255) + // intervalType: UInt8: 1 INTERVALTYPE_TIME, 2 INTERVALTYPE_DIST, 255 NONE + // ToDo: split down further to allow rest intervals when the PM5 schedule dictates it + bufferBuilder.writeUInt8(data.sessiontype === 'Distance' ? 2 : (data.sessiontype === 'Time' ? 1 : 255)) // workoutState: UInt8 0 WAITTOBEGIN, 1 WORKOUTROW, 10 WORKOUTEND bufferBuilder.writeUInt8(data.sessionStatus === 'Rowing' ? 1 : (data.sessionStatus === 'WaitingForStart' ? 0 : 10)) // rowingState: UInt8 0 INACTIVE, 1 ACTIVE From b4e8f16b3c0caf9c0f35d6d70716d5a38a92ca62 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 11 Jan 2023 10:12:54 +0100 Subject: [PATCH 007/209] Improvement of code quality Replaced the horrible ested If...then....else with a much more readable case statement to implement the Concept 2 table --- app/engine/VO2max.js | 47 ++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/app/engine/VO2max.js b/app/engine/VO2max.js index 6d15189c2d..b26de3dcc8 100644 --- a/app/engine/VO2max.js +++ b/app/engine/VO2max.js @@ -96,36 +96,31 @@ function createVO2max (config) { log.debug(`--- VO2Max Interpolated 2K pace: ${Math.floor(projectedTwoKPace / 60)}:${(projectedTwoKPace % 60).toFixed(1)}`) // This implements the table with formulas found at https://www.concept2.com/indoor-rowers/training/calculators/vo2max-calculator - if (config.userSettings.highlyTrained) { - // Highly trained - if (config.userSettings.sex === 'male') { - // Highly trained male - if (config.userSettings.weight > 75) { - // Highly trained male, above 75 Kg - Y = 15.7 - (1.5 * projectedTwoKTimeInMinutes) - } else { - // Highly trained male, equal or below 75 Kg - Y = 15.1 - (1.5 * projectedTwoKTimeInMinutes) - } - } else { - // Highly trained female - if (config.userSettings.weight > 61.36) { - // Highly trained female, above 61.36 Kg - Y = 14.9 - (1.5 * projectedTwoKTimeInMinutes) - } else { - // Highly trained female, equal or below 61.36 Kg - Y = 14.6 - (1.5 * projectedTwoKTimeInMinutes) - } - } - } else { - // Not highly trained - if (config.userSettings.sex === 'male') { + switch (true) { + case (config.userSettings.sex === 'male' && config.userSettings.highlyTrained && config.userSettings.weight > 75): + // Highly trained male, above 75 Kg + Y = 15.7 - (1.5 * projectedTwoKTimeInMinutes + break + case (config.userSettings.sex === 'male' && config.userSettings.highlyTrained): + // Highly trained male, equal or below 75 Kg + Y = 15.1 - (1.5 * projectedTwoKTimeInMinutes) + break + case (config.userSettings.sex === 'male'): // Not highly trained male Y = 10.7 - (0.9 * projectedTwoKTimeInMinutes) - } else { + break + case (config.userSettings.sex === 'female' && config.userSettings.highlyTrained && config.userSettings.weight > 61.36): + // Highly trained female, above 61.36 Kg + Y = 14.9 - (1.5 * projectedTwoKTimeInMinutes) + break + case (config.userSettings.sex === 'female' && config.userSettings.highlyTrained): + // Highly trained female, equal or below 61.36 Kg + Y = 14.6 - (1.5 * projectedTwoKTimeInMinutes) + break + case (config.userSettings.sex === 'female'): // Not highly trained female Y = 10.26 - (0.93 * projectedTwoKTimeInMinutes) - } + break } return (Y * 1000) / config.userSettings.weight } From 11ff22eca1c29cde0ef3adc3a5018b3fe1fe8e16 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 11 Jan 2023 10:15:48 +0100 Subject: [PATCH 008/209] Fixed a missing bracket --- app/engine/VO2max.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/engine/VO2max.js b/app/engine/VO2max.js index b26de3dcc8..ee196f2e01 100644 --- a/app/engine/VO2max.js +++ b/app/engine/VO2max.js @@ -99,7 +99,7 @@ function createVO2max (config) { switch (true) { case (config.userSettings.sex === 'male' && config.userSettings.highlyTrained && config.userSettings.weight > 75): // Highly trained male, above 75 Kg - Y = 15.7 - (1.5 * projectedTwoKTimeInMinutes + Y = 15.7 - (1.5 * projectedTwoKTimeInMinutes) break case (config.userSettings.sex === 'male' && config.userSettings.highlyTrained): // Highly trained male, equal or below 75 Kg From e29d723776552369c1bfa29ad6b803fb80f33038 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 11 Jan 2023 23:06:34 +0100 Subject: [PATCH 009/209] Added sanity checks to the config manager Added a lot of sanity checks to the loading of the config. --- app/tools/ConfigManager.js | 199 ++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 1 deletion(-) diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index ed4575b523..98d5f762d7 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -1,4 +1,4 @@ -'use strict' + 'use strict' /* Open Rowing Monitor, https://github.com/laberning/openrowingmonitor @@ -6,6 +6,7 @@ */ import defaultConfig from '../../config/default.config.js' import { deepMerge } from './Helper.js' +import log from 'loglevel' async function getConfig () { let customConfig @@ -16,6 +17,202 @@ async function getConfig () { return customConfig !== undefined ? deepMerge(defaultConfig, customConfig.default) : defaultConfig } +function checkConfig (configToCheck) { + checkRangeValue(configToCheck.loglevel.default, 'loglevel.default',['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') + checkRangeValue(configToCheck.loglevel.RowingEngine, 'loglevel.RowingEngine', ['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') + checkIntegerValue(configToCheck.gpioPin, 'gpioPin', 1, 27, false, false, null) + checkIntegerValue(configToCheck.gpioPriority, 'gpioPriority', -7, 0, true, true, 0) + checkIntegerValue(configToCheck.gpioMinimumPulseLength, 'gpioMinimumPulseLength', 1, 100000, false, true, 0) + checkIntegerValue(configToCheck.gpioPollingInterval, 'gpioPollingInterval', 1, 10, false, true, 10) + checkRangeValue(configToCheck.gpioPollingInterval, 'gpioPollingInterval', [1, 2, 5, 10], true, 10) + checkRangeValue(configToCheck.gpioTriggeredFlank, 'gpioTriggeredFlank', ['Up', 'Down', 'Both'], false, null) + checkIntegerValue(configToCheck.appPriority, 'appPriority', configToCheck.gpioPriority, 0, true, true, 0) + checkIntegerValue(configToCheck.webUpdateInterval, 'webUpdateInterval', 80, 1000, false, true, 1000) + checkBinaryValue(configToCheck.heartrateMonitorBLE, 'heartrateMonitorBLE', true, true) + checkBinaryValue(configToCheck.heartrateMonitorANT, 'heartrateMonitorANT', true, false) + checkRangeValue(configToCheck.bluetoothMode, 'bluetoothMode', ['off', 'PM5', 'FTMS', 'FTMSBIKE', 'CPS', 'CSC'], true, 'FTMS') + checkIntegerValue(configToCheck.peripheralUpdateInterval, 'peripheralUpdateInterval', 80, 1000, false, true, 1000) + checkIntegerValue(configToCheck.numOfPhasesForAveragingScreenData, 'numOfPhasesForAveragingScreenData', 2, null, false, true, 4) + checkBinaryValue(configToCheck.createRowingDataFiles, 'createRowingDataFiles', true, true) + checkBinaryValue(configToCheck.createRawDataFiles, 'createRawDataFiles', true, true) + checkBinaryValue(configToCheck.gzipRawDataFiles, 'gzipRawDataFiles', true, false) + checkBinaryValue(configToCheck.createTcxFiles, 'createTcxFiles', true, true) + checkBinaryValue(configToCheck.gzipTcxFiles, 'gzipTcxFiles', true, false) + if (configToCheck.createRowingDataFiles || configToCheck.createRawDataFiles || configToCheck.createTcxFiles) { + } + checkFloatValue(configToCheck.userSettings.restingHR, 'userSettings.restingHR', 30, 220, false, true, 40) + checkFloatValue(configToCheck.userSettings.maxHR, 'userSettings.maxHR', configToCheck.userSettings.restingHR, 220, false, true, 220) + if (configToCheck.createTcxFiles) { + checkFloatValue(configToCheck.userSettings.minPower, 'userSettings.minPower', 1, 500, false, true, 50) + checkFloatValue(configToCheck.userSettings.maxPower, 'userSettings.maxPower', 100, 6000, false, true, 500) + checkFloatValue(configToCheck.userSettings.distanceCorrectionFactor, 'userSettings.distanceCorrectionFactor', 0, 50, false, true, 5) + checkFloatValue(configToCheck.userSettings.weight, 'userSettings.weight', 25, 500, false, true, 80) + checkRangeValue(configToCheck.userSettings.sex, 'userSettings.sex', ['male', 'female'], true, 'male') + checkBinaryValue(configToCheck.userSettings.highlyTrained, 'userSettings.highlyTrained', true, false) + } + checkIntegerValue(configToCheck.rowerSettings.numOfImpulsesPerRevolution, 'rowerSettings.numOfImpulsesPerRevolution', 1, null, false, false, null) + checkIntegerValue(configToCheck.rowerSettings.flankLength, 'rowerSettings.flankLength', 3, null, false, false, null) + checkFloatValue(configToCheck.rowerSettings.sprocketRadius, 'rowerSettings.sprocketRadius', 0, 20, false, true, 3) + checkFloatValue(configToCheck.rowerSettings.minimumTimeBetweenImpulses, 'rowerSettings.minimumTimeBetweenImpulses', 0, 3, false, false, null) + checkFloatValue(configToCheck.rowerSettings.maximumTimeBetweenImpulses, 'rowerSettings.maximumTimeBetweenImpulses', configToCheck.rowerSettings.minimumTimeBetweenImpulses, 3, false, false, null) + checkFloatValue(configToCheck.rowerSettings.smoothing, 'rowerSettings.smoothing', 1, 1000000, false, true, 1) + checkFloatValue(configToCheck.rowerSettings.dragFactor, 'rowerSettings.dragFactor', 1, 1000000, false, false, null) + checkBinaryValue(configToCheck.rowerSettings.autoAdjustDragFactor, 'rowerSettings.autoAdjustDragFactor', true, false) + checkIntegerValue(configToCheck.rowerSettings.dragFactorSmoothing, 'rowerSettings.dragFactorSmoothing', 1, 1000, false, true, 1) + if (configToCheck.rowerSettings.autoAdjustDragFactor) { + checkFloatValue(configToCheck.rowerSettings.minimumDragQuality, 'rowerSettings.minimumDragQuality', 0, 1, true, true, 0) + } + checkFloatValue(configToCheck.rowerSettings.flywheelInertia, 'rowerSettings.flywheelInertia', 0, 2, false, false, null) + checkFloatValue(configToCheck.rowerSettings.minumumForceBeforeStroke, 'rowerSettings.minumumForceBeforeStroke', 0, 500, true, true, 0) + checkFloatValue(configToCheck.rowerSettings.minumumRecoverySlope, 'rowerSettings.minumumRecoverySlope', 0, 2, true, true, 0) + checkFloatValue(configToCheck.rowerSettings.minimumStrokeQuality, 'rowerSettings.minimumStrokeQuality', 0, 1, true, true, 0) + checkBinaryValue(configToCheck.rowerSettings.autoAdjustRecoverySlope, 'rowerSettings.autoAdjustRecoverySlope', true, false) + if (!configToCheck.rowerSettings.autoAdjustDragFactor && configToCheck.rowerSettings.autoAdjustRecoverySlope) { + log.error('Configuration Error: rowerSettings.autoAdjustRecoverySlope can not be true when configToCheck.rowerSettings.autoAdjustDragFactor is false, ignoring request') + } + if (configToCheck.rowerSettings.autoAdjustDragFactor && configToCheck.rowerSettings.autoAdjustRecoverySlope) { + checkFloatValue(configToCheck.rowerSettings.autoAdjustRecoverySlopeMargin, 'autoAdjustRecoverySlopeMargin', 0, 1, false, true, 1) + } + checkFloatValue(configToCheck.rowerSettings.minimumDriveTime, 'minimumDriveTime', 0, 6, false, true, 0.001) + checkFloatValue(configToCheck.rowerSettings.minimumRecoveryTime, 'minimumRecoveryTime', 0, 6, false, true, 0.001) + checkFloatValue(configToCheck.rowerSettings.maximumStrokeTimeBeforePause, 'maximumStrokeTimeBeforePause', 3, 60, false, true, 6) + checkFloatValue(configToCheck.rowerSettings.magicConstant, 'magicConstant', 0, 28, false, true, 2.8) +} + +function checkIntegerValue (parameter, parameterName, minimumValue, maximumvalue, allowZero, allowRepair, defaultValue) { + let errors = 0 + switch (true) { + case (parameter == undefined): + log.error(`Configuration Error: ${parameterName} isn't defined`) + errors++ + break + case (!Number.isInteger(parameter)): + log.error(`Configuration Error: ${parameterName} should be an integer value, encountered ${parameter}`) + errors++ + break + case (minimumValue != null && parameter < minimumValue): + log.error(`Configuration Error: ${parameterName} should be at least ${minimumValue}, encountered ${parameter}`) + errors++ + break + case (maximumvalue != null && parameter > maximumvalue): + log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) + errors++ + break + case (!allowZero && parameter == 0): + log.error(`Configuration Error: ${parameterName} can't be zero`) + errors++ + break + default: + // No error detected :) + } + if (errors > 0) { + // Errors were made + if (allowRepair) { + log.error(` resolved by setting ${parameterName} to ${defaultValue}`) + // ToDo: fix this by making the function call a call by reference!!! + parameter = defaultValue + } else { + log.error(`As ${parameterName} is a fatal parameter, I'm exiting`) + process.exit(9) + } + } +} + +function checkFloatValue (parameter, parameterName, minimumValue, maximumvalue, allowZero, allowRepair, defaultValue) { + let errors = 0 + switch (true) { + case (parameter == undefined): + log.error(`Configuration Error: ${parameterName} isn't defined`) + errors++ + break + case (!typeof(parameter)==="number"): + log.error(`Configuration Error: ${parameterName} should be a numerical value, encountered ${parameter}`) + errors++ + break + case (minimumValue != null && parameter < minimumValue): + log.error(`Configuration Error: ${parameterName} should be at least ${minimumValue}, encountered ${parameter}`) + errors++ + break + case (maximumvalue != null && parameter > maximumvalue): + log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) + errors++ + break + case (!allowZero && parameter == 0): + log.error(`Configuration Error: ${parameterName} can't be zero`) + errors++ + break + default: + // No error detected :) + } + if (errors > 0) { + // Errors were made + if (allowRepair) { + log.error(` resolved by setting ${parameterName} to ${defaultValue}`) + // ToDo: fix this by making the function call a call by reference!!! + parameter = defaultValue + } else { + log.error(`As ${parameterName} is a fatal parameter, I'm exiting`) + process.exit(9) + } + } +} + +function checkBinaryValue (parameter, parameterName, allowRepair, defaultValue) { + let errors = 0 + switch (true) { + case (parameter == undefined): + log.error(`Configuration Error: ${parameterName} isn't defined`) + errors++ + break + case (!(parameter === true || parameter === false)): + log.error(`Configuration Error: ${parameterName} should be either false or true, encountered ${parameter}`) + errors++ + break + default: + // No error detected :) + } + if (errors > 0) { + // Errors were made + if (allowRepair) { + log.error(` resolved by setting ${parameterName} to ${defaultValue}`) + // ToDo: fix this by making the function call a call by reference!!! + parameter = defaultValue + } else { + log.error(`As ${parameterName} is a fatal parameter, I'm exiting`) + process.exit(9) + } + } +} + +function checkRangeValue (parameter, parameterName, range, allowRepair, defaultValue) { + let errors = 0 + switch (true) { + case (parameter == undefined): + log.error(`Configuration Error: ${parameterName} isn't defined`) + errors++ + break + case (!range.includes(parameter)): + log.error(`Configuration Error: ${parameterName} should be come from ${range}, encountered ${parameter}`) + errors++ + break + default: + // No error detected :) + } + if (errors > 0) { + // Errors were made + if (allowRepair) { + log.error(` resolved by setting ${parameterName} to ${defaultValue}`) + // ToDo: fix this by making the function call a call by reference!!! + parameter = defaultValue + } else { + log.error(`As ${parameterName} is a fatal parameter, I'm exiting`) + process.exit(9) + } + } +} + const config = await getConfig() +checkConfig(config) + export default config From dc43c38e16c25c355e59ba1baed81f2d822cb1c8 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 11 Jan 2023 23:17:56 +0100 Subject: [PATCH 010/209] Improvement of code quality Improvement of code quality --- app/tools/ConfigManager.js | 143 ++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 73 deletions(-) diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index 98d5f762d7..c3bde9012d 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -1,4 +1,4 @@ - 'use strict' +'use strict' /* Open Rowing Monitor, https://github.com/laberning/openrowingmonitor @@ -13,12 +13,11 @@ async function getConfig () { try { customConfig = await import('../../config/config.js') } catch (exception) {} - return customConfig !== undefined ? deepMerge(defaultConfig, customConfig.default) : defaultConfig } function checkConfig (configToCheck) { - checkRangeValue(configToCheck.loglevel.default, 'loglevel.default',['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') + checkRangeValue(configToCheck.loglevel.default, 'loglevel.default', ['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') checkRangeValue(configToCheck.loglevel.RowingEngine, 'loglevel.RowingEngine', ['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') checkIntegerValue(configToCheck.gpioPin, 'gpioPin', 1, 27, false, false, null) checkIntegerValue(configToCheck.gpioPriority, 'gpioPriority', -7, 0, true, true, 0) @@ -38,8 +37,6 @@ function checkConfig (configToCheck) { checkBinaryValue(configToCheck.gzipRawDataFiles, 'gzipRawDataFiles', true, false) checkBinaryValue(configToCheck.createTcxFiles, 'createTcxFiles', true, true) checkBinaryValue(configToCheck.gzipTcxFiles, 'gzipTcxFiles', true, false) - if (configToCheck.createRowingDataFiles || configToCheck.createRawDataFiles || configToCheck.createTcxFiles) { - } checkFloatValue(configToCheck.userSettings.restingHR, 'userSettings.restingHR', 30, 220, false, true, 40) checkFloatValue(configToCheck.userSettings.maxHR, 'userSettings.maxHR', configToCheck.userSettings.restingHR, 220, false, true, 220) if (configToCheck.createTcxFiles) { @@ -73,37 +70,37 @@ function checkConfig (configToCheck) { if (configToCheck.rowerSettings.autoAdjustDragFactor && configToCheck.rowerSettings.autoAdjustRecoverySlope) { checkFloatValue(configToCheck.rowerSettings.autoAdjustRecoverySlopeMargin, 'autoAdjustRecoverySlopeMargin', 0, 1, false, true, 1) } - checkFloatValue(configToCheck.rowerSettings.minimumDriveTime, 'minimumDriveTime', 0, 6, false, true, 0.001) - checkFloatValue(configToCheck.rowerSettings.minimumRecoveryTime, 'minimumRecoveryTime', 0, 6, false, true, 0.001) - checkFloatValue(configToCheck.rowerSettings.maximumStrokeTimeBeforePause, 'maximumStrokeTimeBeforePause', 3, 60, false, true, 6) - checkFloatValue(configToCheck.rowerSettings.magicConstant, 'magicConstant', 0, 28, false, true, 2.8) + checkFloatValue(configToCheck.rowerSettings.minimumDriveTime, 'rowerSettings.minimumDriveTime', 0, 6, false, true, 0.001) + checkFloatValue(configToCheck.rowerSettings.minimumRecoveryTime, 'rowerSettings.minimumRecoveryTime', 0, 6, false, true, 0.001) + checkFloatValue(configToCheck.rowerSettings.maximumStrokeTimeBeforePause, 'rowerSettings.maximumStrokeTimeBeforePause', 3, 60, false, true, 6) + checkFloatValue(configToCheck.rowerSettings.magicConstant, 'rowerSettings.magicConstant', 0, 28, false, true, 2.8) } function checkIntegerValue (parameter, parameterName, minimumValue, maximumvalue, allowZero, allowRepair, defaultValue) { let errors = 0 switch (true) { - case (parameter == undefined): - log.error(`Configuration Error: ${parameterName} isn't defined`) - errors++ - break - case (!Number.isInteger(parameter)): - log.error(`Configuration Error: ${parameterName} should be an integer value, encountered ${parameter}`) - errors++ - break - case (minimumValue != null && parameter < minimumValue): - log.error(`Configuration Error: ${parameterName} should be at least ${minimumValue}, encountered ${parameter}`) - errors++ - break - case (maximumvalue != null && parameter > maximumvalue): - log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) - errors++ - break - case (!allowZero && parameter == 0): - log.error(`Configuration Error: ${parameterName} can't be zero`) - errors++ - break - default: - // No error detected :) + case (parameter === undefined): + log.error(`Configuration Error: ${parameterName} isn't defined`) + errors++ + break + case (!Number.isInteger(parameter)): + log.error(`Configuration Error: ${parameterName} should be an integer value, encountered ${parameter}`) + errors++ + break + case (minimumValue != null && parameter < minimumValue): + log.error(`Configuration Error: ${parameterName} should be at least ${minimumValue}, encountered ${parameter}`) + errors++ + break + case (maximumvalue != null && parameter > maximumvalue): + log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) + errors++ + break + case (!allowZero && parameter == 0): + log.error(`Configuration Error: ${parameterName} can't be zero`) + errors++ + break + default: + // No error detected :) } if (errors > 0) { // Errors were made @@ -121,28 +118,28 @@ function checkIntegerValue (parameter, parameterName, minimumValue, maximumvalue function checkFloatValue (parameter, parameterName, minimumValue, maximumvalue, allowZero, allowRepair, defaultValue) { let errors = 0 switch (true) { - case (parameter == undefined): - log.error(`Configuration Error: ${parameterName} isn't defined`) - errors++ - break - case (!typeof(parameter)==="number"): - log.error(`Configuration Error: ${parameterName} should be a numerical value, encountered ${parameter}`) - errors++ - break - case (minimumValue != null && parameter < minimumValue): - log.error(`Configuration Error: ${parameterName} should be at least ${minimumValue}, encountered ${parameter}`) - errors++ - break - case (maximumvalue != null && parameter > maximumvalue): - log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) - errors++ - break - case (!allowZero && parameter == 0): - log.error(`Configuration Error: ${parameterName} can't be zero`) - errors++ - break - default: - // No error detected :) + case (parameter === undefined): + log.error(`Configuration Error: ${parameterName} isn't defined`) + errors++ + break + case (!typeof (parameter) === 'number'): + log.error(`Configuration Error: ${parameterName} should be a numerical value, encountered ${parameter}`) + errors++ + break + case (minimumValue != null && parameter < minimumValue): + log.error(`Configuration Error: ${parameterName} should be at least ${minimumValue}, encountered ${parameter}`) + errors++ + break + case (maximumvalue != null && parameter > maximumvalue): + log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) + errors++ + break + case (!allowZero && parameter == 0): + log.error(`Configuration Error: ${parameterName} can't be zero`) + errors++ + break + default: + // No error detected :) } if (errors > 0) { // Errors were made @@ -160,16 +157,16 @@ function checkFloatValue (parameter, parameterName, minimumValue, maximumvalue, function checkBinaryValue (parameter, parameterName, allowRepair, defaultValue) { let errors = 0 switch (true) { - case (parameter == undefined): - log.error(`Configuration Error: ${parameterName} isn't defined`) - errors++ - break - case (!(parameter === true || parameter === false)): - log.error(`Configuration Error: ${parameterName} should be either false or true, encountered ${parameter}`) - errors++ - break - default: - // No error detected :) + case (parameter === undefined): + log.error(`Configuration Error: ${parameterName} isn't defined`) + errors++ + break + case (!(parameter === true || parameter === false)): + log.error(`Configuration Error: ${parameterName} should be either false or true, encountered ${parameter}`) + errors++ + break + default: + // No error detected :) } if (errors > 0) { // Errors were made @@ -187,16 +184,16 @@ function checkBinaryValue (parameter, parameterName, allowRepair, defaultValue) function checkRangeValue (parameter, parameterName, range, allowRepair, defaultValue) { let errors = 0 switch (true) { - case (parameter == undefined): - log.error(`Configuration Error: ${parameterName} isn't defined`) - errors++ - break - case (!range.includes(parameter)): - log.error(`Configuration Error: ${parameterName} should be come from ${range}, encountered ${parameter}`) - errors++ - break - default: - // No error detected :) + case (parameter === undefined): + log.error(`Configuration Error: ${parameterName} isn't defined`) + errors++ + break + case (!range.includes(parameter)): + log.error(`Configuration Error: ${parameterName} should be come from ${range}, encountered ${parameter}`) + errors++ + break + default: + // No error detected :) } if (errors > 0) { // Errors were made From 0378f27655c593c567eae2e1b7814e5c2083f06e Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 11 Jan 2023 23:19:48 +0100 Subject: [PATCH 011/209] Fixed Lint errors Fixed Lint errors --- app/tools/ConfigManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index c3bde9012d..12fe1d3c75 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -95,7 +95,7 @@ function checkIntegerValue (parameter, parameterName, minimumValue, maximumvalue log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) errors++ break - case (!allowZero && parameter == 0): + case (!allowZero && parameter === 0): log.error(`Configuration Error: ${parameterName} can't be zero`) errors++ break @@ -134,7 +134,7 @@ function checkFloatValue (parameter, parameterName, minimumValue, maximumvalue, log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) errors++ break - case (!allowZero && parameter == 0): + case (!allowZero && parameter === 0): log.error(`Configuration Error: ${parameterName} can't be zero`) errors++ break From ce9294dfb82fbb7f7d06196216c9c204df4efb1c Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 11 Jan 2023 23:29:52 +0100 Subject: [PATCH 012/209] Centralising parameter check Removed sanity checks in RowingStatistics, as the configmanager centralises the parameter check --- app/engine/RowingStatistics.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index 8249b3d56f..de4d10c939 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -15,8 +15,8 @@ const log = loglevel.getLogger('RowingEngine') function createRowingStatistics (config, session) { const numOfDataPointsForAveraging = config.numOfPhasesForAveragingScreenData - const webUpdateInterval = Math.min(config.webUpdateInterval, 2000) - const peripheralUpdateInterval = Math.min(config.peripheralUpdateInterval, 1000) + const webUpdateInterval = config.webUpdateInterval + const peripheralUpdateInterval = config.peripheralUpdateInterval const emitter = new EventEmitter() const rower = createRower(config.rowerSettings) const minimumStrokeTime = config.rowerSettings.minimumRecoveryTime + config.rowerSettings.minimumDriveTime From 3364ef38a8624bc7fe765a17a1cd01ebf50c517b Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 11 Jan 2023 23:30:11 +0100 Subject: [PATCH 013/209] Centralising parameter check Removed sanity checks in RowingStatistics, as the configmanager centralises the parameter check --- app/engine/Flywheel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/engine/Flywheel.js b/app/engine/Flywheel.js index 565db81ac1..ee2e4d8448 100644 --- a/app/engine/Flywheel.js +++ b/app/engine/Flywheel.js @@ -29,7 +29,7 @@ const log = loglevel.getLogger('RowingEngine') function createFlywheel (rowerSettings) { const angularDisplacementPerImpulse = (2.0 * Math.PI) / rowerSettings.numOfImpulsesPerRevolution - const flankLength = Math.max(3, rowerSettings.flankLength) + const flankLength = rowerSettings.flankLength const minimumDragFactorSamples = Math.floor(rowerSettings.minimumRecoveryTime / rowerSettings.maximumTimeBetweenImpulses) const minumumTorqueBeforeStroke = rowerSettings.minumumForceBeforeStroke * (rowerSettings.sprocketRadius / 100) const currentDt = createStreamFilter(rowerSettings.smoothing, rowerSettings.maximumTimeBetweenImpulses) From fb64547e307890bb4a5c447fad032610871f3bc4 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Thu, 12 Jan 2023 12:25:06 +0100 Subject: [PATCH 014/209] Allowed the config check to repair settings Added the ability to automatically fix forgotten or implausible settings when possible. --- app/tools/ConfigManager.js | 195 +++++++++++++++++++------------------ 1 file changed, 98 insertions(+), 97 deletions(-) diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index 12fe1d3c75..3bc3a5b20e 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -3,6 +3,7 @@ Open Rowing Monitor, https://github.com/laberning/openrowingmonitor Merges the different config files and presents the configuration to the application + Checks the config for plausibilit, fixes the errors when needed */ import defaultConfig from '../../config/default.config.js' import { deepMerge } from './Helper.js' @@ -17,86 +18,87 @@ async function getConfig () { } function checkConfig (configToCheck) { - checkRangeValue(configToCheck.loglevel.default, 'loglevel.default', ['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') - checkRangeValue(configToCheck.loglevel.RowingEngine, 'loglevel.RowingEngine', ['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') - checkIntegerValue(configToCheck.gpioPin, 'gpioPin', 1, 27, false, false, null) - checkIntegerValue(configToCheck.gpioPriority, 'gpioPriority', -7, 0, true, true, 0) - checkIntegerValue(configToCheck.gpioMinimumPulseLength, 'gpioMinimumPulseLength', 1, 100000, false, true, 0) - checkIntegerValue(configToCheck.gpioPollingInterval, 'gpioPollingInterval', 1, 10, false, true, 10) - checkRangeValue(configToCheck.gpioPollingInterval, 'gpioPollingInterval', [1, 2, 5, 10], true, 10) - checkRangeValue(configToCheck.gpioTriggeredFlank, 'gpioTriggeredFlank', ['Up', 'Down', 'Both'], false, null) - checkIntegerValue(configToCheck.appPriority, 'appPriority', configToCheck.gpioPriority, 0, true, true, 0) - checkIntegerValue(configToCheck.webUpdateInterval, 'webUpdateInterval', 80, 1000, false, true, 1000) - checkBinaryValue(configToCheck.heartrateMonitorBLE, 'heartrateMonitorBLE', true, true) - checkBinaryValue(configToCheck.heartrateMonitorANT, 'heartrateMonitorANT', true, false) - checkRangeValue(configToCheck.bluetoothMode, 'bluetoothMode', ['off', 'PM5', 'FTMS', 'FTMSBIKE', 'CPS', 'CSC'], true, 'FTMS') - checkIntegerValue(configToCheck.peripheralUpdateInterval, 'peripheralUpdateInterval', 80, 1000, false, true, 1000) - checkIntegerValue(configToCheck.numOfPhasesForAveragingScreenData, 'numOfPhasesForAveragingScreenData', 2, null, false, true, 4) - checkBinaryValue(configToCheck.createRowingDataFiles, 'createRowingDataFiles', true, true) - checkBinaryValue(configToCheck.createRawDataFiles, 'createRawDataFiles', true, true) - checkBinaryValue(configToCheck.gzipRawDataFiles, 'gzipRawDataFiles', true, false) - checkBinaryValue(configToCheck.createTcxFiles, 'createTcxFiles', true, true) - checkBinaryValue(configToCheck.gzipTcxFiles, 'gzipTcxFiles', true, false) - checkFloatValue(configToCheck.userSettings.restingHR, 'userSettings.restingHR', 30, 220, false, true, 40) - checkFloatValue(configToCheck.userSettings.maxHR, 'userSettings.maxHR', configToCheck.userSettings.restingHR, 220, false, true, 220) + checkRangeValue(configToCheck.loglevel, 'default', ['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') + checkRangeValue(configToCheck.loglevel, 'RowingEngine', ['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') + checkIntegerValue(configToCheck, 'gpioPin', 1, 27, false, false, null) + checkIntegerValue(configToCheck, 'gpioPriority', -7, 0, true, true, 0) + checkIntegerValue(configToCheck, 'gpioMinimumPulseLength', 1, 100000, false, true, 0) + checkIntegerValue(configToCheck, 'gpioPollingInterval', 1, 10, false, true, 10) + checkRangeValue(configToCheck, 'gpioPollingInterval', [1, 2, 5, 10], true, 10) + checkRangeValue(configToCheck, 'gpioTriggeredFlank', ['Up', 'Down', 'Both'], false, null) + checkIntegerValue(configToCheck, 'appPriority', configToCheck.gpioPriority, 0, true, true, 0) + checkIntegerValue(configToCheck, 'webUpdateInterval', 80, 1000, false, true, 1000) + checkBinaryValue(configToCheck, 'heartrateMonitorBLE', true, true) + checkBinaryValue(configToCheck, 'heartrateMonitorANT', true, false) + checkRangeValue(configToCheck, 'bluetoothMode', ['off', 'PM5', 'FTMS', 'FTMSBIKE', 'CPS', 'CSC'], true, 'FTMS') + checkIntegerValue(configToCheck, 'peripheralUpdateInterval', 80, 1000, false, true, 1000) + checkIntegerValue(configToCheck, 'numOfPhasesForAveragingScreenData', 2, null, false, true, 4) + checkBinaryValue(configToCheck, 'createRowingDataFiles', true, true) + checkBinaryValue(configToCheck, 'createRawDataFiles', true, true) + checkBinaryValue(configToCheck, 'gzipRawDataFiles', true, false) + checkBinaryValue(configToCheck, 'createTcxFiles', true, true) + checkBinaryValue(configToCheck, 'gzipTcxFiles', true, false) + checkFloatValue(configToCheck.userSettings, 'restingHR', 30, 220, false, true, 40) + checkFloatValue(configToCheck.userSettings, 'maxHR', configToCheck.userSettings.restingHR, 220, false, true, 220) if (configToCheck.createTcxFiles) { - checkFloatValue(configToCheck.userSettings.minPower, 'userSettings.minPower', 1, 500, false, true, 50) - checkFloatValue(configToCheck.userSettings.maxPower, 'userSettings.maxPower', 100, 6000, false, true, 500) - checkFloatValue(configToCheck.userSettings.distanceCorrectionFactor, 'userSettings.distanceCorrectionFactor', 0, 50, false, true, 5) - checkFloatValue(configToCheck.userSettings.weight, 'userSettings.weight', 25, 500, false, true, 80) - checkRangeValue(configToCheck.userSettings.sex, 'userSettings.sex', ['male', 'female'], true, 'male') - checkBinaryValue(configToCheck.userSettings.highlyTrained, 'userSettings.highlyTrained', true, false) + checkFloatValue(configToCheck.userSettings, 'minPower', 1, 500, false, true, 50) + checkFloatValue(configToCheck.userSettings, 'maxPower', 100, 6000, false, true, 500) + checkFloatValue(configToCheck.userSettings, 'distanceCorrectionFactor', 0, 50, false, true, 5) + checkFloatValue(configToCheck.userSettings, 'weight', 25, 500, false, true, 80) + checkRangeValue(configToCheck.userSettings, 'sex', ['male', 'female'], true, 'male') + checkBinaryValue(configToCheck.userSettings, 'highlyTrained', true, false) } - checkIntegerValue(configToCheck.rowerSettings.numOfImpulsesPerRevolution, 'rowerSettings.numOfImpulsesPerRevolution', 1, null, false, false, null) - checkIntegerValue(configToCheck.rowerSettings.flankLength, 'rowerSettings.flankLength', 3, null, false, false, null) - checkFloatValue(configToCheck.rowerSettings.sprocketRadius, 'rowerSettings.sprocketRadius', 0, 20, false, true, 3) - checkFloatValue(configToCheck.rowerSettings.minimumTimeBetweenImpulses, 'rowerSettings.minimumTimeBetweenImpulses', 0, 3, false, false, null) - checkFloatValue(configToCheck.rowerSettings.maximumTimeBetweenImpulses, 'rowerSettings.maximumTimeBetweenImpulses', configToCheck.rowerSettings.minimumTimeBetweenImpulses, 3, false, false, null) - checkFloatValue(configToCheck.rowerSettings.smoothing, 'rowerSettings.smoothing', 1, 1000000, false, true, 1) - checkFloatValue(configToCheck.rowerSettings.dragFactor, 'rowerSettings.dragFactor', 1, 1000000, false, false, null) - checkBinaryValue(configToCheck.rowerSettings.autoAdjustDragFactor, 'rowerSettings.autoAdjustDragFactor', true, false) - checkIntegerValue(configToCheck.rowerSettings.dragFactorSmoothing, 'rowerSettings.dragFactorSmoothing', 1, 1000, false, true, 1) + checkIntegerValue(configToCheck.rowerSettings, 'numOfImpulsesPerRevolution', 1, null, false, false, null) + checkIntegerValue(configToCheck.rowerSettings, 'flankLength', 3, null, false, false, null) + checkFloatValue(configToCheck.rowerSettings, 'sprocketRadius', 0, 20, false, true, 3) + checkFloatValue(configToCheck.rowerSettings, 'minimumTimeBetweenImpulses', 0, 3, false, false, null) + checkFloatValue(configToCheck.rowerSettings, 'maximumTimeBetweenImpulses', configToCheck.rowerSettings.minimumTimeBetweenImpulses, 3, false, false, null) + checkFloatValue(configToCheck.rowerSettings, 'smoothing', 1, 1000000, false, true, 1) + checkFloatValue(configToCheck.rowerSettings, 'dragFactor', 1, 1000000, false, false, null) + checkBinaryValue(configToCheck.rowerSettings, 'autoAdjustDragFactor', true, false) + checkIntegerValue(configToCheck.rowerSettings, 'dragFactorSmoothing', 1, 1000, false, true, 1) if (configToCheck.rowerSettings.autoAdjustDragFactor) { - checkFloatValue(configToCheck.rowerSettings.minimumDragQuality, 'rowerSettings.minimumDragQuality', 0, 1, true, true, 0) + checkFloatValue(configToCheck.rowerSettings, 'minimumDragQuality', 0, 1, true, true, 0) } - checkFloatValue(configToCheck.rowerSettings.flywheelInertia, 'rowerSettings.flywheelInertia', 0, 2, false, false, null) - checkFloatValue(configToCheck.rowerSettings.minumumForceBeforeStroke, 'rowerSettings.minumumForceBeforeStroke', 0, 500, true, true, 0) - checkFloatValue(configToCheck.rowerSettings.minumumRecoverySlope, 'rowerSettings.minumumRecoverySlope', 0, 2, true, true, 0) - checkFloatValue(configToCheck.rowerSettings.minimumStrokeQuality, 'rowerSettings.minimumStrokeQuality', 0, 1, true, true, 0) - checkBinaryValue(configToCheck.rowerSettings.autoAdjustRecoverySlope, 'rowerSettings.autoAdjustRecoverySlope', true, false) + checkFloatValue(configToCheck.rowerSettings, 'flywheelInertia', 0, null, false, false, null) + checkFloatValue(configToCheck.rowerSettings, 'minumumForceBeforeStroke', 0, 500, true, true, 0) + checkFloatValue(configToCheck.rowerSettings, 'minumumRecoverySlope', 0, null, true, true, 0) + checkFloatValue(configToCheck.rowerSettings, 'minimumStrokeQuality', 0, 1, true, true, 0) + checkBinaryValue(configToCheck.rowerSettings, 'autoAdjustRecoverySlope', true, false) if (!configToCheck.rowerSettings.autoAdjustDragFactor && configToCheck.rowerSettings.autoAdjustRecoverySlope) { - log.error('Configuration Error: rowerSettings.autoAdjustRecoverySlope can not be true when configToCheck.rowerSettings.autoAdjustDragFactor is false, ignoring request') + log.error('Configuration Error: rowerSettings.autoAdjustRecoverySlope can not be true when rowerSettings.autoAdjustDragFactor is false, ignoring request') } if (configToCheck.rowerSettings.autoAdjustDragFactor && configToCheck.rowerSettings.autoAdjustRecoverySlope) { - checkFloatValue(configToCheck.rowerSettings.autoAdjustRecoverySlopeMargin, 'autoAdjustRecoverySlopeMargin', 0, 1, false, true, 1) + checkFloatValue(configToCheck.rowerSettings, 'autoAdjustRecoverySlopeMargin', 0, 1, false, true, 1) } - checkFloatValue(configToCheck.rowerSettings.minimumDriveTime, 'rowerSettings.minimumDriveTime', 0, 6, false, true, 0.001) - checkFloatValue(configToCheck.rowerSettings.minimumRecoveryTime, 'rowerSettings.minimumRecoveryTime', 0, 6, false, true, 0.001) - checkFloatValue(configToCheck.rowerSettings.maximumStrokeTimeBeforePause, 'rowerSettings.maximumStrokeTimeBeforePause', 3, 60, false, true, 6) - checkFloatValue(configToCheck.rowerSettings.magicConstant, 'rowerSettings.magicConstant', 0, 28, false, true, 2.8) + checkFloatValue(configToCheck.rowerSettings, 'minimumDriveTime', 0, null, false, true, 0.001) + checkFloatValue(configToCheck.rowerSettings, 'minimumRecoveryTime', 0, null, false, true, 0.001) + checkFloatValue(configToCheck.rowerSettings, 'maximumStrokeTimeBeforePause', 3, 60, false, true, 6) + checkFloatValue(configToCheck.rowerSettings, 'magicConstant', 0, null, false, true, 2.8) } -function checkIntegerValue (parameter, parameterName, minimumValue, maximumvalue, allowZero, allowRepair, defaultValue) { +function checkIntegerValue (parameterSection, parameterName, minimumValue, maximumvalue, allowZero, allowRepair, defaultValue) { + // PLEASE NOTE: the parameterSection, parameterName seperation is needed to force a call by reference, which is needed for the repair action let errors = 0 switch (true) { - case (parameter === undefined): - log.error(`Configuration Error: ${parameterName} isn't defined`) + case (parameterSection[parameterName] === undefined): + log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) errors++ break - case (!Number.isInteger(parameter)): - log.error(`Configuration Error: ${parameterName} should be an integer value, encountered ${parameter}`) + case (!Number.isInteger(parameterSection[parameterName])): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be an integer value, encountered ${parameterSection[parameterName]}`) errors++ break - case (minimumValue != null && parameter < minimumValue): - log.error(`Configuration Error: ${parameterName} should be at least ${minimumValue}, encountered ${parameter}`) + case (minimumValue != null && parameterSection[parameterName] < minimumValue): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be at least ${minimumValue}, encountered ${parameterSection[parameterName]}`) errors++ break - case (maximumvalue != null && parameter > maximumvalue): - log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) + case (maximumvalue != null && parameterSection[parameterName] > maximumvalue): + log.error(`Configuration Error: ${parameterSection}.${parameterName} can't be above ${maximumvalue}, encountered ${parameterSection[parameterName]}`) errors++ break - case (!allowZero && parameter === 0): - log.error(`Configuration Error: ${parameterName} can't be zero`) + case (!allowZero && parameterSection[parameterName] === 0): + log.error(`Configuration Error: ${parameterSection}.${parameterName} can't be zero`) errors++ break default: @@ -105,37 +107,37 @@ function checkIntegerValue (parameter, parameterName, minimumValue, maximumvalue if (errors > 0) { // Errors were made if (allowRepair) { - log.error(` resolved by setting ${parameterName} to ${defaultValue}`) - // ToDo: fix this by making the function call a call by reference!!! - parameter = defaultValue + log.error(` resolved by setting ${parameterSection}.${parameterName} to ${defaultValue}`) + parameterSection[parameterName] = defaultValue } else { - log.error(`As ${parameterName} is a fatal parameter, I'm exiting`) + log.error(` as ${parameterSection}.${parameterName} is a fatal parameter, I'm exiting`) process.exit(9) } } } -function checkFloatValue (parameter, parameterName, minimumValue, maximumvalue, allowZero, allowRepair, defaultValue) { +function checkFloatValue (parameterSection, parameterName, minimumValue, maximumvalue, allowZero, allowRepair, defaultValue) { + // PLEASE NOTE: the parameterSection, parameterName seperation is needed to force a call by reference, which is needed for the repair action let errors = 0 switch (true) { - case (parameter === undefined): - log.error(`Configuration Error: ${parameterName} isn't defined`) + case (parameterSection[parameterName] === undefined): + log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) errors++ break - case (!typeof (parameter) === 'number'): - log.error(`Configuration Error: ${parameterName} should be a numerical value, encountered ${parameter}`) + case (!typeof (parameterSection[parameterName]) === 'number'): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be a numerical value, encountered ${parameterSection[parameterName]}`) errors++ break - case (minimumValue != null && parameter < minimumValue): - log.error(`Configuration Error: ${parameterName} should be at least ${minimumValue}, encountered ${parameter}`) + case (minimumValue != null && parameterSection[parameterName] < minimumValue): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be at least ${minimumValue}, encountered ${parameterSection[parameterName]}`) errors++ break - case (maximumvalue != null && parameter > maximumvalue): - log.error(`Configuration Error: ${parameterName} can't be above ${maximumvalue}, encountered ${parameter}`) + case (maximumvalue != null && parameterSection[parameterName] > maximumvalue): + log.error(`Configuration Error: ${parameterSection}.${parameterName} can't be above ${maximumvalue}, encountered ${parameterSection[parameterName]}`) errors++ break - case (!allowZero && parameter === 0): - log.error(`Configuration Error: ${parameterName} can't be zero`) + case (!allowZero && parameterSection[parameterName] === 0): + log.error(`Configuration Error: ${parameterSection}.${parameterName} can't be zero`) errors++ break default: @@ -144,25 +146,25 @@ function checkFloatValue (parameter, parameterName, minimumValue, maximumvalue, if (errors > 0) { // Errors were made if (allowRepair) { - log.error(` resolved by setting ${parameterName} to ${defaultValue}`) - // ToDo: fix this by making the function call a call by reference!!! - parameter = defaultValue + log.error(` resolved by setting ${parameterSection}.${parameterName} to ${defaultValue}`) + parameterSection[parameterName] = defaultValue } else { - log.error(`As ${parameterName} is a fatal parameter, I'm exiting`) + log.error(` as ${parameterSection}.${parameterName} is a fatal parameter, I'm exiting`) process.exit(9) } } } -function checkBinaryValue (parameter, parameterName, allowRepair, defaultValue) { +function checkBinaryValue (parameterSection, parameterName, allowRepair, defaultValue) { + // PLEASE NOTE: the parameterSection, parameterName seperation is needed to force a call by reference, which is needed for the repair action let errors = 0 switch (true) { - case (parameter === undefined): - log.error(`Configuration Error: ${parameterName} isn't defined`) + case (parameterSection[parameterName] === undefined): + log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) errors++ break - case (!(parameter === true || parameter === false)): - log.error(`Configuration Error: ${parameterName} should be either false or true, encountered ${parameter}`) + case (!(parameterSection[parameterName] === true || parameterSection[parameterName] === false)): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be either false or true, encountered ${parameterSection[parameterName]}`) errors++ break default: @@ -171,25 +173,25 @@ function checkBinaryValue (parameter, parameterName, allowRepair, defaultValue) if (errors > 0) { // Errors were made if (allowRepair) { - log.error(` resolved by setting ${parameterName} to ${defaultValue}`) - // ToDo: fix this by making the function call a call by reference!!! - parameter = defaultValue + log.error(` resolved by setting ${parameterSection}.${parameterName} to ${defaultValue}`) + parameterSection[parameterName] = defaultValue } else { - log.error(`As ${parameterName} is a fatal parameter, I'm exiting`) + log.error(` as ${parameterSection}.${parameterName} is a fatal parameter, I'm exiting`) process.exit(9) } } } -function checkRangeValue (parameter, parameterName, range, allowRepair, defaultValue) { +function checkRangeValue (parameterSection, parameterName, range, allowRepair, defaultValue) { + // PLEASE NOTE: the parameterSection, parameterName seperation is needed to force a call by reference, which is needed for the repair action let errors = 0 switch (true) { - case (parameter === undefined): - log.error(`Configuration Error: ${parameterName} isn't defined`) + case (parameterSection[parameterName] === undefined): + log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) errors++ break - case (!range.includes(parameter)): - log.error(`Configuration Error: ${parameterName} should be come from ${range}, encountered ${parameter}`) + case (!range.includes(parameterSection[parameterName])): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be come from ${range}, encountered ${parameterSection[parameterName]}`) errors++ break default: @@ -198,11 +200,10 @@ function checkRangeValue (parameter, parameterName, range, allowRepair, defaultV if (errors > 0) { // Errors were made if (allowRepair) { - log.error(` resolved by setting ${parameterName} to ${defaultValue}`) - // ToDo: fix this by making the function call a call by reference!!! - parameter = defaultValue + log.error(` resolved by setting ${parameterSection}.${parameterName} to ${defaultValue}`) + parameterSection[parameterName] = defaultValue } else { - log.error(`As ${parameterName} is a fatal parameter, I'm exiting`) + log.error(` as ${parameterSection}.${parameterName} is a fatal parameter, I'm exiting`) process.exit(9) } } From fcb3944848e2fb6ac15d999a0cc52cd5c1bf00f4 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Thu, 12 Jan 2023 12:28:27 +0100 Subject: [PATCH 015/209] Removed some artificial limits --- app/tools/ConfigManager.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index 3bc3a5b20e..afe90676a7 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -22,7 +22,7 @@ function checkConfig (configToCheck) { checkRangeValue(configToCheck.loglevel, 'RowingEngine', ['trace', 'debug', 'info', 'warn', 'error', 'silent'], true, 'error') checkIntegerValue(configToCheck, 'gpioPin', 1, 27, false, false, null) checkIntegerValue(configToCheck, 'gpioPriority', -7, 0, true, true, 0) - checkIntegerValue(configToCheck, 'gpioMinimumPulseLength', 1, 100000, false, true, 0) + checkIntegerValue(configToCheck, 'gpioMinimumPulseLength', 1, null, false, true, 0) checkIntegerValue(configToCheck, 'gpioPollingInterval', 1, 10, false, true, 10) checkRangeValue(configToCheck, 'gpioPollingInterval', [1, 2, 5, 10], true, 10) checkRangeValue(configToCheck, 'gpioTriggeredFlank', ['Up', 'Down', 'Both'], false, null) @@ -53,10 +53,10 @@ function checkConfig (configToCheck) { checkFloatValue(configToCheck.rowerSettings, 'sprocketRadius', 0, 20, false, true, 3) checkFloatValue(configToCheck.rowerSettings, 'minimumTimeBetweenImpulses', 0, 3, false, false, null) checkFloatValue(configToCheck.rowerSettings, 'maximumTimeBetweenImpulses', configToCheck.rowerSettings.minimumTimeBetweenImpulses, 3, false, false, null) - checkFloatValue(configToCheck.rowerSettings, 'smoothing', 1, 1000000, false, true, 1) - checkFloatValue(configToCheck.rowerSettings, 'dragFactor', 1, 1000000, false, false, null) + checkFloatValue(configToCheck.rowerSettings, 'smoothing', 1, null, false, true, 1) + checkFloatValue(configToCheck.rowerSettings, 'dragFactor', 1, null, false, false, null) checkBinaryValue(configToCheck.rowerSettings, 'autoAdjustDragFactor', true, false) - checkIntegerValue(configToCheck.rowerSettings, 'dragFactorSmoothing', 1, 1000, false, true, 1) + checkIntegerValue(configToCheck.rowerSettings, 'dragFactorSmoothing', 1, null, false, true, 1) if (configToCheck.rowerSettings.autoAdjustDragFactor) { checkFloatValue(configToCheck.rowerSettings, 'minimumDragQuality', 0, 1, true, true, 0) } From 94a2aad8405e67eee9c8d2de1d465c4e09ec5512 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 17:07:48 +0100 Subject: [PATCH 016/209] Added logic for more complex workouts Added logic for more complex workouts: RowingStatistics will handle this completely independently --- app/server.js | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/app/server.js b/app/server.js index 49f87a712a..a63af5c7c4 100644 --- a/app/server.js +++ b/app/server.js @@ -47,11 +47,27 @@ if (config.appPriority) { // Hopefully this will be filled through the WebGUI or through the BLE interface (PM5-BLE can do this...) // When set, ORM will terminate the session after reaching the target. If not set, it will behave as usual (a "Just row" session). // When set, the GUI will behave similar to a PM5 in that it counts down from the target to 0 -const session = { - targetDistance: 0, // Target distance in meters - targetTime: 0 // Target time in seconds +const intervalSettings = [] + +/* an example of the workout setting that RowingStatistics will obey: a 1 minute warmup, a 2K timed piece followed by a 1 minute cooldown +// This should normally come from the PM5 interface or the webinterface +intervalSettings[0] = { + targetDistance: 0, + targetTime: 60 +} + +/* Additional intervals for testing +intervalSettings[1] = { + targetDistance: 2000, + targetTime: 0 } +intervalSettings[2] = { + targetDistance: 0, + targetTime: 60 +} +*/ + log.info(`Session settings: distance limit: ${(session.targetDistance > 0 ? `${session.targetDistance} meters` : 'none')}, time limit: ${(session.targetTime > 0 ? `${session.targetTime} seconds` : 'none')}\n`) const peripheralManager = createPeripheralManager() @@ -120,7 +136,15 @@ function handleRotationImpulse (dataPoint) { rowingStatistics.handleRotationImpulse(dataPoint) } -const rowingStatistics = createRowingStatistics(config, session) +const rowingStatistics = createRowingStatistics(config) +if (intervalSettings.length > 0) { + // There is an interval defined at startup, let's inform RowingStatistics + // ToDo: update these settings when the PM5 or webinterface tells us to + rowingStatistics.setIntervalParameters(intervalSettings) +} else { + log.info('Starting a just row session, no time or distance target set') +} + const workoutRecorder = createWorkoutRecorder() const workoutUploader = createWorkoutUploader(workoutRecorder) @@ -153,11 +177,11 @@ rowingStatistics.on('rowingPaused', (metrics) => { }) rowingStatistics.on('intervalTargetReached', (metrics) => { - // This is called when the RowingStatistics conclude the target is reached - // This isn't the most optimal solution yet, as this interval is the only one set. A logcal extansion would be - // to provide a next intervaltarget. Thus, the use case of a next interval has to be implemented as well - // (i.e. setting a new interval target). For now, this interval is the one and only so we stop. - stopWorkout() + // This is called when the RowingStatistics conclude the intervaltarget is reached + // Update all screens to reflect this change, as targetTime and targetDistance have changed + // ToDo: recording this event in the recordings accordingly should be done as well + webServer.notifyClients('metrics', metrics) + peripheralManager.notifyMetrics('metricsUpdate', metrics) }) rowingStatistics.on('rowingStopped', (metrics) => { From 37edd0290b7bcf99d49e0702bb85c814f24169dd Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 17:29:58 +0100 Subject: [PATCH 017/209] Update to facilitate more complex workouts Update to facilitate more complex workouts. RowingStatistics will now manage the intervals completely independently and alert server.js only when the session has ended. --- app/engine/RowingStatistics.js | 101 +++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 18 deletions(-) diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index de4d10c939..dc2b0e8cbf 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -13,7 +13,7 @@ import { createCurveAligner } from './utils/CurveAligner.js' import loglevel from 'loglevel' const log = loglevel.getLogger('RowingEngine') -function createRowingStatistics (config, session) { +function createRowingStatistics (config) { const numOfDataPointsForAveraging = config.numOfPhasesForAveragingScreenData const webUpdateInterval = config.webUpdateInterval const peripheralUpdateInterval = config.peripheralUpdateInterval @@ -26,6 +26,12 @@ function createRowingStatistics (config, session) { const cyclePower = createStreamFilter(numOfDataPointsForAveraging, 0) const cycleLinearVelocity = createStreamFilter(numOfDataPointsForAveraging, 0) let sessionStatus = 'WaitingForStart' + let intervalSettings = [] + let currentIntervalNumber = -1 + let intervalTargetDistance = 0 + let intervalTargetTime = 0 + let intervalPrevAccumulatedDistance = 0 + let intervalPrevAccumulatedTime = 0 let heartrateResetTimer let totalLinearDistance = 0.0 let totalMovingTime = 0 @@ -91,7 +97,7 @@ function createRowingStatistics (config, session) { updateContinousMetrics() updateCycleMetrics() handleRecoveryEnd() - emitMetrics('intervalTargetReached') + handleIntervalEnd() break case (sessionStatus === 'Rowing' && lastStrokeState === 'Recovery' && rower.strokeState() === 'Drive'): updateContinousMetrics() @@ -103,7 +109,7 @@ function createRowingStatistics (config, session) { updateContinousMetrics() updateCycleMetrics() handleDriveEnd() - emitMetrics('intervalTargetReached') + handleIntervalEnd() break case (sessionStatus === 'Rowing' && lastStrokeState === 'Drive' && rower.strokeState() === 'Recovery'): updateContinousMetrics() @@ -113,7 +119,7 @@ function createRowingStatistics (config, session) { break case (sessionStatus === 'Rowing' && intervalTargetReached()): updateContinousMetrics() - emitMetrics('intervalTargetReached') + handleIntervalEnd() break case (sessionStatus === 'Rowing'): updateContinousMetrics() @@ -181,6 +187,12 @@ function createRowingStatistics (config, session) { rower.allowMovement() totalMovingTime = 0 totalLinearDistance = 0.0 + intervalSettings = [] + currentIntervalNumber = -1 + intervalTargetDistance = 0 + intervalTargetTime = 0 + intervalPrevAccumulatedDistance = 0 + intervalPrevAccumulatedTime = 0 totalNumberOfStrokes = -1 driveLastStartTime = 0 distanceOverTime.reset() @@ -242,6 +254,63 @@ function createRowingStatistics (config, session) { calories.push(totalMovingTime, totalCalories) } + function setIntervalParameters (intervalParameters) { + intervalSettings = intervalParameters + currentIntervalNumber = -1 + if (intervalSettings.length > 0) { + log.info(`Workout recieved with ${intervalSettings.length} interval(s)`) + activateNextIntervalParameters() + } else { + // intervalParameters were empty, lets log this odd situation + log.error('Recieved workout containing no intervals') + } + } + + function intervalTargetReached () { + // This tests wether the end of the current interval is reached + if ((intervalTargetDistance > 0 && rower.totalLinearDistanceSinceStart() >= intervalTargetDistance) || (intervalTargetTime > 0 && rower.totalMovingTimeSinceStart() >= intervalTargetTime)) { + return true + } else { + return false + } + } + + function handleIntervalEnd () { + // initiated when the state machine has concluded the interval has ended + if (intervalSettings.length > 0 && intervalSettings.length > (currentIntervalNumber + 1)) { + // There is a next interval available + emitMetrics('intervalTargetReached') + activateNextIntervalParameters() + } else { + // There is no additional interval available + stopTraining () + } + } + + function activateNextIntervalParameters () { + if (intervalSettings.length > 0 && intervalSettings.length > (currentIntervalNumber + 1)) { + // This function sets the interval parameters in absolute distances/times + // Thus the interval target always is a projected "finishline" from the current position + intervalPrevAccumulatedTime = rower.totalMovingTimeSinceStart() + intervalPrevAccumulatedDistance = rower.totalLinearDistanceSinceStart() + + currentIntervalNumber++ + if (intervalSettings[currentIntervalNumber].targetDistance > 0) { + // A target distance is set + intervalTargetTime = 0 + intervalTargetDistance = intervalPrevAccumulatedDistance + intervalSettings[currentIntervalNumber].targetDistance + log.info(`Interval settings for interval ${currentIntervalNumber + 1} of ${intervalSettings.length}: Distance target ${intervalSettings[currentIntervalNumber].targetDistance} meters`) + } else { + // A target time is set + intervalTargetTime = intervalPrevAccumulatedTime + intervalSettings[currentIntervalNumber].targetTime + intervalTargetDistance = 0 + log.info(`Interval settings for interval ${currentIntervalNumber + 1} of ${intervalSettings.length}: time target ${secondsToTimeString(intervalSettings[currentIntervalNumber].targetTime)} minutes`) + } + } else { + log.error('Interval error: there is no next interval!') + } + } + // initiated when a new heart rate value is received from heart rate sensor function handleHeartrateMeasurement (value) { // set the heart rate to zero if we did not receive a value for some time @@ -254,14 +323,6 @@ function createRowingStatistics (config, session) { heartrateBatteryLevel = value.batteryLevel } - function intervalTargetReached () { - if ((session.targetDistance > 0 && rower.totalLinearDistanceSinceStart() >= session.targetDistance) || (session.targetTime > 0 && rower.totalMovingTimeSinceStart() >= session.targetTime)) { - return true - } else { - return false - } - } - function measureRecoveryHR () { // This function is called when the rowing session is stopped. postExerciseHR[0] is the last measured excercise HR // Thus postExerciseHR[1] is Recovery HR after 1 min, etc.. @@ -298,11 +359,13 @@ function createRowingStatistics (config, session) { sessionStatus, strokeState: rower.strokeState(), totalMovingTime: totalMovingTime > 0 ? totalMovingTime : 0, - driveLastStartTime: driveLastStartTime > 0 ? driveLastStartTime : 0, - totalMovingTimeFormatted: session.targetTime > 0 ? secondsToTimeString(Math.round(Math.max(session.targetTime - totalMovingTime, 0))) : secondsToTimeString(Math.round(totalMovingTime)), + totalMovingTimeFormatted: intervalTargetTime > 0 ? secondsToTimeString(Math.round(Math.max(intervalTargetTime - totalMovingTime, 0))) : secondsToTimeString(Math.round(totalMovingTime - intervalPrevAccumulatedTime)), totalNumberOfStrokes: totalNumberOfStrokes > 0 ? totalNumberOfStrokes : 0, totalLinearDistance: totalLinearDistance > 0 ? totalLinearDistance : 0, // meters - totalLinearDistanceFormatted: session.targetDistance > 0 ? Math.max(session.targetDistance - totalLinearDistance, 0) : totalLinearDistance, + totalLinearDistanceFormatted: intervalTargetDistance > 0 ? Math.max(intervalTargetDistance - totalLinearDistance, 0) : totalLinearDistance - intervalPrevAccumulatedDistance, + intervalNumber: Math.max(currentIntervalNumber + 1, 0), // Interval number + intervalMovingTime: totalMovingTime - intervalPrevAccumulatedTime, + intervalLinearDistance: totalLinearDistance - intervalPrevAccumulatedDistance, strokeCalories: strokeCalories > 0 ? strokeCalories : 0, // kCal strokeWork: strokeWork > 0 ? strokeWork : 0, // Joules totalCalories: calories.yAtSeriesEnd() > 0 ? calories.yAtSeriesEnd() : 0, // kcal @@ -312,11 +375,12 @@ function createRowingStatistics (config, session) { cycleStrokeRate: cycleDuration.clean() > minimumStrokeTime && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? (60.0 / cycleDuration.clean()) : 0, // strokeRate in SPM cycleDistance: cycleDistance.raw() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cycleDistance.clean() : 0, // meters cycleLinearVelocity: cycleLinearVelocity.clean() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cycleLinearVelocity.clean() : 0, // m/s - cyclePace: cycleLinearVelocity.raw() > 0 ? cyclePace : Infinity, // seconds/500m + cyclePace: cycleLinearVelocity.raw() > 0 ? cyclePace : Infinity, // seconds/50 0m cyclePaceFormatted: cycleLinearVelocity.raw() > 0 ? secondsToTimeString(Math.round(cyclePace)) : Infinity, cyclePower: cyclePower.clean() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cyclePower.clean() : 0, // watts - cycleProjectedEndTime: session.targetDistance > 0 ? distanceOverTime.projectY(session.targetDistance) : session.targetTime, - cycleProjectedEndLinearDistance: session.targetTime > 0 ? distanceOverTime.projectX(session.targetTime) : session.targetDistance, + cycleProjectedEndTime: intervalTargetDistance > 0 ? distanceOverTime.projectY(intervalTargetDistance) : intervalTargetTime, + cycleProjectedEndLinearDistance: intervalTargetTime > 0 ? distanceOverTime.projectX(intervalTargetTime) : intervalTargetDistance, + driveLastStartTime: driveLastStartTime > 0 ? driveLastStartTime : 0, driveDuration: driveDuration.clean() >= config.rowerSettings.minimumDriveTime && totalNumberOfStrokes > 0 && sessionStatus === 'Rowing' ? driveDuration.clean() : NaN, // seconds driveLength: driveLength.clean() > 0 && sessionStatus === 'Rowing' ? driveLength.clean() : NaN, // meters of chain movement driveDistance: driveDistance.clean() >= 0 && sessionStatus === 'Rowing' ? driveDistance.clean() : NaN, // meters @@ -355,6 +419,7 @@ function createRowingStatistics (config, session) { return Object.assign(emitter, { handleHeartrateMeasurement, handleRotationImpulse, + setIntervalParameters, pause: pauseTraining, stop: stopTraining, resume: allowResumeTraining, From 1405b80bc7c008012323c4d3a0bfa8549c7869e7 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 17:31:28 +0100 Subject: [PATCH 018/209] Removal of surplus logging line --- app/server.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/server.js b/app/server.js index a63af5c7c4..ecdd20a75c 100644 --- a/app/server.js +++ b/app/server.js @@ -68,8 +68,6 @@ intervalSettings[2] = { } */ -log.info(`Session settings: distance limit: ${(session.targetDistance > 0 ? `${session.targetDistance} meters` : 'none')}, time limit: ${(session.targetTime > 0 ? `${session.targetTime} seconds` : 'none')}\n`) - const peripheralManager = createPeripheralManager() peripheralManager.on('control', (event) => { From e5696378b002621100625d78df48e729c3dcfa2e Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 17:34:25 +0100 Subject: [PATCH 019/209] Fixed a Lint error --- app/engine/RowingStatistics.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index dc2b0e8cbf..616b6cbb8f 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -283,7 +283,7 @@ function createRowingStatistics (config) { activateNextIntervalParameters() } else { // There is no additional interval available - stopTraining () + stopTraining() } } @@ -355,7 +355,7 @@ function createRowingStatistics (config) { function getMetrics () { const cyclePace = cycleLinearVelocity.clean() !== 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? (500.0 / cycleLinearVelocity.clean()) : Infinity return { - sessiontype: session.targetDistance > 0 ? 'Distance' : (session.targetTime > 0 ? 'Time' : 'JustRow'), + sessiontype: intervalTargetDistance > 0 ? 'Distance' : (intervalTargetTime > 0 ? 'Time' : 'JustRow'), sessionStatus, strokeState: rower.strokeState(), totalMovingTime: totalMovingTime > 0 ? totalMovingTime : 0, From 758f2d25ea67a42b55b13e7d3993d1dd9a34e06a Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 17:57:13 +0100 Subject: [PATCH 020/209] Added Intervals.icu compatibility Added Intervals.icu to the list of compatible users of tcx files. --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 6563cf8a79..069399301f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -49,7 +49,7 @@ Open Rowing Monitor also implements different Bluetooth Low Energy (BLE) protoco * **Concept2 PM**: Open Rowing Monitor implements part of the Concept2 PM Bluetooth Smart Communication Interface Definition. This is still work in progress and only implements the most common parts of the spec, so it is not guaranteed to work with all applications that support C2 rowing machines. Our interface currently can only report metrics, but can't recieve commands and session parameters from the app yet. It is known to work with [EXR](https://www.exrgame.com) and all the samples from [The Erg Arcade](https://ergarcade.com), for example you can [row in the clouds](https://ergarcade.github.io/mrdoob-clouds/). -* **FTMS Rower**: This is the FTMS profile for rowing machines and supports all rowing specific metrics (such as stroke rate). So far not many training applications for this profile exist, but the market is evolving. We've successfully tested it with [EXR](https://www.exrgame.com), [MyHomeFit](https://myhomefit.de) and [Kinomap](https://www.kinomap.com). +* **FTMS Rower**: This is the FTMS profile for rowing machines and supports all rowing specific metrics (such as stroke rate). So far not many training applications for this profile exist, but the market is evolving. We've successfully tested it with [EXR](https://www.exrgame.com) (preferred method), [MyHomeFit](https://myhomefit.de) and [Kinomap](https://www.kinomap.com). * **FTMS Indoor Bike**: This FTMS profile is used by Smart Bike Trainers and widely adopted by training applications for bike training. It does not support rowing specific metrics. But it can present metrics such as power and distance to the biking application and use cadence for stroke rate. So why not use your virtual rowing bike to row up a mountain in [Zwift](https://www.zwift.com), [Bkool](https://www.bkool.com), [The Sufferfest](https://thesufferfest.com) or similar :-) @@ -61,7 +61,7 @@ Open Rowing Monitor also implements different Bluetooth Low Energy (BLE) protoco Open Rowing Monitor is based on the idea that metrics should be easily accessible for further analysis. Therefore, Open Rowing Monitor can create the following files: -* **Training Center XML files (TCX)**: These are XML-files that contain the most essential metrics of a rowing session. Most training analysis tools will accept a tcx-file. You can upload these files to training platforms like [Strava](https://www.strava.com), [Garmin Connect](https://connect.garmin.com) or [Trainingpeaks](https://trainingpeaks.com) to track your training sessions; +* **Training Center XML files (TCX)**: These are XML-files that contain the most essential metrics of a rowing session. Most training analysis tools will accept a tcx-file. You can upload these files to training platforms like [Strava](https://www.strava.com), [Garmin Connect](https://connect.garmin.com), [Intervals.icu](https://intervals.icu/), [RowsAndAll](https://rowsandall.com/) or [Trainingpeaks](https://trainingpeaks.com) to track your training sessions; * **RowingData** files, which are comma-seperated files with all metrics Open Rowing Monitor can produce. These can be used with [RowingData](https://pypi.org/project/rowingdata/) to display your results locally, or uploaded to [RowsAndAll](https://rowsandall.com/) for a webbased analysis (including dynamic in-stroke metrics). The csv-files can also be processed manually in Excel, allowing your own custom analysis. Please note that for visualising in-stroke metrics in [RowsAndAll](https://rowsandall.com/) (i.e. force, power and handle speed curves), you need their yearly subscription; From f628a6e7914ac15fa8d32bb261f6f7579ae127cb Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 21:18:43 +0100 Subject: [PATCH 021/209] Updates to fix review comments Updates to fix review comments --- app/tools/ConfigManager.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index afe90676a7..afb2b3f541 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -28,16 +28,16 @@ function checkConfig (configToCheck) { checkRangeValue(configToCheck, 'gpioTriggeredFlank', ['Up', 'Down', 'Both'], false, null) checkIntegerValue(configToCheck, 'appPriority', configToCheck.gpioPriority, 0, true, true, 0) checkIntegerValue(configToCheck, 'webUpdateInterval', 80, 1000, false, true, 1000) - checkBinaryValue(configToCheck, 'heartrateMonitorBLE', true, true) - checkBinaryValue(configToCheck, 'heartrateMonitorANT', true, false) + checkBooleanValue(configToCheck, 'heartrateMonitorBLE', true, true) + checkBooleanValue(configToCheck, 'heartrateMonitorANT', true, false) checkRangeValue(configToCheck, 'bluetoothMode', ['off', 'PM5', 'FTMS', 'FTMSBIKE', 'CPS', 'CSC'], true, 'FTMS') checkIntegerValue(configToCheck, 'peripheralUpdateInterval', 80, 1000, false, true, 1000) checkIntegerValue(configToCheck, 'numOfPhasesForAveragingScreenData', 2, null, false, true, 4) - checkBinaryValue(configToCheck, 'createRowingDataFiles', true, true) - checkBinaryValue(configToCheck, 'createRawDataFiles', true, true) - checkBinaryValue(configToCheck, 'gzipRawDataFiles', true, false) - checkBinaryValue(configToCheck, 'createTcxFiles', true, true) - checkBinaryValue(configToCheck, 'gzipTcxFiles', true, false) + checkBooleanValue(configToCheck, 'createRowingDataFiles', true, true) + checkBooleanValue(configToCheck, 'createRawDataFiles', true, true) + checkBooleanValue(configToCheck, 'gzipRawDataFiles', true, false) + checkBooleanValue(configToCheck, 'createTcxFiles', true, true) + checkBooleanValue(configToCheck, 'gzipTcxFiles', true, false) checkFloatValue(configToCheck.userSettings, 'restingHR', 30, 220, false, true, 40) checkFloatValue(configToCheck.userSettings, 'maxHR', configToCheck.userSettings.restingHR, 220, false, true, 220) if (configToCheck.createTcxFiles) { @@ -46,7 +46,7 @@ function checkConfig (configToCheck) { checkFloatValue(configToCheck.userSettings, 'distanceCorrectionFactor', 0, 50, false, true, 5) checkFloatValue(configToCheck.userSettings, 'weight', 25, 500, false, true, 80) checkRangeValue(configToCheck.userSettings, 'sex', ['male', 'female'], true, 'male') - checkBinaryValue(configToCheck.userSettings, 'highlyTrained', true, false) + checkBooleanValue(configToCheck.userSettings, 'highlyTrained', true, false) } checkIntegerValue(configToCheck.rowerSettings, 'numOfImpulsesPerRevolution', 1, null, false, false, null) checkIntegerValue(configToCheck.rowerSettings, 'flankLength', 3, null, false, false, null) @@ -55,7 +55,7 @@ function checkConfig (configToCheck) { checkFloatValue(configToCheck.rowerSettings, 'maximumTimeBetweenImpulses', configToCheck.rowerSettings.minimumTimeBetweenImpulses, 3, false, false, null) checkFloatValue(configToCheck.rowerSettings, 'smoothing', 1, null, false, true, 1) checkFloatValue(configToCheck.rowerSettings, 'dragFactor', 1, null, false, false, null) - checkBinaryValue(configToCheck.rowerSettings, 'autoAdjustDragFactor', true, false) + checkBooleanValue(configToCheck.rowerSettings, 'autoAdjustDragFactor', true, false) checkIntegerValue(configToCheck.rowerSettings, 'dragFactorSmoothing', 1, null, false, true, 1) if (configToCheck.rowerSettings.autoAdjustDragFactor) { checkFloatValue(configToCheck.rowerSettings, 'minimumDragQuality', 0, 1, true, true, 0) @@ -64,7 +64,7 @@ function checkConfig (configToCheck) { checkFloatValue(configToCheck.rowerSettings, 'minumumForceBeforeStroke', 0, 500, true, true, 0) checkFloatValue(configToCheck.rowerSettings, 'minumumRecoverySlope', 0, null, true, true, 0) checkFloatValue(configToCheck.rowerSettings, 'minimumStrokeQuality', 0, 1, true, true, 0) - checkBinaryValue(configToCheck.rowerSettings, 'autoAdjustRecoverySlope', true, false) + checkBooleanValue(configToCheck.rowerSettings, 'autoAdjustRecoverySlope', true, false) if (!configToCheck.rowerSettings.autoAdjustDragFactor && configToCheck.rowerSettings.autoAdjustRecoverySlope) { log.error('Configuration Error: rowerSettings.autoAdjustRecoverySlope can not be true when rowerSettings.autoAdjustDragFactor is false, ignoring request') } @@ -124,7 +124,7 @@ function checkFloatValue (parameterSection, parameterName, minimumValue, maximum log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) errors++ break - case (!typeof (parameterSection[parameterName]) === 'number'): + case (!(typeof (parameterSection[parameterName]) === 'number')): log.error(`Configuration Error: ${parameterSection}.${parameterName} should be a numerical value, encountered ${parameterSection[parameterName]}`) errors++ break @@ -155,7 +155,7 @@ function checkFloatValue (parameterSection, parameterName, minimumValue, maximum } } -function checkBinaryValue (parameterSection, parameterName, allowRepair, defaultValue) { +function checkBooleanValue (parameterSection, parameterName, allowRepair, defaultValue) { // PLEASE NOTE: the parameterSection, parameterName seperation is needed to force a call by reference, which is needed for the repair action let errors = 0 switch (true) { From 75e2455b10154dbbd871f8c795db81d4360413a1 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 21:37:25 +0100 Subject: [PATCH 022/209] Added workout management to RowingStatistics Added workout management to the role of RowingStatistics --- docs/Architecture.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Architecture.md b/docs/Architecture.md index f8dd5c0e7d..0187737d0d 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -95,7 +95,7 @@ stateDiagram-v2 Stopped --> [*] ``` -Please note: the 'Stopped' state isn't directly part of the state machine that is defined in `handleRotationImpulse`, it is a direct consequence of emitting the `intervalTargetReached` message to `Server.js`, where `Server.js` concludes there is no next interval left, and thus `stopTraining()` has to be called (which does set the sessionState to 'Stopped'). This is needed as RowingStatistics shouldn't be aware about the existence of next intervals, as it only deals with the current interval. +Please note: the 'Stopped' state in the `handleRotationImpulse`'s state machine is a direct consequence of either `rower.js` indicating the flywheel is in a freespin or reaching the end of an interval without any subsequent interval being present in the workout. The later is tested in the function ` handleIntervalEnd()`, which determines this. Although this distinction could be handled by the state machine as part of `handleRotationImpulse`, we felt it would make the state machine less readable as it would add another three new states. #### metrics maintained in RowingStatistics.js @@ -107,7 +107,7 @@ In a nutshell: * `RowingStatistics.js` maintains the session state, thus determines whether the rowing machine is 'Rowing', or 'WaitingForDrive', etc., * `RowingStatistics.js` applies a moving median filter across strokes to make metrics less volatile and thus better suited for presentation, * `RowingStatistics.js` calculates derived metrics (like Calories) and trands (like Calories per hour), -* `RowingStatistics.js` gaurds interval and session boundaries, and will chop up the metrics-stream accordingly, where Rower.js will just move on without looking at these artifical boundaries. +* `RowingStatistics.js` maintains the workout intervals, guards interval and session boundaries, and will chop up the metrics-stream accordingly, where `Rower.js` will just move on without looking at these artifical boundaries. In total, this takes full control of the displayed metrics in a specific interval. From d67745c5df8afa20e67674f050425d327f6285c1 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 21:45:25 +0100 Subject: [PATCH 023/209] Fixed Line error Fixed Line error --- docs/Architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Architecture.md b/docs/Architecture.md index 0187737d0d..7858654840 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -95,7 +95,7 @@ stateDiagram-v2 Stopped --> [*] ``` -Please note: the 'Stopped' state in the `handleRotationImpulse`'s state machine is a direct consequence of either `rower.js` indicating the flywheel is in a freespin or reaching the end of an interval without any subsequent interval being present in the workout. The later is tested in the function ` handleIntervalEnd()`, which determines this. Although this distinction could be handled by the state machine as part of `handleRotationImpulse`, we felt it would make the state machine less readable as it would add another three new states. +Please note: the 'Stopped' state in the `handleRotationImpulse`'s state machine is a direct consequence of either `rower.js` indicating the flywheel is in a freespin or reaching the end of an interval without any subsequent interval being present in the workout. The later is tested in the function `handleIntervalEnd()`, which determines this. Although this distinction could be handled by the state machine as part of `handleRotationImpulse`, we felt it would make the state machine less readable as it would add another three new states. #### metrics maintained in RowingStatistics.js From 7251a8144d8e8ed6f7a3d450a8971d90a3d1493b Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 21:52:55 +0100 Subject: [PATCH 024/209] Douncheck with 0.8.4 settings Checked that the sanity check would fix all mew variables, allowing a 0.8.4 config file to be used with V1Beta without any crashes or issues. --- app/tools/ConfigManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index afb2b3f541..225e4b9a2c 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -25,7 +25,7 @@ function checkConfig (configToCheck) { checkIntegerValue(configToCheck, 'gpioMinimumPulseLength', 1, null, false, true, 0) checkIntegerValue(configToCheck, 'gpioPollingInterval', 1, 10, false, true, 10) checkRangeValue(configToCheck, 'gpioPollingInterval', [1, 2, 5, 10], true, 10) - checkRangeValue(configToCheck, 'gpioTriggeredFlank', ['Up', 'Down', 'Both'], false, null) + checkRangeValue(configToCheck, 'gpioTriggeredFlank', ['Up', 'Down', 'Both'], true, 'Up') checkIntegerValue(configToCheck, 'appPriority', configToCheck.gpioPriority, 0, true, true, 0) checkIntegerValue(configToCheck, 'webUpdateInterval', 80, 1000, false, true, 1000) checkBooleanValue(configToCheck, 'heartrateMonitorBLE', true, true) From f1e7d086dfc236c9284c4286877928c455bbca0f Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 22:09:23 +0100 Subject: [PATCH 025/209] Added restart limit to prevent bootloop Added a restart limit to the service definition to prevent an infinite bootloop --- install/webbrowserkiosk.service | 2 ++ 1 file changed, 2 insertions(+) diff --git a/install/webbrowserkiosk.service b/install/webbrowserkiosk.service index de6f2a4e48..519ac55531 100644 --- a/install/webbrowserkiosk.service +++ b/install/webbrowserkiosk.service @@ -1,6 +1,8 @@ [Unit] Description=X11 Web Browser Kiosk After=multi-user.target +StartLimitIntervalSec=60 +StartLimitBurst=5 [Service] Type=simple From 675c85cb594b10857336e19f6966776ed2f40f7c Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 15 Jan 2023 22:09:27 +0100 Subject: [PATCH 026/209] Added restart limit to prevent bootloop Added a restart limit to the service definition to prevent an infinite bootloop --- install/openrowingmonitor.service | 2 ++ 1 file changed, 2 insertions(+) diff --git a/install/openrowingmonitor.service b/install/openrowingmonitor.service index 71ece090c4..3e42478381 100644 --- a/install/openrowingmonitor.service +++ b/install/openrowingmonitor.service @@ -1,6 +1,8 @@ [Unit] Description=Open Rowing Monitor After=multi-user.target +StartLimitIntervalSec=60 +StartLimitBurst=5 [Service] Type=simple From 36953315bde771bd7c1398fe1e39ac08435807c5 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Mon, 16 Jan 2023 12:18:39 +0100 Subject: [PATCH 027/209] Move functionality to the Finite State Machine On hindsight, the approach of letting the FSM handle all state transitions explicitly is much clearer --- docs/Architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Architecture.md b/docs/Architecture.md index 7858654840..64fc2ed2a8 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -95,7 +95,7 @@ stateDiagram-v2 Stopped --> [*] ``` -Please note: the 'Stopped' state in the `handleRotationImpulse`'s state machine is a direct consequence of either `rower.js` indicating the flywheel is in a freespin or reaching the end of an interval without any subsequent interval being present in the workout. The later is tested in the function `handleIntervalEnd()`, which determines this. Although this distinction could be handled by the state machine as part of `handleRotationImpulse`, we felt it would make the state machine less readable as it would add another three new states. +Please note: `handleRotationImpulse` implements all these state transitions, where the state transitions for the end of an interval and the end of a session are handled individually as the metrics updates differ slightly. #### metrics maintained in RowingStatistics.js From 6eed136caf59119cbbaf3ac6a03d9f81a5067047 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Mon, 16 Jan 2023 12:18:46 +0100 Subject: [PATCH 028/209] Move functionality to the Finite State Machine On hindsight, the approach of letting the FSM handle all state transitions explicitly is much clearer --- app/engine/RowingStatistics.js | 46 +++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index 616b6cbb8f..3ae9d34346 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -93,11 +93,18 @@ function createRowingStatistics (config) { sessionStatus = 'Paused' pauseTraining() break - case (sessionStatus === 'Rowing' && lastStrokeState === 'Recovery' && rower.strokeState() === 'Drive' && intervalTargetReached()): + case (sessionStatus === 'Rowing' && lastStrokeState === 'Recovery' && rower.strokeState() === 'Drive' && isIntervalTargetReached() && isNextIntervalAvailable()): updateContinousMetrics() updateCycleMetrics() handleRecoveryEnd() - handleIntervalEnd() + activateNextIntervalParameters() + emitMetrics('intervalTargetReached') + break + case (sessionStatus === 'Rowing' && lastStrokeState === 'Recovery' && rower.strokeState() === 'Drive' && isIntervalTargetReached()): + updateContinousMetrics() + updateCycleMetrics() + handleRecoveryEnd() + stopTraining() break case (sessionStatus === 'Rowing' && lastStrokeState === 'Recovery' && rower.strokeState() === 'Drive'): updateContinousMetrics() @@ -105,11 +112,18 @@ function createRowingStatistics (config) { handleRecoveryEnd() emitMetrics('recoveryFinished') break - case (sessionStatus === 'Rowing' && lastStrokeState === 'Drive' && rower.strokeState() === 'Recovery' && intervalTargetReached()): + case (sessionStatus === 'Rowing' && lastStrokeState === 'Drive' && rower.strokeState() === 'Recovery' && isIntervalTargetReached() && isNextIntervalAvailable()): updateContinousMetrics() updateCycleMetrics() handleDriveEnd() - handleIntervalEnd() + activateNextIntervalParameters() + emitMetrics('intervalTargetReached') + break + case (sessionStatus === 'Rowing' && lastStrokeState === 'Drive' && rower.strokeState() === 'Recovery' && isIntervalTargetReached()): + updateContinousMetrics() + updateCycleMetrics() + handleDriveEnd() + stopTraining() break case (sessionStatus === 'Rowing' && lastStrokeState === 'Drive' && rower.strokeState() === 'Recovery'): updateContinousMetrics() @@ -117,9 +131,14 @@ function createRowingStatistics (config) { handleDriveEnd() emitMetrics('driveFinished') break - case (sessionStatus === 'Rowing' && intervalTargetReached()): + case (sessionStatus === 'Rowing' && isIntervalTargetReached() && isNextIntervalAvailable()): + updateContinousMetrics() + activateNextIntervalParameters() + emitMetrics('intervalTargetReached') + break + case (sessionStatus === 'Rowing' && isIntervalTargetReached()): updateContinousMetrics() - handleIntervalEnd() + stopTraining() break case (sessionStatus === 'Rowing'): updateContinousMetrics() @@ -266,7 +285,7 @@ function createRowingStatistics (config) { } } - function intervalTargetReached () { + function isIntervalTargetReached () { // This tests wether the end of the current interval is reached if ((intervalTargetDistance > 0 && rower.totalLinearDistanceSinceStart() >= intervalTargetDistance) || (intervalTargetTime > 0 && rower.totalMovingTimeSinceStart() >= intervalTargetTime)) { return true @@ -275,15 +294,12 @@ function createRowingStatistics (config) { } } - function handleIntervalEnd () { - // initiated when the state machine has concluded the interval has ended - if (intervalSettings.length > 0 && intervalSettings.length > (currentIntervalNumber + 1)) { - // There is a next interval available - emitMetrics('intervalTargetReached') - activateNextIntervalParameters() + function isNextIntervalAvailable () { + // This function tests whether there is a next interval available + if (currentIntervalNumber > -1 && intervalSettings.length > 0 && intervalSettings.length > (currentIntervalNumber + 1)) { + return true } else { - // There is no additional interval available - stopTraining() + return false } } From 3e2f95420520fd93631a14f8e89aa11bbe70f109 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Mon, 16 Jan 2023 17:18:57 +0100 Subject: [PATCH 029/209] Added paragraph about handle-based sensors Added a paragraph about handle-based sensors. --- docs/rower_settings.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/rower_settings.md b/docs/rower_settings.md index 726313280c..759bac466c 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -64,6 +64,14 @@ Please note that the process identification numbers will differ. ## Making sure the hardware is connected correctly and works as intended +### Checking the physical properties of the rower + +One thing to check is what the original sensor actually measures. You can physically look in the rower, but most manuals also include an exploded view of all parts in the machine. There you need to look at the placement of the sensor and the magnets. Most air-rowers measure the flywheel speed, but most water-rowers measure the handle speed and direction. Open Rowing Monitor is best suited for handling a spinning flywheel or water impellor, or anything directly attached to that. If your machine measures the impellor or flywheel directly, please note the number of magnets per rotation, as you need that parameter later on. So when you encounter a handle-connected machine and it is possible and within your comfort zone, try to add sensors to the flywheel or impellor. + +If you are uncomfortable modifying you machine, you can still make OpenRowingMonitor work, but with a loss of data quality. Where a flywheel or impellor can give information about the force and speeds created, the alternative can not. So you end up with a fixed distance per stroke, but you can connect to tools like EXR and the like. By setting *autoAdjustDragFactor* to false, *autoAdjustRecoverySlope* to false, *minumumRecoverySlope* to 0, *minimumStrokeQuality* to 0.01 and other parameters like dragFactor to a realistic well-choosen value (to make the metrics look plausible), OpenRowingMonitor will essentially calculate distance based on impulses encountered. Although not ideal for metrics, this can result in a working solution. Please note that the distance per stroke is essentially fixed, so many more advanced metrics are not relevant and stroke detection might be a bit vulnerable. + +### Checking the electrical properties of the rower + Before you physically connect anything to anything else, **check the electric properties of the rower** you are connecting to. Skipping this might destroy your Raspberry Pi as some rowers are known to exceed the Raspberry Pi electrical properties. For example, a Concept 2 RowErg provides 15V signals to the monitor, which will destroy the GPIO-ports. Other rowers provide signals aren't directly detectable by the raspberry Pi. For example, the Concept 2 Model C provides 0.2V pulses, thus staying below the detectable 1.8V treshold that the Raspberry Pi uses. Using a scope or a voltmeter is highly recommended. Please observe that the maximum input a Raspberry Pi GPIO pin can handle is 3.3V and 0.5A, and it will switch at 1.8V (see [this overview of the Raspberry Pi electrical properties](https://raspberrypi.stackexchange.com/questions/3209/what-are-the-min-max-voltage-current-values-the-gpio-pins-can-handle)). In our [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) there are some people who are brilliant with electrical connections, so don't be affraid to ask for help there. When you have a working solution, please report it so that we can include it in the documentation, allowing us to help others. Next, when the electric connection has been made, we need to look if the data is recieved well and has sufficient quality to be used. You can change `config/config.js` by From f7aae7b6e058ddc87814d6b0cb1142ed4d27d966 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Mon, 16 Jan 2023 17:21:03 +0100 Subject: [PATCH 030/209] Added reason to modify hardware setup Added reason to modify hardware setup in documentation --- docs/rower_settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rower_settings.md b/docs/rower_settings.md index 759bac466c..75ad3fe8b0 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -66,7 +66,7 @@ Please note that the process identification numbers will differ. ### Checking the physical properties of the rower -One thing to check is what the original sensor actually measures. You can physically look in the rower, but most manuals also include an exploded view of all parts in the machine. There you need to look at the placement of the sensor and the magnets. Most air-rowers measure the flywheel speed, but most water-rowers measure the handle speed and direction. Open Rowing Monitor is best suited for handling a spinning flywheel or water impellor, or anything directly attached to that. If your machine measures the impellor or flywheel directly, please note the number of magnets per rotation, as you need that parameter later on. So when you encounter a handle-connected machine and it is possible and within your comfort zone, try to add sensors to the flywheel or impellor. +One thing to check is what the original sensor actually measures. You can physically look in the rower, but most manuals also include an exploded view of all parts in the machine. There you need to look at the placement of the sensor and the magnets. Most air-rowers measure the flywheel speed, but most water-rowers measure the handle speed and direction. Open Rowing Monitor is best suited for handling a spinning flywheel or water impellor, or anything directly attached to that. If your machine measures the impellor or flywheel directly, please note the number of magnets per rotation, as you need that parameter later on. So when you encounter a handle-connected machine and it is possible and within your comfort zone, try to add sensors to the flywheel or impellor as it results in much better metrics. If you are uncomfortable modifying you machine, you can still make OpenRowingMonitor work, but with a loss of data quality. Where a flywheel or impellor can give information about the force and speeds created, the alternative can not. So you end up with a fixed distance per stroke, but you can connect to tools like EXR and the like. By setting *autoAdjustDragFactor* to false, *autoAdjustRecoverySlope* to false, *minumumRecoverySlope* to 0, *minimumStrokeQuality* to 0.01 and other parameters like dragFactor to a realistic well-choosen value (to make the metrics look plausible), OpenRowingMonitor will essentially calculate distance based on impulses encountered. Although not ideal for metrics, this can result in a working solution. Please note that the distance per stroke is essentially fixed, so many more advanced metrics are not relevant and stroke detection might be a bit vulnerable. From b4739536d21f8c8666133313cd8f4fbe9390e853 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 17 Jan 2023 11:14:47 +0100 Subject: [PATCH 031/209] Added link to software setup Added link to software setup --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 3482627e2c..5ce1116be6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -83,7 +83,7 @@ How to connect this to your rowing machine is specific to your device. You need * [Concept 2 RowErg](hardware_setup_Concept2_RowErg.md) * [Sportstech WRX700](hardware_setup_WRX700.md) -If your machine isn't listed, you can still follow this generic manual. +If your machine isn't listed, you can still follow this generic manual for hardware setup, and [adjust the software settings following the settings adjustment guide](rower_settings.md). ![Connecting the reed sensor](img/raspberrypi_reedsensor_wiring.jpg) *Connecting the reed sensor* From 2e50a48e6170b65497f2512cd5de3b6b7f9e37fa Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 17 Jan 2023 11:48:28 +0100 Subject: [PATCH 032/209] Added a list of known machines --- docs/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/README.md b/docs/README.md index 069399301f..f74c3a591e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -69,6 +69,23 @@ Open Rowing Monitor is based on the idea that metrics should be easily accessibl Uploading your sessions to Strava is an integrated feature, for all other platforms this is currently a manual step. Uploading to [RowsAndAll](https://rowsandall.com/) can be automated through their e-mail interface, see [this description](https://rowsandall.com/rowers/developers/). The Open rowing Monito installer can also set up a network share that contains all training data so it is easy to grab the files from there and manually upload them to the training platform of your choice. +## Supported machines + +Several machines are known to work with Open Rowing Monitor: + +* Abilica Winrower 2.0: Air rower that is known to work, see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/48); +* [Concept 2 Model D, Model E and RowErg](hardware_setup_Concept2_RowErg.md): fully supported Air rower, dynamic drag calculation and all metrics available including force curves +* Decathlon Rower120: known to work by adding magnets to the flywheel, currently basic metrics only, see [this discussion](https://github.com/laberning/openrowingmonitor/issues/110); +* DKN R-320 Air Rower: fully supported Air rower, static drag calculation, basic metrics only; +* FDF Neon Pro V rower: known to work, see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/87); +* ForceUSA R3: supported Air rower, dynamic drag calculation and all metrics available including force curves; +* NordickTrack RX800: fully supported hybrid Magnetic/Air rower, dynamic drag calculation and all metrics available including force curves; +* Sportplus MR-SP-08: work in progress, see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/95); +* [Sportstech WRX700](hardware_setup_WRX700.md): fully supported water rower, static drag calculation, all metrics available including force curves; +* [OpenErgo machines](https://openergo.webs.com/): several machines have been made to work, see [example 1](https://github.com/laberning/openrowingmonitor/discussions/80), [example 2](https://github.com/laberning/openrowingmonitor/discussions/105) and [example 3](https://github.com/laberning/openrowingmonitor/discussions/115) + +If your machine isn't listed, it just means that you need to [adjust the software settings following the settings adjustment guide](rower_settings.md). Don't worry, in the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) there always are friendly people to help you set up your machine and the settings. + ## Installation You will need a Raspberry Pi Zero W, Raspberry Pi Zero 2 W, Raspberry Pi 3 or a Raspberry Pi 4 with a fresh installation of Raspberry Pi OS Lite for this (the 64Bit kernel is preferred). Connect to the device with SSH and initiate the following command to install Open Rowing Monitor as an automatically starting system service: From 89e534110ea3892db24480a0fb802b3b8f7aae82 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 17 Jan 2023 23:37:56 +0100 Subject: [PATCH 033/209] Added a link to supported rowers --- docs/README.md | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/docs/README.md b/docs/README.md index f74c3a591e..ec1b9aea35 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,7 +11,7 @@ Open Rowing Monitor is a free and open source performance monitor for rowing mac It is a Node.js application that runs on a Raspberry Pi and measures the rotation of the rower's flywheel (or similar) to calculate rowing specific metrics, such as power, split time, speed, stroke rate, distance and calories. It can share these metrics for controling games and record these metrics for further analysis. -It is currently developed and tested with a Sportstech WRX700 water-rower and a Concept2 air-rower. In the past, it was also tested extensively on a NordicTrack RX-800 hybrid air/magnetic rower. But it should run fine with any rowing machine that uses some kind of damping mechanism, as long as you can add something to measure the speed of the flywheel. It has shown to work well with DIY rowing machines like the [Openergo](https://openergo.webs.com), providing the construction is decent. +Open Rowing Monitor should run fine with any rowing machine that uses some kind of damping mechanism, as long as you can add something to measure the speed of the flywheel. It has shown to work well with DIY rowing machines like the [Openergo](https://openergo.webs.com), providing the construction is decent. For a full list of supported rowing machines, you can visit the list of [supported rowers](Supported_Rowers.md). If your machine isn't listed, it just means that you need to [adjust the software settings following the settings adjustment guide](rower_settings.md) yourself. But don't worry, in the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) there always are friendly people to help you set up your machine and the settings. ## Features @@ -69,23 +69,6 @@ Open Rowing Monitor is based on the idea that metrics should be easily accessibl Uploading your sessions to Strava is an integrated feature, for all other platforms this is currently a manual step. Uploading to [RowsAndAll](https://rowsandall.com/) can be automated through their e-mail interface, see [this description](https://rowsandall.com/rowers/developers/). The Open rowing Monito installer can also set up a network share that contains all training data so it is easy to grab the files from there and manually upload them to the training platform of your choice. -## Supported machines - -Several machines are known to work with Open Rowing Monitor: - -* Abilica Winrower 2.0: Air rower that is known to work, see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/48); -* [Concept 2 Model D, Model E and RowErg](hardware_setup_Concept2_RowErg.md): fully supported Air rower, dynamic drag calculation and all metrics available including force curves -* Decathlon Rower120: known to work by adding magnets to the flywheel, currently basic metrics only, see [this discussion](https://github.com/laberning/openrowingmonitor/issues/110); -* DKN R-320 Air Rower: fully supported Air rower, static drag calculation, basic metrics only; -* FDF Neon Pro V rower: known to work, see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/87); -* ForceUSA R3: supported Air rower, dynamic drag calculation and all metrics available including force curves; -* NordickTrack RX800: fully supported hybrid Magnetic/Air rower, dynamic drag calculation and all metrics available including force curves; -* Sportplus MR-SP-08: work in progress, see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/95); -* [Sportstech WRX700](hardware_setup_WRX700.md): fully supported water rower, static drag calculation, all metrics available including force curves; -* [OpenErgo machines](https://openergo.webs.com/): several machines have been made to work, see [example 1](https://github.com/laberning/openrowingmonitor/discussions/80), [example 2](https://github.com/laberning/openrowingmonitor/discussions/105) and [example 3](https://github.com/laberning/openrowingmonitor/discussions/115) - -If your machine isn't listed, it just means that you need to [adjust the software settings following the settings adjustment guide](rower_settings.md). Don't worry, in the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) there always are friendly people to help you set up your machine and the settings. - ## Installation You will need a Raspberry Pi Zero W, Raspberry Pi Zero 2 W, Raspberry Pi 3 or a Raspberry Pi 4 with a fresh installation of Raspberry Pi OS Lite for this (the 64Bit kernel is preferred). Connect to the device with SSH and initiate the following command to install Open Rowing Monitor as an automatically starting system service: From 47316d5027b19c800ae1daebb8c43475fa8b180e Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 17 Jan 2023 23:45:07 +0100 Subject: [PATCH 034/209] Creation to support users --- docs/Supported_Rowers.md | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docs/Supported_Rowers.md diff --git a/docs/Supported_Rowers.md b/docs/Supported_Rowers.md new file mode 100644 index 0000000000..36c079c786 --- /dev/null +++ b/docs/Supported_Rowers.md @@ -0,0 +1,61 @@ +# Known rowers and their support status + +The following rowers are known to work, or are even actively supported: + +| Brand | Type | Rower type | Measurement type | HW Modification needed | Support status | Rower profile | Basic Metrics | Advanced Metrics | Limitations | Remarks | +| ----- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | +| Abilica | Winrower 2.0 | Air rower | Handle drive wheel | No | Known to work | - | Yes | No | Static distance | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/48) | +| Concept 2 | Model B, C | Air rower | Flywheel | Modification to electrical signal | In development | - | - | - | - | [Concept 2 Model C discussion](https://github.com/laberning/openrowingmonitor/issues/77) | +| | Model D, E | Air rower | Flywheel | Modification to electrical signal | Active support | Concept2_RowErg | Yes | Yes | None | [Concept 2 Model D, Model E and RowErg setup](hardware_setup_Concept2_RowErg.md) | +| | RowErg | Air rower | Flywheel | Modification to electrical signal | Active support | Concept2_RowErg | Yes | Yes | None | [Concept 2 Model D, Model E and RowErg setup](hardware_setup_Concept2_RowErg.md) | +| Decathlon | Rower 120 | Physical friction | Flywheel | Adding sensor and adding magnets to the flywheel | In development | - | - | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/issues/110) | +| DKN | R-320 | Air Rower | Flywheel | No | Full support | DKN_R320 | Yes | No | Static drag | - | +| FDF | Neon Pro V | Air rower | Flywheel | Sensor replacement | Known to work | - | Yes | - | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/87) | +| ForceUSA | R3 | Air Rower | Flywheel | No | Supported | ForceUSA_R3 | Yes | Yes | None | - | +| NordicTrack | RX800 | Hybrid Magnetic and Air rower | Flywheel | None | Full support | NordicTrack_RX800 | Yes | Yes | None | Also known under ProForm brand | +| Sportplus | MR-SP-08 | Water rower | Handle drive wheel | In development | - | - | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/95) | +| Sportstech | WRX700 | Water rower | Impellor | Add one magnet | Active support | Sportstech_WRX700 | Yes | Yes | Static drag | see [Sportstech WRX700 setup](hardware_setup_WRX700.md) +| White label | Air Rower | Air rower | Fywheel | None | Supported | Generic_Air_Rower | Yes | Yes | None | Sold under different brand names | +| Open ergo | - | Air rower | Flywheel | Addition of magnets en sensor | Known to work | - | Yes | Yes | None | Machine specific profile is needed, but is done before, see [example 1](https://github.com/laberning/openrowingmonitor/discussions/80), [example 2](https://github.com/laberning/openrowingmonitor/discussions/105) and [example 3](https://github.com/laberning/openrowingmonitor/discussions/115) | + +If your machine isn't listed, it just means that you need to [adjust the software settings following the settings adjustment guide](rower_settings.md) yourself. But don't worry, in the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) there always are friendly people to help you set up your machine and the settings. + +## Support status +In the table, the support status means the following: +* **Active support**: These are the testmachines of the developers, these are tested almost on a daily basis. These settings are automatically modified to facilitate updates of the rowing engine; +* **Full support**: We actively maintain a the configuration, including automatically updating these settings to facilitate chages of the rowing engine, and are part of the automated regression test set. So as a user, you can be assured this setting will keep working; +* **Supported**: Users have reported a working configuration, and this configuration is part of `rowerProfiles.js`, but we lack the raw data samples to maintain the rower for future updates. This means that future support isn't guaranteed; +* **Configuration known**: Users have reported a working configuration, but it isn't actively supported by these users and it isn't on our rader to maintain. You need to add the configuration to your `config.js` manually and maintain it yourself when there are updates to the engine; +* **Known to work**: Users have reported that the rower is known to work, but the configuration is not known by us; +* **In development**: Users are known to be working to get the rower connected, but the configuration is not yet known by us. + +Please note: the support status largely depends on the willingness of users to report their settings and provide decent samples of their data. So when you have a machine, please provide this information. + +## Basic Metrics +With basic metrics we mean: +* Distance rowed, +* Training Duration, +* Power, +* Pace, +* Strokes per Minute, +* Drive time, +* Recovery Time, +* Calories used, +* Total number of strokes, +* Heart Rate + +## Extended Metrics +With extended metrics, we mean: +* Drag factor, +* Drive length, +* Average handle force, +* Peak handle force, +* Handle force curve, +* Handle velocity curve, +* Handle power curve. + +## Limitations +With the limitation, we mean: +* **None**: No limitations, drag calculation and distance per stroke are dynamic based on flywheel behaviour and automatically adapt to environmental conditions; +* **Static drag**: the drag calculation is fixed, so changes in air/water properties due to temperature or settings are not automatically adjusted; +* **Static distance**: the distance per impulse is fixed, thus making the measurement of a more forceful stroke impossible. This typically happens when the handle movement is measured, but not its effect on the flywheel. From 0ba86d891cd714fb7204ecb8cbaa3b7205b3fd37 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 17 Jan 2023 23:49:00 +0100 Subject: [PATCH 035/209] Fixed Lint errors Fixed Lint errors --- docs/Supported_Rowers.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/Supported_Rowers.md b/docs/Supported_Rowers.md index 36c079c786..259e52907f 100644 --- a/docs/Supported_Rowers.md +++ b/docs/Supported_Rowers.md @@ -21,7 +21,9 @@ The following rowers are known to work, or are even actively supported: If your machine isn't listed, it just means that you need to [adjust the software settings following the settings adjustment guide](rower_settings.md) yourself. But don't worry, in the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) there always are friendly people to help you set up your machine and the settings. ## Support status + In the table, the support status means the following: + * **Active support**: These are the testmachines of the developers, these are tested almost on a daily basis. These settings are automatically modified to facilitate updates of the rowing engine; * **Full support**: We actively maintain a the configuration, including automatically updating these settings to facilitate chages of the rowing engine, and are part of the automated regression test set. So as a user, you can be assured this setting will keep working; * **Supported**: Users have reported a working configuration, and this configuration is part of `rowerProfiles.js`, but we lack the raw data samples to maintain the rower for future updates. This means that future support isn't guaranteed; @@ -32,7 +34,9 @@ In the table, the support status means the following: Please note: the support status largely depends on the willingness of users to report their settings and provide decent samples of their data. So when you have a machine, please provide this information. ## Basic Metrics + With basic metrics we mean: + * Distance rowed, * Training Duration, * Power, @@ -45,7 +49,9 @@ With basic metrics we mean: * Heart Rate ## Extended Metrics + With extended metrics, we mean: + * Drag factor, * Drive length, * Average handle force, @@ -55,7 +61,9 @@ With extended metrics, we mean: * Handle power curve. ## Limitations + With the limitation, we mean: + * **None**: No limitations, drag calculation and distance per stroke are dynamic based on flywheel behaviour and automatically adapt to environmental conditions; * **Static drag**: the drag calculation is fixed, so changes in air/water properties due to temperature or settings are not automatically adjusted; * **Static distance**: the distance per impulse is fixed, thus making the measurement of a more forceful stroke impossible. This typically happens when the handle movement is measured, but not its effect on the flywheel. From c82a97796c39edc888cf1861808eea1189d0247f Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 17 Jan 2023 23:53:41 +0100 Subject: [PATCH 036/209] Fixed a table error --- docs/Supported_Rowers.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Supported_Rowers.md b/docs/Supported_Rowers.md index 259e52907f..d993a92134 100644 --- a/docs/Supported_Rowers.md +++ b/docs/Supported_Rowers.md @@ -1,5 +1,7 @@ # Known rowers and their support status +Open Rowing Monitor works with a very wide range of rowing machines. It is currently developed and tested with a Sportstech WRX700 water-rower and a Concept2 air-rower. In the past, it was also tested extensively on a NordicTrack RX-800 hybrid air/magnetic rower. But it should run fine with any rowing machine that uses some kind of damping mechanism, as long as you can add something to measure the speed of the flywheel. It has shown to work well with DIY rowing machines like the [Openergo](https://openergo.webs.com/), providing the construction is decent. + The following rowers are known to work, or are even actively supported: | Brand | Type | Rower type | Measurement type | HW Modification needed | Support status | Rower profile | Basic Metrics | Advanced Metrics | Limitations | Remarks | @@ -13,7 +15,7 @@ The following rowers are known to work, or are even actively supported: | FDF | Neon Pro V | Air rower | Flywheel | Sensor replacement | Known to work | - | Yes | - | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/87) | | ForceUSA | R3 | Air Rower | Flywheel | No | Supported | ForceUSA_R3 | Yes | Yes | None | - | | NordicTrack | RX800 | Hybrid Magnetic and Air rower | Flywheel | None | Full support | NordicTrack_RX800 | Yes | Yes | None | Also known under ProForm brand | -| Sportplus | MR-SP-08 | Water rower | Handle drive wheel | In development | - | - | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/95) | +| Sportplus | MR-SP-08 | Water rower | Handle drive wheel | - | In development | - | - | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/95) | | Sportstech | WRX700 | Water rower | Impellor | Add one magnet | Active support | Sportstech_WRX700 | Yes | Yes | Static drag | see [Sportstech WRX700 setup](hardware_setup_WRX700.md) | White label | Air Rower | Air rower | Fywheel | None | Supported | Generic_Air_Rower | Yes | Yes | None | Sold under different brand names | | Open ergo | - | Air rower | Flywheel | Addition of magnets en sensor | Known to work | - | Yes | Yes | None | Machine specific profile is needed, but is done before, see [example 1](https://github.com/laberning/openrowingmonitor/discussions/80), [example 2](https://github.com/laberning/openrowingmonitor/discussions/105) and [example 3](https://github.com/laberning/openrowingmonitor/discussions/115) | From 704c2faaae526fc915c99ebe6a71eefc5ef32746 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 18 Jan 2023 09:29:28 +0100 Subject: [PATCH 037/209] Removed the Sportplus as an option --- docs/Supported_Rowers.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/Supported_Rowers.md b/docs/Supported_Rowers.md index d993a92134..17effd2f57 100644 --- a/docs/Supported_Rowers.md +++ b/docs/Supported_Rowers.md @@ -15,7 +15,6 @@ The following rowers are known to work, or are even actively supported: | FDF | Neon Pro V | Air rower | Flywheel | Sensor replacement | Known to work | - | Yes | - | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/87) | | ForceUSA | R3 | Air Rower | Flywheel | No | Supported | ForceUSA_R3 | Yes | Yes | None | - | | NordicTrack | RX800 | Hybrid Magnetic and Air rower | Flywheel | None | Full support | NordicTrack_RX800 | Yes | Yes | None | Also known under ProForm brand | -| Sportplus | MR-SP-08 | Water rower | Handle drive wheel | - | In development | - | - | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/95) | | Sportstech | WRX700 | Water rower | Impellor | Add one magnet | Active support | Sportstech_WRX700 | Yes | Yes | Static drag | see [Sportstech WRX700 setup](hardware_setup_WRX700.md) | White label | Air Rower | Air rower | Fywheel | None | Supported | Generic_Air_Rower | Yes | Yes | None | Sold under different brand names | | Open ergo | - | Air rower | Flywheel | Addition of magnets en sensor | Known to work | - | Yes | Yes | None | Machine specific profile is needed, but is done before, see [example 1](https://github.com/laberning/openrowingmonitor/discussions/80), [example 2](https://github.com/laberning/openrowingmonitor/discussions/105) and [example 3](https://github.com/laberning/openrowingmonitor/discussions/115) | From 6e5089d4a3e5827cc24335c9b89c314caf4a608c Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 18 Jan 2023 09:30:10 +0100 Subject: [PATCH 038/209] Update Supported_Rowers.md --- docs/Supported_Rowers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Supported_Rowers.md b/docs/Supported_Rowers.md index 17effd2f57..ab4cd81822 100644 --- a/docs/Supported_Rowers.md +++ b/docs/Supported_Rowers.md @@ -5,7 +5,7 @@ Open Rowing Monitor works with a very wide range of rowing machines. It is curre The following rowers are known to work, or are even actively supported: | Brand | Type | Rower type | Measurement type | HW Modification needed | Support status | Rower profile | Basic Metrics | Advanced Metrics | Limitations | Remarks | -| ----- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | +| ----- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---------------- | | Abilica | Winrower 2.0 | Air rower | Handle drive wheel | No | Known to work | - | Yes | No | Static distance | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/48) | | Concept 2 | Model B, C | Air rower | Flywheel | Modification to electrical signal | In development | - | - | - | - | [Concept 2 Model C discussion](https://github.com/laberning/openrowingmonitor/issues/77) | | | Model D, E | Air rower | Flywheel | Modification to electrical signal | Active support | Concept2_RowErg | Yes | Yes | None | [Concept 2 Model D, Model E and RowErg setup](hardware_setup_Concept2_RowErg.md) | From 60350f3dc74e71f9e2f7f3063ec95eca8ed8d920 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 18 Jan 2023 14:11:19 +0100 Subject: [PATCH 039/209] Added recommendation of OS Lite 64Bit --- docs/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 5ce1116be6..dd03e7200f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -19,11 +19,11 @@ This guide roughly explains how to set up the rowing software and hardware. ### Initialization of the Raspberry Pi -* Install **Raspberry Pi OS Lite** on the SD Card i.e. with the [Raspberry Pi Imager](https://www.raspberrypi.org/software) +* Install **Raspberry Pi OS Lite** on the SD Card i.e. with the [Raspberry Pi Imager](https://www.raspberrypi.org/software). Here, Raspberry Pi OS Lite 64 Bit is recommended as it is better suited for real-time environments; * Configure the network connection and enable SSH, if you use the Raspberry Pi Imager, you can automatically do this while writing the SD Card, just press `Ctrl-Shift-X`(see [here](https://www.raspberrypi.org/blog/raspberry-pi-imager-update-to-v1-6/) for a description), otherwise follow the instructions below * Connect the device to your network ([headless](https://www.raspberrypi.org/documentation/configuration/wireless/headless.md) or via [command line](https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md)) * Enable [SSH](https://www.raspberrypi.org/documentation/remote-access/ssh/README.md) -* Tune the OS if needed [by following this guide](Improving_Raspberry_Performance.md) +* Tune the OS if needed [by following our performance improvement guide](Improving_Raspberry_Performance.md) ### Installation of the Open Rowing Monitor From f737fdb04d7f5bdc7ec280b407b056e77c10557d Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Sun, 22 Jan 2023 14:38:44 +0100 Subject: [PATCH 040/209] Fixed a bad example config The example configuration pointed to a renamed rower.... --- install/config.js | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/install/config.js b/install/config.js index 35482b2524..ff7f170f25 100644 --- a/install/config.js +++ b/install/config.js @@ -20,19 +20,23 @@ export default { default: 'debug' }, - // example: set a rower profile: - rowerSettings: rowerProfiles.DKNR320 - - // example: set custom rower settings: - rowerSettings: { - numOfImpulsesPerRevolution: 1, - dragFactor: 0.03, - flywheelInertia: 0.3 - } - - // example: set a rower profile, but overwrite some settings: - rowerSettings: Object.assign(rowerProfiles.DKNR320, { - autoAdjustDragFactor: true - }) - */ + // The rower specific settings. Either choose a profile from config/rowerProfiles.js or + // define the settings individually. If you find good settings for a new rowing device + // please send them to us (together with a raw recording of 10 strokes) so we can add + // the device to the profiles. + + // EXAMPLE ROWER CONFIG : using a DKN R-320 Air Rower as is + // rowerSettings: rowerProfiles.DKN_R320 + + // EXAMPLE ROWER CONFIG: Just set custom rower settings to make it work + // rowerSettings: { + // numOfImpulsesPerRevolution: 1, + // dragFactor: 0.03, + // flywheelInertia: 0.3 + // } + + // EXAMPLE ROWER CONFIG: set a rower profile, but overwrite some settings: + // rowerSettings: Object.assign(rowerProfiles.DKN_R320, { + // autoAdjustDragFactor: true + // }) } From ca3dc3aa2ab1a92f47c751586516656fd06354ab Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Fri, 27 Jan 2023 15:29:33 +0100 Subject: [PATCH 041/209] Added depiction of maximumTimeBetweenImpulses Added depiction of maximumTimeBetweenImpulses to illustrate pause behaviour --- docs/img/maximumTimeBetweenImpulses.jpg | Bin 0 -> 415061 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/img/maximumTimeBetweenImpulses.jpg diff --git a/docs/img/maximumTimeBetweenImpulses.jpg b/docs/img/maximumTimeBetweenImpulses.jpg new file mode 100644 index 0000000000000000000000000000000000000000..42b6dd155ce977a395123ec8294c9607f3fbf88e GIT binary patch literal 415061 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 XxOh@n;ipeV#m#+xF1j+*|Gx Date: Fri, 27 Jan 2023 16:00:30 +0100 Subject: [PATCH 042/209] Added an example of a bouncing sensor Added an example of a bouncing sensor --- docs/img/CurrentDt_With_Lots_Of_Bounce.jpg | Bin 0 -> 360828 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/img/CurrentDt_With_Lots_Of_Bounce.jpg diff --git a/docs/img/CurrentDt_With_Lots_Of_Bounce.jpg b/docs/img/CurrentDt_With_Lots_Of_Bounce.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b92517428da176a208e4698b25dbe65f5377413 GIT binary patch literal 360828 zcmeEv2UwHqvhI(dAVrGwE?uh9Q6Q*`E+R+=iHh_lN+%Em0i_BEC;~xxkMtrEdR0KG zfRq4&^n@BnAUErtbI)CC-F?p9`|h>xUhAIZ;eSXW@+1g`56joN@{8C)jiR|u zO2P-6q9-AxC&9M^JODs)`scGHAp!pVMskX9j%Uaz&Qekl{-Bx;I7LEAdWwwn=d&jK zbs*t&fQgO@)jn;FDL<-2aiL}QZlo!vat&a35#45 zm6elMP*l2d<0o|uO)YJmJ4VJPre@|AHV>>V7Po_KnB`}q3#hdv7nk9htfG9mF* zQgX`cH>p|KIk|cH1%*Wwl~vU>wRQCkt!?ccon75My+gwzqhsS=Cnk~e3ya^EmVd0Q zqPKT;_x2AkhetoJiv%G3w`Kju%6_vhdcwL+k&%&-k^j6dl2bl}gOr}^^o7f37_J$R z-}gArC;gOy@p}Bb@|LswGKMIo2amr{G7HEe1<^k*?SHQ9Z(CT%|JBO=V`2Y$U6TMc zDGA}?kH(7?-qSD$OmM0yP^YF!=Ey7?q7> z(Z>TYDlm2%fi!g>zL_X6qLL857(`=0w4THrgSbl)Jp-aEMRXsDE;BJqAcjW7Sdth& z6EOoKPC^8hh+rBKKqP{uM3k9`tp91V3EQq_ue~fs^y8WBjg993);SV&_HkUeJ04h@ z*FUECqQ?E^*J+g^3n|>w642TV=$OoS5)jFXBpyT=5Ov^p(1C4N=aU->cwi4LeDcg8 zo8Vu*{EP>VA=-H09lHqWuq^nH)C@Y_2tA@GuGUp2yet=S9MFXaG9y2zon|y39z+=s zb>Mf<0dBogXty06IB60floG@+I)k^_5O@Io0<_Do4*1(e;Q?M}+M|OwJaCQ4yU+o# zedaykWnVn7OK<7`WJQV)kAJZYa)e2RpBi~hKkjO~BC%gu_)RbmW=o~7yv1@ zx~v(eDhW|PhT|YJ%%~hw<_4;S`$O}IeQ`Z^K8@eHvd76yPIApni+tu_mKAb3cbda_ zfCKY*26md2QCTF-l+<@9;~_;F&`1?CSW#?b_)}a`EtkbSt7=*bd5`A zz$oH#WkblO)K&|x7p?{Vq6&%;*2}0zPOF}PxCUJ1rmOC3xJul;^EjOU*kQoR^z!`d zSNnNTo8sbFBh&naQa$&b)5DXxVngIg>ff#@d(y(x97uPCA~A3G?;cmmS#Hr=V8rId zXFSIl0y758-u(1f;3L_cXyCCgO>{_*%QF8)Dj))X337^?jOv`FXp;Qu3srMf@f@oN znOCo`*)mEy`y!QOp%`b(~+Aw$LynBrezSy5H7QU zpshT~??X(DZ`sX)@+OaD_U~MVO)NK`m`-D9L0f(?uyI+EHAVwP#!O8@hK7_fc^-x{L|cV^a;Wd# z8_+qjoY%x9A{e1xMc44aPt}k+cz|pg55!M(g7(iv-~o+6@>w~w>Ba@D7Va8~e1pav zSxRLQ+jj$8zF8&zNPEfewN$dFM88K1(|&1?+sRk(wzmNu_y#(Z0D|I8+mDtv?$5iQ zJ{g(pjDfH9(FRwoMLkRIaX|_@S<3Jgug{ouGt$0I@EB_P3jahKsY(+!&$5wN?Ca(n zULA2~JYiD%rENTi+dO%hOq@Tkz9$t2;yICDWl0@)>UnI~)>gB<5k9M3ZK~d-=*aej ze}RoOR@{WUJ|V{7KaRH`5jNOM3Isez3V*lWXt*~ z5<#=lL^tT->B`-Il}5hz0wXh;TD0Kg;hw;@w!o-67qmNZo(D^A1^tniNgIB`d@^k< z_yr<3kDX;*y^M)716OKhnafq(KDDuQ7`-H5l@)gV$pG&unRu8DT5LaaB)lqqudsVwN68K$+LRTgXXJggSB1hM^kvQ>Q9 zPIW0*`MepX1FI3#Ut8m2Ef>AoAUp6ru=;++S6&<6WALNF3bxQtiyr?ZJYkRWAquq_W4vl zXoyMo`n8KK45Fs5p)K-zE91A(HIe-m6InHl>cU}UdlT9rjF=CYONA-)rtAW0n_6uW$=6{Z5uZ;#w)MppO8pK=D9pf zAT2pA@uH1gEA}0ukrxJs^VpC~D!Q`i)rUdm&7Z#Fn%arxR@|^A!79z*?5ZNH@j%$E zN?DgdsKepy$)0|J?aJlQxI@PSDEH_Q6IKJ-Lyq1$ep&|IHHW`N%%vjG3uy9_1~WV$ z776TwCc+OExE6!>c$oQZDes;1JMz`U^g{+@9{^|0@MGH$Tx&~UjK}~kX^R#Qe5C{( zi)0{f6z_BqG!YL72DIUU{ZoX{Lq|B1wy}{45Af+nAlA7EkX=@Ctr%@Hf^ZcAPFlwB zz|lqL$H5?F&|D@D^+w|b^m%Qx$y>UbIB@KZNBnbvMSLG}_QlI!h9&-~M;7B<8CTHb z>#$tkxaQ@JAcgw!TI0v%$$o~mk;vx6#etp+%W=0ntZfO79)H4RB+uzikEQC}^`<)d zGU#i#@o^-70%#(?)$-_aqb>P+tkvxC6U-oaGY^+!5dSyK5jiG7fLjDBejOyONOySk ztvy{ZBEaWkAiaBO(AN;(o^WI*GAUvBCZ*pGt=k^Ee07Ma*^^rw`gq{IG5jPZ8KEgc zQux7Xvvd7PZJy%@5$yOQ06xS(`OhBclYS?d8vCb9<4w$tsuyabJ_S-99JJHclQr`z z9PgLYcESi|6AxgLoabr7Dt$G~lf3lK_;FnjUJ7uus`FTju)h-vlPZAc$!$=!wI50B zCl*->E~N)hT~lT_$HjUt?gZh4Tg60S6>!?eZ*i`8;H=cssoNu-b(|mb3iG;_^eDLt zmDRW}wAuMOUDHinnoF(ix zg6BJ+`;_2g&gvr)FbT9p@m+inFQz)$g~_wsu$}YFj%gg6>0kp0dV&X9ZdAQ+Igxct z>416!WOr15aMKnv;R&8P93MJiKaN*Di%D#2ur75+G9^>3nUxs~8#jvf{$QoYZut)# z7enp$F&lHQS@ax`XrYA9a-lljCGUb~sTA%_8HIi=7$6((ojnJ2+@{vEv!9^&5H13DFSwr&7M(`HQWZHz2PJc@GG!Gak>BKG}*iHhP#~;{u2w-7&%vjm7Az9p@fAipp8H6Me+d9~ZjSvM?E} z+H{=N0wTc$JcVHrt?$8X49s&$@Rb-tLKiO?ec%0H z-f&Pb`KnwH0V8eEfG)y)p(o9R*k|RZz1^<$7VLFrD9=>;c*+b{#7{#m?9<|lFJ|;F zPkq{9tOqXNE*zwGTP}d7L+7$AxU;>`x^1;D&8$8rXN#)hcXY%d5BgqRI0U(QmPLJlUC z%FupZvexNa;yYS!aXvxa2YciAQRWyQR9~Aa$Gs-+bQ?yQSJ*rkyXz`Z$)Ffta>6oM ziwv3i{hvz7^H}B&!ayX^roH_jS(7I zJo2m90cTgEK{!SZl4GEW+*i2r%&S~R`g_lqJhnEzEGbd%n>Jiig zAzy=7D1&l;c+Z@x9&Nl{$W?Loa9d%L705gktrrhK9%W36kZ$!}EHIDPl^o+w>i5{V zMTEEhDvw?e55ESorF1yhRr;)t9dFU+pi6uB zt@|sAZ=~-{E=1y{uBS-}ld>(!!lth5w4I2&|I#Fc1C2n)xprJb4N|Y8_Bzd^rFx~M zdo9@(DS;#ZNcDTYY+Ah0Ayo>wFiNiQ$(cKd5I zZS-Fujr@WkMMs^mqy&?{KvaOrWxNDyCxV9e$(v}Z^+4UR3T<6gfI8@lmj_3% zzAO)QFr+P$!5NY4r89Nl1TfX_AoeJT>V-jp#BTdbpWPKtS^8<5)db?x=&q5I(K%NU zW5GW_EclPak;M1@^JDej%J?6P-30+iDE54j@6NnJhtzZSV9S_W^N06BuGe4ISYPkW zf8W}UP>0_*u2YsGVDS@MRv(fDolAwxq$G0qlicNO+yaL*j>Y;Ba~Xo3Q=sRmoNsiC zxiq+be7i)Z1?!iwuEsuCHCTaG#zk9bQVy$AQ=I+&W;yy^5F6-eCJi2#Xlpm+7R9j4 zm1=D2U-`bf7^zKbaygM(zkcGgzq+6PIy_f32CL%BJ@eB;yZ2ZPjxs^-mptu?pcwyZ zz&AhUKljTD}Ado&VZ_>$`a>k;~`$Cf4 zbA8sp1gUASZe+MGe`~OBw(Me$}h_WHECf+(WEBF zIgJlyDNZ>1In-m?e52aw7h9i~esXFn3b`7%&&nh6K#hZd2(JxG@}b!3gVOo*=oT+EQgzZ^80g`EDLBtC)X1uzO$zGjtC6_h`My zzw}i@*t>9!{3=N3l4jbmB44nifz<$xuOaT3d=nvr2j&TAFBB)A)l>a{f)J-Il z-rZd}c;HxVUN%hT_t>7t+H7p}-!k4mXT5)M_{kHv%`Xs=21l4gJaAps;McSlBrB=E zxm>XGq zh)fzDI1d3~hOzoisn#hAf!qVlL1!!LETdlY)|m^{-CqfRU`h7$Ws$W0Ck?T60^!Yb zOetKr4I0`cJW?VQrRyrC`F34gZHlp&-i(p7G0qw-+HcmcOD)pKZ%HTcax*) z>+8v>%2-kJt~tEE3_NsWpwoYF^+Cfx3=hRT=1b*LKVe{?tIV|ot#l!awy`3-8_Y8!P{W778ki5ib0&TPC1v{pJlaLxe_ zoRf`0oU_jT99EO*#cJXxF>Oxv+HsuPX!*1Tt1 z*{{fQt8an-dmSmKzv-mWZSuIFkx7MiDF(=8SAOJ(kgLYg_xm5WH~B-ZIT;*;`LU_> zk&%-t3ePn1AT^?}8W1*Ag@ZLG#u)i3)GxvLZB$)qzzbS*ckAvckEhK5Ni)30A(NJ! zz<3ZBW3l`kejk%Gcg)gubY(K7wtm>&)Enj>{EX^_@1)f->1M1S-1ZmspMR7}N8))9 zt8V}3IzX((C064SnYR7_IzX((C04Wk|545QXTOgBa5e5P;*wv+D8&1}j@gLvAj;#v z(t&?GrvGhKEAjFF`$}S>%>Vo{|HrDq|MXqZM3TjSEy*HL{{JR_lEuki4m8mCHROGp zJnz@^%}&X`W_SK|BmOU&@`?9}vLWig-=zb}Z+|n?;8!%h!0zW?Hfb9Ex`UI@P5BFU z3*!C%&GbQ(1yL4%rw))O{%WQHapVs%5lS54^Doc=Vj}SmkVGO<^8C3ed47-U_fJeD z7BwX2+h?174uE>m#H5KeSw_7e^T^z@QzkJf-ig~!!%PICZ*;LF%a2QIB1`4(oGz_U znh?9l`>C0ep-XYsiq;CNWNoS3Tg&GiIi1G($?DO|C8v$`K$tsL7jn6NL_NW`wOzk1 z@9smbZP3cQ+jR&1VneQ*d<`K=nejs5>gN(PT9RHxhfu821gV)0fy$RV`|toYrgymI zC}|||hkx;*e2-Xygxgs`Z~M&0-tnu~)}QS9MbLDHk(<&8ee-fWNmfpibXhgJU6g<@ z3jD6lXxakP`L94|;%met1yKjof!`|`(}xDV@Z2Kz4Y)nF=Nwiw>~g_z`Az*~kxcWZ zz8blq8a!n;Zc=kWzXM+FgrHI7bgb~TQ}CUyAIoh|WKxMsXITE~2B1Gg0!KrUC>ViW zct1IDKK5gg?~M-jizr0Q?)%SjFNFKv7zKY*yMq1BHc?jwR)w+(%NPLk{W<$1kAV2i&RbCl`Qy0~0 z`jgX%h{e2n+Q$%dKZ&bZwK?nGll6rDJ04%dgXR*SBR{le$W?Z*s14SZ5kj;7C;d(iZj@6)@Kv4mn& z@8o{X?3+b9Gwlb3`7~b+E3K2TO1{!B?Eb-Vj(rm}gI*ZUox<6Gmt& z6=BE>s1|%MhzBTvm4Y(+6FN)i;c){VXo|oP_%$db5V(_R=Rm2dRnUt-%93STDk;1zJ?*xm4nZ6U9zcIO120Xk>`ymAJ7Gw^X7tL3E>t4kXca zCI$_}aETZw5<_GnGC{;-h-efMha)18MC_G_I{)+Wb`~8}qlMmFo$j05dlXX_SeI%F z{!&x&@6qUc&llU`@6!%GvwFflYMk0;7~FP2zcHey0b2~TeWN@~Y$eQz#sdzpP=7zv z_%p99+O-VMn78YX!OYIBy0=?7$U(NMH>{TbwImopV-{DS+AxvDC zMeD1KCFR507kDcQc^{@1_YVTMGfC3Wpz6Gj^E`AAYs~#Q@EK=|u;g;_io4cr_aC7} z+XuLN1iorqFL_d{LO#}1TE@`^Ca(ff<9DrA!*|^Dmez_cKn~b3HDZ=*wsKmE`Dd0*6ruZ;}%l%tD#iciIy{mv(6u;UjsZcUW;_<}h5-U39k5p~=dzyCmDT-$`< zMQz#HL$#?|pM}W1-amh59I?BRcn$vrVSG0glAaT%?U`yEX zfJ-_QJX%&YaQYh;i+b4PBCAMcs`!R49Wx8A$0*NwB6pc6mly&jk=IC zG|pgz9oGoYhu(|o%f-acQyJM|sZ+I+)lYaX+eKec#W;d2_GQ*9X~o5hTScYgT%{KK zscYFxCTAA`fm0>kSCO2m?C4%ki)avbvj|wxGt!U%RV;i|2 z=>;Wzu^ux|HSV+f#x#Eb9{aR|ey#Xm{#BK8;o(Ijl)~9sZj_%e=}LO}PUFj9{@Umo zY5(#c+27_UkIx>b2Av@ch0ND3M#cE{+ zoR%1mBjd#V*8*_6N+>^-O?AYx_Mzq&H)zsu)i#`m+13*{_9 zbk-P9%Xnue75Lk%lgaXV+3c&?F_qh4KeSr9c{#lfon|{MM$59KkfZRdCTc6I+_o1A z+}O&rks!YC?b&wrR~FCj2c<|$biFxfZ0_<7+({jPf4ii}&U%G1U9q$}aG)Q}nwqq# zq>TrfRcDWrK#s+DfOC}!Ny~hza<$38nQFVvIVLkX_U0o?cix4U`O14o2?&W3(l#$p zC-k($>n9?k8|gJ(+wH+U7#A9t)3Fx3UonbY_iW^?$cluIA9zfY#?zf7^et6dBSqlJ zDldQIAp9PoBeATU*jhl;fxoT;kYeo3pk9Rx=`l%&`P^<;HCwRrwD`+#pDh6w-)|by z`D`sp0`pDa&^i0|t5KuXV6wG7e)-Qsj@vnYcmPuNEnu1HC`mogg!Xy4qJ>VBj<)NQ z4tSD5sjBB>({ewol4ZS1s&(RRdxpTJ&+``_Y|quiovYDlTRLoD;s4%?I-_yR`A35Y zoSZ4DIHqXL#K&d#$Cq$!%5=F*19hfOx8GjF->X%E7+IepPA(=+ul}!eppGzemrd3^ z_6{vFeX`Z^n~^k{L?{<(+S{vrz!q0zBtc}=0<3|LL_N53M7d(->$sr3feD!Qq> zTY$ruhT@+1GVK0}^^*S6*!z)2MUabk@c>w+ziZx_IV#P^|H9GoMlqV-aKt)*qnL|t z3M5z}|ALoP**1q-yQ}Vqa(^HgT00%4`yskM!MT87g--vr zbCigg5V4E@e%Qso&Zl6dt+RvLJfTS#-A+{9@qwJ5F_lTlNdP@m04BMzRZAOj!9oUY!FsPunbzzbK8D z$O~;7>{XpE*l6X8W{A{3-Q5h>vyq{}?~ZEQz!Yl-0|A8?Q}q#do-M1pD}#Off#$DL zrz^^9hFxuHs%j(0CNEcC2s_0Wr$&CNsg1rv(lgCrxC&;nugq>P9ld2}dVRvYE#JJw z(UrZ;oy?ih1Fmk&3Iqa$1zAm0f#$m{>WqfJ6(}+8`Ro4bZ~Z~yW1`IdULBBj%&rO7 z&WnE#DJQwDL}IMgBaji&#DW>eK3qFGDfPPOd+`XE`%Ts*c~neGh7 z$j;N<*$pK>9~%@;$M)Cc^KTzUZ>)W zjV#nIGMX+c^Ur^V2OMXgpD>OLt@|c#8AsDuj~hMlU<@7HR00>h3|!m910e`j&)Mh` z`nwjNReSuX4i%CG4`dm2X(9H@d)M1qD z{j&#c+DGH%Fx%ID_ie4|4PFH}LWLgL*7cT`6!uKZY&sEojm1?z{Ux;Qcj>MCt&c=} zOk_(T>cFpcfN?KIXc#=?E<1%WneW|Z4sm#!&3}pl7Zdat;(VOesEtZ7s!x{?8fjGQ z@0>M!svC9_RWS#NiT0Y?331-dh}^IEG*o6OKL=-NIH|FRMYpuEFy?08)$h@#!rZVx zmlblSzgtPUlD_zigsaiEJaIHmoqHKD{h_};j8ZsZ9C)^b^@|15JE=cxOpyOpUeMqD z>Y!6wz)QFe7%w-tTb~hNdMSV1$j@fna(4OMKxp6nu#~HipN+<0=vT_Wz+y>cYWzDH z^?sW{BR(dwb^dKS;0xMN$KKFJh3ZxhRmm`B2q6qtheW)pBjT5sRLn9MIpba}58}AW ze22kk`K*JZyvjhR_p*?A8Qb$^MNX7Tgw9dg2j0@S{Eb{mvyW9Dpc1qkOmBwU^e1w? zgQ~uOPn`@Ps!i(WK0of$Kx@2{EJhZ;Aaj-bBCThiL0X)c5WFDzBv{qj|9HDZ;CAl~ zG3tCJ1Va&lr`Nji^ znuerXJ#^a-9xHYFk&|Z1>+R*qt5coRb;=F&$!zAyF+fm@fZ zKdszK8}ETu9;}C!SUYso&fqPYk(4@;R^?EZ6?} zNb$|}FqR<8>5~ZfD`b&@VWEKql2Fgq4!i!Bg1>)el1Quz;Y1rX3=zb54>@ksT8?r~ znj>)A3sRC-lUTbxT-+~ufr)64ReB zH-g}Sh-pF~+S{K$P@*#1e(agmhzI7t?cXugsM%ZN=FDQ7u3I+x4V8HcHiLA=!RxG) zyOg;7>WhPgqIXOjCtwC=J9CT{Dhb|Sh4^1G>BQ%VH9-Fzbl_s59#@sLo@^AOL7`84 zH)YWoZGm0JqisAe`FMM?YYr6kyS%m=6C_j1TljlQ(ASeUX;7aBz$LVs}tk;+UD`o zZW3)uZE9VHcfLK}ak}V;1?c*0;flg6!>zdaElRNdqMlc-20hXyv06(Dg}ufr{jx=? zTRE8ay+cuhb*^j4N=<6mt3D5VA4+|)o&#(7+r4dHLuf1r3pvy^z@X7m3qI`<_H9sd z{$bf^77ZJ&f#=ogGYNG95QG>|a&7Wd`2`;a@>8X?UGPYrQ$c(VLEM;T*^j2z$5=Jb zeaz>*#@1~(K^Yt-{^3<7ulzL?3i7dCQ&M!>{3xsi9AOdhqOA1uVti8g*oge>6?>#n z+9O2)n7YbZho=(Aae&)5XsUzRe>`lLDxf=gbzD7pR`SdHZ|`2j^d?Yrf|Yk_f>jH$ z8u|C_FnFLCVgzefWk=h+VNP10J=gdBZf+f)lG=l4kHqSv6tYv-y7>nKKK{=U-b~xe z8!JfN={qe=+~X2oa%zUkY-8s{gdcpO6N6oAxFoaM+LT@7-x+T|Pb0adH{v?9*|{no z?(p!(ss=?F?%c(>@=NW4L8cfNJV5&PyyhBXu5SGyy?USznslG0@vTV$^o+B2{MYWO zrk>);;v4H+^tH4F?pfOUIW3) zw90EChUvuN2mf7l!011N9j(fQ=b@cE)DZrmuq8x5g*nN#_&t(MVLagVSdq|&_EKdh zax&&hl2Ep`f@Jcy7rmFFo_K4v%o4URd%`e!!BI(jUF~YAb28<%BbkQCJIdm9Jp49X zzRGi{JBa@hksK#*{MGJ9PCk!yKMU5hsSCYwH(R@Q+-^{2;{zI=1tCRqwBdpCva+KP zl>*HG_vU!j^_R5=cWFiavE14GsmJH?JYLT^NR{5-J8@pw(ZK_$swRq@l0w=0a-JJD zA%9!7y9j)soHg=wQAMfo%*~@nqXiAhH0I|7XJ%RMp8|H0ci{n){&B+$Ca|LtKBEMI^GS+Oo_8xu8}rQ_TARRk-a}UZ>^0bozX;Y z(L-*cYzH>wsKmY}-E$$W=GMwtI8LC0Hi!AgZIsW81(NUkpcxHy7#0iz0>r$8Pk-$# zX@)k_4ZO z=-Q~x^>qqdamH~PPRRoadfG%aEV;1lW;2|fpfzCRD06}QoBQ%igZ>NlpE7tcKJ)34 z0@8hfxpyu3NYX!{DxMwtdRK(chl|QA2n@&v35D;tq6v#JnY0?DWE=ZxulC zlIqsW1vardZmqS*Rgg23(;0C#=p06>)k1K}F~uUQEAN{VUHKhGgP$UMOL14D&S@&r ztXan+VH29jrqDSMM#Bwq)w%fW%Ru<;4>zavg_K@usXkN^Ceb1VSp`1tUp;WV^(sZD{shnE^0fR)W7PUO-HAR7-{8fvWMSCI<6W z1$Owe`KNG+>^HR>CKox20!i9GZ~$(+oRnCGf19@Suu}8XR??W>Hzv1x}ZaB=*fu`=F4%RJ%O?F5p=eL&;<91z~(7MDE`i%!2?hZoWpM( zlImj(2Tp?K@Bkv}L>B5~P9R_S#&dv%c2$?zn|; zN-Q{MnG?E?!Y958$2fO%_Al;d(twDo`o*OqUaS95$3K?_%7G2gLP?=@$$ zq*@P#94Q5z^Tqw-pjmdJTi6%bu1TXklCnFXNGNu=g@Mg`mwLJ04^WLkR(orSZ&-B> zpMCCbOeS_G(lbNy# zyLBg>)yLAq1JzSrt0SU9ncSflI&@xe ztAqAAds)4Yn6jacO?7kz-&1XhVDE***qp=}#7)F6%OP=7m=#pR4ieNZp{bKB#11JN zXFl)6pw_;zJQ6s(NfU^mY_OimO6jn5zlC_WQ$G%>jHzityj!kbLsZPR>kg3MtiEK$ z+Od0=EBkwW6Kv98xMXCrS#oV4PxFbjy7d>VC`7a#6NQ%V-J8Fk?NA}{edOEI`dc)|J{W`r#Vf*x{RRTV`W`4D9v znZvVk`gYZw8u^rNB|}Z>ODzp^oQa8fCp|$T=*)Ox% zzl?zvK~yjt`7Oo8ZGMGT+J#Y$s=H_TGS&IZMV~%jw`z3rKXsyU`3u7&>2rqEH|wym4$S(%}ae}KleE4ncEcKWLn4=C^Itm75Te7@xW6k zH%{R`cT5h%raF*a;IgLROa}Z>!5PLg54|~|wOvj>iv_*)l&3NlhH_iGGgh`|8FwD@ z!59z3P1~XFKbNRax+V~8c1l|yf&Au!kKw;FDIR=aV9KU7r9q)nd+&uoOmev^^-JB* zT2GG>w>Ntn*SfGaV+ggi1WXF5?K-9$+4ZG*%{zf>=Aq2>Dch$gjYZWu6$;)X)9P0X zW8g^Rhj8YSV_FbbxNngpRp6JyJ9o^@2MVpPIXY8)v+7^tBuoQ&^EC|sR<+@I)$p%8 z9q~>Kl8N&)?5kZMfs|5N>4j+%1s=>^fN(QnLP{HBS#YDwnZ>!xH=O^qxl!rI@=oc@ z?a$*&Dl*Mvb_n%$dkni#+RDJ2UEQO>Lkn{|z9-*bxqL{6HS>geBhEC^Gez{sm;2NN zYOI)Y;^XxgaH~Hkq{=}yomM|WZy3oVeyL2_VWJdYgqSlk&e!M=Hz+dp0yY4@^k|c|h>$11W^BfS{XWruhxGx^qr8jj-j=}@H&a_7dad_YwllNcTcmGmP(?9fF z$kEZ1UUkCK_Pm&`L#MUlH$IU)0hDO|3*~FJNIlZqV_t03Ci0h5+COCrJ4L@Ff9y}P z>b#>cf6xh~gMiUwO2d zcSHF!$o-bp7s~@pd0OdMp`d=9PX`1po2Hxlf2rk}NTB_Hwt*96^2d@1Z6abWlO@Fi z18vzaPsUQ$Dlq89W;`e&8)#zJA8V3;k3eI7#r>Nt>9OrAN2Q|O9x6`^3=x0hHeyFZF zL}ZY-Q~cDA22a?-fi17IBe{(?loK$Ec%VXBKQ|}=cNHZGLrt|b*hhE{>U~TLxEXVh z`}px@U>`$ZgC|qOc^eVz>F`_IZYRmIJwJ^0V=GN!ns#ysTm?Hf)e<;RCd>FxnHIu6fI1_$f@EZrbOI(vIgoG05Absb2z%=c}-VUs6(O!UN%#BU3Zj zwO6+SxrfYI()kSw=tsq zzhsVk!Yzw=gLIF0)Oo@`E+L!E`z^lrFuv0xNxhFgW6l_K2J#SP+AfyujKl-<=Bq3> zgx3!pzVlKi&^JFIFJKyczn7*`6#9M3-o3GJa(HQR$#mmMB|$^eM*cf+r~EP382_3t z`2mw!k8oz@>8vI*Od;08afW9kces%wudB3C(|J|FrO(aGiz1tP;kYC=?UYhU91t|4 zv1SxI)yd8&pZr*Uw${;hAaV0cxnM*gx#AC+fG^$X?c5Dxm8)J@M4lh~a@)o2CwL%b zCNNOlXvoV_?}=XZh`1!fYVWFCDqFUa>2+y}VlSlZaHR^@-ZcUzIO~7n5B}?;KJcZW zAwoy4?Le@cIZh0Dfy$Y_0BfDgd#q zXAB>I^bvKKJNw<3iNJYU7As$woAn8^>O%u5-sMWCR)fycg!aB`2Jir#@Gy_ec>c-I z4C6->tP{>CIC)8TtzM2ofET%t6cs`XVK80IYivch_gys14$UiA9||hn16}RBuLeXF^0b+5KX-S%+uwaaN7j4gjJ3=v3HP%=!U@`Ng-hK9 z3u{F~kOpVBkFkxCws&ashINkNgU3cFa62BL#QhYjfm-_DSR`xnq~knOl7>e@G$~2O zqNxEm-kc4W7>r$lOF3Ua6UySe^IfCpxLCBGT*q7UtiY)UVy5I6lcHPZ?6 zvcKupmC0L7^7RrE+PqU|d!%SMMV33m;fV9xy>h))ogvMiM+a>$zyC|raQ}+um|7t& zm=vB?XoN*ZlY!j_wF^~YM+AbW<&kq{u}D21FC?PIG)xL&fHL{M9-kX1xv6qpYmnil zQ(3gfy1=)u^JW)-B4WAX* zskgH^0UnXx6U|NkPLLJNXvvVJRV#8KRY>$l^CF!lZ|LnW;QE4`dc#57(#8h@{yQ*X zzd(ium{ob=3qfzn93^YUAKSlq72S35fR`>%Cvlc(eQz7FPLB+jR%mS!8W)bqt{N2% z;RtMwInhddLTm8G17@t6w5J{<_SP_0lgorLh!GFy1uX@IK22M_kG!}^khvfEqd$;g zBe`KUUbRKN;=`U?8gLGF-|a(AUEQMs#EVUTl97zlzA@t))u_o?1Nk1IVh`pygmdI4 zisyTWujN5=O7JwokYL)#+6;M2l22xbm{3e+_t=-#{D?FUftb}N+i_}5OO4Ek8+~z=PF?_3miS?8^JE=NTF@U^QmXwe|X)uG( z)HPLU%p^DhOs#xlp5qbC=XAuT0`*g|_c3R=n(fKCM-SZt13e0@^?kf#zF7_M>xvIu zw(}Mie4(N()KtmegM9tOq!c9~F`Xe~6PwIDn2(m(*gAVM!_78YEn73Td-XHrbhm+b zBGoH>9}?r>qf>#!D|%AKmE*D)sa#ks%gKgTT=F<3r1H(8{WXN+H_%rzr2Q%FXQ1GL_?&K&F;#`+!OGX>7dz3Q756R z(6eA&n>rHZ6o&-Yy|0YXST~&WP@C=7#)nn~cU&bAsAWMHW6E=*f_8zH>W}aMRg<)@ z&HR3{TNTH*ZyGWxVa;bf$gzDHnjl{Wm7NYBrVhhbKRyo^l#FY5UiTvF6rH3n=p!j=0mc{(duL&=f-BDX~Q zfv}x^J^Zt8qGZfjaa&N;`Zx@lo<308>+!hYq& zL)86z3VcKFG>lMjtdu=W2t0Kir*Et=9Y8(C~@G& zllDNQKg{&()?s>Wb3k9QR17y|!sj=(t`;*w69j_8Q{Ad>sq7F2Yl~YGSN9!98pVpb z7NnRh0%Otqc;JOM?BemFZ8&v;6e>NRM4w;aB?Z%7Opt54S%X=Lp;7vwG5pwDwN~`q z6LZuRnZsbZMI<5u(ovc; zQIHOah;#v^g&q+RA<{uw2m(^1cN7q$cOt#_4$?~?^bVmV)Bpib-h0PBDl<* zGk#y2lgMKi% z$XM;w;p7thP5IQs@(Fc?$J8OcNrhVENZRm7z5~IdhuHdEf5eSWfh}vQF~Q8y`--Gg z^h!%wzMCsMEI)irys(`|G{$1uVaFY(g$=0`iVhoSQ?G||$zom2hAd4a1Fz;bRbAQ3 zeZ);e-}sAMi~K>H^U?&M{6xNAN|^QMO=vZp8QYm#4=X4o(F~a}$eW4eB#yWy_hkDU zR``D$fN61ra)mBM(ke~Un43n(Vy+!zqkJxg=gLY5tV&MCw0CXcs?Ky@Uu1mUzLj+K zHE5s3u6jGVdv$At!W*w$XH+s)B{O}{#Os;K@3kXq@UzWL<>O3aDh zi#X=F@BbP+$#(8R;dL3&?6R4!C>A0zC2Y$0cFOX~%*xTj^;$207iD_u!^ZdFU&P$M z)O*oe<@3Crx}VfZ>$RD%@CT+FftEtIO&ym)4W?R>1@|C2UujB52d}laQbyKze_BhT z`s8}Idu_K^d%u8%ru>yMXJG?J0}N_B@GYIck;-u1va#yaP;PJwE|NaEVPIaOzi|{9 znCb%xNk&&r?m;R7I##Q` z^^~Ti)PyVH4RL2gy)E*?2N^$!l;=q4*^Celt;FmxPra9N6i6%>wjNm;X*Aj>nJCubC`&UDSeaaEM}qaok7kDVT$*pq}?6L}~m z6qx#TPTmb_8cUPeN|Bz&G&1RFGh+=)>+Zy1K%$`kR-yl&i;1eh!7220GFaQ^sxwxQ zsMRIAvf@wg^e4>3x9+?(57%&PhpEJDs%d2v%{}859|?|`i2~7`=Sh=z%%_A%PVYaT zGacvlR2YZDk*lI>^oJ1s$EegDzAnBw5ZA@n08X>-V8*Q3;5pi4(R7BxA2TPT&qWHD z0SAzgupQ*hUA-W|Yb=?!{oJ?^t{y6X5b%vF+&P=S}lT1}-A(fiGbE{^Sq<7GYwpv-Ig80%(P{spR*!HW9Wpx22>A z7mC14aKM9_RaqvPyO907$Kg||CUs*Vu{k~U?IUAR^fl`dZom^5JCl2y3g5?v+bzO8xO4!@Q}5klV#K4HpLaw&o@v3!$rtSM!%(6X?50)3Ylpc%TGA$%Lqce#?)L!YkP!IlgMg>DqB5uDOJ0fRdn=XX6&{*WDdSO(Uq zKD^bOI2IH)P1vOC&mTbBIu_xzaO7tT0bvLAh#mzUpO=+XJd5v@TT_|$!1pg<_zra& zc`vB(qJk{0XG+5lZML`gGrt?GE@I5T=(0I9QI7@AQ!WRcYw1$_@QrXIg|y)yrAMQM zIQ_YiY>X$ZYTwqHCo+5U^ae53X-QG|>v#wg7!G#y37gWqt}COvvU8|>b^V}MTDr~4 zt>mfvF*o;5aglNck;l~98w%S;!nvAv()+~Tx}|J?!c;76PXwTZFE1HxW}ODJb`N_ zUw;FxfvDhC{@^?E>3Xp1&T(RK!o9Zj;oPpF@oQ_}TV144v-A5D>ZdSOsask=aKd5OfEHJ+ zi`zF}y{U!--?zJ_rV| z@Qx0*%^9x`D?Q6d$ha*2HMxE4tKisAnawGxad}-`iUJ{eby=43Ot{DgzLi2Ux>b3} z(M`UQ*iItX_3Oi5VNNuwjb&u*T^E!DaP^p(PP|T)ZK>Y#R<<5lsl@YGKnna)hoea> zlm{`FATu-I59iM9$e1)R)}UznXh}m({TqOo+ebq9QZ=YUvsI8Sa|A~Ck$7<|ry@|I z)d}vk7)}dgc{0vD=G^zpQ{}=eKH+2c5x@yx@kyLH@A%WjeOKRwqH31hg>wZ%M!$t2 zb+cHn8jP#y;b|BwF|E z+}@9-=xxpN6dpV#WjRDa1{!}}L_22@h=v`*$9$A4)7Rk9St7pw8{nyMctC@=7oJW5 z;?3ms;Mzib@z3QgGnKF*;t-l9r@!U5|M$-RB_Rr2S_z^VG(IyJ7saN2&A<`UtGbbL zg$2^#k8&|>*dNRAY*4`bwqr*E5oVRsHI9iSZk|<22=&?hQj};~^WKt#NUb z^Asf+T?w-oy3&;8({tkG{XzL3>U$%wtY8{0s=Q2 z=al*aVj)z|WsC>NL0OG9IvbLRsc#Ouh=4UjKm4K}eFVxPMv918W91C|@YrN%jFv(7 z?UWi0^B9l}w)o;%Lj@9yXT>I?=664BJL%0>G(?;nqxh0kACrg=U_V_B`z{<3ZQ>0L zdG|H&O>r!r7T%B$i`<_+BQW#4YVAlmCMJ#`F(3by#S%m2r~k)a2$PFJNW4oU1L56q zW=MW+-|d~vm3-@P>;!G&%ls8vbSsfGkT%b$41x2&jtUifI#OQ;97k^h_#?x%%U&b3 zygw<697;Xc7|0I zm8v0RE&6U|FXZx21HgRwBdNPt!eJ2M8&)tF2`5|J=7WyRM6Gr>$5@Nc*3$z^d3Zg) zAjho;;nKbL;&p>Fu{}q7L^11c$MiNrdO0F8e|V35#iD=LA=C5{)Ny5AlyxLUu3<{! zTBbH{!$kX8o;^!T`pDk{X29?T;wR^;FYXcea4g=izL~L#bvibiNcy+(-5YUF!3^uI zIg*1q2*&(Vs1|QsPg0UtY4ORIMb=wTe7<4*Sh;F^ZDU<*R)PiQm%7)bb+XH)d4~D= z1vciDRbLj8xp+7ncyx8iNN>3_1U0$^y;4>*+t;0P@ksW?$}QZS>j<%WOIo_dBndk|qJ?QDi=TaKQNf-N^r z2sXJ4VG?#jxI)v4VYXXSA5Gf|j5!=+;@<%Abj8S${JnmT4wVYN2_BQj8*8Iy(pf%! ztnbH>dqiff;ra2OrZE453T+f74qo6^NHTjE7oYdx>%K!X zXci3?x*dvrch+(tT7&cStL;n0?5+-QyjQBI5~pA~qCmXX&{W!n8n=q@XmyBaeJltE ziiNDmif<)n_tVtQL+MQLz;?85V|FcPU&!VIw0*t15bHZl?K5gU9n5b)DYChCE*K>}Pi;&8Z3TLel1zoV!^LQV6k-j0}|-815k=wyR*3 ze}z~CnVkP@0AN@|&%}ZW5|*4hxz==%9v0VndvA3^UX6Wy>vL6^^tByq;e`EtQhKhU zmQTSWdCzTJ`ccQw1q;T7fjeL;9y%^CnO+sA$YX7@#8#yEuqo_m6H9d$^6s#g)%gt* z9H0i**(ykZiR@`ocC&sHZkJwtzO(%s@FKhr@jZI{*LzdV?=0^N%ax~wF338Uau=+0 zZAAD_H=Nv#n;N}qIy->WhW8EC$O2MhJZoP~eU`t=c_;Zs~}(eVHxF+jsRminb4lEBUV^O8zF%i{w2|y%2518a8h_lgm36%{>lk z88_PIFmnpIL}uk9>CB%#8oK@}_e(B=cI@&mjCSY)iN5u4Ssb^&6Y}o+V+P%FQ_9Tj z{zq8#YSvfNR1+ao=tc>mwX%}Af}6m%vIgt8kCu+i`*zXU`s`r}fWV~_*%lumRTg#e zPHEfV22R(MPJ_g`&4ihigDvGtnfIt=BFTEvCjfj&aTW;*Zp;}UmrI$V@hFVGx(4K7 zyfkJ;1Y3waJ@4#TD#o@y)N2`Nd{xi4?loz96gVbLz33^`DmilyZ*sRj!my)MbhlWk z?TR^fnuSkwQ@4ye0S7r?=GrttJvkR`r--kN&bXC#`0y9tT+O5Emk7TOy;eaPq3%L4 z@mbmWs8)9M=?3wVTHxNe^cRpffBcQB7GDm#2*L~XhI+9s?b&Fxj~J=I!D7}-geJbU zogpApS~&-nP_S+9<;fEVk&##@RvtBx`~*NSNA>B=ivqw`!$poquuV$=^C=W8SL>94 zP=Gu3J`@Z9@sB>asVn#pGyJSJU?$Q%KX>Qu>+nKPB2^;^$xG?Xp7{*`Hg=taY^V=< zSsY4WPQgd)#9UMwoXD?z*6SL!Oc>RC^f@I?B0V&NQbs7R#~u}OK(p`XDRBlQJgyt7 zv*r%v4ow?ziix_*A?;S$<)_4w`YI8$)lhz@-b{`jk|ai+$$T}DOhW|QPv;Bu(BDDA4!(uaj*4ql$lH^0(x$X@6zyw7hyyTQy( zVV+U_%=vQRlM%4)8%I3wsW{E43$C=;ksybMEXrI)CD!I!4?cW4b6=<{IC_Nt6GG&~ z-Wetm`m5rYN?N$Bog+-1x2I{|2Pg+k#}-(6@J2zIe*-8}LI%2PTkD8PGj<1E=4KNiPZFWX3*2@H90E1EXhx7UglnVVrcbPCf(^ai zO_fq|zS&@p+^QuGK&TJ(&?i``3MS?bj~`w%lKApF>V4gVp94#B(t-%CXFvZ6oQI@7 z&$@W%D%?CvRfk;*v`#Uo9~0>B@J6uu%b1w_bmfzyCZwj@ZLMvgP1qv@dy2gccEF1 zw@aSuZR=XMQ8pz}T%R0;srPx(%-p#Bw8wP1y*=fseP?Qh*b|8`5) z-*XFO;fNt<>3L&EAMLEFe(F!$&A|I;jE)qCT=$o*HTq>HCdW>$2Bz_bOK|zY^6UI- z*mtGUf%dEV`rVFHr_!%;37dzvgHELzW!hfzoN>gY51#|MY2t?4dcW5SFG45Jj%3FL zMQR1SI*x*~H{yn`n+;oB%B(i++NVp)a`)|Sz6)4wK&J)m7oYfjXvr=s9C=%zXu^0y z;|8UHDbcGXIR8tbH{9_IdNGLp9#$>rO%U-E_-w}|B9%jliu`){zAoktg$>(&RoJJs zEh|FvdFp{jJ@t}B$eTJ%7Hb8=4DLDy(F692%PkG1{@BstyA_!Hz5GmKNeBQZY&DW8 z`@r&}+w4-U#M*d+|9Kp7luM{qGl+YnPPlMR*?A#&@=6^{*yij`$WvWScP>}HB#LMh za)8E5cG#wT+fifW!^>_DH%VD?q~=x=a1^zn_rH4d?w5sjw*V5ca$AmKq)|;rdAss7?xHCTJ?v|@w2>LsHm4fs**l-<5Tnuv!wAF7w zr=$;Fu06Wo6d7aCLMUQbde502%|tuZCBDovAcM$2e(!jVnTJV=#5E@DxL3iSKYlW% z^as&m_xpyx%*6dXw)||L|1CQQpKcd|g4ajdyl#WcjkDi}@eIsGdy~`^*?<2*qH-(&pEEuos&vY+5cwR8o)9Gv%xpv+j z@qlHb-E+sdEh1G`v#q_7nOc`%GqkT)kfp;bF=Po%2l1VMN8Fqx=;LM*>g$4k=yjFO z&D@a^%^ipVs`ZU9`>Ts1hkH^}*ClQJow}U1xjN?5i$A}S@_65J|1^nm`A`OP4&Q-& z>lG@E-aM?57r__zGSpZQ!`YYDiOy#NhDIat|C;k}F^qB&PG zOrzd-bhA7)+quRq9c@JB_Z#rqlTK}nJ;ewo-(ULf^W*Z$QrcRqyRciBo##)_c26C7 z_k&WnGjTcrjX`+t{`5jJ*-cIOo`2>|pxg*SIAh8(K_^L=bnHh1Q z^HLccA#xIcOJ6+7$9Z(nxqqJ??#yN{nV6vC6j)rpDjeDd&^rcAkZhD}v2aVIa2g<^ zWTw109lP2g>G7Qjw~PjsJx|guhURX%L;66c0VP4AG)4Y^Q90<`OOx3J(ZS8Z0AA$ltv$C2uWOrNtS;h5d-7s(yX8Ej zSfdNtCrX)$B{+^V3U?V@xgmJZMX7pfgK`hUUKhT7o*Vaa@tE7HJ$p6@XH3-liE5Y>4RFnW@(Rrs(J9VGUG@_obO_!O@T?{B3ybmo zpa+&nw}n1UzLoGVrYl^5#L+zg5i&qIUmw_Bat%0OR%-Nu5nri+I{5a&MYQDVTkuEi ziw6@fy7a8Q2`BK8dzqmQg=*;Zvy{W>qepHr*bS|OIxp%&pP&KkMLF4*C(L4y@_|X@ zc3Mrai*cBDJlLBi6&mwo5p99aN~j^8xrmnk0KWgudjs=%gJ~U<)ztxV^E?@Cs@GV% zdfli&25WZCx5K+X5K7FX5W9&(E`Zj&tMX-y-gTRN+le7UPHd<7l-EvKTI!S1=_qK0 zXsqB;V7^1~$D^EqsSgw#_b!4C8fg*zU@AC!UbnfRUpcdy_V;)LozfXOwgC!ql91C! zWa!#PUvLTV3&AvRY8Ic>Z%euUs-`Y-hDSBgJ1It6y2#z;gPAnRaHC%C*99KUqv4#w z%@bB?3Qo6y$sDO9h`-l6jV~a;noJ5M0X!08;&|3>0I$?ouo&s#Hr}{N6zQ5 zZ}1RL*1$ShN0!t@wveB#WRK80^ASqDAn^gf+rxR(ps1+ssdW-Oyt^k|9UT2=BX(l*D6a&cQR z?`zitc#<g9%m7jB9(eG?!ux9PBMg`axHDsb+-*l9p^u!H`XLgK4j=w=?3udFx1@E zpnoGnq%f#5EkzAjQm*)ax4an|bEAaM!|7U}41nh3*4zRi@e1DZnnz-d>fwyw!ay(%pvFZ+=#jXm2xa`qSW*t_oVja7eX& ztihu~7L}m&6G+Q%z)w(c7AA6_$Te+Ezx3H%^weaqFat!i&htgCsw>MVb0n;Q{z1mb2>Oq*Lt{nz(mmvb@;vfxmd70STBpgk zjUucBPB0$McSfBfbz*(_DEze|6bmKmsQ-Lf=zqs{5YXqDAc{FSA8uu9$gtMc<7I4i zNwu~Vojpg3#?u~$$J4Kmk;6P$s;0-vHn80d}Emg-p(E^Pcg}mhuDe zmM7Ncxcx$^45zbF7qM>e#K(2TiA}=}w3xbEMraFJ0=N|AFMx{AWbjKS{8+Aw z;a_zxF5Ij+K44Qr5@nCfNq(*cojvU6n0is_KiogdXQ-#m@$#8B)g34D^iMK=p0xJg zwX@Y0(p6r@#O+ng>e{Tue(GJ4;4QLJ{&@b8o0#0*cig=EcO2^f&8=mSu!})xY0-CF zNe5$25#$AqCh47&M@h9Zodi`EnUrG^)rkH40rE{+%_DqJl|fJ;oh3VOS*iggHRJ_h zwdOqRf>#!fRs136c)McAnI+YR-Sm7**uRrNCUOwIwRy(djx9O`Q@Q%A%E-0J(wq8I znwHNrvqi?i?UMoBo6X3y2S{6*l%>Z`-|6+a>xt2LFaZb((|`8)WNd2x4`*q2`0Vej z?cZDX|N4xNuWk0hFq|>n$O=6}khDnw^bQEW_9RL?Y+Y5};!UUHN~ihQh7PI)KY+{M zTxkpxc~E|<<^17W!*JnUH}9~mvo((MmZINw<&Q?i*ox)rrfkM9|wI?HD@-KxD*@KkIi%8VKT*cwa46^xY zT>EDTLlTwI_QuL~q`zln9wK(q_eZf_;47QyK6VOu4Ko!TDfYGSpp*)_kUGm;Ra$Qs zZodO_@gOOM_SUdpd(LE&b`qU3F!m{P@9#$5-9=g#hf9)i}c>n}b~NS`5MdlS>~e-#D%=ik#lRD0JdS1x7{dsvb3fsz8H#jga+ zT4mEx?w%w+8jF8WFvHlEpct6$LhKb2cy((5-M_#^?%5L^G@RPrKKVmU=HGpi7!_tr>AGU=A$n`=mv6!SBbc6r!p&njcB zoy)<|GlQ(f-8Q5&&o4Fgan_z~5ay>KK;`dlJk+v!+#c$MY`6-%E z@dK?5W3K2k5`2vz9;Jo58VoZ}Nmf-zuml|GhFE0E;rDT$ zyZY-+oJ)t;^O25QbO(jO}ZbKTy3Yq|e`p8uCCz&#f-l^2019FR3hHujD)4b;BBJ=V~*-2R5$F9Rdoh)+LLgx|)QF|$KQcBHjz zuivw=-ol5hk-haB>Xhxl+DW2*ff>tK$yy5xH(7xh5N!FhO4iN2Cvnl<{))G6FMSld z>?&cMu`Rx@Qk#z9%f#Fo5U6vB!?gC7$4hakW9+-ScCNAKuF6K zTn9a_`8n*&_`Ya+d*=XWe?L9v^^Gso(o_VIZ7(vfcXQ+fX4?vbbWF_xDYH8EX4kc5 zs+@&O^oP=sN%lr}li8bxvu3zfK;tkd7*D3glvlT0eGu-E>^;9tc0mQbw(c(YZS^Y5#6rPxU~ciS!7F0WbFwN11nK zT}aKxkdj~_%@5nrV403?62S_#v7$RWFGR;U;s$gRTN7MAv|40Igyd}3$nHPxG_giToy}b_Y3Cm`22)7+@SYT4?8ia)|4*>z;+GF ztkNGwWk)L&s&|4b^q_zk=PkGG2oGvwHH0Uk-Q;2Y5J<@I{g4zRv(@#qWPUT$<# zzNbP9cwV7Vc5^{Iomyu+jDF(|a?=xhQzN5$LsrXKclRlACI8B9l$8r^S2Q@lYQz)h}LN6UgD_xeI7tz%h zNUNB;(1izD&=gN`X@+w%|L=l1nZTf(i+b=4R_a8@bBkFt+RNm}b*8YJi13SU;#Sxq z?!j5hQeH)7H;mY@sztd-SbpRcDwgT*e5s+S;DK7ZV_#O36Qn;e|9~kPnh7msZ8by^ z+0pA;PUo`ldi5jS(T8coVb1E9ANP*01p*sjlnFEaPMkQL%J6_>vwe_LDFj3u41jI)7e71iW<)t1^o@Ace1NX^hJ?%n%SY#QF z$1ei6+ZXGh+L6*cR~me?*b&=neil^`?hRWx17rYu46K=8zvKy7E4^&i{n zcp-z;O~FyONTvjo%X1B%3i!qEDm1Madyahq``Ppf8Mf`IY%;wU6RvI|8BORMCfG0Z z+3as6d~D1lHq`D3*qTND2JFVZff*o%iSmy1@dPBhL0e7A>-3D>cxHm}>x@3*AEnFF5eqAWT_^0y9Mq#v9noExPz z3`^_iYpytr#CvQU6UW?pE|;C`WNlAf00|@m7i0wPa=g^MlrgQC{%!`y^RQ>__OGY? z!UQ%zdiIMY4ivFR9d2w@iqzDxlB&!H`P>Q>&yj!c6ZD`UnCPqiZT&6@Xb|fy{suZc zt2T~#@0;c@c&3GtqNKQm%fmdddrQazvT6~2!Qtw=_^z5Ock$*k)$ac1_R)c<(4G4S zuMRdxm-nG|h$#b^*?g>8X1Qj!Sx&RF9o>c7w$s4*;eFIvAL3gJ-bxk7FOL-6UJsAx z=hHyvLEm*C{oy+Ku3~z=+C$FQ52o;xn(rCOrdirp=CK~A_1}Q4eVjMwvFl}K1!ukT zV1+Xgg6b#frc0FRKTQXUr={LC3T>i@N)RCs*6Rp1!;=!PwqR|iiqZRKP4xH7S=RMZ z?DSl^4)%YQoBiB*39SpuALu>BIG9gV2IQr4?=)i8HvXuUh+uX4&&W$2@X!Bjgbcsn z##=0eB~&)BkKO;NOnE;zK28%{<;!tMFW%JEP2;rDUl7AqH23^P=G}*uQtbVWR<>bU z@cY>B^+gd2aK$`YLpO4NT3nG>x6d{12mmO97#{%FDsuBpHWNM{qeG`rsM3lPn}-|^ zcRH)NqhRA;D`2pJV22>XMorOY!P~>=W@~-H``4!0q8_tdmA=)whh##c_Fhofx$0Fb zjKrOv1O0wI7NpXjoaHmC#jD|>+rZbH*O5+%)eP<5)n=1+&k{eAzNPACWV%Xnzwrfu zZ&6k7F5Xsc{9sK;AKFyfW|%`E?7IUbn`R(HB1c#!y_9Q)KqPnt^dY(W>nOWI)Z1v~ z`(8^$wq>UA15Mh{A?MjT?fvFNp2;<-K<`a`zl&$VMguUt&cUaB8L za0v#HzBsihrGTwn+RGUF@ho6uMTcF+!Skl)h7q(qIGhwnt_EA0Jis4V?tgCZ%=}7O zytF!f36m6pDvep<^ln$kFzfSVFr4a|?=&619~}H~({Zn*?8!~?Gh)IhE;?(feC%*J zpW-pM?mKZ-ja=l9vfqHowFQ^(y658vYJ4dZ2zKda=uWbME;nB1+v2RJ&uYUrywsT} z9x}h_Su)0|gSy6sartEPRN-2v;&1#_1Fa z7_96hctx(WP!4)6&|t#?(oT|XkE}yz5f;aFRb#}`!?5x8JCNm)=$NGBtuv<>9b$r! zhW)QN?jZF)deKabJBe*yWatjVEuraYWl>4Dpd4xt-V$tpuV{RAAp++s#W&AO)srv8 zG5&y`@x=}7SiJlg9ljtzENb1kg7|>nZ*uQ!^}0R1Zm?2S(cnu)zA!erSCHXM>UFqz z_>iG}IGM&Y`VXD2tmAWFNMBCBNIi1WLPnnE0J@d!hMhCP2_$_p=hdgYM}UKD$dZJ=q?@0MiTg+6 z$m0nkX}hv9aX%tmWB(V?HSz!&h}OuD@h4NYH!}9EZBku1+?emyXPlBMQ#t~MxuEXordTqkK?UwrjTWZKp#8_mgIqBgk(pv4?+al4nFo_TCJk&t1o9U+UFmrpXqJ>U2)+h%Uf zZ5$^v!x5AYM>=#u2P3Bkpe(%Q*&{sN0^&zas9(})Tvoti6RRkGBwY<4@5kA8*Wso~ zsS&aj`h@}94kb6-MDvGOFPkw%bbE8$rp%eA_U!`A`_9(no&3^yA+Lhm6sQ&ukui9j zc~|glYznb2j4xvP|G$8UW*^+Si#`<$IITzd6Zl}1sRdJF@y>4c`?5AOL)uKGVJB=n zcbk`iH;25eHNHrGOpBhKnZQ&u5yngPGprOmgs!~yV(o7T2S%9LKZ(`Lh(_;1&fSuA zj0S)z@X)!zbMmyhO}hj%F`=`w(fOPZaV+zj)Yf;pr$nvdv-h zn3t4n>X@jYB*TZP+1o{PFI>a7V^6I?(|Isj+oOE4Hvl1kY)JIrBk?0C4XZPLmZ7WG*egK*elU0ZmjD&~J*)j&&v+$P!_f3xv2FGWnKMK_frKL=>L=VQb9ytG6vy)2 z;x~XbKEb-L4!m3UBL6fJLYm2uSi+^2fd+$!6^4RnG6=qWQK}aPt1hhLAeM2Y$1B^{j$r2n58?Lt zhOS!e7b=+2%N6bkm+n@X4vW2f#I*182uMONO^}5=@#rlC>z33Mzf+xfr_A>DtmSD_ zk<31^q_bL=j!wQcl6xoMP1Qe}hx}Qnq^)@BSNLI95c9(kKb+eGnA40e3rYe9%#Rt5ZKe5S+I+{3%@th5Ny4>E{D|x=Dh@%1 zt%$x+qCaOe@Z?OHF+|1t($V=6lLt@*pWI-})?;^Qw@G6n-8b946*Xcu{tGu|3Yi%B zSbV5KRGyADC>c#F$F-Lk#C^Zl3e|7BpDcJ36v795eQ7s(xM6tY@P@T+$Lvx6+v>8a z(0Bgt`*nu=b-Z`3-EX|dcK|$MM+u6A`}Ex$iB|(_B@Ex3NuOjQ_UkreShWT^ zg*@s}OugFps6hfQ8odB%D>Rh5{@^EYZKC_Z%Dm0XwFctk24|7eP!l&?^t`_}E?prE zrE}Y0Zp#0RE0yfDOLzewWj)7ek4ZR{yybM7% ziP|Bdbvl{r?r>|)nS)L8ZPM-Tl`u(wkn+|gz1%XjED@PssrG?RprSLqvzT z9%_ODh{%qD9kRC@FyK>KPCG(&SF%zqMAE^>&jYo9PK z!;@T=?L6ZKi+ip*+|lUb{PmQH_$C+hTKjVxTWGY}(7lMVHh3X_aha9x98B1&iCBPH zAw_lgLPX_U^J60-<;(tryUA>U<*`?QRv}*ajM_?0r*aJLjx#_vZQkFY-Q!0-CKHcD z@zQ0JD@*T5q9%jVM96>e<}?9bUs9Dvh=u*)TcutrI+}D+oL#_{VT)I?h&GB8-~6-i z=~12i;-=?A8L-U}X_988x=CyW&;xoQo;KbCD&Te>_)EvcT zyr4_Ir4pwPMpuAie0gb=J6D0tqRRZB8!y?AckWFP^xzJzlUo#Ke3)`G{Kz%Jhooyy z0Z-OI3O}`BDaTkGxhNTHe%KJOB}s$@l0rpNmtFrQHdH9TQr3Tc6@(wVIVw`}{(C)*sbAujC`!_+;Zyesy zyVprBR~`5B#2Z-8#O_ZT8T4IQ6z!;t5-PcRfOhNilsXec{F1Cc4m==g7~+u{o?w+y zQ+rDb2l8I~2VnL)m|LugDfQmXqzUJIj3Md1X_zs0L;1OGR?dLdQRJ&L^UT7)@+kaW=VGMD;D^=aE{cI z9!iUtW4TigrNTS5<%OKW;{r4+0NY{mE)kbKY$)w777mae?3pSRAgcU|M$roC=?=$i z|7icU9*RD8+Bf>)9MMrQucij6aRjq#7|LMi;q3ShEoqKfiB1k-2e>0e)TFqEg^dS5{a?*eQd6h>s))fl~=9`Ti#T6x#qYZ2ag(GN$w679-14dTLyl(xttPbc#64{G0 zsZA(DSz>P=iO%qRT*oV#zKS1v3cXe4^eXIcnZ%47vKk`sB4@OEu2R~S<8Wh7%1SSr zO%7VoRKF5&35xblLXKgN$e7l|iwN)RKR565^z0c+CXEsWT50VKK-qa0{Rp}`tZg%t ze8b?gHO-=7-LS&EzlJCzhKDTmQWN_qB!if~momsl>gt%+C3?9XJI&`d%R1>2oqO?< zKkMQD%lG%8XgQNw>|7Jkmgn?J6&(cPXq?4)IU?EL0N>E`x$C^em$p`b9%B2m(=c+P zV&l7{ZMVpC?@nJ|SA6Ly?_|2h;G8OvpE2U)7OPi15@S~Tf)JHfAr1Y}x!^@@WuPtT zSCM}+WBay=fw*hdOILHYrAYmXk1h;;qq-G8l^q?0NyF~Ol-5#z0x(6XA#n6O^2#3& z9~MVeFhu`FvKb%gy5A-#S$#%&YJr}Sa*OO`$R%W2o%z&}9jV|Mow1dzE(Q&imwek8 ze!d*v_Obp!#v8!e*15_qZK_DhaEu{1N+DIL!jd+u${@RDyFwVpO#cvzKk_aMEPpgH z{4Mda|C^=tsQ#xqH}Wbz{tW8M*m885^*s|qZFSnx%qu7G`M%O^>+E-LIWCKt#ZL1@ z{y&8^?->-n&-Y2{dLJtF^=$>&bpYCRA9>RITAU9`QbTV;rk5uv9&5*O-=0bCMr8M! z?en}!%v83jd>c=9+t^6?N&j#!JDrPz@*8z!?s`Re-rRTOKZ<1l$l;G5rDN8K0i(L% z3&{=LmlCw6vGr|qHzx90hQkT&BFG_z6T>43{FNNMf+fLxQA&c}b~Ug$d$PaEDYUpo z*CbEr(v3No|H?n&`P{C0VW&i3@4u=ES;0fcK;E*X~{UMGvA)?tVbESGSW zYBvt%@K$K=|Cj?HhS*I@(R!zd?=JasvgT&iBHPP5xA{C=d%M|LytN%Pe&!uID%RDE z9K!hWY2ViSzm2-8QO7|+zBDI}9M{$ncNkGNwCQZymr&Vv0ewGDX?)B4X5X*`MX-He zgZO667AM1H$6y%86#m$q*CI!nC@x0{+s=D{Y{UI8y?N_;9|WZNB`p8of-V1LE*M^Y zCX49YUQ#pJZEFA~Gg@n|{HiptZoYn}U-4lmfnS3|j5NwY64HAb-xPlL{l1Z`n{}3) zGk~)YTv3qVpolF{ee5tBbXCLZcn(d}tMwn;hc)LKfxkHYkNTcHJa;B4usd>BjTCL| z8uWWurq=3Cymq?R>TbQ6aO!bna{krXW0z{^^6Sx>+$o7G2WV>1zHbiZ<(v{qB9e+1-#B=vkLB_!gEJU218wqVBYKJ=- z>C)oOudtZoOpZ+q_`r3Wy>{9##96}8#<`7~%QiLkGyDzSQ#8d!MjJ=xdH&$Ag$lCeod7Sx3klM*2Q4F0Z0`m`7WG};P zK-T7EaP@hrCDR!wvAG?7p_Q!hFgR0uUk<038`_&51jl`hJTaZ0Bi%%RQTK+Om_gRh zjx-iR?1Ce12s`P}Gew8N4hH6l$H~Lij|DIyEkp7p)9*#Ru=hp9yOpVpWU`+$gX<>r zLj*ya@l(-gvy7*m0yLo|&oWLUevpq8?0>+xMQJaw=n1x;#CrEGeXdKa`$}}7`xXWN z9!+J`+2$3P0B)HhH-?>#7R3FG_`>8Wq;~Ht=Tl^qoyH*bpiax}T+VBJ6)!S=BxP(x zjtoIBxz-*{<93R3>k_yp2;kS(_vZCzU8bfyswBWq)6uoWbkA=<#pv;AW<%ss7u)mi zapH%;=2V~GJpI+3WKEO}un(6T^`uc}=^W17Hqhvn@j@!Nz3h85lES&YHh6m4Aab75 zXr-n*&_>q)#5&`OeNe|@=-BGEz6bs5OCJcS?zbN~Tq9#fbdyPk$s-i-L5#g#x2#@S z-Say&>Z)Y1nB6B~o;>b{A^ovV_9APVd5xR}_3nfMv&1*t3Q1;UHg8nDXkfZEfsFyW z4MF(F_73rs9Mc{<{fUr2Ez)~O zkQPb=1f&M(NQv~`5d@?+=~a3QB?Jg~w%_;7j5ELQoq6AR&vmZ(UB^F??0qF6B>P$G zS?gYF-FGLlbQq|HIbGZd3T4qefU=ea9O>}2^~p-z6=1J;WA|A(#T_TEJJaZDosI3C z%`CZQLRD8%-czsfh7v;bs$>)Dkf3jF_;FBKX7wQwMla~!s*q0c*2mtnZb}c%Wy**MyuF_4QxrAwIw!QqksC51|T5PxNg~ ztK$tHdGT|ff8Sp#o#6`S_hL~k9wxa)o4-Y>pFNo?P?$glo?FaQwBj4SH54F}H#Vfc zE2cBxGm9Meq(IkaE(nKqae2F1l^(pBSXq+7J3B&Uc~Z|7P&88A6cY0{phFr^PJL_d zFcsB&xBJCbP|Sazg0(P7%?RF>k=L{8eg~`389^RFJN@>@Y^qzf#y{Eae=`g?f}n4- zQKX2W%ZpIZ&%L7GS_B9kiq17NU{pcGnGP}QGo{(U%xZwQNL>Qh#fI3Dv=pPx7G$`^ z{7!m>QeILxjP78O@1%`1ldbf&5QHeEp=;6GN{cr@S~Ba9|BQZx{0xj94RVytWrj~E z4Owk0M%}kjjgojQ>Dmk6J+p`lKxe=;96#*+igSa>#|nH<@|O)aj_#?DZ7d<^qUVzn zdQa*)v`@sQh^m_nvk-YWLyDm8Zfo&!i8A&z@c?XcB7L+#4# zRz>^WPN~D|#wqD6wC+5-1Vw8Tt(1 zGH;^_3g(k0kaM`r-Fi*wRyzUJ$+=hCL%VVgd~0)+dO^idjc5n2aw%G!c@$(T>f0U! zdf%p?Ojy8rV~er6EdI$S5e`~fg~#~Fgq02#-EBG{%=xsb4Je3 z1X??unyUJcTDb0IfH=nuA6Ixk!N2zfxBw7|xskM0eT=gd6E!<=%kv6KKPhj$;e=)`qUy#~$c zzZ^KBQsuxtl4$!_f;X}&-G|^t2T>DqQbf!FE!nPyh}BCX1(^8Q8S&5|cy4vxphJ;9 zSxaHV1}*!dA%Y;8d`30^(e32mgU5IhNnPUoxV{TZy91HIvdpdKZ{CHS%527Lb1pv0 zdW?THy*LaYYlw2&5M_h!bB~RHxq?b^P3XE%h56rFO!jSymjh8>fFxo^;n_cjD*m2I z?;l?aZt;1Ex~hjwpDpMbW0E=6opgU4naccbSohY#SLw==dnkKUTmy`FTzPhnB%{PJ-YBZ9m=*rv1_431XU=s{HGap@rkRG%IdYxbrc`x1<> z#C-?Bx!$JVGE6JDyMfz3z3(L^r)Sj}ItD(bD*()5IcNw-6#jgFswe8i&QrCv??Je5 zQ-Wgw-dbd0;@Hi(uygQy{bSxsy(g)Tck6Rd5k59H=ch!MUd?0Q)}^(a#@o7{PF%8J zf<&xBwje|_*5~fbq7Rtax=;z_oXM5m2moj@|;2h#k^EY9YL!f_l+6t ztysREVW61n>tUnTUgi|jguA+<+uJhpx}LhvMslJH=Il1eun{F?q3OEMAqB8ZcoT=H zEa+LrwYb>Gu6V~tbPR^3VAOvQXjO$j{wF1(KRpHsWpiDauV^I>r>89A41y3kJ*x$p zP2F_0q1-`MYqp(N@IjEzWVX_3f)hG3h%(Nwnc~+8>cLJxcUG`BN$fYPZHBtgmvDJ` zo=@@icvkwY#-Ns47w|TY!NM)o2ifokMEshAi+eAf2+X%qeKe+?+`|PIT+;s_Er1s# z2Vy7Ny@+fj4ndYlMI4+!K-e%>mPRd+z?l=RTP|IWV+>p(+{`AvO7B$)-57J%X0F$> zdUpbHC{TVPO(7R#@K zewcS#S6IRK%aRDW_bXK|S?;T%pHcCi)b#C~<65oQcu!sW7U)%7ZgTSShiAqEl2@qr zVvJU!){~4`Z>16!=Agh>&RIxs%Eg*t_F97lSDaa)A>`v zE(bE8e>C!c=N!9@+1(-9IMkvKvzoWapZ7lzT77HQ*;3M`P{gqy%7dSSdIR2^8Mnct z4?1#gLNAz)TNPHgs!YuEdZx*mD>xD$lZOrku6FgMAW76WD2XdHSleo?tZMsrs*uI5 zfvYu#2Uky)F=Ayq92Gk=^3e(drAMA}8L<(^TQJsu@tPW;avV9>zf9i!uCRLJ@D{Wv zrOGW6=QNO?YR`TE_6X*nC{hi`q{r^Vw9MYQ1UJdGso5RYy)1*;Q97y0l2GT(DAb;k z0IeP9lI?%Ce1S;ncUM3OA=Iud@;k%LT7g{cxs9X3?rt8&cw!Ts z-Z4if(9E5B@+9-F8<@n3w7w&n`O;(wsk9;RDm^f-KdXUmYoG|@;}6)ky1PK4jo;N} zpUShP*sp%OYTcJh61KE-5Uu1B=$F;pR5ps!1682G=la1lUaI1#-2=4Z^h@`II) zVL-E;aP*Co9p~7rnQD}7P5C{Ma^YEL)L3DG!>m;SVqkkLPNxP<(TKXD2NjH3*w_`X zs*Zu1g+S0lTDuD4Mi|9fbZn8sd@p_md(Ia;y;bAaybW$lMs4%lF#K zU^|CTD|V9iwIYJ7tUtDhnBDm($ielniiP?5WtP;!>IU)%p+aJ6p?%Sbiu6sd1jr*- zb3-n4wz4jH1AA|mhS(*~CzW;Dsyp(v#k?=4?jqTwkcXX{?e%t0=-C%&2~7imsST;? zn->1y%+M~saS@?0FmdA2iVh+U+(=0&h)P>2#JOBIv@1=fX3egvPWtLu7)$3pa0vU+ z=k={u|Bt#ua18c6`h3@%&#MCkl9_uk>`bSV46|Ke8b-5njj)s!mNF;RS!nqP!sP?* zhJ}?%vBnyguFgeZ7RN&u=mqwARyOr2oluf3nJw{Qv|th09r>_j+5s{8A2})Fy65vz z=3x=>9BDVf&k;O!H^HZ^dT_C1_oNhtib%{=El8Kr6Q)v8}7< zIvf17`9W?QU5CVfQDs}(+b`SbEw5((tG@d>v3l_zEX5lUGi^16j5EAiFDv%&<6o0* zS=HI?S|zDc260rJh)Wob#^H~&tOjQFZynJx6v(_tUmASQ(}=Y>+$8_ zx92gzCrlL=&J!a1J1$&L^?J4-22MMh(ZadIX|-E~UXC!&#r8-uy(K)j7>d{a(qU6? ziT+Nzp@oN*?O^7(`o73oRUlp1(H(Y$a`Qs%x!%?S{Q2x4Wz9YgEf4#NJ8+4K`<%Wq zLKqRuXVH+ttXlWC%QEse)XcZT-VVIg9R#eig!T7aRd5nEV4<6L4)vOk`1%^Ee7v8h zDEBDKp}DPo5xvA4k^fvWy+ChW)~N_BZn+{E0|0AoM&GjM z%Z`wEYzHh53x1d7+~eWdO=YQ(T5#qx*5@(D3a z^Vm*>EAV82n%%nIK30W^{;=^W`p7fp9iaL3b=mqRy-Ed4`$SNS(#X1%E`5kDHR3W~ zJT!~`R)d+sRh%KTbVl;nx-|XD2Q3gY1K~La5rNgw$X9+BUALkEC7QFr*@o}~PRdC= zP5-?XtL*%1Gg3SP^oQNvh@koBG^_X2Jd4-zXQph1j)bb@TziIwM{}2S}dep?9~B z71@w>^@by174CAu)%G1{e?Z;=_1aOC;>(^-$xHo`JxJZRwp=96xg5MBlT^DMZ5^~~ z*TA;)qjcqmNC4Cfw*A%X1^e#TDx_=Ijbvw}OW0YFlDk=T^r&2umh5OxzcF5aogtSY zjOx@MC4h!*tnVzhjb|jpqUJo@P{wyM5~ek+x}xkgU(3G_IS?5g`zCnYq=X@xpH%C% zSuJSbZEQC|kU(J4V|82J)>uf>F)E@~+$?QnBuWpeQz@aM^f+wyiwEnP^z7AB39Q3x zjZcs_et)gt%d?m6p67Y*axV$qNiLeWudy&4-2@@3<=$E9-mK+M*S1jXKyasB%!sDt z7bfkFa8FsP)|%_#4T|Tx3>Np=JT#NXJO44HQ-1fyO6jKi_$SenbAZ#)^C8Akw`yhP zbPvZSJ2+5K9u3?zIemocmu?hC>BYp>%#Dkaz1E?s8)S@O`<;2#_nP>hV5f%IxylF4r_^#gqPniZaX7`iecDQC^;~I}a2sGg90%n1N>4_^(MI&|;K_I?QQ@bN)`| z-Z;e1X(>kAz`XPbAgE1N$)!8`R z8&kDX96z2QYmS@F{^Zv-SNu$`O(PSVtg$8wi>un>6KzEjgs?Kjn+7V^8bKEo01AY6 zrmB1Qa#j1;qsHiA0nN(I5;@k#KMJAJO-8V0~;JR*2W~-+O31Kw^u%- zM)@$n_J|jxK2535ABJ%p2v=ny5D!-QVCxK{=B4iw%M)W|^GpJjPG;jKSaPUD11 z0sm|A5GXWJdyTJf6Ik-E4gt1M@Tn=e`q1f>A1NZ!{=XuT!0RYO9TCoa2aUEOk4e(P zf1Z#|C4S!Tvq)s{9i#^Ybt{a8!|W7ik4ESZw&~CO*fv2o-2gaj!6dvj-_0DsY zuO|Xjr;NMYT_hp&_~Rp1+%2Ich_J}fy8`dy72eARPaMwr$-X*H}DJ{SG3L%kosln$63K z;;R&ousgAftu=AHsfFZk;Yj2#k#45 zMCXJDk3J}I1%+`Mj&+NlIAS@pA!8FQ7S>rReVkT?F)^+rN1Wu_29<3Ps$wlebr~ocGGq6dLgVe1Dayob9F z;L`uX>QyM>`Yd+h3zfAnVTOk34c{D{fEPG>CjeIkOY93faRp9CrBx(EoHS z2W<3biQhqDTs|}B5m>4HnIp9S8TRHmV%!~f1>70u>F&&&)KACCKFtt7*`zm&{;)Cq zjO3L6%u^reEx!nQ0?-fW0U;g)sGE3JU={!VRApudvD&b=fPcEf3dE5@wLAGB# zy8a#1tPV`d_Ra${X6$D-eSSV8+AgO zO8x)z>Zq|qhDTmE$cf{`_fbGD;&F;MGwa&Bl3RIX!k< z+LXul9){X)-U;ZLl|~ef;JxV@e8U?C-y>7{LMCqLehymOSD-*5!)GD<37IgI&E{a6 zFnm7O6hs*PRsCy2(P8sD9JQU@0x{`Q`->>vivdX=T-w6JcR#j?LmaPF0-a)c$YRLG zvRKfvYsIH=vlu5vH+Qe_Nh3!~+vi`hV~qOD@TnsN$qtBrG7K!?q0sVD(;Nn9+m$#* z%Ef-em7~3kR%b5?w*^$jo z`cKEX4S%&kz`p*g)|C{SLPmh(^M;_sz zC*K;H5kDORF6nPhMe3&?2lVT^{LvNg>$?1ht}$Xh>^C&5F@<_Z^dK%oXU*2~MeUWW z#@AgCd2uF!(l;)2?=Be6sxN)%rhdM3$2bfbqp|pEMZtX^H7?Z}g$-R`2~mA3VUs;2 zhP1gF#>V_y9g%m*CQm(HeM9i>IepuX3OD&~%n?2QyZQPe%{&X*Yp6L?OWt-!Ju^bO zsInX=%5)TRWQ-T3u6?EFb)Ll={kYU1;Z42*(3UID*3c8L#s#llo)K*d%hQqZ-Vbm0 z_BEab@qPk02KZY?>4?y3aRpj?>`Ch!E&W6E@x&#B{u{6Zv!6`ebD2!O)YyW_lMF{QEqGxL4Lnf>nMT|C_OKZAqRzg)$PUT$WeRi}k_B2EY9$diu9( z>F4j!iL&iU4K0et$_g&L%Q?6${Rs$>|F&~vvsTtfYe?r>{?32qZ*GfC@>g*5E7tqZ z3tjI~ix2e6^2Jo=P%@`Bre1FNc?bTx?HG-u@E)SSQp=KC7Xj6b3Y<=bvlTTyNEw{Nb9IwNcG?K57blue0TV@rm>gsi0MBFyK_ zdvqcbUT*&O$NlfSKlt_PuQ=mZ%=9b%`_GHZ@d!R4Z+eQ(&Rm;W=RZu}7_pEjkD=M$n$Zkb%bwRCujt5X3uHgf& zKzn9!0}987sO)q*%da|FT|L$LqbWzd4(69x|1#_UJhT40bUV*dXyny@u{)GJajH+GUma+X`3pMtcgVmG!Yl~87|Y7IdXV>RSAW@l<^(y8p514+Ek1Jw z2naF|?h;$abd6S?jm%u#^29^)?5VQ0GSm#OKjZ;+f3fiuOrs5lxoQUZE@!}WzvXW~ydKBxY$D3*$0JMwp9dd) z;JdAsWF|e$X|yL3`IdP>wAb}C+|vOPP|wkn_2AosZo?~vm5=48`r8JW7KX@}R+j1y z{vI9zFG9ao%*J$&WOGLFv`>GPUHh3*>y!tV9zXB?>E-aOme z4@Su1l_>9qoe`<=Z!eO#x{!H;eSg>`>i=?y|Dhn#tJBMw==cZQFDf(L+ ziIFDuoikO*;^Xr8Q~ym$=uYtyg16%{egosT186xM^@IStv(>1O1n%3?pj~#=K$Q;v zs8;=eTeJR=Z5}%hipcCpG*q_>6uU!`S(U6SnmuI~6hQ0V=Z2Y!hc{A43tlHnu4K~X zoL)Ya@}#QUIh?buLDQ?iC*;a^3uL`9XR~B}w^O8F+Is~mlsN;$aAiReb3+m>uE3K|)TaSnkSaR4py{`|I2sa?90`u8;_n`N>mL%O$>s-vJz#fyR%rfN#V{5#W z?ENrj2v3ti)v^rxL6lYIZZWPmx@GR;J9uqT;y&!4Y78g*ac8u}=F(~k?V$D0#8`Xj z=gx^td;2ZdHI3-a!PLT^Bb48QUmL(l-<0GXTwb0Ce3D>oH~#m~h8K#zYCgY8SidTA z{~r|?Jx5QZyhjFHd5)n(Sgsb1oE)*i+|M;5Uy-vCOc&99(w`~Ycn24^uY2mC5uxng zDn@E0ygrP7o){nBQf3zaDEXM~9Hjt*-S|holhDLE7sZr)61O|82rdIZnj-f0QNG6w zmW?K^p0uoO-153mZ6wmrF2?SLRSidbHjWajp6aPJROqEph17qu;s(1gFkO&LHTWOl4k(EyQIz=^w=35p z0!luZd9qzn+rY&)^j4X9``bSQy9iQ1p7le{2Sk(%=Bx}hbjSmD{2<=lKCNK?hif`m z-qmNnjpqLE;1TQJ#j?LjM}H~r{nnoHtEBg<4EBFT02;Ul?JFbDWG~G0TbdRxn@eC^ zY3cLhl29G7@w`3PLBa>?W|DQgq-etuLE18OiHXm>U7_zlR%7dBT5(PJ8h@BAGl^fcudDYu%} zhUpoq!GF|Gv0eRzasSB-Y;p z;Mq-`hcdd9Y4|E%(a`&Ma_#Y`G2n|&7`|;m0j|9wyD)P}B> zxmHFk$qMCBqkX{LX-7t8B6Aoj_TlfH*zar$>OvI%@=U)x(=V9*KM$tIV``-*#qrHq z(JiYC9X#92FBo-v-M)rXLBFkT3z|E65M)%YoqM-yY8FJh zfOq*TZOGx>Iy21HC=oJP1TvSX5j*}x3t;z_VR~^PqGzS*JIImAXGXGK6*XAt!XC~h zOUbe=YdvzR@TS|&+QE^$YflInSWhwtknDEJF)5GE?rc!tTTUqubXA3bSP3SVtMDSq zj#+kUn(GO$Qgi(o=E?@TwH;fgU9!Rp)bAE{@j%`zkazkq41fY!+*z+nA9i_mG>|X( z@c^Zb>8trz$rsPVZz9O&y?*eWXxKf6vDqddE2k3nrg(NOlpWsccx|0YdHsFI@$YOv zh9=Q#{CjxWzt_5aer$b&>UA@|OBu?g>Yu>PX=_By8 z>vzyTiMsg@VMe?bF>ddUYWz=}H$Tni5$OT7Ofl9M?+<7ndwvddG^+vqbwd4-D?pUOqb+7Te<%o^psBlBa2n{+KHQ;MrN(0wttv;ejGCltf^Qc z#vBr)ZBEr;x4U=MoG3->poVPTs&m5I1kdKB{=)Z~A|X;zIuWlGQ-li^K~_012HNp)SKM9!=2L?r!S(5f{i01M3m{d z)~HIN7zG;jGm7q?YrNl1>nk!^)BlJvg?VQ>asKquiNx?GQ~e-k8dvWH|3GD2@Y?0Y z>z7f9v!}s#`xaArTYShwlv7=uT}-{$rqw{pMQm%?=qFIc{zo+UO*4LClvw&y*(|L4 z6~c;(dRxce{Cn+N1nxfqor?|tZj(_S$N$JGfCeP68_Musdy`IA07NR8UlPtW)dN0mdu`x8BzkSL&j59?kWS4v~x$sK*Ym4a6@3?T!`iFw#Kj%C7&C&k1$^=eH6A2_ZAm(d8lJO3yZ-0_r)g3z)aqR|{Qv(N2ZkMn+u5XT2ZA zRL)&)dW_EjnPDj~!?6G}Sbz@JjmIehJFQeBaUyWK)w>Cl>{WQS&nCerC6z)2l+g(X zk)iE737W@CZ`H@9XM`<1iCiS>oL7ZeX3j2l`;3jwPHlfe(vIa#e6GG27Akt$|D?n+ z>FCk^>$5h=|;=ICjO;_bdLww1SPsqZsqVvDHs0qcTj0L!Ug3?h<3_^$5x)O zb(guvL_CdbKiv(7#`7JBum@(cDqJ64O0FYofcBwF5(bsR@9d19Wft(N)b`uFuN&OT zDy|Li|0G)T*3qEPPw-NMIK%`R5l2ss<8?B~|4iTNt~Vp};{0jW-JUTnZokXpw%mP( z3wv$#si&{@6LWzgcaVw-#K2$nVx9X zO^P>-i$p*dy+1K0SZdQ>DopM_=FagRNYD$~VUa=~EE2FUWnPaU5_&jpQgtC8PAni{ zY!v8+2oPJo?u?@l;;7Jzb9Cm zIj<-71+nl^BFe=(t)o00Y>T$fIt#bFXn|vl%TE(b`+4r|8bskowb#{ikF?5(@C*%j-z0@GvV3OFCx9tls458zfu6Nzy9PQFv)c6h}dS$n% zhfiuU#I+M~7yhlLM0Vg1M=X2qlS(d&q%}re>O;Q-*^b%3pCy~3Ou4hOgq+_z{~aVb z%%GhthPfMPK2a&!{vQ7VT`L|m2}&V`H-qCx-z--Xia`WhX<}OM7m^gdjcyh>7aDkc zUU2=Zhx(?^$rDRwp~ZUqo#Fj*lE!yKTdBf&lKPiJv~yl?SNiwN3*jN(9MX>Uij^Ik z5$khnxa*B8mzts2QG2^$Pad@P=Rr) z6Fe+(W8O=+MQCb2PVZLT8|}7|hucNZS}&Tgq?!3uHFk))pC0L1yCJ^V9>lP4Xw+4? zpH&F+Y&;|{5OXX%o_VhUU41CL^U|B4Dy7oAsb}Didkn|8z4}0Jd4%Ye@ zq%^pE%auh3k+XGqL-O*b9);5h0ZzEG-s5%cXu-VcB)efvXcyi|YNQx#u+Lq3?Q)817PB5MzxT}tkP)dM?tyCpS zHj%6IbjJP4X*)d!1!ZAWk^d|pBu$5frHAvkRKL{ns&`=G>}D=FU3TcAQ_xGkbkVU? zQBP%=Ey^LW#_XkGT9siwz>|~1`WY?t+R=t;RUvD=+NwU+xLr)H`4VV>`t5pT}T2)ZR|FCEtB=2q^Dtsq zyqqa)#ArL!!P|0otAwNKmku0*4)i%H3X6F4~ zrI2!-9vkg{t9v{;z5aV>PX5(vz#R?d3J5jig<1%n#0B@jIDd~bfR_d&6fOOT z`G@*-YZSa#jHsrjWRr7D7-KP13;xi)z)7y<6@do!oe*c_z0*aLK*A`_o#gCu3QWvz zE|VREJ3t7n3sLpduJTJq@hH;)E9PY6HYFje2GTQHm(Tn5JHrnP+@!ghYo&uG*6l0r zw7A|&OQtjdYz_%de|5`bo!IZ7d7nVE(fQ}>y#usKTKdF zpkB9<@1d>{4lXP(eSuaW2$E9n%e!{@kWAFhDqRQ&A2ZJVAF7DIQ(9H;_KC8mec~L& z>&;EaAcA?(7sV5wRk$j`?dqRj7Z>q8cff+R^{TJGeOh1YQHiset5bcOc%^i~GW_ea zs2VO@hC*lEmpEeC8xa9QHI|#xQ^dktc|rniGSo<(wS=;*svHHcoT+Xv4`G|w`T56N z8y-<^cWa1W&rpgy*$L8vA4=Cm=4%d3t@eBeRaHKc6sMUhYSiZezfNl~$dydivVObZ zS|8LbnK8%VTEqM2qI12UqjSXn+tE2;FDceR0qy+CC*AT5dk@m%#*+tDlXMGx{(i)U z=TN=daAYww+!H_d*|g21A&yW& z{`x!Bpg!sO1^`1MhOrv z4eL)BnwK8Tt}9tQ*1hB9Ib1Gg##<1ORF|~1SX~$x_X=Xl8LY=YoL+82JZ-L4)8OHj z*NEw$Iu6jMtcMfNjnsb!VYPQ=WdXer zd@!4Z!YWixu%8!^R2!$lqF5#uvN}iiFVnODDzx3L@8ynK_lu?vbiS6w2l4tq`u+oLYQ&9> z8&*;CSDrpR+9LUU=c7kJ(}o;BW)jHl<{&{MRJ5-PE>!OqOFam-^$c!~d*orw;d>kw zaj>K6)gv7_@M++lY&>)q*x;Jmi@qniix2| zaztuMM%ZD#!#+I%$mISpng8u`;y=cW zqY1zQ|ALvi-g2n^j&~3J4G|f$5uB)liHor3;lQUmrPi$nK8$+OEW+=+bWCT!tdxudR zif$x34&7O90($bV;fT{+?Z3WKokL=6#|JyaeWn>_Tl~eI~6b&#N0ykqZ0vTocVJEmWAV z@RMq_335LS;?K8-YR80peUr!d1|7Xwr!F?!AB3?irG*Broy84xqWDYV?qZw|AmD9O zAs@J7Yb(nmG=9;-1W=dlXiQbJ6Oz@f6O}T}=qD8K2SW?CU1+eV8@x%FBw1Z38Pk=sN}r~Hh*UWo(s<*4?OW$7g{(YTmX_wOLx-r6pe5psZH z`3ICy@45fGS92941jue25utRXm3>YD1_U3Y?k%*(U+_;a^wcWo>P?s;eoDdv7)*a z3jT1i{+FcvA0M$En4{Vn8+upk;Vv&fQLe7*XY|~ewtz|kIb@)I4t4u9Q|xLB+P?|5 zC`*)8kwu=+v*a>HHyDnt+PDnhkcxe#b+w5%6t08^$kbS^dS@dM>16lekO3FDXm5~8>tt)V}@}>^M5K(n;PiRg|y5KO!BEF^1Y!rX0kC%??#E6lh+P$GtV@yNHe9;#p5HG zNGSc>M-I`vVM{>$d<<(NQ8ZABm8c6(0$=XasTAWb3Zvy4}O6SOZw<$yJBEeR9+Zy+sRwKOV zi4Avf_C*9LZV2<1?xZlRizF}`j$nW4?d}T2a9|_z*CLxfeAPB5*Q7HU{xqp<;LtN1 z@-8}}9dA;70(#Y(Vij^3$8;$mV=M9rrCHTmqPO!-dI<#y!V%50D-D^hb;(y%g@)l)Z}6O@sxNN-FJu%@qn0Ww5#w)K zj+2Q z10la0awVhN3y zp{ADvIedNfH37GaHuF2^J-=3LQH_bW%hG+%WW4J8RiLv%l5X}5>>vw{JGtL$`E3Uy zFVeq)f_Wa`5IJooA3w<^3-j(t&Gv4f=WRl@3TiTws(pf5aw~_nuBW~1WfVEZv>P;j z?w~{s5D`n1>`aFmWm@cndQc0fT{glOR+PjS?WOe?UIRz-c3Unf$y@eobFMph(p|kJ zP_L`K2J8f`L8-qtVf?MvdF!9`9g9wfpiA1g_3jZrOlKdsF)c{#PVyae&OpxzngJ=L z*jUf@d|4E@296mNkual-nBFK5hc&8Yt5!;so>;ow_0O1sjV~dy zzP^vb>^l09>1B@j(&wT^WsYVrPNy-3KakEfGFy||nmDp64 z@rCn?UPBiS4IklP&b50$V}8MMxEK*O``KWBMs4g@*_-B9%($z&O0O+$G#-!k7%W^F zd2J~yQRXAN=3ZvPIv5?X%DWfZJ}oxl&5TXh)*30Co}V|p!*t*IaXho6FEU2bm42jZ z*f9TU)a4ZkLg2oMhDzpi{(87Tj<_b%o`rNrmGqj|!U;8?w1~z8dCVo-f7?2+x_9BD zuFR*5gvlh&)&tg7!b8IPc!;!m>&!<;z_u~kCD>Ea$YgM?=&YCY`Xe{GXEUI~Mg&r> zWu$%#*fTp-au$}Uw9U_K9JY2>d$OoFe$f5-x&!wwes6+?-{Vux-?$>*OIT8?*B!^F&e6V_CGq1F2AJ%8NGgRMxQB@a-KB1 zwgQ;Z@%7}e5bV0a+GX-leFzEE_&&*Y3xA4orQ1?Vlp9i#-srE|HIumC=zdA!B|?=h z8^S)?5BZk_nrl5wG8$LwM`0H0gJ|wX!Tjff!e_J!^*M#WWG5{SZ#G;apAUIcQ)~J? z8wR}&nl+sBgQOA`mAz&aU3Fp_J2Hex00byG#9IFqNb`H1@BA0y)ypiKSI`MF z3+kb1Lj{iJ`&}Ly;k7)xgxJRf+{B zivL#3dA!Y&HUSJ>3|iDXrp3)mU_fIG#^T||j)>|mQgU#0DxL&SeFvGL#^SWF(fJxM zs_wV3bfn=U>am{bdaR4gPjZzTIUCz-?YZ?xps7AZbX9Kop5*4%N!1p|Nh5EpH|ahv zwx1p_sh6Y}=IQTPXVOwT?>E@+`g5eq*Evz8WH(4rJ)vr+dM$BIRYe~pbWR?SxV1fL z{7WA3L2J6;l7HIFn#5_Zg1C#XG3b~%; zqg83Y$6*x`v$0uqWP@gEKSs9p-m;`)7-nYY`|`T|y5KV-n)|SgOZW}S9eiI#kRc+% zK6C8uCsM=g<0EH1YJnOPMff=f_&H2|M5gN7j_H>N;n_PA3QzW=s|5K)dvhTMz`S!@ zf=ej#j_72;!^E77=&^K%#U8k(?>-@XjP8S|y!Q<1m5(9x+zbp!cB9qrp&b9yz{i6m zyQRf#{U3eJvnyHHM|Bcut5%Ql$<|38yHwRy$7Cf~T+^J2kQQ4^I6k8VB-}o%cdrs? zP4yB#_$0)oGG7+AsFJ&Xg8De4J$b}E>Be(EMWySlC(T@tt>snlf#@(I6e8YWh8T}% zpZ@~DuLT+IQX%9#{rN1Xbl+5rkMxuB&P7+GoD*i z+=Xs~&qHFoD@PZP&a@TIY4N0In0X2FH7t46Ylf!WO;qI%R+M1klDOZ>_9{w29Lnaw z*ssSjzdeCB*Z%r|zv#qkq~yMFJ|eUEPWZFUx_H(456=o)=1^_hmpwJY+g{~{a5Cu* zXiRd(2odXMZ=ajYWiTsnQNV*|D~$IfDsCGk2qf^vF`Fg|ce18c%D?%``usN@@pca} zezi4q*wF?4y89-&^5$_aP}}r?*R_gOs$ptI%++eaj7NlN}rUOKn z$X2(rSJhr}u;1Sj*R;Nazi62J7;n$v@S^}jG}L;u1^tjCg0b}8fXlbKnS#w6)UZ-RLaT1~+A+Lm%OOJAPpWLeQK=k2vW zy92{qt2LU(--rfEH1n4}9KS8EaKE!yP;EBA{47@Ofc0}HaV4IpoL81?%9D$-YuMLE z?tFuvk8mvE)KoCzdTg-KoGvC5^3UE*LP7Bf5uu0rFD?dCDijC z0e>&(J-_XLO!CltJ5i^8=Q$) zA=1r9{T83M?YAYJi5uXt35VU8f2A28U%*M~3LrbpS_c@!2ko+g)1(5zq6$M|#Wms= zfT(OYYI;?YB%4fOt~@1ZDcauN+5@TN-SQno#`$2ITzb}{O3R90QJSSha=9b-)_T19Q86}_kP9yptV0L`vY5VEn1rXR(4A-|p5bkQw?E*rgBN53 z0LBCh=;+!1L)?2tHPx26Ot9`@Wv5&|=0Gxvj1OjtMKk z29GG;xcCQoJpbnmsNch!{>G5%hTcP5!g@3{X$iDn3MSk(GZTErR7Sd@bK$}MRdO+X zwz3e?vnCJnDxqu{H;y&e(ZG*7?uxUtoZg@1lG(PCTA&fzFEx^251RTiHj601p5ldNHiq6P;?CG1IN5T=|Jtw!&rt4eV-_ zL&MzN5+Hk!MvWough~&m49$4nW|x@f?>cI%!crI5Hm-X13#0mk)%k)%!>o^VbMfOz zyDkICix<+eSBy1&AThV2)PI7&{K9#oAB3(=%2?k{3VgJ|w^^;a)8u>>o-(~Yyra4L z1IR&M$hbZ}E^Xj=a*qa8C21%*I<-Eln>U1>yEhNNu7_Eau|%OazGDHe)9Oz&&DNmh zFvxgU!53?s=;zp@)EN2vYNSkjR8N+Al_6EK)4LN!06fG{RR5zB7fu8aDr&?-Y>3?L z7{XSo0dY&gd*ZT0!eGlhA^Fi!7o-koXRJ1C>yF9}Rw@{}cc?>HYGoEkn=RzY}rvBBA-7e*PEel#?+U$8S0 zI98NNhzy1Mom9_&KTUyg(Mjn!vzt%E#*r8NjtqRz6)P^P!y^YY^uzM-Sa@M~BV_yh zsa~(eY-rHOA{)k72dl)0)8;EdA!@eduJg?0s6K66)in26XQP{NWz$;7x7xXyQu*i{ zfimE9c{TyqtNvq<^S^|&{pP-N^m{TESHtDzgi}FI6*dn zP3@&}s|fSA`K(%0dj_E;jm{M_m4W%W@?TF*}QwU4P=ooC!&NUAA>4 z+)m2Gc#;X{o$`cPU#X|0&3r)Z9BRJ0mn*=5;|R+v@wbo^ICEo!!nN&pt}BgJ^6e`E zYxY)lg;AbJESVTn>?Ebq*R}a$!@N) zgk~+bN4#9rwetq7Kj$yilo1MQ1oQyW&}5=-vAl2bkb?sc>wrSZOsT4OvG?Z=XX5Yb z+g{MiMyAw7lpQWCapCY(>n`#VVR8A06z=%Vfn)KxYLQkId9~sFi~sNueRqbD1eJhE zIwb?EWQLFS(`Lc9;ks0zcmsyVya3il-D6n10%#raL{?`e3rEWx-MUM7n9dH+$ms1*PJseH+nZByJ#`0_USi%Jjh$f5r{ z4*r9!=;BQci5<$_br{ZL&OC>*{*a7&P4mjZ-YqsrNaK|AzL}uh*VsW8! zm;$V}f~usXIqGV%ShchoC5^$8%h!#4Kwd(&u(!nUh%BuDN*GI@#+EQA11A}kbXY$s zb_?n7sS$QVc_4agy2z>)Oo1@N>#s4gC3Gz{)g{W7mMSwhx;`(AWTt76yj$1o>VIf8 zrrI1SS#;Du5UQQJ4)krfD*>N<2=gTAxk#O z5igb!z}LmYIm$4283Jx0W)5lo7 z&^ZX}=%pl3RC^cV$I5B~Uh}~zPsGBfQ}L)BM8G6rcZbx94XyPEJ0bx(!j z3DJ9*Ow@B!{lkYoqI*7)K0?0|?82p0B81!Ait~Z`j0s^zC|T+|(21w3{jAe|=wy;M z#QpMlZtZ781o4IQ&^-gN;xdBqQVkT@+^YclBn?cMkNb#f;U_gTP`x&oKKZ%0}Wv-)8WqDD+L}owc#WiQFCW zbckl_+`XHhKM`As2(QUXtOuZ;;5M-}d$X`c1$p@xUQV{qd``AC7SFE{%LDHHTVyVq z$UPtXc#>bCz10+*=62a(hq2SDXdE%yS2T6i{adJvr`aPD(=uij%QOmo44)e9g^g6b z>za_s8p|>p(b(oaj0Y9}B&^-Aub3w6Yz{f~Hm=coAQCj+tBsag-%Gfcb@^=)b+yXy z$yo(hBV1ZJg>5M4S8Yt~_GcdQUuxq2{!&`ggU4vtVx;`<4OF%)TvQ`s33I&y+5?ZV z&ywJpuqPJKiEQ&*R);ynZ$Z4E$ARHJ4}=fJU}mS&I~2YGl9$(pY4r;91>-#|#|^w@ zuY5l`x?oE(;|+g`Feel`5Ioc?`o(Ws+w0!CZPK)_PheU(FO7Xp7)u}_B3pB*-4&Az zO1O8{S6VTY|9Zz>=`*r@PTn5`3lnU5jx;UuwBp$crv_JTdm%xcC~`btZ~Mg`8eL1aJV8At+;{h3I8h`xTk7=2xA+avW=39zOX^;Yq=XYr=~< zYs^y;(ocl?9nz>3RC>n`0ZyQ^ka+EQ zA`)5)_)D9wYeR;TV)d;D2oW4XG7D$xo4dkhufHD{b_<)m0UlbL=RN;Dd-qHA63}|S z%Jz`34%ecGi(hAK-HFpIffQ@oFB$Cj#eO(8b8xi&V%0sb|IMFw{x5vKQjrjUsUUrF zM3+6*+<~-?13V|Kk}Jt%zI!xxRG+6Y3l8Mo4|;N+cG$&Stn&kFhi)|N#Y|u@h6$}u zr8bwxQzuF`Rg$Nh7aVI=nHF6q+*%7Fmt}bmIzR>1K#-%3H3C}2Iq(as6$w6Nn`e_` zEFsNAKGKXjuM+}c)$UQ`u-l5M@wA8@w|#u<`hv4au8ACEOs-D{%+m{3Iwjf>ssl31 z{JSvPSgw4Z{O4|x(>{BWSXUiol(wnQ-qS=MN zg{JjjLPG?V-n_hiQFU}6g>~Jke)zN-Oc5#mOk`FWDT$@<{RuJzP-5DsM#)>6<`rpQ zzB_9-D~l;`Z0eLg-EEG>H&`EkngK~aW?WyMd%tcW#=hdeq-HCj5964nR3&7p<{))k$t zFkD7uL*~)r?X^NhlP1WArGCIMHpRwzx^g0fyqgBvSQ)tA!kApad#^7N8k18B(@Pw- z<81AGlh#ULUbuozGLM>~8R8O9;9Uf&Ef%deF??;`MZjm-NieU=-08v8%4w0(S3ae% z`ptkKhxb|fRYq_E_FEx?FdwKe+z(8?&qGPl2y?fp&>R+1S9=?FZnIj4ad1e37z?R$ zlB7UV;;bH5(^+xljV{0NE|g_RGo0@!2m3fh;GnFkK`z;FvdL1dA{)l5{JlIovbj5+$Q#m2(`8|#;qNpW|l5W4J!^?vpcyNpt=x-Q~qbXzEc8FJkAYHP{rHxslK?4QX$jHJe!zRZB5) zRL;ACT~6Qf^1qj_`a1dd`4@jw!~OGn)HOm@jfes^px*JY;;GLLW2TnH0tdBDbJ;W- z$(@8ppp)=ZVdylR0?2|V*s_f3v_0`+moGJ7#lwQX!R4cJ_jR^^h%ff1l%`lM}`Jc-XU2t95x#mj}o9~o_X zB6QtmByXE)pCxQW3G(Hpm^L4*w75shs%|JCi!_!Jfp{>>qq*+jjls-31=%w zqa})nZ?2Y>UpIJdnvjti%M)rUUvm0CAX$KzKG^U!G=(j2UQxwO0<8q3_{?@E|KmMM z@|=kwc&Y%Cz#A%kOP>NRr)TWbAjjT31KgJ?$AkD@HC3P6Aeld zi*jygo}QAX&pKgrWrQ@%5PWJFpSl*6ELHQrDRqyLFRLn)tZaN-0CcCF$O!K_GsY$v z%9yatyza0@Ln?_Bd+nlAiZ~C0?vFwVVz{jIHKY!A#J7&9qZ@~NHeLIUF)*mE9YSi%&{H84iy0UbGbd2PtE5VwmynsSJ! zN;jaC(t9}dkAtzlaz$Dr2dA&|AZ&J=)QiK^&$@cq+@V8PPqUTgq%k?d;s>?LV^x;b z=)($}osbul6TSv1DJD3Ko!ue}%f}pLHpPSri#i2k?Dlfu zlBJ2zBdV8t_t;I?FC+|}*kHwGkP%o|L%-J8i{X=qamW}MIbLOL!Qs+afmInyETT;lB;T9W3uKXALtkn}yKq}yotr=u0 zk9GA|x)q>nRr)KB{;&7`C#aP_F8*_DVI`CgV9nCJ*>U>lfO_~s=oXg|^W@&8U}?mB zkDrI!v3iA-A0u?&jLo@0Y3EYbUDJF6Het`>H-Xj#sPFV{2jbzcI+3$cZkC5geFq05ucuGi?# zOGqKq@T?|C#vO38f+(i(R*>rp6$L{YtI6Y?kOx-aM!_6<`xcs(Ikb%VymJPP(^V!N zw_$u=>73iK0O@@V^k<-{z!LXgys6F}C~lF2BbE+V8$P&a-+ptxVtI@G7QiY@LhLif2Wv;UoiMl&GdT-`<##gthB*k6X zKavF(F2A##oVc76zk}n8rVzsASoa; z4A~2&v^==sdd54bu2T0yN+cK%t_};-&yQ21($PlfvHE2UZAqz*ID8>L=K;hx>)Z8! zj||KXMCZDNnL*fx;oXirzBZcLig^QJQMF&%+A;mPr4% zborN+J@)RBK)QVT-$Y)0e;0XSiXOcC392A|V!r18C-S*Hn1b%>uVz=;AFL9b#5?|3 zb=~`)g5+tiG82*oLiJ+0H|o*Y_*b$FooBfrWSOt#NYtO?Q{Z2$;x5wfO1YEHgNaw6 z64=ctzr3-4PUr$?HH_rW0&i%`ouhoG84a&3B;zS7cFNmTa7ss~s4JS-AWTfI9g}1$ zd1V{2!`VP3Ix;$>Qk@XeD#3~L^+}<1cJ4P%M`!Iw21vdRa+FYiI-7XSw0|{MR%-A? z=nHT0`}YFr7^{qXG@O7lA-Cz6p12y*AbU>Jog%o5+1HkkG#f7p=V!R>?(Vm-&<45n`1culQxOu{(!BjQZfzw!$Qz^mt zoH5x$bw@ncE@~@ZiIL`4KY>zCFyGg^)u^Hre`!;2doAw-nbEe)pT0;NFk2GLRFgvR zJZNvJa+zabct!AX=i9W5uWDHgdU>W&f@m@}w#n3$GB>{vCB*mO`K+J3Sb;F;Tr0~k z5IR?=Q9F+EsiCVFJSe*goL75&EPZ#w0wnTM_>4{RA1X|E`p*5|U|mqw47 zvM!_;lWo|%NJhU4)TiEU(gG*^7_XclKyl}Co$d5+8p%^Q{TIG6-wnoD10{Fc43A&& zIp~KT#fFivRo|*{C;0Bi<_XOdhrdeF+%A#bve=uF2*o7g*Mv~tabX}1 zkpVv8@g%Z2zj{s=jFPgH9V0(3de+Ln|mTjV(r%Li*}&$Ww=_G_x~_iYCP zVBL?UZDOi)dw_L0`ptibHU5}rqzA_<>gkT067L{>uzpw?WfpTiw&37Q{8&G@Mg`OC zvk)M#?J1yrEICnkP1yV@cpv=o6_#d9PSK`f$xrUbM@MK@d|A9W$hXVnf6yJ|Q559| zrCf{ROG_P#@}(IWUsJkoot1Fw6-8)4a22Dqg3Gke>D@f%;g=zbJ^StPin~uh!Be~= zt!tR%5WDw~BU;UDfh;!@S>dCfAilk<-Yi9Am+}C>At9-%fcr7tDUr7N-kKV10H58v zWm11*`(yY4syqkdVU*~J#-=0Kg~mHU0wHayvZp;>}VT`Z(8z5;?OR z1P|Xem4x%xGb*YHFrQ9l;W>lF;WtmI?gW#d`nN~7n@SUeaeTAx`bv(GhdPe_TGWfF zCaKP)Hzwkvp-X7ND)0rxuoscZry^KgbOV}b zWs3fXhoA)X98Ea&9(`EX$Yvy`&9B!#uCC# zwk69!_3@y+`zp>`aWI!2<7Q|b z-q=o9d@Zw!8m2vs!7}EhnLr=(IdECFSv*xJE|X0w@$o9IRD9HWLH~|{6AcZ6`F`oF zQ#0%;La(oL$lERUQ?v2+vUA*kI@!gpWqJF&OpPX zCWb+k*IYxCT)lv8Y8snrs+XIH$(STq?LzfM?TT-Y5?-_&NRFn|xq?G#xJ|X8HHPNu zT5Q22JAP9F(~IRBX=+8m&KR0b7en_OcuE{O{uM4Wf#o_tFlOPs^))0SEmAN@$!*if z3P(|fD(J|@(=%x8X^oB^@1Memi78A!eXwwc)u=r)qk5#K{2o+$KGGkM$m|1S@^?ik zzd(=wFNG<;7A%0_D20D2i}jW-=_}^DnZSltS?jy!P~sa3C^|F~ZqkQ*S?)Py$an6C z?+7Lzoun7JdpIt$Y30*=S{A0qO8Ckhc#QMXwVa8Y<=N7;gpG~nIoa=?rV%raH=Kz8 z4*Da!FR19DlvGTp`;gN0{sjcvn@?FPRmoF+W0+paqU}w!d}qE_g}qhEney22cLIV?swF$boH)Mn82KZ$u1hrmz zs7a9@^yur|N25nw=1an{7o`J}^kRx4w$SiBiNKWWD#;Ndm1zb2zxoqQ@1LrU5fXUB zlx}HAm5|wDO&#M`!%rR*U;D~DFr?sBxb<+0M=5(?6BH1d>NDui%i1A|Ggjj*eXt)J?+cTZOFF_2+@pV?`V@7W@j=nVVS>vQfcM zm0em9=u1kyrY5rk6+O4c`$*uV(`*2{KdGJHE7Pc&!BME>RcSm9FLd_6DKXwOWzvif zvwiaIm8Z=eb>THR&u-U)ij<_4A4t01clLSE>sI>4SL&|5UN*Z|yIekxa;=7cd~23{ zu&f68n-(HO`tMo@U>?6}1{$V6E(HGQp8sE@p(zDnQ;>D1N}qf#bt&G)kb-!-wvTmn z%r#_>0cfr*uk8o)($PhVhKxZV>!;=sJD<1xP8 zn3L%n+aRhsVkz=bgjLJ&kgk;(iubs3d^E=nKws|j7W#VV&;+;kkJi-7Z;3uU-pB@l z<(44_fww7U?<>nyxugQM&wGR-Ge1f+sNXT<>A{Uzie?lA!l*Z4TPAe2vXu0&lGM}h zHM{Vkp|J29+{}(H0cnWrtl_T4`ZkAmKK* z%`gD5qr7)K@|}j4J`5g6DZ3gxIHEC6^Fv_1KqYf9te3mO={V8DvmsZ2>gKll6JYvN zZ(liWCVYc(Od&LIewpy9JVKP&rbR|AMce1BJA#r`)6N8&o+|_qR2wRQ@mw{|bbb^5 zq{{E}V?KeZK;cMA+hB?^OwWP?)!`|GRRU+gcYu{4T|G!q9mCP=Dp&ti!rwAuyD-t1NZ`9=SP>Z^S5cxJC?& z94o(l-9}OQK<(5$$bCqkR;6A|t%gn#2lm_hsv$h=ol)K0mkkif$t9)!0eSwV>n?aK zagJ)aA@PIIu&aI0r6dnt(;met>VS`&wTEKYu`*8{Z|YU+>EdM(0_C_gY=%?A!yJlr<#z?Y(;se-?F{&#!j4V5QxD?bRVM@dQ*?lI; z+}sC`86Kx=Y#A?~)8PLPG}8>YDzbgLh#ciUCn4EX1L>cJ_2rJd($<>rDx8p`XlWAt zK)kfP{o495TbWH+o3JQvmey(IF@vxx)kCVAchEE7U-|-^)`{>R0QLV7b_%R}8D>ok zaA$8Eej%hE@O+|8PnpfTv}ke4eltN;milobnDmFwnyC{%~?YR0{bj3>Ezl! z-iDflhRpZj+=OnGf*%7GEcnACWzK@qLCtGsi#PjCCrRCDJd;i(vFMN7L0uuU)y%SG z%$LmRNRkk)hA(NSll`+4Rh_~sDgFHmfu-o>%|Gh2sG1Ra71%(%a|4^F7ETw_eH>`~ zrN5jmR)lcAj^oNff6f?a0+m{=91mP6p#h00vs zFx2Jf?M?g^qaJ0Nv>I9A9!P3oXinL1^?vVlX%P5*j=eJ69{?{TACEr+Ue_IASWqJ6 zJPw9kR~>HS95%Ti_!%t|k9&3E*?xWEKB^<+nzOIUj(VP5w%Krz+3h2;8rfyr4$LWN zhP+l|g?KY!R(|>>f~wq&#S|`I8KM-%e<7SUCxzbavJlu%;CK?AVO`B3PsWimXW8AK z43!j)BV>Ey-YFQn*knvTbuj0T9DY#dyyWL!@j&Fl^_DxsE2SGnJ6;|EV2YN3#ExP9 zC>`^1zK%9&{V({>B+xY3ZU57G)Q_K_*CC`+t2IcnxljsH(DF4$q{GX|^|9QOlCn|E_-kB<` zo#|RA$$)l)){ay}-Wny!ig7i8SL{KcVE=}Vc7K{m(PGBm%ycqn&GsB++@#+8o@hyZ z^I6J0*=D&;Dw_L{rb(bEQ+e>`{*r&~A2OF?#7qogG_E(%Mmg!f|8_OZOm263OlIy< z{0#U*#k$^enF zc+>LE$)XLb5%?Ti)SUqYt6-w3Y0d`z#qFNP9M%E-ZRw3mvac50Zmk9*t5IFuBg3*4 z15k03Bf%AIQW9?CvNyd-^*ez-LA9ycgd3=KVgJB;^Rd2TvS?k8w&l@9HCA!nrIig} zL?i0{kiPwgP3j+%_@QULKS4zO^D-aw{d-fq;r%16`urb!Ufa|NLIVLUG*N-T=E6v} z^NV*JYU5V&2jZvhG#U+U*CtL!l7Ccb%~adfR^-N5R;Rx*jWT&YD*9TGoHwu6w~U20 z%i)`uqqap&3NSeyXG|1mTBiC$iac+AQa~--vbqL2d_M3Y?2B&ycn9t_4O_p?O~}6l zj!FObz_HN$y_t*#x^DlUplke-v{QnDo{hsrj{lW0)=s&~!RJszCw4-syzIcdaa7~G zCIKL`UWsXc_@4el^ZxI@M-Ohc3W%|)Ltkpo)5{pk*KHJx5=d$iZ7!wHs=4&&6>Hik-}f#9wfI6M6R( zsxLSD6GYGHk%p**=U5+}kD%wb5v*DqF5E!qnfk@c<%f()PkYVxWb8l_Z~GZk`aTO& z(}{lfiLyC$=6j0>CLMCXT$^wMP;z)9_)If!MtxJmvK*{|i6cKXLsM zq@u>E)99SNtfQvPtXcee$Tl- zYQli;i9?XR@FD`bx%1YPyjIfp9kNeMV{2++EKghgT9#=R=;`e+Y&G;lHRljgJtdbp zm$61g;-74mw6t37uAhj%&N^K`p!7cxM@uxmzK>`5lF~<@V5f@gYiy6NBY7?+h#IDc)ha1}Md_zz5jFef;IEL5dyfd1K5f{0r@WjHx@B%v$X+ zr?r^$>2vu}s#HapbjD)H(Xh*g=7ipJz6JYuCOUX3!8#z6-1Rn#pPQODLE{cM;=AQYT9!4F9`m0!Rf;vnzBmG>s-Tfh1<4nyO=CDz@CBmjwZ_feT$W-1w;Ih(FI zJbH=28A0zqEc*Gf%itWK9RMu3W4Heo_n&`V^?$ol!$mZJe`&PFfJ&d!wa~@NESPOm{wm4`rcs$FkMrJkKhKc(6Hpw@moz;ok zM?!vfz!vv)6-l>49zG`=|LNoMCd7c+81$g*9ucGP1^f;8<5L=f-vM}2-dzKOqAJNH zFXRrlVrtvFX6MIXo8)Sp8s5#EhX{wiK5LSs<3W{N7AMY~Xmz3ibh7Pykp?4B6PGiF z6l;bbr6{m_oVW!&b0ni1m;F)R6dp<3F@r>@RH*6KOrlZIhgUL#o@8FhegL8dsq{)A zAGrfZAb+FKoI5VT%OPlLa2oUNqsgU?*ux|U%+NN|k$X<|LxSg*1^u$RZM~=P{ITYM zH**Yv?vkoS-bw{uEyAYe9;{3r6Hh1BS9MX0!e-T~*CyFNB=P20T{&{P8vPSw-J-!b z(uDN!o^w`BPV)1%)m1AwsFZ1+<8_fsiJ*Z%2^3M1`rF=4H9R|$8U84)1>YyVsW&i? zr1Nf`M^qH<8A~k2)I`s=x| z%vlYJaWVVwF|bT!FI3RE8ParjX~3}Ji5rI5>WSnGC!{Oq zZ~{dpPxc`_i>uG#=-ufajkZHhYj+CX%irE6+Ti6Y!%svuAiFh~+)3#Se8b!>>(vO5 zcq^oyAy3Ed3oD4{hW3dD?cTlredkEF1sDKUff%LQ{=zHyXSFNF!yH;XpG(EM2^i^c+y6&}-3)Bp+O{nS+>bU!}A%V1Jb@|#MfA}3TNdVtW42B5Ox3ca&C-O7Dw5er1_A;Hdw2Q4SXjGSwMK07o~&sl z8%zKBa=5~oDb3M1PNO%G?CciKX;#sf5Iu{(YnfNvZF6^0pyAy6uE~>xOQ6UTjyDZ3~y$qeFgEt&ZFUhFID_U!B@t^D+R^rX5FUg zoO9%R_HkqKm8(NkW0%Ln+v)8=2H_(_@I1BoM8HwhD4t@bMb!Jn82VFcVDnKQ_dpO# zEr{1<efJffH{+|ie+stwPI!HCvOv{S4+;^ zj#{F)IVl=2B_RhC6`>NfzcY(}yK9^ae-XJOURZ&ly>I07OL7`MqOoMWNk;57j|R->arZ$hAvX6os=DWwc^cqs@XIRhFHfbsEHm{A!FW3lcTw%pap`^qeqVt0 z%aZtw>KHOdo%?OL0=sZk9lKCayx=oztX zI>g%^#wkHOTeux#nu8$prRG;&@2w6h53s(T0vv&CVC%B_AY|L{=3>c&Yuu0iiDtA! z^MH&BrshKGxgPzA;ezqotu?G*@(04UCmc0Q55vddWq@1$KV@n(ET;Tc^q&f) zXL2A{y#VQL8X|E=^^nF_V;~icl}@ut=fv2pR`_|`r?3sXXGBB@qZs~v(&fKhH(x+a zv)2=WLL1p>G^jLUB9qH^GCU<;R~`(e#5U7zMt=_~v?%u4+Qr|t*G0dV^i@9C@=Y4S znadRQ6}KA{^=~p?e|o{4N@fqb9Ofe6>R)A~?}sT~Z(FrrQ3R99Urj91@d3z%rbEBx z^k4hYqrg8w4yeP4mqpnk%o%g$i~^slNE4c}zqds{u+BgUr zgDnTzJ$WjcQ?E%}7P+%~(OD)$(o_(-u4n(HigSpg)0P0 zi?9hipCq1P8I$;;5u0eRZ(TgZPM(W0Lcera{JIvAx~ev~Z(Q*|pL&5s&PJwbQAkFd zWp~3EYr~kiXhl@m8rv9FC#!Dkaf^{S(Fnw;4t$}AufT})>#nQ_TMdd(BYxkth8er; zr$)1X%tfBib#9#AfBVjb!wLF%Lc=PYeR%y;QZ7RL0xQhL3g9Y%aIgC8BH5H9+uvZj zxhgIFWrC`eKcU{>c<>6&DYM8dtBaExCm3Iv2;+isySqWWyggw^bs}+N(=D+Oy5#B# zoU3N0s6&c)%?mMlp0 zvi}L9IA!=glw4{sD3Bhela;!r#v013Ht#bgdpjG)i@xNJJfBQR0DDy}tO|O-Mh1{&gJI*=N^ymr>&+r52ds`S4R;UR! zPTH);Kadvis4~3%gf~u#A?58X#>hp~d!vkgKA~h^ap->y9|3uK50F~AaU>h2KLxu)9buI)Md z*Zwdn8l-QnavED+QeE{9JRnYUZ=bC;ub&3j(ABxH#)(FTWU`HJY(3Jy>izNQq!vt? zT7qN^vO87-wC`TXDP7rAT;Jem&=*zhR?5T*7Q-(9F|pw6Nk!3VO^~=)Q}3&y03B0z zi=*SOi(j+DayB@`nx^gYD+oSk3=?pPdOh=@9X`uj1-ea(o`fE4rV+r|%y_Cgq!v*7 zOJIj(XsvwhM~d-?C24q!tPZ|wIZ`~KTJ-9bRTGpaD!A#beyeth`M`;pvl%~JKsdD? z&{+_r{{3B-Q3NK^@LPGE(dfcdH7d%>^cmsTAv9~$d9$MMIO4M*4vh&<@p*0 z6PX+jpmD%BTBgwa?V$McpR>$ei)qONJhCP!xpMOs%D)6xUY7^=(3*;f-4!x)be7qS zo}DH&*8`Q74G9G3f^~`<-38J)wGlJoZZ~gnAmOpp7r38a7_O!2M?Bv-`yGObf}H?f zQPnGf=xUathTAa@3(_N~QRaqL7sqtg8v2r?aU$jEt3j@X;65D+3SU*5Y{fKHBbV#T z+dt0DSPQpOojm@X(|BCvAsCnClHptkBbsdMH?8oOm5337zF0~7O7W;AFLW(sV0rTd z$IXKJ6bTs_#HnXbxx2f9<-hc&X5yb)9sx~5&GV!4e}c_K!S*izlK|@YD!}I)ZcIG6 zp8Q^dPYM8|1bhi@n4h3;{*^C_;m1Up9>Y~0CnPz=|M9Hqw~M4YI6&OyoAYhh?V3A- zdG@hJEz;$m@7rE_uC|65A(H)FGq>HnKk#I$3AoqB8ZFxfizMCIm5B((a5Bk4S`$wXtW|=q9sW>K?l(T!l`>(G_#*ev`wUC;!>-A-`#wfG>W6(I&q2RO z?VRR>SYnZ?##zON+aORw%8vcD`tk4erd=W>*Gv`gu5@%_TkLV%_TvGL6=l|;O*MkL z9hh$yh8KyhKBVcccK5?O1AS77D33Rnp^1g%-LsymD>h3(8wFX17wPBI9TNt329a3} znp!>e6@?y*S+1tIM4H&4Ai1{7h`V|R_**!=BQ4yZVRi$Zdw`6WX+CS+n0QM9>#LKn zV@z_Q99ElfhY-&1ehV{`;Ny|1NeEMr(w1+fDHShbE`HZ|Vn|N>h$3Hhqr1S0)GJKx z^lW!r-9b^)H^psS^eyaIkhJ}V546Xb^N;?f4X_-9(|ft=6q{)R)(LYU8Ds7ON)bJc89bC68tn9GzV z21=_e?`X81x7-Q-HoS1rof*%Fc!$Pz2j+=`vvg&lzS-#TcVXpBLo;C-My|x{ri`hK z7)hD0))OX54%U4Z81=+e{nq-Wt~9ADS&##nsb8~^WC{T}D{J^ZF< z%7zUq&f13f-9!xKJ7dG1hsuBXOm6+aT1Elm-G>&K(Fs=(Jbn>!s!1a7$RRzM zmgSo-jcG%5wv7HS8YLbTed>!mk181(a|QT>LZGFB2MgN(c6{;+JJ$cdgB_y+fT_nb z`V*vbHeI&U?YogyU0AMg5_gSz$#Vc?I3~jJsCC`zvN-Jt-Q4izxmii?o?O?w_Q|y{ zvfkB5XO~ZBdj{_VwiIEnt<78b;p6L%D+W}!VD(31?y>ZApDfiK^<2M3v!xg^t zc3AIeRtd1pAEVX_7WA{cpHvgtK*2oK<)9U(?*_S@go`Qzq*vY~70*x|6?0C3S zR+9aJp!X;L@3u-2D{09Cn!?4_it1JB-%zx_pK3b)IPC71d&Zc8XWa$t-%#FwQ|8CPv54=B-;OD@l4nCoWmrY-$4(#r`1St;whkzt$(*FayLQ-qAUyeyk)oDD`O; zSGV8(c$CqP_m-M(9UA=Tl7A>asCHhs>W@3jsHrI%K(SX=L~n5$ho(gWmNjBG!Wt7& z!<95PN0DT&AMAWfb3JfuE#${EAiHAVKU zo>aGg+O*0$(`480rI9_>j63J`n4Ow|upvV+Z@pig8)j-{oPAc6@A9QcTtaJ?-AZ+} z4X6#R54`@MHl*vWeC zLybZc*qW(&7rzfd52LjLs-HRy4}IYkz08Dx`V z?u1>fKoIeWcY5v*04N8rZPSwSS)jpMk`nobotoH zAaKv?9IATu*}z&U1FiP{{#hkhAYP#TqDN>;uN2kE!(E?hh%7KDNI3cNT2?&V^ejq` zd?rT@K@O;X$@h|1DeB=LU6Fo#kTuF%71f5T%fd87!zNeCw@W3~mr*0^y8SEzB?MXp z-U0LL4TmiP*RSmbibb#lmL5I5dB-honFwsCv4oHf$x=ZL99vMYuaBIZW{{FJj8AQz z0fm4@BlyX`7lvVZR-o*TgW=v4cB7d2I!ss zjDF3qfb3|d=u6Hj%G83yNWK-wraxq$&d53U;^1YI6U$(6Y4TvUuH=E!<{kLP{Lbxq z(bPy4oQCp%SNM-**;2R6SH_tJs(~jDh{r0sy(J4N{7&Cwk5A#!yR67plq;%2C-2M0 zdd7WuDW30Y`A%P)sIP{QT-_F@5RfGw_D~k!`!aWZggxO~vM3qxYHpiWDDvv-yIERN z8uZqmde|)aUVSFRd(f2xf5?K+V8RN}p}qg}P4(aL@{S#7Irt+&D94;KA6JZ*&7YL9 zp}oZn*sa2EIj1P?WcUe?*{Q|n^K7T_wk>B!03P<#AV<&@g5Gekv$#|eVEWL7>~yza z&8>9Zbl~uK3Xe#DVxei+<))aAp4m-{liJTUtnr0BY7P<&SFazS(6cgf2dcPzJbL!% z82m8){usr^S%w5$=B&}<8mbuP=Yb8Np;h41_LsgEzKh|vDfYyqt7$2U?j(5CSfet2 zncaRAiYX0B-AUak*0u}_dwRh)M9}407SR9)pYdeWP)&}o{eM+XbmzKu{$4pP|9jjT#E6b@oRHyRG*QR}xhdMD(W0ozZT&l=28uVwDMrg*iWk>CtF#0_{9_afwH zE2aBK-uIclTj$g-zq0YvofoZrWNPsBWS~0Nbaf4N#Q1LS|KaVe28LaftkVgcJ2M_z4qGcS&!?y z=bS&_9_F48%5`7yi*MZG6+9F)^GK95Kr6M?D20iDO$$uo%ssN+dK<(@&=Oz2e|Vjd zg11BS z*05QY&da!CwqyDqe(_2$MvGsPR{Yv73-1l31GLM=@(c4dqfRNKWGKZBBA&7W$wGt9 z_F7eLfky6|Xq3)u-2_%}d!^`;U1I&}-}v^4$tr*R5UC@+8q25#kch;Bs7_9~v=4Eg7a!cSd zc|R54Jx%}zWcasdL0*o?o_dZa^K|t+Q7oj*ws#Vv&5~qoVvwaKjl6DTByc~>FObnB zAuUH*)jR*Gq^nb7gI7&QJLs-9gSG;Jf68Z%TICrZNs5Q0NjD=u;`MXiSZaV2XeH5o z%Tt?vjE=WoRX4j0`GC8FcE|%-WQ!<2Uip@9wYwbSYX%`ka}VF+WDEULN=p3|fdxIy z>o<3O{PD7G5P(}azoZITIAO}*Tgv}>{zg?<7D%yQ160v}sRQ!AN;c|$rbIpV8{!IZTLWBu=3`4m&CosCl+dw$imTDG9Jgj7DO)=fQ zvQl*aUdXy&BV!WY{;50on@ZD@*M+f^nt*vkT=HauxO#KTo+&=@iu8BQn={lHbQ!ejShgrrs+^$Lz4+t6J z&S7(=iPTaJ7a4UcF+9_sIv@v>=rL;O`X%8!6ON2e%@s!^#`AH3vrMid5H1FRfdU;M3_PA#QE0S ziMM%*Ge7ZS2H-#)Zg$_?90klgD3hDl9|0Xy;9@2j5KLh{IB$7T6!Se!H&$jXk{A?8 zp|Sz8Xd9$gj+{e;!SQe<2=ZApYH=2kli6DpDNCv4>7-mq1l7#XXL6;ZVOd;^?+9dl+>seVU%j z*mXCBU&vjT^?!34({nz8B)42#L*C0V<8d&`di$fT9cCZ+)$=t=8oA)(!c;)`vUCYL zbA{<=pVj2w|w7G?#_du-nyfSbsxI_Qd+)>LocGl z`^|N_SDz+V@j7>8_Mxd`2MMY{-*RrT*N;}$J3;-jh7Cszx>#l%aX|3_?jsiQNASja zXw@-CT7LizDGw#aQF44J)aBM7ske)<+3E2HrNGDK4mrc1rGCE1RI*wZZ8_u>u7IUc z2A!tQG(M3$N5o2uSB$FwNs-Rd$3`dVxmfOs`hv8o8z|_OK5V8L)m`@_Hns zJ)BU|nEGicBKUP;BNLN#RYa7Vu?aNq(pi9Q1U+V1eO-z!1DzktmKru8w6{Ata)q=^jURP3mUnHRj-?+8AA7X34~lnge{4+lb^rCGi(F3xGIG!K3)WuGy2 zygRqA;YHBV*l%|>HeGHI*sD`3(A|1;u?#^Zp^NP79`=;^`g^pl^PUjwG++Q;th0AZ zGu_jAbBuh&AzL|X*!wWm&_G7dJH-okqi#?NY@Vpu0y?Mk`HQ)8%5&4;@eBXpTit%_ z7^=Y%&xy|IVb6u+X?JoYB4b%NxaTR%*`n;kYi46j8vo)9p6O1#P(a>DMJgorNslgB zk8*akqwBq>=9j}>YeBJ3! z>5^p~kOtWB<>Tnv&dCGPosSF56-QSjV&#Ra)>uSkRBWK}P;vwh`qR=+ynsglI5b^B zkjcO}Gw)(+mfM=EU7J=TBsmjrsjN@sND|?PQmTpXKD-AaJ>63t@_&APg$mRCmi38B zytC8JE(nsRPTX@2FR}Cj#EbrrQL5bZpvrVY-b#=zleVstH3?~rPA5WX;wbt`c zHHyRuI$*zP?c%fav(L$5>j1Z)n7);D_wEuD%g`4ut@)`rJ!$6nT3u!6aj>xoyVmPRF)ON+Mv56~nk8=cpjw#e29_ly;}cX@ zeGJZXG2bIoweQ5rt+p}?D+&x1JXSQ~ug=#$yAQvDD~2(c%u%ADPK(>4{H|d&2%Y*m ztFm^In7XwEY>GD$D;?HBhk_AGj($3KEDom$DAPgi^T+A8q3&|jCeuC=6>E;S{mXrXwWBy1PI#d?74ArsMMaWI~n zf0%O4aVNw?IfUWY>hS;1)j^5}NEhs8z;(@%srU1l9Wfl=EUxfvMt`K@jSLf&7hIoo zg>2{m*bP1ROQRwdr&i=>+hO@xm1$0f(|(e;*auOCX?ah(uH1^c-ncL^Y<+pr8;MZ%&cvd#I+ z7uUAwDMS=L1X?_!qw`Zf-IcZ^A$|8*#hC-}{1fP84#Me{n>o8$7C=nWmP|)tG_xgi zN{{6i$KiHMApbdvF-~I3{jyr^uVGwq&N1Ik9@S9!b@$T>_1}~?8K-t;)JO|;WdU5O zH?Ar`KaECxo(U>3-c(kQd;|=Kgv1|l#y?))uD5d1nI;ptKgf3WSM#VC4~z*_>f=ee z$BSYPx0GF=+Smpf509^|{(#XRc;p))TG;zqqYbjYDDW=_v7T;7 zss{NuO0P#nN85TR75~IDNS?aTeqsT;zpX2uA9*)Jg2t%-YAkEJkQk6%aGc88;plb`UDj~W{2>Dx0mLYn=R+MLEMBnm9~*$7*3xD ze&G!B&@TWiYKiXSubmUp3a%UvccKr)^5>RB>+vO6DA(S&19?yXIq(cJGuDMwLYt?% zYaGP1f68aQuHzG_L?_b8L`!Qo9|g*0f)vCUFnYDMmyLe|OIa_Qh$s*!3Ma>qLh8|_ zr|jt9)U6VUw5b_%PzQ5QjrZ2$8*h=-4;}6=7j>d|XMaKB%OB*=N=hnI z`MxFtyo;XVWxzYk#~il$^VHWYaC_@>s{W-u?`l|q>Zt}5@a-?V+kbq9{`$oadJ;~D z@Bn4B!b8K6XU=Jniv*X}Bk}jes-#}?jIeJ*c_D?c(K)t35mThU>S!I9E$;T2sg;ej z&1%mx13i;Yk<78zAa}a46$gwXL{_;;#XGbNaZQpRKHoxDFUHA@SR& zV4u?4*5>A97~ig&5$ErQ1p&BB38?O`oMgy;R^`dbJn36=zJM3h@@^954FqZYU)Bj` z2!1Gs^d3}Qi*eDcw=i$m9({@ynoKk;5KaIfrsNC48z%}*?RTYyG|DSaEoz@GsdGdL z()AP*U~f)NOsTziF?b9xyf^u#-^Un}`6Yk&_Mp<&F_*aEt02<}Qsrtt|b`_{9Wp$-gtBkWXCMYjZ_3q`+Z0ie%T;lbmHMpR~N_bc=GCD^3ImZw* zaFZUtqh%)ip0*bHbo^}hQKSlMK%tLgrz}3Io0M<<^izl{UD|Pr>~MaWsL)MXp>b+f z3i1!HwZFfVJjSzuMx30RVz{^CU<_!oMb@5m?zbLEGW`51#jlXe7ec{r->UjYg>Vrn zPL#tlXW+G}X^(Q@Eb0?(Ny)&muE-jmX|f~*Z( zXbp%(+p!m9^AlhI+I2dATZBB{*>$(B%HgJ?e{Z{c#TGmaqk)fxNYTCaHIYk2sX~qs znQCt`6y>O=Cb5a{IoiIg26i#mKeTe5X%cE^*(aIZh#$+Fp3|;|ewEQAXCinm-J3;2 z)kG;mtN=sakg`z;t}$L44h}A>6f4AeVRc-S9w9-#Q&Y!hfP`OJ%#B4R=`e2bpLixR zJQoY_a`QFtBz$3Z|5KUv{=Mznq6MdU6yD==Z&)@huj{wc?-!|D6M8JVz1fX*6U~t; z6tm5!h&$QxnA4_gAtD2B0?SVK(&pdB;CC0P?JuQvO?S=%v79C0Rql**&srZEN+ScG zSEoHB(UXR!g}HS%Pp60WPN3cv?76Y>v{E0c z(sPCqmTRP&lb#{{GM4vAq1)$mfgCBWiz_CB3?X>mf#?ShE7+$G z=3gMgG8jmV97M}V`1O(bzCZC~RS>1{PPBK~mcjZB;p{2SnxA-IQGz-GEku+L-~SB+ z_2GXsx`?gR(dLV^u(N#!FyTf`=rV3QxL%0T&?=8RTDwA>Z`vZ?aXc2OH6z8B{`C7x zN5apd;?i`LoYe|8^1fvb0L;Sggq5wcFyott=d=S;5g zbL6VW6m8%erD4SAZ&%li{zr8kqe#(Q^CeJUNLuNen5RH~nykt;=U`WA(Dnrh`YPhF z`^zDB?n+h@&UA~Tr_3KrLK&CGD$)$*X<3hJVi@J_7b{Ad(PW) zaL6J>d{DW|SWro{)xPoOv+tWDA@nbSn#ph4D!TCfPf=p!0?*F(Kk+UQOh54kLrE`f z#&cr5^1<74VB8h8>5SB$c%4)&7xl})T}hqa7wxKBev3;Jqjq+B?MA(SZ?d49hP#o@ zI!oYwnOP&vX`eH6w*Xm!c~$M-7|-4t`)%p&mfiDJ%`vYTVu=NkBmQg_Q9ES4M+KxM zk6aScDw}>PekZ9?MC0-pmba>H?K9kb8=HwWJbP9 z#o3U)H6-Qp#r+`U(T7}3Bgukg_T-IzEHR%zXFc2aYA!$!y8FvZ`_EOH&j?Nr0AnFD zd+0U5>wEgg3tWmb>2e?Sl!59Fp>>f0dKHb&rHZ+7=-1 zh=I-NgAnBCf@LD1{g!02uleuHWvw15ME0iyKM+^kF-qRYbJ>I{w^TVnsHwvEL#*I0 z&*{WW)m{)UC4Lj(4q};$&d}M8Pb^Hcs?!F3J(|)oblbL!C&UxAw2q0``ySzoX2SFK(l0uzYCq@6I-}hVk9= zcexXCVkYaph<*E749I80$ioUwLe%5}XZdzFJ;3p5`q)s(PF_*(^MgTjBV_Pgu@#L4m;PUfRX%3c}mSG2~ z>cfVx569XdaZ^laZRKDJ)0oU-#E$@AlDrsq{be%hx!HmKnKh?L3*mUw0VIdn$WC~!xj&k5+2w-Ko#kLZz|xOnub{hM9Pe3Vt<a6C*B>$N^?_#W44DZ_StQ!Q`^4^pSpUJ|L!>c@p-Z{H;j0T3qgAW z75jl6*XWwz{6r7iD^I`XD)>lGPv^63!M(jqc{dYAQ=@pP>FglxUZr<B$+LV8I_LPH+hQ%i{5=@?Z%H^fH!h>h zt=?_HIJkiAO?k(Zx<%e-zAaN2c>lB6@$_^2%hx+aB`u!krKpoZrc80|4i9!8JQmCC zSl%T&S#NKc%slr{S=TtY`{Eft@vvC9aK02Dvp`@!xs@(O$U9p%m#aV^T)8|zyfGbC zx+E$_L?AP=$kS)TyTV<1squ}*Y)NaxHEV8Zh6baSwMn*@q|3^W&iM;4+MZQtmM=7t zPXww&g^n@($)`NXYjF$7l+K@8g-&xUGE7NK-;eg#+}Am*E3V0fs|y?0eY^oLa%V+u z1C{4c2d0r@Pg2bvbJc_qvNiW2lDuAeInnFIW9waR5`9nncu>8mpw7~mb3e=nat+Lo z@kK4hr7uUcq7qAAPb=`D+gXFfCddTmorpv@a{FC?bS3ooKt*6%! zv%M_g|)VjyD(he$iiJM0r@W zgN)vhuNrvewZ*zZhzowOaxswAiJ2c?Z(4Jo*NWrvd_KWh$CIyR7H`xu4V{)LX?bQG z^UfBGQ#+45$m+O>WL%u{U6P;(+%G`MQ>~kI=c|Z|R^}N1C7%Uv`J6OAQd6Ty@6^X# z`p!T%{w11hp*GpS;f6c^_qou@*zujCOo=I`u;CKq#@q1bI!l&NP6I`y<%UHIPii_p zx%B~Fz-u^h6=*?xqu2OjX#u^)IbH3|@n{{L0osBx7G2Fu>wutZ@;r2SbeT!#_aCL! zF}}r>A*fBJgQul!vbVg5iP}Q5xr_w_IJ%WaZ@EG;-NERL#qc01^Eqd`H$i6xOByb+ zso>oQE1(yH3k&hPd0uU={mb$cvQZ}Mehi_qw#}xcdH-t{|N9;N?_Ucfhk!}hU?k{! zC}`bf%{Y{LY;{wTBY_!CfC=+tzYX>QD}@d%z^Wjh)vVPEDL8JgrnY+BdEE3+S$v1v zb>%!7s`eAFN&G>b6$mY+(cP1M4P4fv0*-twt|c%*M6Gvn(y@9^9IWHMS^lC_AEgXDcCcZ-Mxi>o6r0 z25WgbD|w*5T8JNzKDO@WF?$R4R(yHJ*|URp)A&nnl?Zhr^ZQxE#hmdY9VxQy>^{@# zV>X*~u6 m#@jxfO61x(k+0+H}GF3gnx{JV7>Mt+{Xd4UO$RuP2J)TM-_4$Zx}@) z^1Br*r!;0vD~e~dwA;)rD5fKty-1|L<9n$NY00Ipd^VhsiJ{1{2jblP?mvFpKfNA? zPaBILGz1{Xw(eapkFg({EQ>kB?5wPEkkY2SxjYaVp(Y`~v>bHe`a5D~=WOBls+55$ zKGkn{tq!3)-MuzkEkk87XJy6fccqG7ZIrO(=8H$#`JpH&3uhKRo5D%4T4Q(SUyl5k zwrrjDY0Ri&6j?S+JpJP+Zbg^f!aly8Ls#dT!00ODk->Hl)EDPPenB z!oPQHX>7%0FJ`HDE6PGum#v4ggoZ+OzM`Nl4VO0oGow1{OlK#BD>G9aWu5b`5N3|` zAH~cwSrR%ANg<0P3AwUB`!6}Qo#ly?FpwFr5dPCa`d5M3-`_iePQTEtJ(zF&iFa>a zqg2|KJ(kQtfQ2cNQ6HpF*5|6`4#KEk47!Gg)G1^;D@oNw&A0Gzdn7r8Ebm6;oCVWu zP=Bl^9-RAfdgxAy{8E)&z%T*}yvRxnYn28`&O4=w*{24@4i9@g-=a1*F|4Zo+G^8s zC)PXm3`xwig2PT)tf*qtl*5yu7Ac-z{ICNhnLpZB|8HGc*Q};drym>8o)Su45}Ohp`oR(K_Y_Y9M3%8=b4-6x)%SZI$Y&$Mf+y^Y=Sy z1{$4!VN_&;(D|!RAo;tY%DIJ6mb3FG@XkX!q0%&eOIn?9;;O3HE#r7oDosQE0mg(< zpfkukmzElYb4IHcp`iz*I_TmhnX-a=V=J$FPQRss9V{rp9s`#C_&M#@%#XL5F7A~a zNc$cG^8YGq$LM?4dkpN}*>=!&b&0J^08hO*soEt2>oA=E-Io1?)h&R7yjaaQgC2cs z4o&4fOD2WnB1ux1_c9!gMgZMDxJ zBQ)0gd>gr5IH5vm=QSAST@Bd9_R|w#X>+BsH(_KIVTasQf*cQH*A0jzlv#_e&@H^L zX9?O2W2qN#6L@1LTDXg%=nfT>Pf}Ju6#>ay@2`H+zZcaW4(vK$UiK_P!Hv@dkq>vr zs&y2XG+MnWe%Rdk)V`(~CA09fLsTpi-ZMXajk;5e7d>S4=|)%<&!Y>3roI7|kF3o@ ziFomeezC&Xn56EU=K+YC7cTV7g1CmxLr1!Wo^TSq+!4?BDSOL6x~w7Lxh1w9qw%R+ zd_eufV`i_~N7b&C=`9X6xteYIv~XQRjVqpRy=;8T^8)ZOvqy^$$&D>AF3IFKpFA2H z7@NO}2ERH0`8~rC$oRDA8Pm1?u>Iu7~Z)0L{U-2=>v}Yi6m16u;Twc zpyj_P>0Kpqlm67IMVFTGc711Jd|0ce5_oJ`$Gm4s%T_mL(d2FMnO^P&=6N@!$xXg+ zR|wtqXa|WL^?6ic4BXA?(Qb>iV30{1$TWXzOIJSon|YIE7J(_jgD(f5cLnoT-0$=b zbNwezx8c=d2(Q^2BQ2%bq@IzSL%}vPyZFr5;*0!;9)cJUmaA^8&Vo6VIW%>|{&N%s zlZZ=cr>_iMit;zH9Ypz&Lc*rG)2(3%+HR@EcuKnxaS)5OMAK%|wT3qcvh8^3Krz}4 zp(I~p;>3&}GpudKmwjbG4+h^|IxNylLKpTkw7+T5^GIMsZo=lE&+Jy;FltpkOKvF$ zD+K0p*TAnq{qtP*@9zD7u9b8Ncv=MO>$}B^^0U;-Oy{lH?L8V5elic6W@-e+`Cpxf zeqY8FZ$rToTb%7cQjdnTC4(HmX!&KEjLDZ1o~9p{ObBz%(nM!y-mTDtu^t}kBpIB! z93DFEZHG<4Cj>mHPx2Wu$BRl153&4W^gJyXsy*3FcG(XfvPR+e%gTKL$h$+><204t z9Ys7m2d0TF)JJ>4I-Uh6u?gx5Z+mj)jFwDGipkO&a5lV~9sIgx*y?+INmcCd-fU~6 z(#_A#lQe!Rf>-EH&WSKASoI$IqW9t#jKimA!yn0ax%eEryh3hEjd+FmH_&;K zDi^5uut+b4;ZAVG2}v0Oqo1Lzr=sJ)gXtZB|EmWh_8aLbdJ8d(t3goenAO1ImbICV zAWGpokX#TerLBRx>$Ud;xK&g~TRDaRRHMY{UwYI4KS9&q_v5%ba_)g8cB`5N2b_r;K{5Y%^~cB@6iNXq<(du>g-Cy+Tw zI^Kn%w(G&euYp}mC|;BZZ(P5FSk0;tEqStM>dN_I-w`Mwr~{SoFdks+y`*pW!+eF0g0W=_LUi!3VR9%uo2VWbPgOEns?=8kcw%i zrf`EX;DOE);Q7}b3mFZ-HtP>13yjcuK@l{*oO;jVlc3_&FHc?kSvM_kt zadEozNXKZ_*pkw!$|N#y^KiZwAfyM2MFIgUohaB(Im^o3+`&#J_@yh#~GM81|vM{o>)wq3A$}VAnWB||UXyE2WA?|vxH*X zfF>5F8*^~oizOavj%1?nQ|Ab8{LVuuGy&p@`?)1u`Dx!fG-HzxxTS$;dc&0#KJ|gU zsgc=Em`=XbN#E@PAMcX(*jc7=$oU0}+HlF{MtEV<;zfa^s@t#fp7L)~a)DXFj*;hV zI`)?w((^;LRw}#rbjyYf-DrG|zt6RPGigfX9evndgGqQGziVKo*Npw(MTk)|{Em00HJzxEOrWwhm6@-y%`^_#gC#3&p_bO zz+ah^AUKEiIm&Qa-CJ#6IrY9Wc}4Hvz`tCD>SsNfLs$u@acd3bc*QX!?$zjMr;X%n zzjLu8v=s2|U7je+^2Y+?Uw77nigR}LH3;%vB?%GP*r*<(uRoH>MZn5dmV%-U7*a^v z5*Kf=>S@es?*J@@%HE(yLG$V_8ULm~Vo&H@*e~N$P7zrGul!Y$G7OXax52DyrU{mk zR;Ow*VDH2 z0o3O1Hjpjbb@aU*r#y6;7(8pP0sGGhk6uutE0rdWzrJ$fE4gL}c6@X3c+yFolD;Q? zo%MzIAiPeg08q=asMUe$$`!TTad>awb$lL=(@ocV%&WRsQMu#(hURm0*!niT|4Fup z?Dx%@`a)Qrrv=%lcFm6ct!nJ`0>X|1$4@}$1^2NRCGS1*EdB7V^axzP+Mbh)b*x}L zkV~lBkGAyRv}s^j`;~lp1NqXQcZ;eA0(3=2#Hi3OUL%QfF%|`PS*eoajYZhZ_mt>< zL^tvdO?1s4yuR5}g#|BQGQLfRyKFp9#JsH=tL+=cL$2tP810HJ7vyqC zqVvgRA6lTNXfSCYb=QxQ*Ip0mcz!4F!SI5(+VxI#V@5kZ&|9wwJY%xe&&tqp2o=R^z-_kO{>U571yI%?`J=7wTJ`ZuOBN3PjW~HP^9K zU%YnflTY9&d50k=S|~|i3}N`}Cr9}snDO*#m8*SrZlqQhFms^KTo?bCI)A&8wPB5r zWevm#3TOXTz6I)U!k#}YDKA6xsO|`V>?an@le1sdvdN;IDLIQ2d@R|u6Q;DZzbmmw z?^DU1)qQBLH60$`+!{XX>JsJ*&0-#Xw^l`e<6@4Ea;*GW#rUysAK`4LvSakk&q_|0 z)IOeH_Q+eJ-rf$CJ9MkfNm^QSq0)RG8O&2G$R@ib%X<};A@5hDoYAGSr?YQWZGrlM zo?1iuijox#bkn~H=i0NJd`le0O!PqFxSS%~Ilz>Hf(Rlb4gxxZS#eL~HDGK&bO zV>8UtOegqJBN+vWWfspyWUPU{g6#PvXcXc>P&bjAO1MH5zpL%r&Weeva$gy5IaYue z840c-Msal_dM;_s%+Cic(oMdPb1=C@Wl;~`_IYs1w&l5S89@ynsWP~}ska(vwY<6M zIlkVpPWE{#SJoYz4avXgxxhytE8E#G?JirDnDTRNK~xP^B?CV_7TalpAWwN$#!wwQ z+#lA^FPzx;ZfomwhA1Z&51WU1&L-GjZga@Fj?%9VAmV%RT+?z+D%su?;Nx#Jw$b|uNswAeCbfxL0y zDU;zX(3f`(9f*mZrJ{0c2OX;1KDs`tLHJb_>ZictikSTSBllmuW<7k-rX@P>k5$Os zjN4K_9o~|8PlQ|5zX2aVKf{~`;$kf>*k;8VQgx&=(GgNP4834GM{=(!uNZ5A*-im` z`~nXMXzf`MZwA%0l;cDx^k6+WUe7o%Gf{MT5Q{7P3CN{KI~2H^9vJeO=*pbPa6oC( z0$am8_hZbqzT?6!So&Ox!2XMV3^NKnTlZG+E>7`dI~L>5drn<(2_ImD(|sNewl&EC zdrKsJ*1-WOx*3cEOm{^)=SnO1y)n$eE=Q_N68X-Aqf|BXANkafw zX2tjiaN_+5&M;(joulZeE8q<8b^Pe3uY0>()<)7L<(DYAcYz zvBS9Cv$WYCXyazr1T%%0jM0N$>GzSZQ^2U*pLjy2B_>DjNuwPnj%U`3*VjOCH~Gys z+*N`9^)B=JIv{;iG~evJTv>xWSx%17b42?PZXG28fVF{#)X6a!j5AR!=B)>W8Nm5T4&v}Rz5S@}sUuQ=e z&gArF??zENU(XP^uu~=EgSE!_Ej&E3<8>_Q<-~n!zb&IZ_Ca&5*X(#3zipEyQCYsy=_9)|7J+zz)Q1&EeHeC2KZs2X5A1|~D zXzto)nAd`(?2N2^Up-faRAir10qK8dc=f+Z|Nq^4Vr;*m6gLJgH{NASVv1Hh;PADu zu*qn79Ja3<^U_cAw)acTMe+NgKcXkSCRWXG-xOSN6?8w?ig2oyEG3R(Wd zTf@6!eN6$Dc+n3duRE}6f)Z|O`B;!GY1a))E%+(%K|VhrNV(L=I11^RFRpA(CUD+X zsTnJG%R-FXe^t>qb|GbxusiHk^mOL8sr-1IvQrOgKhcHcdzahwZV5r|v~9tTN*Y)8 zwN|Wk+Wj>7^6L8L96kyj;Io3BM)vR8SPL>~AL|pvETZ)cvi-L)aWeFC4$H zrEXTh>t<@OB6R-glwjC01MRy+tNa@0N5r`^47TE04UK>)*V|r@s8P2H6p=7mRKR~d z?m&4cq1G z5)0^HYs6~aCug>b)?y`afABkxM_bSU-3Mc2pviZ`7k!MUM|2uf1gq2&KOD}OZ%e#* z8n1|PFPp@KlqhOwY`y~yyLF{E|2Xkje)CRZQGDr;jR6`ECN412C6miF~t#aQH(Fy+EN- zuEui@1rM(R&nEEkOyYCdXK;!i8k$^Z?0flFTi_K)24jHGqKy{D@S!0K+a4uj^lB5= z?{7JMv=o=R9x8qP`asS~2;d%rmA>SK$g)sP^ES<8}@c z_)=u)6Y}w@SsmH0daM8v~KKJ>FH(!a}-kR<}diosC(>Mbg z>GQD#j8w84Wtiliu%GIb7v86>tFD5uC-0E23&(~%KMf^R<$^WRSmblgo=AF-Bk@lk zA`AWVWJEZM(9y3Pdll9@tezPRwT9#+J1~n{3#t3J&`170~QV6OYw} zcU9cJxue1jZPqW&L$^0raxzREk^) z-aU^oLf!Vyrl%6X`TtjL;D8CD7gA+^alYkC{*WcTMvZ$1%hE!>2d_llpKm7Sri3A%!vDd*deVo*t3z1rk)hBNipgJJxOBT5^(IT1r7` zLq`t88kkj2LEp?bfYO`0%l>bNc7GNEI-_{X0yR1)QIg#VO|sj=CY&85 z+2gsJkaOr*lBHh2DJiw$up8Ya7dM+6T?Gdx5x{X;FiJC1zkf$j{*DV%(g_hj2>NCc z?j;tDi-6%*hL(4V80S)GzZl-T?l%w9HUB)_O+g$~O*Ei;?fN6c0h|CAT*v9QnCy-0 zaif0eAiwEwJ+kSFl#0OU!ugq-fA;-}I-p@a$KssuVZ=$C|0 z^G)+pmCX$V+PksY=Y>@g1gdrTwwIs2G!qb)@=#(jrh()u>t=kIp$^E}$sM%>KSa&g z1tr}C$-O=B`xUxIIsN6cgn7ay=xH7S=W2uG`h#doS9x z4fSXd^n8}Yoo^2XZ2`U*Yv{a(&q1RWR?eU%l;>>`olIxfc9Z)x4RPJF98fdPD~GU8 z-&cFP1IW3SNvwm@=4zF)j7)cY%dLQlSb@V1RLxsyj z3oIi>izZh>TP)1-wA7e9n(G(Ml)?;G3p$Cd28zuJ5pDv7Rf2?76-7IsFZ+l~S&nN8 z7?uC2h5%tkYBw=1@we2wwR{^FmuC<%R z#wNBG8#rEOK2N+g5&u5Ta=daps*LA3PT8x8Ob#$guR@T|nIbs++sB6}pY6&C?CvGH z9A-&QSDzZHb<`w(z*a-6-q|R(FD~kesw0$g!9uM=&aNey=TtCCX$qdeG)Nt=lpKleyik1TayrMg0JNQQJ* z-_(u5xZ>syFzy52yWZeXr=F_6B;*GMvi>Y~2aEp1Gam?fvBV$dSiWh}$OHBMu^dPLly(EfxM4WvE2C#^DbdU^YoPu_9N zN%-zf%>Avr0$p@?<7tnFf!%|63kDjtBCgdCgS01tXHwTY@kn&Z)3I04!3EF`Qv&ak zDnq-EC`T3Tb}{&ULa-1HPV{xr=2?tJ9|y{@GUx2%Ev*^PijCEY(EgvB=iw;e6gWVa z-?$1!xXI7YfAqp*NqFI&%OW(2qC-sOZWrZB61VtrNU|}!*A7Vd9NGKhnq%Peo=0L0 z94!N&7qM=Y0Em%wec<&!Muh+TXM`XQ4uFa+6g%F=HC|95Vw(l-QYDTOn0NMGB4KqP zyvBdq<%hJm-NwRGULL~kQ1G{%u(yf~6k4!h<1v0Qk%O_M?;k8hB-5MRsr4$N&L2kb zXAV#GS+ZVxEzv3B&5Fd>%qARd>y8~rpQa%}&FTt({!jhloOipa^(i(?-YJ;Y)#so5EKaJxQ^B)vJy=>WB*Uz@WWV~HOVW0p81~QvOeP`}-|uBRG7~$+ zrou6$=YCmvqIkVRVn@M&7fJS{|8v5l{GnszsCa;qqbEtKZuFO1<)0mQ|LT1MbVIYN zRhS6BXNuW@N19T7NCyLow&lrA<41{;%jNI?m)t2l5pn-wCW+)ADd(YIuz}5z3xh?; zTZzYh^PKHfPe27Dx#Z+fsC0urC1lfr~+bk;d0C9gCUU{sMz)A$h+%36~^;q?U$H)+=;DkOiK^OqgYm2_44#s+*pQ6`7^Z0 zmIoAmIqAL4Z2H~W&#QQo-IOTPbdA(d`MNN1wb$IT%-^#nf?*SMLKO#|P4()%vu9LE zMXCM64>7}+d)AP+A-V-6jJQ)_0`Cod^XDN>(Um6~23o0UifZ&P*661VP9v;>oe0E- zcOL||#PaJJLO819S0`-!yXYAr6v-)1ME$*nBw_Qu&BIN@Z%p!-U`|?P+kK7a5ybq0?KTjf{(glQQ*emCVfcpFgK*q zV9U1m6_PZ$?AI)Ta{ogQ+4%kC&k&x*e<1mhgt1q5~NwoB9CCc5A%#DAo;EY_M3HO4~9`_EwY} z4v?S|rnie#PP`?WRqF(V6oAO&^FQg5T>gjm|F1>Jq4%A?L6PCRqR0{510{bE1&2i| zd}qTilEv+h-fEsk9Iz;fc+pmejE>u_}=}8_P|wX*(okn3MgG7TI;UbqPgTAjqVV zX6$$!AdYn4UHUPIpA8SL;}9{xymwx1jsJ*zpRuUqPo>aQR#rJ|$W=c?z?vkbQAitX zO#S)NXb^%Uyxp@nJgklqLdOo|m7vlJU}GS3y3dADLk!Sr!P*1@RV@wODfeR_)_ zh5u>z;qHr32NdebL*13L(d1238RK8A7DG9}+HR2O)PzrV&+|g-* zzkSZy?5Uq4W`!x!})ULz=;r z1g-M321}%{yRw?k`sg07I7>9TtcYU<3Q0cSI_`0um`P$nUXAm8M)X2+)R0SKvJrKc zJ0vleTb#CQgCGaq6CNZcR)bDn?$d6Kvw2t-S3(q#C9|wX7@V}i@=?hZBle5s_!Sa0 z%!>3p;BcmFGooUNcWvlgHA$^>2QAFXFA)Tl?Gnfa_tn>ZW>^<~?O<#$_2ySld^{!h zY-yF*FgzmUZG6ydayoq}>XW_IHSFVqbCcrE2czr^qeihGC?7^?j0Jvhy$r|}(rX=? z^&QOlgZ$iuGfYlb$`Q$?Wa%Gf<=VY2VSP;@3u9YCV@Argv!%zmHmBAh7QcY8Uck2a z&$QQUz;`d60)FOnpE-Fkvr(O(NCP~O4H%Ob*@1cKwV$9~w%K0>*evWGzm&7dB7Y*x zSdofQuEaHzsgJ(2bCx?7rfsDh-u*x9y=Pog>AF4~L`4COs31K`mEIMpqC*#u-ie5a zbdU}qph$0m0#YLah92oXkuJRxdhay>fdB#jYxdc*XZG2%&)M_t_rp2AGoO+y!$O{Q zKlgLp?YijI&^32nA?&9keXq?xLZ%>u#PrX3vzrej$Khu~51s{Ls#m9Bi4bF zzj<-gr>6h~z2B0-)eOFI@iJmaOgB4<#ht1@f`gQ7EfdIgdK5o_7k< z=#woS+OyK-;pY`2VCXZW^!H)>e{>h|%*&3CH`DW{`_4{YW(Z0!9eDIkjUJ?R zdr|kRMM{w5b)ex>x&_{eYLmTTi%q+YSIEnQ)<`cdcD_@teD~TQ#h2`nkN${L_l@zV zsqUxXu1UYd+2?z8snqJzH&&i$Zpynu&szWj&1RQhFZDC5d+h;31r?R|SK4=SQv$F7 zX}&z)*WT?rz27XZ!sDVv-}@k3PQRhg*5Nqo$8`r;U-0j#CJaUh9AxP0=#Z@y<@tTh z8_WKLA#cLQbC>36cu68MH9uzqoY5Pv0WKel$DjVzH}}{6xwk1VJ*k7qqNPOKvMFd` z@|hjp#!t$ljyT?VeC{3XGO^%-anHR}b^lpx%-c5+ zZW(B*P9DmpG!ifp=mPyPX}bj;SDn}PbWwzoS|`)*Y6o{>VtNIm&M4{7LA*jZrSFq6 zy_A8VhCHpn65@C7<+(_r)G(cd+Nn$%ea-Mu_${-JV=kgVADSDcn$&2f{P|09kI*`sQCd>TI#@U)w#L3mRVtp>zVSY8YykB3uXTl2_nxu4+6P@bbuC< zNQC!)MsEN5=if!ZAHhA~@jE+P^Yblv)NPI|Q)6S2_LEX2SBqMIrdX+!s0-LnCe(c< zn&JB=t&Lt9k6Et_$4pmMB>!T`H%Pf7iq`%{~lTgZ41)lFu#rtW8#Rpk#ljmlDNP5W+nb|vC z4J5RFfNrcryWDQrHnSZdwgN8waCYz3@5Bb@>=o5Yhk31v(d9uq-EO0NwJS_a8c&h0 zdFtIzBYv~P1=-3jXREv87*bB++t*~d;AzhsrVD(@S}FUzIA|y)@ZbyHGSCR zj$&^OrPsD{=KxW-ezT;SFQL4u;nr%0$gy4MA#ef}d&hJ_t5(c~;_9@q3&};E!w-Id zGIOAY*!jdoAXMN+@~j{6$rwYt68x$gRRP~^M)fo6#lKtu{fFpf7|ycEZ1P5K~DXo46;#0IKVl!MDf2962{2c&dZJ@%uKGWU-dlDsfZmL zrX9N^_UyrDJ?G%}R)hz!Ra*wTJ4wgF7|uEF_qi5`;+0r91~;rYZuvMxumkZQEcJ&0 zBfo1lznQ7{|MKrL&L^{rv~@^4(L1VMbW#WKfRaXsX6*iL1K4E)d*^ocBu9-OSBIZ^N#^N#dXRkE_>_V)IE4~JHO%wgs6mERmaq%+`gTR_nf+l=j9hzSe|cf2Z312^4a z`L?}x>%HGsdDsCIdO8k0?^sxN0p^uCUf0RN9-tk?#@n|EVQYmnRxEOs5ADqZlfDS{ z9F@=KfhU!J;(aQCAo-x++|+}}BT`5>WVmG7&|rsMr0XV2!$n0DoW8BS%m+WcfEwC9 zv)=ESQ7^+h{8^5%Ix5xCbFGe4`Dzs@UhFUqhnx*6z+1G?c=IP;3z@91t{E}p`_$99 z0Z%=zpibs}BH#Bt&zC}}Xu$rOWmd{XNAe?<+q#gq)VqwjTJKzQP?69r>46^)pn{iKrO zo;=Uj7aTvwxP;6-o4o!|=2fw88>9avpTLKfz$BB^xvWy#OSM$_nk{tzV;0HxGoMk7 zLI$C8c`Bt-1&9pIEPBx)@$bO?sZs+R^xyTEg2OO28lwSv8dOjqS*Uj@+raED!pFja zLX9$$xRo>XK22R%j?@1ftmJ&Ehnsh~)3_Sn_?`MQ3aatn$FX8Z2lBr0;80uh>|EVj zJ@%=a2P<2iv=N_D4XYYVDt2VlPu^jkr>Zto=fj2ZmdKIqtFnXy>m9_Dg29tEmLH&t zV@}t1gq1m8wV7y%*>nXAKkM z-vX#%>DaJK+nbm0>)M3+Iopt1mGKY?BXxMA#lgcT_SeL>7Od!w(?girPA=e26I=>C zuQhqQA&77@>xw%-b1E7yj9Qb2t1B}!vMQ`;4#ruszE!k2?xtz%Ps!DfFODo&gd@AG z#H?srl13x5D0Nnx7oIWH>CN4NWTUQ}MDB%a1j^n(vk=9G*;Oe<9Uoe+3ypE?jL8K`cPR7~N6pZG z7Z^v*or?;2AD2Z5t@>%M8jNNPfc5R~KI>{)!?Jn5uSi+g|^)y zF@KW0#CF8R*Hb1fB|p0zg`g}W5XEvI=B|!K7Ic3YXrX&h)1;F_Nx~>DEkSjkS^Jn| zEDQ7XdW`Nvja-v&O_a}OZ*bx?4|N?0x8*ZEAZP3?pVZ6@+fQCxf5({DI@9t6;88uj zQ&xs6teas{&@I7VPR>!47=7ekqwpZlUoy_sZvOME;^yq!3!<*=tU!=>-1919^@hWC7PIwj{53a+LjB@ z_s@3qR_Pv63ZC@|11SX6ODe398uDi!20Fopnz5r;wcGXTdet-^u*=G9b9af+}z!vz?FsYCqpyedsODz6^ zvVY$EfAX@l$iC=$3AqmN3FxIF^QUcmT;HClY;WaOYD69A0tEte^GO+6c+%SAG2w=M zVgW@H=iu_2&F6Y#cK4V_AR^wcGqAEu`s<8$gL58|bxCJ#VSrw!{IPs){ZelpK~%;M zkolosG5V%$QvSE4ZfV}JlAAr-K!=;+B7=UnW}x*IC6&(#OPaA{aGt$uGnmF{Fu)q( z_u23T*`~XPP{C|noWgN@jNDa-x*%u+v_6PtY2lTj>Mt)DAhxwS+`(Qj6@k+6wF@6Kv8si~^Qv+#1n6!LPM(%pQjvb!d;dT<^+9cU`xsHr+vT!Do4 z9!{(yMq9?A(B9qlJ=AFQobGfZCT#4nGMj`$9=Cy+an5XG3aiDCK|osNw=LT?+i}@v z(?NIBqzFi)jhUe-=YvFnLJsM>Ih{(<%75vF+A6uBY|ee`7}Rr0Hea;+!OX*qxyJ|L z?bqP-`3K0|?|8;95`s&!#!Mnk36Oc?)1UlyyZp9e6k{O7UFh+G{%q^YXEGvZlH-9D zfL6!|eE_CfNJtOa#HMidzh9G-=hKKq(y7}B>07Owpdw0b84TU8icL z)a3qjo0c3T4!S%f@EiLZ{sH={X=?srd(;HFBlB0kwM)_8TA<_M-%OMFuhxB^_BS@K z_+Q`sI?4Z-TSHQ&%euZ-C$wzpt=9Gww>bjrO5HMYR|BF6wBA6Jck|?vtkpO)lAgUb z{^diYXHcu`^Xiz(ZCCa}zb(@(FfzKda-f-q(IhbW-m;6l%edzyQX$SuhK6k}R7X-z za)|4DwF$zF!wnDK#cG9>XsA^qz#q)H2T)vDu9MxQt578763o)k0=L{yj%}FV>|NC> z>Zy7Ot0xcYk*PufxCZbMqhtoP!y5phCBqm$;!w1v5x052K!mZ2AV*=o&-$JP0V5JJ;-!N44Us2f4 zBrt#I2R>2)s!V@_bN}7R2>QQqZ?G7kP&BVVaG5!tG*enkT2xH1b@&RFczSuL+mos1 zi`ZdN;aU&M)+h+cD`ec}<;>nFe`Yh1qUdR^u+w=@)EA87x^enPPnj2w!_QS!8iqv( ze9#kN_9Nk3hu*-hrHBP0H7;&qnD1gvqC z{6M}c!-YZ8WsUYN)-UQBj>*hH=$9xo#=J%uJJZ!MsQ{}IvmTqMT!$oF`46@*Y!mg` z3N7eV#Ph=M+ zZ#|s7tnK&h2(zzslI2EWswHs2^Yf1HgZ5|RNK>VUZ4^tFcb^NdsDkWq-vU z(Bx@QsZW9Jykfx3(ub_AxpFUO+@tPZy$65_-Ml^0zd}}?T?e*Ct;V_cIXo^rWkxD>U>NSmTYc^Jb{$*M3+5=mxw zQV{V+&K^R*%A-H>{r|OR)eO-J-`L1}rjKn%%*%o0mHOaM5hCpbHkODTb+8Foi)YE# zW&a49IcTzSN;mNF3mJJuzcO#8RSvffWz>lHo>&KboSCnB=u|*Cz2tgPU%{NxCx{0u zq*(Gq$r6I2g34f56BXoxJYNhqDJE&@?#@l9 zWBk>lqYf8hxxR?(+@+O*ypK*7TZjI}Q@uZOPj}8-qrsNH6RR7l4HwmF`MFGSLFQxF zi3yG$$PZmqd<~N>P&@0~k-a*65S5!jk{N39ijZ_jJmyCFzqffzupB6nma1UjePqJz z03e!wH5tUS&|~+11CRV$7;V>YOtMvJ`YchOIeEEYFusGv9bDPZ(l&h@m^b<>f~ zZucmIUgV{_p4Bq@b>_@@YU#+7>bSkSOp-?f--uq#E022 z>eHM#d`XU~J@xT;&cUHCU2kK{wTVAuCMe49 z|2G`XA6k_^1BGAr$}iE@zqclb5BJMYG77f~vvB%BTkNI9RCYt0AhHi%dSbzr6bE0t zCgf%qPyA3eV~#D_- zT~kHIH#G7dyt&RR7a)PY!Ix$-LYh>{lqMfKV1cPpPs8$C{h2wWD%D zN@ZZrc2smyX3Z_kID7u8=#v!E*Z0?>Tv}YZg$&C4>juIcuB~SqqH`@ zf(NmydopANrPCFO_&!2>f~;EY4UbtAh+v`7>l(s;>q|-WQ-{Zf(R$DCErzloT#WsG zJvIIT80pVwy+?9#NtVNtuYZa){sTD)YS#ae)dSmZv^czP7(zkhaNxaltX|~`tKsnp zJQNnH8Yh#~VV+bb9gKeVYjTtjuzyfq9o;&`_&$$6ZOq&NQ?nFmf|(D1teOpL1R^6^ z8sebAe#Wj+L|^O2jqOeoIE@=H6})Uz*_gK7KdPx85S%dPS0VO^aS-B8$=* zU;EW){vCvykGc+f(hFmqJ>E1UPVklGTaKKiv*^9OoFh)UZi@UR=j{(4A5P%I>6-Oj z2$NPnUv*pPxS;s5Z^io)o{Dn{;wfqp!tPqujD)bLI4&LIOjsOVd;c}wuh~>Zzi!a7 zsDJl3mA_jd>blvuzpSKR>FApCtLA5(r1Ri#IQ?48)QjroCYyq4RppenvyGLmoMfyR z&5^LV71Y@Lo5q%eqQ@q6`Ec0!kjs9Q`bke8h8(7b^Jtw8zO!TN{gX%TH2Y*kADICs zDVceEa{~%{W|dcWVX=+4NhVx{n;2 zu;t8iDP+#2#2>LDG#FQ%b8|D>a|Nj_KqRZf3I9!L>2QAVU$^={OR0ZWnE$kvU;Ulb z-_Dc&Z7lRA%OG))m3KixZrf35tDu0>>EZc|&Ua@dU` ze7)kT$;7=_MIDN&&^B=pdC=05ZAYjBKfBj*TxYB*D~;7tfT%u)vrZ9OVtMGsh>i^u z+jjGX?u`%_^|(KC!}`5lO{23h7Ipfw3lb5b*(;qea|g=ugM`Z*iY5ym-uhEvqqQU6 zDzcyf4wm1BXv8rBm79w-KDl1wg@F=4?WU4G7d)aqZ)mrN7#Z{~sg!N2W*-=Cit6T6*NqK7h#h>5{%{gpFs_Ubs+nVW^VXo? z)fYY8Z`RC8)6pNJ5eI>uWC3=ik*du`riFE0cMus}PN8mYXU==}rqFh)sQHxc_Il<2QXR|58!n&!(0?TYUbNh9}SIR`8fa!`N z1WQLJ42Qy9$tTM;0pmG0y<-lSQML(b9K)zGd%0ob_0c4+Nmd=ojhC%9{^vD5qB8v) zeQdLdzO!vA#jBg2sl$)aFXB2*#f47ec23}BjUy^LPR<38FrZ0-5Yb<|rtdn{M}41{ zM4WEnNPh*oaXjmHp2&rZRnDBy$emn!@vbLV^wy(X1zjDhMY)uj-B_0uS*i8!dHaSX zX%K%nmGMYVnt5XIhkGMdZ(9j=JkfUg0@qcX8ye&F)J6-Bptz#)N1xVJ){PxUHZlKl zZDMD4|+cM9T!t*TJ{4B8@G>`+cxk6W03`vGu(B zy*+G~(44V?EqC^`ydhZzAHmlMS;x14##PiD8CJj?(^uwYAbQ{}wSMhUV}@|C@D{+i z1JZbDv)v#&YV{RyzD!}rHQBaK)v%F!&8W0Pv@fW8Gg((xnT(Di#W_vg7aj)U5owx& zl;N#{_UtbochVT8W)5o~s+AF|u4LFtN73#YxjrUi$JNZnN8`d9Xigb=lNL(}&ti3L zt4Q0b#+}E$;eD++px; zFxGZmSSpP!Sj=YnO#kHQ+;j0&b9-{XYcf+f#OCa5s4-!l%vH?SHDn1i5B! z+&yzEUfImFt_63$2R+?TTd|*v4_uCr5%qjKsno)EXYu>GXWN|k+|x>k9_6&2*kasK zyz$#vi{J=6)zbU86M;SmLwM)9M4>29a#cCKaN1`EA@q?Nk7ulUf9G0K``kH>*7P^J z`<1db>TC2P7qcShJDGEMw{3r-X_oDgPqE2JcX1?=0h@7a-;!OUNbIN!%ARKVwj)oz zpJ3_ZW$f3vzccZy=&_B@M___$Dca=kr^HKO%5xL~7o#bHS&sq@TV z@?9@jTbH&WCDHg8(TyXxScF=;PB*XvLGDTF5M)i`HP7PgCr2vxH9AK3+xf9pfWGcHOO+Eix&}9L61)VbrTR zJIC_;FKx!}{Pd3uj_fkP8>`h_L^*&nuNm?yC(&=j%&2#fEz#o)iUgmWi5F>*VpBhZ zisw;thKyNdH4(3?7;DblBL#Ucv($;qPlp#0DR6#GM?(Rn9$$ZF`ug>a1dk=pdubA$KHA8d;pO49YbR(i$fhXtD#4+z zbpNJklCeYw?bd^uE7Olq!|1r`0T?y@`0M_z+Bq~Peew*hT~0spRXw-ovnL8*jfXMN z__95Z4e;FhApUL$jK8}F*=BW;nXPe=Mansr?D&Bk;^3V3VT%T!{Wph8TSzaAJ}MD+ z5EJQ=WYU2+pnJ2^)#Gb>myQU$Yrj0 z!z3IK7Y@w>o!>=e?mZV@h*d7I;hDkHPN;LS8)d{Q_G>rxf7({(0tRhO6z~5&3&!6u zW01_rmO~;0q*!rg8wTHcJ9150k)k0^dUy4$AYtjy40_@kDidS(0~B$Mkk@i)W}S09 zW2G4W17!UJWa<{BynkQi)q2gK#nRY`-_3@OORvL|O5!n#1PDdqux=4JZl#nQ5GXz~ zj2@Wnp;>)?Az{Pg&Ti-s$m42WWWM)Xsr-oV6Si|7FNy=&3DhU=&{rmid<0*%qfGnD zW%<<;6AwCq0zoX|BYvLepL#zjm(-I|)=LrOzdEI6yZ|`sGdmyD4dU2~C-&C>-a!tT zpJgTfCg}3Zd+zeA9HW&nx2}`#tF~753~HkNj6g3>EZko==`dg)hYwteoJpmSE06gU zU{D#erIO;P^x#VHNJ$P*sw3a}I%{_K8l{B$5>U>Wae2zaE6t_rODPZ{TM;|D7HdS1 z{3&R^|4!?8nedG2R#DDb@B?)vsaHl&3O@(cOD~S_8`ebbkif#M)p}rCplb-4v9->XbBeV;K7WxX8BZTvjHv=a0yJR64 z+Z8lq?ZAuySCB6eRAM(}I<(l@b*{!k{_)Fh$p!yR3$nMICn<22wFE@*epR+)DHhEb zwm&sAvBg_toL?01ed@Z;ZPXhFezxk$SnJfRcm@8gh1e#5^uzlwB7+?%rKTHt5O>$s z!xx~&XGTj3zJF2Q-`581JutnoKS+3owBeH8oQ%q|19#bqB`IWDmE6=L!xPsxq5~lG zqK=VfOz$2KXch?YC0f*ei3^aTRFM02-0tKwLRUZY6eEx~fw7Q&xvNT8&oaEfV7#Vx zaK%L6X&!}&EPiFUu6CZYp@TxA^hw6;yw%U+D_#UfUrQswl)~h4;6gp#ZBnE^`_%(9E0h2Eurnw?{v@y#y?VLRK8@#m3l z*)(?tOxoCvj}8Mv?T(klQlXWWgxgP?@L6E}rJn90gV3ioRUJo)UO4?(6AUfP{_-oD zEXU7aK4h%n;nOgMS$ZJ2f3i%+c*dm}{(+#~aOC%zD2ZJ0);Tk+Q4}J7mC`CI-`5}| z)+bgCZUrN&tu7|?&E)Wo#_J6g%-N^H%HQ$^tbQrC-D5_xh9R}bwF44rY{xr~c#{P8 zU&b0u|I8FP8=dic^WQS?lTUt@$$sH?HBc)FnyY9ws$8WK@Wf=`jKfV!lgoEsUIu+# zhllM@E{+DT3}$oQfg#SSn{0?gKkOR!tnp251l<-?(Iks4hh zX*6O7oY4--GxUTTbKp&jd7xw3CRWudPi?kK>W+EI0Aq`e`{d2T5A!JTp8Gu8#Zn5^ zMhPVu4oa(DPz`qbp2SY;C#yY4S%(PuBZSdu540pQy586jRamI6jc1y8aIcWc`8v;F zrq{x2=Xhx+amM8_p51|2$IVysvgd3xIjX!k!$jT1;~82y*JNvB_j*d6`AT4?Wf<_( z!Qr9|Octt@#sxC_>`8R`)oD%ctm#a0XY~V9X7C@pr?A%#tEvm?q@qFqfI`pjE#lu@+u0s_$4p(vK8`Q>?#R6XTJW@8nyXFDwojZ_9{( z3M11T!`R76%cPvVzE$lQYDCP2Y^Y`mEBOU?iu|N4L%0erJCOEr+*rqpR;n7ek*6&WBQn`Y5&uwc<7pl{d?LJrB=do`g_dV7<9V zy*P&5z~C^@LAJUYTwG<^!}w#qrr}j!PEcVjV+U2)P6!h>;tt~A%ih2`jEx*lJl9*- zapMw2)%EzxTqg<+p?N(UdgKS5Ix|$>)%T%bFEu<&jUM>;t?lbJG`m_R&N1DZM#BD+ zU1`ZHzFFu`^5hviXV7;Eua32>WhuK_1L4ZOnX6}Ej35E=R(DXU#FOM(! zUWT#5_|H||Gt+R751#(6e+}0-4-SI!S#x=$PiL5%os>a{oT~~*fwiS2p5Ch8D;&ef z=BT?qUmetYapb8k#*%fz74SLF41Vt%)n9hpO!o3{#?R}9EmXuf+S@agZ>1TA8qEK! z-T?I`%r_6Gk>a8X<|t;2#x*Le6G=c-5H}L(k+*?s7;)bsXAZ8ryj|v6QbX-oG~4?d`90kCC2d*zY;&&10e& zA&@C`v&nfi$(y3%n<^DsUl8fj`N6oe3r`>>`YRv8aE)4VHp#4uIofg7*^2J)*D#^# zYBa%qRx)|%d0nz{X{@_n?K8pjr@lLCu7e}qGQI~K<6`K9D<7JCf}TEDusCbQT1g#z z`~;>`L-4>Y@mvyqcph0;GtRr_)c4>couNj~MBZj)%s1-86=hD&cTmfB&zxGdk6Lb( zF^9VCN>Mfn$1}s*W3f3$_BiZ*1V9HQS!9{HrskOQh22hIpe+u6GNn?q9mqDHqW>AY zaIUT?zC=+}7-)j5kNruUTk*jqc>HM>=31c)H<71kNFeG&eORHW_8sjm+kK?pP~2O@ zOIxXR_9!T|QFtwL5+L8?ZwCD!rR};V;JL>Qu;=}B@OvZV;J1K5Zb!uM<@r_d{QG8F7@{$w%|rfO-8$8iL@5H5XyW^~HD&*+z2{eT4pIq8>f1 z3FEEHx!YYOfcTHK9*Rr#Gr~!KNcM~4Yu6KKli4ji(_)RPM`pf|p@?sj^-pOQ77$PF zZ01+dG`giBEU9(5n_+({Z6A#skveOOGA zNklcWvCVqFa%^W-Zjt8ZctURpNdyk8l6Ncz@0Gwbqo}5gjZM4kXO-A_te+xZyuEz3 z`0|GH+sp3Dq*XExDR+z?#Wu3avs`Ikagt+veF@&7F1|)E)`@*Hwt{kOb(#5$`@ZfI z+RjrWYi4Ix@O@mIkMEYMkFn?Q?es|ZT$Tv#S0f-$&iWE$lx+X?pp?gc^hMA3Rg{>| zi`sR`Q6&K>RsV0xH3DRuY_DAg5Xih8UWcoNaE%W)_+47Vul)v9P!4VQ&@B>aQMb9L$aPFv93?=%Q>%RUf_@dESVZ{i0e@#-Us4 zod_3bvKbf$&znbGFA(vf14py!rU$q>v;yF31=kmPtQ)j`tEqyST>m% z0g7mg@QPBlvUBgC5kEk^nah1&7boH8aByf0tsCExdB^_da8b6zu?Zjz4Er~3(8_o~;@h6nL}-It`oDL#y@F z)JSei#E#NVU&q*i$pG)fKEP{{&@`5!XqRKjl23Kl&078C^j5&cRWNm{5q#?CQcFy> z)G1?KF>p#I^;2 z%$k2#(lJDq4j?EH(TUwP8s?`L9?vLw)#;9ls=vbMI?u^=z)^~(A;R%~4RtD9ykcCA zq8q0Nk80gx$;=36iO7?z`lBeGt`!vAK;>%Ih6&IL#%zPq)fnTFJdib%BAZu}oP)e6 zoxZZ_VAOrYH*37DFiFQSX>bLe;%vOP3$P4a8ibzbH<}R-Q#13ZnCxv`Y`QF65lnP} zKE%#du2D5Uwb2Zy4u5e%2G$(TppTvWIVJICWH*hU zrzsTC@hvJ{xd?tDLdCe_vSGVHPDBtw=P7z1p5q2s)Phyo&TPv0dn5j{SA4kr$@VLQApHE~|)<@fpf}7h|FvHht$n!LQgJaqG+Id3UB)bQEb- zlPCRfboS;<)bNGbAh9soK^6u7bGoD;kOYWZh4_#uGAFulUFVR$qv(i(0n8{SrhW_9 zm}zc*=kloabp|(GP4BFo9=Vm5l!bmyvX)u<%lrrR;UpflpNf}l+B8}lYuE=EN^CaX z8je*(W<7dK{}kM*)Y_4n@ny?5rGlp*Q7zY-y+&Nfv)xk($!EL*kL-iKXTC;=oO2{y zv-bOB>k)s0Tuzdm9m13fZf_iU&GVgM-<2?XqXl(QRjku_Y<-xL6CHUSb%QHmW z7tfxv%p*O|En|i|W;b=JGNx@|Q7{fm4QhT>!?Y6M@91K#{N-T&uU}sRK}@YZq!9&L zPh*W0dp}~F$QoG^{Pt}&k||s`x}^{x=CPqNs=N69JBcGd@V1-1*5cOoHoNun#G{gHh_BuxU-Q>auovZLao<j9PiRU3ZKYDfCWKGtm5)D1WjM!;WL$?b zArXJKV`vd7K{bk=>V876*B-kpmJL;LYZ_ zI;c*J6xTU)z-LzY=5nA_ftU)8GRqu!+xhSp zWqcA3gU}@*@>0-EYFa(!ucXtQS-x4wHJY)4$hysxHWzDW`Yy`8l)MbeJkp6P^6&@x zE07JvLNi;)xg-W8e-a!imdQ|~SbR?iP*+nL3cj+aBlta@>>h7OTT>IO zdiABU^qRy;D``N`nKv)wrlt|lhr9XeECxwYnbFTrQe>?TWkhX-CnlkCw&|MP&fyG545_E=++2RrVt^t%yiAPY4wcEd?|iRmz0Z>|6}^LM$1YRwzeMVqUB#+L z;7ceenvI;`JF)`n8`C5Dvyn^5=kw-mN5*JT=Evv4D$Xk%1jU>t$K03cS~Xn;bhDmf zg3TC)SnJ~4r0rTB@}ZGVku-AO*fp&d}YC}`7yH#-2Zx-q|>D$eyk72%W zKR|uO#qaBfdGvD7n* z$O^teJ3A5=JjlQ@h1F8VK6|7M;43yfPF;ZYNJb$|Q;r5~DY)P8`31^OtUiF<+7e8MK zqtS7N0X5NJ@{kNR#7F8wu{jKtsb@t~by|rJtE!8y({7Cr=eCeIbK_^}yme0x5=OmS z!#SnAr@k`l%pA61uGT){+dL;Ny4Uqu17H$U{CM}!bhc?Ld-Wp*p*xdP&_tHc8y+n# z1pT$x*f%Cw#WH-H9I-MXC$GLI=fH1y2J7g^ng^&Ji$;%kdRaV!ymy2;W0?RdKKMIa zbc5gvBlXqmLh(L{_otll&+6`usNR4eJ6tB%%+yKqAISS)Fb9?Uz;;;g(U4u@=#O%n+K#~ ztGX-CC+-)Ono>#`g-_OR@Ju59iew8vvM`P_puiBl<62zYy)`FG+rtp&l$d z(bM2>X<=oZ-@dn!joB2s33f4#+dbICTw1`Kqb_*pCA8)w);*PGHVWz~-$7)#&t$h= z3q>lZx2v%ts5JYtxWj*DIW?c-l7h~4*_y<&zgAP(v26)ezC{^j{DN~pJm32^YLb=u zLU!vjxYPK%nmaItS=(s_&pg%M?}Rbcn$=1FEZE|& z)t#dVXZPA9h8s(MCR>J zkGT)n!2;OzmukXqUwN8;fNW52^dZz}rl0}VUAH>+v9;lw!q2sY*d9*!U)bX&^WG2R zL4rflXi9Chr#N)2TS}Sk+4X#*NVd-3Vt+ly8RYpPqm?Dj@`;liS$g(5icm41h-M}J zG`x5CI=eb0Bu?j2kw6FSJi1rdC(ZUPYSOx0>y4$@^WnUr!`l9cr0{B4d5k5KK;vWL zwUUAF1q#y!BHIZ%I%lbqe4S?Q+c@w~S#G82b0lxeLX8JTOyRu6) z3Dye=3$D%p9mkl`9P%U{ehcb(V{Sj(kut(gEIH)+cpi+1S`yT;^Uizgf~8~Xf=5po zj<3-a8=J~8b=3ygHVTs|Fu!5Gfa-A;4;#H~&NZDTCWbwlgewmAWoZaEw8&CKA+R}z z=W`8TXY*>@=h;MzEYHwn%+ew82_YK`MVKVk^9U=6+5S5%tA^e=tc#$Td3T_}^-cdN z9YOXXTD9wLLlOtVGnmKO7Wwdc_;<_4@~&kaiO$!H-kXvOE@}WG=i?XSa;d3RVrz^6 z?**mz0V3_cmyk8lXn};$$X*~)_@Jgpcsq{sR83}jBuUHQDOY{pAI#O*5G3~p2o?78 z0ym5ZP&G&44mq!LP3_aX6_@yWm^SMB#|kK(w%i}&}8@o z48qHXaN?mMWzx^rZktzODt!`JE7XeeM6N!FYUC&ZN>eW)bhN@oA&Bzv8kzc&@Y8dV zy|AB#%;+BHeNH&*Sef@MCqh_ zj6RNF!V)?d)l!l>#66$uQZqX0?FS7#7=^J?ir&*jWdrbKHZA0LfIrEO$A6<|8;#GK zHAS?5NhVkHDZfmTE{~d&`?*L2l&1JyY}4M*aN^nZnImgV^_z{VJ< zo^7l&20=Q~>uFJgm5w)5JavQWkPNF+TL&lL$gXU4puAGt{TzLA5`^L}L{m&CI(7CL zuMIRi)_jca2n}H#2dJBj2;}HbCvkq(Z*ZXlFfdBa@p2?v7M~j%13j5L=hb~n-usg+ z6FW+)lZe^1IVW||4ENMi)uNtw-9X+4F76r+x9EX2hRCe^c60vT`^8gE&oS9xGZL(n zBAYGOmkMD;1}pHbTbk;UG?tJ^xRGZ76oXf<^2uBC0DJg(@u-RR41GZKx`UiRs6NEl zrvs%50%T6o)a=Age!-ThT<&?in>m}azw{$tAIf*oq@g1yd4E{CRzcm;rXP=A;?BLn z@f=#HD*TrA$f!n+nVhvP#e_-sI-{mSR^mts2(+f0&9jCX@tGALDyx~MUvqz;s!FwB z-F16rf{`Xh(KoL}gARU=(N|sa2IFOB-NgaCFPP!d1B0;K6mNv7C)vZ~MwxTCrD&&z zCe}yxWk3rlO%(gXqp&F;qjE>fcL{>z;RL5Oht2V~J@Q;;m}X`|< zWEKeVx4Z9CAg{G_`tS#ccUGS=M0V`?BgB2orZZm5M_|*<#nB5tZ~U zGXt+m#G9xHI(0=mY^44s-5q9HyGvq_(!vwyp2ds^d2wFIJ6}<=5S}&E2&Cbl*t4cd zhE=F|6$e!PtwJx{l!|6^^!J%j?D;&q4&~uaq~(q%VI+a(LdakYV1K|jdMHM9@gl?8 zIcntBu$2A)Xpj&)%wH5If=afIjsVFms(U~gM zpJo0SHH1^#^um?Y%U*J;p}~DGF|tVtwO;Jk33^Ri?Rb{hQT3`}N8G`m1e)$N^}I^& zysatFP;kR#vBZv{rm6V|A&FhVZiLUMPM?7>mZ?3s6SS^V<*Nh;V|k0Y$=`?P(N_@3 zG55Ry%IWWSzsinbi~&jm+bqxAQ+xf!tLWCGdDoKBWkMVpui2uXM%FHZo$UEi8S(r^ zY*4v}ZC-^%cZaQ3x^WUR{a}-NM(+ox9NTDJMrGHN+ekBqv5oEYGT569w>TwD+MgtA zqIV2)P4?ALLI-GmNpXmpn{4FT-)BuHd+RB7XbEFxrF>UFcKtYGV-=fatn%_vFMtjr z{;utSJE*SEfM6wGH&n(GSoWm^$Q?aj$vv+zctp}BrTepX{ZwsD8R7QTkuPEM+OK(1 z>!j+61$)Z(H2P}?B#j;y-eU?WZhAAp3>AchNJrn5EWGq<&s_3TL*N@+$6hm(w256OVQvf8*@_FOC_OM#!TC4OBvkP zyK5TnYZ?U-5doSZ+wdS%DI`b)LU{>WT;ToAIJv4!!A(T)q2Mu{#XT3D4h*v;PHxKt z?Kf+)sGnF!;dI2ydi85{5~=O}9q$CU4fR#lFhF{Q6G8Q%OzOblzUbAxLeA}ML@i`T zHi^4wIA3EdpQ-L}Vx|5DX1WDT={Pst;wxI2!2D^S@s_cw;ILci{fX859S1-!2glH_ z&%P|~2@uz0gFv>0x3a>x$^No<4K()E(ZvI8{6SK|NiPuAd5)U_cC4>fR07{-=oHQS z#h7I)x;!fXerRF9)Hc(fD{4SVGno;+|LAD1UME}m4oy*!fILg25KNKhr>tLF}AMRr&Grg*@QbHOKP?T5n*Mav_LIqZT6uQ~S?rL#q_e;M{648BfE) z^3E?_gC?-vZT91{Q{49iUN-;muFd^PQRmgxSOO_7FoiF*pbagfv)A+Vg9gd7>GJLJ zgZuf3&!dzccHXH)1zgiW^jBaAdZ0RlR@^8<%r}gfb>(?N7`at>2tH;eA=I zO2n|pd&^u?rsJm`+KpmZC};UmnmIBVg+UR*ii4WaoC&JpOVRc9_s{`yO;DEM0~u~& zm%NGAJE50_I}ButG*xA~I4cU#k#t7~*nq;u+Vr4oRBOG;OBw~X=#muxQPKz_JIzK@ zwZp0Wtq0S0m1EF#Rpdu?a7i3lNl3iJ&0`^SQQf80k2l66hi8GBjL!kRzcXvy z($~W+uLEsG?~pJ5n@XI)NCl56lV%MP@tN0gJKOGSibBw1?O3g!WQ1?HNX`)PsERIs z(fe_>uTAR{Bk!9%o6vNnlOblOnEyz8iNVMJ?(bK`fp29PK5n1fM^Fr`rXY<0~ zyh|aE26Jw7@MK=_dvgq;3dmbwx1lF#@W(CepCK2k;cT~&_JY{E zgo~-rFrJZtQc>55ds3$EP}MXaCwhZc4%w9SZJ;`~xH=p3&ygE&&1#C*RPcF)0k>_M z(+?b3T9m;PITX0i-^J08__`-%IrFKtvuK+smRD*MqI;<fzP3}~kW;^{ z&_TWmani(9cWpo7z}4~P14;a4q&U*SVf%qDZWI1|eS8qbc3-e>d6in7*@3AeZshIf z>eWq%ZcF@a6BeJsy+XL@eecN%Ro#{;elM4p#d2+3qyLKRZ~TtzY5x(~!^d2lo?%JH zVBaBuyV;|nD0&ShMe{M#WaU;%s8OxTk{@3y7{hM?u`-mzthTT}v$wSK+FRG8-w;qOXPdk2me%pZc zd_GE^`MSeld+FgXB2rscp1t;}%=OyF=pC4?v9j#ISIjGjcKm8wPu9Ao^iP8J;^OPI zg$!xa9H^1Ec#{+=`modeGpSbU(}p;l1@oPy3%#=-C1v)-lrv$R9A<7BtsE#aK=p9J z?xikA?>wwHxyJL<=FQe6cPYAHcNqC}1tKzMV*R>ckD`U+$9&nGyBEqgrKhFREfXX< z63MYps~4|vXnxLJPT=ADPj3Fv-T&d5e=+_QFoN>a9XQES{J&lvWfK=4y4ONa0y63- z696L8TGB@j8!V4bukkgn9IeQM01&On57w}Pt6Y1Rk^Hj4{!bflHH*{RzH9Vfei3Qg zxByhcP9w45JAe%Oa`X@a9^wjl*5>z&r=5{-3QJyCsgAZ%j*$U?z7oE7^O`Ou=_*s) z9qM7b^jJQ&6+;9%t-*3l0s^s3!#38xh^~8F%PomjcM=kiZ@$dK9`bWpjq1hB>uUin z&%urGOEUx+oI1MU@_|!*WtGimA<8ax&xEAtM@vx9oZ*7xS8k(vQ?^tG54;uXT*t}gS z*i>glMlwg?ZE0E3D#G?%d?$)a-zrh**_;Wc{9!J_niWwCemk=9S{m3|Yl4s?;zX?yeP) zI3=Rl-eLUKHZNR`Z*9>>8@nMUa4HEWE=(~f4al4$FP7SIVER(@*3awiyg&<4OUy?V z*)K73HG-c!!dm*@;nh$}=TD}BAQlFq4}=fr!Uze2{#I~rFKzWRVIxFoy+VwLI7RWe zg!G||1YwGK&JsI~zq&9$p} zoj{TKhwg5^!pQRH$k3w-5H=bZm2-(y#%s{EBACjZWIkNuOzi*B{@`OttN1X_A-uSr zYhjkFgB4spR<2%w7%q_)?EVrJa`C#)Md}Df%&TN)9%36aF|CrdgYURniB!CJekou_ zpFF_=&^cCt`oa1enYLm>B2OLYXk-BCm-Q=;uH$cd$YF>f*T#o3DwEoJzzp75sOBm6 z>wT0#JU-)uMB$iFHnUgdFG$+e`M<2L)SgA({<8MsRxXpc*YP&a2q)d0l^+_Xxo&sn z-;78-3xiUDZ{T7GF8*|Qapg}f4y^J*rcR{n9>ky)&!rOKcMx$qU(>mYZzdB)ChA^3 zt_u=hg2*3~t`V_lKvVpQaW9}W1mWQW)nv%ij}@bv{92NYovd{a^#=lKcAw8EM4py_ zhToOv<@LZ%7?-_aPA2Kj+Ljo}Swj zcq@j_MPHL*SYReBAVGy~wq}iIJB6@!R(`+eC2rcs!v=O~smk+vMX$DmbyWgg&&0%< zXI7fW3L-Cfz4@!8WZ|S(gF6sHdQX<;GK<$9!``4pw2c`r2L&ty*!QRoJ56nz?&$~9 z#}x`QQ{|0}Z_>nuIc@o?Y1FYDpyplP|5n@N#hjJAC!d^|>hK+>d}D@QR&-;d(z!yv zN<^H_Q(pulwUxt!;gl5y{RhPHV(sK|!uYx8_Q}79IvmWAm*C<$MPFxk=JM9v7rU;s zkNp6G@b4mj7KzL8pFi;DugB?PZ|DrIdq=VoLwi`qzf;Ixt=(C1i+{`~XEA|3!C;P{ZXU04snYL(G%MMsBKy88r=E9lK? z`SlYY)*3tyPKoNKzuiyhu#bzw&Chp7E~wu%OkTVl!$!I*wnamVDP$cz)q;Gyc}!#6 z#|$K#>P(kaug~YRToFAr!HW?zt8s;xk`6t@gTn{U7~A)rSoFqR`235=z~E6p7d&Yp zf>&uVtYNXD4%U+1uVH*Mfytp}Ll2mqf(A(Z&swXwcT4*eIMCfr)D)%@@}yK#x-0rV zthPYXdb9bhx2SeR9tVA4nWu|tO-K)pLlsE^H;GSD~Hm1su= zbRrnw!KMZ0#q`kERP#n9Y#V zr?*HvW;@D~EpC#MOU-(k!7bihm0#dd%FslFjGWVA5E=7G%Joy$1fr_pEpzI}?-&*f z!3JFH=}U3OBifKqK%A~yb2}q5C+oL{UOxT*+(%lX|1e{lrN94+Xj>aEJ>zd&S}|6B zG5VZFomP8{ zm@H3K<+8!IE0EpfLa~o)Xhewwi$;lF3A<46t&zz60^q?$lB8#1D+UG^YRrFEYcKto zgZ{k^2Kvip0`+4EK12w6#C;JH@7TL#d%H0=m0|f5+24+IRrkW8F2`zDhVO13??8PboffR85nm*3 z9l}R5g5)eOmhGc475xMK!~q zdv!APiD^kPO63zZfSXzE82PJPXPEj$6jF`?*@-h+!!0N?U%KX6zICU_Lrt7gcWy(j zo)4nRoI^0Vsk#6r*6vbq6Yu3n0P&$bqNJ_4ytyy%RN`XX`0fJQ_RTp4`UwYd>h&svlM_hqi*FN$hPPHrgdU`v z`tS3cZqpeH`41ZNrTcnG``0lX`g{}3LF^wS0_CPIt*ZZV_F`buBn!EKR7Z%QkzFjk zsEo(lq>XNH7>KC5J3w<8;?x@T5bh0+2cm>R9;RptZ}aut`DmSr+8B!;HmsI0D%oy9 zn}HVE>1pF-al=8+1MZF(8lH&|G%5UZDMXe@^Re>mX>oDDv)Wc(?HJ7{t!n(t)usxL zI(z`H_$+mpSv8y>tDg)ql74>(U^7`7*^l5An{7x-$OSXpjrrvQd+Ks=B`f(Ep1P0O({IZ>``1?ugVc zQShNLF%d1o_GO6&Ds20p(?h9|O`hRcXw+(R_l@9K117U|fKOhp9>d={ z%>r7s8LU{3?Kh&jZEf)(2cl3NB-lG<_LmeIgUgK+ETeN1;nY=MC;V1g1PTM zVURzzCPPM-mPogYtukWVk84i#fyV%dq5y&ZKU$s;y7MUrGiUt> zCoUl8NBG@GvibL(K8dxIQp$$Eake2RZJ&o6X&iq5T+J&lr->&v|1jO&W=hTiG2 z{ti539NDvfAnPU8wx>KHzj1tUSHFQvBgts={?={VA&30fi*`obm#v9twB+N)3iQuN zRcps9`s6f96*#t+)-Q55sFxAR=|Xb4rg-N%x|9uKPVF#qXc<6}m3V5cw00oi_Wo{( zp+utjmhQDTL`nBUcDdto ziLC*yrvXVMX>MbPkh3Z{-!_!&V&(li)g$v^t1epnjuFD!4Y~*LfvGd95TPm1J!yTT z{0EbeT%<10;4oFu(0=!$bSs_ctnl~1h+dRKgP9Ap(aqj5-|S@ZDExCmcYwgF^e+c+ zge()`;jkGVhStamcz1DpUeSqT~cvy=7u zoSA&yvjHy;A(Lr&CiVM6Vxy0>6V3gIh(%9cV%^$$7LlRp?BnJME0y&PF~xK8@0Q+G z-j71vGRC_cjgG@bwBE)l+HTX2@T1E<$A9$yQL+T(6a_k}eunGJ{O`5%q;+T48mRYt z`aD+|dA??91#?v=+=*20+yd$S)(8|rygiFNr`?YMWG#KjfI8qvNw$KX6^Aiq8WV5 z8Mrs3$|ycQ?79^}dCgyr-HGXkRJ?}-cgsb?ts1^N363C%Vc$0P@eBgXz?ynA@vuYB^?_i)-k1u;cITwmE2~ZEEO#Et&fe+Ap%O z%#|ezIjfQ7w5?sq&BG}T5xeED3!NO(bpvfvj`7Ra1-s;Kb4kCTtm)|1cQF{{^XSvr z*RGH2tE)?1P0`wYKx1@nU0}F9LBZ}S;r%mOYast*g|n_z-vg{OmXtf^kP_4ooZ-Z~ zyxsC);q660@$x%K9MBvlg3^QEBPkBfXsiuK*m*sCdxra6g-A<&g4|Hfe&egVjed27 z{E@6=v36_0wur5MjWQ2NazP3-xpGwTrkB|dhzKA^zH1w))>ZD<$eQ$M z0KpSdgRN;(l-jtrg}e^Wg1wvttB=XvHxoUJoi#OD@AI+YiTm(emGS2E&otF`Uke!@ z_~*hM*aUojd-dIc35w1hBU5oyd_8#RDs5qI_3iMFFvO#n4n@+m@$7VSHU$!G)yW>k zGpG%xiKf1w;EzH3fxO@L}L zFdw&-hXfT%xfP3Qrqub~;gT2*k5B)w{SDp&psN30V<@(Ao2!G=ll7j@BIkkjgES~@ zXtgZ73Wg(Hp9Q^{mt(X;T_Aw&6!t#!_AG`>4n3`4=g)2uW#X$)+S z7dhB-Dqkwn>e2phip=KTi%KwRZ+^&-MT~hYFjZPz@r-`{p7*4@+>`O8kwK9g(i)MS zZJLxy@`vzBIcNT`s+7wydEUaB310$qgx&n^qzMKJ>PLW;UI6nj?v(GxTN6&BDbNMl zEowz`ag)9tCmBp>29at7)N>Dl{NP(o^ELGv*pv<(2mK7K!R*)#&sdqx675*NY^ExK zm#8IncQ_e*2nMK&VvbTVE(!?DS++@}8o$(zs)>87W={Kw?3;u@l0ca*E~IR`G$*Ah zug%UW9oZaH zoo?0DBid%^T;{3JBLNydnDOS*koVj5!XBBEGqwhuY{C6{Go^t7WO1F&T77AIJ}b4x z_ZG^e4TRM6Z7Roxnv_YEDbrrE3|zx%ZB=3R6)_nf_zw85wu{COmuMu%uJ{C|c00Z2 z=`?&$8pX5U@Z%~e-1qD)JRD{VnIzRWwLfl!l2)2*G9^dwTE6*)obQ+uYT46!GMzL<@bi`JT9p&2u(d;Y@Ek8@HhgYlj&7{Hj{Uar z%Dz@2eUmiNvv{&qo&%MBQPBL3e|h%ZI#nYcpbck*n!4FDKQq-9+;G%Y{-EtyR@C6d zV96$;&$)rbN%??cq(jr)5`Tl6=|XYY`nG*{$39;z_&5vx<}23`ebHg=+DN^YRfz&; z>er4H(?b6^g$WX-7t7J)lhH&eC+hzZXR%TdGx|(F8K`EF1o{k!OkrHpWZt)E>ZYu2 zLo-%k84mG-?rUyx6~D*r z_G~Ku%0Per1_Ge;bTE6WD+G?}09nI0ThUa_aRhC8@Qr6KEmwO!v2iSo4Owihsiz8GtSlxp1-nI9C<_}R`hlb3|^Qa+Mh11bMkow^d zvFyY^a7IdpO==$^Na0>CfUi#nIy-LvB6?MAdDZm2t;!CGgv1fN$8U2pQf<$#E>FY^8Yp;{AwvZf5o{L~4E8l3Sp% z0z|-Y68Rn8!qg{r&9MEr^pkl*$d(xQtYx$}0IaQ{CE1!wK&6ko7dlPrA0PAuB!b`c zCARCdDJMAoEjnMcnfs%p5;tJQ1Kk@u+d0$LbXA7i-?1y)eL4_r9-3jU zB@ZDT-#lxpH%#1Xl2#R=$ya5IQQ*m^zx8f}dJ4(uZwIp|@UAkd8`@eNK3FeV^7At) ztCZ+r`C^$q0Uwrt&~e9G1v{uXz|1m$vBkDaWMKs`x-|>KHM%Wj8!HQpWw;-XZ>Pj% zxwhu5_@(WMph*3Wr)sTCSRnN|+?}*p03E-9^4nHoI@?>GRYz;oRt7^Ji_)q;;{b~8*z8>(;QAM-_6tZsq%BogRR-w% zjy>Hj56o(+&cqHwvX{fHaxHpSd`|AU`vs(?!(QP+N1zLo(fio&C;X1(_1-=gHcF27 zY1!{~1P>%x6a$cC?QwAJo&{Bt!!xSS{b{2TxfO?JluAH=H%t{HF3mLm*`?!jNlNow zUf(yfE`neb^=o2l=df(H*jIhfWC9rH;)Ka=WV8wS@=D};e(Z{?+*t2SU4U@o(FMfw zvo{274{#Vk8Qrq~Y{2U5i!gyNmfZ%defPKeXaF4Y3Ckx|zImoys3Zoh1;30(qZy&I z_H*fP0Bipf{-eJiDMEJHmBFfCW6S|@_dQ8s{fAxb>2DEqK=a;m^Ypyfgl|#)Em@N@a=JH|opy@^Szvp4NL~ zyg7rmL}d2S{#Iq}Xx?O|fgIaRh%UYC`)EPsI^wy8qJ8d6!)x3lnRXqfH#hTFmnWt^ z7UlOFhVMWFf%El5`v};lKTguj^zo|x1|euji^=*z?Vf0ZJma{go}An#B}VzR>&&a; zw!3D9kW^%aVe1DdoBuOJoK_v)EGF;Hq;YLVOyxcszr?K?N7i|=Q;Il}!z~>hoJHXo z-N0VWiZy*k;h>ZAfpT;ioq6x;)}^?)*f5?W;rZx7*b5lQv|}NI+S~T?nD8^0ZIE2k z9hI20fXDCTcEa$+h?i%f=htVw4dv^wQTaFIJ&GQcK6|_wd~@xU;1&A+hkWeyy z;y*wqnpN;}=CtF~rcFN+z5RN%Md~QE=oyGEC7{>qX_9F-3%$^i*Am%47Sb?YFHXy1 zAVG24Pnmo$pfGdYZ`>3jd){)YF_wxkRxNp2 zpM>CLdd+C>^j69kS08&wS+BCtnzE4M&9`q(X?H?NYyPHtyk2^ETZ>#r7tm;m3697! zCga{&JEH^6Jxtkw>wgHaNmjwrZVMc{@6W+Tww^TQG@CZD>KHw8Lp9TDRU-!V0>1}hF_K;qE6LKrr(2QdhQw;Sd0h7Q@GR1 zenrXw4jlaB7f~xbB;%Sa%cL#c9A9a;aecL4&$kJc(l)kBPt#vMP2;}HCDHFAV_zLb zlmBk%t<$U%tbO)Uf~qogA7^Zp?uHci1HTU?U!rW;RWoB0a$>$)S+U)EEA>vta4B#4 zza8P<84(hzQ4uLivMf0Lg`UZhu@2{C*O(_A^aNO4j!R<=IN4W8m7cE=qI_U%Wa3K>S7I8@e?k~Q_&!$yCKOX1J76g&y2&FqB>N1P^9s!f}azptv+A+#;sUMix=G+O7a&yF6ve6A8)jhb5n~kd?wU z^rD{v+x78Z#;^Zgy}~IR_2IhQ7NY68=BKYd@fC}je|||0i**A?>z-_rjK4bQ=<`4k z{43v1FN#OV_W4~S2-^$I+#lOvk@NOS=-kN-%XoCn6@-s6QA!72)ubIu)Y_GkY8y#V z+mFXbMTw;-DlUHtl) z)30F~b|dTca{&@RCyv>JO|tEa+g;01Qbad)^35kknq7-WJ2-jSw}_e zkWPF-MP>LQP=Z2A$`<|o&i*%_Jjr7S25-66B%N7%1ZdEMDPM_oVWasTha5(z=FH)1 zR*7(exc37gD-eerPr3%_RvxBc?$9}|`DwC#Rghm@@RMIe)s_GauX%%7d;9d0vf!cq zIUW-uJ@%)M-cZxJlVu0W1ZgQc7y=9d4Mj7>vsEWCWP0laYV|=NV12%l`Bxt7Z(fWO zsAWH7tCOO7m-7hq(j+w@DP6j`bZcOq{mfyLo6vstMV5Qc-w+r24N{+n=Np}x)(QkC z+}3&M2=hT;PZz&{0GgfP&yMzmESZHTUy*Qy_C5!tbe5)Fwm#des&g>Tnx6rOQut|8 zhrj5Xu;lr5(fTZC;_f1w^hc><_~?XkJ#V)t-`f)ckFm(IagLp`j|gIqOH`B6 z#VQ|z+O{cCfctx5X%ol8eVkmDrg?66XS1uZ$dRJby!yP)cmzG~ciabth}U_JpUZ$k zvdQkD5&)Kn)X{GnBMHi*Go)Nm6{mHWW~M?|FoGrwC(xjAXV8WwU{~PLo3h=s@y1_7 zKVU5Z;tPgt-rE%}bIb=|9^S48P{L1^QfJh9J>UoW_O&S09_qxu z4QZGdYgXiKjv?)a0dNzO<6?h#velDQD^(C~N35{TF#WdDV4UnR)g`4gJMjX=sk>SA z`#JylV5-^u;AQA3ON15e3q}V}CVOxo<`6GJ!xmAu^qZykw0E9la61AgcQfuy4sL&; zQY5W6MdSN$PVKe$u6U$X2W$Be=d-DZXX4=u|FgQl7Ema3hLpW^(6czjQGD| z)zE(UJE8yoame!DUg`_!rP&j>cTcK^D|l2~ik#^zEBC)xzS^NWSwL7~ZMJS?Zln|? zF;ay(i||NZbtxUNJNl9=1FCP8U_FsNJd^>Uf;tvlHR`2LT#f?<6jCY~qu6kzH76DL zhvx%T86>;z%}KBAPfeGM=vJudZ(Q)Y{Zvz8N=ZvnHn=_*X z6ZoDu7ITbE$<@I-Pm0WRwY5?yOENT3KG*=zkxRJTi#iad-l8StU>DxD|G=K;3ZL90 zv696R9yQ`U11?3iJ#$GU#SjEqP3&p{9?g6K&o#cDAPAdnGp`bx@u?LU?B=cbR0z1Y&}U#yqjcENpgX@x@SN%@^zOaf zD1P(E7y3|U)Y49pby<$=)DT_OjHL9xI|wVQmoevU+1}sDImxSjAz=qb>NYkqNRWsw zTX@Hjt5IzXq?<+ZcN{!$J<+i1IiA}fs6eR*;*~h<`D?;0KP6I(^t#+6z?;_2rikQu zKVs8dprH%m{vEZ}RTauMQ|m2cv;3{8`SK5a%|CKzQZB4X6WfA#OM_oa>X;;dad+#M zihhiWch}KeVTL^c7^N~nQErU;T4y^SRgL{97go5n{7mx-eB6G2APh`g55~SS(0JXH zjZ~aUiA=pxa^du56NL;3Nz_CaJip5=C`nSc0DjdWPsw{S_|ihLgq#mJ>2MB5J`agJ zXX~+dkG!zEB~H3L;%p&kyxmXk6Cu#}0#hUH-WQOJ2D(z{@!&(1T`N;96Ty!?F8MQT ziXUHJ)q6a9AW1q@-*Qw9uu%nMZ-g|;-l%cn8yn(?ews3TY#B>@{WjR+(W1m=YyyBm53|o&l+S!y13zh}LZrJYOf)^eh@5#() z_ppBkT}Yg*kZ&X%Nf!<~Qhd>UMUwQRB2>;HxQh*twHQAGscA!`EjHiADYMnn@HIr@NH04 zT%B1xRyj=6)c9<2m!HovMWZ#1rgd>m%3=zUcdI9VaZ^pdB7!&1^N0}5B-}P|O@rI7 zGo!;yY!rG2SAcJ29LX2U_SUP3yl|H+Q~x0gkv<7#HKi#l?97ZhQsSHZGq#0XF3x4% zNzuso(}bm)iQgOAdUt>!VEbpELmP=Gb5hPA7|Ia-AObnMkMT8QfSg8U`A7Jp!PakD zD?AIx35TXv4k(%m7W%eXRoG{yp8zX=x>sIvaD@k&7AwlRo(v{tKzx_Zi;`4g5A?;(+SyAT#21y{#g1}YDZE+nn*aJQhCDTWD##` zd+h7gA)~Z|R;e1{by}%(ZZi;#h{mro?ZflX-P-xlnp$WLxS01z(Tr<QHU&*}6gH{=E&B+xjn0-kGvM89tfYgtzt=&Fx}Lz}YWt+k@zvZv!{> zZ%l3fHs?co7|A&d8FCSs#u+Sh@7;WBo0`pb;R+!VYDzH2`9p6KRL1VJZq_5 z4sP?iSEuCb54_n6*3~d4<#ZmSb5pI*{6RI0N~}^F`y&S6v}DWtItVEQ(?U!ArABxB z`{_~n_#=pE=?IUXI#OI9M4X$cL`0u7Qm!^B?TCwxZz_DvaV{UZjN{n z;dF~4U>Ftc3vVth=L&Asj2}&bVLI07ePfE%gu|CKzAJBmM=OY$x~j%9b0-+EL7@3qInj)rh!{tt4ZFRWXOHH>8LivmXO^OQO0;T3$Z zyyONE{bmgI611>I!e_9lrq3jK*4NSB%*8;I=UdzFAp?0F9p>xeB2_E71~s_rM<{eO zK;RZ_mBG_#x6x25?WU#GFQTiXrzC*b1}F*L@qT5zLXW)IK_#Lz_}Y@m*%AZG^n+-* zSpa7=)GydW5)?mNo*q7aPTcjTCBXWJhHaJ1UUxr>6i_~~9b@ulGs=$i<^I-4vUW*B z5rpeME!%AlyPHG&SB}o;oF9{(x)^;8wPsuowjJKJ5bSK|aP9UJxOF|?VR0CDHrLgA zij$clIYmcu51E;C&2M~-}V+daOO9s$VTlnsBve!#bh1Lmo27~w4RYwYTIVdC-mw@J5N*U)=# zWhLTUBu>ITHWycu@AC|MM~FCy7MhNqoZCQ6KdGf9aF<~Hd|-`o4}n;n(1`zUxK0UV z!7DNw=P}RX*7{oMM=H4+`>RUVJsJ@0VyU$@Ze060RYx>=G=o1FtC_Ic<~U@`VDK!* z=%Ec*`Na67{z(#z#j-)w=$*5P-OXP_M5ly2icGEP zibBF$peYnC8~C468J>38ThJ~!s`Fd+@O*U#uPigQ>8}BI9*0`F=tM+(!3PSDjF*jf zW>i+S_iPKTfG^lq2^qV5(8}*4Pp~l{b(ACxRPLSo@(o})j~{LwYc248R$W!Mw=W_1 zBU>~4v+XQ2uLp9y*queZo$+&0ue4)AB< zrP;bbOmiKLs{3MF0c?0ye@7%{Afi|roNuZs8&ZIbbBwLIGd3S35dRgB2v-g1uh;!btuuhu68y z#PW@_Z=$?$KY{HzA({P~hsL!41@@rTqt%f5`>{esyj4dLAE;| z@jVwdtl07&R|Hi6ff4Bj0syL~hi4nB`UJd2gS1u2gnIzZ^9sKL|viw}$N2V=c!V6Z|5sJTc)Aia5%fflb;rsa$lEGasPYi(-f{4d#ROJb3f z9Sf{HAf1YxRL_HT9N>cT{TK!FoRSttfZLy!dh{nH+6(p3N6|Re3`S`-W`js(#`E-c zb%q>v9+F6G>A?$9nGY?#v%xzW95EGDhIkLvrMYV z-J(1{y9IWZST@khn5HJu7`?)^UqsVP^L@ub1SgLLJh@k@!YHaQUFBztldCJe*h{?_Q}efi0_A1nx@xK7jU)5jZnU!iZhu>K1Z8pO2d(x zgCFriv3V0IXV&mOxykYQ+1<7bmdV2D&e}^6;WB4~3T5_bCl3#1W(6lK7sJl(18Ob> z@wsMcY*_Z)Qz+8sU{b_}@patf_Gu7+$)yaq{;x<5`G5eYuTx!aKCeKz0u^AQd1b0PcD)+2euaau@#G@=ccTLxh3AkmT zDt>qV8wcu8yi{{NJyz| zwtAK0`{1W2Zn(v#X|9qh0KkX_;d2%arJwT#qt8~#zO}!o!;*9eJ(@MRcx^fM!Ogkt z10INi;UdGV(OAbwJj)pB^*FZX_{5(@T7)*?cZuMSNtuZLb*ug%%wkB4ja%f5#6Vhj z@;B^{4aF%e%1VO*eP$@qwG^4HzQ2lTVkg_(+#fy~8i$K&MIMjcs0&EasC>)h-qm=G zv9p6UH*J4QhG(V=BiJjbmY@~HgWO#4nINb)54uI|K9+laRsm(VHx3`L@UX}+v017J z9%Lu7i70;)Dsc>!H=D#z9W_OF_%^^pq@OuaW)#j;M~$7Lmfw2HP{(H^gf`N%)4Y0v zLWjBQ)YGuXl&W42Hqd>0WzFFrO-c1_vFdQ7DBU0+k2+5nh|B$CesAD&_xY2vH(52i zA;t{@A7sJa7JBuPb%>#DXKRUe(**;Uk(4zD>||TBCV%Gft0W-}58!P1^5x%Z7ys?8 zfOQg{HdfBzdM5PdnTtWSiK%Qi+x;Q&FKeXvTtt*hZy<5L*(S2No?~V<6TST}_5-QP zxSZ!DNa_0mKH~!%juWADn98^tKa3&I2Sm`C;`9j@-fiRCC5}K?8EAHk1jH)XJA6~F z%M_Lj{9Dex-3bWr2*A5<^^1rY5wPCbT6y5DIVtmf9BEBV|{Hrj81z2@3Mu z-Y{-<_Q^4waOY5uNCc3sb(w4FsKQ67!sf1msSzxjbIfz4T>;JpT;`98!W7!IDi5FI z4VOzQvgUAJ26e-tOkNd;iiFG*22$>BSD>BKT$1$TTT%zCC2!GfX+Kxi`!{2EE(CJk z1jKwK;q6JnfLxWYJM%ZLMW?@8qh1f8<$*PiQ^;S-uOlUpU2?Y-yBl7nPC|-Ggpwt@bzU4EuQYSzVBIj`1jGr%(2zH&3o@TM)cBu4l|Z!mXC(3ntZao<&U)pxM}QA^3x(=vaun(C zhQqg-zN<0`n)Qz`9;K197Yfahb0Q%kQ&%`|1*2}+xk9aiezC4MhXSbY?K!C6wHWE7TtOI(dyRczVq%tEd7i|7OBrNFaFCwJN$#`MH&%Ds~;ao$s%lS2gAG1++Y<5T*x>i;W zs~j#G&FFArqjn`zHWwz?)Azs<4=`;DH!@R>`ZdC+rR6c>&!hD)=h?iG&6u@3!EWTN zhqS=ynX)J_V^&_Pw@hWZP~%ypuzx6d&n*w`c4!DB_3CnA=@*Bk6>ZbCrfxVMopc3T zp@(IY*Zkg6`EC}jq9$OfwZl+yRncw`Ko*g{f|6OBWcC5ZE3$o0$&lAO27|#ModlUU zPr1h}dI^AzP?hap`|RJoyq*cDJLh=-VuiiFo~c}M`40U@g#!4&W?G-zfKIFb1Do=J z_x|3{TvS{1hw3@TeOx| z(OPb8UI`}|cnw_hemj^^TE#iX;%4gWQ;&K}Eb}YD=TwE4T?!eG_Z({_qu64zkIhSd z5q0hhQ|LAitwilwjFcc<;53z4W~de^Jx``L*L&FEd~=K5w`@=@Xo!M8^;uTE95(B6 zRh9D4;hJu5sz!2^e>PFMOCW;}%Ny2DD@aiuuSNu40|p#kUJTRnR8M6X(=K21J+PGR z&B;IFL~Js&;MB^E{~zAoGak-%Z6BS41koZwbP^(o8bl)6L=ruS-i=;IIszw8gg%x}JM-`9O!$90}Z$zajtt;VaQ zw5`T3sES5y<)01!H}=nhGybDL@$bj0Y6cbIziDWf+P zP=ZWOv^S2RL_3aXW$^nninw+L`*QI6Lufcx`_--Ym-;$=6$1Kej+s`QKC^YbAPTQk z%FRCW5RVuH^lXe>&`r4SkQ5;kRiHGy4kiF_Mi>EU8ZHohx~4d~VizeZ1)V>b+LI>; zTyc=-p4d86o#Sl0XaXjucp~40IYK*0wuZJ1<`GOU5F*uLmtwUZ$I6iRO6q_18Wbu=JcOvM|;(AM|i;=3@9TQ#bt9hf`aPh z5;-3e9NTm8L}X6fTAEmzZGKg_0HEIR1>e=w#dUFed#Xg`QM0Jo4P-i(n_*%4v+him zP2cjP1|dVW&KmhidHuC>1B{Tj0~Bsv<>$Y@a#L&1AJ3Q%dxp_U{j%}!q`ErxJ@P3k zuuzPp_o}>PK(qSCOl3Yb4>??SM^9eyg>|5i1(26NWc$J>U_#Eh|Ix+q;3`+^2}y^SdM+M!I*}PLgTZ-6x3gW%am# z^1S!uUL{`#&2+^}DifN~kF;in7R?05Lenb(%fW&dx9|^;7d+4~W+CbFSh-^a%JJF- z5FELZTIWVYkl%UL?r^Q;g0>7T8+6!6q^!nsh@&O$Gjla|>0<8bkzD@y`xaeVU(m2= zVjf-+0eN|RdjO6NOP9fL#w^~SIZV~+(|9T3QC=e-knWPTSSw^OTw-O_*GGH-e=~I@ zFqqxmk8owqJwmiIxe9DcWvD2;# zZLS&H%WdLen(lGgxotA%{B*!q>Wu$lw5}qJ?Hd|!e$u-b-f0NuRai>O{J3N)H`iVS zC0q`WQ5J@c! z5Br?Ae$N`wm8U)Vo2<26Z5^Ho-7^~Ht-Nbo?d=<%F-He(-7jVJQieb6RlcYn0=O`nR8(Azd3FSt%|UX4{N8j{Pck)X_zAQrzahZva)PNx+Y!@Q8Gsv8y- z)7{gXxm#N*5B7CvC-3d``fe)Y92ix3f}}Ryl&S0BH63f@of|zZN~a=H8uAv#rKSQX z_WFMwi2-8+evDY>5MC5bQM>q*T~{fnHdbUx#EaxwnDa#WeY{;>3DHtlP*+3~B`#M1 z7=zpJk`?j{^H?)HzEQGjdO6@VS)70JdYjA*1o0?NU;D5rN7EqwsfeSM*#UPu!}%{z zn0wz0M7_qR{;WsOCI?>Bei8VS0#tNL+|ogF)^GYXHmVyxRy8wGkRx*~lcx)$4WP=u zZpK5HFFGNF>K(~TxIx`&%aKR5&q^cTPDymHIUkX<9GgC!4?9b17G8YwhFdd=fz`}U z`{(I&IwhBrdp5QT0HIB6r)4;vx;J$oGOHDL@n0*UUbhMCO`J{!M zd+|x&Uc*asJ6^{Z-;$v@kpv`5(t=*fl3(W60=fbr`X5#YiPSfb;3UA5HJVzmg$slI zhD%(G{&A{l8bQZ&-Gw;oYqOT*{c|at047rg&^t^DlM6Ep?@uO(^^xcZeQ!5sif+gy zBKJ>Wxyt>s@PHo(ZYfA7k-V$B>1lrtE8Sa}y`Re=Gs6m)!fPFUXK#dmScl&m!Yh#~ zX4zJW7AYR5^)7G{Y-*%vFV+6g*+2aSs#l5GY-osX_--aysWJ=SpTiG`a;IR{+Ia~U zN`g-j@7;;F?L&xjlQy9ViO!H7^kOYgd~E#lQr=#eK#u;tIXI7Ujgrt+=IgC+`@{28js0T5{p`D=UyXt(LgrMbx2!BJKDE zqH%v z_Uyg!qKeeVGbISbT^*B9(Q<+Br@l(QS;?vn%H1bN9^27lkV~8&ny&qvdsZIRCX@W* z!4B`DVFtT9g~-uK8E|$MZq&J;`02MmgN_RMdXnadwU3~MTOBvlj0pjwxbY7771i9Q zk9JGoNu+s&K{r)(6aEQn)0~`~y@9G7%iww>OSuHf#(6VhNt`@(ql6W zxz6kYxp6^f4WShmIepydF#MvvKiFFT%{NKn=@2AQ1|h2gwk*ZF52H{Nzc>cWG?%^& z(nz;B)`7Wf?HC^%ad-3bnt1J6xkug4RO{bX27%l;ki#rIKx(t}m-9O8RQo9_mbb`W zXvUVGhXP1!C@XTf3OYh?{=}Q)z=WD>YJT1^w9*Gu-A9Gl=3x^bGXQ;W)b`!V`y7ZWDdNnlHo6qmjLc^}g~%Y?KSmWgnHel;!2`yr_M)>vpd3}4vP zR5Oa;tgBB`EKCBVT_aDeJnnJCdT}I|X4s*kgWc_XRTLVMTQ6p+JH#n8Kc350vqr*p z*@MS#i^dhr$d2tCJ31z9sSPy7y^gpMa5jik;2ylVf>(xwL&y(z++$3eR%fw~&I(1% zJR~k%(V=L0i+F|@C{#nVNL;A;nf&`L|aX_njY*#gK4zG`MZ<`c|~K$Dox3 zck8g5ko_Iu5#m9_h>!!9ekF@PAth#fvC34w9RAUq7tTJ}< zkpz(v`bQE)YSzTm#`wbsSx0-imk@RT>9pKN$k&D!OCdW-U+}l+ zm?R^90vfKLBXwhRuRCA2*Q+Pws!QJ%Sw?eHP_jTRw_eje#D&Wz99Fg1Gao8(?kQ!I zCm*oWD=uh@F~!b&u27YJ)(QY0vbh`3fWFq`s~JU`f^FQ;`c(>%S6+VqV^H$--JQ|f< zlUnwLqeU(pQQ*Cgw)h^zkcd9H!t1o#g#%*V-0QAA%T1^Tu(08Lzb8rmv#Ni?)G=e(J_Y85iB*%-aZdv$0FENWy4YGUNMs8 zSW}{rq|Z8g?KP#+z)lod8(>w>;6A6+=*=vmM@gmi2&uk(3UHXo!7_i_s`@hp{fQ6I zlp)B2PHoTfqgS#L>#{41q<2!-`FUR4HI&sdi6y4zpz?1)cFpjH>a_X?6z}QlR2b(eVcMi*D z*(O07I5~PSuyT*i_JZo?kx!qPD_iWbN|;vc^XHvK9r7)|XQ8VJ#RUd-dhs1cBUjTr z`KC0uBCwjED+FIaAR>ix2yefUjj~z|2EfQH(=YP zidN3#Ryj|noZ>O8wFq(2j+XRKlKTaMVml>OM7m9azG6f?wyRYRBpN8JxJEPzim|0f zzQ7|+=KH7KT7MkIp~pK?7;ndS%@imliK;E{%+HE|Ry)nWVx`L^lkV6;a%?Ch128lh z%58`!7>%R@@)TLA;Xhev_%68d(xd#d>gP$eJNCKXDSJQUvpohk%t6nce_lJV6&-@q zsb-Q%hz#cxC4{U2JhiOpm3n?_Jziv}a3fg0REl@!sNLhIjLv-<=77AOc^6qd0BQZ5 zKPZg)j2}mF);UL4K~x>t)RQ&cm2apN9Z$8PwuinAB zucVT+OK-W}b^y><50Lx_v;aYW_ToO60z6EV^D$MMUENW)b5K%OkDf6+@8+29q6fn$ zROk>tlW}`k6i&$3J@3WR0O!oEi2x5nit}yDXzLSBkqhSL2NG2X1glD0rOj{`zx9sW z@R2xdoH~tu-^~*q(oJKfH0t0M`5bln!>YQzD#kL{`UgF;vZgQLRLJjnZ(&yk<^a7(_V zWG!kOMZ?cCBJxt2;BHbhh*Dj}_c{x~nHi8T^#~H2oc^xFA+>TwPb8UCNBgd-rS|L^ zPUFPfJ8p`eeg4{d(`{Vu!6H$lurC}d6KgjW>^|*UD)dfjy8y(}T8lc*eej*9nJnLE zXY*WTu(T#ItYB@(y76*T_Bp@+5MGO@L{JadA}lPd-z+4{9fU4haAdIONgF%=;5bI4 z!CBX7FSs$t5I4nqj<6}UQTy%XSRO~sSn207&_UtT$oXhOU|dRpe`1%h?$K=Vt(pjw z+Q03^H!u^rha&@B@e-Gg)`5Y?VvloA+{Ma@gbKA$jhQE(M*&+uEni?}_y11g{_MRL zI2?a32e;Jbc}j~QLOnX0=y&0Fo)%2&CnjWl&21W%*VC$?>S3+)fLkKE=NIUG6YB_! zdnwXRc9?%oV`RHTk9apL+DvjJuv6K|1>iIAy}#Ce)li`fCN?7!H`|0hJy?w_mN+qvY2zF>5`hI7~`Ix6hOZxwdq ze4xtD3s`=%Q^)ka6+p6A6TQoiD#}xvxnQx9@J6?dxZf)iqeQtb!62mKl+KRXv(I2k zF!-P&LwAm%1zW34E{tUEUAc1@Hkdg%vIwV>xb~uZ)*_9ET0COfrB9Vgj5~EDS^5NXqJUiFS(9Qm93D z@ZK84hxeg>fpkjZCT)FofQlN)`nO}LzXJdNKQ-8!NY6`~$mXDsPNWh4w`#8n2}Atk zawG{YlIT)kT1#|4$)-GW;hsY9?l9?@u6>C~)Z(ng0}dfJ^WWa!;@4%(j7s!Bsqi6o zOiQZl>O@MRI*a-H5@M_$G=U~TIRXeC3zrlt*RGCnBc-SHIr|!7Irenlf1|d}>|0M4 z4K^FO4VY=}pX@H9Ki<)@Uooqzkvq6p?7m3}Xo>E<_~|xBw((&Dr4-qeYDV1dfgO4$ zeI&x%v+09Gnu&a+{<;txsOD=}aaistE=n(+sj5&BpXiYN8$O5wUeLcQcmV^p)@&h_ z_E>AQgm%332WPU)=dXG6VD)t(4h)09=P6{i=a>AW zR5q&H#R}_LLD1yYHm9bLS9P&-j*y2hJDm4EaPNDCT5=riL9)>^Fd0s2Y$apF8^Fyb z5YUH5*(=9Ckd1xph&akvhcljMNZtk*mXq5J>ad?v1z+_Hz@I@<5%(j@z8IUmeJE<$ zv~ZpV2cuwbhWKcq>?3$7(_1@Q&ZS(N&>LN89&sOJ#h^XQRtL6?Mu$WH z?V8|CvA2z6rbH&`_M7QZ+&_P~^h>^E)2hl3&n(Yq~8>N z;NU)^XJca7tJA*1`;|GMlS0%vF4iYbN0J?5S-!Y++&EsT2uuS*ITiDDyRr1*lqR~u zr&XG9>U~QCVhWDMRr|6XX3hs4VzP2rj%w=!X#e^ku}PzuaglZnVPGJR;hg(Ct$}@B z>E8D$hQWX$@jUnYfj#a{u)eQt!I5)SYh%_!o840MSADo)$uir!0U*oxIAoVclIIx~i+QKrK<$ zZjPmwC@er+KCc3fLE7`56>YO)yHo=<=lSsmsEzcqP3e+taynB1jSY>-ill+}`CM*R zBD*m_rH;PffCesF)^g@Al0R4M`SH>@?tKPi_s*f};nwK#f$l6lMhh`NV@j?rJ$i4% zasH|Nmp80VKG%H$TlRD{w0Ehpl^= zld_-_h#*#;4J2W=|4K1UH(ANJPJ;F>lSr@1RlQS_ENq8>!gmOVOE>@H( zEPHWpYVjB7OlhQzg{hLkJC@c^H7VA{D^tBF?c*@c}&Z;Kl1N=Xg zW?hzl_DN*?+PJ>*Nn{wy6}xhH?s<}C*J;Xho-0;+8UxIsB4!zp@LPVZp4iH&p~bg7 zE=&PvQS=biO!alp1y6}+*vXTBG#+Z>#cLMoL$B_&ZSjO>8f;R{2nIY)Ql+Ch5lrzb z<4!>^UTMP_h_8tjrW^8?K~_B%g%rlv>00(T5c$(EIo!zNUKnOlc2PoQ=k;WOS+L0X z{XQoAiUvrZh`vjuvjzyT%*|CurOQ(fQ!Eqr`k~4CXlAl}evou<2|}}>M_%-EYTEV* zi9J&_nI_GrdGoh^@$gKT7@98~J=IcY72@_&sWHXp70^a4dwYTSw2SWaJti>jYGP)HFpVDuYf!}Hm@yBwYa4G1R?WcyH_FI)b6lwA-8jn z7^V~1>7O6c5a}sz=G3IwN@1!R-~v0^Eee zMbD4GrOnv+cl-<(ZR&4~#~B(9G8b2H8R_OYy$`#pD8vF{$!WTIUfgW0==eS{VU`g+ zfT=+r4u}Pi?{?8tlBI_%uGf1tOU^{c^_LTIuB%TKUQ27WE=Clurp-8f ziIVnWv*hAEN|iuzv;wnyyzi>^9|5*VGVi63nsL-$k%-Bz%0sM!Hsv zeT`<7wDaKt0+tO zs#o)5)kEEr^x6F-jll~seHt8%Ov>^|UG1qk-`5gg4O;4G6JcDJo`f`!uZQ{+E9@Ig zJJ2RPB?BCc&n2@X44!B!@BPRjIBObA_ z+v92`+WR=g(I_Hh@?*SYJ95TM#E(QPT!X#uZWZ83ckl@|+`x5Db;cd6n+MSCKb;x> z)f6nR#QtB&dP5e$8ux)bO|^$ocrLyB1P8a4)>_4)1DhmkhWCdzJlUo!XzZpfkh zP-+k1Zx8P@pqk}>fvkUl{5LR}tpXj^LoJAnZS&IP=g+^1%rUacfLtg1fzaoDj8(wV z;N{ISn>uWga}F@yFyDAPA<|nd!!rND4$JgeC`vRyJ#mkA>*%5`o#d18EJLBQ(bg0` zLT?N`7*^?bb?drqGGB(|XTM9mN(9DdffIq#ER^28Uz-9{)szLbU+s@Ld&+tNcaWtP z6RlO+G|v257nMad)zNP9O}wk?RlSSvH_=N5%r`aE{zxLb`!oNKOs^mH0OgB&FPKGa z_~`5by%x#y>6f{o8TTmOd3NL96XhX_n;qupCv|buis)V=GtGuZ#p)+~xlRp}h6?C0S-mpzO- z-kvX-S(9!ZpJ`9{5&2opUBfdwR_SGK)-4b+E2GJ~iCd`h7B0~riN~Zk8$w#=f=?Y= z)2~e6{9Z8*Q#JVnWaurbA7?oto&j4r{bC&o?XqSm@AKgj zOZKxpNb0S}!;{mBj^ZkW7y;QRX|CS30AdMpIHFDSfg)iBW#|*Xq4T*IjBbTxDbw)e zwyZRbnR1;X^K;ayqV*noux3p0D$kAA#CI8Oh=?*;h|<0`6>mdB<{)KPV`nenC{ELA zxooNut7A9e79(DEOn2F(EqNmdR+hbkSt>&T1XAC|Aen{w>6Otn@`4%KE@s_h$4gR;f21GR21n?Dj zl3X2`g~`Hvs+hUU5llkK@@D_G8d08xC-qKDLd`5a8eUs;$16H_Ld7G`?|m1eBv=9eWvo)a*j1x`)G^oR zb6-BdQTVWuI);kkgi zj+NbL=EhO&7~89^uQiAEeH^*URI@B}>3D|CWd-x}1A| zZ=NE~y%=VLHh*kwBzGjo2Vu?(ZIANXi?=F$RI!#n7-aQ>o~}MKmZAr0c@$juqT|WPW};}<+hqET8jqMmuNhN;(x>gp zPW9gCb~A#wsdYbpKkCFqWSg&;p}7vCwz@G=a`VThndoOyS_I#Wxj&reH$7EChqroQ z>s|z5Sn_o3m$~TlJ8R}RiP_SgfllM_B4GYRMaIC+Gcs`JOtO#7+(_-VX#z_VD{2hq zsgi$kP-0!(#5nF)QLI2&ZcD2!(bz5)_$Ef4OfW03dy|4IQWr=QEH=GZJUw01ukQ;H zRB{$d^rA~iF!kaXvpo+JpDz6DIzNNRY0aDdZk&=9SPU=6@wc2>y@d(nu8Y3pWF!^A zaxNv9jU`2UaK!o!z;2)M;V+HC??4OMj7GPYLt3i@Ls4G0NIll4UnZTkIi0+p2gyj? zX?|XK0KebSnk{Ftz`Z}yY?LmHnDw<(dHy=0pvUpsZ@-DIq5pPY_;=*VB-=T7We`IN z%-au1jU0B1tDn^pxV`VY!>979>=F*S(lJ&v{zPzU`Xzdh`ey9Yn}ys2|Em7Y+TD<< z<5q5NU%tUkl;o!m2Bg8^nz1u-2LwyzKmu(rA#JC;a|#Ax*X9+Lp}rZ1a+F;IBwGiP zeve!0K43Ak;26vR((ohjzcAevJ%1%&}?Sb)7) z<`LyQqe6!W+V7dE)RpHvG5dL4^X)d>wZm&Cc35(Z*2mdvfReXbWZbOD zSE_jW(x;?5(JlwwSDqeDOW1Ad;bn!|iueSx?-z0$9)e%AjJfAMx1aePSbIS6{m*b1 zBEZkyF-*%y7*m-TQZauwu&vX2wU#I(73-+F{TVb^vO6(2Q0FY4>IlaWU3#!17;PK5b%FZ^l+@!w7+1)VtTf&j_lPEX1rC&CS?}-+Z;nCy)UtTtRm}1i#s=M zteuPV0rhC+b)jj&Q}gq?5Mp?%pspTXd2F?Ily|4(?g+#9?6~%|gK|a2)VD`$GEk<2 zBSifcX8ZKrL)=DZa+!yp*Rhwqyk?v9z)bOFU|yIm@$64mNysmdJtQI$VTXZo%QwnD zswb0&jqlYcI#1F?b&L5yQ}#1ihR%$Eq(Ph~dX<}8@Ws{KlKLs0O{byfU+8sJ@}~=T zYGS%+PS$^m&=5@v4T#htcf-WiX2`yz)#FYVpvm60b|EEA!_(w*3N=-w#^?n3YIC2iZC|v*amR&N1x9nF;lsM#qX6iN8=H!gYYM&o@~Ab0}w*ih$;2t2y#}TM%00*0jXV-M0}1 z3TIP2ygabSHoc|1()!Iw8<0y)g5Va&Ey=?3#H+cEuB?;0G#9#R;sLMhCzdI`1V%WI zH_PLnEOJxQT0a);OmwQ&^W9c_B#3aAc)uO8D1e}cdf zIjFo(6#IgmK4k#b!@ywCUp^*y%z4ElpGL8zv`kN@Ed5Q|sssHeriBchvge19C&+bo z81l^RaUg4(@1wb?B=_q2shsWz0-1+oS(skq``>ppu!zhB{ELj}Fah0es z_+(XFoR0=dJ>(lJu{-$MVZD;;qE*nNsWZRIiCNpKs)JT}#-SBWlMk*x)8bEy9SJ?Y z$&v{az3$Ao@d(6~M+ds}^Ad#OqQmcMdV3l>a1vj7O?sY`)oWG}?Zl~H{AD@n3!AZz zi#B}=qPB2X#EuhS3xP2CwESBa=wH3t|Kc-I-2cjs zWI*DBfym6QMU`{np=T^fUjgL?L)%3o;Ew%M+OR;6AMalT-kJrU6KbOVbWHynQvTEH z@6y$q!FET{e{Y}I9F|T9Q%A?C#WEYUEPor^b?0{Hcf7xIV73C@uA;0~IOh&_{^%Rn z_Qb~MqFPc>Btsp=)nll?D{}4Z$py)ompfEtk3%ss8BwzgA)<6$9_70q^4N^RHH=zK)A1D?yz5Z-O} zb%_t>Lbd;~Yebyk6$Tj zYnw7|#GfL2-gHcqGnGE&IL<20ce=Qo%5QbwRr1*L7wD~(_z3lb0~syD=<#L}T(vx= zD`ZEw_{NT7#ny*cE_v)3Ercvmgl1Q(xEB!V%e>P zw-Ei!DE-#NCTiT+;=6ho5?@cw48nIz;x465QhNak=Nd?)(*T#IK;-Bw*A}w58-3vQ z+tz40kR zLR|BKYF=h~h|&2Y*==Shc!%UnRTsvZvYxD2 zZPE(0)KpKhbPBM5>pu{fU0g{%_yq!jXsP)md7-mQ?VhxArd}Dr{N>zDshk^{OYgI+18 zOFngqRk-CDPq!-DDdUl67J)^KI{vNgBO)Da3I;*F2U~7H>xQ)(ko?TsyA0AGy&z*4 z;1UJBX{wU9@dKWO=oJZP!H7hgum&^0PMe4PS|pL&ZCsBUGiMc~!|z2s^qmaw*>HWE=9;Kp>2rvu}S*zd%QPmGcccs zzG1ecI5`7pto#My|Bgvh4|ZKEKis(R3k{ubCfZ25gzilLvT^;>8=j?!&r!P3T9y(M zvGT{l`;Z;X66xU1ASG0n!~C1R;|~3G7LJ(IB{jbpV&LY&kdsH4>YZtrK%SxXa9fdn zI*m>sAqr+(|A}$+%6q!!SIwt*wbiI}qiOi?-5S#msxjs-cWAnsUa(EqxSU8-6r>Irl&OoDaVZ4bjj5 zn*=JJJ&K;{_cAkQ{pe`qVPgb+!>lkmlRUL2igsJlYcRR%Hki{yiYNIgd2K^bI`>xN z7@wx}Y_>>SU-W|JdU%?X&=kkKcGi$IoL8^%)yo-$l6_y5pASYN?*lelYyh#C`cHA@ ze`3!9@6H&jMRLA9rBVCg-OkO&!Pe&Mn=-_OAJvsQW=OU&!Qy^4j+32^@4UZmCUY4W z;``B0MRP@rMX>cC*Y{<=(}EzHqkmDLXdb5yohG7>7ZW}&4hA!@ zhF3Bc8gi0O2nkIql)j8Dyy-;B@_DRuP+_q__sj(L1YMFfu9#=ArFNTZ-{xVcshR{+ zS)s2+%pN2yQLl1mB{enW*j35KvM2#vAN!$Dz~h=INGH~LdQ1V=3*!%2`&gho$74lA^hyK&8D4&%_JkW)>*JscL=-3*23{t5akQ+Rv5RsyLq)i{~Ia0)`80yd{?9 zHBmlZMkGtdJsfW|KSsTy`icArCTV_ypn>w~+p*pdf_|1(qe(NnNW1|keY&D*U~wZ( z2qES+>Y%lE@kp!Yp6y>Cf^y0f8LdcnN8!@rBbt~6FpW*qWAsXJZI%IPsw7r`Lye*- zNN)Q(K%eVV9sJojVN?7S)JVF+FsD$mUREB4z zKI-@7E$~P@GZlh7xR_*R$(pj8-y_>p#M-@=?#%G9cz8#{_<1Y6$_)FeqXA$)(<7Qw z>{DV(J!kvG6=L*bYNe*;Lw&t>tQTj2_68jVQ}(+;hOvA7NJSeUK&jW%Rd+lvmu?au z#3y(5`YP;`D(V<5u6pV$h6(fhXrBiWsVVuwQROW>>kKr>nvF;C>X}8VWljFY=X0Vf$@}nsl_Pg$-IIF_Q&r@I$=%`K< zz6HBS-N3yzXJFEhz(tVt;%kYE&}e{HONY-DxNfSI3f*}WbLExhbUeZKKECm_(QrXS zGe7P&Kn>|;S^s@h(QfgpdeZWFj}(X6>cGKAI@}L)4Y#OaQkB8IDLL{csZoE?%Xejd3CSmcL*1hb%6QP~8?oIJ|AytrB zOun>wq{xIWY8LhIeN!$$t%QpA>9*C)=WYfMf7+@PR;494tcAR|_tEx&R&3eMXfyEt zt%Z#KZ68Q$)a}e(U!}IR(Vx$r&&=8~SSsGlBv?&?SlBYmregOke&Rf{>FNO5s-w3m zM=_dWZdH*n^r;2=-ph8%hUPrB)1~gMBNdNz!S#z~*}(Qhzt zlZ1KeK&Xr5G7`?b6}usNkmPiej07z#iQWB(JEIQprhUg0ZB)R7obfDmAJME!q!8rWkH{waOY8YP`w+N z$0ohu3FW6K5TW@E?#%PgeikG!JM!poaV_{@hES-z+dS9{`sIA>V%t2rknE7|-mZvA z6zXO$-T3{?*ZBf;6E$j6c{xWLM1FM6srf4gy+W7G!y+Tx=MMtxy0@^WbYVKlw%HF1g%0XIuE{7< zYncFRLka*Dz|t>(4}!1kNj?OI_4LLcpx#66b&=!4w~W_%$pj9-$`sFlWL9oOx!-(x zb)uS$)Xo*xS*g~t-#E#ZV z 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 literal 0 HcmV?d00001 From 198181dfeb40f372441d3a28940ca8d210b3978d Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Fri, 27 Jan 2023 16:06:43 +0100 Subject: [PATCH 043/209] Updated to help people further Added new insights based on https://github.com/laberning/openrowingmonitor/discussions/115 and https://github.com/JaapvanEkris/openrowingmonitor/discussions/11 --- docs/rower_settings.md | 54 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/docs/rower_settings.md b/docs/rower_settings.md index 75ad3fe8b0..83f59a383b 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -1,7 +1,7 @@ # Guide for rower specific settings -This guide helps you to adjust the rowing monitor specifically for a new type of rower or even for your specific use, when the default rowers don't suffice. In this manual, we will guide you through the settings needed to get your machine working. This is a work in progress, and please get in touch through the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) when you run into problems. +This guide helps you to adjust the rowing monitor specifically for a new type of rower or even for your specific use, when the supported rowers don't suffice (you can [find a list of supported rowers here](Supported_Rowers.md)). In this manual, we will guide you through the settings needed to get your machine working. This is a work in progress, and please get in touch through the [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) when you run into problems. In this manual, we cover the following topics: @@ -64,6 +64,10 @@ Please note that the process identification numbers will differ. ## Making sure the hardware is connected correctly and works as intended +Because any system follows the mantra "Garbage in is garbage out", we first make sure that the signals Open Rowing Monitor recieves are decent. First we check the physical properties, then the electrical properties and last we check the quality of the incoming signal. + +**Please check and fix any mechanical/electrical/quality issues before proceeding, as the subsequent steps depend on a signal with decent quality!!** + ### Checking the physical properties of the rower One thing to check is what the original sensor actually measures. You can physically look in the rower, but most manuals also include an exploded view of all parts in the machine. There you need to look at the placement of the sensor and the magnets. Most air-rowers measure the flywheel speed, but most water-rowers measure the handle speed and direction. Open Rowing Monitor is best suited for handling a spinning flywheel or water impellor, or anything directly attached to that. If your machine measures the impellor or flywheel directly, please note the number of magnets per rotation, as you need that parameter later on. So when you encounter a handle-connected machine and it is possible and within your comfort zone, try to add sensors to the flywheel or impellor as it results in much better metrics. @@ -74,6 +78,8 @@ If you are uncomfortable modifying you machine, you can still make OpenRowingMon Before you physically connect anything to anything else, **check the electric properties of the rower** you are connecting to. Skipping this might destroy your Raspberry Pi as some rowers are known to exceed the Raspberry Pi electrical properties. For example, a Concept 2 RowErg provides 15V signals to the monitor, which will destroy the GPIO-ports. Other rowers provide signals aren't directly detectable by the raspberry Pi. For example, the Concept 2 Model C provides 0.2V pulses, thus staying below the detectable 1.8V treshold that the Raspberry Pi uses. Using a scope or a voltmeter is highly recommended. Please observe that the maximum input a Raspberry Pi GPIO pin can handle is 3.3V and 0.5A, and it will switch at 1.8V (see [this overview of the Raspberry Pi electrical properties](https://raspberrypi.stackexchange.com/questions/3209/what-are-the-min-max-voltage-current-values-the-gpio-pins-can-handle)). In our [GitHub Discussions](https://github.com/laberning/openrowingmonitor/discussions) there are some people who are brilliant with electrical connections, so don't be affraid to ask for help there. When you have a working solution, please report it so that we can include it in the documentation, allowing us to help others. +### Checking signal and measurement quality + Next, when the electric connection has been made, we need to look if the data is recieved well and has sufficient quality to be used. You can change `config/config.js` by ```zsh @@ -92,21 +98,37 @@ You can use the following commands on the command line to restart after a config sudo systemctl restart openrowingmonitor ``` -After rowing a bit, there should be a csv file created with raw data. Please read this data in Excel (it is in US format, so you might need to adapt it to your local settings), to check if it is sufficiently clean. After loading it into Excel, you can visualise it, and probably see something similar to the following: +After rowing a bit, there should be a csv file created with raw data. If no strokes or pauses are detected, you can force the writing of these files by pushing the reset button on the GUI. Please read this data in Excel (it is in US format, so you might need to adapt it to your local settings), to check if it is sufficiently clean. After loading it into Excel, you can visualise it, and probably see something similar to the following: -When the line goes up, the time between impulses from the flywheel goes up, and thus the flywheel is decellerating. When the line goes down, the time between impulses decreases, and thus the flywheel is accelerating. In the first decellerating flank, we see some noise, which Open Rowing Monitor an deal with perfectly. However, looking at the bottom of the first acceleration flank, we see a series of heavy downward spikes. This could be start-up noise, but it also could be systematic across the rowing session. This is problematic as it throws off both stroke detection and many metrics. Typically, it signals an issue in the mechanical construction of the sensor: the fram and sensor vibrate at high speeds, resulting in much noise. +When the line goes up, the time between impulses from the flywheel goes up, and thus the flywheel is decellerating. When the line goes down, the time between impulses decreases, and thus the flywheel is accelerating. In the first decellerating flank, we see some noise, which Open Rowing Monitor an deal with perfectly. However, looking at the bottom of the first acceleration flank, we see a series of heavy downward spikes. This could be start-up noise, but it also could be systematic across the rowing session. This is problematic as it throws off both stroke detection and many metrics. Typically, it signals an issue in the mechanical construction of the sensor: the frame and sensor vibrate at high speeds, resulting in much noise. Fixing this type of errors is key. We adress two familiar measurement quality issues: -A specific issue to watch out for are systemic errors in the magnet placement. For exmple, these 18 pulses from a Concept2 RowErg show a systematic error, that follows a 6 impulse cycle. As the RowErg has 6 magnets, it is very likely that it is caused by magnets not being perfectly aligned (for example due to production tollerances): +* Switch bounce: where a single magnet triggers multiple signals +* Magnet placement errors: where the timing of magnets is off - +#### Fixing switch bounce + +A specific issue to be aware of is *switch bounce*, which typically is seen as a valid signal followed by a very short spike. When looking at a set of plotted signals in Excel, it manafests itself as the following: -In some cases, changing the magnet placing or orientation can fix this completely (see for example [this discussion](https://github.com/laberning/openrowingmonitor/discussions/87)), which yields very good results and near-perfect data. Sometimes, you can't fix this. Open Rowing Monitor can handle this kind of systematic error, as long as the *FlankLength* (described later) is set to at least two full rotations (in this case, 12 magnets). + -Another specific issue to be aware of is *debounce*, which typically is seen as a valid signal followed by a very short spike. This suggests that the sensor picks up the magnet twice. The preferred solution is to fix the physical underlying cause, this is a better alignment of the magnet or replacing the sensor for a more advanced model that only picks up specific signals. However, this might not be practical: some flywheels are extremely well-balanced, and moving magnets might destroy that balance. To prevent that type of error, the **gpioMinimumPulseLength** setting allows you to require a minimal signal length, removing these ghost readings. This is a bit of a try and error process: you'll need to row and increase the value **gpioMinimumPulseLength** further when you see ghost readings, and repeat this process until the noise is acceptable. +As this example scatterplot curve shows, you can vaguely recognize the typical rowing curve in the measurements between 0.02 and 0.08 seconds. However, you also see a lot of very small spikes where the measurements are below 0.01 seconds. Actually there are so many spikes that it masks the real signal completely for Open Rowing Monitor. It contains sections where the time between pulses is 0,00009 seconds, which would mean that the flywheel would be spinning at 120.000 RPM, which physically is impossible for a simple bicycle wheel. This type of scater plot and the underlying data clearly suggests that the sensor picks up the magnet twice or more. This is a measurement quality issue that must be adressed. -Please fix any mechanical issues before proceeding. +The preferred solution is to fix the physical underlying cause, this is a better alignment of the magnet or replacing the sensor for a more advanced model that only picks up specific signals. Using smaller but more powerful magnets also tends to help. However, this might not be practical: some flywheels are extremely well-balanced, and moving or replacing magnets might destroy that balance. To fix that type of error, there are two options: + +* Changing the **gpioMinimumPulseLength** setting allows you to require a minimal signal length, most likely removing these ghost readings. This is a bit of a try and error process: you'll need to row and increase the value **gpioMinimumPulseLength** further with steps of 50 us when you still see ghost readings, and repeat this process until the noise is acceptable. +* Another aveue to persue is to change the detected flank from the default 'Up' to 'Down' in the **gpioTriggeredFlank**, as sometimes the downward flank might be less affected by this issue. + +#### Fixing magnet placement errors + +Another specific issue to watch out for are systemic errors in the magnet placement. For exmple, these 18 pulses from a Concept2 RowErg show a nice clean signal, but also a systematic error, that follows a 6 impulse cycle. As the RowErg has 6 magnets, it is very likely that it is caused by magnets not being perfectly aligned (for example due to production tollerances): + + + +In some cases, changing the magnet placing or orientation can fix this completely (see for example [this discussion](https://github.com/laberning/openrowingmonitor/discussions/87)), which yields very good results and near-perfect data. Sometimes, you can't fix this or you are unwilling to physically modify the machine. Open Rowing Monitor can handle this kind of systematic error, as long as the *FlankLength* (described later) is set to at least two full rotations (in this case, 12 magnets). + +**Please fix any mechanical/electrical/quality issues before proceeding, as the subsequent steps depend on a signal with decent quality!!** ## Setting up a more detailed logging for a better insight into Open Rowing Monitor @@ -155,13 +177,25 @@ When you look at the raw dump of *CurrentDT*, it should provide a nice curve. Wh Another option is to change the *gpioPollingInterval*, which determines how accurate the measurements are. Please note that increasing this will increase the CPU load, so setting it to 1us might come at a price. Setting this from the default value of 5us to 1us might increase precission, but it could disrupt the entire process as the CPU might get overloeded. So experimenting with this value is key. -**gpioTriggeredFlank** and **gpioMinimumPulseLength** are typically used to prevent bounces in the signal: magnets passing could trigger a reed switch twice. The logs provide help here, as the logs indicate abnormal short and long times between impulses (via the minimumTimeBetweenImpulses and maximumTimeBetweenImpulses settings). Please note that during a first stroke, the **CurrentDt** values obviously are longer. +**gpioTriggeredFlank** and **gpioMinimumPulseLength** are typically used to prevent bounces in the signal: magnets passing could trigger a reed switch twice (as described above). The logs provide help here, as the logs indicate abnormal short and long times between impulses (via the minimumTimeBetweenImpulses and maximumTimeBetweenImpulses settings). Please note that during a first stroke, the **CurrentDt** values obviously are longer. ### Setting minimumTimeBetweenImpulses and maximumTimeBetweenImpulses **minimumTimeBetweenImpulses** and **maximumTimeBetweenImpulses** provide a bandwith where values are deemed credible during an active session. The goal here is to help you detect and log any extremely obvious errors. So take a look at the raw datafiles for several damper settings (if available on your rower) and make sure that normal rowing isn't hindered by these settings (i.e. all normal values should fall within *minimumTimeBetweenImpulses* and *maximumTimeBetweenImpulses*). Here, you should rather allow too much noise, than hurt real valid signal, as Open Rowing Monitor can handle a lot of noise by itself. -When using the raw datafiles, realise that the goal is to distinguish good normal strokes from noise. So at startup it is quite accepted that the flywheel starts too slow to produce valid data during the biggest part of the first drive phase. Also at the end of a session the flywheel should spin down out of valid ranges again. Please note, *maximumTimeBetweenImpulses* is also used to detect wether the flywheel is spinning down due to lack of user input. When a *flankLength* of measurements contains sufficient values above *maximumTimeBetweenImpulses*, the flywheel is still decelerating and the *maximumStrokeTimeBeforePause* is structurally exceeded, the rower will pause. So setting the value for *maximumTimeBetweenImpulses* too high might block this behaviour. +A good quality curve of the time between impulses (as captured in the raw datafiles) looks like this: + + + +Here, aside from the startup and spindown, the blue line shows that the impulses typically vary between 0,035 and 0,120 seconds. The red line depicts the *maximumTimeBetweenImpulses*, which is set to 0.120 seconds. When using the raw datafiles, realise that the goal is to distinguish good normal strokes from noise. So at startup it is quite accepted that the flywheel starts too slow to produce valid data during the biggest part of the first drive phase. Also at the end of a session the flywheel should spin down out of valid ranges again. So *maximumTimeBetweenImpulses* could be set lower, sometimes even hitting the "peaks" of the curves, without causing issues in normal use of Open Rowing Monitor (it will add warnings in the logs). Similarily, *minimumTimeBetweenImpulses* could be slightly increased to include some valleys, without causing much issues. + +An important note is that *maximumTimeBetweenImpulses* is also used to detect wether the flywheel is spinning down due to lack of user input. Open Rowing Monitor pauses/stops the row when: + +* the start of the last drive is at least *maximumStrokeTimeBeforePause* ago; +* the entire flank (i.e. the last *flankLength* of measurements) contains only values above *maximumTimeBetweenImpulses*; +* the flywheel is decelerating throughout the flank. + +So setting the value for *maximumTimeBetweenImpulses* too high might block this behaviour as there aren't enough measurements to fill the flank. Although most air-based rowers have a spin down time of around 2 minutes, water rowers typically stop quite fast (think seconds). Therefore, especially the stop behaviour of water rowers requires a bit more attention. Again looking at the behaviour of the curve and the raw data might help here: looking how many residual samples follow after *maximumTimeBetweenImpulses* is exceeded (there should be more than *flankLength*) and how much time it spans since the last drive (exceeding *maximumStrokeTimeBeforePause*) is critical here. ### Review smoothing From 0c90c183825249481b2f4530d4ddd0ddad5d7835 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Fri, 27 Jan 2023 16:11:05 +0100 Subject: [PATCH 044/209] Small wording changes --- docs/rower_settings.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/rower_settings.md b/docs/rower_settings.md index 83f59a383b..8a7552971f 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -113,7 +113,7 @@ A specific issue to be aware of is *switch bounce*, which typically is seen as a -As this example scatterplot curve shows, you can vaguely recognize the typical rowing curve in the measurements between 0.02 and 0.08 seconds. However, you also see a lot of very small spikes where the measurements are below 0.01 seconds. Actually there are so many spikes that it masks the real signal completely for Open Rowing Monitor. It contains sections where the time between pulses is 0,00009 seconds, which would mean that the flywheel would be spinning at 120.000 RPM, which physically is impossible for a simple bicycle wheel. This type of scater plot and the underlying data clearly suggests that the sensor picks up the magnet twice or more. This is a measurement quality issue that must be adressed. +As this example scatterplot curve shows, you can vaguely recognize the typical rowing curve in the measurements between 0.02 and 0.08 seconds. However, you also see a lot of very small spikes where the measurements are below 0.01 seconds. Actually there are so many spikes that it masks the real signal completely for Open Rowing Monitor. It contains sections where the time between pulses is 0.0001 seconds, which would mean that the flywheel would be spinning at 120.000 RPM, which physically is impossible for a simple bicycle wheel used in this example. This type of scater plot and the underlying data clearly suggests that the sensor picks up the magnet twice or more. This is a measurement quality issue that must be adressed. The preferred solution is to fix the physical underlying cause, this is a better alignment of the magnet or replacing the sensor for a more advanced model that only picks up specific signals. Using smaller but more powerful magnets also tends to help. However, this might not be practical: some flywheels are extremely well-balanced, and moving or replacing magnets might destroy that balance. To fix that type of error, there are two options: @@ -187,7 +187,7 @@ A good quality curve of the time between impulses (as captured in the raw datafi -Here, aside from the startup and spindown, the blue line shows that the impulses typically vary between 0,035 and 0,120 seconds. The red line depicts the *maximumTimeBetweenImpulses*, which is set to 0.120 seconds. When using the raw datafiles, realise that the goal is to distinguish good normal strokes from noise. So at startup it is quite accepted that the flywheel starts too slow to produce valid data during the biggest part of the first drive phase. Also at the end of a session the flywheel should spin down out of valid ranges again. So *maximumTimeBetweenImpulses* could be set lower, sometimes even hitting the "peaks" of the curves, without causing issues in normal use of Open Rowing Monitor (it will add warnings in the logs). Similarily, *minimumTimeBetweenImpulses* could be slightly increased to include some valleys, without causing much issues. +Here, aside from the startup and spindown, the blue line shows that the impulses typically vary between 0.035 and 0.120 seconds. The red line depicts the *maximumTimeBetweenImpulses*, which is set to 0.120 seconds. When using the raw datafiles, realise that the goal is to distinguish good normal strokes from noise. So at startup it is quite accepted that the flywheel starts too slow to produce valid data during the biggest part of the first drive phase. Also at the end of a session the flywheel should spin down out of valid ranges again. So *maximumTimeBetweenImpulses* could be set lower, sometimes even hitting the "peaks" of the curves, without causing issues in normal use of Open Rowing Monitor (it will add warnings in the logs). Similarily, *minimumTimeBetweenImpulses* could be slightly increased to include some valleys, without causing much issues. An important note is that *maximumTimeBetweenImpulses* is also used to detect wether the flywheel is spinning down due to lack of user input. Open Rowing Monitor pauses/stops the row when: @@ -199,7 +199,7 @@ So setting the value for *maximumTimeBetweenImpulses* too high might block this ### Review smoothing -**smoothing** is the ultimate fallback mechanism for rowers with very noisy data. For all known rowers currently maintained by Open Rowing Monitor, **NONE** needed this, so only start working with this when the raw files show you have a very noisy signal, physical measures don't work and you can't get your stroke detection to work with other means (please note that we design the mechanisms here to be robust, so they can take a hit). +**smoothing** is the ultimate fallback mechanism for rowers with very noisy data. Please refrain from using it, unless as a last resort (typically increasing *flankLength* is more effective and leads to better results). For all known rowers currently maintained by Open Rowing Monitor, **NONE** needed this, so only start working with this when the raw files show you have a very noisy signal, physical measures don't work and you can't get your stroke detection to work with other means (please note that we design the mechanisms here to be robust, so they can take a hit). This is a running median filter, effectively killing any extreme values. By default, it is set to 1 (off). A value of 3 will allow it to completely ignore any single extreme values, which should do the trick for most rowers. From 3edfe22434cd8e144e502310b989d27be27f8744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Mon, 12 Dec 2022 14:45:07 +0100 Subject: [PATCH 045/209] Refactor and restructure peripheral related code - Create a new main folder to include ANT and BLE - Move peripheralManager with other files with shared information - Refactor static notify characteristics - Refactor code to be more uniform across the different peripherals --- app/ble/common/StaticReadCharacteristic.js | 22 ----------- .../ftms/IndoorBikeFeatureCharacteristic.js | 36 ------------------ app/ble/ftms/RowerFeatureCharacteristic.js | 37 ------------------- app/ble/pm5/DeviceInformationService.js | 32 ---------------- app/peripherals/PeripheralConstants.js | 16 ++++++++ app/{ble => peripherals}/PeripheralManager.js | 8 ++-- app/{ => peripherals}/ant/AntManager.js | 0 app/{ => peripherals}/ble/BufferBuilder.js | 0 .../ble/BufferBuilder.test.js | 0 app/{ => peripherals}/ble/CentralManager.js | 0 app/{ => peripherals}/ble/CentralService.js | 2 +- app/{ => peripherals}/ble/CpsPeripheral.js | 2 +- app/{ => peripherals}/ble/CscPeripheral.js | 2 +- app/{ => peripherals}/ble/FtmsPeripheral.js | 2 +- app/{ => peripherals}/ble/Pm5Peripheral.js | 4 +- .../ble/common/AdvertisingDataBuilder.js | 0 .../ble/common/AdvertisingDataBuilder.test.js | 0 app/peripherals/ble/common/CommonOpCodes.js | 10 +++++ .../ble/common/DeviceInformationService.js | 9 +++-- .../ble/common/SensorLocation.js | 0 .../ble/common/StaticNotifyCharacteristic.js} | 29 ++++++++------- .../ble/common/StaticReadCharacteristic.js | 36 ++++++++++++++++++ .../ble/cps/CpsControlPointCharacteristic.js | 0 .../ble/cps/CpsMeasurementCharacteristic.js | 0 .../ble/cps/CyclingPowerMeterService.js | 0 .../ble/csc/CscControlPointCharacteristic.js | 0 .../ble/csc/CscMeasurementCharacteristic.js | 0 .../ble/csc/CyclingSpeedCadenceService.js | 0 ...itnessMachineControlPointCharacteristic.js | 28 +++++--------- .../ble/ftms/FitnessMachineService.js | 32 ++++++++++++++-- .../FitnessMachineStatusCharacteristic.js | 0 .../ble/ftms/IndoorBikeDataCharacteristic.js | 23 ++++++++++-- .../ble/ftms/RowerDataCharacteristic.js | 21 ++++++++++- .../ble/pm5/DeviceInformationService.js | 32 ++++++++++++++++ app/{ => peripherals}/ble/pm5/GapService.js | 14 +++---- app/{ => peripherals}/ble/pm5/Pm5Constants.js | 14 +++---- .../ble/pm5/Pm5ControlService.js | 0 .../ble/pm5/Pm5RowingService.js | 16 ++++---- .../pm5/characteristic/AdditionalStatus.js | 0 .../pm5/characteristic/AdditionalStatus2.js | 0 .../characteristic/AdditionalStrokeData.js | 0 .../ble/pm5/characteristic/ControlReceive.js | 0 .../ble/pm5/characteristic/ControlTransmit.js | 0 .../ble/pm5/characteristic/GeneralStatus.js | 0 .../MultiplexedCharacteristic.js | 0 .../ble/pm5/characteristic/StrokeData.js | 0 app/server.js | 6 +-- 47 files changed, 225 insertions(+), 208 deletions(-) delete mode 100644 app/ble/common/StaticReadCharacteristic.js delete mode 100644 app/ble/ftms/IndoorBikeFeatureCharacteristic.js delete mode 100644 app/ble/ftms/RowerFeatureCharacteristic.js delete mode 100644 app/ble/pm5/DeviceInformationService.js create mode 100644 app/peripherals/PeripheralConstants.js rename app/{ble => peripherals}/PeripheralManager.js (91%) rename app/{ => peripherals}/ant/AntManager.js (100%) rename app/{ => peripherals}/ble/BufferBuilder.js (100%) rename app/{ => peripherals}/ble/BufferBuilder.test.js (100%) rename app/{ => peripherals}/ble/CentralManager.js (100%) rename app/{ => peripherals}/ble/CentralService.js (91%) rename app/{ => peripherals}/ble/CpsPeripheral.js (98%) rename app/{ => peripherals}/ble/CscPeripheral.js (98%) rename app/{ => peripherals}/ble/FtmsPeripheral.js (98%) rename app/{ => peripherals}/ble/Pm5Peripheral.js (96%) rename app/{ => peripherals}/ble/common/AdvertisingDataBuilder.js (100%) rename app/{ => peripherals}/ble/common/AdvertisingDataBuilder.test.js (100%) create mode 100644 app/peripherals/ble/common/CommonOpCodes.js rename app/{ => peripherals}/ble/common/DeviceInformationService.js (66%) rename app/{ => peripherals}/ble/common/SensorLocation.js (100%) rename app/{ble/pm5/characteristic/ValueReadCharacteristic.js => peripherals/ble/common/StaticNotifyCharacteristic.js} (57%) create mode 100644 app/peripherals/ble/common/StaticReadCharacteristic.js rename app/{ => peripherals}/ble/cps/CpsControlPointCharacteristic.js (100%) rename app/{ => peripherals}/ble/cps/CpsMeasurementCharacteristic.js (100%) rename app/{ => peripherals}/ble/cps/CyclingPowerMeterService.js (100%) rename app/{ => peripherals}/ble/csc/CscControlPointCharacteristic.js (100%) rename app/{ => peripherals}/ble/csc/CscMeasurementCharacteristic.js (100%) rename app/{ => peripherals}/ble/csc/CyclingSpeedCadenceService.js (100%) rename app/{ => peripherals}/ble/ftms/FitnessMachineControlPointCharacteristic.js (84%) rename app/{ => peripherals}/ble/ftms/FitnessMachineService.js (59%) rename app/{ => peripherals}/ble/ftms/FitnessMachineStatusCharacteristic.js (100%) rename app/{ => peripherals}/ble/ftms/IndoorBikeDataCharacteristic.js (82%) rename app/{ => peripherals}/ble/ftms/RowerDataCharacteristic.js (82%) create mode 100644 app/peripherals/ble/pm5/DeviceInformationService.js rename app/{ => peripherals}/ble/pm5/GapService.js (52%) rename app/{ => peripherals}/ble/pm5/Pm5Constants.js (73%) rename app/{ => peripherals}/ble/pm5/Pm5ControlService.js (100%) rename app/{ => peripherals}/ble/pm5/Pm5RowingService.js (80%) rename app/{ => peripherals}/ble/pm5/characteristic/AdditionalStatus.js (100%) rename app/{ => peripherals}/ble/pm5/characteristic/AdditionalStatus2.js (100%) rename app/{ => peripherals}/ble/pm5/characteristic/AdditionalStrokeData.js (100%) rename app/{ => peripherals}/ble/pm5/characteristic/ControlReceive.js (100%) rename app/{ => peripherals}/ble/pm5/characteristic/ControlTransmit.js (100%) rename app/{ => peripherals}/ble/pm5/characteristic/GeneralStatus.js (100%) rename app/{ => peripherals}/ble/pm5/characteristic/MultiplexedCharacteristic.js (100%) rename app/{ => peripherals}/ble/pm5/characteristic/StrokeData.js (100%) diff --git a/app/ble/common/StaticReadCharacteristic.js b/app/ble/common/StaticReadCharacteristic.js deleted file mode 100644 index ef2248fef6..0000000000 --- a/app/ble/common/StaticReadCharacteristic.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict' - -import bleno from '@abandonware/bleno' - -export default class StaticReadCharacteristic extends bleno.Characteristic { - constructor (uuid, description, value) { - super({ - uuid, - properties: ['read'], - value: Buffer.isBuffer(value) ? value : Buffer.from(value), - descriptors: [ - new bleno.Descriptor({ - uuid: '2901', - value: description - }) - ] - }) - this.uuid = uuid - this.description = description - this.value = Buffer.isBuffer(value) ? value : Buffer.from(value) - } -} diff --git a/app/ble/ftms/IndoorBikeFeatureCharacteristic.js b/app/ble/ftms/IndoorBikeFeatureCharacteristic.js deleted file mode 100644 index 4c01098157..0000000000 --- a/app/ble/ftms/IndoorBikeFeatureCharacteristic.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This implements the Indoor Bike Feature Characteristic as defined by the specification. - Used to inform the Central about the features that the Open Rowing Monitor supports. - Make sure that The Fitness Machine Features and Target Setting Features that are announced here - are supported in IndoorBikeDataCharacteristic and FitnessMachineControlPointCharacteristic. -*/ -import bleno from '@abandonware/bleno' -import log from 'loglevel' - -export default class IndoorBikeDataCharacteristic extends bleno.Characteristic { - constructor (uuid, description, value) { - super({ - // Fitness Machine Feature - uuid: '2ACC', - properties: ['read'], - value: null - }) - } - - onReadRequest (offset, callback) { - // see https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0 for details - // Fitness Machine Features for the IndoorBikeDataCharacteristic - // Cadence Supported (1), Total Distance Supported (2), Expended Energy Supported (9), - // Heart Rate Measurement Supported (10), Elapsed Time Supported (12), Power Measurement Supported (14) - // 00000110 01010110 - // Target Setting Features for the IndoorBikeDataCharacteristic - // none - // 0000000 0000000 - const features = [0x06, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - log.debug('Features of Indoor Bike requested') - callback(this.RESULT_SUCCESS, features.slice(offset, features.length)) - } -} diff --git a/app/ble/ftms/RowerFeatureCharacteristic.js b/app/ble/ftms/RowerFeatureCharacteristic.js deleted file mode 100644 index 04e929e85b..0000000000 --- a/app/ble/ftms/RowerFeatureCharacteristic.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This implements the Rower Feature Characteristic as defined by the specification. - Used to inform the Central about the features that the Open Rowing Monitor supports. - Make sure that The Fitness Machine Features and Target Setting Features that are announced here - are supported in RowerDataCharacteristic and FitnessMachineControlPointCharacteristic. -*/ -import bleno from '@abandonware/bleno' -import log from 'loglevel' - -export default class RowerFeatureCharacteristic extends bleno.Characteristic { - constructor () { - super({ - // Fitness Machine Feature - uuid: '2ACC', - properties: ['read'], - value: null - }) - } - - onReadRequest (offset, callback) { - // see https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0 for details - // Fitness Machine Features for the RowerDataCharacteristic - // Total Distance Supported (2), Pace Supported (5), Expended Energy Supported (9), - // Heart Rate Measurement Supported (10), Elapsed Time Supported (bit 12), - // Power Measurement Supported (14) - // 00100100 01010110 - // Target Setting Features for the RowerDataCharacteristic - // none - // 0000000 0000000 - const features = [0x24, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - log.debug('Features of Rower requested') - callback(this.RESULT_SUCCESS, features.slice(offset, features.length)) - }; -} diff --git a/app/ble/pm5/DeviceInformationService.js b/app/ble/pm5/DeviceInformationService.js deleted file mode 100644 index 9741d54269..0000000000 --- a/app/ble/pm5/DeviceInformationService.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Provides the required Device Information of the PM5 -*/ -import bleno from '@abandonware/bleno' -import { constants, getFullUUID } from './Pm5Constants.js' -import ValueReadCharacteristic from './characteristic/ValueReadCharacteristic.js' - -export default class DeviceInformationService extends bleno.PrimaryService { - constructor () { - super({ - // InformationenService uuid as defined by the PM5 specification - uuid: getFullUUID('0010'), - characteristics: [ - // C2 module number string - new ValueReadCharacteristic(getFullUUID('0011'), constants.model, 'model'), - // C2 serial number string - new ValueReadCharacteristic(getFullUUID('0012'), constants.serial, 'serial'), - // C2 hardware revision string - new ValueReadCharacteristic(getFullUUID('0013'), constants.hardwareRevision, 'hardwareRevision'), - // C2 firmware revision string - new ValueReadCharacteristic(getFullUUID('0014'), constants.firmwareRevision, 'firmwareRevision'), - // C2 manufacturer name string - new ValueReadCharacteristic(getFullUUID('0015'), constants.manufacturer, 'manufacturer'), - // Erg Machine Type - new ValueReadCharacteristic(getFullUUID('0016'), constants.ergMachineType, 'ergMachineType') - ] - }) - } -} diff --git a/app/peripherals/PeripheralConstants.js b/app/peripherals/PeripheralConstants.js new file mode 100644 index 0000000000..3e1e1369b0 --- /dev/null +++ b/app/peripherals/PeripheralConstants.js @@ -0,0 +1,16 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Some PM5 specific constants +*/ +export const PeripheralConstants = { + serial: '123456789', + model: 'PM5', + name: 'PM5 123456789 Row', + hardwareRevision: '907', + // See https://www.concept2.com/service/monitors/pm5/firmware for available versions + // please note: hardware versions exclude a software version, and thus might confuse the client + firmwareRevision: '210', + manufacturer: 'Concept2' +} diff --git a/app/ble/PeripheralManager.js b/app/peripherals/PeripheralManager.js similarity index 91% rename from app/ble/PeripheralManager.js rename to app/peripherals/PeripheralManager.js index c75861fa24..02e54ee410 100644 --- a/app/ble/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -6,12 +6,12 @@ switching between them */ import config from '../tools/ConfigManager.js' -import { createFtmsPeripheral } from './FtmsPeripheral.js' -import { createPm5Peripheral } from './Pm5Peripheral.js' +import { createFtmsPeripheral } from './ble/FtmsPeripheral.js' +import { createPm5Peripheral } from './ble/Pm5Peripheral.js' import log from 'loglevel' import EventEmitter from 'node:events' -import { createCpsPeripheral } from './CpsPeripheral.js' -import { createCscPeripheral } from './CscPeripheral.js' +import { createCpsPeripheral } from './ble/CpsPeripheral.js' +import { createCscPeripheral } from './ble/CscPeripheral.js' const modes = ['FTMS', 'FTMSBIKE', 'PM5', 'CSC', 'CPS'] function createPeripheralManager () { diff --git a/app/ant/AntManager.js b/app/peripherals/ant/AntManager.js similarity index 100% rename from app/ant/AntManager.js rename to app/peripherals/ant/AntManager.js diff --git a/app/ble/BufferBuilder.js b/app/peripherals/ble/BufferBuilder.js similarity index 100% rename from app/ble/BufferBuilder.js rename to app/peripherals/ble/BufferBuilder.js diff --git a/app/ble/BufferBuilder.test.js b/app/peripherals/ble/BufferBuilder.test.js similarity index 100% rename from app/ble/BufferBuilder.test.js rename to app/peripherals/ble/BufferBuilder.test.js diff --git a/app/ble/CentralManager.js b/app/peripherals/ble/CentralManager.js similarity index 100% rename from app/ble/CentralManager.js rename to app/peripherals/ble/CentralManager.js diff --git a/app/ble/CentralService.js b/app/peripherals/ble/CentralService.js similarity index 91% rename from app/ble/CentralService.js rename to app/peripherals/ble/CentralService.js index f8b28a51ea..0183d5db07 100644 --- a/app/ble/CentralService.js +++ b/app/peripherals/ble/CentralService.js @@ -7,7 +7,7 @@ */ import { createCentralManager } from './CentralManager.js' import process from 'process' -import config from '../tools/ConfigManager.js' +import config from '../../tools/ConfigManager.js' import log from 'loglevel' log.setLevel(config.loglevel.default) diff --git a/app/ble/CpsPeripheral.js b/app/peripherals/ble/CpsPeripheral.js similarity index 98% rename from app/ble/CpsPeripheral.js rename to app/peripherals/ble/CpsPeripheral.js index 5d24e47784..89cce8774a 100644 --- a/app/ble/CpsPeripheral.js +++ b/app/peripherals/ble/CpsPeripheral.js @@ -6,7 +6,7 @@ a Cycling Power Profile */ import bleno from '@abandonware/bleno' -import config from '../tools/ConfigManager.js' +import config from '../../tools/ConfigManager.js' import log from 'loglevel' import CyclingPowerService from './cps/CyclingPowerMeterService.js' import DeviceInformationService from './common/DeviceInformationService.js' diff --git a/app/ble/CscPeripheral.js b/app/peripherals/ble/CscPeripheral.js similarity index 98% rename from app/ble/CscPeripheral.js rename to app/peripherals/ble/CscPeripheral.js index 3c8e99cc79..6915d13dbe 100644 --- a/app/ble/CscPeripheral.js +++ b/app/peripherals/ble/CscPeripheral.js @@ -6,7 +6,7 @@ a Cycling Speed and Cadence Profile */ import bleno from '@abandonware/bleno' -import config from '../tools/ConfigManager.js' +import config from '../../tools/ConfigManager.js' import log from 'loglevel' import DeviceInformationService from './common/DeviceInformationService.js' import CyclingSpeedCadenceService from './csc/CyclingSpeedCadenceService.js' diff --git a/app/ble/FtmsPeripheral.js b/app/peripherals/ble/FtmsPeripheral.js similarity index 98% rename from app/ble/FtmsPeripheral.js rename to app/peripherals/ble/FtmsPeripheral.js index 7a54392f9f..c0845c6864 100644 --- a/app/ble/FtmsPeripheral.js +++ b/app/peripherals/ble/FtmsPeripheral.js @@ -13,7 +13,7 @@ */ import bleno from '@abandonware/bleno' import FitnessMachineService from './ftms/FitnessMachineService.js' -import config from '../tools/ConfigManager.js' +import config from '../../tools/ConfigManager.js' import log from 'loglevel' import DeviceInformationService from './common/DeviceInformationService.js' import AdvertisingDataBuilder from './common/AdvertisingDataBuilder.js' diff --git a/app/ble/Pm5Peripheral.js b/app/peripherals/ble/Pm5Peripheral.js similarity index 96% rename from app/ble/Pm5Peripheral.js rename to app/peripherals/ble/Pm5Peripheral.js index 4e905198a6..badfe8e357 100644 --- a/app/ble/Pm5Peripheral.js +++ b/app/peripherals/ble/Pm5Peripheral.js @@ -8,7 +8,7 @@ see: https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf */ import bleno from '@abandonware/bleno' -import { constants } from './pm5/Pm5Constants.js' +import { pm5Constants } from './pm5/Pm5Constants.js' import DeviceInformationService from './pm5/DeviceInformationService.js' import GapService from './pm5/GapService.js' import log from 'loglevel' @@ -16,7 +16,7 @@ import Pm5ControlService from './pm5/Pm5ControlService.js' import Pm5RowingService from './pm5/Pm5RowingService.js' function createPm5Peripheral (controlCallback, options) { - const peripheralName = constants.name + const peripheralName = pm5Constants.name const deviceInformationService = new DeviceInformationService() const gapService = new GapService() const controlService = new Pm5ControlService() diff --git a/app/ble/common/AdvertisingDataBuilder.js b/app/peripherals/ble/common/AdvertisingDataBuilder.js similarity index 100% rename from app/ble/common/AdvertisingDataBuilder.js rename to app/peripherals/ble/common/AdvertisingDataBuilder.js diff --git a/app/ble/common/AdvertisingDataBuilder.test.js b/app/peripherals/ble/common/AdvertisingDataBuilder.test.js similarity index 100% rename from app/ble/common/AdvertisingDataBuilder.test.js rename to app/peripherals/ble/common/AdvertisingDataBuilder.test.js diff --git a/app/peripherals/ble/common/CommonOpCodes.js b/app/peripherals/ble/common/CommonOpCodes.js new file mode 100644 index 0000000000..2c8d16e15d --- /dev/null +++ b/app/peripherals/ble/common/CommonOpCodes.js @@ -0,0 +1,10 @@ +'use-strict' + +export const ResultOpCode = { + reserved: 0x00, + success: 0x01, + opCodeNotSupported: 0x02, + invalidParameter: 0x03, + operationFailed: 0x04, + controlNotPermitted: 0x05 +} diff --git a/app/ble/common/DeviceInformationService.js b/app/peripherals/ble/common/DeviceInformationService.js similarity index 66% rename from app/ble/common/DeviceInformationService.js rename to app/peripherals/ble/common/DeviceInformationService.js index 100f5c4766..c0b2daa3bf 100644 --- a/app/ble/common/DeviceInformationService.js +++ b/app/peripherals/ble/common/DeviceInformationService.js @@ -5,6 +5,7 @@ todo: Could provide some info on the device here, maybe OS, Node version etc... */ import bleno from '@abandonware/bleno' +import { PeripheralConstants } from '../../PeripheralConstants.js' import StaticReadCharacteristic from './StaticReadCharacteristic.js' export default class DeviceInformationService extends bleno.PrimaryService { @@ -13,10 +14,10 @@ export default class DeviceInformationService extends bleno.PrimaryService { // uuid of 'Device Information Service' uuid: '180a', characteristics: [ - new StaticReadCharacteristic('2A24', 'Model Number', 'ORM2'), - new StaticReadCharacteristic('2A25', 'Serial Number', '1234'), - new StaticReadCharacteristic('2A28', 'Software Revision', '2'), - new StaticReadCharacteristic('2A29', 'Manufacturer Name', 'OpenRowingMonitor') + new StaticReadCharacteristic('2A24', 'Model Number', PeripheralConstants.model), + new StaticReadCharacteristic('2A25', 'Serial Number', PeripheralConstants.serial), + new StaticReadCharacteristic('2A28', 'Software Revision', PeripheralConstants.firmwareRevision), + new StaticReadCharacteristic('2A29', 'Manufacturer Name', PeripheralConstants.manufacturer) ] }) } diff --git a/app/ble/common/SensorLocation.js b/app/peripherals/ble/common/SensorLocation.js similarity index 100% rename from app/ble/common/SensorLocation.js rename to app/peripherals/ble/common/SensorLocation.js diff --git a/app/ble/pm5/characteristic/ValueReadCharacteristic.js b/app/peripherals/ble/common/StaticNotifyCharacteristic.js similarity index 57% rename from app/ble/pm5/characteristic/ValueReadCharacteristic.js rename to app/peripherals/ble/common/StaticNotifyCharacteristic.js index 7797cd109f..37b6181874 100644 --- a/app/ble/pm5/characteristic/ValueReadCharacteristic.js +++ b/app/peripherals/ble/common/StaticNotifyCharacteristic.js @@ -1,39 +1,40 @@ 'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - A simple Characteristic that gives read and notify access to a static value - Currently also used as placeholder on a lot of characteristics that are not yet implemented properly -*/ import bleno from '@abandonware/bleno' import log from 'loglevel' -export default class ValueReadCharacteristic extends bleno.Characteristic { - constructor (uuid, value, description) { +export default class StaticNotifyCharacteristic extends bleno.Characteristic { + constructor (uuid, description, value, addRead = false) { super({ uuid, - properties: ['read', 'notify'], - value: null + properties: addRead ? ['read', 'notify'] : ['notify'], + value: null, + descriptors: [ + new bleno.Descriptor({ + uuid: '2901', + value: description + }) + ] }) - this.uuid = uuid - this._value = Buffer.isBuffer(value) ? value : Buffer.from(value) + this._uuid = uuid this._description = description + this._value = Buffer.isBuffer(value) ? value : Buffer.from(value) this._updateValueCallback = null } onReadRequest (offset, callback) { - log.debug(`ValueReadRequest: ${this._description ? this._description : this.uuid}`) + log.debug(`ValueReadRequest: ${this._description ? this._description : this._uuid}`) callback(this.RESULT_SUCCESS, this._value.slice(offset, this._value.length)) } onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`characteristic ${this._description ? this._description : this.uuid} - central subscribed with maxSize: ${maxValueSize}`) + log.debug(`characteristic ${this._description ? this._description : this._uuid} - central subscribed with maxSize: ${maxValueSize}`) this._updateValueCallback = updateValueCallback return this.RESULT_SUCCESS } onUnsubscribe () { - log.debug(`characteristic ${this._description ? this._description : this.uuid} - central unsubscribed`) + log.debug(`characteristic ${this._description ? this._description : this._uuid} - central unsubscribed`) this._updateValueCallback = null return this.RESULT_UNLIKELY_ERROR } diff --git a/app/peripherals/ble/common/StaticReadCharacteristic.js b/app/peripherals/ble/common/StaticReadCharacteristic.js new file mode 100644 index 0000000000..71bfbb8248 --- /dev/null +++ b/app/peripherals/ble/common/StaticReadCharacteristic.js @@ -0,0 +1,36 @@ +'use strict' + +import bleno from '@abandonware/bleno' +import log from 'loglevel' + +export default class StaticReadCharacteristic extends bleno.Characteristic { + constructor (uuid, description, value, addNotify = false) { + super({ + uuid, + properties: addNotify ? ['read', 'notify'] : ['read'], + value: Buffer.isBuffer(value) ? value : Buffer.from(value), + descriptors: [ + new bleno.Descriptor({ + uuid: '2901', + value: description + }) + ] + }) + this._uuid = uuid + this._description = description + this._value = Buffer.isBuffer(value) ? value : Buffer.from(value) + this._updateValueCallback = null + } + + onSubscribe (maxValueSize, updateValueCallback) { + log.debug(`characteristic ${this._description ? this._description : this._uuid} - central subscribed with maxSize: ${maxValueSize}`) + this._updateValueCallback = updateValueCallback + return this.RESULT_SUCCESS + } + + onUnsubscribe () { + log.debug(`characteristic ${this._description ? this._description : this._uuid} - central unsubscribed`) + this._updateValueCallback = null + return this.RESULT_UNLIKELY_ERROR + } +} diff --git a/app/ble/cps/CpsControlPointCharacteristic.js b/app/peripherals/ble/cps/CpsControlPointCharacteristic.js similarity index 100% rename from app/ble/cps/CpsControlPointCharacteristic.js rename to app/peripherals/ble/cps/CpsControlPointCharacteristic.js diff --git a/app/ble/cps/CpsMeasurementCharacteristic.js b/app/peripherals/ble/cps/CpsMeasurementCharacteristic.js similarity index 100% rename from app/ble/cps/CpsMeasurementCharacteristic.js rename to app/peripherals/ble/cps/CpsMeasurementCharacteristic.js diff --git a/app/ble/cps/CyclingPowerMeterService.js b/app/peripherals/ble/cps/CyclingPowerMeterService.js similarity index 100% rename from app/ble/cps/CyclingPowerMeterService.js rename to app/peripherals/ble/cps/CyclingPowerMeterService.js diff --git a/app/ble/csc/CscControlPointCharacteristic.js b/app/peripherals/ble/csc/CscControlPointCharacteristic.js similarity index 100% rename from app/ble/csc/CscControlPointCharacteristic.js rename to app/peripherals/ble/csc/CscControlPointCharacteristic.js diff --git a/app/ble/csc/CscMeasurementCharacteristic.js b/app/peripherals/ble/csc/CscMeasurementCharacteristic.js similarity index 100% rename from app/ble/csc/CscMeasurementCharacteristic.js rename to app/peripherals/ble/csc/CscMeasurementCharacteristic.js diff --git a/app/ble/csc/CyclingSpeedCadenceService.js b/app/peripherals/ble/csc/CyclingSpeedCadenceService.js similarity index 100% rename from app/ble/csc/CyclingSpeedCadenceService.js rename to app/peripherals/ble/csc/CyclingSpeedCadenceService.js diff --git a/app/ble/ftms/FitnessMachineControlPointCharacteristic.js b/app/peripherals/ble/ftms/FitnessMachineControlPointCharacteristic.js similarity index 84% rename from app/ble/ftms/FitnessMachineControlPointCharacteristic.js rename to app/peripherals/ble/ftms/FitnessMachineControlPointCharacteristic.js index 7d96096f12..9d52b3c207 100644 --- a/app/ble/ftms/FitnessMachineControlPointCharacteristic.js +++ b/app/peripherals/ble/ftms/FitnessMachineControlPointCharacteristic.js @@ -10,6 +10,7 @@ */ import bleno from '@abandonware/bleno' import log from 'loglevel' +import { ResultOpCode } from '../common/CommonOpCodes.js' // see https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0 for details const ControlPointOpCode = { @@ -37,15 +38,6 @@ const ControlPointOpCode = { responseCode: 0x80 } -const ResultCode = { - reserved: 0x00, - success: 0x01, - opCodeNotSupported: 0x02, - invalidParameter: 0x03, - operationFailed: 0x04, - controlNotPermitted: 0x05 -} - export default class FitnessMachineControlPointCharacteristic extends bleno.Characteristic { constructor (controlPointCallback) { super({ @@ -70,12 +62,12 @@ export default class FitnessMachineControlPointCharacteristic extends bleno.Char if (this.controlPointCallback({ name: 'requestControl' })) { log.debug('requestControl sucessful') this.controlled = true - callback(this.buildResponse(opCode, ResultCode.success)) + callback(this.buildResponse(opCode, ResultOpCode.success)) } else { - callback(this.buildResponse(opCode, ResultCode.operationFailed)) + callback(this.buildResponse(opCode, ResultOpCode.operationFailed)) } } else { - callback(this.buildResponse(opCode, ResultCode.controlNotPermitted)) + callback(this.buildResponse(opCode, ResultOpCode.controlNotPermitted)) } break @@ -109,30 +101,30 @@ export default class FitnessMachineControlPointCharacteristic extends bleno.Char const crr = data.readUInt8(5) * 0.0001 const cw = data.readUInt8(6) * 0.01 if (this.controlPointCallback({ name: 'setIndoorBikeSimulationParameters', value: { windspeed, grade, crr, cw } })) { - callback(this.buildResponse(opCode, ResultCode.success)) + callback(this.buildResponse(opCode, ResultOpCode.success)) } else { - callback(this.buildResponse(opCode, ResultCode.operationFailed)) + callback(this.buildResponse(opCode, ResultOpCode.operationFailed)) } break } default: log.info(`opCode ${opCode} is not supported`) - callback(this.buildResponse(opCode, ResultCode.opCodeNotSupported)) + callback(this.buildResponse(opCode, ResultOpCode.opCodeNotSupported)) } } handleSimpleCommand (opCode, opName, callback) { if (this.controlled) { if (this.controlPointCallback({ name: opName })) { - const response = this.buildResponse(opCode, ResultCode.success) + const response = this.buildResponse(opCode, ResultOpCode.success) callback(response) } else { - callback(this.buildResponse(opCode, ResultCode.operationFailed)) + callback(this.buildResponse(opCode, ResultOpCode.operationFailed)) } } else { log.info(`initating command '${opName}' requires 'requestControl'`) - callback(this.buildResponse(opCode, ResultCode.controlNotPermitted)) + callback(this.buildResponse(opCode, ResultOpCode.controlNotPermitted)) } } diff --git a/app/ble/ftms/FitnessMachineService.js b/app/peripherals/ble/ftms/FitnessMachineService.js similarity index 59% rename from app/ble/ftms/FitnessMachineService.js rename to app/peripherals/ble/ftms/FitnessMachineService.js index d4703742b4..6a411fe355 100644 --- a/app/ble/ftms/FitnessMachineService.js +++ b/app/peripherals/ble/ftms/FitnessMachineService.js @@ -18,23 +18,25 @@ import bleno from '@abandonware/bleno' import RowerDataCharacteristic from './RowerDataCharacteristic.js' -import RowerFeatureCharacteristic from './RowerFeatureCharacteristic.js' import IndoorBikeDataCharacteristic from './IndoorBikeDataCharacteristic.js' -import IndoorBikeFeatureCharacteristic from './IndoorBikeFeatureCharacteristic.js' import FitnessMachineControlPointCharacteristic from './FitnessMachineControlPointCharacteristic.js' import FitnessMachineStatusCharacteristic from './FitnessMachineStatusCharacteristic.js' +import StaticReadCharacteristic from '../common/StaticReadCharacteristic.js' +import BufferBuilder from '../BufferBuilder.js' export default class FitnessMachineService extends bleno.PrimaryService { constructor (options, controlPointCallback) { const simulateIndoorBike = options?.simulateIndoorBike === true const dataCharacteristic = simulateIndoorBike ? new IndoorBikeDataCharacteristic() : new RowerDataCharacteristic() - const featureCharacteristic = simulateIndoorBike ? new IndoorBikeFeatureCharacteristic() : new RowerFeatureCharacteristic() const statusCharacteristic = new FitnessMachineStatusCharacteristic() + const ftmsFeaturesBuffer = new BufferBuilder() + ftmsFeaturesBuffer.writeUInt16LE(featuresFlag) + super({ // Fitness Machine uuid: '1826', characteristics: [ - featureCharacteristic, + new StaticReadCharacteristic('2ACC', 'FTMS Feature', ftmsFeaturesBuffer.getBuffer()), dataCharacteristic, new FitnessMachineControlPointCharacteristic(controlPointCallback), statusCharacteristic @@ -52,3 +54,25 @@ export default class FitnessMachineService extends bleno.PrimaryService { this.statusCharacteristic.notify(event) } } + +export const FtmsBikeFeaturesFlags = { + averageSpeedSupported: (0x01 << 0), + cadenceSupported: (0x01 << 1), + totalDistanceSupported: (0x01 << 2), + inclinationSupported: (0x01 << 3), + elevationGainSupported: (0x01 << 4), + paceSupported: (0x01 << 5), + stepCountSupported: (0x01 << 6), + resistanceLevelSupported: (0x01 << 7), + strideCountSupported: (0x01 << 8), + expendedEnergySupported: (0x01 << 9), + heartRateMeasurementSupported: (0x01 << 10), + metabolicEquivalentSupported: (0x01 << 11), + elapsedTimeSupported: (0x01 << 12), + remainingTimeSupported: (0x01 << 13), + powerMeasurementSupported: (0x01 << 14), + forceOnBeltAndPowerOutputSupported: (0x01 << 15), + userDataRetentionSupported: (0x01 << 16) +} + +export const featuresFlag = FtmsBikeFeaturesFlags.cadenceSupported | FtmsBikeFeaturesFlags.totalDistanceSupported | FtmsBikeFeaturesFlags.paceSupported | FtmsBikeFeaturesFlags.expendedEnergySupported | FtmsBikeFeaturesFlags.heartRateMeasurementSupported | FtmsBikeFeaturesFlags.elapsedTimeSupported | FtmsBikeFeaturesFlags.powerMeasurementSupported diff --git a/app/ble/ftms/FitnessMachineStatusCharacteristic.js b/app/peripherals/ble/ftms/FitnessMachineStatusCharacteristic.js similarity index 100% rename from app/ble/ftms/FitnessMachineStatusCharacteristic.js rename to app/peripherals/ble/ftms/FitnessMachineStatusCharacteristic.js diff --git a/app/ble/ftms/IndoorBikeDataCharacteristic.js b/app/peripherals/ble/ftms/IndoorBikeDataCharacteristic.js similarity index 82% rename from app/ble/ftms/IndoorBikeDataCharacteristic.js rename to app/peripherals/ble/ftms/IndoorBikeDataCharacteristic.js index 9a1b71c017..f33e05e729 100644 --- a/app/ble/ftms/IndoorBikeDataCharacteristic.js +++ b/app/peripherals/ble/ftms/IndoorBikeDataCharacteristic.js @@ -60,10 +60,9 @@ export default class IndoorBikeDataCharacteristic extends bleno.Characteristic { // Field flags as defined in the Bluetooth Documentation // Instantaneous speed (default), Instantaneous Cadence (2), Total Distance (4), // Instantaneous Power (6), Total / Expended Energy (8), Heart Rate (9), Elapsed Time (11) - // 01010100 - bufferBuilder.writeUInt8(0x54) // 00001011 - bufferBuilder.writeUInt8(0x0B) + // 01010100 + bufferBuilder.writeUInt16LE(measurementFlag) // see https://www.bluetooth.com/specifications/specs/gatt-specification-supplement-3/ // for some of the data types @@ -98,3 +97,21 @@ export default class IndoorBikeDataCharacteristic extends bleno.Characteristic { return this.RESULT_SUCCESS } } + +export const RowingMeasurementFlags = { + moreDataPresent: (0x01 << 0), + averageSpeedPresent: (0x01 << 1), + instantaneousCadencePresent: (0x01 << 2), + averageCadencePresent: (0x01 << 3), + totalDistancePresent: (0x01 << 4), + resistanceLevelPresent: (0x01 << 5), + instantaneousPowerPresent: (0x01 << 6), + averagePowerPresent: (0x01 << 7), + expendedEnergyPresent: (0x01 << 8), + heartRatePresent: (0x01 << 9), + metabolicEquivalentPresent: (0x01 << 10), + elapsedTimePresent: (0x01 << 11), + remainingTimePresent: (0x01 << 12) +} + +export const measurementFlag = RowingMeasurementFlags.instantaneousCadencePresent | RowingMeasurementFlags.totalDistancePresent | RowingMeasurementFlags.instantaneousPowerPresent | RowingMeasurementFlags.expendedEnergyPresent | RowingMeasurementFlags.heartRatePresent | RowingMeasurementFlags.elapsedTimePresent diff --git a/app/ble/ftms/RowerDataCharacteristic.js b/app/peripherals/ble/ftms/RowerDataCharacteristic.js similarity index 82% rename from app/ble/ftms/RowerDataCharacteristic.js rename to app/peripherals/ble/ftms/RowerDataCharacteristic.js index a3a376266e..81df3f6a1d 100644 --- a/app/ble/ftms/RowerDataCharacteristic.js +++ b/app/peripherals/ble/ftms/RowerDataCharacteristic.js @@ -55,9 +55,8 @@ export default class RowerDataCharacteristic extends bleno.Characteristic { // todo: might add: Average Stroke Rate (1), Average Pace (4), Average Power (6) // Remaining Time (12) // 00101100 - bufferBuilder.writeUInt8(0x2c) + bufferBuilder.writeUInt16LE(measurementFlag) // 00001011 - bufferBuilder.writeUInt8(0x0B) // see https://www.bluetooth.com/specifications/specs/gatt-specification-supplement-3/ // for some of the data types @@ -98,3 +97,21 @@ export default class RowerDataCharacteristic extends bleno.Characteristic { return this.RESULT_SUCCESS } } + +export const RowingMeasurementFlags = { + moreDataPresent: (0x01 << 0), + averageStrokeRatePresent: (0x01 << 1), + totalDistancePresent: (0x01 << 2), + instantaneousPacePresent: (0x01 << 3), + averagePacePresent: (0x01 << 4), + instantaneousPowerPresent: (0x01 << 5), + averagePowerPresent: (0x01 << 6), + resistanceLevelPresent: (0x01 << 7), + expendedEnergyPresent: (0x01 << 8), + heartRatePresent: (0x01 << 9), + metabolicEquivalentPresent: (0x01 << 10), + elapsedTimePresent: (0x01 << 11), + remainingTimePresent: (0x01 << 12) +} + +export const measurementFlag = RowingMeasurementFlags.totalDistancePresent | RowingMeasurementFlags.instantaneousPacePresent | RowingMeasurementFlags.instantaneousPowerPresent | RowingMeasurementFlags.expendedEnergyPresent | RowingMeasurementFlags.heartRatePresent | RowingMeasurementFlags.elapsedTimePresent diff --git a/app/peripherals/ble/pm5/DeviceInformationService.js b/app/peripherals/ble/pm5/DeviceInformationService.js new file mode 100644 index 0000000000..42a25efaba --- /dev/null +++ b/app/peripherals/ble/pm5/DeviceInformationService.js @@ -0,0 +1,32 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Provides the required Device Information of the PM5 +*/ +import bleno from '@abandonware/bleno' +import StaticNotifyCharacteristic from '../common/StaticNotifyCharacteristic.js' +import { getFullUUID, pm5Constants } from './Pm5Constants.js' + +export default class DeviceInformationService extends bleno.PrimaryService { + constructor () { + super({ + // InformationenService uuid as defined by the PM5 specification + uuid: getFullUUID('0010'), + characteristics: [ + // C2 module number string + new StaticNotifyCharacteristic(getFullUUID('0011'), 'model', 'PM5', true), + // C2 serial number string + new StaticNotifyCharacteristic(getFullUUID('0012'), 'serial', pm5Constants.serial, true), + // C2 hardware revision string + new StaticNotifyCharacteristic(getFullUUID('0013'), 'hardwareRevision', pm5Constants.hardwareRevision, true), + // C2 firmware revision string + new StaticNotifyCharacteristic(getFullUUID('0014'), 'firmwareRevision', pm5Constants.firmwareRevision, true), + // C2 manufacturer name string + new StaticNotifyCharacteristic(getFullUUID('0015'), 'manufacturer', pm5Constants.manufacturer, true), + // Erg Machine Type + new StaticNotifyCharacteristic(getFullUUID('0016'), 'ergMachineType', pm5Constants.ergMachineType, true) + ] + }) + } +} diff --git a/app/ble/pm5/GapService.js b/app/peripherals/ble/pm5/GapService.js similarity index 52% rename from app/ble/pm5/GapService.js rename to app/peripherals/ble/pm5/GapService.js index f90c42c8b0..168cdd5116 100644 --- a/app/ble/pm5/GapService.js +++ b/app/peripherals/ble/pm5/GapService.js @@ -6,8 +6,8 @@ todo: not sure if this is correct, the normal GAP service has 0x1800 */ import bleno from '@abandonware/bleno' -import { constants, getFullUUID } from './Pm5Constants.js' -import ValueReadCharacteristic from './characteristic/ValueReadCharacteristic.js' +import StaticNotifyCharacteristic from '../common/StaticNotifyCharacteristic.js' +import { getFullUUID, pm5Constants } from './Pm5Constants.js' export default class GapService extends bleno.PrimaryService { constructor () { @@ -16,15 +16,15 @@ export default class GapService extends bleno.PrimaryService { uuid: getFullUUID('0000'), characteristics: [ // GAP device name - new ValueReadCharacteristic('2A00', constants.name), + new StaticNotifyCharacteristic('2A00', undefined, pm5Constants.name, true), // GAP appearance - new ValueReadCharacteristic('2A01', [0x00, 0x00]), + new StaticNotifyCharacteristic('2A01', undefined, [0x00, 0x00], true), // GAP peripheral privacy - new ValueReadCharacteristic('2A02', [0x00]), + new StaticNotifyCharacteristic('2A02', undefined, [0x00], true), // GAP reconnect address - new ValueReadCharacteristic('2A03', '00:00:00:00:00:00'), + new StaticNotifyCharacteristic('2A03', undefined, '00:00:00:00:00:00', true), // Peripheral preferred connection parameters - new ValueReadCharacteristic('2A04', [0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0xE8, 0x03]) + new StaticNotifyCharacteristic('2A04', undefined, [0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0xE8, 0x03], true) ] }) } diff --git a/app/ble/pm5/Pm5Constants.js b/app/peripherals/ble/pm5/Pm5Constants.js similarity index 73% rename from app/ble/pm5/Pm5Constants.js rename to app/peripherals/ble/pm5/Pm5Constants.js index e4c352d4f5..c71762126f 100644 --- a/app/ble/pm5/Pm5Constants.js +++ b/app/peripherals/ble/pm5/Pm5Constants.js @@ -1,18 +1,16 @@ 'use strict' + +import { PeripheralConstants } from '../../PeripheralConstants.js' + /* Open Rowing Monitor, https://github.com/laberning/openrowingmonitor Some PM5 specific constants */ -const constants = { - serial: '123456789', - model: 'PM5', - name: 'PM5 123456789 Row', - hardwareRevision: '907', +const pm5Constants = { + ...PeripheralConstants, // See https://www.concept2.com/service/monitors/pm5/firmware for available versions // please note: hardware versions exclude a software version, and thus might confuse the client - firmwareRevision: '210', - manufacturer: 'Concept2', ergMachineType: [0x05] } @@ -23,5 +21,5 @@ function getFullUUID (uuid) { export { getFullUUID, - constants + pm5Constants } diff --git a/app/ble/pm5/Pm5ControlService.js b/app/peripherals/ble/pm5/Pm5ControlService.js similarity index 100% rename from app/ble/pm5/Pm5ControlService.js rename to app/peripherals/ble/pm5/Pm5ControlService.js diff --git a/app/ble/pm5/Pm5RowingService.js b/app/peripherals/ble/pm5/Pm5RowingService.js similarity index 80% rename from app/ble/pm5/Pm5RowingService.js rename to app/peripherals/ble/pm5/Pm5RowingService.js index 8e00cf5f1d..e0fc3842f7 100644 --- a/app/ble/pm5/Pm5RowingService.js +++ b/app/peripherals/ble/pm5/Pm5RowingService.js @@ -20,13 +20,13 @@ */ import bleno from '@abandonware/bleno' import { getFullUUID } from './Pm5Constants.js' -import ValueReadCharacteristic from './characteristic/ValueReadCharacteristic.js' import MultiplexedCharacteristic from './characteristic/MultiplexedCharacteristic.js' import GeneralStatus from './characteristic/GeneralStatus.js' import AdditionalStatus from './characteristic/AdditionalStatus.js' import AdditionalStatus2 from './characteristic/AdditionalStatus2.js' import AdditionalStrokeData from './characteristic/AdditionalStrokeData.js' import StrokeData from './characteristic/StrokeData.js' +import StaticNotifyCharacteristic from '../common/StaticNotifyCharacteristic.js' export default class PM5RowingService extends bleno.PrimaryService { constructor () { @@ -46,23 +46,23 @@ export default class PM5RowingService extends bleno.PrimaryService { // C2 rowing additional status 2 additionalStatus2, // C2 rowing general status and additional status samplerate - new ValueReadCharacteristic(getFullUUID('0034'), 'samplerate', 'samplerate'), + new StaticNotifyCharacteristic(getFullUUID('0034'), 'samplerate', 'samplerate', true), // C2 rowing stroke data strokeData, // C2 rowing additional stroke data additionalStrokeData, // C2 rowing split/interval data - new ValueReadCharacteristic(getFullUUID('0037'), 'split data', 'split data'), + new StaticNotifyCharacteristic(getFullUUID('0037'), 'split data', 'split data', true), // C2 rowing additional split/interval data - new ValueReadCharacteristic(getFullUUID('0038'), 'additional split data', 'additional split data'), + new StaticNotifyCharacteristic(getFullUUID('0038'), 'additional split data', 'additional split data', true), // C2 rowing end of workout summary data - new ValueReadCharacteristic(getFullUUID('0039'), 'workout summary', 'workout summary'), + new StaticNotifyCharacteristic(getFullUUID('0039'), 'workout summary', 'workout summary', true), // C2 rowing end of workout additional summary data - new ValueReadCharacteristic(getFullUUID('003A'), 'additional workout summary', 'additional workout summary'), + new StaticNotifyCharacteristic(getFullUUID('003A'), 'additional workout summary', 'additional workout summary', true), // C2 rowing heart rate belt information - new ValueReadCharacteristic(getFullUUID('003B'), 'heart rate belt information', 'heart rate belt information'), + new StaticNotifyCharacteristic(getFullUUID('003B'), 'heart rate belt information', 'heart rate belt information', true), // C2 force curve data - new ValueReadCharacteristic(getFullUUID('003D'), 'force curve data', 'force curve data'), + new StaticNotifyCharacteristic(getFullUUID('003D'), 'force curve data', 'force curve data', true), // C2 multiplexed information multiplexedCharacteristic ] diff --git a/app/ble/pm5/characteristic/AdditionalStatus.js b/app/peripherals/ble/pm5/characteristic/AdditionalStatus.js similarity index 100% rename from app/ble/pm5/characteristic/AdditionalStatus.js rename to app/peripherals/ble/pm5/characteristic/AdditionalStatus.js diff --git a/app/ble/pm5/characteristic/AdditionalStatus2.js b/app/peripherals/ble/pm5/characteristic/AdditionalStatus2.js similarity index 100% rename from app/ble/pm5/characteristic/AdditionalStatus2.js rename to app/peripherals/ble/pm5/characteristic/AdditionalStatus2.js diff --git a/app/ble/pm5/characteristic/AdditionalStrokeData.js b/app/peripherals/ble/pm5/characteristic/AdditionalStrokeData.js similarity index 100% rename from app/ble/pm5/characteristic/AdditionalStrokeData.js rename to app/peripherals/ble/pm5/characteristic/AdditionalStrokeData.js diff --git a/app/ble/pm5/characteristic/ControlReceive.js b/app/peripherals/ble/pm5/characteristic/ControlReceive.js similarity index 100% rename from app/ble/pm5/characteristic/ControlReceive.js rename to app/peripherals/ble/pm5/characteristic/ControlReceive.js diff --git a/app/ble/pm5/characteristic/ControlTransmit.js b/app/peripherals/ble/pm5/characteristic/ControlTransmit.js similarity index 100% rename from app/ble/pm5/characteristic/ControlTransmit.js rename to app/peripherals/ble/pm5/characteristic/ControlTransmit.js diff --git a/app/ble/pm5/characteristic/GeneralStatus.js b/app/peripherals/ble/pm5/characteristic/GeneralStatus.js similarity index 100% rename from app/ble/pm5/characteristic/GeneralStatus.js rename to app/peripherals/ble/pm5/characteristic/GeneralStatus.js diff --git a/app/ble/pm5/characteristic/MultiplexedCharacteristic.js b/app/peripherals/ble/pm5/characteristic/MultiplexedCharacteristic.js similarity index 100% rename from app/ble/pm5/characteristic/MultiplexedCharacteristic.js rename to app/peripherals/ble/pm5/characteristic/MultiplexedCharacteristic.js diff --git a/app/ble/pm5/characteristic/StrokeData.js b/app/peripherals/ble/pm5/characteristic/StrokeData.js similarity index 100% rename from app/ble/pm5/characteristic/StrokeData.js rename to app/peripherals/ble/pm5/characteristic/StrokeData.js diff --git a/app/server.js b/app/server.js index ecdd20a75c..965f62e937 100644 --- a/app/server.js +++ b/app/server.js @@ -13,12 +13,12 @@ import log from 'loglevel' import config from './tools/ConfigManager.js' import { createRowingStatistics } from './engine/RowingStatistics.js' import { createWebServer } from './WebServer.js' -import { createPeripheralManager } from './ble/PeripheralManager.js' -import { createAntManager } from './ant/AntManager.js' +import { createPeripheralManager } from './peripherals/PeripheralManager.js' // eslint-disable-next-line no-unused-vars import { replayRowingSession } from './tools/RowingRecorder.js' import { createWorkoutRecorder } from './engine/WorkoutRecorder.js' import { createWorkoutUploader } from './engine/WorkoutUploader.js' +import { createAntManager } from './peripherals/ant/AntManager.js' const exec = promisify(child_process.exec) // set the log levels @@ -193,7 +193,7 @@ rowingStatistics.on('rowingStopped', (metrics) => { }) if (config.heartrateMonitorBLE) { - const bleCentralService = child_process.fork('./app/ble/CentralService.js') + const bleCentralService = child_process.fork('./app/peripherals/ble/CentralService.js') bleCentralService.on('message', (heartrateMeasurement) => { rowingStatistics.handleHeartrateMeasurement(heartrateMeasurement) }) From 7ef338d85627d1f95ab33f2f52e5841403f5c966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Mon, 12 Dec 2022 23:20:39 +0100 Subject: [PATCH 046/209] Refactor heart rate peripherals Refactor ANT manager to be a central class managing the ANT stick state. This state could be used for future implementation of other ANT profiles and the peripheralManager should be responsible for creating once needed --- app/engine/RowingStatistics.js | 2 +- app/peripherals/PeripheralManager.js | 24 ++++++++ app/peripherals/ant/AntManager.js | 57 +++++-------------- app/peripherals/ant/HrmPeripheral.js | 51 +++++++++++++++++ .../{CentralService.js => HrmPeripheral.js} | 8 +-- .../HeartRateManager.js} | 32 +++++------ app/server.js | 17 +++--- 7 files changed, 118 insertions(+), 73 deletions(-) create mode 100644 app/peripherals/ant/HrmPeripheral.js rename app/peripherals/ble/{CentralService.js => HrmPeripheral.js} (60%) rename app/peripherals/ble/{CentralManager.js => hrm/HeartRateManager.js} (83%) diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index 616b6cbb8f..f6e2ff8f7d 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -417,7 +417,7 @@ function createRowingStatistics (config) { } return Object.assign(emitter, { - handleHeartrateMeasurement, + handleHeartRateMeasurement: handleHeartrateMeasurement, handleRotationImpulse, setIntervalParameters, pause: pauseTraining, diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js index 02e54ee410..f518bc7a90 100644 --- a/app/peripherals/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -12,6 +12,9 @@ import log from 'loglevel' import EventEmitter from 'node:events' import { createCpsPeripheral } from './ble/CpsPeripheral.js' import { createCscPeripheral } from './ble/CscPeripheral.js' +import child_process from 'child_process' +import AntManager from './ant/AntManager.js' +import { createAntHrmPeripheral } from './ant/HrmPeripheral.js' const modes = ['FTMS', 'FTMSBIKE', 'PM5', 'CSC', 'CPS'] function createPeripheralManager () { @@ -94,11 +97,32 @@ function createPeripheralManager () { }) } + function startBleHeartRateService () { + const hrmPeripheral = child_process.fork('./app/peripherals/ble/HrmPeripheral.js') + hrmPeripheral.on('message', (heartRateMeasurement) => { + emitter.emit('heartRateBleMeasurement', heartRateMeasurement) + }) + } + + function startAntHeartRateService () { + if (!this._antManager) { + this._antManager = new AntManager() + } + + const antHrm = createAntHrmPeripheral(this._antManager) + + antHrm.on('heartRateMeasurement', (heartRateMeasurement) => { + emitter.emit('heartRateAntMeasurement', heartRateMeasurement) + }) + } + function controlCallback (event) { emitter.emit('control', event) } return Object.assign(emitter, { + startAntHeartRateService, + startBleHeartRateService, getPeripheral, getPeripheralMode, switchPeripheralMode, diff --git a/app/peripherals/ant/AntManager.js b/app/peripherals/ant/AntManager.js index 8a6bcec4d5..3961477d73 100644 --- a/app/peripherals/ant/AntManager.js +++ b/app/peripherals/ant/AntManager.js @@ -9,55 +9,26 @@ - Garmin USB or USB2 ANT+ or an off-brand clone of it (ID 0x1008) - Garmin mini ANT+ (ID 0x1009) */ -import log from 'loglevel' import Ant from 'ant-plus' -import EventEmitter from 'node:events' -function createAntManager () { - const emitter = new EventEmitter() - const antStick = new Ant.GarminStick2() - const antStick3 = new Ant.GarminStick3() +export default class AntManager { + constructor () { // it seems that we have to use two separate heart rate sensors to support both old and new // ant sticks, since the library requires them to be bound before open is called - const heartrateSensor = new Ant.HeartRateSensor(antStick) - const heartrateSensor3 = new Ant.HeartRateSensor(antStick3) - - heartrateSensor.on('hbData', (data) => { - emitter.emit('heartrateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel: data.BatteryLevel }) - }) - - heartrateSensor3.on('hbData', (data) => { - emitter.emit('heartrateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel: data.BatteryLevel }) - }) - - antStick.on('startup', () => { - log.info('classic ANT+ stick found') - heartrateSensor.attach(0, 0) - }) - - antStick3.on('startup', () => { - log.info('mini ANT+ stick found') - heartrateSensor3.attach(0, 0) - }) - - antStick.on('shutdown', () => { - log.info('classic ANT+ stick lost') - }) - - antStick3.on('shutdown', () => { - log.info('mini ANT+ stick lost') - }) - - if (!antStick.open()) { - log.debug('classic ANT+ stick NOT found') + this._stick = new Ant.GarminStick3() // 0fcf:1009 + if (!this._stick.is_present()) { + this._stick = new Ant.GarminStick2() // 0fcf:1008 + } } - if (!antStick3.open()) { - log.debug('mini ANT+ stick NOT found') + openAntStick () { + if (!this._stick.open()) { + return false + } + return this._stick } - return Object.assign(emitter, { - }) + getAntStick () { + return this._stick + } } - -export { createAntManager } diff --git a/app/peripherals/ant/HrmPeripheral.js b/app/peripherals/ant/HrmPeripheral.js new file mode 100644 index 0000000000..4f6883d67a --- /dev/null +++ b/app/peripherals/ant/HrmPeripheral.js @@ -0,0 +1,51 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are required for + a Cycling Speed and Cadence Profile +*/ +import EventEmitter from 'node:events' +import Ant from 'ant-plus' +import log from 'loglevel' + +function createAntHrmPeripheral (antManager) { + const emitter = new EventEmitter() + const antStick = antManager.getAntStick() + + const heartRateSensor = new Ant.HeartRateSensor(antStick) + + heartRateSensor.on('hbData', (data) => { + emitter.emit('heartRateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel: data.BatteryLevel }) + }) + + antStick.on('startup', () => { + log.info('ANT+ stick found') + heartRateSensor.attach(0, 0) + }) + + antStick.on('shutdown', () => { + log.info('classic ANT+ stick lost') + }) + + if (!antManager.openAntStick()) { + throw new Error('Error opening Ant Stick') + } + + function destroy () { + return new Promise((resolve) => { + heartRateSensor.detach() + heartRateSensor.on('detached', () => { + antStick.removeAllListeners() + heartRateSensor.removeAllListeners() + resolve() + }) + }) + } + + return Object.assign(emitter, { + destroy + }) +} + +export { createAntHrmPeripheral } diff --git a/app/peripherals/ble/CentralService.js b/app/peripherals/ble/HrmPeripheral.js similarity index 60% rename from app/peripherals/ble/CentralService.js rename to app/peripherals/ble/HrmPeripheral.js index 0183d5db07..1916c700d6 100644 --- a/app/peripherals/ble/CentralService.js +++ b/app/peripherals/ble/HrmPeripheral.js @@ -5,14 +5,14 @@ Starts the central manager in a forked thread since noble does not like to run in the same thread as bleno */ -import { createCentralManager } from './CentralManager.js' import process from 'process' import config from '../../tools/ConfigManager.js' import log from 'loglevel' +import { createHeartRateManager } from './hrm/HeartRateManager.js' log.setLevel(config.loglevel.default) -const centralManager = createCentralManager() +const heartRateManager = createHeartRateManager() -centralManager.on('heartrateMeasurement', (heartrateMeasurement) => { - process.send(heartrateMeasurement) +heartRateManager.on('heartRateMeasurement', (heartRateMeasurement) => { + process.send(heartRateMeasurement) }) diff --git a/app/peripherals/ble/CentralManager.js b/app/peripherals/ble/hrm/HeartRateManager.js similarity index 83% rename from app/peripherals/ble/CentralManager.js rename to app/peripherals/ble/hrm/HeartRateManager.js index c21c340447..ae92e208b4 100644 --- a/app/peripherals/ble/CentralManager.js +++ b/app/peripherals/ble/hrm/HeartRateManager.js @@ -49,7 +49,7 @@ NobleBindings.prototype.onDisconnComplete = function (handle, reason) { const noble = new Noble(new NobleBindings()) // END of noble patch -function createCentralManager () { +function createHeartRateManager () { const emitter = new EventEmitter() let batteryLevel @@ -64,10 +64,10 @@ function createCentralManager () { noble.on('discover', (peripheral) => { noble.stopScanning() - connectHeartratePeripheral(peripheral) + connectHeartRatePeripheral(peripheral) }) - function connectHeartratePeripheral (peripheral) { + function connectHeartRatePeripheral (peripheral) { // connect to the heart rate sensor peripheral.connect((error) => { if (error) { @@ -75,7 +75,7 @@ function createCentralManager () { return } log.info(`heart rate peripheral connected, name: '${peripheral.advertisement?.localName}', id: ${peripheral.id}`) - subscribeToHeartrateMeasurement(peripheral) + subscribeToHeartRateMeasurement(peripheral) }) peripheral.once('disconnect', () => { @@ -87,33 +87,33 @@ function createCentralManager () { } // see https://www.bluetooth.com/specifications/specs/heart-rate-service-1-0/ - function subscribeToHeartrateMeasurement (peripheral) { - const heartrateMeasurementUUID = '2a37' + function subscribeToHeartRateMeasurement (peripheral) { + const heartRateMeasurementUUID = '2a37' const batteryLevelUUID = '2a19' - peripheral.discoverSomeServicesAndCharacteristics([], [heartrateMeasurementUUID, batteryLevelUUID], + peripheral.discoverSomeServicesAndCharacteristics([], [heartRateMeasurementUUID, batteryLevelUUID], (error, services, characteristics) => { if (error) { log.error(error) return } - const heartrateMeasurementCharacteristic = characteristics.find( - characteristic => characteristic.uuid === heartrateMeasurementUUID + const heartRateMeasurementCharacteristic = characteristics.find( + characteristic => characteristic.uuid === heartRateMeasurementUUID ) const batteryLevelCharacteristic = characteristics.find( characteristic => characteristic.uuid === batteryLevelUUID ) - if (heartrateMeasurementCharacteristic !== undefined) { - heartrateMeasurementCharacteristic.notify(true, (error) => { + if (heartRateMeasurementCharacteristic !== undefined) { + heartRateMeasurementCharacteristic.notify(true, (error) => { if (error) { log.error(error) return } - heartrateMeasurementCharacteristic.on('data', (data, isNotification) => { + heartRateMeasurementCharacteristic.on('data', (data, isNotification) => { const buffer = Buffer.from(data) const flags = buffer.readUInt8(0) // bits of the feature flag: @@ -121,7 +121,7 @@ function createCentralManager () { // 1 + 2: Sensor Contact Status // 3: Energy Expended Status // 4: RR-Interval - const heartrateUint16LE = flags & 0b1 + const heartRateUint16LE = flags & 0b1 // from the specs: // While most human applications require support for only 255 bpm or less, special @@ -129,8 +129,8 @@ function createCentralManager () { // If the Heart Rate Measurement Value is less than or equal to 255 bpm a UINT8 format // should be used for power savings. // If the Heart Rate Measurement Value exceeds 255 bpm a UINT16 format shall be used. - const heartrate = heartrateUint16LE ? buffer.readUInt16LE(1) : buffer.readUInt8(1) - emitter.emit('heartrateMeasurement', { heartrate, batteryLevel }) + const heartrate = heartRateUint16LE ? buffer.readUInt16LE(1) : buffer.readUInt8(1) + emitter.emit('heartRateMeasurement', { heartrate, batteryLevel }) }) }) } @@ -155,4 +155,4 @@ function createCentralManager () { }) } -export { createCentralManager } +export { createHeartRateManager } diff --git a/app/server.js b/app/server.js index 965f62e937..32e449c4e9 100644 --- a/app/server.js +++ b/app/server.js @@ -18,7 +18,6 @@ import { createPeripheralManager } from './peripherals/PeripheralManager.js' import { replayRowingSession } from './tools/RowingRecorder.js' import { createWorkoutRecorder } from './engine/WorkoutRecorder.js' import { createWorkoutUploader } from './engine/WorkoutUploader.js' -import { createAntManager } from './peripherals/ant/AntManager.js' const exec = promisify(child_process.exec) // set the log levels @@ -192,17 +191,17 @@ rowingStatistics.on('rowingStopped', (metrics) => { workoutRecorder.writeRecordings() }) -if (config.heartrateMonitorBLE) { - const bleCentralService = child_process.fork('./app/peripherals/ble/CentralService.js') - bleCentralService.on('message', (heartrateMeasurement) => { - rowingStatistics.handleHeartrateMeasurement(heartrateMeasurement) +if (config.heartRateMonitorBLE) { + peripheralManager.startBleHeartRateService() + peripheralManager.on('heartRateBleMeasurement', (heartRateMeasurement) => { + rowingStatistics.handleHeartRateMeasurement(heartRateMeasurement) }) } -if (config.heartrateMonitorANT) { - const antManager = createAntManager() - antManager.on('heartrateMeasurement', (heartrateMeasurement) => { - rowingStatistics.handleHeartrateMeasurement(heartrateMeasurement) +if (config.heartRateMonitorANT) { + peripheralManager.startAntHeartRateService() + peripheralManager.on('heartRateAntMeasurement', (heartRateMeasurement) => { + rowingStatistics.handleHeartRateMeasurement(heartRateMeasurement) }) } From a3cd6e6f39aaea122800e89036ac88e1ed4c0249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 17 Dec 2022 21:35:22 +0100 Subject: [PATCH 047/209] Add OFF mode to BLE peripheral and refactoring Add OFF mode to be able to turn BLE advertisement off. Rename switchPeripheralMode function to include BLE in order to be more descriptive. --- app/client/components/DashboardActions.js | 8 +-- app/client/lib/app.js | 4 +- app/peripherals/PeripheralManager.js | 71 ++++++++++++----------- app/server.js | 8 +-- config/default.config.js | 1 + 5 files changed, 49 insertions(+), 43 deletions(-) diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index 109cdfa4f4..cde18ec60d 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -65,7 +65,7 @@ export class DashboardActions extends AppElement { return html` ${this.renderOptionalButtons()} - +

${this.dialog ? this.dialog : ''} ` @@ -116,7 +116,7 @@ export class DashboardActions extends AppElement { case 'FTMS': return 'FTMS Rower' default: - return '' + return 'Off' } } @@ -135,8 +135,8 @@ export class DashboardActions extends AppElement { this.sendEvent('triggerAction', { command: 'reset' }) } - switchPeripheralMode () { - this.sendEvent('triggerAction', { command: 'switchPeripheralMode' }) + switchBlePeripheralMode () { + this.sendEvent('triggerAction', { command: 'switchBlePeripheralMode' }) } uploadTraining () { diff --git a/app/client/lib/app.js b/app/client/lib/app.js index 86da9f67b7..5961202a8b 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -130,8 +130,8 @@ export function createApp (app) { function handleAction (action) { switch (action.command) { - case 'switchPeripheralMode': { - if (socket)socket.send(JSON.stringify({ command: 'switchPeripheralMode' })) + case 'switchBlePeripheralMode': { + if (socket)socket.send(JSON.stringify({ command: 'switchBlePeripheralMode' })) break } case 'reset': { diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js index f518bc7a90..efa8ed203d 100644 --- a/app/peripherals/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -16,83 +16,88 @@ import child_process from 'child_process' import AntManager from './ant/AntManager.js' import { createAntHrmPeripheral } from './ant/HrmPeripheral.js' -const modes = ['FTMS', 'FTMSBIKE', 'PM5', 'CSC', 'CPS'] +const bleModes = ['FTMS', 'FTMSBIKE', 'PM5', 'CSC', 'CPS', 'OFF'] function createPeripheralManager () { const emitter = new EventEmitter() - let peripheral - let mode + let blePeripheral + let bleMode - createPeripheral(config.bluetoothMode) + createBlePeripheral(config.bluetoothMode) - function getPeripheral () { - return peripheral + function getBlePeripheral () { + return blePeripheral } - function getPeripheralMode () { - return mode + function getBlePeripheralMode () { + return bleMode } - function switchPeripheralMode (newMode) { + function switchBlePeripheralMode (newMode) { // if now mode was passed, select the next one from the list if (newMode === undefined) { - newMode = modes[(modes.indexOf(mode) + 1) % modes.length] + newMode = bleModes[(bleModes.indexOf(bleMode) + 1) % bleModes.length] } - createPeripheral(newMode) + createBlePeripheral(newMode) } function notifyMetrics (type, metrics) { - peripheral.notifyData(type, metrics) + blePeripheral.notifyData(type, metrics) } function notifyStatus (status) { - peripheral.notifyStatus(status) + blePeripheral.notifyStatus(status) } - async function createPeripheral (newMode) { - if (peripheral) { - await peripheral.destroy() + async function createBlePeripheral (newMode) { + if (blePeripheral) { + await blePeripheral.destroy() } switch (newMode) { case 'PM5': log.info('bluetooth profile: Concept2 PM5') - peripheral = createPm5Peripheral(controlCallback) - mode = 'PM5' + blePeripheral = createPm5Peripheral(controlCallback) + bleMode = 'PM5' break case 'FTMSBIKE': log.info('bluetooth profile: FTMS Indoor Bike') - peripheral = createFtmsPeripheral(controlCallback, { + blePeripheral = createFtmsPeripheral(controlCallback, { simulateIndoorBike: true }) - mode = 'FTMSBIKE' + bleMode = 'FTMSBIKE' break + case 'CSC': log.info('bluetooth profile: Cycling Speed and Cadence') - peripheral = createCscPeripheral() - mode = 'CSC' + blePeripheral = createCscPeripheral() + bleMode = 'CSC' break + case 'CPS': log.info('bluetooth profile: Cycling Power Meter') - peripheral = createCpsPeripheral() - mode = 'CPS' + blePeripheral = createCpsPeripheral() + bleMode = 'CPS' break case 'FTMS': - default: log.info('bluetooth profile: FTMS Rower') - peripheral = createFtmsPeripheral(controlCallback, { + blePeripheral = createFtmsPeripheral(controlCallback, { simulateIndoorBike: false }) - mode = 'FTMS' + bleMode = 'FTMS' break + + default: + log.info('bluetooth profile: Off') + bleMode = 'OFF' } - peripheral.triggerAdvertising() + if (bleMode.toLocaleLowerCase() !== 'OFF'.toLocaleLowerCase()) { blePeripheral.triggerAdvertising() } emitter.emit('control', { req: { - name: 'peripheralMode', - peripheralMode: mode + name: 'blePeripheralMode', + peripheralMode: bleMode } }) } @@ -123,9 +128,9 @@ function createPeripheralManager () { return Object.assign(emitter, { startAntHeartRateService, startBleHeartRateService, - getPeripheral, - getPeripheralMode, - switchPeripheralMode, + getBlePeripheral, + getBlePeripheralMode, + switchBlePeripheralMode, notifyMetrics, notifyStatus }) diff --git a/app/server.js b/app/server.js index 32e449c4e9..d287559a74 100644 --- a/app/server.js +++ b/app/server.js @@ -98,7 +98,7 @@ peripheralManager.on('control', (event) => { peripheralManager.notifyStatus({ name: 'startedOrResumedByUser' }) event.res = true break - case 'peripheralMode': + case 'blePeripheralMode': webServer.notifyClients('config', getConfig()) event.res = true break @@ -216,8 +216,8 @@ workoutUploader.on('resetWorkout', () => { const webServer = createWebServer() webServer.on('messageReceived', async (message, client) => { switch (message.command) { - case 'switchPeripheralMode': - peripheralManager.switchPeripheralMode() + case 'switchBlePeripheralMode': + peripheralManager.switchBlePeripheralMode() break case 'reset': resetWorkout() @@ -243,7 +243,7 @@ webServer.on('clientConnected', (client) => { // todo: extract this into some kind of state manager function getConfig () { return { - peripheralMode: peripheralManager.getPeripheralMode(), + peripheralMode: peripheralManager.getBlePeripheralMode(), stravaUploadEnabled: !!config.stravaClientId && !!config.stravaClientSecret, shutdownEnabled: !!config.shutdownCommand } diff --git a/config/default.config.js b/config/default.config.js index fa16cfa77b..e44371de35 100644 --- a/config/default.config.js +++ b/config/default.config.js @@ -78,6 +78,7 @@ export default { // - FTMSBIKE: The FTMS profile is used by Smart Bike Trainers (please note: the speed and power are still aimed for rowing, NOT for a bike!) // - CPS: The BLE Cycling Power Profile simulates a bike for more modern Garmin watches // - CSC: The BLE Cycling Speed and Cadence Profile simulates a bike for older Garmin watches + // - OFF: Turns Bluetooth advertisement off bluetoothMode: 'FTMS', // Turn this on if you want support for Bluetooth Low Energy heart rate monitors From 17d6a74332175265fd4d90b7788b58797d9def1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sun, 18 Dec 2022 15:19:47 +0100 Subject: [PATCH 048/209] Enable rotation of the heart rate monitor modes Add button to the GUI so the user can switch between heart rate monitor modes (BLE, ANT, OFF). Update peripheralManager to handle switching and implement necessary changes to the structure of the peripheralManager. --- app/client/components/DashboardActions.js | 14 +++-- app/client/lib/app.js | 4 ++ app/client/store/appState.js | 6 +- app/peripherals/PeripheralManager.js | 76 ++++++++++++++++++----- app/peripherals/ant/AntManager.js | 32 ++++++++-- app/peripherals/ant/HrmPeripheral.js | 27 ++++---- app/peripherals/ble/HrmPeripheral.js | 33 +++++++--- app/peripherals/ble/hrm/HrmService.js | 17 +++++ app/server.js | 28 ++++----- config/default.config.js | 14 ++--- 10 files changed, 178 insertions(+), 73 deletions(-) create mode 100644 app/peripherals/ble/hrm/HrmService.js diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index cde18ec60d..d6564dff1b 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -7,7 +7,7 @@ import { AppElement, html, css } from './AppElement.js' import { customElement, state } from 'lit/decorators.js' -import { icon_undo, icon_expand, icon_compress, icon_poweroff, icon_bluetooth, icon_upload } from '../lib/icons.js' +import { icon_undo, icon_expand, icon_compress, icon_poweroff, icon_bluetooth, icon_upload, icon_heartbeat } from '../lib/icons.js' import './AppDialog.js' @customElement('dashboard-actions') @@ -66,7 +66,9 @@ export class DashboardActions extends AppElement { ${this.renderOptionalButtons()} -
${this.peripheralMode()}
+
${this.blePeripheralMode()}
+ +
${this.appState?.config?.hrmPeripheralMode}
${this.dialog ? this.dialog : ''} ` } @@ -101,8 +103,8 @@ export class DashboardActions extends AppElement { return buttons } - peripheralMode () { - const value = this.appState?.config?.peripheralMode + blePeripheralMode () { + const value = this.appState?.config?.blePeripheralMode switch (value) { case 'PM5': @@ -139,6 +141,10 @@ export class DashboardActions extends AppElement { this.sendEvent('triggerAction', { command: 'switchBlePeripheralMode' }) } + switchHrmPeripheralMode () { + this.sendEvent('triggerAction', { command: 'switchHrmMode' }) + } + uploadTraining () { this.dialog = html` diff --git a/app/client/lib/app.js b/app/client/lib/app.js index 5961202a8b..e68071572a 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -134,6 +134,10 @@ export function createApp (app) { if (socket)socket.send(JSON.stringify({ command: 'switchBlePeripheralMode' })) break } + case 'switchHrmMode': { + if (socket)socket.send(JSON.stringify({ command: 'switchHrmMode' })) + break + } case 'reset': { resetFields() if (socket)socket.send(JSON.stringify({ command: 'reset' })) diff --git a/app/client/store/appState.js b/app/client/store/appState.js index 12666d7de6..ef27e1204d 100644 --- a/app/client/store/appState.js +++ b/app/client/store/appState.js @@ -11,8 +11,10 @@ export const APP_STATE = { // contains all the rowing metrics that are delivered from the backend metrics: {}, config: { - // currently can be FTMS, FTMSBIKE, PM5, CSC, CPS - peripheralMode: '', + // currently can be FTMS, FTMSBIKE, PM5, CSC, CPS, OFF + blePeripheralMode: '', + // currently can be ANT, BLE, OFF + hrmPeripheralMode: '', // true if upload to strava is enabled stravaUploadEnabled: false, // true if remote device shutdown is enabled diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js index efa8ed203d..803985438f 100644 --- a/app/peripherals/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -12,17 +12,23 @@ import log from 'loglevel' import EventEmitter from 'node:events' import { createCpsPeripheral } from './ble/CpsPeripheral.js' import { createCscPeripheral } from './ble/CscPeripheral.js' -import child_process from 'child_process' import AntManager from './ant/AntManager.js' import { createAntHrmPeripheral } from './ant/HrmPeripheral.js' +import { createBleHrmPeripheral } from './ble/HrmPeripheral.js' const bleModes = ['FTMS', 'FTMSBIKE', 'PM5', 'CSC', 'CPS', 'OFF'] +const hrmModes = ['ANT', 'BLE', 'OFF'] function createPeripheralManager () { const emitter = new EventEmitter() + let _antManager let blePeripheral let bleMode + let hrmPeripheral + let hrmMode + createBlePeripheral(config.bluetoothMode) + createHrmPeripheral(config.heartRateMode) function getBlePeripheral () { return blePeripheral @@ -32,6 +38,14 @@ function createPeripheralManager () { return bleMode } + function getHrmPeripheral () { + return hrmPeripheral + } + + function getHrmPeripheralMode () { + return hrmMode + } + function switchBlePeripheralMode (newMode) { // if now mode was passed, select the next one from the list if (newMode === undefined) { @@ -102,22 +116,55 @@ function createPeripheralManager () { }) } - function startBleHeartRateService () { - const hrmPeripheral = child_process.fork('./app/peripherals/ble/HrmPeripheral.js') - hrmPeripheral.on('message', (heartRateMeasurement) => { - emitter.emit('heartRateBleMeasurement', heartRateMeasurement) - }) + function switchHrmMode (newMode) { + if (newMode === undefined) { + newMode = hrmModes[(hrmModes.indexOf(hrmMode) + 1) % hrmModes.length] + } + createHrmPeripheral(newMode) } - function startAntHeartRateService () { - if (!this._antManager) { - this._antManager = new AntManager() + async function createHrmPeripheral (newMode) { + if (hrmPeripheral) { + await hrmPeripheral.destroy() + hrmPeripheral.removeAllListeners() + + if (_antManager && newMode !== 'ANT') { await _antManager.closeAntStick() } } - const antHrm = createAntHrmPeripheral(this._antManager) + switch (newMode) { + case 'ANT': + log.info('heart rate profile: ANT') + if (!_antManager) { + _antManager = new AntManager() + } + + hrmPeripheral = createAntHrmPeripheral(_antManager) + hrmMode = 'ANT' + await hrmPeripheral.attach() + break - antHrm.on('heartRateMeasurement', (heartRateMeasurement) => { - emitter.emit('heartRateAntMeasurement', heartRateMeasurement) + case 'BLE': + log.info('heart rate profile: BLE') + hrmPeripheral = createBleHrmPeripheral() + hrmMode = 'BLE' + break + + default: + log.info('heart rate profile: Off') + hrmMode = 'OFF' + } + + if (hrmMode.toLocaleLowerCase() !== 'OFF'.toLocaleLowerCase()) { + hrmPeripheral.on('heartRateMeasurement', (heartRateMeasurement) => { + emitter.emit('heartRateMeasurement', heartRateMeasurement) + }) + } + + emitter.emit('control', { + req: { + name: 'hrmPeripheralMode', + peripheralMode: hrmMode + } }) } @@ -126,10 +173,11 @@ function createPeripheralManager () { } return Object.assign(emitter, { - startAntHeartRateService, - startBleHeartRateService, getBlePeripheral, getBlePeripheralMode, + getHrmPeripheral, + getHrmPeripheralMode, + switchHrmMode, switchBlePeripheralMode, notifyMetrics, notifyStatus diff --git a/app/peripherals/ant/AntManager.js b/app/peripherals/ant/AntManager.js index 3961477d73..d268c54afe 100644 --- a/app/peripherals/ant/AntManager.js +++ b/app/peripherals/ant/AntManager.js @@ -9,9 +9,12 @@ - Garmin USB or USB2 ANT+ or an off-brand clone of it (ID 0x1008) - Garmin mini ANT+ (ID 0x1009) */ +import log from 'loglevel' import Ant from 'ant-plus' export default class AntManager { + _isStickOpen = false + constructor () { // it seems that we have to use two separate heart rate sensors to support both old and new // ant sticks, since the library requires them to be bound before open is called @@ -22,10 +25,31 @@ export default class AntManager { } openAntStick () { - if (!this._stick.open()) { - return false - } - return this._stick + return new Promise((resolve, reject) => { + if (!this._stick.open()) { + reject(new Error('Error opening Ant Stick')) + } + this._stick.once('startup', () => { + log.info('ANT+ stick found') + this._isStickOpen = true + resolve(this._stick) + }) + }) + } + + closeAntStick () { + return new Promise(resolve => { + this._stick.once('shutdown', () => { + log.info('ANT+ stick is closed') + this._isStickOpen = false + resolve() + }) + this._stick.close() + }) + } + + isStickOpen () { + return this._isStickOpen } getAntStick () { diff --git a/app/peripherals/ant/HrmPeripheral.js b/app/peripherals/ant/HrmPeripheral.js index 4f6883d67a..e85ea664cf 100644 --- a/app/peripherals/ant/HrmPeripheral.js +++ b/app/peripherals/ant/HrmPeripheral.js @@ -7,7 +7,6 @@ */ import EventEmitter from 'node:events' import Ant from 'ant-plus' -import log from 'loglevel' function createAntHrmPeripheral (antManager) { const emitter = new EventEmitter() @@ -19,32 +18,28 @@ function createAntHrmPeripheral (antManager) { emitter.emit('heartRateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel: data.BatteryLevel }) }) - antStick.on('startup', () => { - log.info('ANT+ stick found') - heartRateSensor.attach(0, 0) - }) - - antStick.on('shutdown', () => { - log.info('classic ANT+ stick lost') - }) - - if (!antManager.openAntStick()) { - throw new Error('Error opening Ant Stick') + function attach () { + return new Promise(resolve => { + heartRateSensor.once('attached', () => { + resolve() + }) + heartRateSensor.attach(0, 0) + }) } function destroy () { return new Promise((resolve) => { - heartRateSensor.detach() - heartRateSensor.on('detached', () => { - antStick.removeAllListeners() + heartRateSensor.once('detached', () => { heartRateSensor.removeAllListeners() resolve() }) + heartRateSensor.detach() }) } return Object.assign(emitter, { - destroy + destroy, + attach }) } diff --git a/app/peripherals/ble/HrmPeripheral.js b/app/peripherals/ble/HrmPeripheral.js index 1916c700d6..cd3de2767b 100644 --- a/app/peripherals/ble/HrmPeripheral.js +++ b/app/peripherals/ble/HrmPeripheral.js @@ -5,14 +5,29 @@ Starts the central manager in a forked thread since noble does not like to run in the same thread as bleno */ -import process from 'process' -import config from '../../tools/ConfigManager.js' -import log from 'loglevel' -import { createHeartRateManager } from './hrm/HeartRateManager.js' +import EventEmitter from 'node:events' +import child_process from 'child_process' -log.setLevel(config.loglevel.default) -const heartRateManager = createHeartRateManager() +function createBleHrmPeripheral () { + const emitter = new EventEmitter() -heartRateManager.on('heartRateMeasurement', (heartRateMeasurement) => { - process.send(heartRateMeasurement) -}) + const bleHrmProcess = child_process.fork('./app/peripherals/ble/hrm/HrmService.js') + + bleHrmProcess.on('message', (heartRateMeasurement) => { + emitter.emit('heartRateMeasurement', heartRateMeasurement) + }) + + function destroy () { + return new Promise(resolve => { + bleHrmProcess.kill() + bleHrmProcess.removeAllListeners() + resolve() + }) + } + + return Object.assign(emitter, { + destroy + }) +} + +export { createBleHrmPeripheral } diff --git a/app/peripherals/ble/hrm/HrmService.js b/app/peripherals/ble/hrm/HrmService.js new file mode 100644 index 0000000000..518af51d39 --- /dev/null +++ b/app/peripherals/ble/hrm/HrmService.js @@ -0,0 +1,17 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Starts the central manager in a forked thread since noble does not like + to run in the same thread as bleno +*/ +import process from 'process' +import log from 'loglevel' +import config from '../../../tools/ConfigManager.js' +import { createHeartRateManager } from './HeartRateManager.js' + +log.setLevel(config.loglevel.default) +const heartRateManager = createHeartRateManager() +heartRateManager.on('heartRateMeasurement', (heartRateMeasurement) => { + process.send(heartRateMeasurement) +}) diff --git a/app/server.js b/app/server.js index d287559a74..7ecef8652e 100644 --- a/app/server.js +++ b/app/server.js @@ -102,11 +102,19 @@ peripheralManager.on('control', (event) => { webServer.notifyClients('config', getConfig()) event.res = true break + case 'hrmPeripheralMode': + webServer.notifyClients('config', getConfig()) + event.res = true + break default: log.info('unhandled Command', event.req) } }) +peripheralManager.on('heartRateMeasurement', (heartRateMeasurement) => { + rowingStatistics.handleHeartRateMeasurement(heartRateMeasurement) +}) + function pauseWorkout () { rowingStatistics.pause() } @@ -191,20 +199,6 @@ rowingStatistics.on('rowingStopped', (metrics) => { workoutRecorder.writeRecordings() }) -if (config.heartRateMonitorBLE) { - peripheralManager.startBleHeartRateService() - peripheralManager.on('heartRateBleMeasurement', (heartRateMeasurement) => { - rowingStatistics.handleHeartRateMeasurement(heartRateMeasurement) - }) -} - -if (config.heartRateMonitorANT) { - peripheralManager.startAntHeartRateService() - peripheralManager.on('heartRateAntMeasurement', (heartRateMeasurement) => { - rowingStatistics.handleHeartRateMeasurement(heartRateMeasurement) - }) -} - workoutUploader.on('authorizeStrava', (data, client) => { webServer.notifyClient(client, 'authorizeStrava', data) }) @@ -219,6 +213,9 @@ webServer.on('messageReceived', async (message, client) => { case 'switchBlePeripheralMode': peripheralManager.switchBlePeripheralMode() break + case 'switchHrmMode': + peripheralManager.switchHrmMode() + break case 'reset': resetWorkout() break @@ -243,7 +240,8 @@ webServer.on('clientConnected', (client) => { // todo: extract this into some kind of state manager function getConfig () { return { - peripheralMode: peripheralManager.getBlePeripheralMode(), + blePeripheralMode: peripheralManager.getBlePeripheralMode(), + hrmPeripheralMode: peripheralManager.getHrmPeripheralMode(), stravaUploadEnabled: !!config.stravaClientId && !!config.stravaClientSecret, shutdownEnabled: !!config.shutdownCommand } diff --git a/config/default.config.js b/config/default.config.js index e44371de35..94efe8616f 100644 --- a/config/default.config.js +++ b/config/default.config.js @@ -81,15 +81,11 @@ export default { // - OFF: Turns Bluetooth advertisement off bluetoothMode: 'FTMS', - // Turn this on if you want support for Bluetooth Low Energy heart rate monitors - // Will currenty connect to the first device found - heartrateMonitorBLE: true, - - // Turn this on if you want support for ANT+ heart rate monitors - // You will need an ANT+ USB stick for this to work, the following models might work: - // - Garmin USB or USB2 ANT+ or an off-brand clone of it (ID 0x1008) - // - Garmin mini ANT+ (ID 0x1009) - heartrateMonitorANT: false, + // Selects the heart rate monitor mode. Supported modes: + // - BLE: Use Bluetooth Low Energy to connect Heart Rate Monitor (Will currently connect to the first device found) + // - ANT: Use Ant+ to connect Heart Rate Monitor + // - OFF: turns of Heart Rate Monitor discovery + heartRateMode: 'BLE', // Defines the name that is used to announce the FTMS Rower via Bluetooth Low Energy (BLE) // Some rowing training applications expect that the rowing device is announced with a certain name From 3bb0229d3a629bff96e36eff378d6a0b28db5674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sun, 18 Dec 2022 23:50:06 +0100 Subject: [PATCH 049/209] Move to new ant-plus library Move to a new, still maintained, ant-plus library that solves the connection dropout issue experienced with the original when using HRM as well as that provides a cleaner interface to manage the ANT device. --- app/peripherals/ant/AntManager.js | 43 +++++++++------------------- app/peripherals/ant/HrmPeripheral.js | 38 ++++++++++++------------ package.json | 2 +- 3 files changed, 33 insertions(+), 50 deletions(-) diff --git a/app/peripherals/ant/AntManager.js b/app/peripherals/ant/AntManager.js index d268c54afe..c4a538414c 100644 --- a/app/peripherals/ant/AntManager.js +++ b/app/peripherals/ant/AntManager.js @@ -10,42 +10,27 @@ - Garmin mini ANT+ (ID 0x1009) */ import log from 'loglevel' -import Ant from 'ant-plus' +import { AntDevice } from 'incyclist-ant-plus/lib/bindings/index.js' export default class AntManager { _isStickOpen = false + _stick = new AntDevice({ startupTimeout: 2000 }) - constructor () { - // it seems that we have to use two separate heart rate sensors to support both old and new - // ant sticks, since the library requires them to be bound before open is called - this._stick = new Ant.GarminStick3() // 0fcf:1009 - if (!this._stick.is_present()) { - this._stick = new Ant.GarminStick2() // 0fcf:1008 - } - } + async openAntStick () { + if (this._isStickOpen) return + if (!(await this._stick.open())) { throw (new Error('Error opening Ant Stick')) } - openAntStick () { - return new Promise((resolve, reject) => { - if (!this._stick.open()) { - reject(new Error('Error opening Ant Stick')) - } - this._stick.once('startup', () => { - log.info('ANT+ stick found') - this._isStickOpen = true - resolve(this._stick) - }) - }) + log.info('ANT+ stick found') + this._isStickOpen = true } - closeAntStick () { - return new Promise(resolve => { - this._stick.once('shutdown', () => { - log.info('ANT+ stick is closed') - this._isStickOpen = false - resolve() - }) - this._stick.close() - }) + async closeAntStick () { + if (!this._isStickOpen) return + + if (!(await this._stick.close())) { throw (new Error('Error closing Ant Stick')) } + + log.info('ANT+ stick is closed') + this._isStickOpen = false } isStickOpen () { diff --git a/app/peripherals/ant/HrmPeripheral.js b/app/peripherals/ant/HrmPeripheral.js index e85ea664cf..99fe289d7e 100644 --- a/app/peripherals/ant/HrmPeripheral.js +++ b/app/peripherals/ant/HrmPeripheral.js @@ -6,35 +6,33 @@ a Cycling Speed and Cadence Profile */ import EventEmitter from 'node:events' -import Ant from 'ant-plus' +import log from 'loglevel' +import { HeartRateSensor } from 'incyclist-ant-plus' function createAntHrmPeripheral (antManager) { const emitter = new EventEmitter() const antStick = antManager.getAntStick() + const heartRateSensor = new HeartRateSensor(0) - const heartRateSensor = new Ant.HeartRateSensor(antStick) + async function attach () { + if (!antManager.isStickOpen()) { await antManager.openAntStick() } + this.channel = await antStick.getChannel() - heartRateSensor.on('hbData', (data) => { - emitter.emit('heartRateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel: data.BatteryLevel }) - }) - - function attach () { - return new Promise(resolve => { - heartRateSensor.once('attached', () => { - resolve() - }) - heartRateSensor.attach(0, 0) + this.channel.on('data', (profile, deviceID, data) => { + emitter.emit('heartRateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel: data.BatteryLevel }) }) + + if (!(await this.channel.startSensor(heartRateSensor))) { + log.error('Could not start ANT+ heart rate sensor') + } } - function destroy () { - return new Promise((resolve) => { - heartRateSensor.once('detached', () => { - heartRateSensor.removeAllListeners() - resolve() - }) - heartRateSensor.detach() - }) + async function destroy () { + if (!this.channel) { + log.debug('Ant Sensor does not seem to be running') + return + } + await this.channel.stopSensor(heartRateSensor) } return Object.assign(emitter, { diff --git a/package.json b/package.json index e59db4080f..d1fbe6e2c9 100644 --- a/package.json +++ b/package.json @@ -33,9 +33,9 @@ "dependencies": { "@abandonware/bleno": "0.5.1-4", "@abandonware/noble": "1.9.2-15", - "ant-plus": "0.1.24", "finalhandler": "1.1.2", "form-data": "4.0.0", + "incyclist-ant-plus": "^0.1.15", "lit": "2.1.3", "loglevel": "1.8.0", "nosleep.js": "0.12.0", From e938f5d8a00f068234119c5011db871c37b47ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Tue, 20 Dec 2022 09:46:28 +0100 Subject: [PATCH 050/209] Fix app crash when bleMode is set to OFF initially Add guard clauses to notifyMetric call if bleMode is off. Set blePeripheral and hrmPeripheral to undefined to avoid repeated call to destroy() (i.e. calling destroy() on an already destroyed peripheral) --- app/peripherals/PeripheralManager.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js index 803985438f..9dcb4e2b0c 100644 --- a/app/peripherals/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -55,16 +55,17 @@ function createPeripheralManager () { } function notifyMetrics (type, metrics) { - blePeripheral.notifyData(type, metrics) + if (bleMode !== 'OFF') { blePeripheral.notifyData(type, metrics) } } function notifyStatus (status) { - blePeripheral.notifyStatus(status) + if (bleMode !== 'OFF') { blePeripheral.notifyStatus(status) } } async function createBlePeripheral (newMode) { if (blePeripheral) { await blePeripheral.destroy() + blePeripheral = undefined } switch (newMode) { @@ -127,7 +128,7 @@ function createPeripheralManager () { if (hrmPeripheral) { await hrmPeripheral.destroy() hrmPeripheral.removeAllListeners() - + hrmPeripheral = undefined if (_antManager && newMode !== 'ANT') { await _antManager.closeAntStick() } } From 4f62b2322e3f65109333dbebddee9297770f38d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Wed, 21 Dec 2022 13:01:58 +0100 Subject: [PATCH 051/209] Add ANT+ profile manager - Implement an ANT+ profile manager similar to BLE - Implement ANT+ Fitness Equipment profile to be able to broadcast data - Add button to the UI to scroll through the ANT+ profiles --- app/client/components/DashboardActions.js | 8 +- app/client/lib/app.js | 4 + app/client/lib/icons.js | 2 + app/client/store/appState.js | 2 + app/peripherals/PeripheralManager.js | 61 +++++- app/peripherals/ant/AntManager.js | 2 +- app/peripherals/ant/FEPeripheral.js | 218 ++++++++++++++++++++++ app/server.js | 8 + config/default.config.js | 7 +- 9 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 app/peripherals/ant/FEPeripheral.js diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index d6564dff1b..6cf0c91c10 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -7,7 +7,7 @@ import { AppElement, html, css } from './AppElement.js' import { customElement, state } from 'lit/decorators.js' -import { icon_undo, icon_expand, icon_compress, icon_poweroff, icon_bluetooth, icon_upload, icon_heartbeat } from '../lib/icons.js' +import { icon_undo, icon_expand, icon_compress, icon_poweroff, icon_bluetooth, icon_upload, icon_heartbeat, icon_antplus } from '../lib/icons.js' import './AppDialog.js' @customElement('dashboard-actions') @@ -69,6 +69,8 @@ export class DashboardActions extends AppElement {
${this.blePeripheralMode()}
${this.appState?.config?.hrmPeripheralMode}
+ +
${this.appState?.config?.antPeripheralMode}
${this.dialog ? this.dialog : ''} ` } @@ -141,6 +143,10 @@ export class DashboardActions extends AppElement { this.sendEvent('triggerAction', { command: 'switchBlePeripheralMode' }) } + switchAntPeripheralMode () { + this.sendEvent('triggerAction', { command: 'switchAntPeripheralMode' }) + } + switchHrmPeripheralMode () { this.sendEvent('triggerAction', { command: 'switchHrmMode' }) } diff --git a/app/client/lib/app.js b/app/client/lib/app.js index e68071572a..c4104893c9 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -134,6 +134,10 @@ export function createApp (app) { if (socket)socket.send(JSON.stringify({ command: 'switchBlePeripheralMode' })) break } + case 'switchAntPeripheralMode': { + if (socket)socket.send(JSON.stringify({ command: 'switchAntPeripheralMode' })) + break + } case 'switchHrmMode': { if (socket)socket.send(JSON.stringify({ command: 'switchHrmMode' })) break diff --git a/app/client/lib/icons.js b/app/client/lib/icons.js index 23b9a75668..e23328061b 100644 --- a/app/client/lib/icons.js +++ b/app/client/lib/icons.js @@ -25,3 +25,5 @@ export const icon_expand = svg`` export const icon_bluetooth = svg`` export const icon_upload = svg`` + +export const icon_antplus = svg`` diff --git a/app/client/store/appState.js b/app/client/store/appState.js index ef27e1204d..77c78e2def 100644 --- a/app/client/store/appState.js +++ b/app/client/store/appState.js @@ -15,6 +15,8 @@ export const APP_STATE = { blePeripheralMode: '', // currently can be ANT, BLE, OFF hrmPeripheralMode: '', + // currently can be FE, OFF + antPeripheralMode: '', // true if upload to strava is enabled stravaUploadEnabled: false, // true if remote device shutdown is enabled diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js index 9dcb4e2b0c..afba110164 100644 --- a/app/peripherals/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -15,8 +15,10 @@ import { createCscPeripheral } from './ble/CscPeripheral.js' import AntManager from './ant/AntManager.js' import { createAntHrmPeripheral } from './ant/HrmPeripheral.js' import { createBleHrmPeripheral } from './ble/HrmPeripheral.js' +import { createFEPeripheral } from './ant/FEPeripheral.js' const bleModes = ['FTMS', 'FTMSBIKE', 'PM5', 'CSC', 'CPS', 'OFF'] +const antModes = ['FE', 'OFF'] const hrmModes = ['ANT', 'BLE', 'OFF'] function createPeripheralManager () { const emitter = new EventEmitter() @@ -24,11 +26,15 @@ function createPeripheralManager () { let blePeripheral let bleMode + let antPeripheral + let antMode + let hrmPeripheral let hrmMode createBlePeripheral(config.bluetoothMode) createHrmPeripheral(config.heartRateMode) + createAntPeripheral(config.antplusMode) function getBlePeripheral () { return blePeripheral @@ -38,6 +44,14 @@ function createPeripheralManager () { return bleMode } + function getAntPeripheral () { + return antPeripheral + } + + function getAntPeripheralMode () { + return antMode + } + function getHrmPeripheral () { return hrmPeripheral } @@ -56,10 +70,12 @@ function createPeripheralManager () { function notifyMetrics (type, metrics) { if (bleMode !== 'OFF') { blePeripheral.notifyData(type, metrics) } + if (antMode !== 'OFF') { antPeripheral.notifyData(type, metrics) } } function notifyStatus (status) { if (bleMode !== 'OFF') { blePeripheral.notifyStatus(status) } + if (antMode !== 'OFF') { antPeripheral.notifyStatus(status) } } async function createBlePeripheral (newMode) { @@ -117,6 +133,46 @@ function createPeripheralManager () { }) } + function switchAntPeripheralMode (newMode) { + if (newMode === undefined) { + newMode = antModes[(antModes.indexOf(antMode) + 1) % antModes.length] + } + createAntPeripheral(newMode) + } + + async function createAntPeripheral (newMode) { + if (antPeripheral) { + await antPeripheral.destroy() + antPeripheral = undefined + + if (_antManager && hrmMode !== 'ANT' && newMode === 'OFF') { await _antManager.closeAntStick() } + } + + switch (newMode) { + case 'FE': + log.info('ant plus profile: FE') + if (!_antManager) { + _antManager = new AntManager() + } + + antPeripheral = createFEPeripheral(_antManager) + antMode = 'FE' + await antPeripheral.attach() + break + + default: + log.info('ant plus profile: Off') + antMode = 'OFF' + } + + emitter.emit('control', { + req: { + name: 'antPeripheralMode', + peripheralMode: antMode + } + }) + } + function switchHrmMode (newMode) { if (newMode === undefined) { newMode = hrmModes[(hrmModes.indexOf(hrmMode) + 1) % hrmModes.length] @@ -129,7 +185,7 @@ function createPeripheralManager () { await hrmPeripheral.destroy() hrmPeripheral.removeAllListeners() hrmPeripheral = undefined - if (_antManager && newMode !== 'ANT') { await _antManager.closeAntStick() } + if (_antManager && newMode !== 'ANT' && antMode === 'OFF') { await _antManager.closeAntStick() } } switch (newMode) { @@ -176,10 +232,13 @@ function createPeripheralManager () { return Object.assign(emitter, { getBlePeripheral, getBlePeripheralMode, + getAntPeripheral, + getAntPeripheralMode, getHrmPeripheral, getHrmPeripheralMode, switchHrmMode, switchBlePeripheralMode, + switchAntPeripheralMode, notifyMetrics, notifyStatus }) diff --git a/app/peripherals/ant/AntManager.js b/app/peripherals/ant/AntManager.js index c4a538414c..e6759d4b3b 100644 --- a/app/peripherals/ant/AntManager.js +++ b/app/peripherals/ant/AntManager.js @@ -10,7 +10,7 @@ - Garmin mini ANT+ (ID 0x1009) */ import log from 'loglevel' -import { AntDevice } from 'incyclist-ant-plus/lib/bindings/index.js' +import { AntDevice } from 'incyclist-ant-plus/lib/ant-device.js' export default class AntManager { _isStickOpen = false diff --git a/app/peripherals/ant/FEPeripheral.js b/app/peripherals/ant/FEPeripheral.js new file mode 100644 index 0000000000..86e89a9319 --- /dev/null +++ b/app/peripherals/ant/FEPeripheral.js @@ -0,0 +1,218 @@ +'use strict' + +import log from 'loglevel' +import { Messages } from 'incyclist-ant-plus' +import { PeripheralConstants } from '../PeripheralConstants.js' + +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are required for + a Cycling Speed and Cadence Profile +*/ + +function createFEPeripheral (antManager) { + const antStick = antManager.getAntStick() + const deviceType = 0x11 // Ant FE-C device + const deviceNumber = 1 + const deviceId = parseInt(PeripheralConstants.serial, 10) & 0xFFFF + const channel = 1 + const broadcastPeriod = 8192 // 8192/32768 ~4hz + const broadcastInterval = broadcastPeriod / 32768 * 1000 // millisecond + const rfChannel = 57 // 2457 MHz + let dataPageCount = 0 + let commonPageCount = 0 + let timer + + let sessionData = { + accumulatedStrokes: 0, + accumulatedDistance: 0, + accumulatedTime: 0, + accumulatedPower: 0, + cycleLinearVelocity: 0, + strokeRate: 0, + instantaneousPower: 0, + distancePerStroke: 0, + fitnessEquipmentState: fitnessEquipmentStates.inUse, + sessionStatus: 'WaitingForStart' + } + + async function attach () { + if (!antManager.isStickOpen()) { await antManager.openAntStick() } + + const messages = [ + Messages.assignChannel(channel, 'transmit'), + Messages.setDevice(channel, deviceId, deviceType, deviceNumber), + Messages.setFrequency(channel, rfChannel), + Messages.setPeriod(channel, broadcastPeriod), + Messages.openChannel(channel) + ] + + log.info(`ANT+ FE server start [deviceId=${deviceId} channel=${channel}]`) + for (const message of messages) { + antStick.write(message) + } + + timer = setInterval(onBroadcastInterval, broadcastInterval) + } + + function destroy () { + return new Promise((resolve) => { + clearInterval(timer) + log.info(`ANT+ FE server stopped [deviceId=${deviceId} channel=${channel}]`) + + const messages = [ + Messages.closeChannel(channel), + Messages.unassignChannel(channel) + ] + for (const message of messages) { + antStick.write(message) + } + resolve() + }) + } + + function onBroadcastInterval () { + dataPageCount++ + let data + + switch (true) { + case dataPageCount === 65 || dataPageCount === 66: + if (commonPageCount % 2 === 0) { // 0x50 - Common Page for Manufacturers Identification (approx twice a minute) + data = [ + channel, + 0x50, // Page 80 + 0xFF, // Reserved + 0xFF, // Reserved + parseInt(PeripheralConstants.hardwareRevision, 10) & 0xFF, // Hardware Revision + ...Messages.intToLEHexArray(40, 2), // Manufacturer ID (value 255 = Development ID, value 40 = concept2) + 0x0001 // Model Number + ] + } + if (commonPageCount % 2 === 1) { // 0x51 - Common Page for Product Information (approx twice a minute) + data = [ + channel, + 0x51, // Page 81 + 0xFF, // Reserved + parseInt(PeripheralConstants.firmwareRevision.slice(-2), 10), // SW Revision (Supplemental) + parseInt(PeripheralConstants.firmwareRevision[0], 10), // SW Version + ...Messages.intToLEHexArray(parseInt(PeripheralConstants.serial, 10), 4) // Serial Number (None) + ] + } + + if (dataPageCount === 66) { + commonPageCount++ + dataPageCount = 0 + } + break + case dataPageCount % 8 === 4: // 0x11 - General Settings Page (once a second) + case dataPageCount % 8 === 7: + data = [ + channel, + 0x11, // Page 17 + 0xFF, // Reserved + 0xFF, // Reserved + ...Messages.intToLEHexArray(sessionData.distancePerStroke, 1), // Stroke Length in 0.01 m + 0x7FFF, // Incline (Not Used) + 0x00, // Resistance (DF may be reported if conversion to the % is worked out (value in % with a resolution of 0.5%). + ...Messages.intToLEHexArray(feCapabilitiesBitField, 1) + ] + if (sessionData.sessionStatus === 'Rowing') { + log.debug(`Page 17 Data Sent. Event=${dataPageCount}. Stroke Length=${sessionData.distancePerStroke}.`) + log.debug(`Hex Stroke Length=0x${sessionData.distancePerStroke.toString(16)}.`) + } + break + case dataPageCount % 8 === 3: // 0x16 - Specific Rower Data (once a second) + case dataPageCount % 8 === 0: + data = [ + channel, + 0x16, // Page 22 + 0xFF, // Reserved + 0xFF, // Reserved + ...Messages.intToLEHexArray(sessionData.accumulatedStrokes, 1), // Stroke Count + ...Messages.intToLEHexArray(sessionData.strokeRate, 1), // Cadence / Stroke Rate + ...Messages.intToLEHexArray(sessionData.instantaneousPower, 2), // Instant Power (2 bytes) + ...Messages.intToLEHexArray((sessionData.fitnessEquipmentState + rowingCapabilitiesBitField), 1) + ] + if (sessionData.sessionStatus === 'Rowing') { + log.debug(`Page 22 Data Sent. Event=${dataPageCount}. Strokes=${sessionData.accumulatedStrokes}. Stroke Rate=${sessionData.strokeRate}. Power=${sessionData.instantaneousPower}`) + log.debug(`Hex Strokes=0x${sessionData.accumulatedStrokes.toString(16)}. Hex Stroke Rate=0x${sessionData.strokeRate.toString(16)}. Hex Power=0x${Messages.intToLEHexArray(sessionData.instantaneousPower, 2)}.`) + } + break + case dataPageCount % 4 === 2: // 0x10 - General FE Data (twice a second) + default: + data = [ + channel, + 0x10, // Page 16 + 0x16, // Rowing Machine (22) + ...Messages.intToLEHexArray(sessionData.accumulatedTime, 1), // elapsed time + ...Messages.intToLEHexArray(sessionData.accumulatedDistance, 1), // distance travelled + ...Messages.intToLEHexArray(sessionData.cycleLinearVelocity, 2), // speed in 0.001 m/s + 0xFF, // heart rate not being sent + ...Messages.intToLEHexArray((sessionData.fitnessEquipmentState + feCapabilitiesBitField), 1) + ] + if (sessionData.sessionStatus === 'Rowing') { + log.debug(`Page 16 Data Sent. Event=${dataPageCount}. Time=${sessionData.accumulatedTime}. Distance=${sessionData.accumulatedDistance}. Speed=${sessionData.cycleLinearVelocity}.`) + log.debug(`Hex Time=0x${sessionData.accumulatedTime.toString(16)}. Hex Distance=0x${sessionData.accumulatedDistance.toString(16)}. Hex Speed=0x${Messages.intToLEHexArray(sessionData.cycleLinearVelocity, 2)}.`) + } + break + } + + const message = Messages.broadcastData(data) + antStick.write(message) + } + + function notifyData (type, data) { + if (type === 'strokeFinished' || type === 'metricsUpdate') { + sessionData = { + ...sessionData, + accumulatedDistance: data.totalLinearDistance & 0xFF, + accumulatedStrokes: data.totalNumberOfStrokes & 0xFF, + accumulatedTime: Math.trunc(data.totalMovingTime * 4) & 0xFF, + cycleLinearVelocity: Math.round(data.cycleLinearVelocity * 1000), + strokeRate: Math.round(data.cycleStrokeRate) & 0xFF, + instantaneousPower: Math.round(data.cyclePower) & 0xFFFF, + distancePerStroke: Math.round(data.cycleDistance * 100), + sessionStatus: data.sessionStatus + } + } + } + + // FE does not have status characteristic + function notifyStatus (status) { + } + + return { + notifyData, + notifyStatus, + attach, + destroy + } +} + +const fitnessEquipmentStates = { + asleep: (1 << 0x04), + ready: (2 << 0x04), + inUse: (3 << 0x04), + finished: (4 << 0x04), + lapToggleBit: (8 << 0x04) +} + +const fitnessEquipmentCapabilities = { + hrDataSourceHandContactSensors: (0x03 << 0), + hrDataSourceEmSensors: (0x02 << 0), + hrDataSourceAntSensors: (0x01 << 0), + hrDataSourceInvalid: (0x00 << 0), + distanceTraveledEnabled: (0x01 << 2), + virtualSpeed: (0x01 << 3), + realSpeed: (0x00 << 3) +} + +const rowingMachineCapabilities = { + accumulatedStrokesEnabled: (0x01 << 0) +} + +const feCapabilitiesBitField = fitnessEquipmentCapabilities.hrDataSourceInvalid | fitnessEquipmentCapabilities.distanceTraveledEnabled | fitnessEquipmentCapabilities.realSpeed +const rowingCapabilitiesBitField = rowingMachineCapabilities.accumulatedStrokesEnabled + +export { createFEPeripheral } diff --git a/app/server.js b/app/server.js index 7ecef8652e..b64bb2644c 100644 --- a/app/server.js +++ b/app/server.js @@ -102,6 +102,10 @@ peripheralManager.on('control', (event) => { webServer.notifyClients('config', getConfig()) event.res = true break + case 'antPeripheralMode': + webServer.notifyClients('config', getConfig()) + event.res = true + break case 'hrmPeripheralMode': webServer.notifyClients('config', getConfig()) event.res = true @@ -213,6 +217,9 @@ webServer.on('messageReceived', async (message, client) => { case 'switchBlePeripheralMode': peripheralManager.switchBlePeripheralMode() break + case 'switchAntPeripheralMode': + peripheralManager.switchAntPeripheralMode() + break case 'switchHrmMode': peripheralManager.switchHrmMode() break @@ -241,6 +248,7 @@ webServer.on('clientConnected', (client) => { function getConfig () { return { blePeripheralMode: peripheralManager.getBlePeripheralMode(), + antPeripheralMode: peripheralManager.getAntPeripheralMode(), hrmPeripheralMode: peripheralManager.getHrmPeripheralMode(), stravaUploadEnabled: !!config.stravaClientId && !!config.stravaClientSecret, shutdownEnabled: !!config.shutdownCommand diff --git a/config/default.config.js b/config/default.config.js index 94efe8616f..099bc400de 100644 --- a/config/default.config.js +++ b/config/default.config.js @@ -81,11 +81,16 @@ export default { // - OFF: Turns Bluetooth advertisement off bluetoothMode: 'FTMS', + // Selects the AN+ that is broadcasted to external peripherals and apps. Supported modes: + // - FE: ANT+ Fitness Equipment + // - OFF: Turns Bluetooth advertisement off + antplusMode: 'OFF', + // Selects the heart rate monitor mode. Supported modes: // - BLE: Use Bluetooth Low Energy to connect Heart Rate Monitor (Will currently connect to the first device found) // - ANT: Use Ant+ to connect Heart Rate Monitor // - OFF: turns of Heart Rate Monitor discovery - heartRateMode: 'BLE', + heartRateMode: 'OFF', // Defines the name that is used to announce the FTMS Rower via Bluetooth Low Energy (BLE) // Some rowing training applications expect that the rowing device is announced with a certain name From cd1ff3d00143534633bc3b0f1fcb07419c81fec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Wed, 21 Dec 2022 22:21:00 +0100 Subject: [PATCH 052/209] Fix crash when peripheral mode changed too quickly Add boolean guard flag to fix potential crash when user clicks the peripheral change buttons without waiting for the first request to complete in the GUI (i.e. clicks too quickly). --- app/peripherals/PeripheralManager.js | 55 ++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js index afba110164..1563c6c438 100644 --- a/app/peripherals/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -32,6 +32,8 @@ function createPeripheralManager () { let hrmPeripheral let hrmMode + let isPeripheralChangeInProgress = false + createBlePeripheral(config.bluetoothMode) createHrmPeripheral(config.heartRateMode) createAntPeripheral(config.antplusMode) @@ -61,11 +63,14 @@ function createPeripheralManager () { } function switchBlePeripheralMode (newMode) { + if (isPeripheralChangeInProgress) return + isPeripheralChangeInProgress = true // if now mode was passed, select the next one from the list if (newMode === undefined) { newMode = bleModes[(bleModes.indexOf(bleMode) + 1) % bleModes.length] } createBlePeripheral(newMode) + isPeripheralChangeInProgress = false } function notifyMetrics (type, metrics) { @@ -80,7 +85,7 @@ function createPeripheralManager () { async function createBlePeripheral (newMode) { if (blePeripheral) { - await blePeripheral.destroy() + await blePeripheral?.destroy() blePeripheral = undefined } @@ -134,18 +139,26 @@ function createPeripheralManager () { } function switchAntPeripheralMode (newMode) { + if (isPeripheralChangeInProgress) return + isPeripheralChangeInProgress = true if (newMode === undefined) { newMode = antModes[(antModes.indexOf(antMode) + 1) % antModes.length] } createAntPeripheral(newMode) + isPeripheralChangeInProgress = false } async function createAntPeripheral (newMode) { if (antPeripheral) { - await antPeripheral.destroy() + await antPeripheral?.destroy() antPeripheral = undefined - if (_antManager && hrmMode !== 'ANT' && newMode === 'OFF') { await _antManager.closeAntStick() } + try { + if (_antManager && hrmMode !== 'ANT' && newMode === 'OFF') { await _antManager.closeAntStick() } + } catch (error) { + log.error(error) + return + } } switch (newMode) { @@ -155,9 +168,14 @@ function createPeripheralManager () { _antManager = new AntManager() } - antPeripheral = createFEPeripheral(_antManager) - antMode = 'FE' - await antPeripheral.attach() + try { + antPeripheral = createFEPeripheral(_antManager) + antMode = 'FE' + await antPeripheral.attach() + } catch (error) { + log.error(error) + return + } break default: @@ -174,18 +192,26 @@ function createPeripheralManager () { } function switchHrmMode (newMode) { + if (isPeripheralChangeInProgress) return + isPeripheralChangeInProgress = true if (newMode === undefined) { newMode = hrmModes[(hrmModes.indexOf(hrmMode) + 1) % hrmModes.length] } createHrmPeripheral(newMode) + isPeripheralChangeInProgress = false } async function createHrmPeripheral (newMode) { if (hrmPeripheral) { - await hrmPeripheral.destroy() - hrmPeripheral.removeAllListeners() + await hrmPeripheral?.destroy() + hrmPeripheral?.removeAllListeners() hrmPeripheral = undefined - if (_antManager && newMode !== 'ANT' && antMode === 'OFF') { await _antManager.closeAntStick() } + try { + if (_antManager && newMode !== 'ANT' && antMode === 'OFF') { await _antManager.closeAntStick() } + } catch (error) { + log.error(error) + return + } } switch (newMode) { @@ -195,9 +221,14 @@ function createPeripheralManager () { _antManager = new AntManager() } - hrmPeripheral = createAntHrmPeripheral(_antManager) - hrmMode = 'ANT' - await hrmPeripheral.attach() + try { + hrmPeripheral = createAntHrmPeripheral(_antManager) + hrmMode = 'ANT' + await hrmPeripheral.attach() + } catch (error) { + log.error(error) + return + } break case 'BLE': From a0686150a2b04f4dba5358e683c00e1cf8ef5add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Thu, 22 Dec 2022 14:20:20 +0100 Subject: [PATCH 053/209] Update button layout styling for the GUI Restyle the button layout to be responsive and fix potential overflows --- app/client/components/DashboardActions.js | 52 +++++++++++++++++------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index 6cf0c91c10..84db932e01 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -14,28 +14,44 @@ import './AppDialog.js' export class DashboardActions extends AppElement { static styles = css` button { + position: relative; outline:none; background-color: var(--theme-button-color); border: 0; border-radius: var(--theme-border-radius); color: var(--theme-font-color); - margin: 0.2em 0; + margin: 0.2em 4px; font-size: 60%; text-decoration: none; display: inline-flex; - width: 3.5em; - height: 2.5em; + width: 3.2em; + min-width: 3.2em; + height: 2.2em; justify-content: center; align-items: center; } + button:hover { filter: brightness(150%); } + button > div.text { + position: absolute; + left: 2px; + bottom: 2px; + font-size: 40%; + } + #fullscreen-icon { display: inline-flex; } + .top-button-group { + display: flex; + flex-wrap: wrap; + justify-content: center; + } + #windowed-icon { display: none; } @@ -45,7 +61,7 @@ export class DashboardActions extends AppElement { } .peripheral-mode { - font-size: 80%; + font-size: 50%; } @media (display-mode: fullscreen) { @@ -63,14 +79,22 @@ export class DashboardActions extends AppElement { render () { return html` - - ${this.renderOptionalButtons()} - -
${this.blePeripheralMode()}
- -
${this.appState?.config?.hrmPeripheralMode}
- -
${this.appState?.config?.antPeripheralMode}
+
+ + ${this.renderOptionalButtons()} + + +
+
+ +
${this.blePeripheralMode()}
+
${this.dialog ? this.dialog : ''} ` } @@ -114,9 +138,9 @@ export class DashboardActions extends AppElement { case 'FTMSBIKE': return 'FTMS Bike' case 'CSC': - return 'BLE Bike Speed + Cadence' + return 'Bike Speed + Cadence' case 'CPS': - return 'BLE Bike Power' + return 'Bike Power' case 'FTMS': return 'FTMS Rower' default: From 405bcab55a45f476efd628a5d979db75317c788e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sun, 1 Jan 2023 23:23:26 +0100 Subject: [PATCH 054/209] Code cleanup Change logging level for the broadcast data of the ANT+ FE peripheral. Fix callback signature mismatch in bleno `stopAdvertising()` method --- app/peripherals/ant/FEPeripheral.js | 12 ++++++------ app/peripherals/ble/CpsPeripheral.js | 2 +- app/peripherals/ble/CscPeripheral.js | 2 +- app/peripherals/ble/FtmsPeripheral.js | 2 +- app/peripherals/ble/Pm5Peripheral.js | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/peripherals/ant/FEPeripheral.js b/app/peripherals/ant/FEPeripheral.js index 86e89a9319..0a3b99cc38 100644 --- a/app/peripherals/ant/FEPeripheral.js +++ b/app/peripherals/ant/FEPeripheral.js @@ -118,8 +118,8 @@ function createFEPeripheral (antManager) { ...Messages.intToLEHexArray(feCapabilitiesBitField, 1) ] if (sessionData.sessionStatus === 'Rowing') { - log.debug(`Page 17 Data Sent. Event=${dataPageCount}. Stroke Length=${sessionData.distancePerStroke}.`) - log.debug(`Hex Stroke Length=0x${sessionData.distancePerStroke.toString(16)}.`) + log.trace(`Page 17 Data Sent. Event=${dataPageCount}. Stroke Length=${sessionData.distancePerStroke}.`) + log.trace(`Hex Stroke Length=0x${sessionData.distancePerStroke.toString(16)}.`) } break case dataPageCount % 8 === 3: // 0x16 - Specific Rower Data (once a second) @@ -135,8 +135,8 @@ function createFEPeripheral (antManager) { ...Messages.intToLEHexArray((sessionData.fitnessEquipmentState + rowingCapabilitiesBitField), 1) ] if (sessionData.sessionStatus === 'Rowing') { - log.debug(`Page 22 Data Sent. Event=${dataPageCount}. Strokes=${sessionData.accumulatedStrokes}. Stroke Rate=${sessionData.strokeRate}. Power=${sessionData.instantaneousPower}`) - log.debug(`Hex Strokes=0x${sessionData.accumulatedStrokes.toString(16)}. Hex Stroke Rate=0x${sessionData.strokeRate.toString(16)}. Hex Power=0x${Messages.intToLEHexArray(sessionData.instantaneousPower, 2)}.`) + log.trace(`Page 22 Data Sent. Event=${dataPageCount}. Strokes=${sessionData.accumulatedStrokes}. Stroke Rate=${sessionData.strokeRate}. Power=${sessionData.instantaneousPower}`) + log.trace(`Hex Strokes=0x${sessionData.accumulatedStrokes.toString(16)}. Hex Stroke Rate=0x${sessionData.strokeRate.toString(16)}. Hex Power=0x${Messages.intToLEHexArray(sessionData.instantaneousPower, 2)}.`) } break case dataPageCount % 4 === 2: // 0x10 - General FE Data (twice a second) @@ -152,8 +152,8 @@ function createFEPeripheral (antManager) { ...Messages.intToLEHexArray((sessionData.fitnessEquipmentState + feCapabilitiesBitField), 1) ] if (sessionData.sessionStatus === 'Rowing') { - log.debug(`Page 16 Data Sent. Event=${dataPageCount}. Time=${sessionData.accumulatedTime}. Distance=${sessionData.accumulatedDistance}. Speed=${sessionData.cycleLinearVelocity}.`) - log.debug(`Hex Time=0x${sessionData.accumulatedTime.toString(16)}. Hex Distance=0x${sessionData.accumulatedDistance.toString(16)}. Hex Speed=0x${Messages.intToLEHexArray(sessionData.cycleLinearVelocity, 2)}.`) + log.trace(`Page 16 Data Sent. Event=${dataPageCount}. Time=${sessionData.accumulatedTime}. Distance=${sessionData.accumulatedDistance}. Speed=${sessionData.cycleLinearVelocity}.`) + log.trace(`Hex Time=0x${sessionData.accumulatedTime.toString(16)}. Hex Distance=0x${sessionData.accumulatedDistance.toString(16)}. Hex Speed=0x${Messages.intToLEHexArray(sessionData.cycleLinearVelocity, 2)}.`) } break } diff --git a/app/peripherals/ble/CpsPeripheral.js b/app/peripherals/ble/CpsPeripheral.js index 89cce8774a..48dc712781 100644 --- a/app/peripherals/ble/CpsPeripheral.js +++ b/app/peripherals/ble/CpsPeripheral.js @@ -65,7 +65,7 @@ function createCpsPeripheral () { return new Promise((resolve) => { bleno.disconnect() bleno.removeAllListeners() - bleno.stopAdvertising(resolve) + bleno.stopAdvertising(() => resolve()) }) } diff --git a/app/peripherals/ble/CscPeripheral.js b/app/peripherals/ble/CscPeripheral.js index 6915d13dbe..cc457fe93b 100644 --- a/app/peripherals/ble/CscPeripheral.js +++ b/app/peripherals/ble/CscPeripheral.js @@ -65,7 +65,7 @@ function createCscPeripheral () { return new Promise((resolve) => { bleno.disconnect() bleno.removeAllListeners() - bleno.stopAdvertising(resolve) + bleno.stopAdvertising(() => resolve()) }) } diff --git a/app/peripherals/ble/FtmsPeripheral.js b/app/peripherals/ble/FtmsPeripheral.js index c0845c6864..53b363ec52 100644 --- a/app/peripherals/ble/FtmsPeripheral.js +++ b/app/peripherals/ble/FtmsPeripheral.js @@ -78,7 +78,7 @@ function createFtmsPeripheral (controlCallback, options) { return new Promise((resolve) => { bleno.disconnect() bleno.removeAllListeners() - bleno.stopAdvertising(resolve) + bleno.stopAdvertising(() => resolve()) }) } diff --git a/app/peripherals/ble/Pm5Peripheral.js b/app/peripherals/ble/Pm5Peripheral.js index badfe8e357..d9050647dc 100644 --- a/app/peripherals/ble/Pm5Peripheral.js +++ b/app/peripherals/ble/Pm5Peripheral.js @@ -68,7 +68,7 @@ function createPm5Peripheral (controlCallback, options) { return new Promise((resolve) => { bleno.disconnect() bleno.removeAllListeners() - bleno.stopAdvertising(resolve) + bleno.stopAdvertising(() => resolve()) }) } From 35303547e2f633ff78e88b2bf625b1cc2e53fe57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Tue, 3 Jan 2023 10:39:29 +0100 Subject: [PATCH 055/209] Fix error on simultaneous ANT peripheral startup Move the peripheral startup sequence to an async function to ensure proper startup order and to avoid multiple simultaneous calls to the ANT stick causing app crash. --- app/peripherals/PeripheralManager.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js index 1563c6c438..349863a410 100644 --- a/app/peripherals/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -34,9 +34,13 @@ function createPeripheralManager () { let isPeripheralChangeInProgress = false - createBlePeripheral(config.bluetoothMode) - createHrmPeripheral(config.heartRateMode) - createAntPeripheral(config.antplusMode) + setupPeripherals() + + async function setupPeripherals () { + await createBlePeripheral(config.bluetoothMode) + await createHrmPeripheral(config.heartRateMode) + await createAntPeripheral(config.antplusMode) + } function getBlePeripheral () { return blePeripheral @@ -74,13 +78,13 @@ function createPeripheralManager () { } function notifyMetrics (type, metrics) { - if (bleMode !== 'OFF') { blePeripheral.notifyData(type, metrics) } - if (antMode !== 'OFF') { antPeripheral.notifyData(type, metrics) } + if (bleMode !== 'OFF') { blePeripheral?.notifyData(type, metrics) } + if (antMode !== 'OFF') { antPeripheral?.notifyData(type, metrics) } } function notifyStatus (status) { - if (bleMode !== 'OFF') { blePeripheral.notifyStatus(status) } - if (antMode !== 'OFF') { antPeripheral.notifyStatus(status) } + if (bleMode !== 'OFF') { blePeripheral?.notifyStatus(status) } + if (antMode !== 'OFF') { antPeripheral?.notifyStatus(status) } } async function createBlePeripheral (newMode) { From 3f129ceec2c1709bad9d1be2bfb2d85d650f22cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Tue, 3 Jan 2023 10:50:27 +0100 Subject: [PATCH 056/209] Add peripheral shutdown for app termination In order to avoid errors with peripheral processes on the next startup (e.g. ANT Stick getting stuck) graceful explicit shutdown of these is necessary on app termination. --- app/peripherals/PeripheralManager.js | 14 ++++++++++++++ app/server.js | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js index 349863a410..df793d7e4f 100644 --- a/app/peripherals/PeripheralManager.js +++ b/app/peripherals/PeripheralManager.js @@ -264,7 +264,21 @@ function createPeripheralManager () { emitter.emit('control', event) } + async function shutdownAllPeripherals () { + log.debug('shutting down all peripherals') + + try { + await blePeripheral?.destroy() + await antPeripheral?.destroy() + await hrmPeripheral?.destroy() + await _antManager?.closeAntStick() + } catch (error) { + log.error('peripheral shutdown was unsuccessful, restart of Pi may required', error) + } + } + return Object.assign(emitter, { + shutdownAllPeripherals, getBlePeripheral, getBlePeripheralMode, getAntPeripheral, diff --git a/app/server.js b/app/server.js index b64bb2644c..b6a28fce5a 100644 --- a/app/server.js +++ b/app/server.js @@ -140,6 +140,22 @@ function resetWorkout () { const gpioTimerService = child_process.fork('./app/gpio/GpioTimerService.js') gpioTimerService.on('message', handleRotationImpulse) +process.once('SIGINT', async (signal) => { + log.debug(`${signal} signal was received, shutting down gracefully`) + await peripheralManager.shutdownAllPeripherals() + process.exit(0) +}) +process.once('SIGTERM', async (signal) => { + log.debug(`${signal} signal was received, shutting down gracefully`) + await peripheralManager.shutdownAllPeripherals() + process.exit(0) +}) +process.once('uncaughtException', async (error) => { + log.error('Uncaught Exception:', error) + await peripheralManager.shutdownAllPeripherals() + process.exit(1) +}) + function handleRotationImpulse (dataPoint) { workoutRecorder.recordRotationImpulse(dataPoint) rowingStatistics.handleRotationImpulse(dataPoint) From aa3b39f86ab00c0f745db43189aa78499c0b9d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sun, 12 Feb 2023 22:55:26 +0100 Subject: [PATCH 057/209] Change PM5 serial to comply with C2 standards The PM5 serial number should start with "43" (in line with consistent HW and SW revision) --- app/peripherals/PeripheralConstants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/peripherals/PeripheralConstants.js b/app/peripherals/PeripheralConstants.js index 3e1e1369b0..89a82ffab8 100644 --- a/app/peripherals/PeripheralConstants.js +++ b/app/peripherals/PeripheralConstants.js @@ -5,7 +5,7 @@ Some PM5 specific constants */ export const PeripheralConstants = { - serial: '123456789', + serial: '431234567', model: 'PM5', name: 'PM5 123456789 Row', hardwareRevision: '907', From f28580fef36e031b603ae785846aed068db91fed Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 14 Feb 2023 10:45:16 +0100 Subject: [PATCH 058/209] Improvement of the stroke detection Improved the explanation of the stroke detection algorithm based on https://github.com/laberning/openrowingmonitor/issues/124 --- docs/rower_settings.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/rower_settings.md b/docs/rower_settings.md index 8a7552971f..a978ce0479 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -221,13 +221,21 @@ Their accuracy isn't super-critical. In later sections, we will describe how to These settings are the core of the stroke detection and are the ones that require the most effort to get right. The most cricial settings are the *flankLength* and *minimumStrokeQuality*, where other metrics are much less critical. -**minimumStrokeQuality** is a setting that defines the minimal goodness of fit of the beforementioned recovery slope with the datapoints. When the slope doesn't fit the data well, this will block moving to the next phase. A value of 0.1 is extrmely relaxed, where 0.95 would be extremely tight. This is set to 0.34 for most rowers, which is a working setting for all maintained rowers to date. The accuracy of this setting isn't super critical for stroke detection to work: for example, on a Concept2 values between 0.28 to 0.42 are known to give reliable stroke detection. Setting this too relaxed will result in earlier phase changes, settng this too strict will delay phase detection. This setting is primarily used to optimise the stroke detection for advanced metrics (like drive time, drive length, force curves), so unless it gets in the way, there is no immediate need to change it. +In a nutshell, a rowingstroke contains a drive phase and a recovery phase, and Open Rowing Monitor needs to recognise both reliably to work well. Please note, that for an actual transition to another phase respectively **minimumDriveTime** or **minimumRecoveryTime** have to be exceeded as well. -The **flankLength** setting determines the condition when the stroke detection is sufficiently confident that the stroke has started/ended. In essence, the stroke detection looks for a consecutive increasing/decreasing impulse lengths, and the **flankLength** determines how many consecutive flanks have to be seen before the stroke detection considers a stroke to begin or end. Generally, a *flankLength* of 3 to 4 typically works. The technical minimum is 3, the maximum is limited by CPU-time. Please note that making the flank longer does *not* change your measurement in any way: the algorithms always rely on the beginning of the flank, not at the current end. If any, increasing the *flanklength* has the side-effect that some calculations are performed with more rigour, making them more precise as they get more data. Please note that the rower itself might limit the *flankLength*: some rowers only have 4 or 5 datapoints in a drive phase, naturally limiting the number of datapoints that can be used for stroke phase detection. +To detect strokes, Open Rowing Monitor uses the following criteria before attempting a stroke phase transition: -Please note that a longer *flankLength* also requires more CPU time, where the calculation grows exponentially as *flankLength* becomes longer. On a Raspberry Pi 4B, a *flankLength* of 12 has been succesfully used without issue. What the practical limit on a Rapberry Pi Zero 2 W is, is still a matter of investigation. +* a drive is detected when the handleforce is above **minumumForceBeforeStroke** AND the slope of a series of *flankLength* times between impulses is below the **minumumRecoverySlope** (i.e. accelerating) +* a recovery is detected when the handleforce is below **minumumForceBeforeStroke** OR the slope of a series of *flankLength* times between impulses is above the **minumumRecoverySlope** (i.e. decelerating) where the goodness of fit of that slope exceeds the **minimumStrokeQuality** -To make life a bit easier, it is possible to replay a recorded raw rowing session. To do this, uncomment and modify the following lines in `server.js`: +**minimumStrokeQuality** is a setting that defines the minimal goodness of fit of the beforementioned minumumRecoverySlope with the datapoints. When the slope doesn't fit the data well, this will block moving to the next phase. A value of 0.1 is extrmely relaxed, where 0.95 would be extremely tight. This is set to 0.34 for most rowers, which is a working setting for all maintained rowers to date. The accuracy of this setting isn't super critical for stroke detection to work: for example, on a Concept2 values between 0.28 to 0.42 are known to give reliable stroke detection. Setting this too relaxed will result in earlier phase changes, settng this too strict will delay phase detection. This setting is primarily used to optimise the stroke detection for advanced metrics (like drive time, drive length, force curves), so unless it gets in the way, there is no immediate need to change it. Please note that setting this value to 1, it will effectively disable half of the criteria for detecting a recovery, effectively making it completely handle-force based. + +The **flankLength** and **minumumRecoverySlope** settings determine the condition when the stroke detection is sufficiently confident that the stroke has started/ended. In essence, the stroke detection looks for a consecutive increasing/decreasing impulse lengths (with slope **minumumRecoverySlope**), and the **flankLength** determines how many consecutive flanks have to be seen before the stroke detection considers a stroke to begin or end. Setting these paramters requires some trial and error: + +* **minumumRecoverySlope** can be set to 0, where Open Rowing Monitor will use a quite robust selection on an accelerating or decelerating flywheel. This is recomended as a starting point for getting stroke detection to work. It can be further optimised later (see the later section on advanced stroke detection); +* Generally, a *flankLength* of 3 to 4 typically works. The technical minimum is 3, the maximum is limited by CPU-time. Please note that making the flank longer does *not* change your measurement in any way: the algorithms always rely on the beginning of the flank, not at the current end. If any, increasing the *flanklength* has the side-effect that some calculations are performed with more rigour, making them more precise as they get more data. Please note that the rower itself might limit the *flankLength*: some rowers only have 4 or 5 datapoints in a drive phase, naturally limiting the number of datapoints that can be used for stroke phase detection. Increasing this number too far (beyond a significant part of the stroke) will remove the fluctuations in the flywheel speed needed for stroke detections, so there is a practical upper limit to what the value of *flankLength* can be for a specific rower. Please note that a longer *flankLength* also requires more CPU time, where the calculation grows exponentially as *flankLength* becomes longer. On a Raspberry Pi 4B, a *flankLength* of 15 has been succesfully used without issue. What the practical limit on a Rapberry Pi Zero 2 W is, is still a matter of investigation. + +To make life a bit easier, it is possible to replay a raw recording of a previous rowing session. To do this, uncomment and modify the following lines in `server.js`: ```js replayRowingSession(handleRotationImpulse, { From 3de19c08c7980e5a2cdd7eabbf68a5de20393b45 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 14 Feb 2023 10:48:54 +0100 Subject: [PATCH 059/209] Fixed a Lint error --- docs/rower_settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rower_settings.md b/docs/rower_settings.md index a978ce0479..dc6d4744e2 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -226,7 +226,7 @@ In a nutshell, a rowingstroke contains a drive phase and a recovery phase, and O To detect strokes, Open Rowing Monitor uses the following criteria before attempting a stroke phase transition: * a drive is detected when the handleforce is above **minumumForceBeforeStroke** AND the slope of a series of *flankLength* times between impulses is below the **minumumRecoverySlope** (i.e. accelerating) -* a recovery is detected when the handleforce is below **minumumForceBeforeStroke** OR the slope of a series of *flankLength* times between impulses is above the **minumumRecoverySlope** (i.e. decelerating) where the goodness of fit of that slope exceeds the **minimumStrokeQuality** +* a recovery is detected when the handleforce is below **minumumForceBeforeStroke** OR the slope of a series of *flankLength* times between impulses is above the **minumumRecoverySlope** (i.e. decelerating) where the goodness of fit of that slope exceeds the **minimumStrokeQuality** **minimumStrokeQuality** is a setting that defines the minimal goodness of fit of the beforementioned minumumRecoverySlope with the datapoints. When the slope doesn't fit the data well, this will block moving to the next phase. A value of 0.1 is extrmely relaxed, where 0.95 would be extremely tight. This is set to 0.34 for most rowers, which is a working setting for all maintained rowers to date. The accuracy of this setting isn't super critical for stroke detection to work: for example, on a Concept2 values between 0.28 to 0.42 are known to give reliable stroke detection. Setting this too relaxed will result in earlier phase changes, settng this too strict will delay phase detection. This setting is primarily used to optimise the stroke detection for advanced metrics (like drive time, drive length, force curves), so unless it gets in the way, there is no immediate need to change it. Please note that setting this value to 1, it will effectively disable half of the criteria for detecting a recovery, effectively making it completely handle-force based. From 674df2f6fc0d90f8b3b2d6809d39c2562eecb707 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 14 Feb 2023 14:19:33 +0100 Subject: [PATCH 060/209] Added link to rower settings manual --- config/rowerProfiles.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/config/rowerProfiles.js b/config/rowerProfiles.js index 74a33f64c4..7515039a37 100644 --- a/config/rowerProfiles.js +++ b/config/rowerProfiles.js @@ -4,9 +4,10 @@ This file contains the rower specific settings for different models of ergometers. - These have been generated by the community. If your rower is not listed here and you did find - good settings for your rowing device please send them to us (together with a raw recording of - 10 strokes) so we can add the device here. + These have been generated by the community. If your rower is not listed here, please follow + https://github.com/laberning/openrowingmonitor/blob/main/docs/rower_settings.md to find the right settings + After you found good settings for your rowing device please send them to us (together with a raw recording + of at least 10 strokes) so we can add the device here and start to maintain it. */ export default { From bef044110da4b38745131592ad5d7aaa13a04650 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 14 Feb 2023 14:23:44 +0100 Subject: [PATCH 061/209] Added link to documentation --- install/config.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/install/config.js b/install/config.js index ff7f170f25..0f434d6da4 100644 --- a/install/config.js +++ b/install/config.js @@ -20,10 +20,11 @@ export default { default: 'debug' }, - // The rower specific settings. Either choose a profile from config/rowerProfiles.js or - // define the settings individually. If you find good settings for a new rowing device - // please send them to us (together with a raw recording of 10 strokes) so we can add - // the device to the profiles. + // The rower specific settings. Either choose a profile from config/rowerProfiles.js (see + // https://github.com/laberning/openrowingmonitor/blob/main/docs/Supported_Rowers.md) or define + // the settings manually (see https://github.com/laberning/openrowingmonitor/blob/main/docs/rower_settings.md + // on how to do this). If you find good settings for a new rowing device please send them to us (together + // with a raw recording of at least 10 strokes) so we can add the device to the profiles. // EXAMPLE ROWER CONFIG : using a DKN R-320 Air Rower as is // rowerSettings: rowerProfiles.DKN_R320 From 1cadf0008ece76d5f61cccdaadf7dc5e7fc124e5 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 15 Feb 2023 16:11:04 +0100 Subject: [PATCH 062/209] Added a description of the new ANT+ functionality Added a description of the new ANT+ functionality --- docs/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index ec1b9aea35..55c8177c0e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -45,7 +45,7 @@ If you connect a physical screen directly to the Raspberry Pi, then this interfa ### Bluetooth Low Energy (BLE) -Open Rowing Monitor also implements different Bluetooth Low Energy (BLE) protocols so you can use your rowing machine with different fitness applications. Some apps use the Fitness Machine Service (FTMS), which is a standardized GATT protocol for different types of fitness machines. Other apps prefer to see a Concept 2 PM5. To help you connect to your app and game of choice, Open Rowing Monitor currently supports the following Bluetooth protocols: +Open Rowing Monitor can recieve recieve heartrate data via BLE. Asides this functionality, Open Rowing Monitor also implements different Bluetooth Low Energy (BLE) protocols so you can use your rowing machine to share rowing metrics with different fitness applications. Some apps use the Fitness Machine Service (FTMS), which is a standardized GATT protocol for different types of fitness machines. Other apps prefer to see a Concept 2 PM5. To help you connect to your app and game of choice, Open Rowing Monitor currently supports the following Bluetooth protocols: * **Concept2 PM**: Open Rowing Monitor implements part of the Concept2 PM Bluetooth Smart Communication Interface Definition. This is still work in progress and only implements the most common parts of the spec, so it is not guaranteed to work with all applications that support C2 rowing machines. Our interface currently can only report metrics, but can't recieve commands and session parameters from the app yet. It is known to work with [EXR](https://www.exrgame.com) and all the samples from [The Erg Arcade](https://ergarcade.com), for example you can [row in the clouds](https://ergarcade.github.io/mrdoob-clouds/). @@ -57,6 +57,10 @@ Open Rowing Monitor also implements different Bluetooth Low Energy (BLE) protoco * **BLE Cycling Speed and Cadence Profile**: used for older Garmin Forerunner and Garmin Venu watches and similar types, again simulating a bike activity. Please note to set the wheel circumference to 10mm to make this work well. +### ANT+ + +You can add a ANT+ USB-stick to your Raspberry Pi, which allows to to recieve data from your ANT+ heartrate monitor. On top of recieving the heartrate data, Open Rowing Monitor can also broadcast rowing metrics via ANT+, which can be recieved by the more expensive series of Garmin smartwatches, which then can calculate metrics like training load etc.. + ### Export of Training Sessions Open Rowing Monitor is based on the idea that metrics should be easily accessible for further analysis. Therefore, Open Rowing Monitor can create the following files: From 7b4a716eb36b7356f6276a95023429e39f6e5126 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 15 Feb 2023 16:19:24 +0100 Subject: [PATCH 063/209] Added incyclist-ant-plus as dependency Added incyclist-ant-plus as dependency --- package-lock.json | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/package-lock.json b/package-lock.json index 995beada5d..ec4af7ad66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "ant-plus": "0.1.24", "finalhandler": "1.1.2", "form-data": "4.0.0", + "incyclist-ant-plus": "^0.1.16", "lit": "2.1.3", "loglevel": "1.8.0", "nosleep.js": "0.12.0", @@ -5969,6 +5970,41 @@ "node": ">=0.8.19" } }, + "node_modules/incyclist-ant-plus": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/incyclist-ant-plus/-/incyclist-ant-plus-0.1.16.tgz", + "integrity": "sha512-gNbdZR1IhucfCX8zjZnshQ0eJHqO1nZNTzf6/3fZdI8h3MgJMp7K0HxpKK9Tpw2ibPj2ORy/ujqLr5/EqCYtlw==", + "dependencies": { + "queue-fifo": "^0.2.6" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "usb": "^2.7.0" + } + }, + "node_modules/incyclist-ant-plus/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "optional": true + }, + "node_modules/incyclist-ant-plus/node_modules/usb": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.8.0.tgz", + "integrity": "sha512-umwfJjG3ADI+0xO+7pkrblX2+2BYDgzJTgWrSoxisXncsA2zW30VX2yly5W2U/gqldx6x2sn9b1Uk2gZht6JBQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">=10.20.0 <11.x || >=12.17.0 <13.0 || >=14.0.0" + } + }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -15682,6 +15718,34 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "incyclist-ant-plus": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/incyclist-ant-plus/-/incyclist-ant-plus-0.1.16.tgz", + "integrity": "sha512-gNbdZR1IhucfCX8zjZnshQ0eJHqO1nZNTzf6/3fZdI8h3MgJMp7K0HxpKK9Tpw2ibPj2ORy/ujqLr5/EqCYtlw==", + "requires": { + "queue-fifo": "^0.2.6", + "usb": "^2.7.0" + }, + "dependencies": { + "node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "optional": true + }, + "usb": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.8.0.tgz", + "integrity": "sha512-umwfJjG3ADI+0xO+7pkrblX2+2BYDgzJTgWrSoxisXncsA2zW30VX2yly5W2U/gqldx6x2sn9b1Uk2gZht6JBQ==", + "optional": true, + "requires": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.5.0" + } + } + } + }, "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", From 1ae7128dc74f85e4a2754662af45d91b8682314c Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 15 Feb 2023 16:37:44 +0100 Subject: [PATCH 064/209] Added missing dependencies Added missing dependencies: queue-fifo@0.2.6, dbly-linked-list@0.3.4, lodash.isequal@4.5.0, @types/w3c-web-usb@1.0.6. --- package-lock.json | 66 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec4af7ad66..c6eb8f1b51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2556,6 +2556,12 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.6.tgz", + "integrity": "sha512-cSjhgrr8g4KbPnnijAr/KJDNKa/bBa+ixYkywFRvrhvi9n1WEl7yYbtRyzE6jqNQiSxxJxoAW3STaOQwJHndaw==", + "optional": true + }, "node_modules/@web/parse5-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@web/parse5-utils/-/parse5-utils-1.3.0.tgz", @@ -3845,6 +3851,14 @@ "node": ">=0.10" } }, + "node_modules/dbly-linked-list": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/dbly-linked-list/-/dbly-linked-list-0.3.4.tgz", + "integrity": "sha512-327vOlwspi9i1T3Kc9yZhRUR8qDdgMQ4HmXsFDDCQ/HTc3sNe7gnF5b0UrsnaOJ0rvmG7yBZpK0NoOux9rKYKw==", + "dependencies": { + "lodash.isequal": "^4.5.0" + } + }, "node_modules/debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -6797,6 +6811,11 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -7373,9 +7392,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -8938,6 +8957,14 @@ "node": ">=0.6" } }, + "node_modules/queue-fifo": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/queue-fifo/-/queue-fifo-0.2.6.tgz", + "integrity": "sha512-rwlnZHAaTmWEGKC7ziasK8u4QnZW/uN6kSiG+tHNf/1GA+R32FArZi18s3SYUpKcA0Y6jJoUDn5GT3Anoc2mWw==", + "dependencies": { + "dbly-linked-list": "0.3.4" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -13124,6 +13151,12 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" }, + "@types/w3c-web-usb": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.6.tgz", + "integrity": "sha512-cSjhgrr8g4KbPnnijAr/KJDNKa/bBa+ixYkywFRvrhvi9n1WEl7yYbtRyzE6jqNQiSxxJxoAW3STaOQwJHndaw==", + "optional": true + }, "@web/parse5-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@web/parse5-utils/-/parse5-utils-1.3.0.tgz", @@ -14117,6 +14150,14 @@ "assert-plus": "^1.0.0" } }, + "dbly-linked-list": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/dbly-linked-list/-/dbly-linked-list-0.3.4.tgz", + "integrity": "sha512-327vOlwspi9i1T3Kc9yZhRUR8qDdgMQ4HmXsFDDCQ/HTc3sNe7gnF5b0UrsnaOJ0rvmG7yBZpK0NoOux9rKYKw==", + "requires": { + "lodash.isequal": "^4.5.0" + } + }, "debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -16357,6 +16398,11 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -16812,9 +16858,9 @@ } }, "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==" }, "node-pre-gyp": { "version": "0.17.0", @@ -17988,6 +18034,14 @@ "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true }, + "queue-fifo": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/queue-fifo/-/queue-fifo-0.2.6.tgz", + "integrity": "sha512-rwlnZHAaTmWEGKC7ziasK8u4QnZW/uN6kSiG+tHNf/1GA+R32FArZi18s3SYUpKcA0Y6jJoUDn5GT3Anoc2mWw==", + "requires": { + "dbly-linked-list": "0.3.4" + } + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", From c029a42d374bb76b481839cac3bcee8f5ed40aac Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 15 Feb 2023 16:53:54 +0100 Subject: [PATCH 065/209] Update to accommodate the new peripheral settings Update to respect new peripheral settings introduced with the new peripheralmanager --- app/tools/ConfigManager.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index 225e4b9a2c..1a3a0aba23 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -28,10 +28,10 @@ function checkConfig (configToCheck) { checkRangeValue(configToCheck, 'gpioTriggeredFlank', ['Up', 'Down', 'Both'], true, 'Up') checkIntegerValue(configToCheck, 'appPriority', configToCheck.gpioPriority, 0, true, true, 0) checkIntegerValue(configToCheck, 'webUpdateInterval', 80, 1000, false, true, 1000) - checkBooleanValue(configToCheck, 'heartrateMonitorBLE', true, true) - checkBooleanValue(configToCheck, 'heartrateMonitorANT', true, false) - checkRangeValue(configToCheck, 'bluetoothMode', ['off', 'PM5', 'FTMS', 'FTMSBIKE', 'CPS', 'CSC'], true, 'FTMS') checkIntegerValue(configToCheck, 'peripheralUpdateInterval', 80, 1000, false, true, 1000) + checkRangeValue(configToCheck, 'bluetoothMode', ['OFF', 'PM5', 'FTMS', 'FTMSBIKE', 'CPS', 'CSC'], true, 'OFF') + checkRangeValue(configToCheck, 'antplusMode', ['OFF', 'FE'], true, 'OFF') + checkRangeValue(configToCheck, 'heartRateMode', ['OFF', 'ANT', 'BLE'], true, 'OFF') checkIntegerValue(configToCheck, 'numOfPhasesForAveragingScreenData', 2, null, false, true, 4) checkBooleanValue(configToCheck, 'createRowingDataFiles', true, true) checkBooleanValue(configToCheck, 'createRawDataFiles', true, true) From 765d975b04a9dc37096ccbf920cd8f2e51eee3d9 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 21 Feb 2023 12:42:31 +0100 Subject: [PATCH 066/209] Better description of stroke detection --- docs/physics_openrowingmonitor.md | 60 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/docs/physics_openrowingmonitor.md b/docs/physics_openrowingmonitor.md index ffae93fd1a..8a2aee521b 100644 --- a/docs/physics_openrowingmonitor.md +++ b/docs/physics_openrowingmonitor.md @@ -179,9 +179,29 @@ As ${Δω \over Δt}$ = α and D = k \* ω2 As α and ω have been derived in a robust manner, and there are no alternative more robust approaches to determining instant τ that allows for handle force curves, we consider this the best attainable result. Testing shows that the results are quite useable. -### Detecting force on the flywheel +## Detecting the stroke phase + +One of the key elements of rowing is detecting the stroke phases and thus calculate the associated metrics for that phase. Assuming that `engine/Flywheel.js` has determined whether there is a force present on the flywheel, `engine/Rower.js` can now transform this information into the phase of the rowing stroke. On an indoor rower, the rowing cycle will always start with a drive, followed by a recovery. This results in the follwing phases: + +* The **Drive phase**, where the rower pulls on the handle, some force on the flywheel is excerted and the flywheel is accelerating or at least not decelerating in accordance with the drag; -One of the key elements of rowing is detecting the stroke phases and thus calculate the associated metrics. From the perspective of Open Rowing Monitor, there only is a stream of *CurrentDt*'s, which should form the basis of this detection: +* The **Recovery Phase**, where the rower returns to his starting position and the flywheel decelerates as the drag on the flywheel is slowing it down; + +As the rowing cycle always follows this fixed schema, Open Rowing Monitor models it as a finite state machine (implemented in `handleRotationImpulse` in `engine/Rower.js`). + +```mermaid +stateDiagram-v2 + direction LR + Drive --> Recovery: Flywheel
isn't powered + Drive --> Drive: Flywheel
is powered + Recovery --> Drive: Flywheel
is powered + Recovery --> Recovery: Flywheel
isn't powered +``` + + +*Finite state machine of rowing cycle* + +From the perspective of Open Rowing Monitor, there only is a stream of *CurrentDt*'s, which should form the basis of this detection: The following picture shows the time between impulses through time: ![Measurements of flywheel](img/physics/flywheelmeasurement.png) @@ -189,17 +209,17 @@ The following picture shows the time between impulses through time: Open Rowing Monitor combines two types of force detection, which work independently: *basic force detection* and *advanced stroke detection*. Both can detect a stroke accuratly, and the combination has proven its use. -In `engine/Flywheel.js`, two functions provide force detection: +In `engine/Flywheel.js`, two functions provide force detection, which use the following criteria before attempting a stroke phase transition: -* `isUnpowered()`: which indicates that the simple or the advanced force detection indicate that a force is absent; +* `isPowered()`: which indicates a force is present, suggesting a drive phase. This is true when the slope of a series of *flankLength* times between impulses is below the **minumumRecoverySlope** (i.e. accelerating) AND the handleforce is above **minumumForceBeforeStroke** (i.e. the torque τ is above a certain threshold); -* `isPowered()`: which indicates that both the simple or the advanced force detection indicate that a force is present. +* `isUnpowered()`: which indicates that there is no force present, suggesting a recovery phase. This is true when the slope of a series of *flankLength* times between impulses is above the **minumumRecoverySlope** (i.e. decelerating) where the goodness of fit of that slope exceeds the **minimumStrokeQuality** OR the handleforce is below **minumumForceBeforeStroke** (i.e. the torque τ is below a certain threshold) -The choice for the logical relations between the two types of force detection is based on testing: where a sudden presence of force on a flywheel (i.e. the start of a drive) is quite easily and consistently detected, its abscence has proven to be more difficult. In practice, the beginning of a drive is easily recognised as strong leg muscles excert much force onto the flywheel in a very short period of time. The end of the drive is more difficult to assess, as the dragforce of the flywheel increases with its speed, and the weaker arm muscles have taken over, making the transition to the recovery much harder to detect. In theory, in the end of the drive phase the drag force might be bigger than the force from the arms, resulting in an overall negative torque. +The choice for the logical relations between the two types of force detection is based on testing: where a sudden presence of force on a flywheel (i.e. the start of a drive) is quite easily and consistently detected, its abscence has proven to be more difficult. In practice, the beginning of a drive is easily recognised as strong leg muscles excert much force onto the flywheel in a very short period of time, leading to an easily recognisable (large) torque τ and a sudden decrease in currentDt's. The end of the drive is more difficult to assess, as the dragforce of the flywheel increases with its speed, and the weaker arm muscles have taken over, making the transition to the recovery much harder to detect. In theory, in the end of the drive phase the drag force might be bigger than the force from the arms, resulting in an overall negative torque. -In the remainder of this paragraph, we describe the underlying physics of these force detection methods. +In the remainder of this paragraph, we describe the underlying physics of both these force detection methods. -#### Basic force detection +### Basic force detection through currentDt slope One of the key indicator is the acceleration/decelleration of the flywheel. Looking at a simple visualisation of the rowing stroke, we try to achieve the following: @@ -218,7 +238,7 @@ A more nuanced, but more vulnerable, approach is to compare the slope of this fu In Open Rowing Monitor, the settings allow for using the more robust ascending/descending approach (by setting *minumumRecoverySlope* to 0), for a more accurate approach (by setting *minumumRecoverySlope* to a static value) or even a dynamic approach (by setting *autoAdjustRecoverySlope* to true) -#### Advanced force detection +### Advanced force detection through torque τ The more advanced, but more vulnerable approach depends on the calculated torque. When looking at *CurrentDt* and Torque over time, we get the following picture: @@ -366,28 +386,6 @@ From theory [[13]](#13)), we know that the handle Power is > $$ P_{Handle} = τ * ω $$ -## Detecting the stroke phase - -Knowing that `engine/Flywheel.js` has determined whether there is a force on the flywheel, `engine/Rower.js` can now transform this into the phase of the rowing stroke. On an indoor rower, the rowing cycle will always start with a stroke, followed by a recovery. This results in the follwing phases: - -* The **Drive phase**, where the rower pulls on the handle, some force on the flywheel is excerted and the flywheel is accelerating or at least not decelerating in accordance with the drag; - -* The **Recovery Phase**, where the rower returns to his starting position and the flywheel decelerates as the drag on the flywheel is slowing it down; - -As the rowing cycle always follows this fixed schema, Open Rowing Monitor models it as a finite state machine (implemented in `handleRotationImpulse` in `engine/Rower.js`). - -```mermaid -stateDiagram-v2 - direction LR - Drive --> Recovery: Flywheel
isn't powered - Drive --> Drive: Flywheel
is powered - Recovery --> Drive: Flywheel
is powered - Recovery --> Recovery: Flywheel
isn't powered -``` - - -*Finite state machine of rowing cycle* - ## A mathematical perspective on key metrics ### Noise Filtering algorithms applied From f31372b27c3d98190eaf3290660fef810f4c66b5 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 21 Feb 2023 12:45:03 +0100 Subject: [PATCH 067/209] Better wording --- docs/physics_openrowingmonitor.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/physics_openrowingmonitor.md b/docs/physics_openrowingmonitor.md index 8a2aee521b..cc9457e66b 100644 --- a/docs/physics_openrowingmonitor.md +++ b/docs/physics_openrowingmonitor.md @@ -205,15 +205,15 @@ From the perspective of Open Rowing Monitor, there only is a stream of *CurrentD The following picture shows the time between impulses through time: ![Measurements of flywheel](img/physics/flywheelmeasurement.png) -*Measurements of flywheel* +*example currentDt Measurements of flywheel* Open Rowing Monitor combines two types of force detection, which work independently: *basic force detection* and *advanced stroke detection*. Both can detect a stroke accuratly, and the combination has proven its use. In `engine/Flywheel.js`, two functions provide force detection, which use the following criteria before attempting a stroke phase transition: -* `isPowered()`: which indicates a force is present, suggesting a drive phase. This is true when the slope of a series of *flankLength* times between impulses is below the **minumumRecoverySlope** (i.e. accelerating) AND the handleforce is above **minumumForceBeforeStroke** (i.e. the torque τ is above a certain threshold); +* `isPowered()`: which indicates a force is present, suggesting a drive phase. This is true when the slope of a series of *flankLength* times between impulses is below the **minumumRecoverySlope** (i.e. accelerating, as is the case in the measurements in above figure before the dotted line) AND the handleforce is above **minumumForceBeforeStroke** (i.e. the torque τ is above a certain threshold); -* `isUnpowered()`: which indicates that there is no force present, suggesting a recovery phase. This is true when the slope of a series of *flankLength* times between impulses is above the **minumumRecoverySlope** (i.e. decelerating) where the goodness of fit of that slope exceeds the **minimumStrokeQuality** OR the handleforce is below **minumumForceBeforeStroke** (i.e. the torque τ is below a certain threshold) +* `isUnpowered()`: which indicates that there is no force present, suggesting a recovery phase. This is true when the slope of a series of *flankLength* times between impulses is above the **minumumRecoverySlope** (i.e. decelerating, as is the case in the measurements in above figure after the dotted line) where the goodness of fit of that slope exceeds the **minimumStrokeQuality** OR the handleforce is below **minumumForceBeforeStroke** (i.e. the torque τ is below a certain threshold) The choice for the logical relations between the two types of force detection is based on testing: where a sudden presence of force on a flywheel (i.e. the start of a drive) is quite easily and consistently detected, its abscence has proven to be more difficult. In practice, the beginning of a drive is easily recognised as strong leg muscles excert much force onto the flywheel in a very short period of time, leading to an easily recognisable (large) torque τ and a sudden decrease in currentDt's. The end of the drive is more difficult to assess, as the dragforce of the flywheel increases with its speed, and the weaker arm muscles have taken over, making the transition to the recovery much harder to detect. In theory, in the end of the drive phase the drag force might be bigger than the force from the arms, resulting in an overall negative torque. From 025c41f5d62aa4c877b2f5c89981e3bf321e66cb Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 28 Feb 2023 20:50:04 +0100 Subject: [PATCH 068/209] Update attribution.md --- docs/attribution.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/attribution.md b/docs/attribution.md index f5a8ec1333..e3925344e1 100644 --- a/docs/attribution.md +++ b/docs/attribution.md @@ -6,7 +6,7 @@ Open Rowing Monitor uses some great work by others. Thank you for all the great * Dave Vernooy's project description on [ErgWare](https://dvernooy.github.io/projects/ergware) has some good information on the maths involved in a rowing ergometer. -* Nomath has done a very impressive [Reverse engineering of the actual workings of the Concept 2 PM5](https://www.c2forum.com/viewtopic.php?f=7&t=194719), including experimentally checking drag calculations. +* Nomath has done a very impressive [Reverse engineering of the actual workings of the Concept 2 PM5](https://www.c2forum.com/viewtopic.php?f=7&t=194719), including experimentally checking drag calculations, which is at the base of our physics engine. * Bluetooth is quite a complex beast, luckily the Bluetooth SIG releases all the [Bluetooth Specifications](https://www.bluetooth.com/specifications/specs). @@ -14,6 +14,6 @@ Open Rowing Monitor uses some great work by others. Thank you for all the great * The frontend uses some icons from [Font Awesome](https://fontawesome.com/), licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). -* Thank you to [Jaap van Ekris](https://github.com/JaapvanEkris) for his contributions to this project. +* Thank you to [Jaap van Ekris](https://github.com/JaapvanEkris) for his many contributions to this project, especially the physics engine and the file exports. -* Thanks to [Abasz](https://github.com/Abasz) for his great contributions to the GPIO and BLE implementation +* Thanks to [Abasz](https://github.com/Abasz) for his great contributions to the GPIO, BLE and Ant+ implementations, as well as the many constructive feedback that helped improve many areas of OpenRowingMonitor. From 65b273bbea16b3548189a06f45b0737b470bb7ea Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 1 Mar 2023 09:01:34 +0100 Subject: [PATCH 069/209] Fixed Lint errors --- docs/attribution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/attribution.md b/docs/attribution.md index e3925344e1..257e59e557 100644 --- a/docs/attribution.md +++ b/docs/attribution.md @@ -6,7 +6,7 @@ Open Rowing Monitor uses some great work by others. Thank you for all the great * Dave Vernooy's project description on [ErgWare](https://dvernooy.github.io/projects/ergware) has some good information on the maths involved in a rowing ergometer. -* Nomath has done a very impressive [Reverse engineering of the actual workings of the Concept 2 PM5](https://www.c2forum.com/viewtopic.php?f=7&t=194719), including experimentally checking drag calculations, which is at the base of our physics engine. +* Nomath has done a very impressive [Reverse engineering of the actual workings of the Concept 2 PM5](https://www.c2forum.com/viewtopic.php?f=7&t=194719), including experimentally checking drag calculations, which is at the base of our physics engine. * Bluetooth is quite a complex beast, luckily the Bluetooth SIG releases all the [Bluetooth Specifications](https://www.bluetooth.com/specifications/specs). From 97c1da96d69582a2d4d3e86e95a58894e381d8c8 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Thu, 2 Mar 2023 11:25:20 +0100 Subject: [PATCH 070/209] Dealt with an edge case Dealt with an edge case where there are no strokes detected, but a number of impulses is recorded (Typically during first calibration). --- app/engine/WorkoutRecorder.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/engine/WorkoutRecorder.js b/app/engine/WorkoutRecorder.js index 05e59849d5..693d4553dd 100644 --- a/app/engine/WorkoutRecorder.js +++ b/app/engine/WorkoutRecorder.js @@ -311,8 +311,12 @@ function createWorkoutRecorder () { function minimumRecordingTimeHasPassed () { const minimumRecordingTimeInSeconds = 10 const rotationImpulseTimeTotal = rotationImpulses.reduce((acc, impulse) => acc + impulse, 0) - const strokeTimeTotal = strokes[strokes.length - 1].totalMovingTime - return (Math.max(rotationImpulseTimeTotal, strokeTimeTotal) > minimumRecordingTimeInSeconds) + if (strokes.length > 0) { + const strokeTimeTotal = strokes[strokes.length - 1].totalMovingTime + return (Math.max(rotationImpulseTimeTotal, strokeTimeTotal) > minimumRecordingTimeInSeconds) + } else { + return (rotationImpulseTimeTotal > minimumRecordingTimeInSeconds) + } } return { From bd97723f8b969082e79c8fd6ad303ed9f69b280c Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Thu, 9 Mar 2023 10:55:45 +0100 Subject: [PATCH 071/209] Cut/copy/paste error in log message --- app/engine/Flywheel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/engine/Flywheel.js b/app/engine/Flywheel.js index ee2e4d8448..d45ad7779a 100644 --- a/app/engine/Flywheel.js +++ b/app/engine/Flywheel.js @@ -71,7 +71,7 @@ function createFlywheel (rowerSettings) { if (dataPoint < rowerSettings.minimumTimeBetweenImpulses && maintainMetrics) { // This shouldn't happen, but let's log it to clarify there is some issue going on here - log.debug(`*** WARNING: currentDt of ${dataPoint} sec is above minimumTimeBetweenImpulses (${rowerSettings.minimumTimeBetweenImpulses} sec)`) + log.debug(`*** WARNING: currentDt of ${dataPoint} sec is below minimumTimeBetweenImpulses (${rowerSettings.minimumTimeBetweenImpulses} sec)`) } currentDt.push(dataPoint) From 6aa5c696c6bffc2b58760bcbd64316694d026469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Wed, 22 Mar 2023 12:54:33 +0100 Subject: [PATCH 072/209] Add force curve component Add a component that shows the force curve of the last drive in a chart. --- app/client/components/DashboardForceCurve.js | 105 ++++++++++++++++++ app/client/components/PerformanceDashboard.js | 4 +- app/client/lib/app.js | 8 +- package.json | 3 +- 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 app/client/components/DashboardForceCurve.js diff --git a/app/client/components/DashboardForceCurve.js b/app/client/components/DashboardForceCurve.js new file mode 100644 index 0000000000..d73f0b55ee --- /dev/null +++ b/app/client/components/DashboardForceCurve.js @@ -0,0 +1,105 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Component that renders a metric of the dashboard +*/ + +import { AppElement, html, css } from './AppElement.js' +import { customElement, property } from 'lit/decorators.js' +import Chart from 'chart.js/auto' + +@customElement('dashboard-force-curve') +export class DashboardForceCurve extends AppElement { + static styles = css` + canvas { + margin-top: 24px; + } + ` + @property({ type: Object }) + value = [] + + chart + + firstUpdated () { + const ctx = this.renderRoot.querySelector('#chart').getContext('2d') + this.chart = new Chart( + ctx, + { + type: 'line', + data: { + datasets: [ + { + fill: true, + data: this.value?.map((data, index) => ({ y: data, x: index })), + pointRadius: 1, + borderColor: 'rgb(255,255,255)', + backgroundColor: 'rgb(220,220,220)' + } + ] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + title: { + display: true, + text: 'Force Curve', + color: 'rgb(255,255,255)', + font: { + size: 32 + }, + padding: { + } + }, + labels: { + boxWidth: 0, + font: { + size: 0 + } + } + } + }, + scales: { + x: { + type: 'linear', + display: false + }, + y: { + ticks: { + color: 'rgb(255,255,255)' + } + } + }, + animations: { + tension: { + duration: 200, + easing: 'easeInQuad' + }, + y: { + duration: 200, + easing: 'easeInQuad' + }, + x: { + duration: 200, + easing: 'easeInQuad' + } + } + } + } + ) + } + + render () { + if (this.chart?.data) { + this.chart.data.datasets[0].data = this.value?.map((data, index) => ({ y: data, x: index })) + this.forceCurve = this.value + this.chart.update() + } + + return html` + + ` + } +} diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index a37fcb41fc..7243452322 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -8,6 +8,7 @@ import { AppElement, html, css } from './AppElement.js' import { APP_STATE } from '../store/appState.js' import { customElement, property } from 'lit/decorators.js' +import './DashboardForceCurve.js' import './DashboardMetric.js' import './DashboardActions.js' import './BatteryIcon.js' @@ -32,7 +33,7 @@ export class PerformanceDashboard extends AppElement { } } - dashboard-metric, dashboard-actions { + dashboard-metric, dashboard-actions,dashboard-force-curve { background: var(--theme-widget-color); text-align: center; position: relative; @@ -69,6 +70,7 @@ export class PerformanceDashboard extends AppElement { } ` : html``} + diff --git a/app/client/lib/app.js b/app/client/lib/app.js index c4104893c9..fff8a1b96f 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -9,7 +9,7 @@ import NoSleep from 'nosleep.js' import { filterObjectByKeys } from './helper.js' const rowingMetricsFields = ['totalNumberOfStrokes', 'totalLinearDistanceFormatted', 'totalCalories', 'cyclePower', 'heartrate', - 'heartrateBatteryLevel', 'cyclePaceFormatted', 'cycleStrokeRate', 'totalMovingTimeFormatted'] + 'heartrateBatteryLevel', 'cyclePaceFormatted', 'cycleStrokeRate', 'totalMovingTimeFormatted', 'driveHandleForceCurve'] export function createApp (app) { const urlParameters = new URLSearchParams(window.location.search) @@ -79,11 +79,11 @@ export function createApp (app) { // if we are in reset state only update heart rate and peripheral mode if (data.totalNumberOfStrokes < 1) { if (data.totalLinearDistanceFormatted > 0) { - activeFields = ['totalLinearDistanceFormatted', 'heartrate', 'heartrateBatteryLevel'] + activeFields = ['totalLinearDistanceFormatted', 'heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve'] } else if (data.totalMovingTimeFormatted !== '00:00') { - activeFields = ['totalMovingTimeFormatted', 'heartrate', 'heartrateBatteryLevel'] + activeFields = ['totalMovingTimeFormatted', 'heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve'] } else { - activeFields = ['heartrate', 'heartrateBatteryLevel'] + activeFields = ['heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve'] } } diff --git a/package.json b/package.json index d1fbe6e2c9..60e95ad56d 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "pigpio": "3.3.1", "serve-static": "1.14.2", "ws": "8.5.0", - "xml2js": "0.4.23" + "xml2js": "0.4.23", + "chart.js": "^4.2.1" }, "//fix1Comment": "version 0.5.3-8 currently does not work with bleno", "optionalDependencies": { From 00d9c824d0bc05b7df506710b2f51c5a487fcb74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Wed, 22 Mar 2023 13:34:27 +0100 Subject: [PATCH 073/209] Create settings dialog and improve AppDialog Update AppDialog to be able to handle invalid forms, and implement the settings dialog that communicates via appState --- app/client/components/AppDialog.js | 22 +- app/client/components/PerformanceDashboard.js | 36 ++- app/client/components/SettingsDialog.js | 206 ++++++++++++++++++ app/client/lib/icons.js | 1 + 4 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 app/client/components/SettingsDialog.js diff --git a/app/client/components/AppDialog.js b/app/client/components/AppDialog.js index eab5d2efae..e37a27901c 100644 --- a/app/client/components/AppDialog.js +++ b/app/client/components/AppDialog.js @@ -46,10 +46,15 @@ export class AppDialog extends AppElement { justify-content: center; align-items: center; } - button:hover { + button:hover:not(.disabled) { filter: brightness(150%); } + button.disabled { + filter: brightness(50%); + pointer: none + } + fieldset { border: 0; margin: unset; @@ -67,6 +72,8 @@ export class AppDialog extends AppElement { padding: 0; } ` + @property({ type: Boolean }) + isValid = true @property({ type: Boolean, reflect: true }) dialogOpen @@ -74,13 +81,13 @@ export class AppDialog extends AppElement { render () { return html` -
+
- - + +
@@ -95,6 +102,13 @@ export class AppDialog extends AppElement { } } + confirm () { + if (this.isValid) { + this.close({ target: { returnValue: 'confirm' } }) + this.dialogOpen = false + } + } + firstUpdated () { this.dialog.value.showModal() } diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index 7243452322..4e5c91324a 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -7,12 +7,13 @@ import { AppElement, html, css } from './AppElement.js' import { APP_STATE } from '../store/appState.js' -import { customElement, property } from 'lit/decorators.js' +import { customElement, property, state } from 'lit/decorators.js' import './DashboardForceCurve.js' import './DashboardMetric.js' import './DashboardActions.js' import './BatteryIcon.js' -import { icon_route, icon_stopwatch, icon_bolt, icon_paddle, icon_heartbeat, icon_fire, icon_clock } from '../lib/icons.js' +import './SettingsDialog' +import { icon_route, icon_stopwatch, icon_bolt, icon_paddle, icon_heartbeat, icon_fire, icon_clock, icon_settings } from '../lib/icons.js' @customElement('performance-dashboard') export class PerformanceDashboard extends AppElement { @@ -44,7 +45,26 @@ export class PerformanceDashboard extends AppElement { dashboard-actions { padding: 0.5em 0 0 0; } + + .settings { + padding: 0.1em 0; + position: absolute; + bottom: 0; + right: 0; + z-index: 20; + } + + .settings .icon { + cursor: pointer; + height: 1em; + } + + .settings:hover .icon { + filter: brightness(150%); + } ` + @state({ type: Object }) + dialog @property({ type: Object }) metrics @@ -55,6 +75,10 @@ export class PerformanceDashboard extends AppElement { render () { const metrics = this.calculateFormattedMetrics(this.appState.metrics) return html` +
+ ${icon_settings} + ${this.dialog ? this.dialog : ''} +
@@ -77,6 +101,14 @@ export class PerformanceDashboard extends AppElement { ` } + openSettings () { + this.dialog = html`` + + function dialogClosed (event) { + this.dialog = undefined + } + } + // todo: so far this is just a port of the formatter from the initial proof of concept client // we could split this up to make it more readable and testable calculateFormattedMetrics (metrics) { diff --git a/app/client/components/SettingsDialog.js b/app/client/components/SettingsDialog.js new file mode 100644 index 0000000000..9e15267b6e --- /dev/null +++ b/app/client/components/SettingsDialog.js @@ -0,0 +1,206 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + Component that renders the action buttons of the dashboard +*/ + +import { AppElement, html, css } from './AppElement.js' +import { customElement, property, queryAll } from 'lit/decorators.js' +import { icon_settings } from '../lib/icons.js' +import './AppDialog.js' + +@customElement('settings-dialog') +export class DashboardActions extends AppElement { + static styles = css` + .metric-selector-feedback{ + font-size: 0.4em; + padding-top: 8px; + } + + .metric-selector-feedback>div { + display: grid; + grid-template-columns: repeat(4,1fr); + grid-template-rows: repeat(2, max-content); + gap: 8px; + } + + .settings-dialog>div.metric-selector{ + display: grid; + grid-template-columns: repeat(4,max-content); + grid-template-rows: repeat(3, max-content); + gap: 8px; + + } + + .settings-dialog>div>label{ + font-size: 0.6em; + } + + input[type="checkbox"]{ + cursor: pointer; + align-self: center; + width: 1.5em; + height: 1.5em; + } + + .icon { + height: 1.6em; + } + + legend{ + text-align: center; + } + + table { + min-height: 70px; + margin-top: 8px; + width: 100%; + } + + table, th, td { + font-size: 0.8em; + border: 1px solid white; + border-collapse: collapse; + } + + tr { + height: 50%; + } + + th, td { + padding: 8px; + text-align: center; + background-color: var(--theme-widget-color); + } + ` + + @property({ type: Object }) + config + + @queryAll('input') + inputs + + static get properties () { + return { + selectedMetrics: { type: Array }, + sumSelectedSlots: { type: Number }, + isValid: { type: Boolean } + } + } + + constructor () { + super() + this.selectedMetrics = [] + this.sumSelectedSlots = 0 + this.isValid = false + } + + @property({ type: Object }) + icon + + render () { + return html` + + ${icon_settings}
Settings
+ +

Select metrics to be shown:

+
+ + + + + + + + + + + + + + + + + + + + +
+
Slots remaining: ${8 - this.sumSelectedSlots} + + ${this.renderSelectedMetrics()} +
+
+
+ ` + } + + firstUpdated () { + this.selectedMetrics = this.config.dashboardMetrics + this.sumSelectedSlots = this.selectedMetrics.length + if (this.sumSelectedSlots === 8) { + this.isValid = true + } else { + this.isValid = false + } + [...this.inputs].forEach(input => { + input.checked = this.selectedMetrics.find(metric => metric === input.name) !== undefined + }) + } + + renderSelectedMetrics () { + const selectedMetrics = [html`${[0, 1, 2, 3].map(index => html`${this.selectedMetrics[index]}`)}`] + selectedMetrics.push(html`${[4, 5, 6, 7].map(index => html`${this.selectedMetrics[index]}`)}`) + + return selectedMetrics + } + + toggleCheck (e) { + if ((e.target.checked && this.selectedMetrics.length < 4 && e.target.size > 1 && this.selectedMetrics.length + e.target.size > 4) || (e.target.checked && this.sumSelectedSlots + 1 > 8)) { + this.isValid = this.isFormValid() + e.target.checked = false + return + } + + if (e.target.checked) { + for (let index = 0; index < e.target.size; index++) { + this.selectedMetrics = [...this.selectedMetrics, e.target.name] + } + } else { + for (let index = 0; index < e.target.size; index++) { + this.selectedMetrics.splice(this.selectedMetrics.findIndex(metric => metric === e.target.name), 1) + } + } + + this.sumSelectedSlots = this.selectedMetrics.length + if (this.isFormValid()) { + this.isValid = true + } else { + this.isValid = false + } + } + + isFormValid () { + return this.sumSelectedSlots === 8 && this.selectedMetrics[3] !== this.selectedMetrics[4] + } + + close (event) { + this.dispatchEvent(new CustomEvent('close')) + if (event.detail === 'confirm') { + this.dispatchEvent(new CustomEvent('changeGuiSetting', { + detail: { + ...this.appState, + config: { + ...this.appState.config, + guiConfigs: { + dashboardMetrics: this.selectedMetrics + } + } + }, + bubbles: true, + composed: true + })) + } + } +} diff --git a/app/client/lib/icons.js b/app/client/lib/icons.js index e23328061b..78d6e13543 100644 --- a/app/client/lib/icons.js +++ b/app/client/lib/icons.js @@ -27,3 +27,4 @@ export const icon_bluetooth = svg`` export const icon_antplus = svg`` +export const icon_settings = svg`` From cac178f06d1975ea460b5acbf7ef7b43191fe09a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Wed, 22 Mar 2023 13:44:34 +0100 Subject: [PATCH 074/209] Add settable metric tiles and settings persistence Make the metric tiles settable via the settings dialog and implement persistence of these settings to the browser localStorage (partially fix #131) --- app/client/components/PerformanceDashboard.js | 62 ++++++++++++------- app/client/index.js | 16 ++++- app/client/lib/app.js | 4 +- app/client/store/appState.js | 5 +- 4 files changed, 59 insertions(+), 28 deletions(-) diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index 4e5c91324a..91492b6287 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -34,7 +34,7 @@ export class PerformanceDashboard extends AppElement { } } - dashboard-metric, dashboard-actions,dashboard-force-curve { + dashboard-metric, dashboard-actions, dashboard-force-curve { background: var(--theme-widget-color); text-align: center; position: relative; @@ -63,6 +63,32 @@ export class PerformanceDashboard extends AppElement { filter: brightness(150%); } ` + dashboardMetricComponents = (formattedMetrics, appState) => ({ + distance: html``, + + pace: html``, + + power: html``, + + stkRate: html``, + + heartRate: html` + ${formattedMetrics?.heartrateBatteryLevel?.value + ? html`` + : ''} + `, + + totalStk: html``, + + calories: html``, + + timer: html``, + + forceCurve: html``, + + actions: html`` + }) + @state({ type: Object }) dialog @@ -73,31 +99,19 @@ export class PerformanceDashboard extends AppElement { appState = APP_STATE render () { - const metrics = this.calculateFormattedMetrics(this.appState.metrics) + const metricConfig = [...new Set(this.appState.config.guiConfigs.dashboardMetrics)].reduce((prev, metricName) => { + prev.push(this.dashboardMetricComponents(this.metrics, this.appState)[metricName]) + return prev + }, []) + + this.metrics = this.calculateFormattedMetrics(this.appState.metrics) return html`
${icon_settings} ${this.dialog ? this.dialog : ''}
- - - - - ${metrics?.heartrate?.value - ? html` - - ${metrics?.heartrateBatteryLevel?.value - ? html` - - ` - : '' - } - ` - : html``} - - - - + + ${metricConfig} ` } @@ -124,10 +138,10 @@ export class PerformanceDashboard extends AppElement { const formattedMetrics = {} for (const [key, value] of Object.entries(metrics)) { const valueFormatted = fieldFormatter[key] ? fieldFormatter[key](value) : value - if (valueFormatted.value !== undefined && valueFormatted.unit !== undefined) { + if (valueFormatted?.value !== undefined && valueFormatted?.unit !== undefined) { formattedMetrics[key] = { - value: valueFormatted.value, - unit: valueFormatted.unit + value: valueFormatted?.value, + unit: valueFormatted?.unit } } else { formattedMetrics[key] = { diff --git a/app/client/index.js b/app/client/index.js index b26dfcd4e6..d81f2cd3a4 100644 --- a/app/client/index.js +++ b/app/client/index.js @@ -28,6 +28,11 @@ export class App extends LitElement { // todo: we also want a mechanism here to get notified of state changes }) + const config = this.appState.config.guiConfigs + Object.keys(config).forEach(key => { + config[key] = JSON.parse(localStorage.getItem(key)) ?? config[key] + }) + // this is how we implement changes to the global state: // once any child component sends this CustomEvent we update the global state according // to the changes that were passed to us @@ -39,13 +44,22 @@ export class App extends LitElement { this.addEventListener('triggerAction', (event) => { this.app.handleAction(event.detail) }) + + // notify the app about the triggered action + this.addEventListener('changeGuiSetting', (event) => { + Object.keys(event.detail.config.guiConfigs).forEach(key => { + localStorage.setItem(key, JSON.stringify(event.detail.config.guiConfigs[key])) + }) + + this.updateState(event.detail) + }) } // the global state is updated by replacing the appState with a copy of the new state // todo: maybe it is more convenient to just pass the state elements that should be changed? // i.e. do something like this.appState = { ..this.appState, ...newState } updateState = (newState) => { - this.appState = { ...newState } + this.appState = { ...this.appState, ...newState } } // return a deep copy of the state to other components to minimize risk of side effects diff --git a/app/client/lib/app.js b/app/client/lib/app.js index fff8a1b96f..740499806c 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -38,7 +38,7 @@ export function createApp (app) { let initialWebsocketOpenend = true function initWebsocket () { // use the native websocket implementation of browser to communicate with backend - socket = new WebSocket(`ws://${location.host}/websocket`) + socket = new WebSocket('ws://localhost:100/websocket') socket.addEventListener('open', (event) => { console.log('websocket opened') @@ -71,7 +71,7 @@ export function createApp (app) { const data = message.data switch (message.type) { case 'config': { - app.updateState({ ...app.getState(), config: data }) + app.updateState({ ...app.getState(), config: { ...app.getState().config, ...data } }) break } case 'metrics': { diff --git a/app/client/store/appState.js b/app/client/store/appState.js index 77c78e2def..454a0cd174 100644 --- a/app/client/store/appState.js +++ b/app/client/store/appState.js @@ -20,6 +20,9 @@ export const APP_STATE = { // true if upload to strava is enabled stravaUploadEnabled: false, // true if remote device shutdown is enabled - shutdownEnabled: false + shutdownEnabled: false, + guiConfigs: { + dashboardMetrics: ['distance', 'timer', 'pace', 'power', 'stkRate', 'totalStk', 'calories', 'actions'] + } } } From 28d223c1094a5ef33dd48156ed5578db3aa71104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Wed, 22 Mar 2023 15:02:16 +0100 Subject: [PATCH 075/209] Add the ability to hide icons Implement GUI setting to hide icons in exchange for increased font size (implements: #131) --- app/client/components/DashboardMetric.js | 4 +-- app/client/components/PerformanceDashboard.js | 16 +++++----- app/client/components/SettingsDialog.js | 30 +++++++++++++++++-- app/client/store/appState.js | 3 +- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/app/client/components/DashboardMetric.js b/app/client/components/DashboardMetric.js index 185c89f470..215a89a72b 100644 --- a/app/client/components/DashboardMetric.js +++ b/app/client/components/DashboardMetric.js @@ -35,7 +35,7 @@ export class DashboardMetric extends AppElement { ` @property({ type: Object }) - icon + icon = '' @property({ type: String }) unit = '' @@ -47,7 +47,7 @@ export class DashboardMetric extends AppElement { return html`
${this.icon}
- ${this.value !== undefined ? this.value : '--'} + ${this.value !== undefined ? this.value : '--'} ${this.unit}
diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index 91492b6287..22c01b5889 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -64,25 +64,25 @@ export class PerformanceDashboard extends AppElement { } ` dashboardMetricComponents = (formattedMetrics, appState) => ({ - distance: html``, + distance: html``, - pace: html``, + pace: html``, - power: html``, + power: html``, - stkRate: html``, + stkRate: html``, - heartRate: html` + heartRate: html` ${formattedMetrics?.heartrateBatteryLevel?.value ? html`` : ''} `, - totalStk: html``, + totalStk: html``, - calories: html``, + calories: html``, - timer: html``, + timer: html``, forceCurve: html``, diff --git a/app/client/components/SettingsDialog.js b/app/client/components/SettingsDialog.js index 9e15267b6e..9bec86ba31 100644 --- a/app/client/components/SettingsDialog.js +++ b/app/client/components/SettingsDialog.js @@ -6,7 +6,7 @@ */ import { AppElement, html, css } from './AppElement.js' -import { customElement, property, queryAll } from 'lit/decorators.js' +import { customElement, property, query, queryAll } from 'lit/decorators.js' import { icon_settings } from '../lib/icons.js' import './AppDialog.js' @@ -73,14 +73,26 @@ export class DashboardActions extends AppElement { text-align: center; background-color: var(--theme-widget-color); } + + .show-icons-selector { + display: flex; + gap: 8px; + } + + app-dialog > *:last-child { + margin-bottom: -24px; + } ` @property({ type: Object }) config - @queryAll('input') + @queryAll('.metric-selector>input') inputs + @query('input[name="showIcons"]') + showIconInput + static get properties () { return { selectedMetrics: { type: Array }, @@ -93,6 +105,7 @@ export class DashboardActions extends AppElement { super() this.selectedMetrics = [] this.sumSelectedSlots = 0 + this.showIcons = true this.isValid = false } @@ -132,6 +145,10 @@ export class DashboardActions extends AppElement { ${this.renderSelectedMetrics()} +

+ + +

` } @@ -139,6 +156,7 @@ export class DashboardActions extends AppElement { firstUpdated () { this.selectedMetrics = this.config.dashboardMetrics this.sumSelectedSlots = this.selectedMetrics.length + this.showIcons = this.config.showIcons if (this.sumSelectedSlots === 8) { this.isValid = true } else { @@ -147,6 +165,7 @@ export class DashboardActions extends AppElement { [...this.inputs].forEach(input => { input.checked = this.selectedMetrics.find(metric => metric === input.name) !== undefined }) + this.showIconInput.checked = this.showIcons } renderSelectedMetrics () { @@ -181,6 +200,10 @@ export class DashboardActions extends AppElement { } } + toggleIcons (e) { + this.showIcons = e.target.checked + } + isFormValid () { return this.sumSelectedSlots === 8 && this.selectedMetrics[3] !== this.selectedMetrics[4] } @@ -194,7 +217,8 @@ export class DashboardActions extends AppElement { config: { ...this.appState.config, guiConfigs: { - dashboardMetrics: this.selectedMetrics + dashboardMetrics: this.selectedMetrics, + showIcons: this.showIcons } } }, diff --git a/app/client/store/appState.js b/app/client/store/appState.js index 454a0cd174..ee1af51447 100644 --- a/app/client/store/appState.js +++ b/app/client/store/appState.js @@ -22,7 +22,8 @@ export const APP_STATE = { // true if remote device shutdown is enabled shutdownEnabled: false, guiConfigs: { - dashboardMetrics: ['distance', 'timer', 'pace', 'power', 'stkRate', 'totalStk', 'calories', 'actions'] + dashboardMetrics: ['distance', 'timer', 'pace', 'power', 'stkRate', 'totalStk', 'calories', 'actions'], + showIcons: true } } } From 457c96fe3c77aac648962a60a602dabf3e6e8b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Wed, 22 Mar 2023 20:21:28 +0100 Subject: [PATCH 076/209] Fix webSocket address bug --- app/client/lib/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/lib/app.js b/app/client/lib/app.js index 740499806c..7ce477615c 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -38,7 +38,7 @@ export function createApp (app) { let initialWebsocketOpenend = true function initWebsocket () { // use the native websocket implementation of browser to communicate with backend - socket = new WebSocket('ws://localhost:100/websocket') + socket = new WebSocket(`ws://${location.host}/websocket`) socket.addEventListener('open', (event) => { console.log('websocket opened') From 6834e3a5588effd344be254a278be8b8870ef902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Thu, 23 Mar 2023 16:08:56 +0100 Subject: [PATCH 077/209] Code refactoring and improve code consistency --- app/client/components/DashboardActions.js | 14 +-- app/client/components/DashboardForceCurve.js | 14 +-- app/client/components/DashboardMetric.js | 2 +- app/client/components/PerformanceDashboard.js | 21 ++-- app/client/components/SettingsDialog.js | 100 ++++++++---------- app/client/index.js | 14 +-- 6 files changed, 73 insertions(+), 92 deletions(-) diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index 84db932e01..e416917a11 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -74,8 +74,8 @@ export class DashboardActions extends AppElement { } ` - @state({ type: Object }) - dialog + @state() + _dialog render () { return html` @@ -95,7 +95,7 @@ export class DashboardActions extends AppElement {
${this.blePeripheralMode()}
- ${this.dialog ? this.dialog : ''} + ${this._dialog ? this._dialog : ''} ` } @@ -176,14 +176,14 @@ export class DashboardActions extends AppElement { } uploadTraining () { - this.dialog = html` + this._dialog = html` ${icon_upload}
Upload to Strava?

Do you want to finish your workout and upload it to Strava?

` function dialogClosed (event) { - this.dialog = undefined + this._dialog = undefined if (event.detail === 'confirm') { this.sendEvent('triggerAction', { command: 'uploadTraining' }) } @@ -191,14 +191,14 @@ export class DashboardActions extends AppElement { } shutdown () { - this.dialog = html` + this._dialog = html` ${icon_poweroff}
Shutdown Open Rowing Monitor?

Do you want to shutdown the device?

` function dialogClosed (event) { - this.dialog = undefined + this._dialog = undefined if (event.detail === 'confirm') { this.sendEvent('triggerAction', { command: 'shutdown' }) } diff --git a/app/client/components/DashboardForceCurve.js b/app/client/components/DashboardForceCurve.js index d73f0b55ee..5222a2e1c3 100644 --- a/app/client/components/DashboardForceCurve.js +++ b/app/client/components/DashboardForceCurve.js @@ -6,7 +6,7 @@ */ import { AppElement, html, css } from './AppElement.js' -import { customElement, property } from 'lit/decorators.js' +import { customElement, property, state } from 'lit/decorators.js' import Chart from 'chart.js/auto' @customElement('dashboard-force-curve') @@ -16,14 +16,16 @@ export class DashboardForceCurve extends AppElement { margin-top: 24px; } ` + @property({ type: Object }) value = [] - chart + @state() + _chart firstUpdated () { const ctx = this.renderRoot.querySelector('#chart').getContext('2d') - this.chart = new Chart( + this._chart = new Chart( ctx, { type: 'line', @@ -92,10 +94,10 @@ export class DashboardForceCurve extends AppElement { } render () { - if (this.chart?.data) { - this.chart.data.datasets[0].data = this.value?.map((data, index) => ({ y: data, x: index })) + if (this._chart?.data) { + this._chart.data.datasets[0].data = this.value?.map((data, index) => ({ y: data, x: index })) this.forceCurve = this.value - this.chart.update() + this._chart.update() } return html` diff --git a/app/client/components/DashboardMetric.js b/app/client/components/DashboardMetric.js index 215a89a72b..18d7a9f83c 100644 --- a/app/client/components/DashboardMetric.js +++ b/app/client/components/DashboardMetric.js @@ -41,7 +41,7 @@ export class DashboardMetric extends AppElement { unit = '' @property({ type: String }) - value = '' + value render () { return html` diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index 22c01b5889..bca882145e 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -6,8 +6,7 @@ */ import { AppElement, html, css } from './AppElement.js' -import { APP_STATE } from '../store/appState.js' -import { customElement, property, state } from 'lit/decorators.js' +import { customElement, state } from 'lit/decorators.js' import './DashboardForceCurve.js' import './DashboardMetric.js' import './DashboardActions.js' @@ -63,6 +62,9 @@ export class PerformanceDashboard extends AppElement { filter: brightness(150%); } ` + @state() + _dialog + dashboardMetricComponents = (formattedMetrics, appState) => ({ distance: html``, @@ -89,15 +91,6 @@ export class PerformanceDashboard extends AppElement { actions: html`` }) - @state({ type: Object }) - dialog - - @property({ type: Object }) - metrics - - @property({ type: Object }) - appState = APP_STATE - render () { const metricConfig = [...new Set(this.appState.config.guiConfigs.dashboardMetrics)].reduce((prev, metricName) => { prev.push(this.dashboardMetricComponents(this.metrics, this.appState)[metricName]) @@ -108,7 +101,7 @@ export class PerformanceDashboard extends AppElement { return html`
${icon_settings} - ${this.dialog ? this.dialog : ''} + ${this._dialog ? this._dialog : ''}
${metricConfig} @@ -116,10 +109,10 @@ export class PerformanceDashboard extends AppElement { } openSettings () { - this.dialog = html`` + this._dialog = html`` function dialogClosed (event) { - this.dialog = undefined + this._dialog = undefined } } diff --git a/app/client/components/SettingsDialog.js b/app/client/components/SettingsDialog.js index 9bec86ba31..d76c1cf5e0 100644 --- a/app/client/components/SettingsDialog.js +++ b/app/client/components/SettingsDialog.js @@ -6,7 +6,7 @@ */ import { AppElement, html, css } from './AppElement.js' -import { customElement, property, query, queryAll } from 'lit/decorators.js' +import { customElement, property, query, queryAll, state } from 'lit/decorators.js' import { icon_settings } from '../lib/icons.js' import './AppDialog.js' @@ -85,36 +85,29 @@ export class DashboardActions extends AppElement { ` @property({ type: Object }) - config + config = {} @queryAll('.metric-selector>input') - inputs + _inputs @query('input[name="showIcons"]') - showIconInput + _showIconInput - static get properties () { - return { - selectedMetrics: { type: Array }, - sumSelectedSlots: { type: Number }, - isValid: { type: Boolean } - } - } + @state() + _selectedMetrics = [] - constructor () { - super() - this.selectedMetrics = [] - this.sumSelectedSlots = 0 - this.showIcons = true - this.isValid = false - } + @state() + _sumSelectedSlots = 0 - @property({ type: Object }) - icon + @state() + _isValid = false + + @state() + _showIcons = true render () { return html` - + ${icon_settings}
Settings

Select metrics to be shown:

@@ -140,7 +133,7 @@ export class DashboardActions extends AppElement { -
Slots remaining: ${8 - this.sumSelectedSlots} +
Slots remaining: ${8 - this._sumSelectedSlots} ${this.renderSelectedMetrics()}
@@ -154,77 +147,74 @@ export class DashboardActions extends AppElement { } firstUpdated () { - this.selectedMetrics = this.config.dashboardMetrics - this.sumSelectedSlots = this.selectedMetrics.length - this.showIcons = this.config.showIcons - if (this.sumSelectedSlots === 8) { - this.isValid = true + this._selectedMetrics = [...this.config.dashboardMetrics] + this._sumSelectedSlots = this._selectedMetrics.length + this._showIcons = this.config.showIcons + if (this._sumSelectedSlots === 8) { + this._isValid = true } else { - this.isValid = false + this._isValid = false } - [...this.inputs].forEach(input => { - input.checked = this.selectedMetrics.find(metric => metric === input.name) !== undefined + [...this._inputs].forEach(input => { + input.checked = this._selectedMetrics.find(metric => metric === input.name) !== undefined }) - this.showIconInput.checked = this.showIcons + this._showIconInput.checked = this._showIcons } renderSelectedMetrics () { - const selectedMetrics = [html`${[0, 1, 2, 3].map(index => html`${this.selectedMetrics[index]}`)}`] - selectedMetrics.push(html`${[4, 5, 6, 7].map(index => html`${this.selectedMetrics[index]}`)}`) + const selectedMetrics = [html`${[0, 1, 2, 3].map(index => html`${this._selectedMetrics[index]}`)}`] + selectedMetrics.push(html`${[4, 5, 6, 7].map(index => html`${this._selectedMetrics[index]}`)}`) return selectedMetrics } toggleCheck (e) { - if ((e.target.checked && this.selectedMetrics.length < 4 && e.target.size > 1 && this.selectedMetrics.length + e.target.size > 4) || (e.target.checked && this.sumSelectedSlots + 1 > 8)) { - this.isValid = this.isFormValid() + if ((e.target.checked && this._selectedMetrics.length < 4 && e.target.size > 1 && this._selectedMetrics.length + e.target.size > 4) || (e.target.checked && this._sumSelectedSlots + 1 > 8)) { + this._isValid = this.isFormValid() e.target.checked = false return } if (e.target.checked) { for (let index = 0; index < e.target.size; index++) { - this.selectedMetrics = [...this.selectedMetrics, e.target.name] + this._selectedMetrics = [...this._selectedMetrics, e.target.name] } } else { for (let index = 0; index < e.target.size; index++) { - this.selectedMetrics.splice(this.selectedMetrics.findIndex(metric => metric === e.target.name), 1) + this._selectedMetrics.splice(this._selectedMetrics.findIndex(metric => metric === e.target.name), 1) + this._selectedMetrics = [...this._selectedMetrics] } } - this.sumSelectedSlots = this.selectedMetrics.length + this._sumSelectedSlots = this._selectedMetrics.length if (this.isFormValid()) { - this.isValid = true + this._isValid = true } else { - this.isValid = false + this._isValid = false } } toggleIcons (e) { - this.showIcons = e.target.checked + this._showIcons = e.target.checked } isFormValid () { - return this.sumSelectedSlots === 8 && this.selectedMetrics[3] !== this.selectedMetrics[4] + return this._sumSelectedSlots === 8 && this._selectedMetrics[3] !== this._selectedMetrics[4] } close (event) { this.dispatchEvent(new CustomEvent('close')) if (event.detail === 'confirm') { - this.dispatchEvent(new CustomEvent('changeGuiSetting', { - detail: { - ...this.appState, - config: { - ...this.appState.config, - guiConfigs: { - dashboardMetrics: this.selectedMetrics, - showIcons: this.showIcons - } + this.sendEvent('changeGuiSetting', { + ...this.appState, + config: { + ...this.appState.config, + guiConfigs: { + dashboardMetrics: this._selectedMetrics, + showIcons: this._showIcons } - }, - bubbles: true, - composed: true - })) + } + }) } } } diff --git a/app/client/index.js b/app/client/index.js index d81f2cd3a4..a4ce57e6a7 100644 --- a/app/client/index.js +++ b/app/client/index.js @@ -14,10 +14,7 @@ import './components/PerformanceDashboard.js' @customElement('web-app') export class App extends LitElement { @state() - appState = APP_STATE - - @state() - metrics + _appState = APP_STATE constructor () { super() @@ -28,7 +25,7 @@ export class App extends LitElement { // todo: we also want a mechanism here to get notified of state changes }) - const config = this.appState.config.guiConfigs + const config = this._appState.config.guiConfigs Object.keys(config).forEach(key => { config[key] = JSON.parse(localStorage.getItem(key)) ?? config[key] }) @@ -59,14 +56,14 @@ export class App extends LitElement { // todo: maybe it is more convenient to just pass the state elements that should be changed? // i.e. do something like this.appState = { ..this.appState, ...newState } updateState = (newState) => { - this.appState = { ...this.appState, ...newState } + this._appState = { ...this._appState, ...newState } } // return a deep copy of the state to other components to minimize risk of side effects getState = () => { // could use structuredClone once the browser support is wider // https://developer.mozilla.org/en-US/docs/Web/API/structuredClone - return JSON.parse(JSON.stringify(this.appState)) + return JSON.parse(JSON.stringify(this._appState)) } // once we have multiple views, then we would rather reference some kind of router here @@ -74,8 +71,7 @@ export class App extends LitElement { render () { return html` ` } From fe5a7e7ed13890ab3d48bb37b0ea692574220ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Thu, 23 Mar 2023 18:14:44 +0100 Subject: [PATCH 078/209] Remove dependency on server formatted values Remove dependency on metric formatting logic at the server. Implement the formatting of the raw data on the client side. Make adding new metric tiles more modular and extensible via simplified creation API --- app/client/components/PerformanceDashboard.js | 70 ++++--------------- app/client/components/SettingsDialog.js | 31 +++----- app/client/lib/app.js | 21 +----- app/client/lib/helper.js | 56 +++++++++++++++ app/client/store/dashboardMetrics.js | 35 ++++++++++ 5 files changed, 114 insertions(+), 99 deletions(-) create mode 100644 app/client/store/dashboardMetrics.js diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index bca882145e..48c1620d1e 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -7,12 +7,9 @@ import { AppElement, html, css } from './AppElement.js' import { customElement, state } from 'lit/decorators.js' -import './DashboardForceCurve.js' -import './DashboardMetric.js' -import './DashboardActions.js' -import './BatteryIcon.js' import './SettingsDialog' -import { icon_route, icon_stopwatch, icon_bolt, icon_paddle, icon_heartbeat, icon_fire, icon_clock, icon_settings } from '../lib/icons.js' +import { icon_settings } from '../lib/icons.js' +import { DASHBOARD_METRICS } from '../store/dashboardMetrics.js' @customElement('performance-dashboard') export class PerformanceDashboard extends AppElement { @@ -65,39 +62,25 @@ export class PerformanceDashboard extends AppElement { @state() _dialog - dashboardMetricComponents = (formattedMetrics, appState) => ({ - distance: html``, + dashboardMetricComponentsFactory = (appState) => { + const metrics = appState.metrics + const configs = appState.config.guiConfigs - pace: html``, + const dashboardMetricComponents = Object.keys(DASHBOARD_METRICS).reduce((dashboardMetrics, key) => { + dashboardMetrics[key] = DASHBOARD_METRICS[key].template(metrics, configs.showIcons) - power: html``, + return dashboardMetrics + }, {}) - stkRate: html``, - - heartRate: html` - ${formattedMetrics?.heartrateBatteryLevel?.value - ? html`` - : ''} - `, - - totalStk: html``, - - calories: html``, - - timer: html``, - - forceCurve: html``, - - actions: html`` - }) + return dashboardMetricComponents + } render () { const metricConfig = [...new Set(this.appState.config.guiConfigs.dashboardMetrics)].reduce((prev, metricName) => { - prev.push(this.dashboardMetricComponents(this.metrics, this.appState)[metricName]) + prev.push(this.dashboardMetricComponentsFactory(this.appState)[metricName]) return prev }, []) - this.metrics = this.calculateFormattedMetrics(this.appState.metrics) return html`
${icon_settings} @@ -115,33 +98,4 @@ export class PerformanceDashboard extends AppElement { this._dialog = undefined } } - - // todo: so far this is just a port of the formatter from the initial proof of concept client - // we could split this up to make it more readable and testable - calculateFormattedMetrics (metrics) { - const fieldFormatter = { - totalLinearDistanceFormatted: (value) => value >= 10000 - ? { value: (value / 1000).toFixed(2), unit: 'km' } - : { value: Math.round(value), unit: 'm' }, - totalCalories: (value) => Math.round(value), - cyclePower: (value) => Math.round(value), - cycleStrokeRate: (value) => Math.round(value) - } - - const formattedMetrics = {} - for (const [key, value] of Object.entries(metrics)) { - const valueFormatted = fieldFormatter[key] ? fieldFormatter[key](value) : value - if (valueFormatted?.value !== undefined && valueFormatted?.unit !== undefined) { - formattedMetrics[key] = { - value: valueFormatted?.value, - unit: valueFormatted?.unit - } - } else { - formattedMetrics[key] = { - value: valueFormatted - } - } - } - return formattedMetrics - } } diff --git a/app/client/components/SettingsDialog.js b/app/client/components/SettingsDialog.js index d76c1cf5e0..e6b1f7b631 100644 --- a/app/client/components/SettingsDialog.js +++ b/app/client/components/SettingsDialog.js @@ -9,6 +9,7 @@ import { AppElement, html, css } from './AppElement.js' import { customElement, property, query, queryAll, state } from 'lit/decorators.js' import { icon_settings } from '../lib/icons.js' import './AppDialog.js' +import { DASHBOARD_METRICS } from '../store/dashboardMetrics.js' @customElement('settings-dialog') export class DashboardActions extends AppElement { @@ -28,9 +29,7 @@ export class DashboardActions extends AppElement { .settings-dialog>div.metric-selector{ display: grid; grid-template-columns: repeat(4,max-content); - grid-template-rows: repeat(3, max-content); gap: 8px; - } .settings-dialog>div>label{ @@ -112,26 +111,7 @@ export class DashboardActions extends AppElement {

Select metrics to be shown:

- - - - - - - - - - - - - - - - - - - - + ${this.renderAvailableMetricList()}
Slots remaining: ${8 - this._sumSelectedSlots} @@ -161,6 +141,13 @@ export class DashboardActions extends AppElement { this._showIconInput.checked = this._showIcons } + renderAvailableMetricList () { + return Object.keys(DASHBOARD_METRICS).map(key => html` + + + `) + } + renderSelectedMetrics () { const selectedMetrics = [html`${[0, 1, 2, 3].map(index => html``)}`] selectedMetrics.push(html`${[4, 5, 6, 7].map(index => html``)}`) diff --git a/app/client/lib/app.js b/app/client/lib/app.js index 7ce477615c..214c4d54a6 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -8,9 +8,6 @@ import NoSleep from 'nosleep.js' import { filterObjectByKeys } from './helper.js' -const rowingMetricsFields = ['totalNumberOfStrokes', 'totalLinearDistanceFormatted', 'totalCalories', 'cyclePower', 'heartrate', - 'heartrateBatteryLevel', 'cyclePaceFormatted', 'cycleStrokeRate', 'totalMovingTimeFormatted', 'driveHandleForceCurve'] - export function createApp (app) { const urlParameters = new URLSearchParams(window.location.search) const mode = urlParameters.get('mode') @@ -75,20 +72,7 @@ export function createApp (app) { break } case 'metrics': { - let activeFields = rowingMetricsFields - // if we are in reset state only update heart rate and peripheral mode - if (data.totalNumberOfStrokes < 1) { - if (data.totalLinearDistanceFormatted > 0) { - activeFields = ['totalLinearDistanceFormatted', 'heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve'] - } else if (data.totalMovingTimeFormatted !== '00:00') { - activeFields = ['totalMovingTimeFormatted', 'heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve'] - } else { - activeFields = ['heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve'] - } - } - - const filteredData = filterObjectByKeys(data, activeFields) - app.updateState({ ...app.getState(), metrics: filteredData }) + app.updateState({ ...app.getState(), metrics: data }) break } case 'authorizeStrava': { @@ -124,8 +108,7 @@ export function createApp (app) { function resetFields () { const appState = app.getState() // drop all metrics except heartrate - appState.metrics = filterObjectByKeys(appState.metrics, ['heartrate', 'heartrateBatteryLevel']) - app.updateState(appState) + app.updateState({ ...appState, metrics: { ...filterObjectByKeys(appState.metrics, ['heartrate', 'heartrateBatteryLevel']) } }) } function handleAction (action) { diff --git a/app/client/lib/helper.js b/app/client/lib/helper.js index 16bae1394f..1bca643560 100644 --- a/app/client/lib/helper.js +++ b/app/client/lib/helper.js @@ -1,4 +1,8 @@ 'use strict' + +import { html } from 'lit' +import '../components/DashboardMetric.js' + /* Open Rowing Monitor, https://github.com/laberning/openrowingmonitor @@ -14,3 +18,55 @@ export function filterObjectByKeys (object, keys) { return obj }, {}) } + +/** + * Pipe for converting seconds to pace format 00:00 + * + * @param seconds The actual time in seconds. +*/ +export function secondsToPace (seconds) { + const hours = Math.floor((seconds % 86400) / 3600) + const mins = Math.floor(((seconds % 86400) % 3600) / 60) + + if (seconds === undefined || seconds === null || seconds === Infinity || isNaN(seconds)) return '--' + if (hours > 0) { + return `${hours}:${mins.toString().padStart(2, '0')}:${(Math.round(seconds) % 60) + .toString() + .padStart(2, '0')}` + } else { + return `${mins}:${(Math.round(seconds) % 60).toString().padStart(2, '0')}` + } +} + +/** + * Pipe for formatting distance in meters with units + * + * @param value The distance in meters. + * @param showInMiles Boolean whether to use imperial metric (default: false). +*/ +export function formatDistance (value, showInMiles = false) { + if (showInMiles === false) { + return value >= 10000 + ? { distance: formatNumber((value / 1000), 2), unit: 'km' } + : { distance: formatNumber(value), unit: 'm' } + } + + return { distance: formatNumber((value / 1609.344), 2), unit: 'mi' } +} + +/** + * Pipe for formatting numbers to specific decimal + * + * @param value The number. + * @param decimalPlaces The number of decimal places to round to (default: 0). +*/ +export function formatNumber (value, decimalPlaces = 0) { + const decimal = decimalPlaces > 0 ? decimalPlaces * 10 : 1 + if (value === undefined || value === null || value === Infinity || isNaN(value) || value === 0) { return '--' } + + return Math.round(value * decimal) / decimal +} + +export function simpleMetricFactory (value, unit, icon) { + return html`` +} diff --git a/app/client/store/dashboardMetrics.js b/app/client/store/dashboardMetrics.js new file mode 100644 index 0000000000..cd6ee12589 --- /dev/null +++ b/app/client/store/dashboardMetrics.js @@ -0,0 +1,35 @@ +import { html } from 'lit' +import { simpleMetricFactory, formatDistance, formatNumber, secondsToPace } from '../lib/helper' +import { icon_bolt, icon_clock, icon_fire, icon_heartbeat, icon_paddle, icon_route, icon_stopwatch } from '../lib/icons' +import '../components/DashboardForceCurve.js' +import '../components/DashboardActions.js' +import '../components/BatteryIcon.js' + +export const DASHBOARD_METRICS = { + distance: { + displayName: 'Distance', + size: 1, + template: (metrics, showIcon) => { + const linearDistance = formatDistance(metrics?.totalLinearDistance) + + return simpleMetricFactory(linearDistance.distance, linearDistance.unit, showIcon ? icon_route : '') + } + }, + pace: { displayName: 'Pace/500', size: 1, template: (metrics, showIcon) => simpleMetricFactory(secondsToPace(500 / metrics?.cycleLinearVelocity), '/500m', showIcon ? icon_stopwatch : '') }, + power: { displayName: 'Power', size: 1, template: (metrics, showIcon) => simpleMetricFactory(formatNumber(metrics?.cyclePower), 'watt', showIcon ? icon_bolt : '') }, + stkRate: { displayName: 'Stroke rate', size: 1, template: (metrics, showIcon) => simpleMetricFactory(formatNumber(metrics?.cycleStrokeRate), '/min', showIcon ? icon_paddle : '') }, + heartRate: { + displayName: 'Heart rate', + size: 1, + template: (metrics, showIcon) => html` + ${metrics?.heartrateBatteryLevel + ? html`` + : ''} +` + }, + totalStk: { displayName: 'Total strokes', size: 1, template: (metrics, showIcon) => simpleMetricFactory(metrics?.totalNumberOfStrokes, 'stk', showIcon ? icon_paddle : '') }, + calories: { displayName: 'Calories', size: 1, template: (metrics, showIcon) => simpleMetricFactory(formatNumber(metrics?.totalCalories), 'kcal', showIcon ? icon_fire : '') }, + timer: { displayName: 'Timer', size: 1, template: (metrics, showIcon) => simpleMetricFactory(secondsToPace(metrics?.totalMovingTime), '', showIcon ? icon_clock : '') }, + forceCurve: { displayName: 'Force curve', size: 2, template: (metrics) => html`` }, + actions: { displayName: 'Actions', size: 1, template: () => html`` } +} From a4ef6d86b072b691885daeca88ee7080edd542c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Thu, 23 Mar 2023 23:02:48 +0100 Subject: [PATCH 079/209] Show peak value in the force curve Add the capability of showing the peak value for the handle force curve --- app/client/components/DashboardForceCurve.js | 24 +++++++++++++++++--- package.json | 5 ++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/client/components/DashboardForceCurve.js b/app/client/components/DashboardForceCurve.js index 5222a2e1c3..74a8b7aced 100644 --- a/app/client/components/DashboardForceCurve.js +++ b/app/client/components/DashboardForceCurve.js @@ -7,7 +7,8 @@ import { AppElement, html, css } from './AppElement.js' import { customElement, property, state } from 'lit/decorators.js' -import Chart from 'chart.js/auto' +import ChartDataLabels from 'chartjs-plugin-datalabels' +import { Chart, Filler, Legend, LinearScale, LineController, LineElement, PointElement } from 'chart.js/auto' @customElement('dashboard-force-curve') export class DashboardForceCurve extends AppElement { @@ -17,6 +18,11 @@ export class DashboardForceCurve extends AppElement { } ` + constructor () { + super() + Chart.register(ChartDataLabels, Legend, Filler, LinearScale, LineController, PointElement, LineElement) + } + @property({ type: Object }) value = [] @@ -33,7 +39,7 @@ export class DashboardForceCurve extends AppElement { datasets: [ { fill: true, - data: this.value?.map((data, index) => ({ y: data, x: index })), + data: this.value?.map((data, index) => ({ y: parseInt(data, 10), x: index })), pointRadius: 1, borderColor: 'rgb(255,255,255)', backgroundColor: 'rgb(220,220,220)' @@ -44,6 +50,18 @@ export class DashboardForceCurve extends AppElement { responsive: true, maintainAspectRatio: false, plugins: { + datalabels: { + anchor: 'center', + align: 'top', + formatter: (value) => `Peak: ${Math.round(value.y)}`, + display: (ctx) => Math.max( + ...ctx.dataset.data.map((point) => point.y) + ) === ctx.dataset.data[ctx.dataIndex].y, + font: { + size: 16 + }, + color: 'rgb(255,255,255)' + }, legend: { title: { display: true, @@ -95,7 +113,7 @@ export class DashboardForceCurve extends AppElement { render () { if (this._chart?.data) { - this._chart.data.datasets[0].data = this.value?.map((data, index) => ({ y: data, x: index })) + this._chart.data.datasets[0].data = this.value?.map((data, index) => ({ y: parseInt(data, 10), x: index })) this.forceCurve = this.value this._chart.update() } diff --git a/package.json b/package.json index 60e95ad56d..518b9646b6 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "dependencies": { "@abandonware/bleno": "0.5.1-4", "@abandonware/noble": "1.9.2-15", + "chart.js": "^4.2.1", + "chartjs-plugin-datalabels": "^2.2.0", "finalhandler": "1.1.2", "form-data": "4.0.0", "incyclist-ant-plus": "^0.1.15", @@ -42,8 +44,7 @@ "pigpio": "3.3.1", "serve-static": "1.14.2", "ws": "8.5.0", - "xml2js": "0.4.23", - "chart.js": "^4.2.1" + "xml2js": "0.4.23" }, "//fix1Comment": "version 0.5.3-8 currently does not work with bleno", "optionalDependencies": { From 89432fef996db8bda80f3d6ecdd040de236b1afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Fri, 24 Mar 2023 21:35:21 +0100 Subject: [PATCH 080/209] Expose app configs to the metric tile factory Make all settings available to the metric creator factory in order for subcomponents (e.g DashboardAction) to use it without depending directly on the global appState. --- app/client/components/DashboardActions.js | 21 ++++++++++++------- app/client/components/PerformanceDashboard.js | 4 ++-- app/client/store/dashboardMetrics.js | 20 +++++++++--------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index e416917a11..e8aa034e2a 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -6,7 +6,7 @@ */ import { AppElement, html, css } from './AppElement.js' -import { customElement, state } from 'lit/decorators.js' +import { customElement, property, state } from 'lit/decorators.js' import { icon_undo, icon_expand, icon_compress, icon_poweroff, icon_bluetooth, icon_upload, icon_heartbeat, icon_antplus } from '../lib/icons.js' import './AppDialog.js' @@ -74,6 +74,12 @@ export class DashboardActions extends AppElement { } ` + @property({ type: Object }) + config = {} + + @property({ type: Object }) + appMode = 'BROWSER' + @state() _dialog @@ -84,11 +90,11 @@ export class DashboardActions extends AppElement { ${this.renderOptionalButtons()}
@@ -104,7 +110,7 @@ export class DashboardActions extends AppElement { // changing to fullscreen mode only makes sence when the app is openend in a regular // webbrowser (kiosk and standalone mode are always in fullscreen view) and if the // browser supports this feature - if (this.appState?.appMode === 'BROWSER' && document.documentElement.requestFullscreen) { + if (this.appMode === 'BROWSER' && document.documentElement.requestFullscreen) { buttons.push(html` `) } - if (this.appState?.config?.stravaUploadEnabled) { + if (this.config?.stravaUploadEnabled) { buttons.push(html` `) @@ -130,8 +136,7 @@ export class DashboardActions extends AppElement { } blePeripheralMode () { - const value = this.appState?.config?.blePeripheralMode - + const value = this.config?.blePeripheralMode switch (value) { case 'PM5': return 'C2 PM5' diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index 48c1620d1e..5b6f2442ff 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -64,10 +64,10 @@ export class PerformanceDashboard extends AppElement { dashboardMetricComponentsFactory = (appState) => { const metrics = appState.metrics - const configs = appState.config.guiConfigs + const configs = appState.config const dashboardMetricComponents = Object.keys(DASHBOARD_METRICS).reduce((dashboardMetrics, key) => { - dashboardMetrics[key] = DASHBOARD_METRICS[key].template(metrics, configs.showIcons) + dashboardMetrics[key] = DASHBOARD_METRICS[key].template(metrics, configs) return dashboardMetrics }, {}) diff --git a/app/client/store/dashboardMetrics.js b/app/client/store/dashboardMetrics.js index cd6ee12589..3d3975db6d 100644 --- a/app/client/store/dashboardMetrics.js +++ b/app/client/store/dashboardMetrics.js @@ -9,27 +9,27 @@ export const DASHBOARD_METRICS = { distance: { displayName: 'Distance', size: 1, - template: (metrics, showIcon) => { + template: (metrics, config) => { const linearDistance = formatDistance(metrics?.totalLinearDistance) - return simpleMetricFactory(linearDistance.distance, linearDistance.unit, showIcon ? icon_route : '') + return simpleMetricFactory(linearDistance.distance, linearDistance.unit, config.guiConfigs.showIcons ? icon_route : '') } }, - pace: { displayName: 'Pace/500', size: 1, template: (metrics, showIcon) => simpleMetricFactory(secondsToPace(500 / metrics?.cycleLinearVelocity), '/500m', showIcon ? icon_stopwatch : '') }, - power: { displayName: 'Power', size: 1, template: (metrics, showIcon) => simpleMetricFactory(formatNumber(metrics?.cyclePower), 'watt', showIcon ? icon_bolt : '') }, - stkRate: { displayName: 'Stroke rate', size: 1, template: (metrics, showIcon) => simpleMetricFactory(formatNumber(metrics?.cycleStrokeRate), '/min', showIcon ? icon_paddle : '') }, + pace: { displayName: 'Pace/500', size: 1, template: (metrics, config) => simpleMetricFactory(secondsToPace(500 / metrics?.cycleLinearVelocity), '/500m', config.guiConfigs.showIcons ? icon_stopwatch : '') }, + power: { displayName: 'Power', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cyclePower), 'watt', config.guiConfigs.showIcons ? icon_bolt : '') }, + stkRate: { displayName: 'Stroke rate', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cycleStrokeRate), '/min', config.guiConfigs.showIcons ? icon_paddle : '') }, heartRate: { displayName: 'Heart rate', size: 1, - template: (metrics, showIcon) => html` + template: (metrics, config) => html` ${metrics?.heartrateBatteryLevel ? html`` : ''} ` }, - totalStk: { displayName: 'Total strokes', size: 1, template: (metrics, showIcon) => simpleMetricFactory(metrics?.totalNumberOfStrokes, 'stk', showIcon ? icon_paddle : '') }, - calories: { displayName: 'Calories', size: 1, template: (metrics, showIcon) => simpleMetricFactory(formatNumber(metrics?.totalCalories), 'kcal', showIcon ? icon_fire : '') }, - timer: { displayName: 'Timer', size: 1, template: (metrics, showIcon) => simpleMetricFactory(secondsToPace(metrics?.totalMovingTime), '', showIcon ? icon_clock : '') }, + totalStk: { displayName: 'Total strokes', size: 1, template: (metrics, config) => simpleMetricFactory(metrics?.totalNumberOfStrokes, 'stk', config.guiConfigs.showIcons ? icon_paddle : '') }, + calories: { displayName: 'Calories', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.totalCalories), 'kcal', config.guiConfigs.showIcons ? icon_fire : '') }, + timer: { displayName: 'Timer', size: 1, template: (metrics, config) => simpleMetricFactory(secondsToPace(metrics?.totalMovingTime), '', config.guiConfigs.showIcons ? icon_clock : '') }, forceCurve: { displayName: 'Force curve', size: 2, template: (metrics) => html`` }, - actions: { displayName: 'Actions', size: 1, template: () => html`` } + actions: { displayName: 'Actions', size: 1, template: (appState, config) => html`` } } From 5b44b88c398d7ea745a0b4de2b65120d74f38f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Fri, 24 Mar 2023 21:42:07 +0100 Subject: [PATCH 081/209] Change `changeGuiSetting` event API Restrict the event payload to data this component is responsible for and handle immutable object construction at the main event handler side. --- app/client/components/SettingsDialog.js | 10 ++-------- app/client/index.js | 7 +++---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/app/client/components/SettingsDialog.js b/app/client/components/SettingsDialog.js index e6b1f7b631..d3440cea02 100644 --- a/app/client/components/SettingsDialog.js +++ b/app/client/components/SettingsDialog.js @@ -193,14 +193,8 @@ export class DashboardActions extends AppElement { this.dispatchEvent(new CustomEvent('close')) if (event.detail === 'confirm') { this.sendEvent('changeGuiSetting', { - ...this.appState, - config: { - ...this.appState.config, - guiConfigs: { - dashboardMetrics: this._selectedMetrics, - showIcons: this._showIcons - } - } + dashboardMetrics: this._selectedMetrics, + showIcons: this._showIcons }) } } diff --git a/app/client/index.js b/app/client/index.js index a4ce57e6a7..b88be5bc6d 100644 --- a/app/client/index.js +++ b/app/client/index.js @@ -44,11 +44,10 @@ export class App extends LitElement { // notify the app about the triggered action this.addEventListener('changeGuiSetting', (event) => { - Object.keys(event.detail.config.guiConfigs).forEach(key => { - localStorage.setItem(key, JSON.stringify(event.detail.config.guiConfigs[key])) + Object.keys(event.detail).forEach(key => { + localStorage.setItem(key, JSON.stringify(event.detail[key])) }) - - this.updateState(event.detail) + this.updateState({ config: { ...this._appState.config, guiConfigs: { ...event.detail } } }) }) } From 11db116f5e397479ba03d05a21dcd9fd52159e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Fri, 24 Mar 2023 21:55:55 +0100 Subject: [PATCH 082/209] Remove global appState property Remove appState property from the base class to avoid property drilling. Expose full appState to those components only that really need it in order to decouple dependency on global objects to prevent potential future issues when refactoring and making changes. --- app/client/components/AppElement.js | 13 ------------- app/client/components/PerformanceDashboard.js | 7 +++++-- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/app/client/components/AppElement.js b/app/client/components/AppElement.js index efe6c39454..59b00cabed 100644 --- a/app/client/components/AppElement.js +++ b/app/client/components/AppElement.js @@ -6,22 +6,9 @@ */ import { LitElement } from 'lit' -import { property } from 'lit/decorators.js' -import { APP_STATE } from '../store/appState.js' export * from 'lit' export class AppElement extends LitElement { - // this is how we implement a global state: a global state object is passed via properties - // to child components - @property({ type: Object }) - appState = APP_STATE - - // ..and state changes are send back to the root component of the app by dispatching - // a CustomEvent - updateState () { - this.sendEvent('appStateChanged', this.appState) - } - // a helper to dispatch events to the parent components sendEvent (eventType, eventData) { this.dispatchEvent( diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index 5b6f2442ff..0e12ad44f8 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -6,7 +6,7 @@ */ import { AppElement, html, css } from './AppElement.js' -import { customElement, state } from 'lit/decorators.js' +import { customElement, property, state } from 'lit/decorators.js' import './SettingsDialog' import { icon_settings } from '../lib/icons.js' import { DASHBOARD_METRICS } from '../store/dashboardMetrics.js' @@ -20,7 +20,7 @@ export class PerformanceDashboard extends AppElement { padding: 1vw; grid-gap: 1vw; grid-template-columns: repeat(4, minmax(0, 1fr)); - grid-template-rows: repeat(2, minmax(0, 1fr)); + grid-template-rows: repeat(3, minmax(0, 1fr)); } @media (orientation: portrait) { @@ -59,6 +59,9 @@ export class PerformanceDashboard extends AppElement { filter: brightness(150%); } ` + @property() + appState = {} + @state() _dialog From 594f8099c3a67462d33c7e59ea8922252b5be83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 14:22:37 +0100 Subject: [PATCH 083/209] Change settings styling and fix a formatter bug --- app/client/components/SettingsDialog.js | 33 ++++++++++++++----------- app/client/lib/helper.js | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/app/client/components/SettingsDialog.js b/app/client/components/SettingsDialog.js index d3440cea02..7ada79635a 100644 --- a/app/client/components/SettingsDialog.js +++ b/app/client/components/SettingsDialog.js @@ -15,25 +15,19 @@ import { DASHBOARD_METRICS } from '../store/dashboardMetrics.js' export class DashboardActions extends AppElement { static styles = css` .metric-selector-feedback{ - font-size: 0.4em; + font-size: 0.5em; padding-top: 8px; } - .metric-selector-feedback>div { - display: grid; - grid-template-columns: repeat(4,1fr); - grid-template-rows: repeat(2, max-content); - gap: 8px; - } - .settings-dialog>div.metric-selector{ display: grid; - grid-template-columns: repeat(4,max-content); + grid-template-columns: repeat(3,max-content); gap: 8px; } .settings-dialog>div>label{ font-size: 0.6em; + width: fit-content; } input[type="checkbox"]{ @@ -43,6 +37,12 @@ export class DashboardActions extends AppElement { height: 1.5em; } + label>span { + cursor: pointer; + -webkit-user-select: none; + user-select: none; + } + .icon { height: 1.6em; } @@ -58,7 +58,7 @@ export class DashboardActions extends AppElement { } table, th, td { - font-size: 0.8em; + font-size: 0.9em; border: 1px solid white; border-collapse: collapse; } @@ -86,7 +86,7 @@ export class DashboardActions extends AppElement { @property({ type: Object }) config = {} - @queryAll('.metric-selector>input') + @queryAll('.metric-selector input') _inputs @query('input[name="showIcons"]') @@ -119,8 +119,10 @@ export class DashboardActions extends AppElement {
${this._selectedMetrics[index]}
${this._selectedMetrics[index]}

- - +

` @@ -143,8 +145,9 @@ export class DashboardActions extends AppElement { renderAvailableMetricList () { return Object.keys(DASHBOARD_METRICS).map(key => html` - - + `) } diff --git a/app/client/lib/helper.js b/app/client/lib/helper.js index 1bca643560..e4fab7ce02 100644 --- a/app/client/lib/helper.js +++ b/app/client/lib/helper.js @@ -61,7 +61,7 @@ export function formatDistance (value, showInMiles = false) { * @param decimalPlaces The number of decimal places to round to (default: 0). */ export function formatNumber (value, decimalPlaces = 0) { - const decimal = decimalPlaces > 0 ? decimalPlaces * 10 : 1 + const decimal = Math.pow(10, decimalPlaces) if (value === undefined || value === null || value === Infinity || isNaN(value) || value === 0) { return '--' } return Math.round(value * decimal) / decimal From bf55638e82accb82426ee5b65391507f1c3a7a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 14:27:18 +0100 Subject: [PATCH 084/209] Add new metric tiles - Add drag factor (int) - Add distance per stroke (meters with 1 decimal place) - Add drive length (meters with 2 decimal places) - Add drive duration (seconds with 2 decimal places) - Add recovery duration (seconds with 2 decimal places) --- app/client/lib/icons.js | 1 + app/client/store/dashboardMetrics.js | 28 +++++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/client/lib/icons.js b/app/client/lib/icons.js index 78d6e13543..4adea7a67b 100644 --- a/app/client/lib/icons.js +++ b/app/client/lib/icons.js @@ -28,3 +28,4 @@ export const icon_upload = svg`` export const icon_settings = svg`` +export const rower_icon = svg`` diff --git a/app/client/store/dashboardMetrics.js b/app/client/store/dashboardMetrics.js index 3d3975db6d..300db7b6ab 100644 --- a/app/client/store/dashboardMetrics.js +++ b/app/client/store/dashboardMetrics.js @@ -1,6 +1,6 @@ import { html } from 'lit' import { simpleMetricFactory, formatDistance, formatNumber, secondsToPace } from '../lib/helper' -import { icon_bolt, icon_clock, icon_fire, icon_heartbeat, icon_paddle, icon_route, icon_stopwatch } from '../lib/icons' +import { icon_bolt, icon_clock, icon_fire, icon_heartbeat, icon_paddle, icon_route, icon_stopwatch, rower_icon } from '../lib/icons' import '../components/DashboardForceCurve.js' import '../components/DashboardActions.js' import '../components/BatteryIcon.js' @@ -15,21 +15,39 @@ export const DASHBOARD_METRICS = { return simpleMetricFactory(linearDistance.distance, linearDistance.unit, config.guiConfigs.showIcons ? icon_route : '') } }, + pace: { displayName: 'Pace/500', size: 1, template: (metrics, config) => simpleMetricFactory(secondsToPace(500 / metrics?.cycleLinearVelocity), '/500m', config.guiConfigs.showIcons ? icon_stopwatch : '') }, + power: { displayName: 'Power', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cyclePower), 'watt', config.guiConfigs.showIcons ? icon_bolt : '') }, + stkRate: { displayName: 'Stroke rate', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cycleStrokeRate), '/min', config.guiConfigs.showIcons ? icon_paddle : '') }, heartRate: { displayName: 'Heart rate', size: 1, template: (metrics, config) => html` - ${metrics?.heartrateBatteryLevel - ? html`` - : ''} -` + ${metrics?.heartrateBatteryLevel + ? html`` + : ''} + ` }, + totalStk: { displayName: 'Total strokes', size: 1, template: (metrics, config) => simpleMetricFactory(metrics?.totalNumberOfStrokes, 'stk', config.guiConfigs.showIcons ? icon_paddle : '') }, + calories: { displayName: 'Calories', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.totalCalories), 'kcal', config.guiConfigs.showIcons ? icon_fire : '') }, + timer: { displayName: 'Timer', size: 1, template: (metrics, config) => simpleMetricFactory(secondsToPace(metrics?.totalMovingTime), '', config.guiConfigs.showIcons ? icon_clock : '') }, + + distancePerStk: { displayName: 'Dist per Stroke', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cycleDistance, 1), 'm', config.guiConfigs.showIcons ? rower_icon : '') }, + + dragFactor: { displayName: 'Drag factor', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.dragFactor), '', config.guiConfigs.showIcons ? 'Drag' : '') }, + + driveLength: { displayName: 'Drive length', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.driveLength, 2), 'm', config.guiConfigs.showIcons ? 'Drive' : '') }, + + driveDuration: { displayName: 'Drive duration', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.driveDuration, 2), 'sec', config.guiConfigs.showIcons ? 'Drive' : '') }, + + recoveryDuration: { displayName: 'Recovery duration', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.recoveryDuration, 2), 'sec', config.guiConfigs.showIcons ? 'Recovery' : '') }, + forceCurve: { displayName: 'Force curve', size: 2, template: (metrics) => html`` }, + actions: { displayName: 'Actions', size: 1, template: (appState, config) => html`` } } From 74a73c571a64b672359a4ff2eb7584fcc65cf946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 17:15:54 +0100 Subject: [PATCH 085/209] Add experimental 12 cell grid mode Implement 12 cell grid mode to show allow showing more metrics. Experimental means that this layout will not render properly on every screen size (though should work on bigger screens well). That would require more media queries and css logic to tweak the styling This may be implemented at a later stage. --- app/client/components/PerformanceDashboard.js | 6 +- app/client/components/SettingsDialog.js | 63 +++++++++++++++++-- app/client/store/appState.js | 3 +- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/app/client/components/PerformanceDashboard.js b/app/client/components/PerformanceDashboard.js index 0e12ad44f8..4ab15dbb33 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -20,7 +20,6 @@ export class PerformanceDashboard extends AppElement { padding: 1vw; grid-gap: 1vw; grid-template-columns: repeat(4, minmax(0, 1fr)); - grid-template-rows: repeat(3, minmax(0, 1fr)); } @media (orientation: portrait) { @@ -85,6 +84,11 @@ export class PerformanceDashboard extends AppElement { }, []) return html` +
${icon_settings} ${this._dialog ? this._dialog : ''} diff --git a/app/client/components/SettingsDialog.js b/app/client/components/SettingsDialog.js index 7ada79635a..8bd7fd01b9 100644 --- a/app/client/components/SettingsDialog.js +++ b/app/client/components/SettingsDialog.js @@ -25,6 +25,21 @@ export class DashboardActions extends AppElement { gap: 8px; } + .experimental-settings { + display: flex; + flex-direction: column; + } + + .experimental-settings label { + width: fit-content; + margin-top: 8px; + font-size: 0.7em; + } + + .experimental-settings label>input { + font-size: 0.7em; + } + .settings-dialog>div>label{ font-size: 0.6em; width: fit-content; @@ -92,6 +107,9 @@ export class DashboardActions extends AppElement { @query('input[name="showIcons"]') _showIconInput + @query('input[name="maxNumberOfTiles"]') + _maxNumberOfTilesInput + @state() _selectedMetrics = [] @@ -104,6 +122,9 @@ export class DashboardActions extends AppElement { @state() _showIcons = true + @state() + _maxNumberOfTiles = 8 + render () { return html` @@ -113,7 +134,7 @@ export class DashboardActions extends AppElement {
${this.renderAvailableMetricList()}
-
Slots remaining: ${8 - this._sumSelectedSlots} +
Slots remaining: ${this._maxNumberOfTiles - this._sumSelectedSlots} ${this.renderSelectedMetrics()}
@@ -124,6 +145,13 @@ export class DashboardActions extends AppElement {

+

+ Experimental settings: + +

` } @@ -132,7 +160,8 @@ export class DashboardActions extends AppElement { this._selectedMetrics = [...this.config.dashboardMetrics] this._sumSelectedSlots = this._selectedMetrics.length this._showIcons = this.config.showIcons - if (this._sumSelectedSlots === 8) { + this._maxNumberOfTiles = this.config.maxNumberOfTiles + if (this._sumSelectedSlots === this._maxNumberOfTiles) { this._isValid = true } else { this._isValid = false @@ -141,6 +170,7 @@ export class DashboardActions extends AppElement { input.checked = this._selectedMetrics.find(metric => metric === input.name) !== undefined }) this._showIconInput.checked = this._showIcons + this._maxNumberOfTilesInput.checked = this._maxNumberOfTiles === 12 } renderAvailableMetricList () { @@ -153,13 +183,28 @@ export class DashboardActions extends AppElement { renderSelectedMetrics () { const selectedMetrics = [html`${[0, 1, 2, 3].map(index => html`${this._selectedMetrics[index]}`)}`] - selectedMetrics.push(html`${[4, 5, 6, 7].map(index => html`${this._selectedMetrics[index]}`)}`) + selectedMetrics.push(html`${[4, 5, 6, 7].map(index => html`${this._selectedMetrics[index]}`)}`) + if (this._maxNumberOfTiles === 12) { + selectedMetrics.push(html`${[8, 9, 10, 11].map(index => html`${this._selectedMetrics[index]}`)}`) + } return selectedMetrics } toggleCheck (e) { - if ((e.target.checked && this._selectedMetrics.length < 4 && e.target.size > 1 && this._selectedMetrics.length + e.target.size > 4) || (e.target.checked && this._sumSelectedSlots + 1 > 8)) { + if (e.target.checked && + ((this._selectedMetrics.length % 4 === 3 && e.target.size > 1) || + (this._sumSelectedSlots + e.target.size > this._maxNumberOfTiles))) { this._isValid = this.isFormValid() e.target.checked = false return @@ -188,8 +233,13 @@ export class DashboardActions extends AppElement { this._showIcons = e.target.checked } + toggleMaxTiles (e) { + this._maxNumberOfTiles = e.target.checked ? 12 : 8 + this._isValid = this.isFormValid() + } + isFormValid () { - return this._sumSelectedSlots === 8 && this._selectedMetrics[3] !== this._selectedMetrics[4] + return this._sumSelectedSlots === this._maxNumberOfTiles && this._selectedMetrics[3] !== this._selectedMetrics[4] && this._selectedMetrics[7] !== this._selectedMetrics?.[8] } close (event) { @@ -197,7 +247,8 @@ export class DashboardActions extends AppElement { if (event.detail === 'confirm') { this.sendEvent('changeGuiSetting', { dashboardMetrics: this._selectedMetrics, - showIcons: this._showIcons + showIcons: this._showIcons, + maxNumberOfTiles: this._maxNumberOfTiles }) } } diff --git a/app/client/store/appState.js b/app/client/store/appState.js index ee1af51447..7865fff50e 100644 --- a/app/client/store/appState.js +++ b/app/client/store/appState.js @@ -23,7 +23,8 @@ export const APP_STATE = { shutdownEnabled: false, guiConfigs: { dashboardMetrics: ['distance', 'timer', 'pace', 'power', 'stkRate', 'totalStk', 'calories', 'actions'], - showIcons: true + showIcons: true, + maxNumberOfTiles: 8 } } } From c5bec08ea9468a0a7573faa3263798bd849d3dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 19:33:23 +0100 Subject: [PATCH 086/209] Fix styling when text is used for metric tile --- app/client/components/DashboardMetric.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/components/DashboardMetric.js b/app/client/components/DashboardMetric.js index 18d7a9f83c..76f0d5ca2f 100644 --- a/app/client/components/DashboardMetric.js +++ b/app/client/components/DashboardMetric.js @@ -45,7 +45,7 @@ export class DashboardMetric extends AppElement { render () { return html` -
${this.icon}
+
${this.icon}
${this.value !== undefined ? this.value : '--'} ${this.unit} From ee667d727a119f2f6ce0f659e5bce7d26217b157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 19:43:26 +0100 Subject: [PATCH 087/209] Prevent BLE HR monitor process crash (fixes: #135) In case of an uncaught exception in the BLE HR child process the process would crash and not restart. Add code to catch these uncaught exceptions to prevent such crash and enable code to continue. --- app/peripherals/ble/hrm/HrmService.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/peripherals/ble/hrm/HrmService.js b/app/peripherals/ble/hrm/HrmService.js index 518af51d39..00a6551160 100644 --- a/app/peripherals/ble/hrm/HrmService.js +++ b/app/peripherals/ble/hrm/HrmService.js @@ -11,7 +11,15 @@ import config from '../../../tools/ConfigManager.js' import { createHeartRateManager } from './HeartRateManager.js' log.setLevel(config.loglevel.default) -const heartRateManager = createHeartRateManager() -heartRateManager.on('heartRateMeasurement', (heartRateMeasurement) => { - process.send(heartRateMeasurement) -}) +start() + +function start () { + const heartRateManager = createHeartRateManager() + heartRateManager.on('heartRateMeasurement', (heartRateMeasurement) => { + process.send(heartRateMeasurement) + }) + + process.on('uncaughtException', (err) => { + log.error('An error occurred in BLE Heart Rate service if you experience issues with the bluetooth connection to your heart rate sensor please restart app: ', err) + }) +} From e7c40873cdb949b4d66907114b46f5e238ed118c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 20:09:24 +0100 Subject: [PATCH 088/209] Fix HR battery level not showing (fixes: #132) Fix the HR battery level not showing on the HR metric tile (ANT and BLE) For ANT handle case when BatteryLevel is not present only BatteryStatus. BLE devices do not necessarily send battery level with all HR broadcast so read the battery level on connect. --- app/client/lib/app.js | 2 +- app/client/store/dashboardMetrics.js | 4 +-- app/engine/RowingStatistics.js | 20 +++++++-------- app/peripherals/ant/HrmPeripheral.js | 27 ++++++++++++++++++++- app/peripherals/ble/hrm/HeartRateManager.js | 12 ++++++++- 5 files changed, 50 insertions(+), 15 deletions(-) diff --git a/app/client/lib/app.js b/app/client/lib/app.js index 214c4d54a6..004acaa280 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -108,7 +108,7 @@ export function createApp (app) { function resetFields () { const appState = app.getState() // drop all metrics except heartrate - app.updateState({ ...appState, metrics: { ...filterObjectByKeys(appState.metrics, ['heartrate', 'heartrateBatteryLevel']) } }) + app.updateState({ ...appState, metrics: { ...filterObjectByKeys(appState.metrics, ['heartrate', 'heartRateBatteryLevel']) } }) } function handleAction (action) { diff --git a/app/client/store/dashboardMetrics.js b/app/client/store/dashboardMetrics.js index 300db7b6ab..092f3ea4c4 100644 --- a/app/client/store/dashboardMetrics.js +++ b/app/client/store/dashboardMetrics.js @@ -25,8 +25,8 @@ export const DASHBOARD_METRICS = { displayName: 'Heart rate', size: 1, template: (metrics, config) => html` - ${metrics?.heartrateBatteryLevel - ? html`` + ${metrics?.heartRateBatteryLevel > 0 + ? html`` : ''} ` }, diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index b456c79478..c7dc1ae116 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -32,7 +32,7 @@ function createRowingStatistics (config) { let intervalTargetTime = 0 let intervalPrevAccumulatedDistance = 0 let intervalPrevAccumulatedTime = 0 - let heartrateResetTimer + let heartRateResetTimer let totalLinearDistance = 0.0 let totalMovingTime = 0 let totalNumberOfStrokes = 0 @@ -52,7 +52,7 @@ function createRowingStatistics (config) { const driveHandlePowerCurve = createCurveAligner(50) let dragFactor = config.rowerSettings.dragFactor let heartrate = 0 - let heartrateBatteryLevel = 0 + let heartRateBatteryLevel = 0 const postExerciseHR = [] let instantPower = 0.0 let lastStrokeState = 'WaitingForDrive' @@ -328,15 +328,15 @@ function createRowingStatistics (config) { } // initiated when a new heart rate value is received from heart rate sensor - function handleHeartrateMeasurement (value) { + function handleHeartRateMeasurement (value) { // set the heart rate to zero if we did not receive a value for some time - if (heartrateResetTimer)clearInterval(heartrateResetTimer) - heartrateResetTimer = setTimeout(() => { + if (heartRateResetTimer)clearInterval(heartRateResetTimer) + heartRateResetTimer = setTimeout(() => { heartrate = 0 - heartrateBatteryLevel = 0 + heartRateBatteryLevel = 0 }, 6000) heartrate = value.heartrate - heartrateBatteryLevel = value.batteryLevel + heartRateBatteryLevel = value.batteryLevel } function measureRecoveryHR () { @@ -408,8 +408,8 @@ function createRowingStatistics (config) { recoveryDuration: recoveryDuration.clean() >= config.rowerSettings.minimumRecoveryTime && totalNumberOfStrokes > 0 && sessionStatus === 'Rowing' ? recoveryDuration.clean() : NaN, // seconds dragFactor: dragFactor > 0 ? dragFactor : config.rowerSettings.dragFactor, // Dragfactor instantPower: instantPower > 0 && rower.strokeState() === 'Drive' ? instantPower : 0, - heartrate: heartrate > 30 ? heartrate : undefined, - heartrateBatteryLevel: heartrateBatteryLevel > 0 ? heartrateBatteryLevel : undefined // BE AWARE, changing undefined to NaN kills the GUI!!! + heartrate: heartrate > 30 ? heartrate : 0, + heartRateBatteryLevel } } @@ -433,7 +433,7 @@ function createRowingStatistics (config) { } return Object.assign(emitter, { - handleHeartRateMeasurement: handleHeartrateMeasurement, + handleHeartRateMeasurement, handleRotationImpulse, setIntervalParameters, pause: pauseTraining, diff --git a/app/peripherals/ant/HrmPeripheral.js b/app/peripherals/ant/HrmPeripheral.js index 99fe289d7e..8e7cff85fe 100644 --- a/app/peripherals/ant/HrmPeripheral.js +++ b/app/peripherals/ant/HrmPeripheral.js @@ -13,13 +13,38 @@ function createAntHrmPeripheral (antManager) { const emitter = new EventEmitter() const antStick = antManager.getAntStick() const heartRateSensor = new HeartRateSensor(0) + let batteryLevel = 0 async function attach () { if (!antManager.isStickOpen()) { await antManager.openAntStick() } this.channel = await antStick.getChannel() this.channel.on('data', (profile, deviceID, data) => { - emitter.emit('heartRateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel: data.BatteryLevel }) + switch (data.BatteryStatus) { + case 'New': + batteryLevel = 100 + break + case 'Good': + batteryLevel = 80 + break + case 'Ok': + batteryLevel = 60 + break + case 'Low': + batteryLevel = 40 + break + case 'Critical': + batteryLevel = 20 + break + default: + batteryLevel = 0 + } + + if (data.BatteryLevel > 0) { + batteryLevel = data.BatteryLevel + } + + emitter.emit('heartRateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel }) }) if (!(await this.channel.startSensor(heartRateSensor))) { diff --git a/app/peripherals/ble/hrm/HeartRateManager.js b/app/peripherals/ble/hrm/HeartRateManager.js index ae92e208b4..1b6c91f76e 100644 --- a/app/peripherals/ble/hrm/HeartRateManager.js +++ b/app/peripherals/ble/hrm/HeartRateManager.js @@ -81,7 +81,7 @@ function createHeartRateManager () { peripheral.once('disconnect', () => { // todo: figure out if we have to dispose the peripheral somehow to prevent memory leaks log.info('heart rate peripheral disconnected, searching new one') - batteryLevel = undefined + batteryLevel = 0 noble.startScanning(['180d'], false) }) } @@ -136,6 +136,16 @@ function createHeartRateManager () { } if (batteryLevelCharacteristic !== undefined) { + batteryLevelCharacteristic.read((error, data) => { + if (error) { + log.error(error) + return + } + + const buffer = Buffer.from(data) + batteryLevel = buffer.readUInt8(0) + }) + batteryLevelCharacteristic.notify(true, (error) => { if (error) { log.error(error) From a1068cf77fe3c444480fc37558c40b97d9956277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 20:21:00 +0100 Subject: [PATCH 089/209] Fix type conversion in the curveMetrics Fix the string conversion of the curveMetrics and push the formatting logic to the consumer that require this (eg. WorkoutRecorder). This enables other consumers of curveMetrics to use non-rounded, "raw" data instead of preformatted as well as avoid potential future bugs from the type conversion. --- app/client/components/DashboardForceCurve.js | 4 ++-- app/client/lib/helper.js | 19 +++++++++++++------ app/engine/Rower.js | 6 +++--- app/engine/RowingStatistics.js | 6 +++--- app/engine/WorkoutRecorder.js | 4 ++-- app/engine/utils/curveMetrics.js | 4 ++-- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/app/client/components/DashboardForceCurve.js b/app/client/components/DashboardForceCurve.js index 74a8b7aced..1d064e1ddc 100644 --- a/app/client/components/DashboardForceCurve.js +++ b/app/client/components/DashboardForceCurve.js @@ -39,7 +39,7 @@ export class DashboardForceCurve extends AppElement { datasets: [ { fill: true, - data: this.value?.map((data, index) => ({ y: parseInt(data, 10), x: index })), + data: this.value?.map((data, index) => ({ y: data, x: index })), pointRadius: 1, borderColor: 'rgb(255,255,255)', backgroundColor: 'rgb(220,220,220)' @@ -113,7 +113,7 @@ export class DashboardForceCurve extends AppElement { render () { if (this._chart?.data) { - this._chart.data.datasets[0].data = this.value?.map((data, index) => ({ y: parseInt(data, 10), x: index })) + this._chart.data.datasets[0].data = this.value?.map((data, index) => ({ y: data, x: index })) this.forceCurve = this.value this._chart.update() } diff --git a/app/client/lib/helper.js b/app/client/lib/helper.js index e4fab7ce02..444de37340 100644 --- a/app/client/lib/helper.js +++ b/app/client/lib/helper.js @@ -22,7 +22,7 @@ export function filterObjectByKeys (object, keys) { /** * Pipe for converting seconds to pace format 00:00 * - * @param seconds The actual time in seconds. + * @param {number} seconds The actual time in seconds. */ export function secondsToPace (seconds) { const hours = Math.floor((seconds % 86400) / 3600) @@ -41,8 +41,8 @@ export function secondsToPace (seconds) { /** * Pipe for formatting distance in meters with units * - * @param value The distance in meters. - * @param showInMiles Boolean whether to use imperial metric (default: false). + * @param {number} value The distance in meters. + * @param {boolean} showInMiles Boolean whether to use imperial metric (default: false). */ export function formatDistance (value, showInMiles = false) { if (showInMiles === false) { @@ -57,8 +57,8 @@ export function formatDistance (value, showInMiles = false) { /** * Pipe for formatting numbers to specific decimal * - * @param value The number. - * @param decimalPlaces The number of decimal places to round to (default: 0). + * @param {number} value The number. + * @param {number} decimalPlaces The number of decimal places to round to (default: 0). */ export function formatNumber (value, decimalPlaces = 0) { const decimal = Math.pow(10, decimalPlaces) @@ -67,6 +67,13 @@ export function formatNumber (value, decimalPlaces = 0) { return Math.round(value * decimal) / decimal } -export function simpleMetricFactory (value, unit, icon) { +/** + * Helper function to create a simple metric tile + * + * @param {string | number} value The metric to show + * @param {string} unit The unit of the metric. + * @param {string | import('lit').TemplateResult<2>} icon The number of decimal places to round to (default: 0). +*/ +export function simpleMetricFactory (value = '--', unit = '', icon = '') { return html`` } diff --git a/app/engine/Rower.js b/app/engine/Rower.js index 82f73e2523..e66b466e26 100644 --- a/app/engine/Rower.js +++ b/app/engine/Rower.js @@ -20,9 +20,9 @@ const log = loglevel.getLogger('RowingEngine') function createRower (rowerSettings) { const flywheel = createFlywheel(rowerSettings) const sprocketRadius = rowerSettings.sprocketRadius / 100 - const driveHandleForce = createCurveMetrics(2) - const driveHandleVelocity = createCurveMetrics(3) - const driveHandlePower = createCurveMetrics(1) + const driveHandleForce = createCurveMetrics() + const driveHandleVelocity = createCurveMetrics() + const driveHandlePower = createCurveMetrics() let _strokeState = 'WaitingForDrive' let _totalNumberOfStrokes = -1.0 let recoveryPhaseStartTime = 0.0 diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index c7dc1ae116..155a7b6575 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -402,9 +402,9 @@ function createRowingStatistics (config) { driveDistance: driveDistance.clean() >= 0 && sessionStatus === 'Rowing' ? driveDistance.clean() : NaN, // meters driveAverageHandleForce: driveAverageHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveAverageHandleForce.clean() : NaN, drivePeakHandleForce: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? drivePeakHandleForce.clean() : NaN, - driveHandleForceCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandleForceCurve.lastCompleteCurve() : [NaN], - driveHandleVelocityCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandleVelocityCurve.lastCompleteCurve() : [NaN], - driveHandlePowerCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandlePowerCurve.lastCompleteCurve() : [NaN], + driveHandleForceCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandleForceCurve.lastCompleteCurve() : [], + driveHandleVelocityCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandleVelocityCurve.lastCompleteCurve() : [], + driveHandlePowerCurve: drivePeakHandleForce.clean() > 0 && sessionStatus === 'Rowing' ? driveHandlePowerCurve.lastCompleteCurve() : [], recoveryDuration: recoveryDuration.clean() >= config.rowerSettings.minimumRecoveryTime && totalNumberOfStrokes > 0 && sessionStatus === 'Rowing' ? recoveryDuration.clean() : NaN, // seconds dragFactor: dragFactor > 0 ? dragFactor : config.rowerSettings.dragFactor, // Dragfactor instantPower: instantPower > 0 && rower.strokeState() === 'Drive' ? instantPower : 0, diff --git a/app/engine/WorkoutRecorder.js b/app/engine/WorkoutRecorder.js index 693d4553dd..b538f47ae2 100644 --- a/app/engine/WorkoutRecorder.js +++ b/app/engine/WorkoutRecorder.js @@ -83,8 +83,8 @@ function createWorkoutRecorder () { `${currentstroke.cycleStrokeRate.toFixed(1)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.cyclePace.toFixed(2) : NaN)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.cyclePower.toFixed(0) : NaN)},` + `${currentstroke.cycleDistance.toFixed(2)},${(currentstroke.driveDuration * 1000).toFixed(0)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.driveLength.toFixed(2) : NaN)},${(currentstroke.recoveryDuration * 1000).toFixed(0)},` + `${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.cycleLinearVelocity.toFixed(2) : 0)},${currentstroke.totalLinearDistance.toFixed(1)},${currentstroke.totalCalories.toFixed(1)},${currentstroke.dragFactor.toFixed(1)},` + - `${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.drivePeakHandleForce.toFixed(1) : NaN)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.driveAverageHandleForce.toFixed(1) : 0)},"${currentstroke.driveHandleForceCurve}",` + - `"${currentstroke.driveHandleVelocityCurve}","${currentstroke.driveHandlePowerCurve}"\n` + `${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.drivePeakHandleForce.toFixed(1) : NaN)},${(currentstroke.totalNumberOfStrokes > 0 ? currentstroke.driveAverageHandleForce.toFixed(1) : 0)},"${currentstroke.driveHandleForceCurve.map(value => value.toFixed(2))}",` + + `"${currentstroke.driveHandleVelocityCurve.map(value => value.toFixed(3))}","${currentstroke.driveHandlePowerCurve.map(value => value.toFixed(1))}"\n` i++ } diff --git a/app/engine/utils/curveMetrics.js b/app/engine/utils/curveMetrics.js index 4725ae74c7..1236424011 100644 --- a/app/engine/utils/curveMetrics.js +++ b/app/engine/utils/curveMetrics.js @@ -6,7 +6,7 @@ */ import { createSeries } from './Series.js' -function createCurveMetrics (precission = 0) { +function createCurveMetrics () { const _curve = createSeries() let _max = 0 let totalInputXTime = 0 @@ -15,7 +15,7 @@ function createCurveMetrics (precission = 0) { function push (deltaTime, inputValue) { // add the new dataPoint to the array, we have to move datapoints starting at the oldst ones if (inputValue > 0) { - _curve.push(inputValue.toFixed(precission)) + _curve.push(inputValue) _max = Math.max(_max, inputValue) totalInputXTime += deltaTime * inputValue totaltime += deltaTime From 918c9b53fa4a0cf349c523d30aeda31f31099839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 20:28:56 +0100 Subject: [PATCH 090/209] Remove formatting logic from RowingStatistics Remove logic of formatting metrics in RowingStatistics and move these to the consuming end (e.g. client). --- app/engine/RowingStatistics.js | 18 ++---------------- app/server.js | 3 ++- app/tools/Helper.js | 26 ++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index 155a7b6575..3c475492ed 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -11,6 +11,7 @@ import { createStreamFilter } from './utils/StreamFilter.js' import { createCurveAligner } from './utils/CurveAligner.js' import loglevel from 'loglevel' +import { secondsToTimeString } from '../tools/Helper.js' const log = loglevel.getLogger('RowingEngine') function createRowingStatistics (config) { @@ -375,12 +376,11 @@ function createRowingStatistics (config) { sessionStatus, strokeState: rower.strokeState(), totalMovingTime: totalMovingTime > 0 ? totalMovingTime : 0, - totalMovingTimeFormatted: intervalTargetTime > 0 ? secondsToTimeString(Math.round(Math.max(intervalTargetTime - totalMovingTime, 0))) : secondsToTimeString(Math.round(totalMovingTime - intervalPrevAccumulatedTime)), totalNumberOfStrokes: totalNumberOfStrokes > 0 ? totalNumberOfStrokes : 0, totalLinearDistance: totalLinearDistance > 0 ? totalLinearDistance : 0, // meters - totalLinearDistanceFormatted: intervalTargetDistance > 0 ? Math.max(intervalTargetDistance - totalLinearDistance, 0) : totalLinearDistance - intervalPrevAccumulatedDistance, intervalNumber: Math.max(currentIntervalNumber + 1, 0), // Interval number intervalMovingTime: totalMovingTime - intervalPrevAccumulatedTime, + intervalRemainingTime: intervalTargetTime - totalMovingTime, intervalLinearDistance: totalLinearDistance - intervalPrevAccumulatedDistance, strokeCalories: strokeCalories > 0 ? strokeCalories : 0, // kCal strokeWork: strokeWork > 0 ? strokeWork : 0, // Joules @@ -392,7 +392,6 @@ function createRowingStatistics (config) { cycleDistance: cycleDistance.raw() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cycleDistance.clean() : 0, // meters cycleLinearVelocity: cycleLinearVelocity.clean() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cycleLinearVelocity.clean() : 0, // m/s cyclePace: cycleLinearVelocity.raw() > 0 ? cyclePace : Infinity, // seconds/50 0m - cyclePaceFormatted: cycleLinearVelocity.raw() > 0 ? secondsToTimeString(Math.round(cyclePace)) : Infinity, cyclePower: cyclePower.clean() > 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? cyclePower.clean() : 0, // watts cycleProjectedEndTime: intervalTargetDistance > 0 ? distanceOverTime.projectY(intervalTargetDistance) : intervalTargetTime, cycleProjectedEndLinearDistance: intervalTargetTime > 0 ? distanceOverTime.projectX(intervalTargetTime) : intervalTargetDistance, @@ -413,19 +412,6 @@ function createRowingStatistics (config) { } } - // converts a timeStamp in seconds to a human readable hh:mm:ss format - function secondsToTimeString (secondsTimeStamp) { - if (secondsTimeStamp === Infinity) return '∞' - const hours = Math.floor(secondsTimeStamp / 60 / 60) - const minutes = Math.floor(secondsTimeStamp / 60) - (hours * 60) - const seconds = Math.floor(secondsTimeStamp % 60) - if (hours > 0) { - return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` - } else { - return `${minutes}:${seconds.toString().padStart(2, '0')}` - } - } - function caloriesPerPeriod (periodBegin, periodEnd) { const beginCalories = calories.projectX(periodBegin) const endCalories = calories.projectX(periodEnd) diff --git a/app/server.js b/app/server.js index b6a28fce5a..099658f638 100644 --- a/app/server.js +++ b/app/server.js @@ -18,6 +18,7 @@ import { createPeripheralManager } from './peripherals/PeripheralManager.js' import { replayRowingSession } from './tools/RowingRecorder.js' import { createWorkoutRecorder } from './engine/WorkoutRecorder.js' import { createWorkoutUploader } from './engine/WorkoutUploader.js' +import { secondsToTimeString } from './tools/Helper.js' const exec = promisify(child_process.exec) // set the log levels @@ -290,7 +291,7 @@ async function shutdown () { function logMetrics (metrics) { log.info(`stroke: ${metrics.totalNumberOfStrokes}, dist: ${metrics.totalLinearDistance.toFixed(1)}m, speed: ${metrics.cycleLinearVelocity.toFixed(2)}m/s` + - `, pace: ${metrics.cyclePaceFormatted}/500m, power: ${Math.round(metrics.cyclePower)}W, cal: ${metrics.totalCalories.toFixed(1)}kcal` + + `, pace: ${secondsToTimeString(metrics.cyclePace)}/500m, power: ${Math.round(metrics.cyclePower)}W, cal: ${metrics.totalCalories.toFixed(1)}kcal` + `, SPM: ${metrics.cycleStrokeRate.toFixed(1)}, drive dur: ${metrics.driveDuration.toFixed(2)}s, rec. dur: ${metrics.recoveryDuration.toFixed(2)}s` + `, stroke dur: ${metrics.cycleDuration.toFixed(2)}s`) } diff --git a/app/tools/Helper.js b/app/tools/Helper.js index 63f388e04a..2a809fe709 100644 --- a/app/tools/Helper.js +++ b/app/tools/Helper.js @@ -26,3 +26,29 @@ export function deepMerge (...objects) { return prev }, {}) } + +// converts a timeStamp in seconds to a human readable hh:mm:ss format +export function secondsToTimeString (secondsTimeStamp) { + if (secondsTimeStamp === Infinity) return '∞' + const hours = Math.floor(secondsTimeStamp / 60 / 60) + const minutes = Math.floor(secondsTimeStamp / 60) - (hours * 60) + const seconds = Math.floor(secondsTimeStamp % 60) + if (hours > 0) { + return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` + } else { + return `${minutes}:${seconds.toString().padStart(2, '0')}` + } +} + +/** + * Pipe for formatting numbers to specific decimal + * + * @param {number} value The number. + * @param {number} decimalPlaces The number of decimal places to round to (default: 0). +*/ +export function formatNumber (value, decimalPlaces = 0) { + const decimal = Math.pow(10, decimalPlaces) + if (value === undefined || value === null || value === Infinity || isNaN(value) || value === 0) { return '--' } + + return Math.round(value * decimal) / decimal +} From b494be4b9dd5b796efdb07cb9009efa3bdd3ae49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Sat, 25 Mar 2023 21:59:21 +0100 Subject: [PATCH 091/209] Fix bug re. ignoring app mode Refactor appMode setting so it becomes internal to the DashboardAction component as it is not used anywhere else. This prevents exposing unnecessary - essentially internal - state to the global appState. --- app/client/components/DashboardActions.js | 21 +++++++++++++++++---- app/client/lib/app.js | 7 +------ app/client/store/appState.js | 2 -- app/client/store/dashboardMetrics.js | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index e8aa034e2a..60823fc08d 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -77,8 +77,8 @@ export class DashboardActions extends AppElement { @property({ type: Object }) config = {} - @property({ type: Object }) - appMode = 'BROWSER' + @state() + _appMode = 'BROWSER' @state() _dialog @@ -105,12 +105,25 @@ export class DashboardActions extends AppElement { ` } + firstUpdated () { + switch (new URLSearchParams(window.location.search).get('mode')) { + case 'standalone': + this._appMode = 'STANDALONE' + break + case 'kiosk': + this._appMode = 'KIOSK' + break + default: + this._appMode = 'BROWSER' + } + } + renderOptionalButtons () { const buttons = [] // changing to fullscreen mode only makes sence when the app is openend in a regular // webbrowser (kiosk and standalone mode are always in fullscreen view) and if the // browser supports this feature - if (this.appMode === 'BROWSER' && document.documentElement.requestFullscreen) { + if (this._appMode === 'BROWSER' && document.documentElement.requestFullscreen) { buttons.push(html` `) diff --git a/app/client/lib/app.js b/app/client/lib/app.js index 004acaa280..b5e4904885 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -9,12 +9,7 @@ import NoSleep from 'nosleep.js' import { filterObjectByKeys } from './helper.js' export function createApp (app) { - const urlParameters = new URLSearchParams(window.location.search) - const mode = urlParameters.get('mode') - const appMode = mode === 'standalone' ? 'STANDALONE' : mode === 'kiosk' ? 'KIOSK' : 'BROWSER' - app.updateState({ ...app.getState(), appMode }) - - const stravaAuthorizationCode = urlParameters.get('code') + const stravaAuthorizationCode = new URLSearchParams(window.location.search).get('code') let socket diff --git a/app/client/store/appState.js b/app/client/store/appState.js index 7865fff50e..2e1e0a1883 100644 --- a/app/client/store/appState.js +++ b/app/client/store/appState.js @@ -6,8 +6,6 @@ */ export const APP_STATE = { - // currently can be STANDALONE (Mobile Home Screen App), KIOSK (Raspberry Pi deployment) or '' (default) - appMode: '', // contains all the rowing metrics that are delivered from the backend metrics: {}, config: { diff --git a/app/client/store/dashboardMetrics.js b/app/client/store/dashboardMetrics.js index 092f3ea4c4..0d2d6b551e 100644 --- a/app/client/store/dashboardMetrics.js +++ b/app/client/store/dashboardMetrics.js @@ -49,5 +49,5 @@ export const DASHBOARD_METRICS = { forceCurve: { displayName: 'Force curve', size: 2, template: (metrics) => html`` }, - actions: { displayName: 'Actions', size: 1, template: (appState, config) => html`` } + actions: { displayName: 'Actions', size: 1, template: (_, config) => html`` } } From 475fe85c00b8c1fcbaddd3d17d3b06d61942778d Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:27:02 +0200 Subject: [PATCH 092/209] Clarification of minimumStrokeQuality Clarification of the minimumStrokeQuality parameters role in the Recovery detection --- config/rowerProfiles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/rowerProfiles.js b/config/rowerProfiles.js index 7515039a37..2721504335 100644 --- a/config/rowerProfiles.js +++ b/config/rowerProfiles.js @@ -43,7 +43,7 @@ export default { minumumRecoverySlope: 0, // The minimum quality level of the stroke detection: 1.0 is perfect, 0.1 pretty bad. Normally around 0.33. Setting this too high will stop - // the recovery phase from being detected. + // the recovery phase from being detected through the slope angle (i.e. it will completely rely on the absence of the minumumForceBeforeStroke). minimumStrokeQuality: 0.34, // ORM can automatically calculate the recovery slope and adjust it dynamically. For this to work, autoAdjustDragFactor MUST be set to true From bc9dc83596995828adc3e21f1d200169b002c0f4 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:32:48 +0200 Subject: [PATCH 093/209] Made position of createRawDataFiles clearer Added a better description of the placement of createRawDataFiles based on https://github.com/laberning/openrowingmonitor/discussions/139 --- docs/rower_settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rower_settings.md b/docs/rower_settings.md index dc6d4744e2..5390872e2f 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -86,7 +86,7 @@ Next, when the electric connection has been made, we need to look if the data is sudo nano /opt/openrowingmonitor/config/config.js ``` -Here, you can change the setting for **createRawDataFiles** by setting: +Here, you can change the setting for **createRawDataFiles** by setting/adding the following BEFORE the rowerSettings element (so outside the rowerSettings scope): ```js createRawDataFiles: true, From dfc2881f3667ff3b32b03814e367adee0beb0eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=A1sz?= <> Date: Tue, 18 Apr 2023 23:19:53 +0200 Subject: [PATCH 094/209] Make changes to GUI to better support intervals Change distance, timer and calories tile to change behaviour when current workout is an interval session (i.e. not JustRow). Expose data necessary for this in RowingStatistics. Remove miles option from formatter. --- app/client/lib/helper.js | 13 ++++--------- app/client/store/dashboardMetrics.js | 23 ++++++++++++++++++++--- app/engine/RowingStatistics.js | 3 ++- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/app/client/lib/helper.js b/app/client/lib/helper.js index 444de37340..e6c98a46b9 100644 --- a/app/client/lib/helper.js +++ b/app/client/lib/helper.js @@ -42,16 +42,11 @@ export function secondsToPace (seconds) { * Pipe for formatting distance in meters with units * * @param {number} value The distance in meters. - * @param {boolean} showInMiles Boolean whether to use imperial metric (default: false). */ -export function formatDistance (value, showInMiles = false) { - if (showInMiles === false) { - return value >= 10000 - ? { distance: formatNumber((value / 1000), 2), unit: 'km' } - : { distance: formatNumber(value), unit: 'm' } - } - - return { distance: formatNumber((value / 1609.344), 2), unit: 'mi' } +export function formatDistance (value) { + return value >= 10000 + ? { distance: formatNumber((value / 1000), 2), unit: 'km' } + : { distance: formatNumber(value), unit: 'm' } } /** diff --git a/app/client/store/dashboardMetrics.js b/app/client/store/dashboardMetrics.js index 0d2d6b551e..8848f20286 100644 --- a/app/client/store/dashboardMetrics.js +++ b/app/client/store/dashboardMetrics.js @@ -10,7 +10,8 @@ export const DASHBOARD_METRICS = { displayName: 'Distance', size: 1, template: (metrics, config) => { - const linearDistance = formatDistance(metrics?.totalLinearDistance) + const distance = metrics?.sessiontype === 'Distance' ? Math.max(metrics?.intervalTargetDistance - metrics?.intervalLinearDistance, 0) : metrics?.totalLinearDistance + const linearDistance = formatDistance(distance ?? 0) return simpleMetricFactory(linearDistance.distance, linearDistance.unit, config.guiConfigs.showIcons ? icon_route : '') } @@ -33,9 +34,25 @@ export const DASHBOARD_METRICS = { totalStk: { displayName: 'Total strokes', size: 1, template: (metrics, config) => simpleMetricFactory(metrics?.totalNumberOfStrokes, 'stk', config.guiConfigs.showIcons ? icon_paddle : '') }, - calories: { displayName: 'Calories', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.totalCalories), 'kcal', config.guiConfigs.showIcons ? icon_fire : '') }, + calories: { + displayName: 'Calories', + size: 1, + template: (metrics, config) => { + const calories = metrics?.sessiontype === 'Calories' ? Math.max(metrics?.intervalTargetCalories - metrics?.intervalLinearCalories, 0) : metrics?.totalCalories + + return simpleMetricFactory(formatNumber(calories ?? 0), 'kcal', config.guiConfigs.showIcons ? icon_fire : '') + } + }, - timer: { displayName: 'Timer', size: 1, template: (metrics, config) => simpleMetricFactory(secondsToPace(metrics?.totalMovingTime), '', config.guiConfigs.showIcons ? icon_clock : '') }, + timer: { + displayName: 'Timer', + size: 1, + template: (metrics, config) => { + const time = metrics?.sessiontype === 'Time' ? Math.max(metrics?.intervalTargetTime - metrics?.intervalMovingTime, 0) : metrics?.totalMovingTime + + return simpleMetricFactory(secondsToPace(time ?? 0), '', config.guiConfigs.showIcons ? icon_clock : '') + } + }, distancePerStk: { displayName: 'Dist per Stroke', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cycleDistance, 1), 'm', config.guiConfigs.showIcons ? rower_icon : '') }, diff --git a/app/engine/RowingStatistics.js b/app/engine/RowingStatistics.js index 3c475492ed..0edc6f9f7e 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -380,8 +380,9 @@ function createRowingStatistics (config) { totalLinearDistance: totalLinearDistance > 0 ? totalLinearDistance : 0, // meters intervalNumber: Math.max(currentIntervalNumber + 1, 0), // Interval number intervalMovingTime: totalMovingTime - intervalPrevAccumulatedTime, - intervalRemainingTime: intervalTargetTime - totalMovingTime, + intervalTargetTime: intervalTargetTime > intervalPrevAccumulatedTime ? intervalTargetTime - intervalPrevAccumulatedTime : 0, intervalLinearDistance: totalLinearDistance - intervalPrevAccumulatedDistance, + intervalTargetDistance: intervalTargetDistance > intervalPrevAccumulatedDistance ? intervalTargetDistance - intervalPrevAccumulatedDistance : 0, strokeCalories: strokeCalories > 0 ? strokeCalories : 0, // kCal strokeWork: strokeWork > 0 ? strokeWork : 0, // Joules totalCalories: calories.yAtSeriesEnd() > 0 ? calories.yAtSeriesEnd() : 0, // kcal From c0770891ce2e740e9153d76c0bcfd6a77c069568 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Wed, 19 Apr 2023 10:25:36 +0200 Subject: [PATCH 095/209] Metric selection screen added --- docs/img/Metrics_Selection.png | Bin 0 -> 140133 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/img/Metrics_Selection.png diff --git a/docs/img/Metrics_Selection.png b/docs/img/Metrics_Selection.png new file mode 100644 index 0000000000000000000000000000000000000000..77730dec05f479f0645c28006819146a9377709e GIT binary patch literal 140133 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

TD*jEj37T0+^{$`-6UCr>0k=w^ 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