diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index d2547a9de8..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "env": { - "browser": false, - "node": true, - "es2021": true - }, - "extends": [ - "standard" - ], - "parserOptions": { - "ecmaVersion": 13, - "sourceType": "module" - }, - "ignorePatterns": ["**/*.min.js"], - "rules": { - "camelcase": 0 - } -} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 80f5ee0b7e..836d74aba2 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x] + node-version: [22.x] steps: - name: Checkout repository diff --git a/.markdownlint.json b/.markdownlint.json index 75d13e4028..a978447aed 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,5 +1,6 @@ { "default": true, "MD013": false, - "MD049": { "style": "asterisk" } + "MD049": { "style": "asterisk" }, + "MD059": false } diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..2640e1df91 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +unsafe-perm=true +user=0 diff --git a/app/WebServer.js b/app/WebServer.js index 6eb1eec028..dba87d7ab8 100644 --- a/app/WebServer.js +++ b/app/WebServer.js @@ -1,10 +1,10 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Creates the WebServer which serves the static assets and communicates with the clients - via WebSockets + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ +/** + * Creates the WebServer which serves the static assets and communicates with the clients via WebSockets + */ import { WebSocket, WebSocketServer } from 'ws' import finalhandler from 'finalhandler' import http from 'http' @@ -12,17 +12,22 @@ import serveStatic from 'serve-static' import log from 'loglevel' import EventEmitter from 'events' -function createWebServer () { +export function createWebServer (config) { const emitter = new EventEmitter() const port = process.env.PORT || 80 const serve = serveStatic('./build', { index: ['index.html'] }) + let timer = setTimeout(timeBasedPresenter, config.webUpdateInterval) + let lastKnownMetrics + let heartRate + let heartRateBatteryLevel + resetLastKnownMetrics() const server = http.createServer((req, res) => { serve(req, res, finalhandler(req, res)) }) server.listen(port, (err) => { - if (err) throw err + if (err) { throw err } log.info(`webserver running on port ${port}`) }) @@ -30,12 +35,13 @@ function createWebServer () { wss.on('connection', function connection (client) { log.debug('websocket client connected') - emitter.emit('clientConnected', client) + notifyClient(client, 'config', getConfig()) + notifyClient(client, 'metrics', lastKnownMetrics) client.on('message', function incoming (data) { try { const message = JSON.parse(data) if (message) { - emitter.emit('messageReceived', message, client) + emitter.emit('messageReceived', message) } else { log.warn(`invalid message received: ${data}`) } @@ -43,11 +49,105 @@ function createWebServer () { log.error(err) } }) - client.on('close', function () { + client.on('close', function close () { log.debug('websocket client disconnected') }) }) + // This function handles all incomming commands. As all commands are broadasted to all application parts, + // we need to filter here what the webserver will react to and what it will ignore + // The start...reset commands are handled by the RowingEngine and the result will be reported by the metrics update, so we ignore them here + /* eslint-disable-next-line no-unused-vars -- this is part of the standardised handleCommand interface */ + function handleCommand (commandName, data) { + switch (commandName) { + case ('updateIntervalSettings'): + break + case ('start'): + break + case ('startOrResume'): + break + case ('pause'): + break + case ('stop'): + break + case ('reset'): + resetLastKnownMetrics() + notifyClients('metrics', lastKnownMetrics) + break + case 'switchBlePeripheralMode': + break + case 'switchAntPeripheralMode': + break + case 'switchHrmMode': + break + case 'refreshPeripheralConfig': + notifyClients('config', getConfig()) + break + case 'upload': + break + case 'shutdown': + break + default: + log.error(`WebServer: Recieved unknown command: ${commandName}`) + } + } + + function presentRowingMetrics (metrics) { + if (metrics.metricsContext === undefined) { return } + switch (true) { + case (metrics.metricsContext.isSessionStart): + notifyClients('metrics', metrics) + break + case (metrics.metricsContext.isSessionStop): + notifyClients('metrics', metrics) + break + case (metrics.metricsContext.isIntervalEnd): + notifyClients('metrics', metrics) + break + case (metrics.metricsContext.isPauseStart): + notifyClients('metrics', metrics) + break + case (metrics.metricsContext.isPauseEnd): + notifyClients('metrics', metrics) + break + case (metrics.metricsContext.isDriveStart): + notifyClients('metrics', metrics) + break + case (metrics.metricsContext.isRecoveryStart): + notifyClients('metrics', metrics) + break + // no default + } + lastKnownMetrics = metrics + } + + // initiated when a new heart rate value is received from heart rate sensor + async function presentHeartRate (value) { + heartRate = value.heartrate + heartRateBatteryLevel = value.batteryLevel + } + + // Make sure that the GUI is updated with the latest metrics even when no fresh data arrives + function timeBasedPresenter () { + notifyClients('metrics', lastKnownMetrics) + } + + /** + * @param {Metrics} metrics + */ + function addHeartRateToMetrics (metrics) { + if (heartRate !== undefined) { + metrics.heartrate = heartRate + } else { + metrics.heartrate = undefined + } + if (heartRateBatteryLevel !== undefined) { + metrics.heartRateBatteryLevel = heartRateBatteryLevel + } else { + metrics.heartRateBatteryLevel = undefined + } + } + function notifyClient (client, type, data) { const messageString = JSON.stringify({ type, data }) if (wss.clients.has(client)) { @@ -60,18 +160,61 @@ function createWebServer () { } function notifyClients (type, data) { + clearTimeout(timer) + if (type === 'metrics') { addHeartRateToMetrics(data) } const messageString = JSON.stringify({ type, data }) wss.clients.forEach(function each (client) { if (client.readyState === WebSocket.OPEN) { client.send(messageString) } }) + timer = setTimeout(timeBasedPresenter, config.webUpdateInterval) + } + + function getConfig () { + return { + blePeripheralMode: config.bluetoothMode, + antPeripheralMode: config.antPlusMode, + hrmPeripheralMode: config.heartRateMode, + uploadEnabled: ((config.userSettings.strava.allowUpload && !config.userSettings.strava.autoUpload) || (config.userSettings.intervals.allowUpload && !config.userSettings.intervals.autoUpload) || (config.userSettings.rowsAndAll.allowUpload && !config.userSettings.rowsAndAll.autoUpload)), + shutdownEnabled: !!config.shutdownCommand + } + } + + function resetLastKnownMetrics () { + lastKnownMetrics = { + strokeState: 'WaitingForDrive', + sessionState: 'WaitingForStart', + totalMovingTime: 0, + pauseCountdownTime: 0, + totalNumberOfStrokes: 0, + totalLinearDistance: 0, + cyclePace: Infinity, + cyclePower: 0, + cycleStrokeRate: 0, + driveLength: 0, + driveDuration: 0, + driveHandleForceCurve: [], + driveDistance: 0, + recoveryDuration: 0, + dragFactor: undefined, + interval: { + type: 'justrow', + movingTime: { + sinceStart: 0, + toEnd: 0 + }, + distance: { + fromStart: 0, + toEnd: 0 + } + } + } } return Object.assign(emitter, { - notifyClient, - notifyClients + presentRowingMetrics, + presentHeartRate, + handleCommand }) } - -export { createWebServer } diff --git a/app/ant/AntManager.js b/app/ant/AntManager.js deleted file mode 100644 index 8a6bcec4d5..0000000000 --- a/app/ant/AntManager.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This manager creates a module to listen to ANT+ devices. - This currently can be used to get the heart rate from ANT+ heart rate sensors. - - Requires an ANT+ USB stick, the following models might work: - - 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() - // 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') - } - - if (!antStick3.open()) { - log.debug('mini ANT+ stick NOT found') - } - - return Object.assign(emitter, { - }) -} - -export { createAntManager } diff --git a/app/ble/CentralManager.js b/app/ble/CentralManager.js deleted file mode 100644 index c21c340447..0000000000 --- a/app/ble/CentralManager.js +++ /dev/null @@ -1,158 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This manager creates a Bluetooth Low Energy (BLE) Central that listens - and subscribes to heart rate services -*/ -import log from 'loglevel' -import EventEmitter from 'node:events' -import Noble from '@abandonware/noble/lib/noble.js' -import NobleBindings from '@abandonware/noble/lib/hci-socket/bindings.js' - -// We are using peripherals and centrals at the same time (with bleno and noble). -// The libraries do not play nice together in this scenario when they see peripherals -// from each other via the HCI-Socket. -// This is a quick patch for two handlers in noble that would otherwise throw warnings -// when they see a peripheral or handle that is managed by bleno - -// START of noble patch -Noble.prototype.onRssiUpdate = function (peripheralUuid, rssi) { - const peripheral = this._peripherals[peripheralUuid] - - if (peripheral) { - peripheral.rssi = rssi - peripheral.emit('rssiUpdate', rssi) - } -} - -NobleBindings.prototype.onDisconnComplete = function (handle, reason) { - const uuid = this._handles[handle] - - if (uuid) { - this._aclStreams[handle].push(null, null) - this._gatts[handle].removeAllListeners() - this._signalings[handle].removeAllListeners() - - delete this._gatts[uuid] - delete this._gatts[handle] - delete this._signalings[uuid] - delete this._signalings[handle] - delete this._aclStreams[handle] - delete this._handles[uuid] - delete this._handles[handle] - - this.emit('disconnect', uuid) - } -} - -const noble = new Noble(new NobleBindings()) -// END of noble patch - -function createCentralManager () { - const emitter = new EventEmitter() - let batteryLevel - - noble.on('stateChange', (state) => { - if (state === 'poweredOn') { - // search for heart rate service - noble.startScanning(['180d'], false) - } else { - noble.stopScanning() - } - }) - - noble.on('discover', (peripheral) => { - noble.stopScanning() - connectHeartratePeripheral(peripheral) - }) - - function connectHeartratePeripheral (peripheral) { - // connect to the heart rate sensor - peripheral.connect((error) => { - if (error) { - log.error(error) - return - } - log.info(`heart rate peripheral connected, name: '${peripheral.advertisement?.localName}', id: ${peripheral.id}`) - subscribeToHeartrateMeasurement(peripheral) - }) - - 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 - noble.startScanning(['180d'], false) - }) - } - - // see https://www.bluetooth.com/specifications/specs/heart-rate-service-1-0/ - function subscribeToHeartrateMeasurement (peripheral) { - const heartrateMeasurementUUID = '2a37' - const batteryLevelUUID = '2a19' - - peripheral.discoverSomeServicesAndCharacteristics([], [heartrateMeasurementUUID, batteryLevelUUID], - (error, services, characteristics) => { - if (error) { - log.error(error) - return - } - - const heartrateMeasurementCharacteristic = characteristics.find( - characteristic => characteristic.uuid === heartrateMeasurementUUID - ) - - const batteryLevelCharacteristic = characteristics.find( - characteristic => characteristic.uuid === batteryLevelUUID - ) - - if (heartrateMeasurementCharacteristic !== undefined) { - heartrateMeasurementCharacteristic.notify(true, (error) => { - if (error) { - log.error(error) - return - } - - heartrateMeasurementCharacteristic.on('data', (data, isNotification) => { - const buffer = Buffer.from(data) - const flags = buffer.readUInt8(0) - // bits of the feature flag: - // 0: Heart Rate Value Format - // 1 + 2: Sensor Contact Status - // 3: Energy Expended Status - // 4: RR-Interval - const heartrateUint16LE = flags & 0b1 - - // from the specs: - // While most human applications require support for only 255 bpm or less, special - // applications (e.g. animals) may require support for higher bpm values. - // 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 }) - }) - }) - } - - if (batteryLevelCharacteristic !== undefined) { - batteryLevelCharacteristic.notify(true, (error) => { - if (error) { - log.error(error) - return - } - - batteryLevelCharacteristic.on('data', (data, isNotification) => { - const buffer = Buffer.from(data) - batteryLevel = buffer.readUInt8(0) - }) - }) - } - }) - } - - return Object.assign(emitter, { - }) -} - -export { createCentralManager } diff --git a/app/ble/CentralService.js b/app/ble/CentralService.js deleted file mode 100644 index f8b28a51ea..0000000000 --- a/app/ble/CentralService.js +++ /dev/null @@ -1,18 +0,0 @@ -'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 { createCentralManager } from './CentralManager.js' -import process from 'process' -import config from '../tools/ConfigManager.js' -import log from 'loglevel' - -log.setLevel(config.loglevel.default) -const centralManager = createCentralManager() - -centralManager.on('heartrateMeasurement', (heartrateMeasurement) => { - process.send(heartrateMeasurement) -}) diff --git a/app/ble/CpsPeripheral.js b/app/ble/CpsPeripheral.js deleted file mode 100644 index 5d24e47784..0000000000 --- a/app/ble/CpsPeripheral.js +++ /dev/null @@ -1,108 +0,0 @@ -'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 deleted file mode 100644 index 3c8e99cc79..0000000000 --- a/app/ble/CscPeripheral.js +++ /dev/null @@ -1,108 +0,0 @@ -'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 deleted file mode 100644 index 7a54392f9f..0000000000 --- a/app/ble/FtmsPeripheral.js +++ /dev/null @@ -1,124 +0,0 @@ -'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 Fitness Machine Device - - Relevant parts from https://www.bluetooth.com/specifications/specs/fitness-machine-profile-1-0/ - The Fitness Machine shall instantiate one and only one Fitness Machine Service as Primary Service - The User Data Service, if supported, shall be instantiated as a Primary Service. - The Fitness Machine may instantiate the Device Information Service - (Manufacturer Name String, Model Number String) -*/ -import bleno from '@abandonware/bleno' -import FitnessMachineService from './ftms/FitnessMachineService.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() - - bleno.on('stateChange', (state) => { - triggerAdvertising(state) - }) - - bleno.on('advertisingStart', (error) => { - if (!error) { - bleno.setServices( - [fitnessMachineService, 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 controlPointCallback (event) { - const obj = { - req: event, - res: {} - } - if (controlCallback) controlCallback(obj) - return obj.res - } - - 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 advertisingBuilder = new AdvertisingDataBuilder([fitnessMachineService.uuid]) - advertisingBuilder.setShortName(peripheralName) - advertisingBuilder.setLongName(peripheralName) - - bleno.startAdvertisingWithEIRData( - advertisingBuilder.buildAppearanceData(), - advertisingBuilder.buildScanData(), - (error) => { - if (error) log.error(error) - } - ) - } else { - bleno.stopAdvertising() - } - } - - // present current rowing metrics to FTMS central - function notifyData (type, data) { - if (type === 'strokeFinished' || type === 'metricsUpdate') { - fitnessMachineService.notifyData(data) - } - } - - // present current rowing status to FTMS central - function notifyStatus (status) { - fitnessMachineService.notifyStatus(status) - } - - return { - triggerAdvertising, - notifyData, - notifyStatus, - destroy - } -} - -export { createFtmsPeripheral } diff --git a/app/ble/PeripheralManager.js b/app/ble/PeripheralManager.js deleted file mode 100644 index c75861fa24..0000000000 --- a/app/ble/PeripheralManager.js +++ /dev/null @@ -1,110 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This manager creates the different Bluetooth Low Energy (BLE) Peripherals and allows - switching between them -*/ -import config from '../tools/ConfigManager.js' -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', 'CSC', 'CPS'] -function createPeripheralManager () { - const emitter = new EventEmitter() - let peripheral - let mode - - createPeripheral(config.bluetoothMode) - - function getPeripheral () { - return peripheral - } - - function getPeripheralMode () { - return mode - } - - function switchPeripheralMode (newMode) { - // if now mode was passed, select the next one from the list - if (newMode === undefined) { - newMode = modes[(modes.indexOf(mode) + 1) % modes.length] - } - createPeripheral(newMode) - } - - function notifyMetrics (type, metrics) { - peripheral.notifyData(type, metrics) - } - - function notifyStatus (status) { - peripheral.notifyStatus(status) - } - - async function createPeripheral (newMode) { - if (peripheral) { - await peripheral.destroy() - } - - 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() - - emitter.emit('control', { - req: { - name: 'peripheralMode', - peripheralMode: mode - } - }) - } - - function controlCallback (event) { - emitter.emit('control', event) - } - - return Object.assign(emitter, { - getPeripheral, - getPeripheralMode, - switchPeripheralMode, - notifyMetrics, - notifyStatus - }) -} - -export { createPeripheralManager } diff --git a/app/ble/Pm5Peripheral.js b/app/ble/Pm5Peripheral.js deleted file mode 100644 index 4e905198a6..0000000000 --- a/app/ble/Pm5Peripheral.js +++ /dev/null @@ -1,107 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are used by the - Concept2 PM5 rowing machine. - - 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 DeviceInformationService from './pm5/DeviceInformationService.js' -import GapService from './pm5/GapService.js' -import log from 'loglevel' -import Pm5ControlService from './pm5/Pm5ControlService.js' -import Pm5RowingService from './pm5/Pm5RowingService.js' - -function createPm5Peripheral (controlCallback, options) { - const peripheralName = constants.name - const deviceInformationService = new DeviceInformationService() - const gapService = new GapService() - const controlService = new Pm5ControlService() - const rowingService = new Pm5RowingService() - - bleno.on('stateChange', (state) => { - triggerAdvertising(state) - }) - - bleno.on('advertisingStart', (error) => { - if (!error) { - bleno.setServices( - [gapService, deviceInformationService, controlService, rowingService], - (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') { - bleno.startAdvertising( - peripheralName, - [gapService.uuid], - (error) => { - if (error) log.error(error) - } - ) - } else { - bleno.stopAdvertising() - } - } - - // present current rowing metrics to C2-PM5 central - function notifyData (type, data) { - rowingService.notifyData(type, data) - } - - // present current rowing status to C2-PM5 central - function notifyStatus (status) { - } - - return { - triggerAdvertising, - notifyData, - notifyStatus, - destroy - } -} - -export { createPm5Peripheral } diff --git a/app/ble/common/AdvertisingDataBuilder.js b/app/ble/common/AdvertisingDataBuilder.js deleted file mode 100644 index ba3dabf412..0000000000 --- a/app/ble/common/AdvertisingDataBuilder.js +++ /dev/null @@ -1,133 +0,0 @@ -'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 deleted file mode 100644 index 8fbc991f75..0000000000 --- a/app/ble/common/AdvertisingDataBuilder.test.js +++ /dev/null @@ -1,117 +0,0 @@ -'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 deleted file mode 100644 index 100f5c4766..0000000000 --- a/app/ble/common/DeviceInformationService.js +++ /dev/null @@ -1,23 +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' -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/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/cps/CpsControlPointCharacteristic.js b/app/ble/cps/CpsControlPointCharacteristic.js deleted file mode 100644 index 6b1283d625..0000000000 --- a/app/ble/cps/CpsControlPointCharacteristic.js +++ /dev/null @@ -1,29 +0,0 @@ -'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 deleted file mode 100644 index c87fcece50..0000000000 --- a/app/ble/cps/CpsMeasurementCharacteristic.js +++ /dev/null @@ -1,95 +0,0 @@ -'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/csc/CscControlPointCharacteristic.js b/app/ble/csc/CscControlPointCharacteristic.js deleted file mode 100644 index 1f9a110b95..0000000000 --- a/app/ble/csc/CscControlPointCharacteristic.js +++ /dev/null @@ -1,29 +0,0 @@ -'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 deleted file mode 100644 index 60461588c2..0000000000 --- a/app/ble/csc/CscMeasurementCharacteristic.js +++ /dev/null @@ -1,81 +0,0 @@ -'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 deleted file mode 100644 index 261b38505f..0000000000 --- a/app/ble/csc/CyclingSpeedCadenceService.js +++ /dev/null @@ -1,36 +0,0 @@ -'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/FitnessMachineControlPointCharacteristic.js b/app/ble/ftms/FitnessMachineControlPointCharacteristic.js deleted file mode 100644 index 7d96096f12..0000000000 --- a/app/ble/ftms/FitnessMachineControlPointCharacteristic.js +++ /dev/null @@ -1,147 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - The connected Central can remotly control some parameters or our rowing monitor via this Control Point - - So far tested on: - - Fulgaz: uses setIndoorBikeSimulationParameters - - Zwift: uses startOrResume and setIndoorBikeSimulationParameters -*/ -import bleno from '@abandonware/bleno' -import log from 'loglevel' - -// see https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0 for details -const ControlPointOpCode = { - requestControl: 0x00, - reset: 0x01, - setTargetSpeed: 0x02, - setTargetInclincation: 0x03, - setTargetResistanceLevel: 0x04, - setTargetPower: 0x05, - setTargetHeartRate: 0x06, - startOrResume: 0x07, - stopOrPause: 0x08, - setTargetedExpendedEnergy: 0x09, - setTargetedNumberOfSteps: 0x0A, - setTargetedNumberOfStrides: 0x0B, - setTargetedDistance: 0x0C, - setTargetedTrainingTime: 0x0D, - setTargetedTimeInTwoHeartRateZones: 0x0E, - setTargetedTimeInThreeHeartRateZones: 0x0F, - setTargetedTimeInFiveHeartRateZones: 0x10, - setIndoorBikeSimulationParameters: 0x11, - setWheelCircumference: 0x12, - spinDownControl: 0x13, - setTargetedCadence: 0x14, - 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({ - // Fitness Machine Control Point - uuid: '2AD9', - value: null, - properties: ['write'] - }) - - this.controlled = false - if (!controlPointCallback) { throw new Error('controlPointCallback required') } - this.controlPointCallback = controlPointCallback - } - - // Central sends a command to the Control Point - // todo: handle offset and withoutResponse properly - onWriteRequest (data, offset, withoutResponse, callback) { - const opCode = data.readUInt8(0) - switch (opCode) { - case ControlPointOpCode.requestControl: - if (!this.controlled) { - if (this.controlPointCallback({ name: 'requestControl' })) { - log.debug('requestControl sucessful') - this.controlled = true - callback(this.buildResponse(opCode, ResultCode.success)) - } else { - callback(this.buildResponse(opCode, ResultCode.operationFailed)) - } - } else { - callback(this.buildResponse(opCode, ResultCode.controlNotPermitted)) - } - break - - case ControlPointOpCode.reset: - this.handleSimpleCommand(ControlPointOpCode.reset, 'reset', callback) - // as per spec the reset command shall also reset the control - this.controlled = false - break - - case ControlPointOpCode.startOrResume: - this.handleSimpleCommand(ControlPointOpCode.startOrResume, 'startOrResume', callback) - break - - case ControlPointOpCode.stopOrPause: { - const controlParameter = data.readUInt8(1) - if (controlParameter === 1) { - this.handleSimpleCommand(ControlPointOpCode.stopOrPause, 'stop', callback) - } else if (controlParameter === 2) { - this.handleSimpleCommand(ControlPointOpCode.stopOrPause, 'pause', callback) - } else { - log.error(`stopOrPause with invalid controlParameter: ${controlParameter}`) - } - break - } - - // todo: Most tested bike apps use these to simulate a bike ride. Not sure how we can use these in our rower - // since there is no adjustable resistance on the rowing machine - case ControlPointOpCode.setIndoorBikeSimulationParameters: { - const windspeed = data.readInt16LE(1) * 0.001 - const grade = data.readInt16LE(3) * 0.01 - 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)) - } else { - callback(this.buildResponse(opCode, ResultCode.operationFailed)) - } - break - } - - default: - log.info(`opCode ${opCode} is not supported`) - callback(this.buildResponse(opCode, ResultCode.opCodeNotSupported)) - } - } - - handleSimpleCommand (opCode, opName, callback) { - if (this.controlled) { - if (this.controlPointCallback({ name: opName })) { - const response = this.buildResponse(opCode, ResultCode.success) - callback(response) - } else { - callback(this.buildResponse(opCode, ResultCode.operationFailed)) - } - } else { - log.info(`initating command '${opName}' requires 'requestControl'`) - callback(this.buildResponse(opCode, ResultCode.controlNotPermitted)) - } - } - - // build the response message as defined by the spec - buildResponse (opCode, resultCode) { - const buffer = Buffer.alloc(3) - buffer.writeUInt8(0x80, 0) - buffer.writeUInt8(opCode, 1) - buffer.writeUInt8(resultCode, 2) - return buffer - } -} diff --git a/app/ble/ftms/FitnessMachineService.js b/app/ble/ftms/FitnessMachineService.js deleted file mode 100644 index d4703742b4..0000000000 --- a/app/ble/ftms/FitnessMachineService.js +++ /dev/null @@ -1,54 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implements the Fitness Machine Service (FTMS) according to specs. - Either presents a FTMS Rower (for rower applications that can use parameters such as Stroke Rate) or - simulates a FTMS Indoor Bike (for usage with bike training apps) - - Relevant parts from https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0 - For Discovery we should implement: - - Fitness Machine Feature Characteristic - - Rower Data Characteristic - - Training Status Characteristic (not yet implemented) todo: Maybe implement a simple version of it to see which - applications make use of it. Might become interesting, if we implement training management - - Fitness Machine Status Characteristic - - Fitness Machine Control Point Characteristic -*/ -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' - -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() - super({ - // Fitness Machine - uuid: '1826', - characteristics: [ - featureCharacteristic, - dataCharacteristic, - new FitnessMachineControlPointCharacteristic(controlPointCallback), - statusCharacteristic - ] - }) - this.dataCharacteristic = dataCharacteristic - this.statusCharacteristic = statusCharacteristic - } - - notifyData (event) { - this.dataCharacteristic.notify(event) - } - - notifyStatus (event) { - this.statusCharacteristic.notify(event) - } -} diff --git a/app/ble/ftms/IndoorBikeDataCharacteristic.js b/app/ble/ftms/IndoorBikeDataCharacteristic.js deleted file mode 100644 index 9a1b71c017..0000000000 --- a/app/ble/ftms/IndoorBikeDataCharacteristic.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This implements the Indoor Bike Data Characteristic as defined by the Bluetooth SIG - Currently hardly any applications exist that support these FTMS Characteristic for Rowing. - So we use this to simulate an FTMS Indoor Bike characteristic. - Of course we can not deliver rowing specific parameters like this (such as stroke rate), but - this allows us to use the open rowing monitor with bike training platforms such as - Zwift, Sufferfest, RGT Cycling, Kinomap, Bkool, Rouvy and more... - So far tested on: - - Kinomap.com: uses Power and Speed - - Fulgaz: uses Power and Speed - - Zwift: uses Power - - RGT Cycling: connects Power but then disconnects again (seems something is missing here) - - From specs: - The Server should notify this characteristic at a regular interval, typically once per second - while in a connection and the interval is not configurable by the Client -*/ -import bleno from '@abandonware/bleno' -import log from 'loglevel' -import BufferBuilder from '../BufferBuilder.js' - -export default class IndoorBikeDataCharacteristic extends bleno.Characteristic { - constructor () { - super({ - // Indoor Bike Data - uuid: '2AD2', - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - this._subscriberMaxValueSize = null - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`IndoorBikeDataCharacteristic - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - this._subscriberMaxValueSize = maxValueSize - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('IndoorBikeDataCharacteristic - central unsubscribed') - this._updateValueCallback = null - this._subscriberMaxValueSize = null - return this.RESULT_UNLIKELY_ERROR - } - - notify (data) { - // ignore events without the mandatory fields - if (!('cycleLinearVelocity' in data)) { - log.error('can not deliver bike data without mandatory fields') - return this.RESULT_SUCCESS - } - - if (this._updateValueCallback) { - const bufferBuilder = new BufferBuilder() - // 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) - - // see https://www.bluetooth.com/specifications/specs/gatt-specification-supplement-3/ - // for some of the data types - // Instantaneous Speed in km/h - 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.cycleStrokeRate * 2)) - // Total Distance in meters - bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance)) - // Instantaneous Power in watts - bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) - // Energy - // Total energy in kcal - 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.totalCaloriesPerHour)) - // Energy per minute - 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.totalMovingTime)) - - const buffer = bufferBuilder.getBuffer() - if (buffer.length > this._subscriberMaxValueSize) { - log.warn(`IndoorBikeDataCharacteristic - notification of ${buffer.length} bytes is too large for the subscriber`) - } - this._updateValueCallback(bufferBuilder.getBuffer()) - } - return this.RESULT_SUCCESS - } -} 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/RowerDataCharacteristic.js b/app/ble/ftms/RowerDataCharacteristic.js deleted file mode 100644 index a3a376266e..0000000000 --- a/app/ble/ftms/RowerDataCharacteristic.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This implements the Rower Data Characteristic as defined by the Bluetooth SIG - Currently not many applications exist that support thes FTMS Characteristic for Rowing so its hard - to verify this. So far tested on: - - Kinomap.com: uses Power, Split Time and Strokes per Minutes - - From the specs: - The Server should notify this characteristic at a regular interval, typically once per second - while in a connection and the interval is not configurable by the Client -*/ -import bleno from '@abandonware/bleno' -import log from 'loglevel' -import BufferBuilder from '../BufferBuilder.js' - -export default class RowerDataCharacteristic extends bleno.Characteristic { - constructor () { - super({ - // Rower Data - uuid: '2AD1', - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - this._subscriberMaxValueSize = null - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`RowerDataCharacteristic - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - this._subscriberMaxValueSize = maxValueSize - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('RowerDataCharacteristic - central unsubscribed') - this._updateValueCallback = null - this._subscriberMaxValueSize = null - return this.RESULT_UNLIKELY_ERROR - } - - notify (data) { - // ignore events without the mandatory fields - if (!('cycleStrokeRate' in data && 'totalNumberOfStrokes' in data)) { - return this.RESULT_SUCCESS - } - - if (this._updateValueCallback) { - const bufferBuilder = new BufferBuilder() - // Field flags as defined in the Bluetooth Documentation - // Stroke Rate (default), Stroke Count (default), Total Distance (2), Instantaneous Pace (3), - // Instantaneous Power (5), Total / Expended Energy (8), Heart Rate (9), Elapsed Time (11) - // todo: might add: Average Stroke Rate (1), Average Pace (4), Average Power (6) - // Remaining Time (12) - // 00101100 - bufferBuilder.writeUInt8(0x2c) - // 00001011 - bufferBuilder.writeUInt8(0x0B) - - // 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.cycleStrokeRate * 2)) - // Stroke Count - bufferBuilder.writeUInt16LE(Math.round(data.totalNumberOfStrokes)) - // Total Distance in meters - 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.cyclePace !== Infinity && data.cyclePace < 65535 ? Math.round(data.cyclePace) : 0xFFFF) - // Instantaneous Power in watts - bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) - // Energy in kcal - // Total energy in kcal - 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.totalCaloriesPerHour)) - // Energy per minute - 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.totalMovingTime)) - - const buffer = bufferBuilder.getBuffer() - if (buffer.length > this._subscriberMaxValueSize) { - log.warn(`RowerDataCharacteristic - notification of ${buffer.length} bytes is too large for the subscriber`) - } - this._updateValueCallback(bufferBuilder.getBuffer()) - } - return this.RESULT_SUCCESS - } -} 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/ble/pm5/GapService.js b/app/ble/pm5/GapService.js deleted file mode 100644 index f90c42c8b0..0000000000 --- a/app/ble/pm5/GapService.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Provides all required GAP Characteristics of the PM5 - 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' - -export default class GapService extends bleno.PrimaryService { - constructor () { - super({ - // GAP Service UUID of PM5 - uuid: getFullUUID('0000'), - characteristics: [ - // GAP device name - new ValueReadCharacteristic('2A00', constants.name), - // GAP appearance - new ValueReadCharacteristic('2A01', [0x00, 0x00]), - // GAP peripheral privacy - new ValueReadCharacteristic('2A02', [0x00]), - // GAP reconnect address - new ValueReadCharacteristic('2A03', '00:00:00:00:00:00'), - // Peripheral preferred connection parameters - new ValueReadCharacteristic('2A04', [0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0xE8, 0x03]) - ] - }) - } -} diff --git a/app/ble/pm5/Pm5Constants.js b/app/ble/pm5/Pm5Constants.js deleted file mode 100644 index e4c352d4f5..0000000000 --- a/app/ble/pm5/Pm5Constants.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Some PM5 specific constants -*/ -const constants = { - 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', - ergMachineType: [0x05] -} - -// PM5 uses 128bit UUIDs that are always prefixed and suffixed the same way -function getFullUUID (uuid) { - return `ce06${uuid}43e511e4916c0800200c9a66` -} - -export { - getFullUUID, - constants -} diff --git a/app/ble/pm5/Pm5ControlService.js b/app/ble/pm5/Pm5ControlService.js deleted file mode 100644 index 83e5a28e82..0000000000 --- a/app/ble/pm5/Pm5ControlService.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - The Control service can be used to send control commands to the PM5 device - todo: not yet wired -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from './Pm5Constants.js' -import ControlTransmit from './characteristic/ControlTransmit.js' -import ControlReceive from './characteristic/ControlReceive.js' - -export default class PM5ControlService extends bleno.PrimaryService { - constructor () { - super({ - uuid: getFullUUID('0020'), - characteristics: [ - new ControlReceive(), - new ControlTransmit() - ] - }) - } -} diff --git a/app/ble/pm5/Pm5RowingService.js b/app/ble/pm5/Pm5RowingService.js deleted file mode 100644 index 8e00cf5f1d..0000000000 --- a/app/ble/pm5/Pm5RowingService.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This seems to be the central service to get information about the workout - This Primary Service provides a lot of stuff that we most certainly do not need to simulate a - simple PM5 service. - - todo: figure out to which services some common applications subscribe and then just implement those - // fluid simulation uses GeneralStatus STROKESTATE_DRIVING - // cloud simulation uses MULTIPLEXER, AdditionalStatus -> currentPace - // EXR: subscribes to: 'general status', 'additional status', 'additional status 2', 'additional stroke data' - Might implement: - * GeneralStatus - * AdditionalStatus - * AdditionalStatus2 - * (StrokeData) - * AdditionalStrokeData - * and of course the multiplexer -*/ -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' - -export default class PM5RowingService extends bleno.PrimaryService { - constructor () { - const multiplexedCharacteristic = new MultiplexedCharacteristic() - const generalStatus = new GeneralStatus(multiplexedCharacteristic) - const additionalStatus = new AdditionalStatus(multiplexedCharacteristic) - const additionalStatus2 = new AdditionalStatus2(multiplexedCharacteristic) - const strokeData = new StrokeData(multiplexedCharacteristic) - const additionalStrokeData = new AdditionalStrokeData(multiplexedCharacteristic) - super({ - uuid: getFullUUID('0030'), - characteristics: [ - // C2 rowing general status - generalStatus, - // C2 rowing additional status - additionalStatus, - // C2 rowing additional status 2 - additionalStatus2, - // C2 rowing general status and additional status samplerate - new ValueReadCharacteristic(getFullUUID('0034'), 'samplerate', 'samplerate'), - // C2 rowing stroke data - strokeData, - // C2 rowing additional stroke data - additionalStrokeData, - // C2 rowing split/interval data - new ValueReadCharacteristic(getFullUUID('0037'), 'split data', 'split data'), - // C2 rowing additional split/interval data - new ValueReadCharacteristic(getFullUUID('0038'), 'additional split data', 'additional split data'), - // C2 rowing end of workout summary data - new ValueReadCharacteristic(getFullUUID('0039'), 'workout summary', 'workout summary'), - // C2 rowing end of workout additional summary data - new ValueReadCharacteristic(getFullUUID('003A'), 'additional workout summary', 'additional workout summary'), - // C2 rowing heart rate belt information - new ValueReadCharacteristic(getFullUUID('003B'), 'heart rate belt information', 'heart rate belt information'), - // C2 force curve data - new ValueReadCharacteristic(getFullUUID('003D'), 'force curve data', 'force curve data'), - // C2 multiplexed information - multiplexedCharacteristic - ] - }) - this.generalStatus = generalStatus - this.additionalStatus = additionalStatus - this.additionalStatus2 = additionalStatus2 - this.strokeData = strokeData - this.additionalStrokeData = additionalStrokeData - this.multiplexedCharacteristic = multiplexedCharacteristic - } - - notifyData (type, data) { - if (type === 'strokeFinished' || type === 'metricsUpdate') { - this.generalStatus.notify(data) - this.additionalStatus.notify(data) - this.additionalStatus2.notify(data) - this.strokeData.notify(data) - this.additionalStrokeData.notify(data) - } else if (type === 'strokeStateChanged') { - // the stroke state is delivered via the GeneralStatus Characteristic, so we only need to notify that one - this.generalStatus.notify(data) - } - } -} diff --git a/app/ble/pm5/characteristic/AdditionalStatus.js b/app/ble/pm5/characteristic/AdditionalStatus.js deleted file mode 100644 index 2173275976..0000000000 --- a/app/ble/pm5/characteristic/AdditionalStatus.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implementation of the AdditionalStatus as defined in: - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from '../Pm5Constants.js' -import log from 'loglevel' -import BufferBuilder from '../../BufferBuilder.js' - -export default class AdditionalStatus extends bleno.Characteristic { - constructor (multiplexedCharacteristic) { - super({ - // id for AdditionalStatus as defined in the spec - uuid: getFullUUID('0032'), - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - this._multiplexedCharacteristic = multiplexedCharacteristic - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`AdditionalStatus - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('AdditionalStatus - central unsubscribed') - this._updateValueCallback = null - return this.RESULT_UNLIKELY_ERROR - } - - notify (data) { - if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { - const bufferBuilder = new BufferBuilder() - // elapsedTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) - // speed: UInt16LE in 0.001 m/sec - bufferBuilder.writeUInt16LE(Math.round(data.cycleLinearVelocity * 1000)) - // strokeRate: UInt8 in strokes/min - 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.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.totalLinearDistance && data.totalLinearDistance !== 0) { - averagePace = (data.totalMovingTime / data.totalLinearDistance) * 500 - } - bufferBuilder.writeUInt16LE(Math.round(Math.min(averagePace * 100, 65535))) - // restDistance: UInt16LE - bufferBuilder.writeUInt16LE(0) - // restTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(0 * 100) - if (!this._updateValueCallback) { - // 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.cyclePower)) - } - // ergMachineType: 0 TYPE_STATIC_D - bufferBuilder.writeUInt8(0) - - if (this._updateValueCallback) { - this._updateValueCallback(bufferBuilder.getBuffer()) - } else { - this._multiplexedCharacteristic.notify(0x32, bufferBuilder.getBuffer()) - } - return this.RESULT_SUCCESS - } - } -} diff --git a/app/ble/pm5/characteristic/AdditionalStatus2.js b/app/ble/pm5/characteristic/AdditionalStatus2.js deleted file mode 100644 index 66ccc66aec..0000000000 --- a/app/ble/pm5/characteristic/AdditionalStatus2.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implementation of the AdditionalStatus2 as defined in: - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from '../Pm5Constants.js' -import log from 'loglevel' -import BufferBuilder from '../../BufferBuilder.js' - -export default class AdditionalStatus2 extends bleno.Characteristic { - constructor (multiplexedCharacteristic) { - super({ - // id for AdditionalStatus2 as defined in the spec - uuid: getFullUUID('0033'), - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - this._multiplexedCharacteristic = multiplexedCharacteristic - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`AdditionalStatus2 - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('AdditionalStatus2 - central unsubscribed') - this._updateValueCallback = null - return this.RESULT_UNLIKELY_ERROR - } - - notify (data) { - if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { - const bufferBuilder = new BufferBuilder() - // elapsedTime: UInt24LE in 0.01 sec - 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.cyclePower)) - } - // 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 - bufferBuilder.writeUInt16LE(0) - // splitAverageCalories - bufferBuilder.writeUInt16LE(0) - // lastSplitTime - bufferBuilder.writeUInt24LE(0 * 100) - // lastSplitDistance in 1 m - bufferBuilder.writeUInt24LE(0) - - if (this._updateValueCallback) { - this._updateValueCallback(bufferBuilder.getBuffer()) - } else { - this._multiplexedCharacteristic.notify(0x33, bufferBuilder.getBuffer()) - } - return this.RESULT_SUCCESS - } - } -} diff --git a/app/ble/pm5/characteristic/AdditionalStrokeData.js b/app/ble/pm5/characteristic/AdditionalStrokeData.js deleted file mode 100644 index 2a05515806..0000000000 --- a/app/ble/pm5/characteristic/AdditionalStrokeData.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implementation of the AdditionalStrokeData as defined in: - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from '../Pm5Constants.js' -import log from 'loglevel' -import BufferBuilder from '../../BufferBuilder.js' - -export default class AdditionalStrokeData extends bleno.Characteristic { - constructor (multiplexedCharacteristic) { - super({ - // id for AdditionalStrokeData as defined in the spec - uuid: getFullUUID('0036'), - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - this._multiplexedCharacteristic = multiplexedCharacteristic - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`AdditionalStrokeData - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('AdditionalStrokeData - central unsubscribed') - this._updateValueCallback = null - return this.RESULT_UNLIKELY_ERROR - } - - notify (data) { - if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { - const bufferBuilder = new BufferBuilder() - // elapsedTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) - // strokePower: UInt16LE in watts - bufferBuilder.writeUInt16LE(Math.round(data.cyclePower)) - // strokeCalories: UInt16LE in cal - bufferBuilder.writeUInt16LE(Math.round(data.strokeCalories * 1000)) - // strokeCount: UInt16LE - bufferBuilder.writeUInt16LE(Math.round(data.totalNumberOfStrokes)) - // projectedWorkTime: UInt24LE in 1 sec - bufferBuilder.writeUInt24LE(Math.round(data.cycleProjectedEndTime)) - // projectedWorkDistance: UInt24LE in 1 m - 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 in 0.1 Joules - bufferBuilder.writeUInt16LE(Math.round(data.strokeWork * 10)) - } - - if (this._updateValueCallback) { - this._updateValueCallback(bufferBuilder.getBuffer()) - } else { - this._multiplexedCharacteristic.notify(0x36, bufferBuilder.getBuffer()) - } - return this.RESULT_SUCCESS - } - } -} diff --git a/app/ble/pm5/characteristic/ControlReceive.js b/app/ble/pm5/characteristic/ControlReceive.js deleted file mode 100644 index ace8b2347e..0000000000 --- a/app/ble/pm5/characteristic/ControlReceive.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implementation of the ControlReceive Characteristic as defined in: - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf - Used to receive controls from the central -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from '../Pm5Constants.js' -import log from 'loglevel' - -export default class ControlReceive extends bleno.Characteristic { - constructor () { - super({ - // id for ControlReceive as defined in the spec - uuid: getFullUUID('0021'), - value: null, - properties: ['write'] - }) - this._updateValueCallback = null - } - - // Central sends a command to the Control Point - onWriteRequest (data, offset, withoutResponse, callback) { - log.debug('ControlReceive command: ', data) - } -} diff --git a/app/ble/pm5/characteristic/ControlTransmit.js b/app/ble/pm5/characteristic/ControlTransmit.js deleted file mode 100644 index 644ec7a2b7..0000000000 --- a/app/ble/pm5/characteristic/ControlTransmit.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implementation of the ControlTransmit Characteristic as defined in: - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf - Used to transmit controls to the central -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from '../Pm5Constants.js' -import log from 'loglevel' -import BufferBuilder from '../../BufferBuilder.js' - -export default class ControlTransmit extends bleno.Characteristic { - constructor () { - super({ - // id for ControlTransmit as defined in the spec - uuid: getFullUUID('0022'), - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`ControlTransmit - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('ControlTransmit - central unsubscribed') - this._updateValueCallback = null - return this.RESULT_UNLIKELY_ERROR - } - - notify (data) { - if (this._updateValueCallback) { - const bufferBuilder = new BufferBuilder() - this._updateValueCallback(bufferBuilder.getBuffer()) - return this.RESULT_SUCCESS - } - } -} diff --git a/app/ble/pm5/characteristic/GeneralStatus.js b/app/ble/pm5/characteristic/GeneralStatus.js deleted file mode 100644 index c0116ee038..0000000000 --- a/app/ble/pm5/characteristic/GeneralStatus.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implementation of the GeneralStatus as defined in: - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from '../Pm5Constants.js' -import log from 'loglevel' -import BufferBuilder from '../../BufferBuilder.js' - -export default class GeneralStatus extends bleno.Characteristic { - constructor (multiplexedCharacteristic) { - super({ - // id for GeneralStatus as defined in the spec - uuid: getFullUUID('0031'), - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - this._multiplexedCharacteristic = multiplexedCharacteristic - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`GeneralStatus - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('GeneralStatus - central unsubscribed') - this._updateValueCallback = null - return this.RESULT_UNLIKELY_ERROR - } - - notify (data) { - if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { - const bufferBuilder = new BufferBuilder() - // elapsedTime: UInt24LE in 0.01 sec - 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 - 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.sessionStatus === 'Rowing' ? 1 : (data.sessionStatus === 'WaitingForStart' ? 0 : 10)) - // rowingState: UInt8 0 INACTIVE, 1 ACTIVE - bufferBuilder.writeUInt8(data.sessionStatus === 'Rowing' ? 1 : 0) - // strokeState: UInt8 2 DRIVING, 4 RECOVERY - bufferBuilder.writeUInt8(data.strokeState === 'WaitingForDrive' ? 0 : (data.strokeState === 'Drive' ? 2 : 4)) - // totalWorkDistance: UInt24LE in 1 m - bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance)) - // workoutDuration: UInt24LE in 0.01 sec (if type TIME) - 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(Math.round(Math.min(data.dragFactor, 255))) - - if (this._updateValueCallback) { - this._updateValueCallback(bufferBuilder.getBuffer()) - } else { - this._multiplexedCharacteristic.notify(0x31, bufferBuilder.getBuffer()) - } - return this.RESULT_SUCCESS - } - } -} diff --git a/app/ble/pm5/characteristic/MultiplexedCharacteristic.js b/app/ble/pm5/characteristic/MultiplexedCharacteristic.js deleted file mode 100644 index 7f1ee4e38f..0000000000 --- a/app/ble/pm5/characteristic/MultiplexedCharacteristic.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implements the Multiplexed Characteristic as defined by the spec: - - "On some Android platforms, there is a limitation to the number of notification messages allowed. - To circumvent this issue, a single characteristic (C2 multiplexed data - info) exists to allow multiple characteristics to be multiplexed onto a single characteristic. The last byte in the - characteristic will indicate which data characteristic is multiplexed." -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from '../Pm5Constants.js' -import log from 'loglevel' - -export default class MultiplexedCharacteristic extends bleno.Characteristic { - constructor () { - super({ - // id for MultiplexedInformation as defined in the spec - uuid: getFullUUID('0080'), - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`MultiplexedCharacteristic - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('MultiplexedCharacteristic - central unsubscribed') - this._updateValueCallback = null - return this.RESULT_UNLIKELY_ERROR - } - - centralSubscribed () { - return this._updateValueCallback !== null - } - - notify (id, characteristicBuffer) { - const characteristicId = Buffer.alloc(1) - characteristicId.writeUInt8(id, 0) - const buffer = Buffer.concat( - [ - characteristicId, - characteristicBuffer - ], - characteristicId.length + characteristicBuffer.length - ) - - if (this._updateValueCallback) { - this._updateValueCallback(buffer) - } - return this.RESULT_SUCCESS - } -} diff --git a/app/ble/pm5/characteristic/StrokeData.js b/app/ble/pm5/characteristic/StrokeData.js deleted file mode 100644 index 4f69bda2e9..0000000000 --- a/app/ble/pm5/characteristic/StrokeData.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implementation of the StrokeData as defined in: - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf - todo: we could calculate all the missing stroke metrics in the RowerEngine -*/ -import bleno from '@abandonware/bleno' -import { getFullUUID } from '../Pm5Constants.js' -import log from 'loglevel' -import BufferBuilder from '../../BufferBuilder.js' - -export default class StrokeData extends bleno.Characteristic { - constructor (multiplexedCharacteristic) { - super({ - // id for StrokeData as defined in the spec - uuid: getFullUUID('0035'), - value: null, - properties: ['notify'] - }) - this._updateValueCallback = null - this._multiplexedCharacteristic = multiplexedCharacteristic - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`StrokeData - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('StrokeData - central unsubscribed') - this._updateValueCallback = null - return this.RESULT_UNLIKELY_ERROR - } - - notify (data) { - if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) { - const bufferBuilder = new BufferBuilder() - // elapsedTime: UInt24LE in 0.01 sec - bufferBuilder.writeUInt24LE(Math.round(data.totalMovingTime * 100)) - // distance: UInt24LE in 0.1 m - bufferBuilder.writeUInt24LE(Math.round(data.totalLinearDistance * 10)) - // driveLength: UInt8 in 0.01 m - bufferBuilder.writeUInt8(Math.round(data.driveLength * 100)) - // driveTime: UInt8 in 0.01 s - bufferBuilder.writeUInt8(Math.round(data.driveDuration * 100)) - // strokeRecoveryTime: UInt16LE in 0.01 s - bufferBuilder.writeUInt16LE(Math.round(data.recoveryDuration * 100)) - // strokeDistance: UInt16LE in 0.01 s - 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 in 0.1 Joules - bufferBuilder.writeUInt16LE(Math.round(data.strokeWork * 10)) - } - // strokeCount: UInt16LE - bufferBuilder.writeUInt16LE(data.totalNumberOfStrokes) - if (this._updateValueCallback) { - this._updateValueCallback(bufferBuilder.getBuffer()) - } else { - this._multiplexedCharacteristic.notify(0x35, bufferBuilder.getBuffer()) - } - return this.RESULT_SUCCESS - } - } -} diff --git a/app/ble/pm5/characteristic/ValueReadCharacteristic.js b/app/ble/pm5/characteristic/ValueReadCharacteristic.js deleted file mode 100644 index 7797cd109f..0000000000 --- a/app/ble/pm5/characteristic/ValueReadCharacteristic.js +++ /dev/null @@ -1,40 +0,0 @@ -'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) { - super({ - uuid, - properties: ['read', 'notify'], - value: null - }) - this.uuid = uuid - this._value = Buffer.isBuffer(value) ? value : Buffer.from(value) - this._description = description - this._updateValueCallback = null - } - - onReadRequest (offset, callback) { - 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}`) - 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/client/components/AppDialog.js b/app/client/components/AppDialog.js index eab5d2efae..1d4e273a88 100644 --- a/app/client/components/AppDialog.js +++ b/app/client/components/AppDialog.js @@ -1,10 +1,9 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Component that renders a html dialog */ - import { AppElement, html, css } from './AppElement.js' import { customElement, property } from 'lit/decorators.js' import { ref, createRef } from 'lit/directives/ref.js' @@ -46,10 +45,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 +71,8 @@ export class AppDialog extends AppElement { padding: 0; } ` + @property({ type: Boolean }) + isValid = true @property({ type: Boolean, reflect: true }) dialogOpen @@ -74,13 +80,13 @@ export class AppDialog extends AppElement { render () { return html` -
+
- - + +
@@ -95,6 +101,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/AppElement.js b/app/client/components/AppElement.js index efe6c39454..817492b415 100644 --- a/app/client/components/AppElement.js +++ b/app/client/components/AppElement.js @@ -1,27 +1,14 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Base Component for all other App Components */ 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/BatteryIcon.js b/app/client/components/BatteryIcon.js index 2321a736c5..7bc62e1e01 100644 --- a/app/client/components/BatteryIcon.js +++ b/app/client/components/BatteryIcon.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Component that renders a battery indicator */ diff --git a/app/client/components/DashboardActions.js b/app/client/components/DashboardActions.js index 109cdfa4f4..a24ca248fd 100644 --- a/app/client/components/DashboardActions.js +++ b/app/client/components/DashboardActions.js @@ -1,41 +1,57 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Component that renders the action buttons of the dashboard */ 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 { customElement, property, state } from 'lit/decorators.js' +import { iconUndo, iconExpand, iconCompress, iconPoweroff, iconBluetooth, iconUpload, iconHeartbeat, iconAntplus } from '../lib/icons.js' import './AppDialog.js' @customElement('dashboard-actions') 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) { @@ -58,65 +74,95 @@ export class DashboardActions extends AppElement { } ` - @state({ type: Object }) - dialog + @property({ type: Object }) + config = {} + + @state() + _appMode = 'BROWSER' + + @state() + _dialog render () { return html` - - ${this.renderOptionalButtons()} - -
${this.peripheralMode()}
- ${this.dialog ? this.dialog : ''} +
+ + ${this.renderOptionalButtons()} + + +
+
+ +
${this.blePeripheralMode()}
+
+ ${this._dialog ? this._dialog : ''} ` } + 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.appState?.appMode === 'BROWSER' && document.documentElement.requestFullscreen) { + if (this._appMode === 'BROWSER' && document.documentElement.requestFullscreen) { buttons.push(html` `) } // add a button to power down the device, if browser is running on the device in kiosk mode // and the shutdown feature is enabled // (might also make sence to enable this for all clients but then we would need visual feedback) - if (this.appState?.appMode === 'KIOSK' && this.appState?.config?.shutdownEnabled) { + if (this._appMode === 'KIOSK' && this.config?.shutdownEnabled) { buttons.push(html` - + `) } - if (this.appState?.config?.stravaUploadEnabled) { + if (this.config?.uploadEnabled) { buttons.push(html` - + `) } return buttons } - peripheralMode () { - const value = this.appState?.config?.peripheralMode - + blePeripheralMode () { + const value = this.config?.blePeripheralMode switch (value) { case 'PM5': return 'C2 PM5' 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: - return '' + return 'Off' } } @@ -135,34 +181,42 @@ export class DashboardActions extends AppElement { this.sendEvent('triggerAction', { command: 'reset' }) } - switchPeripheralMode () { - this.sendEvent('triggerAction', { command: 'switchPeripheralMode' }) + switchBlePeripheralMode () { + this.sendEvent('triggerAction', { command: 'switchBlePeripheralMode' }) + } + + switchAntPeripheralMode () { + this.sendEvent('triggerAction', { command: 'switchAntPeripheralMode' }) + } + + switchHrmPeripheralMode () { + this.sendEvent('triggerAction', { command: 'switchHrmMode' }) } uploadTraining () { - this.dialog = html` + this._dialog = html` - ${icon_upload}
Upload to Strava?
-

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

+ ${iconUpload}
Upload training?
+

Do you want to finish your workout and upload it to webservices (Strava, Intervals.icu and RowsAndAll)?

` function dialogClosed (event) { - this.dialog = undefined + this._dialog = undefined if (event.detail === 'confirm') { - this.sendEvent('triggerAction', { command: 'uploadTraining' }) + this.sendEvent('triggerAction', { command: 'upload' }) } } } shutdown () { - this.dialog = html` + this._dialog = html` - ${icon_poweroff}
Shutdown Open Rowing Monitor?
+ ${iconPoweroff}
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 new file mode 100644 index 0000000000..2e57958c7c --- /dev/null +++ b/app/client/components/DashboardForceCurve.js @@ -0,0 +1,125 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Component that renders a metric of the dashboard +*/ + +import { AppElement, html, css } from './AppElement.js' +import { customElement, property, state } from 'lit/decorators.js' +import ChartDataLabels from 'chartjs-plugin-datalabels' +import { Chart, Filler, Legend, LinearScale, LineController, LineElement, PointElement } from 'chart.js' + +@customElement('dashboard-force-curve') +export class DashboardForceCurve extends AppElement { + static styles = css` + canvas { + margin-top: 24px; + } + ` + + constructor () { + super() + Chart.register(ChartDataLabels, Legend, Filler, LinearScale, LineController, PointElement, LineElement) + } + + @property({ type: Object }) + value = [] + + @state() + _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: { + 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, + 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/DashboardMetric.js b/app/client/components/DashboardMetric.js index 185c89f470..0301874fee 100644 --- a/app/client/components/DashboardMetric.js +++ b/app/client/components/DashboardMetric.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Component that renders a metric of the dashboard */ @@ -35,19 +35,21 @@ export class DashboardMetric extends AppElement { ` @property({ type: Object }) - icon + icon = '' @property({ type: String }) unit = '' @property({ type: String }) - value = '' + value render () { return html` -
${this.icon}
+
+
${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 a37fcb41fc..7d0e932eb3 100644 --- a/app/client/components/PerformanceDashboard.js +++ b/app/client/components/PerformanceDashboard.js @@ -1,17 +1,15 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Component that renders the dashboard */ import { AppElement, html, css } from './AppElement.js' -import { APP_STATE } from '../store/appState.js' -import { customElement, property } from 'lit/decorators.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 { customElement, property, state } from 'lit/decorators.js' +import './SettingsDialog.js' +import { iconSettings } from '../lib/icons.js' +import { DASHBOARD_METRICS } from '../store/dashboardMetrics.js' @customElement('performance-dashboard') export class PerformanceDashboard extends AppElement { @@ -22,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(2, minmax(0, 1fr)); } @media (orientation: portrait) { @@ -32,7 +29,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; @@ -43,64 +40,70 @@ 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%); + } ` + @property() + appState = {} + + @state() + _dialog - @property({ type: Object }) - metrics + dashboardMetricComponentsFactory = (appState) => { + const metrics = appState.metrics + const configs = appState.config - @property({ type: Object }) - appState = APP_STATE + const dashboardMetricComponents = Object.keys(DASHBOARD_METRICS).reduce((dashboardMetrics, key) => { + dashboardMetrics[key] = DASHBOARD_METRICS[key].template(metrics, configs) + + return dashboardMetrics + }, {}) + + return dashboardMetricComponents + } render () { - const metrics = this.calculateFormattedMetrics(this.appState.metrics) + const metricConfig = [...new Set(this.appState.config.guiConfigs.dashboardMetrics)].reduce((prev, metricName) => { + prev.push(this.dashboardMetricComponentsFactory(this.appState)[metricName]) + return prev + }, []) + return html` - - - - - ${metrics?.heartrate?.value - ? html` - - ${metrics?.heartrateBatteryLevel?.value - ? html` - - ` - : '' - } - ` - : html``} - - - + +
+ ${iconSettings} + ${this._dialog ? this._dialog : ''} +
+ + ${metricConfig} ` } - // 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) - } + openSettings () { + this._dialog = html`` - 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 - } - } + /* eslint-disable-next-line no-unused-vars -- Standard construct?? */ + function dialogClosed (event) { + this._dialog = undefined } - return formattedMetrics } } diff --git a/app/client/components/SettingsDialog.js b/app/client/components/SettingsDialog.js new file mode 100644 index 0000000000..d0471cef88 --- /dev/null +++ b/app/client/components/SettingsDialog.js @@ -0,0 +1,253 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Component that renders the action buttons of the dashboard +*/ + +import { AppElement, html, css } from './AppElement.js' +import { customElement, property, query, queryAll, state } from 'lit/decorators.js' +import { iconSettings } from '../lib/icons.js' +import './AppDialog.js' +import { DASHBOARD_METRICS } from '../store/dashboardMetrics.js' + +@customElement('settings-dialog') +export class DashboardActions extends AppElement { + static styles = css` + .metric-selector-feedback{ + font-size: 0.5em; + padding-top: 8px; + } + + .settings-dialog>div.metric-selector{ + display: grid; + grid-template-columns: repeat(3,max-content); + 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; + } + + input[type="checkbox"]{ + cursor: pointer; + align-self: center; + width: 1.5em; + height: 1.5em; + } + + label>span { + cursor: pointer; + -webkit-user-select: none; + user-select: none; + } + + .icon { + height: 1.6em; + } + + legend{ + text-align: center; + } + + table { + min-height: 70px; + margin-top: 8px; + width: 100%; + } + + table, th, td { + font-size: 0.9em; + border: 1px solid white; + border-collapse: collapse; + } + + tr { + height: 50%; + } + + th, td { + padding: 8px; + 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('.metric-selector input') + _inputs + + @query('input[name="showIcons"]') + _showIconInput + + @query('input[name="maxNumberOfTiles"]') + _maxNumberOfTilesInput + + @state() + _selectedMetrics = [] + + @state() + _sumSelectedSlots = 0 + + @state() + _isValid = false + + @state() + _showIcons = true + + @state() + _maxNumberOfTiles = 8 + + render () { + return html` + + ${iconSettings}
Settings
+ +

Select metrics to be shown:

+
+ ${this.renderAvailableMetricList()} +
+
Slots remaining: ${this._maxNumberOfTiles - this._sumSelectedSlots} + + ${this.renderSelectedMetrics()} +
+
+

+ +

+

+ Experimental settings: + +

+
+ ` + } + + firstUpdated () { + this._selectedMetrics = [...this.config.dashboardMetrics] + this._sumSelectedSlots = this._selectedMetrics.length + this._showIcons = this.config.showIcons + this._maxNumberOfTiles = this.config.maxNumberOfTiles + if (this._sumSelectedSlots === this._maxNumberOfTiles) { + this._isValid = true + } else { + this._isValid = false + } + [...this._inputs].forEach(input => { + input.checked = this._selectedMetrics.find(metric => metric === input.name) !== undefined + }) + this._showIconInput.checked = this._showIcons + this._maxNumberOfTilesInput.checked = this._maxNumberOfTiles === 12 + } + + renderAvailableMetricList () { + return Object.keys(DASHBOARD_METRICS).map(key => html` + + `) + } + + 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]}`)}`) + 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 === 3 && e.target.size > 1) || (this._sumSelectedSlots + e.target.size > this._maxNumberOfTiles))) { + 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._selectedMetrics = [...this._selectedMetrics] + } + } + + this._sumSelectedSlots = this._selectedMetrics.length + if (this.isFormValid()) { + this._isValid = true + } else { + this._isValid = false + } + } + + toggleIcons (e) { + this._showIcons = e.target.checked + } + + toggleMaxTiles (e) { + this._maxNumberOfTiles = e.target.checked ? 12 : 8 + this._isValid = this.isFormValid() + } + + isFormValid () { + return this._sumSelectedSlots === this._maxNumberOfTiles && this._selectedMetrics[3] !== this._selectedMetrics[4] && this._selectedMetrics[7] !== this._selectedMetrics?.[8] + } + + close (event) { + this.dispatchEvent(new CustomEvent('close')) + if (event.detail === 'confirm') { + this.sendEvent('changeGuiSetting', { + dashboardMetrics: this._selectedMetrics, + showIcons: this._showIcons, + maxNumberOfTiles: this._maxNumberOfTiles + }) + } + } +} diff --git a/app/client/index.js b/app/client/index.js index b26dfcd4e6..4bfc50271d 100644 --- a/app/client/index.js +++ b/app/client/index.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Main Initialization Component of the Web Component App */ @@ -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,6 +25,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,20 +41,28 @@ 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).forEach(key => { + localStorage.setItem(key, JSON.stringify(event.detail[key])) + }) + this.updateState({ config: { ...this._appState.config, guiConfigs: { ...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 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 @@ -60,8 +70,7 @@ export class App extends LitElement { render () { return html` ` } diff --git a/app/client/lib/app.js b/app/client/lib/app.js index 86da9f67b7..011ae1e7de 100644 --- a/app/client/lib/app.js +++ b/app/client/lib/app.js @@ -1,49 +1,29 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Initialization file of the Open Rowing Monitor App */ - +/* eslint-disable no-console -- This runs client side, so I guess we have no logging capabilities? */ import NoSleep from 'nosleep.js' import { filterObjectByKeys } from './helper.js' -const rowingMetricsFields = ['totalNumberOfStrokes', 'totalLinearDistanceFormatted', 'totalCalories', 'cyclePower', 'heartrate', - 'heartrateBatteryLevel', 'cyclePaceFormatted', 'cycleStrokeRate', 'totalMovingTimeFormatted'] - 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') - let socket initWebsocket() resetFields() requestWakeLock() - function websocketOpened () { - if (stravaAuthorizationCode) { - handleStravaAuthorization(stravaAuthorizationCode) - } - } - - function handleStravaAuthorization (stravaAuthorizationCode) { - if (socket)socket.send(JSON.stringify({ command: 'stravaAuthorizationCode', data: stravaAuthorizationCode })) - } - let initialWebsocketOpenend = true function initWebsocket () { // use the native websocket implementation of browser to communicate with backend socket = new WebSocket(`ws://${location.host}/websocket`) + /* eslint-disable-next-line no-unused-vars -- Standard construct?? */ socket.addEventListener('open', (event) => { console.log('websocket opened') if (initialWebsocketOpenend) { - websocketOpened() initialWebsocketOpenend = false } }) @@ -53,6 +33,7 @@ export function createApp (app) { socket.close() }) + /* eslint-disable-next-line no-unused-vars -- Standard construct?? */ socket.addEventListener('close', (event) => { console.log('websocket closed, attempting reconnect') setTimeout(() => { @@ -71,33 +52,15 @@ 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': { - 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'] - } else if (data.totalMovingTimeFormatted !== '00:00') { - activeFields = ['totalMovingTimeFormatted', 'heartrate', 'heartrateBatteryLevel'] - } else { - activeFields = ['heartrate', 'heartrateBatteryLevel'] - } - } - - const filteredData = filterObjectByKeys(data, activeFields) - app.updateState({ ...app.getState(), metrics: filteredData }) - break - } - case 'authorizeStrava': { - const currentUrl = encodeURIComponent(window.location.href) - window.location.href = `https://www.strava.com/oauth/authorize?client_id=${data.stravaClientId}&response_type=code&redirect_uri=${currentUrl}&approval_prompt=force&scope=activity:write` + app.updateState({ ...app.getState(), metrics: data }) break } default: { - console.error(`unknown message type: ${message.type}`, message.data) + console.error('unknown message type: %s', message.type, message.data) } } } catch (err) { @@ -124,27 +87,38 @@ 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) { + if (!socket) { + console.error('no socket available for communication!') + return + } switch (action.command) { - case 'switchPeripheralMode': { - if (socket)socket.send(JSON.stringify({ command: 'switchPeripheralMode' })) + case 'switchBlePeripheralMode': { + socket.send(JSON.stringify({ command: 'switchBlePeripheralMode' })) + break + } + case 'switchAntPeripheralMode': { + socket.send(JSON.stringify({ command: 'switchAntPeripheralMode' })) + break + } + case 'switchHrmMode': { + socket.send(JSON.stringify({ command: 'switchHrmMode' })) break } case 'reset': { resetFields() - if (socket)socket.send(JSON.stringify({ command: 'reset' })) + socket.send(JSON.stringify({ command: 'reset' })) break } - case 'uploadTraining': { - if (socket)socket.send(JSON.stringify({ command: 'uploadTraining' })) + case 'upload': { + socket.send(JSON.stringify({ command: 'upload' })) break } case 'shutdown': { - if (socket)socket.send(JSON.stringify({ command: 'shutdown' })) + socket.send(JSON.stringify({ command: 'shutdown' })) break } default: { diff --git a/app/client/lib/helper.js b/app/client/lib/helper.js index 16bae1394f..e249ea6298 100644 --- a/app/client/lib/helper.js +++ b/app/client/lib/helper.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Helper functions */ @@ -14,3 +14,43 @@ export function filterObjectByKeys (object, keys) { return obj }, {}) } + +/** + * Pipe for converting seconds to a human readable time format 00:00 + * @param {number} timeInSeconds The actual time in seconds. +*/ +export function secondsToTimeString (timeInSeconds) { + if (timeInSeconds === undefined || timeInSeconds === null || isNaN(timeInSeconds)) { return '--' } + if (timeInSeconds === Infinity) { return '∞' } + const timeInRoundedSeconds = Math.round(timeInSeconds) + const hours = Math.floor(timeInRoundedSeconds / 3600) + const minutes = Math.floor(timeInRoundedSeconds / 60) - (hours * 60) + const seconds = Math.floor(timeInRoundedSeconds % 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 distance in meters with units + * @param {number} value The distance in meters. +*/ +export function formatDistance (value) { + return value >= 99999.5 ? + { distance: formatNumber((value / 1000), 2), unit: 'km' } : + { distance: formatNumber(value), unit: 'm' } +} + +/** + * 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 +} diff --git a/app/client/lib/helper.test.js b/app/client/lib/helper.test.js index 42fd02c692..96578a3b7e 100644 --- a/app/client/lib/helper.test.js +++ b/app/client/lib/helper.test.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ import { test } from 'uvu' import * as assert from 'uvu/assert' diff --git a/app/client/lib/icons.js b/app/client/lib/icons.js index 23b9a75668..85da58ae7a 100644 --- a/app/client/lib/icons.js +++ b/app/client/lib/icons.js @@ -1,27 +1,41 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor SVG Icons that are used by the Application */ import { svg } from 'lit' -export const icon_route = svg`` -export const icon_stopwatch = svg`` -export const icon_bolt = svg`` -export const icon_paddle = svg` +export const iconRoute = svg`` +export const iconStopwatch = svg`` +export const iconBolt = svg`` +export const iconPaddle = svg` ` -export const icon_heartbeat = svg`` -export const icon_fire = svg`` -export const icon_clock = svg`` -export const icon_undo = svg`` -export const icon_poweroff = svg`` -export const icon_expand = svg`` -export const icon_compress = svg`` -export const icon_bluetooth = svg`` -export const icon_upload = svg`` +export const iconHeartbeat = svg`` +export const iconFire = svg`` +export const iconClock = svg`` +export const iconAlarmclock = svg` + + ` +export const iconUndo = svg`` +export const iconPoweroff = svg`` +export const iconExpand = svg`` +export const iconCompress = svg`` +export const iconBluetooth = svg`` +export const iconUpload = svg`` + +export const iconAntplus = svg`` +export const iconSettings = svg`` +export const rowerIcon = svg`` diff --git a/app/client/store/appState.js b/app/client/store/appState.js index 12666d7de6..39ed76d3a0 100644 --- a/app/client/store/appState.js +++ b/app/client/store/appState.js @@ -1,21 +1,55 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Defines the global state of the app + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ - +/** + * @file Defines the initial global state of the webclient, before the webserver pushes actual data + */ 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: {}, + metrics: { + strokeState: 'WaitingForDrive', + sessionState: 'WaitingForStart', + totalMovingTime: 0, + pauseCountdownTime: 0, + totalNumberOfStrokes: 0, + totalLinearDistance: 0, + cyclePace: Infinity, + cyclePower: 0, + cycleStrokeRate: 0, + driveLength: 0, + driveDuration: 0, + driveHandleForceCurve: [], + driveDistance: 0, + recoveryDuration: 0, + dragFactor: undefined, + interval: { + type: 'justrow', + movingTime: { + sinceStart: 0, + toEnd: 0 + }, + distance: { + fromStart: 0, + toEnd: 0 + } + } + }, config: { - // currently can be FTMS, FTMSBIKE, PM5, CSC, CPS - peripheralMode: '', - // true if upload to strava is enabled - stravaUploadEnabled: false, + // currently can be FTMS, FTMSBIKE, PM5, CSC, CPS, OFF + blePeripheralMode: '', + // currently can be ANT, BLE, OFF + hrmPeripheralMode: '', + // currently can be FE, OFF + antPeripheralMode: '', + // true if manual upload to strava, intervals or rowsandall is enabled + uploadEnabled: false, // true if remote device shutdown is enabled - shutdownEnabled: false + shutdownEnabled: false, + guiConfigs: { + dashboardMetrics: ['distance', 'timer', 'pace', 'power', 'stkRate', 'totalStk', 'calories', 'actions'], + showIcons: true, + maxNumberOfTiles: 8 + } } } diff --git a/app/client/store/dashboardMetrics.js b/app/client/store/dashboardMetrics.js new file mode 100644 index 0000000000..648ea43780 --- /dev/null +++ b/app/client/store/dashboardMetrics.js @@ -0,0 +1,110 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ + +import { html } from 'lit' +import { formatDistance, formatNumber, secondsToTimeString } from '../lib/helper' +import { iconBolt, iconClock, iconAlarmclock, iconFire, iconHeartbeat, iconPaddle, iconRoute, iconStopwatch, rowerIcon } from '../lib/icons' +import '../components/DashboardForceCurve.js' +import '../components/DashboardActions.js' +import '../components/DashboardMetric.js' +import '../components/BatteryIcon.js' + +export const DASHBOARD_METRICS = { + distance: { + displayName: 'Distance', + size: 1, + template: (metrics, config) => { + let distance + switch (true) { + case (metrics?.interval?.type === 'rest' && metrics?.pauseCountdownTime > 0): + distance = 0 + break + case (metrics?.interval?.type === 'distance'): + distance = Math.max(metrics?.interval?.distance?.toEnd, 0) + break + default: + distance = Math.max(metrics?.interval?.distance?.fromStart, 0) + } + const linearDistance = formatDistance(distance ?? 0) + + return simpleMetricFactory(linearDistance.distance, linearDistance.unit, config?.guiConfigs?.showIcons ? iconRoute : '') + } + }, + + pace: { displayName: 'Pace/500', size: 1, template: (metrics, config) => simpleMetricFactory(secondsToTimeString(metrics?.cyclePace), '/500m', config?.guiConfigs?.showIcons ? iconStopwatch : '') }, + + power: { displayName: 'Power', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cyclePower), 'watt', config?.guiConfigs?.showIcons ? iconBolt : '') }, + + stkRate: { displayName: 'Stroke rate', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cycleStrokeRate), '/min', config?.guiConfigs?.showIcons ? iconPaddle : '') }, + heartRate: { + displayName: 'Heart rate', + size: 1, + template: (metrics, config) => html` + ${metrics?.heartRateBatteryLevel > 0 ? + html`` : + ''} + ` + }, + + totalStk: { displayName: 'Total strokes', size: 1, template: (metrics, config) => simpleMetricFactory(metrics?.totalNumberOfStrokes, 'stk', config?.guiConfigs?.showIcons ? iconPaddle : '') }, + + calories: { + displayName: 'Calories', + size: 1, + template: (metrics, config) => { + const calories = metrics?.interval?.type === 'Calories' ? Math.max(metrics?.interval?.TargetCalories - metrics?.interval?.Calories, 0) : metrics?.totalCalories + + return simpleMetricFactory(formatNumber(calories ?? 0), 'kcal', config?.guiConfigs?.showIcons ? iconFire : '') + } + }, + + timer: { + displayName: 'Timer', + size: 1, + template: (metrics, config) => { + let time + let icon + switch (true) { + case (metrics?.interval?.type === 'rest' && metrics?.pauseCountdownTime > 0): + time = metrics?.pauseCountdownTime + icon = iconAlarmclock + break + case (metrics?.interval?.type === 'time'): + time = Math.max(metrics?.interval?.movingTime?.toEnd, 0) + icon = iconClock + break + default: + time = Math.max(metrics?.interval?.movingTime?.sinceStart, 0) + icon = iconClock + } + + return simpleMetricFactory(secondsToTimeString(time ?? 0), '', config?.guiConfigs?.showIcons ? icon : '') + } + }, + + distancePerStk: { displayName: 'Dist per Stroke', size: 1, template: (metrics, config) => simpleMetricFactory(formatNumber(metrics?.cycleDistance, 1), 'm', config?.guiConfigs?.showIcons ? rowerIcon : '') }, + + 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: (_, config) => html`` } +} + +/** + * 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). +*/ +function simpleMetricFactory (value = '--', unit = '', icon = '') { + return html`` +} diff --git a/app/engine/Flywheel.js b/app/engine/Flywheel.js index b20b09c1e3..e2024e3c95 100644 --- a/app/engine/Flywheel.js +++ b/app/engine/Flywheel.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor This models the flywheel with all of its attributes, which we can also test for being powered @@ -22,25 +22,27 @@ import loglevel from 'loglevel' import { createStreamFilter } from './utils/StreamFilter.js' -import { createSeries } from './utils/Series.js' -import { createOLSLinearSeries } from './utils/OLSLinearSeries.js' +import { createTSLinearSeries } from './utils/FullTSLinearSeries.js' import { createTSQuadraticSeries } from './utils/FullTSQuadraticSeries.js' +import { createWeighedSeries } from './utils/WeighedSeries.js' + const log = loglevel.getLogger('RowingEngine') -function createFlywheel (rowerSettings) { +export 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 minimumAngularVelocity = angularDisplacementPerImpulse / rowerSettings.maximumTimeBetweenImpulses + const minimumTorqueBeforeStroke = rowerSettings.minimumForceBeforeStroke * (rowerSettings.sprocketRadius / 100) const currentDt = createStreamFilter(rowerSettings.smoothing, rowerSettings.maximumTimeBetweenImpulses) - const _deltaTime = createOLSLinearSeries(flankLength) + const _deltaTime = createTSLinearSeries(flankLength) const _angularDistance = createTSQuadraticSeries(flankLength) - const _angularVelocityMatrix = [] - const _angularAccelerationMatrix = [] - const drag = createStreamFilter(rowerSettings.dragFactorSmoothing, (rowerSettings.dragFactor / 1000000)) - const recoveryDeltaTime = createOLSLinearSeries() + const drag = createWeighedSeries(rowerSettings.dragFactorSmoothing, (rowerSettings.dragFactor / 1000000)) + const recoveryDeltaTime = createTSLinearSeries() const strokedetectionMinimalGoodnessOfFit = rowerSettings.minimumStrokeQuality - const minumumRecoverySlope = createStreamFilter(rowerSettings.dragFactorSmoothing, rowerSettings.minumumRecoverySlope) + const minimumRecoverySlope = createWeighedSeries(rowerSettings.dragFactorSmoothing, rowerSettings.minimumRecoverySlope) + let _angularVelocityMatrix = [] + let _angularAccelerationMatrix = [] let _deltaTimeBeforeFlank let _angularVelocityAtBeginFlank let _angularVelocityBeforeFlank @@ -57,11 +59,12 @@ function createFlywheel (rowerSettings) { let currentAngularDistance reset() + /* eslint-disable max-statements -- we need to maintain a lot of metrics in the main loop, nothing we can do about that */ 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() + log.debug(`*** WARNING: currentDt of ${dataPoint} sec isn't between 0 and maximumStrokeTimeBeforePause (${rowerSettings.maximumStrokeTimeBeforePause} sec), value skipped`) + return } if (dataPoint > rowerSettings.maximumTimeBetweenImpulses && maintainMetrics) { @@ -69,9 +72,15 @@ function createFlywheel (rowerSettings) { 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)`) + if (dataPoint < rowerSettings.minimumTimeBetweenImpulses) { + if (_deltaTime.length() >= flankLength && maintainMetrics) { + // We are in a normal operational mode, so this shouldn't happen, but let's log it to clarify there is some issue going on here, but accept the value as the TS estimator can handle it + log.debug(`*** WARNING: currentDt of ${dataPoint} sec is below minimumTimeBetweenImpulses (${rowerSettings.minimumTimeBetweenImpulses} sec)`) + } else { + // This is probably due to the start-up noise of a slow but accelerating flywheel as the flink isn't filled or we aren't maintaining metrics + log.debug(`*** WARNING: currentDt of ${dataPoint} sec is below minimumTimeBetweenImpulses (${rowerSettings.minimumTimeBetweenImpulses} sec) in a startup phase, value skipped, consider udjusting the gpio debounce filter`) + return + } } currentDt.push(dataPoint) @@ -81,7 +90,7 @@ function createFlywheel (rowerSettings) { // 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() + _deltaTimeBeforeFlank = _deltaTime.Y.atSeriesBegin() totalTimeSpinning += _deltaTimeBeforeFlank _angularVelocityBeforeFlank = _angularVelocityAtBeginFlank _angularAccelerationBeforeFlank = _angularAccelerationAtBeginFlank @@ -99,7 +108,7 @@ function createFlywheel (rowerSettings) { } // 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!) + // Please note that deltaTime MUST use dirty data to be ale to use the regression algorithms effictively (Otherwise the Goodness of Fit can't be used as a filter!) currentRawTime += currentDt.raw() currentAngularDistance += angularDisplacementPerImpulse _deltaTime.push(currentRawTime, currentDt.raw()) @@ -116,22 +125,24 @@ function createFlywheel (rowerSettings) { } // 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) + _angularVelocityMatrix[_angularVelocityMatrix.length] = createWeighedSeries(flankLength, 0) + _angularAccelerationMatrix[_angularAccelerationMatrix.length] = createWeighedSeries(flankLength, 0) let i = 0 + while (i < _angularVelocityMatrix.length) { - _angularVelocityMatrix[i].push(_angularDistance.firstDerivativeAtPosition(i)) - _angularAccelerationMatrix[i].push(_angularDistance.secondDerivativeAtPosition(i)) + _angularVelocityMatrix[i].push(_angularDistance.firstDerivativeAtPosition(i), _angularDistance.goodnessOfFit()) + _angularAccelerationMatrix[i].push(_angularDistance.secondDerivativeAtPosition(i), _angularDistance.goodnessOfFit()) i++ } - _angularVelocityAtBeginFlank = _angularVelocityMatrix[0].median() - _angularAccelerationAtBeginFlank = _angularAccelerationMatrix[0].median() + _angularVelocityAtBeginFlank = _angularVelocityMatrix[0].weighedAverage() + _angularAccelerationAtBeginFlank = _angularAccelerationMatrix[0].weighedAverage() // And finally calculate the torque - _torqueAtBeginFlank = (rowerSettings.flywheelInertia * _angularAccelerationAtBeginFlank + drag.clean() * Math.pow(_angularVelocityAtBeginFlank, 2)) + _torqueAtBeginFlank = (rowerSettings.flywheelInertia * _angularAccelerationAtBeginFlank + drag.weighedAverage() * Math.pow(_angularVelocityAtBeginFlank, 2)) } + /* eslint-enable max-statements */ function maintainStateOnly () { maintainMetrics = false @@ -152,11 +163,12 @@ function createFlywheel (rowerSettings) { // 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())) + drag.push(slopeToDrag(recoveryDeltaTime.slope()), recoveryDeltaTime.goodnessOfFit()) + 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()) + minimumRecoverySlope.push((1 - rowerSettings.autoAdjustRecoverySlopeMargin) * recoveryDeltaTime.slope(), recoveryDeltaTime.goodnessOfFit()) 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 @@ -213,16 +225,26 @@ function createFlywheel (rowerSettings) { } function dragFactor () { - // Ths function returns the current dragfactor of the flywheel - return drag.clean() + // This function returns the current dragfactor of the flywheel + return drag.weighedAverage() + } + + function dragFactorIsReliable () { + // This returns whether the dragfactor is considered reliable, based on measurements instead of a default value + // We can't use reliable() as a filter on the dragFactor() function as Rower.js always needs some dragfactor for most calculations + if (rowerSettings.autoAdjustDragFactor) { + return drag.reliable() + } else { + return true + } } 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)) { + // * The angular velocity at the begin of the flank is above the minimum angular velocity (dependent on maximumTimeBetweenImpulses) + // * The entire flank has a positive trend, i.e. the flywheel is decelerating consistent with the dragforce being present + if (_angularVelocityAtBeginFlank < minimumAngularVelocity && deltaTimeSlopeAbove(minimumRecoverySlope.weighedAverage())) { return true } else { return false @@ -230,9 +252,9 @@ function createFlywheel (rowerSettings) { } 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)) { + // Check if the flywheel has reached its minimum speed, and that it isn't flywheel noise. We conclude this based on the first element in the flank + // as this angular velocity is created by all curves that are in that flank and having an acceleration in the rest of the flank + if ((_angularVelocityAtBeginFlank >= minimumAngularVelocity) && (_deltaTime.Y.atSeriesBegin() <= rowerSettings.maximumTimeBetweenImpulses) && (_deltaTime.Y.atSeriesBegin() > rowerSettings.minimumTimeBetweenImpulses)) { return true } else { return false @@ -240,8 +262,9 @@ function createFlywheel (rowerSettings) { } function isUnpowered () { - if ((deltaTimeSlopeAbove(minumumRecoverySlope.clean()) || torqueAbsent()) && _deltaTime.length() >= flankLength) { - // We reached the minimum number of increasing currentDt values + // We consider the flywheel unpowered when there is an acceleration consistent with the drag being the only forces AND no torque being seen + // As in the first stroke drag is unreliable for automatic drag updating machines, torque can't be used when drag indicates it is unreliable for these machines + if (deltaTimeSlopeAbove(minimumRecoverySlope.weighedAverage()) && (torqueAbsent() || (rowerSettings.autoAdjustDragFactor && !drag.reliable()))) { return true } else { return false @@ -249,23 +272,7 @@ function createFlywheel (rowerSettings) { } 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) { + if (deltaTimeSlopeBelow(minimumRecoverySlope.weighedAverage()) && torquePresent()) { return true } else { return false @@ -276,6 +283,7 @@ function createFlywheel (rowerSettings) { // 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 + // Please note, as this acceleration isn't linear, _deltaTime.goodnessOfFit() will not be good by definition, so we need omit it if (_deltaTime.slope() < threshold && _deltaTime.length() >= flankLength) { return true } else { @@ -296,8 +304,8 @@ function createFlywheel (rowerSettings) { } 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) { + // This is a typical indication that the flywheel is accelerating: the torque is above a certain threshold (so a force is present on the handle) + if (_torqueAtBeginFlank >= minimumTorqueBeforeStroke) { return true } else { return false @@ -305,8 +313,11 @@ function createFlywheel (rowerSettings) { } 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) { + // This is a typical indication that the flywheel is decelerating: the torque is below a certain threshold (so a force is absent on the handle) + // We need to consider the situation rowerSettings.autoAdjustDragFactor && !drag.reliable() as a high default dragfactor (as set via config) blocks the + // detection of the first recovery based on Torque, and thus the calculation of the true dragfactor in that setting. + // This let the recovery detection fall back onto slope-based stroke detection only for the first stroke (until drag is calculated reliably) + if (_torqueAtBeginFlank < minimumTorqueBeforeStroke) { return true } else { return false @@ -329,6 +340,10 @@ function createFlywheel (rowerSettings) { currentCleanTime = 0 currentRawTime = 0 currentAngularDistance = 0 + _angularVelocityMatrix = null + _angularVelocityMatrix = [] + _angularAccelerationMatrix = null + _angularAccelerationMatrix = [] _deltaTime.push(0, 0) _angularDistance.push(0, 0) _deltaTimeBeforeFlank = 0 @@ -351,11 +366,11 @@ function createFlywheel (rowerSettings) { angularAcceleration, torque, dragFactor, + dragFactorIsReliable, isDwelling, isAboveMinimumSpeed, isUnpowered, - isPowered + isPowered, + reset } } - -export { createFlywheel } diff --git a/app/engine/Flywheel.test.js b/app/engine/Flywheel.test.js index 9e2276ca28..0fa485eb45 100644 --- a/app/engine/Flywheel.test.js +++ b/app/engine/Flywheel.test.js @@ -1,33 +1,36 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ import { test } from 'uvu' import * as assert from 'uvu/assert' import { deepMerge } from '../tools/Helper.js' -import { replayRowingSession } from '../tools/RowingRecorder.js' +import { replayRowingSession } from '../recorders/RowingReplayer.js' import rowerProfiles from '../../config/rowerProfiles.js' import { createFlywheel } from './Flywheel.js' -const baseConfig = { +const baseConfig = { // Based on Concept 2 settings, as this is the validation system 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, + sprocketRadius: 1.4, + maximumStrokeTimeBeforePause: 6.0, + dragFactor: 110, autoAdjustDragFactor: true, + minimumDragQuality: 0.95, dragFactorSmoothing: 3, - dragFactor: 100, - minimumDragQuality: 0.83, - flywheelInertia: 0.1, - sprocketRadius: 2 + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.020, + flankLength: 12, + smoothing: 1, + minimumStrokeQuality: 0.36, + minimumForceBeforeStroke: 10, + minimumRecoverySlope: 0.00070, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.15, + minimumDriveTime: 0.40, + minimumRecoveryTime: 0.90, + flywheelInertia: 0.1031, + magicConstant: 2.8 } // Test behaviour for no datapoints @@ -39,20 +42,17 @@ test('Correct Flywheel behaviour at initialisation', () => { testAngularVelocity(flywheel, 0) testAngularAcceleration(flywheel, 0) testTorque(flywheel, 0) - testDragFactor(flywheel, 0.0001) + testDragFactor(flywheel, 0.00011) testIsDwelling(flywheel, false) testIsUnpowered(flywheel, false) - testIsPowered(flywheel, true) + testIsPowered(flywheel, false) }) // 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', () => { @@ -64,10 +64,10 @@ test('Correct Flywheel behaviour for a noisefree stroke', () => { testAngularVelocity(flywheel, 0) testAngularAcceleration(flywheel, 0) testTorque(flywheel, 0) - testDragFactor(flywheel, 0.0001) + testDragFactor(flywheel, 0.00011) testIsDwelling(flywheel, false) testIsUnpowered(flywheel, false) - testIsPowered(flywheel, true) + testIsPowered(flywheel, false) flywheel.pushValue(0.011221636) flywheel.pushValue(0.011175504) flywheel.pushValue(0.01116456) @@ -87,13 +87,13 @@ test('Correct Flywheel behaviour for a noisefree stroke', () => { 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) + testDeltaTime(flywheel, 0.011062297) + testSpinningTime(flywheel, 0.077918634) + testAngularPosition(flywheel, 8.377580409572781) + testAngularVelocity(flywheel, 94.77498684553687) + testAngularAcceleration(flywheel, 28.980405331480235) + testTorque(flywheel, 3.975932584148498) + testDragFactor(flywheel, 0.00011) testIsDwelling(flywheel, false) testIsUnpowered(flywheel, false) testIsPowered(flywheel, true) @@ -112,13 +112,13 @@ test('Correct Flywheel behaviour for a noisefree stroke', () => { 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) + testDeltaTime(flywheel, 0.010722165) + testSpinningTime(flywheel, 0.23894732900000007) + testAngularPosition(flywheel, 24.085543677521745) + testAngularVelocity(flywheel, 97.12541571421204) + testAngularAcceleration(flywheel, -29.657604177526746) + testTorque(flywheel, -2.0200308891605716) + testDragFactor(flywheel, 0.00011) testIsDwelling(flywheel, false) testIsUnpowered(flywheel, true) testIsPowered(flywheel, false) @@ -137,32 +137,27 @@ test('Correct Flywheel behaviour for a noisefree stroke', () => { 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) + testDeltaTime(flywheel, 0.020722165) + testSpinningTime(flywheel, 0.43343548300000007) + testAngularPosition(flywheel, 39.79350694547071) + testAngularVelocity(flywheel, 50.85265548983507) + testAngularAcceleration(flywheel, -159.89027501034317) + testTorque(flywheel, -16.20022817082592) + testDragFactor(flywheel, 0.00011) 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', () => { @@ -174,10 +169,10 @@ test('Correct Flywheel behaviour at maintainStateOnly', () => { testAngularVelocity(flywheel, 0) testAngularAcceleration(flywheel, 0) testTorque(flywheel, 0) - testDragFactor(flywheel, 0.0001) + testDragFactor(flywheel, 0.00011) testIsDwelling(flywheel, false) testIsUnpowered(flywheel, false) - testIsPowered(flywheel, true) + testIsPowered(flywheel, false) flywheel.maintainStateOnly() flywheel.pushValue(0.011221636) flywheel.pushValue(0.011175504) @@ -204,7 +199,7 @@ test('Correct Flywheel behaviour at maintainStateOnly', () => { testAngularVelocity(flywheel, 0) testAngularAcceleration(flywheel, 0) testTorque(flywheel, 0) - testDragFactor(flywheel, 0.0001) + testDragFactor(flywheel, 0.00011) testIsDwelling(flywheel, false) testIsUnpowered(flywheel, false) testIsPowered(flywheel, true) @@ -229,7 +224,7 @@ test('Correct Flywheel behaviour at maintainStateOnly', () => { testAngularVelocity(flywheel, 0) testAngularAcceleration(flywheel, 0) testTorque(flywheel, 0) - testDragFactor(flywheel, 0.0001) + testDragFactor(flywheel, 0.00011) testIsDwelling(flywheel, false) testIsUnpowered(flywheel, true) testIsPowered(flywheel, false) @@ -240,9 +235,9 @@ test('Correct Flywheel behaviour with a SportsTech WRX700', async () => { testSpinningTime(flywheel, 0) testAngularPosition(flywheel, 0) testDragFactor(flywheel, (rowerProfiles.Sportstech_WRX700.dragFactor / 1000000)) + flywheel.maintainStateAndMetrics() // 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) @@ -254,9 +249,9 @@ test('Correct Flywheel behaviour with a DKN R-320', async () => { testSpinningTime(flywheel, 0) testAngularPosition(flywheel, 0) testDragFactor(flywheel, (rowerProfiles.DKN_R320.dragFactor / 1000000)) + flywheel.maintainStateAndMetrics() // Inject 10 strokes - flywheel.maintainStateAndMetrics() await replayRowingSession(flywheel.pushValue, { filename: 'recordings/DKNR320.csv', realtime: false, loop: false }) testSpinningTime(flywheel, 22.249536391000003) @@ -270,13 +265,13 @@ test('Correct Flywheel behaviour with a NordicTrack RX800', async () => { testSpinningTime(flywheel, 0) testAngularPosition(flywheel, 0) testDragFactor(flywheel, (rowerProfiles.NordicTrack_RX800.dragFactor / 1000000)) + flywheel.maintainStateAndMetrics() // 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) + testSpinningTime(flywheel, 22.612226401999987) + testAngularPosition(flywheel, 1443.5618243245099) // 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)) }) @@ -286,24 +281,40 @@ test('Correct Flywheel behaviour with a full session on a SportsTech WRX700', as testSpinningTime(flywheel, 0) testAngularPosition(flywheel, 0) testDragFactor(flywheel, (rowerProfiles.Sportstech_WRX700.dragFactor / 1000000)) + flywheel.maintainStateAndMetrics() // 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) + testSpinningTime(flywheel, 2340.0100514160117) + testAngularPosition(flywheel, 37325.26231730033) // The dragfactor should remain static testDragFactor(flywheel, (rowerProfiles.Sportstech_WRX700.dragFactor / 1000000)) }) +test('A full session for a Concept2 Model C should produce plausible results', async () => { + const flywheel = createFlywheel(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_Model_C)) + testSpinningTime(flywheel, 0) + testAngularPosition(flywheel, 0) + testDragFactor(flywheel, (rowerProfiles.Concept2_Model_C.dragFactor / 1000000)) + flywheel.maintainStateAndMetrics() + + await replayRowingSession(flywheel.pushValue, { filename: 'recordings/Concept2_Model_C.csv', realtime: false, loop: false }) + + testSpinningTime(flywheel, 181.47141999999985) + testAngularPosition(flywheel, 15636.753834467596) + // As we don't detect strokes here (this is a function of Rower.js, the dragcalculation shouldn't be triggered + testDragFactor(flywheel, (rowerProfiles.Concept2_Model_C.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 @@ -311,7 +322,6 @@ test('A full session for a Concept2 RowErg should produce plausible results', as }) // 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()}`) @@ -353,4 +363,8 @@ function testIsPowered (flywheel, expectedValue) { assert.ok(flywheel.isPowered() === expectedValue, `isPowered should be ${expectedValue} at ${flywheel.spinningTime()} sec, is ${flywheel.isPowered()}`) } +function reportAll (flywheel) { // eslint-disable-line no-unused-vars + assert.ok(0, `deltaTime: ${flywheel.deltaTime()}, spinningTime: ${flywheel.spinningTime()}, ang. pos: ${flywheel.angularPosition()}, ang. vel: ${flywheel.angularVelocity()}, Ang. acc: ${flywheel.angularAcceleration()}, Torque: ${flywheel.torque()}, DF: ${flywheel.dragFactor()}`) +} + test.run() diff --git a/app/engine/Rower.js b/app/engine/Rower.js index 82f73e2523..6857fb7f55 100644 --- a/app/engine/Rower.js +++ b/app/engine/Rower.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor The Rowing Engine models the physics of a real rowing boat. It takes impulses from the flywheel of a rowing machine and estimates @@ -10,25 +10,25 @@ 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 */ - +/* eslint-disable max-lines -- There is a lot of state machine dependent math going on here. Hard to keep short while maintaining readability */ import loglevel from 'loglevel' import { createFlywheel } from './Flywheel.js' import { createCurveMetrics } from './utils/curveMetrics.js' const log = loglevel.getLogger('RowingEngine') -function createRower (rowerSettings) { +export 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 - let _recoveryDuration = 0.0 + let _recoveryDuration let drivePhaseStartTime = 0.0 - let _driveDuration = 0.0 + let _driveDuration let drivePhaseStartAngularPosition = 0.0 let drivePhaseAngularDisplacement = 0.0 let _driveLinearDistance = 0.0 @@ -36,13 +36,15 @@ function createRower (rowerSettings) { 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 _cycleDuration + let _cycleLinearVelocity + let _cyclePower let totalLinearDistance = 0.0 let preliminaryTotalLinearDistance = 0.0 let _driveLength = 0.0 + flywheel.maintainStateOnly() + // called if the sensor detected an impulse, currentDt is an interval in seconds function handleRotationImpulse (currentDt) { // Provide the flywheel with new data @@ -53,19 +55,32 @@ function createRower (rowerSettings) { 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 + case (_strokeState === 'WaitingForDrive' && flywheel.isAboveMinimumSpeed() && flywheel.isPowered()): + // We are above the minimum speed, so we can leave the WaitingForDrive state // 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() + // We change into the "Drive" phase since were waiting for a drive phase, and we see a clear force exerted on the flywheel + log.debug(`*** Rowing (re)started with a DRIVE phase at time: ${flywheel.spinningTime().toFixed(4)} sec`) _strokeState = 'Drive' startDrivePhase() break + case (_strokeState === 'WaitingForDrive' && flywheel.isAboveMinimumSpeed() && flywheel.isUnpowered()): + // We are above the minimum speed, so we can leave the WaitingForDrive state + // As we are not certain what caused the "WaitingForDrive", we explicitly start the flywheel maintaining metrics again + flywheel.maintainStateAndMetrics() + // We change into the "REcovery" phase, as somehow there is a force exerted on the flywheel consistent with a dragforce + // We need to update the _totalNumberOfStrokes manually as startDrivePhase() normally does this + log.debug(`*** Rowing (re)started with a RECOVERY phase at time: ${flywheel.spinningTime().toFixed(4)} sec`) + _totalNumberOfStrokes++ + _strokeState = 'Recovery' + startRecoveryPhase() + 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()): + case (_strokeState === 'Drive' && ((flywheel.spinningTime() - drivePhaseStartTime) >= rowerSettings.minimumDriveTime || _totalNumberOfStrokes < 1) && 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 + // In the first stroke, we might not exceed the minimumdrivetime in the first stroke, so we shouldn't allow it to limit us. log.debug(`*** RECOVERY phase started at time: ${flywheel.spinningTime().toFixed(4)} sec`) _strokeState = 'Recovery' endDrivePhase() @@ -73,7 +88,7 @@ function createRower (rowerSettings) { 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)`) + log.debug(`Time: ${flywheel.spinningTime().toFixed(4)} sec: Delta Time trend is upwards, suggests no power, but waiting for drive phase length (${(flywheel.spinningTime() - drivePhaseStartTime).toFixed(4)} sec) to exceed minimumDriveTime (${rowerSettings.minimumDriveTime} sec)`) updateDrivePhase() break case (_strokeState === 'Drive'): @@ -140,16 +155,22 @@ function createRower (rowerSettings) { function endDrivePhase () { // Here, we conclude the Drive Phase - // The FSM guarantees that we have a credible driveDuration and cycletime + // The FSM guarantees that we have a credible driveDuration and cycletime in normal operation, but NOT at the start _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 + if (_driveDuration >= rowerSettings.minimumDriveTime && _recoveryDuration >= rowerSettings.minimumRecoveryTime) { + _cycleDuration = _recoveryDuration + _driveDuration + _cycleLinearVelocity = calculateLinearVelocity(drivePhaseAngularDisplacement + recoveryPhaseAngularDisplacement, _cycleDuration) + _cyclePower = calculateCyclePower() + } else { + _cycleDuration = undefined + _cycleLinearVelocity = undefined + _cyclePower = undefined + } } function startRecoveryPhase () { @@ -168,23 +189,29 @@ function createRower (rowerSettings) { function endRecoveryPhase () { // First, we conclude the recovery phase - // The FSM guarantees that we have a credible recoveryDuration and cycletime + // The FSM guarantees that we have a credible recoveryDuration and cycletime in normal operation, but NOT at the start + flywheel.markRecoveryPhaseCompleted() // This MUST be executed before the dragfactor is used in any calculation here! _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() + if (_driveDuration >= rowerSettings.minimumDriveTime && _recoveryDuration >= rowerSettings.minimumRecoveryTime) { + _cycleDuration = _recoveryDuration + _driveDuration + _cycleLinearVelocity = calculateLinearVelocity(drivePhaseAngularDisplacement + recoveryPhaseAngularDisplacement, _cycleDuration) + _cyclePower = calculateCyclePower() + } else { + _cycleDuration = undefined + _cycleLinearVelocity = undefined + _cyclePower = undefined + } } 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}`) + log.error(`Time: ${flywheel.spinningTime().toFixed(4)} sec: calculateLinearDistance error: Angular Displacement of ${baseAngularDisplacement} was not credible, baseTime = ${baseTime}`) return 0 } } @@ -235,59 +262,114 @@ function createRower (rowerSettings) { } function cycleDuration () { - return _cycleDuration + if (_driveDuration >= rowerSettings.minimumDriveTime && _recoveryDuration >= rowerSettings.minimumRecoveryTime) { + return _cycleDuration + } else { + return undefined + } } function cycleLinearDistance () { - return _driveLinearDistance + _recoveryLinearDistance + if (_driveDuration >= rowerSettings.minimumDriveTime && _recoveryDuration >= rowerSettings.minimumRecoveryTime) { + return _driveLinearDistance + _recoveryLinearDistance + } else { + return undefined + } } function cycleLinearVelocity () { - return _cycleLinearVelocity + if (_driveDuration >= rowerSettings.minimumDriveTime && _recoveryDuration >= rowerSettings.minimumRecoveryTime) { + return _cycleLinearVelocity + } else { + return undefined + } } function cyclePower () { - return _cyclePower + if (_driveDuration >= rowerSettings.minimumDriveTime && _recoveryDuration >= rowerSettings.minimumRecoveryTime) { + return _cyclePower + } else { + return undefined + } } - function driveDuration () { - return _driveDuration + if (_driveDuration >= rowerSettings.minimumDriveTime) { + return _driveDuration + } else { + return undefined + } } function driveLinearDistance () { - return _driveLinearDistance + if (_driveDuration >= rowerSettings.minimumDriveTime) { + return _driveLinearDistance + } else { + return undefined + } } function driveLength () { - return _driveLength + if (_driveDuration >= rowerSettings.minimumDriveTime) { + return _driveLength + } else { + return undefined + } } function driveAverageHandleForce () { - return driveHandleForce.average() + if (_driveDuration >= rowerSettings.minimumDriveTime) { + return driveHandleForce.average() + } else { + return undefined + } } function drivePeakHandleForce () { - return driveHandleForce.peak() + if (_driveDuration >= rowerSettings.minimumDriveTime) { + return driveHandleForce.peak() + } else { + return undefined + } } function driveHandleForceCurve () { - return driveHandleForce.curve() + if (_driveDuration >= rowerSettings.minimumDriveTime) { + return driveHandleForce.curve() + } else { + return undefined + } } function driveHandleVelocityCurve () { - return driveHandleVelocity.curve() + if (_driveDuration >= rowerSettings.minimumDriveTime) { + return driveHandleVelocity.curve() + } else { + return undefined + } } function driveHandlePowerCurve () { - return driveHandlePower.curve() + if (_driveDuration >= rowerSettings.minimumDriveTime) { + return driveHandlePower.curve() + } else { + return undefined + } } function recoveryDuration () { - return _recoveryDuration + if (_recoveryDuration >= rowerSettings.minimumRecoveryTime) { + return _recoveryDuration + } else { + return undefined + } } function recoveryDragFactor () { - return flywheel.dragFactor() * 1000000 + if (flywheel.dragFactorIsReliable()) { + return flywheel.dragFactor() * 1000000 + } else { + return undefined + } } function instantHandlePower () { @@ -299,8 +381,11 @@ function createRower (rowerSettings) { } function allowMovement () { - log.debug(`*** ALLOW MOVEMENT command by RowingEngine recieved at time: ${flywheel.spinningTime().toFixed(4)} sec`) - _strokeState = 'WaitingForDrive' + if (_strokeState === 'Stopped') { + // We have to check whether there actually was a stop/pause, in order to prevent weird behaviour from the state machine + log.debug(`*** ALLOW MOVEMENT command by RowingEngine recieved at time: ${flywheel.spinningTime().toFixed(4)} sec`) + _strokeState = 'WaitingForDrive' + } } function pauseMoving () { @@ -317,7 +402,10 @@ function createRower (rowerSettings) { function reset () { _strokeState = 'WaitingForDrive' - flywheel.maintainStateOnly() + flywheel.reset() + driveHandleForce.reset() + driveHandleVelocity.reset() + driveHandlePower.reset() _totalNumberOfStrokes = -1.0 drivePhaseStartTime = 0.0 drivePhaseStartAngularPosition = 0.0 @@ -365,5 +453,3 @@ function createRower (rowerSettings) { reset } } - -export { createRower } diff --git a/app/engine/Rower.test.js b/app/engine/Rower.test.js index 9e32ab5be7..938d255988 100644 --- a/app/engine/Rower.test.js +++ b/app/engine/Rower.test.js @@ -1,40 +1,42 @@ '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. + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ +/** + * 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 { replayRowingSession } from '../recorders/RowingReplayer.js' import { deepMerge } from '../tools/Helper.js' import { createRower } from './Rower.js' -const baseConfig = { +const baseConfig = { // Based on Concept 2 settings, as this is the validation system 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, + sprocketRadius: 1.4, + maximumStrokeTimeBeforePause: 0.3, // Modification to standard settings to shorten test cases + dragFactor: 110, autoAdjustDragFactor: true, + minimumDragQuality: 0.95, dragFactorSmoothing: 3, - dragFactor: 100, - minimumDragQuality: 0.83, - flywheelInertia: 0.1, - magicConstant: 2.8, - sprocketRadius: 2 + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.017, + flankLength: 12, + smoothing: 1, + minimumStrokeQuality: 0.36, + minimumForceBeforeStroke: 20, // Modification to standard settings to shorten test cases + minimumRecoverySlope: 0.00070, + autoAdjustRecoverySlope: false, // Modification to standard settings to shorten test cases + autoAdjustRecoverySlopeMargin: 0.04, + minimumDriveTime: 0.04, // Modification to standard settings to shorten test cases + minimumRecoveryTime: 0.09, // Modification to standard settings to shorten test cases + flywheelInertia: 0.10138, + magicConstant: 2.8 } // Test behaviour for no datapoints @@ -44,68 +46,43 @@ test('Correct rower behaviour at initialisation', () => { 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) + testCycleDuration(rower, undefined) // Default value + testCycleLinearDistance(rower, undefined) + testCycleLinearVelocity(rower, undefined) + testCyclePower(rower, undefined) + testDriveDuration(rower, undefined) + testDriveLinearDistance(rower, undefined) + testDriveLength(rower, undefined) + testDriveAverageHandleForce(rower, undefined) + testDrivePeakHandleForce(rower, undefined) + testRecoveryDuration(rower, undefined) + testRecoveryDragFactor(rower, undefined) 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 one datapoint // 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) +test('Test behaviour for three perfect identical strokes, including settingling behaviour of metrics', () => { + const rower = createRower(baseConfig) 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) + testCycleDuration(rower, undefined) // Default value + testCycleLinearDistance(rower, undefined) + testCycleLinearVelocity(rower, undefined) + testCyclePower(rower, undefined) + testDriveDuration(rower, undefined) + testDriveLinearDistance(rower, undefined) + testDriveLength(rower, undefined) + testDriveAverageHandleForce(rower, undefined) + testDrivePeakHandleForce(rower, undefined) + testRecoveryDuration(rower, undefined) + testRecoveryDragFactor(rower, undefined) 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) @@ -115,11 +92,8 @@ test('Correct Rower behaviour for three noisefree strokes with dynamic dragfacto 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) @@ -128,21 +102,21 @@ test('Correct Rower behaviour for three noisefree strokes with dynamic dragfacto rower.handleRotationImpulse(0.010511225) rower.handleRotationImpulse(0.010386684) testStrokeState(rower, 'Drive') - testTotalMovingTimeSinceStart(rower, 0.088970487) - testTotalLinearDistanceSinceStart(rower, 0.27588786257094444) + testTotalMovingTimeSinceStart(rower, 0.077918634) + testTotalLinearDistanceSinceStart(rower, 0.2491943602992768) 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) + testCycleDuration(rower, undefined) // still default value + testCycleLinearDistance(rower, undefined) + testCycleLinearVelocity(rower, undefined) // This isn't filled after the first drive, as we haven't survived a complete cycle yet + testCyclePower(rower, undefined) // This isn't filled after the first drive, as we haven't survived a complete cycle yet + testDriveDuration(rower, undefined) // This isn't filled after the first drive as it is too short + testDriveLinearDistance(rower, undefined) + testDriveLength(rower, undefined) + testDriveAverageHandleForce(rower, undefined) + testDrivePeakHandleForce(rower, undefined) + testRecoveryDuration(rower, undefined) + testRecoveryDragFactor(rower, undefined) + testInstantHandlePower(rower, 372.09477620281604) // Recovery initial stroke starts here rower.handleRotationImpulse(0.010769) rower.handleRotationImpulse(0.010707554) @@ -160,22 +134,22 @@ test('Correct Rower behaviour for three noisefree strokes with dynamic dragfacto rower.handleRotationImpulse(0.011131862) rower.handleRotationImpulse(0.011209919) testStrokeState(rower, 'Recovery') - testTotalMovingTimeSinceStart(rower, 0.24984299900000007) - testTotalLinearDistanceSinceStart(rower, 0.7931776048914653) + testTotalMovingTimeSinceStart(rower, 0.23894732900000007) + testTotalLinearDistanceSinceStart(rower, 0.7831822752262985) testTotalNumberOfStrokes(rower, 1) - testCycleDuration(rower, 0.143485717) - testCycleLinearDistance(rower, 0.7931776048914653) - testCycleLinearVelocity(rower, 3.1244766799874912) - testCyclePower(rower, 0) + testCycleDuration(rower, undefined) + testCycleLinearDistance(rower, undefined) + testCycleLinearVelocity(rower, undefined) + testCyclePower(rower, undefined) 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) + testDriveLinearDistance(rower, 0.46278952627008546) + testDriveLength(rower, 0.19058995431778075) + testDriveAverageHandleForce(rower, 276.20193475035796) + testDrivePeakHandleForce(rower, 325.1619554833936) + testRecoveryDuration(rower, undefined) + testRecoveryDragFactor(rower, undefined) testInstantHandlePower(rower, 0) - // Drive seconds stroke starts here + // Drive second stroke starts here rower.handleRotationImpulse(0.011221636) rower.handleRotationImpulse(0.011175504) rower.handleRotationImpulse(0.01116456) @@ -196,21 +170,21 @@ test('Correct Rower behaviour for three noisefree strokes with dynamic dragfacto rower.handleRotationImpulse(0.010511225) rower.handleRotationImpulse(0.010386684) testStrokeState(rower, 'Drive') - testTotalMovingTimeSinceStart(rower, 0.46020725100000004) - testTotalLinearDistanceSinceStart(rower, 1.519974294345203) + testTotalMovingTimeSinceStart(rower, 0.44915539800000004) + testTotalLinearDistanceSinceStart(rower, 1.828822466846578) testTotalNumberOfStrokes(rower, 2) - testCycleDuration(rower, 0.404798464) - testCycleLinearDistance(rower, 1.0716565176674184) - testCycleLinearVelocity(rower, 3.1521398371477467) - testCyclePower(rower, 87.69492447163606) + testCycleDuration(rower, 0.34889498300000005) + testCycleLinearDistance(rower, 1.3660329405764926) + testCycleLinearVelocity(rower, 4.474643028948317) + testCyclePower(rower, 250.86103806520188) 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) + testDriveLinearDistance(rower, 0.43908201661387253) + testDriveLength(rower, 0.19058995431778075) + testDriveAverageHandleForce(rower, 236.59556700196183) + testDrivePeakHandleForce(rower, 380.1396336099103) + testRecoveryDuration(rower, 0.20540926600000003) + testRecoveryDragFactor(rower, 283.12720365097886) + testInstantHandlePower(rower, 504.63602120716615) // Recovery second stroke starts here rower.handleRotationImpulse(0.010769) rower.handleRotationImpulse(0.010707554) @@ -228,20 +202,20 @@ test('Correct Rower behaviour for three noisefree strokes with dynamic dragfacto rower.handleRotationImpulse(0.011131862) rower.handleRotationImpulse(0.011209919) testStrokeState(rower, 'Recovery') - testTotalMovingTimeSinceStart(rower, 0.6210797630000001) - testTotalLinearDistanceSinceStart(rower, 2.2519530842089575) + testTotalMovingTimeSinceStart(rower, 0.6101840930000001) + testTotalLinearDistanceSinceStart(rower, 2.5606258278697) 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) + testCycleDuration(rower, 0.44526865700000007) + testCycleLinearDistance(rower, 1.1708853776369939) + testCycleLinearVelocity(rower, 4.492259872066099) + testCyclePower(rower, 253.83566752220193) + testDriveDuration(rower, 0.23985939100000003) + testDriveLinearDistance(rower, 1.0733115961672441) + testDriveLength(rower, 0.322536845768552) + testDriveAverageHandleForce(rower, 285.0923064376231) + testDrivePeakHandleForce(rower, 439.7407274840117) + testRecoveryDuration(rower, 0.20540926600000003) + testRecoveryDragFactor(rower, 283.12720365097886) // As we decelerate the flywheel quite fast, this is expected testInstantHandlePower(rower, 0) // Drive third stroke starts here rower.handleRotationImpulse(0.011221636) @@ -264,21 +238,21 @@ test('Correct Rower behaviour for three noisefree strokes with dynamic dragfacto rower.handleRotationImpulse(0.010511225) rower.handleRotationImpulse(0.010386684) testStrokeState(rower, 'Drive') - testTotalMovingTimeSinceStart(rower, 0.8314440150000004) - testTotalLinearDistanceSinceStart(rower, 3.17912621803638) + testTotalMovingTimeSinceStart(rower, 0.8203921620000004) + testTotalLinearDistanceSinceStart(rower, 3.4875767518323193) 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) + testCycleDuration(rower, 0.3379838680000002) + testCycleLinearDistance(rower, 1.0245247054323694) + testCycleLinearVelocity(rower, 4.4747508859834575) + testCyclePower(rower, 250.8791788061379) + testDriveDuration(rower, 0.23985939100000003) + testDriveLinearDistance(rower, 0.5854426888184969) + testDriveLength(rower, 0.322536845768552) + testDriveAverageHandleForce(rower, 194.28476369698888) + testDrivePeakHandleForce(rower, 380.1396336085015) + testRecoveryDuration(rower, 0.09812447700000015) + testRecoveryDragFactor(rower, 283.12720365097886) + testInstantHandlePower(rower, 504.63602120535336) // Recovery third stroke starts here rower.handleRotationImpulse(0.010769) rower.handleRotationImpulse(0.010707554) @@ -296,20 +270,20 @@ test('Correct Rower behaviour for three noisefree strokes with dynamic dragfacto rower.handleRotationImpulse(0.011131862) rower.handleRotationImpulse(0.011209919) testStrokeState(rower, 'Recovery') - testTotalMovingTimeSinceStart(rower, 0.9923165270000005) - testTotalLinearDistanceSinceStart(rower, 3.911105007900135) + testTotalMovingTimeSinceStart(rower, 0.9814208570000005) + testTotalLinearDistanceSinceStart(rower, 4.219380112855441) 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) + testCycleLinearDistance(rower, 1.3172460498416183) + testCycleLinearVelocity(rower, 4.46818431211662) + testCyclePower(rower, 249.77632391313173) + testDriveDuration(rower, 0.27311228700000023) + testDriveLinearDistance(rower, 1.2196722683718688) + testDriveLength(rower, 0.3665191429188092) + testDriveAverageHandleForce(rower, 254.91449219500532) + testDrivePeakHandleForce(rower, 439.74072748282515) + testRecoveryDuration(rower, 0.09812447700000015) + testRecoveryDragFactor(rower, 283.12720365097886) testInstantHandlePower(rower, 0) // Dwelling state starts here rower.handleRotationImpulse(0.020769) @@ -328,40 +302,40 @@ test('Correct Rower behaviour for three noisefree strokes with dynamic dragfacto rower.handleRotationImpulse(0.021131862) rower.handleRotationImpulse(0.021209919) testStrokeState(rower, 'WaitingForDrive') - testTotalMovingTimeSinceStart(rower, 1.1137102920000004) + testTotalMovingTimeSinceStart(rower, 1.1344792920000004) 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) + testTotalLinearDistanceSinceStart(rower, 4.8536096924088135) + testCycleDuration(rower, 0.4476004410000002) + testCycleLinearDistance(rower, 1.9514756293949902) + testCycleLinearVelocity(rower, 4.359860828186694) + testCyclePower(rower, 232.0469744651364) + testDriveDuration(rower, 0.27311228700000023) + testDriveLinearDistance(rower, 1.2196722683718688) + testDriveLength(rower, 0.3665191429188092) + testDriveAverageHandleForce(rower, 254.91449219500532) + testDrivePeakHandleForce(rower, 439.74072748282515) + testRecoveryDuration(rower, 0.17448815399999995) + testRecoveryDragFactor(rower, 283.12720365097886) 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 behaviour after reset + +// Test behaviour for one datapoint + +// Test behaviour for noisy stroke // 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 @@ -375,7 +349,7 @@ test('sample data for Sportstech WRX700 should produce plausible results', async await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv', realtime: false, loop: false }) testTotalMovingTimeSinceStart(rower, 46.302522627) - testTotalLinearDistanceSinceStart(rower, 166.2959671641673) + testTotalLinearDistanceSinceStart(rower, 166.29596716416734) testTotalNumberOfStrokes(rower, 16) // As dragFactor is static, it should remain in place testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor) @@ -386,6 +360,7 @@ test('sample data for DKN R-320 should produce plausible results', async () => { testTotalMovingTimeSinceStart(rower, 0) testTotalLinearDistanceSinceStart(rower, 0) testTotalNumberOfStrokes(rower, 0) + // As dragFactor is static, it should be known at initialisation testRecoveryDragFactor(rower, rowerProfiles.DKN_R320.dragFactor) await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/DKNR320.csv', realtime: false, loop: false }) @@ -402,15 +377,15 @@ test('sample data for NordicTrack RX800 should produce plausible results', async testTotalMovingTimeSinceStart(rower, 0) testTotalLinearDistanceSinceStart(rower, 0) testTotalNumberOfStrokes(rower, 0) - testRecoveryDragFactor(rower, rowerProfiles.NordicTrack_RX800.dragFactor) + testRecoveryDragFactor(rower, undefined) await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/RX800.csv', realtime: false, loop: false }) - testTotalMovingTimeSinceStart(rower, 17.389910236000024) - testTotalLinearDistanceSinceStart(rower, 62.052936751782944) - testTotalNumberOfStrokes(rower, 8) + testTotalMovingTimeSinceStart(rower, 22.259092749999997) + testTotalLinearDistanceSinceStart(rower, 80.49260485116434) + testTotalNumberOfStrokes(rower, 10) // As dragFactor is dynamic, it should have changed - testRecoveryDragFactor(rower, 486.702741763346) + testRecoveryDragFactor(rower, 491.1395313462149) }) test('A full session for SportsTech WRX700 should produce plausible results', async () => { @@ -422,27 +397,43 @@ test('A full session for SportsTech WRX700 should produce plausible results', as await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false }) - testTotalMovingTimeSinceStart(rower, 2342.241183077012) - testTotalLinearDistanceSinceStart(rower, 8408.914799199298) + testTotalMovingTimeSinceStart(rower, 2340.0100514160117) + testTotalLinearDistanceSinceStart(rower, 8406.791871958883) 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 Model C should produce plausible results', async () => { + const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_Model_C)) + testTotalMovingTimeSinceStart(rower, 0) + testTotalLinearDistanceSinceStart(rower, 0) + testTotalNumberOfStrokes(rower, 0) + testRecoveryDragFactor(rower, undefined) + + await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/Concept2_Model_C.csv', realtime: false, loop: false }) + + testTotalMovingTimeSinceStart(rower, 181.47141999999985) + testTotalLinearDistanceSinceStart(rower, 552.0863658667265) + testTotalNumberOfStrokes(rower, 84) + // As dragFactor isn't static, it should have changed + testRecoveryDragFactor(rower, 123.82587294279575) +}) + 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) + testRecoveryDragFactor(rower, undefined) await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', realtime: false, loop: false }) - testTotalMovingTimeSinceStart(rower, 590.4201840000001) - testTotalLinearDistanceSinceStart(rower, 2030.6574002852396) + testTotalMovingTimeSinceStart(rower, 590.111937) + testTotalLinearDistanceSinceStart(rower, 2027.493082238415) testTotalNumberOfStrokes(rower, 206) - // As dragFactor isn't static, it should be updated - testRecoveryDragFactor(rower, 80.81243631988698) + // As dragFactor isn't static, it should have changed + testRecoveryDragFactor(rower, 80.60573080009686) }) function testStrokeState (rower, expectedValue) { @@ -510,10 +501,8 @@ 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()}`) +function reportAll (rower) { // eslint-disable-line no-unused-vars + assert.ok(0, `time: ${rower.totalMovingTimeSinceStart()}, state ${rower.strokeState()}, No Strokes: ${rower.totalNumberOfStrokes() + 1}, 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/RowingStatistics.js b/app/engine/RowingStatistics.js index 8249b3d56f..44ff977070 100644 --- a/app/engine/RowingStatistics.js +++ b/app/engine/RowingStatistics.js @@ -1,10 +1,10 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This Module calculates the training specific metrics. + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ -import { EventEmitter } from 'events' +/** + * This Module creates a persistent, consistent and user presentable set of metrics. + */ import { createRower } from './Rower.js' import { createOLSLinearSeries } from './utils/OLSLinearSeries.js' import { createStreamFilter } from './utils/StreamFilter.js' @@ -13,165 +13,57 @@ import { createCurveAligner } from './utils/CurveAligner.js' import loglevel from 'loglevel' 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 emitter = new EventEmitter() +export function createRowingStatistics (config) { + const numOfDataPointsForAveraging = config.numOfPhasesForAveragingScreenData // Used for metrics updated twice per cycle + const halfNumOfDataPointsForAveraging = Math.round(numOfDataPointsForAveraging / 2) // Used for metrics updated twice per cycle 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 + const cycleDuration = createStreamFilter(numOfDataPointsForAveraging, undefined) + const cycleDistance = createStreamFilter(numOfDataPointsForAveraging, undefined) + const cyclePower = createStreamFilter(numOfDataPointsForAveraging, undefined) + const cycleLinearVelocity = createStreamFilter(numOfDataPointsForAveraging, undefined) + let metricsContext let totalLinearDistance = 0.0 let totalMovingTime = 0 - let totalNumberOfStrokes = 0 + let totalNumberOfStrokes = -1 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 driveDuration = createStreamFilter(halfNumOfDataPointsForAveraging, undefined) + const driveLength = createStreamFilter(halfNumOfDataPointsForAveraging, undefined) + const driveDistance = createStreamFilter(halfNumOfDataPointsForAveraging, undefined) + const recoveryDuration = createStreamFilter(halfNumOfDataPointsForAveraging, undefined) + const driveAverageHandleForce = createStreamFilter(halfNumOfDataPointsForAveraging, undefined) + const drivePeakHandleForce = createStreamFilter(halfNumOfDataPointsForAveraging, undefined) + const driveHandleForceCurve = createCurveAligner(config.rowerSettings.minimumForceBeforeStroke) const driveHandleVelocityCurve = createCurveAligner(1.0) const driveHandlePowerCurve = createCurveAligner(50) - let dragFactor = config.rowerSettings.dragFactor - let heartrate = 0 - let heartrateBatteryLevel = 0 - const postExerciseHR = [] + let dragFactor let instantPower = 0.0 let lastStrokeState = 'WaitingForDrive' - // send metrics to the web clients periodically - setInterval(emitWebMetrics, webUpdateInterval) - - // 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, peripheralUpdateInterval) + resetMetricsContext() - function handleRotationImpulse (currentDt) { - // Provide the rower with new data - rower.handleRotationImpulse(currentDt) - - // 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() - } - - function startTraining () { - rower.allowMovement() - } - - function allowResumeTraining () { - rower.allowMovement() - sessionStatus = 'WaitingForStart' - } - - function resumeTraining () { + function allowStartOrResumeTraining () { 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() + metricsContext.isMoving = false 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 () { @@ -183,18 +75,104 @@ function createRowingStatistics (config, session) { totalLinearDistance = 0.0 totalNumberOfStrokes = -1 driveLastStartTime = 0 - distanceOverTime.reset() driveDuration.reset() + recoveryDuration.reset() + driveLength.reset() + driveDistance.reset() + driveAverageHandleForce.reset() + drivePeakHandleForce.reset() + driveHandleForceCurve.reset() + driveHandleVelocityCurve.reset() + driveHandlePowerCurve.reset() cycleDuration.reset() cycleDistance.reset() cyclePower.reset() strokeCalories = 0 strokeWork = 0 - postExerciseHR.splice(0, postExerciseHR.length) cycleLinearVelocity.reset() lastStrokeState = 'WaitingForDrive' - emitMetrics('rowingPaused') - sessionStatus = 'WaitingForStart' + resetMetricsContext() + } + + /** + * Calculates the linear metrics based on a currentDt + * + * @param {float} time between two impulses in seconds + * + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/new-ble-api/docs/Architecture.md#rowingstatisticsjs|the architecture description} + */ + function handleRotationImpulse (currentDt) { + // Provide the rower with new data + rower.handleRotationImpulse(currentDt) + + resetMetricsContext() + + // This is the core of the finite state machine that defines all state transitions + switch (true) { + case (lastStrokeState === 'WaitingForDrive' && rower.strokeState() === 'Drive'): + updateContinousMetrics() + metricsContext.isMoving = true + metricsContext.isDriveStart = true + break + case (lastStrokeState === 'WaitingForDrive' && rower.strokeState() === 'Recovery'): + updateContinousMetrics() + metricsContext.isMoving = true + metricsContext.isRecoveryStart = true + break + case (lastStrokeState === 'WaitingForDrive'): + // We can't change into the "Rowing" state since we are waiting for a drive phase that didn't come + metricsContext.isMoving = false // This has the disired side-effect that the many of the reported instanous metrics are zero-ed + break + case (lastStrokeState !== 'Stopped' && rower.strokeState() === 'Stopped'): + metricsContext.isMoving = false // This has the disired side-effect that the many of the reported instanous metrics are zero-ed + // This is intended behaviour, as the rower/flywheel indicate the rower has stopped somehow. So zero-ing all metrics fits that state better then a last know good state + break + case (lastStrokeState === 'Stopped'): + metricsContext.isMoving = false + // We are in a stopped state, so we won't update any metrics + // This is a permanent state, regardless of current action of the flywheel + break + case (lastStrokeState !== 'WaitingForDrive' && rower.strokeState() === 'WaitingForDrive'): + metricsContext.isMoving = false // This has the desired side-effect that the many of the reported instanous metrics are zero-ed + // Please note, the sessionmanager will trigger a pause based on this condition + break + // From this point on, we can be certain that the LastStrokeState and rower.strokeState() aren't 'Stopped' or 'WaitingForDrive', so we are processing an active stroke + case (lastStrokeState === 'Recovery' && rower.strokeState() === 'Drive'): + updateContinousMetrics() + updateCycleMetrics() + handleRecoveryEnd() + metricsContext.isMoving = true + metricsContext.isDriveStart = true + break + case (lastStrokeState === 'Recovery' && rower.strokeState() === 'Recovery'): + updateContinousMetrics() + metricsContext.isMoving = true + break + case (lastStrokeState === 'Drive' && rower.strokeState() === 'Recovery'): + updateContinousMetrics() + updateCycleMetrics() + handleDriveEnd() + metricsContext.isMoving = true + metricsContext.isRecoveryStart = true + break + case (lastStrokeState === 'Drive' && rower.strokeState() === 'Drive'): + updateContinousMetrics() + metricsContext.isMoving = true + break + default: + log.error(`Time: ${rower.totalMovingTimeSinceStart()}, combination of last stroke state ${lastStrokeState} and state ${rower.strokeState()} found in the Rowing Statistics, which is not captured by Finite State Machine`) + } + lastStrokeState = rower.strokeState() + return allMetrics() + } + + // Basic metricContext structure + function resetMetricsContext () { + metricsContext = { + isMoving: false, + isDriveStart: false, + isRecoveryStart: false + } } // initiated when updating key statistics @@ -205,8 +183,7 @@ function createRowingStatistics (config, session) { } function updateCycleMetrics () { - distanceOverTime.push(rower.totalMovingTimeSinceStart(), rower.totalLinearDistanceSinceStart()) - if (rower.cycleDuration() < maximumStrokeTime && rower.cycleDuration() > minimumStrokeTime) { + if (rower.cycleDuration() !== undefined && rower.cycleDuration() < maximumStrokeTime && rower.cycleDuration() > minimumStrokeTime && totalNumberOfStrokes > 0) { // stroke duration has to be credible to be accepted cycleDuration.push(rower.cycleDuration()) cycleDistance.push(rower.cycleLinearDistance()) @@ -218,133 +195,76 @@ function createRowingStatistics (config, session) { } 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()) + if (rower.driveDuration() !== undefined) { + 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 - 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(() => { - heartrate = 0 - heartrateBatteryLevel = 0 - }, 6000) - heartrate = value.heartrate - heartrateBatteryLevel = value.batteryLevel - } - - function intervalTargetReached () { - if ((session.targetDistance > 0 && rower.totalLinearDistanceSinceStart() >= session.targetDistance) || (session.targetTime > 0 && rower.totalMovingTimeSinceStart() >= session.targetTime)) { - return true + if (rower.recoveryDuration() !== undefined) { + recoveryDuration.push(rower.recoveryDuration()) + } + if (rower.recoveryDuration() !== undefined && rower.recoveryDragFactor() !== undefined) { + dragFactor = rower.recoveryDragFactor() } else { - return false + dragFactor = undefined } - } - 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) - } + if (cyclePower.reliable() && cycleDuration.reliable()) { + // ToDo: see if this can be made part of the continuousmatrcs as Garmin and Concept2 also have a 'calories' type of training + // 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.Y.atSeriesEnd() + strokeCalories + calories.push(totalMovingTime, totalCalories) } } - function emitWebMetrics () { - emitMetrics('webMetricsUpdate') - } - - function emitPeripheralMetrics () { - emitMetrics('peripheralMetricsUpdate') - } - - function emitMetrics (emitType = 'webMetricsUpdate') { - emitter.emit(emitType, getMetrics()) - } - - function getMetrics () { - const cyclePace = cycleLinearVelocity.clean() !== 0 && cycleLinearVelocity.raw() > 0 && sessionStatus === 'Rowing' ? (500.0 / cycleLinearVelocity.clean()) : Infinity + /* eslint-disable complexity -- As this is the central metric being delivered to all consumers, who need to accept this at face value, we need a lot of defensive coding */ + function allMetrics () { + const cyclePace = cycleLinearVelocity.clean() !== 0 && cycleLinearVelocity.raw() > 0 && metricsContext.isMoving === true ? (500.0 / cycleLinearVelocity.clean()) : Infinity return { - sessiontype: session.targetDistance > 0 ? 'Distance' : (session.targetTime > 0 ? 'Time' : 'JustRow'), - sessionStatus, + metricsContext, 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 + totalCalories: calories.Y.atSeriesEnd() > 0 ? calories.Y.atSeriesEnd() : 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) - if (hours > 0) { - return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` - } else { - return `${minutes}:${seconds.toString().padStart(2, '0')}` + cycleDuration: cycleDuration.reliable() && cycleDuration.clean() > minimumStrokeTime && cycleDuration.clean() < maximumStrokeTime && cycleLinearVelocity.raw() > 0 && totalNumberOfStrokes > 0 && metricsContext.isMoving === true ? cycleDuration.clean() : undefined, // seconds + cycleStrokeRate: cycleDuration.reliable() && cycleDuration.clean() > minimumStrokeTime && cycleDuration.clean() < maximumStrokeTime && cycleLinearVelocity.raw() > 0 && totalNumberOfStrokes > 0 && metricsContext.isMoving === true ? (60.0 / cycleDuration.clean()) : undefined, // strokeRate in SPM + cycleDistance: cycleDistance.reliable() && cycleDistance.raw() > 0 && cycleLinearVelocity.raw() > 0 && metricsContext.isMoving === true ? cycleDistance.clean() : undefined, // meters + cycleLinearVelocity: cycleLinearVelocity.reliable() && cycleLinearVelocity.clean() > 0 && cycleLinearVelocity.raw() > 0 && metricsContext.isMoving === true ? cycleLinearVelocity.clean() : undefined, // m/s + cyclePace: cycleLinearVelocity.reliable() && cycleLinearVelocity.clean() > 0 && metricsContext.isMoving === true ? cyclePace : Infinity, // seconds/500m + cyclePower: cyclePower.reliable() && cyclePower.clean() > 0 && cycleLinearVelocity.raw() > 0 && metricsContext.isMoving === true ? cyclePower.clean() : undefined, // watts + driveLastStartTime: driveLastStartTime > 0 ? driveLastStartTime : 0, + driveDuration: driveDuration.reliable() && driveDuration.clean() >= config.rowerSettings.minimumDriveTime && totalNumberOfStrokes > 0 && metricsContext.isMoving === true ? driveDuration.clean() : undefined, // seconds + driveLength: driveLength.reliable() && driveLength.clean() > 0 && metricsContext.isMoving === true ? driveLength.clean() : undefined, // meters of chain movement + driveDistance: driveDistance.reliable() && driveDistance.clean() >= 0 && metricsContext.isMoving === true ? driveDistance.clean() : undefined, // meters + driveAverageHandleForce: driveAverageHandleForce.clean() > 0 && metricsContext.isMoving === true ? driveAverageHandleForce.clean() : undefined, + drivePeakHandleForce: drivePeakHandleForce.clean() > 0 && metricsContext.isMoving === true ? drivePeakHandleForce.clean() : undefined, + driveHandleForceCurve: drivePeakHandleForce.clean() > 0 && metricsContext.isMoving === true ? driveHandleForceCurve.lastCompleteCurve() : [], + driveHandleVelocityCurve: drivePeakHandleForce.clean() > 0 && metricsContext.isMoving === true ? driveHandleVelocityCurve.lastCompleteCurve() : [], + driveHandlePowerCurve: drivePeakHandleForce.clean() > 0 && metricsContext.isMoving === true ? driveHandlePowerCurve.lastCompleteCurve() : [], + recoveryDuration: recoveryDuration.reliable() && recoveryDuration.clean() >= config.rowerSettings.minimumRecoveryTime && totalNumberOfStrokes > 0 && metricsContext.isMoving === true ? recoveryDuration.clean() : undefined, // seconds + dragFactor: dragFactor > 0 ? dragFactor : undefined, // Dragfactor + instantPower: instantPower > 0 && rower.strokeState() === 'Drive' ? instantPower : 0 } } + /* eslint-enable complexity */ function caloriesPerPeriod (periodBegin, periodEnd) { const beginCalories = calories.projectX(periodBegin) @@ -352,14 +272,12 @@ function createRowingStatistics (config, session) { return (endCalories - beginCalories) } - return Object.assign(emitter, { - handleHeartrateMeasurement, + return { handleRotationImpulse, - pause: pauseTraining, - stop: stopTraining, - resume: allowResumeTraining, - reset: resetTraining - }) + allowStartOrResumeTraining, + stopTraining, + pauseTraining, + resetTraining, + getMetrics: allMetrics + } } - -export { createRowingStatistics } diff --git a/app/engine/RowingStatistics.test.js b/app/engine/RowingStatistics.test.js new file mode 100644 index 0000000000..7a39617b4c --- /dev/null +++ b/app/engine/RowingStatistics.test.js @@ -0,0 +1,569 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * 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. +*/ +// ToDo: test the effects of smoothing parameters +import { test } from 'uvu' +import * as assert from 'uvu/assert' +import rowerProfiles from '../../config/rowerProfiles.js' +import { replayRowingSession } from '../recorders/RowingReplayer.js' +import { deepMerge } from '../tools/Helper.js' + +import { createRowingStatistics } from './RowingStatistics.js' + +const baseConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: { // Based on Concept 2 settings, as this is the validation system + numOfImpulsesPerRevolution: 6, + sprocketRadius: 1.4, + maximumStrokeTimeBeforePause: 0.3, // Modification to standard settings to shorten test cases + dragFactor: 110, + autoAdjustDragFactor: true, + minimumDragQuality: 0.95, + dragFactorSmoothing: 3, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.017, + flankLength: 12, + smoothing: 1, + minimumStrokeQuality: 0.36, + minimumForceBeforeStroke: 20, // Modification to standard settings to shorten test cases + minimumRecoverySlope: 0.00070, + autoAdjustRecoverySlope: false, // Modification to standard settings to shorten test cases + autoAdjustRecoverySlopeMargin: 0.04, + minimumDriveTime: 0.04, // Modification to standard settings to shorten test cases + minimumRecoveryTime: 0.09, // Modification to standard settings to shorten test cases + flywheelInertia: 0.10138, + magicConstant: 2.8 + } +} + +// Test behaviour for no datapoints +test('Correct rower behaviour at initialisation', () => { + const rowingStatistics = createRowingStatistics(baseConfig) + testStrokeState(rowingStatistics, 'WaitingForDrive') + testTotalMovingTime(rowingStatistics, 0) + testTotalNumberOfStrokes(rowingStatistics, 0) + testTotalLinearDistance(rowingStatistics, 0) + testCycleDuration(rowingStatistics, undefined) // Default value + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) + testCyclePower(rowingStatistics, undefined) + testDriveDuration(rowingStatistics, undefined) + testDriveDistance(rowingStatistics, undefined) + testDriveLength(rowingStatistics, undefined) + testDriveAverageHandleForce(rowingStatistics, undefined) + testDrivePeakHandleForce(rowingStatistics, undefined) + testRecoveryDuration(rowingStatistics, undefined) + testDragFactor(rowingStatistics, undefined) + testInstantHandlePower(rowingStatistics, undefined) +}) + +// Test behaviour for one datapoint + +// Test behaviour for three perfect identical strokes, including settingling behaviour of metrics +test('Test behaviour for three perfect identical strokes, including settingling behaviour of metrics', () => { + const rowingStatistics = createRowingStatistics(baseConfig) + testStrokeState(rowingStatistics, 'WaitingForDrive') + testTotalMovingTime(rowingStatistics, 0) + testTotalLinearDistance(rowingStatistics, 0) + testTotalNumberOfStrokes(rowingStatistics, 0) + testCycleDuration(rowingStatistics, undefined) // Default value + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) + testCyclePower(rowingStatistics, undefined) + testDriveDuration(rowingStatistics, undefined) + testDriveDistance(rowingStatistics, undefined) + testDriveLength(rowingStatistics, undefined) + testDriveAverageHandleForce(rowingStatistics, undefined) + testDrivePeakHandleForce(rowingStatistics, undefined) + testRecoveryDuration(rowingStatistics, undefined) + testDragFactor(rowingStatistics, undefined) + testInstantHandlePower(rowingStatistics, undefined) + // Drive initial stroke starts here + rowingStatistics.handleRotationImpulse(0.011221636) + rowingStatistics.handleRotationImpulse(0.011175504) + rowingStatistics.handleRotationImpulse(0.01116456) + rowingStatistics.handleRotationImpulse(0.011130263) + rowingStatistics.handleRotationImpulse(0.011082613) + rowingStatistics.handleRotationImpulse(0.011081761) + rowingStatistics.handleRotationImpulse(0.011062297) + rowingStatistics.handleRotationImpulse(0.011051853) + rowingStatistics.handleRotationImpulse(0.010973313) + rowingStatistics.handleRotationImpulse(0.010919756) + rowingStatistics.handleRotationImpulse(0.01086431) + rowingStatistics.handleRotationImpulse(0.010800864) + rowingStatistics.handleRotationImpulse(0.010956987) + rowingStatistics.handleRotationImpulse(0.010653396) + rowingStatistics.handleRotationImpulse(0.010648619) + rowingStatistics.handleRotationImpulse(0.010536818) + rowingStatistics.handleRotationImpulse(0.010526151) + rowingStatistics.handleRotationImpulse(0.010511225) + rowingStatistics.handleRotationImpulse(0.010386684) + testStrokeState(rowingStatistics, 'Drive') + testTotalMovingTime(rowingStatistics, 0.077918634) + testTotalLinearDistance(rowingStatistics, 0.2491943602992768) + testTotalNumberOfStrokes(rowingStatistics, 0) + testCycleDuration(rowingStatistics, undefined) // still default value + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) // This isn't filled after the first drive, as we haven't survived a complete cycle yet + testCyclePower(rowingStatistics, undefined) // This isn't filled after the first drive, as we haven't survived a complete cycle yet + testDriveDuration(rowingStatistics, undefined) // Shouldn't this one be filled after the first drive? + testDriveDistance(rowingStatistics, undefined) + testDriveLength(rowingStatistics, undefined) // Shouldn't this one be filled after the first drive? + testDriveAverageHandleForce(rowingStatistics, undefined) + testDrivePeakHandleForce(rowingStatistics, undefined) + testRecoveryDuration(rowingStatistics, undefined) + testDragFactor(rowingStatistics, undefined) + testInstantHandlePower(rowingStatistics, undefined) + // Recovery initial stroke starts here + rowingStatistics.handleRotationImpulse(0.010769) + rowingStatistics.handleRotationImpulse(0.010707554) + rowingStatistics.handleRotationImpulse(0.010722165) + rowingStatistics.handleRotationImpulse(0.01089567) + rowingStatistics.handleRotationImpulse(0.010917504) + rowingStatistics.handleRotationImpulse(0.010997969) + rowingStatistics.handleRotationImpulse(0.011004655) + rowingStatistics.handleRotationImpulse(0.011013618) + rowingStatistics.handleRotationImpulse(0.011058193) + rowingStatistics.handleRotationImpulse(0.010807149) + rowingStatistics.handleRotationImpulse(0.0110626) + rowingStatistics.handleRotationImpulse(0.011090787) + rowingStatistics.handleRotationImpulse(0.011099509) + rowingStatistics.handleRotationImpulse(0.011131862) + rowingStatistics.handleRotationImpulse(0.011209919) + testStrokeState(rowingStatistics, 'Recovery') + testTotalMovingTime(rowingStatistics, 0.23894732900000007) + testTotalLinearDistance(rowingStatistics, 0.7831822752262985) + testTotalNumberOfStrokes(rowingStatistics, 0) + testCycleDuration(rowingStatistics, undefined) + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) + testCyclePower(rowingStatistics, undefined) + testDriveDuration(rowingStatistics, undefined) + testDriveDistance(rowingStatistics, 0.46278952627008546) + testDriveLength(rowingStatistics, 0.19058995431778075) + testDriveAverageHandleForce(rowingStatistics, 276.20193475035796) + testDrivePeakHandleForce(rowingStatistics, 325.1619554833936) + testRecoveryDuration(rowingStatistics, undefined) + testDragFactor(rowingStatistics, undefined) + testInstantHandlePower(rowingStatistics, undefined) + // Drive second stroke starts here + rowingStatistics.handleRotationImpulse(0.011221636) + rowingStatistics.handleRotationImpulse(0.011175504) + rowingStatistics.handleRotationImpulse(0.01116456) + rowingStatistics.handleRotationImpulse(0.011130263) + rowingStatistics.handleRotationImpulse(0.011082613) + rowingStatistics.handleRotationImpulse(0.011081761) + rowingStatistics.handleRotationImpulse(0.011062297) + rowingStatistics.handleRotationImpulse(0.011051853) + rowingStatistics.handleRotationImpulse(0.010973313) + rowingStatistics.handleRotationImpulse(0.010919756) + rowingStatistics.handleRotationImpulse(0.01086431) + rowingStatistics.handleRotationImpulse(0.010800864) + rowingStatistics.handleRotationImpulse(0.010956987) + rowingStatistics.handleRotationImpulse(0.010653396) + rowingStatistics.handleRotationImpulse(0.010648619) + rowingStatistics.handleRotationImpulse(0.010536818) + rowingStatistics.handleRotationImpulse(0.010526151) + rowingStatistics.handleRotationImpulse(0.010511225) + rowingStatistics.handleRotationImpulse(0.010386684) + testStrokeState(rowingStatistics, 'Drive') + testTotalMovingTime(rowingStatistics, 0.44915539800000004) + testTotalLinearDistance(rowingStatistics, 1.828822466846578) + testTotalNumberOfStrokes(rowingStatistics, 1) + testCycleDuration(rowingStatistics, undefined) + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) + testCyclePower(rowingStatistics, undefined) + testDriveDuration(rowingStatistics, 0.143485717) + testDriveDistance(rowingStatistics, 0.46278952627008546) + testDriveLength(rowingStatistics, 0.19058995431778075) + testDriveAverageHandleForce(rowingStatistics, 276.20193475035796) + testDrivePeakHandleForce(rowingStatistics, 325.1619554833936) + testRecoveryDuration(rowingStatistics, 0.20540926600000003) + testDragFactor(rowingStatistics, 283.12720365097886) + testInstantHandlePower(rowingStatistics, undefined) + // Recovery second stroke starts here + rowingStatistics.handleRotationImpulse(0.010769) + rowingStatistics.handleRotationImpulse(0.010707554) + rowingStatistics.handleRotationImpulse(0.010722165) + rowingStatistics.handleRotationImpulse(0.01089567) + rowingStatistics.handleRotationImpulse(0.010917504) + rowingStatistics.handleRotationImpulse(0.010997969) + rowingStatistics.handleRotationImpulse(0.011004655) + rowingStatistics.handleRotationImpulse(0.011013618) + rowingStatistics.handleRotationImpulse(0.011058193) + rowingStatistics.handleRotationImpulse(0.010807149) + rowingStatistics.handleRotationImpulse(0.0110626) + rowingStatistics.handleRotationImpulse(0.011090787) + rowingStatistics.handleRotationImpulse(0.011099509) + rowingStatistics.handleRotationImpulse(0.011131862) + rowingStatistics.handleRotationImpulse(0.011209919) + testStrokeState(rowingStatistics, 'Recovery') + testTotalMovingTime(rowingStatistics, 0.6101840930000001) + testTotalLinearDistance(rowingStatistics, 2.5606258278697) + testTotalNumberOfStrokes(rowingStatistics, 1) + testCycleDuration(rowingStatistics, undefined) + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) + testCyclePower(rowingStatistics, undefined) + testDriveDuration(rowingStatistics, 0.23985939100000003) + testDriveDistance(rowingStatistics, 1.0733115961672441) + testDriveLength(rowingStatistics, 0.322536845768552) + testDriveAverageHandleForce(rowingStatistics, 285.0923064376231) + testDrivePeakHandleForce(rowingStatistics, 439.7407274840117) + testRecoveryDuration(rowingStatistics, 0.20540926600000003) + testDragFactor(rowingStatistics, 283.12720365097886) // As we decelerate the flywheel quite fast, this is expected + testInstantHandlePower(rowingStatistics, undefined) + // Drive third stroke starts here + rowingStatistics.handleRotationImpulse(0.011221636) + rowingStatistics.handleRotationImpulse(0.011175504) + rowingStatistics.handleRotationImpulse(0.01116456) + rowingStatistics.handleRotationImpulse(0.011130263) + rowingStatistics.handleRotationImpulse(0.011082613) + rowingStatistics.handleRotationImpulse(0.011081761) + rowingStatistics.handleRotationImpulse(0.011062297) + rowingStatistics.handleRotationImpulse(0.011051853) + rowingStatistics.handleRotationImpulse(0.010973313) + rowingStatistics.handleRotationImpulse(0.010919756) + rowingStatistics.handleRotationImpulse(0.01086431) + rowingStatistics.handleRotationImpulse(0.010800864) + rowingStatistics.handleRotationImpulse(0.010956987) + rowingStatistics.handleRotationImpulse(0.010653396) + rowingStatistics.handleRotationImpulse(0.010648619) + rowingStatistics.handleRotationImpulse(0.010536818) + rowingStatistics.handleRotationImpulse(0.010526151) + rowingStatistics.handleRotationImpulse(0.010511225) + rowingStatistics.handleRotationImpulse(0.010386684) + testStrokeState(rowingStatistics, 'Drive') + testTotalMovingTime(rowingStatistics, 0.8203921620000004) + testTotalLinearDistance(rowingStatistics, 3.4875767518323193) + testTotalNumberOfStrokes(rowingStatistics, 2) + testCycleDuration(rowingStatistics, undefined) + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) + testCyclePower(rowingStatistics, undefined) + testDriveDuration(rowingStatistics, 0.23985939100000003) + testDriveDistance(rowingStatistics, 1.0733115961672441) + testDriveLength(rowingStatistics, 0.322536845768552) + testDriveAverageHandleForce(rowingStatistics, 285.0923064376231) + testDrivePeakHandleForce(rowingStatistics, 439.7407274840117) + testRecoveryDuration(rowingStatistics, 0.09812447700000015) + testDragFactor(rowingStatistics, 283.12720365097886) + testInstantHandlePower(rowingStatistics, undefined) + // Recovery third stroke starts here + rowingStatistics.handleRotationImpulse(0.010769) + rowingStatistics.handleRotationImpulse(0.010707554) + rowingStatistics.handleRotationImpulse(0.010722165) + rowingStatistics.handleRotationImpulse(0.01089567) + rowingStatistics.handleRotationImpulse(0.010917504) + rowingStatistics.handleRotationImpulse(0.010997969) + rowingStatistics.handleRotationImpulse(0.011004655) + rowingStatistics.handleRotationImpulse(0.011013618) + rowingStatistics.handleRotationImpulse(0.011058193) + rowingStatistics.handleRotationImpulse(0.010807149) + rowingStatistics.handleRotationImpulse(0.0110626) + rowingStatistics.handleRotationImpulse(0.011090787) + rowingStatistics.handleRotationImpulse(0.011099509) + rowingStatistics.handleRotationImpulse(0.011131862) + rowingStatistics.handleRotationImpulse(0.011209919) + testStrokeState(rowingStatistics, 'Recovery') + testTotalMovingTime(rowingStatistics, 0.9814208570000005) + testTotalLinearDistance(rowingStatistics, 4.219380112855441) + testTotalNumberOfStrokes(rowingStatistics, 2) + testCycleDuration(rowingStatistics, undefined) + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) + testCyclePower(rowingStatistics, undefined) + testDriveDuration(rowingStatistics, 0.27311228700000023) + testDriveDistance(rowingStatistics, 1.2196722683718688) + testDriveLength(rowingStatistics, 0.3665191429188092) + testDriveAverageHandleForce(rowingStatistics, 254.91449219500532) + testDrivePeakHandleForce(rowingStatistics, 439.74072748282515) + testRecoveryDuration(rowingStatistics, 0.09812447700000015) + testDragFactor(rowingStatistics, 283.12720365097886) + testInstantHandlePower(rowingStatistics, undefined) + // Dwelling state starts here + rowingStatistics.handleRotationImpulse(0.020769) + rowingStatistics.handleRotationImpulse(0.020707554) + rowingStatistics.handleRotationImpulse(0.020722165) + rowingStatistics.handleRotationImpulse(0.02089567) + rowingStatistics.handleRotationImpulse(0.020917504) + rowingStatistics.handleRotationImpulse(0.020997969) + rowingStatistics.handleRotationImpulse(0.021004655) + rowingStatistics.handleRotationImpulse(0.021013618) + rowingStatistics.handleRotationImpulse(0.021058193) + rowingStatistics.handleRotationImpulse(0.020807149) + rowingStatistics.handleRotationImpulse(0.0210626) + rowingStatistics.handleRotationImpulse(0.021090787) + rowingStatistics.handleRotationImpulse(0.021099509) + rowingStatistics.handleRotationImpulse(0.021131862) + rowingStatistics.handleRotationImpulse(0.021209919) + testStrokeState(rowingStatistics, 'WaitingForDrive') + testTotalMovingTime(rowingStatistics, 1.1137102920000004) + testTotalNumberOfStrokes(rowingStatistics, 2) + testTotalLinearDistance(rowingStatistics, 4.804822801673938) + testCycleDuration(rowingStatistics, undefined) + testCycleDistance(rowingStatistics, undefined) + testCycleLinearVelocity(rowingStatistics, undefined) + testCyclePower(rowingStatistics, undefined) + testDriveDuration(rowingStatistics, undefined) + testDriveDistance(rowingStatistics, undefined) + testDriveLength(rowingStatistics, undefined) + testDriveAverageHandleForce(rowingStatistics, undefined) + testDrivePeakHandleForce(rowingStatistics, undefined) + testRecoveryDuration(rowingStatistics, undefined) + testDragFactor(rowingStatistics, 283.12720365097886) + testInstantHandlePower(rowingStatistics, undefined) +}) + +// Test behaviour for noisy upgoing flank + +// Test behaviour for noisy downgoing flank + +// Test behaviour for noisy stroke + +// Test behaviour after reset + +// Test behaviour for one datapoint + +// Test behaviour for noisy stroke + +// Test drag factor calculation + +// Test Dynamic stroke detection + +// Test behaviour after reset + +// Test behaviour with real-life data + +test('sample data for Sportstech WRX700 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const rowingStatistics = createRowingStatistics(testConfig) + testTotalMovingTime(rowingStatistics, 0) + testTotalLinearDistance(rowingStatistics, 0) + testTotalNumberOfStrokes(rowingStatistics, 0) + testDragFactor(rowingStatistics, undefined) + + await replayRowingSession(rowingStatistics.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv', realtime: false, loop: false }) + + testTotalMovingTime(rowingStatistics, 46.302522627) + testTotalLinearDistance(rowingStatistics, 166.29596716416734) + testTotalNumberOfStrokes(rowingStatistics, 15) + // As dragFactor is static, it should remain in place + testDragFactor(rowingStatistics, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('sample data for DKN R-320 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.DKN_R320) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const rowingStatistics = createRowingStatistics(testConfig) + testTotalMovingTime(rowingStatistics, 0) + testTotalLinearDistance(rowingStatistics, 0) + testTotalNumberOfStrokes(rowingStatistics, 0) + testDragFactor(rowingStatistics, undefined) + + await replayRowingSession(rowingStatistics.handleRotationImpulse, { filename: 'recordings/DKNR320.csv', realtime: false, loop: false }) + + testTotalMovingTime(rowingStatistics, 21.701535821) + testTotalLinearDistance(rowingStatistics, 70.11298001986664) + testTotalNumberOfStrokes(rowingStatistics, 9) + // As dragFactor is static, it should remain in place + testDragFactor(rowingStatistics, rowerProfiles.DKN_R320.dragFactor) +}) + +test('sample data for NordicTrack RX800 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.NordicTrack_RX800) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const rowingStatistics = createRowingStatistics(testConfig) + testTotalMovingTime(rowingStatistics, 0) + testTotalLinearDistance(rowingStatistics, 0) + testTotalNumberOfStrokes(rowingStatistics, 0) + testDragFactor(rowingStatistics, undefined) + + await replayRowingSession(rowingStatistics.handleRotationImpulse, { filename: 'recordings/RX800.csv', realtime: false, loop: false }) + + testTotalMovingTime(rowingStatistics, 22.259092749999997) + testTotalLinearDistance(rowingStatistics, 80.49260485116434) + testTotalNumberOfStrokes(rowingStatistics, 9) + // As dragFactor is dynamic, it should have changed + testDragFactor(rowingStatistics, 491.1395313462149) +}) + +test('A full session for SportsTech WRX700 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const rowingStatistics = createRowingStatistics(testConfig) + testTotalMovingTime(rowingStatistics, 0) + testTotalLinearDistance(rowingStatistics, 0) + testTotalNumberOfStrokes(rowingStatistics, 0) + testDragFactor(rowingStatistics, undefined) + + await replayRowingSession(rowingStatistics.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false }) + + testTotalMovingTime(rowingStatistics, 2340.0100514160117) + testTotalLinearDistance(rowingStatistics, 8406.791871958883) + testTotalNumberOfStrokes(rowingStatistics, 845) + // As dragFactor is static, it should remain in place + testDragFactor(rowingStatistics, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('A full session for a Concept2 Model C should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_Model_C) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const rowingStatistics = createRowingStatistics(testConfig) + testTotalMovingTime(rowingStatistics, 0) + testTotalLinearDistance(rowingStatistics, 0) + testTotalNumberOfStrokes(rowingStatistics, 0) + testDragFactor(rowingStatistics, undefined) + + await replayRowingSession(rowingStatistics.handleRotationImpulse, { filename: 'recordings/Concept2_Model_C.csv', realtime: false, loop: false }) + + testTotalMovingTime(rowingStatistics, 181.47141999999985) + testTotalLinearDistance(rowingStatistics, 552.0863658667265) + testTotalNumberOfStrokes(rowingStatistics, 83) + // As dragFactor isn't static, it should have changed + testDragFactor(rowingStatistics, 123.82587294279575) +}) + +test('A full session for a Concept2 RowErg should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_RowErg) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const rowingStatistics = createRowingStatistics(testConfig) + testTotalMovingTime(rowingStatistics, 0) + testTotalLinearDistance(rowingStatistics, 0) + testTotalNumberOfStrokes(rowingStatistics, 0) + testDragFactor(rowingStatistics, undefined) + + await replayRowingSession(rowingStatistics.handleRotationImpulse, { filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', realtime: false, loop: false }) + + testTotalMovingTime(rowingStatistics, 590.111937) + testTotalLinearDistance(rowingStatistics, 2027.493082238415) + testTotalNumberOfStrokes(rowingStatistics, 205) + // As dragFactor isn't static, it should have changed + testDragFactor(rowingStatistics, 80.60573080009686) +}) + +function testStrokeState (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().strokeState === expectedValue, `strokeState should be ${expectedValue} at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().strokeState}`) +} + +function testTotalMovingTime (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().totalMovingTime === expectedValue, `totalMovingTime should be ${expectedValue} sec at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().totalMovingTime}`) +} + +function testTotalNumberOfStrokes (rowingStatistics, expectedValue) { + // Please note there is a stroke 0 + assert.ok(rowingStatistics.getMetrics().totalNumberOfStrokes === expectedValue, `totalNumberOfStrokes should be ${expectedValue} at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().totalNumberOfStrokes}`) +} + +function testTotalLinearDistance (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().totalLinearDistance === expectedValue, `totalLinearDistance should be ${expectedValue} meters at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().totalLinearDistance}`) +} + +function testCycleDuration (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().cycleDuration === expectedValue, `cycleDuration should be ${expectedValue} sec at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().cycleDuration}`) +} + +function testCycleDistance (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().cycleDistance === expectedValue, `cycleDistance should be ${expectedValue} meters at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().cycleDistance}`) +} + +function testCycleLinearVelocity (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().cycleLinearVelocity === expectedValue, `cycleLinearVelocity should be ${expectedValue} m/s at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().cycleLinearVelocity}`) +} + +function testCyclePower (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().cyclePower === expectedValue, `cyclePower should be ${expectedValue} Watt at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().cyclePower}`) +} + +function testDriveDuration (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().driveDuration === expectedValue, `driveDuration should be ${expectedValue} sec at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().driveDuration}`) +} + +function testDriveDistance (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().driveDistance === expectedValue, `DriveDistance should be ${expectedValue} meters at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().driveDistance}`) +} + +function testDriveLength (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().driveLength === expectedValue, `driveLength should be ${expectedValue} meters at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().driveLength}`) +} + +function testDriveAverageHandleForce (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().driveAverageHandleForce === expectedValue, `driveAverageHandleForce should be ${expectedValue} N at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().driveAverageHandleForce}`) +} + +function testDrivePeakHandleForce (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().drivePeakHandleForce === expectedValue, `drivePeakHandleForce should be ${expectedValue} N at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().drivePeakHandleForce}`) +} + +function testRecoveryDuration (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().recoveryDuration === expectedValue, `recoveryDuration should be ${expectedValue} sec at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().recoveryDuration}`) +} + +function testDragFactor (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().dragFactor === expectedValue, `dragFactor should be ${expectedValue} N*m*s^2 at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().dragFactor}`) +} + +function testInstantHandlePower (rowingStatistics, expectedValue) { + assert.ok(rowingStatistics.getMetrics().instantHandlePower === expectedValue, `instantHandlePower should be ${expectedValue} Watt at ${rowingStatistics.getMetrics().totalMovingTime} sec, is ${rowingStatistics.getMetrics().instantHandlePower}`) +} + +function reportAll (rowingStatistics) { // eslint-disable-line no-unused-vars + assert.ok(0, `time: ${rowingStatistics.getMetrics().totalMovingTime}, state ${rowingStatistics.getMetrics().strokeState}, No Strokes: ${rowingStatistics.getMetrics().totalNumberOfStrokes + 1}, Lin Distance: ${rowingStatistics.getMetrics().totalLinearDistance}, cycle dur: ${rowingStatistics.getMetrics().cycleDuration}, cycle Lin Dist: ${rowingStatistics.getMetrics().cycleLinearDistance}, Lin Velocity: ${rowingStatistics.getMetrics().cycleLinearVelocity}, Power: ${rowingStatistics.getMetrics().cyclePower}, Drive Dur: ${rowingStatistics.getMetrics().driveDuration}, Drive Lin. Dist. ${rowingStatistics.driveDistance}, Drive Length: ${rowingStatistics.getMetrics().driveLength}, Av. Handle Force: ${rowingStatistics.getMetrics().driveAverageHandleForce}, Peak Handle Force: ${rowingStatistics.getMetrics().drivePeakHandleForce}, Rec. Dur: ${rowingStatistics.getMetrics().recoveryDuration}, Dragfactor: ${rowingStatistics.getMetrics().dragFactor}, Inst Handle Power: ${rowingStatistics.getMetrics().instantHandlePower}`) +} + +test.run() diff --git a/app/engine/SessionManager.js b/app/engine/SessionManager.js new file mode 100644 index 0000000000..d0def988da --- /dev/null +++ b/app/engine/SessionManager.js @@ -0,0 +1,511 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +/* +/** + * @file This Module calculates the workout, interval and split specific metrics, as well as guards their boundaries + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Architecture.md#sessionmanagerjs|the description} + */ +/* eslint-disable max-lines -- This handles quite a complex state machine with three levels of workout segments, not much we can do about it */ +import { EventEmitter } from 'events' +import { createRowingStatistics } from './RowingStatistics.js' +import { createWorkoutSegment } from './utils/workoutSegment.js' + +import loglevel from 'loglevel' +const log = loglevel.getLogger('RowingEngine') + +export function createSessionManager (config) { + const emitter = new EventEmitter() + const rowingStatistics = createRowingStatistics(config) + const session = createWorkoutSegment(config) + const interval = createWorkoutSegment(config) + const split = createWorkoutSegment(config) + let metrics = {} + let lastBroadcastedMetrics = {} + let pauseTimer + let pauseCountdownTimer = 0 + let watchdogTimer + const watchdogTimout = 1000 * config.rowerSettings.maximumStrokeTimeBeforePause // Pause timeout in miliseconds + let sessionState = 'WaitingForStart' + let intervalSettings = [] + let currentIntervalNumber = -1 + let splitNumber = -1 + let isUnplannedPause = false + let splitRemainder = null + + metrics = refreshMetrics() + setIntervalParameters([{ type: 'justrow' }]) + emitMetrics(metrics) + lastBroadcastedMetrics = { ...metrics } + + /** + * This function handles all incomming commands. As all commands are broadasted to all managers, we need to filter here what is relevant + * for the RowingEngine and what is not + * + * @param {Command} Name of the command to be executed by the commandhandler + * @param {unknown} data for executing the command + * + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Architecture.md#command-flow|The command flow documentation} + */ + function handleCommand (commandName, data) { + resetMetricsSessionContext(lastBroadcastedMetrics) + switch (commandName) { + case ('updateIntervalSettings'): + if (sessionState !== 'Rowing') { + setIntervalParameters(data) + } else { + log.debug(`SessionManager, time: ${metrics.totalMovingTime}, rejected new interval settings as session was already in progress`) + } + emitMetrics(lastBroadcastedMetrics) + break + case ('start'): + if (sessionState !== 'Rowing') { + clearTimeout(pauseTimer) + StartOrResumeTraining() + sessionState = 'WaitingForStart' + emitMetrics(lastBroadcastedMetrics) + } + break + case ('startOrResume'): + if (sessionState !== 'Rowing' && sessionState !== 'WaitingForStart') { + clearTimeout(pauseTimer) + StartOrResumeTraining() + sessionState = 'Paused' + emitMetrics(lastBroadcastedMetrics) + } + break + case ('pause'): + if (sessionState === 'Rowing') { + pauseTraining(lastBroadcastedMetrics) + lastBroadcastedMetrics = refreshMetrics() // as the pause button is forced, we need to fetch the zero'ed metrics + lastBroadcastedMetrics.metricsContext.isPauseStart = true + sessionState = 'Paused' + isUnplannedPause = true + emitMetrics(lastBroadcastedMetrics) + } + break + case ('stop'): + if (sessionState === 'Rowing') { + clearTimeout(pauseTimer) + stopTraining(lastBroadcastedMetrics) + lastBroadcastedMetrics.metricsContext.isSessionStop = true + sessionState = 'Stopped' + emitMetrics(lastBroadcastedMetrics) + } + break + case ('reset'): + clearTimeout(pauseTimer) + if (sessionState === 'Rowing') { + sessionState = 'Stopped' + lastBroadcastedMetrics.metricsContext.isSessionStop = true + emitMetrics(lastBroadcastedMetrics) + } + resetTraining(lastBroadcastedMetrics) + lastBroadcastedMetrics = refreshMetrics() // as the engine is reset, we need to fetch the zero'ed metrics + sessionState = 'WaitingForStart' + emitMetrics(lastBroadcastedMetrics) + break + case 'switchBlePeripheralMode': + break + case 'switchAntPeripheralMode': + break + case 'switchHrmMode': + break + case 'refreshPeripheralConfig': + break + case 'upload': + break + case 'shutdown': + clearTimeout(pauseTimer) + stopTraining(lastBroadcastedMetrics) + if (sessionState === 'Rowing') { + lastBroadcastedMetrics.metricsContext.isSessionStop = true + sessionState = 'Stopped' + emitMetrics(lastBroadcastedMetrics) + } + break + default: + log.error(`Recieved unknown command: ${commandName}`) + } + } + + function refreshMetrics () { + const baseMetrics = rowingStatistics.getMetrics() + resetMetricsSessionContext(baseMetrics) + baseMetrics.timestamp = new Date() + return baseMetrics + } + + function StartOrResumeTraining () { + rowingStatistics.allowStartOrResumeTraining() + } + + function stopTraining (baseMetrics) { + clearTimeout(watchdogTimer) + interval.push(baseMetrics) + split.push(baseMetrics) + rowingStatistics.stopTraining() + } + + // clear the metrics in case the user pauses rowing + function pauseTraining (baseMetrics) { + clearTimeout(watchdogTimer) + session.push(baseMetrics) + interval.push(baseMetrics) + rowingStatistics.pauseTraining() + } + + function resetTraining (baseMetrics) { + stopTraining(baseMetrics) + rowingStatistics.resetTraining() + rowingStatistics.allowStartOrResumeTraining() + intervalSettings = null + intervalSettings = [] + currentIntervalNumber = -1 + pauseCountdownTimer = 0 + splitNumber = -1 + metrics = refreshMetrics() + lastBroadcastedMetrics = { ...metrics } + sessionState = 'WaitingForStart' + session.reset() + interval.reset() + split.reset() + setIntervalParameters([{ type: 'justrow' }]) + isUnplannedPause = false + splitRemainder = null + emitMetrics(metrics) + } + + /** + * This function processes the currentDt and guards the session, interval and split boundaries + * + * @param {float} time between two impulses in seconds + * + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Architecture.md#session-interval-and-split-boundaries-in-sessionmanagerjs|The session, interval and split setup} + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Architecture.md#sessionstates-in-sessionmanagerjs|The states maintained} + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Architecture.md#rowing-metrics-flow|the flags set} + */ + /* eslint-disable max-statements, complexity -- This handles quite a complex state machine with three levels of workout segments, not much we can do about it */ + function handleRotationImpulse (currentDt) { + let temporaryDatapoint + + // Clear the watchdog as we got a currentDt, we'll set it at the end again + clearTimeout(watchdogTimer) + + // Provide the rower with new data + metrics = rowingStatistics.handleRotationImpulse(currentDt) + resetMetricsSessionContext(metrics) + if (sessionState === 'Rowing' && split.getStartTimestamp() !== undefined && split.timeSinceStart(metrics) >= 0) { + // If we are moving, timestamps should be based on movingTime as it is more accurate and consistent for the consumers + metrics.timestamp = new Date(split.getStartTimestamp().getTime() + (split.timeSinceStart(metrics) * 1000)) + } else { + metrics.timestamp = new Date() + } + + if (metrics.metricsContext.isMoving && (metrics.metricsContext.isDriveStart || metrics.metricsContext.isRecoveryStart)) { + session.push(metrics) + interval.push(metrics) + split.push(metrics) + } + + // This is the core of the finite state machine that defines all session state transitions + switch (true) { + case (sessionState === 'WaitingForStart' && metrics.metricsContext.isMoving === true): + StartOrResumeTraining() + sessionState = 'Rowing' + metrics.metricsContext.isSessionStart = true + // eslint-disable-next-line no-case-declarations -- Code clarity outweighs lint rules + const startTimestamp = new Date(metrics.timestamp.getTime() - metrics.totalMovingTime * 1000) + session.setStartTimestamp(startTimestamp) + interval.setStartTimestamp(startTimestamp) + split.setStartTimestamp(startTimestamp) + emitMetrics(metrics) + break + case (sessionState === 'WaitingForStart'): + // We can't change into the "Rowing" state since we are waiting for a drive phase that didn't come + emitMetrics(metrics) + break + case (sessionState === 'Paused' && metrics.metricsContext.isMoving === true && isUnplannedPause): + // It was a spontanuous pause + StartOrResumeTraining() + sessionState = 'Rowing' + metrics.metricsContext.isPauseEnd = true + emitMetrics(metrics) + isUnplannedPause = false + activateNextSplitParameters(metrics) + break + case (sessionState === 'Paused' && metrics.metricsContext.isMoving === true): + // We are leaving a planned rest interval + StartOrResumeTraining() + sessionState = 'Rowing' + metrics.metricsContext.isPauseEnd = true + metrics.metricsContext.isIntervalEnd = true + emitMetrics(metrics) + activateNextIntervalParameters(metrics) + break + case (sessionState === 'Paused'): + // We are in a paused state, and didn't see a drive, so nothing to do here + emitMetrics(metrics) + break + case (sessionState !== 'Stopped' && metrics.strokeState === 'Stopped'): + // We do not need to refetch the metrics as RowingStatistics will already have zero-ed the metrics when strokeState = 'Stopped' + // This is intended behaviour, as the rower/flywheel indicate the rower has stopped somehow + stopTraining(metrics) + sessionState = 'Stopped' + metrics.metricsContext.isSessionStop = true + emitMetrics(metrics) + break + case (sessionState === 'Stopped'): + // We are in a stopped state, and will remain there + sessionState = 'Stopped' + emitMetrics(metrics) + break + case (sessionState === 'Rowing' && metrics.strokeState === 'WaitingForDrive'): + // This is an unplanned pause + // We do not need to refetch the metrics as RowingStatistics will already have zero-ed the metrics when strokeState = 'WaitingForDrive' + pauseTraining(metrics) + sessionState = 'Paused' + isUnplannedPause = true + splitRemainder = split.remainder(metrics) + metrics.metricsContext.isPauseStart = true + metrics.metricsContext.isSplitEnd = true + emitMetrics(metrics) + activateNextSplitParameters(metrics) + break + case (sessionState === 'Rowing' && metrics.metricsContext.isMoving && interval.isEndReached(metrics) && isNextIntervalActive()): + // The next interval is an active one, so we just keep on going + // As we typically overshoot our interval target, we project the intermediate value + temporaryDatapoint = interval.interpolateEnd(lastBroadcastedMetrics, metrics) + sessionState = 'Rowing' + if (temporaryDatapoint.modified) { + // The intermediate datapoint is actually different + temporaryDatapoint.metricsContext.isIntervalEnd = true + temporaryDatapoint.metricsContext.isSplitEnd = true + emitMetrics(temporaryDatapoint) + activateNextIntervalParameters(temporaryDatapoint) + emitMetrics(metrics) + } else { + metrics.metricsContext.isIntervalEnd = true + metrics.metricsContext.isSplitEnd = true + emitMetrics(metrics) + activateNextIntervalParameters(metrics) + } + break + case (sessionState === 'Rowing' && metrics.metricsContext.isMoving && interval.isEndReached(metrics) && isNextIntervalAvailable()): + // There is a next interval, but it is a rest interval, so we forcefully stop the session + // As we typically overshoot our interval target, we project the intermediate value + sessionState = 'Paused' + isUnplannedPause = false + temporaryDatapoint = interval.interpolateEnd(lastBroadcastedMetrics, metrics) + if (temporaryDatapoint.modified) { + // The intermediate datapoint is actually different + temporaryDatapoint.metricsContext.isIntervalEnd = true + temporaryDatapoint.metricsContext.isSplitEnd = true + temporaryDatapoint.metricsContext.isPauseStart = true + emitMetrics(temporaryDatapoint) + activateNextIntervalParameters(temporaryDatapoint) + } else { + metrics.metricsContext.isIntervalEnd = true + metrics.metricsContext.isSplitEnd = true + metrics.metricsContext.isPauseStart = true + emitMetrics(metrics) + activateNextIntervalParameters(metrics) + } + + if (interval.timeToEnd(metrics) > 0) { + // If a minimal pause timer has been set, we need to make sure the user obeys that + pauseCountdownTimer = interval.timeToEnd(temporaryDatapoint) + stopTraining(temporaryDatapoint) + pauseTimer = setTimeout(onPauseTimer, 100) + } else { + // No minimal pause time has been set, so we pause the engine. In this state automatically activates the session again upon the next drive + pauseCountdownTimer = 0 + pauseTraining(temporaryDatapoint) + } + metrics = refreshMetrics() // Here we want to switch to a zero-ed message as the flywheel has stopped + break + case (sessionState === 'Rowing' && metrics.metricsContext.isMoving && interval.isEndReached(metrics)): + // Here we do NOT want zero the metrics, as we want to keep the metrics we had when we crossed the finishline + stopTraining(metrics) + sessionState = 'Stopped' + temporaryDatapoint = interval.interpolateEnd(lastBroadcastedMetrics, metrics) + if (temporaryDatapoint.modified) { + temporaryDatapoint.metricsContext.isSessionStop = true + emitMetrics(temporaryDatapoint) + } else { + metrics.metricsContext.isSessionStop = true + emitMetrics(metrics) + } + break + case (sessionState === 'Rowing' && metrics.metricsContext.isMoving && split.isEndReached(metrics)): + sessionState = 'Rowing' + temporaryDatapoint = split.interpolateEnd(lastBroadcastedMetrics, metrics) + if (temporaryDatapoint.modified) { + temporaryDatapoint.metricsContext.isSplitEnd = true + emitMetrics(temporaryDatapoint) + activateNextSplitParameters(temporaryDatapoint) + emitMetrics(metrics) + } else { + metrics.metricsContext.isSplitEnd = true + emitMetrics(metrics) + activateNextSplitParameters(metrics) + } + break + case (sessionState === 'Rowing' && metrics.metricsContext.isMoving): + sessionState = 'Rowing' + emitMetrics(metrics) + break + default: + log.error(`SessionManager: Time: ${metrics.totalMovingTime}, combination of ${sessionState} and state ${metrics.strokeState} is not captured by Finite State Machine`) + } + + if (sessionState === 'Rowing' && metrics.metricsContext.isMoving) { + watchdogTimer = setTimeout(onWatchdogTimeout, watchdogTimout) + } + lastBroadcastedMetrics = { ...metrics } + } + /* eslint-enable max-statements, complexity */ + + // Basic metricContext structure + function resetMetricsSessionContext (metricsToReset) { + metricsToReset.metricsContext.isSessionStart = false + metricsToReset.metricsContext.isIntervalEnd = false + metricsToReset.metricsContext.isSplitEnd = false + metricsToReset.metricsContext.isPauseStart = false + metricsToReset.metricsContext.isPauseEnd = false + metricsToReset.metricsContext.isSessionStop = false + } + + function setIntervalParameters (intervalParameters) { + intervalSettings = null + intervalSettings = intervalParameters + currentIntervalNumber = -1 + splitNumber = -1 + splitRemainder = null + if (intervalSettings.length > 0) { + log.info(`SessionManager: Workout plan recieved with ${intervalSettings.length} interval(s)`) + metrics = refreshMetrics() + + session.setStart(metrics) + session.summarize(intervalParameters) + + activateNextIntervalParameters(metrics) + emitMetrics(metrics) + } else { + // intervalParameters were empty, lets log this odd situation + log.error('SessionManager: Recieved workout plan containing no intervals') + } + } + + 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 { + return false + } + } + + function isNextIntervalActive () { + // This function tests whether there is a next interval available + if (currentIntervalNumber > -1 && intervalSettings.length > 0 && intervalSettings.length > (currentIntervalNumber + 1)) { + return (intervalSettings[currentIntervalNumber + 1].type !== 'rest') + } else { + return false + } + } + + function activateNextIntervalParameters (baseMetrics) { + 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 + currentIntervalNumber++ + log.info(`Activating interval settings for interval ${currentIntervalNumber + 1} of ${intervalSettings.length}`) + interval.setStart(baseMetrics) + interval.setEnd(intervalSettings[currentIntervalNumber]) + + // As the interval has changed, we need to reset the split metrics + splitRemainder = null + activateNextSplitParameters(baseMetrics) + } else { + log.error('SessionManager: expected a next interval, but did not find one!') + } + } + + function activateNextSplitParameters (baseMetrics) { + splitNumber++ + log.error(`Activating split settings for split ${splitNumber + 1}`) + split.setStart(baseMetrics) + if (splitRemainder !== null && sessionState === 'Rowing') { + // We have a part of the split still have to complete + split.setEnd(splitRemainder) + splitRemainder = null + } else { + split.setEnd(interval.getSplit()) + } + } + + function onPauseTimer () { + pauseCountdownTimer = pauseCountdownTimer - 0.1 + if (pauseCountdownTimer > 0) { + // The countdowntimer still has some time left on it + pauseTimer = setTimeout(onPauseTimer, 100) + lastBroadcastedMetrics.timestamp = new Date() + } else { + // The timer has run out + pauseTraining(lastBroadcastedMetrics) + sessionState = 'Paused' + lastBroadcastedMetrics = refreshMetrics() + pauseCountdownTimer = 0 + log.debug(`Time: ${lastBroadcastedMetrics.totalMovingTime}, rest interval ended`) + } + emitMetrics(lastBroadcastedMetrics) + } + + function emitMetrics (metricsToEmit) { + enrichMetrics(metricsToEmit) + emitter.emit('metricsUpdate', metricsToEmit) + } + + function enrichMetrics (metricsToEnrich) { + metricsToEnrich.sessionState = sessionState + metricsToEnrich.pauseCountdownTime = Math.max(pauseCountdownTimer, 0) // Time left on the countdown timer + metricsToEnrich.metricsContext.isUnplannedPause = isUnplannedPause // Indication for the PM5 emulator to distinguish between planned and unplanned pauses + metricsToEnrich.workout = session.metrics(metricsToEnrich) + metricsToEnrich.interval = interval.metrics(metricsToEnrich) + metricsToEnrich.interval.workoutStepNumber = Math.max(currentIntervalNumber, 0) // Interval number, to keep in sync with the workout plan + metricsToEnrich.split = split.metrics(metricsToEnrich) + metricsToEnrich.split.number = splitNumber + } + + function onWatchdogTimeout () { + pauseTraining(lastBroadcastedMetrics) + metrics = refreshMetrics() + log.error(`Time: ${metrics.totalMovingTime}, Forced a session pause due to unexpeted flywheel stop, exceeding the maximumStrokeTimeBeforePause (i.e. ${watchdogTimout / 1000} seconds) without new datapoints`) + sessionState = 'Paused' + isUnplannedPause = true + metrics.metricsContext.isPauseStart = true + metrics.metricsContext.isSplitEnd = true + session.push(metrics) + interval.push(metrics) + split.push(metrics) + emitMetrics(metrics) + activateNextSplitParameters(metrics) + lastBroadcastedMetrics = { ...metrics } + } + + /** + * @returns all metrics in the session manager + * @remark FOR TESTING PURPOSSES ONLY! + */ + function getMetrics () { + enrichMetrics(metrics) + return metrics + } + + return Object.assign(emitter, { + handleCommand, + handleRotationImpulse, + getMetrics + }) +} diff --git a/app/engine/SessionManager.test.js b/app/engine/SessionManager.test.js new file mode 100644 index 0000000000..8f2e4c3ea1 --- /dev/null +++ b/app/engine/SessionManager.test.js @@ -0,0 +1,563 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This test is a test of the SessionManager, that tests wether this object fills all fields correctly, + * and cuts off a session, interval and split decently + */ +// ToDo: test the effects of smoothing parameters +import { test } from 'uvu' +import * as assert from 'uvu/assert' +import rowerProfiles from '../../config/rowerProfiles.js' +import { replayRowingSession } from '../recorders/RowingReplayer.js' +import { deepMerge } from '../tools/Helper.js' + +import { createSessionManager } from './SessionManager.js' + +test('sample data for Sportstech WRX700 should produce plausible results for an unlimited run', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 46.302522627) + testTotalLinearDistance(sessionManager, 166.29596716416734) + testTotalNumberOfStrokes(sessionManager, 15) + // As dragFactor is static, it should remain in place + testDragFactor(sessionManager, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('sample data for Sportstech WRX700 should produce plausible results for a 150 meter session', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'distance', + targetDistance: 150, + targetTime: 0 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 41.734896595) + testTotalLinearDistance(sessionManager, 150.02019165448286) + testTotalNumberOfStrokes(sessionManager, 14) + // As dragFactor is static, it should remain in place + testDragFactor(sessionManager, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('sample data for Sportstech WRX700 should produce plausible results for a 45 seconds session', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'time', + targetDistance: 0, + targetTime: 45 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 45.077573161000004) + testTotalLinearDistance(sessionManager, 163.46539751030917) + testTotalNumberOfStrokes(sessionManager, 15) + // As dragFactor is static, it should remain in place + testDragFactor(sessionManager, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('sample data for DKN R-320 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.DKN_R320) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/DKNR320.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 21.701535821) + testTotalLinearDistance(sessionManager, 70.11298001986664) + testTotalNumberOfStrokes(sessionManager, 9) + // As dragFactor is static, it should remain in place + testDragFactor(sessionManager, rowerProfiles.DKN_R320.dragFactor) +}) + +test('sample data for NordicTrack RX800 should produce plausible results without intervalsettings', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.NordicTrack_RX800) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/RX800.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 22.259092749999997) + testTotalLinearDistance(sessionManager, 80.49260485116434) + testTotalNumberOfStrokes(sessionManager, 9) + // As dragFactor is dynamic, it should have changed + testDragFactor(sessionManager, 491.1395313462149) +}) + +test('sample data for NordicTrack RX800 should produce plausible results for a 20 seconds session', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.NordicTrack_RX800) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'time', + targetDistance: 0, + targetTime: 20 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/RX800.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 20.02496380499998) + testTotalLinearDistance(sessionManager, 72.3905525302199) + testTotalNumberOfStrokes(sessionManager, 8) + // As dragFactor is dynamic, it should have changed + testDragFactor(sessionManager, 487.65077394777813) +}) + +test('sample data for NordicTrack RX800 should produce plausible results for a 75 meter session', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.NordicTrack_RX800) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'distance', + targetDistance: 75, + targetTime: 0 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/RX800.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 20.78640177499998) + testTotalLinearDistance(sessionManager, 75.04096463553918) + testTotalNumberOfStrokes(sessionManager, 9) + // As dragFactor is dynamic, it should have changed + testDragFactor(sessionManager, 491.1395313462149) +}) + +test('A full unlimited session for SportsTech WRX700 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 2340.0100514160117) + testTotalLinearDistance(sessionManager, 8406.791871958883) + testTotalNumberOfStrokes(sessionManager, 845) + // As dragFactor is static, it should remain in place + testDragFactor(sessionManager, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('A 8000 meter session for SportsTech WRX700 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'distance', + targetDistance: 8000, + targetTime: 0 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 2236.509317727007) + testTotalLinearDistance(sessionManager, 8000.605126630236) + testTotalNumberOfStrokes(sessionManager, 804) + // As dragFactor is static, it should remain in place + testDragFactor(sessionManager, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('A 2300 sec session for SportsTech WRX700 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'time', + targetDistance: 0, + targetTime: 2300 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 2300.00695516701) + testTotalLinearDistance(sessionManager, 8252.525825823619) + testTotalNumberOfStrokes(sessionManager, 830) + // As dragFactor is static, it should remain in place + testDragFactor(sessionManager, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('A 2400 sec session for SportsTech WRX700 should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'time', + targetDistance: 0, + targetTime: 2400 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 2340.0100514160117) + testTotalLinearDistance(sessionManager, 8406.791871958883) + testTotalNumberOfStrokes(sessionManager, 845) + // As dragFactor is static, it should remain in place + testDragFactor(sessionManager, rowerProfiles.Sportstech_WRX700.dragFactor) +}) + +test('A full session for a Concept2 Model C should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_Model_C) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/Concept2_Model_C.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 181.47141999999985) + testTotalLinearDistance(sessionManager, 552.0863658667265) + testTotalNumberOfStrokes(sessionManager, 83) + // As dragFactor isn't static, it should have changed + testDragFactor(sessionManager, 123.82587294279575) +}) + +test('A 500 meter session for a Concept2 Model C should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_Model_C) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'distance', + targetDistance: 500, + targetTime: 0 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/Concept2_Model_C.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 156.87138200000004) + testTotalLinearDistance(sessionManager, 500.03019828253076) + testTotalNumberOfStrokes(sessionManager, 73) + // As dragFactor isn't static, it should have changed + testDragFactor(sessionManager, 123.69864738410088) +}) + +test('A 3 minute session for a Concept2 Model C should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_Model_C) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'time', + targetDistance: 0, + targetTime: 180 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/Concept2_Model_C.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 180.96533299999987) + testTotalLinearDistance(sessionManager, 551.8641725505744) + testTotalNumberOfStrokes(sessionManager, 83) + // As dragFactor isn't static, it should have changed + testDragFactor(sessionManager, 123.82587294279575) +}) + +test('A full session for a Concept2 RowErg should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_RowErg) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 590.111937) + testTotalLinearDistance(sessionManager, 2027.493082238415) + testTotalNumberOfStrokes(sessionManager, 205) + // As dragFactor isn't static, it should have changed + testDragFactor(sessionManager, 80.60573080009686) +}) + +test('A 2000 meter session for a Concept2 RowErg should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_RowErg) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'distance', + targetDistance: 2000, + targetTime: 0 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 582.1907659999988) + testTotalLinearDistance(sessionManager, 2000.0158938948496) + testTotalNumberOfStrokes(sessionManager, 203) + // As dragFactor isn't static, it should have changed + testDragFactor(sessionManager, 80.55270240035931) +}) + +test('A 580 seconds session for a Concept2 RowErg should produce plausible results', async () => { + const rowerProfile = deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_RowErg) + const testConfig = { + loglevel: { + default: 'silent', + RowingEngine: 'silent' + }, + numOfPhasesForAveragingScreenData: 2, + rowerSettings: rowerProfile + } + const sessionManager = createSessionManager(testConfig) + + const intervalSettings = [] + intervalSettings[0] = { + type: 'time', + targetDistance: 0, + targetTime: 580 + } + sessionManager.handleCommand('updateIntervalSettings', intervalSettings) + + testTotalMovingTime(sessionManager, 0) + testTotalLinearDistance(sessionManager, 0) + testTotalNumberOfStrokes(sessionManager, 0) + testDragFactor(sessionManager, undefined) + + await replayRowingSession(sessionManager.handleRotationImpulse, { filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', realtime: false, loop: false }) + + testTotalMovingTime(sessionManager, 580.0033639999992) + testTotalLinearDistance(sessionManager, 1992.6040191024413) + testTotalNumberOfStrokes(sessionManager, 202) + // As dragFactor isn't static, it should have changed + testDragFactor(sessionManager, 80.5946092810885) +}) + +function testTotalMovingTime (sessionManager, expectedValue) { + assert.ok(sessionManager.getMetrics().totalMovingTime === expectedValue, `totalMovingTime should be ${expectedValue} sec at ${sessionManager.getMetrics().totalMovingTime} sec, is ${sessionManager.getMetrics().totalMovingTime}`) +} + +function testTotalNumberOfStrokes (sessionManager, expectedValue) { + // Please note there is a stroke 0 + assert.ok(sessionManager.getMetrics().totalNumberOfStrokes === expectedValue, `totalNumberOfStrokes should be ${expectedValue} at ${sessionManager.getMetrics().totalMovingTime} sec, is ${sessionManager.getMetrics().totalNumberOfStrokes}`) +} + +function testTotalLinearDistance (sessionManager, expectedValue) { + assert.ok(sessionManager.getMetrics().totalLinearDistance === expectedValue, `totalLinearDistance should be ${expectedValue} meters at ${sessionManager.getMetrics().totalMovingTime} sec, is ${sessionManager.getMetrics().totalLinearDistance}`) +} + +function testDragFactor (sessionManager, expectedValue) { + assert.ok(sessionManager.getMetrics().dragFactor === expectedValue, `dragFactor should be ${expectedValue} N*m*s^2 at ${sessionManager.getMetrics().totalMovingTime} sec, is ${sessionManager.getMetrics().dragFactor}`) +} + +function reportAll (sessionManager) { // eslint-disable-line no-unused-vars + assert.ok(0, `time: ${sessionManager.getMetrics().totalMovingTime}, state ${sessionManager.getMetrics().strokeState}, No Strokes: ${sessionManager.getMetrics().totalNumberOfStrokes}, Lin Distance: ${sessionManager.getMetrics().totalLinearDistance}, cycle dur: ${sessionManager.getMetrics().cycleDuration}, cycle Lin Dist: ${sessionManager.getMetrics().cycleLinearDistance}, Lin Velocity: ${sessionManager.getMetrics().cycleLinearVelocity}, Power: ${sessionManager.getMetrics().cyclePower}, Drive Dur: ${sessionManager.getMetrics().driveDuration}, Drive Lin. Dist. ${sessionManager.driveDistance}, Drive Length: ${sessionManager.getMetrics().driveLength}, Av. Handle Force: ${sessionManager.getMetrics().driveAverageHandleForce}, Peak Handle Force: ${sessionManager.getMetrics().drivePeakHandleForce}, Rec. Dur: ${sessionManager.getMetrics().recoveryDuration}, Dragfactor: ${sessionManager.getMetrics().dragFactor}, Inst Handle Power: ${sessionManager.getMetrics().instantHandlePower}`) +} + +test.run() diff --git a/app/engine/VO2max.js b/app/engine/VO2max.js deleted file mode 100644 index 6d15189c2d..0000000000 --- a/app/engine/VO2max.js +++ /dev/null @@ -1,165 +0,0 @@ -'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 deleted file mode 100644 index 5370a1432f..0000000000 --- a/app/engine/WorkoutRecorder.js +++ /dev/null @@ -1,319 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This Module captures the metrics of a rowing session and persists them. - - Todo: split this into multiple modules -*/ -import log from 'loglevel' -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) { - if (startTime === undefined) { - startTime = new Date() - } - // impulse recordings a currently only used to create raw data files, so we can skip it - // if raw data file creation is disabled - if (config.createRawDataFiles) { - rotationImpulses.push(impulse) - } - } - - function recordStroke (stroke) { - if (startTime === undefined) { - startTime = new Date() - } - strokes.push(stroke) - } - - async function createRawDataFile () { - 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}_raw.csv${config.gzipRawDataFiles ? '.gz' : ''}` - log.info(`saving session as raw data file ${filename}...`) - - try { - await fs.mkdir(directory, { recursive: true }) - } catch (error) { - if (error.code !== 'EEXIST') { - log.error(`can not create directory ${directory}`, error) - } - } - 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) { - log.error('error creating tcx file') - return - } - const directory = `${config.dataDirectory}/recordings/${startTime.getFullYear()}/${(startTime.getMonth() + 1).toString().padStart(2, '0')}` - const filename = `${directory}/${tcxRecord.filename}${config.gzipTcxFiles ? '.gz' : ''}` - log.info(`saving session as tcx file ${filename}...`) - - try { - await fs.mkdir(directory, { recursive: true }) - } catch (error) { - if (error.code !== 'EEXIST') { - log.error(`can not create directory ${directory}`, error) - } - } - - await createFile(tcxRecord.tcx, `${filename}`, config.gzipTcxFiles) - } - - async function activeWorkoutToTcx () { - // we need at least two strokes to generate a valid tcx file - if (strokes.length < 5) return - const stringifiedStartTime = startTime.toISOString().replace(/T/, '_').replace(/:/g, '-').replace(/\..+/, '') - const filename = `${stringifiedStartTime}_rowing.tcx` - - const tcx = await workoutToTcx({ - id: startTime.toISOString(), - startTime, - strokes - }) - - return { - tcx, - filename - } - } - - async function workoutToTcx (workout) { - let versionArray = process.env.npm_package_version.split('.') - 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: { - $: { xmlns: 'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2', 'xmlns:ns2': 'http://www.garmin.com/xmlschemas/ActivityExtension/v2' }, - Activities: { - Activity: { - $: { Sport: 'Other' }, - Id: workout.id, - Lap: [ - { - $: { StartTime: workout.startTime.toISOString() }, - 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', - Cadence: Math.round(workout.strokes.reduce((sum, s) => sum + s.cycleStrokeRate, 0) / (workout.strokes.length - 1)), - TriggerMethod: 'Manual', - Track: { - Trackpoint: (() => { - return workout.strokes.map((stroke) => { - const trackPointTime = new Date(workout.startTime.getTime() + stroke.totalMovingTime * 1000) - const trackpoint = { - Time: trackPointTime.toISOString(), - DistanceMeters: stroke.totalLinearDistance.toFixed(2), - Cadence: Math.round(stroke.cycleStrokeRate), - Extensions: { - 'ns2:TPX': { - 'ns2:Speed': stroke.cycleLinearVelocity.toFixed(2), - 'ns2:Watts': Math.round(stroke.cyclePower) - } - } - } - if (stroke.heartrate !== undefined && stroke.heartrate > 30) { - trackpoint.HeartRateBpm = { Value: stroke.heartrate } - } - return trackpoint - }) - })() - }, - Extensions: { - 'ns2:LX': { - '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: `Indoor Rowing, Drag factor: ${drag.toFixed(1)} 10-6 N*m*s2, Estimated VO2Max: ${VO2maxoutput}${hrrAdittion}` - } - }, - Author: { - $: { 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:type': 'Application_t' }, - Name: 'Open Rowing Monitor', - Build: { - Version: { - VersionMajor: versionArray[0], - VersionMinor: versionArray[1], - BuildMajor: versionArray[2], - BuildMinor: 0 - }, - LangID: 'en', - PartNumber: 'OPE-NROWI-NG' - } - } - } - } - - const builder = new xml2js.Builder() - return builder.buildObject(tcxObject) - } - - async function reset () { - await createRecordings() - strokes = [] - rotationImpulses = [] - postExerciseHR = [] - startTime = undefined - } - - async function createFile (content, filename, compress = false) { - if (compress) { - const gzipContent = await gzip(content) - try { - await fs.writeFile(filename, gzipContent) - } catch (err) { - log.error(err) - } - } else { - try { - await fs.writeFile(filename, content) - } catch (err) { - log.error(err) - } - } - } - - function handlePause () { - createRecordings() - } - - async function createRecordings () { - if (!config.createRawDataFiles && !config.createTcxFiles) { - return - } - - if (!minimumRecordingTimeHasPassed()) { - log.debug('workout is shorter than minimum workout time, skipping automatic creation of recordings...') - return - } - - const parallelCalls = [] - - if (config.createRawDataFiles) { - parallelCalls.push(createRawDataFile()) - } - 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[strokes.length - 1].totalMovingTime - return (Math.max(rotationImpulseTimeTotal, strokeTimeTotal) > minimumRecordingTimeInSeconds) - } - - return { - recordStroke, - recordRotationImpulse, - handlePause, - activeWorkoutToTcx, - writeRecordings: createRecordings, - updateHRRecovery, - reset - } -} - -export { createWorkoutRecorder } diff --git a/app/engine/WorkoutUploader.js b/app/engine/WorkoutUploader.js deleted file mode 100644 index 1f4e4af3b8..0000000000 --- a/app/engine/WorkoutUploader.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Handles uploading workout data to different cloud providers -*/ -import log from 'loglevel' -import EventEmitter from 'events' -import { createStravaAPI } from '../tools/StravaAPI.js' -import config from '../tools/ConfigManager.js' - -function createWorkoutUploader (workoutRecorder) { - const emitter = new EventEmitter() - - let stravaAuthorizationCodeResolver - let requestingClient - - function getStravaAuthorizationCode () { - return new Promise((resolve) => { - emitter.emit('authorizeStrava', { stravaClientId: config.stravaClientId }, requestingClient) - stravaAuthorizationCodeResolver = resolve - }) - } - - const stravaAPI = createStravaAPI(getStravaAuthorizationCode) - - function stravaAuthorizationCode (stravaAuthorizationCode) { - if (stravaAuthorizationCodeResolver) { - stravaAuthorizationCodeResolver(stravaAuthorizationCode) - stravaAuthorizationCodeResolver = undefined - } - } - - async function upload (client) { - log.debug('uploading workout to strava...') - try { - requestingClient = client - // todo: we might signal back to the client whether we had success or not - const tcxActivity = await workoutRecorder.activeWorkoutToTcx() - if (tcxActivity !== undefined) { - await stravaAPI.uploadActivityTcx(tcxActivity) - emitter.emit('resetWorkout') - } else { - log.error('can not upload an empty workout to strava') - } - } catch (error) { - log.error('can not upload workout to strava:', error.message) - } - } - - return Object.assign(emitter, { - upload, - stravaAuthorizationCode - }) -} - -export { createWorkoutUploader } diff --git a/app/engine/utils/BinarySearchTree.js b/app/engine/utils/BinarySearchTree.js new file mode 100644 index 0000000000..2fb7c1bc8a --- /dev/null +++ b/app/engine/utils/BinarySearchTree.js @@ -0,0 +1,361 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/jaapvanekris/openrowingmonitor + + This creates an ordered series with labels + It allows for efficient determining the Median, Number of Above and Below +*/ + +export function createLabelledBinarySearchTree () { + let tree = null + + function push (label, value) { + if (value === undefined || isNaN(value)) { return } + if (tree === null) { + tree = newNode(label, value) + } else { + tree = pushInTree(tree, label, value) + } + } + + function pushInTree (currentTree, label, value) { + if (value <= currentTree.value) { + // The value should be on the left side of currentTree + if (currentTree.leftNode === null) { + currentTree.leftNode = newNode(label, value) + } else { + currentTree.leftNode = pushInTree(currentTree.leftNode, label, value) + } + } else { + // The value should be on the right side of currentTree + if (currentTree.rightNode === null) { + currentTree.rightNode = newNode(label, value) + } else { + currentTree.rightNode = pushInTree(currentTree.rightNode, label, value) + } + } + currentTree.numberOfLeafsAndNodes = currentTree.numberOfLeafsAndNodes + 1 + return currentTree + } + + function newNode (label, value) { + return { + label, + value, + leftNode: null, + rightNode: null, + numberOfLeafsAndNodes: 1 + } + } + + function size () { + if (tree !== null) { + return tree.numberOfLeafsAndNodes + } else { + return 0 + } + } + + function minimum () { + return minimumValueInTree(tree) + } + + function minimumValueInTree (subTree) { + if (subTree.leftNode === null) { + return subTree.value + } else { + return minimumValueInTree(subTree.leftNode) + } + } + + function maximum () { + return maximumValueInTree(tree) + } + + function maximumValueInTree (subTree) { + if (subTree.rightNode === null) { + return subTree.value + } else { + return maximumValueInTree(subTree.rightNode) + } + } + + function numberOfValuesAbove (testedValue) { + return countNumberOfValuesAboveInTree(tree, testedValue) + } + + function countNumberOfValuesAboveInTree (currentTree, testedValue) { + if (currentTree === null) { + return 0 + } else { + // We encounter a filled node + if (currentTree.value > testedValue) { + // testedValue < currentTree.value, so we can find the tested value in the left and right branch + return (countNumberOfValuesAboveInTree(currentTree.leftNode, testedValue) + countNumberOfValuesAboveInTree(currentTree.rightNode, testedValue) + 1) + } else { + // currentTree.value < testedValue, so we need to find values from the right branch + return countNumberOfValuesAboveInTree(currentTree.rightNode, testedValue) + } + } + } + + function numberOfValuesEqualOrBelow (testedValue) { + return countNumberOfValuesEqualOrBelowInTree(tree, testedValue) + } + + function countNumberOfValuesEqualOrBelowInTree (currentTree, testedValue) { + if (currentTree === null) { + return 0 + } else { + // We encounter a filled node + if (currentTree.value <= testedValue) { + // testedValue <= currentTree.value, so we can only find the tested value in the left branch + return (countNumberOfValuesEqualOrBelowInTree(currentTree.leftNode, testedValue) + countNumberOfValuesEqualOrBelowInTree(currentTree.rightNode, testedValue) + 1) + } else { + // currentTree.value > testedValue, so we only need to look at the left branch + return countNumberOfValuesEqualOrBelowInTree(currentTree.leftNode, testedValue) + } + } + } + + function remove (label) { + if (tree !== null) { + tree = removeFromTree(tree, label) + } + } + + function removeFromTree (currentTree, label) { + // Clean up the underlying sub-trees first + if (currentTree.leftNode !== null) { + currentTree.leftNode = removeFromTree(currentTree.leftNode, label) + } + if (currentTree.rightNode !== null) { + currentTree.rightNode = removeFromTree(currentTree.rightNode, label) + } + + // Next, handle the situation when we need to remove the node itself + if (currentTree.label === label) { + // First we need to remove the current node, then we need to investigate the underlying sub-trees to determine how it is resolved + // First, release the memory of the current node before we start to rearrange the tree, as this might cause a memory leak + currentTree.label = null + currentTree.value = null + currentTree.numberOfLeafsAndNodes = null + switch (true) { + case (currentTree.leftNode === null && currentTree.rightNode === null): + // As the underlying sub-trees are empty as well, we return an empty tree + currentTree = null + break + case (currentTree.leftNode !== null && currentTree.rightNode === null): + // As only the left node contains data, we can simply replace the removed node with the left sub-tree + currentTree = currentTree.leftNode + break + case (currentTree.leftNode === null && currentTree.rightNode !== null): + // As only the right node contains data, we can simply replace the removed node with the right sub-tree + currentTree = currentTree.rightNode + break + case (currentTree.leftNode !== null && currentTree.rightNode !== null): + // As all underlying sub-trees are filled, we need to move a leaf to the now empty node. Here, we can be a bit smarter + // as there are two potential nodes to use, we try to balance the tree a bit more as this increases performance + if (currentTree.leftNode.numberOfLeafsAndNodes > currentTree.rightNode.numberOfLeafsAndNodes) { + // The left sub-tree is bigger then the right one, lets use the closest predecessor to restore some balance + currentTree.value = clostestPredecessor(currentTree.leftNode).value + currentTree.label = clostestPredecessor(currentTree.leftNode).label + currentTree.leftNode = destroyClostestPredecessor(currentTree.leftNode) + } else { + // The right sub-tree is smaller then the right one, lets use the closest successor to restore some balance + currentTree.value = clostestSuccesor(currentTree.rightNode).value + currentTree.label = clostestSuccesor(currentTree.rightNode).label + currentTree.rightNode = destroyClostestSuccessor(currentTree.rightNode) + } + break + // no default + } + } + + // Recalculate the tree size + switch (true) { + case (currentTree === null): + // We are now an empty leaf, nothing to do here + break + case (currentTree.leftNode === null && currentTree.rightNode === null): + // This is a filled leaf + currentTree.numberOfLeafsAndNodes = 1 + break + case (currentTree.leftNode !== null && currentTree.rightNode === null): + currentTree.numberOfLeafsAndNodes = currentTree.leftNode.numberOfLeafsAndNodes + 1 + break + case (currentTree.leftNode === null && currentTree.rightNode !== null): + currentTree.numberOfLeafsAndNodes = currentTree.rightNode.numberOfLeafsAndNodes + 1 + break + case (currentTree.leftNode !== null && currentTree.rightNode !== null): + currentTree.numberOfLeafsAndNodes = currentTree.leftNode.numberOfLeafsAndNodes + currentTree.rightNode.numberOfLeafsAndNodes + 1 + break + // no default + } + return currentTree + } + + function clostestPredecessor (currentTree) { + // This function finds the maximum value in a tree + if (currentTree.rightNode !== null) { + // We haven't reached the end of the tree yet + return clostestPredecessor(currentTree.rightNode) + } else { + // We reached the largest value in the tree + return { + label: currentTree.label, + value: currentTree.value + } + } + } + + function destroyClostestPredecessor (currentTree) { + // This function finds the maximum value in a tree + if (currentTree.rightNode !== null) { + // We haven't reached the end of the tree yet + currentTree.rightNode = destroyClostestPredecessor(currentTree.rightNode) + currentTree.numberOfLeafsAndNodes = currentTree.numberOfLeafsAndNodes - 1 + return currentTree + } else { + // We reached the largest value in the tree + // First, release the memory of the current node before we start to rearrange the tree, as this might cause a memory leak + currentTree.label = null + currentTree.value = null + currentTree.numberOfLeafsAndNodes = null + return currentTree.leftNode + } + } + + function clostestSuccesor (currentTree) { + // This function finds the maximum value in a tree + if (currentTree.leftNode !== null) { + // We haven't reached the end of the tree yet + return clostestSuccesor(currentTree.leftNode) + } else { + // We reached the smallest value in the tree + return { + label: currentTree.label, + value: currentTree.value + } + } + } + + function destroyClostestSuccessor (currentTree) { + // This function finds the maximum value in a tree + if (currentTree.leftNode !== null) { + // We haven't reached the end of the tree yet + currentTree.leftNode = destroyClostestSuccessor(currentTree.leftNode) + currentTree.numberOfLeafsAndNodes = currentTree.numberOfLeafsAndNodes - 1 + return currentTree + } else { + // We reached the smallest value in the tree + // First, release the memory of the current node before we start to rearrange the tree, as this might cause a memory leak + currentTree.label = null + currentTree.value = null + currentTree.numberOfLeafsAndNodes = null + return currentTree.rightNode + } + } + + function median () { + if (tree !== null && tree.numberOfLeafsAndNodes > 0) { + // BE AWARE, UNLIKE WITH ARRAYS, THE COUNTING OF THE ELEMENTS STARTS WITH 1 !!!!!!! + // THIS LOGIC THUS WORKS DIFFERENT THAN MOST ARRAYS FOUND IN ORM!!!!!!! + const mid = Math.floor(tree.numberOfLeafsAndNodes / 2) + return tree.numberOfLeafsAndNodes % 2 !== 0 ? valueAtInorderPosition(tree, mid + 1) : (valueAtInorderPosition(tree, mid) + valueAtInorderPosition(tree, mid + 1)) / 2 + } else { + return 0 + } + } + + /** + * @remark: // BE AWARE TESTING PURPOSSES ONLY + */ + function valueAtInorderPos (position) { + if (tree !== null && position >= 1) { + return valueAtInorderPosition(tree, position) + } else { + return undefined + } + } + + function valueAtInorderPosition (currentTree, position) { + let currentNodePosition + if (currentTree === null) { + // We are now an empty tree, this shouldn't happen + return undefined + } + + // First we need to find out what the InOrder Postion we currently are at + if (currentTree.leftNode !== null) { + currentNodePosition = currentTree.leftNode.numberOfLeafsAndNodes + 1 + } else { + currentNodePosition = 1 + } + + switch (true) { + case (position === currentNodePosition): + // The current position is the one we are looking for + return currentTree.value + case (currentTree.leftNode === null): + // The current node's left side is empty, but position <> currentNodePosition, so we have no choice but to move downwards + return valueAtInorderPosition(currentTree.rightNode, (position - 1)) + case (currentTree.leftNode !== null && currentNodePosition > position): + // The position we look for is in the left side of the currentTree + return valueAtInorderPosition(currentTree.leftNode, position) + case (currentTree.leftNode !== null && currentNodePosition < position && currentTree.rightNode !== null): + // The position we look for is in the right side of the currentTree + return valueAtInorderPosition(currentTree.rightNode, (position - currentNodePosition)) + default: + return undefined + } + } + + function orderedSeries () { + return orderedTree(tree) + } + + function orderedTree (currentTree) { + if (currentTree === null) { + return [] + } else { + // We encounter a filled node + return [...orderedTree(currentTree.leftNode), currentTree.value, ...orderedTree(currentTree.rightNode)] + } + } + + function reset () { + resetTree(tree) + tree = null + } + + function resetTree (currentTree) { + if (currentTree !== null) { + currentTree.label = null + currentTree.value = null + if (currentTree.leftNode !== null) { + resetTree(currentTree.leftNode) + currentTree.leftNode = null + } + if (currentTree.rightNode !== null) { + resetTree(currentTree.rightNode) + currentTree.rightNode = null + } + currentTree.numberOfLeafsAndNodes = null + } + } + + return { + push, + remove, + size, + numberOfValuesAbove, + numberOfValuesEqualOrBelow, + minimum, + maximum, + median, + valueAtInorderPos, + orderedSeries, + reset + } +} diff --git a/app/engine/utils/BinarySearchTree.test.js b/app/engine/utils/BinarySearchTree.test.js new file mode 100644 index 0000000000..e7b8e541ae --- /dev/null +++ b/app/engine/utils/BinarySearchTree.test.js @@ -0,0 +1,207 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/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 { createLabelledBinarySearchTree } from './BinarySearchTree.js' + +test('Series behaviour with an empty tree', () => { + const dataTree = createLabelledBinarySearchTree() + testSize(dataTree, 0) + testNumberOfValuesAbove(dataTree, 0, 0) + testNumberOfValuesEqualOrBelow(dataTree, 0, 0) + testNumberOfValuesAbove(dataTree, 10, 0) + testNumberOfValuesEqualOrBelow(dataTree, 10, 0) + testMedian(dataTree, 0) +}) + +test('Tree behaviour with a single pushed value. Tree = [9]', () => { + const dataTree = createLabelledBinarySearchTree() + dataTree.push(1, 9) + testOrderedSeries(dataTree, [9]) + testSize(dataTree, 1) + testValueAtInorderPos(dataTree, 1, 9) + testNumberOfValuesAbove(dataTree, 0, 1) + testNumberOfValuesEqualOrBelow(dataTree, 0, 0) + testNumberOfValuesAbove(dataTree, 10, 0) + testNumberOfValuesEqualOrBelow(dataTree, 10, 1) + testMedian(dataTree, 9) +}) + +test('Tree behaviour with a second pushed value. Tree = [9, 3]', () => { + const dataTree = createLabelledBinarySearchTree() + dataTree.push(1, 9) + dataTree.push(2, 3) + testOrderedSeries(dataTree, [3, 9]) + testSize(dataTree, 2) + testValueAtInorderPos(dataTree, 1, 3) + testValueAtInorderPos(dataTree, 2, 9) + testNumberOfValuesAbove(dataTree, 0, 2) + testNumberOfValuesEqualOrBelow(dataTree, 0, 0) + testNumberOfValuesAbove(dataTree, 10, 0) + testNumberOfValuesEqualOrBelow(dataTree, 10, 2) + testMedian(dataTree, 6) +}) + +test('Tree behaviour with a third pushed value. Tree = [9, 3, 6]', () => { + const dataTree = createLabelledBinarySearchTree() + dataTree.push(1, 9) + dataTree.push(2, 3) + dataTree.push(3, 6) + testOrderedSeries(dataTree, [3, 6, 9]) + testSize(dataTree, 3) + testValueAtInorderPos(dataTree, 1, 3) + testValueAtInorderPos(dataTree, 2, 6) + testValueAtInorderPos(dataTree, 3, 9) + testNumberOfValuesAbove(dataTree, 0, 3) + testNumberOfValuesEqualOrBelow(dataTree, 0, 0) + testNumberOfValuesAbove(dataTree, 10, 0) + testNumberOfValuesEqualOrBelow(dataTree, 10, 3) + testMedian(dataTree, 6) +}) + +test('Tree behaviour with a fourth pushed value. Tree = [3, 6, 12]', () => { + const dataTree = createLabelledBinarySearchTree() + dataTree.push(1, 9) + dataTree.push(2, 3) + dataTree.push(3, 6) + dataTree.remove(1) + dataTree.push(4, 12) + testOrderedSeries(dataTree, [3, 6, 12]) + testSize(dataTree, 3) + testValueAtInorderPos(dataTree, 1, 3) + testValueAtInorderPos(dataTree, 2, 6) + testValueAtInorderPos(dataTree, 3, 12) + testNumberOfValuesAbove(dataTree, 0, 3) + testNumberOfValuesEqualOrBelow(dataTree, 0, 0) + testNumberOfValuesAbove(dataTree, 10, 1) + testNumberOfValuesEqualOrBelow(dataTree, 10, 2) + testMedian(dataTree, 6) +}) + +test('Tree behaviour with a fifth pushed value. Series = [6, 12, -3]', () => { + const dataTree = createLabelledBinarySearchTree() + dataTree.push(1, 9) + dataTree.push(2, 3) + dataTree.push(3, 6) + dataTree.remove(1) + dataTree.push(4, 12) + dataTree.remove(2) + dataTree.push(5, -3) + testOrderedSeries(dataTree, [-3, 6, 12]) + testSize(dataTree, 3) + testValueAtInorderPos(dataTree, 1, -3) + testValueAtInorderPos(dataTree, 2, 6) + testValueAtInorderPos(dataTree, 3, 12) + testNumberOfValuesAbove(dataTree, 0, 2) + testNumberOfValuesEqualOrBelow(dataTree, 0, 1) + testNumberOfValuesAbove(dataTree, 10, 1) + testNumberOfValuesEqualOrBelow(dataTree, 10, 2) + testMedian(dataTree, 6) +}) + +test('Tree behaviour with complex removals. Series = [9, 6, 5, 8, 7, 9, 12, 10, 11]', () => { + const dataTree = createLabelledBinarySearchTree() + dataTree.push(1, 9) + dataTree.push(2, 6) + dataTree.push(3, 5) + dataTree.push(4, 8) + dataTree.push(5, 7) + dataTree.push(6, 9) + dataTree.push(7, 12) + dataTree.push(8, 10) + dataTree.push(9, 11) + testOrderedSeries(dataTree, [5, 6, 7, 8, 9, 9, 10, 11, 12]) + testSize(dataTree, 9) + testValueAtInorderPos(dataTree, 5, 9) + testMedian(dataTree, 9) + dataTree.remove(1) + testOrderedSeries(dataTree, [5, 6, 7, 8, 9, 10, 11, 12]) + testSize(dataTree, 8) + testValueAtInorderPos(dataTree, 4, 8) + testValueAtInorderPos(dataTree, 5, 9) + testMedian(dataTree, 8.5) + dataTree.remove(3) + testOrderedSeries(dataTree, [6, 7, 8, 9, 10, 11, 12]) + testSize(dataTree, 7) + testValueAtInorderPos(dataTree, 4, 9) + testMedian(dataTree, 9) +}) + +// Test based on https://levelup.gitconnected.com/deletion-in-binary-search-tree-with-javascript-fded82e1791c +test('Tree behaviour with complex removals. Series = [50, 30, 70, 20, 40, 60, 80]', () => { + const dataTree = createLabelledBinarySearchTree() + dataTree.push(1, 50) + dataTree.push(2, 30) + dataTree.push(3, 70) + dataTree.push(4, 20) + dataTree.push(5, 40) + dataTree.push(6, 60) + dataTree.push(7, 80) + testOrderedSeries(dataTree, [20, 30, 40, 50, 60, 70, 80]) + testSize(dataTree, 7) + testValueAtInorderPos(dataTree, 4, 50) + dataTree.remove(4) + testOrderedSeries(dataTree, [30, 40, 50, 60, 70, 80]) + testSize(dataTree, 6) + testValueAtInorderPos(dataTree, 3, 50) + testValueAtInorderPos(dataTree, 4, 60) + testMedian(dataTree, 55) + dataTree.remove(2) + testOrderedSeries(dataTree, [40, 50, 60, 70, 80]) + testSize(dataTree, 5) + testValueAtInorderPos(dataTree, 3, 60) + testMedian(dataTree, 60) + dataTree.remove(1) + testOrderedSeries(dataTree, [40, 60, 70, 80]) + testSize(dataTree, 4) + testValueAtInorderPos(dataTree, 2, 60) + testValueAtInorderPos(dataTree, 3, 70) + testMedian(dataTree, 65) +}) + +test('Tree behaviour with a five pushed values followed by a reset, Tree = []', () => { + const dataTree = createLabelledBinarySearchTree() + dataTree.push(1, 9) + dataTree.push(2, 3) + dataTree.push(3, 6) + dataTree.push(4, 12) + dataTree.push(5, -3) + dataTree.reset() + testSize(dataTree, 0) + testNumberOfValuesAbove(dataTree, 0, 0) + testNumberOfValuesEqualOrBelow(dataTree, 0, 0) + testNumberOfValuesAbove(dataTree, 10, 0) + testNumberOfValuesEqualOrBelow(dataTree, 10, 0) + testMedian(dataTree, 0) +}) + +function testSize (tree, expectedValue) { + assert.ok(tree.size() === expectedValue, `Expected size should be ${expectedValue}, encountered ${tree.size()}`) +} + +function testNumberOfValuesAbove (tree, cutoff, expectedValue) { + assert.ok(tree.numberOfValuesAbove(cutoff) === expectedValue, `Expected numberOfValuesAbove(${cutoff}) to be ${expectedValue}, encountered ${tree.numberOfValuesAbove(cutoff)}`) +} + +function testNumberOfValuesEqualOrBelow (tree, cutoff, expectedValue) { + assert.ok(tree.numberOfValuesEqualOrBelow(cutoff) === expectedValue, `Expected numberOfValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered ${tree.numberOfValuesEqualOrBelow(cutoff)}`) +} + +function testOrderedSeries (tree, expectedValue) { + assert.ok(tree.orderedSeries().toString() === expectedValue.toString(), `Expected ordered series to be ${expectedValue}, encountered ${tree.orderedSeries()}`) +} + +function testValueAtInorderPos (tree, position, expectedValue) { + assert.ok(tree.valueAtInorderPos(position) === expectedValue, `Expected valueAtInorderPos(${position}) to be ${expectedValue}, encountered ${tree.valueAtInorderPos(position)}`) +} + +function testMedian (tree, expectedValue) { + assert.ok(tree.median() === expectedValue, `Expected median to be ${expectedValue}, encountered ${tree.median()}`) +} + +test.run() diff --git a/app/engine/utils/CurveAligner.js b/app/engine/utils/CurveAligner.js index adff69c346..11109a8aba 100644 --- a/app/engine/utils/CurveAligner.js +++ b/app/engine/utils/CurveAligner.js @@ -1,11 +1,11 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor This keeps an array, for ForceMetrics, and cleans it up */ -function createCurveAligner (minimumValue) { +export function createCurveAligner (minimumValue) { let _lastCompleteCurve = [] function push (curve) { @@ -30,7 +30,8 @@ function createCurveAligner (minimumValue) { } function reset () { - _lastCompleteCurve.splice(0, _lastCompleteCurve.length) + _lastCompleteCurve = null + _lastCompleteCurve = [] } return { @@ -39,5 +40,3 @@ function createCurveAligner (minimumValue) { reset } } - -export { createCurveAligner } diff --git a/app/engine/utils/FullTSLinearSeries.js b/app/engine/utils/FullTSLinearSeries.js index b0e9c3d4b4..3cef184821 100644 --- a/app/engine/utils/FullTSLinearSeries.js +++ b/app/engine/utils/FullTSLinearSeries.js @@ -1,17 +1,21 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/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. + 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. + out of the queue) automatically. This is a property of the Series object 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 + In order to prevent unneccessary calculations, this implementation uses lazy evaluation, + so it will calculate the intercept and goodnessOfFit only when needed, as many uses only + (first) need the slope. + This implementation uses concepts that are described here: https://en.wikipedia.org/wiki/Theil%E2%80%93Sen_estimator @@ -19,54 +23,55 @@ */ import { createSeries } from './Series.js' +import { createLabelledBinarySearchTree } from './BinarySearchTree.js' import loglevel from 'loglevel' const log = loglevel.getLogger('RowingEngine') -function createTSLinearSeries (maxSeriesLength = 0) { +export function createTSLinearSeries (maxSeriesLength = 0) { const X = createSeries(maxSeriesLength) const Y = createSeries(maxSeriesLength) - const slopes = [] + const A = createLabelledBinarySearchTree() 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: A contains all a's (as in the general formula y = a * x + b) + // Where the a's are labeled in the Binary Search Tree with their xi when they BEGIN in the point (xi, yi) + if (x === undefined || isNaN(x) || y === undefined || isNaN(y)) { return } + + if (maxSeriesLength > 0 && X.length() >= maxSeriesLength) { + // The maximum of the array has been reached, so when pushing the x,y the array gets shifted, + // thus we have to remove the a's belonging to the current position X0 as well before this value is trashed + A.remove(X.get(0)) } - // 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][.]. + X.push(x) + Y.push(y) - // Calculate the slopes of this new point + // Calculate all the slopes of the newly added 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) + while (i < X.length() - 1) { + // Calculate the slope with all preceeding datapoints and X.length() - 1'th datapoint (as the array starts at zero) + A.push(X.get(i), calculateSlope(i, X.length() - 1)) 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() + _A = A.median() } else { _A = 0 } - _B = Y.average() - (_A * X.average()) + + // Invalidate the previously calculated intercept and goodnessOfFit. We'll only calculate them if we need them + _B = null + _goodnessOfFit = null } function slope () { @@ -74,6 +79,7 @@ function createTSLinearSeries (maxSeriesLength = 0) { } function intercept () { + calculateIntercept() return _B } @@ -84,6 +90,7 @@ function createTSLinearSeries (maxSeriesLength = 0) { function coefficientB () { // For testing purposses only! + calculateIntercept() return _B } @@ -93,15 +100,43 @@ function createTSLinearSeries (maxSeriesLength = 0) { function goodnessOfFit () { // This function returns the R^2 as a goodness of fit indicator - if (X.length() >= 2) { - return _goodnessOfFit - } else { - return 0 + // It will automatically recalculate the _goodnessOfFit when it isn't defined + // This lazy approach is intended to prevent unneccesary calculations + let i = 0 + let sse = 0 + let sst = 0 + if (_goodnessOfFit === null) { + if (X.length() >= 2) { + while (i < X.length()) { + sse += Math.pow((Y.get(i) - projectX(X.get(i))), 2) + sst += Math.pow((Y.get(i) - Y.average()), 2) + i++ + } + switch (true) { + case (sse === 0): + _goodnessOfFit = 1 + break + case (sse > sst): + // This is a pretty bad fit as the error is bigger than just using the line for the average y as intercept + _goodnessOfFit = 0 + break + case (sst !== 0): + _goodnessOfFit = 1 - (sse / sst) + break + default: + // When SST = 0, R2 isn't defined + _goodnessOfFit = 0 + } + } else { + _goodnessOfFit = 0 + } } + return _goodnessOfFit } function projectX (x) { if (X.length() >= 2) { + calculateIntercept() return (_A * x) + _B } else { return 0 @@ -110,64 +145,14 @@ function createTSLinearSeries (maxSeriesLength = 0) { function projectY (y) { if (X.length() >= 2 && _A !== 0) { + calculateIntercept() return ((y - _B) / _A) } else { + log.error('TS Linear Regressor, attempted a Y-projection while slope was zero!') 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))) @@ -177,28 +162,47 @@ function createTSLinearSeries (maxSeriesLength = 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 calculateIntercept () { + // Calculate all the intercepts for the newly added point and the newly calculated A, when needed + // This function is only called when an intercept is really needed, as this saves a lot of CPU cycles when only a slope suffices + const B = createLabelledBinarySearchTree() + if (_B === null) { + if (X.length() > 1) { + // There are at least two points in the X and Y arrays, so let's calculate the intercept + let i = 0 + while (i < X.length()) { + // Please note , as we need to recreate the B-tree for each newly added datapoint anyway, the label i isn't relevant + B.push(i, (Y.get(i) - (_A * X.get(i)))) + i++ + } + _B = B.median() + } else { + _B = 0 + } } + B.reset() + } + + function reliable () { + return (X.length() >= 2) } function reset () { - X.reset() - Y.reset() - slopes.splice(0, slopes.length) - _A = 0 - _B = 0 - _goodnessOfFit = 0 + if (X.length() > 0) { + // There is something to reset + X.reset() + Y.reset() + A.reset() + _A = 0 + _B = 0 + _goodnessOfFit = 0 + } } return { push, + X, + Y, slope, intercept, coefficientA, @@ -207,20 +211,7 @@ function createTSLinearSeries (maxSeriesLength = 0) { goodnessOfFit, projectX, projectY, - numberOfXValuesAbove, - numberOfXValuesEqualOrBelow, - numberOfYValuesAbove, - numberOfYValuesEqualOrBelow, - xAtSeriesBegin, - xAtSeriesEnd, - yAtSeriesBegin, - yAtSeriesEnd, - xSum, - ySum, - xSeries, - ySeries, + reliable, reset } } - -export { createTSLinearSeries } diff --git a/app/engine/utils/FullTSLinearSeries.test.js b/app/engine/utils/FullTSLinearSeries.test.js new file mode 100644 index 0000000000..b0c29955c2 --- /dev/null +++ b/app/engine/utils/FullTSLinearSeries.test.js @@ -0,0 +1,268 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import { test } from 'uvu' +import * as assert from 'uvu/assert' + +import { createTSLinearSeries } from './FullTSLinearSeries.js' + +test('Correct behaviour of a series after initialisation', () => { + const dataSeries = createTSLinearSeries(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 = createTSLinearSeries(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 = createTSLinearSeries(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 = createTSLinearSeries(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 = createTSLinearSeries(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 = createTSLinearSeries(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 = createTSLinearSeries(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 = createTSLinearSeries(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.X.atSeriesBegin() === expectedValue, `Expected X.atSeriesBegin to be ${expectedValue}, encountered a ${series.X.atSeriesBegin()}`) +} + +function testYAtSeriesBegin (series, expectedValue) { + assert.ok(series.Y.atSeriesBegin() === expectedValue, `Expected Y.atSeriesBegin to be ${expectedValue}, encountered a ${series.Y.atSeriesBegin()}`) +} + +function testXAtSeriesEnd (series, expectedValue) { + assert.ok(series.X.atSeriesEnd() === expectedValue, `Expected X.atSeriesEnd to be ${expectedValue}, encountered a ${series.X.atSeriesEnd()}`) +} + +function testYAtSeriesEnd (series, expectedValue) { + assert.ok(series.Y.atSeriesEnd() === expectedValue, `Expected Y.atSeriesEnd to be ${expectedValue}, encountered a ${series.Y.atSeriesEnd()}`) +} + +function testNumberOfXValuesAbove (series, cutoff, expectedValue) { + assert.ok(series.X.numberOfValuesAbove(cutoff) === expectedValue, `Expected X.numberOfValuesAbove(${cutoff}) to be ${expectedValue}, encountered a ${series.X.numberOfValuesAbove(cutoff)}`) +} + +function testNumberOfYValuesAbove (series, cutoff, expectedValue) { + assert.ok(series.Y.numberOfValuesAbove(cutoff) === expectedValue, `Expected Y.numberOfValuesAbove(${cutoff}) to be ${expectedValue}, encountered a ${series.Y.numberOfValuesAbove(cutoff)}`) +} + +function testNumberOfXValuesEqualOrBelow (series, cutoff, expectedValue) { + assert.ok(series.X.numberOfValuesEqualOrBelow(cutoff) === expectedValue, `Expected X.numberOfValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered a ${series.X.numberOfValuesEqualOrBelow(cutoff)}`) +} + +function testNumberOfYValuesEqualOrBelow (series, cutoff, expectedValue) { + assert.ok(series.Y.numberOfValuesEqualOrBelow(cutoff) === expectedValue, `Expected Y.numberOfValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered a ${series.Y.numberOfValuesEqualOrBelow(cutoff)}`) +} + +function testXSum (series, expectedValue) { + assert.ok(series.X.sum() === expectedValue, `Expected X.sum to be ${expectedValue}, encountered a ${series.X.sum()}`) +} + +function testYSum (series, expectedValue) { + assert.ok(series.Y.sum() === expectedValue, `Expected Y.sum to be ${expectedValue}, encountered a ${series.Y.sum()}`) +} + +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/FullTSQuadraticSeries.js b/app/engine/utils/FullTSQuadraticSeries.js index a5a9ede858..138a899715 100644 --- a/app/engine/utils/FullTSQuadraticSeries.js +++ b/app/engine/utils/FullTSQuadraticSeries.js @@ -1,85 +1,95 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor - The TSLinearSeries is a datatype that represents a Quadratic Series. It allows + The FullTSQuadraticSeries 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 + A key constraint is to prevent heavy calculations at the end of a stroke (due to large + array based curve fitting), which might be performed on a Pi zero or Zero 2W + + In order to prevent unneccessary calculations, this implementation uses lazy evaluation, + so it will calculate the B, C and goodnessOfFit only when needed, as many uses only + (first) need the first and second direvative. 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: + The determination of the coefficients is based on the Lagrange interpolation, which is 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 { createLabelledBinarySearchTree } from './BinarySearchTree.js' import loglevel from 'loglevel' const log = loglevel.getLogger('RowingEngine') -function createTSQuadraticSeries (maxSeriesLength = 0) { +export function createTSQuadraticSeries (maxSeriesLength = 0) { const X = createSeries(maxSeriesLength) const Y = createSeries(maxSeriesLength) - const A = [] + const A = createLabelledBinarySearchTree() + const linearResidu = createTSLinearSeries(maxSeriesLength) let _A = 0 let _B = 0 let _C = 0 + let _goodnessOfFit = 0 function push (x, y) { - const linearResidu = createTSLinearSeries(maxSeriesLength) + // Invariant: A contains all a's (as in the general formula y = a * x^2 + b * x + c) + // Where the a's are labeled in the Binary Search Tree with their Xi when they BEGIN in the point (Xi, Yi) + if (x === undefined || isNaN(x) || y === undefined || isNaN(y)) { return } + + if (maxSeriesLength > 0 && X.length() >= maxSeriesLength) { + // The maximum of the array has been reached, so when pushing the new datapoint (x,y), the array will get shifted, + // thus we have to remove all the A's that start with the old position X0 BEFORE this value gets thrown away + A.remove(X.get(0)) + } 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 + // Calculate the coefficient a for the new interval by adding the newly added datapoint + let i = 0 + let j = 0 + + switch (true) { + case (X.length() >= 3): + // There are now at least three datapoints in the X and Y arrays, so let's calculate the A portion belonging for the new datapoint via Quadratic Theil-Sen regression + // First we calculate the A for the formula + while (i < X.length() - 2) { + j = i + 1 + while (j < X.length() - 1) { + A.push(X.get(i), calculateA(i, j, X.length() - 1)) + j++ + } + i++ + } + _A = A.median() + + // We invalidate the linearResidu, B, C, and goodnessOfFit, as this will trigger a recalculate when they are needed + linearResidu.reset() + _B = null + _C = null + _goodnessOfFit = null + break + default: + _A = 0 + _B = 0 + _C = 0 + _goodnessOfFit = 0 } } function firstDerivativeAtPosition (position) { - if (X.length() > 2 && position < X.length()) { + if (X.length() >= 3 && position < X.length()) { + calculateB() return ((_A * 2 * X.get(position)) + _B) } else { return 0 @@ -87,7 +97,7 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { } function secondDerivativeAtPosition (position) { - if (X.length() > 2 && position < X.length()) { + if (X.length() >= 3 && position < X.length()) { return (_A * 2) } else { return 0 @@ -95,7 +105,8 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { } function slope (x) { - if (X.length() > 2) { + if (X.length() >= 3) { + calculateB() return ((_A * 2 * x) + _B) } else { return 0 @@ -109,16 +120,21 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { function coefficientB () { // For testing purposses only! + calculateB() return _B } function coefficientC () { // For testing purposses only! + calculateB() + calculateC() return _C } function intercept () { - return coefficientC() + calculateB() + calculateC() + return _C } function length () { @@ -127,118 +143,119 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { 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 + let i = 0 + let sse = 0 + let sst = 0 + if (_goodnessOfFit === null) { + if (X.length() >= 3) { + while (i < X.length()) { + sse += Math.pow((Y.get(i) - projectX(X.get(i))), 2) + sst += Math.pow((Y.get(i) - Y.average()), 2) + i++ + } + switch (true) { + case (sse === 0): + _goodnessOfFit = 1 + break + case (sse > sst): + // This is a pretty bad fit as the error is bigger than just using the line for the average y as intercept + _goodnessOfFit = 0 + break + case (sst !== 0): + _goodnessOfFit = 1 - (sse / sst) + break + default: + // When SST = 0, R2 isn't defined + _goodnessOfFit = 0 + } + } else { + _goodnessOfFit = 0 + } } + return _goodnessOfFit } function projectX (x) { - const _C = coefficientC() - if (X.length() > 2) { + if (X.length() >= 3) { + calculateB() + calculateC() 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 calculateA (pointOne, pointTwo, pointThree) { + let result = 0 + if (X.get(pointOne) !== X.get(pointTwo) && X.get(pointOne) !== X.get(pointThree) && 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 + result = (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))) + return result + } else { + log.error('TS Quadratic Regressor, Division by zero prevented in CalculateA!') + return 0 + } } - function xSeries () { - return X.series() + function calculateB () { + // Calculate all the linear slope for the newly added point and the newly calculated A + // This function is only called when a linear slope is really needed, as this saves a lot of CPU cycles when only a slope suffices + if (_B === null) { + if (X.length() >= 3) { + fillLinearResidu() + _B = linearResidu.slope() + } else { + _B = 0 + } + } } - function ySeries () { - return Y.series() + function calculateC () { + // Calculate all the intercept for the newly added point and the newly calculated A + // This function is only called when a linear intercept is really needed, as this saves a lot of CPU cycles when only a slope suffices + if (_C === null) { + if (X.length() >= 3) { + fillLinearResidu() + _C = linearResidu.intercept() + } else { + _C = 0 + } + } } - 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 + function fillLinearResidu () { + // To calculate the B and C via Linear regression over the residu, we need to fill it if empty + if (linearResidu.length() === 0) { + let i = 0 + while (i < X.length()) { + linearResidu.push(X.get(i), Y.get(i) - (_A * Math.pow(X.get(i), 2))) + i++ } - 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 reliable () { + return (X.length() >= 3) } function reset () { - X.reset() - Y.reset() - A.splice(0, A.length) - _A = 0 - _B = 0 - _C = 0 + if (X.length() > 0) { + // There is something to reset + X.reset() + Y.reset() + A.reset() + linearResidu.reset() + _A = 0 + _B = 0 + _C = 0 + _goodnessOfFit = 0 + } } return { push, + X, + Y, firstDerivativeAtPosition, secondDerivativeAtPosition, slope, @@ -249,22 +266,7 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { length, goodnessOfFit, projectX, - numberOfXValuesAbove, - numberOfXValuesEqualOrBelow, - numberOfYValuesAbove, - numberOfYValuesEqualOrBelow, - xAtSeriesBegin, - xAtSeriesEnd, - xAtPosition, - yAtSeriesBegin, - yAtSeriesEnd, - yAtPosition, - xSum, - ySum, - xSeries, - ySeries, + reliable, reset } } - -export { createTSQuadraticSeries } diff --git a/app/engine/utils/FullTSQuadraticSeries.test.js b/app/engine/utils/FullTSQuadraticSeries.test.js index 473b5b0484..211dc1450c 100644 --- a/app/engine/utils/FullTSQuadraticSeries.test.js +++ b/app/engine/utils/FullTSQuadraticSeries.test.js @@ -1,10 +1,11 @@ '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 + Open Rowing Monitor, https://github.com/JaapvanEkris/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' @@ -56,6 +57,7 @@ test('Quadratic Approximation on a perfect noisefree function y = 2 * Math.pow(x testCoefficientA(dataSeries, 2) testCoefficientB(dataSeries, 2) testCoefficientC(dataSeries, 2) + testGoodnessOfFitEquals(dataSeries, 1) }) 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', () => { @@ -75,6 +77,7 @@ test('Quadratic Approximation on a perfect noisefree function y = 2 * Math.pow(x testCoefficientA(dataSeries, 2) testCoefficientB(dataSeries, 2) testCoefficientC(dataSeries, 2) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(1, 6) dataSeries.push(2, 14) dataSeries.push(3, 26) @@ -88,6 +91,7 @@ test('Quadratic Approximation on a perfect noisefree function y = 2 * Math.pow(x testCoefficientA(dataSeries, 2) testCoefficientB(dataSeries, 2) testCoefficientC(dataSeries, 2) + testGoodnessOfFitEquals(dataSeries, 1) }) test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, noisefree', () => { @@ -99,82 +103,102 @@ test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, no testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-8, 228) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-7, 172) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-6, 124) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-5, 84) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-4, 52) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-3, 28) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-2, 12) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-1, 4) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(0, 4) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(1, 12) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(2, 28) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(3, 52) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(4, 84) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(5, 124) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(6, 172) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(7, 228) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(8, 292) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(9, 364) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(10, 444) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 1) }) test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, with some noise (+/- 1)', () => { @@ -186,82 +210,102 @@ test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, wi testCoefficientA(dataSeries, 2) testCoefficientB(dataSeries, -36) testCoefficientC(dataSeries, -195) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-8, 229) testCoefficientA(dataSeries, 4) - testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 3.6666666666666643) // This is quite acceptable as ORM ignores the C + testCoefficientB(dataSeries, 4.333333333333334) + testCoefficientC(dataSeries, 7.166666666666671) + testGoodnessOfFitEquals(dataSeries, 0.9998746217034155) dataSeries.push(-7, 171) - testCoefficientA(dataSeries, 3.666666666666667) - testCoefficientB(dataSeries, -1.8333333333333335) - testCoefficientC(dataSeries, -20.916666666666682) + testCoefficientA(dataSeries, 3.3333333333333335) + testCoefficientB(dataSeries, -7.999999999999991) + testCoefficientC(dataSeries, -48.33333333333328) + testGoodnessOfFitEquals(dataSeries, 0.9998468647471163) 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) + testGoodnessOfFitEquals(dataSeries, 0.9999165499911914) + dataSeries.push(-5, 83) + testCoefficientA(dataSeries, 3.8666666666666667) + testCoefficientB(dataSeries, 1.8666666666666671) + testCoefficientC(dataSeries, -4.333333333333336) // This is quite acceptable as ORM ignores the C + testGoodnessOfFitEquals(dataSeries, 0.9999366117119067) dataSeries.push(-4, 53) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 3.8571428571428577) // This is quite acceptable as ORM ignores the C + testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 0.9999402806808002) dataSeries.push(-3, 27) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9999042318865254) dataSeries.push(-2, 13) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 3.8888888888888893) // This is quite acceptable as ORM ignores the C + testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 0.9999495097395712) dataSeries.push(-1, 3) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9999117149452151) dataSeries.push(0, 5) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 5) + testGoodnessOfFitEquals(dataSeries, 0.9998721709098177) dataSeries.push(1, 11) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9997996371611135) dataSeries.push(2, 29) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 5) + testGoodnessOfFitEquals(dataSeries, 0.9996545703483187) dataSeries.push(3, 51) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9993201651380683) dataSeries.push(4, 85) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 5) + testGoodnessOfFitEquals(dataSeries, 0.9987227718173796) dataSeries.push(5, 123) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9986961263098004) dataSeries.push(6, 173) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 5) + testGoodnessOfFitEquals(dataSeries, 0.9993274803746546) dataSeries.push(7, 227) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9996526505917571) dataSeries.push(8, 293) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 5) + testGoodnessOfFitEquals(dataSeries, 0.9998002774328024) dataSeries.push(9, 363) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) // We get a 3 instead of 4, which is quite acceptable (especially since ORM ignores the C) + testGoodnessOfFitEquals(dataSeries, 0.9998719089295779) dataSeries.push(10, 444) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 0.9999558104799866) }) test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, with some noise (+/- 1) and spikes (+/- 9)', () => { @@ -277,63 +321,78 @@ test('Quadratic Approximation on function y = 4 * Math.pow(x, 2) + 4 * x + 4, wi 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) + testGoodnessOfFitEquals(dataSeries, 0.9999402806808002) + dataSeries.push(-3, 37) // FIRST SPIKE +9 + testCoefficientA(dataSeries, 4.215277777777778) + testCoefficientB(dataSeries, 7.694940476190471) + testCoefficientC(dataSeries, 18.816964285714235) + testGoodnessOfFitEquals(dataSeries, 0.9997971509015441) 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) + testCoefficientA(dataSeries, 3.9714285714285715) + testCoefficientB(dataSeries, 3.6000000000000036) // Coefficient B seems to take a hit anyway + testCoefficientC(dataSeries, 2.842857142857163) // We get a 2.8 instead of 4, which is quite acceptable (especially since ORM ignores the C) + testGoodnessOfFitEquals(dataSeries, 0.9991656951087963) dataSeries.push(-1, 3) - testCoefficientA(dataSeries, 4) - testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientA(dataSeries, 3.9555555555555557) + testCoefficientB(dataSeries, 3.37777777777778) + testCoefficientC(dataSeries, 2.4222222222222243) + testGoodnessOfFitEquals(dataSeries, 0.9992769580376006) dataSeries.push(0, 5) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 5) + testGoodnessOfFitEquals(dataSeries, 0.9988530568930122) dataSeries.push(1, 11) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9982053643291688) dataSeries.push(2, 29) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 5) + testGoodnessOfFitEquals(dataSeries, 0.9969166946967148) dataSeries.push(3, 51) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9939797134586851) dataSeries.push(4, 85) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 5) + testGoodnessOfFitEquals(dataSeries, 0.9888468297958631) dataSeries.push(5, 123) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9886212128178015) dataSeries.push(6, 173) - testCoefficientA(dataSeries, 4) - testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientA(dataSeries, 4.044444444444444) + testCoefficientB(dataSeries, 3.822222222222223) + testCoefficientC(dataSeries, 3.577777777777783) + testGoodnessOfFitEquals(dataSeries, 0.9945681627011398) dataSeries.push(7, 227) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9968997006175546) dataSeries.push(8, 293) - testCoefficientA(dataSeries, 4) - testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 3) // This is quite acceptable as ORM ignores the C + testCoefficientA(dataSeries, 3.9047619047619047) + testCoefficientB(dataSeries, 4.888888888888889) + testCoefficientC(dataSeries, 2.9682539682539684) // This is quite acceptable as ORM ignores the C + testGoodnessOfFitEquals(dataSeries, 0.9995034675221599) dataSeries.push(9, 363) - testCoefficientA(dataSeries, 4) + testCoefficientA(dataSeries, 4) // These results match up 100% with the previous test, showing that a spike has no carry over effects testCoefficientB(dataSeries, 4) - testCoefficientC(dataSeries, 4) // We get a 3 instead of 4, which is quite acceptable (especially since ORM ignores the C) + testCoefficientC(dataSeries, 3) + testGoodnessOfFitEquals(dataSeries, 0.9998719089295779) dataSeries.push(10, 444) testCoefficientA(dataSeries, 4) testCoefficientB(dataSeries, 4) testCoefficientC(dataSeries, 4) + testGoodnessOfFitEquals(dataSeries, 0.9999558104799866) }) test('Quadratic TS Estimation should be decent for standard real-life example from MathBits with some noise', () => { @@ -352,9 +411,10 @@ test('Quadratic TS Estimation should be decent for standard real-life example fr 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 + testCoefficientA(dataSeries, -0.17702838827838824) // In the example, the TI084 results in -0.1737141137, which we consider acceptably close + testCoefficientB(dataSeries, 14.929144536019532) // In the example, the TI084 results in 14.52117133, which we consider acceptably close + testCoefficientC(dataSeries, -31.325531135531037) // In the example, the TI084 results in -21.89774466, which we consider acceptably close + testGoodnessOfFitEquals(dataSeries, 0.9781087883163964) }) test('Quadratic TS Estimation should be decent for standard real-life example from VarsityTutors with some noise', () => { @@ -367,9 +427,10 @@ test('Quadratic TS Estimation should be decent for standard real-life example fr 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 + testCoefficientA(dataSeries, 1.0833333333333333) // The example results in 1.1071 for OLS, which we consider acceptably close + testCoefficientB(dataSeries, 1.0833333333333333) // The example results in 1 for OLS, which we consider acceptably close + testCoefficientC(dataSeries, 0.8333333333333335) // The example results in 0.5714 for OLS, which we consider acceptably close + testGoodnessOfFitEquals(dataSeries, 0.9851153039832286) }) test('Quadratic TS Estimation should be decent for standard example from VTUPulse with some noise, without the vertex being part of the dataset', () => { @@ -380,9 +441,10 @@ test('Quadratic TS Estimation should be decent for standard example from VTUPuls 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 + testCoefficientA(dataSeries, 0.8583333333333334) // The example results in 0.7642857 for OLS, which we consider acceptably close given the small sample size + testCoefficientB(dataSeries, -6.420833333333334) // The example results in -5.5128571 for OLS, which we consider acceptably close given the small sample size + testCoefficientC(dataSeries, 14.387500000000003) // The example results in 12.4285714 for OLS, which we consider acceptably close given the small sample size + testGoodnessOfFitEquals(dataSeries, 0.9825283785404673) }) 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', () => { @@ -413,9 +475,10 @@ test('Quadratic TS Estimation should be decent for standard real-life example fr 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) + testCoefficientA(dataSeries, -2.030477132951317) + testCoefficientB(dataSeries, 0.5976858995201227) + testCoefficientC(dataSeries, 0.17630021024409503) + testGoodnessOfFitEquals(dataSeries, 0.23921110548689295) }) test('Quadratic TS Estimation should be decent for standard real-life example from Statology.org with some noise and chaotic X values', () => { @@ -432,9 +495,10 @@ test('Quadratic TS Estimation should be decent for standard real-life example fr 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 + testCoefficientA(dataSeries, -0.10119047619047619) // The example results in -0.1012 for R after two rounds, which we consider acceptably close + testCoefficientB(dataSeries, 6.801190476190477) // The example results in 6.7444 for R after two rounds, which we consider acceptably close + testCoefficientC(dataSeries, -21.126190476190516) // The example results in 18.2536 for R after two rounds, but for ORM, this factor is irrelevant + testGoodnessOfFitEquals(dataSeries, 0.9571127392718894) }) test('Quadratic TS Estimation should be decent for standard real-life example from StatsDirect.com with some noise and chaotic X values', () => { @@ -450,9 +514,10 @@ test('Quadratic TS Estimation should be decent for standard real-life example fr 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 + testCoefficientA(dataSeries, -0.00046251263566907585) // The example results in -0.00045 through QR decomposition by Givens rotations, which we consider acceptably close + testCoefficientB(dataSeries, 2.441798780934297) // The example results in 2.39893 for QR decomposition by Givens rotations, which we consider acceptably close + testCoefficientC(dataSeries, -1235.044997485239) // The example results in -1216.143887 for QR decomposition by Givens rotations, but for ORM, this factor is irrelevant + testGoodnessOfFitEquals(dataSeries, 0.9790379024208455) }) test('Quadratic Approximation with a clean function and a reset', () => { @@ -467,6 +532,7 @@ test('Quadratic Approximation with a clean function and a reset', () => { testCoefficientA(dataSeries, 2) testCoefficientB(dataSeries, 2) testCoefficientC(dataSeries, 2) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(-4, 26) dataSeries.push(-3, 14) // Pi ;) dataSeries.push(-2, 6) @@ -477,6 +543,7 @@ test('Quadratic Approximation with a clean function and a reset', () => { testCoefficientA(dataSeries, 2) testCoefficientB(dataSeries, 2) testCoefficientC(dataSeries, 2) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.push(3, 26) dataSeries.push(4, 42) dataSeries.push(5, 62) @@ -488,22 +555,27 @@ test('Quadratic Approximation with a clean function and a reset', () => { testCoefficientA(dataSeries, 2) testCoefficientB(dataSeries, 2) testCoefficientC(dataSeries, 2) + testGoodnessOfFitEquals(dataSeries, 1) dataSeries.reset() testCoefficientA(dataSeries, 0) testCoefficientB(dataSeries, 0) testCoefficientC(dataSeries, 0) + testGoodnessOfFitEquals(dataSeries, 0) dataSeries.push(-1, 2) testCoefficientA(dataSeries, 0) testCoefficientB(dataSeries, 0) testCoefficientC(dataSeries, 0) + testGoodnessOfFitEquals(dataSeries, 0) dataSeries.push(0, 2) testCoefficientA(dataSeries, 0) testCoefficientB(dataSeries, 0) testCoefficientC(dataSeries, 0) + testGoodnessOfFitEquals(dataSeries, 0) dataSeries.push(1, 6) testCoefficientA(dataSeries, 2) testCoefficientB(dataSeries, 2) testCoefficientC(dataSeries, 2) + testGoodnessOfFitEquals(dataSeries, 1) }) test('Quadratic TS Estimation should result in a straight line for function y = x', () => { @@ -519,28 +591,36 @@ test('Quadratic TS Estimation should result in a straight line for function y = testCoefficientA(dataSeries, 0) testCoefficientB(dataSeries, 1) testCoefficientC(dataSeries, 0) + testGoodnessOfFitEquals(dataSeries, 1) }) function testCoefficientA (series, expectedValue) { - assert.ok(series.coefficientA() === expectedValue, `Expected value for coefficientA at X-position ${series.xAtSeriesEnd()} is ${expectedValue}, encountered a ${series.coefficientA()}`) + assert.ok(series.coefficientA() === expectedValue, `Expected value for coefficientA at X-position ${series.X.atSeriesEnd()} 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()}`) + assert.ok(series.coefficientB() === expectedValue, `Expected value for coefficientB at X-position ${series.X.atSeriesEnd()} 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()}`) + assert.ok(series.coefficientC() === expectedValue, `Expected value for coefficientC at X-position ${series.X.atSeriesEnd()} 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 testGoodnessOfFitEquals (series, expectedValue) { + assert.ok(series.goodnessOfFit() === expectedValue, `Expected goodnessOfFit at X-position ${series.X.atSeriesEnd()} is ${expectedValue}, encountered ${series.goodnessOfFit()}`) } -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)}`) +function testGoodnessOfFitBetween (series, expectedValueAbove, expectedValueBelow) { // eslint-disable-line no-unused-vars + assert.ok(series.goodnessOfFit() > expectedValueAbove, `Expected goodnessOfFit at X-position ${series.X.atSeriesEnd()} above ${expectedValueAbove}, encountered ${series.goodnessOfFit()}`) + assert.ok(series.goodnessOfFit() < expectedValueBelow, `Expected goodnessOfFit at X-position ${series.X.atSeriesEnd()} below ${expectedValueBelow}, encountered ${series.goodnessOfFit()}`) +} + +function testSlope (series, position, expectedValue) { // eslint-disable-line no-unused-vars + assert.ok(series.slope(position) === expectedValue, `Expected value for Slope-${position} at X-position ${series.X.atSeriesEnd()} (slope at X-position ${series.X.atPosition(position)}) is ${expectedValue}, encountered a ${series.slope(position)}`) +} + +function reportAll (series) { // eslint-disable-line no-unused-vars + assert.ok(series.coefficientA() === 99, `time: ${series.X.atSeriesEnd()}, 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 index cc382f6234..6d0c26541e 100644 --- a/app/engine/utils/OLSLinearSeries.js +++ b/app/engine/utils/OLSLinearSeries.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/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 @@ -28,18 +28,18 @@ import { createSeries } from './Series.js' import loglevel from 'loglevel' const log = loglevel.getLogger('RowingEngine') -function createOLSLinearSeries (maxSeriesLength = 0) { +export 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) { + if (x === undefined || isNaN(x) || y === undefined || isNaN(y)) { return } X.push(x) XX.push(x * x) Y.push(y) @@ -53,7 +53,6 @@ function createOLSLinearSeries (maxSeriesLength = 0) { 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 @@ -94,73 +93,13 @@ function createOLSLinearSeries (maxSeriesLength = 0) { if (X.length() >= 2 && _slope !== 0) { return ((y - _intercept) / _slope) } else { + log.error('OLS Regressor, attempted a Y-projection while slope was zero!') 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 reliable () { + return (X.length() >= 2 && _slope !== 0) } function reset () { @@ -176,28 +115,15 @@ function createOLSLinearSeries (maxSeriesLength = 0) { return { push, + X, + Y, slope, intercept, length, goodnessOfFit, projectX, projectY, - numberOfXValuesAbove, - numberOfXValuesEqualOrBelow, - numberOfYValuesAbove, - numberOfYValuesEqualOrBelow, - numberOfUpwardTrend, - numberOfFlatOrDownwardTrend, - xAtSeriesBegin, - xAtSeriesEnd, - yAtSeriesBegin, - yAtSeriesEnd, - xSum, - ySum, - xSeries, - ySeries, + reliable, reset } } - -export { createOLSLinearSeries } diff --git a/app/engine/utils/OLSLinearSeries.test.js b/app/engine/utils/OLSLinearSeries.test.js index 92e6445eb0..9bf25cc3c0 100644 --- a/app/engine/utils/OLSLinearSeries.test.js +++ b/app/engine/utils/OLSLinearSeries.test.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ import { test } from 'uvu' import * as assert from 'uvu/assert' @@ -199,43 +199,43 @@ function testLength (series, expectedValue) { } function testXAtSeriesBegin (series, expectedValue) { - assert.ok(series.xAtSeriesBegin() === expectedValue, `Expected xAtSeriesBegin to be ${expectedValue}, encountered a ${series.xAtSeriesBegin()}`) + assert.ok(series.X.atSeriesBegin() === expectedValue, `Expected X.atSeriesBegin to be ${expectedValue}, encountered a ${series.X.atSeriesBegin()}`) } function testYAtSeriesBegin (series, expectedValue) { - assert.ok(series.yAtSeriesBegin() === expectedValue, `Expected yAtSeriesBegin to be ${expectedValue}, encountered a ${series.yAtSeriesBegin()}`) + assert.ok(series.Y.atSeriesBegin() === expectedValue, `Expected Y.atSeriesBegin to be ${expectedValue}, encountered a ${series.Y.atSeriesBegin()}`) } function testXAtSeriesEnd (series, expectedValue) { - assert.ok(series.xAtSeriesEnd() === expectedValue, `Expected xAtSeriesEnd to be ${expectedValue}, encountered a ${series.xAtSeriesEnd()}`) + assert.ok(series.X.atSeriesEnd() === expectedValue, `Expected X.atSeriesEnd to be ${expectedValue}, encountered a ${series.X.atSeriesEnd()}`) } function testYAtSeriesEnd (series, expectedValue) { - assert.ok(series.yAtSeriesEnd() === expectedValue, `Expected yAtSeriesEnd to be ${expectedValue}, encountered a ${series.yAtSeriesEnd()}`) + assert.ok(series.Y.atSeriesEnd() === expectedValue, `Expected Y.atSeriesEnd to be ${expectedValue}, encountered a ${series.Y.atSeriesEnd()}`) } function testNumberOfXValuesAbove (series, cutoff, expectedValue) { - assert.ok(series.numberOfXValuesAbove(cutoff) === expectedValue, `Expected numberOfXValuesAbove(${cutoff}) to be ${expectedValue}, encountered a ${series.numberOfXValuesAbove(cutoff)}`) + assert.ok(series.X.numberOfValuesAbove(cutoff) === expectedValue, `Expected X.numberOfValuesAbove(${cutoff}) to be ${expectedValue}, encountered a ${series.X.numberOfValuesAbove(cutoff)}`) } function testNumberOfYValuesAbove (series, cutoff, expectedValue) { - assert.ok(series.numberOfYValuesAbove(cutoff) === expectedValue, `Expected numberOfYValuesAbove(${cutoff}) to be ${expectedValue}, encountered a ${series.numberOfYValuesAbove(cutoff)}`) + assert.ok(series.Y.numberOfValuesAbove(cutoff) === expectedValue, `Expected Y.numberOfValuesAbove(${cutoff}) to be ${expectedValue}, encountered a ${series.Y.numberOfValuesAbove(cutoff)}`) } function testNumberOfXValuesEqualOrBelow (series, cutoff, expectedValue) { - assert.ok(series.numberOfXValuesEqualOrBelow(cutoff) === expectedValue, `Expected numberOfXValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered a ${series.numberOfXValuesEqualOrBelow(cutoff)}`) + assert.ok(series.X.numberOfValuesEqualOrBelow(cutoff) === expectedValue, `Expected X.numberOfValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered a ${series.X.numberOfValuesEqualOrBelow(cutoff)}`) } function testNumberOfYValuesEqualOrBelow (series, cutoff, expectedValue) { - assert.ok(series.numberOfYValuesEqualOrBelow(cutoff) === expectedValue, `Expected numberOfYValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered a ${series.numberOfYValuesEqualOrBelow(cutoff)}`) + assert.ok(series.Y.numberOfValuesEqualOrBelow(cutoff) === expectedValue, `Expected Y.numberOfValuesEqualOrBelow(${cutoff}) to be ${expectedValue}, encountered a ${series.Y.numberOfValuesEqualOrBelow(cutoff)}`) } function testXSum (series, expectedValue) { - assert.ok(series.xSum() === expectedValue, `Expected xSum to be ${expectedValue}, encountered a ${series.xSum()}`) + assert.ok(series.X.sum() === expectedValue, `Expected X.sum to be ${expectedValue}, encountered a ${series.X.sum()}`) } function testYSum (series, expectedValue) { - assert.ok(series.ySum() === expectedValue, `Expected ySum to be ${expectedValue}, encountered a ${series.ySum()}`) + assert.ok(series.Y.sum() === expectedValue, `Expected y.Sum to be ${expectedValue}, encountered a ${series.Y.sum()}`) } function testSlopeEquals (series, expectedValue) { diff --git a/app/engine/utils/Series.js b/app/engine/utils/Series.js index 2bc189578c..15a67fd9d0 100644 --- a/app/engine/utils/Series.js +++ b/app/engine/utils/Series.js @@ -1,18 +1,33 @@ '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 + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ - -function createSeries (maxSeriesLength) { - const seriesArray = [] +/** + * This creates a series with a maximum number of values. It allows for determining the Average, Median, Number of Positive, number of Negative + * @remark BE AWARE: The median function is extremely CPU intensive for larger series. Use the BinarySearchTree for that situation instead! + * + * @param {number} [maxSeriesLength] The maximum length of the series (0 for unlimited) + */ +export function createSeries (maxSeriesLength = 0) { + /** + * @type {Array} + */ + let seriesArray = [] let seriesSum = 0 let numPos = 0 let numNeg = 0 + let min = undefined + let max = undefined + /** + * @param {float} value to be added to the series + */ function push (value) { + if (value === undefined || isNaN(value)) { return } + + if (min !== undefined) { min = Math.min(min, value) } + if (max !== undefined) { max = Math.max(max, 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 @@ -22,6 +37,12 @@ function createSeries (maxSeriesLength) { } else { numNeg-- } + if (min === seriesArray[0]) { + min = undefined + } + if (max === seriesArray[0]) { + max = undefined + } seriesArray.shift() } seriesArray.push(value) @@ -33,10 +54,16 @@ function createSeries (maxSeriesLength) { } } + /** + * @output {number} length of the series + */ function length () { return seriesArray.length } + /** + * @output {float} value at the head of the series (i.e. the one first added) + */ function atSeriesBegin () { if (seriesArray.length > 0) { return seriesArray[0] @@ -45,6 +72,9 @@ function createSeries (maxSeriesLength) { } } + /** + * @output {float} value at the tail of the series (i.e. the one last added) + */ function atSeriesEnd () { if (seriesArray.length > 0) { return seriesArray[seriesArray.length - 1] @@ -53,6 +83,10 @@ function createSeries (maxSeriesLength) { } } + /** + * @param {number} position + * @output {float} value at a specific postion, starting at 0 + */ function get (position) { if (position >= 0 && position < seriesArray.length) { return seriesArray[position] @@ -61,6 +95,10 @@ function createSeries (maxSeriesLength) { } } + /** + * @param {number} testedValue + * @output {number} number of values in the series above the tested value + */ function numberOfValuesAbove (testedValue) { if (testedValue === 0) { return numPos @@ -77,6 +115,10 @@ function createSeries (maxSeriesLength) { } } + /** + * @param {number} testedValue + * @output {number} number of values in the series below or equal to the tested value + */ function numberOfValuesEqualOrBelow (testedValue) { if (testedValue === 0) { return numNeg @@ -93,10 +135,16 @@ function createSeries (maxSeriesLength) { } } + /** + * @output {float} sum of the entire series + */ function sum () { return seriesSum } + /** + * @output {float} average of the entire series + */ function average () { if (seriesArray.length > 0) { return seriesSum / seriesArray.length @@ -105,6 +153,33 @@ function createSeries (maxSeriesLength) { } } + /** + * @output {float} smallest element in the series + */ + function minimum () { + if (seriesArray.length > 0) { + if (isNaN(min)) { min = Math.min(...seriesArray) } + return min + } else { + return 0 + } + } + + /** + * @output {float} largest value in the series + */ + function maximum () { + if (seriesArray.length > 0) { + if (isNaN(max)) { max = Math.max(...seriesArray) } + return max + } else { + return 0 + } + } + + /** + * @output {float} median of the series (DO NOT USE FOR LARGE SERIES!) + */ function median () { if (seriesArray.length > 0) { const mid = Math.floor(seriesArray.length / 2) @@ -115,6 +190,9 @@ function createSeries (maxSeriesLength) { } } + /** + * @output {array} returns the entire series + */ function series () { if (seriesArray.length > 0) { return seriesArray @@ -123,11 +201,17 @@ function createSeries (maxSeriesLength) { } } + /** + * Resets the series to its initial state + */ function reset () { - seriesArray.splice(0, seriesArray.length) + seriesArray = /** @type {Array} */(/** @type {unknown} */(null)) + seriesArray = [] seriesSum = 0 numPos = 0 numNeg = 0 + min = undefined + max = undefined } return { @@ -140,10 +224,10 @@ function createSeries (maxSeriesLength) { numberOfValuesEqualOrBelow, sum, average, + minimum, + maximum, median, series, reset } } - -export { createSeries } diff --git a/app/engine/utils/Series.test.js b/app/engine/utils/Series.test.js index 8df93334a7..1d9962c3ec 100644 --- a/app/engine/utils/Series.test.js +++ b/app/engine/utils/Series.test.js @@ -1,9 +1,10 @@ '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 + Open Rowing Monitor, https://github.com/JaapvanEkris/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' @@ -21,6 +22,8 @@ test('Series behaviour with an empty series', () => { testSum(dataSeries, 0) testAverage(dataSeries, 0) testMedian(dataSeries, 0) + testMinimum(dataSeries, 0) + testMaximum(dataSeries, 0) }) test('Series behaviour with a single pushed value. Series = [9]', () => { @@ -36,6 +39,8 @@ test('Series behaviour with a single pushed value. Series = [9]', () => { testSum(dataSeries, 9) testAverage(dataSeries, 9) testMedian(dataSeries, 9) + testMinimum(dataSeries, 9) + testMaximum(dataSeries, 9) }) test('Series behaviour with a second pushed value. Series = [9, 3]', () => { @@ -52,6 +57,8 @@ test('Series behaviour with a second pushed value. Series = [9, 3]', () => { testSum(dataSeries, 12) testAverage(dataSeries, 6) testMedian(dataSeries, 6) + testMinimum(dataSeries, 3) + testMaximum(dataSeries, 9) }) test('Series behaviour with a third pushed value. Series = [9, 3, 6]', () => { @@ -69,6 +76,8 @@ test('Series behaviour with a third pushed value. Series = [9, 3, 6]', () => { testSum(dataSeries, 18) testAverage(dataSeries, 6) testMedian(dataSeries, 6) + testMinimum(dataSeries, 3) + testMaximum(dataSeries, 9) }) test('Series behaviour with a fourth pushed value. Series = [3, 6, 12]', () => { @@ -87,6 +96,8 @@ test('Series behaviour with a fourth pushed value. Series = [3, 6, 12]', () => { testSum(dataSeries, 21) testAverage(dataSeries, 7) testMedian(dataSeries, 6) + testMinimum(dataSeries, 3) + testMaximum(dataSeries, 12) }) test('Series behaviour with a fifth pushed value. Series = [6, 12, -3]', () => { @@ -106,6 +117,38 @@ test('Series behaviour with a fifth pushed value. Series = [6, 12, -3]', () => { testSum(dataSeries, 15) testAverage(dataSeries, 5) testMedian(dataSeries, 6) + testMinimum(dataSeries, -3) + testMaximum(dataSeries, 12) +}) + +test('Series behaviour pushing out the min and max value and forcing a recalculate of min/max via the array.', () => { + const dataSeries = createSeries(3) + dataSeries.push(9) + dataSeries.push(3) + dataSeries.push(6) + testMinimum(dataSeries, 3) + testMaximum(dataSeries, 9) + dataSeries.push(6) + testMinimum(dataSeries, 3) + testMaximum(dataSeries, 6) + dataSeries.push(6) + testMinimum(dataSeries, 6) + testMaximum(dataSeries, 6) +}) + +test('Series behaviour pushing out the min and max value, replacing them just in time.', () => { + const dataSeries = createSeries(3) + dataSeries.push(9) + dataSeries.push(3) + dataSeries.push(6) + testMinimum(dataSeries, 3) + testMaximum(dataSeries, 9) + dataSeries.push(12) + testMinimum(dataSeries, 3) + testMaximum(dataSeries, 12) + dataSeries.push(1) + testMinimum(dataSeries, 1) + testMaximum(dataSeries, 12) }) test('Series behaviour with a five pushed values followed by a reset, Series = []', () => { @@ -160,4 +203,12 @@ function testMedian (series, expectedValue) { assert.ok(series.median() === expectedValue, `Expected median to be ${expectedValue}, encountered ${series.median()}`) } +function testMinimum (series, expectedValue) { + assert.ok(series.minimum() === expectedValue, `Expected minimum to be ${expectedValue}, encountered ${series.minimum()}`) +} + +function testMaximum (series, expectedValue) { + assert.ok(series.maximum() === expectedValue, `Expected maximum to be ${expectedValue}, encountered ${series.maximum()}`) +} + test.run() diff --git a/app/engine/utils/StreamFilter.js b/app/engine/utils/StreamFilter.js index f22aea991b..6f77c68664 100644 --- a/app/engine/utils/StreamFilter.js +++ b/app/engine/utils/StreamFilter.js @@ -1,23 +1,31 @@ '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 + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ +/** + * This keeps a series of specified length, which we can ask for an moving median + * + */ +import { createLabelledBinarySearchTree } from './BinarySearchTree.js' -import { createSeries } from './Series.js' - -function createStreamFilter (maxLength, defaultValue) { - const dataPoints = createSeries(maxLength) +export function createStreamFilter (maxLength, defaultValue) { let lastRawDatapoint = defaultValue let cleanDatapoint = defaultValue + let position = 0 + let bst = createLabelledBinarySearchTree() function push (dataPoint) { - lastRawDatapoint = dataPoint - dataPoints.push(dataPoint) - cleanDatapoint = dataPoints.median() + if (dataPoint !== undefined && !isNaN(dataPoint)) { + lastRawDatapoint = dataPoint + if (maxLength > 0) { + position = (position + 1) % maxLength + bst.remove(position) + bst.push(position, dataPoint) + } else { + bst.push(position, dataPoint) + } + cleanDatapoint = bst.median() + } } function raw () { @@ -25,7 +33,7 @@ function createStreamFilter (maxLength, defaultValue) { } function clean () { - if (dataPoints.length() > 0) { + if (bst.size() > 0) { // The series contains sufficient values to be valid return cleanDatapoint } else { @@ -35,11 +43,11 @@ function createStreamFilter (maxLength, defaultValue) { } function reliable () { - return dataPoints.length() > 0 + return bst.size() > 0 } function reset () { - dataPoints.reset() + bst.reset() lastRawDatapoint = defaultValue cleanDatapoint = defaultValue } @@ -52,5 +60,3 @@ function createStreamFilter (maxLength, defaultValue) { reset } } - -export { createStreamFilter } diff --git a/app/engine/utils/StreamFilter.test.js b/app/engine/utils/StreamFilter.test.js index 05c0d4fea4..a5dbc9c8e9 100644 --- a/app/engine/utils/StreamFilter.test.js +++ b/app/engine/utils/StreamFilter.test.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ import { test } from 'uvu' import * as assert from 'uvu/assert' diff --git a/app/engine/utils/WeighedSeries.js b/app/engine/utils/WeighedSeries.js new file mode 100644 index 0000000000..8581597f5b --- /dev/null +++ b/app/engine/utils/WeighedSeries.js @@ -0,0 +1,113 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This creates a series with a maximum number of values + It allows for determining the Average, Median, Number of Positive, number of Negative +*/ + +import { createSeries } from './Series.js' + +export function createWeighedSeries (maxSeriesLength, defaultValue) { + const dataArray = createSeries(maxSeriesLength) + const weightArray = createSeries(maxSeriesLength) + const weightedArray = createSeries(maxSeriesLength) + + function push (value, weight) { + if (value === undefined || isNaN(value) || weight === undefined || isNaN(weight)) { return } + dataArray.push(value) + weightArray.push(weight) + weightedArray.push(value * weight) + } + + function length () { + return dataArray.length() + } + + function atSeriesBegin () { + return dataArray.atSeriesBegin() + } + + function atSeriesEnd () { + return dataArray.atSeriesEnd() + } + + function get (position) { + return dataArray.get(position) + } + + function numberOfValuesAbove (testedValue) { + return dataArray.numberOfValuesAbove(testedValue) + } + + function numberOfValuesEqualOrBelow (testedValue) { + return dataArray.numberOfValuesEqualOrBelow(testedValue) + } + + function sum () { + return dataArray.sum() + } + + function average () { + if (dataArray.length() > 0) { + // The series contains sufficient values to be valid + return dataArray.average() + } else { + // The array isn't sufficiently filled + return defaultValue + } + } + + function weighedAverage () { + if (dataArray.length() > 0 && weightArray.sum() !== 0) { + return (weightedArray.sum() / weightArray.sum()) + } else { + return defaultValue + } + } + + function minimum () { + return dataArray.minimum() + } + + function maximum () { + return dataArray.maximum() + } + + function median () { + return dataArray.median() + } + + function reliable () { + return dataArray.length() > 0 + } + + function series () { + return dataArray.series() + } + + function reset () { + dataArray.reset() + weightArray.reset() + weightedArray.reset() + } + + return { + push, + length, + atSeriesBegin, + atSeriesEnd, + get, + numberOfValuesAbove, + numberOfValuesEqualOrBelow, + sum, + average, + weighedAverage, + minimum, + maximum, + median, + series, + reliable, + reset + } +} diff --git a/app/engine/utils/curveMetrics.js b/app/engine/utils/curveMetrics.js index 4725ae74c7..746a15562c 100644 --- a/app/engine/utils/curveMetrics.js +++ b/app/engine/utils/curveMetrics.js @@ -1,12 +1,12 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor This keeps an array, for all in-stroke metrics */ import { createSeries } from './Series.js' -function createCurveMetrics (precission = 0) { +export 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 @@ -69,5 +69,3 @@ function createCurveMetrics (precission = 0) { reset } } - -export { createCurveMetrics } diff --git a/app/engine/utils/metrics.interface.js b/app/engine/utils/metrics.interface.js new file mode 100644 index 0000000000..b95d8786a6 --- /dev/null +++ b/app/engine/utils/metrics.interface.js @@ -0,0 +1,77 @@ +/** + * @typedef {{isMoving: boolean, + * isDriveStart: boolean, + * isRecoveryStart: boolean, + * isSessionStart: boolean, + * isIntervalStart: boolean, + * isSplitEnd: boolean, + * isPauseStart: boolean, + * isPauseEnd: boolean, + * isSessionStop: boolean + * }} MetricsContext + */ +/** + * @typedef {'justrow'| + * 'time'| + * 'distance'| + * 'calories'| + * 'rest' + * } SessionType + */ +/** + * @typedef {'WaitingForStart'| + * 'Rowing'| + * 'Paused'| + * 'Stopped' + * } SessionState + */ +/** + * @typedef {'WaitingForDrive'| + * 'Drive'| + * 'Recovery'| + * 'Stopped' + * } StrokeState + */ +/** + * @typedef {{ + * metricsContext: MetricsContext, + * sessionStatus: SessionState, + * strokeState: StrokeState, + * timestamp: number, + * cyclePower: number, + * totalLinearDistance: number, + * totalMovingTime: number, + * totalNumberOfStrokes: number, + * driveLastStartTime: number, + * driveLength: number, + * driveDuration: number, + * driveHandleForceCurve: Array, + * driveHandleVelocityCurve: Array, + * driveHandlePowerCurve: Array, + * drivePeakHandleForce: number, + * driveAverageHandleForce: number, + * cycleStrokeRate: number, + * cyclePace: number, + * cycleLinearVelocity: number, + * cycleDistance: number, + * cycleDuration: number, + * cycleProjectedEndTime: number, + * cycleProjectedEndLinearDistance: number + * recoveryDuration: number, + * strokeCalories: number, + * totalCalories: number, + * totalCaloriesPerHour: number, + * totalCaloriesPerMinute: number, + * strokeWork: number, + * dragFactor: number, + * heartrate?: number, + * heartRateBatteryLevel?: number + * splitNumber: number + * }} Metrics + */ +/** + * @typedef {{ + * totalMovingTime: number, + * totalLinearDistance: number + * }} SplitTimeDistanceData + */ diff --git a/app/engine/utils/workoutSegment.js b/app/engine/utils/workoutSegment.js new file mode 100644 index 0000000000..ce62d82665 --- /dev/null +++ b/app/engine/utils/workoutSegment.js @@ -0,0 +1,611 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This Module supports the creation and use of workoutSegment + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Architecture.md#session-interval-and-split-boundaries-in-sessionmanagerjs|the description of the concepts used} + */ +/* eslint-disable max-lines -- This contains a lot of defensive programming, so it is long */ +import { createOLSLinearSeries } from './OLSLinearSeries.js' +import { createSeries } from './Series.js' +import loglevel from 'loglevel' +const log = loglevel.getLogger('RowingEngine') + +export function createWorkoutSegment (config) { + const numOfDataPointsForAveraging = config.numOfPhasesForAveragingScreenData + const distanceOverTime = createOLSLinearSeries(Math.min(4, numOfDataPointsForAveraging)) + const _power = createSeries() + const _linearVelocity = createSeries() + const _strokerate = createSeries() + const _strokedistance = createSeries() + const _caloriesPerHour = createSeries() + const _dragFactor = createSeries() + let _type = 'justrow' + let _startTimestamp + let _startMovingTime = 0 + let _startLinearDistance = 0 + let _startStrokeNumber = 0 + let _startCalories = 0 + let _targetTime = 0 + let _targetDistance = 0 + let _endMovingTime = 0 + let _endLinearDistance = 0 + let _totalNumberIntervals = 0 + let _split = { + type: 'justrow', + targetDistance: 0, + targetTime: 0 + } + + function setStart (baseMetrics) { + resetSegmentMetrics() + _startMovingTime = (baseMetrics.totalMovingTime !== undefined && baseMetrics.totalMovingTime > 0 ? baseMetrics.totalMovingTime : 0) + _startLinearDistance = (baseMetrics.totalLinearDistance !== undefined && baseMetrics.totalLinearDistance > 0 ? baseMetrics.totalLinearDistance : 0) + _startTimestamp = baseMetrics.timestamp + _startCalories = baseMetrics.totalCalories + _startStrokeNumber = baseMetrics.totalNumberOfStrokes + } + + function setStartTimestamp (timestamp) { + _startTimestamp = timestamp + } + + function getStartTimestamp () { + return _startTimestamp + } + + /** + * This function summarizes a group of intervals into a single workout + */ + function summarize (intervals) { + let intervalNumber = 0 + let totalDistance = 0 + let totalTime = 0 + let containsJustRow = false + _totalNumberIntervals = Math.max(intervals.length, 1) + switch (true) { + case (intervals.length === 0): + setEnd({ type: 'justrow' }) + break + case (intervals.length === 1): + setEnd(intervals[0]) + break + case (intervals.length > 1): + while (intervalNumber < intervals.length) { + switch (true) { + case (intervals[intervalNumber].type === 'rest' && intervals[intervalNumber].targetTime > 0): + // As a rest has no impact on the (target) total moving time and distance, there is nothing to do here + break + case (intervals[intervalNumber].type === 'distance' && intervals[intervalNumber].targetDistance > 0): + totalDistance = totalDistance + Number(intervals[intervalNumber].targetDistance) + break + case (intervals[intervalNumber].type === 'time' && intervals[intervalNumber].targetTime > 0): + totalTime = totalTime + Number(intervals[intervalNumber].targetTime) + break + case (intervals[intervalNumber].type === 'justrow'): + containsJustRow = true + break + default: + containsJustRow = true + } + intervalNumber++ + } + switch (true) { + case (containsJustRow): + setEnd({ type: 'justrow' }) + break + case (totalDistance > 0 && totalTime === 0): + setEnd({ type: 'distance', targetDistance: totalDistance }) + break + case (totalTime > 0 && totalDistance === 0): + setEnd({ type: 'time', targetTime: totalTime }) + break + case (totalTime > 0 && totalDistance > 0): + setEnd({ type: 'justrow' }) + break + default: + setEnd({ type: 'justrow' }) + } + break + default: + setEnd({ type: 'justrow' }) + } + } + + /** + * This function sets the segment parameters used + */ + function setEnd (intervalSettings) { + // Set the primairy parameters + switch (true) { + case (intervalSettings.type === 'rest' && Number(intervalSettings.targetTime) > 0): + // A target time is set for a rest interval + _type = 'rest' + _targetTime = Number(intervalSettings.targetTime) + _targetDistance = 0 + _endMovingTime = _startMovingTime + Number(intervalSettings.targetTime) + _endLinearDistance = 0 + log.debug(` Workout parser, recognised ${_type} interval/split, ${_targetTime} seconds`) + break + case (intervalSettings.type === 'rest'): + // An undefined rest interval + _type = 'rest' + _targetTime = 0 + _targetDistance = 0 + _endMovingTime = _startMovingTime + _endLinearDistance = 0 + log.debug(` Workout parser, recognised undetermined ${_type} interval`) + break + case (intervalSettings.type === 'distance' && Number(intervalSettings.targetDistance) > 0): + // A target distance is set + _type = 'distance' + _targetTime = 0 + _targetDistance = Number(intervalSettings.targetDistance) + _endMovingTime = 0 + _endLinearDistance = _startLinearDistance + Number(intervalSettings.targetDistance) + log.debug(` Workout parser, recognised ${_type} interval/split, ${_targetDistance} meters`) + break + case (intervalSettings.type === 'time' && Number(intervalSettings.targetTime) > 0): + // A target time is set + _type = 'time' + _targetTime = Number(intervalSettings.targetTime) + _targetDistance = 0 + _endMovingTime = _startMovingTime + Number(intervalSettings.targetTime) + _endLinearDistance = 0 + log.debug(` Workout parser, recognised ${_type} interval/split, ${_targetTime} seconds`) + break + case (intervalSettings.type === 'justrow'): + _type = 'justrow' + _targetTime = 0 + _targetDistance = 0 + _endMovingTime = 0 + _endLinearDistance = 0 + log.debug(` Workout parser, recognised ${_type} interval/split`) + break + default: + log.error(`Workout parser, unknown interval type '${intervalSettings.type}', defaulting to a 'justrow' interval`) + _type = 'justrow' + _targetTime = 0 + _targetDistance = 0 + _endMovingTime = 0 + _endLinearDistance = 0 + } + + // Set the split parameters + switch (true) { + case (intervalSettings.type === 'rest'): + // A rest interval has no split defined + _split = { + type: 'rest', + targetDistance: 0, + targetTime: _targetTime + } + break + case (!!intervalSettings.split && intervalSettings.split !== undefined && intervalSettings.split.type === 'distance' && Number(intervalSettings.split.targetDistance) > 0): + // A target distance is set + _split = { + type: 'distance', + targetDistance: Number(intervalSettings.split.targetDistance), + targetTime: 0 + } + break + case (!!intervalSettings.split && intervalSettings.split !== undefined && intervalSettings.split.type === 'time' && Number(intervalSettings.split.targetTime) > 0): + // A target time is set + _split = { + type: 'time', + targetDistance: 0, + targetTime: Number(intervalSettings.split.targetTime) + } + break + case (!!intervalSettings.split && intervalSettings.split !== undefined && intervalSettings.split.type === 'justrow'): + _split = { + type: _type, + targetDistance: _targetDistance, + targetTime: _targetTime + } + break + case (!intervalSettings.split): + // Split is left empty, we default to the entire interval + _split = { + type: _type, + targetDistance: _targetDistance, + targetTime: _targetTime + } + break + default: + log.error(`Workout parser, unknown split type '${intervalSettings.split.type}', defaulting to copying interval type`) + _split = { + type: _type, + targetDistance: _targetDistance, + targetTime: _targetTime + } + } + } + + /** + * Updates projectiondata and segment metrics + */ + function push (baseMetrics) { + distanceOverTime.push(baseMetrics.totalMovingTime, baseMetrics.totalLinearDistance) + if (!!baseMetrics.cyclePower && !isNaN(baseMetrics.cyclePower) && baseMetrics.cyclePower > 0) { _power.push(baseMetrics.cyclePower) } + if (!!baseMetrics.cycleLinearVelocity && !isNaN(baseMetrics.cycleLinearVelocity) && baseMetrics.cycleLinearVelocity > 0) { _linearVelocity.push(baseMetrics.cycleLinearVelocity) } + if (!!baseMetrics.cycleStrokeRate && !isNaN(baseMetrics.cycleStrokeRate) && baseMetrics.cycleStrokeRate > 0) { _strokerate.push(baseMetrics.cycleStrokeRate) } + if (!!baseMetrics.cycleDistance && !isNaN(baseMetrics.cycleDistance) && baseMetrics.cycleDistance > 0) { _strokedistance.push(baseMetrics.cycleDistance) } + if (!!baseMetrics.totalCaloriesPerHour && !isNaN(baseMetrics.totalCaloriesPerHour) && baseMetrics.totalCaloriesPerHour > 0) { _caloriesPerHour.push(baseMetrics.totalCaloriesPerHour) } + if (!!baseMetrics.dragFactor && !isNaN(baseMetrics.dragFactor) && baseMetrics.dragFactor > 0) { _dragFactor.push(baseMetrics.dragFactor) } + } + + /** + * @returns {float} the distance from te start of the workoutsegment + */ + function distanceFromStart (baseMetrics) { + if (!isNaN(_startLinearDistance) && _startLinearDistance >= 0 && !isNaN(baseMetrics.totalLinearDistance) && baseMetrics.totalLinearDistance > _startLinearDistance) { + return baseMetrics.totalLinearDistance - _startLinearDistance + } else { + return 0 + } + } + + /** + * @returns {float} the remaining distance to the end of the workoutsegment + */ + function distanceToEnd (baseMetrics) { + if (_type === 'distance' && _endLinearDistance > 0) { + // We have set a distance boundary + return _endLinearDistance - baseMetrics.totalLinearDistance + } else { + return undefined + } + } + + /** + * @returns {float} the moving time since the start of the workoutsegment + */ + function timeSinceStart (baseMetrics) { + if (!isNaN(_startMovingTime) && _startMovingTime >= 0 && !isNaN(baseMetrics.totalMovingTime) && baseMetrics.totalMovingTime > _startMovingTime) { + return baseMetrics.totalMovingTime - _startMovingTime + } else { + return 0 + } + } + + /** + * @returns {float} the projected time to the end of the workoutsegment + */ + function projectedEndTime () { + switch (true) { + case (_type === 'distance' && _endLinearDistance > 0 && distanceOverTime.reliable()): + // We are in a distance based interval, so we need to project + return (distanceOverTime.projectY(_endLinearDistance) - _startMovingTime) + case (_type === 'time' && _endMovingTime > 0): + return _targetTime + default: + return undefined + } + } + + /** + * @returns {float} the projected time to the end of the workoutsegment + */ + function projectedEndDistance () { + switch (true) { + case (_type === 'distance' && _endLinearDistance > 0): + return _targetDistance + case (_type === 'time' && _endMovingTime > 0 && distanceOverTime.reliable()): + // We are in a time based interval, so we need to project + return (distanceOverTime.projectX(_endMovingTime) - _startLinearDistance) + default: + return undefined + } + } + + /** + * @returns {float} the remaining time to the end of the workoutsegment + */ + function timeToEnd (baseMetrics) { + if ((_type === 'time' || _type === 'rest') && _endMovingTime > 0) { + // We are in a time based interval + return _endMovingTime - baseMetrics.totalMovingTime + } else { + return undefined + } + } + + /** + * @returns {float} the total time since start of the workoutsegment + */ + function totalTime (baseMetrics) { + if (!isNaN(_startTimestamp) && _startTimestamp >= 0 && !isNaN(baseMetrics.timestamp) && baseMetrics.timestamp > _startTimestamp) { + return Math.max((baseMetrics.timestamp.getTime() - _startTimestamp.getTime()) / 1000, (baseMetrics.totalMovingTime - _startMovingTime)) + } else { + return 0 + } + } + + /** + * @returns {float} the time spent not moving since start of the workoutsegment + */ + function restTime (baseMetrics) { + if (!isNaN(_startMovingTime) && !isNaN(_startTimestamp) && _startTimestamp >= 0 && !isNaN(baseMetrics.totalMovingTime) && !isNaN(baseMetrics.timestamp) && baseMetrics.timestamp > _startTimestamp) { + return (Math.max(baseMetrics.timestamp.getTime() - _startTimestamp.getTime(), 0) / 1000) - Math.max(baseMetrics.totalMovingTime - _startMovingTime, 0) + } else { + return 0 + } + } + + /** + * @returns {float} the time spent not moving since the start of the workoutsgment + */ + function averageLinearVelocity (baseMetrics) { + if (!isNaN(_startMovingTime) && _startMovingTime >= 0 && !isNaN(_startLinearDistance) && _startLinearDistance >= 0 && !isNaN(baseMetrics.totalMovingTime) && baseMetrics.totalMovingTime > _startMovingTime && !isNaN(baseMetrics.totalLinearDistance) && baseMetrics.totalLinearDistance > _startLinearDistance) { + return (baseMetrics.totalLinearDistance - _startLinearDistance) / (baseMetrics.totalMovingTime - _startMovingTime) + } else { + return _linearVelocity.average() + } + } + + /** + * @param {float} linear velocity + * @returns {float} pace per 500 meters + */ + function linearVelocityToPace (linearVel) { + if (!isNaN(linearVel) && linearVel > 0) { + return (500.0 / linearVel) + } else { + return Infinity + } + } + + /** + * @returns {number} the number of strokes since the start of the segment + */ + function numberOfStrokes (baseMetrics) { + if (!isNaN(_startStrokeNumber) && _startStrokeNumber >= 0 && !isNaN(baseMetrics.totalNumberOfStrokes) && baseMetrics.totalNumberOfStrokes > _startStrokeNumber) { + return baseMetrics.totalNumberOfStrokes - _startStrokeNumber + } else { + return 0 + } + } + + function spentCalories (baseMetrics) { + if (!isNaN(_startCalories) && _startCalories >= 0 && !isNaN(baseMetrics.totalCalories) && baseMetrics.totalCalories > _startCalories) { + return baseMetrics.totalCalories - _startCalories + } else { + return 0 + } + } + + /** + * @returns {boolean} If the boundary of the planned segment has been reached + */ + function isEndReached (baseMetrics) { + if ((_type === 'distance' && _endLinearDistance > 0 && baseMetrics.totalLinearDistance >= _endLinearDistance) || (_type === 'time' && _endMovingTime > 0 && baseMetrics.totalMovingTime >= _endMovingTime)) { + // We have exceeded the boundary + return true + } else { + return false + } + } + + /* + * This function is used to precisely calculate the end of a workout segment after the sessionManager conlcudes it has passed the workoutSegment's boundary + */ + function interpolateEnd (prevMetrics, currMetrics) { + const projectedMetrics = { ...prevMetrics } + projectedMetrics.modified = false + switch (true) { + case (_type === 'distance' && _endLinearDistance > 0 && currMetrics.totalLinearDistance > _endLinearDistance): + // We are in a distance based interval, and overshot the targetDistance + projectedMetrics.totalMovingTime = interpolatedTime(prevMetrics, currMetrics, _endLinearDistance) + projectedMetrics.timestamp = new Date(currMetrics.timestamp.getTime() - ((currMetrics.totalMovingTime - projectedMetrics.totalMovingTime) * 1000)) + projectedMetrics.totalLinearDistance = _endLinearDistance + projectedMetrics.timestamp = currMetrics.timestamp - ((currMetrics.totalMovingTime - projectedMetrics.totalMovingTime) * 1000) + projectedMetrics.modified = true + break + case (_type === 'time' && _endMovingTime > 0 && currMetrics.totalMovingTime > _endMovingTime): + // We are in a time based interval, and overshot the targetTime + projectedMetrics.totalLinearDistance = interpolatedDistance(prevMetrics, currMetrics, _endMovingTime) + projectedMetrics.totalMovingTime = _endMovingTime + projectedMetrics.timestamp = new Date(_startTimestamp.getTime() + (_targetTime * 1000)) + projectedMetrics.modified = true + break + default: + // Nothing to do + } + projectedMetrics.timestamp = new Date(currMetrics.timestamp.getTime() - ((currMetrics.totalMovingTime - projectedMetrics.totalMovingTime) * 1000)) + // Prevent the edge case where we trigger two strokes at milliseconds apart when using the interpolation function + projectedMetrics.metricsContext.isDriveStart = false + projectedMetrics.metricsContext.isRecoveryStart = false + projectedMetrics.metricsContext.isSessionStart = false + projectedMetrics.metricsContext.isIntervalEnd = false + projectedMetrics.metricsContext.isSplitEnd = false + projectedMetrics.metricsContext.isPauseStart = false + projectedMetrics.metricsContext.isPauseEnd = false + projectedMetrics.metricsContext.isSessionStop = false + return projectedMetrics + } + + function interpolatedTime (prevMetrics, currMetrics, targetDistance) { + if (prevMetrics.totalLinearDistance < targetDistance && targetDistance < currMetrics.totalLinearDistance) { + // See https://en.wikipedia.org/wiki/Linear_interpolation + return (prevMetrics.totalMovingTime + ((currMetrics.totalMovingTime - prevMetrics.totalMovingTime) * ((targetDistance - prevMetrics.totalLinearDistance) / (currMetrics.totalLinearDistance - prevMetrics.totalLinearDistance)))) + } else { + return currMetrics.totalMovingTime + } + } + + function interpolatedDistance (prevMetrics, currMetrics, targetTime) { + if (prevMetrics.totalMovingTime < targetTime && targetTime < currMetrics.totalMovingTime) { + // See https://en.wikipedia.org/wiki/Linear_interpolation + return (prevMetrics.totalLinearDistance + ((currMetrics.totalLinearDistance - prevMetrics.totalLinearDistance) * ((targetTime - prevMetrics.totalMovingTime) / (currMetrics.totalMovingTime - prevMetrics.totalMovingTime)))) + } else { + return currMetrics.totalLinearDistance + } + } + + function getSplit () { + return _split + } + + function targetDistance () { + if (_type === 'distance' && _endLinearDistance > 0) { + return _targetDistance + } else { + return undefined + } + } + + function targetTime () { + if (_type === 'time' && _endMovingTime > 0) { + // We have a distance boundary + return _targetTime + } else { + return undefined + } + } + + function type () { + return _type + } + + /** + * This function returns all the workoutSegment metrics for the current workoutSegment + */ + function metrics (baseMetrics) { + return { + type: _type, + ...(_totalNumberIntervals > 0 ? { numberOfIntervals: _totalNumberIntervals } : {}), + numberOfStrokes: numberOfStrokes(baseMetrics), + distance: { + absoluteStart: _startLinearDistance, + fromStart: distanceFromStart(baseMetrics), + target: targetDistance(), + toEnd: distanceToEnd(baseMetrics), + projectedEnd: projectedEndDistance() + }, + movingTime: { + absoluteStart: _startMovingTime, + sinceStart: timeSinceStart(baseMetrics), + target: targetTime(), + toEnd: timeToEnd(baseMetrics), + projectedEnd: projectedEndTime() + }, + timeSpent: { + total: totalTime(baseMetrics), + moving: timeSinceStart(baseMetrics), + rest: restTime(baseMetrics) + }, + linearVelocity: { + average: averageLinearVelocity(baseMetrics), + minimum: _linearVelocity.minimum(), + maximum: _linearVelocity.maximum() + }, + pace: { + average: linearVelocityToPace(averageLinearVelocity(baseMetrics)), + minimum: linearVelocityToPace(_linearVelocity.minimum()), + maximum: linearVelocityToPace(_linearVelocity.maximum()) + }, + power: { + average: _power.average(), + minimum: _power.minimum(), + maximum: _power.maximum() + }, + strokeDistance: { + average: _strokedistance.average(), + minimum: _strokedistance.minimum(), + maximum: _strokedistance.maximum() + }, + strokerate: { + average: _strokerate.average(), + minimum: _strokerate.minimum(), + maximum: _strokerate.maximum() + }, + dragfactor: { + average: _dragFactor.average(), + minimum: _dragFactor.minimum(), + maximum: _dragFactor.maximum() + }, + calories: { + totalSpent: spentCalories(baseMetrics), + averagePerHour: _caloriesPerHour.average() + } + } + } + + /** + * This function returns the remaining split (used for managing unplanned pausesremainder (baseMetrics) + */ + function remainder (baseMetrics) { + switch (_type) { + case ('distance'): + return { + type: _type, + targetDistance: distanceToEnd(baseMetrics) + } + case ('time'): + return { + type: _type, + targetTime: timeToEnd(baseMetrics) + } + default: + return { + type: _type, + targetTime: 0 + } + } + } + + /** + * This internal function resets the metrics of the segment, this is called after setting a new target + */ + function resetSegmentMetrics () { + _linearVelocity.reset() + _strokerate.reset() + _strokedistance.reset() + _caloriesPerHour.reset() + _power.reset() + _dragFactor.reset() + _type = 'justrow' + _startTimestamp = undefined + _startMovingTime = 0 + _startLinearDistance = 0 + _startStrokeNumber = 0 + _startCalories = 0 + _targetTime = 0 + _targetDistance = 0 + _endMovingTime = 0 + _endLinearDistance = 0 + _split = { + type: 'justrow', + targetDistance: 0, + targetTime: 0 + } + } + + /** + * This externally exposed function resets all data from a workoutsegment, including the regressor used for projections + */ + function reset () { + resetSegmentMetrics() + distanceOverTime.reset() + } + + return { + setStart, + setStartTimestamp, + getStartTimestamp, + summarize, + setEnd, + isEndReached, + interpolateEnd, + metrics, + timeSinceStart, + timeToEnd, + type, + push, + getSplit, + remainder, + reset + } +} diff --git a/app/engine/utils/workoutSegment.test.js b/app/engine/utils/workoutSegment.test.js new file mode 100644 index 0000000000..bdc193f89e --- /dev/null +++ b/app/engine/utils/workoutSegment.test.js @@ -0,0 +1,478 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This Module tests the behaviour of the workout segments + */ +import { test } from 'uvu' +import * as assert from 'uvu/assert' + +import { createWorkoutSegment } from './workoutSegment.js' + +const basicConfig = { + numOfPhasesForAveragingScreenData: 4 +} + +test('Test workoutSegment initialisation behaviour without setting an interval', () => { + const startingPoint = { + timestamp: new Date(), + totalMovingTime: 0, + totalLinearDistance: 0, + metricsContext: {} + } + + const testSegment = createWorkoutSegment(basicConfig) + testDistanceFromStart(testSegment, startingPoint, 0) + testTimeSinceStart(testSegment, startingPoint, 0) + testdistanceToEnd(testSegment, startingPoint, undefined) + testTimeToEnd(testSegment, startingPoint, undefined) + testTargetTime(testSegment, startingPoint, undefined) + testTargetDistance(testSegment, startingPoint, undefined) + testIsEndReached(testSegment, startingPoint, false) +}) + +test('Test workoutSegment initialisation behaviour without setting an interval, after 2050 meters', () => { + const startingPoint = { + timestamp: new Date(), + totalMovingTime: 0, + totalLinearDistance: 0, + cyclePower: 0, + cycleLinearVelocity: 0, + cycleStrokeRate: 0, + cycleDistance: 0, + totalCaloriesPerHour: 0, + dragFactor: 0, + metricsContext: {} + } + + const endPoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 490 * 1000), + totalMovingTime: 490, + totalLinearDistance: 2050, + cyclePower: 200, + cycleLinearVelocity: 4.16666, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const testSegment = createWorkoutSegment(basicConfig) + testDistanceFromStart(testSegment, startingPoint, 0) + testTimeSinceStart(testSegment, startingPoint, 0) + testdistanceToEnd(testSegment, startingPoint, undefined) + testTimeToEnd(testSegment, startingPoint, undefined) + testTargetTime(testSegment, startingPoint, undefined) + testTargetDistance(testSegment, startingPoint, undefined) + testIsEndReached(testSegment, startingPoint, false) + testDistanceFromStart(testSegment, endPoint, 2050) + testTimeSinceStart(testSegment, endPoint, 490) + testdistanceToEnd(testSegment, endPoint, undefined) + testTimeToEnd(testSegment, endPoint, undefined) + testIsEndReached(testSegment, endPoint, false) + testSegment.push(endPoint) + testAverageLinearVelocity (testSegment, endPoint, 4.183673469387755) + testMaximumLinearVelocity (testSegment, endPoint, 4.16666) + testMinimumLinearVelocity (testSegment, endPoint, 4.16666) + testAveragePace (testSegment, endPoint, 119.51219512195122) + testMaximumPace (testSegment, endPoint, 120.0001920003072) + testMinimumPace (testSegment, endPoint, 120.0001920003072) + testAveragePower (testSegment, endPoint, 200) + testMaximumPower (testSegment, endPoint, 200) + testMinimumPower (testSegment, endPoint, 200) +}) + +test('Test workoutSegment behaviour with setting a distance interval', () => { + const distanceInterval = { + type: 'distance', + targetDistance: 2025, + targetTime: 0, + split: { + type: 'distance', + targetDistance: 500, + targetTime: 0 + } + } + + const startingPoint = { + timestamp: new Date(), + totalMovingTime: 0, + totalLinearDistance: 0, + cyclePower: 0, + cycleLinearVelocity: 0, + cycleStrokeRate: 0, + cycleDistance: 0, + totalCaloriesPerHour: 0, + dragFactor: 100, + metricsContext: {} + } + + const middlePoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 480 * 1000), + totalMovingTime: 480, + totalLinearDistance: 2000, + cyclePower: 200, + cycleLinearVelocity: 4.16666, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const endPoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 490 * 1000), + totalMovingTime: 490, + totalLinearDistance: 2050, + cyclePower: 200, + cycleLinearVelocity: 4.16666, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const testSegment = createWorkoutSegment(basicConfig) + testSegment.setStart(startingPoint) + testSegment.setEnd(distanceInterval) + testDistanceFromStart(testSegment, startingPoint, 0) + testTimeSinceStart(testSegment, startingPoint, 0) + testdistanceToEnd(testSegment, startingPoint, 2025) + testTimeToEnd(testSegment, startingPoint, undefined) + testIsEndReached(testSegment, startingPoint, false) + testDistanceFromStart(testSegment, middlePoint, 2000) + testTimeSinceStart(testSegment, middlePoint, 480) + testdistanceToEnd(testSegment, middlePoint, 25) + testTimeToEnd(testSegment, middlePoint, undefined) + testIsEndReached(testSegment, middlePoint, false) + testDistanceFromStart(testSegment, endPoint, 2050) + testTimeSinceStart(testSegment, endPoint, 490) + testdistanceToEnd(testSegment, endPoint, -25) + testTimeToEnd(testSegment, endPoint, undefined) + testIsEndReached(testSegment, endPoint, true) + testInterpolation(testSegment, middlePoint, endPoint, 485, 2025) + testSegment.push(middlePoint) + testSegment.push(endPoint) + testAverageLinearVelocity (testSegment, endPoint, 4.183673469387755) + testMaximumLinearVelocity (testSegment, endPoint, 4.16666) + testMinimumLinearVelocity (testSegment, endPoint, 4.16666) + testAveragePace (testSegment, endPoint, 119.51219512195122) + testMaximumPace (testSegment, endPoint, 120.0001920003072) + testMinimumPace (testSegment, endPoint, 120.0001920003072) + testAveragePower (testSegment, endPoint, 200) + testMaximumPower (testSegment, endPoint, 200) + testMinimumPower (testSegment, endPoint, 200) +}) + +test('Test workoutSegment behaviour with setting a time interval', () => { + const distanceInterval = { + type: 'time', + targetDistance: 0, + targetTime: 485, + split: { + type: 'time', + targetDistance: 0, + targetTime: 60 + } + } + + const startingPoint = { + timestamp: new Date(), + totalMovingTime: 0, + totalLinearDistance: 0, + metricsContext: {} + } + + const middlePoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 480 * 1000), + totalMovingTime: 480, + totalLinearDistance: 2000, + cyclePower: 200, + cycleLinearVelocity: 4.16666, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const endPoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 490 * 1000), + totalMovingTime: 490, + totalLinearDistance: 2050, + cyclePower: 200, + cycleLinearVelocity: 4.16666, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const testSegment = createWorkoutSegment(basicConfig) + testSegment.setStart(startingPoint) + testSegment.setEnd(distanceInterval) + testDistanceFromStart(testSegment, startingPoint, 0) + testTimeSinceStart(testSegment, startingPoint, 0) + testdistanceToEnd(testSegment, startingPoint, undefined) + testTimeToEnd(testSegment, startingPoint, 485) + testIsEndReached(testSegment, startingPoint, false) + testDistanceFromStart(testSegment, middlePoint, 2000) + testTimeSinceStart(testSegment, middlePoint, 480) + testdistanceToEnd(testSegment, middlePoint, undefined) + testTimeToEnd(testSegment, middlePoint, 5) + testIsEndReached(testSegment, middlePoint, false) + testDistanceFromStart(testSegment, endPoint, 2050) + testTimeSinceStart(testSegment, endPoint, 490) + testdistanceToEnd(testSegment, endPoint, undefined) + testTimeToEnd(testSegment, endPoint, -5) + testIsEndReached(testSegment, endPoint, true) + testInterpolation(testSegment, middlePoint, endPoint, 485, 2025) + testSegment.push(middlePoint) + testSegment.push(endPoint) + testAverageLinearVelocity (testSegment, middlePoint, 4.166666666666667) + testMaximumLinearVelocity (testSegment, middlePoint, 4.16666) + testMinimumLinearVelocity (testSegment, middlePoint, 4.16666) + testAveragePace (testSegment, middlePoint, 119.99999999999999) + testMaximumPace (testSegment, middlePoint, 120.0001920003072) + testMinimumPace (testSegment, middlePoint, 120.0001920003072) + testAveragePower (testSegment, middlePoint, 200) + testMaximumPower (testSegment, middlePoint, 200) + testMinimumPower (testSegment, middlePoint, 200) +}) + +test('Test split behaviour when setting a distance interval', () => { + const distanceInterval = { + type: 'distance', + targetDistance: 2025, + targetTime: 0, + split: { + type: 'distance', + targetDistance: 500, + targetTime: 0 + } + } + + const startingPoint = { + timestamp: new Date(), + totalMovingTime: 0, + totalLinearDistance: 0, + metricsContext: {} + } + + const middlePoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 118 * 1000), + totalMovingTime: 118, + totalLinearDistance: 490, + cyclePower: 180, + cycleLinearVelocity: 4.1, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const endPoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 122 * 1000), + totalMovingTime: 122, + totalLinearDistance: 510, + cyclePower: 220, + cycleLinearVelocity: 4.3, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const testSegment = createWorkoutSegment(basicConfig) + const testSplit = createWorkoutSegment(basicConfig) + testSegment.setStart(startingPoint) + testSegment.setEnd(distanceInterval) + testSplit.setStart(startingPoint) + testSplit.setEnd(testSegment.getSplit()) + testDistanceFromStart(testSplit, startingPoint, 0) + testTimeSinceStart(testSplit, startingPoint, 0) + testdistanceToEnd(testSplit, startingPoint, 500) + testTimeToEnd(testSplit, startingPoint, undefined) + testIsEndReached(testSplit, startingPoint, false) + testDistanceFromStart(testSplit, middlePoint, 490) + testTimeSinceStart(testSplit, middlePoint, 118) + testdistanceToEnd(testSplit, middlePoint, 10) + testTimeToEnd(testSplit, middlePoint, undefined) + testIsEndReached(testSplit, middlePoint, false) + testDistanceFromStart(testSplit, endPoint, 510) + testTimeSinceStart(testSplit, endPoint, 122) + testdistanceToEnd(testSplit, endPoint, -10) + testTimeToEnd(testSplit, endPoint, undefined) + testIsEndReached(testSplit, endPoint, true) + testInterpolation(testSplit, middlePoint, endPoint, 120, 500) + testSegment.push(middlePoint) + testSegment.push(endPoint) + testAverageLinearVelocity (testSegment, middlePoint, 4.1525423728813555) + testMaximumLinearVelocity (testSegment, middlePoint, 4.3) + testMinimumLinearVelocity (testSegment, middlePoint, 4.1) + testAveragePace (testSegment, middlePoint, 120.40816326530613) + testMaximumPace (testSegment, middlePoint, 116.27906976744187) + testMinimumPace (testSegment, middlePoint, 121.95121951219514) + testAveragePower (testSegment, middlePoint, 200) + testMaximumPower (testSegment, middlePoint, 220) + testMinimumPower (testSegment, middlePoint, 180) +}) + +test('Test split behaviour with setting a time interval', () => { + const distanceInterval = { + type: 'time', + targetDistance: 0, + targetTime: 485, + split: { + type: 'time', + targetDistance: 0, + targetTime: 120 + } + } + + const startingPoint = { + timestamp: new Date(), + totalMovingTime: 0, + totalLinearDistance: 0, + metricsContext: {} + } + + const middlePoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 118 * 1000), + totalMovingTime: 118, + totalLinearDistance: 490, + cyclePower: 200, + cycleLinearVelocity: 4.16666, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const endPoint = { + timestamp: new Date(startingPoint.timestamp.getTime() + 122 * 1000), + totalMovingTime: 122, + totalLinearDistance: 510, + cyclePower: 200, + cycleLinearVelocity: 4.16666, + cycleStrokeRate: 20, + cycleDistance: 10, + totalCaloriesPerHour: 800, + dragFactor: 100, + metricsContext: {} + } + + const testSegment = createWorkoutSegment(basicConfig) + const testSplit = createWorkoutSegment(basicConfig) + testSegment.setStart(startingPoint) + testSegment.setEnd(distanceInterval) + testSplit.setStart(startingPoint) + testSplit.setEnd(testSegment.getSplit()) + testDistanceFromStart(testSplit, startingPoint, 0) + testTimeSinceStart(testSplit, startingPoint, 0) + testdistanceToEnd(testSplit, startingPoint, undefined) + testTimeToEnd(testSplit, startingPoint, 120) + testIsEndReached(testSplit, startingPoint, false) + testDistanceFromStart(testSplit, middlePoint, 490) + testTimeSinceStart(testSplit, middlePoint, 118) + testdistanceToEnd(testSplit, middlePoint, undefined) + testTimeToEnd(testSplit, middlePoint, 2) + testIsEndReached(testSplit, middlePoint, false) + testDistanceFromStart(testSplit, endPoint, 510) + testTimeSinceStart(testSplit, endPoint, 122) + testdistanceToEnd(testSplit, endPoint, undefined) + testTimeToEnd(testSplit, endPoint, -2) + testIsEndReached(testSplit, endPoint, true) + testInterpolation(testSplit, middlePoint, endPoint, 120, 500) + testSegment.push(middlePoint) + testSegment.push(endPoint) + testAverageLinearVelocity (testSegment, middlePoint, 4.1525423728813555) + testMaximumLinearVelocity (testSegment, middlePoint, 4.16666) + testMinimumLinearVelocity (testSegment, middlePoint, 4.16666) + testAveragePace (testSegment, middlePoint, 120.40816326530613) + testMaximumPace (testSegment, middlePoint, 120.0001920003072) + testMinimumPace (testSegment, middlePoint, 120.0001920003072) + testAveragePower (testSegment, middlePoint, 200) + testMaximumPower (testSegment, middlePoint, 200) + testMinimumPower (testSegment, middlePoint, 200) +}) + +// ToDo: Test the project EndTime and project EndDistance functions + +function testDistanceFromStart (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).distance.fromStart === expectedValue, `Expected distance from the start should be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).distance.fromStart}`) +} + +function testTimeSinceStart (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).movingTime.sinceStart === expectedValue, `Expected time since start should be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).movingTime.sinceStart}`) +} + +function testdistanceToEnd (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).distance.toEnd === expectedValue, `Expected distance from the end to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).distance.toEnd}`) +} + +function testTimeToEnd (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).movingTime.toEnd === expectedValue, `Expected time to end to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).movingTime.toEnd}`) +} + +function testIsEndReached (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.isEndReached(testedDatapoint) === expectedValue, `Expected time to end to be ${expectedValue}, encountered ${testedSegment.isEndReached(testedDatapoint)}`) +} + +function testTargetTime (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).movingTime.target === expectedValue, `Expected time to end to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).movingTime.target}`) +} + +function testTargetDistance (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).distance.target === expectedValue, `Expected time to end to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).distance.target}`) +} + +function testInterpolation (testedSegment, dataPointOne, dataPointTwo, ExpectedTime, ExpectedDistance) { + assert.ok(testedSegment.interpolateEnd(dataPointOne, dataPointTwo).totalMovingTime === ExpectedTime, `Expected extrapolated time be ${ExpectedTime}, encountered ${testedSegment.interpolateEnd(dataPointOne, dataPointTwo).totalMovingTime}`) + assert.ok(testedSegment.interpolateEnd(dataPointOne, dataPointTwo).totalLinearDistance === ExpectedDistance, `Expected time to end to be ${ExpectedDistance}, encountered ${testedSegment.interpolateEnd(dataPointOne, dataPointTwo).totalLinearDistance}`) +} + +function testAverageLinearVelocity (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).linearVelocity.average === expectedValue, `Expected average linear velocity to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).linearVelocity.average}`) +} + +function testMaximumLinearVelocity (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).linearVelocity.maximum === expectedValue, `Expected maximum linear velocity to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).linearVelocity.maximum}`) +} + +function testMinimumLinearVelocity (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).linearVelocity.minimum === expectedValue, `Expected minimum linear velocity to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).linearVelocity.minimum}`) +} + +function testAveragePace (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).pace.average === expectedValue, `Expected average pace to end to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).pace.average}`) +} + +function testMaximumPace (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).pace.maximum === expectedValue, `Expected maximum pace to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).pace.maximum}`) +} + +function testMinimumPace (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).pace.minimum === expectedValue, `Expected minimum pace to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).pace.minimum}`) +} + +function testAveragePower (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).power.average === expectedValue, `Expected average power to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).power.average}`) +} + +function testMaximumPower (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).power.maximum === expectedValue, `Expected maximum power to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).power.maximum}`) +} + +function testMinimumPower (testedSegment, testedDatapoint, expectedValue) { + assert.ok(testedSegment.metrics(testedDatapoint).power.minimum === expectedValue, `Expected minimum power to be ${expectedValue}, encountered ${testedSegment.metrics(testedDatapoint).power.minimum}`) +} + +test.run() diff --git a/app/gpio/GpioTimerService.js b/app/gpio/GpioTimerService.js index 368ab7ca73..61dbd29527 100644 --- a/app/gpio/GpioTimerService.js +++ b/app/gpio/GpioTimerService.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Measures the time between impulses on the GPIO pin. Started in a separate thread, since we want the measured time to be as close as @@ -27,7 +27,7 @@ export function createGpioTimerService () { // 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?') + log.debug(`Gpio-service: FAILED to set priority of Gpio-Thread, error ${err}, are root permissions granted?`) } } @@ -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) } diff --git a/app/peripherals/PeripheralConstants.js b/app/peripherals/PeripheralConstants.js new file mode 100644 index 0000000000..a5f9066b74 --- /dev/null +++ b/app/peripherals/PeripheralConstants.js @@ -0,0 +1,22 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * @file Some constants used by the peripherals and especially the PM5 interface + * + * @remark please note: hardware versions exclude a software version, and thus might confuse the client + * See https://www.concept2.com/service/monitors/pm5/firmware for available versions + * For ErgZone, it is crucial to set the manufacturer to the appname to correctly handle our data + */ +export const PeripheralConstants = { + serial: '431099999', + model: 'PM5', + name: 'PM5 431099999', + hardwareRevision: '634', + firmwareRevision: '8200-000372-176.000', + manufacturer: `${process.env.npm_package_name || ''}` +} + +export const bleBroadcastInterval = 1000 +export const bleMinimumKnowDataUpdateInterval = 4000 diff --git a/app/peripherals/PeripheralManager.js b/app/peripherals/PeripheralManager.js new file mode 100644 index 0000000000..97a97eed66 --- /dev/null +++ b/app/peripherals/PeripheralManager.js @@ -0,0 +1,473 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This manager creates the different Bluetooth Low Energy (BLE), ANT+ and MQTT Peripherals and allows + * switching between them + */ +/* eslint-disable max-lines -- This handles quite a lot of peripherals, can't do that with less code */ +import EventEmitter from 'node:events' + +import log from 'loglevel' + +import AntManager from './ant/AntManager.js' +import { BleManager } from './ble/BleManager.js' + +import { createAntHrmPeripheral } from './ant/HrmPeripheral.js' +import { createBleHrmPeripheral } from './ble/HrmPeripheral.js' +import { createCpsPeripheral } from './ble/CpsPeripheral.js' +import { createCscPeripheral } from './ble/CscPeripheral.js' +import { createFEPeripheral } from './ant/FEPeripheral.js' +import { createFtmsPeripheral } from './ble/FtmsPeripheral.js' +import { createMQTTPeripheral } from './mqtt/mqtt.js' +import { createPm5Peripheral } from './ble/Pm5Peripheral.js' + +/** + * @type {Array} + */ +const bleModes = ['FTMS', 'FTMSBIKE', 'PM5', 'CSC', 'CPS', 'OFF'] +/** + * @type {Array} + */ +const antModes = ['FE', 'OFF'] +/** + * @type {Array} + */ +const hrmModes = ['ANT', 'BLE', 'OFF'] + +/** + * @param {Config} config + */ +export function createPeripheralManager (config) { + /** + * @type {EventEmitter<{heartRateMeasurement: Array>, control: Array}>} + */ + const emitter = new EventEmitter() + const mqttEnabled = (config.mqtt.mqttBroker !== '') && (config.mqtt.username !== '') && (config.mqtt.password !== '') && (config.mqtt.machineName !== '') + /** + * @type {AntManager} + */ + let _antManager + /** + * @type {BleManager} + */ + let _bleManager + + /** + * @type {ReturnType | undefined} + */ + let blePeripheral + /** + * @type {BluetoothModes} + */ + let bleMode + + /** + * @type {ReturnType | undefined} + */ + let antPeripheral + /** + * @type {AntPlusModes} + */ + let antMode + + /** + * @type {ReturnType | undefined} + */ + let mqttPeripheral + if (mqttEnabled) { + mqttPeripheral = createMQTTPeripheral(config) + + mqttPeripheral.on('control', (req) => { + emitter.emit('control', req) + }) + } + + /** + * @type {ReturnType | ReturnType | undefined} + */ + let hrmPeripheral + /** + * @type {HeartRateModes} + */ + let hrmMode + /** + * @type {NodeJS.Timeout} + */ + let hrmWatchdogTimer + /** + * @type {Omit & {heartRateBatteryLevel?: number }} + */ + let lastHrmData = { + heartrate: undefined, + heartRateBatteryLevel: undefined, + rrIntervals: [] + } + + let isPeripheralChangeInProgress = false + + setupPeripherals() + + async function setupPeripherals () { + // The order is important, starting with the BLEs causes EBUSY error on the HCI socket on switching. I was not able to find the cause - its probably the order within the async initialization of the BleManager, but cannot find a proper fix + await createAntPeripheral(config.antPlusMode) + await createHrmPeripheral(config.heartRateMode) + await createBlePeripheral(config.bluetoothMode) + } + + /** + * This function handles all incomming commands. As all commands are broadasted to all managers, we need to filter here what is relevant + * for the peripherals and what is not + * + * @param {Command} Name of the command to be executed by the commandhandler + * @param {unknown} data for executing the command + * + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Architecture.md#command-flow|The command flow documentation} + */ + /* eslint-disable-next-line no-unused-vars -- data is irrelevant here, but it is a standardised interface */ + async function handleCommand (commandName, data) { + switch (commandName) { + case ('updateIntervalSettings'): + break + case ('start'): + break + case ('startOrResume'): + notifyStatus({ name: 'startedOrResumedByUser' }) + break + case ('pause'): + notifyStatus({ name: 'stoppedOrPausedByUser' }) + break + case ('stop'): + notifyStatus({ name: 'stoppedOrPausedByUser' }) + break + case ('reset'): + notifyStatus({ name: 'reset' }) + break + case 'switchBlePeripheralMode': + switchBlePeripheralMode() + break + case 'switchAntPeripheralMode': + switchAntPeripheralMode() + break + case 'switchHrmMode': + switchHrmMode() + break + case 'refreshPeripheralConfig': + break + case 'upload': + break + case 'shutdown': + await shutdownAllPeripherals() + break + default: + log.error(`PeripheralManager: Received unknown command: ${commandName}`) + } + } + + /** + * @param {BluetoothModes} [newMode] + */ + async function switchBlePeripheralMode (newMode) { + if (isPeripheralChangeInProgress) { return } + isPeripheralChangeInProgress = true + // if no mode was passed, select the next one from the list + if (newMode === undefined) { + newMode = bleModes[(bleModes.indexOf(bleMode) + 1) % bleModes.length] + } + config.bluetoothMode = newMode + await createBlePeripheral(newMode) + isPeripheralChangeInProgress = false + } + + /** + * @param {Metrics} metrics + */ + function notifyMetrics (metrics) { + addHeartRateToMetrics(metrics) + if (bleMode !== 'OFF') { blePeripheral?.notifyData(metrics) } + if (antMode !== 'OFF') { antPeripheral?.notifyData(metrics) } + if (mqttEnabled) { mqttPeripheral?.notifyData(metrics) } + } + + /** + * @param {{name: string}} status + */ + function notifyStatus (status) { + if (bleMode !== 'OFF') { blePeripheral?.notifyStatus(status) } + if (antMode !== 'OFF') { antPeripheral?.notifyStatus(status) } + } + + /** + * @param {BluetoothModes} newMode + */ + async function createBlePeripheral (newMode) { + try { + if (_bleManager === undefined && newMode !== 'OFF') { + _bleManager = new BleManager() + } + } catch (error) { + log.error('BleManager creation error: ', error) + return + } + + if (blePeripheral) { + await blePeripheral?.destroy() + blePeripheral = undefined + } + + switch (newMode) { + case 'PM5': + log.info('bluetooth profile: Concept2 PM5') + blePeripheral = createPm5Peripheral(_bleManager, config, controlCallback) + bleMode = 'PM5' + break + case 'FTMSBIKE': + log.info('bluetooth profile: FTMS Indoor Bike') + blePeripheral = createFtmsPeripheral(_bleManager, controlCallback, config, true) + bleMode = 'FTMSBIKE' + break + case 'CSC': + log.info('bluetooth profile: Cycling Speed and Cadence') + blePeripheral = createCscPeripheral(_bleManager, config) + bleMode = 'CSC' + break + case 'CPS': + log.info('bluetooth profile: Cycling Power Meter') + blePeripheral = createCpsPeripheral(_bleManager, config) + bleMode = 'CPS' + break + case 'FTMS': + log.info('bluetooth profile: FTMS Rower') + blePeripheral = createFtmsPeripheral(_bleManager, controlCallback, config, false) + bleMode = 'FTMS' + break + default: + log.info('bluetooth profile: Off') + bleMode = 'OFF' + try { + if (_bleManager && hrmMode !== 'BLE') { + _bleManager.close() + } + } catch (error) { + log.error(error) + return + } + } + + emitter.emit('control', { + req: { + name: 'refreshPeripheralConfig', + data: {} + } + }) + } + + /** + * @param {AntPlusModes} [newMode] + */ + async function switchAntPeripheralMode (newMode) { + if (isPeripheralChangeInProgress) { return } + isPeripheralChangeInProgress = true + if (newMode === undefined) { + newMode = antModes[(antModes.indexOf(antMode) + 1) % antModes.length] + } + config.antPlusMode = newMode + await createAntPeripheral(newMode) + isPeripheralChangeInProgress = false + } + + /** + * @param {AntPlusModes} newMode + */ + async function createAntPeripheral (newMode) { + if (antPeripheral) { + await antPeripheral?.destroy() + antPeripheral = undefined + } + + switch (newMode) { + case 'FE': + log.info('ant plus profile: FE') + if (_antManager === undefined) { + _antManager = new AntManager() + } + + try { + antPeripheral = createFEPeripheral(_antManager) + antMode = 'FE' + await antPeripheral.attach() + } catch (error) { + log.error(error) + return + } + break + + default: + log.info('ant plus profile: Off') + antMode = 'OFF' + try { + if (_antManager && hrmMode !== 'ANT') { await _antManager.closeAntStick() } + } catch (error) { + log.error(error) + return + } + } + + emitter.emit('control', { + req: { + name: 'refreshPeripheralConfig', + data: {} + } + }) + } + + /** + * @param {HeartRateModes} [newMode] + */ + async function switchHrmMode (newMode) { + if (isPeripheralChangeInProgress) { return } + isPeripheralChangeInProgress = true + if (newMode === undefined) { + newMode = hrmModes[(hrmModes.indexOf(hrmMode) + 1) % hrmModes.length] + } + config.heartRateMode = newMode + await createHrmPeripheral(newMode) + isPeripheralChangeInProgress = false + } + + /** + * @param {HeartRateModes} newMode + */ + async function createHrmPeripheral (newMode) { + if (hrmPeripheral) { + await hrmPeripheral?.destroy() + hrmPeripheral?.removeAllListeners() + hrmPeripheral = undefined + try { + if (_antManager && newMode !== 'ANT' && antMode === 'OFF') { await _antManager.closeAntStick() } + if (_bleManager && newMode !== 'BLE' && bleMode === 'OFF') { _bleManager.close() } + } catch (error) { + log.error(error) + return + } + } + + switch (newMode) { + case 'ANT': + log.info('heart rate profile: ANT') + if (_antManager === undefined) { + _antManager = new AntManager() + } + + try { + hrmPeripheral = createAntHrmPeripheral(_antManager) + hrmMode = 'ANT' + await hrmPeripheral.attach() + } catch (error) { + log.error(error) + return + } + break + + case 'BLE': + log.info('heart rate profile: BLE') + try { + if (_bleManager === undefined) { + _bleManager = new BleManager() + } + } catch (error) { + log.error('BleManager creation error: ', error) + return + } + hrmPeripheral = createBleHrmPeripheral(_bleManager) + hrmMode = 'BLE' + await hrmPeripheral.attach() + break + + default: + log.info('heart rate profile: Off') + hrmMode = 'OFF' + } + + if (hrmPeripheral && hrmMode.toLocaleLowerCase() !== 'OFF'.toLocaleLowerCase()) { + hrmPeripheral.on('heartRateMeasurement', (heartRateMeasurement) => { + // Clear the HRM watchdog as new HRM data has been received + clearTimeout(hrmWatchdogTimer) + // Make sure we check the HRM validity here, so the rest of the app doesn't have to + if (heartRateMeasurement.heartrate !== undefined && config.userSettings.restingHR <= heartRateMeasurement.heartrate && heartRateMeasurement.heartrate <= config.userSettings.maxHR) { + lastHrmData = { ...heartRateMeasurement, heartRateBatteryLevel: heartRateMeasurement.batteryLevel } + emitter.emit('heartRateMeasurement', heartRateMeasurement) + } else { + log.info(`PeripheralManager: Heartrate value of ${heartRateMeasurement.heartrate} was outside valid range, setting it to undefined`) + heartRateMeasurement.heartrate = undefined + heartRateMeasurement.batteryLevel = undefined + emitter.emit('heartRateMeasurement', heartRateMeasurement) + } + // Re-arm the HRM watchdog to guarantee failsafe behaviour: after 6 seconds of no new HRM data, it will be invalidated + hrmWatchdogTimer = setTimeout(onHRMWatchdogTimeout, 6000) + }) + } + + emitter.emit('control', { + req: { + name: 'refreshPeripheralConfig', + data: {} + } + }) + } + + function onHRMWatchdogTimeout () { + lastHrmData.heartrate = undefined + lastHrmData.heartRateBatteryLevel = undefined + log.info('PeripheralManager: Heartrate data has not been updated in 6 seconds, setting it to undefined') + emitter.emit('heartRateMeasurement', lastHrmData) + } + + /** + * @param {Metrics} metrics + */ + function addHeartRateToMetrics (metrics) { + if (lastHrmData.heartrate !== undefined) { + metrics.heartrate = lastHrmData.heartrate + } else { + metrics.heartrate = undefined + } + // So far battery level is not used by any of the peripherals adding it for completeness sake + if (lastHrmData.heartRateBatteryLevel !== undefined) { + metrics.heartRateBatteryLevel = lastHrmData.heartRateBatteryLevel + } else { + metrics.heartRateBatteryLevel = undefined + } + } + + /** + * @param {ControlPointEvent} event + */ + function controlCallback (event) { + emitter.emit('control', event) + + return true + } + + async function shutdownAllPeripherals () { + log.debug('shutting down all peripherals') + + try { + await blePeripheral?.destroy() + await antPeripheral?.destroy() + await hrmPeripheral?.destroy() + await _antManager?.closeAntStick() + _bleManager?.close() + if (mqttEnabled) { await mqttPeripheral?.destroy() } + } catch (error) { + log.error('peripheral shutdown was unsuccessful, restart of Pi may required', error) + } + } + + return Object.assign(emitter, { + handleCommand, + notifyMetrics, + notifyStatus + }) +} diff --git a/app/peripherals/ant/AntManager.js b/app/peripherals/ant/AntManager.js new file mode 100644 index 0000000000..9bc479e00c --- /dev/null +++ b/app/peripherals/ant/AntManager.js @@ -0,0 +1,45 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This manager creates a module to listen to ANT+ devices. + * This currently can be used to get the heart rate from ANT+ heart rate sensors. + * + * For this to work, you need an ANT+ USB stick, the following models might work: + * - Garmin USB or USB2 ANT+ or an off-brand clone of it (ID 0x1008) + * - Garmin mini ANT+ (ID 0x1009) + */ +import log from 'loglevel' + +import { AntDevice } from 'incyclist-ant-plus/lib/ant-device.js' + +export default class AntManager { + _isStickOpen = false + _stick = new AntDevice({ startupTimeout: 2000 }) + + async openAntStick () { + if (this._isStickOpen) { return } + if (!(await this._stick.open())) { throw (new Error('Error opening Ant Stick')) } + + log.info('ANT+ stick found') + this._isStickOpen = true + } + + 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 () { + return this._isStickOpen + } + + getAntStick () { + return this._stick + } +} diff --git a/app/peripherals/ant/FEPeripheral.js b/app/peripherals/ant/FEPeripheral.js new file mode 100644 index 0000000000..24975b61fb --- /dev/null +++ b/app/peripherals/ant/FEPeripheral.js @@ -0,0 +1,290 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Creates a ANT+ Peripheral with all the datapages that are required for an indoor rower + */ +import log from 'loglevel' + +import { PeripheralConstants } from '../PeripheralConstants.js' + +import { Messages } from 'incyclist-ant-plus' + +/** + * @param {import('./AntManager').default} antManager + */ +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 accumulatedTime = 0 + let accumulatedDistance = 0 + let accumulatedStrokes = 0 + /** + * @type {NodeJS.Timeout} + */ + let timer + + let sessionData = { + accumulatedStrokes: 0, + accumulatedDistance: 0, + accumulatedTime: 0, + accumulatedPower: 0, + cycleLinearVelocity: 0, + strokeRate: 0, + instantaneousPower: 0, + distancePerStroke: 0, + fitnessEquipmentState: fitnessEquipmentStates.ready, + sessionState: '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 = setTimeout(onBroadcastInterval, broadcastInterval) + } + + function destroy () { + return new Promise((/** @type {(value: void) => void} */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 /** @type {Array} */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.sessionState === 'Rowing') { + 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) + 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.sessionState === 'Rowing') { + 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) + 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.sessionState === 'Rowing') { + 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 + } + + const message = Messages.broadcastData(data) + antStick.write(message) + timer = setTimeout(onBroadcastInterval, broadcastInterval) + } + + /** + * @remark Be aware: time, distance and strokes must always count upwards as small changes trigger a rollover at the watch side. So we must force this + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/discussions/100|this bugreport} + * @param {Metrics} data + */ + function notifyData (data) { + accumulatedTime = Math.max(data.workout.timeSpent, sessionData.accumulatedTime) + accumulatedDistance = Math.max(data.workout.distance.fromStart, accumulatedDistance) + accumulatedStrokes = Math.max(data.workout.numberOfStrokes, accumulatedStrokes) + sessionData = { + ...sessionData, + accumulatedTime: (accumulatedTime > 0 ? Math.round(accumulatedTime * 4) : 0) & 0xFF, + accumulatedDistance: (accumulatedDistance > 0 ? Math.round(accumulatedDistance) : 0) & 0xFF, + accumulatedStrokes: (accumulatedStrokes > 0 ? Math.round(accumulatedStrokes) : 0) & 0xFF, + cycleLinearVelocity: (data.metricsContext.isMoving && data.cycleLinearVelocity > 0 ? Math.round(data.cycleLinearVelocity * 1000) : 0), + strokeRate: (data.metricsContext.isMoving && data.cycleStrokeRate > 0 ? Math.round(data.cycleStrokeRate) : 0) & 0xFF, + instantaneousPower: (data.metricsContext.isMoving && data.cyclePower > 0 ? Math.round(data.cyclePower) : 0) & 0xFFFF, + distancePerStroke: (data.metricsContext.isMoving && data.cycleDistance > 0 ? Math.round(data.cycleDistance * 100) : 0), + sessionState: data.sessionState + } + + /** + * @See {@link https://c2usa.fogbugz.com/default.asp?W119| states description} + * - when machine is on and radio active, but have not yet begun a session -> status set to "ready", speed, etc. are all 0 (as forced by above requirement for data.metricsContext.isMoving) + * - first stroke -> status = 3 (in use) + * - end of wokrout -> status = 4 (finished) + * - Pause: go to 4 (finished, if data.metricsContext.isMoving = false); back to inUse if rowing starts coming back. + * every time move from "ready" to "inUse" it will create a new piece on the watch. + */ + // ToDo: if cross split; raise LAP Toggle + switch (true) { + case (data.sessionState === 'Rowing'): + sessionData.fitnessEquipmentState = fitnessEquipmentStates.inUse + break + case (data.sessionState === 'Stopped'): + sessionData.fitnessEquipmentState = fitnessEquipmentStates.finished + break + case (data.sessionState === 'Paused'): + sessionData.fitnessEquipmentState = fitnessEquipmentStates.finished + break + case (data.sessionState === 'WaitingForStart'): + sessionData.fitnessEquipmentState = fitnessEquipmentStates.ready + break + default: + sessionData.fitnessEquipmentState = fitnessEquipmentStates.ready + } + } + + /** + * FE does not have status characteristic, but is notified of a reset, which should be handled + * @param {{name: string}} status + */ + function notifyStatus (status) { + switch (status?.name) { + case ('reset'): + reset() + break + default: + // Do nothing + } + } + + function reset () { + dataPageCount = 0 + commonPageCount = 0 + accumulatedTime = 0 + accumulatedDistance = 0 + accumulatedStrokes = 0 + sessionData = { + accumulatedStrokes: 0, + accumulatedDistance: 0, + accumulatedTime: 0, + accumulatedPower: 0, + cycleLinearVelocity: 0, + strokeRate: 0, + instantaneousPower: 0, + distancePerStroke: 0, + fitnessEquipmentState: fitnessEquipmentStates.ready, + sessionState: 'WaitingForStart' + } + } + + 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/peripherals/ant/HrmPeripheral.js b/app/peripherals/ant/HrmPeripheral.js new file mode 100644 index 0000000000..43e21a1a65 --- /dev/null +++ b/app/peripherals/ant/HrmPeripheral.js @@ -0,0 +1,121 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Creates a ANT+ peripheral to recieve heartrate data from a HRM belt +*/ +import EventEmitter from 'node:events' +import log from 'loglevel' + +import { HeartRateSensor } from 'incyclist-ant-plus' + +/** + * @event createAntHrmPeripheral#heartRateMeasurement + * @type {HeartRateMeasurementEvent} + */ +/** + * @typedef {import('incyclist-ant-plus').IChannel} IChannel + */ + +/** + * @param {import('./AntManager.js').default} antManager + * @fires createAntHrmPeripheral#heartRateMeasurement + */ +function createAntHrmPeripheral (antManager) { + /** + * @type {EventEmitter<{heartRateMeasurement: Array}>} + */ + const emitter = new EventEmitter() + const antStick = antManager.getAntStick() + const heartRateSensor = new HeartRateSensor(0) + let lastBeatCount = 0 + let lastBeatTime = 0 + + /** + * The RR interval in seconds + * @type {Array} + */ + let rrIntervals = [] + /** + * @type {number | undefined} + */ + let batteryLevel + /** @type {IChannel & EventEmitter | undefined} */ + let channel + + async function attach () { + if (!antManager.isStickOpen()) { await antManager.openAntStick() } + channel = /** @type {IChannel & EventEmitter} */(antStick.getChannel()) + + channel.on('data', (profile, deviceID, /** @type {import('incyclist-ant-plus').HeartRateSensorState} */data) => { + 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 = undefined + } + + if (data.BatteryLevel && data.BatteryLevel > 0) { + batteryLevel = data.BatteryLevel + } + + if (data.BeatCount !== lastBeatCount) { + /** + * @type {number | undefined} + */ + let beatTimeDiff + if (data.PreviousBeat !== undefined) { + // Logic using previousBeatTime and also saving last beat time is seemingly redundant, but the specs prescribes that firstly the previousBeatTime should be used and only if that is not available should be the difference between two successive message be used when the beat count difference is one. + beatTimeDiff = data.PreviousBeat > data.BeatTime ? 65535 - (data.PreviousBeat - data.BeatTime) : data.BeatTime - data.PreviousBeat + } else if (data.BeatCount - lastBeatCount === 1) { + beatTimeDiff = lastBeatTime > data.BeatTime ? 65535 - (lastBeatTime - data.BeatTime) : data.BeatTime - lastBeatTime + } + + rrIntervals = beatTimeDiff !== undefined ? [Math.round(beatTimeDiff / 1024 * 1000) / 1000] : [] + + lastBeatCount = data.BeatCount + lastBeatTime = data.BeatTime + } + + emitter.emit('heartRateMeasurement', { + heartrate: data.ComputedHeartRate, + rrIntervals, + batteryLevel, + manufacturerId: data.ManId, + serialNumber: data.SerialNumber + }) + }) + + if (!(await channel.startSensor(heartRateSensor))) { + log.error('Could not start ANT+ heart rate sensor') + } + } + + async function destroy () { + if (!channel) { + log.debug('Ant Sensor does not seem to be running') + return + } + await channel.stopSensor(heartRateSensor) + } + + return Object.assign(emitter, { + destroy, + attach + }) +} + +export { createAntHrmPeripheral } diff --git a/app/peripherals/ble/BleManager.js b/app/peripherals/ble/BleManager.js new file mode 100644 index 0000000000..9d255c5152 --- /dev/null +++ b/app/peripherals/ble/BleManager.js @@ -0,0 +1,148 @@ +import loglevel from 'loglevel' + +import HciSocket from 'hci-socket' +import NodeBleHost from 'ble-host' + +/** + * @typedef {import('./ble-host.interface.js').BleManager} BleHostManager + */ + +const log = loglevel.getLogger('Peripherals') + +export class BleManager { + /** + * @type {HciSocket | undefined} + */ + #transport + /** + * @type {BleHostManager | undefined} + */ + #manager + /** + * @type {Promise | undefined} + */ + #managerOpeningTask + + open () { + if (this.#manager !== undefined) { + return Promise.resolve(this.#manager) + } + + if (this.#managerOpeningTask === undefined) { + this.#managerOpeningTask = new Promise((resolve, reject) => { + if (this.#manager) { + resolve(this.#manager) + } + log.debug('Opening BLE manager') + + if (this.#transport === undefined) { + this.#transport = new HciSocket() + } + + NodeBleHost.BleManager.create(this.#transport, {}, (/** @type {Error | null} */err, /** @type {BleHostManager} */manager) => { + if (err) { reject(err) } + this.#manager = manager + this.#managerOpeningTask = undefined + resolve(manager) + }) + }) + } + + return this.#managerOpeningTask + } + + close () { + try { + this.#transport?.close() + } catch (e) { + if (e.message !== 'Transport closed') { + log.error('Error while closing Ble socket') + + throw e + } + + log.debug('Ble socket is closed') + this.#transport = undefined + this.#manager = undefined + } + } + + isOpen () { + return this.#manager !== undefined + } + + getManager () { + return this.open() + } +} + +/** + * Convert a 16-bit C2 PM5 UUID to a BLE standard 128-bit UUID. + * @param {string} uuid + * @returns + */ +export const toBLEStandard128BitUUID = (uuid) => { + return `0000${uuid}-0000-1000-8000-00805F9B34FB` +} + +export class GattNotifyCharacteristic { + get characteristic () { + return this.#characteristic + } + + get isSubscribed () { + return this.#isSubscribed + } + + #characteristic + #isSubscribed = false + + /** + * @type {import('./ble-host.interface.js').Connection | undefined} + */ + #connection + + /** + * @param {GattServerCharacteristicFactory} characteristic + */ + constructor (characteristic) { + this.#characteristic = { + ...characteristic, + onSubscriptionChange: (/** @type {import('./ble-host.interface.js').Connection} */connection, /** @type {boolean} */ notification) => { + log.debug(`${this.#characteristic.name} subscription change: ${connection.peerAddress}, notification: ${notification}`) + this.#isSubscribed = notification + this.#connection = notification ? connection : undefined + } + } + } + + /** + * @param {Buffer | string} buffer + */ + notify (buffer) { + if (this.#characteristic.notify === undefined) { + throw new Error(`Characteristics ${this.#characteristic.name} has not been initialized`) + } + + if (!this.#isSubscribed || this.#connection === undefined) { + return + } + + this.#characteristic.notify(this.#connection, buffer) + } +} + +export class GattService { + get gattService () { + return this.#gattService + } + + #gattService + + /** + * @param {GattServerServiceFactory} gattService + */ + constructor (gattService) { + this.#gattService = gattService + } +} diff --git a/app/ble/BufferBuilder.js b/app/peripherals/ble/BufferBuilder.js similarity index 83% rename from app/ble/BufferBuilder.js rename to app/peripherals/ble/BufferBuilder.js index 5aebc7f32c..bba12177bb 100644 --- a/app/ble/BufferBuilder.js +++ b/app/peripherals/ble/BufferBuilder.js @@ -1,16 +1,22 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor A buffer builder that simplifies the creation of payloads for BLE messages */ import log from 'loglevel' -export default class BufferBuilder { +export class BufferBuilder { constructor () { + /** + * @type {Array} + */ this._dataArray = [] } + /** + * @param {number} value + */ writeUInt8 (value) { const buffer = Buffer.alloc(1) try { @@ -21,6 +27,9 @@ export default class BufferBuilder { this._dataArray.push(buffer) } + /** + * @param {number} value + */ writeUInt16LE (value) { const buffer = Buffer.alloc(2) try { @@ -31,6 +40,9 @@ export default class BufferBuilder { this._dataArray.push(buffer) } + /** + * @param {number} value + */ writeUInt24LE (value) { const _value = value || 0 const buffer = Buffer.alloc(3) @@ -47,6 +59,9 @@ export default class BufferBuilder { this._dataArray.push(buffer) } + /** + * @param {number} value + */ writeUInt32LE (value) { const _value = value || 0 const buffer = Buffer.alloc(4) diff --git a/app/ble/BufferBuilder.test.js b/app/peripherals/ble/BufferBuilder.test.js similarity index 92% rename from app/ble/BufferBuilder.test.js rename to app/peripherals/ble/BufferBuilder.test.js index 72d7f133c5..1f5d0a3eaa 100644 --- a/app/ble/BufferBuilder.test.js +++ b/app/peripherals/ble/BufferBuilder.test.js @@ -1,11 +1,13 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ -import { test } from 'uvu' import * as assert from 'uvu/assert' -import BufferBuilder from './BufferBuilder.js' import log from 'loglevel' +import { test } from 'uvu' + +import { BufferBuilder } from './BufferBuilder.js' + log.setLevel(log.levels.SILENT) test('valid max UInts should produce correct buffer', () => { @@ -52,6 +54,7 @@ test('negative writeUInt32LE should produce 4 bit buffer of 0x0', () => { test('invalid datatype value UInt16LE should produce 2 bit buffer of 0x0', () => { const buffer = new BufferBuilder() + // @ts-ignore buffer.writeUInt16LE(new Map()) assert.equal(buffer.getBuffer(), Buffer.from([0x0, 0x0])) }) diff --git a/app/peripherals/ble/CpsPeripheral.js b/app/peripherals/ble/CpsPeripheral.js new file mode 100644 index 0000000000..e5b1904b7c --- /dev/null +++ b/app/peripherals/ble/CpsPeripheral.js @@ -0,0 +1,166 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are required for + * a Cycling Power Profile + */ +import NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +import { bleBroadcastInterval, bleMinimumKnowDataUpdateInterval } from '../PeripheralConstants.js' + +import { CyclingPowerService } from './cps/CyclingPowerMeterService.js' +import { DeviceInformationService } from './common/DeviceInformationService.js' + +/** + * @typedef {import('./ble-host.interface.js').Connection} Connection + * @typedef {import('./ble-host.interface.js').BleManager} BleManager + */ + +const log = loglevel.getLogger('Peripherals') + +/** + * + * @param {import('./BleManager.js').BleManager} bleManager + * @param {Config} config + * @returns + */ +export function createCpsPeripheral (bleManager, config) { + const cyclingPowerService = new CyclingPowerService((event) => { + log.debug('CPS Control Point', event) + return false + }) + /** + * @type {Metrics} + */ + let lastKnownMetrics = { + // This reference is to satisfy type checking while simplifying the initialization of lastKnownMetrics (i.e. allow partial initialization but have the type system consider it as a full Metrics type) + .../** @type {Metrics} */({}), + totalMovingTime: 0, + totalLinearDistance: 0, + dragFactor: config.rowerSettings.dragFactor + } + let timer = setTimeout(onBroadcastInterval, bleBroadcastInterval) + + const deviceInformationService = new DeviceInformationService() + const cpsAppearance = 1156 + const advDataBuffer = new NodeBleHost.AdvertisingDataBuilder() + .addFlags(['leGeneralDiscoverableMode', 'brEdrNotSupported']) + .addLocalName(/* isComplete */ false, `${config.ftmsRowerPeripheralName}`) + .addAppearance(cpsAppearance) + .add16BitServiceUUIDs(/* isComplete */ false, [cyclingPowerService.gattService.uuid]) + .build() + const scanResponseBuffer = new NodeBleHost.AdvertisingDataBuilder() + .addLocalName(/* isComplete */ true, `${config.ftmsRowerPeripheralName} (CPS)`) + .build() + + /** + * @type {BleManager | undefined} + */ + let _manager + /** + * @type {Connection | undefined} + */ + let _connection + + setup() + + async function setup () { + _manager = await bleManager.getManager() + _manager.gattDb.setDeviceName(`${config.ftmsRowerPeripheralName} (CPS)`) + _manager.gattDb.addServices([cyclingPowerService.gattService, deviceInformationService.gattService]) + _manager.setAdvertisingData(advDataBuffer) + _manager.setScanResponseData(scanResponseBuffer) + + await triggerAdvertising() + } + + async function triggerAdvertising () { + _connection = await new Promise((/** @type {(value: Connection) => void} */resolve) => { + /** @type {BleManager} */(_manager).startAdvertising({/* options */}, (_status, connection) => { + resolve(connection) + }) + }) + log.debug(`CPS Connection established, address: ${_connection.peerAddress}`) + + _connection.once('disconnect', async () => { + log.debug(`CPS client disconnected (address: ${_connection?.peerAddress}), restarting advertising`) + _connection = undefined + await triggerAdvertising() + }) // restart advertising after disconnect + } + + // Broadcast the last known metrics + function onBroadcastInterval () { + cyclingPowerService.notifyData(lastKnownMetrics) + timer = setTimeout(onBroadcastInterval, bleBroadcastInterval) + } + + /** Records the last known rowing metrics to CPS central + * As the client calculates its own speed based on time and distance, + * we an only update the last known metrics upon a stroke state change to prevent spiky behaviour + * @param {Metrics} metrics + */ + function notifyData (metrics) { + if (metrics.metricsContext === undefined) { return } + switch (true) { + case (metrics.metricsContext.isSessionStop): + lastKnownMetrics = { ...metrics } + clearTimeout(timer) + onBroadcastInterval() + break + case (metrics.metricsContext.isPauseStart): + lastKnownMetrics = { ...metrics } + clearTimeout(timer) + onBroadcastInterval() + break + case (metrics.metricsContext.isRecoveryStart): + lastKnownMetrics = { ...metrics } + clearTimeout(timer) + onBroadcastInterval() + break + case (metrics.timestamp - lastKnownMetrics.timestamp >= bleMinimumKnowDataUpdateInterval): + lastKnownMetrics = { ...metrics } + clearTimeout(timer) + onBroadcastInterval() + break + default: + // Do nothing + } + } + + /** + * CPS does not have status characteristic + * @param {{name: string}} status + */ + /* eslint-disable-next-line no-unused-vars -- standardized characteristic interface where the status parameter isn't relevant */ + function notifyStatus (status) { + } + + function destroy () { + log.debug('Shutting down CPS peripheral') + clearTimeout(timer) + _manager?.gattDb.removeService(cyclingPowerService.gattService) + _manager?.gattDb.removeService(deviceInformationService.gattService) + return new Promise((resolve) => { + if (_connection !== undefined) { + log.debug('Terminating current CPS connection') + _connection.removeAllListeners() + _connection.once('disconnect', resolve) + _connection.disconnect() + + return + } + _manager?.stopAdvertising(resolve) + }) + } + + return { + triggerAdvertising, + notifyData, + notifyStatus, + destroy + } +} diff --git a/app/peripherals/ble/CscPeripheral.js b/app/peripherals/ble/CscPeripheral.js new file mode 100644 index 0000000000..97178a310e --- /dev/null +++ b/app/peripherals/ble/CscPeripheral.js @@ -0,0 +1,164 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are required for + a Cycling Speed and Cadence Profile +*/ +import NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +import { bleBroadcastInterval, bleMinimumKnowDataUpdateInterval } from '../PeripheralConstants.js' + +import { CyclingSpeedCadenceService } from './csc/CyclingSpeedCadenceService.js' +import { DeviceInformationService } from './common/DeviceInformationService.js' + +/** + * @typedef {import('./ble-host.interface.js').Connection} Connection + * @typedef {import('./ble-host.interface.js').BleManager} BleManager + */ + +const log = loglevel.getLogger('Peripherals') + +/** + * @param {import('./BleManager.js').BleManager} bleManager + * @param {Config} config + */ +export function createCscPeripheral (bleManager, config) { + const cyclingSpeedCadenceService = new CyclingSpeedCadenceService((event) => { + log.debug('CSC Control Point', event) + return false + }) + + /** + * @type {Metrics} + */ + let lastKnownMetrics = { + // This reference is to satisfy type checking while simplifying the initialization of lastKnownMetrics (i.e. allow partial initialization but have the type system consider it as a full Metrics type) + .../** @type {Metrics} */({}), + totalMovingTime: 0, + totalLinearDistance: 0, + dragFactor: config.rowerSettings.dragFactor + } + let timer = setTimeout(onBroadcastInterval, bleBroadcastInterval) + + const deviceInformationService = new DeviceInformationService() + const cscAppearance = 1157 // Cycling Speed and Cadence Sensor + const advDataBuffer = new NodeBleHost.AdvertisingDataBuilder() + .addFlags(['leGeneralDiscoverableMode', 'brEdrNotSupported']) + .addLocalName(/* isComplete */ false, `${config.ftmsRowerPeripheralName}`) + .addAppearance(cscAppearance) + .add16BitServiceUUIDs(/* isComplete */ false, [cyclingSpeedCadenceService.gattService.uuid]) + .build() + const scanResponseBuffer = new NodeBleHost.AdvertisingDataBuilder() + .addLocalName(/* isComplete */ true, `${config.ftmsRowerPeripheralName} (CSC)`) + .build() + + /** + * @type {BleManager | undefined} + */ + let _manager + /** + * @type {Connection | undefined} + */ + let _connection + + setup() + + async function setup () { + _manager = await bleManager.getManager() + _manager.gattDb.setDeviceName(`${config.ftmsRowerPeripheralName} (CSC)`) + _manager.gattDb.addServices([cyclingSpeedCadenceService.gattService, deviceInformationService.gattService]) + _manager.setAdvertisingData(advDataBuffer) + _manager.setScanResponseData(scanResponseBuffer) + + await triggerAdvertising() + } + + async function triggerAdvertising () { + _connection = await new Promise((/** @type {(value: Connection) => void} */resolve) => { + /** @type {BleManager} */(_manager).startAdvertising({/* options */}, (_status, connection) => { + resolve(connection) + }) + }) + log.debug(`CSC Connection established, address: ${_connection.peerAddress}`) + + _connection.once('disconnect', async () => { + log.debug(`CSC client disconnected (address: ${_connection?.peerAddress}), restarting advertising`) + _connection = undefined + await triggerAdvertising() + }) // restart advertising after disconnect + } + + // present current rowing metrics to CSC central + function onBroadcastInterval () { + cyclingSpeedCadenceService.notifyData(lastKnownMetrics) + timer = setTimeout(onBroadcastInterval, bleBroadcastInterval) + } + + /** Records the last known rowing metrics to CSC central + * As the client calculates its own speed based on time and distance, + * we an only update the last known metrics upon a stroke state change to prevent spiky behaviour + * @param {Metrics} metrics + */ + function notifyData (metrics) { + if (metrics.metricsContext === undefined) { return } + switch (true) { + case (metrics.metricsContext.isSessionStop): + lastKnownMetrics = { ...metrics } + clearTimeout(timer) + onBroadcastInterval() + break + case (metrics.metricsContext.isPauseStart): + lastKnownMetrics = { ...metrics } + clearTimeout(timer) + onBroadcastInterval() + break + case (metrics.metricsContext.isRecoveryStart): + lastKnownMetrics = { ...metrics } + clearTimeout(timer) + onBroadcastInterval() + break + case (metrics.timestamp - lastKnownMetrics.timestamp >= bleMinimumKnowDataUpdateInterval): + lastKnownMetrics = { ...metrics } + clearTimeout(timer) + onBroadcastInterval() + break + default: + // Do nothing + } + } + + /** + * CSC does not have status characteristic + * @param {{name: string}} status + */ + /* eslint-disable-next-line no-unused-vars -- standardized characteristic interface where the status parameter isn't relevant */ + function notifyStatus (status) { + } + + function destroy () { + log.debug('Shutting down CSC peripheral') + clearTimeout(timer) + _manager?.gattDb.removeService(cyclingSpeedCadenceService.gattService) + _manager?.gattDb.removeService(deviceInformationService.gattService) + return new Promise((resolve) => { + if (_connection !== undefined) { + log.debug('Terminating current CSC connection') + _connection.removeAllListeners() + _connection.once('disconnect', resolve) + _connection.disconnect() + + return + } + _manager?.stopAdvertising(resolve) + }) + } + + return { + triggerAdvertising, + notifyData, + notifyStatus, + destroy + } +} diff --git a/app/peripherals/ble/FtmsPeripheral.js b/app/peripherals/ble/FtmsPeripheral.js new file mode 100644 index 0000000000..9f761a7b5e --- /dev/null +++ b/app/peripherals/ble/FtmsPeripheral.js @@ -0,0 +1,149 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are required for + a Fitness Machine Device + + Relevant parts from https://www.bluetooth.com/specifications/specs/fitness-machine-profile-1-0/ + The Fitness Machine shall instantiate one and only one Fitness Machine Service as Primary Service + The User Data Service, if supported, shall be instantiated as a Primary Service. + The Fitness Machine may instantiate the Device Information Service + (Manufacturer Name String, Model Number String) +*/ +import NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +import { DeviceInformationService } from './common/DeviceInformationService.js' +import { FitnessMachineService } from './ftms/FitnessMachineService.js' + +/** + * @typedef {import('./ble-host.interface.js').BleManager} BleManager + * @typedef {import('./ble-host.interface.js').Connection} Connection + */ + +const log = loglevel.getLogger('Peripherals') + +/** + * @param {import('./BleManager.js').BleManager} bleManager + * @param {ControlPointCallback} controlCallback + * @param {Config} config + * @param {boolean} simulateIndoorBike + */ +export function createFtmsPeripheral (bleManager, controlCallback, config, simulateIndoorBike) { + const peripheralName = simulateIndoorBike ? config.ftmsBikePeripheralName : config.ftmsRowerPeripheralName + const fitnessMachineService = new FitnessMachineService(controlCallback, simulateIndoorBike) + const deviceInformationService = new DeviceInformationService() + + const rowerSupportedDataFlag = simulateIndoorBike ? 0x01 << 5 : 0x01 << 4 + const fitnessMachineAvailable = 0x01 + + const advDataBuffer = new NodeBleHost.AdvertisingDataBuilder() + .addFlags(['leGeneralDiscoverableMode', 'brEdrNotSupported']) + .addLocalName(/* isComplete */ false, peripheralName.slice(0, 15)) + .add16BitServiceUUIDs(/* isComplete */ true, [fitnessMachineService.gattService.uuid]) + .add16BitServiceData(fitnessMachineService.gattService.uuid, Buffer.from([fitnessMachineAvailable, rowerSupportedDataFlag, rowerSupportedDataFlag >> 8])) + .build() + + const scanResponseBuffer = new NodeBleHost.AdvertisingDataBuilder() + .addLocalName(/* isComplete */ true, peripheralName) + .build() + + const broadcastInterval = config.ftmsUpdateInterval + /** + * @type {Metrics} + */ + let lastKnownMetrics = { + // This reference is to satisfy type checking while simplifying the initialization of lastKnownMetrics (i.e. allow partial initialization but have the type system consider it as a full Metrics type) + .../** @type {Metrics} */({}), + totalMovingTime: 0, + totalLinearDistance: 0, + dragFactor: config.rowerSettings.dragFactor + } + + let timer = setTimeout(onBroadcastInterval, broadcastInterval) + + /** + * @type {BleManager | undefined} + */ + let _manager + /** + * @type {Connection | undefined} + */ + let _connection + + setup() + + async function setup () { + _manager = await bleManager.getManager() + _manager.gattDb.setDeviceName(peripheralName) + _manager.gattDb.addServices([fitnessMachineService.gattService, deviceInformationService.gattService]) + _manager.setAdvertisingData(advDataBuffer) + _manager.setScanResponseData(scanResponseBuffer) + + await triggerAdvertising() + } + + async function triggerAdvertising () { + _connection = await new Promise((/** @type {(value: Connection) => void} */resolve) => { + /** @type {BleManager} */(_manager).startAdvertising({/* options */}, (_status, connection) => { + resolve(connection) + }) + }) + log.debug(`FTMS Connection established, address: ${_connection.peerAddress}`) + + await new Promise((resolve) => { /** @type {Connection} */(_connection).gatt.exchangeMtu(resolve) }) + + _connection.once('disconnect', async () => { + log.debug(`FTMS client disconnected (address: ${_connection?.peerAddress}), restarting advertising`) + _connection = undefined + await triggerAdvertising() + }) // restart advertising after disconnect + } + + /** Records the last known rowing metrics to FTMS central + * @param {Metrics} data + */ + function notifyData (data) { + lastKnownMetrics = data + } + + /** + * Present current rowing status to FTMS central + * @param {{name: string}} status + */ + function notifyStatus (status) { + fitnessMachineService.notifyStatus(status) + } + + function destroy () { + log.debug(`Shutting down FTMS ${simulateIndoorBike ? 'Bike' : 'Rower'} peripheral`) + clearTimeout(timer) + _manager?.gattDb.removeService(fitnessMachineService.gattService) + _manager?.gattDb.removeService(deviceInformationService.gattService) + return new Promise((resolve) => { + if (_connection !== undefined) { + log.debug(`Terminating current FTMS ${simulateIndoorBike ? 'Bike' : 'Rower'} connection`) + _connection.removeAllListeners() + _connection.once('disconnect', resolve) + _connection.disconnect() + + return + } + _manager?.stopAdvertising(resolve) + }) + } + + // present current rowing metrics to FTMS central + function onBroadcastInterval () { + fitnessMachineService.notifyData(lastKnownMetrics) + timer = setTimeout(onBroadcastInterval, broadcastInterval) + } + + return { + triggerAdvertising, + notifyData, + notifyStatus, + destroy + } +} diff --git a/app/peripherals/ble/HrmPeripheral.js b/app/peripherals/ble/HrmPeripheral.js new file mode 100644 index 0000000000..508f9c11c0 --- /dev/null +++ b/app/peripherals/ble/HrmPeripheral.js @@ -0,0 +1,42 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import EventEmitter from 'node:events' + +import { HrmService } from './hrm/HrmService.js' + +/** + * @event createBleHrmPeripheral#heartRateMeasurement + * @param {import ('./BleManager.js').BleManager} bleManager + */ +export function createBleHrmPeripheral (bleManager) { + /** + * @type {EventEmitter<{heartRateMeasurement: Array}>} + */ + const emitter = new EventEmitter() + /** + * @type {HrmService | undefined} + */ + let _hrmService + + async function attach () { + _hrmService = new HrmService(await bleManager.getManager()) + + _hrmService.on('heartRateMeasurement', (data) => { + emitter.emit('heartRateMeasurement', data) + }) + + _hrmService.start() + } + + async function destroy () { + _hrmService?.removeAllListeners() + await _hrmService?.stop() + } + + return Object.assign(emitter, { + destroy, + attach + }) +} diff --git a/app/peripherals/ble/Pm5Peripheral.js b/app/peripherals/ble/Pm5Peripheral.js new file mode 100644 index 0000000000..308da8eaf3 --- /dev/null +++ b/app/peripherals/ble/Pm5Peripheral.js @@ -0,0 +1,129 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are used by the + Concept2 PM5 rowing machine. + + see: https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + and https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf +*/ +import NodeBleHost from 'ble-host' +import log from 'loglevel' + +import { pm5Constants, toC2128BitUUID } from './pm5/Pm5Constants.js' +import { Pm5AppearanceService } from './pm5/Pm5AppearanceService.js' +import { Pm5ControlService } from './pm5/control-service/Pm5ControlService.js' +import { Pm5DeviceInformationService } from './pm5/Pm5DeviceInformationService.js' +import { Pm5HeartRateControlService } from './pm5/heart-rate-service/Pm5HeartRateControlService.js' +import { Pm5RowingService } from './pm5/rowing-service/Pm5RowingService.js' +import { DeviceInformationService } from './common/DeviceInformationService.js' + +/** + * @typedef {import('./ble-host.interface.js').BleManager} BleManager + * @typedef {import('./ble-host.interface.js').Connection} Connection + */ + +/** + * @param {import ('./BleManager.js').BleManager} bleManager + * @param {Config} config + * @param {ControlPointCallback} controlCallback + */ +export function createPm5Peripheral (bleManager, config, controlCallback) { + const deviceInformationService = new Pm5DeviceInformationService() + const appearanceService = new Pm5AppearanceService() + const controlService = new Pm5ControlService(controlCallback) + const rowingService = new Pm5RowingService(config) + const heartRateControlService = new Pm5HeartRateControlService() + const gattServices = [appearanceService.gattService, controlService.gattService, deviceInformationService.gattService, rowingService.gattService, heartRateControlService.gattService, new DeviceInformationService().gattService] + + const advDataBuffer = new NodeBleHost.AdvertisingDataBuilder() + .addFlags(['leGeneralDiscoverableMode', 'brEdrNotSupported']) + .addLocalName(/* isComplete */ true, `${pm5Constants.name} Row`) + .build() + const scanResponseBuffer = new NodeBleHost.AdvertisingDataBuilder() + .add128BitServiceUUIDs(/* isComplete */ true, [toC2128BitUUID('0000')]) + .build() + + /** + * @type {BleManager | undefined} + */ + let _manager + /** + * @type {Connection | undefined} + */ + let _connection + + setup() + + async function setup () { + _manager = await bleManager.getManager() + _manager.gattDb.setDeviceName(pm5Constants.name) + _manager.gattDb.addServices(gattServices) + _manager.setAdvertisingData(advDataBuffer) + _manager.setScanResponseData(scanResponseBuffer) + + await triggerAdvertising() + } + + async function triggerAdvertising () { + _connection = await new Promise((/** @type {(value: Connection) => void} */resolve) => { + /** @type {BleManager} */(_manager).startAdvertising({/* options */}, (_status, connection) => { + resolve(connection) + }) + }) + log.debug(`PM5 Connection established, address: ${_connection.peerAddress}`) + + await new Promise((resolve) => { /** @type {Connection} */(_connection).gatt.exchangeMtu(resolve) }) + + _connection.once('disconnect', async () => { + log.debug(`PM5 client disconnected (address: ${_connection?.peerAddress}), restarting advertising`) + _connection = undefined + await triggerAdvertising() + }) // restart advertising after disconnect + } + + /** + * Records the last known rowing metrics to FTMS central + * @param {Metrics} data + */ + function notifyData (data) { + rowingService.notifyData(data) + } + + /** + * Present current rowing status to C2-PM5 central + * @param {{name: string}} status + */ + /* eslint-disable-next-line no-unused-vars -- standardized characteristic interface where the data parameter isn't relevant */ + function notifyStatus (status) { + } + + function destroy () { + log.debug('Shutting down PM5 peripheral') + + if (_manager !== undefined) { + gattServices.forEach((service) => { + /** @type {BleManager} */(_manager).gattDb.removeService(service) + }) + } + return new Promise((resolve) => { + if (_connection !== undefined) { + log.debug('Terminating current PM5 connection') + _connection.removeAllListeners() + _connection.once('disconnect', resolve) + _connection.disconnect() + + return + } + _manager?.stopAdvertising(resolve) + }) + } + + return { + triggerAdvertising, + notifyData, + notifyStatus, + destroy + } +} diff --git a/app/peripherals/ble/ble-host.interface.js b/app/peripherals/ble/ble-host.interface.js new file mode 100644 index 0000000000..7292251062 --- /dev/null +++ b/app/peripherals/ble/ble-host.interface.js @@ -0,0 +1,658 @@ +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/* eslint-disable no-unused-vars */ +import { EventEmitter } from 'node:stream' + +/** + * - not-permitted (Characteristic cannot be read) + * - open (Can always be read) + * - encrypted (Can only be read when the link is encrypted) + * - encrypted-mitm (Can only be read when the link is encrypted with a key that was generated with MITM protection) + * - encrypted-mitm-sc (Can only be read when the link is encrypted with a key that was generated with MITM protection and Secure Connections pairing) + * - custom (A user-provided method will called upon each read to determine if the read should be permitted) + * @typedef {'not-permitted'|'open'|'encrypted'|'encrypted-mitm'|'encrypted-mitm-sc'|'custom'}CharacteristicPermission + */ + +/** + * BLE Manager for handling Bluetooth Low Energy operations. + */ +export class BleManager { + /** + * @type {GattServerDb} + */ + // @ts-ignore + gattDb + /** + * Creates a BleManager instance. + * @param {import('node:events').EventEmitter} transport - The transport object for HCI packets. + * @param {object} options - Optional parameters. + * @param {string} options.staticRandomAddress - Optional static random address. + * @param {Function} callback - Callback function with error and manager instance. + */ + static create (transport, options, callback) { + callback(null, new BleManager()) + } + + /** + * Starts a scan for BLE devices. + * @param {object} parameters - Scan parameters. + * @param {boolean} [parameters.activeScan=true] - Request scan response data. + * @param {number} [parameters.scanWindow=16] - Scan window in 0.625 ms units. + * @param {number} [parameters.scanInterval=16] - Scan interval in 0.625 ms units. + * @param {boolean} [parameters.filterDuplicates=false] - Filter duplicate advertisements. + * @param {Array} [parameters.scanFilters] - Array of scan filters. + * @returns {Scanner} The scanner instance. + */ + startScan (parameters) { + return new Scanner() + } + + /** + * Connects to a BLE device. + * @param {string} bdAddrType - Address type: "public" or "random". + * @param {string} bdAddr - Bluetooth Device Address. + * @param {object} parameters - Connection parameters. + * @param {number} [parameters.connIntervalMin=20] - Minimum connection interval. + * @param {number} [parameters.connIntervalMax=25] - Maximum connection interval. + * @param {number} [parameters.connLatency=0] - Slave latency. + * @param {number} [parameters.supervisionTimeout=500] - Supervision timeout. + * @param {(connection: Connection) => void} callback - Callback with the connection object. + * @returns {PendingConnection} A pending connection object. + */ + connect (bdAddrType, bdAddr, parameters, callback) { + return new PendingConnection() + } + + /** + * Removes a bonding between the local controller and a peer device. + * @param {string} identityAddressType - Identity address type ("public" or "random"). + * @param {string} identityAddress - The identity address. + */ + removeBond (identityAddressType, identityAddress) {} + + /** + * Sets advertising data. + * @param {Buffer} data - Buffer containing max 31 bytes of advertising data. + * @param {Function} [callback] - Callback with HCI status code. + */ + setAdvertisingData (data, callback) {} + + /** + * Sets scan response data. + * @param {Buffer} data - Buffer containing max 31 bytes of scan response data. + * @param {Function} [callback] - Callback with HCI status code. + */ + setScanResponseData (data, callback) {} + + /** + * Starts advertising. + * @param {object} parameters - Advertising parameters. + * @param {number} [parameters.intervalMin=62.5] - Minimum advertising interval. + * @param {number} [parameters.intervalMax=62.5] - Maximum advertising interval. + * @param {string} [parameters.advertisingType="ADV_IND"] - Advertising type. + * @param {object} [parameters.directedAddress] - Directed address object. + * @param {(status: number, connection: Connection) => void} callback - Callback function. + */ + startAdvertising (parameters, callback) {} + + /** + * Stops advertising. + * @param {Function} [callback] - Callback with HCI status code. + */ + stopAdvertising (callback) {} +} + +/** + * Scanner for BLE device discovery. + * @fires Scanner#report + */ +export class Scanner extends EventEmitter { + /** + * Stops the scan. + */ + stopScan () {} +} + +/** + * Event emitted when a report is received during the scan. + * @type {object} + * @property {boolean} connectable - Whether the device is connectable (i.e. it did not send ADV_NONCONN_IND). + * @property {string} addressType - Address type, either 'public' or 'random'. + * @property {string} address - The Bluetooth address of the device. + * @property {number} rssi - The RSSI (Received Signal Strength Indicator) in dBm. (-127 to 20, 127 means not available). + * @property {Array} rawDataItems - Raw advertising data items. + * @property {number} type - Type of advertisement. + * @property {Buffer} data - Raw advertisement data. + * @property {object} parsedDataItems - Parsed advertising data items (only included fields will be present). + * @property {object} flags - Flags object for advertisement. + * @property {boolean} leLimitedDiscoverableMode - Whether the device supports LE limited discoverable mode. + * @property {boolean} leGeneralDiscoverableMode - Whether the device supports LE general discoverable mode. + * @property {boolean} brEdrNotSupported - Whether the device does not support BR/EDR. + * @property {boolean} simultaneousLeAndBdEdrToSameDeviceCapableController - Whether the controller supports simultaneous LE and BR/EDR to the same device. + * @property {boolean} simultaneousLeAndBrEdrToSameDeviceCapableHost - Whether the host supports simultaneous LE and BR/EDR to the same device. + * @property {Buffer} raw - Raw advertisement data. + * @property {Array} serviceUuids - Array of UUIDs of the services advertised. + * @property {string} localName - The local name of the device (shortened form ends with '...'). + * @property {number} txPowerLevel - Transmit power level in dBm. + * @property {object} slaveConnectionIntervalRange - Connection interval range object for slave devices. + * @property {number} slaveConnectionIntervalRange.min - Minimum connection interval in 1.25ms units. + * @property {number} slaveConnectionIntervalRange.max - Maximum connection interval in 1.25ms units. + * @property {Array} serviceSolicitations - Array of UUIDs for service solicitations. + * @property {Array} serviceData - Service data array. + * @property {string} serviceData.uuid - The UUID of the service data. + * @property {Buffer} serviceData.data - The service data buffer. + * @property {number} appearance - The 16-bit appearance value of the device. + * @property {Array} publicTargetAddresses - Array of public target addresses. + * @property {Array} randomTargetAddresses - Array of random target addresses. + * @property {number} advertisingInterval - The advertising interval in 0.625ms units. + * @property {string} uri - URI data (if available). + * @property {object} leSupportedFeatures - Supported features for the device. + * @property {number} leSupportedFeatures.low - The lower 32 bits of the supported features. + * @property {number} leSupportedFeatures.high - The higher 32 bits of the supported features. + * @property {Array} manufacturerSpecificData - Manufacturer-specific data. + * @property {number} manufacturerSpecificData.companyIdentifierCode - Company identifier code. + * @property {Buffer} manufacturerSpecificData.data - Manufacturer-specific data buffer. + * @event Scanner#report + */ + +/** + * Pending connection object. + */ +export class PendingConnection { + /** + * Cancels a pending connection. + * @param {Function} callback - Callback function if cancel succeeds. + */ + cancel (callback) {} +} + +/** + * BLE Connection object. + */ +export class Connection extends EventEmitter { + /** + * @type {string} + * Local address type ("public" or "random"). + */ + // @ts-ignore + ownAddressType + + /** + * @type {string} + * Local address. + */ + // @ts-ignore + ownAddress + + /** + * @type {string} + * Peer device address type. + */ + // @ts-ignore + peerAddressType + + /** + * @type {string} + * Peer device address. + */ + // @ts-ignore + peerAddress + + /** + * @type {GattConnection} + */ + // @ts-ignore + gatt + + /** + * Disconnects the connection. + * @param {number} [reason] - HCI error code. + */ + disconnect (reason) {} + + /** + * Reads RSSI value. + * @param {Function} callback - Callback function with status and RSSI value. + */ + readRssi (callback) {} +} + +/** + * Scan filter object. + * @typedef {object} ScanFilter + * @property {string} uuid - UUID of the filter. + */ + +/** + * Represents a GATT Server Database that manages services, characteristics, and descriptors. + */ +export class GattServerDb { + /** + * Sets the device name in the Device Name characteristic. + * @param {Buffer | string} name - The new device name to store (max 248 bytes). + */ + setDeviceName (name) { } + + /** + * Sets the Appearance characteristic. + * @param {number} appearance - The 16-bit unsigned integer representing the appearance. + */ + setAppearance (appearance) { } + + /** + * Returns the Service Changed Characteristic from the GATT service. + * @returns {GattServerCharacteristic} The Service Changed Characteristic. + */ + getSvccCharacteristic () { + return new GattServerCharacteristic() + } + + /** + * Adds one or more services to the GATT database. + * @param {Array>} services - Array of services to add. + */ + addServices (services) { } + + /** + * Removes a service from the GATT database. + * @param {Partial} service - The service to remove. + * @returns {boolean} True if the service was removed, false otherwise. + */ + removeService (service) { + return true + } +} + +/** + * Represents a GATT Service. + * @typedef {object} GattServerService + * @property {string | number} uuid - The UUID of the service. + * @property {boolean} [isSecondaryService=false] - Whether the service is secondary. + * @property {Array} [includedServices=[]] - Array of included services. + * @property {number} [startHandle] - Proposed start handle for the service. + * @property {number} endHandle - Actual end handle after service is added. + * @property {Array>} [characteristics=[]] - Array of characteristics for this service. + */ + +/** + * Represents a GATT Server Descriptor. + * @typedef {object} GattServerDescriptor + * @property {string | number} uuid - The UUID of the descriptor. + * @property {number} [maxLength] - Maximum length of the descriptor value. + * @property {string} [readPerm] - Read permission for the descriptor. + * @property {string} [writePerm] - Write permission for the descriptor. + * @property {Buffer | string} value - The value of the descriptor. + * @property {Function} [onAuthorizeRead] - Custom authorization for read operations. + * @property {Function} [onRead] - Custom read handler for the descriptor. + * @property {Function} [onPartialRead] - Custom partial read handler for the descriptor. + * @property {Function} [onAuthorizeWrite] - Custom authorization for write operations. + * @property {Function} [onWrite] - Custom write handler for the descriptor. + * @property {Function} [onPartialWrite] - Custom partial write handler for the descriptor. + */ + +/** + * GATT Server Characteristic Class + */ +export class GattServerCharacteristic { + /** + * The declared properties for this characteristic. + * @type {object} + */ + // @ts-ignore + properties + + /** + * The declaration handle of the characteristic. + * @type {number} + */ + // @ts-ignore + declarationHandle + + /** + * The value handle of the characteristic. + * @type {Buffer} + */ + // @ts-ignore + value + /** + * The UUID of the characteristic. + * @type {string | number} + */ + // @ts-ignore + uuid + /** + * MAx MTU size. + * @type {number} + */ + // @ts-ignore + maxLength = 512 + /** + * Defines the permission needed to read the characteristic. + * @type {CharacteristicPermission} + */ + // @ts-ignore + readPerm = 'open' + /** + * Defines the permission needed to write the characteristic. + * @type {CharacteristicPermission} + */ + // @ts-ignore + writePerm = 'open' + /** + * @type {Array} + */ + descriptors = [] + + /** + * Notify the connection of a value update. + * @param {Connection} connection - The BLE connection. + * @param {Buffer | string} value - The value to notify. + * @param {Function} [sentCallback] - A callback when the packet is sent. + * @param {Function} [completeCallback] - A callback when the packet is fully acknowledged. + * @returns {boolean} Whether the client was subscribed or not. + */ + notify (connection, value, sentCallback, completeCallback) { + return true + } + + /** + * Indicate to the connection with a value update. + * @param {Connection} connection - The BLE connection. + * @param {Buffer | string} value - The value to indicate. + * @param {(errorCode: number, value: Buffer | string) => void} [callback] - Callback that will be called when confirmation arrives. + * @returns {boolean} Whether the client was subscribed or not. + */ + indicate (connection, value, callback) { + return true + } + + /** + * Handler for when the subscription to notifications or indications changes. + * @param {Connection} connection - The BLE connection. + * @param {boolean} notification - Whether the client has subscribed to notifications. + * @param {boolean} indication - Whether the client has subscribed to indications. + * @param {boolean} isWrite - Whether the change is due to a write to the CCCD. + */ + onSubscriptionChange (connection, notification, indication, isWrite) { } + + /** + * @param {Connection} connection - The BLE connection that requests the read + * @param {(errorCode: number, value: Buffer | string) => void} callback - Callback that should be called with the result + */ + onRead (connection, callback) {} + + /** + * This optional method will be called when a write needs to be done + * @param {Connection} connection + * @param {boolean} needsResponse + * @param {Buffer} value + * @param {(errorCode: number, value?: Buffer | string) => void} callback + */ + onWrite (connection, needsResponse, value, callback) {} +} + +/** + * Represents a GATT Client connection for interacting with remote GATT servers. + */ +export class GattConnection { + /** + * Performs an MTU exchange request to negotiate the MTU size. + * @param {Function} [callback] - The callback function to be invoked after the operation. + * The first argument passed to the callback will be an `AttErrors` code or 0 on success. + * @throws {Error} Will throw if MTU exchange is attempted more than once on the same connection. + */ + exchangeMtu (callback) { } + + /** + * Performs the Discover All Primary Services procedure. + * The services will be cached and persisted if bonded. + * If cached, the callback will be invoked immediately. + * @param {(services: Array) => void} callback - The callback function that receives an array of `GattClientService` objects. + */ + discoverAllPrimaryServices (callback) { } + + /** + * Performs the Discover Primary Service By UUID procedure. + * The services array will contain only services with the specified UUID. + * @param {string | number} uuid - The UUID of the service to find. + * @param {number} [numToFind] - Optional limit to the number of services to discover. + * @param {Function} [callback] - The callback function that receives an array of `GattClientService` objects. + */ + discoverServicesByUuid (uuid, numToFind, callback) { } + + /** + * Invalidates the services from the service cache within a specified handle range. + * @param {number} startHandle - The starting handle of the invalidated range. + * @param {number} endHandle - The ending handle of the invalidated range. + * @param {Function} [callback] - Callback to be called when the invalidation is complete. + */ + invalidateServices (startHandle, endHandle, callback) { } + + /** + * Reads characteristics using their UUID within a specified handle range. + * @param {number} startHandle - The starting handle of the search. + * @param {number} endHandle - The ending handle of the search. + * @param {string | number} uuid - The UUID of the characteristic. + * @param {Function} callback - Callback function that receives the `AttErrors` code and results. + */ + readUsingCharacteristicUuid (startHandle, endHandle, uuid, callback) { } + + /** + * Starts a Reliable Write transaction. All writes after this call will be queued until `commitReliableWrite` is called. + */ + beginReliableWrite () { } + + /** + * Cancels any pending Reliable Write transactions. + * @param {Function} [callback] - Callback to be called when the transaction is canceled. + */ + cancelReliableWrite (callback) { } + + /** + * Commits all pending writes in a Reliable Write transaction. + * @param {Function} [callback] - Callback to be called when the transaction is committed. + */ + commitReliableWrite (callback) { } + + /** + * Retrieves the current MTU for the connection. + * @type {number} + */ + get currentMtu () { return 23 } + + /** + * Event emitted when a GATT request times out (30 seconds after it was sent). + * @event timeout + */ +} + +/** + * Represents a service on a remote GATT server. + * Instances of this class are created during discovery procedures. + */ +export class GattClientService { + /** + * The starting handle of the service. + * @type {number} + */ + // @ts-ignore + startHandle + + /** + * The ending handle of the service. + * @type {number} + */ + // @ts-ignore + endHandle + + /** + * The UUID of the service. + * @type {string} + */ + // @ts-ignore + uuid + + /** + * Finds all included services for this service. + * @param {(characteristics: Array) => void} callback - The callback function that receives an array of `GattClientService` objects. + */ + findIncludedServices (callback) { } + + /** + * Discovers all characteristics of this service. + * @param {(characteristics: Array) => void} callback - The callback function that receives an array of `GattClientCharacteristic` objects. + */ + discoverCharacteristics (callback) { } +} + +/** + * Represents a characteristic present on a remote GATT server. + * Instances of this class are created during characteristic discovery. + */ +export class GattClientCharacteristic extends EventEmitter { + /** + * The declared properties for this characteristic. + * @type {object} + */ + // @ts-ignore + properties + + /** + * The declaration handle of the characteristic. + * @type {number} + */ + // @ts-ignore + declarationHandle + + /** + * The value handle of the characteristic. + * @type {number} + */ + // @ts-ignore + valueHandle + + /** + * The UUID of the characteristic. + * @type {string} + */ + // @ts-ignore + uuid + + /** + * Discovers all descriptors associated with this characteristic. + * @param {Function} callback - The callback function that receives an array of `GattClientDescriptor` objects. + */ + discoverDescriptors (callback) { } + + /** + * Reads the value of this characteristic. + * @param {(errorCode: number, value: Buffer) => void} callback - The callback function that receives an `AttErrors` code and the read value (Buffer). + */ + read (callback) { } + + /** + * Reads the value of this characteristic with a single read request. + * @param {Function} callback - The callback function that receives an `AttErrors` code and the read value (Buffer). + */ + readShort (callback) { } + + /** + * Reads the value of this characteristic starting from a specific offset. + * @param {number} offset - The starting offset. + * @param {Function} callback - The callback function that receives the value (Buffer). + */ + readLong (offset, callback) { } + + /** + * Writes a value to this characteristic. + * @param {Buffer | string} value - The value to write. + * @param {Function} [callback] - The callback function that receives an `AttErrors` code. + */ + write (value, callback) { } + + /** + * Writes a value to this characteristic at a specific offset. + * @param {Buffer | string} value - The value to write. + * @param {number} offset - The starting offset. + * @param {Function} [callback] - The callback function that receives an `AttErrors` code. + */ + writeLong (value, offset, callback) { } + + /** + * Writes a value to this characteristic without expecting a response. + * @param {Buffer | string} value - The value to write. + * @param {Function} [sentCallback] - Callback when the packet has been sent. + * @param {Function} [completeCallback] - Callback when the packet has been acknowledged. + */ + writeWithoutResponse (value, sentCallback, completeCallback) { } + + /** + * Writes the Client Characteristic Configuration Descriptor (CCCD) to enable or disable notifications/indications. + * @param {boolean} enableNotifications - Whether notifications should be enabled. + * @param {boolean} enableIndications - Whether indications should be enabled. + * @param {(err: number) => void} [callback] - The callback function that receives an `AttErrors` code. + */ + writeCCCD (enableNotifications, enableIndications, callback) { } + + /** + * Event emitted when a notification or indication is received for this characteristic. + * @param {Buffer} value - The value of the notification/indication. + * @param {boolean} isIndication - Whether it is an indication (true) or notification (false). + * @param {Function} callback - Callback that must be called if `isIndication` is true. + * @event change + */ +} + +/** + * Represents a descriptor associated with a characteristic on a remote GATT server. + */ +export class GattClientDescriptor { + /** + * The handle of this descriptor. + * @type {number} + */ + // @ts-ignore + handle + + /** + * The UUID of this descriptor. + * @type {string} + */ + // @ts-ignore + uuid + + /** + * Reads the value of this descriptor. + * @param {Function} callback - The callback function that receives an `AttErrors` code and the read value (Buffer). + */ + read (callback) { } + + /** + * Reads the value of this descriptor with a single read request. + * @param {Function} callback - The callback function that receives an `AttErrors` code and the read value (Buffer). + */ + readShort (callback) { } + + /** + * Reads the value of this descriptor starting from a specific offset. + * @param {number} offset - The starting offset. + * @param {Function} callback - The callback function that receives the value (Buffer). + */ + readLong (offset, callback) { } + + /** + * Writes a value to this descriptor. + * @param {Buffer | string} value - The value to write. + * @param {Function} [callback] - The callback function that receives an `AttErrors` code. + */ + write (value, callback) { } + + /** + * Writes a value to this descriptor at a specific offset. + * @param {Buffer | string} value - The value to write. + * @param {number} offset - The starting offset. + * @param {Function} [callback] - The callback function that receives an `AttErrors` code. + */ + writeLong (value, offset, callback) { } +} diff --git a/app/peripherals/ble/common/CommonOpCodes.js b/app/peripherals/ble/common/CommonOpCodes.js new file mode 100644 index 0000000000..01238f1f30 --- /dev/null +++ b/app/peripherals/ble/common/CommonOpCodes.js @@ -0,0 +1,12 @@ +'use-strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +export const ResultOpCode = { + reserved: 0x00, + success: 0x01, + opCodeNotSupported: 0x02, + invalidParameter: 0x03, + operationFailed: 0x04, + controlNotPermitted: 0x05 +} diff --git a/app/peripherals/ble/common/DeviceInformationService.js b/app/peripherals/ble/common/DeviceInformationService.js new file mode 100644 index 0000000000..1570da0575 --- /dev/null +++ b/app/peripherals/ble/common/DeviceInformationService.js @@ -0,0 +1,25 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + todo: Could provide some info on the device here, maybe OS, Node version etc... +*/ +import { PeripheralConstants } from '../../PeripheralConstants.js' + +import { GattService } from '../BleManager.js' +import { createStaticReadCharacteristic } from './StaticReadCharacteristic.js' + +export class DeviceInformationService extends GattService { + constructor () { + super({ + name: 'Device Information Service', + uuid: 0x180A, + characteristics: [ + createStaticReadCharacteristic(0x2A24, PeripheralConstants.model, 'Model Number'), + createStaticReadCharacteristic(0x2A25, PeripheralConstants.serial, 'Serial Number'), + createStaticReadCharacteristic(0x2A28, PeripheralConstants.firmwareRevision, 'Software Revision'), + createStaticReadCharacteristic(0x2A29, PeripheralConstants.manufacturer, 'Manufacturer Name') + ] + }) + } +} diff --git a/app/ble/common/SensorLocation.js b/app/peripherals/ble/common/SensorLocation.js similarity index 79% rename from app/ble/common/SensorLocation.js rename to app/peripherals/ble/common/SensorLocation.js index 9a86a15ed6..4a64280875 100644 --- a/app/ble/common/SensorLocation.js +++ b/app/peripherals/ble/common/SensorLocation.js @@ -1,6 +1,8 @@ 'use strict' - -import BufferBuilder from '../BufferBuilder.js' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import { BufferBuilder } from '../BufferBuilder.js' export const sensorLocations = { diff --git a/app/peripherals/ble/common/StaticReadCharacteristic.js b/app/peripherals/ble/common/StaticReadCharacteristic.js new file mode 100644 index 0000000000..5b0584b339 --- /dev/null +++ b/app/peripherals/ble/common/StaticReadCharacteristic.js @@ -0,0 +1,42 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +const log = loglevel.getLogger('Peripherals') + +/** + * @param {string | number} uuid + * @param {Buffer | string | Array} value + * @param {Buffer | string} [description] + * @param {boolean} [addNotify = false] + * @returns {Partial} + */ +export function createStaticReadCharacteristic (uuid, value, description, addNotify = false) { + const descriptors = description !== undefined ? + [ + { + uuid: 0x2901, + value: description + }] : + undefined + + const onSubscriptionChange = addNotify ? + (connection, notification) => { + log.debug(`${description !== undefined ? description : uuid} subscription change: ${connection.peerAddress}, notification: ${notification}`) + } : + undefined + + return { + uuid, + properties: addNotify ? ['read', 'notify'] : ['read'], + descriptors, + onRead: (connection, callback) => { + log.debug(`Static read characteristic has been called: ${description}`) + callback(NodeBleHost.AttErrors.SUCCESS, Buffer.isBuffer(value) ? value : Buffer.from(value)) + }, + onSubscriptionChange + } +} diff --git a/app/peripherals/ble/common/bluetooth.interfaces.js b/app/peripherals/ble/common/bluetooth.interfaces.js new file mode 100644 index 0000000000..95a43d3a37 --- /dev/null +++ b/app/peripherals/ble/common/bluetooth.interfaces.js @@ -0,0 +1,28 @@ +/** + * @typedef {{ + * req?: { + * name: Command, + * data: unknown + * } + * }} ControlPointEvent + */ +/** + * @typedef {(event: ControlPointEvent) => boolean} ControlPointCallback + */ +/** + * @typedef {Partial & {name: string}} GattServerCharacteristicFactory + */ +/** + * @typedef {Partial & { name: string }} GattServerServiceFactory + */ +/** + * @typedef {{ + * heartrate?: number, + * rrIntervals: Array, + * energyExpended?: number, + * hasContact?: boolean + * batteryLevel?: number, + * manufacturerId?: number | string, + * serialNumber?: number | string + * }} HeartRateMeasurementEvent + */ diff --git a/app/peripherals/ble/cps/CpsControlPointCharacteristic.js b/app/peripherals/ble/cps/CpsControlPointCharacteristic.js new file mode 100644 index 0000000000..caf7b85990 --- /dev/null +++ b/app/peripherals/ble/cps/CpsControlPointCharacteristic.js @@ -0,0 +1,53 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/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 NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +const log = loglevel.getLogger('Peripherals') + +export class CyclingPowerControlPointCharacteristic { + get characteristic () { + return this.#characteristic + } + + /** + * @type {GattServerCharacteristicFactory} + */ + #characteristic + + /** + * @param {ControlPointCallback} controlPointCallback + */ + /* eslint-disable-next-line no-unused-vars -- standardized characteristic interface where the callback parameter isn't relevant */ + constructor (controlPointCallback) { + this.#characteristic = { + name: 'Cycling Power Meter Control Point', + uuid: 0x2A55, + properties: ['write', 'indicate'], + onWrite: (connection, _needsResponse, opCode, callback) => { + log.debug(`CPS control is called: ${opCode}`) + const response = this.#onWriteRequest(opCode) + + if (this.#characteristic.indicate === undefined) { + throw new Error(`Characteristics ${this.#characteristic.name} has not been initialized`) + } + + this.#characteristic.indicate(connection, response) + callback(NodeBleHost.AttErrors.SUCCESS) // actually only needs to be called when needsResponse is true + } + } + } + + // Central sends a command to the Control Point + // No need to handle any request to have this working + /* eslint-disable-next-line no-unused-vars -- standardized characteristic interface where parameters aren't relevant */ + #onWriteRequest (data, offset, withoutResponse, callback) { + return Buffer.from([0]) + } +} diff --git a/app/peripherals/ble/cps/CpsMeasurementCharacteristic.js b/app/peripherals/ble/cps/CpsMeasurementCharacteristic.js new file mode 100644 index 0000000000..bea74aa841 --- /dev/null +++ b/app/peripherals/ble/cps/CpsMeasurementCharacteristic.js @@ -0,0 +1,68 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import { BufferBuilder } from '../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../BleManager.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 class CyclingPowerMeasurementCharacteristic extends GattNotifyCharacteristic { + constructor () { + super({ + name: 'Cycling Power Meter Measurement', + uuid: 0x2A63, + properties: ['notify'], + descriptors: [ + { + uuid: 0x2901, + value: 'Cycling Power Measurement' + } + ] + }) + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + + // Features flag + bufferBuilder.writeUInt16LE(cpsMeasurementFeaturesFlags.wheelRevolutionDataPresent | cpsMeasurementFeaturesFlags.crankRevolutionDataPresent) + + // Instantaneous Power + bufferBuilder.writeUInt16LE(data.cyclePower > 0 ? Math.round(data.cyclePower) : 0) + + // Wheel revolution count (basically the distance in cm) + bufferBuilder.writeUInt32LE(data.totalLinearDistance > 0 ? Math.round(Math.round(data.totalLinearDistance * 100)) : 0) + + // Wheel revolution time (ushort with 2048 resolution, resetting in every 32sec) + bufferBuilder.writeUInt16LE(data.totalMovingTime > 0 ? Math.round(data.totalMovingTime * 2048) % Math.pow(2, 16) : 0) + + // Total stroke count + bufferBuilder.writeUInt16LE(data.totalNumberOfStrokes > 0 ? Math.round(data.totalNumberOfStrokes) : 0) + + // last stroke time time (ushort with 1024 resolution, resetting in every 64sec) + bufferBuilder.writeUInt16LE(data.driveLastStartTime > 0 ? Math.round(data.driveLastStartTime * 1024) % Math.pow(2, 16) : 0) + + super.notify(bufferBuilder.getBuffer()) + } +} diff --git a/app/ble/cps/CyclingPowerMeterService.js b/app/peripherals/ble/cps/CyclingPowerMeterService.js similarity index 64% rename from app/ble/cps/CyclingPowerMeterService.js rename to app/peripherals/ble/cps/CyclingPowerMeterService.js index ac2c811f32..5b9c2721fb 100644 --- a/app/ble/cps/CyclingPowerMeterService.js +++ b/app/peripherals/ble/cps/CyclingPowerMeterService.js @@ -1,35 +1,45 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/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' +import { createStaticReadCharacteristic } from '../common/StaticReadCharacteristic.js' -export default class CyclingPowerService extends bleno.PrimaryService { +import { BufferBuilder } from '../BufferBuilder.js' +import { GattService } from '../BleManager.js' + +import { CyclingPowerControlPointCharacteristic } from './CpsControlPointCharacteristic.js' +import { CyclingPowerMeasurementCharacteristic } from './CpsMeasurementCharacteristic.js' + +export class CyclingPowerService extends GattService { + #measurementCharacteristic + + /** + * @param {ControlPointCallback} controlPointCallback + */ constructor (controlPointCallback) { const cpsFeatureBuffer = new BufferBuilder() cpsFeatureBuffer.writeUInt32LE(featuresFlag) const measurementCharacteristic = new CyclingPowerMeasurementCharacteristic() super({ - // Cycling Power - uuid: '1818', + name: 'Cycling Power', + uuid: 0x1818, characteristics: [ - new StaticReadCharacteristic('2A65', 'Cycling Power Feature', cpsFeatureBuffer.getBuffer()), - measurementCharacteristic, - new StaticReadCharacteristic('2A5D', 'Sensor Location', SensorLocationAsBuffer()), - new CyclingPowerControlPointCharacteristic(controlPointCallback) + createStaticReadCharacteristic(0x2A65, cpsFeatureBuffer.getBuffer(), 'Cycling Power Feature'), + measurementCharacteristic.characteristic, + createStaticReadCharacteristic(0x2A5D, SensorLocationAsBuffer(), 'Sensor Location'), + new CyclingPowerControlPointCharacteristic(controlPointCallback).characteristic ] }) - this.measurementCharacteristic = measurementCharacteristic + this.#measurementCharacteristic = measurementCharacteristic } - notifyData (event) { - this.measurementCharacteristic.notify(event) + /** + * @param {Metrics} data + */ + notifyData (data) { + this.#measurementCharacteristic.notify(data) } } diff --git a/app/peripherals/ble/csc/CscControlPointCharacteristic.js b/app/peripherals/ble/csc/CscControlPointCharacteristic.js new file mode 100644 index 0000000000..31c60e88ce --- /dev/null +++ b/app/peripherals/ble/csc/CscControlPointCharacteristic.js @@ -0,0 +1,53 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/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 NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +const log = loglevel.getLogger('Peripherals') + +export class CyclingSpeedCadenceControlPointCharacteristic { + get characteristic () { + return this.#characteristic + } + + /** + * @type {GattServerCharacteristicFactory} + */ + #characteristic + + /** + * @param {ControlPointCallback} controlPointCallback + */ + /* eslint-disable-next-line no-unused-vars -- standardized characteristic interface where the callback parameter isn't relevant */ + constructor (controlPointCallback) { + this.#characteristic = { + name: 'Cycling Speed and Cadence Control Point', + uuid: 0x2A55, + properties: ['write', 'indicate'], + onWrite: (connection, _needsResponse, opCode, callback) => { + log.debug(`CSC control is called: ${opCode}`) + const response = this.#onWriteRequest(opCode) + + if (this.#characteristic.indicate === undefined) { + throw new Error(`Characteristics ${this.#characteristic.name} has not been initialized`) + } + + this.#characteristic.indicate(connection, response) + callback(NodeBleHost.AttErrors.SUCCESS) // actually only needs to be called when needsResponse is true + } + } + } + + // Central sends a command to the Control Point + // No need to handle any request to have this working + /* eslint-disable-next-line no-unused-vars -- standardized interface where the parameters aren't relevant */ + #onWriteRequest (data, offset, withoutResponse, callback) { + return Buffer.from([0]) + } +} diff --git a/app/peripherals/ble/csc/CscMeasurementCharacteristic.js b/app/peripherals/ble/csc/CscMeasurementCharacteristic.js new file mode 100644 index 0000000000..6d10c34d84 --- /dev/null +++ b/app/peripherals/ble/csc/CscMeasurementCharacteristic.js @@ -0,0 +1,54 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import { BufferBuilder } from '../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../BleManager.js' + +export class CyclingSpeedCadenceMeasurementCharacteristic extends GattNotifyCharacteristic { + constructor () { + super({ + name: 'Cycling Speed and Cadence Measurement', + uuid: 0x2A5B, + properties: ['notify'], + descriptors: [ + { + uuid: 0x2901, + value: 'Cycling Speed and Cadence Measurement' + } + ] + }) + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + + // Features flag + bufferBuilder.writeUInt8(cscFeaturesFlags.crankRevolutionDataSupported | cscFeaturesFlags.wheelRevolutionDataSupported) + + // Wheel revolution count (basically the distance in cm) + bufferBuilder.writeUInt32LE(data.totalLinearDistance > 0 ? Math.round(Math.round(data.totalLinearDistance * 100)) : 0) + + // Wheel revolution time (ushort with 1024 resolution, resetting in every 64sec) + bufferBuilder.writeUInt16LE(data.totalMovingTime > 0 ? Math.round(data.totalMovingTime * 1024) % Math.pow(2, 16) : 0) + + // Total stroke count + bufferBuilder.writeUInt16LE(data.totalNumberOfStrokes > 0 ? Math.round(data.totalNumberOfStrokes) : 0) + + // last stroke time time (ushort with 1024 resolution, resetting in every 64sec) + bufferBuilder.writeUInt16LE(data.driveLastStartTime > 0 ? Math.round(data.driveLastStartTime * 1024) % Math.pow(2, 16) : 0) + + super.notify(bufferBuilder.getBuffer()) + } +} + +export const cscFeaturesFlags = +{ + wheelRevolutionDataSupported: (0x01 << 0), + crankRevolutionDataSupported: (0x01 << 1), + multipleSensorLocationSupported: (0x01 << 2) +} diff --git a/app/peripherals/ble/csc/CyclingSpeedCadenceService.js b/app/peripherals/ble/csc/CyclingSpeedCadenceService.js new file mode 100644 index 0000000000..a732587a92 --- /dev/null +++ b/app/peripherals/ble/csc/CyclingSpeedCadenceService.js @@ -0,0 +1,46 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import { SensorLocationAsBuffer } from '../common/SensorLocation.js' + +import { BufferBuilder } from '../BufferBuilder.js' +import { GattService } from '../BleManager.js' + +import { CyclingSpeedCadenceMeasurementCharacteristic, cscFeaturesFlags } from './CscMeasurementCharacteristic.js' +import { CyclingSpeedCadenceControlPointCharacteristic } from './CscControlPointCharacteristic.js' +import { createStaticReadCharacteristic } from '../common/StaticReadCharacteristic.js' + +export class CyclingSpeedCadenceService extends GattService { + #measurementCharacteristic + + /** + * @param {ControlPointCallback} controlPointCallback + */ + constructor (controlPointCallback) { + const cscFeatureBuffer = new BufferBuilder() + cscFeatureBuffer.writeUInt16LE(featuresFlag) + const measurementCharacteristic = new CyclingSpeedCadenceMeasurementCharacteristic() + + super({ + name: 'Cycling Speed and Cadence', + uuid: 0x1816, + characteristics: [ + createStaticReadCharacteristic(0x2A5C, cscFeatureBuffer.getBuffer(), 'Cycling Speed and Cadence Feature'), + measurementCharacteristic.characteristic, + new CyclingSpeedCadenceControlPointCharacteristic(controlPointCallback).characteristic, + createStaticReadCharacteristic(0x2A5D, SensorLocationAsBuffer(), 'Sensor Location') + ] + }) + this.#measurementCharacteristic = measurementCharacteristic + } + + /** + * @param {Metrics} data + */ + notifyData (data) { + this.#measurementCharacteristic.notify(data) + } +} + +const featuresFlag = cscFeaturesFlags.crankRevolutionDataSupported | cscFeaturesFlags.wheelRevolutionDataSupported diff --git a/app/peripherals/ble/ftms/FitnessMachineControlPointCharacteristic.js b/app/peripherals/ble/ftms/FitnessMachineControlPointCharacteristic.js new file mode 100644 index 0000000000..c1aecb4351 --- /dev/null +++ b/app/peripherals/ble/ftms/FitnessMachineControlPointCharacteristic.js @@ -0,0 +1,145 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + The connected Central can remotely control some parameters or our rowing monitor via this Control Point +*/ +import NodeBleHost from 'ble-host' +import logevel from 'loglevel' + +import { swapObjectPropertyValues } from '../../../tools/Helper.js' + +import { ResultOpCode } from '../common/CommonOpCodes.js' + +const log = logevel.getLogger('Peripherals') + +// see https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0 for details +const ControlPointOpCode = { + requestControl: 0x00, + reset: 0x01, + setTargetSpeed: 0x02, + setTargetInclincation: 0x03, + setTargetResistanceLevel: 0x04, + setTargetPower: 0x05, + setTargetHeartRate: 0x06, + startOrResume: 0x07, + stopOrPause: 0x08, + setTargetedExpendedEnergy: 0x09, + setTargetedNumberOfSteps: 0x0A, + setTargetedNumberOfStrides: 0x0B, + setTargetedDistance: 0x0C, + setTargetedTrainingTime: 0x0D, + setTargetedTimeInTwoHeartRateZones: 0x0E, + setTargetedTimeInThreeHeartRateZones: 0x0F, + setTargetedTimeInFiveHeartRateZones: 0x10, + setIndoorBikeSimulationParameters: 0x11, + setWheelCircumference: 0x12, + spinDownControl: 0x13, + setTargetedCadence: 0x14, + responseCode: 0x80 +} + +export class FitnessMachineControlPointCharacteristic { + get characteristic () { + return this.#characteristic + } + + #controlled = false + /** + * @type {GattServerCharacteristicFactory} + */ + #characteristic + #controlPointCallback + + /** + * @param {ControlPointCallback} controlPointCallback + */ + constructor (controlPointCallback) { + if (!controlPointCallback) { throw new Error('controlPointCallback required') } + this.#controlPointCallback = controlPointCallback + + this.#characteristic = { + name: 'Fitness Machine Control Point', + uuid: 0x2AD9, + properties: ['write', 'indicate'], + onWrite: (connection, _needsResponse, opCode, callback) => { + log.debug('FTMS control is called:', opCode) + const response = this.#onWriteRequest(opCode) + + if (this.#characteristic.indicate === undefined) { + log.debug(`Characteristics ${this.#characteristic.name} has not been initialized`) + throw new Error(`Characteristics ${this.#characteristic.name} has not been initialized`) + } + + this.#characteristic.indicate(connection, response) + callback(NodeBleHost.AttErrors.SUCCESS) // actually only needs to be called when needsResponse is true + } + } + } + + /** + * @param {Buffer} data + * @returns {Buffer} + */ + #onWriteRequest (data) { + const opCode = data.readUInt8(0) + switch (opCode) { + case ControlPointOpCode.requestControl: + this.#controlled = true + return this.#buildResponse(opCode, ResultOpCode.success) + case ControlPointOpCode.reset: + // The spec expects that after the reset command also the control shall be reset, but this leads to an error situation + // ErgZone will send a reset at the start of communication, without pushing any workoutplan, leading to a loss of information + if (this.#controlled) { + this.#controlPointCallback({ req: { name: 'reset', data: {} } }) + return this.#buildResponse(opCode, ResultOpCode.success) + } else { + log.error('FTMS: Reset attempted before RequestControl') + } + break + case ControlPointOpCode.startOrResume: + if (this.#controlled) { + this.#controlPointCallback({ req: { name: 'startOrResume', data: {} } }) + return this.#buildResponse(opCode, ResultOpCode.success) + } else { + log.error('FTMS: startOrResume attempted before RequestControl') + } + break + case ControlPointOpCode.stopOrPause: { + if (this.#controlled) { + const controlParameter = data.readUInt8(1) + if (controlParameter === 1) { + this.#controlPointCallback({ req: { name: 'stop', data: {} } }) + return this.#buildResponse(opCode, ResultOpCode.success) + } else if (controlParameter === 2) { + this.#controlPointCallback({ req: { name: 'pause', data: {} } }) + return this.#buildResponse(opCode, ResultOpCode.success) + } + log.error(`FitnessMachineControlPointCharacteristic: stopOrPause with invalid controlParameter: ${controlParameter}`) + } else { + log.error('FTMS: stopOrPause attempted before RequestControl') + } + break + } + // TODO: Potentially handle setTargetPower and setDistance, etc. by integrating it into the interval/session manager. Difficulty is that this is a simple justrow like command with one target and no limits. + // So far, no apps have been found that actually use this interaction to develop and test against. + default: + log.info(`FitnessMachineControlPointCharacteristic: opCode ${swapObjectPropertyValues(ControlPointOpCode)[opCode]} is not supported`) + } + + log.info(`FitnessMachineControlPointCharacteristic: opCode ${swapObjectPropertyValues(ControlPointOpCode)[opCode]} is not supported`) + return this.#buildResponse(opCode, ResultOpCode.opCodeNotSupported) + } + + /** + * @param {number} opCode + * @param {number} resultCode + */ + #buildResponse (opCode, resultCode) { + const buffer = Buffer.alloc(3) + buffer.writeUInt8(0x80, 0) + buffer.writeUInt8(opCode, 1) + buffer.writeUInt8(resultCode, 2) + return buffer + } +} diff --git a/app/peripherals/ble/ftms/FitnessMachineService.js b/app/peripherals/ble/ftms/FitnessMachineService.js new file mode 100644 index 0000000000..db981fe311 --- /dev/null +++ b/app/peripherals/ble/ftms/FitnessMachineService.js @@ -0,0 +1,102 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implements the Fitness Machine Service (FTMS) according to specs. + Either presents a FTMS Rower (for rower applications that can use parameters such as Stroke Rate) or + simulates a FTMS Indoor Bike (for usage with bike training apps) + + Relevant parts from https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0 + For Discovery we should implement: + - Fitness Machine Feature Characteristic + - Rower Data Characteristic + - Training Status Characteristic (not yet implemented) todo: Maybe implement a simple version of it to see which + applications make use of it. Might become interesting, if we implement training management + - Fitness Machine Status Characteristic + - Fitness Machine Control Point Characteristic +*/ +import { BufferBuilder } from '../BufferBuilder.js' +import { GattService } from '../BleManager.js' +import { createStaticReadCharacteristic } from '../common/StaticReadCharacteristic.js' + +import { FitnessMachineControlPointCharacteristic } from './FitnessMachineControlPointCharacteristic.js' +import { FitnessMachineStatusCharacteristic } from './FitnessMachineStatusCharacteristic.js' +import { IndoorBikeDataCharacteristic } from './IndoorBikeDataCharacteristic.js' +import { RowerDataCharacteristic } from './RowerDataCharacteristic.js' + +export class FitnessMachineService extends GattService { + #dataCharacteristic + #statusCharacteristic + + /** + * @param {ControlPointCallback} controlPointCallback + * @param {boolean} [simulateIndoorBike = false] + */ + constructor (controlPointCallback, simulateIndoorBike = false) { + const ftmsFeaturesBuffer = new BufferBuilder() + ftmsFeaturesBuffer.writeUInt16LE(featuresFlag) + + const dataCharacteristic = simulateIndoorBike ? new IndoorBikeDataCharacteristic() : new RowerDataCharacteristic() + const statusCharacteristic = new FitnessMachineStatusCharacteristic() + + super({ + name: 'Fitness Machine', + uuid: 0x1826, + characteristics: [ + createStaticReadCharacteristic(0x2ACC, ftmsFeaturesBuffer.getBuffer(), 'FTMS Feature'), + dataCharacteristic.characteristic, + new FitnessMachineControlPointCharacteristic(controlPointCallback).characteristic, + statusCharacteristic.characteristic + ] + }) + + this.#dataCharacteristic = dataCharacteristic + this.#statusCharacteristic = statusCharacteristic + } + + /** + * @param {Metrics} data + */ + notifyData (data) { + this.#dataCharacteristic.notify(data) + } + + /** + * Present current rowing status to FTMS central + * @param {{name: string}} status + */ + notifyStatus (status) { + this.#statusCharacteristic.notify(status) + } +} + +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 + +export const FTMSTypeField = { + TreadmillSupported: (0x01 << 0), + CrossTrainerSupported: (0x01 << 1), + StepClimberSupported: (0x01 << 2), + StairClimberSupported: (0x01 << 3), + RowerSupported: (0x01 << 4), + IndoorBikeSupported: (0x01 << 5) +} diff --git a/app/ble/ftms/FitnessMachineStatusCharacteristic.js b/app/peripherals/ble/ftms/FitnessMachineStatusCharacteristic.js similarity index 50% rename from app/ble/ftms/FitnessMachineStatusCharacteristic.js rename to app/peripherals/ble/ftms/FitnessMachineStatusCharacteristic.js index 681ce00b4d..f6fb93e0f7 100644 --- a/app/ble/ftms/FitnessMachineStatusCharacteristic.js +++ b/app/peripherals/ble/ftms/FitnessMachineStatusCharacteristic.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor Implements the Status Characteristics, that can be used to notify the central about the current training machine settings. Currently only used to notify the central about training resets. @@ -9,8 +9,11 @@ If the Server supports the Fitness Machine Control Point, the Fitness Machine Status characteristic shall be exposed by the Server. Otherwise, supporting the Fitness Machine Status characteristic is optional. */ -import bleno from '@abandonware/bleno' -import log from 'loglevel' +import loglevel from 'loglevel' + +import { GattNotifyCharacteristic } from '../BleManager.js' + +const log = loglevel.getLogger('Peripherals') // see page 67 https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0 const StatusOpCode = { @@ -38,51 +41,39 @@ const StatusOpCode = { targetedCadenceChanged: 0x15 } -export default class FitnessMachineStatusCharacteristic extends bleno.Characteristic { +export class FitnessMachineStatusCharacteristic extends GattNotifyCharacteristic { constructor () { super({ - // Fitness Machine Status - uuid: '2ADA', - value: null, + name: 'Fitness Machine Status', + uuid: 0x2ADA, properties: ['notify'] }) - this._updateValueCallback = null - } - - onSubscribe (maxValueSize, updateValueCallback) { - log.debug(`FitnessMachineStatusCharacteristic - central subscribed with maxSize: ${maxValueSize}`) - this._updateValueCallback = updateValueCallback - return this.RESULT_SUCCESS - } - - onUnsubscribe () { - log.debug('FitnessMachineStatusCharacteristic - central unsubscribed') - this._updateValueCallback = null - return this.RESULT_UNLIKELY_ERROR } + /** + * Present current rowing status to FTMS central + * @param {{name: string}} status + */ + // @ts-ignore: Type is not assignable to type notify (status) { if (!(status && status.name)) { - log.error('can not deliver status without name') - return this.RESULT_SUCCESS + return } - if (this._updateValueCallback) { - const buffer = Buffer.alloc(2) - switch (status.name) { - case 'reset': - buffer.writeUInt8(StatusOpCode.reset, 0) - break - case 'stoppedOrPausedByUser': - buffer.writeUInt8(StatusOpCode.stoppedOrPausedByUser, 0) - break - case 'startedOrResumedByUser': - buffer.writeUInt8(StatusOpCode.startedOrResumedByUser, 0) - break - default: - log.error(`status ${status.name} is not supported`) - } - this._updateValueCallback(buffer) + + const buffer = Buffer.alloc(2) + switch (status.name) { + case 'reset': + buffer.writeUInt8(StatusOpCode.reset, 0) + break + case 'stoppedOrPausedByUser': + buffer.writeUInt8(StatusOpCode.stoppedOrPausedByUser, 0) + break + case 'startedOrResumedByUser': + buffer.writeUInt8(StatusOpCode.startedOrResumedByUser, 0) + break + default: + log.error(`status ${status.name} is not supported`) } - return this.RESULT_SUCCESS + super.notify(buffer) } } diff --git a/app/peripherals/ble/ftms/IndoorBikeDataCharacteristic.js b/app/peripherals/ble/ftms/IndoorBikeDataCharacteristic.js new file mode 100644 index 0000000000..d8ab449cbf --- /dev/null +++ b/app/peripherals/ble/ftms/IndoorBikeDataCharacteristic.js @@ -0,0 +1,95 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This implements the Indoor Bike Data Characteristic as defined by the Bluetooth SIG + Currently hardly any applications exist that support these FTMS Characteristic for Rowing. + So we use this to simulate an FTMS Indoor Bike characteristic. + Of course we can not deliver rowing specific parameters like this (such as stroke rate), but + this allows us to use the open rowing monitor with bike training platforms such as + Zwift, Sufferfest, RGT Cycling, Kinomap, Bkool, Rouvy and more... + So far tested on: + - Kinomap.com: uses Power and Speed + - Fulgaz: uses Power and Speed + - Zwift: uses Power + - RGT Cycling: connects Power but then disconnects again (seems something is missing here) + + From specs: + The Server should notify this characteristic at a regular interval, typically once per second + while in a connection and the interval is not configurable by the Client +*/ +import { BufferBuilder } from '../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../BleManager.js' + +export class IndoorBikeDataCharacteristic extends GattNotifyCharacteristic { + constructor () { + super({ + name: 'Indoor Bike Data', + uuid: 0x2AD2, + properties: ['notify'] + }) + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + // ignore events without the mandatory fields + if (!('cycleLinearVelocity' in data)) { + return + } + + const bufferBuilder = new BufferBuilder() + // 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) + // 00001011 + // 01010100 + bufferBuilder.writeUInt16LE(measurementFlag) + + // see https://www.bluetooth.com/specifications/specs/gatt-specification-supplement-3/ + // for some of the data types + // Instantaneous Speed in km/h + bufferBuilder.writeUInt16LE(data.cycleLinearVelocity > 0 ? data.cycleLinearVelocity * 3.6 * 100 : 0) + // Instantaneous Cadence in rotations per minute (we use this to communicate the strokes per minute) + bufferBuilder.writeUInt16LE(data.cycleStrokeRate > 0 ? Math.round(data.cycleStrokeRate * 2) : 0) + // Total Distance in meters + bufferBuilder.writeUInt24LE(data.totalLinearDistance > 0 ? Math.round(data.totalLinearDistance) : 0) + // Instantaneous Power in watts + bufferBuilder.writeUInt16LE(data.cyclePower > 0 ? Math.round(data.cyclePower) : 0) + // Energy + // Total energy in kcal + bufferBuilder.writeUInt16LE(data.totalCalories > 0 ? Math.round(data.totalCalories) : 0) + // Energy per hour + // The Energy per Hour field represents the average expended energy of a user during a + // period of one hour. + bufferBuilder.writeUInt16LE(data.totalCaloriesPerHour > 0 ? Math.round(data.totalCaloriesPerHour) : 0) + // Energy per minute + bufferBuilder.writeUInt8(data.totalCaloriesPerMinute > 0 ? Math.round(data.totalCaloriesPerMinute) : 0) + // Heart Rate: Beats per minute with a resolution of 1 + bufferBuilder.writeUInt8(data?.heartrate ? Math.round(data.heartrate) : 0) + // Elapsed Time: Seconds with a resolution of 1 + bufferBuilder.writeUInt16LE(Math.round(data.totalMovingTime)) + + super.notify(bufferBuilder.getBuffer()) + } +} + +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/peripherals/ble/ftms/RowerDataCharacteristic.js b/app/peripherals/ble/ftms/RowerDataCharacteristic.js new file mode 100644 index 0000000000..12ea2e2927 --- /dev/null +++ b/app/peripherals/ble/ftms/RowerDataCharacteristic.js @@ -0,0 +1,97 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This implements the Rower Data Characteristic as defined by the Bluetooth SIG + Currently not many applications exist that support thes FTMS Characteristic for Rowing so its hard + to verify this. So far tested on: + - Kinomap.com: uses Power, Split Time and Strokes per Minutes + + From the specs: + The Server should notify this characteristic at a regular interval, typically once per second + while in a connection and the interval is not configurable by the Client +*/ +import { BufferBuilder } from '../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../BleManager.js' + +export class RowerDataCharacteristic extends GattNotifyCharacteristic { + constructor () { + super( + { + name: 'Rower Data', + uuid: 0x2AD1, + properties: ['notify'] + }) + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + // ignore events without the mandatory fields + if (!('cycleStrokeRate' in data && 'totalNumberOfStrokes' in data)) { + return + } + + const bufferBuilder = new BufferBuilder() + // Field flags as defined in the Bluetooth Documentation + // Stroke Rate (default), Stroke Count (default), Total Distance (2), Instantaneous Pace (3), + // Instantaneous Power (5), Total / Expended Energy (8), Heart Rate (9), Elapsed Time (11) + // todo: might add: Average Stroke Rate (1), Average Pace (4), Average Power (6) + // Remaining Time (12) + // 00101100 + bufferBuilder.writeUInt16LE(measurementFlag) + // 00001011 + + // 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(data.cycleStrokeRate > 0 ? Math.round(data.cycleStrokeRate * 2) : 0) + // Stroke Count + bufferBuilder.writeUInt16LE(data.totalNumberOfStrokes > 0 ? Math.round(data.totalNumberOfStrokes) : 0) + // Total Distance in meters + bufferBuilder.writeUInt24LE(data.totalLinearDistance > 0 ? Math.round(data.totalLinearDistance) : 0) + // 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.cyclePace !== Infinity && data.cyclePace < 65535 ? Math.round(data.cyclePace) : 0) + // Instantaneous Power in watts + bufferBuilder.writeUInt16LE(data.cyclePower > 0 ? Math.round(data.cyclePower) : 0) + // Energy in kcal + // Total energy in kcal + bufferBuilder.writeUInt16LE(data.totalCalories > 0 ? Math.round(data.totalCalories) : 0) + // Energy per hour + // The Energy per Hour field represents the average expended energy of a user during a + // period of one hour. + bufferBuilder.writeUInt16LE(data.totalCaloriesPerHour > 0 ? Math.round(data.totalCaloriesPerHour) : 0) + // Energy per minute + bufferBuilder.writeUInt8(data.totalCaloriesPerMinute > 0 ? Math.round(data.totalCaloriesPerMinute) : 0) + // Heart Rate: Beats per minute with a resolution of 1 + bufferBuilder.writeUInt8(data?.heartrate ? Math.round(data.heartrate) : 0) + // Elapsed Time: Seconds with a resolution of 1 + bufferBuilder.writeUInt16LE(data.totalMovingTime > 0 ? Math.round(data.totalMovingTime) : 0) + + super.notify(bufferBuilder.getBuffer()) + } +} + +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/hrm/HrmService.js b/app/peripherals/ble/hrm/HrmService.js new file mode 100644 index 0000000000..88c7604454 --- /dev/null +++ b/app/peripherals/ble/hrm/HrmService.js @@ -0,0 +1,306 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import EventEmitter from 'node:events' + +import { BleManager } from 'ble-host' +import logger from 'loglevel' + +import { toBLEStandard128BitUUID } from '../BleManager.js' + +/** + * @typedef {import('../ble-host.interface.js').Connection} Connection + * @typedef {import('../ble-host.interface.js').Scanner} Scanner + * @typedef {import('../ble-host.interface.js').GattClientCharacteristic} GattClientCharacteristic + */ + +const log = logger.getLogger('Peripherals') + +const heartRateServiceUUID = toBLEStandard128BitUUID('180D') +const heartRateMeasurementUUID = toBLEStandard128BitUUID('2A37') + +const batteryLevelServiceUUID = toBLEStandard128BitUUID('180F') +const batteryLevelMeasurementUUID = toBLEStandard128BitUUID('2A19') + +const deviceInformationServiceUUID = toBLEStandard128BitUUID('180A') +const manufacturerIdUUID = toBLEStandard128BitUUID('2A29') +const serialNumberUUID = toBLEStandard128BitUUID('2A25') + +/** + * @event HrmService#heartRateMeasurement + * @extends {EventEmitter<{heartRateMeasurement: Array}>} + */ +export class HrmService extends EventEmitter { + #manager + /** + * @type {Scanner | undefined} + */ + #scanner + /** + * @type {Connection | undefined} + */ + #connection + /** + * @type {import('../ble-host.interface.js').GattClientCharacteristic | undefined} + */ + #heartRateMeasurementCharacteristic + /** + * @type {import('../ble-host.interface.js').GattClientCharacteristic | undefined} + */ + #batteryLevelCharacteristic + /** + * @type {number | undefined} + */ + #batteryLevel + /** + * @type {number | undefined} + */ + #energyExpended + /** + * @type {Array} + */ + #rrIntervals = [] + /** + * @type {number | string | undefined} + */ + #manufacturerId + /** + * @type {number | string | undefined} + */ + #serialNumber + + /** + * @param {import('../ble-host.interface.js').BleManager} manager + */ + constructor (manager) { + super() + this.#manager = manager + } + + /* eslint-disable max-statements -- This initialises the BLE HRM handler */ + async start () { + this.#scanner = this.#manager.startScan({ + scanFilters: [new BleManager.ServiceUUIDScanFilter(heartRateServiceUUID)] + }) + this.#connection = undefined + this.#heartRateMeasurementCharacteristic?.removeAllListeners() + this.#batteryLevelCharacteristic?.removeAllListeners() + + const device = await new Promise((resolve) => { + /** @type {Scanner} */(this.#scanner).on('report', (eventData) => { + if (eventData.connectable) { + resolve(eventData) + } + }) + }) + + log.info(`Found device (${device.parsedDataItems.localName || 'no name'})`) + + this.#scanner.removeAllListeners() + this.#scanner.stopScan() + + this.#connection = await new Promise((/** @type {(value: Connection) => void} */resolve) => { + this.#manager.connect(device.addressType, device.address, {}, (connection) => { + resolve(connection) + }) + }) + + this.#connection.once('disconnect', () => { + log.debug(`Disconnected from ${this.#connection?.peerAddress}, restart scanning`) + + this.start() + }) + + log.debug('Connected to ' + this.#connection.peerAddress) + const primaryServices = await new Promise((/** @type {(value: Array) => void} */resolve, reject) => { + if (this.#connection === undefined) { + reject(new Error('Connection has been disposed')) + + return + } + + this.#connection.gatt.discoverAllPrimaryServices((services) => { + if (services.length === 0) { + reject(new Error('No heart rate services was found')) + } + resolve(services) + }) + }) + + const deviceInformationService = primaryServices.find(service => service.uuid === deviceInformationServiceUUID) + if (deviceInformationService !== undefined) { + log.debug('HR device information service was discovered') + const characteristics = await new Promise((/** @type {(value: { serialNumber?: GattClientCharacteristic, manufacturerId?: GattClientCharacteristic}) => void} */resolve) => { + deviceInformationService.discoverCharacteristics((characteristics) => { + resolve({ + serialNumber: characteristics.find(characteristic => characteristic.uuid === serialNumberUUID), manufacturerId: characteristics.find(characteristic => characteristic.uuid === manufacturerIdUUID) + }) + }) + }) + + this.#manufacturerId = await new Promise((resolve) => { + if (characteristics.manufacturerId === undefined) { + resolve(undefined) + + return + } + + characteristics.manufacturerId.read((_errorCode, data) => { + resolve(data.toString()) + }) + }) + + this.#serialNumber = await new Promise((resolve) => { + if (characteristics.serialNumber === undefined) { + resolve(undefined) + + return + } + + characteristics.serialNumber.read((_errorCode, data) => { + resolve(data.toString()) + }) + }) + } + + const heartRateService = primaryServices.find(service => service.uuid === heartRateServiceUUID) + if (heartRateService === undefined) { + log.error(`Heart rate service not found in ${device.localName}`) + + this.start() + + return + } + + this.#heartRateMeasurementCharacteristic = await new Promise((resolve) => { + heartRateService.discoverCharacteristics((characteristics) => { + resolve(characteristics.find(characteristic => characteristic.uuid === heartRateMeasurementUUID)) + }) + }) + + if (this.#heartRateMeasurementCharacteristic === undefined) { + log.error(`Heart rate measurement characteristic not found in ${device.localName}`) + + this.start() + + return + } + + this.#heartRateMeasurementCharacteristic.writeCCCD(/* enableNotifications */ true, /* enableIndications */ false) + this.#heartRateMeasurementCharacteristic.on('change', (value) => { + log.debug('New heart rate value:', value) + this.#onHeartRateNotify(value) + }) + + const batteryService = primaryServices.find(service => service.uuid === batteryLevelServiceUUID) + if (batteryService === undefined) { + log.info(`Battery service not found in ${device.localName}`) + + return + } + + this.#batteryLevelCharacteristic = await new Promise((resolve) => { + batteryService.discoverCharacteristics((characteristics) => { + resolve(characteristics.find(characteristic => characteristic.uuid === batteryLevelMeasurementUUID)) + }) + }) + + if (this.#batteryLevelCharacteristic === undefined) { + log.error(`Battery level characteristic not found in ${device.localName}`) + + return + } + + this.#batteryLevel = await new Promise((resolve) => { + if (this.#batteryLevelCharacteristic === undefined) { + resolve(0) + + return + } + + this.#batteryLevelCharacteristic.read((_errorCode, data) => resolve(data.readUInt8(0))) + }) + this.#batteryLevelCharacteristic.writeCCCD(/* enableNotifications */ true, /* enableIndications */ false) + this.#batteryLevelCharacteristic.on('change', (level) => { + log.debug('New battery level value:', level) + this.#onBatteryNotify(level) + }) + } + + stop () { + this.#batteryLevelCharacteristic?.removeAllListeners() + this.#heartRateMeasurementCharacteristic?.removeAllListeners() + this.#scanner?.stopScan() + return new Promise((/** @type {(value: void) => void} */resolve) => { + log.debug('Shutting down HRM peripheral') + if (this.#connection !== undefined) { + log.debug('Terminating current HRM connection') + this.#connection.removeAllListeners() + this.#connection.once('disconnect', resolve) + this.#connection.disconnect() + + return + } + resolve() + }) + } + + /** + * @param {Buffer} data + */ + #onHeartRateNotify (data) { + const flags = data.readUInt8(0) + // bits of the feature flag: + // 0: Heart Rate Value Format + // 1 + 2: Sensor Contact Status + // 3: Energy Expended Status + // 4: RR-Interval + const is16BitHeartRate = Boolean(flags >> 0 & 0x01) // Checking the first bit + const hasSensorContact = Boolean(flags >> 1 & 0x01) // Checking bits 1 and 2 (sensor contact) + const isSensorContactSupported = Boolean(flags >> 2 & 0x01) // Checking bits 1 and 2 (sensor contact) + const hasEnergyExpended = Boolean(flags >> 3 & 0x01) // Checking bit 3 (energy expended) + const hasRRInterval = Boolean(flags >> 4 & 0x01) // Checking bit 4 (RR interval) + + // from the specs: + // While most human applications require support for only 255 bpm or less, special + // applications (e.g. animals) may require support for higher bpm values. + // 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 = is16BitHeartRate ? data.readUInt16LE(1) : data.readUInt8(1) + let offsetStart = is16BitHeartRate ? 1 : 2 + + // Energy Expended (if present) + if (hasEnergyExpended) { + this.#energyExpended = data.readUInt16LE(offsetStart) + offsetStart += 2 + } + + // RR Intervals (if present) + this.#rrIntervals = [] + if (hasRRInterval) { + while (offsetStart < data.length) { + this.#rrIntervals.push(Math.round(data.readUInt16LE(offsetStart) / 1024 * 1000) / 1000) // Convert to seconds + offsetStart += 2 + } + } + + this.emit('heartRateMeasurement', { + heartrate, + rrIntervals: this.#rrIntervals, + energyExpended: this.#energyExpended, + batteryLevel: this.#batteryLevel, + manufacturerId: this.#manufacturerId, + serialNumber: this.#serialNumber, + hasContact: isSensorContactSupported ? hasSensorContact : undefined + }) + } + + /** + * @param {Buffer} data + */ + #onBatteryNotify (data) { + this.#batteryLevel = data.readUInt8(0) + } +} diff --git a/app/peripherals/ble/pm5/Pm5AppearanceService.js b/app/peripherals/ble/pm5/Pm5AppearanceService.js new file mode 100644 index 0000000000..1d64ae0ca0 --- /dev/null +++ b/app/peripherals/ble/pm5/Pm5AppearanceService.js @@ -0,0 +1,32 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Provides all required GAP Characteristics of the PM5 + todo: not sure if this is correct, the normal GAP service has 0x1800 +*/ +import { GattService, toBLEStandard128BitUUID } from '../BleManager.js' +import { createStaticReadCharacteristic } from '../common/StaticReadCharacteristic.js' + +import { pm5Constants } from './Pm5Constants.js' + +export class Pm5AppearanceService extends GattService { + constructor () { + super({ + name: 'Generic Access', + uuid: toBLEStandard128BitUUID('1800'), + characteristics: [ + // GAP device name + createStaticReadCharacteristic(toBLEStandard128BitUUID('2A00'), pm5Constants.name, 'Device Name'), + // GAP appearance + createStaticReadCharacteristic(toBLEStandard128BitUUID('2A01'), [0x00, 0x00], 'Appearance'), + // GAP peripheral privacy + createStaticReadCharacteristic(toBLEStandard128BitUUID('2A02'), [0x00], 'Peripheral Privacy'), + // GAP reconnect address + createStaticReadCharacteristic(toBLEStandard128BitUUID('2A03'), '00:00:00:00:00:00', 'Reconnect Address'), + // Peripheral preferred connection parameters + createStaticReadCharacteristic(toBLEStandard128BitUUID('2A04'), [0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0xE8, 0x03], 'Preferred Connection Parameters') + ] + }) + } +} diff --git a/app/peripherals/ble/pm5/Pm5Constants.js b/app/peripherals/ble/pm5/Pm5Constants.js new file mode 100644 index 0000000000..467d7019b9 --- /dev/null +++ b/app/peripherals/ble/pm5/Pm5Constants.js @@ -0,0 +1,27 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Some PM5 specific constants + */ + +import { PeripheralConstants } from '../../PeripheralConstants.js' + +import { ErgModelType } from './csafe-service/CsafeCommandsMapping.js' + +export 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 + // ergMachineType: 0 TYPE_STATIC_D + ergMachineType: ErgModelType.ERGMODEL_TYPE_D +} + +/** + * PM5 uses 128bit UUIDs that are always prefixed and suffixed the same way + * @param {string} uuid + */ +export function toC2128BitUUID (uuid) { + return `CE06${uuid}-43E5-11E4-916C-0800200C9A66` +} diff --git a/app/peripherals/ble/pm5/Pm5DeviceInformationService.js b/app/peripherals/ble/pm5/Pm5DeviceInformationService.js new file mode 100644 index 0000000000..c6a9efc66d --- /dev/null +++ b/app/peripherals/ble/pm5/Pm5DeviceInformationService.js @@ -0,0 +1,66 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Provides the required Device Information of the PM5 +*/ +import NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +import { GattService } from '../BleManager.js' +import { createStaticReadCharacteristic } from '../common/StaticReadCharacteristic.js' + +import { pm5Constants, toC2128BitUUID } from './Pm5Constants.js' +import { BufferBuilder } from '../BufferBuilder.js' + +const log = loglevel.getLogger('Peripherals') + +export class Pm5DeviceInformationService extends GattService { + constructor () { + const firmwareRevision = pm5Constants.firmwareRevision.padEnd(20, '\0') + const manufacturer = pm5Constants.manufacturer.padEnd(16, '\0') + const moduleNumber = 'PM5'.padEnd(16, '\0') + + super({ + name: 'Information Service', + uuid: toC2128BitUUID('0010'), + characteristics: [ + // C2 module number string + createStaticReadCharacteristic(toC2128BitUUID('0011'), moduleNumber, 'Model'), + // C2 serial number string + createStaticReadCharacteristic(toC2128BitUUID('0012'), pm5Constants.serial, 'Serial'), + // C2 hardware revision string + createStaticReadCharacteristic(toC2128BitUUID('0013'), pm5Constants.hardwareRevision, 'Hardware Revision'), + // C2 firmware revision string - this needs to be exactly 20bytes (anything that is not used a null should be added) + createStaticReadCharacteristic(toC2128BitUUID('0014'), firmwareRevision, 'Firmware Revision'), + // C2 manufacturer name string - this needs to be exactly 16bytes (anything that is not used a null should be added) + createStaticReadCharacteristic(toC2128BitUUID('0015'), manufacturer, 'Manufacturer'), + // Erg Machine Type - - this needs to be exactly 16bytes (anything that is not used a null should be added) + createStaticReadCharacteristic(toC2128BitUUID('0016'), [pm5Constants.ergMachineType], 'ErgMachineType'), + // ATT MTU characteristic + // TODO: find out why does this prevent ErgData connecting in some cases (its a hit or miss, sometimes it works sometimes it does not. Unclear what the issue could be). + // { + // ...createStaticReadCharacteristic(toC2128BitUUID('0017'), [0x23, 0x00], 'MTU'), + // onRead: (connection, callback) => { + // const maxMtu = Math.min(connection.gatt.currentMtu, 512) + // log.debug(`PM5 MTU characteristic called, current ATT Rx MTU: ${maxMtu} (max: ${connection.gatt.currentMtu})`) + // const bufferBuilder = new BufferBuilder() + // bufferBuilder.writeUInt16LE(maxMtu) + // callback(NodeBleHost.AttErrors.SUCCESS, bufferBuilder.getBuffer()) + // } + // }, + // LL DLE characteristic + { + ...createStaticReadCharacteristic(toC2128BitUUID('0018'), [27], 'LL DLE'), + onRead: (connection, callback) => { + const llMax = Math.min(Math.max(connection.gatt.currentMtu, 27), 251) + log.debug(`PM5 LL DLE called, current : ${llMax}`) + const bufferBuilder = new BufferBuilder() + bufferBuilder.writeUInt16LE(llMax) + callback(NodeBleHost.AttErrors.SUCCESS, bufferBuilder.getBuffer()) + } + } + ] + }) + } +} diff --git a/app/peripherals/ble/pm5/control-service/ControlReceiveCharacteristic.js b/app/peripherals/ble/pm5/control-service/ControlReceiveCharacteristic.js new file mode 100644 index 0000000000..36b97329df --- /dev/null +++ b/app/peripherals/ble/pm5/control-service/ControlReceiveCharacteristic.js @@ -0,0 +1,76 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implementation of the ControlReceive Characteristic as defined in: + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + Used to receive controls from the central +*/ +import NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +import { toHexString } from '../../../../tools/Helper.js' + +import { UniqueFrameFlags } from '../csafe-service/CsafeCommandsMapping.js' +import { toC2128BitUUID } from '../Pm5Constants.js' + +const log = loglevel.getLogger('Peripherals') + +export class ControlReceiveCharacteristic { + get characteristic () { + return this.#characteristic + } + + /** + * @type {GattServerCharacteristicFactory} + */ + #characteristic + /** + * @type {Array} + */ + #currentDataBuffer = [] + + #csafeCommandService + + /** + * @param {import('../csafe-service/CsafeManagerService.js').CsafeManagerService} csafeCommandService + */ + constructor (csafeCommandService) { + this.#csafeCommandService = csafeCommandService + this.#characteristic = { + name: 'Control Receive', + uuid: toC2128BitUUID('0021'), + properties: ['write', 'write-without-response'], + onWrite: (_connection, needsResponse, data, callback) => { + log.debug('PM5 Control is called:', data) + + if (data.indexOf(UniqueFrameFlags.ExtendedStartFlag) >= 0 || data.indexOf(UniqueFrameFlags.StandardStartFlag) >= 0) { + // One command frame can arrive in multiple writes so we need accumulate until we have a full frame indicated by the StopFlag (0xF2) + // Reset buffer when a new frame is started + this.#currentDataBuffer = [] + } + this.#currentDataBuffer.push(...data) + + if (needsResponse) { + callback(NodeBleHost.AttErrors.SUCCESS) // actually only needs to be called when needsResponse is true + } + + if (data.indexOf(UniqueFrameFlags.StopFlag) < 0) { + return + } + + log.debug('PM5 Control frame is complete:', toHexString(this.#currentDataBuffer)) + + const frame = this.#currentDataBuffer.slice(this.#currentDataBuffer.findIndex((byte) => byte === UniqueFrameFlags.StandardStartFlag || byte === UniqueFrameFlags.ExtendedStartFlag)) + + try { + this.#csafeCommandService.processCommand(frame) + } catch (e) { + // TODO: Indicate via the transfer characteristic that some error occurred + log.warn(e) + } + } + } + } +} diff --git a/app/peripherals/ble/pm5/control-service/ControlTransmitCharacteristic.js b/app/peripherals/ble/pm5/control-service/ControlTransmitCharacteristic.js new file mode 100644 index 0000000000..740539b18b --- /dev/null +++ b/app/peripherals/ble/pm5/control-service/ControlTransmitCharacteristic.js @@ -0,0 +1,34 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implementation of the ControlTransmit Characteristic as defined in: + https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + Used to transmit controls to the central +*/ +import loglevel from 'loglevel' + +import { GattNotifyCharacteristic } from '../../BleManager.js' + +import { toC2128BitUUID } from '../Pm5Constants.js' + +const log = loglevel.getLogger('Peripherals') + +export class ControlTransmitCharacteristic extends GattNotifyCharacteristic { + constructor () { + super({ + name: 'Control Transmit', + uuid: toC2128BitUUID('0022'), + properties: ['notify'] + }) + } + + /** + * @param {Buffer} buffer + * @override + */ + notify (buffer) { + log.debug('PM5 response notify:', buffer) + super.notify(buffer) + } +} diff --git a/app/peripherals/ble/pm5/control-service/Pm5ControlService.js b/app/peripherals/ble/pm5/control-service/Pm5ControlService.js new file mode 100644 index 0000000000..fa1aa1288b --- /dev/null +++ b/app/peripherals/ble/pm5/control-service/Pm5ControlService.js @@ -0,0 +1,34 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + The Control service can be used to send control commands to the PM5 device + todo: not yet wired +*/ +import { GattService } from '../../BleManager.js' + +import { CsafeManagerService } from '../csafe-service/CsafeManagerService.js' + +import { toC2128BitUUID } from '../Pm5Constants.js' + +import { ControlReceiveCharacteristic } from './ControlReceiveCharacteristic.js' +import { ControlTransmitCharacteristic } from './ControlTransmitCharacteristic.js' + +export class Pm5ControlService extends GattService { + /** + * @param {ControlPointCallback} controlCallback + */ + constructor (controlCallback) { + const transmitCharacteristic = new ControlTransmitCharacteristic() + const csafeManagerService = new CsafeManagerService(transmitCharacteristic, controlCallback) + + super({ + name: 'Control Service', + uuid: toC2128BitUUID('0020'), + characteristics: [ + new ControlReceiveCharacteristic(csafeManagerService).characteristic, + transmitCharacteristic.characteristic + ] + }) + } +} diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeCommand.js b/app/peripherals/ble/pm5/csafe-service/CsafeCommand.js new file mode 100644 index 0000000000..bd03d70656 --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeCommand.js @@ -0,0 +1,51 @@ +import { swapObjectPropertyValues } from '../../../../tools/Helper.js' + +import { longCommands, shortCommands } from './CsafeCommandsMapping.js' + +export class CsafeCommand { + get command () { + return this.#command + } + + get data () { + return this.#data + } + + #command + #data + + /** + * + * @param {import('./CsafeCommandsMapping.js').CsafeCommandsNumbers} command + * @param {Array} data + */ + constructor (command, data) { + this.#command = command + this.#data = data + } + + /** + * Return whether the command has parameters or not (long or short). This only relates to the request data, + * and not whether the response should have data or not + */ + isShortCommand () { + return CsafeCommand.isShortCommand(this.#command) + } + + toString () { + /** + * @type {ReverseKeyValue>} + */ + const toString = swapObjectPropertyValues(this.isShortCommand() ? shortCommands : longCommands) + + return toString[this.#command] + } + + /** + * + * @param {number} command + */ + static isShortCommand (command) { + return Boolean(command >> 7) + } +} diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeCommand.test.js b/app/peripherals/ble/pm5/csafe-service/CsafeCommand.test.js new file mode 100644 index 0000000000..28edbe826e --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeCommand.test.js @@ -0,0 +1,36 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import * as assert from 'uvu/assert' +import { suite } from 'uvu' + +import { CsafeCommand } from './CsafeCommand.js' +import { ProprietaryLongSetDataCommands } from './CsafeCommandsMapping.js' + +const csafeCommandTests = suite('CsafeCommand') + +csafeCommandTests('isShortCommand method should return true for short and false for long command', () => { + const longCommands = [0x69, 0x05, 0x01, 0x50] + const shortCommands = [0x9B, 0x81, 0x89, 0x80] + + longCommands.forEach((command) => { + const csafeCommand = new CsafeCommand(command, []) + assert.is(csafeCommand.isShortCommand(), false, `long command: 0x${command.toString(16)}`) + }) + + shortCommands.forEach((command) => { + const csafeCommand = new CsafeCommand(command, []) + assert.is(csafeCommand.isShortCommand(), true, `short command: 0x${command.toString(16)}`) + }) +}) + +csafeCommandTests('toString method should return the string name of the command per the CSAFE Spec', () => { + const csafeCommand = new CsafeCommand(ProprietaryLongSetDataCommands.CSAFE_PM_SET_EXTENDED_HRM, []) + + const commandString = Object.entries(ProprietaryLongSetDataCommands).filter(a => a[1] === ProprietaryLongSetDataCommands.CSAFE_PM_SET_EXTENDED_HRM)[0][0] + + assert.is(csafeCommand.toString(), commandString) +}) + +csafeCommandTests.run() diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeCommandsMapping.js b/app/peripherals/ble/pm5/csafe-service/CsafeCommandsMapping.js new file mode 100644 index 0000000000..364c47f6b1 --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeCommandsMapping.js @@ -0,0 +1,845 @@ +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + based on version 08-08-2023 of the C2 Bluetooth specification, see https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf +*/ + +/** + * @readonly + * @enum {number} + */ +/* eslint-disable max-lines -- Concept 2 uses a lot of enums, not much we can do about them */ +export const UniqueFrameFlags = { + ExtendedStartFlag: 0xF0, + StandardStartFlag: 0xF1, + StopFlag: 0xF2, + StuffFlag: 0xF3 +} + +/** + * @readonly + * @enum {number} + */ +export const PreviousFrameStatus = { + Ok: 0x00, + Reject: 0x10, + Bad: 0x20, + NotReady: 0x30 +} + +/** + * @readonly + * @enum {number} + */ +export const StateMachineState = { + Error: 0x00, + Ready: 0x01, + Idle: 0x02, + HaveId: 0x03, + InUse: 0x05, + Pause: 0x06, + Finish: 0x07, + Manual: 0x08, + OffLine: 0x09 +} + +export const WorkoutState = { + WORKOUTSTATE_WAITTOBEGIN: 0, + WORKOUTSTATE_WORKOUTROW: 1, + WORKOUTSTATE_COUNTDOWNPAUSE: 2, + WORKOUTSTATE_INTERVALREST: 3, + WORKOUTSTATE_INTERVALWORKTIME: 4, + WORKOUTSTATE_INTERVALWORKDISTANCE: 5, + WORKOUTSTATE_INTERVALRESTENDTOWORKTIME: 6, + WORKOUTSTATE_INTERVALRESTENDTOWORKDISTANCE: 7, + WORKOUTSTATE_INTERVALWORKTIMETOREST: 8, + WORKOUTSTATE_INTERVALWORKDISTANCETOREST: 9, + WORKOUTSTATE_WORKOUTEND: 10, + WORKOUTSTATE_TERMINATE: 11, + WORKOUTSTATE_WORKOUTLOGGED: 12, + WORKOUTSTATE_REARM: 13 +} + +export const RowingState = { + ROWINGSTATE_INACTIVE: 0, + ROWINGSTATE_ACTIVE: 1 +} + +export const StrokeState = { + STROKESTATE_WAITING_FOR_WHEEL_TO_REACH_MIN_SPEED_STATE: 0, + STROKESTATE_WAITING_FOR_WHEEL_TO_ACCELERATE_STATE: 1, + STROKESTATE_DRIVING_STATE: 2, + STROKESTATE_DWELLING_AFTER_DRIVE_STATE: 3, + STROKESTATE_RECOVERY_STATE: 4 +} + +export const DurationTypes = { + CSAFE_TIME_DURATION: 0, + CSAFE_CALORIES_DURATION: 0X40, + CSAFE_DISTANCE_DURATION: 0X80, + CSAFE_WATTS_DURATION: 0XC0 +} + +/** + * @readonly + * @enum {number} + */ +export const ErgModelType = { + /** Model D/E type (0). */ + ERGMODEL_TYPE_D: 0x00, + /** Model C/B type (1). */ + ERGMODEL_TYPE_C: 0x01, + /** Model A type (2). */ + ERGMODEL_TYPE_A: 0x02 + +} + +/** + * @readonly + * @enum {number} + */ +export const PublicShortCommands = { + CSAFE_GETSTATUS_CMD: 0x80, + CSAFE_RESET_CMD: 0x81, + CSAFE_GOIDLE_CMD: 0x82, + CSAFE_GOHAVEID_CMD: 0x83, + CSAFE_GOINUSE_CMD: 0x85, + CSAFE_GOFINISHED_CMD: 0x86, + CSAFE_GOREADY_CMD: 0x87, + CSAFE_BADID_CMD: 0x88, + CSAFE_GETVERSION_CMD: 0x91, + CSAFE_GETID_CMD: 0x92, + CSAFE_GETUNITS_CMD: 0x93, + CSAFE_GETSERIAL_CMD: 0x94, + CSAFE_GETLIST_CMD: 0x98, + CSAFE_GETUTILIZATION_CMD: 0x99, + CSAFE_GETMOTORCURRENT_CMD: 0x9A, + CSAFE_GETODOMETER_CMD: 0x9B, + CSAFE_GETERRORCODE_CMD: 0x9C, + CSAFE_GETSERVICECODE_CMD: 0x9D, + CSAFE_GETUSERCFG1_CMD: 0x9E, + CSAFE_GETUSERCFG2_CMD: 0x9F, + CSAFE_GETTWORK_CMD: 0xA0, + CSAFE_GETHORIZONTAL_CMD: 0xA1, + CSAFE_GETVERTICAL_CMD: 0xA2, + CSAFE_GETCALORIES_CMD: 0xA3, + CSAFE_GETPROGRAM_CMD: 0xA4, + CSAFE_GETSPEED_CMD: 0xA5, + CSAFE_GETPACE_CMD: 0xA6, + CSAFE_GETCADENCE_CMD: 0xA7, + CSAFE_GETGRADE_CMD: 0xA8, + CSAFE_GETGEAR_CMD: 0xA9, + CSAFE_GETUPLIST_CMD: 0xAA, + CSAFE_GETUSERINFO_CMD: 0xAB, + CSAFE_GETTORQUE_CMD: 0xAC, + CSAFE_GETHRCUR_CMD: 0xB0, + CSAFE_GETHRTZONE_CMD: 0xB2, + CSAFE_GETMETS_CMD: 0xB3, + CSAFE_GETPOWER_CMD: 0xB4, + CSAFE_GETHRAVG_CMD: 0xB5, + CSAFE_GETHRMAX_CMD: 0xB6, + CSAFE_GETUSERDATA1_CMD: 0xBE, + CSAFE_GETUSERDATA2_CMD: 0xBF, + CSAFE_GETAUDIOCHANNEL_CMD: 0xC0, + CSAFE_GETAUDIOVOLUME_CMD: 0xC1, + CSAFE_GETAUDIOMUTE_CMD: 0xC2, + CSAFE_ENDTEXT_CMD: 0xE0, + CSAFE_DISPLAYPOPUP_CMD: 0xE1, + CSAFE_GETPOPUPSTATUS_CMD: 0xE5 +} + +/** + * @readonly + * @enum {number} + */ +export const PublicLongCommands = { + /** [Configuration] - Response: N/A */ + CSAFE_AUTOUPLOAD_CMD2: 0x01, + /** - Response: N/A */ + // CSAFE_UPLIST_CMD: 0x02 + /** - Response: N/A */ + CSAFE_UPSTATUSSEC_CMD: 0x04, + /** - Response: N/A */ + // CSAFE_UPLISTSEC_CMD: 0x05 + /** [# of Digits] - Response: N/A */ + CSAFE_IDDIGITS_CMD: 0x10, + /** [Hour, Minute, Second] - Response: N/A */ + CSAFE_SETTIME_CMD: 0x11, + /** [Year, Month, Day] - Response: N/A */ + CSAFE_SETDATE_CMD: 0x12, + /** [State Timeout] - Response N/A */ + CSAFE_SETTIMEOUT_CMD: 0x13, + /** Same as the proprietary wrapper [...One or more PMspecific commands] - Response PM specific */ + CSAFE_SETUSERCFG1_CMD1: 0x1A, + /** - Response */ + // CSAFE_SETUSERCFG2_CMD: 0x1B, + /** [Distance (LSB), Horizontal Distance (MSB), Units Specifier] - Response N/A */ + CSAFE_SETHORIZONTAL_CMD: 0x21, + /** - Response: N/A */ + // CSAFE_SETVERTICAL_CMD: 0x22 + /** [Total Calories (LSB), Total Calories (MSB)] - Response N/A */ + CSAFE_SETCALORIES_CMD: 0x23, + /** [Programmed or Pre-stored Workout, ] - Response N/A */ + CSAFE_SETPROGRAM_CMD: 0x24, + /** - Response */ + // CSAFE_SETSPEED_CMD: 0x25, + /** - Response */ + // CSAFE_SETGRADE_CMD: 0x28, + /** - Response */ + // CSAFE_SETGEAR_CMD: 0x29, + /** - Response */ + // CSAFE_SETUSERINFO_CMD: 0x2B, + /** - Response */ + // CSAFE_SETTORQUE_CMD: 0x2C, + /** - Response */ + // CSAFE_SETLEVEL_CMD: 0x2D, + /** - Response */ + // CSAFE_SETTARGETHR_CMD: 0x30, + /** - Response */ + // CSAFE_SETMETS_CMD: 0x33, + /** [Stroke Watts (LSB), Stroke Watts (MSB), Units Specifier] - Response N/A */ + CSAFE_SETPOWER_CMD: 0x34, + /** - Response */ + // CSAFE_SETHRZONE_CMD: 0x35, + /** - Response */ + // CSAFE_SETHRMAX_CMD: 0x36, + /** - Response */ + // CSAFE_SETCHANNELRANGE_CMD: 0x40, + /** - Response */ + // CSAFE_SETVOLUMERANGE_CMD: 0x41, + /** - Response */ + // CSAFE_SETAUDIOMUTE_CMD: 0x42, + /** - Response */ + // CSAFE_SETAUDIOCHANNEL_CMD: 0x43, + /** - Response */ + // CSAFE_SETAUDIOVOLUME_CMD: 0x44, + /** - Response */ + // CSAFE_STARTTEXT_CMD: 0x60, + /** - Response */ + // CSAFE_APPENDTEXT_CMD: 0x61, + /** - Response */ + // CSAFE_GETTEXTSTATUS_CMD: 0x65, + /** [Capability Code] - Response [Capability Code 0x00: [Max Rx Frame, Max Tx Frame, Min Interframe]; Capability Code 0x01:[0x00, 0x00]; Capability Code 0x02: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] ] */ + CSAFE_GETCAPS_CMD: 0x70, + /** + * Assumes Proprietary set Config (short/long) commands as data (e.g. set Date and Time) + */ + CSAFE_SETPMCFG_CMD: 0x76, + /** + * Assumes Proprietary set Data (short/long) commands as data (e.g. set Extended HR belt) + */ + CSAFE_SETPMDATA_CMD: 0x77, + /** + * Assumes Proprietary Get Config (short/long) commands as data (e.g. get Date and Time) + */ + CSAFE_GETPMCFG_CMD: 0x7E, + /** + * Assumes Proprietary Get Data (short/long) commands as data (e.g. get Extended HR belt) + */ + CSAFE_GETPMDATA_CMD: 0x7F +} + +/** + * @readonly + * @enum {number} + */ +export const ProprietaryLongSetConfigCommands = { + /** - Response */ + // CSAFE_PM_SET_BAUDRATE: 0x00, + /** [Workout Type] - Response N/A */ + CSAFE_PM_SET_WORKOUTTYPE: 0x01, + /** - Response */ + // CSAFE_PM_SET_STARTTYPE: 0x02, + /** [Time/Distance duration (0: Time, 0x40: Calories, 0x60: Watt-Min, 0x80: Distance), Duration (MSB), Duration, Duration, Duration (LSB)] - Response N/A */ + CSAFE_PM_SET_WORKOUTDURATION: 0x03, + /** [Duration (MSB), Duration (LSB)] - Response N/A */ + CSAFE_PM_SET_RESTDURATION: 0x04, + /** [Time/Distance duration (0: Time, 0x40: Calories, 0xC0: Watt-Min, 0x80: Distance), Duration (MSB), Duration, Duration Duration (LSB)] - Response N/A */ + CSAFE_PM_SET_SPLITDURATION: 0x05, + /** [Pace Time (MSB), Pace Time, Pace Time, Pace Time (LSB)] - Response N/A */ + CSAFE_PM_SET_TARGETPACETIME: 0x06, + /** - Response */ + // CSAFE_PM_SET_INTERVALIDENTIFIER: 0x07 + /** - Response */ + // CSAFE_PM_SET_OPERATIONALSTATE: 0x08 + /** [Type] - Response N/A */ + CSAFE_PM_SET_RACETYPE: 0x09, + /** - Response */ + // CSAFE_PM_SET_WARMUPDURATION: 0x0A + /** [Erg Physical Address, Race Lane Number] - Response N/A */ + CSAFE_PM_SET_RACELANESETUP: 0x0B, + /** [Erg Physical Address, Race Lane Number] - Response N/A */ + CSAFE_PM_SET_RACELANEVERIFY: 0x0C, + /** [Start Type (0: Random, 1: Countdown, 2: Random modified), Count Start Count/Race Start State, Ready Tick Count (MSB), Ready Tick Count Ready Tick Count Ready Tick Count (LSB), Attention Tick Count/Countdown Ticks Per, Number (MSB), Attention Tick Count/Countdown Ticks Per, Number, Attention Tick Count/Countdown Ticks Per, Number, Attention Tick Count/Countdown Ticks Per, Number (LSB), Row Tick Count (MSB), Row Tick Count Row Tick Count Row Tick Count (LSB)] - Response N/A */ + CSAFE_PM_SET_RACESTARTPARAMS: 0x0D, + /** [Starting Erg Slave Address] - Response N/A */ + CSAFE_PM_SET_ERGSLAVEDISCOVYREQUEST: 0x0E, + /** [Boat] - Response N/A */ + CSAFE_PM_SET_BOATNUMBER: 0x0F, + /** [HW address (MSB), HW address, HW address, HW address (LSB), Erg Number (Logical Address)] - Response N/A */ + CSAFE_PM_SET_ERGNUMBER: 0x10, + /** - Response */ + // CSAFE_PM_SET_COMMUNICATIONSTA: 0x11, + /** - Response */ + // CSAFE_PM_SET_CMDUPLIST: 0x12 + /** [Screen Type, Screen Value] - Response N/A */ + CSAFE_PM_SET_SCREENSTATE: 0x13, + /** [Programming mode (0: Disable, 1: Enable)] - Response N/A */ + CSAFE_PM_CONFIGURE_WORKOUT: 0x14, + /** [Avg Watts (MSB), Avg Watts (LSB)] - Response N/A */ + CSAFE_PM_SET_TARGETAVGWATTS: 0x15, + /** [Cals/Hr (MSB), Cals/Hr (LSB)] - Response N/A */ + CSAFE_PM_SET_TARGETCALSPERHR: 0x16, + /** [Interval Type (0: Time, 1: Distance, 2: Rest, 3:Time w/ Undefined Rest 4: Distance w/ Undefined Rest, 5: + Undefined Rest, 6: Calorie, 7: Calorie w/ Undefined Rest, 8: WattMinute, 9: WattMinute w/ Undefined + Rest)] - Response N/A */ + CSAFE_PM_SET_INTERVALTYPE: 0x17, + /** [Interval Count] - Response N/A */ + CSAFE_PM_SET_WORKOUTINTERVALCOUNT: 0x18, + /** [Display Update Rate] - Response N/A */ + CSAFE_PM_SET_DISPLAYUPDATERATE: 0x19, + /** [HW address (MSB), HW address, HW address, HW address (LSB), Authen PW (MSB), Authen PW, Authen PW, Authen PW, Authen PW, Authen PW, Authen PW, Authen PW (LSB)] - Response [Result] */ + CSAFE_PM_SET_AUTHENPASSWORD: 0x1A, + /** [Tick Time (MSB), Tick Time, Tick Time, Tick Time (LSB)] - Response N/A */ + CSAFE_PM_SET_TICKTIME: 0x1B, + /** [Tick Time Offset (MSB), Tick Time Offset, Tick Time Offset, Tick Time Offset (LSB)] - Response N/A */ + CSAFE_PM_SET_TICKTIMEOFFSET: 0x1C, + /** [Sample Tick (MSB), Sample Tick, Sample Tick, Sample Tick (LSB)] - Response N/A */ + CSAFE_PM_SET_RACEDATASAMPLETICKS: 0x1D, + /** [Type] - Response N/A */ + CSAFE_PM_SET_RACEOPERATIONTYP: 0x1E, + /** [Display Tick (MSB), Display Tick, Display Tick, Display Tick (LSB)] - Response N/A */ + CSAFE_PM_SET_RACESTATUSDISPLA: 0x1F, + /** [Warning Tick (MSB), Warning Tick, Warning Tick, Warning Tick (LSB)] - Response N/A */ + CSAFE_PM_SET_RACESTATUSWARNIN: 0x20, + /** [Doze Sec (MSB), Doze Sec (LSB), Sleep Sec (MSB), Sleep Sec (LSB), Unused, Unused, Unused, Unused] - Response N/A */ + CSAFE_PM_SET_RACEIDLEMODEPARA: 0x21, + /** [Time Hours (1 - 12), Time Minutes (0 - 59), Time Meridiem (0 = AM, 1 = PM), Date Month (1 - 12), Date Day (1 - 31), Date Year (MSB), Date Year (LSB)] - Response N/A */ + CSAFE_PM_SET_DATETIME: 0x22, + /** [Language Type] - Response N/A */ + CSAFE_PM_SET_LANGUAGETYPE: 0x23, + /** [Config Index, WEP Mode] - Response N/A */ + CSAFE_PM_SET_WIFICONFIG: 0x24, + /** [CPU/Tick Rate] - Response N/A */ + CSAFE_PM_SET_CPUTICKRATE: 0x25, + /** [Logcard User] - Response N/A */ + CSAFE_PM_SET_LOGCARDUSER: 0x26, + /** [Mode (disable/enable)] - Response N/A */ + CSAFE_PM_SET_SCREENERRORMODE: 0x27, + /** [Dummy Data (..., Dummy Data (- Response N/A */ + CSAFE_PM_SET_CABLETEST3: 0x28, + /** [User Number, User ID (MSB), User ID, User ID, User ID (LSB)] - Response N/A */ + CSAFE_PM_SET_USER_ID: 0x29, + /** [User Number, User Weight (MSB), User Weight (LSB), User DOB Day, User DOB Month, User DOB Year (MSB), User DOB Year (LSB), User Gender] - Response N/A */ + CSAFE_PM_SET_USER_PROFILE: 0x2A, + /** [Device Manufacture ID, Device Type, Device Num (MSB), Device Num (LSB)] - Response N/A */ + CSAFE_PM_SET_HRM: 0x2B, + /** [Physical Address of First Erg In Race] - Response N/A */ + CSAFE_PM_SET_RACESTARTINGPHYSCALADDRESS: 0x2C, + /** [User Number, Mfg ID, Device Type, Belt ID (MSB), Belt ID (LSB)] - Response N/A */ + CSAFE_PM_SET_HRBELT_INFO: 0x2D, + /** [RF Frequency, RF Period Hz (MSB), RF Period Hz (LSB), Datapage Pattern, Activity Timeout] - Response N/A */ + CSAFE_PM_SET_SENSOR_CHANNEL: 0x2F +} + +/** + * @readonly + * @enum {number} + */ +export const ProprietaryLongSetDataCommands = { + /** - Response */ + // CSAFE_PM_SET_TEAM_DISTANCE: 0x30, + /** - Response */ + // CSAFE_PM_SET_TEAM_FINISH_TIME: 0x31, + /** [Racer ID (Erg physical address), Racer Name (MSB), Racer Name, ..., Racer Name (LSB - - Response N/A */ + CSAFE_PM_SET_RACEPARTICIPANT: 0x32, + /** [First Racer ID, First Racer Position, First Racer Delta Distance/Time (MSB), ..., First Racer Delta Distance/Time (LSB - ..., Forth Racer ID, Forth Racer Position, Forth Racer Delta Distance/Time (MSB), ..., Forth Racer Delta Distance/Time (LSB - Team Distance (MSB - ..., Team Distance (LSB - Mode] - Response N/A */ + CSAFE_PM_SET_RACESTATUS: 0x33, + /** [Start address (MSB), Start address, Start address, ..., 64nd data to be set] - Response [Bytes written] */ + CSAFE_PM_SET_LOGCARD_MEMORY1: 0x34, + /** [1st Character, 2nd Character, ..., 32nd character] - Response N/A */ + CSAFE_PM_SET_DISPLAYSTRING: 0x35, + /** [Bitmap index (MSB), Bitmap index (LSB), Block length, ..., Data Index + 63] - Response [Total bitmap bytes (MSB), Total bitmap bytes (LSB)] */ + CSAFE_PM_SET_DISPLAYBITMAP: 0x36, + /** [Race Type, Race Length (MSB), Race Length, ..., Race Length (LSB - Race Participants, Race State, Race Lane] - Response N/A */ + CSAFE_PM_SET_LOCALRACEPARTICIPANT: 0x37, + /** [Game Type ID , Workout Duration Time (MSB), Workout Duration Time, Workout Duration Time, Workout Duration Time (LSB), Split Duration Time (MSB), Split Duration Time , Split Duration Time , Split Duration Time (LSB), Target Pace Time (MSB), Target Pace Time , Target Pace Time , Target Pace Time (LSB), Target Avg Watts (MSB), Target Avg Watts , Target Avg Watts , Target Avg Watts (LSB), Target Cals Per Hour (MSB), Target Cals Per Hour, Target Cals Per Hour, Target Cals Per Hour (LSB), Target Stroke Rate ] - Response N/A */ + CSAFE_PM_SET_GAMEPARAMS: 0x38, + /** [unused, HRM mfg id, HRM device type, HRM belt id (MSB), HRM belt id, HRM belt id, HRM belt id (LSB)] - Response N/A */ + CSAFE_PM_SET_EXTENDED_HRBELT_INFO: 0x39, + /** [HRM mfg id, HRM device type, HRM belt id (MSB), HRM belt id, HRM belt id, HRM belt id (LSB)] - Response N/A */ + CSAFE_PM_SET_EXTENDED_HRM: 0x3A, + /** [State (enable/disable), Intensity (0 - 100%)] - Response N/A */ + CSAFE_PM_SET_LEDBACKLIGHT: 0x3B, + /** [Record Type (Enum), Record Index (MSB), Record Index (LSB) (65535 archives all)] - Response N/A */ + CSAFE_PM_SET_DIAGLOG_RECORD_ARCHIVE: 0x3C, + /** [Wireless channel bit mask (MSB), Wireless channel bit mask, Wireless channel bit mask, Wireless channel bit mask (LSB)] - Response N/A */ + CSAFE_PM_SET_WIRELESS_CHANNEL: 0x3D, + /** [Undefined rest to work transition time, 1sec LSB (MSB), Undefined rest to work transition time (LSB), Undefined rest interval, 1sec LSB (MSB), Undefined rest interval, (LSB), Race prompt bitmap display duration, 1sec LSB (MSB), Race prompt bitmap display duration, Race prompt bitmap display duration, Race prompt bitmap display duration (LSB), Time Cap duration, 1 sec LSB (MSB), Time Cap duration, Time Cap duration, Time Cap duration (LSB)] - Response N/A */ + CSAFE_PM_SET_RACECONTROLPARMS: 0x3E +} + +/** + * @readonly + * @enum {number} + */ +export const ProprietaryLongGetDataCommands = { + /** [Device type (0: ESRAM, 1: Ext SRAM, 2: FLASH), Start address (MSB), Start address, Start address, Start address (LSB), Block length] - Response [Bytes read, 1st data read, 2nd data read, ..., 64nd data read] */ + CSAFE_PM_GET_MEMORY: 0x68, + /** [Start address (MSB), Start address, Start address, Start address (LSB), Block length] - Response [Bytes read, 1st data read, 2nd data read, ..., 64nd data read] */ + CSAFE_PM_GET_LOGCARD_MEMORY: 0x69, + /** [Start address (MSB), Start address, Start address, Start address (LSB), Block length] - Response [Bytes read, 1st data read, 2nd data read, ..., 64nd data read] */ + CSAFE_PM_GET_INTERNALLOGMEMORY: 0x6A, + /** [Block length] - Response [Bytes read, 1st data read (MSB), 1st data read (LSB), 2nd data read (MSB), ..., 16th data read (LSB)] */ + CSAFE_PM_GET_FORCEPLOTDATA: 0x6B, + /** [Block length in bytes] - Response [Bytes read, 1st data read (LSB), 1st data read (MSB), 2nd data read (LSB), ..., 16th data read (MSB)] */ + CSAFE_PM_GET_HEARTBEATDATA: 0x6C, + /** [0 (unused)] - Response [User I/F Events (MSB), User I/F Events (LSB)] */ + CSAFE_PM_GET_UI_EVENTS: 0x6D, + /** [0 (unused)] - Response [Stroke Distance (MSB), Stroke Distance (LSB), Stroke Drive Time, Stroke Recovery Time (MSB), Stroke Recovery Time (LSB), Stroke Length, Drive Counter (MSB), Drive Counter (LSB), Peak Drive Force (MSB), Peak Drive Force (LSB), Impulse Drive Force (MSB), Impulse Drive Force (LSB), Avg Drive Force (MSB), Avg Drive Force (LSB), Work Per Stroke (MSB), Work Per Stroke (LSB)] */ + CSAFE_PM_GET_STROKESTATS: 0x6E, + /** [Record Type (Enum)] - Response [Record Type (Enum), Record Num (MSB), Record Num (LSB)] */ + CSAFE_PM_GET_DIAGLOG_RECORD_NUM: 0x70, + /** [Record Type (Enum), Record Index (MSB), Record Index (LSB), Record Offset Bytes (MSB), Record Offset Bytes (LSB)] - Response [Record Index (MSB), Record Index (LSB), Valid Record Bytes (MSB), Valid Record Bytes (LSB), 1st data read, 2nd data read, ..., 68nd data read] */ + CSAFE_PM_GET_DIAGLOG_RECORD: 0x71, + /** [0 (unused)] - Response [Hash (MSB), Hash, Hash, Hash, Hash, Hash, Hash, Hash (LSB), 0 (unused), 0 (unused), ..., 0 (unused)] */ + CSAFE_PM_GET_CURRENT_WORKOUT: 0x72, + /** Internal Use */ + // CSAFE_PM_GET_GAME_SCORE: 0x78, + /** [0 (unused)] - Response [Game ID enumeration, Game Score (MSB) (Fish/Darts 1 point LSB, Target 0.1% LSB), Game Score (LSB)] */ + CSAFE_PM_GET_GAME_SCORE: 0x78 +} + +/** + * @readonly + * @enum {number} + */export const ProprietaryLongGetConfigCommands = { + /** [HW address1 (MSB), HW address, HW address, HW address (LSB)] - Response [Erg #] */ + CSAFE_PM_GET_ERG_NUMBER: 0x50, + /** [Logical Erg Number Requested, Physical Erg Number Requested, HW address, HW address, HW address (LSB)] - Response [Logical Erg #, HW address1 (MSB), HW address, HW address, HW address (LSB), Physical Erg #] */ + CSAFE_PM_GET_ERGNUMBERREQUEST: 0x51, + /** [User Number] - Response [User ID (MSB), User ID, User ID, ..., User ID (LSB)] */ + CSAFE_PM_GET_USERIDSTRING: 0x52, + /** [Race Type, Race Length (MSB), Race Length, Race Length, Race Length (LSB), Race Participants, Race State] - Response [HW address (MSB), HW address, HW address, HW address (LSB), UserID String (MSB), UserID String, ..., UserID String (LSB), Machine type] */ + CSAFE_PM_GET_LOCALRACEPARTICIPANT: 0x53, + /** [User Number] - Response [User Number, User ID (MSB), User ID, User ID, User ID (LSB)] */ + CSAFE_PM_GET_USER_ID: 0x54, + /** [User Number] - Response [User Number, User Weight (MSB), User Weight (LSB), User DOB Day, User DOB Month, User DOB Year (MSB), User DOB Year (LSB), User Gender] */ + CSAFE_PM_GET_USER_PROFILE: 0x55, + /** [User Number] - Response [User Number, Mfg ID, Device Type, Belt ID (MSB), Belt ID (LSB)] */ + CSAFE_PM_GET_HRBELT_INFO: 0x56, + /** [User Number] - Response [User Number, Mfg ID, Device Type, Belt ID (MSB), Belt ID, Belt ID, Belt ID (LSB)] */ + CSAFE_PM_GET_EXTENDED_HRBELT_INFO: 0x57, + /** [Structure ID enumeration, Split/interval number (1 - M), Bytes read, 1st data read, 2nd data read, ..., 2: Nth data read] - Response [Structure ID enumeration, Split/interval number, Bytes read, 1st data read, 2nd data read, ..., 2: Nth data read] */ + CSAFE_PM_GET_CURRENT_LOG_STRUCTURE: 0x58 +} + +/** + * @readonly + * @enum {number} + */ +export const ProprietaryShortGetDataCommands = { + /** [Work Time (MSB), Work Time, Work Time, Work Time (LSB)] */ + CSAFE_PM_GET_WORKTIME: 0xA0, + /** [Projected Work Time (MSB), Projected Work Time, Projected Work Time, Projected Work Time (LSB)] */ + CSAFE_PM_GET_PROJECTED_WORKTIME: 0xA1, + /** [Total Rest Time (MSB), Total Rest Time, Total Rest Time, Total Rest Time (LSB)] */ + CSAFE_PM_GET_TOTAL_RESTTIME: 0xA2, + /** [Work Distance (MSB), Work Distance, Work Distance, Work Distance (LSB)] */ + CSAFE_PM_GET_WORKDISTANCE: 0xA3, + /** [Total Work Distance (MSB), Total Work Distance, Total Work Distance, Total Work Distance (LSB)] */ + CSAFE_PM_GET_TOTAL_WORKDISTANCE: 0xA4, + /** [Projected Work Distance (MSB), Projected Work Distance, Projected Work Distance, Projected Work Distance (LSB)] */ + CSAFE_PM_GET_PROJECTED_WORKDISTANCE: 0xA5, + /** [Rest Distance (MSB), Rest Distance (LSB)] */ + CSAFE_PM_GET_RESTDISTANCE: 0xA6, + /** [Total Rest Distance (MSB), Total Rest Distance, Total Rest Distance, Total Rest Distance (LSB)] */ + CSAFE_PM_GET_TOTAL_RESTDISTANCE: 0xA7, + /** [Pace / 500m (MSB), Pace / 500m, Pace / 500m, Pace / 500m (LSB)] */ + CSAFE_PM_GET_STROKE_500M_PACE: 0xA8, + /** [Stroke Watts (MSB), Stroke Watts, Stroke Watts, Stroke Watts (LSB)] */ + CSAFE_PM_GET_STROKE_POWER: 0xA9, + /** [Stroke Cals/Hr (MSB), Stroke Cals/Hr, Stroke Cals/Hr, Stroke Cals/Hr (LSB)] */ + CSAFE_PM_GET_STROKE_CALORICBURNRATE: 0xAA, + /** [Split Avg Pace / 500m (MSB), Split Avg Pace / 500m, Split Avg Pace / 500m, Split Avg Pace / 500m (LSB)] */ + CSAFE_PM_GET_SPLIT_AVG_500M_PACE: 0xAB, + /** [Split Avg Watts (MSB), Split Avg Watts, Split Avg Watts, Split Avg Watts (LSB)] */ + CSAFE_PM_GET_SPLIT_AVG_POWER: 0xAC, + /** [Split Avg Cals/Hr (MSB), Split Avg Cals/Hr, Split Avg Cals/Hr, Split Avg Cals/Hr (LSB)] */ + CSAFE_PM_GET_SPLIT_AVG_CALORICBURNRATE: 0xAD, + /** [Split Avg Cals (MSB), Split Avg Cals, Split Avg Cals, Split Avg Cals (LSB)] */ + CSAFE_PM_GET_SPLIT_AVG_CALORIES: 0xAE, + /** [Total Avg Pace / 500m (MSB), Total Avg Pace / 500m, Total Avg Pace / 500m, Total Avg Pace / 500m (LSB)] */ + CSAFE_PM_GET_TOTAL_AVG_500MPACE: 0xAF, + /** [Total Avg Watts (MSB), Total Avg Watts, Total Avg Watts, Total Avg Watts (LSB)] */ + CSAFE_PM_GET_TOTAL_AVG_POWER: 0xB0, + /** [Total Avg Cals/Hr (MSB), Total Avg Cals/Hr, Total Avg Cals/Hr, Total Avg Cals/Hr (LSB)] */ + CSAFE_PM_GET_TOTAL_AVG_CALORICBURNRATE: 0xB1, + /** [Total Avg Calories (MSB), Total Avg Calories, Total Avg Calories, Total Avg Calories (LSB)] */ + CSAFE_PM_GET_TOTAL_AVG_CALORIES: 0xB2, + /** [Strokes/Min] */ + CSAFE_PM_GET_STROKE_RATE: 0xB3, + /** [Split/Interval Avg Strokes/Min] */ + CSAFE_PM_GET_SPLIT_AVG_STROKERATE: 0xB4, + /** [Total Avg Strokes/Min] */ + CSAFE_PM_GET_TOTAL_AVG_STROKERATE: 0xB5, + /** [Avg Beats/Min] */ + CSAFE_PM_GET_AVG_HEART_RATE: 0xB6, + /** [Split/Interval Avg Beats/Min] */ + CSAFE_PM_GET_ENDING_AVG_HEARTRATE: 0xB7, + /** [Rest Interval Avg Beats/Min] */ + CSAFE_PM_GET_REST_AVG_HEARTRATE: 0xB8, + /** [Elapsed Time / Split (MSB), Elapsed Time / Split, Elapsed Time / Split, Elapsed Time / Split (LSB)] */ + CSAFE_PM_GET_SPLITTIME: 0xB9, + /** [Last Elapsed Time / Split (MSB), Last Elapsed Time / Split, Last Elapsed Time / Split, Last Elapsed Time / Split (LSB)] */ + CSAFE_PM_GET_LAST_SPLITTIME: 0xBA, + /** [Work Distance/Split (MSB), Work Distance/Split, Work Distance/Split, Work Distance/Split (LSB)] */ + CSAFE_PM_GET_SPLITDISTANCE: 0xBB, + /** [Last Work Distance/Split (MSB), Last Work Distance/Split, Last Work Distance/Split, Last Work Distance/Split (LSB)] */ + CSAFE_PM_GET_LAST_SPLITDISTANCE: 0xBC, + /** [Last Rest Interval Distance (MSB), Last Rest Interval Distance, Last Rest Interval Distance, Last Rest Interval Distance (LSB)] */ + CSAFE_PM_GET_LAST_RESTDISTANCE: 0xBD, + /** [Target Pace Time (MSB), Target Pace Time, Target Pace Time, Target Pace Time (LSB)] */ + CSAFE_PM_GET_TARGETPACETIME: 0xBE, + /** [Stroke State] */ + CSAFE_PM_GET_STROKESTATE: 0xBF, + /** [Stroke Rate State] */ + CSAFE_PM_GET_STROKERATESTATE: 0xC0, + /** [Drag Factor] */ + CSAFE_PM_GET_DRAGFACTOR: 0xC1, + /** [Encoder Period (Float MSB), Encoder Period, Encoder Period, Encoder Period (Float LSB)] */ + CSAFE_PM_GET_ENCODER_PERIOD: 0xC2, + /** [Heartrate State] */ + CSAFE_PM_GET_HEARTRATESTATE: 0xC3, + /** [Sync Data (Float MSB), Sync Data, Sync Data, Sync Data (Float LSB)] */ + CSAFE_PM_GET_SYNC_DATA: 0xC4, + /** [Work Distance (Float MSB), Work Distance, Work Distance, Work Distance (Float LSB), Work Time (Float MSB), Work Time, Work Time, Work Time (Float LSB), Stroke Pace (Float MSB), Stroke Pace, Stroke Pace, Stroke Pace (Float LSB), Avg Heartrate (Float MSB), Avg Heartrate, Avg Heartrate, Avg Heartrate (Float LSB)] */ + CSAFE_PM_GET_SYNCDATAALL: 0xC5, + /** [Tick Time Stamp (MSB), Tick Time Stamp, Tick Time Stamp, Tick Time Stamp (LSB), Total Race Meters (MSB), Total Race Meters, Total Race Meters, Total Race Meters (LSB), 500m Pace (MSB), 500m Pace (LSB), Race Elapsed Time (MSB), Race Elapsed Time, Race Elapsed Time, Race Elapsed Time (LSB), Stroke Rate, Race State, Percent Battery Level, Stroke State, Rowing, EPM Status, Race Operation Type, Race Start State] */ + CSAFE_PM_GET_RACE_DATA: 0xC6, + /** [Tick Time (MSB), Tick Time, Tick Time, Tick Time (LSB)] */ + CSAFE_PM_GET_TICK_TIME: 0xC7, + /** [Error Type] */ + CSAFE_PM_GET_ERRORTYPE: 0xC8, + /** [Error Value (MSB), Error Value (LSB)] */ + CSAFE_PM_GET_ERRORVALUE: 0xC9, + /** [Status Type] */ + CSAFE_PM_GET_STATUSTYPE: 0xCA, + /** [Status Value] */ + CSAFE_PM_GET_STATUSVALUE: 0xCB, + /** [EPM Status] */ + CSAFE_PM_GET_EPMSTATUS: 0xCC, + /** [Display Update Time (MSB), Display Update Time, Display Update Time, Display Update Time (LSB)] */ + CSAFE_PM_GET_DISPLAYUPDATETIME: 0xCD, + /** [EPM Fractional Time] */ + CSAFE_PM_GET_SYNCFRACTIONALTIME: 0xCE, + /** [Rest Time (LSB), Rest Time (MSB)] */ + CSAFE_PM_GET_RESTTIME: 0xCF +} + +/** + * @readonly + * @enum {number} + */ +export const ProprietaryShortGetConfigCommands = { + /** [FW Exe Version # (MSB), FW Exe Version #, ..., FW Exe Version # (LSB)] */ + CSAFE_PM_GET_FW_VERSION: 0x80, + /** [HW Version # (MSB), HW Version #, ..., HW Version # (LSB)] */ + CSAFE_PM_GET_HW_VERSION: 0x81, + /** [HW address (MSB), HW address, HW address, HW address (LSB)] */ + CSAFE_PM_GET_HW_ADDRESS: 0x82, + /** [Tick timebase (Float MSB), Tick timebase, Tick timebase, Tick timebase (Float LSB)] */ + CSAFE_PM_GET_TICK_TIMEBASE: 0x83, + /** [(Channel Status, 0 = Inactive, 1 = Discovery, 2 = Paired If paired then:), Device Manufacture ID, Device Type, Device Num (MSB), Device Num (LSB), Else Bytes 1-4: 0] */ + CSAFE_PM_GET_HRM: 0x84, + /** [Time Hours (1 - 12), Time Minutes (0 - 59), Time Meridiem (0 = AM, 1 = PM), Date Month (1 - 12), Date Day (1 - 31), Date Year (MSB), Date Year (LSB)] */ + CSAFE_PM_GET_DATETIME: 0x85, + /** [Screen type, Screen value, Screen status] */ + CSAFE_PM_GET_SCREENSTATESTATUS: 0x86, + /** [Erg Physical Address] */ + CSAFE_PM_GET_RACE_LANE_REQUEST: 0x87, + /** [Erg Logical Address] */ + CSAFE_PM_GET_RACE_ENTRY_REQUEST: 0x88, + /** [Workout type] */ + CSAFE_PM_GET_WORKOUTTYPE: 0x89, + /** [Display type] */ + CSAFE_PM_GET_DISPLAYTYPE: 0x8A, + /** [Display units] */ + CSAFE_PM_GET_DISPLAYUNITS: 0x8B, + /** [Language type] */ + CSAFE_PM_GET_LANGUAGETYPE: 0x8C, + /** [Workout state] */ + CSAFE_PM_GET_WORKOUTSTATE: 0x8D, + /** [Interval type] */ + CSAFE_PM_GET_INTERVALTYPE: 0x8E, + /** [Operational state] */ + CSAFE_PM_GET_OPERATIONALSTATE: 0x8F, + /** [Log card state] */ + CSAFE_PM_GET_LOGCARDSTATE: 0x90, + /** [Log card status] */ + CSAFE_PM_GET_LOGCARDSTATUS: 0x91, + /** [Power-up state] */ + CSAFE_PM_GET_POWERUPSTATE: 0x92, + /** [Rowing state] */ + CSAFE_PM_GET_ROWINGSTATE: 0x93, + /** [Screen Content Version # (MSB), Screen Content Version #, ..., Screen Content Version # (LSB)] */ + CSAFE_PM_GET_SCREENCONTENT_VERSION: 0x94, + /** [Communication state] */ + CSAFE_PM_GET_COMMUNICATIONSTATE: 0x95, + /** [Race Participant Count] */ + CSAFE_PM_GET_RACEPARTICIPANTCOUNT: 0x96, + /** [Battery Level Percent] */ + CSAFE_PM_GET_BATTERYLEVELPERCENT: 0x97, + /** [HW address (MSB), HW address, ..., Operational State] */ + CSAFE_PM_GET_RACEMODESTATUS: 0x98, + /** [Log Start Address (MSB), Log Start Address, ..., Last Log Entry Length (LSB)] */ + CSAFE_PM_GET_INTERNALLOGPARAMS: 0x99, + /** [PM Base HW Revision (MSB), PM Base HW Revision (LSB), ..., Unused (0)] */ + CSAFE_PM_GET_PRODUCTCONFIGURATION: 0x9A, + /** [Status, # of Erg slaves present] */ + CSAFE_PM_GET_ERGSLAVEDISCOVERREQUESTSTATUS: 0x9B, + /** [Configuration Index, WEP Mode] */ + CSAFE_PM_GET_WIFICONFIG: 0x9C, + /** [CPU/Tick Rate Enumeration] */ + CSAFE_PM_GET_CPUTICKRATE: 0x9D, + /** [Number Users on Card, Number of Current User] */ + CSAFE_PM_GET_LOGCARDUSERCENSUS: 0x9E, + /** [Workout Interval Count] */ + CSAFE_PM_GET_WORKOUTINTERVALCOUNT: 0x9F, + /** [Time/Distance duration (0: Time, 0x40: Calories, 0xC0: Watt-Min, 0x80: Distance), Duration (MSB), Duration, Duration, Duration (LSB)] */ + CSAFE_PM_GET_WORKOUTDURATION: 0xE8, + /** [Work Other (MSB), Work Other, Work Other, Work Other (LSB)] */ + CSAFE_PM_GET_WORKOTHER: 0xE9, + /** [HRM Channel Status, HRM manufacturer ID, HRM device type, HRM device number (MSB), HRM device number, HRM device number, HRM device number (LSB)] */ + CSAFE_PM_GET_EXTENDED_HRM: 0xEA, + /** [DF Calibration Verified Status] */ + CSAFE_PM_GET_DEFCALIBRATIONVERFIED: 0xEB, + /** [Flywheel speed, rpm (MSB), Flywheel speed, rpm (LSB)] */ + CSAFE_PM_GET_FLYWHEELSPEED: 0xEC, + /** [Erg machine type] */ + CSAFE_PM_GET_ERGMACHINETYPE: 0xED, + /** [Race begin tick time, (MSB), Race begin tick time, ..., Race end tick time (LSB)] */ + CSAFE_PM_GET_RACE_BEGINEND_TICKCOUNT: 0xEE, + /** [Update info type (MSB), Update info type (LSB), Update status (MSB), Update status (LSB)] */ + CSAFE_PM_GET_PM5_FWUPDATESTATUS: 0xEF +} + +export const shortCommands = { + ...PublicShortCommands, + ...ProprietaryShortGetDataCommands, + ...ProprietaryShortGetConfigCommands +} +export const longCommands = { + ...PublicLongCommands, + ...ProprietaryLongGetDataCommands, + ...ProprietaryLongGetConfigCommands, + ...ProprietaryLongSetDataCommands, + ...ProprietaryLongSetConfigCommands +} + +/** + * @readonly + * @enum {number} + */ +export const WorkoutTypes = { + /** JustRow, no splits (0). */ + WORKOUTTYPE_JUSTROW_NOSPLITS: 0, + /** JustRow, splits (1). */ + WORKOUTTYPE_JUSTROW_SPLITS: 1, + /** Fixed distance, no splits (2). */ + WORKOUTTYPE_FIXEDDIST_NOSPLITS: 2, + /** Fixed distance, splits (3). */ + WORKOUTTYPE_FIXEDDIST_SPLITS: 3, + /** Fixed time, no splits (4). */ + WORKOUTTYPE_FIXEDTIME_NOSPLITS: 4, + /** Fixed time, splits (5). */ + WORKOUTTYPE_FIXEDTIME_SPLITS: 5, + /** Fixed time interval (6). */ + WORKOUTTYPE_FIXEDTIME_INTERVAL: 6, + /** Fixed distance interval (7). */ + WORKOUTTYPE_FIXEDDIST_INTERVAL: 7, + /** Variable interval (8). */ + WORKOUTTYPE_VARIABLE_INTERVAL: 8, + /** Variable interval, undefined rest (9). */ + WORKOUTTYPE_VARIABLE_UNDEFINEDREST_INTERVAL: 9, + /** Fixed calorie, splits (10). */ + WORKOUTTYPE_FIXEDCALORIE_SPLITS: 10, + /** Fixed watt-minute, splits (11). */ + WORKOUTTYPE_FIXEDWATTMINUTE_SPLITS: 11, + /** Fixed calorie interval (12). */ + WORKOUTTYPE_FIXEDCALS_INTERVAL: 12 +} + +/** + * @readonly + * @enum {number} + */ +export const IntervalTypes = { + /** Time interval type (0). */ + INTERVALTYPE_TIME: 0, + /** Distance interval type (1). */ + INTERVALTYPE_DIST: 1, + /** Rest interval type (2). */ + INTERVALTYPE_REST: 2, + /** Time undefined rest interval type (3). */ + INTERVALTYPE_TIMERESTUNDEFINED: 3, + /** Distance undefined rest interval type (4). */ + INTERVALTYPE_DISTANCERESTUNDEFINED: 4, + /** Undefined rest interval type (5). */ + INTERVALTYPE_RESTUNDEFINED: 5, + /** Calorie interval type (6). */ + INTERVALTYPE_CALORIE: 6, + /** Calorie undefined rest interval type (7). */ + INTERVALTYPE_CALORIERESTUNDEFINED: 7, + /** Watt-minute interval type (8). */ + INTERVALTYPE_WATTMINUTE: 8, + /** Watt-minute undefined rest interval type (9). */ + INTERVALTYPE_WATTMINUTERESTUNDEFINED: 9, + /** No interval type (255 ). */ + INTERVALTYPE_NONE: 255 +} + +/** + * @readonly + * @enum {number} + */ +export const ScreenTypes = { + SCREENTYPE_NONE: 0, + /** Workout type (1). */ + SCREENTYPE_WORKOUT: 1, + /** Race type (2). */ + SCREENTYPE_RACE: 2, + /** CSAFE type (3). */ + SCREENTYPE_CSAFE: 3, + /** Diagnostic type (4). */ + SCREENTYPE_DIAG: 4, + /** Manufacturing type (5). */ + SCREENTYPE_MFG: 5 +} + +/** + * @readonly + * @enum {number} + */ +export const ScreenValue = { + /** < None value (0). */ + SCREENVALUEWORKOUT_NONE: 0, + /** < Prepare to workout type (1). */ + SCREENVALUEWORKOUT_PREPARETOROWWORKOUT: 1, + /** < Terminate workout type (2). */ + SCREENVALUEWORKOUT_TERMINATEWORKOUT: 2, + /** < Rearm workout type (3). */ + SCREENVALUEWORKOUT_REARMWORKOUT: 3, + /** < Refresh local copies of logcard structures(4). */ + SCREENVALUEWORKOUT_REFRESHLOGCARD: 4, + /** < Prepare to race start (5). */ + SCREENVALUEWORKOUT_PREPARETORACESTART: 5, + /** < Goto to main screen (6). */ + SCREENVALUEWORKOUT_GOTOMAINSCREEN: 6, + /** < Log device busy warning (7). */ + SCREENVALUEWORKOUT_LOGCARDBUSYWARNING: 7, + /** < Log device select user (8). */ + SCREENVALUEWORKOUT_LOGCARDSELECTUSER: 8, + /** < Reset race parameters (9). */ + SCREENVALUEWORKOUT_RESETRACEPARAMS: 9, + /** < Cable test slave indication(10). */ + SCREENVALUEWORKOUT_CABLETESTSLAVE: 10, + /** < Fish game (11). */ + SCREENVALUEWORKOUT_FISHGAME: 11, + /** < Display participant info (12). */ + SCREENVALUEWORKOUT_DISPLAYPARTICIPANTINFO: 12, + /** < Display participant info w/ confirmation (13). */ + SCREENVALUEWORKOUT_DISPLAYPARTICIPANTINFOCONFIRM: 13, + /** < Display type set to target (20). */ + SCREENVALUEWORKOUT_CHANGEDISPLAYTYPETARGET: 20, + /** < Display type set to standard (21). */ + SCREENVALUEWORKOUT_CHANGEDISPLAYTYPESTANDARD: 21, + /** < Display type set to forcevelocity (22). */ + SCREENVALUEWORKOUT_CHANGEDISPLAYTYPEFORCEVELOCITY: 22, + /** < Display type set to Paceboat (23). */ + SCREENVALUEWORKOUT_CHANGEDISPLAYTYPEPACEBOAT: 23, + /** < Display type set to perstroke (24). */ + SCREENVALUEWORKOUT_CHANGEDISPLAYTYPEPERSTROKE: 24, + /** < Display type set to simple (25). */ + SCREENVALUEWORKOUT_CHANGEDISPLAYTYPESIMPLE: 25, + /** < Units type set to timemeters (30). */ + SCREENVALUEWORKOUT_CHANGEUNITSTYPETIMEMETERS: 30, + /** < Units type set to pace (31). */ + SCREENVALUEWORKOUT_CHANGEUNITSTYPEPACE: 31, + /** < Units type set to watts (32). */ + SCREENVALUEWORKOUT_CHANGEUNITSTYPEWATTS: 32, + /** < Units type set to caloric burn rate(33). */ + SCREENVALUEWORKOUT_CHANGEUNITSTYPECALORICBURNRATE: 33, + /** < Basic target game (34). */ + SCREENVALUEWORKOUT_TARGETGAMEBASIC: 34, + /** < Advanced target game (35). */ + SCREENVALUEWORKOUT_TARGETGAMEADVANCED: 35, + /** < Dart game (36). */ + SCREENVALUEWORKOUT_DARTGAME: 36, + /** < USB wait ready (37). */ + SCREENVALUEWORKOUT_GOTOUSBWAITREADY: 37, + /** < Tach cable test disable (38). */ + SCREENVALUEWORKOUT_TACHCABLETESTDISABLE: 38, + /** < Tach simulator disable (39). */ + SCREENVALUEWORKOUT_TACHSIMDISABLE: 39, + /** < Tach simulator enable, rate = 1:12 (40). */ + SCREENVALUEWORKOUT_TACHSIMENABLERATE1: 40, + /** < Tach simulator enable, rate = 1:35 (41). */ + SCREENVALUEWORKOUT_TACHSIMENABLERATE2: 41, + /** < Tach simulator enable, rate = 1:42 (42). */ + SCREENVALUEWORKOUT_TACHSIMENABLERATE3: 42, + /** < Tach simulator enable, rate = 3:04 (43). */ + SCREENVALUEWORKOUT_TACHSIMENABLERATE4: 43, + /** < Tach simulator enable, rate = 3:14 (44). */ + SCREENVALUEWORKOUT_TACHSIMENABLERATE5: 44, + /** < Tach cable test enable (45). */ + SCREENVALUEWORKOUT_TACHCABLETESTENABLE: 45, + /** < Units type set to calories(46). */ + SCREENVALUEWORKOUT_CHANGEUNITSTYPECALORIES: 46, + /** < Virtual key select A (47). */ + SCREENVALUEWORKOUT_VIRTUALKEY_A: 47, + /** < Virtual key select B (48). */ + SCREENVALUEWORKOUT_VIRTUALKEY_B: 48, + /** < Virtual key select C (49). */ + SCREENVALUEWORKOUT_VIRTUALKEY_C: 49, + /** < Virtual key select D (50). */ + SCREENVALUEWORKOUT_VIRTUALKEY_D: 50, + /** < Virtual key select E (51). */ + SCREENVALUEWORKOUT_VIRTUALKEY_E: 51, + /** < Virtual key select Units (52). */ + SCREENVALUEWORKOUT_VIRTUALKEY_UNITS: 52, + /** < Virtual key select Display (53). */ + SCREENVALUEWORKOUT_VIRTUALKEY_DISPLAY: 53, + /** < Virtual key select Menu (54). */ + SCREENVALUEWORKOUT_VIRTUALKEY_MENU: 54, + /** < Tach simulator enable, rate = random (55). */ + SCREENVALUEWORKOUT_TACHSIMENABLERATERANDOM: 55, + /** < Screen redraw (255). */ + SCREENVALUEWORKOUT_SCREENREDRAW: 255 +} + +/** + * @readonly + * @enum {number} + */ +export const OperationalStates = { + OPERATIONALSTATE_RESET: 0, // Reset state + OPERATIONALSTATE_READY: 1, // Ready state + OPERATIONALSTATE_WORKOUT: 2, // Workout state + OPERATIONALSTATE_WARMUP: 3, // Warm-up state + OPERATIONALSTATE_RACE: 4, // Race state + OPERATIONALSTATE_POWEROFF: 5, // Power-off state + OPERATIONALSTATE_PAUSE: 6, // Pause state + OPERATIONALSTATE_INVOKEBOOTLOADER: 7, // Invoke boot loader state + OPERATIONALSTATE_POWEROFF_SHIP: 8, // Power-off ship state + OPERATIONALSTATE_IDLE_CHARGE: 9, // Idle charge state + OPERATIONALSTATE_IDLE: 10, // Idle state + OPERATIONALSTATE_MFGTEST: 11, // Manufacturing test state + OPERATIONALSTATE_FWUPDATE: 12, // Firmware update state + OPERATIONALSTATE_DRAGFACTOR: 13, // Drag factor state + OPERATIONALSTATE_DFCALIBRATION: 100 // Drag factor calibration state +} + +/** + * @typedef {Extract, number>} CsafeCommandsNumbers + */ diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeFrameBase.js b/app/peripherals/ble/pm5/csafe-service/CsafeFrameBase.js new file mode 100644 index 0000000000..f3c2f4b605 --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeFrameBase.js @@ -0,0 +1,61 @@ +'use strict' + +import { PublicLongCommands, UniqueFrameFlags } from './CsafeCommandsMapping.js' + +export class CsafeFrameBase { + /** + * Check if the command is C2 proprietary or public. + * @param {number} command + */ + static isProprietary (command) { + return command === PublicLongCommands.CSAFE_SETPMCFG_CMD || + command === PublicLongCommands.CSAFE_SETPMDATA_CMD || + command === PublicLongCommands.CSAFE_GETPMCFG_CMD || + command === PublicLongCommands.CSAFE_GETPMDATA_CMD + } + + /** + * @param {number} byte + */ + static shouldStuffByte (byte) { + return (byte & 0xFC) === 0xF0 + } + + /** + * Returns the offset byte value for byte stuffing. + * @param {number} byte + */ + static stuffByte (byte) { + return [0xF3, byte & 0x03] + } + + /** + * Returns the real byte values for a frame. + * @param {Array} frame + */ + static unStuffByte (frame) { + return frame + // Do byte-un-stuffing + .reduce((buffer, byte, index, array) => { + if (byte === UniqueFrameFlags.StuffFlag) { + return buffer + } + + buffer.push( + index > 0 && array[index - 1] === UniqueFrameFlags.StuffFlag && (byte & 0xFC) === 0 ? + byte + 0xF0 : + byte + ) + + return buffer + }, /** @type {Array} */([])) + } + + /** + * Generates a 1 byte XOR checksum for a byte array. + * @param {Array} bytes + */ + static checksumFromBytes (bytes) { + return bytes.reduce((checkSum, byte) => checkSum ^ byte, 0x00) + } +} diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeManagerService.js b/app/peripherals/ble/pm5/csafe-service/CsafeManagerService.js new file mode 100644 index 0000000000..166ecf5378 --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeManagerService.js @@ -0,0 +1,233 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * @file The CsafeManagerService maps all CSAFE commands to the relevant actions within OpenRowingMonitor + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#csafe-commands|the command mapping description} + */ +import loglevel from 'loglevel' + +import { swapObjectPropertyValues } from '../../../../tools/Helper.js' +import { Concept2Date, createWorkoutPlan } from '../utils/C2toORMMapper.js' + +import { DurationTypes, IntervalTypes, ProprietaryLongGetConfigCommands, ProprietaryLongSetConfigCommands, ProprietaryLongSetDataCommands, ProprietaryShortGetConfigCommands, ScreenTypes, ScreenValue, WorkoutTypes } from './CsafeCommandsMapping.js' + +import { CsafeRequestFrame } from './CsafeRequestFrame.js' +import { CsafeResponseFrame } from './CsafeResponseFrame.js' + +/** + * @typedef {import('./CsafeCommand.js').CsafeCommand} CsafeCommand + */ + +const log = loglevel.getLogger('Peripherals') + +export class CsafeManagerService { + #lastResponseFlag = 1 + #controlTransmitCharacteristic + #controlPointCallback + #workoutplan + + /** + * @param {import('../control-service/ControlTransmitCharacteristic.js').ControlTransmitCharacteristic} controlTransmitCharacteristic + * @param {ControlPointCallback} controlCallback + */ + constructor (controlTransmitCharacteristic, controlCallback) { + this.#controlTransmitCharacteristic = controlTransmitCharacteristic + this.#controlPointCallback = controlCallback + this.#workoutplan = createWorkoutPlan() + } + + /** + * @param {Array} buffer + */ + /* eslint-disable max-statements, max-depth -- This handles quite a complex mapping, can't do that with less code or less complexity */ + processCommand (buffer) { + let intervalLength + let pauseLength + let j + + const csafeFrame = new CsafeRequestFrame(buffer) + + const commands = csafeFrame.commands + + log.debug('PM5 commands received:', csafeFrame.commands.map((command) => command.toString())) + + this.#lastResponseFlag = this.#lastResponseFlag ^ 1 + + const response = new CsafeResponseFrame(this.#lastResponseFlag, csafeFrame.frameType) + + if (csafeFrame.isExtended()) { + // in the response the addresses should be swapped compared to the request + response.setDestinationAddress(csafeFrame.sourceAddress) + response.setSourceAddress(csafeFrame.destinationAddress) + } + + if (csafeFrame.isProprietary()) { + response.setProprietaryWrapper(csafeFrame.proprietaryCommandWrapper) + } + + let i = 0 + let commandData + while (i < commands.length) { + commandData = commands[i].data + switch (commands[i].command) { + case (ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTINTERVALCOUNT): + if (commandData[0] === 0) { + this.#workoutplan.reset() + log.debug('Created empty workoutplan') + } + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}, CSAFE_PM_SET_WORKOUTINTERVALCOUNT, number: ${commandData}`) + break + case (ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTTYPE): + log.debug(`command ${i + 1}, CSAFE_PM_SET_WORKOUTTYPE, ${swapObjectPropertyValues(WorkoutTypes)[commandData[0]]}`) + switch (commandData[0]) { + case (WorkoutTypes.WORKOUTTYPE_JUSTROW_NOSPLITS): + this.#workoutplan.addInterval('justrow', commands[i].data) + response.addCommand(commands[i].command) + log.debug(' Added justrow interval') + break + case (WorkoutTypes.WORKOUTTYPE_JUSTROW_SPLITS): + this.#workoutplan.addInterval('justrow', commands[i].data) + response.addCommand(commands[i].command) + log.debug(' Added justrow interval') + break + case (WorkoutTypes.WORKOUTTYPE_FIXEDTIME_INTERVAL): + response.addCommand(commands[i].command) + i++ // Move to the duration + intervalLength = commands[i].data + response.addCommand(commands[i].command) + i++ // Move to the rest specification + pauseLength = commands[i].data + response.addCommand(commands[i].command) + j = 0 + while (j < 25) { + this.#workoutplan.addInterval('time', intervalLength) + this.#workoutplan.addInterval('rest', pauseLength) + j++ + } + log.debug(`PM5 WORKOUTTYPE_FIXEDTIME_INTERVAL is mapped to 25 '${this.#workoutplan.forelastInterval().type}' intervals of ${this.#workoutplan.forelastInterval().targetTime} seconds, followed by a ${this.#workoutplan.lastInterval().targetTime} seconds '${this.#workoutplan.lastInterval().type}' intervals`) + break + case (WorkoutTypes.WORKOUTTYPE_FIXEDDIST_INTERVAL): + response.addCommand(commands[i].command) + i++ // Move to the duration + intervalLength = commands[i].data + response.addCommand(commands[i].command) + i++ // Move to the rest specification + pauseLength = commands[i].data + response.addCommand(commands[i].command) + j = 0 + while (j < 25) { + this.#workoutplan.addInterval('distance', intervalLength) + this.#workoutplan.addInterval('rest', pauseLength) + j++ + } + log.debug(`PM5 WORKOUTTYPE_FIXEDDIST_INTERVAL is mapped to 25 '${this.#workoutplan.forelastInterval().type}' intervals with ${this.#workoutplan.forelastInterval().targetDistance} meters length, followed by a ${this.#workoutplan.lastInterval().targetTime} seconds '${this.#workoutplan.lastInterval().type}' intervals`) + break + default: + response.addCommand(commands[i].command) + } + break + case (ProprietaryLongSetConfigCommands.CSAFE_PM_SET_INTERVALTYPE): + if (commandData[0] === IntervalTypes.INTERVALTYPE_NONE) { + this.#workoutplan.addInterval('justrow', commands[i].data) + log.debug(`command ${i + 1}, CSAFE_PM_SET_INTERVALTYPE, ${swapObjectPropertyValues(IntervalTypes)[commandData[0]]}, mapped to '${this.#workoutplan.lastInterval().type}' interval`) + } + response.addCommand(commands[i].command) + break + case (ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTDURATION): + if (commandData[0] === DurationTypes.CSAFE_DISTANCE_DURATION) { + this.#workoutplan.addInterval('distance', commands[i].data) + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}, CSAFE_PM_SET_WORKOUTDURATION, ${swapObjectPropertyValues(DurationTypes)[commandData[0]]}, mapped to '${this.#workoutplan.lastInterval().type}' interval, length ${this.#workoutplan.lastInterval().targetDistance} meters`) + } else { + this.#workoutplan.addInterval('time', commands[i].data) + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}, CSAFE_PM_SET_WORKOUTDURATION, ${swapObjectPropertyValues(DurationTypes)[commandData[0]]}, mapped to '${this.#workoutplan.lastInterval().type}' interval, duration ${this.#workoutplan.lastInterval().targetTime} seconds`) + } + break + case (ProprietaryLongSetConfigCommands.CSAFE_PM_SET_SPLITDURATION): + if (commandData[0] === DurationTypes.CSAFE_DISTANCE_DURATION) { + this.#workoutplan.addSplit('distance', commands[i].data) + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}, CSAFE_PM_SET_SPLITDURATION, ${swapObjectPropertyValues(DurationTypes)[commandData[0]]}, mapped to '${this.#workoutplan.lastInterval().split.type}' split, length ${this.#workoutplan.lastInterval().split.targetDistance} meters`) + } else { + this.#workoutplan.addSplit('time', commands[i].data) + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}, CSAFE_PM_SET_SPLITDURATION, ${swapObjectPropertyValues(DurationTypes)[commandData[0]]}, mapped to '${this.#workoutplan.lastInterval().split.type}' split, duration ${this.#workoutplan.lastInterval().split.targetTime} seconds`) + } + break + case (ProprietaryLongSetConfigCommands.CSAFE_PM_SET_TARGETPACETIME): + // Feature not yet implemented in Open Rowing Monitor + this.#workoutplan.addPaceTarget(commands[i].data) + response.addCommand(commands[i].command) + log.error(`command ${i + 1}, CSAFE_PM_SET_TARGETPACETIME interval target pace ${500 * this.#workoutplan.lastInterval().targetLinearVelocity} seconds/500m, NOT IMPLEMENTED YET!`) + break + case (ProprietaryLongSetConfigCommands.CSAFE_PM_SET_RESTDURATION): + this.#workoutplan.addInterval('rest', commands[i].data) + response.addCommand(commands[i].command) + if (this.#workoutplan.lastInterval().type === 'rest') { + log.debug(`command ${i + 1}, CSAFE_PM_SET_RESTDURATION, mapped to '${this.#workoutplan.lastInterval().type}' interval, length ${this.#workoutplan.lastInterval().targetTime} seconds`) + } else { + log.debug(`command ${i + 1}, CSAFE_PM_SET_RESTDURATION, ignored as it was empty`) + } + break + case (ProprietaryLongSetConfigCommands.CSAFE_PM_CONFIGURE_WORKOUT): + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}, CSAFE_PM_CONFIGURE_WORKOUT Programming Mode: ${commandData[0] === 0 ? 'Disabled' : 'Enabled'}`) + break + case (ProprietaryLongGetConfigCommands.CSAFE_PM_GET_EXTENDED_HRBELT_INFO): + response.addCommand( + ProprietaryLongGetConfigCommands.CSAFE_PM_GET_EXTENDED_HRBELT_INFO, + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + ) + log.debug(`command ${i + 1}, CSAFE_PM_GET_EXTENDED_HRBELT_INFO`) + break + case (ProprietaryLongSetDataCommands.CSAFE_PM_SET_EXTENDED_HRBELT_INFO): + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}, CSAFE_PM_SET_EXTENDED_HRBELT_INFO`) + break + case (ProprietaryShortGetConfigCommands.CSAFE_PM_GET_DATETIME): + response.addCommand(ProprietaryShortGetConfigCommands.CSAFE_PM_GET_DATETIME, new Concept2Date().toC2DateByteArray()) + log.debug(`command ${i + 1}, CSAFE_PM_GET_DATETIME`) + break + case (ProprietaryLongSetConfigCommands.CSAFE_PM_SET_SCREENSTATE): + /* eslint-disable max-depth -- Screenstate is a nasty beast to handle, requiring quite some layers to make sense of it */ + if (commandData[0] === ScreenTypes.SCREENTYPE_WORKOUT) { + switch (commandData[1]) { + case ScreenValue.SCREENVALUEWORKOUT_TERMINATEWORKOUT: + // we can handle specific commands and communicate back via the controlPointCallback by calling a Command + // EXR and the PM5 routinely send this at the START of a rowing session. To prevent this from blocking valid sessions, it is mapped to the startOrResume event + this.#controlPointCallback({ req: { name: 'startOrResume', data: {} } }) + break + case (ScreenValue.SCREENVALUEWORKOUT_PREPARETOROWWORKOUT): + // TODO: the ControlPointEvent data interface should be fixed because it is not unified now across the consumers. The peripherals are the only one using the `req: {name: etc.}`format + if (this.#workoutplan.length() > 0) { + // We have a workout plan with defined intervals, let's tell everybody the good news! + this.#controlPointCallback({ req: { name: 'updateIntervalSettings', data: this.#workoutplan.result() } }) + this.#workoutplan.reset() + } + this.#controlPointCallback({ req: { name: 'start', data: {} } }) + break + case (ScreenValue.SCREENVALUEWORKOUT_VIRTUALKEY_D): + // The 'Resume' button is pressed + this.#controlPointCallback({ req: { name: 'startOrResume', data: {} } }) + break + // no default + } + } + /* eslint-enable max-depth */ + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}, CSAFE_PM_SET_SCREENSTATE data: ${swapObjectPropertyValues(ScreenTypes)[commandData[0]]}, ${swapObjectPropertyValues(ScreenValue)[commandData[1]]}`) + break + default: + response.addCommand(commands[i].command) + log.debug(`command ${i + 1}: unhandled command ${swapObjectPropertyValues(ProprietaryShortGetConfigCommands)[commands[i].command]}`) + } + i++ + } + this.#controlTransmitCharacteristic.notify(response.build()) + } + /* eslint-enable max-statements, max-depth */ +} diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeManagerService.test.js b/app/peripherals/ble/pm5/csafe-service/CsafeManagerService.test.js new file mode 100644 index 0000000000..0fb1b006ca --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeManagerService.test.js @@ -0,0 +1,57 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import * as assert from 'uvu/assert' +import { suite } from 'uvu' + +import { CsafeManagerService } from './CsafeManagerService.js' +import { ProprietaryLongSetDataCommands } from './CsafeCommandsMapping.js' + +const cafeManagerService = suite('CsafeManagerService') + +cafeManagerService('should handle CSAFE_PM_GET_EXTENDED_HRBELT_INFO', () => { + const expectedBuffer = [0xF1, 0x01, 0x7F, 0x09, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF2] + const csafeManager = new CsafeManagerService(/** @type {any} */ ({ + notify: (/** @type {Buffer} */buffer) => { + assert.equal([...buffer], expectedBuffer) + } + }), /** @type {any} */ () => { return false }) + + csafeManager.processCommand([0xF1, 0x7F, 0x03, 0x57, 0x01, 0x00, 0x2A, 0xF2]) +}) + +cafeManagerService('should handle CSAFE_PM_SET_EXTENDED_HRBELT_INFO', () => { + const expectedBuffer = [0xF0, 0x00, 0xFD, 0x01, 0x77, 0x01, ProprietaryLongSetDataCommands.CSAFE_PM_SET_EXTENDED_HRBELT_INFO, 0x4E, 0xF2] + const csafeManager = new CsafeManagerService(/** @type {any} */ ({ + notify: (/** @type {Buffer} */buffer) => { + assert.equal([...buffer], expectedBuffer) + } + }), /** @type {any} */ () => { return false }) + + csafeManager.processCommand([0xF0, 0xFD, 0x00, 0x77, 0x09, ProprietaryLongSetDataCommands.CSAFE_PM_SET_EXTENDED_HRBELT_INFO, 0x07, 0x00, 0x0A, 0x00, 0xB0, 0x2F, 0xCD, 0x62, 0x7A, 0xF2]) +}) + +cafeManagerService('should create the response including commands that are not handled specifically', () => { + const expectedBuffer = [0xF1, 0x01, 0x7F, 0x0a, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x1d, 0xF2] + const csafeManager = new CsafeManagerService(/** @type {any} */ ({ + notify: (/** @type {Buffer} */buffer) => { + assert.equal([...buffer], expectedBuffer) + } + }), /** @type {any} */ () => { return false }) + + csafeManager.processCommand([0xF1, 0x7F, 0x04, 0x57, 0x01, 0x00, 0x39, 0x14, 0xF2]) +}) + +cafeManagerService('should handle extended frame responses', () => { + const expectedBuffer = [0xF0, 0x00, 0xFD, 0x01, 0x77, 0x01, 0x39, 0x4E, 0xF2] + const csafeManager = new CsafeManagerService(/** @type {any} */ ({ + notify: (/** @type {Buffer} */buffer) => { + assert.equal([...buffer], expectedBuffer) + } + }), /** @type {any} */ () => { return false }) + + csafeManager.processCommand([0xf0, 0xfd, 0x00, 0x77, 0x09, 0x39, 0x07, 0x00, 0x0a, 0x00, 0xb0, 0x2f, 0xcd, 0x62, 0x7a, 0xf2]) +}) + +cafeManagerService.run() diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeRequestFrame.js b/app/peripherals/ble/pm5/csafe-service/CsafeRequestFrame.js new file mode 100644 index 0000000000..8c9133157e --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeRequestFrame.js @@ -0,0 +1,138 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ + +import { toHexString } from '../../../../tools/Helper.js' + +import { CsafeCommand } from './CsafeCommand.js' +import { CsafeFrameBase } from './CsafeFrameBase.js' +import { UniqueFrameFlags } from './CsafeCommandsMapping.js' + +/** + * InvalidFrameError type. + * + * Thrown when a frame contains an invalid checksum. + */ +class InvalidFrameError extends Error {} + +export class CsafeRequestFrame { + /** + * Frame type (Standard/Extended) getter. + * @returns {UniqueFrameFlags} + */ + get frameType () { + return this.#frameContent[0] + } + + get commands () { + return this.#commands + } + + get proprietaryCommandWrapper () { + return this.#commandWrapperFlag + } + + get destinationAddress () { + return this.#destinationAddress + } + + get sourceAddress () { + return this.#sourceAddress + } + + /** + * @type {number | undefined} + */ + #destinationAddress = undefined + /** + * @type {number | undefined} + */ + #sourceAddress = undefined + /** + * @type {number | undefined} + */ + #commandWrapperFlag = undefined + /** + * @type {Array} + */ + #commands = [] + /** + * @type {Array} + */ + #frameContent + /** + * @param {Array} buffer + */ + constructor (buffer) { + this.#frameContent = CsafeFrameBase.unStuffByte(buffer) + + if (!this.#validateChecksum()) { + throw new InvalidFrameError(`Checksum does not match. ${toHexString(buffer)}`) + } + + this.#parse() + } + + /** + * Check if frame is C2 proprietary or public. + * @returns {this is {proprietaryCommandWrapper:number, #commandWrapperFlag: number}} + */ + isProprietary () { + return this.#commandWrapperFlag !== undefined && CsafeFrameBase.isProprietary(this.#commandWrapperFlag) + } + + /** + * Check if the command is C2 proprietary or public. + * @returns {this is { #destinationAddress: number, #sourceAddress: number, destinationAddress: number, sourceAddress: number }} + */ + isExtended () { + return this.frameType === UniqueFrameFlags.ExtendedStartFlag + } + + /** + * @param {import('./CsafeCommandsMapping.js').CsafeCommandsNumbers | undefined} commandNumber + */ + getCommand (commandNumber) { + return this.#commands.find((command) => command.command === commandNumber) + } + + #parse () { + // Standard frame (Standard Start Flag | Frame Contents | Checksum | Stop Flag) + // Extended frame (Extended Start Flag | Destination Address | Source Address | Frame Contents | Checksum | Stop Flag) + if (this.frameType === UniqueFrameFlags.ExtendedStartFlag) { + this.#destinationAddress = this.#frameContent[1] + this.#sourceAddress = this.#frameContent[2] + } + + const frameContentStartPos = this.frameType === UniqueFrameFlags.StandardStartFlag ? 1 : 3 + + this.#commandWrapperFlag = CsafeFrameBase.isProprietary(this.#frameContent[frameContentStartPos]) ? this.#frameContent[frameContentStartPos] : undefined + + const content = this.#frameContent.slice(this.#commandWrapperFlag === undefined ? frameContentStartPos : frameContentStartPos + 2, this.#frameContent.length - 2) + + for (let i = 0; i < content.length;) { + const command = content[i] + const isShortCommand = CsafeCommand.isShortCommand(command) + const commandDataLength = isShortCommand ? 0 : content[i + 1] + const data = content.slice(i + 2, i + 2 + commandDataLength) + + this.#commands.push( + new CsafeCommand(command, data) + ) + + i += commandDataLength + (isShortCommand ? 1 : 2) + } + } + + /** + * Validates the frame checksum byte. + */ + #validateChecksum () { + const endIdx = this.#frameContent.length - 2 + const checkBytes = this.#frameContent.slice(this.frameType === UniqueFrameFlags.StandardStartFlag ? 1 : 3, endIdx) + const validate = CsafeFrameBase.checksumFromBytes(checkBytes) + + return this.#frameContent[this.#frameContent.length - 2] === validate + } +} diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeRequestFrame.test.js b/app/peripherals/ble/pm5/csafe-service/CsafeRequestFrame.test.js new file mode 100644 index 0000000000..9ee0ee5e51 --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeRequestFrame.test.js @@ -0,0 +1,98 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import * as assert from 'uvu/assert' +import { suite } from 'uvu' + +import { ProprietaryLongSetConfigCommands, ScreenTypes, ScreenValue, WorkoutTypes } from './CsafeCommandsMapping.js' +import { CsafeRequestFrame } from './CsafeRequestFrame.js' + +const csafeRequestFrameTests = suite('CsafeRequestFrame') + +csafeRequestFrameTests('should parse single short (i.e. with no data)', () => { + const commandValue = 0x85 + const setDateCommand = [0xF1, 0x7E, 0x01, commandValue, 0xFA, 0xF2] + + const frame = new CsafeRequestFrame(setDateCommand) + + const expectedNumberOfCommands = 1 + + assert.ok(frame.isProprietary()) + assert.is(frame.commands.length, expectedNumberOfCommands) + assert.is(frame.commands[expectedNumberOfCommands - 1].command, commandValue) + assert.is(frame.commands[expectedNumberOfCommands - 1].data.length, 0) +}) + +csafeRequestFrameTests('should parse single long command (i.e. with data)', () => { + const commandValue = 0x57 + const data = [0x00] + const getExtendedHrBeltInfoCommand = [0xF1, 0x7F, 0x03, commandValue, data.length, ...data, 0x2A, 0xF2] + + const frame = new CsafeRequestFrame(getExtendedHrBeltInfoCommand) + + const expectedNumberOfCommands = 1 + + assert.ok(frame.isProprietary()) + assert.is(frame.commands.length, expectedNumberOfCommands) + assert.is(frame.commands[expectedNumberOfCommands - 1].command, commandValue) + assert.equal(frame.commands[expectedNumberOfCommands - 1].data, data) +}) + +csafeRequestFrameTests('should parse multi proprietary long commands', () => { + const setWorkoutTypeCommand = 0x01 + const setWorkoutTypeData = [WorkoutTypes.WORKOUTTYPE_JUSTROW_SPLITS] + const setScreenStateCommand = ProprietaryLongSetConfigCommands.CSAFE_PM_SET_SCREENSTATE + const setScreenStateValue = [ScreenTypes.SCREENTYPE_WORKOUT, ScreenValue.SCREENVALUEWORKOUT_PREPARETOROWWORKOUT] + // f1 76 07 01 01 01 13 02 00 01 61 f2 + const setJustRowWorkout = [0xF1, 0x76, 0x07, setWorkoutTypeCommand, setWorkoutTypeData.length, ...setWorkoutTypeData, setScreenStateCommand, setScreenStateValue.length, ...setScreenStateValue, 0x61, 0xF2] + + const frame = new CsafeRequestFrame(setJustRowWorkout) + + const expectedNumberOfCommands = 2 + + assert.ok(frame.isProprietary()) + assert.is(frame.commands.length, expectedNumberOfCommands) + assert.equal(frame.commands[0].data, setWorkoutTypeData) + assert.equal(frame.commands[1].data, setScreenStateValue) +}) + +csafeRequestFrameTests('should parse multi proprietary short commands', () => { + const getDateCommand = 0x85 + const getHardwareVersionCommand = 0x81 + const getWorkDistanceCommand = 0xA3 + const multiShortCommand = [0xF1, 0x76, 0x03, getWorkDistanceCommand, getDateCommand, getHardwareVersionCommand, 0xD2, 0xF2] + + const frame = new CsafeRequestFrame(multiShortCommand) + + const expectedNumberOfCommands = 3 + + assert.ok(frame.isProprietary()) + assert.is(frame.commands.length, expectedNumberOfCommands) +}) + +csafeRequestFrameTests('should parse byte stuffed frame', () => { + const f0 = [0xF3, 0x00] + const f1 = [0xF3, 0x01] + const f2 = [0xF3, 0x02] + const f3 = [0xF3, 0x03] + const multiShortCommand = [0xF1, ...f0, 0x81, ...f1, ...f2, ...f3, 0x81, 0xF2] + + const frame = new CsafeRequestFrame(multiShortCommand) + + const expectedNumberOfCommands = 5 + assert.is(frame.commands.length, expectedNumberOfCommands) + + assert.is(frame.commands[0].command.toString(16), 'f0') + assert.is(frame.commands[2].command.toString(16), 'f1') + assert.is(frame.commands[3].command.toString(16), 'f2') + assert.is(frame.commands[4].command.toString(16), 'f3') +}) + +csafeRequestFrameTests('should validate checksum', () => { + const testFrame = [0xf1, 0x76, 0x60, 0x18, 0x01, 0x00, 0x01, 0x01, 0x08, 0x17, 0x01, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x75, 0x30, 0x04, 0x02, 0x01, 0x2c, 0x14, 0x01, 0x01, 0x18, 0x01, 0x01, 0x17, 0x01, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x5d, 0xc0, 0x04, 0x02, 0x00, 0xf3, 0x00, 0x14, 0x01, 0x01, 0x18, 0x01, 0x02, 0x17, 0x01, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x46, 0x50, 0x04, 0x02, 0x00, 0xb4, 0x14, 0x01, 0x01, 0x18, 0x01, 0x03, 0x17, 0x01, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x2e, 0xe0, 0x04, 0x02, 0x00, 0x78, 0x14, 0x01, 0x01, 0x18, 0x01, 0x04, 0x17, 0x01, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x17, 0x70, 0x65, 0xf2] + + assert.not.throws(() => new CsafeRequestFrame(testFrame)) +}) + +csafeRequestFrameTests.run() diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeResponseFrame.js b/app/peripherals/ble/pm5/csafe-service/CsafeResponseFrame.js new file mode 100644 index 0000000000..0761beae1c --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeResponseFrame.js @@ -0,0 +1,152 @@ +'use strict' + +import { PreviousFrameStatus, StateMachineState, UniqueFrameFlags } from './CsafeCommandsMapping.js' +import { CsafeCommand } from './CsafeCommand.js' +import { CsafeFrameBase } from './CsafeFrameBase.js' + +export class CsafeResponseFrame { + /** + * Frame type (Standard/Extended) getter. + * @returns {UniqueFrameFlags} + */ + get frameType () { + return this.#frameType + } + + get commands () { + return this.#commands + } + + #frameToggle + #stateMachineState + #frameType + #previousStatus + #destinationAddress + #sourceAddress + /** + * @type {Array} + */ + #commands = [] + /** + * @type {import('./CsafeCommandsMapping.js').CsafeCommandsNumbers | undefined} + */ + #proprietaryWrapper = undefined + + /** + * @param {number} [frameToggle] + * @param {StateMachineState} [stateMachineState] + * @param {UniqueFrameFlags} [frameType] + * @param {PreviousFrameStatus} [previousStatus] + */ + constructor (frameToggle = 0, frameType = UniqueFrameFlags.StandardStartFlag, stateMachineState = StateMachineState.Ready, previousStatus = PreviousFrameStatus.Ok) { + this.#frameToggle = frameToggle + this.#stateMachineState = stateMachineState + this.#frameType = frameType + this.#previousStatus = previousStatus + + if (frameType === UniqueFrameFlags.ExtendedStartFlag) { + this.#destinationAddress = 0x00 + this.#sourceAddress = 0xFD + } + } + + /** + * + * @param {import('./CsafeCommandsMapping.js').CsafeCommandsNumbers} command + * @param {Array} [data] + */ + addCommand (command, data = []) { + this.#commands.push(new CsafeCommand(command, data)) + } + + /** + * Set if frame is C2 proprietary or public. + * @param {number} command + */ + setProprietaryWrapper (command) { + this.#proprietaryWrapper = command + } + + /** + * Set Extended Frame's Destination Address. + * @param {number} command + */ + setDestinationAddress (command) { + if (this.#frameType !== UniqueFrameFlags.ExtendedStartFlag) { + throw new Error('This frame cannot have a Destination Address as it is not an extended frame') + } + + this.#destinationAddress = command + } + + /** + * Set Extended Frame's Source Address. + * @param {number} command + */ + setSourceAddress (command) { + if (this.#frameType !== UniqueFrameFlags.ExtendedStartFlag) { + throw new Error('This frame cannot have a Source Address as it is not an extended frame') + } + + this.#sourceAddress = command + } + + /** + * Check if the command is C2 proprietary or public. + * @returns {this is { #proprietaryWrapper: number }} + */ + isProprietary () { + return this.#proprietaryWrapper !== undefined + } + + /** + * Check if the command is C2 proprietary or public. + * @returns {this is { #destinationAddress: number, #sourceAddress: number, destinationAddress: number, sourceAddress: number }} + */ + isExtended () { + return this.#frameType === UniqueFrameFlags.ExtendedStartFlag + } + + build () { + const /** @type {Array} */ addresses = [] + + if (this.isExtended()) { + addresses.push(this.#destinationAddress) + addresses.push(this.#sourceAddress) + } + + const statusBit = this.#frameToggle << 7 | this.#previousStatus | this.#stateMachineState + const frameContent = [statusBit] + + const commands = this.#commands.reduce((/** @type {Array} */ buffer, command) => { + buffer.push(command.command) + if (command.data.length > 0) { + buffer.push(command.data.length) + buffer.push(...command.data) + } + + return buffer + }, []) + + if (this.isProprietary()) { + frameContent.push(this.#proprietaryWrapper) + frameContent.push(commands.length) + } + + frameContent.push(...commands) + + const checksum = CsafeFrameBase.checksumFromBytes(frameContent) + + const stuffedFrameContent = [...addresses, ...frameContent, checksum].reduce((/** @type {Array} */ buffer, byte) => { + if (CsafeFrameBase.shouldStuffByte(byte)) { + buffer.push(...CsafeFrameBase.stuffByte(byte)) + } else { + buffer.push(byte) + } + + return buffer + }, []) + + return Buffer.from([this.#frameType, ...stuffedFrameContent, UniqueFrameFlags.StopFlag]) + } +} diff --git a/app/peripherals/ble/pm5/csafe-service/CsafeResponseFrame.test.js b/app/peripherals/ble/pm5/csafe-service/CsafeResponseFrame.test.js new file mode 100644 index 0000000000..d9de90526d --- /dev/null +++ b/app/peripherals/ble/pm5/csafe-service/CsafeResponseFrame.test.js @@ -0,0 +1,110 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +import * as assert from 'uvu/assert' +import { suite } from 'uvu' + +import { PreviousFrameStatus, ProprietaryLongGetConfigCommands, ProprietaryLongSetConfigCommands, PublicLongCommands, StateMachineState, UniqueFrameFlags } from './CsafeCommandsMapping.js' +import { CsafeFrameBase } from './CsafeFrameBase.js' +import { CsafeResponseFrame } from './CsafeResponseFrame.js' + +const csafeResponseFrameTests = suite('CsafeResponseFrame') + +csafeResponseFrameTests('should calculate status byte correctly', () => { + const frameToggle = 1 + const stateMachineState = StateMachineState.InUse + const frameType = UniqueFrameFlags.StandardStartFlag + const previousStatus = PreviousFrameStatus.NotReady + const response = new CsafeResponseFrame(frameToggle, frameType, stateMachineState, previousStatus) + + const responseBuffer = response.build() + + assert.is(responseBuffer[1], frameToggle << 7 | previousStatus | stateMachineState) +}) + +csafeResponseFrameTests('should parse commands added with no data', () => { + const frameToggle = 1 + const response = new CsafeResponseFrame(frameToggle) + const commands = [ProprietaryLongGetConfigCommands.CSAFE_PM_GET_HRBELT_INFO, ProprietaryLongGetConfigCommands.CSAFE_PM_GET_EXTENDED_HRBELT_INFO] + response.addCommand(commands[0], []) + response.addCommand(commands[1], []) + + const responseBuffer = response.build() + + assert.is(responseBuffer[2], commands[0]) + assert.is(responseBuffer[3], commands[1]) +}) + +csafeResponseFrameTests('should add proprietary wrapper to the response if set', () => { + const commands = [ProprietaryLongGetConfigCommands.CSAFE_PM_GET_HRBELT_INFO, ProprietaryLongGetConfigCommands.CSAFE_PM_GET_EXTENDED_HRBELT_INFO] + const response = new CsafeResponseFrame() + response.addCommand(commands[0], []) + response.addCommand(commands[1], []) + + response.setProprietaryWrapper(PublicLongCommands.CSAFE_GETPMCFG_CMD) + + const responseBuffer = response.build() + + assert.is(responseBuffer[4], commands[0]) + assert.is(responseBuffer[5], commands[1]) +}) + +csafeResponseFrameTests('should parse commands added with data', () => { + const frameToggle = 1 + const response = new CsafeResponseFrame(frameToggle) + const commands = [ProprietaryLongGetConfigCommands.CSAFE_PM_GET_HRBELT_INFO, ProprietaryLongGetConfigCommands.CSAFE_PM_GET_EXTENDED_HRBELT_INFO] + response.addCommand(commands[0], [1, 1, 1, 0, 1]) + response.addCommand(commands[1], [1, 1, 1, 0, 0, 0, 1]) + + const responseBuffer = response.build() + + const firstCommand = responseBuffer.subarray(2, 2 + 2 + response.commands[0].data.length) + const secondCommand = responseBuffer.subarray(2 + firstCommand.byteLength, firstCommand.byteLength + 2 + 2 + response.commands[1].data.length) + + assert.is(firstCommand[1], response.commands[0].data.length, 'Length byte') + assert.equal([...firstCommand.subarray(2, firstCommand.byteLength)], response.commands[0].data, 'Data items') + assert.is(secondCommand[1], response.commands[1].data.length, 'Length byte') + assert.equal([...secondCommand.subarray(2, secondCommand.byteLength)], response.commands[1].data, 'Data items') +}) + +csafeResponseFrameTests('should stuff bytes that need byte-stuffing', () => { + const frameToggle = 1 + const response = new CsafeResponseFrame(frameToggle) + + response.setProprietaryWrapper(PublicLongCommands.CSAFE_SETPMCFG_CMD) + + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTINTERVALCOUNT) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTTYPE) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_INTERVALTYPE) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTDURATION) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_RESTDURATION) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_TARGETPACETIME) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_CONFIGURE_WORKOUT) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTINTERVALCOUNT) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_INTERVALTYPE) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTDURATION) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_RESTDURATION) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_TARGETPACETIME) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_CONFIGURE_WORKOUT) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_WORKOUTTYPE) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_SPLITDURATION) + response.addCommand(ProprietaryLongSetConfigCommands.CSAFE_PM_SET_SCREENSTATE) + + const responseBuffer = response.build() + + assert.equal([...responseBuffer.subarray(responseBuffer.byteLength - 3, responseBuffer.byteLength - 1)], CsafeFrameBase.stuffByte(0xF1)) +}) + +csafeResponseFrameTests('should calculate proper checksum', () => { + const frameToggle = 1 + const response = new CsafeResponseFrame(frameToggle, UniqueFrameFlags.ExtendedStartFlag) + response.setProprietaryWrapper(0x77) + + response.addCommand(0x39, []) + + const responseBuffer = response.build() + assert.is(responseBuffer[responseBuffer.byteLength - 2], 0xCE) +}) + +csafeResponseFrameTests.run() diff --git a/app/peripherals/ble/pm5/heart-rate-service/Pm5HeartRateControlService.js b/app/peripherals/ble/pm5/heart-rate-service/Pm5HeartRateControlService.js new file mode 100644 index 0000000000..bef05939e0 --- /dev/null +++ b/app/peripherals/ble/pm5/heart-rate-service/Pm5HeartRateControlService.js @@ -0,0 +1,102 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + The Control service can be used to send control commands to the PM5 device + ToDo: not yet wired +*/ +import NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +import { GattService } from '../../BleManager.js' + +import { toC2128BitUUID } from '../Pm5Constants.js' + +const log = loglevel.getLogger('Peripherals') + +export class Pm5HeartRateControlService extends GattService { + /** + * @type {HeartRateMeasurementEvent} + */ + #heartRateMeasurementEvent = { + rrIntervals: [] + } + + #lastBeatTime = 0 + #lastBeatCount = 0 + + constructor () { + super({ + name: 'Control Service', + uuid: toC2128BitUUID('0040'), + characteristics: [ + { + uuid: toC2128BitUUID('0041'), + properties: ['write', 'write-without-response'], + onWrite: (_connection, needsResponse, data, callback) => { + log.debug('PM5 Heart Rate Received is called:', data) + + this.#onWrite(data) + + if (needsResponse) { + callback(NodeBleHost.AttErrors.SUCCESS) // actually only needs to be called when needsResponse is true + } + } + } + ] + }) + } + + /** + * @param {Buffer} data + */ + #onWrite (data) { + // Bluetooth + if (data.readUint8(0) === 0) { + // Energy Expended Lo, (BT HRM value) + // Energy Expended Hi, + this.#heartRateMeasurementEvent.energyExpended = data.readUint16LE(1) + + // RR Interval Lo, (BT HRM value) + // RR Interval Hi, + this.#heartRateMeasurementEvent.rrIntervals = [data.readUint16LE(3)] + // HR Value Lo, (BT HRM value) + // HR Value Hi, + this.#heartRateMeasurementEvent.heartrate = data.readUint16LE(5) + // Status Flags, (BT HRM value) + const flags = data.readUint8(6) + const hasSensorContact = Boolean(flags >> 1 & 0x01) // Checking bits 1 and 2 (sensor contact) + const isSensorContactSupported = Boolean(flags >> 2 & 0x01) // Checking bits 1 and 2 (sensor contact) + this.#heartRateMeasurementEvent.hasContact = isSensorContactSupported ? hasSensorContact : undefined + } + + if (data.readUint8(0) === 1) { + // HR Measurement Lo, (ANT HRM value) + // HR Measurement Hi, + const beatTime = data.readUint16LE(1) + // Heart Beat Count (ANT HRM value) + const beatCount = data.readUint8(3) + // HR (ANT HRM value) + this.#heartRateMeasurementEvent.heartrate = data.readUint8(4) + + this.#heartRateMeasurementEvent.rrIntervals = [] + if (beatCount - this.#lastBeatCount === 1) { + const beatTimeDiff = this.#lastBeatCount > beatTime ? 65535 - (this.#lastBeatTime - beatTime) : beatTime - this.#lastBeatTime + + this.#heartRateMeasurementEvent.rrIntervals = [Math.round(beatTimeDiff / 1024 * 1000) / 1000] + } + + this.#lastBeatCount = beatCount + this.#lastBeatTime = beatTime + } + + // Spare_0, + // Spare_1, + // Spare_2, + // Spare_3, + // Spare_4, + // Spare_5, + // Spare_6, + // Spare_7 + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/Pm5RowingService.js b/app/peripherals/ble/pm5/rowing-service/Pm5RowingService.js new file mode 100644 index 0000000000..4062ad68aa --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/Pm5RowingService.js @@ -0,0 +1,372 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * @file This is the central service to get information about the workout. It implementats the BLE message service as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#message-grouping-and-timing|the description of desired behaviour} +*/ +import { createSeries } from '../../../../engine/utils/Series.js' +import { GattService } from '../../BleManager.js' +import { createStaticReadCharacteristic } from '../../common/StaticReadCharacteristic.js' +import { appendPauseIntervalToActiveInterval, mergeTwoSplits } from '../utils/ORMtoC2Mapper.js' + +import { toC2128BitUUID } from '../Pm5Constants.js' + +import { AdditionalSplitDataCharacteristic } from './session-characteristics/AdditionalSplitDataCharacteristic.js' +import { AdditionalStatus2Characteristic } from './status-characteristics/AdditionalStatus2Characteristic.js' +import { AdditionalStatus3Characteristic } from './status-characteristics/AdditionalStatus3Characteristic.js' +import { AdditionalStatusCharacteristic } from './status-characteristics/AdditionalStatusCharacteristic.js' +import { AdditionalStrokeDataCharacteristic } from './other-characteristics/AdditionalStrokeDataCharacteristic.js' +import { AdditionalWorkoutSummary2Characteristic } from './session-characteristics/AdditionalWorkoutSummary2Characteristic.js' +import { AdditionalWorkoutSummaryCharacteristic } from './session-characteristics/AdditionalWorkoutSummaryCharacteristic.js' +import { ForceCurveCharacteristic } from './other-characteristics/ForceCurveCharacteristic.js' +import { GeneralStatusCharacteristic } from './status-characteristics/GeneralStatusCharacteristic.js' +import { LoggedWorkoutCharacteristic } from './session-characteristics/LoggedWorkoutCharacteristic.js' +import { MultiplexedCharacteristic } from './other-characteristics/MultiplexedCharacteristic.js' +import { SampleRateCharacteristic } from './other-characteristics/SampleRateCharacteristic.js' +import { SplitDataCharacteristic } from './session-characteristics/SplitDataCharacteristic.js' +import { StrokeDataCharacteristic } from './other-characteristics/StrokeDataCharacteristic.js' +import { WorkoutSummaryCharacteristic } from './session-characteristics/WorkoutSummaryCharacteristic.js' + +export class Pm5RowingService extends GattService { + #generalStatus + #additionalStatus + #additionalStatus2 + #additionalStatus3 + + #strokeData + #additionalStrokeData + #forceCurveData + + #splitData + #additionalSplitData + + #workoutSummary + #additionalWorkoutSummary + #additionalWorkoutSummary2 + + #loggedWorkout + + /** + * @type {Metrics} + */ + #lastKnownMetrics + #config + + #splitHR + #workoutHR + #previousSplitMetrics + #partialC2SplitMetrics + #C2SplitNumber + #lastActiveIntervalMetrics + #accumulatedC2RestTime + #timer + + /** + * @param {Config} config + */ + /* eslint-disable max-statements -- This is the heart of the PM5 interface with a lot of characteristics, so there is a lot to initialise */ + constructor (config) { + const multiplexedCharacteristic = new MultiplexedCharacteristic() + const generalStatus = new GeneralStatusCharacteristic(multiplexedCharacteristic) + const additionalStatus = new AdditionalStatusCharacteristic(multiplexedCharacteristic) + const additionalStatus2 = new AdditionalStatus2Characteristic(multiplexedCharacteristic) + const additionalStatus3 = new AdditionalStatus3Characteristic(multiplexedCharacteristic) + const strokeData = new StrokeDataCharacteristic(multiplexedCharacteristic) + const forceCurveData = new ForceCurveCharacteristic(multiplexedCharacteristic) + const additionalStrokeData = new AdditionalStrokeDataCharacteristic(multiplexedCharacteristic) + const splitData = new SplitDataCharacteristic(multiplexedCharacteristic) + const additionalSplitData = new AdditionalSplitDataCharacteristic(multiplexedCharacteristic) + const workoutSummary = new WorkoutSummaryCharacteristic(multiplexedCharacteristic) + const additionalWorkoutSummary = new AdditionalWorkoutSummaryCharacteristic(multiplexedCharacteristic) + const loggedWorkout = new LoggedWorkoutCharacteristic(multiplexedCharacteristic) + + super({ + name: 'Rowing Service', + uuid: toC2128BitUUID('0030'), + characteristics: [ + // C2 rowing general status + generalStatus.characteristic, + // C2 rowing additional status + additionalStatus.characteristic, + // C2 rowing additional status 2 + additionalStatus2.characteristic, + // C2 rowing additional status 3 + additionalStatus3.characteristic, + // C2 rowing general status and additional status sample rate (0 - for 1000 ms) + new SampleRateCharacteristic(config).characteristic, + // C2 rowing stroke data + strokeData.characteristic, + // C2 rowing additional stroke data + additionalStrokeData.characteristic, + // C2 rowing split/interval data (18 bytes) + splitData.characteristic, + // C2 rowing additional split/interval data (19 bytes) + additionalSplitData.characteristic, + // C2 rowing end of workout summary data (20 bytes) + workoutSummary.characteristic, + // C2 rowing end of workout additional summary data (19 bytes) + additionalWorkoutSummary.characteristic, + // C2 rowing heart rate belt information (6 bytes) - Specs states Write is necessary we omit that + createStaticReadCharacteristic(toC2128BitUUID('003B'), new Array(6).fill(0), 'Heart Rate Belt Information', true), + // C2 force curve data (2-288 bytes) + forceCurveData.characteristic, + // Logged Workout + loggedWorkout.characteristic, + // C2 multiplexed information + multiplexedCharacteristic.characteristic + ] + }) + this.#generalStatus = generalStatus + this.#additionalStatus = additionalStatus + this.#additionalStatus2 = additionalStatus2 + this.#additionalStatus3 = additionalStatus3 + this.#strokeData = strokeData + this.#additionalStrokeData = additionalStrokeData + this.#splitData = splitData + this.#forceCurveData = forceCurveData + this.#additionalSplitData = additionalSplitData + this.#workoutSummary = workoutSummary + this.#additionalWorkoutSummary = additionalWorkoutSummary + this.#additionalWorkoutSummary2 = new AdditionalWorkoutSummary2Characteristic(multiplexedCharacteristic) + this.#loggedWorkout = loggedWorkout + this.#lastKnownMetrics = { + .../** @type {Metrics} */({}), + sessionState: 'WaitingForStart', + strokeState: 'WaitingForDrive', + totalMovingTime: 0, + totalLinearDistance: 0, + cycleLinearVelocity: 0, + cycleStrokeRate: 0, + cyclePace: 0, + cyclePower: 0, + workout: { + timeSpent: { + total: 0, + rest: 0 + }, + distance: { + fromStart: 0 + }, + calories: { + totalSpent: 0 + } + }, + interval: { + type: 'justrow', + movingTime: { + target: 0 + }, + timeSpent: { + moving: 0 + }, + distance: { + target: 0 + }, + pace: { + average: 0 + } + }, + split: { + type: 'justrow', + pace: { + average: 0 + }, + power: { + average: 0 + }, + calories: { + averagePerHour: 0 + } + }, + dragFactor: config.rowerSettings.dragFactor + } + this.#splitHR = createSeries() + this.#workoutHR = createSeries() + this.#config = config + this.#C2SplitNumber = 0 + this.#previousSplitMetrics = { + totalMovingTime: 0, + totalLinearDistance: 0 + } + this.#partialC2SplitMetrics = null + this.#lastActiveIntervalMetrics = null + this.#accumulatedC2RestTime = 0 + this.#timer = setTimeout(() => { this.#onBroadcastInterval() }, this.#config.pm5UpdateInterval) + } + /* eslint-enable max-statements */ + + /** + * @param {Metrics} metrics + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#message-grouping-and-timing|the message timing and grouping analysis} + * @remark Always use a deepClone of the metrics to prevent the subsequent merging with other splits (around an unplanned pause) from affecting the data reported in the recorders and other peripherals! + */ + notifyData (metrics) { + if (metrics.metricsContext === undefined) { return } + if (!(metrics.sessionState === 'Stopped' && !metrics.metricsContext.isSessionStop)) { this.#lastKnownMetrics = structuredClone(metrics) } + if (this.#partialC2SplitMetrics !== null) { this.#lastKnownMetrics = mergeTwoSplits(this.#partialC2SplitMetrics, this.#lastKnownMetrics) } + if (this.#lastActiveIntervalMetrics !== null && metrics.sessionState !== 'Stopped') { this.#lastKnownMetrics = appendPauseIntervalToActiveInterval(this.#lastActiveIntervalMetrics, structuredClone(metrics)) } + this.#lastKnownMetrics.split.C2number = this.#C2SplitNumber + this.#lastKnownMetrics.workout.timeSpent.C2Rest = this.#accumulatedC2RestTime + switch (true) { + case (metrics.metricsContext.isSessionStart): + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#genericStatusDataNotifies(this.#lastKnownMetrics, this.#previousSplitMetrics) + break + case (metrics.metricsContext.isSessionStop): + this.#partialC2SplitMetrics = null + this.#lastActiveIntervalMetrics = this.#lastKnownMetrics // Needed just in case the session is activated again + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#genericStatusDataNotifies(this.#lastKnownMetrics, this.#previousSplitMetrics) + this.#splitDataNotifies(this.#lastKnownMetrics, this.#splitHR) + this.#workoutEndDataNotifies(this.#lastKnownMetrics, this.#workoutHR) + break + case (metrics.metricsContext.isPauseStart && !this.#lastKnownMetrics.metricsContext.isUnplannedPause): + // This is the start of a planned pause + this.#partialC2SplitMetrics = null + this.#lastActiveIntervalMetrics = this.#lastKnownMetrics + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#genericStatusDataNotifies(this.#lastKnownMetrics, this.#previousSplitMetrics) + this.#C2SplitNumber++ + this.#splitHR.reset() + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + break + case (metrics.metricsContext.isPauseStart): + // This is the start of an unplanned pause + this.#partialC2SplitMetrics = this.#lastKnownMetrics + /** @ToDo: Think how to handle HR data well */ + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#genericStatusDataNotifies(this.#lastKnownMetrics, this.#previousSplitMetrics) + this.#previousSplitMetrics = { + totalMovingTime: this.#lastKnownMetrics.split.timeSpent.total, + totalLinearDistance: this.#lastKnownMetrics.split.distance.fromStart + } + this.#splitHR.reset() + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + break + case (metrics.metricsContext.isPauseEnd && !this.#lastKnownMetrics.metricsContext.isUnplannedPause): + // End of a planned pause + this.#lastActiveIntervalMetrics = null + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#accumulatedC2RestTime = this.#accumulatedC2RestTime + this.#lastKnownMetrics.interval.timeSpent.rest + this.#lastKnownMetrics.workout.timeSpent.C2Rest = this.#accumulatedC2RestTime + this.#recoveryStartDataNotifies(this.#lastKnownMetrics) + this.#genericStatusDataNotifies(this.#lastKnownMetrics, this.#previousSplitMetrics) + this.#splitDataNotifies(this.#lastKnownMetrics, this.#splitHR) + this.#previousSplitMetrics = { + totalMovingTime: this.#lastKnownMetrics.split.timeSpent.total, + totalLinearDistance: this.#lastKnownMetrics.split.distance.fromStart + } + this.#C2SplitNumber++ + this.#splitHR.reset() + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + break + case (metrics.metricsContext.isPauseEnd): + // End of an unplanned pause + this.#partialC2SplitMetrics = this.#lastKnownMetrics + /** @ToDo: Adapt to handle an unplanned pause */ + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#genericStatusDataNotifies(this.#lastKnownMetrics, this.#previousSplitMetrics) + this.#splitHR.reset() + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + break + case (metrics.metricsContext.isSplitEnd): + this.#partialC2SplitMetrics = null + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#genericStatusDataNotifies(this.#lastKnownMetrics, this.#previousSplitMetrics) + this.#splitDataNotifies(this.#lastKnownMetrics, this.#splitHR) + this.#previousSplitMetrics = { + totalMovingTime: this.#lastKnownMetrics.split.timeSpent.total, + totalLinearDistance: this.#lastKnownMetrics.split.distance.fromStart + } + this.#C2SplitNumber++ + this.#splitHR.reset() + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + break + case (metrics.metricsContext.isDriveStart): + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#driveStartNotifies(this.#lastKnownMetrics) + break + case (metrics.metricsContext.isRecoveryStart): + this.#splitHR.push(this.#lastKnownMetrics.heartrate) + this.#workoutHR.push(this.#lastKnownMetrics.heartrate) + this.#recoveryStartDataNotifies(this.#lastKnownMetrics) + break + default: + // Do nothing + } + } + + #onBroadcastInterval () { + this.#genericStatusDataNotifies(this.#lastKnownMetrics, this.#previousSplitMetrics) + } + + /** + * @param {Metrics} metrics + * @param {SplitTimeDistanceData} previousSplitMetrics + * @param {SegmentMetrics} splitMetrics + */ + #genericStatusDataNotifies (metrics, previousSplitMetrics) { + clearTimeout(this.#timer) + this.#generalStatus.notify(metrics) + this.#additionalStatus.notify(metrics) + this.#additionalStatus2.notify(metrics, previousSplitMetrics) + this.#additionalStatus3.notify(metrics) + this.#timer = setTimeout(() => { this.#onBroadcastInterval() }, this.#config.pm5UpdateInterval) + } + + /** + * @param {Metrics} metrics + * @param {SegmentMetrics} splitMetrics + */ + #splitDataNotifies (metrics, splitHRMetrics) { + clearTimeout(this.#timer) + this.#splitData.notify(metrics) + this.#additionalSplitData.notify(metrics, splitHRMetrics) + this.#timer = setTimeout(() => { this.#onBroadcastInterval() }, this.#config.pm5UpdateInterval) + } + + /** + * @param {Metrics} metrics + */ + #driveStartNotifies (metrics) { + clearTimeout(this.#timer) + this.#strokeData.notify(metrics) + this.#timer = setTimeout(() => { this.#onBroadcastInterval() }, this.#config.pm5UpdateInterval) + } + + /** + * @param {Metrics} metrics + */ + #recoveryStartDataNotifies (metrics) { + clearTimeout(this.#timer) + this.#strokeData.notify(metrics) + this.#additionalStrokeData.notify(metrics) + this.#forceCurveData.notify(metrics) + this.#timer = setTimeout(() => { this.#onBroadcastInterval() }, this.#config.pm5UpdateInterval) + } + + /** + * @param {Metrics} metrics + * @param {SegmentMetrics} workoutMetrics + */ + #workoutEndDataNotifies (metrics, workoutHRMetrics) { + clearTimeout(this.#timer) + this.#workoutSummary.notify(metrics, workoutHRMetrics) + this.#additionalWorkoutSummary.notify(metrics) + this.#additionalWorkoutSummary2.notify(metrics) + this.#loggedWorkout.notify(metrics, workoutHRMetrics) + this.#timer = setTimeout(() => { this.#onBroadcastInterval() }, this.#config.pm5UpdateInterval) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/other-characteristics/AdditionalStrokeDataCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/other-characteristics/AdditionalStrokeDataCharacteristic.js new file mode 100644 index 0000000000..15dca3896e --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/other-characteristics/AdditionalStrokeDataCharacteristic.js @@ -0,0 +1,64 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the AdditionalStrokeData as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#0x0036-additional-stroke-data|the description of desired behaviour} +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' + +import { toC2128BitUUID } from '../../Pm5Constants.js' + +export class AdditionalStrokeDataCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('./MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Additional Stroke Data', + uuid: toC2128BitUUID('0036'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + // elapsedTime: UInt24LE in 0.01 sec + bufferBuilder.writeUInt24LE(data.interval.timeSpent.total > 0 && data.sessionState !== 'WaitingForStart' ? Math.round(data.interval.timeSpent.total * 100) : 0) + // strokePower: UInt16LE in watts + bufferBuilder.writeUInt16LE(data.cyclePower > 0 ? Math.round(data.cyclePower) : 0) + // strokeCalories: UInt16LE in cal + bufferBuilder.writeUInt16LE(data.strokeCalories > 0 ? Math.round(data.strokeCalories * 1000) : 0) + // strokeCount: UInt16LE + bufferBuilder.writeUInt16LE(data.interval.numberOfStrokes > 0 ? Math.round(data.interval.numberOfStrokes) : 0) + // projectedWorkTime: UInt24LE in 1 sec + bufferBuilder.writeUInt24LE(data.interval.movingTime.projectedEnd > 0 ? Math.round(data.interval.movingTime.projectedEnd) : 0) + // projectedWorkDistance: UInt24LE in 1 m + bufferBuilder.writeUInt24LE(data.interval.distance.projectedEnd > 0 ? Math.round(data.interval.distance.projectedEnd) : 0) + if (!this.isSubscribed) { + // the multiplexer uses a slightly different format for the AdditionalStrokeData + // it adds workPerStroke at the end + // workPerStroke: UInt16LE in 0.1 Joules + bufferBuilder.writeUInt16LE(data.strokeWork > 0 ? Math.round(data.strokeWork * 10) : 0) + } + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x36, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/other-characteristics/ForceCurveCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/other-characteristics/ForceCurveCharacteristic.js new file mode 100644 index 0000000000..efec5cd5ba --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/other-characteristics/ForceCurveCharacteristic.js @@ -0,0 +1,83 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the StrokeData as defined in: + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + */ +import loglevel from 'loglevel' + +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' + +import { toC2128BitUUID } from '../../Pm5Constants.js' + +const log = loglevel.getLogger('Peripherals') + +export class ForceCurveCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('./MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Force Curve', + uuid: toC2128BitUUID('003D'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + // PM5 broadcasts this in 20bytes batches (seemingly regardless of the MTU size) + // Similar concept as ESP Rowing Monitor force curve (first two bytes: 1. 2x4bit value where first is total number of notifications - 'characteristics' in the Specs term - second the number of values in the current notification 2. current notification number - e.g. [0x29 /*i.e. 41 */, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] total of 2 consecutive notification will be emitted, current is the 1 and it has 9 data points, all zeros), variable size based on negotiated MTU, only C2 uses 16bits values) - https://github.com/ergarcade/pm5-base/blob/3d16d5d4840af14104fca928acdd3af2ec19cb29/js/pm5.js#L449 + if (data.driveHandleForceCurve.length === 0) { + return + } + + // Data bytes packed as follows: (2 - 288 bytes) example: 0x79001800290029003B003B004000450045005300 + // separated into multiple successive notifications) + + const dataByteSize = 2 + const maxMessageDataSize = 20 + const chunkSize = Math.floor((maxMessageDataSize - 2) / dataByteSize) + const split = Math.floor(data.driveHandleForceCurve.length / chunkSize + (data.driveHandleForceCurve.length % chunkSize === 0 ? 0 : 1)) + + let i = 0 + log.debug(`Force curve data count: ${data.driveHandleForceCurve.length} chunk size(number of values): ${chunkSize}, number of chunks: ${split}`) + + while (i < split) { + const end = (i + 1) * chunkSize < data.driveHandleForceCurve.length ? chunkSize * (i + 1) : data.driveHandleForceCurve.length + + const bufferBuilder = new BufferBuilder() + const currentChunkedData = data.driveHandleForceCurve.slice(i * chunkSize, end) + + // MS Nib = # characteristics, LS Nib = # words, + bufferBuilder.writeUInt8((split << 4) | (currentChunkedData.length & 0x0F)) + // Sequence number (current notification count) + bufferBuilder.writeUInt8(i) + + currentChunkedData.forEach((data) => { + // Data + bufferBuilder.writeUInt16LE(Math.round(data * 0.224809)) + }) + + i++ + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + /* eslint-disable-next-line no-continue -- let's get out of here */ + continue + } + + this.#multiplexedCharacteristic.notify(0x3D, bufferBuilder.getBuffer()) + } + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/other-characteristics/ForceCurveCharacteristic.test.js b/app/peripherals/ble/pm5/rowing-service/other-characteristics/ForceCurveCharacteristic.test.js new file mode 100644 index 0000000000..5045b6e2aa --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/other-characteristics/ForceCurveCharacteristic.test.js @@ -0,0 +1,167 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implementation of the StrokeData as defined in: + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf +*/ +import * as assert from 'uvu/assert' +import { suite } from 'uvu' + +import { ForceCurveCharacteristic } from './ForceCurveCharacteristic.js' + +const forceCurveCharacteristicTest = suite('forceCurveCharacteristicTest') + +const forceCurveData = [ + 35.20670409437894, + 71.24770979105799, + 106.76058707196907, + 147.62432375433332, + 191.5017876211155, + 235.26113001328616, + 285.14921813760674, + 338.01652172714535, + 401.54844368830413, + 462.9684206861586, + 520.4309477550664, + 573.8735122191848, + 617.7803577159515, + 658.609156242382, + 691.0795556356153, + 715.9043059583466, + 737.5400595447022, + 758.8198585977392, + 778.25735407793, + 795.473250100066, + 807.7661782745965, + 811.9359865006522, + 810.2206520776575, + 807.0270703264409, + 806.6963977594922, + 808.9560093066058, + 818.9517239399365, + 826.5161273484823, + 833.0787018711079, + 839.845516255648, + 845.5665462319271, + 851.3611235382654, + 848.4630663040393, + 845.9163188145909, + 848.1255040084359, + 848.4453794744273, + 844.9025006222316, + 840.8804872376313, + 829.9345489599933, + 821.9625255043932, + 814.1660656845103, + 806.0440103036917, + 796.8336476973348, + 786.5688734689126, + 777.296276624122, + 767.9240460566771, + 756.7011323288369, + 741.7714956570477, + 724.67666952788, + 706.5588388338806, + 687.2327020446613, + 667.9257890807414, + 651.0351359410047, + 633.1182926458321, + 617.5187416137509, + 600.2718592907876, + 586.8141420790122, + 568.8362812133483, + 544.0601844649392, + 515.112740526092, + 485.99678442336335, + 454.0430973642798, + 417.64606900272526, + 381.02246993296194, + 339.2866769162796, + 295.08431352641287, + 246.90612619654942, + 202.26069534863754, + 156.8359639803434, + 115.97725171265056, + 84.85233788062578, + 59.11168213118775, + 32.0896186351397 +] + +const expectedForceCurveData = forceCurveData.map((data) => Math.round(data * 0.224809)) + +forceCurveCharacteristicTest('should split force curve data into 20 byte chunks', () => { + const characteristic = new ForceCurveCharacteristic(/** @type {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} */({ + // eslint-disable-next-line no-unused-vars + notify: (_id, _buffer) => { + } + })) + + characteristic.characteristic.onSubscriptionChange(/** @type {import('../../../ble-host.interface.js').Connection} */({}), true) + + /** + * @type {Array>} + */ + const outputBuffer = [] + characteristic.characteristic.notify = (_connection, buffer) => { + if (typeof buffer === 'string') { + return true + } + + outputBuffer.push([...buffer]) + + return true + } + + characteristic.notify(/** @type {Metrics} */({ driveHandleForceCurve: forceCurveData })) + + const maxDataSize = 20 + const dataPerNotify = Math.floor((maxDataSize - 2) / 2) // (Max package size 20 bytes - C2 characteristic header size) / dataByteLength + const expectedNumberOfNotifies = Math.floor(forceCurveData.length / dataPerNotify + (forceCurveData.length % dataPerNotify === 0 ? 0 : 1)) + + assert.is(outputBuffer.length, expectedNumberOfNotifies) +}) + +forceCurveCharacteristicTest('should broadcast correct data', () => { + const characteristic = new ForceCurveCharacteristic(/** @type {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} */({ + // eslint-disable-next-line no-unused-vars + notify: (_id, _buffer) => { + } + })) + + characteristic.characteristic.onSubscriptionChange(/** @type {import('../../../ble-host.interface.js').Connection} */({}), true) + + /** + * @type {Array>} + */ + const outputBuffer = [] + characteristic.characteristic.notify = (_connection, buffer) => { + if (typeof buffer === 'string') { + return true + } + + outputBuffer.push([...buffer]) + + return true + } + + characteristic.notify(/** @type {Metrics} */({ driveHandleForceCurve: forceCurveData })) + + const maxDataSize = 20 + const dataPerNotify = Math.floor((maxDataSize - 2) / 2) // (Max package size 20 bytes - C2 characteristic header size) / dataByteLength + const expectedNumberOfNotifies = Math.floor(forceCurveData.length / dataPerNotify + (forceCurveData.length % dataPerNotify === 0 ? 0 : 1)) + + assert.equal(outputBuffer.map((data) => [data[0], data[1]]), outputBuffer.map((data, index) => [(expectedNumberOfNotifies << 4) | ((data.length - 2) / 2 & 0x0F), index]), 'Notification flag bytes') + assert.is(outputBuffer.reduce((sum, data) => data.slice(2).length / 2 + sum, 0), expectedForceCurveData.length, 'Notified data length') + assert.equal(outputBuffer.reduce((forceData, data) => { + const forces = data.slice(2) + for (let index = 1; index < forces.length; index = index + 2) { + forceData.push(forces[index - 1] | forces[index] << 8) + } + + return forceData + }, []), expectedForceCurveData.map((data) => Math.round(data)), 'Notified data value') +}) + +forceCurveCharacteristicTest.run() diff --git a/app/peripherals/ble/pm5/rowing-service/other-characteristics/MultiplexedCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/other-characteristics/MultiplexedCharacteristic.js new file mode 100644 index 0000000000..d529a6cd7e --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/other-characteristics/MultiplexedCharacteristic.js @@ -0,0 +1,43 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implements the Multiplexed Characteristic as defined by the spec: + + "On some Android platforms, there is a limitation to the number of notification messages allowed. + To circumvent this issue, a single characteristic (C2 multiplexed data + info) exists to allow multiple characteristics to be multiplexed onto a single characteristic. The last byte in the + characteristic will indicate which data characteristic is multiplexed." +*/ +import { GattNotifyCharacteristic } from '../../../BleManager.js' + +import { toC2128BitUUID } from '../../Pm5Constants.js' + +export class MultiplexedCharacteristic extends GattNotifyCharacteristic { + constructor () { + super({ + name: 'Multiplexed Information', + uuid: toC2128BitUUID('0080'), + properties: ['notify'] + }) + } + + /** + * @param {number} id + * @param {Buffer} characteristicBuffer + */ + // @ts-ignore: Type is not assignable to type + notify (id, characteristicBuffer) { + const characteristicId = Buffer.alloc(1) + characteristicId.writeUInt8(id, 0) + const buffer = Buffer.concat( + [ + characteristicId, + characteristicBuffer + ], + characteristicId.length + characteristicBuffer.length + ) + + super.notify(buffer) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/other-characteristics/SampleRateCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/other-characteristics/SampleRateCharacteristic.js new file mode 100644 index 0000000000..f987b68ca7 --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/other-characteristics/SampleRateCharacteristic.js @@ -0,0 +1,49 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implementation of the AdditionalStatus as defined in: + https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf +*/ +import NodeBleHost from 'ble-host' +import loglevel from 'loglevel' + +import { toC2128BitUUID } from '../../Pm5Constants.js' + +const log = loglevel.getLogger('Peripherals') + +export class SampleRateCharacteristic { + get characteristic () { + return this.#characteristic + } + + /** + * @type {GattServerCharacteristicFactory} + */ + #characteristic + #sampleRate + + /** + * @param {Config} config + */ + constructor (config) { + this.#sampleRate = config.pm5UpdateInterval === 1000 ? 0 : 2 + this.#characteristic = { + name: 'Sample Rate', + uuid: toC2128BitUUID('0034'), + properties: ['read', 'write'], + onRead: (connection, callback) => { + log.debug(`PM5 ${this.#characteristic.name} read characteristic has been called`) + callback(NodeBleHost.AttErrors.SUCCESS, Buffer.from([this.#sampleRate])) + }, + onWrite: (_connection, _needsResponse, sampleRate, callback) => { + this.#sampleRate = sampleRate.readUint8(0) + // TODO: needs to be properly handle the rates based on enum + config.pm5UpdateInterval = this.#sampleRate === 0 ? 1000 : 250 + log.debug(`PM5 ${this.#characteristic.name} write is called: ${this.#sampleRate}`) + + callback(NodeBleHost.AttErrors.SUCCESS) // actually only needs to be called when needsResponse is true + } + } + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/other-characteristics/StrokeDataCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/other-characteristics/StrokeDataCharacteristic.js new file mode 100644 index 0000000000..2e68f90f9f --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/other-characteristics/StrokeDataCharacteristic.js @@ -0,0 +1,69 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the StrokeData as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#0x0035-stroke-data|the description of desired behaviour} +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' + +import { toC2128BitUUID } from '../../Pm5Constants.js' + +export class StrokeDataCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('./MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Stroke Data', + uuid: toC2128BitUUID('0035'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + // elapsedTime: UInt24LE in 0.01 sec + bufferBuilder.writeUInt24LE(data.interval.timeSpent.total > 0 && data.sessionState !== 'WaitingForStart' ? Math.round(data.interval.timeSpent.total * 100) : 0) + // distance: UInt24LE in 0.1 m + bufferBuilder.writeUInt24LE(data.interval.distance.fromStart > 0 ? Math.round(data.interval.distance.fromStart * 10) : 0) + // driveLength: UInt8 in 0.01 m + bufferBuilder.writeUInt8(data.driveLength > 0 ? Math.round(data.driveLength * 100) : 0) + // driveTime: UInt8 in 0.01 s + bufferBuilder.writeUInt8(data.driveDuration > 0 ? Math.round(data.driveDuration * 100) : 0) + // strokeRecoveryTime: UInt16LE in 0.01 s + bufferBuilder.writeUInt16LE(data.recoveryDuration > 0 ? Math.round(data.recoveryDuration * 100) : 0) + // strokeDistance: UInt16LE in 0.01 s + bufferBuilder.writeUInt16LE(data.cycleDistance > 0 ? Math.round(data.cycleDistance * 100) : 0) + // peakDriveForce: UInt16LE in 0.1 lbs + bufferBuilder.writeUInt16LE(data.drivePeakHandleForce > 0 ? Math.round(data.drivePeakHandleForce * 0.224809 * 10) : 0) + // averageDriveForce: UInt16LE in 0.1 lbs + bufferBuilder.writeUInt16LE(data.driveAverageHandleForce > 0 ? Math.round(data.driveAverageHandleForce * 0.224809 * 10) : 0) + if (this.isSubscribed) { + // workPerStroke is only added if data is not send via multiplexer + // workPerStroke: UInt16LE in 0.1 Joules + bufferBuilder.writeUInt16LE(data.strokeWork > 0 ? Math.round(data.strokeWork * 10) : 0) + } + // strokeCount: UInt16LE + bufferBuilder.writeUInt16LE(data.interval.numberOfStrokes > 0 ? Math.round(data.interval.numberOfStrokes) : 0) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x35, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalSplitDataCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalSplitDataCharacteristic.js new file mode 100644 index 0000000000..9319692714 --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalSplitDataCharacteristic.js @@ -0,0 +1,75 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the AdditionalStrokeData as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#0x0038-additional-split-data|the description of desired behaviour} + */ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' + +import { pm5Constants, toC2128BitUUID } from '../../Pm5Constants.js' + +export class AdditionalSplitDataCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Additional Split Data', + uuid: toC2128BitUUID('0038'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + * @param {SegmentMetrics} splitData + */ + // @ts-ignore: Type is not assignable to type + /* eslint-disable complexity -- A lot of defensive programming is needed to tame this beast */ + notify (data, splitHRData) { + const bufferBuilder = new BufferBuilder() + // Data bytes packed as follows: (19bytes) - Multiplex as per spec 18bytes, but actually the list show 19. need to verify from the PM5 + + // Elapsed Time in 0.01 sec + bufferBuilder.writeUInt24LE(data.interval.timeSpent.total > 0 && data.sessionState !== 'WaitingForStart' ? Math.round(data.interval.timeSpent.total * 100) : 0) + // Split/Interval Avg Stroke Rate + bufferBuilder.writeUInt8(data.split.strokerate.average > 0 ? Math.round(data.split.strokerate.average) : 0) + // Split/Interval Work Heartrate, + bufferBuilder.writeUInt8(splitHRData.average() > 0 ? Math.round(splitHRData.average()) : 0) + // Split/Interval Rest Heartrate, + bufferBuilder.writeUInt8(0) + // Split/Interval Average Pace (in 0.1 sec) + bufferBuilder.writeUInt16LE(data.split.pace.average !== Infinity && data.split.pace.average > 0 && data.split.pace.average < 655.34 ? Math.round(data.split.pace.average * 10) : 0) + // Split/Interval Total Calories (Cals), + bufferBuilder.writeUInt16LE(data.split.calories.totalSpent > 0 && data.split.calories.totalSpent < 65534 ? Math.round(data.split.calories.totalSpent) : 0) + // Split/Interval Average Calories (Cals/Hr), + bufferBuilder.writeUInt16LE(data.split.calories.averagePerHour > 0 && data.split.calories.averagePerHour < 65534 ? Math.round(data.split.calories.averagePerHour) : 0) + // Split/Interval Speed (0.001 m/s, max=65.534 m/s) + bufferBuilder.writeUInt16LE(data.split.linearVelocity.average !== Infinity && data.split.linearVelocity.average > 0 && data.split.linearVelocity.average < 655.34 ? Math.round(data.split.linearVelocity.average * 1000) : 0) + // Split/Interval Power (Watts, max = 65.534 kW) + bufferBuilder.writeUInt16LE(data.split.power.average > 0 && data.split.power.average < 65534 ? Math.round(data.split.power.average) : 0) + // Split Avg Drag Factor, + bufferBuilder.writeUInt8(data.split.dragfactor.average > 0 && data.split.dragfactor.average < 255 ? Math.round(data.split.dragfactor.average) : 255) + // Split/Interval Number, based on BLE traces, split data messages' split number always starts at 1 + bufferBuilder.writeUInt8(data.split.C2number >= 0 ? data.split.C2number + 1 : 0) + // Erg Machine Type + bufferBuilder.writeUInt8(pm5Constants.ergMachineType) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x38, bufferBuilder.getBuffer()) + } +} +/* eslint-enable complexity */ diff --git a/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalWorkoutSummary2Characteristic.js b/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalWorkoutSummary2Characteristic.js new file mode 100644 index 0000000000..4f754bf749 --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalWorkoutSummary2Characteristic.js @@ -0,0 +1,48 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the StrokeData as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + */ +import { BufferBuilder } from '../../../BufferBuilder.js' + +import { Concept2Date } from '../../utils/C2toORMMapper.js' +import { pm5Constants } from '../../Pm5Constants.js' + +export class AdditionalWorkoutSummary2Characteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + // Data bytes packed as follows: (10Bytes) example: (0x3C) 0333 1212 4808 10 0000 00 + + // Log Entry Date (see https://www.c2forum.com/viewtopic.php?t=200769) + bufferBuilder.writeUInt16LE(new Concept2Date().toC2DateInt()) + // Log Entry Time (see https://www.c2forum.com/viewtopic.php?t=200769) + bufferBuilder.writeUInt16LE(new Concept2Date().toC2TimeInt()) + // Avg Pace (0.1 sec) + bufferBuilder.writeUInt16LE(data.workout.pace.average !== Infinity && data.workout.pace.average > 0 && data.workout.pace.average < 655.34 ? Math.round(data.workout.pace.average * 10) : 0) + // Game Identifier/ Workout Verified (see Appendix), + bufferBuilder.writeUInt8((0 & 0x0F) | ((0 & 0xF0) >> 4)) + // Game Score (Fish/Darts 1 point LSB, Target 0.1% LSB) + bufferBuilder.writeUInt16LE(0) + // Erg Machine Type + bufferBuilder.writeUInt8(pm5Constants.ergMachineType) + + this.#multiplexedCharacteristic.notify(0x3C, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalWorkoutSummaryCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalWorkoutSummaryCharacteristic.js new file mode 100644 index 0000000000..5e4c7f423a --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/session-characteristics/AdditionalWorkoutSummaryCharacteristic.js @@ -0,0 +1,71 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implementation of the StrokeData as defined in: + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' +import { toC2128BitUUID, toC2IntervalType } from '../../utils/ORMtoC2Mapper.js' +import { Concept2Date } from '../../utils/C2toORMMapper.js' + +export class AdditionalWorkoutSummaryCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Additional Workout Summary', + uuid: toC2128BitUUID('003A'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + // Data bytes packed as follows: (19bytes) example: 0x 0333 1212 02 C800 05 3B00 2500 550000 3C00 AA01 + + // Log Entry Date, (see https://www.c2forum.com/viewtopic.php?t=200769) + bufferBuilder.writeUInt16LE(new Concept2Date().toC2DateInt()) + // Log Entry Time, (see https://www.c2forum.com/viewtopic.php?t=200769) + bufferBuilder.writeUInt16LE(new Concept2Date().toC2TimeInt()) + if (this.isSubscribed) { + // intervalType: UInt8, see OBJ_INTERVALTYPE_T enum - NOT IN MULTIPLEXED + bufferBuilder.writeUInt8(toC2IntervalType(data)) + } + // Split/Interval Size (meters or seconds) + if (data.split.type === 'distance') { + bufferBuilder.writeUInt16LE(data.split.distance.fromStart > 0 ? Math.round(data.split.distance.fromStart) : 0) + } else { + bufferBuilder.writeUInt16LE(data.split.timeSpent.moving > 0 ? Math.round(data.split.timeSpent.moving) : 0) + } + // Split/Interval Number, based on BLE traces, split data messages' split number always starts at 1 + bufferBuilder.writeUInt8(data.split.C2number >= 0 ? data.split.C2number + 1 : 0) + // Total Calories + bufferBuilder.writeUInt16LE(data.workout.calories.totalSpent > 0 && data.workout.calories.totalSpent < 65534 ? Math.round(data.workout.calories.totalSpent) : 0) + // Power (Watts) + bufferBuilder.writeUInt16LE(data.workout.power.average > 0 && data.workout.power.average < 65534 ? Math.round(data.workout.power.average) : 0) + // Total Rest Distance (1 m lsb) + bufferBuilder.writeUInt24LE(0) + // Interval Rest Time (seconds) + bufferBuilder.writeUInt16LE(data.workout.timeSpent.C2Rest > 0 ? Math.round(data.workout.timeSpent.C2Rest) : 0) + // Avg Calories (cals/hr) + bufferBuilder.writeUInt16LE(data.workout.calories.averagePerHour > 0 && data.workout.calories.averagePerHour < 65534 ? Math.round(data.workout.calories.averagePerHour) : 0) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + return + } + + this.#multiplexedCharacteristic.notify(0x3A, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/session-characteristics/LoggedWorkoutCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/session-characteristics/LoggedWorkoutCharacteristic.js new file mode 100644 index 0000000000..e5d0af0460 --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/session-characteristics/LoggedWorkoutCharacteristic.js @@ -0,0 +1,57 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implementation of the StrokeData as defined in: + https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + todo: we could calculate all the missing stroke metrics in the RowerEngine +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' + +import { pm5Constants, toC2128BitUUID } from '../../Pm5Constants.js' + +export class LoggedWorkoutCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Additional Workout Summary', + uuid: toC2128BitUUID('003F'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + * @param {SegmentMetrics} workoutData + */ + /* eslint-disable-next-line no-unused-vars -- standardized characteristic interface where the parameters aren't relevant + // @ts-ignore: Type is not assignable to type */ + notify (data, workoutData) { + const bufferBuilder = new BufferBuilder() + // Data bytes packed as follows: (15bytes) example: 0x 41A09A0C97A37088 CAE10801 D400 00 (00000000) + + // Logged Workout Hash, CSAFE_GET_CURRENT_WORKOUT_HASH + bufferBuilder.writeUInt32LE(0xFFFF) + bufferBuilder.writeUInt32LE(0xFFFF) + // Logged Workout Internal Log Address, CSAFE_GET_INTERNALLOGPARAMS + bufferBuilder.writeUInt32LE(0) + // Logged Workout Size (file size in bytes) + bufferBuilder.writeUInt16LE(0) + // Erg Model Type + bufferBuilder.writeUInt8(pm5Constants.ergMachineType) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x3F, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/session-characteristics/SplitDataCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/session-characteristics/SplitDataCharacteristic.js new file mode 100644 index 0000000000..3c222f1729 --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/session-characteristics/SplitDataCharacteristic.js @@ -0,0 +1,64 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the StrokeData as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#0x0037-split-data|the description of desired behaviour} +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' +import { toC2128BitUUID, toC2IntervalType } from '../../utils/ORMtoC2Mapper.js' + +export class SplitDataCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Split Data', + uuid: toC2128BitUUID('0037'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + * @param {SegmentMetrics} splitData + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + // Data bytes packed as follows: (18bytes) + + // Elapsed Time (0.01 sec), + bufferBuilder.writeUInt24LE(data.interval.timeSpent.total > 0 && data.sessionState !== 'WaitingForStart' ? Math.round(data.interval.timeSpent.total * 100) : 0) + // Distance in split (0.1 m), based on experiments with the intervals screen + bufferBuilder.writeUInt24LE(data.interval.distance.fromStart > 0 ? Math.round(data.interval.distance.fromStart * 10) : 0) + // Split/Interval Time (0.1 sec) + bufferBuilder.writeUInt24LE(data.split.timeSpent.moving > 0 ? Math.round(data.split.timeSpent.moving * 10) : 0) + // Split/Interval Distance (1m accurate) + bufferBuilder.writeUInt24LE(data.split.distance.fromStart > 0 ? Math.round(data.split.distance.fromStart) : 0) + // Interval Rest Time (1 sec accurate) + bufferBuilder.writeUInt16LE(data.split.timeSpent.rest > 0 ? Math.round(data.split.timeSpent.rest) : 0) + // Interval Rest Distance Lo (1m accurate) + bufferBuilder.writeUInt16LE(Math.round(0)) + // intervalType: UInt8, see OBJ_INTERVALTYPE_T enum + bufferBuilder.writeUInt8(toC2IntervalType(data)) + // Split/Interval Number, based on BLE traces, split data messages' split number always starts at 1 + bufferBuilder.writeUInt8(data.split.C2number >= 0 ? data.split.C2number + 1 : 0) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x37, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/session-characteristics/WorkoutSummaryCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/session-characteristics/WorkoutSummaryCharacteristic.js new file mode 100644 index 0000000000..06d378044b --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/session-characteristics/WorkoutSummaryCharacteristic.js @@ -0,0 +1,75 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implementation of the StrokeData as defined in: + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' +import { toC2128BitUUID, toC2WorkoutType } from '../../utils/ORMtoC2Mapper.js' +import { Concept2Date } from '../../utils/C2toORMMapper.js' + +export class WorkoutSummaryCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Workout Summary', + uuid: toC2128BitUUID('0039'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + * @param {SegmentMetrics} workoutData + */ + // @ts-ignore: Type is not assignable to type + notify (data, workoutHRData) { + const bufferBuilder = new BufferBuilder() + // Data bytes packed as follows: (20bytes) example: 0333 1212 A0A500 102700 0C 00 00 00 00 8D 00 07 4808 + + // Log Entry Date (see https://www.c2forum.com/viewtopic.php?t=200769) + bufferBuilder.writeUInt16LE(new Concept2Date().toC2DateInt()) + // Log Entry Time (see https://www.c2forum.com/viewtopic.php?t=200769) + bufferBuilder.writeUInt16LE(new Concept2Date().toC2TimeInt()) + // Elapsed Time (0.01 sec lsb), + bufferBuilder.writeUInt24LE(Math.round((data.workout.timeSpent.total - data.workout.timeSpent.C2Rest) * 100)) + // Distance (0.1 m) + bufferBuilder.writeUInt24LE(data.workout.distance.fromStart > 0 ? Math.round(data.workout.distance.fromStart * 10) : 0) + // Average Stroke Rate, + bufferBuilder.writeUInt8(data.workout.strokerate.average > 0 && data.workout.strokerate.average < 255 ? Math.round(data.workout.strokerate.average) : 0) + // Ending Heartrate, + bufferBuilder.writeUInt8(workoutHRData.atSeriesEnd() > 0 ? Math.round(workoutHRData.atSeriesEnd()) : 0) + // Average Heartrate, + bufferBuilder.writeUInt8(workoutHRData.average() > 0 ? Math.round(workoutHRData.average()) : 0) + // Min Heartrate, + bufferBuilder.writeUInt8(workoutHRData.minimum() > 0 ? Math.round(workoutHRData.minimum()) : 0) + // Max Heartrate, + bufferBuilder.writeUInt8(workoutHRData.maximum() > 0 ? Math.round(workoutHRData.maximum()) : 0) + // Drag Factor Average, + bufferBuilder.writeUInt8(data.workout.dragfactor.average > 0 && data.workout.dragfactor.average < 255 ? Math.round(data.workout.dragfactor.average) : 255) + // Recovery Heart Rate, (zero = not valid data. After 1 minute of rest/recovery, PM5 sends this data as a revised End Of Workout summary data characteristic unless the monitor has been turned off or a new workout started) + bufferBuilder.writeUInt8(0) + // workoutType: UInt8, see OBJ_WORKOUTTYPE_T enum + bufferBuilder.writeUInt8(toC2WorkoutType(data)) + if (this.isSubscribed) { + // Avg Pace (0.1 sec) - NOT IN MULTIPLEXED + bufferBuilder.writeUInt16LE(Math.round(data.workout.pace.average)) + } + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x39, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatus2Characteristic.js b/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatus2Characteristic.js new file mode 100644 index 0000000000..16d9490b8c --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatus2Characteristic.js @@ -0,0 +1,71 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the AdditionalStatus2 as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#0x0033--additional-status-2|the description of desired behaviour} +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' + +import { toC2128BitUUID } from '../../Pm5Constants.js' + +export class AdditionalStatus2Characteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Additional Status 2', + uuid: toC2128BitUUID('0033'), + properties: ['notify'] + }) + + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + * @param {SplitTimeDistanceData} previousSplitData + * @param {SegmentMetrics} splitData + */ + // @ts-ignore: Type is not assignable to type + notify (data, previousSplitData) { + const bufferBuilder = new BufferBuilder() + // elapsedTime: UInt24LE in 0.01 sec + bufferBuilder.writeUInt24LE(data.interval.timeSpent.total > 0 && data.sessionState !== 'WaitingForStart' ? Math.round(data.interval.timeSpent.total * 100) : 0) + // intervalCount: UInt8 + bufferBuilder.writeUInt8(data.split.C2number > 0 ? data.split.C2number : 0) + if (this.isSubscribed) { + // the multiplexer uses a slightly different format for the AdditionalStatus2 + // it skips averagePower before totalCalories + // averagePower: UInt16LE in watts + bufferBuilder.writeUInt16LE(data.cyclePower > 0 ? Math.round(data.cyclePower) : 0) + } + // totalCalories: UInt16LE in kCal + bufferBuilder.writeUInt16LE(data.workout.calories.totalSpent > 0 ? Math.round(data.workout.calories.totalSpent) : 0) + // splitAveragePace: UInt16LE in 0.01 sec/500m + bufferBuilder.writeUInt16LE(data.split.pace.average && data.split.pace.average > 0 && data.split.pace.average < 655.34 ? Math.round(data.split.pace.average * 100) : 0) + // splitAveragePower UInt16LE in watts + bufferBuilder.writeUInt16LE(data.split.power.average > 0 && data.split.power.average < 65534 ? Math.round(data.split.power.average) : 0) + // splitAverageCalories + bufferBuilder.writeUInt16LE(data.split.calories.averagePerHour > 0 && data.split.calories.averagePerHour < 65534 ? Math.round(data.split.calories.averagePerHour) : 0) + // lastSplitTime in 0.01 sec (spec says 0.1 sec, but the trace shows 0.01 sec) + bufferBuilder.writeUInt24LE(previousSplitData.totalMovingTime > 0 ? Math.round(previousSplitData.totalMovingTime * 100) : 0) + // lastSplitDistance in 1 m + bufferBuilder.writeUInt24LE(previousSplitData.totalLinearDistance > 0 ? Math.round(previousSplitData.totalLinearDistance) : 0) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x33, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatus3Characteristic.js b/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatus3Characteristic.js new file mode 100644 index 0000000000..4e787b9d5a --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatus3Characteristic.js @@ -0,0 +1,64 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Implementation of the AdditionalStatus2 as defined in: + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' +import { toC2128BitUUID, toC2OperationalState } from '../../utils/ORMtoC2Mapper.js' + +export class AdditionalStatus3Characteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Additional Status 3', + uuid: toC2128BitUUID('003E'), + properties: ['notify'] + }) + + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + */ + // + /* @ts-ignore: Type is not assignable to type */ + notify (data) { + const bufferBuilder = new BufferBuilder() + // Operational State, see Operational states + bufferBuilder.writeUInt8(toC2OperationalState(data)) + // Workout Verification State: PM5 1 is accepted by ErgData ans results in a verifued workout in the logbook. As ORM isn't that trustworthy, we explicitly set it to 0 + // Despite setting this to 0, the logbook still records it as verified + bufferBuilder.writeUInt8(0) + // Screen Number: UInt16 + bufferBuilder.writeUInt16LE(1) + // Last Error: UInt16 + bufferBuilder.writeUInt16LE(0) + // Calibration Mode, (BikeErg only; 0 otherwise) + bufferBuilder.writeUInt8(0) + // Calibration State, (BikeErg only; 0 otherwise) + bufferBuilder.writeUInt8(0) + // Calibration Status, (BikeErg only; 0 otherwise) + bufferBuilder.writeUInt8(0) + // Game ID: UInt8 + bufferBuilder.writeUInt8(0) + // Game Score: UInt16LE + bufferBuilder.writeUInt16LE(0) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x3e, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatusCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatusCharacteristic.js new file mode 100644 index 0000000000..5e908f6845 --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatusCharacteristic.js @@ -0,0 +1,71 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the Additional Status as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#0x0032-additional-status|the description of desired behaviour} +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' + +import { pm5Constants, toC2128BitUUID } from '../../Pm5Constants.js' + +export class AdditionalStatusCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'Additional Status', + uuid: toC2128BitUUID('0032'), + properties: ['notify'] + }) + + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + // elapsedTime: UInt24LE in 0.01 sec + bufferBuilder.writeUInt24LE(data.interval.timeSpent.total > 0 && data.sessionState !== 'WaitingForStart' ? Math.round(data.interval.timeSpent.total * 100) : 0) + // speed: UInt16LE in 0.001 m/sec + bufferBuilder.writeUInt16LE(data.cycleLinearVelocity > 0 ? Math.round(data.cycleLinearVelocity * 1000) : 0) + // strokeRate: UInt8 in strokes/min + bufferBuilder.writeUInt8(data.cycleStrokeRate > 0 ? Math.round(data.cycleStrokeRate) : 0) + // heartrate: UInt8 in bpm, 255 if invalid + bufferBuilder.writeUInt8(data?.heartrate ? Math.round(data.heartrate) : 0) + // currentPace: UInt16LE in 0.01 sec/500m + bufferBuilder.writeUInt16LE(data.cyclePace !== Infinity && data.cyclePace > 0 && data.cyclePace < 655.34 ? Math.round(data.cyclePace * 100) : 0) + // averagePace: UInt16LE in 0.01 sec/500m + bufferBuilder.writeUInt16LE(data.interval.pace.average !== Infinity && data.interval.pace.average > 0 && data.interval.pace.average < 655.34 ? Math.round(data.interval.pace.average * 100) : 0) + // restDistance: UInt16LE + bufferBuilder.writeUInt16LE(0) + // restTime: UInt24LE in 0.01 sec + bufferBuilder.writeUInt24LE(data.pauseCountdownTime > 0 ? Math.round(data.pauseCountdownTime * 100) : 0) + if (!this.isSubscribed) { + // the multiplexer uses a slightly different format for the AdditionalStatus + // it adds averagePower before the ergMachineType + // averagePower: UInt16LE in watts + bufferBuilder.writeUInt16LE(data.cyclePower > 0 && data.cyclePower < 65534 ? Math.round(data.cyclePower) : 0) + } + // ergMachineType: 0 TYPE_STATIC_D + bufferBuilder.writeUInt8(pm5Constants.ergMachineType) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x32, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/rowing-service/status-characteristics/GeneralStatusCharacteristic.js b/app/peripherals/ble/pm5/rowing-service/status-characteristics/GeneralStatusCharacteristic.js new file mode 100644 index 0000000000..6aebde681b --- /dev/null +++ b/app/peripherals/ble/pm5/rowing-service/status-characteristics/GeneralStatusCharacteristic.js @@ -0,0 +1,71 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * Implementation of the GeneralStatus as defined in: + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf + * - https://www.concept2.co.uk/files/pdf/us/monitors/PM5_CSAFECommunicationDefinition.pdf + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#0x0031-general-status|the description of desired behaviour} +*/ +import { BufferBuilder } from '../../../BufferBuilder.js' +import { GattNotifyCharacteristic } from '../../../BleManager.js' +import { toC2128BitUUID, toC2WorkoutType, toC2IntervalTypeGeneralStatus, toC2WorkoutState, toC2RowingState, toC2StrokeState, toC2DurationType } from '../../utils/ORMtoC2Mapper.js' + +export class GeneralStatusCharacteristic extends GattNotifyCharacteristic { + #multiplexedCharacteristic + + /** + * @param {import('../other-characteristics/MultiplexedCharacteristic.js').MultiplexedCharacteristic} multiplexedCharacteristic + */ + constructor (multiplexedCharacteristic) { + super({ + name: 'General Status', + uuid: toC2128BitUUID('0031'), + properties: ['notify'] + }) + this.#multiplexedCharacteristic = multiplexedCharacteristic + } + + /** + * @param {Metrics} data + */ + // @ts-ignore: Type is not assignable to type + notify (data) { + const bufferBuilder = new BufferBuilder() + // elapsedTime: UInt24LE in 0.01 sec + bufferBuilder.writeUInt24LE(data.interval.timeSpent.total > 0 && data.sessionState !== 'WaitingForStart' ? Math.round(data.interval.timeSpent.total * 100) : 0) + // distance: UInt24LE in 0.1 m + bufferBuilder.writeUInt24LE(data.interval.distance.fromStart > 0 ? Math.round(data.interval.distance.fromStart * 10) : 0) + // workoutType: UInt8, see OBJ_WORKOUTTYPE_T enum + bufferBuilder.writeUInt8(toC2WorkoutType(data)) + // intervalType: UInt8, see OBJ_INTERVALTYPE_T enum + bufferBuilder.writeUInt8(toC2IntervalTypeGeneralStatus(data)) + // workoutState: UInt8, see OBJ_WORKOUTSTATE_T enum + bufferBuilder.writeUInt8(toC2WorkoutState(data)) + // rowingState: UInt8, see OBJ_ROWINGSTATE_T + bufferBuilder.writeUInt8(toC2RowingState(data)) + // strokeState: UInt8, see OBJ_STROKESTATE_T + bufferBuilder.writeUInt8(toC2StrokeState(data)) + // totalWorkDistance: UInt24LE in 1 m + bufferBuilder.writeUInt24LE(data.interval.distance.absoluteStart > 0 ? Math.round(data.interval.distance.absoluteStart) : 0) + // workoutDuration: UInt24LE in 0.01 sec (if type TIME) + if (data.interval.type === 'distance') { + bufferBuilder.writeUInt24LE(data.interval.distance.target > 0 ? Math.round(data.interval.distance.target) : 0) + } else { + bufferBuilder.writeUInt24LE(data.interval.movingTime.target > 0 ? Math.round(data.interval.movingTime.target * 100) : 0) + } + // workoutDurationType: UInt8, see DurationTypes enum + bufferBuilder.writeUInt8(toC2DurationType(data)) + // dragFactor: UInt8 + bufferBuilder.writeUInt8(data.dragFactor > 0 ? Math.round(Math.min(data.dragFactor, 255)) : 0) + + if (this.isSubscribed) { + super.notify(bufferBuilder.getBuffer()) + + return + } + + this.#multiplexedCharacteristic.notify(0x31, bufferBuilder.getBuffer()) + } +} diff --git a/app/peripherals/ble/pm5/utils/C2toORMMapper.js b/app/peripherals/ble/pm5/utils/C2toORMMapper.js new file mode 100644 index 0000000000..69a69526a8 --- /dev/null +++ b/app/peripherals/ble/pm5/utils/C2toORMMapper.js @@ -0,0 +1,199 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * @file Contains all supporting functions needed to process Concept2 PM5 workouts commands to the internal ORM workouts + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md|for the entire interface description} + */ +export function createWorkoutPlan () { + let workoutplan = [] + + function reset () { + workoutplan = null + workoutplan = [] + } + + function addInterval (type, data) { + let workoutstep + let targetTime + switch (true) { + case (type === 'rest'): + if (data.length > 1) { + targetTime = readUInt16(data[0], data[1]) + if (targetTime > 0) { + workoutplan.push({}) + workoutstep = workoutplan.length - 1 + workoutplan[workoutstep].type = 'rest' + workoutplan[workoutstep].targetTime = targetTime + } + } + // As ErgData and ErgZone will always send a rest interval (with 0 length), we must ignore that + break + case (type === 'justrow'): + workoutplan.push({}) + workoutstep = workoutplan.length - 1 + workoutplan[workoutstep].type = 'justrow' + break + case (type === 'distance' && data.length > 4): + workoutplan.push({}) + workoutstep = workoutplan.length - 1 + /* eslint-disable-next-line no-case-declarations -- readable code outweighs rules */ + const targetDistance = readUInt32(data[1], data[2], data[3], data[4]) + if (targetDistance > 0) { + workoutplan[workoutstep].type = 'distance' + workoutplan[workoutstep].targetDistance = targetDistance + } else { + workoutplan[workoutstep].type = 'justrow' + } + break + case (type === 'time' && data.length > 4): + workoutplan.push({}) + workoutstep = workoutplan.length - 1 + targetTime = readUInt32(data[1], data[2], data[3], data[4]) / 100 + if (targetTime > 0) { + workoutplan[workoutstep].type = 'time' + workoutplan[workoutstep].targetTime = targetTime + } else { + workoutplan[workoutstep].type = 'justrow' + } + break + default: + workoutplan.push({}) + workoutstep = workoutplan.length - 1 + workoutplan[workoutstep].type = 'justrow' + } + } + + function addPaceTarget (data) { + if (workoutplan.length < 1) { return } + const workoutstep = workoutplan.length - 1 + if (data.length > 3) { + const targetLinearVelocity = 50000 / readUInt32(data[0], data[1], data[2], data[3]) + if (targetLinearVelocity > 0) { workoutplan[workoutstep].targetLinearVelocity = targetLinearVelocity } + } + } + + function addSplit (type, data) { + if (workoutplan.length < 1) { return } + const workoutstep = workoutplan.length - 1 + + workoutplan[workoutstep].split = {} + switch (true) { + case (type === 'justrow'): + workoutplan[workoutstep].split.type = 'justrow' + break + case (type === 'distance' && data.length > 4): + /* eslint-disable-next-line no-case-declarations -- readable code outweighs rules */ + const targetDistance = readUInt32(data[1], data[2], data[3], data[4]) + if (targetDistance > 0) { + workoutplan[workoutstep].split.type = 'distance' + workoutplan[workoutstep].split.targetDistance = targetDistance + } else { + workoutplan[workoutstep].split.type = workoutplan[workoutstep].type + workoutplan[workoutstep].split.targetDistance = workoutplan[workoutstep].targetDistance + } + break + case (type === 'time' && data.length > 4): + /* eslint-disable-next-line no-case-declarations -- readable code outweighs rules */ + const targetTime = readUInt32(data[1], data[2], data[3], data[4]) / 100 + if (targetTime > 0) { + workoutplan[workoutstep].split.type = 'time' + workoutplan[workoutstep].split.targetTime = readUInt32(data[1], data[2], data[3], data[4]) / 100 + } else { + workoutplan[workoutstep].split.type = workoutplan[workoutstep].type + workoutplan[workoutstep].split.targetTime = workoutplan[workoutstep].targetTime + } + break + default: + workoutplan[workoutstep].split.type = workoutplan[workoutstep].type + if (workoutplan[workoutstep].type === 'distance') { workoutplan[workoutstep].split.targetDistance = workoutplan[workoutstep].targetDistance } + if (workoutplan[workoutstep].type === 'time' || workoutplan[workoutstep].type === 'rest') { workoutplan[workoutstep].split.targetTime = workoutplan[workoutstep].targetTime } + } + } + + function length () { + return workoutplan.length + } + + function lastInterval () { + if (workoutplan.length > 0) { + return workoutplan[workoutplan.length - 1] + } else { + return undefined + } + } + + function forelastInterval () { + if (workoutplan.length > 1) { + return workoutplan[workoutplan.length - 2] + } else { + return undefined + } + } + + function result () { + if (workoutplan.length > 0) { + // Make sure we don't end with a rest interval + if (workoutplan[workoutplan.length - 1].type === 'rest') { workoutplan.pop() } + return workoutplan + } else { + return [] + } + } + + return { + reset, + addInterval, + addSplit, + addPaceTarget, + length, + lastInterval, + forelastInterval, + result + } +} + +export function readUInt16 (msb, lsb) { + return (msb * 256) + lsb +} + +function readUInt32 (msb, byte2, byte3, lsb) { + return (msb * 16777216) + (byte2 * 65536) + (byte3 * 256) + lsb +} + +export class Concept2Date extends Date { + /** + * Converts a Date object to a Concept2 date binary format + * @returns {number} The UTC date as a uint16 parsed as per the Concept2 specs + */ + toC2DateInt () { + const yearEpoch = 2000 + + return (this.getMonth() + 1) | (this.getDate()) << 4 | (this.getFullYear() - yearEpoch) << 9 + } + + /** + * Converts a Date object to a Concept2 date byte array format + * @returns {number[]} The UTC date as a byte array parsed as per the Concept2 specs + */ + toC2DateByteArray () { + return [ + this.getHours() % 12 || 12, + this.getMinutes(), + this.getHours() > 12 ? 1 : 0, + this.getMonth() + 1, + this.getDate(), + (this.getFullYear() >> 8) & 0xFF, + this.getFullYear() & 0xFF + ] + } + + /** + * Converts a Date object to a Concept2 time binary format + * @returns {number} The UTC time as a uint16 parsed as per the Concept2 specs + */ + toC2TimeInt () { + return this.getMinutes() | this.getHours() << 8 + } +} diff --git a/app/peripherals/ble/pm5/utils/ORMtoC2Mapper.js b/app/peripherals/ble/pm5/utils/ORMtoC2Mapper.js new file mode 100644 index 0000000000..0959f2437f --- /dev/null +++ b/app/peripherals/ble/pm5/utils/ORMtoC2Mapper.js @@ -0,0 +1,368 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * @file Contains all mapping functions needed to map the internal ORM state to the externally communicated Concept2 PM5 states + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md|for the entire interface description} + */ +/* eslint-disable no-unreachable -- the breaks after the returns trigger this, but there is a lot to say for being systematic about this */ +/* eslint-disable complexity -- There are a lot of decission tables needed to thread this needle */ +import { DurationTypes, IntervalTypes, OperationalStates, RowingState, StrokeState, WorkoutState, WorkoutTypes } from './../csafe-service/CsafeCommandsMapping.js' + +/** + * PM5 uses 128bit UUIDs that are always prefixed and suffixed the same way + * @param {string} uuid + */ +export function toC2128BitUUID (uuid) { + return `CE06${uuid}-43E5-11E4-916C-0800200C9A66` +} + +/** + * Converts the internal workout/interval/split structure to C2's OBJ_WORKOUTTYPE_T + * Is used by characteristics: + * - status-characteristics/GeneralStatusCharacteristic.js (0x0031) + * - session-characteristics/WorkoutSummaryCharacteristic.js (0x0039) + */ +export function toC2WorkoutType (baseMetrics) { + const splitPresent = (baseMetrics.split.type === 'distance' || baseMetrics.split.type === 'time' || baseMetrics.split.type === 'calories') + switch (true) { + case (baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'justrow' && baseMetrics.split.type === 'justrow'): + return WorkoutTypes.WORKOUTTYPE_JUSTROW_NOSPLITS + break + case (baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'justrow' && splitPresent): + return WorkoutTypes.WORKOUTTYPE_JUSTROW_SPLITS + break + case (baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'distance' && baseMetrics.split.type === 'distance' && baseMetrics.interval.distance.target === baseMetrics.split.distance.target): + // There is just a single split with the same size as the interval + return WorkoutTypes.WORKOUTTYPE_FIXEDDIST_NOSPLITS + break + case (baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'distance' && splitPresent): + return WorkoutTypes.WORKOUTTYPE_FIXEDDIST_SPLITS + break + case (baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'time' && baseMetrics.split.type === 'time' && baseMetrics.interval.movingTime.target === baseMetrics.split.movingTime.target): + // There is just a single split with the same size as the interval + return WorkoutTypes.WORKOUTTYPE_FIXEDTIME_NOSPLITS + break + case (baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'time' && splitPresent): + return WorkoutTypes.WORKOUTTYPE_FIXEDTIME_SPLITS + break + case (baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'calories' && splitPresent): + return WorkoutTypes.WORKOUTTYPE_FIXEDCALORIE_SPLITS + break + case (baseMetrics.workout.numberOfIntervals > 1 && baseMetrics.workout.type === 'justrow'): + return WorkoutTypes.WORKOUTTYPE_VARIABLE_INTERVAL + break + case (baseMetrics.workout.numberOfIntervals > 1 && baseMetrics.workout.type === 'distance'): + return WorkoutTypes.WORKOUTTYPE_FIXEDDIST_INTERVAL + break + case (baseMetrics.workout.numberOfIntervals > 1 && baseMetrics.workout.type === 'time'): + return WorkoutTypes.WORKOUTTYPE_FIXEDTIME_INTERVAL + break + default: + return WorkoutTypes.WORKOUTTYPE_JUSTROW_NOSPLITS + } +} + +/** + * Converts the internal workout/interval/split structure to C2's OBJ_INTERVALTYPE_T + * Is used by characteristics: + * - status-characteristics/GeneralStatusCharacteristic.js (0x0031) + */ +export function toC2IntervalTypeGeneralStatus (baseMetrics) { + // ToDo: this is a simplification, as ORM allows to mix different interval types and C2 does not. We might need to adress this based on the overall workout-type (which is a s> + switch (true) { + case (baseMetrics.sessionState === 'Paused' && !baseMetrics.metricsContext.isUnplannedPause): + return IntervalTypes.INTERVALTYPE_REST + break + case (baseMetrics.interval.type === 'distance'): + return IntervalTypes.INTERVALTYPE_DIST + break + case (baseMetrics.interval.type === 'time'): + return IntervalTypes.INTERVALTYPE_TIME + break + case (baseMetrics.interval.type === 'calories'): + return IntervalTypes.INTERVALTYPE_CALORIE + break + default: + return IntervalTypes.INTERVALTYPE_NONE + } +} + +/** + * Converts the internal workout/interval/split structure to C2's OBJ_INTERVALTYPE_T + * Is used by characteristics: + * - session-characteristics/SplitDataCharacteristic.js (0x0037) + * - session-characteristics/AdditionalWorkoutSummaryCharacteristic.js (0x003A) + */ +export function toC2IntervalType (baseMetrics) { + // ToDo: this is a simplification, as ORM allows to mix different interval types and C2 does not. We might need to adress this based on the overall workout-type (which is a summary of all intervals) + switch (true) { + case (baseMetrics.interval.type === 'distance'): + return IntervalTypes.INTERVALTYPE_DIST + break + case (baseMetrics.interval.type === 'time'): + return IntervalTypes.INTERVALTYPE_TIME + break + case (baseMetrics.interval.type === 'calories'): + return IntervalTypes.INTERVALTYPE_CALORIE + break + case (baseMetrics.interval.type === 'rest' && baseMetrics.interval.movingTime.target > 0): + return IntervalTypes.INTERVALTYPE_REST + break + case (baseMetrics.interval.type === 'rest'): + return IntervalTypes.INTERVALTYPE_RESTUNDEFINED + break + default: + return IntervalTypes.INTERVALTYPE_NONE + } +} + +/** + * Converts the internal workout state to C2's OBJ_WORKOUTSTATE_T + * Is used by characteristics: + * - status-characteristics/GeneralStatusCharacteristic.js (0031) + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/PM5_Interface.md#0x0031-general-status|the description of desired behaviour} + */ +export function toC2WorkoutState (baseMetrics) { + // ToDo: this is a simplification, as there are some interval transitions in this state which can be identified based on the state. But we first have to see how intervals behave + switch (true) { + case (baseMetrics.sessionState === 'WaitingForStart'): + return WorkoutState.WORKOUTSTATE_WAITTOBEGIN + break + case (!baseMetrics.metricsContext.isUnplannedPause && baseMetrics.metricsContext.isPauseEnd && baseMetrics.split.type === 'distance'): + return WorkoutState.WORKOUTSTATE_INTERVALRESTENDTOWORKDISTANCE + break + case (!baseMetrics.metricsContext.isUnplannedPause && baseMetrics.metricsContext.isPauseEnd && baseMetrics.split.type === 'time'): + return WorkoutState.WORKOUTSTATE_INTERVALRESTENDTOWORKTIME + break + case (baseMetrics.sessionState === 'Rowing' && baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'distance' && baseMetrics.split.type === 'distance'): + // Session with a single distance interval with multiple splits + return WorkoutState.WORKOUTSTATE_WORKOUTROW + break + case (baseMetrics.sessionState === 'Rowing' && baseMetrics.split.type === 'distance'): + // Session containing multiple intervals + return WorkoutState.WORKOUTSTATE_INTERVALWORKDISTANCE + break + case (baseMetrics.metricsContext.isUnplannedPause && baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'distance'): + // Unplanned pause in a session with a single distance interval with multiple splits + return WorkoutState.WORKOUTSTATE_WORKOUTROW + break + case (baseMetrics.metricsContext.isUnplannedPause && baseMetrics.interval.type === 'distance'): + // Unplanned pause in a session containing multiple intervals + return WorkoutState.WORKOUTSTATE_INTERVALWORKDISTANCE + break + case (baseMetrics.sessionState === 'Rowing' && baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'time' && baseMetrics.split.type === 'time'): + // Session with a single time interval with multiple splits + return WorkoutState.WORKOUTSTATE_WORKOUTROW + break + case (baseMetrics.sessionState === 'Rowing' && baseMetrics.split.type === 'time'): + // Session containing multiple intervals + return WorkoutState.WORKOUTSTATE_INTERVALWORKTIME + break + case (baseMetrics.metricsContext.isUnplannedPause && baseMetrics.workout.numberOfIntervals === 1 && baseMetrics.workout.type === 'time'): + // Unplanned pause in a session with a single time interval with multiple splits + return WorkoutState.WORKOUTSTATE_WORKOUTROW + break + case (baseMetrics.metricsContext.isUnplannedPause && baseMetrics.interval.type === 'time'): + // Unplanned pause in a session containing multiple intervals + return WorkoutState.WORKOUTSTATE_INTERVALWORKTIME + break + case (baseMetrics.sessionState === 'Rowing' || baseMetrics.metricsContext.isUnplannedPause): + return WorkoutState.WORKOUTSTATE_WORKOUTROW + break + case (!baseMetrics.metricsContext.isUnplannedPause && baseMetrics.sessionState === 'Paused' && baseMetrics.metricsContext.isPauseStart): + return WorkoutState.WORKOUTSTATE_INTERVALWORKDISTANCETOREST + break + case (baseMetrics.sessionState === 'Paused' && !baseMetrics.metricsContext.isUnplannedPause): + return WorkoutState.WORKOUTSTATE_INTERVALREST + break + case (baseMetrics.sessionState === 'Stopped'): + return WorkoutState.WORKOUTSTATE_WORKOUTEND + break + default: + return WorkoutState.WORKOUTSTATE_WAITTOBEGIN + } +} + +/** + * Converts the internal rowing state to C2's OBJ_ROWINGSTATE_T + * Is used by characteristics: + * - status-characteristics/GeneralStatusCharacteristic.js (0031) + */ +export function toC2RowingState (baseMetrics) { + switch (true) { + case (baseMetrics.sessionState === 'WaitingForStart'): + return RowingState.ROWINGSTATE_INACTIVE + break + case (baseMetrics.sessionState === 'Rowing'): + return RowingState.ROWINGSTATE_ACTIVE + break + case (baseMetrics.metricsContext.isUnplannedPause): + return RowingState.ROWINGSTATE_INACTIVE + break + case (baseMetrics.sessionState === 'Paused'): + return RowingState.ROWINGSTATE_INACTIVE + break + case (baseMetrics.sessionState === 'Stopped'): + return RowingState.ROWINGSTATE_INACTIVE + break + default: + return RowingState.ROWINGSTATE_INACTIVE + } +} + +/** + * Converts the internal stroke state to C2's OBJ_STROKESTATE_T + * Is used by characteristics: + * - status-characteristics/GeneralStatusCharacteristic.js (0031) + */ +export function toC2StrokeState (baseMetrics) { + switch (true) { + case (baseMetrics.sessionState === 'Paused'): + return StrokeState.STROKESTATE_WAITING_FOR_WHEEL_TO_ACCELERATE_STATE + break + case (baseMetrics.strokeState === 'WaitingForDrive'): + return StrokeState.STROKESTATE_WAITING_FOR_WHEEL_TO_REACH_MIN_SPEED_STATE + break + case (baseMetrics.strokeState === 'Drive' && baseMetrics.metricsContext.isDriveStart): + return StrokeState.STROKESTATE_WAITING_FOR_WHEEL_TO_ACCELERATE_STATE + break + case (baseMetrics.strokeState === 'Drive'): + return StrokeState.STROKESTATE_DRIVING_STATE + break + case (baseMetrics.strokeState === 'Recovery' && baseMetrics.metricsContext.isRecoveryStart): + return StrokeState.STROKESTATE_DWELLING_AFTER_DRIVE_STATE + break + case (baseMetrics.strokeState === 'Recovery'): + return StrokeState.STROKESTATE_RECOVERY_STATE + break + case (baseMetrics.strokeState === 'Stopped'): + return StrokeState.STROKESTATE_WAITING_FOR_WHEEL_TO_REACH_MIN_SPEED_STATE + break + default: + return StrokeState.STROKESTATE_WAITING_FOR_WHEEL_TO_REACH_MIN_SPEED_STATE + } +} + +/** + * Converts the internal rowing state to C2's DurationType + * Is used by characteristics: + * - status-characteristics/GeneralStatusCharacteristic.js (0031) + */ +export function toC2DurationType (baseMetrics) { + switch (true) { + case (baseMetrics.workout.type === 'justrow'): + return DurationTypes.CSAFE_TIME_DURATION + break + case (baseMetrics.workout.type === 'time'): + return DurationTypes.CSAFE_TIME_DURATION + break + case (baseMetrics.workout.type === 'distance'): + return DurationTypes.CSAFE_DISTANCE_DURATION + break + case (baseMetrics.workout.type === 'calories'): + return DurationTypes.CSAFE_CALORIES_DURATION + break + default: + return DurationTypes.CSAFE_TIME_DURATION + } +} + +/** + * Converts the internal rowing state to C2's OBJ_OPERATIONALSTATE_T + * Is used by characteristics: + * status-characteristics/AdditionalStatus3Characteristic.js (003E) + */ +export function toC2OperationalState (baseMetrics) { + switch (true) { + case (baseMetrics.sessionState === 'WaitingForStart'): + return OperationalStates.OPERATIONALSTATE_READY + break + case (baseMetrics.sessionState === 'Rowing'): + return OperationalStates.OPERATIONALSTATE_WORKOUT + break + case (baseMetrics.sessionState === 'Paused'): + return OperationalStates.OPERATIONALSTATE_PAUSE + break + case (baseMetrics.sessionState === 'Stopped'): + return OperationalStates.OPERATIONALSTATE_IDLE + break + default: + return OperationalStates.OPERATIONALSTATE_READY + } +} + +/** + * Used to manage planned pauses, which are handled at the Interval level. Concept2 essentially glues the planned rest interval to the active interval + * The active interval (and thus underlying split) can only contain moving time, as Concept2 considers even an unplanned pause as moving time + * The planned paused interval (and thus underlying split) can only contain rest time. + */ +export function appendPauseIntervalToActiveInterval (activeMetrics, pauseMetrics) { + const result = { ...pauseMetrics } + result.interval = activeMetrics.interval + result.interval.workoutStepNumber = pauseMetrics.interval.workoutStepNumber + result.interval.timeSpent.moving = activeMetrics.interval.timeSpent.moving + result.interval.timeSpent.rest = pauseMetrics.interval.timeSpent.rest + result.interval.timeSpent.total = activeMetrics.interval.timeSpent.moving + pauseMetrics.interval.timeSpent.rest + result.split = activeMetrics.split + result.split.C2number = pauseMetrics.split.C2number + result.split.timeSpent.moving = activeMetrics.split.timeSpent.moving + result.split.timeSpent.rest = pauseMetrics.split.timeSpent.rest + result.split.timeSpent.total = activeMetrics.split.timeSpent.moving + pauseMetrics.split.timeSpent.rest + return result +} + +/** + * Used to manage unplanned pauses, which are handled at the split level alone. Concept2 essentially ignores these, but in ORM these become three splits + * It is used in two scenario's: 1. appending the pause split to the first active split 2. Add the first active split and the pause to the second active split + * In these cases, all time is considered moving time, and NOT rest, so we have to treat it as such + */ +/* eslint-disable max-statements -- There are a lot of metrics to be be copied */ +export function mergeTwoSplits (firstMetrics, secondMetrics) { + const result = { ...secondMetrics } + result.split.C2number = secondMetrics.split.C2number + result.split.workoutStepNumber = secondMetrics.split.workoutStepNumber + result.split.numberOfStrokes = firstMetrics.split.numberOfStrokes + secondMetrics.split.numberOfStrokes + result.split.distance.absoluteStart = firstMetrics.split.distance.absoluteStart + result.split.distance.fromStart = firstMetrics.split.distance.fromStart + secondMetrics.split.distance.fromStart + result.split.movingTime.absoluteStart = firstMetrics.split.movingTime.absoluteStart + result.split.movingTime.sinceStart = firstMetrics.split.movingTime.sinceStart + secondMetrics.split.movingTime.sinceStart + result.split.timeSpent.total = firstMetrics.split.timeSpent.total + secondMetrics.split.timeSpent.total + result.split.timeSpent.moving = result.split.timeSpent.total // C2's definition of moving time essentially equates it to total time for splits with unplanned pauses + result.split.timeSpent.rest = 0 // C2's definition of moving time does not allow for rest time due to unplanned pause + result.split.linearVelocity.average = result.split.timeSpent.moving > 0 ? (result.split.distance.fromStart / result.split.timeSpent.total) : 0 + result.split.linearVelocity.minimum = Math.min(firstMetrics.split.linearVelocity.minimum, secondMetrics.split.linearVelocity.minimum) + result.split.linearVelocity.maximum = Math.max(firstMetrics.split.linearVelocity.maximum, secondMetrics.split.linearVelocity.maximum) + result.split.pace.average = linearVelocityToPace(result.interval.linearVelocity.average) + result.split.pace.minimum = Math.max(firstMetrics.split.pace.minimum, secondMetrics.split.pace.minimum) // Be aware: largest number is slowest pace + result.split.pace.maximum = Math.min(firstMetrics.split.pace.maximum, secondMetrics.split.pace.maximum) // Be aware: biggest number is fastest pace + result.split.power.average = result.split.timeSpent.total > 0 ? ((firstMetrics.split.power.average * firstMetrics.split.timeSpent.total) + (secondMetrics.split.power.average * secondMetrics.split.timeSpent.total)) / result.split.timeSpent.total : 0 + result.split.power.minimum = Math.min(firstMetrics.split.power.minimum, secondMetrics.split.power.minimum) + result.split.power.maximum = Math.max(firstMetrics.split.power.maximum, secondMetrics.split.power.maximum) + result.split.strokeDistance.average = result.split.numberOfStrokes > 0 ? (result.split.distance.fromStart / result.split.numberOfStrokes) : 0 + result.split.strokeDistance.minimum = Math.min(firstMetrics.split.strokeDistance.minimum, secondMetrics.split.strokeDistance.minimum) + result.split.strokeDistance.maximum = Math.max(firstMetrics.split.strokeDistance.maximum, secondMetrics.split.strokeDistance.maximum) + result.split.strokerate.average = result.split.timeSpent.total > 0 ? ((result.split.numberOfStrokes * 60) / result.split.timeSpent.total) : 0 + result.split.strokerate.minimum = Math.min(firstMetrics.split.strokerate.minimum, secondMetrics.split.strokerate.minimum) + result.split.strokerate.maximum = Math.max(firstMetrics.split.strokerate.maximum, secondMetrics.split.strokerate.maximum) + result.split.dragfactor.average = secondMetrics.interval.dragfactor.average + result.split.dragfactor.minimum = Math.min(firstMetrics.split.dragfactor.minimum, secondMetrics.split.dragfactor.minimum) + result.split.dragfactor.maximum = Math.max(firstMetrics.split.dragfactor.maximum, secondMetrics.split.dragfactor.maximum) + result.split.calories.totalSpent = firstMetrics.split.calories.totalSpent + secondMetrics.split.calories.totalSpent + result.split.calories.averagePerHour = result.split.timeSpent.moving > 0 ? ((firstMetrics.split.calories.averagePerHour * firstMetrics.split.timeSpent.total) + (secondMetrics.split.calories.averagePerHour * secondMetrics.split.timeSpent.total)) / result.split.timeSpent.total : 0 + return result +} +/* eslint-enable max-statements */ + +/** + * @param {float} linear velocity + * @returns {float} pace per 500 meters + */ +function linearVelocityToPace (linearVel) { + if (!isNaN(linearVel) && linearVel > 0) { + return (500.0 / linearVel) + } else { + return undefined + } +} diff --git a/app/peripherals/mqtt/mqtt.js b/app/peripherals/mqtt/mqtt.js new file mode 100644 index 0000000000..4ae4cf8aba --- /dev/null +++ b/app/peripherals/mqtt/mqtt.js @@ -0,0 +1,194 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This Module broadcastst the rowing metrics to a MQTT broker + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Integrations.md#recieving-metrics|the description of the metrics provided} + * Please note: as most brokers get easily flooded by highly frequent reporting, so we only report on a per-stroke basis + * + * The MQTT peripheral also allows setting of workout parameters + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Integrations.md#pushing-workouts|the workout setup} + */ +import log from 'loglevel' +import EventEmitter from 'node:events' +import mqtt from 'mqtt' + +/** + * @param {Config} config + */ +export function createMQTTPeripheral (config) { + const emitter = new EventEmitter() + const protocol = 'mqtt' + const host = `${config.mqtt.mqttBroker}` + const port = '1883' + const clientId = `mqtt_${Math.random().toString(16).slice(3)}` + const metricsTopic = `OpenRowingMonitor/${config.mqtt.machineName}/metrics` + const workoutsTopic = `OpenRowingMonitor/${config.mqtt.machineName}/workoutplans` + const connectUrl = `${protocol}://${host}:${port}` + /** + * @type {Metrics} + */ + let lastMetrics = { + .../** @type {Metrics} */({}), + timestamp: new Date(), + interval: { type: 'justrow' }, + sessionState: 'WaitingForStart', + strokeState: 'WaitingForDrive', + metricsContext: { + isMoving: false, + isDriveStart: false, + isRecoveryStart: false, + isSessionStart: false, + isPauseStart: false, + isPauseEnd: false, + isSessionStop: false, + isIntervalEnd: false, + isSplitEnd: false + }, + totalNumberOfStrokes: 0, + totalMovingTime: 0, + totalLinearDistance: 0, + totalCalories: 0, + split: { + number: 0 + }, + heartrate: NaN, + cycleLinearVelocity: 0, + cyclePace: 0, + cyclePower: 0, + driveDuration: NaN, + driveLength: 0, + recoveryDuration: NaN, + cycleDuration: NaN, + cycleStrokeRate: NaN, + cycleDistance: NaN, + drivePeakHandleForce: NaN, + driveAverageHandleForce: NaN, + driveHandleForceCurve: [], + driveHandleVelocityCurve: [], + driveHandlePowerCurve: [], + dragFactor: NaN + } + + const client = mqtt.connect(connectUrl, { + clientId, + clean: true, + connectTimeout: 4000, + username: config.mqtt.username, + password: config.mqtt.password, + reconnectPeriod: 1000 + }) + + client.on('connect', () => { + log.debug(`MQTT Publisher: connected to ${host}, publishing metrics in ${metricsTopic} topic`) + publishMetrics(lastMetrics) + }) + + client.subscribe([workoutsTopic], () => { + log.debug(`MQTT Listener: connected to ${host}, listening to ${workoutsTopic} topic`) + }) + + client.on('message', (topic, payload) => { + // Be aware: application-level input validation of the payload is done centrally at ./engine/utils/workoutSegments.js + try { + const parsedData = JSON.parse(payload.toString()) + log.debug('MQTT Listener: Received Message from ', topic, parsedData) + emitter.emit('control', { + req: { + name: 'updateIntervalSettings', + data: JSON.parse(payload.toString()), + client: null + } + }) + } catch (error) { + log.debug('MQTT Listener, Error parsing JSON:', payload, error) + } + }) + + /** + * @param {Metrics} metrics + */ + async function notifyData (metrics) { + switch (true) { + case (metrics.metricsContext.isSessionStart): + publishMetrics(metrics) + break + case (metrics.metricsContext.isSessionStop): + publishMetrics(metrics) + break + case (metrics.metricsContext.isIntervalEnd): + publishMetrics(metrics) + break + case (metrics.metricsContext.isPauseStart): + publishMetrics(metrics) + break + case (metrics.metricsContext.isPauseEnd): + publishMetrics(metrics) + break + case (metrics.metricsContext.isSplitEnd): + publishMetrics(metrics) + break + case (metrics.metricsContext.isDriveStart): + publishMetrics(metrics) + break + // no default + } + lastMetrics = metrics + } + + /** + * @param {Metrics} metrics + */ + async function publishMetrics (metrics) { + const jsonMetrics = { + timestamp: (metrics.timestamp / 1000).toFixed(3), + intervaltype: metrics.interval.type, + sessionState: metrics.sessionState, + strokeState: metrics.strokeState, + isMoving: metrics.metricsContext.isMoving, + isDriveStart: metrics.metricsContext.isDriveStart, + isRecoveryStart: metrics.metricsContext.isRecoveryStart, + isSessionStart: metrics.metricsContext.isSessionStart, + isPauseStart: metrics.metricsContext.isPauseStart, + isPauseEnd: metrics.metricsContext.isPauseEnd, + isSessionStop: metrics.metricsContext.isSessionStop, + totalNumberOfStrokes: metrics.totalNumberOfStrokes.toFixed(0), + totalMovingTime: metrics.totalMovingTime.toFixed(5), + totalDistance: metrics.totalLinearDistance.toFixed(1), + totalCalories: metrics.totalCalories.toFixed(1), + splitNumber: metrics.split.number.toFixed(0), + heartrate: (metrics.heartrate !== undefined ? metrics.heartrate.toFixed(0) : NaN), + velocity: (metrics.totalNumberOfStrokes > 0 && metrics.cycleLinearVelocity > 0 ? metrics.cycleLinearVelocity.toFixed(2) : NaN), + pace: (metrics.totalNumberOfStrokes > 0 && metrics.cyclePace > 0 ? metrics.cyclePace.toFixed(2) : NaN), + power: (metrics.totalNumberOfStrokes > 0 && metrics.cyclePower > 0 ? metrics.cyclePower.toFixed(0) : NaN), + driveDuration: (metrics.driveDuration > 0 ? (metrics.driveDuration * 1000).toFixed(0) : NaN), + driveLength: (metrics.totalNumberOfStrokes > 0 && metrics.driveLength ? metrics.driveLength.toFixed(2) : NaN), + recoveryDuration: (metrics.recoveryDuration > 0 ? (metrics.recoveryDuration * 1000).toFixed(0) : NaN), + strokeDuration: (metrics.cycleDuration > 0 ? (metrics.cycleDuration * 1000).toFixed(0) : NaN), + strokeRate: (metrics.cycleStrokeRate > 0 ? metrics.cycleStrokeRate.toFixed(1) : NaN), + distancePerStroke: (metrics.cycleDistance > 0 ? metrics.cycleDistance.toFixed(2) : NaN), + peakHandleForce: (metrics.totalNumberOfStrokes > 0 && metrics.drivePeakHandleForce > 0 ? metrics.drivePeakHandleForce.toFixed(1) : NaN), + averageHandleForce: (metrics.totalNumberOfStrokes > 0 && metrics.driveAverageHandleForce > 0 ? metrics.driveAverageHandleForce.toFixed(1) : NaN), + dragfactor: (metrics.dragFactor > 0 ? metrics.dragFactor.toFixed(1) : NaN) + } + + client.publish(metricsTopic, JSON.stringify(jsonMetrics), { qos: 0, retain: false }, (error) => { + if (error) { + log.debug(`MQTT publisher, Error: ${error}`) + } + }) + } + + async function destroy () { + // Publish the last metrics + await publishMetrics(lastMetrics) + // Disconnect the client gracefully + client.end() + } + + return Object.assign(emitter, { + notifyData, + destroy + }) +} diff --git a/app/tools/RowingRecorder.js b/app/recorders/RowingReplayer.js similarity index 60% rename from app/tools/RowingRecorder.js rename to app/recorders/RowingReplayer.js index b73df54274..017558308b 100644 --- a/app/tools/RowingRecorder.js +++ b/app/recorders/RowingReplayer.js @@ -1,24 +1,14 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor A utility to record and replay flywheel measurements for development purposes. */ -import { fork } from 'child_process' + import fs from 'fs' import readline from 'readline' import log from 'loglevel' -function recordRowingSession (filename) { - // measure the gpio interrupts in another process, since we need - // to track time close to realtime - const gpioTimerService = fork('./app/gpio/GpioTimerService.js') - gpioTimerService.on('message', (dataPoint) => { - log.debug(dataPoint) - fs.appendFile(filename, `${dataPoint}\n`, (err) => { if (err) log.error(err) }) - }) -} - async function replayRowingSession (rotationImpulseHandler, options) { if (!options?.filename) { log.error('can not replay rowing session without filename') @@ -26,8 +16,9 @@ async function replayRowingSession (rotationImpulseHandler, options) { } do { + /* eslint-disable-next-line no-await-in-loop -- delay is by design, to simulate true real-time behaviour */ await replayRowingFile(rotationImpulseHandler, options) - // infinite looping only available when using realtime + // infinite looping only available when using realtime } while (options.loop && options.realtime) } @@ -41,18 +32,17 @@ async function replayRowingFile (rotationImpulseHandler, options) { for await (const line of readLine) { const dt = parseFloat(line) // if we want to replay in the original time, wait dt seconds - if (options.realtime) await wait(dt * 1000) + if (options.realtime) { await wait(dt * 1000) } rotationImpulseHandler(dt) } } async function wait (ms) { - return new Promise(resolve => { + return new Promise((resolve) => { setTimeout(resolve, ms) }) } export { - recordRowingSession, replayRowingSession } diff --git a/app/recorders/fileWriter.js b/app/recorders/fileWriter.js new file mode 100644 index 0000000000..16c1612dc7 --- /dev/null +++ b/app/recorders/fileWriter.js @@ -0,0 +1,66 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This Module writes the contents of file to disk (in gzip-format if needed) +*/ +import log from 'loglevel' +import zlib from 'zlib' +import fs from 'fs/promises' +import { promisify } from 'util' +const gzip = promisify(zlib.gzip) + +export function createFileWriter () { + let basefilename + + function setBaseFileName (baseFileName) { + basefilename = `${baseFileName}` + } + + async function writeFile (recorder, compress = false) { + let filename + if (compress) { + filename = `${basefilename}${recorder.postfix}.${recorder.type}.gz` + } else { + filename = `${basefilename}${recorder.postfix}.${recorder.type}` + } + + // we need enough data + if (!recorder.minimumDataAvailable()) { + log.info(`${recorder.presentationName} file has not been written, as there was not enough data recorded`) + return + } + + const fileContent = await recorder.fileContent() + + if (fileContent === undefined) { + log.error(`Error creating ${recorder.presentationName} file`) + } else { + await createFile(fileContent, `${filename}`, compress) + recorder.allDataHasBeenWritten = true + log.info(`${recorder.presentationName}-file has been saved as ${filename}`) + } + } + + async function createFile (content, filename, compress) { + if (compress) { + const gzipContent = await gzip(content) + try { + await fs.writeFile(filename, gzipContent) + } catch (err) { + log.error(err) + } + } else { + try { + await fs.writeFile(filename, content) + } catch (err) { + log.error(err) + } + } + } + + return { + setBaseFileName, + writeFile + } +} diff --git a/app/recorders/fitRecorder.js b/app/recorders/fitRecorder.js new file mode 100644 index 0000000000..8df1e5fab8 --- /dev/null +++ b/app/recorders/fitRecorder.js @@ -0,0 +1,803 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This Module captures the metrics of a rowing session and persists them into the fit format + * It provides a fit-file content, and some metadata for the filewriter and the file-uploaders + */ +/* eslint-disable camelcase -- Imported parameters are not camelCase */ +/* eslint-disable max-lines -- The length is governed by the fit-parameterisation, which we can't control */ +import log from 'loglevel' +import { createName } from './utils/decorators.js' +import { createSeries } from '../engine/utils/Series.js' +import { createVO2max } from './utils/VO2max.js' +import { FitWriter } from '@markw65/fit-file-writer' + +export function createFITRecorder (config) { + const type = 'fit' + const postfix = '_rowing' + const presentationName = 'Garmin fit' + const lapHRMetrics = createSeries() + const sessionHRMetrics = createSeries() + const VO2max = createVO2max(config) + let heartRate = 0 + let sessionData = {} + sessionData.workoutplan = [] + sessionData.workoutplan[0] = { type: 'justrow' } + sessionData.lap = [] + sessionData.complete = false + let lapnumber = 0 + let postExerciseHR = [] + let lastMetrics = {} + let fitfileContent + let fitfileContentIsCurrent = true + let allDataHasBeenWritten = true + + /** + * This function handles all incomming commands. Here, the recordingmanager will have filtered + * all unneccessary commands for us, so we only need to react to 'updateIntervalSettings', 'reset' and 'shutdown' + */ + async function handleCommand (commandName, data) { + switch (commandName) { + case ('updateIntervalSettings'): + if (!lastMetrics.metricsContext.isMoving) { + setIntervalParameters(data) + } + break + case ('reset'): + case ('shutdown'): + if (lastMetrics !== undefined && !!lastMetrics.metricsContext && lastMetrics.metricsContext.isMoving === true && (sessionData.lap[lapnumber].strokes.length > 0) && (lastMetrics.totalMovingTime > sessionData.lap[lapnumber].strokes[sessionData.lap[lapnumber].strokes.length - 1].totalMovingTime)) { + // We apperantly get a shutdown/crash during session + addMetricsToStrokesArray(lastMetrics) + calculateLapMetrics(lastMetrics) + calculateSessionMetrics(lastMetrics) + } + break + default: + log.error(`fitRecorder: Recieved unknown command: ${commandName}`) + } + } + + function setIntervalParameters (intervalParameters) { + if (intervalParameters !== undefined && intervalParameters.length > 0) { + sessionData.workoutplan = null + sessionData.workoutplan = intervalParameters + } + } + + /** + * This function records the metrics in the structure for he fit-file to be generated + * * @param {Metrics} metrics to be recorded + */ + function recordRowingMetrics (metrics) { + switch (true) { + case (metrics.metricsContext.isSessionStart): + sessionData.startTime = metrics.timestamp + lapnumber = 0 + startLap(lapnumber, metrics) + sessionHRMetrics.reset() + addMetricsToStrokesArray(metrics) + break + case (metrics.metricsContext.isSessionStop && lastMetrics.sessionState !== 'Stopped'): + addMetricsToStrokesArray(metrics) + calculateLapMetrics(metrics) + calculateSessionMetrics(metrics) + postExerciseHR = null + postExerciseHR = [] + measureRecoveryHR() + break + case (metrics.metricsContext.isPauseStart && lastMetrics.sessionState === 'Rowing'): + addMetricsToStrokesArray(metrics) + calculateLapMetrics(metrics) + calculateSessionMetrics(metrics) + resetLapMetrics() + postExerciseHR = null + postExerciseHR = [] + measureRecoveryHR() + break + case (metrics.metricsContext.isPauseEnd): + // The session is resumed, so it was a pause instead of a stop + lapnumber++ + addRestLap(lapnumber, metrics, sessionData.lap[lapnumber - 1].endTime, metrics.interval.workoutStepNumber) + lapnumber++ + startLap(lapnumber, metrics) + addMetricsToStrokesArray(metrics) + break + case (metrics.metricsContext.isIntervalEnd): + if (metrics.metricsContext.isDriveStart) { addMetricsToStrokesArray(metrics) } + calculateLapMetrics(metrics) + calculateSessionMetrics(metrics) + resetLapMetrics() + lapnumber++ + startLap(lapnumber, metrics) + break + case (metrics.metricsContext.isSplitEnd): + if (metrics.metricsContext.isDriveStart) { addMetricsToStrokesArray(metrics) } + calculateLapMetrics(metrics) + calculateSessionMetrics(metrics) + resetLapMetrics() + lapnumber++ + startLap(lapnumber, metrics) + break + case (metrics.metricsContext.isDriveStart): + addMetricsToStrokesArray(metrics) + break + // no default + } + lastMetrics = metrics + } + + function addMetricsToStrokesArray (metrics) { + sessionData.lap[lapnumber].strokes.push({}) + const strokenumber = sessionData.lap[lapnumber].strokes.length - 1 + sessionData.lap[lapnumber].strokes[strokenumber].timestamp = metrics.timestamp + sessionData.lap[lapnumber].strokes[strokenumber].totalLinearDistance = metrics.totalLinearDistance + sessionData.lap[lapnumber].strokes[strokenumber].totalNumberOfStrokes = metrics.totalNumberOfStrokes + sessionData.lap[lapnumber].strokes[strokenumber].cycleStrokeRate = metrics.cycleStrokeRate + sessionData.lap[lapnumber].strokes[strokenumber].cyclePower = metrics.cyclePower + sessionData.lap[lapnumber].strokes[strokenumber].cycleLinearVelocity = metrics.cycleLinearVelocity + sessionData.lap[lapnumber].strokes[strokenumber].cycleDistance = metrics.cycleDistance + sessionData.lap[lapnumber].strokes[strokenumber].dragFactor = metrics.dragFactor + if (!isNaN(heartRate) && heartRate > 0) { + sessionData.lap[lapnumber].strokes[strokenumber].heartrate = heartRate + } else { + sessionData.lap[lapnumber].strokes[strokenumber].heartrate = undefined + } + VO2max.push(metrics) + fitfileContentIsCurrent = false + allDataHasBeenWritten = false + } + + function startLap (lapnumber, metrics) { + resetLapMetrics() + sessionData.lap[lapnumber] = { totalMovingTimeAtStart: metrics.totalMovingTime } + sessionData.lap[lapnumber].intensity = 'active' + sessionData.lap[lapnumber].strokes = [] + sessionData.lap[lapnumber].startTime = metrics.timestamp + sessionData.lap[lapnumber].lapNumber = lapnumber + 1 + sessionData.lap[lapnumber].complete = false + } + + function calculateLapMetrics (metrics) { + sessionData.lap[lapnumber].workoutStepNumber = metrics.interval.workoutStepNumber + sessionData.lap[lapnumber].endTime = metrics.timestamp + switch (true) { + case (metrics.metricsContext.isSessionStop && (metrics.interval.type === 'distance' || metrics.interval.type === 'time')): + // As the workout closure has its own events, we need to close the workout step here + sessionData.lap[lapnumber].trigger = metrics.interval.type + sessionData.lap[lapnumber].event = 'workoutStep' + break + case (metrics.metricsContext.isSessionStop): + sessionData.lap[lapnumber].trigger = 'manual' + sessionData.lap[lapnumber].event = 'workoutStep' + break + case (metrics.metricsContext.isIntervalEnd && (metrics.interval.type === 'distance' || metrics.interval.type === 'time')): + sessionData.lap[lapnumber].trigger = metrics.interval.type + sessionData.lap[lapnumber].event = 'workoutStep' + break + case (metrics.metricsContext.isIntervalEnd): + sessionData.lap[lapnumber].trigger = 'manual' + sessionData.lap[lapnumber].event = 'workoutStep' + break + case (metrics.metricsContext.isPauseStart): + // As metrics.metricsContext.isIntervalEnd === false, we know this is a spontanuous pause and not a planned rest interval + sessionData.lap[lapnumber].trigger = 'manual' + sessionData.lap[lapnumber].event = 'speedLowAlert' + break + case (metrics.metricsContext.isSplitEnd && (metrics.split.type === 'distance' || metrics.split.type === 'time')): + sessionData.lap[lapnumber].trigger = metrics.split.type + sessionData.lap[lapnumber].event = 'lap' + break + case (metrics.metricsContext.isSplitEnd): + sessionData.lap[lapnumber].trigger = 'manual' + sessionData.lap[lapnumber].event = 'lap' + break + default: + sessionData.lap[lapnumber].trigger = 'manual' + sessionData.lap[lapnumber].event = 'lap' + } + sessionData.lap[lapnumber].summary = { ...metrics.split } + sessionData.lap[lapnumber].averageHeartrate = lapHRMetrics.average() + sessionData.lap[lapnumber].maximumHeartrate = lapHRMetrics.maximum() + sessionData.lap[lapnumber].complete = true + } + + function resetLapMetrics () { + lapHRMetrics.reset() + if (!isNaN(heartRate) && heartRate > 0) { lapHRMetrics.push(heartRate) } + } + + function addRestLap (lapnumber, metrics, startTime, workoutStepNo) { + sessionData.lap[lapnumber] = { startTime } + sessionData.lap[lapnumber].intensity = 'rest' + sessionData.lap[lapnumber].workoutStepNumber = workoutStepNo + switch (true) { + case (metrics.metricsContext.isIntervalEnd): + // This occurs when the sessionmanager termnates a planned rest interval + sessionData.lap[lapnumber].trigger = 'time' + sessionData.lap[lapnumber].event = 'workoutStep' + break + default: + // It is an unplanned rest lap + sessionData.lap[lapnumber].trigger = 'manual' + sessionData.lap[lapnumber].event = 'lap' + } + sessionData.lap[lapnumber].lapNumber = lapnumber + 1 + sessionData.lap[lapnumber].endTime = metrics.timestamp + sessionData.lap[lapnumber].averageHeartrate = lapHRMetrics.average() + sessionData.lap[lapnumber].maximumHeartrate = lapHRMetrics.maximum() + sessionData.lap[lapnumber].summary = { ...metrics.split } + sessionData.lap[lapnumber].complete = true + VO2max.handleRestart(metrics.split.timeSpent.moving) + } + + function calculateSessionMetrics (metrics) { + sessionData.totalNoLaps = lapnumber + 1 + sessionData.totalTime = metrics.workout.timeSpent.total + sessionData.totalMovingTime = metrics.workout.timeSpent.moving + sessionData.totalRestTime = metrics.workout.timeSpent.rest + sessionData.totalLinearDistance = metrics.workout.distance.fromStart + sessionData.totalNumberOfStrokes = metrics.workout.numberOfStrokes + sessionData.averageLinearVelocity = metrics.workout.linearVelocity.average + sessionData.maximumLinearVelocity = metrics.workout.linearVelocity.maximum + sessionData.averagePower = metrics.workout.power.average + sessionData.maximumPower = metrics.workout.power.maximum + sessionData.averageStrokerate = metrics.workout.strokerate.average + sessionData.maximumStrokerate = metrics.workout.strokerate.maximum + sessionData.averageStrokeDistance = metrics.workout.strokeDistance.average + sessionData.minimumHeartrate = sessionHRMetrics.minimum() + sessionData.averageHeartrate = sessionHRMetrics.average() + sessionData.maximumHeartrate = sessionHRMetrics.maximum() + sessionData.endTime = sessionData.lap[lapnumber].endTime + sessionData.complete = true + } + + /* + * initiated when a new heart rate value is received from heart rate sensor + */ + async function recordHeartRate (value) { + heartRate = value.heartrate + if (!isNaN(heartRate) && heartRate > 0) { + lapHRMetrics.push(heartRate) + sessionHRMetrics.push(heartRate) + } + } + + /* + * This externally exposed function generates the file contont for the file writer and uploaders + */ + async function fileContent () { + if (Object.keys(lastMetrics).length === 0 || Object.keys(sessionData).length === 0) { return undefined } + + if (sessionData.lap[lapnumber].complete !== true) { + addMetricsToStrokesArray(lastMetrics) + calculateLapMetrics(lastMetrics) + } + + if (sessionData.complete !== true) { + calculateSessionMetrics(lastMetrics) + } + + const fitData = await workoutToFit(sessionData) + if (fitData === undefined) { + log.error('error creating fit file content') + return undefined + } else { + return fitData + } + } + + async function workoutToFit (workout) { + // The file content is filled and hasn't changed + if (fitfileContentIsCurrent === true && fitfileContent !== undefined) { return fitfileContent } + + // See https://developer.garmin.com/fit/file-types/activity/ for the fields and their meaning. We use 'Smart Recording' per stroke. + // See also https://developer.garmin.com/fit/cookbook/encoding-activity-files/ for a description of the filestructure and how timestamps should be implemented + // We use 'summary last message sequencing' as the stream makes most sense that way + const fitWriter = new FitWriter() + const versionNumber = parseInt(process.env.npm_package_version, 10) + + // The file header + fitWriter.writeMessage( + 'file_id', + { + time_created: fitWriter.time(workout.startTime), + type: 'activity', + manufacturer: 'concept2', + product: 0, + number: 0 + }, + null, + true + ) + + fitWriter.writeMessage( + 'file_creator', + { + software_version: versionNumber + }, + null, + true + ) + + fitWriter.writeMessage( + 'device_info', + { + timestamp: fitWriter.time(workout.startTime), + device_index: 0, + device_type: 0, + manufacturer: 'concept2' + }, + null, + true + ) + + // The below message deliberately leans on the config.userSettings as they might be changed by external sources + fitWriter.writeMessage( + 'user_profile', + { + gender: config.userSettings.sex, + weight: config.userSettings.weight, + weight_setting: 'metric', + resting_heart_rate: config.userSettings.restingHR, + default_max_heart_rate: config.userSettings.maxHR + }, + null, + true + ) + + fitWriter.writeMessage( + 'sport', + { + sport: 'rowing', + sub_sport: 'indoorRowing', + name: 'Indoor rowing' + }, + null, + true + ) + + // The workout before the start + await createWorkoutSteps(fitWriter, workout) + + // Write the metrics + await createActivity(fitWriter, workout) + + fitfileContent = fitWriter.finish() + fitfileContentIsCurrent = true + return fitfileContent + } + + async function createActivity (writer, workout) { + // Start of the session + await addEvent(writer, workout.startTime, 'workout', 'start') + await addEvent(writer, workout.startTime, 'timer', 'start') + + // Write all laps + let i = 0 + while (i < workout.lap.length) { + if (workout.lap[i].intensity === 'active') { + // eslint-disable-next-line no-await-in-loop -- This is inevitable if you want to have some decent order in the file + await createActiveLap(writer, workout.lap[i]) + } else { + // This is a rest interval + // eslint-disable-next-line no-await-in-loop -- This is inevitable if you want to have some decent order in the file + await createRestLap(writer, workout.lap[i]) + } + i++ + } + + // Finish the seesion with a stop event + await addEvent(writer, workout.endTime, 'timer', 'stopAll') + await addEvent(writer, workout.endTime, 'workout', 'stop') + + // Write the split summary + // ToDo: Find out how records, splits, laps and sessions can be subdivided + writer.writeMessage( + 'split', + { + start_time: writer.time(workout.startTime), + split_type: 'intervalActive', + total_elapsed_time: workout.totalTime, + total_timer_time: workout.totalTime, + total_moving_time: workout.totalMovingTime, + total_distance: workout.totalLinearDistance, + avg_speed: workout.averageLinearVelocity, + max_speed: workout.maximumLinearVelocity, + end_time: writer.time(workout.endTime) + }, + null, + true + ) + + await createVO2MaxRecord(writer, workout) + + // Conclude with a session summary + // See https://developer.garmin.com/fit/cookbook/durations/ for explanation about times + writer.writeMessage( + 'session', + { + timestamp: writer.time(workout.endTime), + message_index: 0, + sport: 'rowing', + sub_sport: 'indoorRowing', + event: 'session', + event_type: 'stop', + trigger: 'activityEnd', + start_time: writer.time(workout.startTime), + total_elapsed_time: workout.totalTime, + total_timer_time: workout.totalTime, + total_moving_time: workout.totalMovingTime, + total_distance: workout.totalLinearDistance, + total_cycles: workout.totalNumberOfStrokes, + avg_speed: workout.averageLinearVelocity, + max_speed: workout.maximumLinearVelocity, + avg_power: workout.averagePower, + max_power: workout.maximumPower, + avg_cadence: workout.averageStrokerate, + max_cadence: workout.maximumStrokerate, + ...(sessionData.minimumHeartrate > 0 ? { min_heart_rate: sessionData.minimumHeartrate } : {}), + ...(sessionData.averageHeartrate > 0 ? { avg_heart_rate: sessionData.averageHeartrate } : {}), + ...(sessionData.maximumHeartrate > 0 ? { max_heart_rate: sessionData.maximumHeartrate } : {}), + avg_stroke_distance: workout.averageStrokeDistance, + first_lap_index: 0, + num_laps: sessionData.totalNoLaps + }, + null, + true + ) + + // Activity summary + writer.writeMessage( + 'activity', + { + timestamp: writer.time(workout.endTime), + local_timestamp: writer.time(workout.startTime) - workout.startTime.getTimezoneOffset() * 60, + total_timer_time: workout.totalTime, + num_sessions: 1, + event: 'activity', + event_type: 'stop', + type: 'manual' + }, + null, + true + ) + + await addHRR2Event(writer) + } + + async function addEvent (writer, time, event, eventType) { + writer.writeMessage( + 'event', + { + timestamp: writer.time(time), + event: event, + event_type: eventType, + event_group: 0 + }, + null, + true + ) + } + + async function createActiveLap (writer, lapdata) { + // It is an active lap, after we make sure it is a completed lap, we can write all underlying records + if (!!lapdata.summary.timeSpent.moving && lapdata.summary.timeSpent.moving > 0 && !!lapdata.summary.distance.fromStart && lapdata.summary.distance.fromStart > 0) { + let i = 0 + while (i < lapdata.strokes.length) { + // eslint-disable-next-line no-await-in-loop -- This is inevitable if you want to have some decent order in the file + await createTrackPoint(writer, lapdata.strokes[i]) + i++ + } + + await addEvent(writer, lapdata.endTime, lapdata.event, 'stop') + + // Conclude the lap with a summary + // See https://developer.garmin.com/fit/cookbook/durations/ for how the different times are defined + writer.writeMessage( + 'lap', + { + timestamp: writer.time(lapdata.endTime), + message_index: lapdata.lapNumber - 1, + sport: 'rowing', + sub_sport: 'indoorRowing', + event: lapdata.event, + wkt_step_index: lapdata.workoutStepNumber, + event_type: 'stop', + intensity: lapdata.intensity, + ...(sessionData.totalNoLaps === lapdata.lapNumber ? { lap_trigger: 'sessionEnd' } : { lap_trigger: lapdata.trigger }), + start_time: writer.time(lapdata.startTime), + total_elapsed_time: lapdata.summary.timeSpent.total, + total_timer_time: lapdata.summary.timeSpent.total, + total_moving_time: lapdata.summary.timeSpent.moving, + total_distance: lapdata.summary.distance.fromStart, + total_cycles: lapdata.summary.numberOfStrokes, + avg_cadence: lapdata.summary.strokerate.average, + max_cadence: lapdata.summary.strokerate.maximum, + avg_stroke_distance: lapdata.summary.strokeDistance.average, + total_calories: lapdata.summary.calories.totalSpent, + avg_speed: lapdata.summary.linearVelocity.average, + max_speed: lapdata.summary.linearVelocity.maximum, + avg_power: lapdata.summary.power.average, + max_power: lapdata.summary.power.maximum, + ...(lapdata.averageHeartrate > 0 ? { avg_heart_rate: lapdata.averageHeartrate } : {}), + ...(lapdata.maximumHeartrate > 0 ? { max_heart_rate: lapdata.maximumHeartrate } : {}) + }, + null, + sessionData.totalNoLaps === lapdata.lapNumber + ) + } + } + + async function createRestLap (writer, lapdata) { + // First, make sure the rest lap is complete + if (!!lapdata.endTime && lapdata.endTime > 0 && !!lapdata.startTime && lapdata.startTime > 0) { + // Pause the session timer with a stop event at the begin of the rest interval + await addEvent(writer, lapdata.startTime, 'timer', 'stop') + + // Add a rest lap summary + // See https://developer.garmin.com/fit/cookbook/durations/ for how the different times are defined + writer.writeMessage( + 'lap', + { + timestamp: writer.time(lapdata.endTime), + message_index: lapdata.lapNumber - 1, + sport: 'rowing', + sub_sport: 'indoorRowing', + event: lapdata.event, + wkt_step_index: lapdata.workoutStepNumber, + event_type: 'stop', + intensity: lapdata.intensity, + lap_trigger: lapdata.trigger, + start_time: writer.time(lapdata.startTime), + total_elapsed_time: lapdata.summary.timeSpent.total, + total_timer_time: lapdata.summary.timeSpent.total, + total_moving_time: 0, + total_distance: 0, + total_cycles: 0, + avg_cadence: 0, + max_cadence: 0, + avg_stroke_distance: 0, + total_calories: 0, + avg_speed: 0, + max_speed: 0, + avg_power: 0, + max_power: 0, + ...(lapdata.averageHeartrate > 0 ? { avg_heart_rate: lapdata.averageHeartrate } : {}), + ...(lapdata.maximumHeartrate > 0 ? { max_heart_rate: lapdata.maximumHeartrate } : {}) + }, + null, + sessionData.totalNoLaps === lapdata.lapNumber + ) + + // Restart of the session + await addEvent(writer, lapdata.endTime, lapdata.event, 'stop') + await addEvent(writer, lapdata.endTime, 'timer', 'start') + } + } + + async function createTrackPoint (writer, trackpoint) { + writer.writeMessage( + 'record', + { + timestamp: writer.time(trackpoint.timestamp), + distance: trackpoint.totalLinearDistance, + total_cycles: trackpoint.totalNumberOfStrokes, + activity_type: 'fitnessEquipment', + ...(trackpoint.cycleLinearVelocity > 0 || trackpoint.isPauseStart ? { speed: trackpoint.cycleLinearVelocity } : {}), + ...(trackpoint.cyclePower > 0 || trackpoint.isPauseStart ? { power: trackpoint.cyclePower } : {}), + ...(trackpoint.cycleStrokeRate > 0 ? { cadence: trackpoint.cycleStrokeRate } : {}), + ...(trackpoint.cycleDistance > 0 ? { cycle_length16: trackpoint.cycleDistance } : {}), + ...(trackpoint.dragFactor > 0 || trackpoint.dragFactor < 255 ? { resistance: trackpoint.dragFactor } : {}), // As the data is stored in an int8, we need to guard the maximum + ...(trackpoint.heartrate !== undefined && trackpoint.heartrate > 0 ? { heart_rate: trackpoint.heartrate } : {}) + } + ) + } + + async function createWorkoutSteps (writer, workout) { + // See https://developer.garmin.com/fit/file-types/workout/ for a general description of the workout structure + // and https://developer.garmin.com/fit/cookbook/encoding-workout-files/ for a detailed description of the workout structure + const maxWorkoutStepNumber = workout.lap[workout.lap.length - 1].workoutStepNumber + writer.writeMessage( + 'workout', + { + sport: 'rowing', + sub_sport: 'indoorRowing', + capabilities: 'fitnessEquipment', + num_valid_steps: maxWorkoutStepNumber + 1, + wkt_name: `Indoor rowing ${createName(workout.totalLinearDistance, workout.totalMovingTime)}` + }, + null, + true + ) + + let i = 0 + while (i < workout.workoutplan.length && i <= maxWorkoutStepNumber) { + switch (true) { + case (workout.workoutplan[i].type === 'distance' && workout.workoutplan[i].targetDistance > 0): + // A target distance is set + createWorkoutStep(writer, i, 'distance', workout.workoutplan[i].targetDistance * 100, 'active') + break + case (workout.workoutplan[i].type === 'time' && workout.workoutplan[i].targetTime > 0): + // A target time is set + createWorkoutStep(writer, i, 'time', workout.workoutplan[i].targetTime * 1000, 'active') + break + case (workout.workoutplan[i].type === 'rest' && workout.workoutplan[i].targetTime > 0): + // A target time is set + createWorkoutStep(writer, i, 'time', workout.workoutplan[i].targetTime * 1000, 'rest') + break + case (workout.workoutplan[i].type === 'justrow'): + createWorkoutStep(writer, i, 'open', 0, 'active') + break + default: + // Nothing to do here, ignore malformed data + } + i++ + } + } + + async function createWorkoutStep (writer, stepNumber, durationType, durationValue, intensityValue) { + writer.writeMessage( + 'workout_step', + { + message_index: stepNumber, + duration_type: durationType, + ...(durationValue > 0 ? { duration_value: durationValue } : {}), + intensity: intensityValue + }, + null, + true + ) + } + + async function createVO2MaxRecord (writer, workout) { + if (!isNaN(VO2max.result()) && VO2max.result() > 10 && VO2max.result() < 60) { + writer.writeMessage( + 'max_met_data', + { + update_time: writer.time(workout.endTime), + sport: 'rowing', + sub_sport: 'indoorRowing', + vo2_max: VO2max.result(), + max_met_category: 'generic' + }, + null, + true + ) + } + } + + async function addHRR2Event (writer) { + if (postExerciseHR.length >= 2 && !isNaN(postExerciseHR[2]) && postExerciseHR[2] > 0) { + writer.writeMessage( + 'event', + { + timestamp: writer.time(new Date()), + event: 'recoveryHr', + event_type: 'marker', + data: postExerciseHR[2] + }, + null, + true + ) + } + } + + 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 (!isNaN(heartRate) && config.userSettings.restingHR <= heartRate && heartRate <= config.userSettings.maxHR) { + log.debug(`*** Fit-recorder HRR-${postExerciseHR.length}: ${heartRate}`) + postExerciseHR.push(heartRate) + fitfileContentIsCurrent = false + allDataHasBeenWritten = false + if (postExerciseHR.length < 4) { + // We haven't got three post-exercise HR measurements yet, let's schedule the next measurement + setTimeout(measureRecoveryHR, 60000) + } else { + log.debug('*** Skipped HRR measurement') + } + } + } + + function minimumDataAvailable () { + return (minimumRecordingTimeHasPassed() && minimumNumberOfStrokesHaveCompleted()) + } + + function minimumRecordingTimeHasPassed () { + const minimumRecordingTimeInSeconds = 10 + if (lastMetrics !== undefined && lastMetrics.totalMovingTime !== undefined) { + const strokeTimeTotal = lastMetrics.totalMovingTime + return (strokeTimeTotal > minimumRecordingTimeInSeconds) + } else { + return false + } + } + + function minimumNumberOfStrokesHaveCompleted () { + const minimumNumberOfStrokes = 2 + if (lastMetrics !== undefined && lastMetrics.totalNumberOfStrokes !== undefined) { + const noStrokes = lastMetrics.totalNumberOfStrokes + return (noStrokes > minimumNumberOfStrokes) + } else { + return false + } + } + + function totalRecordedDistance () { + if (!!sessionData.totalLinearDistance && sessionData.totalLinearDistance > 0) { + return sessionData.totalLinearDistance + } else { + return 0 + } + } + + function totalRecordedMovingTime () { + if (!!sessionData.totalMovingTime && sessionData.totalMovingTime > 0) { + return sessionData.totalMovingTime + } else { + return 0 + } + } + + function sessionDrag () { + return lastMetrics.workout.dragfactor.average + } + + function sessionVO2Max () { + if (VO2max.result() > 10 && VO2max.result() < 60) { + return VO2max.result() + } else { + return undefined + } + } + + function sessionHRR () { + 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 + return postExerciseHR + } else { + return [] + } + } + + function reset () { + heartRate = 0 + lapnumber = 0 + lapHRMetrics.reset() + sessionHRMetrics.reset() + sessionData = null + sessionData = {} + sessionData.workoutplan = [] + sessionData.workoutplan[0] = { type: 'justrow' } + sessionData.lap = [] + sessionData.complete = false + postExerciseHR = null + postExerciseHR = [] + VO2max.reset() + lastMetrics = {} + fitfileContent = null + fitfileContentIsCurrent = true + allDataHasBeenWritten = true + } + + return { + handleCommand, + setIntervalParameters, + recordRowingMetrics, + recordHeartRate, + minimumDataAvailable, + fileContent, + type, + postfix, + presentationName, + totalRecordedDistance, + totalRecordedMovingTime, + sessionDrag, + sessionVO2Max, + sessionHRR, + allDataHasBeenWritten, + reset + } +} diff --git a/app/recorders/intervalsInterface.js b/app/recorders/intervalsInterface.js new file mode 100644 index 0000000000..fcd31c64e5 --- /dev/null +++ b/app/recorders/intervalsInterface.js @@ -0,0 +1,66 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This Module is the interface to the Intervsals.icu webservice +*/ +import log from 'loglevel' +import { createName, createDragLine, createVO2MaxLine, createHRRLine } from './utils/decorators.js' +import fetch, { FormData } from 'node-fetch' + +export function createIntervalsInterface (config) { + let basefilename = '' + + async function setBaseFileName (name) { + basefilename = name + } + + async function uploadSessionResults (recorder) { + // we need enough data + if (!recorder.minimumDataAvailable()) { + log.info(`${recorder.presentationName} file has not been uploaded to Intervals.icu, as there was not enough data recorded`) + return + } + + const form = new FormData() + + const sessionName = createName(recorder.totalRecordedDistance(), recorder.totalRecordedMovingTime()) + form.append('name', sessionName) + + const fileContent = await recorder.fileContent() + const file = new File([fileContent], `${basefilename}${recorder.postfix}.${recorder.type}`, { type: 'text/plain' }) + form.append('file', file) + + const dragLine = createDragLine(recorder.sessionDrag()) + const VO2MaxLine = createVO2MaxLine(recorder.sessionVO2Max()) + log.info(`Intervals HRR Data: ${recorder.sessionHRR()}`) + const HRRLine = createHRRLine(recorder.sessionHRR()) + const sessionNote = `${dragLine}${VO2MaxLine}${HRRLine}` + form.append('description', sessionNote) + + form.append('type', 'Rowing') + form.append('trainer', true) + form.append('indoor', true) + form.append('moving_time', recorder.totalRecordedMovingTime()) + form.append('distance', recorder.totalRecordedDistance()) + form.append('total_elevation_gain', '0') + + try { + await fetch(`https://intervals.icu/api/v1/athlete/${config.userSettings.intervals.athleteId}/activities`, { + method: 'POST', + headers: { + Authorization: 'Basic ' + btoa(`API_KEY:${config.userSettings.intervals.apiKey}`) + }, + body: form + }) + log.info('Intervals.icu interface: uploaded session data') + } catch (error) { + log.error(`Intervals.icu interface error: ${error}`) + } + } + + return { + setBaseFileName, + uploadSessionResults + } +} diff --git a/app/recorders/logRecorder.js b/app/recorders/logRecorder.js new file mode 100644 index 0000000000..1eaa2d163d --- /dev/null +++ b/app/recorders/logRecorder.js @@ -0,0 +1,94 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This Module captures the metrics of a rowing session and persists them. +*/ +import log from 'loglevel' +import { secondsToTimeString } from '../tools/Helper.js' + +export function createLogRecorder () { + let heartRate = 0 + let lastMetrics = { + totalMovingTime: 0, + totalLinearDistance: 0 + } + + // This function handles all incomming commands. Here, the recordingmanager will have filtered + // all unneccessary commands for us, so we only need to react to 'updateIntervalSettings', 'reset' and 'shutdown' + // eslint-disable-next-line no-unused-vars + async function handleCommand (commandName, data) { + const currentdate = new Date() + switch (commandName) { + case ('updateIntervalSettings'): + log.info(`Recieved new Intervalsettings at ${currentdate.getHours()}:${currentdate.getMinutes()}`) + break + case ('reset'): + log.info(`OpenRowingMonitor reset at ${currentdate.getHours()}:${currentdate.getMinutes()}, at ${lastMetrics.totalMovingTime.toFixed(5)} seconds,distance ${lastMetrics.totalLinearDistance.toFixed(1)}m`) + break + case 'shutdown': + log.info(`OpenRowingMonitor shutdown at ${currentdate.getHours()}:${currentdate.getMinutes()}, at ${lastMetrics.totalMovingTime.toFixed(5)} seconds,distance ${lastMetrics.totalLinearDistance.toFixed(1)}m`) + break + default: + log.error(`Logecorder: Recieved unknown command: ${commandName}`) + } + } + + // initiated when a new heart rate value is received from heart rate sensor + async function recordHeartRate (value) { + heartRate = value.heartrate + } + + function recordRowingMetrics (metrics) { + const currentdate = new Date() + switch (true) { + case (metrics.metricsContext.isSessionStart): + log.info(`Rowing started at ${currentdate.getHours()}:${currentdate.getMinutes()}:${currentdate.getSeconds()}`) + break + case (metrics.metricsContext.isSessionStop): + logMetrics(metrics) + log.info(`Rowing ended at ${currentdate.getHours()}:${currentdate.getMinutes()}:${currentdate.getSeconds()}, at ${metrics.totalMovingTime.toFixed(5)} seconds,distance ${metrics.totalLinearDistance.toFixed(1)}m`) + break + case (metrics.metricsContext.isPauseStart && lastMetrics.sessionState === 'Rowing'): + logMetrics(metrics) + log.info(`Rowing stopped/paused at ${currentdate.getHours()}:${currentdate.getMinutes()}:${currentdate.getSeconds()}, at ${metrics.totalMovingTime.toFixed(5)} seconds,distance ${metrics.totalLinearDistance.toFixed(1)}m`) + break + case (metrics.metricsContext.isPauseStart): + // We were not rowing, but a pause is triggered. This is the Rowing Engine signaling it is forced into a pause condition + log.info(`Rowing engine armed again at ${currentdate.getHours()}:${currentdate.getMinutes()}:${currentdate.getSeconds()}`) + break + case (metrics.metricsContext.isPauseEnd): + log.info(`Rowing resumed at ${currentdate.getHours()}:${currentdate.getMinutes()}:${currentdate.getSeconds()}`) + break + case (metrics.metricsContext.isIntervalEnd): + log.info(`New interval started at ${metrics.totalMovingTime.toFixed(5)} seconds, distance ${metrics.totalLinearDistance.toFixed(1)}m`) + break + case (metrics.metricsContext.isSplitEnd): + log.info(`New split started at ${metrics.totalMovingTime.toFixed(5)} seconds, distance ${metrics.totalLinearDistance.toFixed(1)}m`) + break + case (metrics.metricsContext.isDriveStart): + logMetrics(metrics) + break + // no default + } + lastMetrics = metrics + } + + function logMetrics (metrics) { + if (heartRate !== undefined && heartRate > 0) { + log.info(`stroke: ${metrics.totalNumberOfStrokes}, dist: ${metrics.totalLinearDistance.toFixed(1)}m, heartrate ${heartRate} BPM` + + `, pace: ${metrics.cyclePace > 0 ? secondsToTimeString(metrics.cyclePace) : NaN}/500m, stroke dist: ${metrics.cycleDistance > 0 ? metrics.cycleDistance.toFixed(1) : NaN}m, strokerate: ${metrics.cycleStrokeRate > 0 ? metrics.cycleStrokeRate.toFixed(1) : NaN} SPM` + + `, drive dur: ${metrics.driveDuration > 0 ? metrics.driveDuration.toFixed(2) : NaN}s, rec. dur: ${metrics.recoveryDuration > 0 ? metrics.recoveryDuration.toFixed(2) : NaN}s, stroke dur: ${metrics.cycleDuration ? metrics.cycleDuration.toFixed(2) : NaN}s`) + } else { + log.info(`stroke: ${metrics.totalNumberOfStrokes}, dist: ${metrics.totalLinearDistance.toFixed(1)}m, No heartrate detected` + + `, pace: ${metrics.cyclePace > 0 ? secondsToTimeString(metrics.cyclePace) : NaN}/500m, stroke dist: ${metrics.cycleDistance > 0 ? metrics.cycleDistance.toFixed(1) : NaN}m, strokerate: ${metrics.cycleStrokeRate > 0 ? metrics.cycleStrokeRate.toFixed(1) : NaN} SPM` + + `, drive dur: ${metrics.driveDuration > 0 ? metrics.driveDuration.toFixed(2) : NaN}s, rec. dur: ${metrics.recoveryDuration > 0 ? metrics.recoveryDuration.toFixed(2) : NaN}s, stroke dur: ${metrics.cycleDuration ? metrics.cycleDuration.toFixed(2) : NaN}s`) + } + } + + return { + handleCommand, + recordRowingMetrics, + recordHeartRate + } +} diff --git a/app/recorders/rawRecorder.js b/app/recorders/rawRecorder.js new file mode 100644 index 0000000000..7afc83380d --- /dev/null +++ b/app/recorders/rawRecorder.js @@ -0,0 +1,99 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This Module captures the raw pulses of a rowing session and persists them. +*/ +import log from 'loglevel' + +export function createRawRecorder () { + const type = 'csv' + const postfix = '_raw' + const presentationName = 'Raw data' + let rotationImpulses = [] + let allDataHasBeenWritten + + // This function handles all incomming commands. As this recorder is strokestate/sessionstate insensitive, it can be empty + /* eslint-disable-next-line no-unused-vars -- standardised recorder interface where the commands are not relevant for this recorder */ + async function handleCommand (commandName, data) { + // As this recorder isn't rowing/session state dependent at all, we can skip this + } + + async function recordRotationImpulse (impulse) { + // Please observe: this MUST be doe in memory first, before persisting. Persisting to disk without the + // intermediate step of persisting to memory can lead to buffering issues that will mix up impulses in the recording !!!! + await rotationImpulses.push(impulse) + allDataHasBeenWritten = false + } + + /* eslint-disable-next-line no-unused-vars -- standardised recorder interface where the metrics are not relevant for this recorder */ + function recordRowingMetrics (metrics) { + // As this recorder isn't rowing/session state dependent at all, we can skip this + } + + async function fileContent () { + const rawData = rotationImpulses.join('\n') + if (rawData === undefined) { + log.error('error creating raw file content') + return undefined + } else { + return rawData + } + } + + function minimumDataAvailable () { + const minimumRecordingTimeInSeconds = 10 + // We need to make sure that we use the Math.abs(), as a gpio rollover can cause impulse to be negative! + const rotationImpulseTimeTotal = rotationImpulses.reduce((acc, impulse) => acc + Math.abs(impulse), 0) + return (rotationImpulseTimeTotal > minimumRecordingTimeInSeconds) + } + + function totalRecordedDistance () { + return 0 + } + + function totalRecordedMovingTime () { + const rotationImpulseTimeTotal = rotationImpulses.reduce((acc, impulse) => acc + Math.abs(impulse), 0) + if (rotationImpulseTimeTotal > 0) { + return rotationImpulseTimeTotal + } else { + return 0 + } + } + + function sessionDrag () { + return 0 + } + + function sessionVO2Max () { + return undefined + } + + function sessionHRR () { + return [] + } + + function reset () { + rotationImpulses = null + rotationImpulses = [] + allDataHasBeenWritten = true + } + + return { + recordRotationImpulse, + recordRowingMetrics, + handleCommand, + minimumDataAvailable, + fileContent, + type, + postfix, + presentationName, + totalRecordedDistance, + totalRecordedMovingTime, + sessionDrag, + sessionVO2Max, + sessionHRR, + allDataHasBeenWritten, + reset + } +} diff --git a/app/recorders/recordingManager.js b/app/recorders/recordingManager.js new file mode 100644 index 0000000000..fd7e8562c2 --- /dev/null +++ b/app/recorders/recordingManager.js @@ -0,0 +1,199 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This Module captures the metrics of a rowing session and persists them. +*/ +import log from 'loglevel' +import fs from 'fs/promises' +import { createFileWriter } from './fileWriter.js' +import { createLogRecorder } from './logRecorder.js' +import { createRawRecorder } from './rawRecorder.js' +import { createTCXRecorder } from './tcxRecorder.js' +import { createFITRecorder } from './fitRecorder.js' +import { createRowingDataRecorder } from './rowingDataRecorder.js' +import { createRowsAndAllInterface } from './rowsAndAllInterface.js' +import { createIntervalsInterface } from './intervalsInterface.js' +import { createStravaInterface } from './stravaInterface.js' + +export function createRecordingManager (config) { + let startTime + let allRecordingsHaveBeenUploaded = true // ToDo: Make this an uploader responsibility! + const fileWriter = createFileWriter() + const logRecorder = createLogRecorder() + const rawRecorder = createRawRecorder() + const tcxRecorder = createTCXRecorder(config) + const fitRecorder = createFITRecorder(config) + const rowingDataRecorder = createRowingDataRecorder(config) + const rowsAndAllInterface = createRowsAndAllInterface(config) + const intervalsInterface = createIntervalsInterface(config) + const stravaInterface = createStravaInterface(config) + const recordRawData = config.createRawDataFiles + const recordTcxData = config.createTcxFiles || config.stravaClientId !== '' + const recordFitData = config.createFitFiles || config.userSettings.intervals.allowUpload || config.userSettings.strava.allowUpload + const recordRowingData = config.createRowingDataFiles || config.userSettings.rowsAndAll.allowUpload + let writeTimer + let uploadTimer + + /** + * This function handles all incomming commands. As all commands are broadasted to all managers, we need to filter here what is relevant + * for the recorders and what is not + * + * For the 'start', 'startOrResume', 'pause' and 'stop' commands, we await the official SessionManager reaction + * + * @param {Command} Name of the command to be executed by the commandhandler + * @param {unknown} data for executing the command + * + * @see {@link https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Architecture.md#command-flow|The command flow documentation} + */ + async function handleCommand (commandName, data) { + switch (commandName) { + case ('updateIntervalSettings'): + executeCommandsInParralel(commandName, data) + break + case ('start'): + break + case ('startOrResume'): + break + case ('pause'): + break + case ('stop'): + break + case ('reset'): + clearTimeout(writeTimer) + clearTimeout(uploadTimer) + await executeCommandsInParralel(commandName, data) + await writeRecordings() + await uploadRecordings() + startTime = undefined + resetRecordings() + break + case 'switchBlePeripheralMode': + break + case 'switchAntPeripheralMode': + break + case 'switchHrmMode': + break + case 'refreshPeripheralConfig': + break + case 'upload': + log.debug('RecordingManager: Manual upload requested') + if (config.userSettings.rowsAndAll.allowUpload && !config.userSettings.rowsAndAll.autoUpload) { await rowsAndAllInterface.uploadSessionResults(rowingDataRecorder) } + if (config.userSettings.intervals.allowUpload && !config.userSettings.intervals.autoUpload) { await intervalsInterface.uploadSessionResults(fitRecorder) } + if (config.userSettings.strava.allowUpload && !config.userSettings.strava.autoUpload) { await stravaInterface.uploadSessionResults(fitRecorder) } + break + case 'shutdown': + await executeCommandsInParralel(commandName, data) + await writeRecordings() + await uploadRecordings() + break + default: + log.error(`RecordingManager: Recieved unknown command: ${commandName}`) + } + } + + async function recordRotationImpulse (impulse) { + if (startTime === undefined && (recordRawData || recordTcxData || recordFitData || recordRowingData)) { + await nameFilesAndCreateDirectory() + } + if (recordRawData) { await rawRecorder.recordRotationImpulse(impulse) } + } + + async function recordMetrics (metrics) { + if (startTime === undefined && (recordRawData || recordTcxData || recordFitData || recordRowingData)) { + await nameFilesAndCreateDirectory() + } + logRecorder.recordRowingMetrics(metrics) + if (recordRawData) { rawRecorder.recordRowingMetrics(metrics) } + if (recordTcxData) { tcxRecorder.recordRowingMetrics(metrics) } + if (recordFitData) { fitRecorder.recordRowingMetrics(metrics) } + if (recordRowingData) { rowingDataRecorder.recordRowingMetrics(metrics) } + allRecordingsHaveBeenUploaded = false + + if (metrics.metricsContext.isPauseEnd) { + clearTimeout(writeTimer) + clearTimeout(uploadTimer) + } + + if (metrics.metricsContext.isSessionStop || metrics.metricsContext.isPauseStart) { + // Cancel any old timers before setting new ones as it makes them impossible to cancel later on + clearTimeout(writeTimer) + clearTimeout(uploadTimer) + writeRecordings() + const delayTime = 1000 * Math.max(metrics.pauseCountdownTime, 180) + writeTimer = setTimeout(writeRecordings, (delayTime + 10000)) + uploadTimer = setTimeout(uploadRecordings, (delayTime + 15000)) + } + } + + async function recordHeartRate (hrmData) { + logRecorder.recordHeartRate(hrmData) + if (recordTcxData) { tcxRecorder.recordHeartRate(hrmData) } + if (recordFitData) { fitRecorder.recordHeartRate(hrmData) } + if (recordRowingData) { rowingDataRecorder.recordHeartRate(hrmData) } + } + + async function executeCommandsInParralel (commandName, data) { + const parallelCalls = [] + parallelCalls.push(logRecorder.handleCommand(commandName, data)) + if (recordRawData) { parallelCalls.push(rawRecorder.handleCommand(commandName, data)) } + if (recordTcxData) { parallelCalls.push(tcxRecorder.handleCommand(commandName, data)) } + if (recordFitData) { parallelCalls.push(fitRecorder.handleCommand(commandName, data)) } + if (recordRowingData) { parallelCalls.push(rowingDataRecorder.handleCommand(commandName, data)) } + await Promise.all(parallelCalls) + } + + async function nameFilesAndCreateDirectory () { + // Determine the filename, directoryname and base filename to be used by all recorders + startTime = new Date() + const stringifiedStartTime = startTime.toISOString().replace(/T/, '_').replace(/:/g, '-').replace(/\..+/, '') + const directory = `${config.dataDirectory}/recordings/${startTime.getFullYear()}/${(startTime.getMonth() + 1).toString().padStart(2, '0')}` + const fileBaseName = `${directory}/${stringifiedStartTime}` + + // Create the directory if needed + try { + await fs.mkdir(directory, { recursive: true }) + } catch (error) { + if (error.code !== 'EEXIST') { + log.error(`can not create directory ${directory}`, error) + } + } + + // Set the base filename for all writers an uploaders + fileWriter.setBaseFileName(fileBaseName) + rowsAndAllInterface.setBaseFileName(fileBaseName) + stravaInterface.setBaseFileName(fileBaseName) + } + + async function writeRecordings () { + // The await is necessary to prevent a 'reset' to occur during the writing process caused by the same reset + if (config.createRawDataFiles) { await fileWriter.writeFile(rawRecorder, config.gzipRawDataFiles) } + if (config.createRowingDataFiles) { await fileWriter.writeFile(rowingDataRecorder, false) } + if (config.createFitFiles) { await fileWriter.writeFile(fitRecorder, config.gzipFitFiles) } + if (config.createTcxFiles) { await fileWriter.writeFile(tcxRecorder, config.gzipTcxFiles) } + } + + async function uploadRecordings () { + // The await is necessary to prevent the 'reset' to execute (and thus clear file content!) before the uploads has been completed + if (allRecordingsHaveBeenUploaded === true) { return } + if (config.userSettings.rowsAndAll.allowUpload && config.userSettings.rowsAndAll.autoUpload) { await rowsAndAllInterface.uploadSessionResults(rowingDataRecorder) } + if (config.userSettings.intervals.allowUpload && config.userSettings.intervals.autoUpload) { await intervalsInterface.uploadSessionResults(fitRecorder) } + if (config.userSettings.strava.allowUpload && config.userSettings.strava.autoUpload) { await stravaInterface.uploadSessionResults(fitRecorder) } + allRecordingsHaveBeenUploaded = true + } + + async function resetRecordings () { + // The await is necessary to prevent writes already occuring during a reset + if (recordRawData) { await rawRecorder.reset() } + if (recordTcxData) { await tcxRecorder.reset() } + if (recordFitData) { await fitRecorder.reset() } + if (recordRowingData) { await rowingDataRecorder.reset() } + } + + return { + handleCommand, + recordHeartRate, + recordRotationImpulse, + recordMetrics + } +} diff --git a/app/recorders/rowingDataRecorder.js b/app/recorders/rowingDataRecorder.js new file mode 100644 index 0000000000..1da019f764 --- /dev/null +++ b/app/recorders/rowingDataRecorder.js @@ -0,0 +1,263 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This Module captures the metrics of a rowing session and persists them into a RowingData format + * It provides a RowingData file content, and some metadata for the filewriter and the file-uploaders + */ +import log from 'loglevel' +import { createSeries } from '../engine/utils/Series.js' +import { createVO2max } from './utils/VO2max.js' + +export function createRowingDataRecorder (config) { + const type = 'csv' + const postfix = '_rowingData' + const presentationName = 'RowingData' + const VO2max = createVO2max(config) + const drag = createSeries() + let startTime + let splitNumber = 0 + let heartRate = 0 + let strokes = [] + let postExerciseHR = [] + let lastMetrics = {} + let rowingDataFileContent + let rowingDataFileContentIsCurrent = true + let allDataHasBeenWritten = true + + // This function handles all incomming commands. As all commands are broadasted to all application parts, + // we need to filter here what the WorkoutRecorder will react to and what it will ignore + /* eslint-disable-next-line no-unused-vars -- standardised recorder interface where the command payload is not relevant for this recorder */ + async function handleCommand (commandName, data) { + switch (commandName) { + case ('updateIntervalSettings'): + break + case ('reset'): + case ('shutdown'): + if (lastMetrics !== undefined && !!lastMetrics.metricsContext && lastMetrics.metricsContext.isMoving === true && (strokes.length > 0) && (lastMetrics.totalMovingTime > strokes[strokes.length - 1].totalMovingTime)) { + addMetricsToStrokesArray(lastMetrics) + } + break + default: + log.error(`RowingDataRecorder: Recieved unknown command: ${commandName}`) + } + } + + // initiated when a new heart rate value is received from heart rate sensor + async function recordHeartRate (value) { + heartRate = value.heartrate + } + + function recordRowingMetrics (metrics) { + switch (true) { + case (metrics.metricsContext.isSessionStart): + if (startTime === undefined) { + startTime = metrics.timestamp + } + addMetricsToStrokesArray(metrics) + break + case (metrics.metricsContext.isSessionStop && lastMetrics.sessionState !== 'Stopped'): + addMetricsToStrokesArray(metrics) + postExerciseHR = null + postExerciseHR = [] + measureRecoveryHR() + break + case (metrics.metricsContext.isIntervalEnd): + addMetricsToStrokesArray(metrics) + splitNumber++ + break + case (metrics.metricsContext.isPauseStart && lastMetrics.sessionState === 'Rowing'): + addMetricsToStrokesArray(metrics) + postExerciseHR = null + postExerciseHR = [] + measureRecoveryHR() + break + case (metrics.metricsContext.isPauseEnd): + splitNumber++ + addMetricsToStrokesArray(metrics) + break + case (metrics.metricsContext.isSplitEnd): + addMetricsToStrokesArray(metrics) + splitNumber++ + break + case (metrics.metricsContext.isDriveStart): + addMetricsToStrokesArray(metrics) + break + // no default + } + lastMetrics = metrics + } + + function addMetricsToStrokesArray (metrics) { + strokes.push({}) + const strokeNumber = strokes.length - 1 + strokes[strokeNumber].totalNumberOfStrokes = metrics.totalNumberOfStrokes + strokes[strokeNumber].rowingDataSplitNumber = splitNumber + strokes[strokeNumber].timestamp = metrics.timestamp + strokes[strokeNumber].totalMovingTime = metrics.totalMovingTime + if (heartRate !== undefined && heartRate > 0) { + strokes[strokeNumber].heartrate = heartRate + } else { + strokes[strokeNumber].heartrate = undefined + } + strokes[strokeNumber].totalLinearDistance = metrics.totalLinearDistance + strokes[strokeNumber].cycleStrokeRate = metrics.cycleStrokeRate + strokes[strokeNumber].cycleLinearVelocity = metrics.cycleLinearVelocity + strokes[strokeNumber].cyclePace = metrics.cyclePace + strokes[strokeNumber].cyclePower = metrics.cyclePower + strokes[strokeNumber].cycleDistance = metrics.cycleDistance + strokes[strokeNumber].driveDuration = metrics.driveDuration + strokes[strokeNumber].driveLength = metrics.driveLength + strokes[strokeNumber].recoveryDuration = metrics.recoveryDuration + strokes[strokeNumber].totalCalories = metrics.totalCalories + strokes[strokeNumber].dragFactor = metrics.dragFactor + strokes[strokeNumber].drivePeakHandleForce = metrics.drivePeakHandleForce + strokes[strokeNumber].driveAverageHandleForce = metrics.driveAverageHandleForce + strokes[strokeNumber].driveHandleForceCurve = metrics.driveHandleForceCurve + strokes[strokeNumber].driveHandleVelocityCurve = metrics.driveHandleVelocityCurve + strokes[strokeNumber].driveHandlePowerCurve = metrics.driveHandlePowerCurve + VO2max.push(metrics) + if (!isNaN(metrics.dragFactor) && metrics.dragFactor > 0) { drag.push(metrics.dragFactor) } + allDataHasBeenWritten = false + rowingDataFileContentIsCurrent = false + } + + async function fileContent () { + const RowingData = await workoutToRowingData(strokes) + if (RowingData === undefined) { + log.error('error creating RowingData file content') + return undefined + } else { + return RowingData + } + } + + /* eslint-disable complexity -- a lot of complexity is introduced due to defensive programming the output written to file */ + async function workoutToRowingData (strokedata) { + // The file content is filled and hasn't changed + let currentstroke + + if (rowingDataFileContentIsCurrent === true && rowingDataFileContent !== undefined) { return rowingDataFileContent } + + // Required file header, please note this includes a typo and odd spaces as the specification demands it! + let RowingData = ',index, Stroke Number, lapIdx,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 + let i = 0 + while (i < strokedata.length) { + currentstroke = strokedata[i] + // Add the strokes + RowingData += `${(i + 1).toFixed(0)},${(i + 1).toFixed(0)},${currentstroke.totalNumberOfStrokes.toFixed(0)},${currentstroke.rowingDataSplitNumber.toFixed(0)},${(currentstroke.timestamp / 1000).toFixed(3)},` + + `${currentstroke.totalMovingTime.toFixed(5)},${(currentstroke.heartrate !== undefined ? currentstroke.heartrate.toFixed(0) : NaN)},${currentstroke.totalLinearDistance.toFixed(1)},` + + `${currentstroke.cycleStrokeRate > 0 ? currentstroke.cycleStrokeRate.toFixed(1) : NaN},${(currentstroke.totalNumberOfStrokes > 0 && currentstroke.cyclePace > 0 ? currentstroke.cyclePace.toFixed(2) : NaN)},${(currentstroke.totalNumberOfStrokes > 0 && currentstroke.cyclePower > 0 ? currentstroke.cyclePower.toFixed(0) : NaN)},` + + `${currentstroke.cycleDistance > 0 ? currentstroke.cycleDistance.toFixed(2) : NaN},${currentstroke.driveDuration > 0 ? (currentstroke.driveDuration * 1000).toFixed(0) : NaN},${(currentstroke.totalNumberOfStrokes > 0 && currentstroke.driveLength ? currentstroke.driveLength.toFixed(2) : NaN)},${currentstroke.recoveryDuration > 0 ? (currentstroke.recoveryDuration * 1000).toFixed(0) : NaN},` + + `${(currentstroke.totalNumberOfStrokes > 0 && currentstroke.cycleLinearVelocity > 0 ? currentstroke.cycleLinearVelocity.toFixed(2) : NaN)},${currentstroke.totalLinearDistance.toFixed(1)},${currentstroke.totalCalories.toFixed(1)},${currentstroke.dragFactor > 0 ? currentstroke.dragFactor.toFixed(1) : NaN},` + + `${(currentstroke.totalNumberOfStrokes > 0 && currentstroke.drivePeakHandleForce > 0 ? currentstroke.drivePeakHandleForce.toFixed(1) : NaN)},${(currentstroke.totalNumberOfStrokes > 0 && currentstroke.driveAverageHandleForce > 0 ? currentstroke.driveAverageHandleForce.toFixed(1) : NaN)},"${currentstroke.driveAverageHandleForce > 0 ? currentstroke.driveHandleForceCurve.map((value) => value.toFixed(2)) : NaN}",` + + `"${currentstroke.driveAverageHandleForce > 0 ? currentstroke.driveHandleVelocityCurve.map((value) => value.toFixed(3)) : NaN}","${currentstroke.driveAverageHandleForce > 0 ? currentstroke.driveHandlePowerCurve.map((value) => value.toFixed(1)) : NaN}"\n` + i++ + } + rowingDataFileContent = RowingData + rowingDataFileContentIsCurrent = true + return rowingDataFileContent + } + /* eslint-enable complexity */ + + 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 (!isNaN(heartRate) && config.userSettings.restingHR <= heartRate && heartRate <= config.userSettings.maxHR) { + log.debug(`*** RowingData HRR-${postExerciseHR.length}: ${heartRate}`) + postExerciseHR.push(heartRate) + if (postExerciseHR.length < 4) { + // We haven't got three post-exercise HR measurements yet, let's schedule the next measurement + setTimeout(measureRecoveryHR, 60000) + } else { + log.debug('*** Skipped HRR measurement') + } + } + } + + function minimumDataAvailable () { + const minimumRecordingTimeInSeconds = 10 + if (strokes.length > 2) { + const strokeTimeTotal = strokes[strokes.length - 1].totalMovingTime + return (strokeTimeTotal > minimumRecordingTimeInSeconds) + } else { + return (false) + } + } + + function totalRecordedDistance () { + if (minimumDataAvailable() && strokes[strokes.length - 1].totalLinearDistance > 0) { + return strokes[strokes.length - 1].totalLinearDistance + } else { + return 0 + } + } + + function totalRecordedMovingTime () { + if (minimumDataAvailable() && strokes[strokes.length - 1].totalMovingTime > 0) { + return strokes[strokes.length - 1].totalMovingTime + } else { + return 0 + } + } + + function sessionDrag () { + return drag.average() + } + + function sessionVO2Max () { + if (VO2max.result() > 10 && VO2max.result() < 60) { + return VO2max.result() + } else { + return undefined + } + } + + function sessionHRR () { + 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 + return postExerciseHR + } else { + return [] + } + } + + function reset () { + startTime = undefined + heartRate = 0 + strokes = null + strokes = [] + rowingDataFileContent = null + rowingDataFileContent = {} + postExerciseHR = null + postExerciseHR = [] + VO2max.reset() + drag.reset() + lastMetrics = null + lastMetrics = {} + allDataHasBeenWritten = true + } + + return { + handleCommand, + recordRowingMetrics, + recordHeartRate, + minimumDataAvailable, + fileContent, + type, + postfix, + presentationName, + totalRecordedDistance, + totalRecordedMovingTime, + sessionDrag, + sessionVO2Max, + sessionHRR, + allDataHasBeenWritten, + reset + } +} diff --git a/app/recorders/rowsAndAllInterface.js b/app/recorders/rowsAndAllInterface.js new file mode 100644 index 0000000000..8396384c98 --- /dev/null +++ b/app/recorders/rowsAndAllInterface.js @@ -0,0 +1,63 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + This Module is the interface to the RowsAndAll.com webservice +*/ +import log from 'loglevel' +import { createName, createDragLine, createVO2MaxLine, createHRRLine } from './utils/decorators.js' +import fetch, { FormData } from 'node-fetch' + +export function createRowsAndAllInterface (config) { + let basefilename = '' + + async function setBaseFileName (name) { + basefilename = name + } + + async function uploadSessionResults (recorder) { + // we need enough data + if (!recorder.minimumDataAvailable()) { + log.info(`${recorder.presentationName} file has not been uploaded to RowsAndAll.com, as there was not enough data recorded`) + return + } + + const form = new FormData() + + const sessionName = createName(recorder.totalRecordedDistance(), recorder.totalRecordedMovingTime()) + form.append('title', sessionName) + + const fileContent = await recorder.fileContent() + const file = new File([fileContent], `${basefilename}${recorder.postfix}.${recorder.type}`, { type: 'text/plain' }) + form.append('file', file) + + form.append('boattype', 'static') + form.append('workouttype', 'rower') + + const dragLine = createDragLine(recorder.sessionDrag()) + const VO2MaxLine = createVO2MaxLine(recorder.sessionVO2Max()) + log.info(`RowsAndAll HRR Data: ${recorder.sessionHRR()}`) + const HRRLine = createHRRLine(recorder.sessionHRR()) + const sessionNote = `${dragLine}${VO2MaxLine}${HRRLine}` + form.append('notes', sessionNote) + + try { + await fetch('https://rowsandall.com/rowers/api/rowingdata/', { + method: 'POST', + headers: { + 'User-Agent': 'curl/7.87.0', + Authorization: `${config.userSettings.rowsAndAll.apiKey}` + }, + body: form + }) + log.info('RowsAndAll interface: uploaded session data') + } catch (error) { + log.error(`RowsAndAll interface error: ${error}`) + } + } + + return { + setBaseFileName, + uploadSessionResults + } +} diff --git a/app/recorders/stravaInterface.js b/app/recorders/stravaInterface.js new file mode 100644 index 0000000000..c1cbcebc26 --- /dev/null +++ b/app/recorders/stravaInterface.js @@ -0,0 +1,98 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This Module is the interface to the Strava.com webservice + * See https://developers.strava.com/ + * and https://gist.github.com/michaellihs/bb262e2c6ee93093485361de282c242d + */ +/* eslint-disable camelcase -- As Strava's url parameters use underscores, not much we can do about it */ +import log from 'loglevel' +import { createName, createDragLine, createVO2MaxLine, createHRRLine } from './utils/decorators.js' +import fetch, { FormData } from 'node-fetch' +import { replaceInFile } from 'replace-in-file' + +export function createStravaInterface (config) { + let basefilename = '' + + async function setBaseFileName (name) { + basefilename = name + } + + /* eslint-disable max-statements -- Setting up and processing strava communication requires a lot of steps */ + async function uploadSessionResults (recorder) { + // we need enough data + if (!recorder.minimumDataAvailable()) { + log.info(`${recorder.presentationName} file has not been uploaded to Strava.com, as there was not enough data recorded`) + return + } + + // ToDo: check if the uploaded file has changed since last upload based on total recorded movingtime + + let response = await fetch('https://www.strava.com/api/v3/oauth/token', { + method: 'POST', + body: new URLSearchParams({ + client_id: config.userSettings.strava.clientId, + client_secret: config.userSettings.strava.clientSecret, + grant_type: 'refresh_token', + refresh_token: config.userSettings.strava.refreshToken + }) + }) + + let responseJson = await response.json() + const newRefreshToken = responseJson.refresh_token + const accessToken = responseJson.access_token + if (newRefreshToken !== config.userSettings.strava.refreshToken) { + try { + replaceInFile({ + files: '/opt/openrowingmonitor/config/config.js', + from: config.userSettings.strava.refreshToken, + to: newRefreshToken + }) + log.debug('Strava interface: replaced refresh token in config file') + } catch (error) { + log.error('Strava Interface: error replacing refresh token in config file:', error) + } + } + + const form = new FormData() + const sessionName = createName(recorder.totalRecordedDistance(), recorder.totalRecordedMovingTime()) + form.append('name', sessionName) + + const fileContent = await recorder.fileContent() + const file = new File([fileContent], `${basefilename}${recorder.postfix}.${recorder.type}`, { type: 'text/plain' }) + form.append('file', file) + form.append('data_type', recorder.type) + + const dragLine = createDragLine(recorder.sessionDrag()) + const VO2MaxLine = createVO2MaxLine(recorder.sessionVO2Max()) + const HRRLine = createHRRLine(recorder.sessionHRR()) + const sessionNote = `${dragLine}${VO2MaxLine}${HRRLine}` + form.append('description', sessionNote) + + form.append('trainer', true) + form.append('commute', false) + + try { + response = await fetch('https://www.strava.com/api/v3/uploads', { + method: 'POST', + headers: { + Authorization: `Bearer ${accessToken}` + }, + body: form + }) + log.info('Strava.com interface: uploaded session data') + responseJson = await response.json() + log.debug('upload response: %j', responseJson) + } catch (error) { + log.error(`Strava.com interface error: ${error}`) + } + } + /* eslint-enable max-statements */ + + return { + setBaseFileName, + uploadSessionResults + } +} diff --git a/app/recorders/tcxRecorder.js b/app/recorders/tcxRecorder.js new file mode 100644 index 0000000000..6810657d04 --- /dev/null +++ b/app/recorders/tcxRecorder.js @@ -0,0 +1,436 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ +/** + * This Module captures the metrics of a rowing session and persists them into the tcx format + * It provides a tcx-file content, and some metadata for the filewriter and the file-uploaders + */ +/* eslint-disable max-lines -- The length is governed by the creation of all the tcx-parameters, which we can't control */ +import log from 'loglevel' +import { createDragLine, createVO2MaxLine, createHRRLine } from './utils/decorators.js' +import { createSeries } from '../engine/utils/Series.js' +import { createVO2max } from './utils/VO2max.js' + +export function createTCXRecorder (config) { + const type = 'tcx' + const postfix = '_rowing' + const presentationName = 'Garmin tcx' + const lapHRMetrics = createSeries() + const VO2max = createVO2max(config) + let heartRate = 0 + let sessionData + let lapnumber = 0 + let postExerciseHR = [] + let lastMetrics = {} + let tcxfileContent + let tcxfileContentIsCurrent = true + let allDataHasBeenWritten = true + + // This function handles all incomming commands. Here, the recordingmanager will have filtered + // all unneccessary commands for us, so we only need to react to 'reset' and 'shutdown' + // eslint-disable-next-line no-unused-vars + async function handleCommand (commandName, data) { + switch (commandName) { + case ('updateIntervalSettings'): + break + case ('reset'): + case ('shutdown'): + if (lastMetrics !== undefined && !!lastMetrics.metricsContext && lastMetrics.metricsContext.isMoving === true && (sessionData.lap[lapnumber].strokes.length > 0) && (lastMetrics.totalMovingTime > sessionData.lap[lapnumber].strokes[sessionData.lap[lapnumber].strokes.length - 1].totalMovingTime)) { + // We apperantly get a reset/shutdown/crash during a session + addMetricsToStrokesArray(lastMetrics) + calculateLapMetrics(lastMetrics) + } + break + default: + log.error(`tcxRecorder: Recieved unknown command: ${commandName}`) + } + } + + function recordRowingMetrics (metrics) { + switch (true) { + case (metrics.metricsContext.isSessionStart): + sessionData = { startTime: metrics.timestamp } + sessionData.lap = [] + lapnumber = 0 + startLap(lapnumber, metrics) + addMetricsToStrokesArray(metrics) + break + case (metrics.metricsContext.isSessionStop && lastMetrics.sessionState !== 'Stopped'): + addMetricsToStrokesArray(metrics) + calculateLapMetrics(metrics) + postExerciseHR = null + postExerciseHR = [] + measureRecoveryHR() + break + case (metrics.metricsContext.isPauseStart && lastMetrics.sessionState === 'Rowing'): + addMetricsToStrokesArray(metrics) + calculateLapMetrics(metrics) + resetLapMetrics() + postExerciseHR = null + postExerciseHR = [] + measureRecoveryHR() + break + case (metrics.metricsContext.isPauseEnd): + // First add the rest lap hich we seem to have completed + lapnumber++ + addRestLap(lapnumber, metrics, sessionData.lap[lapnumber - 1].endTime) + lapnumber++ + startLap(lapnumber, metrics) + addMetricsToStrokesArray(metrics) + break + case (metrics.metricsContext.isIntervalEnd): + case (metrics.metricsContext.isSplitEnd): + // Please note: we deliberatly add the metrics twice as it marks both the end of the old split and the start of a new one + addMetricsToStrokesArray(metrics) + calculateLapMetrics(metrics) + resetLapMetrics() + lapnumber++ + startLap(lapnumber, metrics) + addMetricsToStrokesArray(metrics) + break + case (metrics.metricsContext.isDriveStart): + addMetricsToStrokesArray(metrics) + break + // no default + } + lastMetrics = metrics + } + + function addMetricsToStrokesArray (metrics) { + sessionData.lap[lapnumber].strokes.push({}) + const strokenumber = sessionData.lap[lapnumber].strokes.length - 1 + sessionData.lap[lapnumber].strokes[strokenumber].timestamp = metrics.timestamp + sessionData.lap[lapnumber].strokes[strokenumber].totalLinearDistance = metrics.totalLinearDistance + sessionData.lap[lapnumber].strokes[strokenumber].cycleStrokeRate = metrics.cycleStrokeRate + sessionData.lap[lapnumber].strokes[strokenumber].cyclePower = metrics.cyclePower + sessionData.lap[lapnumber].strokes[strokenumber].cycleLinearVelocity = metrics.cycleLinearVelocity + sessionData.lap[lapnumber].strokes[strokenumber].isPauseStart = metrics.metricsContext.isPauseStart + if (!isNaN(heartRate) && heartRate > 0) { + sessionData.lap[lapnumber].strokes[strokenumber].heartrate = heartRate + } else { + sessionData.lap[lapnumber].strokes[strokenumber].heartrate = undefined + } + VO2max.push(metrics) + tcxfileContentIsCurrent = false + allDataHasBeenWritten = false + } + + function startLap (lapnumber, metrics) { + resetLapMetrics() + sessionData.lap[lapnumber] = { startTime: metrics.timestamp } + sessionData.lap[lapnumber].intensity = 'Active' + sessionData.lap[lapnumber].strokes = [] + sessionData.lap[lapnumber].complete = false + } + + function calculateLapMetrics (metrics) { + sessionData.lap[lapnumber].endTime = metrics.timestamp + sessionData.lap[lapnumber].summary = { ...metrics.split } + sessionData.lap[lapnumber].averageHeartrate = lapHRMetrics.average + sessionData.lap[lapnumber].maximumHeartrate = lapHRMetrics.maximum + sessionData.lap[lapnumber].complete = true + } + + function resetLapMetrics () { + lapHRMetrics.reset() + if (!isNaN(heartRate) && heartRate > 0) { lapHRMetrics.push(heartRate) } + } + + function addRestLap (lapnumber, metrics, startTime) { + sessionData.lap[lapnumber] = { endTime: metrics.timestamp } + sessionData.lap[lapnumber].intensity = 'Resting' + sessionData.lap[lapnumber].startTime = startTime + sessionData.lap[lapnumber].averageHeartrate = lapHRMetrics.average + sessionData.lap[lapnumber].maximumHeartrate = lapHRMetrics.maximum + sessionData.lap[lapnumber].summary = { ...metrics.split } + sessionData.lap[lapnumber].complete = true + VO2max.handleRestart(metrics.totalMovingTime) + } + + // initiated when a new heart rate value is received from heart rate sensor + async function recordHeartRate (value) { + heartRate = value.heartrate + if (!isNaN(heartRate) && heartRate > 0) { lapHRMetrics.push(heartRate) } + } + + async function fileContent () { + if (Object.keys(lastMetrics).length === 0 || Object.keys(sessionData).length === 0) { return undefined } + + if (sessionData.lap[lapnumber].complete !== true) { + addMetricsToStrokesArray(lastMetrics) + calculateLapMetrics(lastMetrics) + } + + const tcx = await workoutToTcx(sessionData) + if (tcx === undefined) { + log.error('error creating tcx file content') + return undefined + } else { + return tcx + } + } + + async function workoutToTcx (workout) { + // The file content is filled and hasn't changed + if (tcxfileContentIsCurrent === true && tcxfileContent !== undefined) { return tcxfileContent } + + let tcxData = '' + tcxData += '\n' + tcxData += '\n' + tcxData += await createActivity(workout) + tcxData += '\n' + tcxfileContent = tcxData + tcxfileContentIsCurrent = true + return tcxfileContent + } + + async function createActivity (workout) { + let tcxData = '' + tcxData += ' \n' + tcxData += ' \n' + tcxData += ` ${workout.startTime.toISOString()}\n` + let i = 0 + while (i < workout.lap.length) { + if (workout.lap[i].intensity !== 'Resting') { + // eslint-disable-next-line no-await-in-loop -- This is inevitable if you want to have some decent order in the file + tcxData += await createActiveLap(workout.lap[i]) + } else { + // eslint-disable-next-line no-await-in-loop -- This is inevitable if you want to have some decent order in the file + tcxData += await createRestLap(workout.lap[i]) + } + i++ + } + tcxData += await createNotes() + tcxData += await createAuthor() + tcxData += ' \n' + tcxData += ' \n' + return tcxData + } + + async function createActiveLap (lapdata) { + let tcxData = '' + // Make sure the lap is complete + if (!!lapdata.summary.timeSpent.moving && lapdata.summary.timeSpent.moving > 0 && !!lapdata.summary.distance.fromStart && lapdata.summary.distance.fromStart > 0) { + tcxData += ` \n` + tcxData += ` ${lapdata.summary.timeSpent.moving.toFixed(1)}\n` + tcxData += ` ${lapdata.summary.distance.fromStart.toFixed(1)}\n` + tcxData += ` ${lapdata.summary.linearVelocity.maximum.toFixed(2)}\n` + tcxData += ` ${Math.round(lapdata.summary.calories.totalSpent)}\n` + if (!!lapdata.averageHeartrate && !isNaN(lapdata.averageHeartrate) && lapdata.averageHeartrate > 0 && !isNaN(lapdata.maximumHeartrate) && lapdata.maximumHeartrate > 0) { + tcxData += ` ${Math.round(lapdata.averageHeartrate.toFixed(0))}\n` + tcxData += ` ${Math.round(lapdata.maximumHeartrate.toFixed(0))}\n` + } + tcxData += ` ${lapdata.intensity}\n` + tcxData += ` ${lapdata.summary.strokerate.average.toFixed(0)}\n` + tcxData += ' Manual\n' + tcxData += ' \n' + // Add the strokes + let i = 0 + while (i < lapdata.strokes.length) { + // eslint-disable-next-line no-await-in-loop -- This is inevitable if you want to have some decent order in the file + tcxData += await createTrackPoint(lapdata.strokes[i]) + i++ + } + tcxData += ' \n' + tcxData += ' \n' + tcxData += ' \n' + tcxData += ` ${lapdata.summary.numberOfStrokes.toFixed(0)}\n` + tcxData += ` ${lapdata.summary.linearVelocity.average.toFixed(2)}\n` + tcxData += ` ${lapdata.summary.power.average.toFixed(0)}\n` + tcxData += ` ${lapdata.summary.power.maximum.toFixed(0)}\n` + tcxData += ' \n' + tcxData += ' \n' + tcxData += ' \n' + } + return tcxData + } + + async function createRestLap (lapdata) { + let tcxData = '' + // Make sure the lap is complete + if (!!lapdata.endTime && lapdata.endTime > 0) { + tcxData += ` \n` + tcxData += ` ${lapdata.summary.timeSpent.total.toFixed(1)}\n` + tcxData += ' 0\n' + tcxData += ' 0\n' + tcxData += ' 0\n' + if (!!lapdata.averageHeartrate && !isNaN(lapdata.averageHeartrate) && lapdata.averageHeartrate > 0 && !isNaN(lapdata.maximumHeartrate) && lapdata.maximumHeartrate > 0) { + tcxData += ` ${Math.round(lapdata.averageHeartrate.toFixed(0))}\n` + tcxData += ` ${Math.round(lapdata.maximumHeartrate.toFixed(0))}\n` + } + tcxData += ` ${lapdata.intensity}\n` + tcxData += ' Manual\n' + tcxData += ' \n' + } + return tcxData + } + + async function createTrackPoint (trackpoint) { + let tcxData = '' + tcxData += ' \n' + tcxData += ` \n` + tcxData += ` ${trackpoint.totalLinearDistance.toFixed(2)}\n` + tcxData += ` ${(trackpoint.cycleStrokeRate > 0 ? Math.round(trackpoint.cycleStrokeRate) : 0)}\n` + if (trackpoint.cycleLinearVelocity > 0 || trackpoint.cyclePower > 0 || trackpoint.isPauseStart) { + tcxData += ' \n' + tcxData += ' \n' + if (trackpoint.cycleLinearVelocity > 0 || trackpoint.isPauseStart) { + tcxData += ` ${(trackpoint.cycleLinearVelocity > 0 ? trackpoint.cycleLinearVelocity.toFixed(2) : 0)}\n` + } + if (trackpoint.cyclePower > 0 || trackpoint.isPauseStart) { + tcxData += ` ${(trackpoint.cyclePower > 0 ? Math.round(trackpoint.cyclePower) : 0)}\n` + } + tcxData += ' \n' + tcxData += ' \n' + } + if (!isNaN(trackpoint.heartrate) && trackpoint.heartrate > 0) { + tcxData += ' \n' + tcxData += ` ${trackpoint.heartrate}\n` + tcxData += ' \n' + } + tcxData += ' \n' + return tcxData + } + + async function createNotes () { + const dragLine = createDragLine(lastMetrics.workout.dragfactor.average) + const VO2MaxLine = createVO2MaxLine(VO2max.result()) + const HRRLine = createHRRLine(postExerciseHR) + const tcxData = ` Indoor Rowing, ${dragLine}${VO2MaxLine}${HRRLine}\n` + return tcxData + } + + async function createAuthor () { + let versionArray = process.env.npm_package_version.split('.') + if (versionArray.length < 3) { versionArray = ['0', '0', '0'] } + let tcxData = '' + tcxData += ' \n' + tcxData += ' Open Rowing Monitor\n' + tcxData += ' \n' + tcxData += ' \n' + tcxData += ` ${versionArray[0]}\n` + tcxData += ` ${versionArray[1]}\n` + tcxData += ` ${versionArray[2]}\n` + tcxData += ' 0\n' + tcxData += ' \n' + tcxData += ' en\n' + tcxData += ' OPE-NROWI-NG\n' + tcxData += ' \n' + tcxData += ' \n' + return tcxData + } + + 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 (!isNaN(heartRate) && config.userSettings.restingHR <= heartRate && heartRate <= config.userSettings.maxHR) { + log.debug(`*** tcx-recorder 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] + tcxfileContentIsCurrent = false + allDataHasBeenWritten = false + } + if (postExerciseHR.length < 4) { + // We haven't got three post-exercise HR measurements yet, let's schedule the next measurement + setTimeout(measureRecoveryHR, 60000) + } else { + log.debug('*** Skipped HRR measurement') + } + } + } + + function minimumDataAvailable () { + return (minimumRecordingTimeHasPassed() && minimumNumberOfStrokesHaveCompleted()) + } + + function minimumRecordingTimeHasPassed () { + const minimumRecordingTimeInSeconds = 10 + if (lastMetrics !== undefined && lastMetrics.totalMovingTime !== undefined) { + const strokeTimeTotal = lastMetrics.totalMovingTime + return (strokeTimeTotal > minimumRecordingTimeInSeconds) + } else { + return false + } + } + + function minimumNumberOfStrokesHaveCompleted () { + const minimumNumberOfStrokes = 2 + if (lastMetrics !== undefined && lastMetrics.totalNumberOfStrokes !== undefined) { + const noStrokes = lastMetrics.totalNumberOfStrokes + return (noStrokes > minimumNumberOfStrokes) + } else { + return false + } + } + + function totalRecordedDistance () { + if (minimumRecordingTimeHasPassed() && lastMetrics.totalLinearDistance > 0) { + return lastMetrics.totalLinearDistance + } else { + return 0 + } + } + + function totalRecordedMovingTime () { + if (minimumRecordingTimeHasPassed() && lastMetrics.totalMovingTime > 0) { + return lastMetrics.totalMovingTime + } else { + return 0 + } + } + + function sessionDrag () { + return lastMetrics.workout.dragfactor.average + } + + function sessionVO2Max () { + if (VO2max.result() > 10 && VO2max.result() < 60) { + return VO2max.result() + } else { + return undefined + } + } + + function sessionHRR () { + 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 + return postExerciseHR + } else { + return [] + } + } + + function reset () { + heartRate = 0 + sessionData = null + sessionData = {} + sessionData.lap = [] + lapnumber = 0 + lastMetrics = {} + postExerciseHR = null + postExerciseHR = [] + lapHRMetrics.reset() + VO2max.reset() + allDataHasBeenWritten = true + } + + return { + handleCommand, + recordRowingMetrics, + recordHeartRate, + minimumDataAvailable, + fileContent, + type, + postfix, + presentationName, + totalRecordedDistance, + totalRecordedMovingTime, + sessionDrag, + sessionVO2Max, + sessionHRR, + allDataHasBeenWritten, + reset + } +} diff --git a/app/engine/utils/BucketedLinearSeries.js b/app/recorders/utils/BucketedLinearSeries.js similarity index 86% rename from app/engine/utils/BucketedLinearSeries.js rename to app/recorders/utils/BucketedLinearSeries.js index d9352c1ad1..fd72a62ea4 100644 --- a/app/engine/utils/BucketedLinearSeries.js +++ b/app/recorders/utils/BucketedLinearSeries.js @@ -1,17 +1,19 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor This Module calculates a bucketed Linear Regression. It assumes a rising line. */ -import { createOLSLinearSeries } from './OLSLinearSeries.js' +import { createTSLinearSeries } from '../../engine/utils/FullTSLinearSeries.js' -function createBucketedLinearSeries (config) { - const linearSeries = createOLSLinearSeries() - const xCutOffInterval = 5.0 - const yCutOffInterval = 7.0 - const minimumValuesInBracket = 6.0 +/** + * @param {number} xCutOffInterval + * @param {number} yCutOffInterval + * @param {number} minimumValuesInBracket + */ +export function createBucketedLinearSeries (xCutOffInterval, yCutOffInterval, minimumValuesInBracket) { + const linearSeries = createTSLinearSeries() let xBracketStart = 0.0 let xBracketEnd = 0.0 @@ -27,6 +29,10 @@ function createBucketedLinearSeries (config) { let maxX = 0.0 let maxY = 0.0 + /** + * @param {number} x + * @param {number} y + */ function push (x, y) { maxX = Math.max(maxX, x) maxY = Math.max(maxY, y) @@ -95,10 +101,16 @@ function createBucketedLinearSeries (config) { return linearSeries.goodnessOfFit() } + /** + * @param {number} x + */ function projectX (x) { return linearSeries.projectX(x) } + /** + * @param {number} y + */ function projectY (y) { return linearSeries.projectY(y) } @@ -159,5 +171,3 @@ function createBucketedLinearSeries (config) { reset } } - -export { createBucketedLinearSeries } diff --git a/app/recorders/utils/VO2max.js b/app/recorders/utils/VO2max.js new file mode 100644 index 0000000000..d59834a095 --- /dev/null +++ b/app/recorders/utils/VO2max.js @@ -0,0 +1,222 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/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 './BucketedLinearSeries.js' +import loglevel from 'loglevel' +const log = loglevel.getLogger('RowingEngine') + +/** + * @param {Config} config + */ +export function createVO2max (config) { + const bucketedLinearSeries = createBucketedLinearSeries(5.0, 7.0, 6.0) + const minimumValidBrackets = 5.0 + const warmupPeriod = 600 // Period to ignore HR changes to allow the HR to settle + let offset = warmupPeriod + /** + * @type {Vo2MaxMetrics} + */ + let metricsArray = [] + let VO2MaxResult = 0 + let VO2MaxResultIsCurrent = true + + /** + * @param {Metrics} metrics + */ + function push (metrics) { + VO2MaxResultIsCurrent = false + if (metrics.totalMovingTime > offset && !!metrics.heartrate && !isNaN(metrics.heartrate) && metrics.heartrate >= config.userSettings.restingHR && metrics.heartrate < config.userSettings.maxHR && !isNaN(metrics.cyclePower) && metrics.cyclePower > 0 && metrics.cyclePower <= config.userSettings.maxPower) { + // We are outside the startup noise and have numeric fields + metricsArray.push({ + totalMovingTime: metrics.totalMovingTime, + totalLinearDistance: metrics.totalLinearDistance, + cyclePower: metrics.cyclePower, + heartrate: metrics.heartrate + }) + } + } + + /** + * @param {number} totalMovingTime + */ + function handleRestart (totalMovingTime) { + offset = totalMovingTime + warmupPeriod + } + + function result () { + let projectedVO2max = 0 + let interpolatedVO2max = 0 + const lastStroke = metricsArray[metricsArray.length - 1] + + if (VO2MaxResultIsCurrent === true) { return VO2MaxResult } + + if (metricsArray.length > 0 && lastStroke.heartrate >= config.userSettings.restingHR) { + projectedVO2max = extrapolatedVO2max(metricsArray) + } else { + if (metricsArray.length > 0) { + log.debug(`--- Extrapolated VO2Max calculation skipped: last stroke heartrate (${lastStroke.heartrate} BPM) < restingHR (${config.userSettings.restingHR} BPM)`) + } else { + log.debug('--- Extrapolated VO2Max calculation skipped as heartrate data was missing') + } + } + + if (metricsArray.length > 0 && lastStroke.heartrate >= (0.8 * config.userSettings.maxHR)) { + // Concept2's formula is only valid when doing a pretty intense session + interpolatedVO2max = calculateInterpolatedVO2max(metricsArray) + } else { + if (metricsArray.length > 0) { + log.debug(`--- Interpolated VO2Max calculation skipped: last stroke heartrate (${lastStroke.heartrate} BPM) < Zone 4 HR (${0.8 * config.userSettings.maxHR} BPM)`) + } else { + log.debug('--- Intrapolated VO2Max calculation skipped as heartrate data was missing') + } + } + + // Let's combine the results + switch (true) { + case (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)}`) + VO2MaxResult = (projectedVO2max + interpolatedVO2max) / 2 + break + case (interpolatedVO2max >= 10 && interpolatedVO2max <= 60): + // As the previous case wasn't true, we do not have two valid results. As interpolation has delivered a credible result, extrapolation hasn't + log.debug(`--- VO2Max calculation delivered one credible result, the Interpolated VO2Max: ${interpolatedVO2max.toFixed(1)}. The Extrapolated VO2Max: ${projectedVO2max.toFixed(1)} was unreliable`) + VO2MaxResult = interpolatedVO2max + break + case (projectedVO2max >= 10 && projectedVO2max <= 60): + // As the previous two cases are not true, Interpolation hasn't delivered a credible result, but Extrapolation delivered a credible result + log.debug(`--- VO2Max calculation delivered one credible result, the Extrapolated VO2Max: ${projectedVO2max.toFixed(1)}. Interpolated VO2Max: ${interpolatedVO2max.toFixed(1)} was unreliable`) + VO2MaxResult = projectedVO2max + break + default: + // 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)}`) + VO2MaxResult = 0 + } + VO2MaxResultIsCurrent = true + return VO2MaxResult + } + + /** + * @param {Vo2MaxMetrics} metrics + */ + 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 + + bucketedLinearSeries.reset() + let i = 0 + while (i < metrics.length) { + bucketedLinearSeries.push(metrics[i].heartrate, metrics[i].cyclePower) + i++ + } + + 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 + } + + /** + * @param {Vo2MaxMetrics} metrics + */ + 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 lastStroke = metrics[metrics.length - 1] + const distance = lastStroke.totalLinearDistance + const time = lastStroke.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 + 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) + 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 + default: + log.error('--- Intrapolated VO2Max calculation failed due to unknown gender being configured') + } + return (Y * 1000) / config.userSettings.weight + } + + /** + * @param {number} origintime + * @param {number} origindistance + * @param {number} targetdistance + */ + 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 () { + // @ts-ignore + metricsArray = null + metricsArray = [] + bucketedLinearSeries.reset() + } + + return { + push, + handleRestart, + result, + averageObservedHR, + maxObservedHR, + reset + } +} diff --git a/app/recorders/utils/decorators.js b/app/recorders/utils/decorators.js new file mode 100644 index 0000000000..31c88ec150 --- /dev/null +++ b/app/recorders/utils/decorators.js @@ -0,0 +1,81 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Decorators for translating raw metrics to human readable notes in file names and notes +*/ + +/** + * @param {number} distance + * @param {number} time + */ +export function createName (distance, time) { + let shortDuration + switch (true) { + case (distance === 42195): + shortDuration = 'Full Marathon' + break + case (distance === 21097): + shortDuration = 'Half Marathon' + break + case (distance % 1000 === 0): + shortDuration = `${Math.floor(distance / 1000)}K` + break + case (distance % 1000 === 500): + shortDuration = `${Math.floor(distance / 1000)}.5K` + break + case (time % 3600 === 0): + shortDuration = `${Math.floor(time / 3600)} hour` + break + case (time % 3600 === 1800): + shortDuration = `${Math.floor(time / 3600)}.5 hours` + break + case (distance % 60 === 0): + shortDuration = `${Math.floor(time / 60)} minutes` + break + default: + shortDuration = `${Math.floor(distance)} meters` + } + return shortDuration +} + +/** + * @param {number} drag + */ +export function createDragLine (drag) { + return `Drag factor: ${drag.toFixed(1)} 10-6 N*m*s2` +} + +/** + * @param {number} VO2MaxResult + */ +export function createVO2MaxLine (VO2MaxResult) { + let VO2MaxLine + if (VO2MaxResult !== undefined) { + VO2MaxLine = `, estimated VO2Max: ${VO2MaxResult.toFixed(1)} mL/(kg*min)` + } else { + VO2MaxLine = ', no credible VO2Max estimate' + } + return VO2MaxLine +} + +/** + * @param {Array} HRRArray + */ +export function createHRRLine (HRRArray) { + let HRRLine + switch (HRRArray.length) { + case (2): + HRRLine = `, HRR1: ${HRRArray[1] - HRRArray[0]} (${HRRArray[1]} BPM)` + break + case (3): + HRRLine = `, HRR1: ${HRRArray[1] - HRRArray[0]} (${HRRArray[1]} BPM), HRR2: ${HRRArray[2] - HRRArray[0]} (${HRRArray[2]} BPM)` + break + case (4): + HRRLine = `, HRR1: ${HRRArray[1] - HRRArray[0]} (${HRRArray[1]} BPM), HRR2: ${HRRArray[2] - HRRArray[0]} (${HRRArray[2]} BPM), HRR3: ${HRRArray[3] - HRRArray[0]} (${HRRArray[3]} BPM)` + break + default: + HRRLine = '' + } + return HRRLine +} diff --git a/app/recorders/utils/recorders.interfaces.js b/app/recorders/utils/recorders.interfaces.js new file mode 100644 index 0000000000..448f0422d9 --- /dev/null +++ b/app/recorders/utils/recorders.interfaces.js @@ -0,0 +1,6 @@ +/** + * @typedef {Array<{totalMovingTime: number, totalLinearDistance: number, cyclePower: number, heartrate: number}>} Vo2MaxMetrics + */ +/** + * @typedef {ReturnType} SegmentMetrics + */ diff --git a/app/server.js b/app/server.js index 49f87a712a..ac32f0c3f7 100644 --- a/app/server.js +++ b/app/server.js @@ -1,26 +1,24 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - This start file is currently a mess, as this currently is the devlopment playground to plug - everything together while figuring out the physics and model of the application. - todo: refactor this as we progress + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ +/* eslint-disable camelcase -- Some imports simply don't use camelCase */ 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 { createRowingStatistics } from './engine/RowingStatistics.js' +import { createSessionManager } from './engine/SessionManager.js' import { createWebServer } from './WebServer.js' -import { createPeripheralManager } from './ble/PeripheralManager.js' -import { createAntManager } from './ant/AntManager.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 { createPeripheralManager } from './peripherals/PeripheralManager.js' +import { createRecordingManager } from './recorders/recordingManager.js' +/* eslint-disable-next-line no-unused-vars -- replayRowingSession shouldn't be used in a production environments */ +import { replayRowingSession } from './recorders/RowingReplayer.js' + const exec = promisify(child_process.exec) +const shutdownEnabled = !!config.shutdownCommand + // set the log levels log.setLevel(config.loglevel.default) for (const [loggerName, logLevel] of Object.entries(config.loglevel)) { @@ -39,223 +37,121 @@ if (config.appPriority) { // setting priority of current process os.setPriority(mainPriority) } catch (err) { - log.debug('need root permission to set priority of main server thread') + log.error('Could not set priority of main server thread (perhaps root permission is missing?):', err) } } -// 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() +const peripheralManager = createPeripheralManager(config) peripheralManager.on('control', (event) => { - 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) - } + log.debug(`Server: peripheral requested ${event?.req?.name}`) + handleCommand(event?.req?.name, event?.req?.data) + event.res = true }) -function pauseWorkout () { - rowingStatistics.pause() -} - -function stopWorkout () { - rowingStatistics.stop() -} - -function resumeWorkout () { - rowingStatistics.resume() -} - -function resetWorkout () { - workoutRecorder.reset() - rowingStatistics.reset() - peripheralManager.notifyStatus({ name: 'reset' }) -} +peripheralManager.on('heartRateMeasurement', (heartRateMeasurement) => { + // As the peripheralManager already has this info, it will enrich metrics based on the data internally + recordingManager.recordHeartRate(heartRateMeasurement) + webServer.presentHeartRate(heartRateMeasurement) +}) const gpioTimerService = child_process.fork('./app/gpio/GpioTimerService.js') gpioTimerService.on('message', handleRotationImpulse) +// Be aware, both the GPIO as well as the replayer use this as an entrypoint! function handleRotationImpulse (dataPoint) { - workoutRecorder.recordRotationImpulse(dataPoint) - rowingStatistics.handleRotationImpulse(dataPoint) + recordingManager.recordRotationImpulse(dataPoint) + sessionManager.handleRotationImpulse(dataPoint) } -const rowingStatistics = createRowingStatistics(config, session) -const workoutRecorder = createWorkoutRecorder() -const workoutUploader = createWorkoutUploader(workoutRecorder) - -rowingStatistics.on('driveFinished', (metrics) => { - webServer.notifyClients('metrics', metrics) - peripheralManager.notifyMetrics('strokeStateChanged', metrics) -}) - -rowingStatistics.on('recoveryFinished', (metrics) => { - logMetrics(metrics) - webServer.notifyClients('metrics', metrics) - peripheralManager.notifyMetrics('strokeFinished', metrics) - workoutRecorder.recordStroke(metrics) -}) - -rowingStatistics.on('webMetricsUpdate', (metrics) => { - webServer.notifyClients('metrics', metrics) -}) - -rowingStatistics.on('peripheralMetricsUpdate', (metrics) => { - peripheralManager.notifyMetrics('metricsUpdate', metrics) -}) - -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() -}) +const recordingManager = createRecordingManager(config) -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) { - const bleCentralService = child_process.fork('./app/ble/CentralService.js') - bleCentralService.on('message', (heartrateMeasurement) => { - rowingStatistics.handleHeartrateMeasurement(heartrateMeasurement) - }) -} - -if (config.heartrateMonitorANT) { - const antManager = createAntManager() - antManager.on('heartrateMeasurement', (heartrateMeasurement) => { - rowingStatistics.handleHeartrateMeasurement(heartrateMeasurement) - }) -} +const sessionManager = createSessionManager(config) -workoutUploader.on('authorizeStrava', (data, client) => { - webServer.notifyClient(client, 'authorizeStrava', data) +sessionManager.on('metricsUpdate', (metrics) => { + webServer.presentRowingMetrics(metrics) + recordingManager.recordMetrics(metrics) + peripheralManager.notifyMetrics(metrics) }) -workoutUploader.on('resetWorkout', () => { - resetWorkout() +const webServer = createWebServer(config) +webServer.on('messageReceived', async (message) => { + log.debug(`server: webclient requested ${message.command}`) + await handleCommand(message.command, message.data) }) -const webServer = createWebServer() -webServer.on('messageReceived', async (message, client) => { - switch (message.command) { - case 'switchPeripheralMode': - peripheralManager.switchPeripheralMode() - break - case 'reset': - resetWorkout() - break - case 'uploadTraining': - workoutUploader.upload(client) - break +async function handleCommand (command, data) { + switch (command) { case 'shutdown': - await shutdown() + if (shutdownEnabled) { + await shutdownApp() + await shutdownPi() + } else { + log.error('Shutdown requested, but shutdown is disabled') + } break - case 'stravaAuthorizationCode': - workoutUploader.stravaAuthorizationCode(message.data) + case 'reset': + // The initial sessionmanager stop and order of commands is important to prevent race conditions between the recordingManager and sessionMananager during resets + // If the sessionManager starts a new session too soon, recorders will miss the initial metrics broadcast, and crash as there is data added to a lap that hasn't started + await sessionManager.handleCommand(command, data) + await webServer.handleCommand(command, data) + await peripheralManager.handleCommand(command, data) + await recordingManager.handleCommand(command, data) break default: - log.warn('invalid command received:', message) - } -}) - -webServer.on('clientConnected', (client) => { - webServer.notifyClient(client, 'config', getConfig()) -}) - -// todo: extract this into some kind of state manager -function getConfig () { - return { - peripheralMode: peripheralManager.getPeripheralMode(), - stravaUploadEnabled: !!config.stravaClientId && !!config.stravaClientSecret, - shutdownEnabled: !!config.shutdownCommand + sessionManager.handleCommand(command, data) + recordingManager.handleCommand(command, data) + peripheralManager.handleCommand(command, data) + webServer.handleCommand(command, data) } } -// 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) +// This shuts down the pi hardware, use with caution! +async function shutdownPi () { + log.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`) -} +process.once('SIGINT', async (signal) => { + log.debug(`${signal} signal was received, shutting down gracefully`) + await shutdownApp() + process.exit(0) +}) -/* -replayRowingSession(handleRotationImpulse, { -// filename: 'recordings/2021/04/rx800_2021-04-21_1845_Rowing_30Minutes_Damper8.csv', // 30 minutes, damper 10 - realtime: true, - loop: false +process.once('SIGTERM', async (signal) => { + log.debug(`${signal} signal was received, shutting down gracefully`) + await shutdownApp() + process.exit(0) +}) + +process.once('uncaughtException', async (error) => { + log.error('Uncaught Exception:', error) + await shutdownApp() + process.exit(1) }) + +// This shuts down the pi, use with caution! +async function shutdownApp () { + // As we are shutting down, we need to make sure things are closed down nicely and save what we can + gpioTimerService.kill() + await recordingManager.handleCommand('shutdown') + await peripheralManager.handleCommand('shutdown') +} + +/* Uncomment the following lines to simulate a session +setTimeout(function() { + replayRowingSession(handleRotationImpulse, { + filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', // Concept 2, 2000 meter session + realtime: true, + loop: true + }) +}, 30000) */ diff --git a/app/tools/AuthorizedStravaConnection.js b/app/tools/AuthorizedStravaConnection.js deleted file mode 100644 index a653dfcdf3..0000000000 --- a/app/tools/AuthorizedStravaConnection.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Creates an OAuth authorized connection to Strava (https://developers.strava.com/) -*/ -import log from 'loglevel' -import axios from 'axios' -import FormData from 'form-data' -import config from './ConfigManager.js' -import fs from 'fs/promises' - -const clientId = config.stravaClientId -const clientSecret = config.stravaClientSecret -const stravaTokenFile = './config/stravatoken' - -function createAuthorizedConnection (getStravaAuthorizationCode) { - let accessToken - let refreshToken - - const authorizedConnection = axios.create({ - baseURL: 'https://www.strava.com/api/v3' - }) - - authorizedConnection.interceptors.request.use(async config => { - if (!refreshToken) { - try { - refreshToken = await fs.readFile(stravaTokenFile, 'utf-8') - } catch (error) { - log.info('no strava token available yet') - } - } - // if no refresh token is set, then the app has not yet been authorized with Strava - // start oAuth authorization process - if (!refreshToken) { - const authorizationCode = await getStravaAuthorizationCode(); - ({ accessToken, refreshToken } = await authorize(authorizationCode)) - await writeToken('', refreshToken) - // otherwise we just need to get a valid accessToken - } else { - const oldRefreshToken = refreshToken; - ({ accessToken, refreshToken } = await getAccessTokens(refreshToken)) - if (!refreshToken) { - log.error(`strava token is invalid, deleting ${stravaTokenFile}...`) - await fs.unlink(stravaTokenFile) - // if the refreshToken has changed, persist it - } else { - await writeToken(oldRefreshToken, refreshToken) - } - } - - if (!accessToken) { - log.error('strava authorization not successful') - } - - Object.assign(config.headers, { Authorization: `Bearer ${accessToken}` }) - if (config.data instanceof FormData) { - Object.assign(config.headers, config.data.getHeaders()) - } - return config - }) - - authorizedConnection.interceptors.response.use(function (response) { - return response - }, function (error) { - if (error?.response?.status === 401 || error?.message === 'canceled') { - return Promise.reject(new Error('user unauthorized')) - } else { - return Promise.reject(error) - } - }) - - async function oAuthTokenRequest (token, grantType) { - let responsePayload - const payload = { - client_id: clientId, - client_secret: clientSecret, - grant_type: grantType - } - if (grantType === 'authorization_code') { - payload.code = token - } else { - payload.refresh_token = token - } - - try { - const response = await axios.post('https://www.strava.com/oauth/token', payload) - if (response?.status === 200) { - responsePayload = response.data - } else { - log.error(`response error at strava oAuth request for ${grantType}: ${response?.data?.message || response}`) - } - } catch (e) { - log.error(`general error at strava oAuth request for ${grantType}: ${e?.response?.data?.message || e}`) - } - return responsePayload - } - - async function authorize (authorizationCode) { - const response = await oAuthTokenRequest(authorizationCode, 'authorization_code') - return { - refreshToken: response?.refresh_token, - accessToken: response?.access_token - } - } - - async function getAccessTokens (refreshToken) { - const response = await oAuthTokenRequest(refreshToken, 'refresh_token') - return { - refreshToken: response?.refresh_token, - accessToken: response?.access_token - } - } - - async function writeToken (oldToken, newToken) { - if (oldToken !== newToken) { - try { - await fs.writeFile(stravaTokenFile, newToken, 'utf-8') - } catch (error) { - log.info(`can not write strava token to file ${stravaTokenFile}`, error) - } - } - } - - return authorizedConnection -} - -export { - createAuthorizedConnection -} diff --git a/app/tools/ConfigManager.js b/app/tools/ConfigManager.js index ed4575b523..72a73a79e2 100644 --- a/app/tools/ConfigManager.js +++ b/app/tools/ConfigManager.js @@ -1,21 +1,181 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Merges the different config files and presents the configuration to the application + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ +/** + * Merges the different config files and presents the configuration to the application + * Checks the config for plausibility, fixes the errors when needed + */ +/* eslint-disable max-statements,complexity -- There simply is a lot to check before we activate a config. One of the few cases where more is better */ import defaultConfig from '../../config/default.config.js' +import { checkRangeValue, checkIntegerValue, checkBooleanValue, checkFloatValue } from './ConfigValidations.js' import { deepMerge } from './Helper.js' +import log from 'loglevel' + +/** + * @typedef {{ minumumForceBeforeStroke: number, minumumRecoverySlope: number}} OldRowerProfile + * @typedef { Config & { peripheralUpdateInterval:number, antplusMode:AntPlusModes, rowerSettings:OldRowerProfile }} OldConfig + */ +/** + * @returns {Promise} + */ async function getConfig () { + /** + * @type {import('../../config/config.js') | undefined} + */ let customConfig try { customConfig = await import('../../config/config.js') - } catch (exception) {} + } catch (exception) { + log.error('Configuration Error: config.js could not be imported. Reason: ', exception) + } + + // ToDo: check if config.js is a valdif JSON object - return customConfig !== undefined ? deepMerge(defaultConfig, customConfig.default) : defaultConfig + return customConfig !== undefined ? deepMerge(defaultConfig, /** @type {Config} */(customConfig.default)) : defaultConfig +} + +/** + * @param {Config | OldConfig} configToCheck + */ +function runConfigMigration (configToCheck) { + if ('peripheralUpdateInterval' in configToCheck) { + log.error('WARNING: An old version of the config file was detected, peripheralUpdateInterval is now deprecated please use ftmsUpdateInterval and pm5UpdateInterval') + configToCheck.ftmsUpdateInterval = configToCheck.peripheralUpdateInterval + configToCheck.pm5UpdateInterval = configToCheck.peripheralUpdateInterval + } + + if ('antplusMode' in configToCheck) { + log.error('WARNING: An old version of the config file was detected, please update the name of the following setting in the config.js file: antplusMode into antPlusMode') + configToCheck.antPlusMode = configToCheck.antplusMode + } + + if ('minumumForceBeforeStroke' in configToCheck.rowerSettings) { + log.error('WARNING: An old version of the config file was detected, please update the name of the following setting in the config.js file: minumumForceBeforeStroke into minimumForceBeforeStroke') + configToCheck.rowerSettings.minimumForceBeforeStroke = configToCheck.rowerSettings.minumumForceBeforeStroke + } + + if ('minumumRecoverySlope' in configToCheck.rowerSettings) { + log.error('WARNING: An old version of the config file was detected, please update the name of the following setting in the config.js file: minumumRecoverySlope into minimumRecoverySlope') + configToCheck.rowerSettings.minimumRecoverySlope = configToCheck.rowerSettings.minumumRecoverySlope + } +} + +/** + * @param {Config | OldConfig} configToCheck + */ +function checkConfig (configToCheck) { + 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, 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'], true, 'Up') + checkIntegerValue(configToCheck, 'appPriority', configToCheck.gpioPriority, 0, true, true, 0) + checkIntegerValue(configToCheck, 'webUpdateInterval', 80, 1000, false, true, 1000) + checkIntegerValue(configToCheck, 'ftmsUpdateInterval', 150, 1000, false, true, 1000) // Please note: the minimum update interval for iOS is 30ms, for android 7.5ms (see https://stackoverflow.com/questions/37776536/bluetooth-low-energy-on-different-platforms), and some PM5 messages send 5 telegrams + checkIntegerValue(configToCheck, 'pm5UpdateInterval', 150, 1000, false, true, 1000) // Please note: the minimum update interval for iOS is 30ms, for android 7.5ms (see https://stackoverflow.com/questions/37776536/bluetooth-low-energy-on-different-platforms), and some PM5 messages send 5 telegrams + 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) + checkBooleanValue(configToCheck, 'gzipRawDataFiles', true, false) + checkBooleanValue(configToCheck, 'createTcxFiles', true, true) + checkBooleanValue(configToCheck, 'gzipTcxFiles', true, false) + checkBooleanValue(configToCheck, 'createFitFiles', true, true) + checkBooleanValue(configToCheck, 'gzipFitFiles', 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 || configToCheck.createFitFiles) { + 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') + checkBooleanValue(configToCheck.userSettings, 'highlyTrained', true, false) + } + 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, null, false, true, 1) + checkFloatValue(configToCheck.rowerSettings, 'dragFactor', 1, null, false, false, null) + 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) + } + checkFloatValue(configToCheck.rowerSettings, 'flywheelInertia', 0, null, false, false, null) + checkFloatValue(configToCheck.rowerSettings, 'minimumForceBeforeStroke', 0, 500, true, true, 0) + checkFloatValue(configToCheck.rowerSettings, 'minimumRecoverySlope', 0, null, true, true, 0) + checkFloatValue(configToCheck.rowerSettings, 'minimumStrokeQuality', 0, 1, true, true, 0) + 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') + } + if (configToCheck.rowerSettings.autoAdjustDragFactor && configToCheck.rowerSettings.autoAdjustRecoverySlope) { + checkFloatValue(configToCheck.rowerSettings, 'autoAdjustRecoverySlopeMargin', 0, 1, false, true, 1) + } + 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) + if (!configToCheck.mqtt) { + configToCheck.mqtt = { + mqttBroker: '', + username: '', + password: '', + machineName: '' + } + log.error('Configuration Error: MQTT configuration error') + } + if (!!configToCheck.userSettings.rowsAndAll && !!configToCheck.userSettings.rowsAndAll.allowUpload && configToCheck.userSettings.rowsAndAll.allowUpload === true) { + if (!configToCheck.userSettings.rowsAndAll.apiKey || configToCheck.userSettings.rowsAndAll.apiKey === '') { + log.error('Configuration Error: RowsAndAll ApiKey error') + configToCheck.userSettings.rowsAndAll.allowUpload = false + } + } else { + configToCheck.userSettings.rowsAndAll = { allowUpload: false } + } + if (!!configToCheck.userSettings.intervals && !!configToCheck.userSettings.intervals.allowUpload && configToCheck.userSettings.intervals.allowUpload === true) { + if (!configToCheck.userSettings.intervals.athleteId || configToCheck.userSettings.intervals.athleteId === '') { + log.error('Configuration Error: intervals.icu athleteId error') + configToCheck.userSettings.intervals.allowUpload = false + } + if (!configToCheck.userSettings.intervals.apiKey || configToCheck.userSettings.intervals.apiKey === '') { + log.error('Configuration Error: intervals.icu apiKey error') + configToCheck.userSettings.intervals.allowUpload = false + } + } else { + configToCheck.userSettings.intervals = { allowUpload: false } + } + if (!!configToCheck.userSettings.strava && !!configToCheck.userSettings.strava.allowUpload && configToCheck.userSettings.strava.allowUpload === true) { + if (!configToCheck.userSettings.strava.clientId || configToCheck.userSettings.strava.clientId === '' || isNaN(configToCheck.userSettings.strava.clientId)) { + log.error('Configuration Error: strava clientId error') + configToCheck.userSettings.strava.allowUpload = false + } + if (!configToCheck.userSettings.strava.clientSecret || configToCheck.userSettings.strava.clientSecret === '') { + log.error('Configuration Error: strava clientSecret error') + configToCheck.userSettings.strava.allowUpload = false + } + if (!configToCheck.userSettings.strava.refreshToken || configToCheck.userSettings.strava.refreshToken === '') { + log.error('Configuration Error: strava refreshToken error') + configToCheck.userSettings.strava.allowUpload = false + } + } else { + configToCheck.userSettings.strava = { allowUpload: false } + } } const config = await getConfig() +runConfigMigration(config) +checkConfig(config) + export default config diff --git a/app/tools/ConfigValidations.js b/app/tools/ConfigValidations.js new file mode 100644 index 0000000000..3c1f469525 --- /dev/null +++ b/app/tools/ConfigValidations.js @@ -0,0 +1,173 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor + + Merges the different config files and presents the configuration to the application + Checks the config for plausibilit, fixes the errors when needed +*/ +import log from 'loglevel' + +/** + * @param {{[key: string | number | symbol]: any}} parameterSection + * @param {string} parameterName + * @param {number | null} minimumValue + * @param {number | null} maximumvalue + * @param {boolean} allowZero + * @param {boolean} allowRepair + * @param {number | null} defaultValue + */ +// eslint-disable-next-line max-params +export 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 (parameterSection[parameterName] === undefined): + log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) + errors++ + break + case (!Number.isInteger(parameterSection[parameterName])): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be an integer value, encountered ${parameterSection[parameterName]}`) + errors++ + break + 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 && parameterSection[parameterName] > maximumvalue): + log.error(`Configuration Error: ${parameterSection}.${parameterName} can't be above ${maximumvalue}, encountered ${parameterSection[parameterName]}`) + errors++ + break + case (!allowZero && parameterSection[parameterName] === 0): + log.error(`Configuration Error: ${parameterSection}.${parameterName} can't be zero`) + errors++ + break + default: + // No error detected :) + } + if (errors > 0) { + // Errors were made + if (allowRepair) { + log.error(` resolved by setting ${parameterSection}.${parameterName} to ${defaultValue}`) + parameterSection[parameterName] = defaultValue + } else { + log.error(` as ${parameterSection}.${parameterName} is a fatal parameter, I'm exiting`) + process.exit(9) + } + } +} + +/** + * @param {{[key: string | number | symbol]: any}} parameterSection + * @param {string} parameterName + * @param {number | null} minimumValue + * @param {number | null} maximumvalue + * @param {boolean} allowZero + * @param {boolean} allowRepair + * @param {number | null} defaultValue + */ +// eslint-disable-next-line max-params +export 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 (parameterSection[parameterName] === undefined): + log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) + errors++ + break + case (!(typeof (parameterSection[parameterName]) === 'number')): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be a numerical value, encountered ${parameterSection[parameterName]}`) + errors++ + break + 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 && parameterSection[parameterName] > maximumvalue): + log.error(`Configuration Error: ${parameterSection}.${parameterName} can't be above ${maximumvalue}, encountered ${parameterSection[parameterName]}`) + errors++ + break + case (!allowZero && parameterSection[parameterName] === 0): + log.error(`Configuration Error: ${parameterSection}.${parameterName} can't be zero`) + errors++ + break + default: + // No error detected :) + } + if (errors > 0) { + // Errors were made + if (allowRepair) { + log.error(` resolved by setting ${parameterSection}.${parameterName} to ${defaultValue}`) + parameterSection[parameterName] = defaultValue + } else { + log.error(` as ${parameterSection}.${parameterName} is a fatal parameter, I'm exiting`) + process.exit(9) + } + } +} + +/** + * @param {{[key: string | number | symbol]: any}} parameterSection + * @param {string} parameterName + * @param {boolean} allowRepair + * @param {boolean} defaultValue + */ +export 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) { + case (parameterSection[parameterName] === undefined): + log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) + errors++ + break + 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: + // No error detected :) + } + if (errors > 0) { + // Errors were made + if (allowRepair) { + log.error(` resolved by setting ${parameterSection}.${parameterName} to ${defaultValue}`) + parameterSection[parameterName] = defaultValue + } else { + log.error(` as ${parameterSection}.${parameterName} is a fatal parameter, I'm exiting`) + process.exit(9) + } + } +} + +/** + * @param {{[key: string | number | symbol]: any}} parameterSection + * @param {string} parameterName + * @param {Array} range + * @param {boolean} allowRepair + * @param {string | number} defaultValue + */ +export 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 (parameterSection[parameterName] === undefined): + log.error(`Configuration Error: ${parameterSection}.${parameterName} isn't defined`) + errors++ + break + case (!range.includes(parameterSection[parameterName])): + log.error(`Configuration Error: ${parameterSection}.${parameterName} should be come from ${range}, encountered ${parameterSection[parameterName]}`) + errors++ + break + default: + // No error detected :) + } + if (errors > 0) { + // Errors were made + if (allowRepair) { + log.error(` resolved by setting ${parameterSection}.${parameterName} to ${defaultValue}`) + parameterSection[parameterName] = defaultValue + } else { + log.error(` as ${parameterSection}.${parameterName} is a fatal parameter, I'm exiting`) + process.exit(9) + } + } +} diff --git a/app/tools/Helper.js b/app/tools/Helper.js index 63f388e04a..13d30d9715 100644 --- a/app/tools/Helper.js +++ b/app/tools/Helper.js @@ -1,28 +1,80 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Helper functions + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor */ +/** + * Helper functions + */ -// deeply merges any number of objects into a new object +/** + * Deeply merges any number of objects into a new object + * @template {object} T + * @param {...T} objects - Objects to merge. + * @returns {T} - The merged object + */ export function deepMerge (...objects) { - const isObject = obj => obj && typeof obj === 'object' + const isObject = /** @type {(obj: T[keyof T]) => obj is object} */ obj => obj && typeof obj === 'object' - return objects.reduce((prev, obj) => { - Object.keys(obj).forEach(key => { + return objects.reduce((/** @type {T} */prev, /** @type {T} */obj) => { + /** @type {Array} */(Object.keys(obj)).forEach(key => { const pVal = prev[key] const oVal = obj[key] if (Array.isArray(pVal) && Array.isArray(oVal)) { - prev[key] = pVal.concat(...oVal) + /** @type {Array} */(prev[key]) = pVal.concat(...oVal) } else if (isObject(pVal) && isObject(oVal)) { - prev[key] = deepMerge(pVal, oVal) + /** @type {object} */(prev[key]) = deepMerge(pVal, oVal) } else { prev[key] = oVal } }) return prev - }, {}) + }, /** @type {T} */ ({})) +} + +// converts a timeStamp in seconds to a human readable hh:mm:ss format +/** + * @param {number} secondsTimeStamp + * @returns + */ +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 +} + +/** + * Reverses the property and values of the object making the values properties that allow to access the property name by passing in the value (assuming values are unique) + * @template {Record} T + * @param {T} object + * @returns {ReverseKeyValue>} + */ +export function swapObjectPropertyValues (object) { + return Object.fromEntries(Object.entries(object).map(a => a.reverse())) +} + +/** + * @param {Array} array + */ +export function toHexString (array) { + return array.map((item) => `0x${item.toString(16).padStart(2, '0')}`) } diff --git a/app/tools/StravaAPI.js b/app/tools/StravaAPI.js deleted file mode 100644 index f5dbc655a7..0000000000 --- a/app/tools/StravaAPI.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict' -/* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor - - Implements required parts of the Strava API (https://developers.strava.com/) -*/ -import zlib from 'zlib' -import FormData from 'form-data' -import { promisify } from 'util' -import { createAuthorizedConnection } from './AuthorizedStravaConnection.js' -const gzip = promisify(zlib.gzip) - -function createStravaAPI (getStravaAuthorizationCode) { - const authorizedStravaConnection = createAuthorizedConnection(getStravaAuthorizationCode) - - async function uploadActivityTcx (tcxRecord) { - const form = new FormData() - - form.append('file', await gzip(tcxRecord.tcx), tcxRecord.filename) - form.append('data_type', 'tcx.gz') - form.append('name', 'Indoor Rowing Session') - form.append('description', 'Uploaded from Open Rowing Monitor') - form.append('trainer', 'true') - form.append('activity_type', 'Rowing') - - return await authorizedStravaConnection.post('/uploads', form) - } - - async function getAthlete () { - return (await authorizedStravaConnection.get('/athlete')).data - } - - return { - uploadActivityTcx, - getAthlete - } -} -export { - createStravaAPI -} diff --git a/app/tools/global.interfaces.js b/app/tools/global.interfaces.js new file mode 100644 index 0000000000..4c7b61ead1 --- /dev/null +++ b/app/tools/global.interfaces.js @@ -0,0 +1,18 @@ +/** + * @typedef {'requestControl'| + * 'updateIntervalSettings'| + * 'start'| + * 'startOrResume'| + * 'pause'| + * 'stop'| + * 'reset'| + * 'switchBlePeripheralMode'| + * 'switchAntPeripheralMode'| + * 'switchHrmMode'| + * 'refreshPeripheralConfig'| + * 'uploadTraining'| + * 'authorizeStrava'| + * 'stravaAuthorizationCode'| + * 'shutdown' + * } Command + */ diff --git a/app/tools/utility.interfaces.js b/app/tools/utility.interfaces.js new file mode 100644 index 0000000000..82a1f5b789 --- /dev/null +++ b/app/tools/utility.interfaces.js @@ -0,0 +1,15 @@ +/** + * Recursively makes all properties of an object type optional. + * @template T + * @typedef {T extends object ? { [K in keyof T]?: DeepPartial } : T} DeepPartial + */ +/** + * Converts a union type to an object type with the union members as keys and their index as values. + * @template T + * @typedef {Object.} UnionToObject + */ +/** + * Reverses the keys and values of an object type. + * @template {Record} T - The object type to reverse. + * @typedef { { [K in keyof T as T[K]]: keyof T } } ReverseKeyValue - A mapped type that swaps keys and values. + */ diff --git a/bin/openrowingmonitor.sh b/bin/openrowingmonitor.sh index 960fa1b157..cc0207a9a3 100755 --- a/bin/openrowingmonitor.sh +++ b/bin/openrowingmonitor.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +# Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor # # Start script for Open Rowing Monitor # diff --git a/bin/updateopenrowingmonitor.sh b/bin/updateopenrowingmonitor.sh index a30278eb5d..0d1b3e27f9 100755 --- a/bin/updateopenrowingmonitor.sh +++ b/bin/updateopenrowingmonitor.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +# Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor # # Update script for Open Rowing Monitor, use at your own risk! # @@ -97,7 +97,7 @@ switch_branch() { CURRENT_DIR=$(pwd) SCRIPT_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd )" INSTALL_DIR="$(dirname "$SCRIPT_DIR")" -GIT_REMOTE="https://github.com/laberning/openrowingmonitor.git" +GIT_REMOTE="https://github.com/JaapvanEkris/openrowingmonitor.git" cd $INSTALL_DIR @@ -117,6 +117,15 @@ if getopts "b:" arg; then cancel "Branch \"$OPTARG\" does not exist in the repository, can not switch" fi + ARCHITECTURE=$(uname -m) + if [[ $ARCHITECTURE == "armv6l" ]] && [[ $OPTARG != "v1beta_updates_Pi_Zero_W" ]]; then + cancel "Branch \"$OPTARG\" doesn't work on a Pi Zero W, please use branch 'v1beta_updates_Pi_Zero_W'" + fi + if [[ $ARCHITECTURE != "armv6l" ]] && [[ $OPTARG == "v1beta_updates_Pi_Zero_W" ]]; then + cancel "Branch \"$OPTARG\" is a legacy version intended for the Pi Zero W, please use branch 'v1beta_updates' or similar" + fi + + if ask "Do you want to switch from branch \"$CURRENT_BRANCH\" to branch \"$OPTARG\"?" Y; then print "Switching to branch \"$OPTARG\"..." CURRENT_BRANCH=$OPTARG @@ -124,10 +133,16 @@ if getopts "b:" arg; then else cancel "Stopping update - please run without -b parameter to do a regular update" fi + else print "Checking for new version..." REMOTE_VERSION=$(git ls-remote $GIT_REMOTE refs/heads/$CURRENT_BRANCH | awk '{print $1;}') + ARCHITECTURE=$(uname -m) + if [[ $ARCHITECTURE == "armv6l" ]] && [[ $CURRENT_BRANCH != "v1beta_updates_Pi_Zero_W" ]]; then + cancel "Branch \"$OPTARG\" doesn't work on a Pi Zero W, please use branch 'v1beta_updates_Pi_Zero_W'" + fi + if [ "$LOCAL_VERSION" = "$REMOTE_VERSION" ]; then print "You are using the latest version of Open Rowing Monitor from branch \"$CURRENT_BRANCH\"." else diff --git a/config/config.interface.js b/config/config.interface.js new file mode 100644 index 0000000000..20043cc87b --- /dev/null +++ b/config/config.interface.js @@ -0,0 +1,67 @@ +/** + * @typedef {Object} MQTTConfig + * @property {string} mqttBroker - The MQTT broker address. + * @property {string} username - The username for MQTT broker authentication. + * @property {string} password - The password for MQTT broker authentication. + * @property {string} machineName - The name of the machine. + */ +/** + * @typedef {Object} UserSettings + * @property {number} restingHR - The resting heart rate of the user. + * @property {number} maxHR - The maximum observed heart rate during the last year. + * @property {number} minPower - The minimum power a rower can produce. + * @property {number} maxPower - The maximum power a rower can produce. + * @property {number} distanceCorrectionFactor - The effect that doubling the distance has on the maximum achievable average pace. + * @property {number} weight - The weight of the rower in kilograms. + * @property {string} sex - The sex of the rower ("male" or "female"). + * @property {boolean} highlyTrained - Indicates if the user is highly trained. + * @property {Object} rowsAndAll - Configuration for the RowsAndAll.com upload. + * @property {boolean} rowsAndAll.upload - Indicates if the data should be uploaded to RowsAndAll.com. + * @property {string} rowsAndAll.apiKey - The API key for RowsAndAll.com. + * @property {Object} intervals - Configuration for the intervals.icu upload. + * @property {boolean} intervals.upload - Indicates if the data should be uploaded to intervals.icu. + * @property {string} intervals.athleteId - The athlete ID for intervals.icu. + * @property {string} intervals.apiKey - The API key for intervals.icu. + */ +/** + * @typedef {"trace"|"debug"|"info"|"warn"|"error"|"silent"} LogLevels + * @typedef {'FTMS'|'FTMSBIKE'|'PM5'|'CSC'|'CPS'|'OFF'} BluetoothModes + * @typedef {'FE'|'OFF'} AntPlusModes + * @typedef {'ANT'|'BLE'|'OFF'} HeartRateModes + */ +/** + * @typedef {Object} Config + * @property {Object} loglevel - The log levels configuration. + * @property {LogLevels} loglevel.default - The default log level. + * @property {LogLevels} loglevel.RowingEngine - The log level for the rowing engine. + * @property {LogLevels} loglevel.Peripherals - The log level for peripherals. + * @property {number} gpioPin - The GPIO pin used to read sensor data. + * @property {number} gpioPriority - The system level priority of the thread that measures the rotation speed of the flywheel. + * @property {number} gpioPollingInterval - The interval at which the GPIO is inspected for state changes. + * @property {string} gpioTriggeredFlank - The flank to be detected by the GPIO detection. + * @property {number} gpioMinimumPulseLength - The minimum pulse length in microseconds. + * @property {number} appPriority - The system level priority of the thread that processes the flywheel and HR data. + * @property {BluetoothModes} bluetoothMode - The Bluetooth Low Energy Profile that is broadcasted to external peripherals and apps. + * @property {AntPlusModes} antPlusMode - The ANT+ mode that is broadcasted to external peripherals and apps. + * @property {HeartRateModes} heartRateMode - The heart rate monitor mode. + * @property {string} ftmsRowerPeripheralName - The name used to announce the FTMS Rower via Bluetooth Low Energy. + * @property {string} ftmsBikePeripheralName - The name used to announce the FTMS Bike via Bluetooth Low Energy. + * @property {number} webUpdateInterval - The interval for updating all web clients in milliseconds. + * @property {number} ftmsUpdateInterval - The interval between updates of the Bluetooth devices in milliseconds. + * @property {number} pm5UpdateInterval - The interval between updates of the clients using PM5 Bluetooth profile in milliseconds. + * @property {MQTTConfig} mqtt - The MQTT peripheral configuration settings. + * @property {number} numOfPhasesForAveragingScreenData - The number of stroke phases used to smoothen the data displayed on screens. + * @property {string} dataDirectory - The directory in which to store user-specific content. + * @property {boolean} createTcxFiles - Indicates if the training sessions should be stored as Garmin TCX files. + * @property {boolean} createFitFiles - Indicates if the training sessions should be stored as Garmin fit files. + * @property {boolean} createRowingDataFiles - Indicates if the (in-)stroke data should be stored in OpenRowingData CSV files. + * @property {boolean} createRawDataFiles - Indicates if the raw sensor data should be stored in CSV files. + * @property {boolean} gzipTcxFiles - Indicates if gzip compression should be applied to the recorded TCX training sessions file. + * @property {boolean} gzipFitFiles - Indicates if gzip compression should be applied to the recorded fit training sessions file. + * @property {boolean} gzipRawDataFiles - Indicates if gzip compression should be applied to the raw sensor data recording files. + * @property {UserSettings} userSettings - The settings used for the VO2 Max calculation embedded in the TCX file comments. + * @property {RowerProfile} rowerSettings - The rower specific settings. + * @property {string} shutdownCommand - The command to shutdown the device via the user interface. + * @property {string} stravaClientId - The "Client ID" of your Strava API Application. + * @property {string} stravaClientSecret - The "Client Secret" of your Strava API Application. + */ diff --git a/config/default.config.js b/config/default.config.js index fa16cfa77b..aeb7047928 100644 --- a/config/default.config.js +++ b/config/default.config.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor This file contains the default configuration of the Open Rowing Monitor. @@ -13,13 +13,18 @@ */ import rowerProfiles from './rowerProfiles.js' +/** + * The default configuration for the Open Rowing Monitor. + * @type {Config} + */ export default { // 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: 'warn' + RowingEngine: 'warn', + Peripherals: 'warn' }, // Defines the GPIO Pin that is used to read the sensor data from the rowing machine @@ -78,17 +83,19 @@ 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 - // Will currenty connect to the first device found - heartrateMonitorBLE: true, + // Selects the ANT+ that is broadcasted to external peripherals and apps. Supported modes: + // - FE: ANT+ Fitness Equipment + // - OFF: Turns ANT+ Fitness Equipment off + antPlusMode: 'OFF', - // 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: '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 @@ -107,7 +114,18 @@ export default { // 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, + ftmsUpdateInterval: 1000, + + // Interval between updates of the clients using PM5 Bluetooth profile (miliseconds) + pm5UpdateInterval: 1000, + + // MQTT perpipheral configuration settings + mqtt: { + mqttBroker: '', + username: '', + password: '', + machineName: '' + }, // 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 @@ -119,9 +137,12 @@ export default { // currently this directory holds the recorded training sessions dataDirectory: 'data', - // Stores the training sessions as TCX files + // Stores the training sessions as Garmin TCX files createTcxFiles: true, + // Stores the training sessions as Garmin fit files + createFitFiles: true, + // Stores the (in-)stroke data in OpenRowingData CSV files createRowingDataFiles: true, @@ -134,6 +155,9 @@ export default { // you will have to unzip the files before uploading gzipTcxFiles: false, + // Apply gzip compression to the recorded fit training sessions file (fit.gz) + gzipFitFiles: false, + // Apply gzip compression to the raw sensor data recording files (csv.gz) gzipRawDataFiles: true, @@ -165,8 +189,35 @@ export default { // This can be "male" or "female" sex: 'male', - // See for this definition: https://www.concept2.com/indoor-rowers/training/calculators/vo2max-calculator - highlyTrained: false + // Definition copied from https://www.concept2.co.uk/indoor-rowers/training/calculators/vo2max-calculator + // If you have been rowing regularly for several years, training at least four days per week, doing a variety of workout types + // and improving your rowing scores, then we suggest selecting "Highly trained" when using the calculator. + // If you consider yourself a fitness rower and don't push yourself very hard or do any hard pieces, then we suggest selecting "Not highly trained." + highlyTrained: false, + + // Configuration for the RowsAndAll.com upload + rowsAndAll: { + allowUpload: false, + autoUpload: false, + apiKey: '' + }, + + // Configuration for the intervals.icu upload + intervals: { + allowUpload: false, + autoUpload: false, + athleteId: '', + apiKey: '' + }, + + // Configuration for the Strava.com upload + strava: { + allowUpload: false, + autoUpload: false, + clientId: '', + clientSecret: '', + refreshToken: '' + } }, // The rower specific settings. Either choose a profile from config/rowerProfiles.js or diff --git a/config/rowerProfiles.interface.js b/config/rowerProfiles.interface.js new file mode 100644 index 0000000000..0ab2762998 --- /dev/null +++ b/config/rowerProfiles.interface.js @@ -0,0 +1,37 @@ +/** + * @typedef {Object} RowerProfile + * @property {number} numOfImpulsesPerRevolution - Number of impulses triggered per revolution of the flywheel. + * @property {number} sprocketRadius - Radius of the sprocket that attaches the belt/chain to the flywheel. + * @property {number} minimumTimeBetweenImpulses - Minimum duration between impulses in seconds during active rowing. + * @property {number} maximumTimeBetweenImpulses - Maximum duration between impulses in seconds during active rowing. + * @property {number} smoothing - Length of the running average for filtering the currentDt. + * @property {number} flankLength - Number of measurements used for determining the angular velocity and angular acceleration. + * @property {number} minimumForceBeforeStroke - Minimum force on the handle before it is considered a stroke, in Newtons. + * @property {number} minimumRecoverySlope - Minimum inclination of the currentDt's before it is considered a recovery. + * @property {number} minimumStrokeQuality - Minimum quality level of the stroke detection. + * @property {boolean} autoAdjustRecoverySlope - Indicates if the recovery slope should be adjusted dynamically. + * @property {number} autoAdjustRecoverySlopeMargin - Margin used between the automatically calculated recovery slope and a next recovery. + * @property {number} minimumDriveTime - Minimum time of the drive phase in seconds. + * @property {number} minimumRecoveryTime - Minimum time of the recovery phase in seconds. + * @property {number} dragFactor - Drag factor of the rowing machine. + * @property {boolean} autoAdjustDragFactor - Indicates if the drag factor should be adjusted dynamically. + * @property {number} dragFactorSmoothing - Running average of the drag factor over a number of strokes. + * @property {number} minimumDragQuality - Minimum quality indication for the drag factor calculation. + * @property {number} flywheelInertia - Moment of inertia of the flywheel in kg*m^2. + * @property {number} maximumStrokeTimeBeforePause - Time before a stroke is considered paused in seconds. + * @property {number} magicConstant - Constant used to convert flywheel revolutions to rowed distance. + */ +/** + * The default rower profiles for different models of ergometers. + * @type {{ + * DEFAULT: RowerProfile, + * Generic_Air_Rower: RowerProfile, + * Concept2_Model_C: RowerProfile, + * Concept2_RowErg: RowerProfile, + * DKN_R320: RowerProfile, + * ForceUSA_R3: RowerProfile, + * NordicTrack_RX800: RowerProfile, + * Sportstech_WRX700: RowerProfile, + * KayakFirst_Blue: RowerProfile + * }} + */ diff --git a/config/rowerProfiles.js b/config/rowerProfiles.js index 74a33f64c4..121163666b 100644 --- a/config/rowerProfiles.js +++ b/config/rowerProfiles.js @@ -1,13 +1,16 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor 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/JaapvanEkris/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. */ + +/* eslint-disable camelcase */ export default { // The default rower profile @@ -17,32 +20,31 @@ export default { 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 + // as well as the drive length. If all goes well, you end up with average forces around 300 to 800 N and drive lengths around 1.20 to 1.45 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 above the maximum are filtered, so setting these liberaly // might help here minimumTimeBetweenImpulses: 0.014, maximumTimeBetweenImpulses: 0.5, + // NOISE FILTER SETTINGS + // Filter Settings to reduce noise in the measured data // 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 + // Flank length determines the number of measuments that are used for determining the angular velocity and angular acceleration flankLength: 3, + // STROKE DETECTION SETTINGS // 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, + minimumForceBeforeStroke: 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, + minimumRecoverySlope: 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 minimumForceBeforeStroke). minimumStrokeQuality: 0.34, // ORM can automatically calculate the recovery slope and adjust it dynamically. For this to work, autoAdjustDragFactor MUST be set to true @@ -55,15 +57,13 @@ export default { minimumDriveTime: 0.300, // minimum time of the drive 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. - // To display it for your rowing machine, set the logging level of the RowingEngine to 'info'. Then start rowing and - // you will see the measured values in the log. - // Just as a frame of reference: the Concept2 can display this factor from the menu, where it is multiplied with 1.000.000 - // For a new Concept2 the Drag Factor ranges between 80 (Damper setting 1) and 220 (Damper setting 10). Other rowers are - // in the range of 150 to 450 (NordicTrack). + // Needed to determine the drag factor of the rowing machine. This value can be measured in the recovery phasse of the stroke. + // To display it for your rowing machine, set the logging level of the RowingEngine to 'info'. Then start rowing and you will see the measured + // values in the log. + // Just as a frame of reference: the Concept2 can display this factor from the menu, where it ranges between 80 (Damper setting 1) to 220 (Damper setting 10). + // Other rowers are in the range of 150 to 450 (NordicTrack), but more extreme values are found in waterrowers (for example 32000) // Open Rowing Monitor can also automatically adjust this value based on the measured damping. To do so, set the setting - // autoAdjustDragFactor to true (see below). + // autoAdjustDragFactor to true (see below) and set the flywheel inertia. dragFactor: 1500, // Set this to true, if you want to automatically update the drag factor based on the measured @@ -107,7 +107,7 @@ export default { minimumTimeBetweenImpulses: 0.007, smoothing: 1, flankLength: 6, - minumumForceBeforeStroke: 2, + minimumForceBeforeStroke: 2, minimumStrokeQuality: 0.6, minimumDriveTime: 0.200, // minimum time of the drive phase minimumRecoveryTime: 0.600, // minimum time of the recovery phase @@ -118,25 +118,53 @@ export default { flywheelInertia: 0.073, maximumStrokeTimeBeforePause: 6.0 }, + + // Concept2 RowErg, Model B and C + Concept2_Model_C: { + numOfImpulsesPerRevolution: 3, + sprocketRadius: 1.4, + minimumTimeBetweenImpulses: 0.014, + maximumTimeBetweenImpulses: 0.040, + smoothing: 1, + flankLength: 6, + minimumForceBeforeStroke: 50, + minimumRecoverySlope: 0.00070, + minimumStrokeQuality: 0.36, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.01, + minimumDriveTime: 0.400, // minimum time of the drive phase + minimumRecoveryTime: 0.900, // minimum time of the recovery phase + dragFactor: 110, + autoAdjustDragFactor: true, + dragFactorSmoothing: 3, + minimumDragQuality: 0.95, + flywheelInertia: 0.10148, + maximumStrokeTimeBeforePause: 6.0, + magicConstant: 2.8 + }, + // Concept2 RowErg, Model D, E and RowErg Concept2_RowErg: { numOfImpulsesPerRevolution: 6, + sprocketRadius: 1.4, + maximumStrokeTimeBeforePause: 6.0, + dragFactor: 68, + autoAdjustDragFactor: true, + minimumDragQuality: 0.60, + dragFactorSmoothing: 3, minimumTimeBetweenImpulses: 0.005, - maximumTimeBetweenImpulses: 0.022, - flywheelInertia: 0.10163, - sprocketRadius: 1.5, + maximumTimeBetweenImpulses: 0.0145, flankLength: 12, - minimumStrokeQuality: 0.50, - minumumRecoverySlope: 0.00070, + smoothing: 1, + minimumStrokeQuality: 0.34, + minimumForceBeforeStroke: 11, + minimumRecoverySlope: 0.00070, autoAdjustRecoverySlope: true, - autoAdjustRecoverySlopeMargin: 0.035, - minumumForceBeforeStroke: 0, - minimumDriveTime: 0.46, + autoAdjustRecoverySlopeMargin: 0.01, + minimumDriveTime: 0.40, minimumRecoveryTime: 0.90, - dragFactor: 110, - autoAdjustDragFactor: true, - minimumDragQuality: 0.83, - dragFactorSmoothing: 3 + flywheelInertia: 0.101255, + magicConstant: 2.8 }, // DKN R-320 Air Rower @@ -158,10 +186,10 @@ export default { // new engine settings sprocketRadius: 1.5, minimumStrokeQuality: 0.50, - minumumRecoverySlope: 0.00070, + minimumRecoverySlope: 0.00070, autoAdjustRecoverySlope: true, autoAdjustRecoverySlopeMargin: 0.035, - minumumForceBeforeStroke: 20, + minimumForceBeforeStroke: 20, minimumDriveTime: 0.46, minimumRecoveryTime: 0.80, minimumDragQuality: 0.83, @@ -169,11 +197,31 @@ export default { maximumStrokeTimeBeforePause: 4 }, + // KayakFirst kayak/canoe erg (2020 model blue, non-bull) + KayakFirst_Blue: { + numOfImpulsesPerRevolution: 6, + sprocketRadius: 2.7, + maximumStrokeTimeBeforePause: 7.0, + dragFactor: 40, + autoAdjustDragFactor: true, + minimumDragQuality: 0.736, + dragFactorSmoothing: 4, + minimumTimeBetweenImpulses: 0.005, + maximumTimeBetweenImpulses: 0.0145, + flankLength: 12, + smoothing: 1, + minimumForceBeforeStroke: 1, + minimumDriveTime: 0.145, + minimumRecoveryTime: 0.17, + flywheelInertia: 0.039, + magicConstant: 3.45 + }, + // NordicTrack RX800 Air Rower NordicTrack_RX800: { numOfImpulsesPerRevolution: 4, minimumTimeBetweenImpulses: 0.005, - maximumTimeBetweenImpulses: 0.022, + maximumTimeBetweenImpulses: 0.045, sprocketRadius: 3.0, autoAdjustDragFactor: true, minimumDragQuality: 0.83, @@ -182,12 +230,12 @@ export default { dragFactor: 225, flankLength: 11, minimumStrokeQuality: 0.34, - minumumRecoverySlope: 0.001, - autoAdjustRecoverySlope: true, - autoAdjustRecoverySlopeMargin: 0.036, - minumumForceBeforeStroke: 80, + minimumRecoverySlope: 0, + autoAdjustRecoverySlope: false, + autoAdjustRecoverySlopeMargin: 0.1, + minimumForceBeforeStroke: 80, minimumDriveTime: 0.30, - minimumRecoveryTime: 0.90 + minimumRecoveryTime: 0.60 }, // Sportstech WRX700 @@ -195,8 +243,28 @@ export default { numOfImpulsesPerRevolution: 2, minimumTimeBetweenImpulses: 0.005, maximumTimeBetweenImpulses: 0.5, - minumumRecoverySlope: 0.125, + minimumRecoverySlope: 0, flywheelInertia: 0.72, dragFactor: 32000 + }, + + // Virtufit Magnetic Rowing Machine + // https://virtufit.nl/wp-content/uploads/2022/01/VirtuFit-Elite-Magnetic-Rowing-Machine-Manual-EN.pdf + // aka: Obelix - https://pesaschile.cl/categorias/1162-remo-de-aire-magnetico-lite-series-obelix.html + // https://fedesport.cl/products/remo-de-aire-magnetico-lite-series-obelix + virtufit: { + numOfImpulsesPerRevolution: 4, + dragFactor: 380, + autoAdjustDragFactor: true, + minimumDragQuality: 0.93, + autoAdjustRecoverySlope: true, + autoAdjustRecoverySlopeMargin: 0.5, + minimumForceBeforeStroke: 10, + flankLength: 4, + minimumDriveTime: 0.30, + minimumRecoveryTime: 0.020, + minimumTimeBetweenImpulses: 0.007, + flywheelInertia: 0.015, + maximumStrokeTimeBeforePause: 10.0 } } diff --git a/docs/Architecture.md b/docs/Architecture.md index f8dd5c0e7d..0c8e9c1417 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -1,7 +1,7 @@ -# Open Rowing Monitor architecture +# OpenRowingMonitor 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. +In this document, we describe the architectual construction of OpenRowingMonitor. For the reasons behind the physics, please look at [the Physics behind OpenRowingMonitor](Physics_Of_OpenRowingMonitor.md). In this document we describe the main functional blocks in OpenRowingMonitor, and the major design decissions. ## Platform choice @@ -13,9 +13,138 @@ We have chosen to use Raspian as OS, as it is easily installed by the user, it p 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 +## Main functional components and flow between them -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: +OpenRowingMonitor consists out of several isolated functional blocks, some even being their own thread, all communicating through `server.js`. Each functional block has its own manager, maging the entire functional block. In describing OpenRowingMonitor's main architecture, we distinguish between the dataflow and the controleflow. The latter typically is handled by the manager of the section. + +We first describe the main data flows. Next, relation between these main functional components by describing the flow of the key pieces of information in more detail: the flywheel and heartrate measurements, as well as the command structure. + +### Introduction: main data flow + +At the highest level, we recognise the following functional components, with their primary dataflows: + +```mermaid +flowchart LR +A(GpioTimerService.js) -->|currentDt| B(server.js) +B(server.js) -->|currentDt| D(SessionManager.js) +subgraph RowingEngine + D(SessionManager.js) -->|currentDt| N(RowingStatistics.js) + N(RowingStatistics.js) -->|currentDt| O(Rower.js) + O(Rower.js) -->|currentDt| P(Flywheel.js) + P(Flywheel.js) -->|Flywheel metrics| O(Rower.js) + O(Rower.js) -->|Rowing metrics| N(RowingStatistics.js) + N(RowingStatistics.js) -->|Rowing metrics| D(SessionManager.js) +end +D(SessionManager.js) -->|Rowing metrics| B(server.js) +B(server.js) -->|Rowing metrics| E(PeripheralManager.js) +C(PeripheralManager.js) -->|Workout plan| B(server.js) +B(server.js) -->|Workout plan| D(SessionManager.js) +C(PeripheralManager.js) -->|Heart rate data| B(server.js) +E(PeripheralManager.js) -->|Heart rate data| E(PeripheralManager.js) +subgraph peripherals + E(PeripheralManager.js) -->|Rowing metrics + HR Data| F(ANT+ clients) + E(PeripheralManager.js) -->|Rowing metrics + HR Data| G(BLE clients) + E(PeripheralManager.js) -->|Rowing metrics + HR Data| Q(MQTT clients) +end +B(server.js) -->|currentDt| H(RecordingManager.js) +B(server.js) -->|Rowing metrics| H(RecordingManager.js) +B(server.js) -->|Heart rate data| H(RecordingManager.js) +subgraph Recorders + H(RecordingManager.js) -->|currentDt| I(raw recorder) + H(RecordingManager.js) -->|Rowing metrics| J(tcx-recorder) + H(RecordingManager.js) -->|Heart rate data| J(tcx-recorder) + H(RecordingManager.js) -->|Rowing metrics| K(FIT-recorder) + H(RecordingManager.js) -->|Heart rate data| K(FIT-recorder) + H(RecordingManager.js) -->|Rowing metrics| L(RowingData recorder) + H(RecordingManager.js) -->|Heart rate data| L(RowingData recorder) +end +B(server.js) -->|Rowing metrics| M(WebServer.js) +B(server.js) -->|Heart rate data| M(WebServer.js) +subgraph clients + M(WebServer.js) -->|Rowing metrics + HR Data| R(Client.js) +end +``` + +Here, *currentDt* stands for the time between the impulses of the sensor, as measured by the pigpio in 'ticks' (i.e. microseconds sinds OS start). The `GpioTimerService.js` is a small functional block that feeds the rest of the application. + +Key element is that consuming functional blocks (clients) always will filter for themselves: the RowingEngine essentially transforms *currentDt*'s into useable rowing metrics, and attach flags onto them in the `metricsContext` object contained in the metrics. This context allows clients to act upon states that are specifically relevant to them (like the start of the drive, the start of a session, etc.), while ignoring updates that are irrelevant for them. + +### Timing behaviour + +Accurate time keeping and on-time data processing are crucial for OpenRowingMonitor to function well. To realize this, there are several blocks recognized: + +* The **extreme low latency measurement process**: in essence, this is the `GpioTimerService.js` which measures with nanoseconds accuracy, requiring an extremely low latency. Frustrating this process will lead to measurement noise, requiring this process to run on quite an agressive NICE-level. This part of the application is kept deliberatly small to reduce overhead. On data intensive machines, this can produce a (*currentDt*) measurement every 2 miliseconds. +* The **high frequency metrics calculation**: in essence, this is `server.js` and the `RowingEngine`. Although processing isn't too time-critical per se, not having processed a *currentDt* before the next measurement arrives can frustrate the `GpioTimerService.js`. Setting the NICE-level too agressive will frustrate `GpioTimerService.js` as it easily consumes a lot of CPU cycles from it. Therefore, this part still is considered time critical but it can (and should) run on a more relaxed NICE-level compared to the `GpioTimerService.js`, but more agressive than regular processes. Please realise that the use of Theil-Sen estimators causes a significant CPU-load, making this the most CPU-intensive part of OpenRowingMonitor. As the `RowingEngine` will produce a set of metrics as a response to each *currentDt*, it will produce metrics every 2 milliseconds. +* The **non-time critical parts** of OpenRowingMonitor. Specificallythese are the recorders and the peripherals. Missing data for a couple of milliseconds will not be problematic here. To reduce CPU-load, in-session these will only filter the data and do heavy processing only when really needed, preferably after the session. These blocks recieve a message every 4 milliseconds, but peripherals typicall broadcast around 500 milliseconds, and recorders will typically record around every 2500 milliseconds. + +Heartrate data is typically reported every 1000 milliseconds. + +To put it more visually: + +```mermaid +flowchart LR +A(GpioTimerService.js) -->|currentDt, every 2 ms| B(server.js) +B(server.js) -->|currentDt, every 2 ms| D(RowingEngine) +D(RowingEngine) -->|Rowing metrics, every 2ms| B(server.js) +B(server.js) -->|Rowing metrics, every 2ms| E(PeripheralManager.js) +B(server.js) -->|Rowing metrics, every 2ms| H(RecordingManager.js) +B(server.js) -->|Rowing metrics, every 2ms| M(WebServer.js) +``` + +> [!NOTE] +> An avenue for further improvement is to isolate the `GpioTimerService.js` process on a dedicated CPU, to prevent other processes from interfering with its timing. + +> [!NOTE] +> To further reduce CPU load, an option would be to move the non-time critical parts (i.e. the GUI, recorders and peripherals) into seperate processes, with their own (more relaxed) NICE-level. + +### Command flow + +All functional blocks have a 'manager', which expose a `handleCommand()` function, which respond to a defined set of commands. The function call parameters and the commands that can be recieved are identical to all managers, and they are expected to handle/ignore all commands. + +These commands are explicitly restricted to external user actions (i.e. inputs via the web-interface or a peripheral). In essence, this is a user of external session control (via direct input, Bluetooth, ANT+ or MQTT) dictating behaviour of OpenRowingMonitor as an external trigger. Effects of metrics upon a session-state (i.e. session start or end based on a predefined session end) should be handled via the metrics updates. Adittionally, effects upon a session state as a result of a command (i.e. session ends because of a command) should also be handled via the metrics updates whenever possible. These manual commands are connected as follows: + +```mermaid +sequenceDiagram + participant webServer.js + participant PeripheralManager.js + participant server.js + participant SessionManager.js + participant RecordingManager.js + PeripheralManager.js-)server.js: command
(interrupt based) + webServer.js-)server.js: command
(interrupt based) + server.js-)RecordingManager.js: command
(interrupt based) + server.js-)PeripheralManager.js: command
(interrupt based) + server.js-)webServer.js: command
(interrupt based) + server.js-)SessionManager.js: command
(interrupt based) + SessionManager.js-)server.js: Metrics Update
(interrupt based) + server.js-)RecordingManager.js: Metrics Update
(interrupt based) + server.js-)PeripheralManager.js: Metrics Update
(interrupt based) + server.js-)webServer.js: Metrics Update
(interrupt based) +``` + +Both the `webServer.js` and `PeripheralManager.js` can trigger a command. Server.js will communicate this command to all managers, where they will handle this as they see fit. The following commands are defined: + +| command | description | Relvant manager behaviour | +|---|---|---| +| updateIntervalSettings | An update in the interval settings has to be processed. Here the `data` parameter has to be filled with a valid workout object in JSON format | The `SessionManager` will ingest it and use it to structure the workout (see its description). The `fitRecorder` will inject it in the recording | +| start | start of a session initiated by the user. As the true start of a session is actually triggered by the flywheel, which will always be communicated via the metrics, its only purpose is to make sure that the flywheel is allowed to move. This command is routinely sent at the start of a ANT+ FE-C communication. | The `SessionManager` will activate a stopped workout. All other managers will ignore the command, but will obey the `SessionManager`'s response. | +| startOrResume | User forced (re)start of a session. As the true start of a session is actually triggered by the flywheel, its only purpose is to clear the flywheel for further movement. This is not used in normal operation, but can functionally change a 'stopped' session into a 'paused' one. Intended use is to allow a user to continue beyond pre-programmed interval parameters as reaching them results in a session being 'stopped'. | The `SessionManager` will reactivate a stopped workout. All other managers will ignore the command, but will obey the `SessionManager`'s resonse. | +| pause | User/device forced pause of a session (pause of a session triggered from the flywheel will always be triggered via the metrics) | The `SessionManager` will pause an an active workout. All other managers will ignore the command, but will obey the `SessionManager`'s response. | +| stop | User/device forced stop of a session (stop of a session triggered from the flywheel will always be triggered via the metrics) | The `SessionManager` will stop the active workout. All other managers will ignore the command, but will obey the `SessionManager`'s response. | +| reset | User/device has reset the session | All managers will respond by closing the session decently and subsequently resetting their state to the initial state | +| switchBlePeripheralMode | User has selected another BLE device from the GUI | The `peripheralManager` will effectuate this, the rest of the managers will ignore this | +| switchAntPeripheralMode | User has selected another ANT+ device from the GUI | The `peripheralManager` will effectuate this, the rest of the managers will ignore this | +| switchHrmMode | User has selected another heartrate device | The `peripheralManager` will effectuate this, the rest of the managers will ignore this | +| refreshPeripheralConfig | A change in heartrate, BLE or ANT+ device has been performed by the `peripheralManager` | The WebServer/GUI will refresh the current config from the settings manager, the rest of the managers will ignore this | +| upload | A request from the GUI is made to upload the recordings that are set to upload manually | `recordingManager` will handle this request. | +| shutdown | A shutdown is requested, also used when a part of the application crashes or the application recieves a 'SIGINT' | All managers will respond by closing the session decently and closing hardware connections | + +> [!NOTE] +> To guarantee a decent closure of data, a 'stop' command from the user will be ignored by `RecordingManager.js` and `PeripheralManager.js`. The `SessionManager.js` will respond with a new set of metrics, with the 'isSessionStop' flag embedded. On a 'shutdown' command, `RecordingManager.js` and `PeripheralManager.js` do respond by closing their datastreams as if a session-stop was given, to ensure a decent closure. + +### Rowing metrics flow + +We first follow the flow of the flywheel data, which is provided by the interrupt driven `GpioTimerService.js`. The only information retrieved by OpenRowingMonitor is *CurrentDt*: the time between impulses. This data element is transformed in meaningful metrics in the following manner: ```mermaid sequenceDiagram @@ -23,61 +152,140 @@ sequenceDiagram participant pigpio participant GpioTimerService.js participant server.js + participant SessionManager.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) + server.js-)SessionManager.js: currentDt
(interrupt based) + SessionManager.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) + RowingStatistics.js-->>SessionManager.js: Metrics Updates
(interrupt based) + SessionManager.js-)server.js: Metrics Updates
(interrupt based/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. +The clients (both the webserver and periphals) are updated based on the updates of metrics. OpenRowingMonitor 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 `SessionManager.js` to provide a steady stream of updated metrics as it monitors the timers, session state and guarantees that it can present the clients with the freshest data available. It is the responsibility of the clients themselves to act based on the metric updates, and guard against their internal timers. If a broadcast has to be made periodically, say ANT+ updates every 400ms, the ANT+-peripheral should buffer metrics and determine when the broadcast is due. This is needed as more complex broadcast patterns, like the PM5 which mixes time and event based updates, are too complex to manage from a single point. + +A key thing to realize is that `SessionManager.js` will process *currentDt* values and it will transform them into one or more *metricsUpdate* messages. Especially at the end of a lap or split, a single *currentDt* value can result in multiple *metricsUpdate* messages as the `SessionManager.js` will interpolate between distances/times to exactly hit the lap/split end, generating an extra message. Also, when the pause timer is running, a message will be broadcast every second to signal this. When the `SessionManager.js`'s watchdog acts upon an unexpected stop of the *currentDt* flow, spontanuous messages will appear to signal this as well. To enable this behaviour, the message based structure used by `SessionManager.js` is needed. + +Part of the metrics is the metricsContext object, which provides an insight in the state of both stroke (determined in `RowingStatistics.js`) and session (determined in `SessionManager.js`), allowing the clients to trigger on these flags. The following flags are recognised: + +| Flag | Meaning | +|---|---| +| isMoving | Rower is moving | +| isDriveStart | Current metrics are related to the start of a drive | +| isRecoveryStart | Current metrics are related to the start of a recovery | +| isSessionStart | Current metrics are related to the start of a session | +| isIntervalEnd | Current metrics are related to the end of an session interval. An interval implies that there will be no stop of the rowing session between the current and next interval unless there is an intended (temporary) rest period in the session after the interval. If a rest is specified (the flywheel is intended to stop), a "isPauseStart" is indicated as well. | +| isSplitEnd | Current metrics are related to the end of a session split. | +| isPauseStart | Current metrics are related to the start of a session pause. This implies that the flywheel is intended to stop after this message (interval with a forced rest period), or actually has stopped (spontanuous pause). | +| isUnplannedPause | Indication by the sessionManager that the metrics are inside a spontanuous pause if set to 'true'. Used to distinguish between a planned and unplanned pause by the PM5 emulator. | +| isPauseEnd | Current metrics are related to the end of a session pause, implying that the flywheel has started to move again. This is **NOT** sent upon completion of a planned rest period, as the pause is only eneded after the flywheel to reaches its minimum speed again. To identify if the SessionManager is still blocking metrics due to the pause still being active, check if the `pauseCountdownTime` is equal to 0. | +| isSessionStop | Current metrics are related to the stop of a session (i.e. this will be the last meaningful metrics update). | + +State driven clients, like the PM5 interface and the file recorders, will react to these flags by recording or broadcasting when these flags are seen. Please note that several flags can be raised at the same time (for example isDriveStart, isSessionStart and isIntervalStart, but also isIntervalStart and isDriveStart), requiring the consumers to handle these overlapping situations. + +### Heartrate data flow Secondly, the heartrate data follows the same path, but requires significantly less processing: ```mermaid sequenceDiagram - participant clients participant heartrateMonitor + participant PeripheralManager.js 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) + participant webServer.js + participant RecordingManager.js + heartrateMonitor-)PeripheralManager.js: heartrate data
(interrupt based) + PeripheralManager.js-)PeripheralManager.js: heartrate data
(interrupt based) + PeripheralManager.js-)server.js: heartrate data
(interrupt based) + server.js-)webServer.js: heartrate data
(interrupt based) + server.js-)RecordingManager.js: heartrate data
(interrupt based) ``` -### pigpio +> [!NOTE] +> The `PeripheralManager.js` will internally also distribute heartrate updats to data consuming ANT+ and BLE peripherals. + +### Key components in data generation + +#### 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*. +`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 OpenRowingMonitor. Latency in this process will present itself as noise in the measurements of *CurrentDt*. -### GpioTimerService.js +#### 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. +`GpioTimerService.js` is a small independent worker thread, 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 OpenRowingMonitor it provides a stream of measurements that needed to be handled. -### Server.js +#### 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. +* Recieve (interrupt based) GPIO timing signals from `GpioTimerService.js` and send them to the `SessionManager.js`; +* Recieve (interrupt based) Heartrate measurements and sent them to the all interested clients; +* Recieve the metrics update messages from `SessionManager.js` (time-based and state-based updates of metrics) and distribut them to the webclients and periphials; +* Handle user input (through webinterface and periphials) and instruct all managers to act accordingly; + +#### SessionManager.js + +`SessionManager.js` recieves *currentDt* updates, forwards them to `RowingStatistics.js` and subsequently recieves the resulting metrics. Based on state presented, it updates the finite state machine of the sessionstate and the associated metrics. In a nutshell: + +* `SessionManager.js` maintains the session state, thus determines whether the rowing machine is 'Rowing', or 'WaitingForDrive', etc., +* `SessionManager.js` maintains the workout intervals, guards interval and split boundaries, and will chop up the metrics-stream accordingly, where `RowingStatistics.js` will just move on without looking at these artifical boundaries. +* `SessionManager.js` maintains the summary metrics for the entire workout, the current interval, and the current split. + +In total, this takes full control of the displayed metrics in a specific workout, interval and split (i.e. distance or time to set workout segment target, etc.). + +##### session, interval and split boundaries in SessionManager.js + +The `handleRotationImpulse` function of the `SessionManager.js` implements guarding the boundaries of the workoutplan. The session manager maintains three levels in a workoutplan: -### RowingStatistics.js +* The overall session: which is derived by summarising the intervals, and provides a general context for all overall statistics +* The planned interval(s), which can be programmed via the PM5 and MQTT interface, this defaults to 'jutrow' when no data is provided +* Underlying splits, dividing up a planned interval. Splits default to the entire interval when not provided. -`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.). +> [!NOTE] +> Unplanned rests are adminstered as rest splits, allowing them to be easily isolated from active parts of the training. The tcx and fit recorder explicitly distinguish between active and rest laps. -#### sessionStates in RowingStatistics.js +This setup is needed to maintain compatibility with the several outputs, where the PM5 emulation and FIT-data recording are the most dominant. The PM5 can be programmed to have a workout with intervals of a different length/type, but also have a single distance with underlying splits. In practice, using the default behaviour of splits 'inheriting' parameters from the interval, this all translates to being able to always report on the level of splits toi the PM5 interface. The fit-recorder divides a session into laps, where each lap (i.e. split) can be associated with a workoutstep (i.e. interval), again making the split the key element being reported. -`RowingStatistics.js` maintains the following sessionstates: +Schematically, a session is constructed as follows: + + + + + + + + + + + + + + + + + + + + + + +
Session
Interval 1Interval 2Interval 3
Split 1Split 2Split 3Split 4Split 5Split 6RestSplit 7
+ +OpenRowingMonitor will always report the ending of a split, interval and session, and the last message in the split/interval/session will be flagged with a isSplitEnd/isIntervalEnd/isSessionStop flag. Ending an interval will also end the split, raising both flags. Please note that the [PM5 peripheral](./PM5_Interface.md) has a different approach and that difference is handled by the PM5 peripheral itself. + +> [!NOTE] +> The state transitions for the end of an interval and the end of a session (i.e. no next interval) are flagged individually as the resulting metrics updates differ slightly, and the expected behaviour of all other managers is different (especially as recorders and peripherals will stop the workout). + +##### sessionStates in SessionManager.js + +The `handleRotationImpulse` function of the `SessionManager.js` also implements all the state transitions regarding the sessionstates: ```mermaid stateDiagram-v2 @@ -89,33 +297,35 @@ stateDiagram-v2 strokeState=Recovery --> strokeState=Drive strokeState=Recovery --> strokeState=Recovery } - Rowing --> Paused: strokeState
is 'WaitingForDrive' + Rowing --> Paused: strokeState is 'WaitingForDrive'
OR
Next interval is of 'rest' type Paused --> Rowing: strokeState
is 'Drive' - Rowing --> Stopped + Rowing --> Stopped: Last interval completed 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. +> [!NOTE] +> The SessionManager contains a watchdog which will timeout on recieving new *currentDt* values, which forces the state machine into 'Paused' when triggered. This watchdog is needed for specific high drag magnetic rowers that completely stop their flywheel within seconds. + +> [!NOTE] +> A session being 'stopped' can technically be turned into a 'Paused' by sending the 'startOrResume' command to the `handleCommand` function of `SessionManager.js`. Some peripherals send this command routinely. -#### metrics maintained in RowingStatistics.js +#### 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. +`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 associated metrics (i.e. linear velocity, linear distance, power, etc.). The goal is to translate the linear state-dependent rowing metrics from `Rower.js` into meaningful stream of information for the consumers of data. As `Rower.js` can only provide a limited set of absolute metrics at a specific time (as most are stroke state dependent) and is unaware of previous strokes, `RowingStatistics.js` will consume this data and transform it into a consistent and more stable set of metrics useable for presentation. `RowingStatistics.js` also 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` persists metrics to guarantee that they will always reflect the last known valid state to data consumers, removing the need for consumers to understand the effect of stroke state upon metrics validity, * `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` calculates derived metrics (like Calories) and trends (like Calories per hour), -In total, this takes full control of the displayed metrics in a specific interval. +In total, this takes full control of buffering and stabilising the displayed metrics in a specific stroke. -### Rower.js +#### 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 +##### strokeStates in Rower.js `Rower.js` can have the following strokeStates: @@ -133,13 +343,14 @@ stateDiagram-v2 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). +> [!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 +##### 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 `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. @@ -150,6 +361,18 @@ It provides the following types of information: * 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) +### Key components in data dissamination + +#### PeripheralManager + +The Peripheralmanager manages all BLE, ANT+ and MQTT perpherals. It is the source for heartrate data and can also send user commands based on ANT+, BLE or MQTT input. + +#### RecordingManager + +RecordingManager is the base for all recording, recording uploading as well as all normal logging. It acts as a multiplexer over the various recorders, letting the datarecorders decide for themselves how to react to specific metrics and a limited set of relevant commands. The recorders record data according their own rules (fitting with the content they need to generate) and will create a valid file content with accompanying meta-data. + +The RecordingManager also directly manages the uploaders and the filewriter: they take thefile content and its meta-data from a recorder and upload it to a webservice or write it to disk. + ## Major design decissions ### Staying close to *currentDt* @@ -162,18 +385,56 @@ Working with small numbers, and using the impulse time to calculate the angular `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). +Adittional benefit of this approach is that it makes transitions in intervals more smooth: `SessionManager.js` can intersect stroke without causing any pause in metrics (as `Rower.js` and `RowingStatistics.js` keep 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 +### Limits to CPU use + +OpenRowingMonitor allows setting the NICE-level of both the `GpioTimerService.js` worker thread and the main application. We have seen that setting the NICE-level too agressive on a Raspberry Pi 4B (i.e. -7 for `GpioTimerService.js`, and -5 for the main application) results in very decent results (for example, an average GoodnessOfFit of 0.9837 for the recovery slope on a Concept2 RowErg) without any reported issues anywhere and enough CPU cycles to handle the load. + +HOWEVER, when compared to an oracle system (the Concept2 PM5), we see quite a variation in deviation with that result. + +| Distance | Minimal deviation | Average deviation | Maximal deviation | Deviation Spread | +|---|---|---|---|---| +| 5000 meters | 0.70 sec | 1.08 sec | 1.40 sec | 0.70 sec | +| 10000 meters | 0.70 sec | 1.05 sec | 1.40 sec | 0.80 sec | +| 21097 meters | 0.70 sec | 1.08 sec | 1.30 sec | 0.60 sec | + +The deviation spread over 0.8 seconds suggests that measurement is unstable. Reducing the NICE-level too a little less agressive on a Raspberry Pi 4B (i.e. -6 for `GpioTimerService.js`, and -3 for the main application) seems to yield better results. + +### Lack of support for the Raspberry Pi 5 + +Along with the introduction of Raspberry Pi 5, a new GPIO hardware architecture has been introduced, breaking compatibility with `pigpio` (see [issue 52](https://github.com/JaapvanEkris/openrowingmonitor/issues/52)). As discussed there, `pigpio` has strong benefits over competing libraries, specifically + +* the provision of a high resolution measurement +* the possibility to measure on the upward or downward moving flank, or both +* the provision of a built-in debounce filter + +An alternative is the `onoff` library, which was used in OpenRowingMonitor up to version 0.8.2, which does work with the new RPi5 architecture. Although the latter benefits could be moved to `GpioTimerService.js`, the two former benefits can't. Therefore, we decided to wait with moving to onoff until a decent alternative for `pigpio` emerges. + +### Race conditions between commands and metrics + +In specific situations (especially the 'reset' command), the command triggers an update of the metrics by the `SessionManager.js` to close the current sesssion, as well trigger a new metrics update for the new session. As all other managers get the same command around the same time, this is a root cause for race conditions where the 'reset' causes a recorder to complete a session and write the file, and the metrics update will modify it. + +### Structural issues with the PM5 interface and the interal OpenRowingMonitor workout structure + +OpenRowingMonitor's workout structure is similar to Garmin's and many output formats (like the tcx, fit and RowingData formats). However, this approach is different from the PM5 workout structure, leading to a complex interface which statefully has to manage the discrepencies. Key issue is that the concepts of Interval and Split are badly defined in the PM5, and rest periods are not considered independent entities. A key issue is handling unscheduled breaks in a split/interval: the PM5 seems to expect that an interval with a pause still behaves as a single interval. See also the [description of the PM5 interface](./PM5_Interface.md) for more information. + +### Intertwined relation `Flywheel.js` and `Rower.js` regarding stroke state + +`Rower.js` and `Flywheel.js` have an odd intertwined relation: `Flywheel.js` determines the dragfactor, but in order to do that, it needs to know whether it is in a recovery phase, which is determined by `Rower.js`. This technically breaks the dataflow, as processing of the data in `Flywheel.js` becomes dependent on the stroke state determined in `Rower.js` as a resonse to the flywheel state determined in `Flywheel.js`. At its core, dragfactor is a flywheel property, and thus concepually should be positioned in `Flywheel.js`. But from a physics perspective, one can only determine the dragfactor when the stroke state is in recovery. The case can be made that it should be positioned in `Rower.js`, making `Flywheel.js` a conduit only providing angular velocity and angular acceleration. As a side-effect, many calculations that depend on dragfactor (i.e. flywheel torque, etc.) and decissions based upon that (i.e. `isPowered()` and `isUnpowered()`) are also moved to `Rower.js`. This would make `Rower.js` an even stronger concentration of decission logic, without the aid of the current abstractions of `Flywheel.js` to keep the code readable. therefore, it was agreed against it. + +### Use of classes for fundamental datatypes + +OpenRowingMonitor depends a lot on special datatypes, like the `FullTSLinearSeries.js` and `FullTSQuadraticSeries.js` that are the fundamental basis for the physics engine. Unlike some other parts, these have not been converted to a ES6's class-like structure, although their fundamental naure would suggest they should. There are three main reasons for this: -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. +* In JavaScript, a class-like structure is a syntactic modification that does not provide any additional technical benefits, making a change to a class-like structure a pure esthetic excercise. +* The resulting code did not become easier to read. As it would be a purely esthetic excercise, the main argument for implementation would be that the resulting code is easier to understand. Our experience it actually degrades as it results in adding a lot of `this.` to internal variables and making variable scoping more confusing. +* Testing has shown that a side-effect of moving to this new structure is a decrease in performance. As these fundamental datatypes are instantiated and destroyed quite often, having some overhead on this might cause this. But the effect was substatial enough to be measureable, and as it is in a time-critical portion of the application, making this unacceptable. -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: +Although deciding against a class-based notation based on this experiment, we did change the exposure of internal variables (for example, making `fullTSSeries.minimumY()` into `fullTSSeries.Y.minimum()`) and explicitly exported the constructor function, preparing for a final move towards such a setup might the above issues be resolved and improving code readability. -* 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. +### Issues in the physics model -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. +Please see [Physics behind OpenRowingMonitor](physics_openrowingmonitor.md) for some issues in the physics model diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 92122cff90..472ed2f474 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,12 +1,12 @@ -# Contributing Guidelines to Open Rowing Monitor +# Contributing Guidelines to OpenRowingMonitor -Thank you for considering contributing to Open Rowing Monitor. +Thank you for considering contributing to [OpenRowingMonitor](https://github.com/JaapvanEkris/openrowingmonitor). Help is always welcome, and even if you are an absolute beginner in both rowing and coding, you can still help in your own way. -Please read the following sections in order to know how to ask questions and how to work on something. Open Rowing Monitor is a spare time project and by following these guidelines you help me to keep the time for managing this project reasonable. +Please read the following sections in order to know how to ask questions and how to work on something. OpenRowingMonitor is a spare time project where [many have contributed already](attribution.md) and made things possible we never ever dared to dream of. People who contribute are [attributed](attribution.md) and are mentioned in the [release notes](Release_Notes.md) as a way of saying thank you, as OpenRowingMonitor has grown a lot thanks to the community that supports it, and it would never have become what it is now, if it wasn't for these great community contributions and discussions. ## Code of Conduct -All contributors are expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md). I want this to be a place where everyone feels comfortable. Please make sure you are welcoming and friendly to others. +All contributors are expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md). We want this to be a place where everyone feels comfortable. We deeply understand passion for a specific feature, but please be respectfull when other people to contribute their vision as well. Please make sure you are welcoming and friendly to others. ## How can I contribute? @@ -15,15 +15,16 @@ Keep an open mind! There are many ways for helpful contributions, like: * Writing forum posts * Helping people on the forum * Submitting bug reports and feature requests -* Improving the documentation +* Improving the documentation or point out unclear passages +* Testing the app on new machines * Submitting rower profiles / test recordings * Writing code which can be incorporated into the project itself ### Report bugs and submit feature requests -Look for existing issues and pull requests if the problem or feature has already been reported. If you find an issue or pull request which is still open, add comments to it instead of opening a new one. +Look for existing issues and pull requests if the problem or feature has already been reported. If you find an issue or pull request which is still open, please add comments to it instead of opening a new one as it makes seeing the patterns in bad behaviour for us much easier. -Make sure that you are running the latest version of Open Rowing Monitor before submitting a bug report. +Make sure that you are running the latest stable version of OpenRowingMonitor before submitting a bug report. If you report a bug, please include information that can help to investigate the issue further, such as: @@ -31,32 +32,31 @@ If you report a bug, please include information that can help to investigate the * Model of Raspberry Pi and version of operation system * Relevant parts of log messages * If possible, describe a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) +* If relevant and possible, make raw recordings of the rowing session ### Improving the Documentation -The documentation is an important part of Open Rowing Monitor. It is essential that it remains simple and accurate. If you have improvements or find errors, feel free to submit changes via Pull Requests or by filing a bug report or feature request. +The documentation is an important part of OpenRowingMonitor. It is essential that it remains simple and accurate. If you have improvements or find errors, feel free to submit changes via Pull Requests or by filing a bug report or feature request. ### Contributing to the Code -Keep in mind that Open Rowing Monitor is a spare time project which I created to improve the performance of my rowing machine and to experiment with some concepts and technologies that I find interesting. +Keep in mind that OpenRowingMonitor is a spare time project to improve the performance of rowing machines. We intend to keep the code base clean and maintainable, but we will gladly help you add new features to our code. So please realise that contributed code might be refactored before being admitted. Especially we welcome -I intend to keep the code base clean and maintainable by following some standards. I only accept Pull Requests that: - -* Fix bugs for existing functions +* Fixing bugs for existing functions * Enhance the API or implementation of an existing function, configuration or documentation -If you want to contribute new features to the code, please first discuss the change you wish to make via issue, forum, email, or any other method with me before making a change. This will make sure that there is chance of it getting accepted before you spend time working on it. +Academics who use OpenRowingMonitor and improve the math or physics models are more than welcome, and we gladly help you in understanding our setup and discussing your needs, providing that essential improvements in the models will flow back to our codebase. + +If you want to contribute new features or major modifications to the code, please first discuss the change so we can better understand your plans and we can help you place this better in the application. Best way to do this is via an issue or the forum. This will make sure that we all have as much fun in implementing new ideas and people don't spend much time on working on things we need to refactor. #### Standards for Contributions -* Contributions should be as small as possible, preferably one new feature per contribution -* All code should use the [JavaScript Standard Style](https://standardjs.com), if you don't skip the included `git hooks` you should not need to worry about this -* All code should be thoroughly tested -* If possible there should be automated test for your contribution (see the `*.test.js` files; the project uses `uvu`) +* Please thorougly test all code, especially if it requires external devices like smartwatches etc.. +* If possible there should be automated test for your contribution (see the `*.test.js` files; the project uses `uvu`). You can look for inspiration in the [rowing engine directory](https://github.com/JaapvanEkris/openrowingmonitor/tree/main/app/engine) #### Creating a Pull Request -Only open a Pull Request when your contribution is ready for a review. I you want to get feedback on a contribution that does not yet match all criteria for a Pull Request you can open a [Draft pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests). +Only open a Pull Request when your contribution is ready for a review. If you want to get feedback on a contribution that does not yet match all criteria for a Pull Request you can open a [Draft pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests). * Please include a brief summary of the change, mentioning any issues that are fixed (or partially fixed) by this change * Include relevant motivation and context @@ -64,7 +64,7 @@ Only open a Pull Request when your contribution is ready for a review. I you wan * If possible / necessary, add tests and documentation to your contribution * If possible, [sign your commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) -I will review your contribution and respond as quickly as possible. Keep in mind that this is a spare time Open Source project, and it may take me some time to get back to you. Your patience is very much appreciated. +We will review and test your contribution and respond as quickly as possible. Keep in mind that this is a spare time Open Source project, and it may take some time to get back to you. We typically run a lot of tests, which often involves a lot of live rowing, before we accept any code to our main branch, so it typically will take some time before code is accepted. Your patience is very much appreciated. ## Your First Contribution diff --git a/docs/Improving_Raspberry_Performance.md b/docs/Improving_Raspberry_Performance.md index 363b9e6657..a145ce846b 100644 --- a/docs/Improving_Raspberry_Performance.md +++ b/docs/Improving_Raspberry_Performance.md @@ -20,24 +20,18 @@ When installing Open Rowing Monitor, please use a low latency or real time kerne 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): +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 the following option to `/boot/cmdline.txt` (Buster or Bullseye) or `/boot/firmware/cmdline.txt` (Bookworm), 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). +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), [this text](https://forums.raspberrypi.com/viewtopic.php?t=325091), [this text](https://superuser.com/questions/1082194/assign-an-individual-core-to-a-process), [this text](https://raspberrypi.stackexchange.com/questions/61956/can-i-have-1-processor-core-just-for-my-program) and [this text](https://www.cyberciti.biz/tips/setting-processor-affinity-certain-task-or-process.html). ### 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 @@ -70,8 +64,28 @@ To disable triggerhappy, do the following: sudo systemctl disable triggerhappy.service ``` +#### Avahi + +To disable Avahi deamon, do the following: + +```zsh +sudo systemctl disable avahi-daemon.service +``` + +#### nfs-client + +To disable the nfs-client, do the following: + +```zsh +sudo systemctl disable nfs-client.target +``` + +#### others + 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 +Setting AppPrio and gpioPrio. + 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/Integrations.md b/docs/Integrations.md new file mode 100644 index 0000000000..ebdd91adb3 --- /dev/null +++ b/docs/Integrations.md @@ -0,0 +1,274 @@ +# Integrations with other services + + +For services we distinguish between two types of functionality: + +* **Download workout**: here OpenRowingMonitor will fetch the planned workout parameters (target distance, intervals, etc.) from the service before the session and will program the monitor accordingly + +* **Upload results**: here OpenRowingMonitor uploads the result of your rowing session (i.e. total time rowed, pace, stroke rate, etc.) to the service after your session has completed + +Looking at the individual services, we see the following: + +| Service | Download workout plan | Upload results | Remarks | +|---|---|---|---| +| File system | No | Yes | Integrated service | +| Strava | No | Yes | Integrated service | +| RowsAndAll.com | No | Yes | Integrated service | +| Rowingdata | No | Yes | Upoad only, currently requires batch script to import RowingData file | +| Intervals.icu | No | Yes | Integrated service | +| Garmin Connect | No | No | Upoad only, currently requires batch script to upload fit file | +| MQTT | Yes | Yes | Integrated service | + +In the following sections we describe their pro's and con's, as well as their current limitations with OpenRowingMonitor, and how to set it up. + +## File system + +OpenRowingMonitor supports the following exports, which can be obtained via the network share: + +* **Garmin FIT files**: These are binairy files that contain the most interesting metrics of a rowing session. Most modern training analysis tools will accept a FIT-file. You can manually 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; + +* **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 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. + +* **Raw** flywheel measurements of the flywheel, also in CSV files. These files are great to analyse and replay the specifics of your rowing machine (some Excel visualistion can help with this). + +The creation of each of these files is independently controlled via their own parameters in the `config.js`. You can turn on each filetype independently without issue, as OpenRowingMonitor will make sure the names will not be identical, even when the file extension is the same. OpenRowingMonitor can create regular files and gzipped files (which are accepted by several websites) and will write them in the directory specified in the `dataDirectory` parameter of `config.js`. In `config.js`, you can set a parameter to create a file and another parameter to gzip it. The following parameters are available: + +| File type | parameter to create file | parameter to zip file | +|---|---|---| +| Garmin FIT files | createFitFiles | gzipFitFiles | +| Garmin TCX files | createTcxFiles | gzipTcxFiles | +| Rowingdata csv | createRowingDataFiles | - | +| Raw flywheel data | createRawDataFiles | gzipRawDataFiles | + +> [!NOTE] +> To create a gzipped file, you both need to set the both parameters to true. So to create gzipped FIT-files, both the `createFitFiles` and `gzipFitFiles` parameters must be set to true. + +The OpenRowingMonitor installer can 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. + +## Strava + +Uploading your sessions to [Strava](https://www.strava.com) is an integrated feature. The Strava uploader will create and upload the fit-files automatically, and does not require setting the `createFitFiles` parameter. + +This manual is a modified version of [this manual](https://gist.github.com/michaellihs/bb262e2c6ee93093485361de282c242d) and [this manual](https://developers.strava.com/docs/getting-started/#account). + +### Step 1: Create a Strava API + +To use the Starva integration, we first have to create a Strava API Application in Strava. So, first step is to open [https://www.strava.com/settings/api](https://www.strava.com/settings/api) and fill in the following fields as follows: + +* `Application Name` chose whatever name you like, for example 'OpenRowingMonitor' +* `Website` chose whatever website you want to use (needs to be a valid url, e.g. [http://google.com] +* `Callback Domain` any domain name that should be used as a callback, can be 127.0.0.1 + +After you saved your API, you need to upload a image for it. + +Open the [https://strava.github.io/api/v3/oauth/](https://strava.github.io/api/v3/oauth/) page again and copy the following values to a text editor + +* `Client ID` - an ID for your application, used later on to identify your App +* `Secret` - a secret token generated for you (not your OAuth Token!) + +### Step 2: Generate a refresh token + +Open the following URL (replace `CLIENT_ID` with the Client ID you wrote down earlier): + +```HTML +https://www.strava.com/oauth/authorize?client_id=CLIENT_ID&response_type=code&redirect_uri=http%3A%2F%2Flocalhost&scope=activity:write&state=mystate&approval_prompt=force +``` + +Make sure to check the option to upload workouts in the screen popping up before you hit the 'authorize' button. + +Your browser will redirect, but will fail as the URL is local. However, in the URL that was called, there is an element that says 'code=xxxxxx'. Write down that code. + +On your Raspberry Pi, open the shell, and put in the following command (here you need to replace `CLIENT_ID`, `CLIENT_SECRET` and `CODE` with the values you wrote down in the previous steps): + +```shell +curl -X POST https://www.strava.com/oauth/token -F client_id=CLIENT_ID -F client_secret=CLIENT_SECRET -F code=CODE +``` + +curl will respond with a JSON-object. In that JSON-object, you'll find the `refresh_token`. Write that down, as we need it for the settings. + +### Step 3: Setting up Strava in OpenRowingMonitor + +Part of the user specific parameters in `config/config.js` are the Strava settings. So in the user settings, you need to add the following (here you need to replace `CLIENT_ID`, `CLIENT_SECRET` and `refresh_token` with the values you have written down in the previous steps: + +```js + // Configuration for the Strava uploader + strava: { + allowUpload: true, + autoUpload: false, + clientId: 'CLIENT_ID', + clientSecret: 'CLIENT_SECRET', + refreshToken: 'refresh_token' + }, +``` + +The parameter 'allowUpload' allows uploads in general (so disabling it will block all forms of uploading). The parameter 'autoUpload" determines if your workout is uploaded at the end of the session. If you set 'autoUpload' to false, but 'allowUpload' to true, you need to push the upload button on the screen to trigger the upload (making uploading a manual step). + +## RowsAndAll.com + +[RowsAndAll](https://rowsandall.com/) provides the most extensive on-line data analysis environment for rowing. Our RowingData export is made in collaboration with them, and provides the most extensve dataset OpenRowingMonitor can provide. + +The RowsAndAll.com uploader will create and upload the RowingData-files automatically, and does not require setting the `createRowingDataFiles` parameter. Uploading is activated by adding the API-key (which can be found in your [import settings of you user profile](https://rowsandall.com/rowers/me/exportsettings/)) and setting `AllowUpload` to true in the user profile of `config.js`: + +```js + // Configuration for the RowsAndAll.com upload + rowsAndAll: { + allowUpload: true, + autoUpload: false, + apiKey: '' + }, +``` + +The parameter `allowUpload` allows uploads in general (so disabling it will block all forms of uploading). The parameter `autoUpload` determines if your workout is uploaded at the end of the session. If you set `autoUpload` to false, but `allowUpload` to true, you need to push the upload button on the screen to trigger the upload (making uploading a manual step). + +> [!NOTE] +> 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 + +## Rowingdata + +[RowingData](https://pypi.org/project/rowingdata/) is an app that can be installed on your Raspberry Pi, allowing you to automatically have an analysis platform as well. + +## Intervals.icu + +Uploading of fit-files to [Intervals.icu](https://intervals.icu/) is an integrated service. The Intervals.icu uploader will create and upload the FIT-files automatically, and does not require setting the `createFitFiles` parameter. + +The Intervals.icu uploader is activated by adding the athlete-Id and API-key (which can be found in your [settings of you user profile](https://intervals.icu/settings)) and setting `allowUpload` to true in the user profile of `config.js`: + +```js + // Configuration for the intervals.icu upload + intervals: { + allowUpload: true, + autoUpload: false, + athleteId: '', + apiKey: '' + } +``` + +The parameter `allowUpload` allows uploads in general (so disabling it will block all forms of uploading). The parameter `autoUpload` determines if your workout is uploaded at the end of the session. If you set `autoUpload` to false, but `allowUpload` to true, you need to push the upload button on the screen to trigger the upload (making uploading a manual step). + +## Garmin Connect + +Uploading to [Garmin Connect](https://connect.garmin.com) can be done by uploading the fit-file via [python-garminconnect](https://github.com/cyberjunky/python-garminconnect/tree/master) and a batch script. + +## MQTT + +To publish real-time metrics to a MQTT broker, like a home automation system, you need to add the following to your config.js: + +```js + mqtt: { + mqttBroker: '', + username: '', + password: '', + machineName: '' + }, +``` + +Here, the `mqttBroker` is the ip/internet adress of the broker (without the protocol descriptor, so for example `broker.emqx.io`), and the `username` and `password` are the ones you use to log in on that broker. + +The `machineName` is an element that is used to identify your monitor uniquely in your MQTT environment. + +### Recieving metrics + +The topic 'OpenRowingMonitor/`machineName`/metrics' will contain your metrics. Each completed stroke results in one message, initiated at the beginning of the drive. At the begin/end of splits, intervals and sessions an additional message will be sent. Flags indicate the rowing machine state and all associated metrics. + +| Field | Meaning | Unit | +|---|---|---| +| timestamp | The timestamp of the creation of the metrics | JSON timestamp | +| intervaltype | The type of the current interval | `justrow`, `distance`, `time` or `rest` | +| sessionStatus | | | +| strokeState | | | +| isMoving | Flag indicating the rowing machine is moving | Boolean | +| isDriveStart | Flag indicating the message is sent at the beginning of the drive. As the MQTT typically sends this message at the start of the drive, expect this to be true 99% of the time | Boolean | +| isRecoveryStart | Flag indicating the message is sent at the beginning of the recovery. This should be extremely rare. | Boolean | +| isSessionStart | Flag indicating the message is sent at the beginning of a rowing session. | Boolean | +| isPauseStart | Flag indicating the message is sent at the beginning of a pause. | Boolean | +| isPauseEnd | Flag indicating the message is sent at the end of a pause. | Boolean | +| isSessionStop | Flag indicating the message is sent at the end of a session | Boolean | +| totalNumberOfStrokes | | Counter | +| totalMovingTime | | Seconds | +| totalDistance | | Meters | +| totalCalories | | kCal | +| splitNumber | | Counter | +| heartrate | | Beats per minute | +| velocity | | m/s | +| pace | | sec/500m | +| power | | Watts | +| driveDuration | | milliseconds | +| driveLength | | Meters | +| recoveryDuration | | milliseconds | +| strokeDuration | | milliseconds | +| strokeRate | | strokes per minute| +| distancePerStroke | | Meters | +| peakHandleForce | Maximum encountered force during the drive | Newtons | +| averageHandleForce | Average handle force during the drive | Newtons | +| forceCurve | Handle force during the drive | Newtons over drive length | +| velocityCurve | Velocity of the handle during the drive | m/s over drive length | +| powerCurve | Velocity of the handle during the drive | Watts over drive length | +| dragFactor | | 10-6 N\*m\*s2 | + +### Pushing workouts + +In the topic 'OpenRowingMonitor/`machineName`/workoutplans' you can push your workoutplan in stringified JSON format. + +> [!NOTE] +> Workoutplans are only accepted before a session, not during one. + +For example: + +```js +[ + { + "type": "distance", + "targetDistance": "5000", + "targetTime": "0", + "split": { + "type": "distance", + "targetDistance": "500", + "targetTime": "0" + } + } +] +``` + +Will create a session that will stop at exactly 5000 meters, and will create a split every 500 meters. + +> [!NOTE] +> Please observe that a workoutplan will always have to be an array (square brackets). This allows the use of multiple sequential intervals. After completing the last interval, the session will be stopped. + +Valid values for type are: + +* `justrow`: an endless session that will not stop unless you stop rowing. If you like an undetermined cooldown after a session, this is recomended as last interval. +* `distance`: creates an interval that will end at a specified distance. This requires the `targetDistance` to be greater than 0 meters. +* `time`: creates an interval that will end at a specified time. This requires the `targetTime` to be greater than 0 seconds. +* `rest`: creates an rest interval with a minumum duration of `targetTime` seconds. PLease note, duing a rest interval, no metrics will be recorded. + +Splits are optional elements. It will allow a session to be split up into smaller pieces for analysis purposes. In OpenRowingMonitor, intervals and splits do not have to be of the same type. So one can have time based splits in a distance based interval. Please observe that in the transition from one interval to the next, splits are reset. + +So an alternative session is the following: + +```js +[ + { + "type": "time", + "targetTime": "120" + }, + { + "type": "rest", + "targetTime": "60" + }, + { + "type": "distance", + "targetDistance": "2000", + "split": { + "type": "distance", + "targetDistance": "500" + } + }, + { + "type": "justrow" + } +] +``` + +This will create a session that starts with a 120 seconds warmup interval, followed by at least 60 seconds rest, then a 2K, followed by an indefinite cooldown. diff --git a/docs/PM5_Interface.md b/docs/PM5_Interface.md new file mode 100644 index 0000000000..f19ba14545 --- /dev/null +++ b/docs/PM5_Interface.md @@ -0,0 +1,353 @@ +# Description of the PM5 interface + +The design goal is to emulate PM5 communication sufficiently for users to connect easily to apps. We aim to have maximum compatibility with all these apps, making these apps to intuitively to use with OpenRowingMonitor. However, it explicitly is **NOT** our goal to completely emulate a full-blown PM5 with racing features and logbook verification. Also features that might lead to cheating or uploading results to the Concept2 logbook are explicitly excluded. Some testing is one on ErgData, as that is the definitive source how Concept2's data is to be interpreted, excluding interpretation errors by independent software developers. + +This interface emulation is partially based on the description in Concept 2's API documentation ([[1]](#1) and [[2]](#2)). As this documentation is inconclusive about the timing/triggers for messages, as well as the exact definition of the values used, a large part is also based on analysis of the communication via recorded bluetooth traces with current PM5's. + +## Design target for interoperability + +We aim to be interoperable with the following apps: + + +| App | Required characteristics                    | Remarks | +| --- | --------- | ------ | +| [ErgArcade cloud simulation](https://ergarcade.github.io/mrdoob-clouds/) |
  • [0x0031 "General Status"](#0x0031-general-status)
  • [0x0032 "Additional Status"](#0x0032-additional-status)
| | +| [ErgArcade fluid simulation](https://ergarcade.github.io/WebGL-Fluid-Simulation/) |
  • [0x0031 "General Status"](#0x0031-general-status)
| Actually only uses `STROKESTATE_DRIVING` | +| Ergometer space | Does not subscribe to anything, seems to respond to [0x0031 "General Status"](#0x0031-general-status) | Sends a lot of outdated CSAFE commands which will be ignored by OpenRowingMonitor | +| [EXR](https://exrgame.com/) |
  • [CSAFE Commands](#csafe-commands)
  • [0x0031 "General Status"](#0x0031-general-status)
  • [0x0032 "Additional Status"](#0x0032-additional-status)
  • [0x0033 "Additional Status 2"](#0x0033--additional-status-2)
  • [0x0035 "Stroke Data"](#0x0035-stroke-data)
  • [0x0036 "Additional Stroke Data"](#0x0036-additional-stroke-data)
  • [0x003d "Force Curve data"](#0x003d-force-curve-data)
| EXR will only create `WORKOUTTYPE_FIXEDDIST_NOSPLITS` and `WORKOUTTYPE_FIXEDTIME_NOSPLITS` workouts via 'verified C2 workouts' | +| [ErgZone](https://erg.zone/) |
  • [CSAFE Commands](#csafe-commands)
  • [0x0031 "General Status"](#0x0031-general-status)
  • [0x0032 "Additional Status"](#0x0032-additional-status)
  • [0x0033 "Additional Status 2"](#0x0033--additional-status-2)
  • [0x003e "Additional Status 3"](#0x003e-additional-status-3)
  • [0x0035 "Stroke Data"](#0x0035-stroke-data)
  • [0x0036 "Additional Stroke Data"](#0x0036-additional-stroke-data)
  • [0x003d "Force Curve data"](#0x003d-force-curve-data)
  • [0x0037 Split Data](#0x0037-split-data)
  • [0x0038 Additional Split Data](#0x0038-additional-split-data)
  • [0x0039 "Workout Summery"](#0x0039-workout-summery)
  • [0x003a "Additional Workout Summary"](#0x003a-additional-workout-summary)
  • [0x003f "Logged Workout"](#0x003f-logged-workout)
| | +| [KinoMap](https://www.kinomap.com) |
  • [0x0031 "General Status"](#0x0031-general-status)
  • [0x0032 "Additional Status"](#0x0032-additional-status)
  • [0x0033 "Additional Status 2"](#0x0033--additional-status-2)
  • [0x003e "Additional Status 3"](#0x003e-additional-status-3)
  • [0x0035 "Stroke Data"](#0x0035-stroke-data)
  • [0x0036 "Additional Stroke Data"](#0x0036-additional-stroke-data)
  • [0x003d "Force Curve data"](#0x003d-force-curve-data)
  • [0x0037 Split Data](#0x0037-split-data)
  • [0x0038 Additional Split Data](#0x0038-additional-split-data)
  • [0x0039 "Workout Summery"](#0x0039-workout-summery)
  • [0x003a "Additional Workout Summary"](#0x003a-additional-workout-summary)
| | +| [Regatta](https://teamregatta.com/) |
  • [0x0031 "General Status"](#0x0031-general-status)
  • [0x0032 "Additional Status"](#0x0032-additional-status)
  • [0x0033 "Additional Status 2"](#0x0033--additional-status-2)
| | + + +Some apps, like Aviron, Ergatta, Hydrow, iFIT and Peleton claim compatibility with a PM5, and theoretically should work. As we could not test them ourselves due to regional/device limitations, we do not consider them a design target. + +## Structural differences between OpenRowingMonitor and a PM5 + +As OpenRowingMonitor and PM5 have been independently developed, the design choices that have been made are not consistent. Here we adress these differences, as they are quite essential in the further implementation. + +### Workout Hierarchy + +OpenRowingMonitor recognizes three levels in a workout: the Session, the underlying Intervals and the Splits in these Intervals (see [the architecture document](./Architecture.md#session-interval-and-split-boundaries-in-sessionmanagerjs) for a more detailed description). A PM5 recognizes either a workout with one or more Intervals of varying length, or a single workout with several underlying splits with identical length. Some apps (ErgZone) even optimize workouts with multiple identical intervals to a workout with splits. + +The [CsafeManagerService.js](../app/peripherals/ble/pm5/csafe-service/CsafeManagerService.js) therefore will map: + +* a fixed time/distance PM5 workout to a single OpenRowingMonitor Interval, and add the specified splits as OpenRowingMonitor splits if specified. +* A PM5 workout with multiple intervals to multiple OpenRowingMonitor Intervals, without any splits specified (as they can't be specified by the PM5). + +This makes scoping of many variables challenging as it is unclear whether a variable is intended to capture a split or the interval. Concept2's ambiguous description of most variables in [[1]](#1) and [[2]](#2) does not provide any clarification here. + +[workoutSegment.js](../app/engine/utils/workoutSegment.js)'s default behaviour with missing split information helps here to overcome the structural issues. When split nformation is mising, it 'inherits' the split parameters of the above interval (in essence making the split boundaries identical to the interval). This makes the splits always contain the most granular division of the workout regardless of how the PM5 has communicated the workout. In reporting back to the app, the splits are thus the most likely basis for reporting in the PM5 emulated reporting. However, some variables seem to be scoped to the interval or workout level. A key reason for conducting the traces is to understand the scoping of each variable. + +### Positioning split/interval reporting + +OpenRowingMonitor will always report on the end-of-split boundary, including a summary of the split it just completed. A PM5 will report this **after** the split has concluded (i.e. in tje mew split), reporting about the split it has completed. + +### Positioning planned rest intervals + +OpenRowingMonitor treats planned rest intervals similar to normal time based intervals, with the exception that the rowing engine is forced to stop collecting metrics during that interval. A PM5 considers a rest interval a subordinate attribute of a normal interval, and it isn't an independent entity. In [CsafeManagerService.js](../app/peripherals/ble/pm5/csafe-service/CsafeManagerService.js) this is managed by adding a rest interval to OpenRowingMonitor's workout schedule. + +In reporting, we indeed see the PM5 skipping the split/interval reporting when the pause starts, and including the rest data with the split reporting after the pause has ended. This is consistent with the approach that a rest interval only is an extension of an active interval. In OpenRowingMonitor this behaviour is replicated by not reporting the start of a pause as new split, and combining the data from the active split and the rest split. Although the underlying datasets are largely disjunct (as rest intervals have little data associated with them), a key issue is the reporting of the IntervalType, WorkoutState and workoutDurationType in [0x0031 General Status](#0x0031-general-status), and the intervalType [0x0037 "Split Data"](#0x0037-split-data). + +In starting a pause our traces show that message [0x0031 General Status](#0x0031-general-status)'s 'IntervalType' is set from `IntervalTypes.INTERVALTYPE_DIST` to `IntervalTypes.INTERVALTYPE_REST`. [0x0037 "Split Data"](#0x0037-split-data)'s 'IntervalType' reports an `IntervalTypes.INTERVALTYPE_DIST`. For the GeneralStatus message, the workout target clearly contains an element of OpenRowingMonitor's 'sessionState' object (i.e. verify if the sessionState is paused). + +### Positioning unplanned rests + +People might deviate from their workout plan and take a break mid-session. In OpenRowingMonitor this is treated as a seperate rest split, clearly separating active and passive metrics. The PM5 essentially ignores the pause, lets time continue and does not change split/interval upon detection. + +### Different definition of moving time and rest time + +There is a subtle, but significant, difference in the definitions used for timekeeping. OpenRowingMonitor registers moving time and rest time as it occurs, registering the time spent moving and the time spent resting. A PM5 registers time as it is **intended** to be spent, so it only registers planned pause intervals as rest time, and it actually considers unplanned rest as moving time. The effect is that, despite OpenRowingMonitor internally reporting time spent in unplanned rest splits as rest time, the PM5 considers it moving time. It is the PM5's interface's responsibility to adapt to this definition. + +## CSAFE Commands + +Most CSAFE Commands implemented in [CsafeManagerService.js](../app/peripherals/ble/pm5/csafe-service/CsafeManagerService.js) in conjunction with the [C2toORMMapper.js](../app/peripherals/ble/pm5/utils/C2toORMMapper.js). OpenRowingMonitor essentially only implements the commands it needs to recieve workouts. + +### Workout Mapping + +Out primary goal for supporting CSAFE commands is recieving workout plans. A workout is typically a combination of one or more strings of commands. Typically it follows the following pattern + +```js +CSAFE_PM_SET_WORKOUTINTERVALCOUNT +CSAFE_PM_SET_WORKOUTTYPE +CSAFE_PM_SET_INTERVALTYPE +CSAFE_PM_SET_WORKOUTDURATION +CSAFE_PM_SET_RESTDURATION +CSAFE_PM_CONFIGURE_WORKOUT +``` + +Each string of commands represents an interval. It is always closed with `CSAFE_PM_SET_SCREENSTATE`, followed by `SCREENVALUEWORKOUT_PREPARETOROWWORKOUT`. + +| Concept2 Workout Type | General idea | Interval | Splits | +| --- | --- | --- | --- | +| WORKOUTTYPE_JUSTROW_NOSPLITS | A simple unlimited session | single interval, type = 'justrow' | Undefined[^1] | +| WORKOUTTYPE_JUSTROW_SPLITS | A simple unlimited session with splits | single interval, type = 'justrow' | Fixed 'time' or 'distance' | +| WORKOUTTYPE_FIXEDDIST_NOSPLITS | A simple distance session | single interval, type = 'distance' | Undefined[^1] | +| WORKOUTTYPE_FIXEDDIST_SPLITS | A simple distance session with splits | single interval, type = 'distance' | Fixed 'distance' | +| WORKOUTTYPE_FIXEDTIME_NOSPLITS | A simple time limited session | single interval, type = 'time' | Undefined[^1] | +| WORKOUTTYPE_FIXEDTIME_SPLITS | A simple time limited session with splits | single interval, type = 'time' | Fixed 'time' | +| WORKOUTTYPE_FIXEDTIME_INTERVAL | An unlimited repeating time based interval | repeating intervals, type = 'time'[^2] | Undefined[^1] | +| WORKOUTTYPE_FIXEDDIST_INTERVAL | An unlimited repeating distance based interval | repeating intervals, type = 'distance'[^2] | Undefined[^1] | +| WORKOUTTYPE_VARIABLE_INTERVAL | A series of different variable intervals | multiple intervals | Fixed 'time' or 'distance' per interval | +| WORKOUTTYPE_VARIABLE_UNDEFINEDREST_INTERVAL | Not implemented | Not implemented | Not implemented | +| WORKOUTTYPE_FIXEDCALORIE_SPLITS | Not implemented | Not implemented | Not implemented | +| WORKOUTTYPE_FIXEDWATTMINUTE_SPLITS | Not implemented | Not implemented | Not implemented | +| WORKOUTTYPE_FIXEDCALS_INTERVAL | Not implemented | Not implemented | Not implemented | + +> [!NOTE] +> Please be aware that apps like ErgData and ErgZone actually do 'optimisations' behind the scene. Three intervals of 8 minutes with 2 minute rests are typically sent as a `WORKOUTTYPE_FIXEDTIME_INTERVAL`, despite this resulting in an endless series. If the planned rests are omited, it will result in a `WORKOUTTYPE_FIXEDTIME_SPLITS` with a single time interval with splits of the length of the intervals. If one would add a single second to any of the individual intervals, it becomes a `WORKOUTTYPE_VARIABLE_INTERVAL`, and all intervals are programmed manually. Obviously, from a user perspective the target displayed in the GUI will vary across these options (see [issue 118](https://github.com/JaapvanEkris/openrowingmonitor/issues/118)). + +[^1]: Due to default behaviour of the WorkoutSegments object, the split defaults to the interval type and length by inheriting its parameters +[^2]: Due to the beforementioned structural issues, this can only be imitated. As Concept2's PM5 will only allow 50 splits (see [[2]](#2)), we'd expect receiving apps to maintain the same limit. Based on the presence of rest intervals, this will either be 50 working intervals or 25 working intervals interleaved with 25 rest intervals + +## Message grouping and timing + +Based on the Bluetooth trace we can group the messages as well as identify their trigger. This grouping is implemented in the [Pm5RowingService.js](../app/peripherals/ble/pm5/rowing-service/Pm5RowingService.js). + +### Time driven status updates + +On every broadcast interval, the following messages are sent: + +* [0x0031 "General Status"](#0x0031-general-status), +* [0x0032 "Additional Status"](#0x0032-additional-status), +* [0x0033 "Additional Status 2"](#0x0033--additional-status-2) +* [0x003e "Additional Status 3"](#0x003e-additional-status-3) + +### Event Driven messages + +#### End of the drive + +* [0x0035 "Stroke Data"](#0x0035-stroke-data) +* [0x0036 "Additional Stroke Data"](#0x0036-additional-stroke-data) +* [0x003d "Force Curve data"](#0x003d-force-curve-data) + +#### End of the recovery + +* [0x0035 "Stroke Data"](#0x0035-stroke-data) + +#### End of Split + +* [0x0037 Split Data](#0x0037-split-data) +* [0x0038 Additional Split Data](#0x0038-additional-split-data) + +#### End of Workout + +* [0x0039 "Workout Summery"](#0x0039-workout-summery) +* [0x003a "Additional Workout Summary"](#0x003a-additional-workout-summary) +* [0x003f "Logged Workout"](#0x003f-logged-workout) + +### Planned pause behaviour + +#### Entering a rest interval + +When antering a rest interval, no specific messages are sent. However, our trace shows that: + +* message [0x0031 General Status](#0x0031-general-status)'s 'IntervalType' is set from `IntervalTypes.INTERVALTYPE_DIST` to `IntervalTypes.INTERVALTYPE_REST`. This element thus should depend on the OpenRowingMonitor's 'sessionState' object. +* message [0x0031 General Status](#0x0031-general-status)'s 'WorkoutState' is set from `WorkoutState.WORKOUTSTATE_INTERVALWORKDISTANCE` to `WorkoutState.WORKOUTSTATE_INTERVALREST`. +* message [0x0031 General Status](#0x0031-general-status)'s 'totalWorkDistance' is increased with the total linear distanceof the ative interval. This suggests that the totalWorkDistance is the absolute startpoint that is maintained in the WorkoutSegment. +* message [0x0032 "Additional Status"](#0x0032-additional-status)'s 'Rest Time' will start counting down from its starting point to 0. + +#### Metrics behaviour during a rest interval + +The "Elapsed Time" is stopped counting. + +Despite being entered on apps as an attribute of an interval, the PM5 reports a rest period as an independent interval. As soon as the rest interval starts, the interval number is increased and the previous split time and distance are transferred to their respected fields. + +#### Exiting a rest interval + +When exiting a rest interval, a lot of messages are sent: + +* [0x0035 "Stroke Data"](#0x0035-stroke-data), with essentially all values set to 0 +* [0x0036 "Additional Stroke Data"](#0x0036-additional-stroke-data), with essentially all values set to 0 +* [0x0031 "General Status"](#0x0031-general-status) +* [0x0032 "Additional Status"](#0x0032-additional-status) +* [0x0033 "Additional Status 2"](#0x0033--additional-status-2) +* [0x003e "Additional Status 3"](#0x003e-additional-status-3) +* [0x0037 "Split Data"](#0x0037-split-data) +* [0x0038 "Additional Split Data"](#0x0038-additional-split-data) + +### Unplanned pause behaviour + +An unplanned rest/pause is essentially ignored. Time continues, but almost no specific flags are set. + +#### Entering an unplanned rest + +#### Metrics behaviour during unplanned pauses + +The "Elapsed Time" continues. + +The interval number wil **NOT** change during or after the rest period. + +During an unplanned pause, instant metrics will remain their last known good value. They will not be zero'd, which is OpenRowingMonitor's default behaviour (and the correct representation of the machine state). + +It is observed that upon entering the unplanned pause, the lastSplit data from [0x0038 "Additional Split Data"](#0x0038-additional-split-data) is in fact updated with the last state from the active split. + +#### Exiting an unplanned rest + +No specific messages are sent, apart from the obvious ['End of the recovery' messages](#end-of-the-recovery). There are no markings of the end of a split. On the subsequent split boundary, the [0x0037 "Split Data"](#0x0037-split-data) message registers the extra time as part of the "Elapsed time", **not** as "Rest time" which is part of the same message (stays 0). In message [0x0038 "Additional Split Data"](#0x0038-additional-split-data), Average split strokerate, Average split power, Average split speed and average split pace also include the rest period. + +## Specific field behaviour + +### Elapsed time + +According to the documentation ([[1]](#1) and [[2]](#2)), messages [0x0031 "General Status"](#0x0031-general-status), [0x0032 "Additional Status"](#0x0032-additional-status), [0x0033 "Additional Status 2"](#0x0033--additional-status-2), [0x0035 "Stroke Data"](#0x0035-stroke-data), [0x0036 "Additional Stroke Data"](#0x0036-additional-stroke-data), [0x0037 "Split Data"](#0x0037-split-data) and [0x0038 "Additional Split Data"](#0x0038-additional-split-data) all contain the 24 bit element "Elapsed Time", with a 0.01 second precission. + +The recorded Bluetooth trace shows that: + +* the timer isn't active before any movement has commenced, defaults and starts at 0 +* At an interval rollover, this timer is reset to zero, +* At a split rollover, the timer is **NOT** reset but continues. +* The timer is stopped as soon as the session is paused based on a **planned** pause. +* The timer continues on an unplanned pause. + +This behaviour seems to vary between the behaviour of variables `metrics.interval.timeSpent.moving` (especially planned pause behaviour) and `metrics.interval.timeSpent.total` (especially unplanned pause behaviour). The easiest mapping is to `metrics.interval.timeSpent.total`, as it naturally continues during pauses and thus doesn't cause a discontinues change in the timer for a normal split rollover. Stopping the `metrics.interval.timeSpent.total` timer during a planned pause can easily be arranged in [ORMtoC2Mapper.js](../app/peripherals/ble/pm5/utils/ORMtoC2Mapper.js)'s `appendPauseIntervalToActiveInterval` function which is used in this scenario. As a planned pause always ends in an interval rollover, the "Elapsed time' timer is always reset and any discontinuous timer issues will not become visible. + +### Distance + +Similar to Elapsed time, messages [0x0031 "General Status"](#0x0031-general-status), [0x0035 "Stroke Data"](#0x0035-stroke-data) and contain [0x0037 "Split Data"](#0x0037-split-data) the 24 bit element "Distance", with a 0.1 meter precission. We also see + +* the distance isn't active before any movement has commenced, defaults and starts at 0 +* distance being fixed in a pause +* distance is reset upon crossing the interval boundary +* distance continues when crossing a split boundary + +Thus, this is best mapped to `metrics.interval.distance.fromStart`. + +### Stroke numbering + +The messages [0x0035 "Stroke Data"](#0x0035-stroke-data) and [0x0036 "Additional Stroke Data"](#0x0036-additional-stroke-data) contain the stroke number, which behaves as follows: + +* restarts at the end of an interval +* continues when crossing a split + +Thus, this is best mapped to `metrics.interval.numberOfStrokes`. + +### Split numbering + +This is sementically a challenged parameter. The messages [0x0033 "Additional Status 2"](#0x0033--additional-status-2), [0x0037 "Split Data"](#0x0037-split-data), [0x0038 "Additional Split Data"](#0x0038-additional-split-data) all contain the `interval count`. Its use is far from consistent: + +In message [0x0033 "Additional Status 2"](#0x0033--additional-status-2): + +* `interval count` initializes it at 0, +* is increased when either the split/interval changes, +* is increased when moving from an active to a rest interval +* It does not **not** change on an unplanned rest interval + +However, [0x0037 "Split Data"](#0x0037-split-data), [0x0038 "Additional Split Data"](#0x0038-additional-split-data) are sent **after** the split rollover and report about the metrics of the previous split, but uses the `interval count` of the **current interval** (i.e. it is increased and starts reporting about split 1, skipping split 0 in its reporting structure). To manage this, we introduce the `metrics.split.C2number`, as it can skip the effects of unplanned pauses. + +Message [0x003a "Additional Workout Summary"](#0x003a-additional-workout-summary) contains the total number of intervals, which is similar to the number reported in [0x0037 "Split Data"](#0x0037-split-data), [0x0038 "Additional Split Data"](#0x0038-additional-split-data). + +## Definition of individual messages + +### Time based status messages + +Message implementations can be found in the [status-characteristics directory](.../app/peripherals/ble/pm5/rowing-service/status-characteristics). + +#### 0x0031 "General Status" + +Messsage 0x0031 "General Status" is implemented in [GeneralStatusCharacteristic.js](../app/peripherals/ble/pm5/rowing-service/status-characteristics/GeneralStatusCharacteristic.js), with most flags being set in [ORMtoC2Mapper.js](../app/peripherals/ble/pm5/utils/ORMtoC2Mapper.js). Some notes: + +* As described in [elapsed time](#elapsed-time), `Elapsed time` will be mapped to `metrics.interval.timeSpent.moving` +* As described in [distance](#distance)), `distance` will be mapped to `metrics.interval.distance.fromStart` +* The `Workout state` + * starts at `WorkoutState.WORKOUTSTATE_WAITTOBEGIN`, + * changes to `WorkoutState.WORKOUTSTATE_WORKOUTROW` for an active fixed time/distance workout with splits, + * changes to `WorkoutState.WORKOUTSTATE_INTERVALWORKDISTANCE` for an active distance based interval that is part of a multi-interval session + * changes to `WorkoutState.WORKOUTSTATE_INTERVALWORKDISTANCETOREST` for marking the transition from an active interval to a planned rest interval + * changes to `WorkoutState.WORKOUTSTATE_INTERVALREST` for a planned rest interval + * changes to `WorkoutState.WORKOUTSTATE_WORKOUTEND` for marking the end of the workout + * does **not** change when entering an unplanned rest split. +* The `Total work distance` is initialized at 0, and only increased at the end of the interval to reflect the total linear distance travelled so far by the previous intervals. This is best represented by `metrics.interval.distance.absoluteStart` +* The `Workout Duration` is set to the intended length of the current interval (thus ignoring previous interval lengths). The `Workout Duration` is linked to other metrics, thus forcing that these fields must have the same frame of reference (i.e. time/distance in interval and interval target): + * When the `interval type` is 'distance', `Workout Duration` is the length in meters, captured by `metrics.interval.distance.target`. On a 'distance' based interval, the difference between `workout duration` and `distance` is shown on ErgData as a countdown timer. + * When the `interval type` is 'time', `Workout Duration` is a time in 0.01sec precission, best reflected by `metrics.interval.movingTime.target` On a 'time' based interval, the difference between `workout duration` and `elapsed time` is shown on ErgData as a countdown timer on most screens. +* Dragfactor is reset per interval + +#### 0x0032 "Additional Status" + +[0x0032 "Additional Status"](../app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatusCharacteristic.js), + +* As described in [elapsed time](#elapsed-time), `Elapsed time` will be mapped to `metrics.interval.timeSpent.moving` +* As the context suggests that the intention is to produce the actual (i.e. not averaged across a split) metrics, we use `metrics.cycleLinearVelocity`, `metrics.cycleStrokeRate`, `metrics.heartrate`, `metics.cyclePace` and `metrics.cyclePower`. +* For the 'average' pace, it is unclear whether this is intended at the split or interval level. We choose to use the `metrics.interval.pace.average` as we suspect it is used to show on ErgData's overview of average pace, which is only reset at the interval boundary, not the split boundary. Our data analysis of the broadcaste data seem to support this. +* The variable 'Rest time' seems to map to `metrics.pauseCountdownTime`, as it seems to be used to display the countdown timer during pauses. Our data analysis of messages supporta that it counts down during a planned pause. + +> [!NOTE] +> During unplanned pauses, a PM5 continues to broadcast the last known metrics. As none of the apps (ErgZone, EXR, etc.) act based on these metrics, for example by inserting a pause, we choose to have the metrics reflect the true state of the rowing machine, thus deviating from PM5 behaviour. We do this because it better reflects the state of the rowing machine to consuming apps that might not subscribe to all characteristics (especially towards apps like EXR which use 0x0032 to determine pace and strokerate, and thus where visuals will keep going on), and it makes data mappings less complex. + +#### 0x0033 "Additional Status 2" + +See the implementation here: [0x0033 "Additional Status 2"](../app/peripherals/ble/pm5/rowing-service/status-characteristics/AdditionalStatus2Characteristic.js), + +* As described in [elapsed time](#elapsed-time), `Elapsed time` will be mapped to `metrics.interval.timeSpent.moving` +* As descibed in [Interval count](#split-numbering), the `interval count` will be mapped to `metrics.split.C2number` +* `Split average power` is initialized at 0 +* `Total calories` is initialized at 0, and increases across splits, but is reset to 0 at interval rollovers, this suggests it is scoped at the interval. +* The specifications ([[1]](#1) and [[2]](#2)) contain an error. The `Last Split Time` element has an accuracy of 0.01 seconds, similar to the `Elapsed Time` data element, instead of the described 0.1 sec accuracy. `Last Split Time` will be initialised at 0, and after each split transition is updated to contain the final time of the last split for 'distance' based splits. +* The `Last split distance` is initialized at 0, and remains 0 for distance based splits. + +#### 0x003e "Additional Status 3" + +### Interupt driven stroke state messages + +Message implementations can be found in the [other characteristics directory](../app/peripherals/ble/pm5/rowing-service/other-characteristics). + +#### 0x0035 "Stroke Data" + +[0x0035 "Stroke Data"](../app/peripherals/ble/pm5/rowing-service/other-characteristics/StrokeDataCharacteristic.js) is sent at the end of both the drive and the recovery + +* As described in [elapsed time](#elapsed-time), `Elapsed time` will be mapped to `metrics.interval.timeSpent.moving` +* As described in [distance](#distance), `distance` will be mapped to `metrics.interval.distance.fromStart` + +#### 0x0036 "Additional Stroke Data" + +[0x0036 "Additional Stroke Data"](../app/peripherals/ble/pm5/rowing-service/other-characteristics/AdditionalStrokeDataCharacteristic.js) is only sent at the end of the drive + +#### 0x003d "Force Curve data" + +The force curve is in pounds (lbs). + +### Interupt driven session state messages + +Message implementations can be found in the [session status characteristics directory](../app/peripherals/ble/pm5/rowing-service/session-characteristics). + +#### 0x0037 "Split Data" + +* As described in [elapsed time](#elapsed-time), `Elapsed time` will be mapped to `metrics.interval.timeSpent.moving` +* As described in [distance](#distance), `distance` will be mapped to `metrics.interval.distance.fromStart` +* As descibed in [Interval count](#split-numbering), the `interval count` will be mapped to `metrics.split.C2number` + +#### 0x0038 "Additional Split Data" + +* As described in [elapsed time](#elapsed-time), `Elapsed time` will be mapped to `metrics.interval.timeSpent.moving` +* As descibed in [Interval count](#split-numbering), the `interval count` will be mapped to `metrics.split.C2number` + +#### 0x0039 "Workout Summery" + +#### 0x003A "Additional Workout Summary" + +* As descibed in [Interval count](#split-numbering), the `total number of intervals` will be mapped to `metrics.split.C2number` + +#### 0x003f "Logged Workout" + +## Known limitations, open Issues + +### Elapsed time indication on apps and OpenRowingMonitor GUI will deviate + +Apart from the obvious time delay in data representation, apps (like ErgZone) and OpenRowingMonitor's GUI will not show the same overall time if there is an unplanned pause present. This is because OpenRowingMonitor will always work on `metrics.Interval.timeSpent.moving`, whereas the PM5 will essentially present `metrics.Interval.timeSpent.total`. These two will deviate when an unplanned pause is present, as Concept2's definitions will still consider it part of the moving time and OpenRowingMonitor considers it a pause (as [mentioned earlier](#different-definition-of-moving-time-and-rest-time). Key issue is that we can not make the external apps follow OpenRowingMonitor's approach as that breaks their synchronisation with their workout plan. + +Our approach with inserting an additional split has significant benefits in other area's, like keeping the FIT and RowingData recorders implementation clean. It also allows a far better data analysis as rest periods are clearly and consistently marked, regardless whether they were planned or not, allowing them to be filtered or included easily. This allows for a decent performance analysis even when an unplanned pause was needed, as averages aren't muddled by rest periods. + +### Unplanned rest periods muddle metrics + +In Concept2's logic, metrics are averaged across the split, including unplanned rest periods. Metrics like average pace, average stroke rate, average power, etc. thus get averaged with periods of inactivity. The benefit is that metrics appear consistent: a split with an unplanned pause looks longer, and thus average pace should be lowered to look consistent. + +However, this can have weird effects. For example, the average pace (or average stroke rate or power) can go below the observed minimum pace in that split. As this is a flaw in Concept2's logic, and OpenRowingMonitor emulates this behaviour in this interface, we will not resolve this. + +As the FIT-recorder independently records its data, and does respect OpenRowingMonitors' approach of explicitly seperating active from passive periods, these metrics will become inconsistent in their reporting. As the FIT-recorder is much closer to OpenRowingMonitor's native implementation, and the seperation is done based on native flags, the FIT-metrics are considered more accurate. + +## References + +[1] Concept 2 PM5 Bluetooth Smart Interface Specification, Revision 1.30, 3/2/2022 + +[2] Concept2 PM CSAFE Communication Definition, Revision 0.27, 8/8/2023 diff --git a/docs/README.md b/docs/README.md index 6563cf8a79..8e966a84bd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,27 +1,31 @@ -# Open Rowing Monitor +# OpenRowingMonitor -[![Node.js CI](https://github.com/laberning/openrowingmonitor/actions/workflows/node.js.yml/badge.svg)](https://github.com/laberning/openrowingmonitor/actions/workflows/node.js.yml) -[![CodeQL](https://github.com/laberning/openrowingmonitor/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/laberning/openrowingmonitor/actions/workflows/codeql-analysis.yml) -[![pages-build-deployment](https://github.com/laberning/openrowingmonitor/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/laberning/openrowingmonitor/actions/workflows/pages/pages-build-deployment) +[![Node.js CI](https://github.com/JaapvanEkris/openrowingmonitor/actions/workflows/node.js.yml/badge.svg)](https://github.com/JaapvanEkris/openrowingmonitor/actions/workflows/node.js.yml) +[![CodeQL](https://github.com/JaapvanEkris/openrowingmonitor/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/JaapvanEkris/openrowingmonitor/actions/workflows/codeql-analysis.yml) - +OpenRowingMonitor logo -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. +OpenRowingMonitor is a reliable, free and open source monitor for rowing machines. It allows you to upgrade any rowing machine into a smart trainer that can be used with applications and games, making rowing much more fun and affordable! -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 runs on cheap (Raspberry Pi) hardware to calculate rowing metrics, such as power, split time, speed, stroke rate, distance and calories. As it is your data, you can share these metrics with games and analysis in the way you like. -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. +OpenRowingMonitor runs fine on any rowing machine, as long as you can add something to measure the speed of the flywheel, like magnets. It already has been retrofitted to many rowing machines like the [DIY Openergo](https://openergo.webs.com) and many [existing machines that lack a decent monitor](Supported_Rowers.md), and is used by many on a daily basis. If your machine isn't listed, don't worry, adjusting the settings is easy following the [settings adjustment help guide](rower_settings.md) yourself. And in the [GitHub Discussions](https://github.com/JaapvanEkris/openrowingmonitor/discussions) there always are friendly people to help you set up your machine and the settings. ## Features -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. +OpenRowingMonitor can provide you with metrics directly, via smartwatches (ANT+), apps and games (bluetooth) and Home Automation (MQTT). It also allows you to export your data to the analysis tool of your choice. + + +Image showing the main OpenRowingMonitor screen
+ +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 in the configuration file, where we also provide these settings for machines known to us. +OpenRowingMonitor calculates the typical metrics of a rowing machine, where the parameters can be tuned to the specifics of a rower machine by changing the configuration file. We maintain [settings for machines alrrady known to us](Supported_Rowers.md). The underlying software is structurally validated against a Concept2 PM5 in over 300 sessions (totalling over 3 million meters), and results deviate less than 0.1% for every individual rowing session. -Open Rowing Monitor displays the following key metrics on the user interfaces: +OpenRowingMonitor can display the following key metrics on the user interface: * Distance rowed (meters) * Training Duration @@ -31,66 +35,75 @@ Open Rowing Monitor displays the following key metrics on the user interfaces: * Calories used (kcal) * Total number of strokes * Heart Rate (supports BLE and ANT+ heart rate monitors, ANT+ requires an ANT+ USB stick) +* Drag factor +* Drive duration (seconds) +* Drive length (meters) +* Recovery duration (seconds) +* Distance per stroke (meters) +* Force curve with Peak power (Newtons) -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. +It calculates and can export many other key rowing metrics, including Recovery Heart Rate, 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 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 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. +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) in realtime. You can set up the user interface as you like, with the metrics you find important: -
+Image showing the metrics selection screen
-### Bluetooth Low Energy (BLE) +Via the Action tile, it can also be used to reset the training metrics and to select the type of bluetooth and ANT+ connection. -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: +If you connect a (optional) 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. -* **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/). +### Device connections via Bluetooth, ANT+ and MQTT -* **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). +OpenRowingMonitor can recieve heartrate data via Bluetooth Low Energy (BLE) and ANT+. But you can also share your rowing metrics with different applications and devices. We support most common industry standards to help you connect to your app and game of choice, OpenRowingMonitor currently supports the following protocols: -* **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**: OpenRowingMonitor can simulate a Concept2 PM5, providing compatibility with most rowing apps. This implements the most common parts of the spec, so it might not work with all applications. It is known to work with [EXR](https://www.exrgame.com) (preferred method), [ErgZone](https://Erg.Zone), [Kinomap](https://www.kinomap.com) and all the samples from [The Erg Arcade](https://ergarcade.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. +* **FTMS Rower**: This is the FTMS profile for rowing machines and supports all rowing specific metrics (such as stroke rate). We've successfully tested it with [EXR](https://www.exrgame.com), [Peleton](https://www.onepeloton.com/app), [MyHomeFit](https://myhomefit.de) and [Kinomap](https://www.kinomap.com). -* **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+ FE-C**: OpenRowingMonitor can broadcast rowing metrics via ANT+ FE-C, which can be recieved by several series of Garmin smartwatches like the Epix/Fenix series, which then can calculate metrics like training load etc.. -### Export of Training Sessions +* **FTMS Indoor Bike**: This FTMS profile is used by Smart Bike Trainers and widely adopted by bike training apps. 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 :-) -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: +* **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. -* **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; +* **BLE Cycling Speed and Cadence Profile**: used for older Garmin Forerunner and Garmin Venu watches and similar types, again simulating a bike activity. -* **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; +* **MQTT**: this IoT protocol allows you to broadcast metrics for logging or real-time display, but also allows for integration with Home Automation systems like [Home Assistant](https://www.home-assistant.io/), [Domiticz](https://www.domoticz.com/) and Alexa Voice control via [HABridge](https://github.com/bwssytems/ha-bridge). -* **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). +> [!NOTE] +> Use of ANT+ requires adding an ANT+ USB-stick to your Raspberry Pi. -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. +### Export of Training Sessions -## Installation +OpenRowingMonitor is based on the idea your metrics should be easily accessible for further analysis on data platforms. Automatic uploading your sessions to [RowsAndAll](https://rowsandall.com/), [Intervals.icu](https://intervals.icu/) and [Strava](https://www.strava.com) is an integrated feature. For other platforms this is currently a manual step, see [the integration manual](Integrations.md). To allow the data upliad, OpenRowingMonitor can create the following file types: -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: +* **RowingData** files, which are comma-seperated files with all metrics OpenRowingMonitor 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; -```zsh -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/laberning/openrowingmonitor/HEAD/install/install.sh)" -``` +* **Garmin FIT files**: These are binairy files that contain the most interesting metrics of a rowing session. Most modern training analysis tools will accept a FIT-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; -Also have a look at the [Detailed Installation Instructions](installation.md) for more information on the software installation and for instructions on how to connect the rowing machine. +* **Training Center XML files (TCX)**: These are legacy XML-files that contain the most essential metrics of a rowing session. Most training analysis tools will still accept a tcx-file (although FIT usually is recomended). 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; -## How it all started +The OpenRowingMonitor 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 -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. +You will need a Raspberry Pi Zero 2 W, Raspberry Pi 3, Raspberry Pi 4 with a fresh installation of Raspberry Pi OS Lite for this (the 64Bit kernel is recomended). Connect to the device with SSH and just follow the [Detailed Installation Instructions](installation.md) and you'll get a working monitor. This guide will help you install the software and explain how to connect the rowing machine. If you can follow the guide, it will work. If you run into issues, you can always [drop a question in the GitHub Discussions](https://github.com/JaapvanEkris/openrowingmonitor/discussions), and there always is someone to help you. -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 :-) +> [!IMPORTANT] +> Due to architecture differences, both the Raspberry Pi Zero W (see [this discussion for more information](https://github.com/JaapvanEkris/openrowingmonitor/discussions/33)) and Raspberry Pi 5 (see [this discussion for more information](https://github.com/JaapvanEkris/openrowingmonitor/issues/52)) will **not** work. + +> [!TIP] +> Don't have a Raspberry Pi, but do have an ESP32 lying about? No problem, our sister project ported [OpenRowingMonitor for the ESP32](https://github.com/Abasz/ESPRowingMonitor), which works well (although it is a bit less accurate due to platform limitations). ## Further information -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. +This project is in a very stable stage, as it is used daily by many rowers, and the engine is structurally validated against the Concept2 PM5. OpenRowingMonitor is tested extensively for weeks before being released to mainstream users. However, it might contain some things that are still a bit rough on the edges. -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. +This is a larger team effort and OpenRowingMonitor had much direct and indirect support by many people during the years, see the [Attribution to these people here](attribution.md). You can see its development throughout the years [here in the Release notes](Release_Notes.md). Our work is never done, so more functionality will be added in the future, so check the [Development Roadmap](backlog.md) if you are curious. -Check the advanced information on the [Physics behind Open Rowing Monitor](physics_openrowingmonitor.md). +Contributions to improve OpenRowingMonitor further are always welcome! To get an idea how this all works, you can read the [Archtecture description](Architecture.md), the [Physics of OpenRowingMonitor (for advanced readers)](physics_openrowingmonitor.md) and [Contributing Guidelines](CONTRIBUTING.md) how you can help us improve this project. -This project uses some great work by others, see the [Attribution here](attribution.md). +Feel free to leave a message in the [GitHub Discussions](https://github.com/JaapvanEkris/openrowingmonitor/discussions) if you have any questions or ideas related to this project. diff --git a/docs/Release_Notes.md b/docs/Release_Notes.md new file mode 100644 index 0000000000..8057662a44 --- /dev/null +++ b/docs/Release_Notes.md @@ -0,0 +1,132 @@ +# OpenRowingMonitor Release Notes + +## Version 0.9.6 (June 2025) + +Main contributors: [Abasz](https://github.com/Abasz) and [Jaap van Ekris](https://github.com/JaapvanEkris) + +Beta testers: [fkh-bims](https://github.com/fkh-bims), [jryd2000](https://github.com/jryd2000) and [carlito1979](https://github.com/carlito1979) + +### Upgrade instructions for 0.9.6 + +> [!IMPORTANT] +> When upgrading from an existing install, several things have to be done by hand: +> +> - If you use an attached screen, you need to install firefox by `sudo apt-get install firefox` +> - If you use the automated Strava upload, you have to configure your Strava setup in `config.js` again. Please look at the [integrations manual](Integrations.md) for how to do this. + +### New functionality in 0.9.6 + +- **Major upgrade of our PM5 interface**, bringing it much closer to the official PM5 interface specification: apps like [ErgZone](https://Erg.Zone), [EXR](https://exrgame.com) and many others now work in PM5 mode in most scenarios (there are [some known limitations](#known-issues-in-096)). This allows you to set up a workout in the session manager with ease, have force curves presented and record the data (adresses [this request](https://github.com/JaapvanEkris/openrowingmonitor/discussions/78)). +- **Added [RowsAndAll.com](https://rowsandall.com) and [intervals.icu](https://intervals.icu) integration** for workout reporting (i.e. automatic uploading of a result). +- **Added a MQTT peripheral**. This reports metrics live to MQTT brokers and control home automation, etc. (see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/43), [this discussion](https://github.com/JaapvanEkris/openrowingmonitor/discussions/80) and [this request](https://github.com/JaapvanEkris/openrowingmonitor/discussions/98)). The MQTT listener you to push workout plans to OpenRowingMonitor from home automation systems (see [the integrations page](Integrations.md) for more information). + +### Bugfixes and robustness improvements in 0.9.6 + +- **Simplified Strava integration**, which now is in line with the rest of the integrations (see [this discussion](https://github.com/JaapvanEkris/openrowingmonitor/discussions/64)) and greatly simplifying the backend-architecture +- **Rewrite of the entire bluetooth stack**, greatly improving stability and removing limitations. This also fixes the issue that heartrate device can't be switched dynamically (adresses [the known limitation of version 0.9.5](#known-issues-in-095), reported in [this bug](https://github.com/JaapvanEkris/openrowingmonitor/issues/69), [this feature request](https://github.com/JaapvanEkris/openrowingmonitor/discussions/93) and [this bug report](https://github.com/JaapvanEkris/openrowingmonitor/issues/94). +- **Fixed a bug in pause behaviour** for magnetic rowers causing them to sttop permanently (fixes [this bug](https://github.com/JaapvanEkris/openrowingmonitor/discussions/96)). +- **Fixed a bug in the metrics presentation**, which caused some metrics presented/recorded to be averaged too much. +- **Fixed a bug in restart behaviour** that made the recorders crash (fixes [this bug](https://github.com/JaapvanEkris/openrowingmonitor/discussions/100)). +- **Upgraded ESLint and its configuration**, our code is inspected beyond the use of spaces. +- **Introducing JSDoc** in our code, to make our code easier to understand ([see also](https://github.com/JaapvanEkris/openrowingmonitor/issues/90)). +- **Upgrade npm packages and node.js**: we cleaned house by removing a lot of unneeded npm packages, upgraded npm packages where we could and upgraded to Node.js v22 (current) to increase support. This makes our stack current and fixes some security vulnerabilities. +- We **moved from Chromium to Firefox** for the webkiosk service as it greatly reduces the CPU load, practically freeing up a complete CPU core. + +### Known issues in 0.9.6 + +- Our PM5 interface still has some minor limitations: + - ErgZone and similar apps also can set a 'Calories' based workout. This interval type is still on [our backlog](./backlog.md#soon), so it currently isn't supported yet. The PM5 interface will fail silently and will **not** send an error message on this. + - ErgData will not work well with our PM5 interface: sometimes it can program OpenRowingMonitor, but you will **not** be able to save your workout, as we can't create the cryptographic hash to upload the workout results. This also causes a deadlock that hangs communication at both ends (kill the ErgData app to resolve this). As ErgData is propriatary to Concept2, we have decided to **not** put in any effort to resolve this (see [issue 117](https://github.com/JaapvanEkris/openrowingmonitor/issues/117)). +- Some Garmin watches have issues with our 'Cycling Power' and 'Cycling Speed and Cadence' Bluetooth profiles as a result of a change on their side in handling unencrypted Bluetooth commmunication. This affects all current and past versions of OpenRowingMonitor, and might be caused by Garmin (see [issue 125](https://github.com/JaapvanEkris/openrowingmonitor/issues/125)). + +## Version 0.9.5 (February 2025) + +Main contributors: [Jaap van Ekris](https://github.com/JaapvanEkris) and [Abasz](https://github.com/Abasz) + +### New functionality in 0.9.5 + +- Added **FIT-File support**: you can now automatically generate a FIT-file after a rowing session, which allows for a more detailed reporting than the tcx-format, and is commonly accepted by most platforms (see [issue 59](https://github.com/JaapvanEkris/openrowingmonitor/issues/59)). +- **Introduction of the session manager**, which provides support for intervals, splits, rest intervals and spontaneous pauses in the session and also adds these to the FIT, tcx and RowingData recordings. Please note, setting predetermined intervals and splits in a user friendly way (via PM5 emulator and webinterface) is still on [our backlog](./backlog.md#soon). +- **Improvement of Magnetic rower support**: the new session manager makes sure that the session is nicely stopped, even when the flywheel has stopped quite abruptly before pause timeouts have time to kick in. This is the case on some magnetic rowers which have an extreme high drag, resulting in very short spin down times of their flywheel. + +### Bugfixes and robustness improvements in 0.9.5 + +- **Improvement of the architecture**: we cleaned up the old architecture and moved to a more message bus structure where clients are responsible for listening to the data transmissions they are interested in. See [the architecture description](Architecture.md) for a deep-dive of the implementation. Key benefit is that this is more maintainable as it allows serving data more easily to totally different clients (webGUI, recorders and BLE/ANT+) with totally different needs, making future enhancements easier. +- **Improvement of Bluetooth stability**: as a temporary fix we moved from abandonware's NoBle/BleNo Bluetooth implementation to stoprocent's implementation, as that package is better maintained and works better with newer installs of BlueZ. This should fix some issues on Raspberry Pi Bookworm. Unfortunately, none of the NoBle/BleNo descendants are immune to some specific BlueZ issues (see [known issues](#known-issues-in-095)). +- **Performance improvement of the TS estimator**, further reducing CPU load, which significantly improves accuracy of the measurements and metrics as the Linux kernel has an easier job keeping the time accurate. +- **Removed a lot of memory leaks**, although only being problematic in large simulations (i.e. over 3000K), we want to keep our code to behave nice +- **Improved robustness of the stroke detection algorithm** + +### Known issues in 0.9.5 + +- **Bluetooth Heartrate can't be switched dynamically**: due to some underlying OS changes, BLE heartrate monitors can't be activated through the GUI without crashing the BLE metrics broadcast (see [the description of issue 69](https://github.com/JaapvanEkris/openrowingmonitor/issues/69)). As this is an issue in the OS, **all current and previous versions of OpenRowingMonitor are also affected by this issue**. Version 0.9.5 has a workaround implemented: configuring the use of a BLE heartrate monitor in the config file should work. However, dynamic switching via the GUI will crash the BLE connections. This issue is resolved in version 0.9.6. + +## Version 0.9.0 (January 2024) + +Main contributors: [Jaap van Ekris](https://github.com/JaapvanEkris), [Abasz](https://github.com/Abasz) and [carlito1979](https://github.com/carlito1979) + +### New functionality in 0.9.0 + +- **Added support for ANT+ rowing metrics broadcast**, allowing the use of smartwatches for recording and analysing workouts. +- **Allow the user to change the GUI layout and metrics**, including displaying the force curve and support for larger screens +- **Allow user to turn on or off ANT+ and BLE functionality** and dynamically switch between ANT+ and BLE HR monitors from the GUI +- **Added the option for more complex workouts**, as an initial hook for the PM5 and webinterface (these are on [our backlog](./backlog.md#soon)) + +### Bugfixes and robustness improvements in 0.9.0 + +- **Added support for the newest version of Raspberry Pi OS (Bookworm)**, moved from Node.js v16 (EOL) to Node.js v20 (current) and upgraded packages where possible. +- **Improved the accuracy, responsiveness and efficiency** of both the Linear and Quadratic Theil-Sen algorithms. For larger 'flankLength' machines, this results in 50% reduction in CPU use, while increasing the responsiveness and accuracy of the resulting forcecurve and powercurve. +- **Drag calculation and recovery slope calculation are more robust against outliers and stroke detection errors** by also moving them to the Linear Theil-Sen algorithm. +- **Added a configuration sanity check** which logs obvious errors and (if possible) repairs settings, after several users messed up their config and got completely stuck. This configuration sanity check also provides an automated upgrade path for 0.8.2 (old config) users to 0.9.0 (new config), as all the newly added configuration items between these two versions are automatically detected, logged and repaired. +- **Added restart limits** to prevent infinite boot loops of the app crashing and rebooting when there is a config error +- **Fixed the GPIO tick rollover**, which led to a minor hickup in data in rows over 30 minutes +- **Made Flywheel.js more robust** against faulty GPIO data +- **Fixed a lot of small memory leaks** which were to untidy closure of dynamic data structures. Although this wasn't encountered in regular training sessions, it did show in long simulations (over 10.000K); +- **Fixed an application crash** in the RowingData generation when the target directory doesn't exist yet; +- **Improved the structure of the peripherals** to allow a more robust BLE and ANT use +- **Validation of the engine against a PM5 for over 3000KM**, where the deviation is a maximum of 0.1% + +### Removed support in 0.9.0 + +- **Support has been dropped for the Raspberry Pi Zero W**, as WebAssembly will not work on Node.js V16 on ArmV6, and other core packages require at least Node V18 to function on newer versions of the Raspberry Pi OS (see [this discussion](https://github.com/JaapvanEkris/openrowingmonitor/discussions/33)) + +## Version 0.8.4 (January 2023) + +Main contributors: [Jaap van Ekris](https://github.com/JaapvanEkris) and [Abasz](https://github.com/Abasz) + +### New Functionality in 0.8.4 + +- **New Metrics**: With the new rowing engine, new metrics are introduced, including Force curve, Peak force, average force, power curve, handle speed curve, VO2Max (early beta), Heart Rate Recovery. All have over 1000 kilometers of testing under their belt, and have shown to work reliably; +- **Added Cycling Power Profile and Cycling Speed/Cadence bluetooth profiles** for compatibility with more smartwatches +- **Improved metrics through BLE FTMS and BLE C2-PM5**: Based on the new engine, many metrics are added to both FTMS Rower and PM5, making them as complete as they can be. Most metrics also have over a 1000 km of testing with EXR, and both types of interface have been used with EXR intensly. +- **New export format**: There is a RowingData export, which can export all metrics in .csv, which is accepted by both RowingData and RowsAndAll. It is also useable for users to read their data into Excel. This export brings the force curve to users, although it will require a small subscription to see it in RowsAndAll; +- **Simpler set-up**: a better out-of-the-box experience for new users. We trimmed the number of required settings, and for many cases we’ve succeeded: several settings are brought down to their key elements (like a minimal handle force, which can be set more easily for all rowers) or can be told by looking at the logs (like the recovery slope). For several other settings, their need to set them perfectly has been reduced, requiring less tweaking before OpenRowingMonitor starts producing good data. To support this, there also is a new setup document, to help users set up their own rower; +- **Switch to 64Bit**: OpenRowingMonitor supports the 64 Bit Lite core, which has a PREEEMPT-kernel. The setup-script accepts this as well, as this should be the preferred kernel to use. The PREEMPT-kernel is optimized for low latency measurements, like IoT applications. As PREEMPT kernels can handle a lot higher priority for the GPIO-thread, this setting has been switched from a binary setting to a priority setting. +- **An initial stub for session mangement**: As a first step towards sessions and splits, a session object in Server.js is added as a placeholder for session targets. If a target is set, it will termintate the session at the exact right time. As is with the PM5, ORM counts down if a target is set. You can't set these targets through the webGUI or through BLE yet. However, it is a first step towards functional completeness as it lays a preliminary foundation for such functionality. + +### Bugfixes and robustness improvements in 0.8.4 + +- **Totally redesigned rowing engine**: Linear and Quadratic Regression models are now the core of the rowing engine, leaving the classical numerical approximation model. The new model is much more robust against noise, and completely removes the need for noise filtering from OpenRowingMonitor. +- **Improved logging**: the logging has been more focussed on helping the user fix a bad setting, focussing on the underlying state of the engine and its settings (for example the drive time and drive length). Goal is to have users be able to tune their engine based on the log. +- **Finite State Machine based state management**: OpenRowingEngine will now maintain an explicit state for the rower, and RowingStatistics will maintain an explicit state for the session. Aside reducing the code complexity significantly, it greatly impoved robustness. +- **Added a new GPIO-library**, making measurement of the flywheel data much more accurate and allowing to "debounce" the measurements, as many sensors have this issue + +## Version 0.8.2 (Febuary 2022) + +Main contributor: [Lars Berning](https://github.com/laberning) + +### New Functionality in 0.8.2 + +- Added Strava support + +## Version 0.8.1 (September 2021) + +Main contributor: [Jaap van Ekris](https://github.com/JaapvanEkris) + +### Bugfixes and robustness improvements in 0.8.1 + +- **Refactoring of the Rowing Engine**, as [Dave Vernooy's engine (ErgWare)](https://dvernooy.github.io/projects/ergware/) is good, but its variable naming left a bit to be desired. The underlying physics has been described in [the physics of OpenRowingMonitor](physics_openrowingmonitor.md), and is largely based on the work of [Dave Vernooy](https://dvernooy.github.io/projects/ergware/) and [Anu Dudhia](http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html). + +## Version 0.7.0 (March 2021) + +Initial release, Main contributor: [Lars Berning](https://github.com/laberning), porting of [Dave Vernooy's ErgWare](https://dvernooy.github.io/projects/ergware/) to JavaScript and addition of Bluetooth. diff --git a/docs/Supported_Rowers.md b/docs/Supported_Rowers.md new file mode 100644 index 0000000000..1c9953dac2 --- /dev/null +++ b/docs/Supported_Rowers.md @@ -0,0 +1,79 @@ +# 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. With some tricks, we can even make it work with machines that can't measure the impellor directly, but you will fall back to the "Static distance" approach. + +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](https://oshwlab.com/jpbpcb/rower2) | Active support | Concept2_Model_C | Yes | Yes | None | See [this](https://github.com/laberning/openrowingmonitor/issues/77), [this](https://github.com/laberning/openrowingmonitor/discussions/38) and [this](https://github.com/laberning/openrowingmonitor/discussions/151) [this](https://github.com/laberning/openrowingmonitor/discussions/157)discussions| +| | Model D, E | Air rower | Flywheel | [Modification to electrical signal](hardware_setup_Concept2_RowErg.md) | 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](hardware_setup_Concept2_RowErg.md) | 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 | - | +| Domyos | FR120 | Air Rower | Flywheel | No | Known to work | DKN_R320 | Yes | No | Static drag | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/154) | +| FDF | FR-E520 | Water rower | Impellor | Sensor replacement | Known to work | - | Yes | - | - | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/156) | +| | Neon Pro V | Air rower | Flywheel | Sensor replacement | Known to work | - | Yes | - | - | see [this](https://github.com/laberning/openrowingmonitor/discussions/87) and [this](https://github.com/JaapvanEkris/openrowingmonitor/discussions/11) discussion| +| ForceUSA | R3 | Air Rower | Flywheel | No | Supported | ForceUSA_R3 | Yes | Yes | None | - | +| ISE | SY-1750 | Magnetic | Flywheel | Change placement of the reed switches | Known to work | Manual config | Yes | No | Static drag | [see this discussion](https://github.com/laberning/openrowingmonitor/discussions/143) | +| JLL | Ventus 2 | Hybrid Magnetic and Air rower | Flywheel | Unknown | Known to work | Unknown | Yes | Unknown | Unknown | [see this discussion](https://github.com/JaapvanEkris/openrowingmonitor/discussions/42) | +| Johnson | JAR5100 | Air Rower | Flywheel | Yes, add magnets and sensor | Configuration known | - | Yes | Yes | None | [this discussion](https://github.com/laberning/openrowingmonitor/discussions/139) | +| Joroto | MR380 | Water Rower | Impellor | Yes, add magnets and sensor | Configuration known | - | Yes | Yes | None | [this discussion](https://github.com/JaapvanEkris/openrowingmonitor/discussions/46) | +| NOHRD | WaterRower | Water rower | Impellor | Add sensor | Configuration known | Custom profile | Yes | Yes | None | see [this discussion](https://github.com/laberning/openrowingmonitor/discussions/158) | +| NordicTrack | RX800 | Hybrid Magnetic and Air rower | Flywheel | None | Full support | NordicTrack_RX800 | Yes | Yes | None | Also known under ProForm brand | +| 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) | +| Skandika | Nytta | Water rower | Impellor | Add aditional magnets and sensor | Known to work | Unknown | Yes | Unknown | Unknown | see [this discussion](https://github.com/JaapvanEkris/openrowingmonitor/discussions/24) | +| 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 | +| Xebex | Air Rower V2 | Air rower | Flywheel | Modification to the source code | Known to work | Default | Yes | Yes | None | [See this discussion](https://github.com/JaapvanEkris/openrowingmonitor/discussions/28) | + +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. diff --git a/docs/_config.yml b/docs/_config.yml index b06d08b345..d46e310395 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -13,28 +13,24 @@ # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. # You can create any custom variable you would like, and they will be accessible # in the templates via {{ site.myvariable }}. -title: Open Rowing Monitor +title: OpenRowingMonitor #description: A free performance monitor for rowing machines # baseurl: "" # the subpath of your site, e.g. /blog # url: "" # the base hostname & protocol for your site, e.g. http://example.com -author: Lars Berning -twitter: - username: laberning - card: summary +author: Jaap van Ekris social: - name: Lars Berning + name: Jaap van Ekris links: - - https://twitter.com/laberning - - http://www.linkedin.com/in/larsberning - - https://github.com/laberning + - https://www.linkedin.com/in/jaapvanekris/ + - https://github.com/JaapvanEkris defaults: - scope: path: "" values: image: /img/icon.png -github_username: laberning +github_username: JaapvanEkris google_site_verification: kp2LqEz4JhvucGcmjdvFJXF0rpXA-asxk2uTTtQDTKA # Build settings diff --git a/docs/attribution.md b/docs/attribution.md index f5a8ec1333..8e3ec984d5 100644 --- a/docs/attribution.md +++ b/docs/attribution.md @@ -2,18 +2,18 @@ Open Rowing Monitor uses some great work by others. Thank you for all the great resources that helped me to make this project possible. I especially would like to thank: +* Many thanks to [Abasz](https://github.com/Abasz) for his great contributions to the GUI, GPIO, BLE and Ant+ implementations, as well as the many constructive feedback that helped improve many areas of OpenRowingMonitor. You pushing the enveloppe really shaped OpenRowingMonitor into what it is today. + +* Thank you to [Lars Berning](https://github.com/laberning) for creating the initial version and creating the starting point for what OpenRowingMonitor has become now. + * A lot of helpful information for building the physics engine of the rowing machine was found in this scientific work by Anu Dudhia: [The Physics of Ergometers](http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html). * 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). * The app icon is based on this [Image of a rowing machine](https://thenounproject.com/term/rowing-machine/659265) by [Gan Khoon Lay](https://thenounproject.com/leremy/) licensed under [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/). * 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 cdbe1b2e23..5d3c7e362f 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -2,24 +2,36 @@ This is currently is a very minimalistic Backlog for further development of this project. -If you would like to contribute to this project, please read the [Contributing Guidelines](CONTRIBUTING.md) first. +If you would like to contribute to this project, you are more than welcome, but please read the [Contributing Guidelines](CONTRIBUTING.md) first to get the most out of your valuable time. ## Soon -* validate FTMS with more training applications and harden implementation (i.e. Holofit and Coxswain) -* add an option to select the damper setting in the Web UI -* add some more test cases to the rowing engine +* Improve the user interface (We really need help on this!) +* Move to the Wayland window manager, to keep in step with Raspberry Pi OS +* Introduce training plans (i.e. a distance/time to row): + * Integrate with rowsandall.com to retrieve training planning + * Integrate with intervals.icu to retrieve training planning + * add user friendly possibility for user to define training interval timers in the web frontend +* Introduce workout plans (i.e. intervals with **goals** like a target HR or pace): + * Update `server.js`, `SessionManager.js` and the recorders to handle a minimum or maximum pace/HR per interval + * Integrate with intervals.icu to retrieve training targets + * add user friendly possibility for user to define workouts with targets via the GUI + * add user friendly possibility for user to define workouts with targets via the PM5 +* Add calories as interval type + * Add weight correction factor (see [C2 formula](https://www.concept2.com/training/calorie-calculator)) + * Make Calories a continuous metric (similar to distance) instead of a cycle based one + * Add it as a stop criterium for the session manager + * Add it as a workout option to the FIT recorder + * Modify the PM5 peripheral to broadcast the right data + * Update the GUI to allow selecting it ## Later +* validate FTMS with more training applications and harden implementation (i.e. Holofit and Coxswain) * figure out where to set the Service Advertising Data (FTMS.pdf p 15) * add some attributes to BLE DeviceInformationService -* record the workout and show a visual graph of metrics -* show a splash screen while booting the device +* Introduce multiple users with their own parameters (like linked rowsandall.com and intervals.icu accounts, etc.) ## Ideas -* 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 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) +* Add GUI indicators for training zones 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 0000000000..2b92517428 Binary files /dev/null and b/docs/img/CurrentDt_With_Lots_Of_Bounce.jpg differ diff --git a/docs/img/Metrics_Selection.png b/docs/img/Metrics_Selection.png new file mode 100644 index 0000000000..77730dec05 Binary files /dev/null and b/docs/img/Metrics_Selection.png differ diff --git a/docs/img/maximumTimeBetweenImpulses.jpg b/docs/img/maximumTimeBetweenImpulses.jpg new file mode 100644 index 0000000000..42b6dd155c Binary files /dev/null and b/docs/img/maximumTimeBetweenImpulses.jpg differ diff --git a/docs/installation.md b/docs/installation.md index 3482627e2c..935a0b4d55 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,53 +1,191 @@ -# Set up of Open Rowing Monitor +# Set up of OpenRowingMonitor -This guide roughly explains how to set up the rowing software and hardware. + +This guide explains how to set up the rowing software and hardware. In this manual, we cover the following topics: + +- [Requirements](#requirements) +- [Installing OpenRowingMonitor on your Raspberry Pi](#software-installation) +- [Physically connecting your rower to your Raspberry Pi](#hardware-installation) +- [Configuration of OpenRowingMonitor](#rower-settings) +- [Updating OpenRowingMonitor](#updating-openrowingmonitor-to-a-new-version) + +If you can follow this guide, you will get OpenRowingMonitor to work. If you run into issues, you can always [drop a question in the GitHub Discussions](https://github.com/JaapvanEkris/openrowingmonitor/discussions), and there always is someone to help you. ## Requirements -* A Raspberry Pi that supports Bluetooth Low Energy. Probably this also runs on other devices. - * Raspberry Pi Zero W or WH - * Raspberry Pi Zero 2 W or WH - * Raspberry Pi 3 Model A+, B or B+ - * Raspberry Pi 4 Model B -* An SD Card, any size above 4GB should be fine -* A rowing machine (obviously) with some way to measure the rotation of the flywheel - * with a build in reed sensor that you can directly connect to the GPIO pins of the Raspberry Pi - * if your machine doesn't have a sensor, it should be easy to build something similar (magnetically or optical) -* Some Dupont cables to connect the GPIO pins to the sensor +- A Raspberry Pi that supports Bluetooth Low Energy. + - Raspberry Pi Zero 2 W or WH + - Raspberry Pi 3 Model A+, B or B+ + - Raspberry Pi 4 Model B +- An SD Card, any size above 4GB should be fine +- A rowing machine (obviously) with some way to measure the rotation of the flywheel + - with a build in reed sensor that you can directly connect to the GPIO pins of the Raspberry Pi + - if your machine doesn't have a sensor, it should be easy to build something similar (magnetically or optical) +- Some Dupont cables to connect the GPIO pins to the sensor +- Optionally, an ANT+ USB stick + +The cheapest solution is a headless Raspberry Pi Zero 2W (roughly $15), the most expensive is a Raspberry Pi 4 Model B with a 7' tocuh screen in an ABS case (roughly $180). The choice is really yours, but for some data intensive machines (air based rowers with 4 or more magnets) do much better with a Raspberry Pi 4. + +> [!NOTE] +> Due to architectual differences, OpenRowingMonitor will **NOT** work on a Raspberry Pi Zero or a Raspberry Pi 5 ## Software Installation ### 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) -* 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) +- 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. This can be done by selecting "other" Raspberry Pi OS in the imager and select OS Lite 64 Bit. We typically support the current and previous (Legacy) version of Raspberry Pi OS. +- In the Raspbverry Pi Imager, configure the network connection and enable SSH. In 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 our performance improvement guide](Improving_Raspberry_Performance.md) -### Installation of the Open Rowing Monitor +> [!NOTE] +> On a Raspberry Pi Zero 2W, you need to increase the swap-size to 1024 otherwise the installation of OpenRowingMonitor (i.e. the next step) will fail (see [this manual how to do this](https://pimylifeup.com/raspberry-pi-swap-file/)); -Connect to the device with SSH and initiate the following command to set up all required dependencies and to install Open Rowing Monitor as an automatically starting system service: +### Installation of the OpenRowingMonitor software + +Connect to the device with SSH and initiate the following command to set up all required dependencies and to install OpenRowingMonitor as an automatically starting system service: ```zsh -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/laberning/openrowingmonitor/HEAD/install/install.sh)" +sudo /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/jaapvanekris/openrowingmonitor/HEAD/install/install.sh)" ``` -### Updating to a new version +Just answer the questions from the script and OpenRowingMonitor will be installed for you completely. + +> [!TIP] +> Might this install process fail for some reason, you can start it again withoug issue and it will continue where it left off. Especially during installation of npm packages, this is known to happen due to network issues. + + +
+ + +Installing alternative branches -Open Rowing Monitor does not provide proper releases (yet), but you can update to the latest development version with this command: +Sometimes you need some functionality that isn't released in our stable 'main' branch yet, so one of our developers advises you to install an experimental branch. Please do not install an experimental branch unless you known what you are doing and you are told explicitly by any of our developers, as some branches may not even be functional without warning. Installing an alternative branch can be done via: ```zsh -updateopenrowingmonitor.sh +wget https://raw.githubusercontent.com/jaapvanekris/openrowingmonitor/HEAD/install/install.sh +``` + +Followed by opening the downloaded file in a text editor (nano in this case): + +```zsh +sudo nano install.sh +``` + +Here, look for the line + +```zsh +BRANCH="main" +``` + +And change the name of the branch into one of your choosing. Save the file. You can now install the branch by running + +```zsh +sudo /bin/bash ./install.sh ``` -### Running Open Rowing Monitor without root permissions (optional) +Just answer the questions from the script and OpenRowingMonitor will be installed for you completely. -The default installation will run Open Rowing Monitor with root permissions. You can also run it as normal user by modifying the following system services: + +
-#### To use BLE and open the Web-Server on port 80 +### Check if OpenRowingMonitor runs without issue -Issue the following command: +Next, check you need to do is to check the status of the OpenRowingMonitor 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 check if there are no errors reported. + +Please note that the process identification numbers will differ. + +You can also 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.9.0 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.9.0 ==== +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 +``` + +Please check if there are no errors reported. The above snippet shows that OpenRowingMonitor is running, and that bluetooth and the webserver are alive, and that the webclient has connected. + +### Check if OpenRowingMonitor screen runs without issue (if installed) + +Next, check you need to do is to check the status of the OpenRowingMonitor service, which you can do with the command: + +```zsh +sudo systemctl status webbrowserkiosk +``` + +Which typically results in the following response (with some additional logging): + +```zsh +● webbrowserkiosk.service - X11 Web Browser Kiosk + Loaded: loaded (/lib/systemd/system/webbrowserkiosk.service; enabled; vendor preset: enabled) + Active: active (running) since Wed 2024-01-31 23:46:27 CET; 11h ago + Main PID: 746 (xinit) + Tasks: 82 (limit: 8755) + CPU: 2min 50.292s + CGroup: /system.slice/webbrowserkiosk.service + ├─746 xinit /opt/openrowingmonitor/install/webbrowserkiosk.sh -- -nocursor + ├─747 /usr/lib/xorg/Xorg :0 -nocursor + ├─769 sh /opt/openrowingmonitor/install/webbrowserkiosk.sh + ├─774 /usr/bin/openbox --startup /usr/lib/aarch64-linux-gnu/openbox-autostart OPENBOX + ├─777 /usr/lib/chromium-browser/chromium-browser --enable-pinch --disable-infobars --disable-features=AudioServiceSandbox --kiosk --noerrdialogs --ignore-certificate-errors --disable-session-crashed-bubble --disable-pinch -> + ├─804 /usr/lib/chromium-browser/chrome_crashpad_handler --monitor-self --monitor-self-annotation=ptype=crashpad-handler --database=/home/pi/.config/chromium/Crash Reports --annotation=channel=Built on Debian , running on De> + ├─806 /usr/lib/chromium-browser/chrome_crashpad_handler --no-periodic-tasks --monitor-self-annotation=ptype=crashpad-handler --database=/home/pi/.config/chromium/Crash Reports --annotation=channel=Built on Debian , running > + ├─810 /usr/lib/chromium-browser/chromium-browser --type=zygote --no-zygote-sandbox --crashpad-handler-pid=0 --enable-crash-reporter=,Built on Debian , running on Debian 11 --noerrdialogs --change-stack-guard-on-fork=enable + ├─811 /usr/lib/chromium-browser/chromium-browser --type=zygote --crashpad-handler-pid=0 --enable-crash-reporter=,Built on Debian , running on Debian 11 --noerrdialogs --change-stack-guard-on-fork=enable + ├─820 /usr/lib/chromium-browser/chromium-browser --type=zygote --crashpad-handler-pid=0 --enable-crash-reporter=,Built on Debian , running on Debian 11 --noerrdialogs --change-stack-guard-on-fork=enable + ├─845 /usr/lib/chromium-browser/chromium-browser --type=gpu-process --enable-low-end-device-mode --ozone-platform=x11 --crashpad-handler-pid=0 --enable-crash-reporter=,Built on Debian , running on Debian 11 --noerrdialogs -> + ├─850 /usr/lib/chromium-browser/chromium-browser --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --ignore-certificate-errors --ignore-certificate-errors --crashpad-han> + ├─858 /usr/lib/chromium-browser/chromium-browser --type=utility --utility-sub-type=storage.mojom.StorageService --lang=en-US --service-sandbox-type=utility --ignore-certificate-errors --ignore-certificate-errors --crashpad-> + ├─877 /usr/lib/chromium-browser/chromium-browser --type=broker + └─884 /usr/lib/chromium-browser/chromium-browser --type=renderer --crashpad-handler-pid=0 --enable-crash-reporter=,Built on Debian , running on Debian 11 --noerrdialogs --change-stack-guard-on-fork=enable --first-renderer-p> +``` + +Please check if there are no errors reported. + +Please note that the process identification numbers will differ. + +### To use BLE and open the Web-Server on port 80 + +#### Running OpenRowingMonitor without root permissions (optional) + +The default installation will run OpenRowingMonitor with root permissions. You can also run it as normal user by issueing the following command: ```zsh sudo setcap cap_net_bind_service,cap_net_raw=+eip $(eval readlink -f `which node`) @@ -64,36 +202,178 @@ ATTRS{idVendor}=="0fcf", ATTRS{idProduct}=="1009", MODE="0666" ## Hardware Installation -Basically all that's left to do is hook up your sensor to the GPIO pins of the Raspberry Pi and configure the rowing machine specific parameters of the software. +Next step is is to hook up your sensor to the GPIO pins of the Raspberry Pi. Please check the [supported rower list](Supported_Rowers.md) if your machine requires additional electrical or mechanical modification. Some machines' sensors are placed wrong, so this might be corrected. Ideally, it reads the velocity of the flywheel (or anything directly connected to it). -Open Rowing Monitor reads the sensor signal from GPIO port 17 and expects it to pull on GND if the sensor is closed. 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. +OpenRowingMonitor reads the sensor signal from GPIO port 17 (as set by the `gpioPin` setting in `config.js`) and expects it to pull on GND if the sensor is closed. So your wiring probably looks like this: -![Internal wiring of Raspberry Pi](img/raspberrypi_internal_wiring.jpg) -*Internal wiring of Raspberry Pi* +Image showing the internal wiring of Raspberry Pi
-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. +To get a stable reading you should add a pull-up resistor to that pin. It is advised 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 ``` -How to connect this to your rowing machine is specific to your device. You need some kind of mechanism to convert the rotation of the flywheel into impulses. Some rowers have a reed sensor for this built-in, so hooking it up is as simple as connecting the cables. Such a sensor has one or more magnets on the wheel and each one gives an impulse when it passes the sensor. For a specific hardware-setup, please look at: +How to connect this to your rowing machine physically is specific to your device. You need some kind of mechanism to convert the rotation of the flywheel into impulses. Some rowers have a reed sensor for this built-in, so hooking it up is as simple as connecting the cables. Such a sensor has one or more magnets on the wheel and each one gives an impulse when it passes the sensor. -* [Concept 2 RowErg](hardware_setup_Concept2_RowErg.md) -* [Sportstech WRX700](hardware_setup_WRX700.md) +Image showing the connection of the reed sensor
-If your machine isn't listed, you can still follow this generic manual. +There are some manuals covering a specific hardware-setup using the existing sensors, so please look at when relevant: -![Connecting the reed sensor](img/raspberrypi_reedsensor_wiring.jpg) -*Connecting the reed sensor* +- [Concept 2 RowErg](hardware_setup_Concept2_RowErg.md) +- [Sportstech WRX700](hardware_setup_WRX700.md) If you do not have and does not have something like this or if the sensor is not accessible, you can still build something similar quite easily. Some ideas on what to use: -* Reed sensor (i.e. of an old bike tachometer) -* PAS sensor (i.e. from an E-bike) -* Optical chopper wheel +- Reed sensor (i.e. of an old bike tachometer) +- HAL effect sensor +- PAS sensor (i.e. from an E-bike) +- Optical chopper wheel + +From there on, please make sure to also follow the [setup guide for unknown rowing machines (and adjust settings)](rower_settings.md) to get the right parameters to get your setup working. ## Rower Settings -You should now adjust the rower specific parameters in `config/config.js` to suit your rowing machine. You should select a specific rower from the `rowerProfiles.js`, or create your own settings following this [guide for creating the rower specific settings](rower_settings.md). Also have a look at `config/default.config.js` to see what additional config parameters are available to suit your needs. +Last step is to configure the rowing machine specific parameters of the software. To do this, you should now adjust the rower specific parameters in `config/config.js` to suit your rowing machine and your personal needs. You can also have a look at `config/default.config.js` to see what additional config parameters are available. To open the configuration, you can do + +```zsh +sudo nano /opt/openrowingmonitor/config/config.js +``` + +> [!TIP] +> This essentially is a JSON structure, which is quite sensitive to missing or extra commas. Unless it is the last property in a list (i.e. before a closing curly brace), always end a property with a comma. + +### Setting up the hardware and OS configuration + +A key element is how the app behaves on the operating system itself. + +#### Application settings + +OpenRowingMonitor essentially consists of two major threads: the gpio-thread, reading data from the flywheel, and the general application thread. In the settings, you can set their priorities individually. This is the Linux NICE level: minimum setting is +19 (least agressive), theoretical maximum setting is -20 (most agressive). The lower the NICE-number, the more priority it will claim, at the expense of other functions of the operating system. + +Most critical is the `gpioPriority`. This determines 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 normally set to a NICE-level of 0 (normal OS priority). On a well-configured system, the level of noise in the GPIO-thread can be identified by looking at the reported Goodness of Fit from the drag calculation: the better the fit, the lower the noise level. Setting the NICE-level 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 gpio-thread as it interferes with the kernel timekeeping. On a dedicated Raspberry Pi 4, best results for a Concept2 RowErg (100 datapoints per second) were attained by using a NICE-level of -6. + +The NICE-level of the general application is determined by the `appPriority` setting. This maanges 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. Again, 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, and best results on a Raspberry Pi 4 with a Concept 2 RowErg were attained at NICE-level -1. + +#### GPIO settings + +The setting `gpioPin` defines the GPIO Pin that is used to read the sensor data from the rowing machine. Please refer to the [official Rapberry Pi documentation](https://www.raspberrypi.org/documentation/usage/gpio) for the pin layout of the device you are using. If you want to use the internal pull-up resistor of the Raspberry Pi (and you should) you should also configure the pin for that in /boot/config.txt, i.e. 'gpio=17=pu,ip' (see the [official Raspberry Pi documentation](https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md)). + +The setting `gpioPollingInterval` determines the 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, but a Raspberry Pi 4 can handle a polling interval of 1 us, which results in a 16% CPU load. + +The setting `gpioTriggeredFlank` determines what flank is used for detecting a magnet. Valid values are + +- 'Up' for the upward flank, i.e. the GPIO is triggered when the magnet enters the sensors' range (i.e. first there was no magnet detected, followed by a detected magnet); +- 'Down' for the downward flank, i.e. the GPIO is triggered when the magnet leaves the sensors' range (i.e. first there was magnet detected, followed by no detected magnet); +- 'Both' for both flanks. This option is quite unique, as this requires a strong symmetry in the signal. Normally the magnets provide short pulses, followed by long periods of no magnet being detected. Only very specific machines can use this option. + +In practice, it shouldn't matter much which of the two flanks you detect, although in the presence of [debounce](https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/rower_settings.md#fixing-switch-bounce), a specific flank might provide better filtering capabilities or is more reliable to detect. + +The setting `gpioMinimumPulseLength` is related: it determines the minumum pulse length (i.e. a magnet should be present) in nanoseconds before OpenRowingMonitor considers it a valid signal. Shorter pulses typically are caused by ghost readings of the same magnet twice or more. Normal value is 50 us, but for some rowers, values up to 500 us are known to work. Increasing this value reduces ghost readings due to bouncing reed switches etc., which typically are detected as very short measurements in the raw logs. + +A scatter plot showing the typical progress of currentDt with switch bounce + +Making this too long results in missed impulses. Both too long and too short impulses can be detected in the raw logs easily by imprting that log into a spreadsheet and plot the pulsetime. + +### Setting up the rowing machine connected + +Please check the [list of known configurations](Supported_Rowers.md), as for many machines the configuration is already listed in the `/opt/openrowingmonitor/config/rowerProfiles.js` file. If this is the case, copy its name, and add it to the config as follows: + +```js +rowerSettings: rowerProfiles.Concept2_RowErg +``` + +If your machine isn't listed, you are adviced to follow the [setup guide for unknown rowing machines (and adjust settings)](rower_settings.md) as it goes into much more depth about installing OpenRowingMonitor on an unknown machine. + +### Setting up data aquisition and reporting parameters + +#### General data reporting settings + +OpenRowingMonitor calculates metrics once, and then distributes the same metrics to all consumers (i.e. BLE, ANT+ devices, but also the weinterface and recorders). This impleas that data are always consistent across all recordings and visualisations. + +A key element is the number of stroke phases (i.e. Drives and Recoveries) that used to smoothen the data displayed on your screens (i.e. the monitor, but also bluetooth devices, etc.) and recorded data, which is set via the `numOfPhasesForAveragingScreenData` parameter. This is a matter of personal preference: some people prefer a very responsive screen, others like a more stable data presentation. A nice smooth experience is found at 6 stroke phases (i.e. 3 complete strokes). 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. + +#### Setting up your heart rate sensor + +The parameter `heartRateMode` determines the heart rate monitor mode at startup. From the monitor or webinterface, you can change this on the spot as well. This setting has the following modes: + +- BLE: Use Bluetooth Low Energy to connect Heart Rate Monitor. It will connect to the first device found; +- ANT: Use Ant+ to connect Heart Rate Monitor. This requires an optional ANT+ stick. This will also connect to the first ANT+ HRM monitor found. +- OFF: turns of Heart Rate Monitor discovery + +#### Configuration of the main screen/webinterface + +OpenRowingMonitor will always refresh the monitor and webinterface when it detects a drive, recovery or new interval. The parameter `webUpdateInterval` determines the interval for updating all web clients (i.e. the monitor and other users) in miliseconds in between these events. It is 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, and values below 80 ms will be ignored. Please note that a smaller value will use more network and cpu ressources. + +#### Setting up Bluetooth reporting + +Bloothooth Low Energy has several parameters. Most important one is `bluetoothMode` which will determine the Bluetooth Low Energy Profile that is broadcasted to external peripherals and apps at startup. From the monitor or webinterface, you can change this on the spot as well. This setting has the following modes: + +- OFF: Turns Bluetooth advertisement off +- PM5: in this mode OpenRowingMonitor emulates a this emulates a 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: This is the FTMS profile for rowing machines and supports all rowing specific metrics (such as stroke rate). We've successfully tested it with [EXR](https://www.exrgame.com) (preferred method), [MyHomeFit](https://myhomefit.de) and [Kinomap](https://www.kinomap.com). +- FTMSBIKE: 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.(please note: the speed and power are still aimed for rowing, NOT for a bike!) This is known to work with [Zwift](https://www.zwift.com), [Bkool](https://www.bkool.com), [The Sufferfest](https://thesufferfest.com) or similar. +- CPS: The BLE Cycling Power Profile simulates a bike which allows you to connect the rower to a bike activity on your (mostly newer 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. +- CSC: The BLE Cycling Speed and Cadence Profile simulates a bike for older Garmin (Forerunner and Venu) watches and similar types, again simulating a bike activity. + +> [!NOTE] +> For the CSC profile, you need to set the wheel circumference on your watch to 10mm to make this work well. + +There are some additional parameters for tuning your settings for speific BLE profiles: + +- `ftmsRowerPeripheralName` sets 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, so changing this sometimes helps. +- `ftmsBikePeripheralName` 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. +- `ftmsUpdateInterval` determines the interval between updates of the `FTMS` and `FTMS` protocol BLE devices, in miliseconds. Advised is to update at least once per second (default value), as consumers expect this interval. Some apps, like EXR like a more frequent interval of 200 ms to better sync the stroke. +- `pm5UpdateInterval` determines the interval between updates of the `PM5` protocol BLE device, in miliseconds. Advised is to update at least once per second (default value), as consumers expect this interval. Some apps, like EXR like a more frequent interval of 200 ms to better sync the stroke. + +#### Setting up ANT+ + +The parameter `antPlusMode` determines if ANT+ is activated at startup. From the monitor or webinterface, you can change this on the spot as well. + +- FE: OpenRowingMonitor will broadcast rowing metrics via ANT+ Fitness Equipment (ANT+ FE-C), which can be recieved by the more expensive series of Garmin smartwatches like the Epix/Fenix series, which then can calculate metrics like training load etc.. +- OFF: Turns ANT+ advertisement off. + +### Setting up recording parameters + +These are turned off by default. To see how you turn them on and how to configure them, see our [integrations page](Integrations.md). + +### Setting up a user profile + +### Setting up integrations to Strava, intervals.icu and RowsAndAll.com + +These are turned off by default. To see how you turn them on and how to configure them, see our [integrations page](Integrations.md). + +### Checking the configuration + +Once all parameters are set, restart OpenRowingMonitor and look at the the log output of the OpenRowingMonitor-service by putting the following in the command-line: + +```zsh +sudo systemctl restart openrowingmonitor +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.9.0 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.9.0 ==== +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 +``` + +Please check if there are no errors reported, especially for configuration parameters. OpenRowingMonitor will report if it detects abnormal or missing parameters. + +## Updating OpenRowingMonitor to a new version + +OpenRowingMonitor does not provide proper releases (yet), but you can update to the latest development version with this command: + +```zsh +updateopenrowingmonitor.sh +``` diff --git a/docs/physics_openrowingmonitor.md b/docs/physics_openrowingmonitor.md index ffae93fd1a..f258d931c8 100644 --- a/docs/physics_openrowingmonitor.md +++ b/docs/physics_openrowingmonitor.md @@ -1,9 +1,9 @@ # The physics behind Open Rowing Monitor -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. +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 to allow further investigation and keep the link with the actual implementation. -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. +Please note that this text is used as a rationale for design decissions of the physics used 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 or improve our solution. For these academics, we conclude with a section of open design issues as they might provide avenues of future research. If you are interested in just using Open Rowing Monitor as-is, this might not be the text you are looking for. ## Basic concepts @@ -11,12 +11,15 @@ Before we analyze the physics of a rowing engine, we first need to define the ba ### Physical systems in a 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) [[1]](#1). +A rowing machine effectively has two fundamental movements: - +* a **linear** movement (the rowing person moving up and down the rail, or a boat moving forward) and +* a **rotational** movement 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* +Physically these movements are related, as they are connected by a chain or belt, allowing the rowing person to move the flywheel. This is shown in the following figure: + +Image showing a rowing machine with its linear and rotational energy systems +A basic view of an indoor rower's energy systems 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. @@ -28,7 +31,7 @@ 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 currently 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 rower's resistance is dependent on the flywheel's speed. We suspect that on a water rower behaves slightly different from an air rower, as the rotated water mass changes shape when the rotational velocity changes. Currently for Open Rowing Monitor, we consider that the key principle is similar enough for all these rowers (some mass is made to spin and drag brings its speed down) to treat them all as an air rower as a first approximation. However, we are still investigating how to adapt for these specific machines. ### Phases in the rowing stroke @@ -41,8 +44,7 @@ stateDiagram-v2 Recovery --> Drive ``` - -*Basic phases of a rowing stroke* +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: @@ -50,7 +52,7 @@ On an indoor rower, the rowing cycle will always start with a stroke, followed b * 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*. +Combined, we define 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 define 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 @@ -72,7 +74,9 @@ Although the physics is well-understood and even well-described publicly (see [[ ## 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. +Typically, actual measurements are done in the rotational part of the rower, on the flywheel. We explicitly assume that Open Rowing Monitor measures the flywheel movement (directly or indirectly). Some rowing machines are known to measure the movement of the driving axle and thus the velocity and direction of the handle, and not the driven flywheel. This type of measurement blocks access to the physical behaviour of the flywheel (especially acceleration and coast down behaviour), thus making most of the physics engine irrelevant. Open Rowing Monitor can handle some of these rowing machines by fixing specific parameters, but as this measurement approach excludes any meaningful measurement, we will exclude it in the further description. + +In a typical rowing machine, there is a magnetic reed sensor or optical sensor that will measure time between either magnets or reflective stripes on the flywheel or impellor, 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`. @@ -86,7 +90,9 @@ Open Rowing Monitor needs to keep track of several metrics about the flywheel an * 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 **flywheel inertia** of the flywheel in kg \* m2 (denoted with I): the resistance of the flywheel to acceleration/deceleration; + +* The *estimated* **drag factor** of the flywheel in N \* m \* s2 (denoted with k): the level of (air/water/magnet) drag 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. @@ -107,19 +113,19 @@ As the impulse-givers are evenly spread over the flywheel, this can be robustly 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. +* Ghost impulses, typically caused by **bounce** effects of the sensor where the same magnet is seen twice by the sensor. The best resolution is a better mechanical construction of magnets and sensors or adjust the **debounce filter**. ### 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} $$ +$$ ω = {Δθ \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} $$ +$$ α = {Δω \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. @@ -127,84 +133,104 @@ Summarizing, both Angular Velocity ω and Angular Acceleration α are ### 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`. +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`. There are several approaches described in literature [[1]](#1), which Open Rowing Monitor extends to deliver a reliable and practically applicable approach. A first numerical approach is presented by through [[1]](#1) in formula 7.2a: -> $$ k = - I \* {Δω \over Δt} * {1 \over Δω^2} $$ +$$ 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: +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, especially in the presence of systematic errors in the flywheel construction (as is the case with Concept2 Model D and later). Our practical experience based on testing confirms this volatility. An alternative numerical approach is presented by through [[1]](#1) in formula 7.2b: -> $$ k = -I \* {Δ({1 \over ω}) \over Δt} $$ +$$ 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. +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, reducing the effect of single values of *CurrentDt*, the calculated drag factor is more stable but still is too unstable to be used as both the ω's used in this calculation still depend on single values of *CurrentDt*. Additionally, small errors in detection of the drive or recovery phase would change ω dramatically, throwing off the drag calculation significantly (see also [this elaboration](physics_openrowingmonitor.md#use-of-simplified-power-calculation)). Therefore, such an approach typically requires averaging across strokes to prevent drag poisoning (i.e. a single bad measurement of *currentDt* throwing off the drag factor significantly, and thus throwing off all dependent linear metrics significantly), which still lacks robustness of results as drag tends to fluctuate throughout a session. -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: +We can transform formula 7.2b to the definition of the slope of a line, by doing the following: -> $$ { k \over I } = {Δ({1 \over ω}) \over Δt} $$ +$$ { 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: +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. Using regression analysis that is robust to outliers, one can calculate this in a robust manner, reducing the dependence on both the caluclation of ω and stroke detection. As ω is calculated robustly as it is, it is expected to contain less outliers as it is. -> $$ ω = {({2π \over Impulses Per Rotation}) \over currentDt} $$ +However, formula 7.2b can be simplified further, as the angular velocity ω is defined by: -thus making: +$$ ω = {({2π \over Impulses Per Rotation}) \over currentDt} $$ -> $$ { k \over I } = {Δ({1 \over {({2π \over Impulses Per Rotation}) \over currentDt}}) \over Δt} $$ +this can be rewritten as: -removing the division, results in +$$ {k \* 2π \over I \* Impulses Per Rotation} = {ΔcurrentDt \over Δt} $$ -> $$ { k \over I } = {Δ(currentDt \* {Impulses Per Rotation \over 2π}) \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 analyses to calculate the drag based on the raw measured *currentDt*. 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 -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 = slope \* I \* {Impulses Per Rotation \over 2π} $$ -> $$ {k \* 2π \over I \* Impulses Per Rotation} = {ΔcurrentDt \over Δt} $$ +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 approach also brings this calculation as close as possible to the raw *currentDt* data, while not using an individual *currentDt*'s as a divider, which are explicit design goals to reduce data volatility. -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 +Both slopes can be determined through linear regression (see [[5]](#5) and [[6]](#6)) for the collection of datapoints for a specific recovery phase. For determining the slope, we use the linear Theil-Sen Estimator, which is sufficiently robust against noise, especially when filtering on low R2. 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. Additionally, as the drag does not change much from stroke to stroke, a running weighed average across several strokes is used, where the R2 is used as its weight. This has the benefit of favouring better fitting curves over less optimal fitting curves (despite all being above the R2 threshold set). Practical experiments show that this approach outperforms any other noise dampening filter. -> $$ k = slope \* {I \* Impulses Per Rotation \over 2π} $$ +Although both regression approaches are mathematically valid, they do yield different results: the first approach depends on (noise filtered) angular velocity ω as its input where the second approach depends on raw *currentDt* values. Comparing the results for both approaches: -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. +* For approach 1, on a Concept2, the typical R2 is around @@ (low drag) to @@ (high drag) for steady state rowing. Also, calculated drag has a standard deviation of @@ (low drag) to @@ (high drag) across a session. +* For approach 2, On a Concept2, the typical R2 is around 0.96 (low drag) to 0.99 (high drag) for steady state rowing. Also, calculated drag has a standard deviation of @@ (low drag) to @@ (high drag) across an entire session. -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. +Therefore, we choose @@ ### 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 $$ +$$ τ = 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 $$ +$$ τ = 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 +## 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; + +* 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 -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: +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* +Image showing the currentDt measurements of the flywheel through time +example currentDt Measurements of a 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: +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, 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); -* `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, 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. 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: -![Impulses, impulse lengths and rowing cycle phases](img/physics/rowingcycle.png) -*Impulses, impulse lengths and rowing cycle phases* +Image showing the relation between Impulses, impulse lengths and rowing cycle phases +Impulses, impulse lengths and rowing cycle phases 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*). @@ -218,12 +244,12 @@ 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: -![Average curves of a rowing machine](img/physics/currentdtandacceleration.png) -*Average currentDt (red) and Acceleration (blue) of a single stroke on a rowing machine* +Image showing the average currentDt curves of a rowing machine +Average currentDt (red) and Acceleration (blue) of a single stroke on a rowing machine 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. @@ -239,11 +265,11 @@ Open Rowing Monitor only will get impulses at discrete points in time. As Open R 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 estimated **power produced** by the rower (in Watts): the power the rower produced during the stroke; +* The estimated **flywheel power** produced by the rower (in Watts, denoted with P): the power the rower produced during the stroke; -* The estimated **Linear Velocity** of the boat (in Meters/Second): the speed at which the boat is expected to travel; +* The estimated **Linear Velocity** of the boat (in Meters/Second, denoted with u): the speed at which 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 **Linear Distance** of the boat (in Meters, denoted with s): 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; @@ -253,29 +279,29 @@ Knowing that *Time since start*, Angular Velocity ω, Angular Acceleration * The estimated **power on the handle** (in Watts): the power on the handle/chain/belt of the rower; -### Power produced +### Flywheel power 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. We can calculate the energy added to the flywheel through [[1]](#1), formula 8.2: -> $$ ΔE = I \* ({Δω \over Δt}) \* Δθ + k \* ω^2 \* Δθ $$ +$$ ΔE = I \* ({Δω \over Δt}) \* Δθ + k \* ω^2 \* Δθ $$ The power then becomes [[1]](#1), formula 8.3: -> $$ P = {ΔE \over Δt} $$ +$$ P = {ΔE \over Δt} $$ Combining these formulae, makes -> $$ P = I \* ({Δω \over Δt}) \* ω + k \* ω^3 $$ +$$ P = I \* ({Δω \over Δt}) \* ω + k \* ω^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 ω. +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 potentially 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: -> $$ \overline{P} = k \* \overline{\omega}^3 $$ +$$ \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). +Where $\overline{P}$ is the average power and $\overline{\omega}$ is the average angular velocity during the stroke. Here, the average speed $\overline{\omega}$ can be determined in a robust manner (i.e. ${Δθ \over Δt}$ for the entire cycle, which makes Δt sufficiently large to isolate it from measurement noise). 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: @@ -304,43 +330,43 @@ Given these advantages and that in practice it won't have a practical implicatio ### Linear Velocity -In [[1]](#1) and [[2]](#2), it is described that power on a Concept 2 is determined through (formula 9.1): +In [[1]](#1) and [[2]](#2), it is described that flywheel power on a Concept 2 is determined through (formula 9.1): -> $$ \overline{P} = k \* \overline{\omega}^3 = c \* \overline{u}^3 $$ +$$ \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. +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. Again, the average angular velocity $\overline{\omega}$ can be determined per cycle in a robust manner (i.e. ${Δθ \over Δt}$ for the entire cycle, which makes Δt sufficiently large to isolate it from measurement noise). -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)): +In [[1]](#1) and [[2]](#2), it is suggested that flywheel power on a Concept 2 might be determined through (formula 9.4, [[1]](#1)): -> $$ \overline{P} = 4.31 \* \overline{u}^{2.75} $$ +$$ \overline{P} = 4.31 \* \overline{u}^{2.75} $$ -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: +Based on a simple experiment, downloading the exported data of several rowing sessions from Concept 2's logbook, and comparing the reported velocity and flywheel power for each stroke, it can 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: -> $$ \overline{u} = ({k \over C})^{1/3} * \overline{\omega} $$ +$$ \overline{u} = ({k \over C})^{1/3} * \overline{\omega} $$ -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. +As both k and $\overline{\omega}$ 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 missing strokes is undesired behaviour in itself, this approach 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} * θ $$ +$$ 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. +Here, as k can slightly change from cycle to cycle, this calculation should be performed at least once per 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. ### 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 -> $$ s_{Handle} = \text{number of rotations of the flywheel} \* \text{circumference of the sprocket} $$ +$$ 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: -> $$ s_{Handle} = {\theta \over 2\pi} * r * 2\pi $$ +$$ s_{Handle} = {\theta \over 2\pi} * r * 2\pi $$ Which can be simplified into: -> $$ s_{Handle} = θ * r $$ +$$ s_{Handle} = θ * r $$ Where r is the radius of the sprocket in meters and θ the angular distance travelled by the flywheel during the drive. @@ -348,7 +374,7 @@ Where r is the radius of the sprocket in meters and θ the angular distance As the distance travelled by the handle is ${u_{Handle} = θ * r}$, we can decuct: -> $$ u_{Handle} = ω \* r $$ +$$ u_{Handle} = ω \* r $$ Here, ω can be the instantanous or average angular velocity of the flyhweel in Radians, and r is the radius of the sprocket (in meters). @@ -356,7 +382,7 @@ Here, ω can be the instantanous or average angular velocity of the flyhwee From theory [[12]](#12)) and practical application [[7]](#7), we know the handle force is equal to: -> $$ F_{Handle} = {τ \over r} $$ +$$ F_{Handle} = {τ \over r} $$ Where r is the radius of the sprocket in meters. @@ -364,29 +390,7 @@ Where r is the radius of the sprocket in meters. 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* +$$ P_{Handle} = τ * ω $$ ## A mathematical perspective on key metrics @@ -426,13 +430,13 @@ The Theil–Sen estimator can be expanded to apply to Quadratic functions, where For the drag-factor calculation (and the closely related recovery slope detection), we observe three things: -* 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; +* 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 the Incomplete Theil–Sen estimator incapable of calculating their slopes in the stream as the efficient implementations require a fixed window. OLS has a O(1) complexity for continous datastreams, and has proven to be sufficiently robust for most practical use. Using the Linear Theil-sen estimator results in a near O(N) calculation at the start of the *Drive* phase (where N is the length of the recovery in datapoints). The Quadratic Theil-sen estimator results in a 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 CPU-load that could disrupt the application; -* 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. +* In non-time critical replays of earlier recorded rowing sessions, both the Incomplete 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 did. The Theil–Sen estimator, in combination with a filter on r2 has shown to be even a bit more robust than OLS. This suggests that the OLS algorithm combined with a requirement for a sufficiently high r2 handles the outliers sufficiently to prevent drag poisoning and thus provide a stable dragfactor for all calculations. The Linear Theil-Sen estimator outperfomed OLS by a small margin, but noticeably improved stroke detection where OLS could not regardless of parameterisation. -* Applying Quadratic OLS regression does not improve its results +* Applying Quadratic OLS regression does not improve its results when compared to Linear OLS regression or Linear TS. For the drag (and thus recovery slope) calculation, the Linear Theil-Sen estimator has a slightly better performance then OLS, while keeping CPU-load acceptable for a data-intensive rowing machine (Concept 2, 12 datapoints flank, 200 datapoints in the recovery). A Quadratic theil-Sen based drag calculation has shown to be too CPU-intensive. For the stroke detection itself, OLS and Linear Theil-Sen deliver the same results, while OLS is less CPU intensive. -Therefore, we choose to apply the OLS Linear Regression model for the calculation of the dragfactor and the related recovery slope detection. +Therefore, we choose to apply the Linear Theil-Sen estimator for the calculation of the dragfactor and the related recovery slope detection, and use OLS for the stroke detection. #### Regression algorithm used for Angular velocity and Angular Acceleration @@ -444,33 +448,52 @@ We determine the Angular Velocity ω and Angular Acceleration α based 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 $$ +$$ 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 $$ +$$ \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. +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 reported/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. +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. 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. + +The (implied) underlying assumption underpinning the use of Quadratic Theil-Senn regression approach is that the Angular Accelration α is constant, or near constant by approximation in the flank under measurment. In essence, quadratic Theil-Senn regression would be fitting if the acceleration would be a constant, and the relation of θ, α and ω thus would be captured in θ = 1/2 \* α \* t2 + ω \* t. We do realize that in rowing the Angular Accelration α, by nature of the rowing stroke, will vary based on the position in the Drive phase: the ideal force curve is a heystack, thus the force on the flywheel varies in time. + +As the number of datapoints in a *Flanklength* in the relation to the total number of datapoints in a stroke is relatively small, we use quadratic Theil-Senn regression as an approximation on a smaller interval. In tests, 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. When using the right efficient 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). Looking at the resulting fit of the Quadratic Theil-Sen estimator, we see that it consistently is above 0.98, which is an extremely good fit given the noise in the Concept 2 RowErg data. Therefore, we consider this is a sufficiently 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. +Although the determination of angular velocity ω and angular acceleration α based on Quadratic Theil-Senn regression over the time versus angular distance θ works decently, we realize it does not respect the true dynamic nature of angular acceleration α. 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. 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 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: +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 the displacement of magets can present itself as a sinoid-like curve (as the Concept 2 RowErg shows), 3rd or higher polynomials are inclined to follow that curve. 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 new datapoint is added to the sliding window (i.e. 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 12 `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. + +We also observe specific practical issues, which could result in structurally 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: + +Image showing the sinoid measurement deviations of a Concept 2 RowErg over three full flywheel rotations +Deviation of the Concept 2 RowErg 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 ω +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 remain a continuing area of improvement. + +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. + +### Use of Quadratic Theil-Senn regression and a weighed average 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. The flank acts like a sliding window: on each new datapoint the window slides one datapoint, and thus recalculates the critical parameters. Thus, as a datapoint will be part of several flank calculations, we obtain several α's and ω's that are valid approximations for that specific datapoint. Once the datapoint slides out of the sliding window, there are *flankLength* number of approximations for ω and α. A key question is how to combine these multiple approximations α and ω into a single true value for these parameters. + +To obtain the most stable result, a median of all valid values for α and ω can be used 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. It also has the downside of producing "blocky" force cuves. -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. +Using a weighed averager resulted in slightly more stable results and resulted in smoother force curves. The weight is based on the r2: better fitting curves will result in a heiger weigt in the calculation, thus preferring approximations that are a better fit with the data. This approach resulted in smoother (less blocky) force curves while retaining the responsiveness of the force curve. -Reducing extreme values while maintaining the true data volatility is a subject for further improvement. +Reducing extreme values while maintaining the true data responsiveness is a subject for further improvement. ## References diff --git a/docs/rower_settings.md b/docs/rower_settings.md index 726313280c..1ef35e508e 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -1,25 +1,31 @@ # 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 if it isn't listed there. This will always be a work in progress, and please get in touch through the [GitHub Discussions](https://github.com/JaapvanEkris/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 +* Check that OpenRowingMonitor works correctly -* Making sure the hardware is connected correctly and works as intended + * Checking that the software works -* Setting up a more detailed logging for a better insight into Open Rowing Monitor + * Setting up a more detailed logging for a better insight into OpenRowingMonitor -* Setting GPIO parameters to get a clean signal (general settings) +* Setting up the hardware connection -* Critical parameters you must change or review for noise reduction + * Making sure the hardware is connected correctly and works as intended -* Critical parameters you must change or review for stroke detection + * Setting GPIO parameters to get a clean signal (general settings) -* What reliable stroke detection should look like in the logs + * Critical parameters you must change or review for noise reduction + +* Setting up stroke detection + + * 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 @@ -31,13 +37,17 @@ In this manual, we cover the following topics: ## 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 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. +No rowing machine is the same, and some physical construction parameters are important for OpenRowingMonitor 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. As said, 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. + +## Check that OpenRowingMonitor works correctly -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. +Before we dive into the settings themselves, we need to check OpenRowingMonitor's install. -## Check that Open Rowing Monitor works +### Checking that the software 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: +First check you need to do is to check the status of the OpenRowingMonitor service, which you can do with the command: ```zsh sudo systemctl status openrowingmonitor @@ -62,9 +72,61 @@ Which typically results in the following response (with some additional logging) Please note that the process identification numbers will differ. +### Setting up a more detailed logging for a better insight into OpenRowingMonitor + +When installed, OpenRowingMonitor will not flood the log with messages. However, when testing parameters is great to see what OpenRowingMonitor is doing under the hood. 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 activate these settings by restarting OpenRowingMonitor (or the entire Raspberry Pi). 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.9.4 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.9.4 ==== + 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 OpenRowingMonitor 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 OpenRowingMonitor's settings throughout the process. + ## 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. +Because any system follows the mantra "Garbage in is garbage out", we first make sure that the signals OpenRowingMonitor recieves are decent. First we check the physical properties, then the electrical properties and last we check the quality of the incoming signal. As this is quite a critical step, please make sure you fixed any mechanical/electrical/quality issues before proceeding, as the subsequent steps in this manual 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. OpenRowingMonitor 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. + +### Checking the electrical properties of the rower + +> [!CAUTION] +> 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 @@ -72,7 +134,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, @@ -84,62 +146,42 @@ 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: - +A curve showing the typical progress of currentDt -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 OpenRowingMonitor 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 -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). +A specific issue to be aware of is *switch bounce*, which typically is seen as a valid signal followed by a very short spike. Dirst step is to activate raw recording and row at least ten seconds. OpenRowingMonitor will produce a csv-file. When looking at a set of plotted signals in Excel (please note: OpenRowingMonitor records in US-notation, so please replace all decimal points with commas if you are not US-based), it manafests itself as the following: -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. +A scatter plot showing the typical progress of currentDt with switch bounce -Please fix any mechanical issues before proceeding. +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 OpenRowingMonitor. 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. -## Setting up a more detailed logging for a better insight into Open Rowing Monitor +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: -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: +* 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. - ```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' - }, - ``` +#### Fixing magnet placement errors -You can look at the the log output of the OpenRowingMonitor-service by putting the following in the command-line: +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): - ```zsh - sudo journalctl -u openrowingmonitor - ``` +A curve showing the typical Concept 2 RowErg Sinoid deviation of currentDt for three cycles -This allows you to see the current state of the rower. Typically this will show: +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. OpenRowingMonitor 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 impulses *flankLength* for a 6 magnet machine). - ```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. +> [!IMPORTANT] +> Please fix any mechanical/electrical/quality issues before proceeding, as the subsequent steps depend on a signal with decent quality ## 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. +OpenRowingMonitor needs to understand normal rower behaviour, so it needs some information about the typical signals it should expect. ### Setting gpioPriority, gpioPollingInterval, gpioTriggeredFlank, gpioMinimumPulseLength (general settings) @@ -147,31 +189,51 @@ 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. Switching *gpioTriggeredFlank* from 'up' to 'down' or vice verse is known to fix switch bounce. *gpioMinimumPulseLength* is also an approach, basically preventing short spikes. It is adviced to first see what *gpioTriggeredFlank* does, before you start surpressing signals via *gpioMinimumPulseLength*. ### 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. +**minimumTimeBetweenImpulses** and **maximumTimeBetweenImpulses** provide a bandwith where values are deemed credible during an active session. As OpenRowingMonitor can handle a lot of noise by itself, this does **not** filter anything. 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 doesn't generate a ton of warning messages (i.e. all normal values should fall within *minimumTimeBetweenImpulses* and *maximumTimeBetweenImpulses*). Please note, as these two parameters are relatively harmless settings, there is a lot of room for error, but as several plausability checks depend on these values as well (for example, the minimum number of datapoints for the drag calculation), they do require some attentention. + +A good quality curve of the time between impulses (as captured in the raw datafiles) looks like this: + +A curve showing the typical progress of currentDt throughout several strokes + +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 OpenRowingMonitor (it will add warnings in the logs). Similarily, *minimumTimeBetweenImpulses* could be slightly increased to include some valleys, without causing much issues. -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. +An important note is that *maximumTimeBetweenImpulses* is also used to detect wether the flywheel is spinning fast enough to consider it a start and whether it spins down due to lack of user input. + +OpenRowingMonitor starts the row when: + +* the angular velocity at the begin of the flank is above minimum angular velocity (which is directly dependent on the *maximumTimeBetweenImpulses*) + +OpenRowingMonitor pauses/stops the row when: + +* the start of the last drive is at least *maximumStrokeTimeBeforePause* ago; +* the angular velocity at the begin of the flank is below the minimum angular velocity (which is directly dependent on the *maximumTimeBetweenImpulses*) +* the flywheel has a decelerating trend 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. + +Please note that there is a watchdog on the presence of new *currentDt* messages during an active rowing session: when the last recieved value is *maximumStrokeTimeBeforePause* ago, it will force a hard stop of the session. This watchdog will not be triggered during normal rowing sessions, but might be needed for specific magnetic resistance based machines as they tend to stop extremely fast, cutting the engine off new *currentDt* values (i.e. before the normal *maximumStrokeTimeBeforePause* expires while respecting the above conditions). ### 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 OpenRowingMonitor, **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. ## Critical parameters you must change or review for stroke detection -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. +The key feature for OpenRowingMonitor 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 OpenRowingMonitor's stroke detection to work. In this section, we help you set the most critical ones. ### setting numOfImpulsesPerRevolution -**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. +**numOfImpulsesPerRevolution** tells OpenRowingMonitor 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. +**sprocketRadius** tells OpenRowingMonitor 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*. @@ -179,13 +241,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 OpenRowingMonitor 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. + +To detect strokes, OpenRowingMonitor 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** AND 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. But stroke detection will work. 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** 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. +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: -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. +* **minumumRecoverySlope** can be set to 0, where OpenRowingMonitor will essentially 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 twice the number of magnets typically works. The technical minimum is 3. The maximum is limited by CPU-time as the algorithms used become exponentially more CPU-intensive as the *flankLength* increases. On a Raspberry Pi 4B, a *flankLength* of 18 has been succesfully used without issue. What the practical limit on a Rapberry Pi Zero 2 W is, is still a matter of investigation. Increasing the *flankLength* 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 (unlike smoothing filters). Also 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. -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`: +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, { @@ -195,7 +265,7 @@ replayRowingSession(handleRotationImpulse, { }) ``` -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. +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 OpenRowingMonitor. ### minimumDriveTime and minimumRecoveryTime @@ -271,11 +341,11 @@ When stroke detection works well, and you row consistently on the rower with a c ## 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. +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 OpenRowingMonitor 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. +**dragFactor** tells OpenRowingMonitor 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. @@ -309,11 +379,11 @@ Here, the reported slope is the calculated slope during the recovery, and the go ### 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 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. +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. OpenRowingMonitor 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. +First to change is **autoAdjustDragFactor** to "true", which tells OpenRowingMonitor that the Drag Factor must be calculated automatically. Setting it to true, will allow OpenRowingMonitor to automatically calculate the drag factor based on the already set *flywheelInertia* and the on the measured values in the stroke recovery phase. 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: @@ -321,19 +391,19 @@ Each time the drag is calculated, we also get a quality indication from that sam 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 ``` -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. +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 OpenRowingMonitor 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". +For a more accurate stroke detection, the *minumumRecoverySlope* is a crucial parameter. OpenRowingMonitor 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. +**sprocketRadius** tells OpenRowingMonitor 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 diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000000..0f29f60de1 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,91 @@ +import globals from "globals" +import pluginJs from "@eslint/js" +import js from "@eslint/js" +import stylistic from '@stylistic/eslint-plugin' +import { defineConfig } from "eslint/config" +import babelParser from "@babel/eslint-parser" + +/** @type {import('eslint').Linter.Config[]} */ +export default defineConfig([ + stylistic.configs.recommended, + { + plugins: { + '@stylistic': stylistic, + js + }, + extends: ["js/recommended"], + languageOptions: { + parser: babelParser, + globals: { + ...globals.browser, + ...globals.node + }, + ecmaVersion: 13, + sourceType: "module" + }, + rules: { + ...js.configs.recommended.rules, + // Coding issues that have a high chance of leading to errors + 'no-new': ['error'], + 'no-var': ['error'], + 'no-implicit-coercion': ['error', {'allow': ['!!']}], + 'curly': ['error', 'all'], + 'block-scoped-var': ['error'], + 'default-case': ['error'], + 'no-fallthrough': ['error', {'allowEmptyCase': true}], + 'no-continue': ['error'], + 'eqeqeq': ['error', 'always'], + 'no-cond-assign': ['error', 'always'], + 'no-unreachable': ['error'], + 'no-unreachable-loop': ['error'], + 'no-unmodified-loop-condition': ['error'], + 'no-await-in-loop': ['warn'], + 'no-useless-catch': ['error'], + 'no-console': ['error'], + 'arrow-body-style': ['warn', 'as-needed'], + '@stylistic/no-confusing-arrow': ['error', {'allowParens': false, 'onlyOneSimpleParam': false}], + '@stylistic/arrow-parens': ['warn', 'always'], + '@stylistic/quote-props': ['error', 'as-needed'], + // Bad code smells + 'complexity': ['warn', {'max': 20, 'variant': 'modified'}], + 'max-depth': ['warn', {'max': 3}], + 'max-lines': ['warn', {'max': 300, 'skipBlankLines': true, 'skipComments': true}], + 'max-statements': ['warn', { 'max': 30} , {'ignoreTopLevelFunctions': true }], + 'max-statements-per-line': ['warn', { 'max': 2 }], + '@stylistic/max-statements-per-line': ['warn', { 'max': 2 }], + 'max-params': ['warn', { 'max': 5 }], + 'no-warning-comments' : ['warn'], + // More stylistic code issues + '@stylistic/semi': ['warn', 'never'], + 'camelcase': ['warn', { 'properties': 'always', 'ignoreImports': true }], + 'no-array-constructor': ['warn'], + '@stylistic/indent': ['warn', 2, { 'SwitchCase': 1 }], + '@stylistic/no-trailing-spaces': ['warn', {'skipBlankLines': false, 'ignoreComments': false}], + '@stylistic/no-multi-spaces': ['warn', {'ignoreEOLComments': false, 'ignoreEOLComments': false}], + '@stylistic/no-tabs': ['warn'], + '@stylistic/no-multiple-empty-lines': ['warn', {'max': 1, 'maxEOF': 0, 'maxBOF': 0}], + '@stylistic/quotes': ['warn','single'], + '@stylistic/space-before-function-paren': ['warn', {'anonymous': 'never', 'named': 'always'}], + '@stylistic/one-var-declaration-per-line': ['warn', 'always'], + '@stylistic/comma-dangle': ['warn', 'never'], + '@stylistic/brace-style': ['warn', '1tbs', { 'allowSingleLine': true }], + '@stylistic/operator-linebreak': ['warn', 'after'] + }, + }, + { + // Automated tests, here more tests is always better + files: ['*/**/*.test.js'], + rules: { + 'max-depth': ['off'], + 'max-lines': ['off'], + 'max-statements': ['off'] + } + }, + { + files: ['*/client/**/*.js'], + rules: { + '@stylistic/indent': ['off'] + } + }, + pluginJs.configs.recommended, +]); diff --git a/install/config.js b/install/config.js index 35482b2524..db0b1ba659 100644 --- a/install/config.js +++ b/install/config.js @@ -1,6 +1,6 @@ 'use strict' /* - Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor You can modify this file to configure Open Rowing Monitor to your needs. This file should be placed in the 'config' folder of Open Rowing Monitor. @@ -14,25 +14,29 @@ import rowerProfiles from './rowerProfiles.js' export default { - /* - // example: change the default log level: - loglevel: { - 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 - }) - */ + // example: change the default log level: + loglevel: { + default: 'debug' + }, + + // The rower specific settings. Either choose a profile from config/rowerProfiles.js (see + // https://github.com/JaapvanEkris/openrowingmonitor/blob/main/docs/Supported_Rowers.md) or define + // the settings manually (see https://github.com/JaapvanEkris/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 Concept 2 RowErg as is + // rowerSettings: rowerProfiles.Concept2_RowErg + + // 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 + // }) } diff --git a/install/install.sh b/install/install.sh index 79601efd75..80e673d6e7 100755 --- a/install/install.sh +++ b/install/install.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +# Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor # # Installation script for Open Rowing Monitor, use at your own risk! # @@ -10,6 +10,11 @@ set -u # exit when a command fails set -e +RED=$'\e[0;31m' +YELLOW=$'\e[0;33m' +PURPLE=$'\e[0;35m' +NC=$'\e[0m' # No Color + print() { echo "$@" } @@ -48,19 +53,50 @@ ask() { done } +draw_splash() { + print "${YELLOW}" + cat <<'EOF' + ___ _______ _ ____ ____ _ _ + .' `. |_ __ \ (_) |_ \ / _| (_) / |_ +/ .-. \ _ .--. .---. _ .--. | |__) | .--. _ _ __ __ _ .--. .--./) | \/ | .--. _ .--. __ `| |-' .--. _ .--. +| | | |[ '/'`\ \/ /__\\[ `.-. | | __ / / .'`\ \[ \ [ \ [ ][ | [ `.-. | / /'`\; | |\ /| | / .'`\ \[ `.-. | [ | | | / .'`\ \[ `/'`\] +\ `-' / | \__/ || \__., | | | | _| | \ \_| \__. | \ \/\ \/ / | | | | | | \ \._// _| |_\/_| |_| \__. | | | | | | | | |,| \__. | | | + `.___.' | ;.__/ '.__.'[___||__] |____| |___|'.__.' \__/\__/ [___][___||__].',__` |_____||_____|'.__.' [___||__][___]\__/ '.__.' [___] + [__| ( ( __)) +EOF + print + print "${PURPLE}Welcome to the Open Rowing Monitor installer!${NC}" + print +} + CURRENT_DIR=$(pwd) INSTALL_DIR="/opt/openrowingmonitor" -GIT_REMOTE="https://github.com/laberning/openrowingmonitor.git" +GIT_REMOTE="https://github.com/JaapvanEkris/openrowingmonitor.git" +BRANCH="main" + +draw_splash print "This script will set up Open Rowing Monitor on one of the following devices" -print " Raspberry Pi Zero W or WH" print " Raspberry Pi Zero 2 W or WH" print " Raspberry Pi 3 Model A+, B or B+" print " Raspberry Pi 4 Model B" print +print "${RED}A Raspberry Pi 5 is currently NOT compatible${NC}" +print print "You should only run this script on a SD Card that contains Raspberry Pi OS (Lite)" print "and does not contain any important data." +ARCHITECTURE=$(uname -m) +if [[ $ARCHITECTURE == "armv6l" ]]; +then + print + print "You are running a system with ARM v6 architecture (Raspberry Pi Zero W)." + print "Support for this hardware configuration has been discontinued due to package conflicts beyond our control." + print "Your cheapest alternative for the current active branch is the Raspberry Pi Zero 2W" + print "A separate legacy branch can be found at https://github.com/JaapvanEkris/openrowingmonitor/tree/v1beta__Pi_Zero_W" + exit 1 +fi + if [[ -f "/proc/device-tree/model" ]]; then MODEL=$(tr -d '\0' < /proc/device-tree/model) else @@ -70,12 +106,13 @@ fi if [[ $MODEL != Raspberry* ]]; then print cancel "This script currently only works on Raspberry Pi OS, you will have to do a manual installation." + exit 1 fi VERSION=$(grep -oP '(?<=^VERSION=).+' /etc/os-release | tr -d '"') -if [[ $VERSION != "10 (buster)" ]] && [[ $VERSION != "11 (bullseye)" ]]; then +if [[ $VERSION != "10 (buster)" ]] && [[ $VERSION != "11 (bullseye)" ]] && [[ $VERSION != "12 (bookworm)" ]]; then print - print "Warning: So far this install script has only been tested with Raspberry Pi OS 10 (buster) and OS 11 (bullseye)." + print "Warning: So far this install script has only been tested with Raspberry Pi OS 10 (buster), 11 (bullseye) and 12 (bookworm)" if ! ask "You are running Raspberry Pi OS $VERSION, are you sure that you want to continue?" N; then exit 1 fi @@ -113,66 +150,45 @@ print print "Installing System dependencies..." sudo apt-get -y update sudo apt-get -y dist-upgrade -sudo systemctl disable bluetooth +sudo systemctl enable bluetooth +sudo systemctl daemon-reload +sudo systemctl start 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) -if [[ $ARCHITECTURE == "armv6l" ]]; -then - print "You are running a system with ARM v6 architecture. Official support for Node.js has been discontinued" - print "for ARM v6. Installing experimental unofficial build of Node.js..." - - # we stick to node 14 as there are problem with WebAssembly on node 16 on the armv6l architecture - NODEJS_VERSION=v14.18.3 - sudo rm -rf /opt/nodejs - sudo mkdir -p /opt/nodejs - sudo curl https://unofficial-builds.nodejs.org/download/release/$NODEJS_VERSION/node-$NODEJS_VERSION-linux-armv6l.tar.gz | sudo tar -xz --strip 1 -C /opt/nodejs/ - - sudo ln -sfn /opt/nodejs/bin/node /usr/bin/node - sudo ln -sfn /opt/nodejs/bin/node /usr/sbin/node - sudo ln -sfn /opt/nodejs/bin/node /sbin/node - sudo ln -sfn /opt/nodejs/bin/node /usr/local/bin/node - sudo ln -sfn /opt/nodejs/bin/npm /usr/bin/npm - sudo ln -sfn /opt/nodejs/bin/npm /usr/sbin/npm - sudo ln -sfn /opt/nodejs/bin/npm /sbin/npm - sudo ln -sfn /opt/nodejs/bin/npm /usr/local/bin/npm -else - print "Installing Node.js..." - curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - - sudo apt-get install -y nodejs -fi +print "Installing Node.js..." +curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - +sudo apt-get install -y nodejs print -print "Installing Open Rowing Monitor..." +print "Installing Open Rowing Monitor, branch $BRANCH..." if ! [[ -d "${INSTALL_DIR}" ]]; then sudo mkdir -p $INSTALL_DIR + + cd $INSTALL_DIR + + # get project code from repository + sudo git init -q + # older versions of git would use 'master' instead of 'main' for the default branch + sudo git checkout -q -b $BRANCH + sudo git config remote.origin.url $GIT_REMOTE + sudo git config remote.origin.fetch +refs/heads/*:refs/remotes/origin/* + # prevent altering line endings + sudo git config core.autocrlf false + sudo git fetch --force origin + sudo git fetch --force --tags origin + sudo git reset --hard origin/$BRANCH fi cd $INSTALL_DIR -# get project code from repository -sudo git init -q -# older versions of git would use 'master' instead of 'main' for the default branch -sudo git checkout -q -b main -sudo git config remote.origin.url $GIT_REMOTE -sudo git config remote.origin.fetch +refs/heads/*:refs/remotes/origin/* -# prevent altering line endings -sudo git config core.autocrlf false -sudo git fetch --force origin -sudo git fetch --force --tags origin -sudo git reset --hard origin/main - # add bin directory to the system path echo "export PATH=\"\$PATH:$INSTALL_DIR/bin\"" >> ~/.bashrc -# otherwise node-gyp would fail while building the system dependencies -sudo npm config set user 0 - print print "Downloading and compiling Runtime dependencies..." sudo npm ci @@ -183,7 +199,12 @@ fi print print "Setting up GPIO 17 as input and enable the pull-up resistor..." -echo -e "\n# configure GPIO 17 as input and enable the pull-up resistor for Open Rowing Monitor\ngpio=17=pu,ip" | sudo tee -a /boot/config.txt > /dev/null +if [[ $VERSION == "10 (buster)" ]] || [[ $VERSION == "11 (bullseye)" ]]; then + echo -e "\n# configure GPIO 17 as input and enable the pull-up resistor for Open Rowing Monitor\ngpio=17=pu,ip" | sudo tee -a /boot/config.txt > /dev/null +else + # In Bookworm, this file has moved + echo -e "\n# configure GPIO 17 as input and enable the pull-up resistor for Open Rowing Monitor\ngpio=17=pu,ip" | sudo tee -a /boot/firmware/config.txt > /dev/null +fi print print "Setting up Open Rowing Monitor as autostarting system service..." @@ -210,28 +231,45 @@ fi if $INIT_GUI; then print print "Installing Graphical User Interface..." - sudo apt-get -y install --no-install-recommends xserver-xorg xserver-xorg-legacy x11-xserver-utils xinit openbox chromium-browser - sudo gpasswd -a pi tty - sudo sed -i 's/allowed_users=console/allowed_users=anybody\nneeds_root_rights=yes/' /etc/X11/Xwrapper.config - sudo cp install/webbrowserkiosk.service /lib/systemd/system/ - sudo systemctl daemon-reload - sudo systemctl enable webbrowserkiosk - sudo systemctl restart webbrowserkiosk - print "sudo systemctl status webbrowserkiosk" - sudo systemctl status webbrowserkiosk + if [[ $VERSION == "10 (buster)" ]] || [[ $VERSION == "11 (bullseye)" ]]; then + sudo apt-get -y install --no-install-recommends xserver-xorg xserver-xorg-legacy x11-xserver-utils xinit openbox firefox + sudo mkdir /home/pi/.cache + sudo chown -R pi:pi /home/pi/.cache + sudo gpasswd -a pi tty + sudo sed -i 's/allowed_users=console/allowed_users=anybody\nneeds_root_rights=yes/' /etc/X11/Xwrapper.config + sudo cp install/webbrowserkiosk.service /lib/systemd/system/ + sudo systemctl daemon-reload + sudo systemctl enable webbrowserkiosk + sudo systemctl restart webbrowserkiosk + print "sudo systemctl status webbrowserkiosk" + sudo systemctl status webbrowserkiosk --no-pager + else + # ToDo: We aim to installs Wayland on Bookworm as Wayland has a better kiosk mode, as soon as we know how to do a decent Kiosk mode + sudo apt-get -y install --no-install-recommends xserver-xorg xserver-xorg-legacy x11-xserver-utils xinit openbox firefox + sudo mkdir /home/pi/.cache + sudo chown -R pi:pi /home/pi/.cache + sudo gpasswd -a pi tty + sudo sed -i 's/allowed_users=console/allowed_users=anybody\nneeds_root_rights=yes/' /etc/X11/Xwrapper.config + sudo cp install/webbrowserkiosk.service /lib/systemd/system/ + sudo systemctl daemon-reload + sudo systemctl enable webbrowserkiosk + sudo systemctl restart webbrowserkiosk + print "sudo systemctl status webbrowserkiosk" + sudo systemctl status webbrowserkiosk --no-pager + fi print print "Installation of Graphical User Interface finished." print "If the screen resolution or the screen borders are not correct, run 'sudo raspi-config' and modify the display options." fi -cd $CURRENT_DIR - print print "sudo systemctl status openrowingmonitor" -sudo systemctl status openrowingmonitor +sudo systemctl status openrowingmonitor --no-pager print print "Installation of Open Rowing Monitor finished." print "Open Rowing Monitor should now be up and running." print "You can now adjust the configuration in $INSTALL_DIR/config/config.js either via ssh or via the network share" print print "Please reboot the device for all features and settings to take effect." + +cd $CURRENT_DIR diff --git a/install/openrowingmonitor.service b/install/openrowingmonitor.service index 71ece090c4..fc63b600ac 100644 --- a/install/openrowingmonitor.service +++ b/install/openrowingmonitor.service @@ -1,6 +1,8 @@ [Unit] -Description=Open Rowing Monitor +Description=OpenRowingMonitor After=multi-user.target +StartLimitIntervalSec=60 +StartLimitBurst=5 [Service] Type=simple diff --git a/install/smb.conf b/install/smb.conf index 17ea7fd24b..dcd9bbad6a 100644 --- a/install/smb.conf +++ b/install/smb.conf @@ -1,6 +1,6 @@ -# Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +# Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor # -# Samba Configuration for Open Rowing Monitor +# Samba Configuration for OpenRowingMonitor [global] browseable = yes 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 diff --git a/install/webbrowserkiosk.sh b/install/webbrowserkiosk.sh index 1eb5680b6c..6f4f5c143a 100644 --- a/install/webbrowserkiosk.sh +++ b/install/webbrowserkiosk.sh @@ -1,15 +1,13 @@ #!/bin/bash # -# Open Rowing Monitor, https://github.com/laberning/openrowingmonitor +# Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor # -# Runs the Web Frontend in a chromium browser in fullscreen kiosk mode +# Runs the Web Frontend in a Firefox browser in fullscreen kiosk mode # xset s off xset s noblank xset -dpms 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 --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" +# Start Firefox in kiosk mode +nice -n 5 firefox --display=:0 --kiosk-monitor 0 --kiosk http://127.0.0.1/?mode=kiosk diff --git a/package-lock.json b/package-lock.json index 995beada5d..74a0ebe07a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,207 +1,120 @@ { - "name": "openrowingmonitor", - "version": "0.8.2", - "lockfileVersion": 2, + "name": "OpenRowingMonitor", + "version": "0.9.6", + "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "openrowingmonitor", - "version": "0.8.2", + "name": "OpenRowingMonitor", + "version": "0.9.6", "license": "GPL-3.0", "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", - "lit": "2.1.3", - "loglevel": "1.8.0", + "@markw65/fit-file-writer": "^0.1.6", + "ble-host": "^1.0.3", + "chart.js": "^4.5.0", + "chartjs-plugin-datalabels": "^2.2.0", + "finalhandler": "^2.1.0", + "incyclist-ant-plus": "^0.3.5", + "lit": "^2.8.0", + "loglevel": "^1.9.1", + "mqtt": "^5.13.1", + "node-fetch": "^3.3.2", "nosleep.js": "0.12.0", "pigpio": "3.3.1", - "serve-static": "1.14.2", - "ws": "8.5.0", - "xml2js": "0.4.23" + "replace-in-file": "^8.3.0", + "serve-static": "^2.2.0", + "ws": "^8.18.3" }, "devDependencies": { - "@babel/eslint-parser": "7.17.0", - "@babel/plugin-proposal-decorators": "7.17.2", - "@babel/preset-env": "7.16.11", - "@rollup/plugin-babel": "5.3.0", - "@rollup/plugin-commonjs": "21.0.1", - "@rollup/plugin-node-resolve": "13.1.3", - "@snowpack/plugin-babel": "2.1.7", - "@web/rollup-plugin-html": "1.10.1", - "axios": "0.25.0", - "eslint": "8.9.0", - "eslint-config-standard": "17.0.0-0", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-lit": "1.6.1", - "eslint-plugin-n": "14.0.0", - "eslint-plugin-promise": "6.0.0", - "eslint-plugin-wc": "1.3.2", + "@babel/eslint-parser": "^7.27.5", + "@babel/plugin-proposal-decorators": "^7.23.9", + "@babel/preset-env": "^7.27.2", + "@eslint/js": "^9.30.0", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^28.0.6", + "@rollup/plugin-node-resolve": "^16.0.0", + "@rollup/plugin-terser": "^0.4.4", + "@stylistic/eslint-plugin": "^5.1.0", + "@web/rollup-plugin-html": "^2.1.2", + "eslint": "^9.30.0", + "globals": "^16.2.0", "http2-proxy": "5.0.53", - "markdownlint-cli2": "0.4.0", - "nodemon": "2.0.15", + "markdownlint-cli2": "^0.18.1", + "nodemon": "^3.0.3", "npm-run-all": "4.1.5", - "rollup": "2.67.2", - "rollup-plugin-summary": "1.3.0", - "rollup-plugin-terser": "7.0.2", - "simple-git-hooks": "2.7.0", - "snowpack": "3.8.8", - "tar": "6.1.11", - "uvu": "0.5.3" + "rollup": "^4.44.1", + "rollup-plugin-summary": "^3.0.0", + "simple-git-hooks": "^2.9.0", + "tar": "^7.4.3", + "uvu": "^0.5.6" }, "engines": { - "node": ">=14" - }, - "optionalDependencies": { - "@abandonware/bluetooth-hci-socket": "0.5.3-7" - } - }, - "node_modules/@abandonware/bleno": { - "version": "0.5.1-4", - "resolved": "https://registry.npmjs.org/@abandonware/bleno/-/bleno-0.5.1-4.tgz", - "integrity": "sha512-2K/gbDxh4l4TV8xT/XUCwCT3e5aGDGmYad8gxt19CEvBMCs0+JScZ7roNyX0Jzice5rrR5RETcsMwIjJSzbeCQ==", - "hasInstallScript": true, - "os": [ - "darwin", - "linux", - "android", - "freebsd", - "win32" - ], - "dependencies": { - "debug": "^4.3.1", - "napi-thread-safe-callback": "0.0.6", - "node-addon-api": "^3.1.0" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "@abandonware/bluetooth-hci-socket": "^0.5.3-7", - "bplist-parser": "0.3.0", - "xpc-connect": "^2.0.0" - } - }, - "node_modules/@abandonware/bluetooth-hci-socket": { - "version": "0.5.3-7", - "resolved": "https://registry.npmjs.org/@abandonware/bluetooth-hci-socket/-/bluetooth-hci-socket-0.5.3-7.tgz", - "integrity": "sha512-CaGDBeXEooRjaVJlgmnaWeI+MXlEBVN9705tp2GHCF2IFARH3h15lqf6eHjqFsdpQOiMWiBa/QZUAOGjzBrhmA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "linux", - "android", - "freebsd", - "win32" - ], - "dependencies": { - "debug": "^4.3.1", - "nan": "^2.14.2", - "node-pre-gyp": "^0.17.0" - }, - "optionalDependencies": { - "usb": "^1.6.3" - } - }, - "node_modules/@abandonware/noble": { - "version": "1.9.2-15", - "resolved": "https://registry.npmjs.org/@abandonware/noble/-/noble-1.9.2-15.tgz", - "integrity": "sha512-qD9NN5fzvbtHdWYFPDzxY2AveILvDSRX/PTdL0V+CUfyF70ggIJtLBc1WW1hbVMIpu8rZylYgrK+PUEBwIpjCg==", - "hasInstallScript": true, - "os": [ - "darwin", - "linux", - "freebsd", - "win32" - ], - "dependencies": { - "debug": "^4.3.1", - "node-addon-api": "^3.2.0" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "@abandonware/bluetooth-hci-socket": "^0.5.3-8" - } - }, - "node_modules/@abandonware/noble/node_modules/@abandonware/bluetooth-hci-socket": { - "version": "0.5.3-8", - "resolved": "https://registry.npmjs.org/@abandonware/bluetooth-hci-socket/-/bluetooth-hci-socket-0.5.3-8.tgz", - "integrity": "sha512-JIUkTZpAo6vKyXd94OasynjnmAxgCvn3VRrQJM/KXBKbm/yW59BMK6ni1wLy/JLM4eFhsLkd2S907HJnXBSWKw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "linux", - "android", - "freebsd", - "win32" - ], - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.5", - "debug": "^4.3.2", - "nan": "^2.15.0" - }, - "optionalDependencies": { - "usb": "^1.7.2" + "node": ">=20" } }, "node_modules/@ampproject/remapping": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.1.tgz", - "integrity": "sha512-Aolwjd7HSC2PyY0fDj/wA/EimQT4HfEnFYNp5s9CQlrdhyvWTtvZ5YzrUPu6R6/1jKiUlxu8bUhkdSnKHNAHMA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.7.tgz", + "integrity": "sha512-xgu/ySj2mTiUFmdE9yCMfBxLp4DHd5DwmbbD05YAuICfodYT3VvRxbrh81LGQ/8UpSdtMdfKMn3KouYDX59DGQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.2.tgz", - "integrity": "sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.0.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.7.tgz", + "integrity": "sha512-BU2f9tlKQ5CAthiMIgpzAh4eDTLWo1mqi9jqE2OxMG0E/OM199VJt2q8BztTxpnSW0i1ymdwLXRJnYzvDM5r2w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.27.7", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.7", + "@babel/types": "^7.27.7", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -212,93 +125,85 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.5.tgz", + "integrity": "sha512-HLkYQfRICudzcOtjGwkPvGc5nF1b4ljLZh1IRDj50lRZ718NAKVgQpIAUX8bfg6u/yuSKY3L7E0YzIV+OxrB8Q==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || >=14.0.0" }, "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", + "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/parser": "^7.27.5", + "@babel/types": "^7.27.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", - "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -308,13 +213,15 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -324,282 +231,210 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.22.10" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "node_modules/@babel/parser": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.7.tgz", + "integrity": "sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/types": "^7.27.7" }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", - "dev": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -607,13 +442,15 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -622,84 +459,83 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.13.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", - "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.12.0" + "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz", - "integrity": "sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.27.1.tgz", + "integrity": "sha512-DTxe4LBPrtFdsWzgpmbBKevg3e9PBy+dXRt19kSbucbZvL2uqtdqwwpluL1jfxYE0wIDTFp1nTy/q6gNLsxXrg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.1", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/plugin-syntax-decorators": "^7.17.0", - "charcodes": "^0.2.0" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-decorators": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -708,15 +544,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -724,14 +557,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", + "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -740,14 +573,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -756,14 +589,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -772,30 +605,31 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -804,17 +638,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", - "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", + "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -823,14 +656,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -839,15 +674,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -856,14 +690,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.5.tgz", + "integrity": "sha512-JF6uE2s67f0y2RZcm2kpAUEbD50vH62TyWVebxwHAlbSdM49VqPz8t4a1uIjp4NIOIZ4xzLfjY5emt/RCyC7TQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -872,16 +706,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -890,53 +723,63 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/@babel/plugin-transform-classes": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.7.tgz", + "integrity": "sha512-CuLkokN1PEZ0Fsjtq+001aog/C2drDK9nTfK/NRK0n6rBin6cBrvM+zfQjDE+UllhR6/J4a6w8Xq9i4yi3mQrw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.27.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -945,13 +788,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz", - "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.7.tgz", + "integrity": "sha512-pg3ZLdIKWCP0CrJm0O4jYjVthyBeioVfvz9nwt6o5paUxsgJ/8GucSMAIaj6M7xA4WY+SrvtGu2LijzkdyecWQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.7" }, "engines": { "node": ">=6.9.0" @@ -960,121 +805,163 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1083,13 +970,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1098,13 +986,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1113,15 +1002,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1130,13 +1019,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1145,13 +1036,17 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1160,20 +1055,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1182,28 +1072,31 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", - "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1212,14 +1105,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1228,13 +1121,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1243,14 +1137,18 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.7.tgz", + "integrity": "sha512-201B1kFTWhckclcXpWHc8uUpYziDX/Pl4rxl0ZX0DiCZ3jknwfSUALL3QCYeeXXB37yWxJbo+g+Vfq8pAaHi3w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.7", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.27.7" }, "engines": { "node": ">=6.9.0" @@ -1259,13 +1157,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1274,15 +1174,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1291,13 +1190,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1306,13 +1207,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1321,15 +1223,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1338,16 +1240,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1356,17 +1258,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1375,14 +1274,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.5.tgz", + "integrity": "sha512-uhB8yHerfe3MWnuLAhEbeQ4afVoqv8BQsPqrTv7e/jZ9y00kJL6l9a/f4OWaKxotmjzewfEyXE1vgDJenkQ2/Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1391,13 +1290,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1406,13 +1307,14 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1421,14 +1323,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1437,13 +1339,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1452,13 +1356,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1467,13 +1372,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "dev": true, + "license": "MIT", "dependencies": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1482,13 +1388,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1497,13 +1404,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1512,14 +1420,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1528,13 +1437,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1543,28 +1454,99 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/@babel/preset-env": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz", + "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.27.1", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.27.1", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.27.2", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.27.1", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.40.0", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -1573,437 +1555,461 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" + "node_modules/@babel/traverse": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.7.tgz", + "integrity": "sha512-X6ZlfR/O/s5EQ/SnUSLzr+6kGnkg8HXGMzpgsMsrJVcfDtH1vIp6ctCN4eZ1LS5c0+te5Cb6Y514fASjMRJ1nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.5", + "@babel/parser": "^7.27.7", + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.7", + "debug": "^4.3.1", + "globals": "^11.1.0" }, "engines": { "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.7.tgz", + "integrity": "sha512-8OLQgDScAOHXnAz2cV+RfzzNMipuLVBz2biuAJFMV9bfkNf393je3VM8CLkjQodW5+iWsSJdSgSWT6rsZoXHPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.0", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.1.0.tgz", - "integrity": "sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.1", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/@eslint/js": { + "version": "9.30.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.0.tgz", + "integrity": "sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@gar/promisify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz", - "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==", - "dev": true + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz", - "integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==", + "node_modules/@eslint/plugin-kit": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, - "node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", - "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", - "dev": true + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, "engines": { - "node": ">=6.0.0" + "node": ">=18.18.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", - "dev": true + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@lit/reactive-element": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.2.2.tgz", - "integrity": "sha512-HkhTTO2rT8jlf4izz7ME/+YUjqz+ZHgmnOKorA+7tkDmQDg6QzDpWSFz//1YyiL193W4bc7rlQCiYyFiZa9pkQ==" + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", - "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", - "optional": true, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", "dependencies": { - "detect-libc": "^1.0.3", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.5", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" + "engines": { + "node": ">=12" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "optional": true, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "minipass": "^7.0.4" }, "engines": { - "node": ">=10" + "node": ">=18.0.0" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "optional": true, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">=10" + "node": ">=6.0.0" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "optional": true, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "optional": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=6.0.0" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "optional": true, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "license": "MIT", "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "optional": true, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "optional": true, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.3.0.tgz", + "integrity": "sha512-nQIWonJ6eFAvUUrSlwyHDm/aE8PBDu5kRpL0vHMg6K8fK3Diq1xdPjTnsJSwxABhaZ+5eBi1btQB5ShUTKo4nQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/reactive-element": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz", + "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==", + "license": "BSD-3-Clause", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "@lit-labs/ssr-dom-shim": "^1.0.0" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "optional": true, + "node_modules/@markw65/fit-file-writer": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@markw65/fit-file-writer/-/fit-file-writer-0.1.6.tgz", + "integrity": "sha512-EmJhk6mEnSK1Xy0sxyxEUxus9Dzvz58rNOyltnse8k2JUnbL8Uwz1+6E0XYJQ+FQLbrmkY7jluEEaftLb/ceIg==", + "license": "MIT" + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" + "eslint-scope": "5.1.1" } }, "node_modules/@nodelib/fs.scandir": { @@ -2011,6 +2017,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2024,6 +2031,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -2033,6 +2041,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2041,559 +2050,635 @@ "node": ">= 8" } }, - "node_modules/@npmcli/arborist": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.10.0.tgz", - "integrity": "sha512-CLnD+zXG9oijEEzViimz8fbOoFVb7hoypiaf7p6giJhvYtrxLAyY3cZAMPIFQvsG731+02eMDp3LqVBNo7BaZA==", - "dev": true, - "dependencies": { - "@isaacs/string-locale-compare": "^1.0.1", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^1.0.2", - "@npmcli/metavuln-calculator": "^1.1.0", - "@npmcli/move-file": "^1.1.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^1.0.1", - "@npmcli/package-json": "^1.0.1", - "@npmcli/run-script": "^1.8.2", - "bin-links": "^2.2.1", - "cacache": "^15.0.3", - "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "npm-install-checks": "^4.0.0", - "npm-package-arg": "^8.1.5", - "npm-pick-manifest": "^6.1.0", - "npm-registry-fetch": "^11.0.0", - "pacote": "^11.3.5", - "parse-conflict-json": "^1.1.1", - "proc-log": "^1.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "ssri": "^8.0.1", - "treeverse": "^1.0.4", - "walk-up-path": "^1.0.0" - }, - "bin": { - "arborist": "bin/index.js" - }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, "engines": { - "node": ">= 10" + "node": ">=14" } }, - "node_modules/@npmcli/arborist/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/@rollup/plugin-babel": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", + "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==", "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/arborist/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" + "node": ">=14.0.0" }, - "bin": { - "semver": "bin/semver.js" + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, - "engines": { - "node": ">=10" + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } } }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "node_modules/@rollup/plugin-commonjs": { + "version": "28.0.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz", + "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==", "dev": true, + "license": "MIT", "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=10" + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@npmcli/git": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", - "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", + "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", "dev": true, + "license": "MIT", "dependencies": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - } - }, - "node_modules/@npmcli/git/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/git/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" + "node": ">=14.0.0" }, - "bin": { - "semver": "bin/semver.js" + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" }, - "engines": { - "node": ">=10" + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", "dev": true, + "license": "MIT", "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "installed-package-contents": "index.js" + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" }, "engines": { - "node": ">= 10" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@npmcli/map-workspaces": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-1.0.4.tgz", - "integrity": "sha512-wVR8QxhyXsFcD/cORtJwGQodeeaDf0OxcHie8ema4VgFeqwYkFsDPnSrIRSytX8xR6nKPAH89WnwTcaU608b/Q==", + "node_modules/@rollup/pluginutils": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "dev": true, + "license": "MIT", "dependencies": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^7.1.6", - "minimatch": "^3.0.4", - "read-package-json-fast": "^2.0.1" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=10" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@npmcli/metavuln-calculator": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-1.1.1.tgz", - "integrity": "sha512-9xe+ZZ1iGVaUovBVFI9h3qW+UuECUzhvZPxK9RaEA2mjU26o5D0JloGYWwLYvQELJNmBdQB6rrpuN8jni6LwzQ==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz", + "integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "cacache": "^15.0.5", - "pacote": "^11.1.11", - "semver": "^7.3.2" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@npmcli/metavuln-calculator/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz", + "integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz", + "integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@npmcli/move-file/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz", + "integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==", + "cpu": [ + "x64" + ], "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@npmcli/name-from-folder": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz", - "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==", - "dev": true + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz", + "integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@npmcli/node-gyp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", - "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", - "dev": true + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz", + "integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@npmcli/package-json": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-1.0.1.tgz", - "integrity": "sha512-y6jnu76E9C23osz8gEMBayZmaZ69vFOIk8vR1FJL/wbEJ54+9aVG9rLTjQKSXfgYZEr50nw1txBBFfBZZe+bYg==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz", + "integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^2.3.1" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@npmcli/promise-spawn": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", - "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz", + "integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "infer-owner": "^1.0.4" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@npmcli/run-script": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz", - "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz", + "integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rollup/plugin-babel": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", - "integrity": "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz", + "integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - } - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rollup/plugin-commonjs": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz", - "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==", + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz", + "integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==", + "cpu": [ + "loong64" + ], "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^2.38.3" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rollup/plugin-inject": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-4.0.4.tgz", - "integrity": "sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ==", + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz", + "integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "estree-walker": "^2.0.1", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz", + "integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.0.8" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz", - "integrity": "sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz", + "integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^2.42.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz", + "integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz", + "integrity": "sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz", + "integrity": "sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz", + "integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz", + "integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz", + "integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/@stylistic/eslint-plugin": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.1.0.tgz", + "integrity": "sha512-TJRJul4u/lmry5N/kyCU+7RWWOk0wyXN+BncRlDYBqpLFnzXkd7QGVfN7KewarFIXv0IX0jSF/Ksu7aHWEDeuw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/types": "^8.34.1", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" }, "engines": { - "node": ">= 8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "eslint": ">=9.0.0" } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/@sindresorhus/is": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.4.0.tgz", - "integrity": "sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ==", + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@snowpack/plugin-babel": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@snowpack/plugin-babel/-/plugin-babel-2.1.7.tgz", - "integrity": "sha512-q8Zz6nqJ/CHaWccvNCTGP95d/lQLrImiBfJCagO4xcN9p53SUqapd9Yl3uMFeqvrgZP+kFK1vo/edifZWFLo5Q==", + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.10.5", - "workerpool": "^6.0.0" + "@types/ms": "*" } }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, - "engines": { - "node": ">= 6" - } + "license": "MIT" }, - "node_modules/@types/cacheable-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", - "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", + "node_modules/@types/katex": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", + "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true + "license": "MIT" }, - "node_modules/@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "dev": true, - "dependencies": { - "@types/node": "*" - } + "license": "MIT" }, "node_modules/@types/node": { - "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.17.tgz", - "integrity": "sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "version": "24.0.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.7.tgz", + "integrity": "sha512-YIEUUr4yf8q8oQoXPpSlnvKNVKDQlPMWrmOcgzoduo7kvA2UF0/BwJ/eMKFTiTtkNL17I0M6Xe2tvwFU7be6iw==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.8.0" + } }, "node_modules/@types/parse5": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", "dev": true, + "license": "MIT" + }, + "node_modules/@types/readable-stream": { + "version": "4.0.21", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.21.tgz", + "integrity": "sha512-19eKVv9tugr03IgfXlA9UVUVRbW6IuqRO5B92Dl4a6pT7K8uaGrNS0GkxiZD0BOk6PLuXl5FhWl//eX/pzYdTQ==", + "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true, - "dependencies": { - "@types/node": "*" - } + "license": "MIT" }, "node_modules/@types/trusted-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", - "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==", + "license": "MIT", + "optional": true + }, + "node_modules/@typescript-eslint/types": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.0.tgz", + "integrity": "sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } }, "node_modules/@web/parse5-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@web/parse5-utils/-/parse5-utils-1.3.0.tgz", - "integrity": "sha512-Pgkx3ECc8EgXSlS5EyrgzSOoUbM6P8OKS471HLAyvOBcP1NCBn0to4RN/OaKASGq8qa3j+lPX9H14uA5AHEnQg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@web/parse5-utils/-/parse5-utils-2.1.0.tgz", + "integrity": "sha512-GzfK5disEJ6wEjoPwx8AVNwUe9gYIiwc+x//QYxYDAFKUp4Xb1OJAGLc2l2gVrSQmtPGLKrTRcW90Hv4pEq1qA==", "dev": true, + "license": "MIT", "dependencies": { "@types/parse5": "^6.0.1", "parse5": "^6.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/@web/rollup-plugin-html": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@web/rollup-plugin-html/-/rollup-plugin-html-1.10.1.tgz", - "integrity": "sha512-XYJxHtdllwA5l4X8wh8CailrOykOl3YY+BRqO8+wS/I1Kq0JFISg3EUHdWAyVcw0TRDnHNLbOBJTm2ptAM+eog==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@web/rollup-plugin-html/-/rollup-plugin-html-2.3.0.tgz", + "integrity": "sha512-ap4AisBacK6WwrTnVlPErupxlywWU1ELsjGIMZ4VpofvhbVTBIGErJo5VEj2mSJyEH3I1EbzUcWuhDCePrnWEw==", "dev": true, + "license": "MIT", "dependencies": { - "@web/parse5-utils": "^1.3.0", - "glob": "^7.1.6", - "html-minifier-terser": "^6.0.0", - "parse5": "^6.0.1" + "@web/parse5-utils": "^2.1.0", + "glob": "^10.0.0", + "html-minifier-terser": "^7.1.0", + "lightningcss": "^1.24.0", + "parse5": "^6.0.1", + "picomatch": "^2.2.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" } }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "devOptional": true + "node_modules/@web/rollup-plugin-html/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } }, "node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2606,72 +2691,17 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/address": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", - "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", - "dev": true, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "devOptional": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.0.tgz", - "integrity": "sha512-0PhAp58jZNw13UJv7NVdTGb0ZcghHUb3DrZ046JiiJY/BOaTTpbwdHq2VObPCBV8M2GPh7sgrJ3AQ8Ey468LJw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2683,75 +2713,39 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-align/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "devOptional": true, + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/ant-plus": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/ant-plus/-/ant-plus-0.1.24.tgz", - "integrity": "sha512-otEIAN+9jtu/1mwHL81au0sO7muJT1QrWOm9j29NEg3x1Y+ZsSIYX+LSdY+BBr2mLA4hT/vpqv5pWX9KDWceVg==", - "dependencies": { - "usb": "^1.6.0" + "node": ">=8" }, - "engines": { - "node": ">=6.0.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2760,39 +2754,35 @@ "node": ">= 8" } }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "devOptional": true - }, - "node_modules/are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "devOptional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, - "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" @@ -2801,27 +2791,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", - "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -2830,334 +2813,162 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/as-table": { - "version": "1.0.55", - "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", - "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", - "dev": true, - "dependencies": { - "printable-characters": "^1.0.42" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.1", - "util": "0.10.3" - } - }, - "node_modules/assert-plus": { + "node_modules/async-function": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, + "license": "MIT", "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.14.7" + "node": ">= 0.4" } }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "dependencies": { - "object.assign": "^4.1.0" + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "devOptional": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } + "license": "MIT" }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "devOptional": true, - "engines": { - "node": ">=0.6" - } + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "node_modules/bin-links": { + "node_modules/binary-extensions": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-2.3.0.tgz", - "integrity": "sha512-JzrOLHLwX2zMqKdyYZjkDgQGT+kHDkIhv2/IK2lJ00qLxV4TmFoHi8drDBb6H5Zrz1YfgHkai4e2MGPqnoUhqA==", - "dev": true, - "dependencies": { - "cmd-shim": "^4.0.1", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^2.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^3.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", "dependencies": { "file-uri-to-path": "1.0.0" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/boxen/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/boxen/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/boxen/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/bl": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.0.tgz", + "integrity": "sha512-ClDyJGQkc8ZtzdAAbAwBmhMSpwN/sC9HA8jxdYm6nVUbCfZbe2mgza4qh7AuEYyEPB/c4Kznf9s66bnsKMQDjw==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@types/readable-stream": "^4.0.0", + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" } }, - "node_modules/bplist-parser": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.0.tgz", - "integrity": "sha512-zgmaRvT6AN1JpPPV+S0a1/FAtoxSreYDccZGIqEMSvZl9DMe70mJ7MFzpxa1X+gHVdkToE2haRUHHMiW1OdejA==", - "optional": true, - "dependencies": { - "big-integer": "1.6.x" - }, - "engines": { - "node": ">= 5.10.0" + "node_modules/ble-host": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ble-host/-/ble-host-1.0.3.tgz", + "integrity": "sha512-DBKWrz2dCQzHS4HnPd8pNaXACQpcIN51JmZtuEnmW9dkS0RkM9Jbfu5JyLcr5Iie+9SHvZsCmvG3jHaVAlcxrQ==", + "license": "ISC", + "optionalDependencies": { + "hci-socket": "^1.0.0" } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "devOptional": true, + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3168,6 +2979,7 @@ "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-4.0.0.tgz", "integrity": "sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==", "dev": true, + "license": "MIT", "dependencies": { "duplexer": "0.1.1" }, @@ -3176,165 +2988,113 @@ } }, "node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "license": "MIT" }, - "node_modules/bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "devOptional": true, - "hasInstallScript": true, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", "dependencies": { - "node-gyp-build": "^4.3.0" + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" }, "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true, - "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", - "dev": true - }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">= 10" + "node": ">= 0.4" } }, - "node_modules/cacache/node_modules/mkdirp": { + "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, + "license": "MIT", "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true, "engines": { - "node": ">=6" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3345,6 +3105,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3354,110 +3115,110 @@ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dev": true, + "license": "MIT", "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/caniuse-lite": { + "version": "1.0.30001726", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz", + "integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001311", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001311.tgz", - "integrity": "sha512-mleTFtFKfykEeW34EyfhGIFjGCqzhh38Y0LhdQ9aWF+HorZTtdgKV/1hEE0NlFkG2ubvisPV6l400tlbPys98A==", + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "dev": true, + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/charcodes": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz", - "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==", + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", "dev": true, - "engines": { - "node": ">=6" + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, + "node_modules/chart.js": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz", + "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==", + "license": "MIT", "dependencies": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" + "@kurkle/color": "^0.3.0" }, "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + "pnpm": ">=8" } }, - "node_modules/cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "license": "MIT", + "peerDependencies": { + "chart.js": ">=3.0.0" } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -3470,6 +3231,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -3479,6 +3243,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -3487,31 +3252,21 @@ } }, "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "devOptional": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, "node_modules/clean-css": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", - "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", "dev": true, + "license": "MIT", "dependencies": { "source-map": "~0.6.0" }, @@ -3519,261 +3274,243 @@ "node": ">= 10.0" } }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, "engines": { - "node": ">=0.10.0" + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "node_modules/cli-table3/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "engines": { - "node": ">=6" + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "node_modules/cli-table3/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "mimic-response": "^1.0.0" + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/cmd-shim": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz", - "integrity": "sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw==", - "dev": true, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", "dependencies": { - "mkdirp-infer-owner": "^2.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "devOptional": true, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "optional": true, - "bin": { - "color-support": "bin.js" + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=0.1.90" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 0.8" + "node": ">=7.0.0" } }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 12" + "node": ">=14" } }, - "node_modules/common-ancestor-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", - "dev": true + "node_modules/commist": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", + "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==", + "license": "MIT" }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "devOptional": true - }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "devOptional": true - }, "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } + "license": "MIT", + "peer": true }, "node_modules/core-js-compat": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", - "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", + "version": "3.43.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.43.0.tgz", + "integrity": "sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.19.1", - "semver": "7.0.0" + "browserslist": "^4.25.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "devOptional": true - }, - "node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cosmiconfig/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3783,73 +3520,85 @@ "node": ">= 8" } }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 12" } }, - "node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, + "license": "MIT", "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/fb55" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, "engines": { - "node": ">= 6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/fb55" + "url": "https://github.com/sponsors/inspect-js" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, - "bin": { - "cssesc": "bin/cssesc" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, + "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==", + "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" + "lodash.isequal": "^4.5.0" } }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3860,304 +3609,124 @@ } } }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", "dev": true, + "license": "MIT", "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" + "character-entities": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "devOptional": true, - "engines": { - "node": ">=4.0.0" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/default-browser-id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-2.0.0.tgz", - "integrity": "sha1-AezONxpx6F8VoXF354YwR+c9vn0=", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { - "bplist-parser": "^0.1.0", - "pify": "^2.3.0", - "untildify": "^2.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/default-browser-id/node_modules/bplist-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", - "integrity": "sha1-1g1dzCDLptx+HymbNdPh+V2vuuY=", - "dev": true, - "dependencies": { - "big-integer": "^1.6.7" - } - }, - "node_modules/default-browser-id/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { - "object-keys": "^1.0.12" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "devOptional": true - }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/dequal": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz", - "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/detect-port": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", - "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", - "dev": true, - "dependencies": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" - }, - "engines": { - "node": ">= 4.2.1" - } - }, - "node_modules/detect-port/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/detect-port/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dev": true, - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, + "license": "Apache-2.0", "engines": { "node": ">=8" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "dev": true, + "license": "MIT", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "dequal": "^2.0.0" }, "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "node": ">=0.3.1" } }, "node_modules/dot-case": { @@ -4165,159 +3734,151 @@ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, + "license": "MIT", "dependencies": { - "is-obj": "^2.0.0" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, "node_modules/duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "integrity": "sha512-sxNZ+ljy+RA1maXoUReeqBBpBC6RLKmg5ewzV+x+mSETmWNoKdZN6vcQjpFROemza23hGFskJtFNoUWUaQ+R4Q==", "dev": true }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.68", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz", - "integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA==", - "dev": true + "version": "1.5.177", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.177.tgz", + "integrity": "sha512-7EH2G59nLsEMj97fpDuvVcYi6lwTcM1xuWw3PssD8xzboAW7zj7iB3COEEEATUfjLHrs5uKBLQT03V/8URx06g==", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "devOptional": true + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" }, "engines": { "node": ">= 0.4" @@ -4326,1148 +3887,966 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-module-lexer": { - "version": "0.3.26", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz", - "integrity": "sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==", - "dev": true - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, + "license": "MIT", "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.9.7.tgz", - "integrity": "sha512-VtUf6aQ89VTmMLKrWHYG50uByMF4JQlVysb8dmg6cOgW8JnFCipmz7p+HNBl+RR3LLCuBxFGVauAe2wfnF9bLg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esinstall": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/esinstall/-/esinstall-1.1.7.tgz", - "integrity": "sha512-irDsrIF7fZ5BCQEAV5gmH+4nsK6JhnkI9C9VloXdmzJLbM1EcshPw8Ap95UUGc4ZJdzGeOrjV+jgKjQ/Z7Q3pg==", - "dev": true, - "dependencies": { - "@rollup/plugin-commonjs": "^16.0.0", - "@rollup/plugin-inject": "^4.0.2", - "@rollup/plugin-json": "^4.0.0", - "@rollup/plugin-node-resolve": "^10.0.0", - "@rollup/plugin-replace": "^2.4.2", - "builtin-modules": "^3.2.0", - "cjs-module-lexer": "^1.2.1", - "es-module-lexer": "^0.6.0", - "execa": "^5.1.1", - "is-valid-identifier": "^2.0.2", - "kleur": "^4.1.1", - "mkdirp": "^1.0.3", - "picomatch": "^2.3.0", - "resolve": "^1.20.0", - "rimraf": "^3.0.0", - "rollup": "~2.37.1", - "rollup-plugin-polyfill-node": "^0.6.2", - "slash": "~3.0.0", - "validate-npm-package-name": "^3.0.0", - "vm2": "^3.9.2" - } - }, - "node_modules/esinstall/node_modules/@rollup/plugin-commonjs": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz", - "integrity": "sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^2.30.0" + "node": ">= 0.4" } }, - "node_modules/esinstall/node_modules/@rollup/plugin-node-resolve": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-10.0.0.tgz", - "integrity": "sha512-sNijGta8fqzwA1VwUEtTvWCx2E7qC70NMsDh4ZG13byAXYigBNZMxALhKUSycBks5gupJdq0lFrKumFrRZ8H3A==", + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, + "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.17.0" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { - "node": ">= 10.0.0" + "node": ">= 0.4" }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esinstall/node_modules/es-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.6.0.tgz", - "integrity": "sha512-f8kcHX1ArhllUtb/wVSyvygoKCznIjnxhLxy7TCvIiMdT7fL4ZDTIKaadMe6eLvOXg6Wk02UeoFgUoZ2EKZZUA==", - "dev": true - }, - "node_modules/esinstall/node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=6" } }, - "node_modules/esinstall/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, - "node_modules/esinstall/node_modules/rollup": { - "version": "2.37.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.37.1.tgz", - "integrity": "sha512-V3ojEeyGeSdrMSuhP3diBb06P+qV4gKQeanbDv+Qh/BZbhdZ7kHV0xAt8Yjk4GFshq/WjO7R4c7DFM20AwTFVQ==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, + "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=10" }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/esinstall/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", - "integrity": "sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.1.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", + "version": "9.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.0.tgz", + "integrity": "sha512-iN/SiPxmQu6EVkf+m1qpBxzUhE12YqFLOSySuOyVLJLEF9nzTf+h/1AJYc1JWzCnktggeNrjvQGLngDzXirU6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.30.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.0.0-0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0-0.tgz", - "integrity": "sha512-sf9udec8fkLTnH82SmhZQ3E31e4eJaMW09Mt9fbN3OccXFtvSSbGrltpQgGFVooGHoIdiMzDfp6ZNFd+I6Ob+w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "url": "https://eslint.org/donate" + }, "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^14.0.0", - "eslint-plugin-promise": "^6.0.0" + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "dependencies": { - "ms": "^2.1.1" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, - "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "ms": "^2.1.1" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=8.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">=6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "estraverse": "^5.1.0" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "node": ">=0.10" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "ms": "2.0.0" + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=4.0" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" }, - "node_modules/eslint-plugin-lit": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.6.1.tgz", - "integrity": "sha512-BpPoWVhf8dQ/Sz5Pi9NlqbGoH5BcMcVyXhi2XTx2XGMAO9U2lS+GTSsqJjI5hL3OuxCicNiUEWXazAwi9cAGxQ==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "dependencies": { - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "requireindex": "^1.2.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "eslint": ">= 5" + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-n": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-14.0.0.tgz", - "integrity": "sha512-mNwplPLsbaKhHyA0fa/cy8j+oF6bF6l81hzBTWa6JOvPcMNAuIogk2ih6d9tYvWYzyUG+7ZFeChqbzdFpg2QrQ==", - "dev": true, - "dependencies": { - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.3.0", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { - "node": ">=12.22.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "node": ">= 0.6" } }, - "node_modules/eslint-plugin-promise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", - "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", - "dev": true, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "node": ">=6" } }, - "node_modules/eslint-plugin-wc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-1.3.2.tgz", - "integrity": "sha512-/Tt3kIXBp1jh06xYtRqPwAvpNxVVk9YtbcFCKEgLa5l3GY+urZyn376pISaaZxkm9HVD3AIPOF5i9/uFwyF0Zw==", - "dev": true, - "dependencies": { - "is-valid-element-name": "^1.0.0", - "js-levenshtein-esm": "^1.2.0" - }, - "peerDependencies": { - "eslint": ">=5" + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" }, "engines": { - "node": ">=8.0.0" + "node": ">=8.6.0" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "node": ">= 6" } }, - "node_modules/eslint-visitor-keys": { + "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, + "license": "MIT" + }, + "node_modules/fast-unique-numbers": { + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz", + "integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@babel/runtime": "^7.23.8", + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=16.1.0" } }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "reusify": "^1.0.4" } }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "engines": { - "node": ">=7.0.0" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^12.20 || >= 14.13" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=16.0.0" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/filesize": { + "version": "10.1.6", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz", + "integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==", "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=4.0" + "node": ">= 10.4.0" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "to-regex-range": "^5.0.1" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.3.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=16" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } + "license": "ISC" }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, + "license": "MIT", "dependencies": { - "estraverse": "^5.1.0" + "is-callable": "^1.2.7" }, "engines": { - "node": ">=0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, "engines": { - "node": ">=4.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "fetch-blob": "^3.1.2" }, "engines": { - "node": ">=4.0" + "node": ">=12.20.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">= 0.8" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, - "engines": [ - "node >=0.6.0" - ] + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { - "node": ">=8.6.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { - "reusify": "^1.0.4" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fdir": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-5.2.0.tgz", - "integrity": "sha512-skyI2Laxtj9GYzmktPgY6DT8uswXq+VoxH26SskykvEhTSbi7tRM/787uZt/p8maxrQCJdzC90zX1btbxiJ6lw==", - "dev": true + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "flat-cache": "^3.0.4" + "is-glob": "^4.0.3" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10.13.0" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "node_modules/filesize": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz", - "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" + "balanced-match": "^1.0.0" } }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "node_modules/globals": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^2.0.0" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.14.8", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", + "node_modules/globby/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], + "license": "MIT", "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "node": ">= 4" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, + "license": "MIT", "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "node": ">= 0.4" }, - "engines": { - "node": ">= 6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "devOptional": true, + "node_modules/gzip-size": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz", + "integrity": "sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==", + "dev": true, + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "duplexer": "^0.1.2" }, "engines": { - "node": ">= 8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "devOptional": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/gzip-size/node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "devOptional": true, - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } + "license": "MIT" }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "devOptional": true, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "devOptional": true, - "dependencies": { - "ansi-regex": "^2.0.0" + "node": ">= 0.4" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/generic-names": { + "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", - "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "dependencies": { - "loader-utils": "^3.2.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, - "engines": { - "node": ">=6.9.0" + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -5476,210 +4855,278 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "devOptional": true, + "node_modules/hci-socket": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hci-socket/-/hci-socket-1.0.0.tgz", + "integrity": "sha512-gD75SHbPsi9h3671I9u0cWv4Tkbl38eiYrmPnG22eNuPnd7DEbn0QAYJFWVVldx/XhW9Wb7sE3f8+ZlQcYTfWA==", + "hasInstallScript": true, + "license": "ISC", + "optional": true, + "os": [ + "linux" + ], "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "bindings": "~1.5.0", + "node-addon-api": "^3.0.0" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" }, "engines": { - "node": ">=10.13.0" + "node": "^14.13.1 || >=16.0.0" } }, - "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { - "ini": "2.0.0" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8" } }, - "node_modules/global-dirs/node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.8" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "node_modules/http2-proxy": { + "version": "5.0.53", + "resolved": "https://registry.npmjs.org/http2-proxy/-/http2-proxy-5.0.53.tgz", + "integrity": "sha512-k9OUKrPWau/YeViJGv5peEFgSGPE2n8CDyk/G3f+JfaaJzbFMPAK5PJTd99QYSUvgUwVBGNbZJCY/BEb+kUZNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 4" } }, - "node_modules/globby": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-12.1.0.tgz", - "integrity": "sha512-YULDaNwsoUZkRy9TWSY/M7Obh0abamTKoKzTfOI3uU+hfpX2FZqOq8LFDxsjYheF1RH7ITdArgbQnsNBFgcdBA==", + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true, + "license": "ISC" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", "dependencies": { - "array-union": "^3.0.1", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.7", - "ignore": "^5.1.9", - "merge2": "^1.4.1", - "slash": "^4.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/incyclist-ant-plus": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/incyclist-ant-plus/-/incyclist-ant-plus-0.3.5.tgz", + "integrity": "sha512-My4xhH+Ecms//APTHdTu17Mi1nk2iVPXbYJ3T2FDn2eETbr1DTctZaLLjH4paykAeZxjMboWbQCu13yBlT75ZQ==", + "license": "MIT", "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" + "queue-fifo": "^0.2.6" }, "engines": { - "node": ">=10.19.0" + "node": ">=16.0.0" }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" + "optionalDependencies": { + "usb": "^2.15.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, - "node_modules/gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { - "duplexer": "^0.1.2" + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "node_modules/gzip-size/node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "dev": true, - "engines": { - "node": ">=4" + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" }, - "engines": { - "node": ">=6" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, "engines": { "node": ">= 0.4" }, @@ -5687,13 +5134,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-bigints": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5702,367 +5150,350 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "devOptional": true - }, - "node_modules/has-yarn": { + "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=12" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" + "hasown": "^2.0.2" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, + "license": "MIT", "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http2-proxy": { - "version": "5.0.53", - "resolved": "https://registry.npmjs.org/http2-proxy/-/http2-proxy-5.0.53.tgz", - "integrity": "sha512-k9OUKrPWau/YeViJGv5peEFgSGPE2n8CDyk/G3f+JfaaJzbFMPAK5PJTd99QYSUvgUwVBGNbZJCY/BEb+kUZNQ==", - "dev": true - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/httpie": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/httpie/-/httpie-1.1.2.tgz", - "integrity": "sha512-VQ82oXG95oY1fQw/XecHuvcFBA+lZQ9Vwj1RfLcO8a7HpDd4cc2ukwpJt+TUlFaLUAzZErylxWu6wclJ1rUhUQ==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "devOptional": true, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", "dependencies": { - "agent-base": "6", - "debug": "4" + "call-bound": "^1.0.3" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { - "node": ">=10.17.0" + "node": ">=8" } }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "^2.0.0" + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "optional": true, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "is-extglob": "^2.1.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", - "dev": true + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, + "license": "MIT", "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">= 0.4" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true - }, - "node_modules/ignore-walk": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", - "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", - "devOptional": true, - "dependencies": { - "minimatch": "^3.0.4" + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", "dev": true, - "engines": { - "node": ">=4" + "license": "MIT", + "dependencies": { + "@types/estree": "*" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, "engines": { - "node": ">=0.8.19" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/infer-owner": { + "node_modules/is-shared-array-buffer": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "devOptional": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "devOptional": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -6071,11 +5502,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6083,37 +5515,31 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, + "license": "MIT", "dependencies": { - "ci-info": "^2.0.0" + "call-bound": "^1.0.3" }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "dependencies": { - "has": "^1.0.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -6122,927 +5548,1274 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, - "bin": { - "is-docker": "cli.js" + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/isaacs" }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "devOptional": true, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", "dependencies": { - "number-is-nan": "^1.0.0" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", - "dev": true + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "peer": true, + "bin": { + "json5": "lib/cli.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "dev": true, - "engines": { - "node": ">=0.12.0" - } + "license": "MIT" }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "node_modules/katex": { + "version": "0.16.22", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", + "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==", "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "commander": "^8.3.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "katex": "cli.js" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 12" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "*" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", "dev": true, + "license": "MPL-2.0", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "detect-libc": "^2.0.3" }, "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-valid-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-element-name/-/is-valid-element-name-1.0.0.tgz", - "integrity": "sha1-Ju8/12zfHxItEFQG4y01sN4AWYE=", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "is-potential-custom-element-name": "^1.0.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-valid-identifier": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-valid-identifier/-/is-valid-identifier-2.0.2.tgz", - "integrity": "sha512-mpS5EGqXOwzXtKAg6I44jIAqeBfntFLxpAth1rrKbxtKyI6LPktyDYpHBI+tHlduhhX/SF26mFXmxQu995QVqg==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "assert": "^1.4.1" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "call-bind": "^1.0.2" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "devOptional": true - }, - "node_modules/isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 8.0.0" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/gjtorikian/" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" + "uc.micro": "^2.0.0" } }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/lit": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz", + "integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^1.6.0", + "lit-element": "^3.3.0", + "lit-html": "^2.8.0" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/lit-element": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz", + "integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==", + "license": "BSD-3-Clause", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@lit-labs/ssr-dom-shim": "^1.1.0", + "@lit/reactive-element": "^1.3.0", + "lit-html": "^2.8.0" } }, - "node_modules/js-levenshtein-esm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-1.2.0.tgz", - "integrity": "sha512-fzreKVq1eD7eGcQr7MtRpQH94f8gIfhdrc7yeih38xh684TNMK9v5aAu2wxfIRMk/GpAJRrzcirMAPIaSDaByQ==", - "dev": true + "node_modules/lit-html": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz", + "integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } }, - "node_modules/js-tokens": { + "node_modules/load-json-file": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=4" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "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==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" }, - "node_modules/json-stringify-nice": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", - "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, + "license": "MIT" + }, + "node_modules/loglevel": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", + "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" } }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" + "yallist": "^3.0.2" } }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, - "engines": [ - "node >= 0.2.0" - ] + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } }, - "node_modules/jsonschema": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.11.tgz", - "integrity": "sha512-XNZHs3N1IOa3lPKm//npxMhOdaoPw+MvEV0NIgxcER83GTJcG13rehtWmpBCfEt8DrtYwIkMTs8bdXoYs4fvnQ==", + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, - "engines": { - "node": "*" + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "node_modules/markdownlint": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.38.0.tgz", + "integrity": "sha512-xaSxkaU7wY/0852zGApM8LdlIfGCW8ETZ0Rr62IQtAnUMlMuifsg09vWJcNYeL4f0anvr8Vo4ZQar8jGpV0btQ==", "dev": true, + "license": "MIT", "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" + "micromark": "4.0.2", + "micromark-core-commonmark": "2.0.3", + "micromark-extension-directive": "4.0.0", + "micromark-extension-gfm-autolink-literal": "2.1.0", + "micromark-extension-gfm-footnote": "2.1.0", + "micromark-extension-gfm-table": "2.1.1", + "micromark-extension-math": "3.1.0", + "micromark-util-types": "2.0.2" }, "engines": { - "node": ">=0.6.0" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" } }, - "node_modules/just-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-3.1.1.tgz", - "integrity": "sha512-sdMWKjRq8qWZEjDcVA6llnUT8RDEBIfOiGpYFPYa9u+2c39JCsejktSP7mj5eRid5EIvTzIpQ2kDOCw1Nq9BjQ==", - "dev": true - }, - "node_modules/just-diff-apply": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-3.1.2.tgz", - "integrity": "sha512-TCa7ZdxCeq6q3Rgms2JCRHTCfWAETPZ8SzYUbkYF6KR3I03sN29DaOIC+xyWboIcMvjAsD5iG2u/RWzHD8XpgQ==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", - "integrity": "sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==", + "node_modules/markdownlint-cli2": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.18.1.tgz", + "integrity": "sha512-/4Osri9QFGCZOCTkfA8qJF+XGjKYERSHkXzxSyS1hd3ZERJGjvsUao2h4wdnvpHp6Tu2Jh/bPHM0FE9JJza6ng==", "dev": true, + "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kleur": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", - "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", - "dev": true, + "globby": "14.1.0", + "js-yaml": "4.1.0", + "jsonc-parser": "3.3.1", + "markdown-it": "14.1.0", + "markdownlint": "0.38.0", + "markdownlint-cli2-formatter-default": "0.0.5", + "micromatch": "4.0.8" + }, + "bin": { + "markdownlint-cli2": "markdownlint-cli2-bin.mjs" + }, "engines": { - "node": ">=6" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" } }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "node_modules/markdownlint-cli2-formatter-default": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.5.tgz", + "integrity": "sha512-4XKTwQ5m1+Txo2kuQ3Jgpo/KmnG+X90dWt4acufg6HVGadTUG5hzHF/wssp9b5MBYOMCnZ9RMPaU//uHsszF8Q==", "dev": true, - "dependencies": { - "package-json": "^6.3.0" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/DavidAnson" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "markdownlint-cli2": ">=0.0.4" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">= 0.4" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } + "license": "MIT" }, - "node_modules/lit": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/lit/-/lit-2.1.3.tgz", - "integrity": "sha512-46KtKy7iDoY3wZ5VSqBlXll6J/tli5gRMPFRWi5qQ01lvIqcO+dYQwb1l1NYZjbzcHnGnCKrMb8nDv7/ZE4Y4g==", - "dependencies": { - "@lit/reactive-element": "^1.1.0", - "lit-element": "^3.1.0", - "lit-html": "^2.1.0" + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" } }, - "node_modules/lit-element": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.1.2.tgz", - "integrity": "sha512-5VLn5a7anAFH7oz6d7TRG3KiTZQ5GEFsAgOKB8Yc+HDyuDUGOT2cL1CYTz/U4b/xlJxO+euP14pyji+z3Z3kOg==", - "dependencies": { - "@lit/reactive-element": "^1.1.0", - "lit-html": "^2.1.0" + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" } }, - "node_modules/lit-html": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.1.3.tgz", - "integrity": "sha512-WgvdwiNeuoT0mYEEJI+AAV2DEtlqzVM4lyDSaeQSg5ZwhS/CkGJBO/4n66alApEuSS9WXw9+ADBp8SPvtDEKSg==", + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz", + "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/trusted-types": "^2.0.2" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", "dev": true, + "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", "dev": true, - "engines": { - "node": ">= 12.13.0" + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", "dev": true, + "license": "MIT", "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "dev": true - }, - "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=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loglevel": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", - "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==", - "engines": { - "node": ">= 0.6.0" + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/loglevel" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "tslib": "^2.0.3" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "dev": true, - "engines": { - "node": ">=8" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "devOptional": true, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "sourcemap-codec": "^1.4.4" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "devOptional": true, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/markdownlint": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.25.1.tgz", - "integrity": "sha512-AG7UkLzNa1fxiOv5B+owPsPhtM4D6DoODhsJgiaNg1xowXovrYgOnLqAgOOFQpWOlHFVQUzjMY5ypNNTeov92g==", + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "markdown-it": "12.3.2" - }, - "engines": { - "node": ">=12" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/markdownlint-cli2": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.4.0.tgz", - "integrity": "sha512-EcwP5tAbyzzL3ACI0L16LqbNctmh8wNX56T+aVvIxWyTAkwbYNx2V7IheRkXS3mE7R/pnaApZ/RSXcXuzRVPjg==", + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "globby": "12.1.0", - "markdownlint": "0.25.1", - "markdownlint-cli2-formatter-default": "0.0.3", - "markdownlint-rule-helpers": "0.16.0", - "micromatch": "4.0.4", - "strip-json-comments": "4.0.0", - "yaml": "1.10.2" - }, - "bin": { - "markdownlint-cli2": "markdownlint-cli2.js", - "markdownlint-cli2-config": "markdownlint-cli2-config.js", - "markdownlint-cli2-fix": "markdownlint-cli2-fix.js" - }, - "engines": { - "node": ">=12" + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/markdownlint-cli2-formatter-default": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.3.tgz", - "integrity": "sha512-QEAJitT5eqX1SNboOD+SO/LNBpu4P4je8JlR02ug2cLQAqmIhh8IJnSK7AcaHBHhNADqdGydnPpQOpsNcEEqCw==", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "dev": true, - "peerDependencies": { - "markdownlint-cli2": ">=0.0.4" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/markdownlint-cli2/node_modules/strip-json-comments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-4.0.0.tgz", - "integrity": "sha512-LzWcbfMbAsEDTRmhjWIioe8GcDRl0fa35YMXFoJKDdiD/quGFmjJjdgPjFJJNwCMaLyQqFIDqCdHD2V4HfLgYA==", + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/markdownlint-rule-helpers": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.16.0.tgz", - "integrity": "sha512-oEacRUVeTJ5D5hW1UYd2qExYI0oELdYK72k1TKGvIeYJIbqQWAz476NAc7LNixSySUhcNl++d02DvX0ccDk9/w==", - "dev": true + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", "dev": true, - "engines": { - "node": ">= 0.10.0" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", "dev": true, - "engines": { - "node": ">= 8" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/meriyah": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-3.1.6.tgz", - "integrity": "sha512-JDOSi6DIItDc33U5N52UdV6P8v+gn+fqZKfbAfHzdWApRQyQWdcvxPvAr9t01bI2rBxGvSrKRQSCg3SkZC1qeg==", + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "dev": true, - "engines": { - "node": ">=10.4.0" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "devOptional": true, + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -7051,237 +6824,141 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "devOptional": true - }, - "node_modules/minipass": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", - "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", - "devOptional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", "engines": { - "node": ">= 8" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", "dev": true, + "license": "MIT", "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" + "minipass": "^7.1.2" }, "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" + "node": ">= 18" } }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, - "dependencies": { - "minipass": "^3.0.0" + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" + "node": ">=10" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" + "node_modules/mqtt": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.13.1.tgz", + "integrity": "sha512-g+4G+ma0UeL3Pgu1y1si2NHb4VLIEUCtF789WrG99lLG0XZyoab2EJoy58YgGSg/1yFdthDBH0+4llsZZD/vug==", + "license": "MIT", + "dependencies": { + "commist": "^3.2.0", + "concat-stream": "^2.0.0", + "debug": "^4.4.0", + "help-me": "^5.0.0", + "lru-cache": "^10.4.3", + "minimist": "^1.2.8", + "mqtt-packet": "^9.0.2", + "number-allocator": "^1.0.14", + "readable-stream": "^4.7.0", + "rfdc": "^1.4.1", + "socks": "^2.8.3", + "split2": "^4.2.0", + "worker-timers": "^7.1.8", + "ws": "^8.18.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "devOptional": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "bin": { + "mqtt": "build/bin/mqtt.js", + "mqtt_pub": "build/bin/pub.js", + "mqtt_sub": "build/bin/sub.js" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "optional": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "node": ">=16.0.0" } }, - "node_modules/mkdirp-infer-owner": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz", - "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", - "dev": true, + "node_modules/mqtt-packet": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.2.tgz", + "integrity": "sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==", + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - }, - "engines": { - "node": ">=10" + "bl": "^6.0.8", + "debug": "^4.3.4", + "process-nextick-args": "^2.0.1" } }, - "node_modules/mkdirp-infer-owner/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } + "node_modules/mqtt/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" - }, - "node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-thread-safe-callback": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/napi-thread-safe-callback/-/napi-thread-safe-callback-0.0.6.tgz", - "integrity": "sha512-X7uHCOCdY4u0yamDxDrv3jF2NtYc8A1nvPzBQgvpoSX+WB3jAe2cVNsY448V1ucq7Whf9Wdy02HEUoLW5rJKWg==" + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", + "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/needle": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", - "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", - "optional": true, - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "optional": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, - "engines": { - "node": ">= 0.6" - } + "license": "MIT" }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, + "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -7290,277 +6967,130 @@ "node_modules/node-addon-api": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "license": "MIT", + "optional": true }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "optional": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" } }, - "node_modules/node-gyp": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", - "dev": true, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": ">= 10.12.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "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.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, - "node_modules/node-gyp/node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-pre-gyp": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.17.0.tgz", - "integrity": "sha512-abzZt1hmOjkZez29ppg+5gGqdPLUuJeAEwVPtHYEJgx0qzttCbcKFpxrCQn2HYbwCv2c+7JwH4BgEzFkUGpn4A==", - "deprecated": "Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future", - "optional": true, - "dependencies": { - "detect-libc": "^1.0.3", - "mkdirp": "^0.5.5", - "needle": "^2.5.2", - "nopt": "^4.0.3", - "npm-packlist": "^1.4.8", - "npmlog": "^4.1.2", - "rc": "^1.2.8", - "rimraf": "^2.7.1", - "semver": "^5.7.1", - "tar": "^4.4.13" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/node-pre-gyp/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "optional": true - }, - "node_modules/node-pre-gyp/node_modules/fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "optional": true, - "dependencies": { - "minipass": "^2.6.0" - } - }, - "node_modules/node-pre-gyp/node_modules/minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "optional": true, - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "node_modules/node-pre-gyp/node_modules/minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "optional": true, - "dependencies": { - "minipass": "^2.9.0" - } - }, - "node_modules/node-pre-gyp/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "optional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/node-pre-gyp/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/node-pre-gyp/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "optional": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/node-pre-gyp/node_modules/tar": { - "version": "4.4.19", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", - "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", - "optional": true, - "dependencies": { - "chownr": "^1.1.4", - "fs-minipass": "^1.2.7", - "minipass": "^2.9.0", - "minizlib": "^1.3.3", - "mkdirp": "^0.5.5", - "safe-buffer": "^5.2.1", - "yallist": "^3.1.1" - }, - "engines": { - "node": ">=4.5" - } - }, - "node_modules/node-pre-gyp/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "optional": true - }, "node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", - "dev": true + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" }, "node_modules/nodemon": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", - "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", "dev": true, - "hasInstallScript": true, + "license": "MIT", "dependencies": { "chokidar": "^3.5.2", - "debug": "^3.2.7", + "debug": "^4", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", - "semver": "^5.7.1", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" + "undefsafe": "^2.0.5" }, "bin": { "nodemon": "bin/nodemon.js" }, "engines": { - "node": ">=8.10.0" + "node": ">=10" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/nodemon" } }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "dependencies": { - "ms": "^2.1.1" + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "optional": true, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" + "has-flag": "^3.0.0" }, - "bin": { - "nopt": "bin/nopt.js" + "engines": { + "node": ">=4" } }, "node_modules/normalize-package-data": { @@ -7568,6 +7098,7 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -7576,10 +7107,11 @@ } }, "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -7589,220 +7121,141 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/nosleep.js": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/nosleep.js/-/nosleep.js-0.12.0.tgz", - "integrity": "sha512-9d1HbpKLh3sdWlhXMhU6MMH+wQzKkrgfRkYV0EBdvt99YJfj0ilCJrWRDYG2130Tm4GXbEoTCx5b34JSaP+HhA==" - }, - "node_modules/npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", - "devOptional": true, - "dependencies": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/npm-install-checks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", - "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", - "dev": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": ">=10" - } + "integrity": "sha512-9d1HbpKLh3sdWlhXMhU6MMH+wQzKkrgfRkYV0EBdvt99YJfj0ilCJrWRDYG2130Tm4GXbEoTCx5b34JSaP+HhA==", + "license": "MIT" }, - "node_modules/npm-install-checks/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" }, "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "devOptional": true - }, - "node_modules/npm-package-arg": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", - "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" }, "engines": { - "node": ">=10" + "node": ">= 4" } }, - "node_modules/npm-package-arg/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "node_modules/npm-run-all/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/npm-package-arg/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/npm-run-all/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/npm-packlist": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", - "optional": true, - "dependencies": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" + "node": ">=4" } }, - "node_modules/npm-pick-manifest": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", - "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", + "node_modules/npm-run-all/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" + "color-name": "1.1.3" } }, - "node_modules/npm-pick-manifest/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/npm-run-all/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/npm-registry-fetch": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", - "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, + "license": "MIT", "dependencies": { - "make-fetch-happen": "^9.0.1", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, "engines": { - "node": ">=10" + "node": ">=4.8" } }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "node_modules/npm-run-all/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, + "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=0.8.0" } }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/npm-run-all/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, + "license": "MIT", "engines": { - "node": ">=4.8" + "node": ">=4" } }, "node_modules/npm-run-all/node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/npm-run-all/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -7810,8 +7263,9 @@ "node_modules/npm-run-all/node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^1.0.0" }, @@ -7822,17 +7276,32 @@ "node_modules/npm-run-all/node_modules/shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/npm-run-all/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -7840,74 +7309,25 @@ "which": "bin/which" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, + "node_modules/number-allocator": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", + "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", + "license": "MIT", "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "devOptional": true, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "devOptional": true, - "engines": { - "node": ">=0.10.0" + "debug": "^4.3.1", + "js-sdsl": "4.3.0" } }, "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7917,19 +7337,23 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -7939,27 +7363,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -7967,11759 +7375,2255 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "devOptional": true, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", "dependencies": { - "wrappy": "1" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "dev": true, + "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "optional": true, - "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "optional": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "dev": true, + "license": "MIT", "dependencies": { - "p-try": "^1.0.0" + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, + "license": "MIT", "dependencies": { - "p-limit": "^1.1.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" }, "engines": { "node": ">=4" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8" } }, - "node_modules/p-queue": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", - "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dev": true, + "license": "MIT", "dependencies": { - "eventemitter3": "^4.0.4", - "p-timeout": "^3.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "dependencies": { - "p-finally": "^1.0.0" - }, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/package-json/node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/package-json/node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } + "license": "ISC" }, - "node_modules/package-json/node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/package-json/node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", "dev": true, - "dependencies": { - "pump": "^3.0.0" + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10" } }, - "node_modules/package-json/node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/package-json/node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "node_modules/package-json/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, + "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, + "license": "MIT", "dependencies": { - "pump": "^3.0.0" + "bindings": "^1.5.0", + "nan": "^2.14.2" }, "engines": { - "node": ">=6" + "node": ">=10.0.0" } }, - "node_modules/package-json/node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">= 0.4" } }, - "node_modules/package-json/node_modules/got/node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/package-json/node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } }, - "node_modules/package-json/node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true, - "dependencies": { - "json-buffer": "3.0.0" - } + "license": "MIT" }, - "node_modules/package-json/node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/package-json/node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/package-json/node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, + "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==", + "license": "MIT", "dependencies": { - "lowercase-keys": "^1.0.0" + "dbly-linked-list": "0.3.4" } }, - "node_modules/package-json/node_modules/responselike/node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "engines": { - "node": ">=0.10.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" } }, - "node_modules/pacote": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz", - "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", - "dev": true, - "dependencies": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" - }, - "bin": { - "pacote": "lib/bin.js" - }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/pacote/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/pacote/node_modules/npm-packlist": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz", - "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, + "license": "MIT", "dependencies": { - "glob": "^7.1.6", - "ignore-walk": "^3.0.3", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "npm-packlist": "bin/index.js" + "pify": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "picomatch": "^2.2.1" }, "engines": { - "node": ">=6" + "node": ">=8.10.0" } }, - "node_modules/parse-conflict-json": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-1.1.1.tgz", - "integrity": "sha512-4gySviBiW5TRl7XHvp1agcS7SOe0KZOjC//71dzZVWJrY9hCrgtvl5v3SyIxCZ4fZF47TxD9nfzmxcx76xmbUw==", + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "just-diff": "^3.0.1", - "just-diff-apply": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, + "license": "MIT", "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, + "license": "MIT", "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, + "regenerate": "^1.4.2" + }, "engines": { "node": ">=4" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "node_modules/periscopic": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-2.0.3.tgz", - "integrity": "sha512-FuCZe61mWxQOJAQFEfmt9FjzebRlcpFz8sFPbyaCKtdusPkMEbA9ey0eARnRav5zAhmXznhaQkKGFAPn7X9NUw==", + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", "dev": true, - "dependencies": { - "estree-walker": "^2.0.2", - "is-reference": "^1.1.4" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "license": "MIT" }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, - "engines": { - "node": ">=8.6" + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, + "license": "MIT", "bin": { - "pidtree": "bin/pidtree.js" + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=0.10" + "node": ">=6" } }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.10" } }, - "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, + "node_modules/replace-in-file": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-8.3.0.tgz", + "integrity": "sha512-4VhddQiMCPIuypiwHDTM+XHjZoVu9h7ngBbSCnwGRcwdHwxltjt/m//Ep3GDwqaOx1fDSrKFQ+n7uo4uVcEz9Q==", + "license": "MIT", "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.14.2" + "chalk": "^5.3.0", + "glob": "^10.4.2", + "yargs": "^17.7.2" + }, + "bin": { + "replace-in-file": "bin/cli.js" }, "engines": { - "node": ">=10.0.0" + "node": ">=18" } }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, + "node_modules/replace-in-file/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" + "bin": { + "resolve": "bin/resolve" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/pkg-dir/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" }, - "node_modules/postcss": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", - "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", + "node_modules/rollup": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.1.tgz", + "integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==", "dev": true, + "license": "MIT", "dependencies": { - "nanoid": "^3.2.0", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.44.1", + "@rollup/rollup-android-arm64": "4.44.1", + "@rollup/rollup-darwin-arm64": "4.44.1", + "@rollup/rollup-darwin-x64": "4.44.1", + "@rollup/rollup-freebsd-arm64": "4.44.1", + "@rollup/rollup-freebsd-x64": "4.44.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.1", + "@rollup/rollup-linux-arm-musleabihf": "4.44.1", + "@rollup/rollup-linux-arm64-gnu": "4.44.1", + "@rollup/rollup-linux-arm64-musl": "4.44.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.1", + "@rollup/rollup-linux-riscv64-gnu": "4.44.1", + "@rollup/rollup-linux-riscv64-musl": "4.44.1", + "@rollup/rollup-linux-s390x-gnu": "4.44.1", + "@rollup/rollup-linux-x64-gnu": "4.44.1", + "@rollup/rollup-linux-x64-musl": "4.44.1", + "@rollup/rollup-win32-arm64-msvc": "4.44.1", + "@rollup/rollup-win32-ia32-msvc": "4.44.1", + "@rollup/rollup-win32-x64-msvc": "4.44.1", + "fsevents": "~2.3.2" } }, - "node_modules/postcss-modules": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.0.tgz", - "integrity": "sha512-zoUttLDSsbWDinJM9jH37o7hulLRyEgH6fZm2PchxN7AZ8rkdWiALyNhnQ7+jg7cX9f10m6y5VhHsrjO0Mf/DA==", + "node_modules/rollup-plugin-summary": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-summary/-/rollup-plugin-summary-3.0.1.tgz", + "integrity": "sha512-SSoMQ5dCTD+Xq9E6LwHp7DJOnTZ1Dxe/EW0VJDrim2CAVVAGNmuj+1Qg8u/OyUjWqAgoqt4mXDAearjXVpxGSg==", "dev": true, + "license": "MIT", "dependencies": { - "generic-names": "^4.0.0", - "icss-replace-symbols": "^1.1.0", - "lodash.camelcase": "^4.3.0", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "string-hash": "^1.1.1" + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.13.0", + "brotli-size": "^4.0.0", + "cli-table3": "^0.6.5", + "filesize": "^10.1.6", + "globals": "^15.11.0", + "gzip-size": "^7.0.0", + "terser": "^5.36.0" + }, + "engines": { + "node": ">=20.9.0" }, "peerDependencies": { - "postcss": "^8.0.0" + "rollup": "^3.0.0||^4.0.0" } }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "node_modules/rollup-plugin-summary/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, + "license": "MIT", "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">=18" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, + "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" + "mri": "^1.1.0" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=6" } }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" }, "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">=0.4" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "dev": true, + "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0" + "es-errors": "^1.3.0", + "isarray": "^2.0.5" }, "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">= 0.4" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, + "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "engines": { - "node": ">= 0.8.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, "engines": { - "node": ">=4" + "node": ">= 18" } }, - "node_modules/printable-characters": { - "version": "1.0.42", - "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", - "integrity": "sha1-Pxjpd6m9jrN/zE/1ZZ176Qhos9g=", - "dev": true - }, - "node_modules/proc-log": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-1.0.0.tgz", - "integrity": "sha512-aCk8AO51s+4JyuYGg3Q/a6gnrlDO09NpVWePtjp7xwphcoQ04x5WAfCyugcsbLooWcMJ87CLkD4+604IckEdhg==", - "dev": true - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "devOptional": true - }, - "node_modules/promise-all-reject-late": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", - "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" } }, - "node_modules/promise-call-limit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.1.tgz", - "integrity": "sha512-3+hgaa19jzCGLuSCbieeRsu5C2joKfYn8pY6JAuXFRVfF4IO+L7UPpFWNTeWT9pM7uhskvbPPd/oEOktCn317Q==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" } }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" } }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { - "escape-goat": "^2.0.0" + "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">=8" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "devOptional": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-cmd-shim": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz", - "integrity": "sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw==", - "dev": true - }, - "node_modules/read-package-json-fast": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", - "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", - "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "devOptional": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "dev": true, - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, + "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" }, "engines": { - "node": ">= 0.12" - } - }, - "node_modules/requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", - "dev": true, - "engines": { - "node": ">=0.10.5" - } - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "devOptional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "2.67.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.2.tgz", - "integrity": "sha512-hoEiBWwZtf1QdK3jZIq59L0FJj4Fiv4RplCO4pvCRC86qsoFurWB4hKQIjoRf3WvJmk5UZ9b0y5ton+62fC7Tw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-filesize": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-filesize/-/rollup-plugin-filesize-9.1.2.tgz", - "integrity": "sha512-m2fE9hFaKgWKisJzyWXctOFKlgMRelo/58HgeC0lXUK/qykxiqkr6bsrotlvo2bvrwPsjgT7scNdQSr6qtl37A==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.13.8", - "boxen": "^5.0.0", - "brotli-size": "4.0.0", - "colors": "1.4.0", - "filesize": "^6.1.0", - "gzip-size": "^6.0.0", - "pacote": "^11.2.7", - "terser": "^5.6.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/rollup-plugin-polyfill-node": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.6.2.tgz", - "integrity": "sha512-gMCVuR0zsKq0jdBn8pSXN1Ejsc458k2QsFFvQdbHoM0Pot5hEnck+pBP/FDwFS6uAi77pD3rDTytsaUStsOMlA==", - "dev": true, - "dependencies": { - "@rollup/plugin-inject": "^4.0.0" - } - }, - "node_modules/rollup-plugin-summary": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-summary/-/rollup-plugin-summary-1.3.0.tgz", - "integrity": "sha512-81g5aS/3IYdpNydrEZzrJaezibU2L5RCGY1bq3iQtq0vUAxg1Nw9jKL/J0G1McOXfwcQkVh1VfvmKAXmD+BoLg==", - "dev": true, - "dependencies": { - "as-table": "^1.0.55", - "chalk": "^4.1.0", - "rollup-plugin-filesize": "^9.0.2" - }, - "engines": { - "node": ">=12.0.0", - "npm": ">=6.0.0" - }, - "peerDependencies": { - "as-table": "^1.0.55", - "chalk": "^4.1.0", - "rollup-plugin-filesize": "^9.0.2" - } - }, - "node_modules/rollup-plugin-summary/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/rollup-plugin-summary/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/rollup-plugin-summary/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/rollup-plugin-summary/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/rollup-plugin-summary/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-summary/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dev": true, - "dependencies": { - "mri": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "devOptional": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "devOptional": true - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "devOptional": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "devOptional": true - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "devOptional": true - }, - "node_modules/simple-git-hooks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/simple-git-hooks/-/simple-git-hooks-2.7.0.tgz", - "integrity": "sha512-nQe6ASMO9zn5/htIrU37xEIHGr9E6wikXelLbOeTcfsX2O++DHaVug7RSQoq+kO7DvZTH37WA5gW49hN9HTDmQ==", - "dev": true, - "hasInstallScript": true, - "bin": { - "simple-git-hooks": "cli.js" - } - }, - "node_modules/skypack": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/skypack/-/skypack-0.3.2.tgz", - "integrity": "sha512-je1pix0QYER6iHuUGbgcafRJT5TI+EGUIBfzBLMqo3Wi22I2SzB9TVHQqwKCw8pzJMuHqhVTFEHc3Ey+ra25Sw==", - "dev": true, - "dependencies": { - "cacache": "^15.0.0", - "cachedir": "^2.3.0", - "esinstall": "^1.0.0", - "etag": "^1.8.1", - "find-up": "^5.0.0", - "got": "^11.1.4", - "kleur": "^4.1.0", - "mkdirp": "^1.0.3", - "p-queue": "^6.2.1", - "rimraf": "^3.0.0", - "rollup": "^2.23.0", - "validate-npm-package-name": "^3.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/skypack/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/skypack/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/skypack/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/skypack/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/skypack/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/skypack/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/snowpack": { - "version": "3.8.8", - "resolved": "https://registry.npmjs.org/snowpack/-/snowpack-3.8.8.tgz", - "integrity": "sha512-Y/4V8FdzzYpwmJU2TgXRRFytz+GFSliWULK9J5O6C72KyK60w20JKqCdRtVs1S6BuobCedF5vSBD1Gvtm+gsJg==", - "dev": true, - "dependencies": { - "@npmcli/arborist": "^2.6.4", - "bufferutil": "^4.0.2", - "cachedir": "^2.3.0", - "cheerio": "1.0.0-rc.10", - "chokidar": "^3.4.0", - "cli-spinners": "^2.5.0", - "compressible": "^2.0.18", - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "default-browser-id": "^2.0.0", - "detect-port": "^1.3.0", - "es-module-lexer": "^0.3.24", - "esbuild": "~0.9.0", - "esinstall": "^1.1.7", - "estree-walker": "^2.0.2", - "etag": "^1.8.1", - "execa": "^5.1.1", - "fdir": "^5.0.0", - "find-cache-dir": "^3.3.1", - "find-up": "^5.0.0", - "glob": "^7.1.7", - "httpie": "^1.1.2", - "is-plain-object": "^5.0.0", - "is-reference": "^1.2.1", - "isbinaryfile": "^4.0.6", - "jsonschema": "~1.2.5", - "kleur": "^4.1.1", - "magic-string": "^0.25.7", - "meriyah": "^3.1.6", - "mime-types": "^2.1.26", - "mkdirp": "^1.0.3", - "npm-run-path": "^4.0.1", - "open": "^8.2.1", - "pacote": "^11.3.4", - "periscopic": "^2.0.3", - "picomatch": "^2.3.0", - "postcss": "^8.3.5", - "postcss-modules": "^4.0.0", - "resolve": "^1.20.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "rollup": "~2.37.1", - "signal-exit": "^3.0.3", - "skypack": "^0.3.2", - "slash": "~3.0.0", - "source-map": "^0.7.3", - "strip-ansi": "^6.0.0", - "strip-comments": "^2.0.1", - "utf-8-validate": "^5.0.3", - "ws": "^7.3.0", - "yargs-parser": "^20.0.0" - }, - "bin": { - "snowpack": "index.bin.js", - "sp": "index.bin.js" - }, - "engines": { - "node": ">=10.19.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/snowpack/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/snowpack/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/snowpack/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/snowpack/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/snowpack/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/snowpack/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/snowpack/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/snowpack/node_modules/rollup": { - "version": "2.37.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.37.1.tgz", - "integrity": "sha512-V3ojEeyGeSdrMSuhP3diBb06P+qV4gKQeanbDv+Qh/BZbhdZ7kHV0xAt8Yjk4GFshq/WjO7R4c7DFM20AwTFVQ==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/snowpack/node_modules/rollup/node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/snowpack/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/snowpack/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/snowpack/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", - "dev": true, - "dependencies": { - "ip": "^1.1.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", - "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", - "dev": true - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "devOptional": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", - "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", - "dev": true - }, - "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "devOptional": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "devOptional": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string.prototype.padend": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz", - "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "devOptional": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "devOptional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", - "dev": true, - "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "acorn": "^8.5.0" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/touch/node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "optional": true - }, - "node_modules/treeverse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-1.0.4.tgz", - "integrity": "sha512-whw60l7r+8ZU8Tu/Uc2yxtc4ZTZbR/PF3u1IPNKGQ6p8EICLb3Z2lAgoqw9bqYd8IkgnsaOcLzYHFckjqNsf0g==", - "dev": true - }, - "node_modules/tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/untildify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz", - "integrity": "sha1-F+soB5h/dpUunASF/DEdBqgmouA=", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/update-notifier/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/update-notifier/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-notifier/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/update-notifier/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/usb": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/usb/-/usb-1.9.2.tgz", - "integrity": "sha512-dryNz030LWBPAf6gj8vyq0Iev3vPbCLHCT8dBw3gQRXRzVNsIdeuU+VjPp3ksmSPkeMAl1k+kQ14Ij0QHyeiAg==", - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^4.2.0", - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/usb/node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" - }, - "node_modules/utf-8-validate": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz", - "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==", - "devOptional": true, - "hasInstallScript": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "dependencies": { - "inherits": "2.0.1" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "devOptional": true - }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/uvu": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.3.tgz", - "integrity": "sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw==", - "dev": true, - "dependencies": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" - }, - "bin": { - "uvu": "bin.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", - "dev": true, - "dependencies": { - "builtins": "^1.0.3" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/vm2": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.7.tgz", - "integrity": "sha512-g/GZ7V0Mlmch3eDVOATvAXr1GsJNg6kQ5PjvYy3HbJMCRn5slNbo/u73Uy7r5yUej1cRa3ZjtoVwcWSQuQ/fow==", - "dev": true, - "dependencies": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" - }, - "bin": { - "vm2": "bin/vm2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/walk-up-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz", - "integrity": "sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==", - "dev": true - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "optional": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "optional": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "devOptional": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/widest-line/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/widest-line/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "devOptional": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/xpc-connect": { - "name": "debug", - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "optional": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@abandonware/bleno": { - "version": "0.5.1-4", - "resolved": "https://registry.npmjs.org/@abandonware/bleno/-/bleno-0.5.1-4.tgz", - "integrity": "sha512-2K/gbDxh4l4TV8xT/XUCwCT3e5aGDGmYad8gxt19CEvBMCs0+JScZ7roNyX0Jzice5rrR5RETcsMwIjJSzbeCQ==", - "requires": { - "@abandonware/bluetooth-hci-socket": "^0.5.3-7", - "bplist-parser": "0.3.0", - "debug": "^4.3.1", - "napi-thread-safe-callback": "0.0.6", - "node-addon-api": "^3.1.0", - "xpc-connect": "npm:debug" - } - }, - "@abandonware/bluetooth-hci-socket": { - "version": "0.5.3-7", - "resolved": "https://registry.npmjs.org/@abandonware/bluetooth-hci-socket/-/bluetooth-hci-socket-0.5.3-7.tgz", - "integrity": "sha512-CaGDBeXEooRjaVJlgmnaWeI+MXlEBVN9705tp2GHCF2IFARH3h15lqf6eHjqFsdpQOiMWiBa/QZUAOGjzBrhmA==", - "optional": true, - "requires": { - "debug": "^4.3.1", - "nan": "^2.14.2", - "node-pre-gyp": "^0.17.0", - "usb": "^1.6.3" - } - }, - "@abandonware/noble": { - "version": "1.9.2-15", - "resolved": "https://registry.npmjs.org/@abandonware/noble/-/noble-1.9.2-15.tgz", - "integrity": "sha512-qD9NN5fzvbtHdWYFPDzxY2AveILvDSRX/PTdL0V+CUfyF70ggIJtLBc1WW1hbVMIpu8rZylYgrK+PUEBwIpjCg==", - "requires": { - "@abandonware/bluetooth-hci-socket": "^0.5.3-8", - "debug": "^4.3.1", - "node-addon-api": "^3.2.0" - }, - "dependencies": { - "@abandonware/bluetooth-hci-socket": { - "version": "0.5.3-8", - "resolved": "https://registry.npmjs.org/@abandonware/bluetooth-hci-socket/-/bluetooth-hci-socket-0.5.3-8.tgz", - "integrity": "sha512-JIUkTZpAo6vKyXd94OasynjnmAxgCvn3VRrQJM/KXBKbm/yW59BMK6ni1wLy/JLM4eFhsLkd2S907HJnXBSWKw==", - "optional": true, - "requires": { - "@mapbox/node-pre-gyp": "^1.0.5", - "debug": "^4.3.2", - "nan": "^2.15.0", - "usb": "^1.7.2" - } - } - } - }, - "@ampproject/remapping": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.1.tgz", - "integrity": "sha512-Aolwjd7HSC2PyY0fDj/wA/EimQT4HfEnFYNp5s9CQlrdhyvWTtvZ5YzrUPu6R6/1jKiUlxu8bUhkdSnKHNAHMA==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.0" - } - }, - "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.16.7" - } - }, - "@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", - "dev": true - }, - "@babel/core": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.2.tgz", - "integrity": "sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.0.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - } - }, - "@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", - "dev": true, - "requires": { - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", - "dev": true, - "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", - "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", - "dev": true - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "dev": true, - "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - } - }, - "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", - "dev": true - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", - "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-decorators": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz", - "integrity": "sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.1", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/plugin-syntax-decorators": "^7.17.0", - "charcodes": "^0.2.0" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", - "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-decorators": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz", - "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", - "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.0", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - } - }, - "@eslint/eslintrc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.1.0.tgz", - "integrity": "sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.3.1", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - } - } - }, - "@gar/promisify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz", - "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz", - "integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@isaacs/string-locale-compare": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", - "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", - "dev": true - }, - "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@lit/reactive-element": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.2.2.tgz", - "integrity": "sha512-HkhTTO2rT8jlf4izz7ME/+YUjqz+ZHgmnOKorA+7tkDmQDg6QzDpWSFz//1YyiL193W4bc7rlQCiYyFiZa9pkQ==" - }, - "@mapbox/node-pre-gyp": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", - "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", - "optional": true, - "requires": { - "detect-libc": "^1.0.3", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.5", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "dependencies": { - "are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - }, - "gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "optional": true, - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "optional": true - }, - "nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "optional": true, - "requires": { - "abbrev": "1" - } - }, - "npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "optional": true, - "requires": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "optional": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "optional": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@npmcli/arborist": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.10.0.tgz", - "integrity": "sha512-CLnD+zXG9oijEEzViimz8fbOoFVb7hoypiaf7p6giJhvYtrxLAyY3cZAMPIFQvsG731+02eMDp3LqVBNo7BaZA==", - "dev": true, - "requires": { - "@isaacs/string-locale-compare": "^1.0.1", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^1.0.2", - "@npmcli/metavuln-calculator": "^1.1.0", - "@npmcli/move-file": "^1.1.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^1.0.1", - "@npmcli/package-json": "^1.0.1", - "@npmcli/run-script": "^1.8.2", - "bin-links": "^2.2.1", - "cacache": "^15.0.3", - "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "npm-install-checks": "^4.0.0", - "npm-package-arg": "^8.1.5", - "npm-pick-manifest": "^6.1.0", - "npm-registry-fetch": "^11.0.0", - "pacote": "^11.3.5", - "parse-conflict-json": "^1.1.1", - "proc-log": "^1.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "ssri": "^8.0.1", - "treeverse": "^1.0.4", - "walk-up-path": "^1.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "dev": true, - "requires": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@npmcli/git": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", - "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", - "dev": true, - "requires": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@npmcli/installed-package-contents": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", - "dev": true, - "requires": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "@npmcli/map-workspaces": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-1.0.4.tgz", - "integrity": "sha512-wVR8QxhyXsFcD/cORtJwGQodeeaDf0OxcHie8ema4VgFeqwYkFsDPnSrIRSytX8xR6nKPAH89WnwTcaU608b/Q==", - "dev": true, - "requires": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^7.1.6", - "minimatch": "^3.0.4", - "read-package-json-fast": "^2.0.1" - } - }, - "@npmcli/metavuln-calculator": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-1.1.1.tgz", - "integrity": "sha512-9xe+ZZ1iGVaUovBVFI9h3qW+UuECUzhvZPxK9RaEA2mjU26o5D0JloGYWwLYvQELJNmBdQB6rrpuN8jni6LwzQ==", - "dev": true, - "requires": { - "cacache": "^15.0.5", - "pacote": "^11.1.11", - "semver": "^7.3.2" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "dev": true, - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - } - } - }, - "@npmcli/name-from-folder": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz", - "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==", - "dev": true - }, - "@npmcli/node-gyp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", - "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", - "dev": true - }, - "@npmcli/package-json": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-1.0.1.tgz", - "integrity": "sha512-y6jnu76E9C23osz8gEMBayZmaZ69vFOIk8vR1FJL/wbEJ54+9aVG9rLTjQKSXfgYZEr50nw1txBBFfBZZe+bYg==", - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.1" - } - }, - "@npmcli/promise-spawn": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", - "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", - "dev": true, - "requires": { - "infer-owner": "^1.0.4" - } - }, - "@npmcli/run-script": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz", - "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", - "dev": true, - "requires": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" - } - }, - "@rollup/plugin-babel": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", - "integrity": "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - } - }, - "@rollup/plugin-commonjs": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz", - "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - } - }, - "@rollup/plugin-inject": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-4.0.4.tgz", - "integrity": "sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "estree-walker": "^2.0.1", - "magic-string": "^0.25.7" - } - }, - "@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.0.8" - } - }, - "@rollup/plugin-node-resolve": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz", - "integrity": "sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - } - }, - "@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - } - } - }, - "@sindresorhus/is": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.4.0.tgz", - "integrity": "sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ==", - "dev": true - }, - "@snowpack/plugin-babel": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@snowpack/plugin-babel/-/plugin-babel-2.1.7.tgz", - "integrity": "sha512-q8Zz6nqJ/CHaWccvNCTGP95d/lQLrImiBfJCagO4xcN9p53SUqapd9Yl3uMFeqvrgZP+kFK1vo/edifZWFLo5Q==", - "dev": true, - "requires": { - "@babel/core": "^7.10.5", - "workerpool": "^6.0.0" - } - }, - "@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/cacheable-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", - "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.17.tgz", - "integrity": "sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==", - "dev": true - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "@types/parse5": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", - "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==", - "dev": true - }, - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/trusted-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", - "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" - }, - "@web/parse5-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@web/parse5-utils/-/parse5-utils-1.3.0.tgz", - "integrity": "sha512-Pgkx3ECc8EgXSlS5EyrgzSOoUbM6P8OKS471HLAyvOBcP1NCBn0to4RN/OaKASGq8qa3j+lPX9H14uA5AHEnQg==", - "dev": true, - "requires": { - "@types/parse5": "^6.0.1", - "parse5": "^6.0.1" - } - }, - "@web/rollup-plugin-html": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@web/rollup-plugin-html/-/rollup-plugin-html-1.10.1.tgz", - "integrity": "sha512-XYJxHtdllwA5l4X8wh8CailrOykOl3YY+BRqO8+wS/I1Kq0JFISg3EUHdWAyVcw0TRDnHNLbOBJTm2ptAM+eog==", - "dev": true, - "requires": { - "@web/parse5-utils": "^1.3.0", - "glob": "^7.1.6", - "html-minifier-terser": "^6.0.0", - "parse5": "^6.0.1" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "devOptional": true - }, - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "address": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", - "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "devOptional": true, - "requires": { - "debug": "4" - } - }, - "agentkeepalive": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.0.tgz", - "integrity": "sha512-0PhAp58jZNw13UJv7NVdTGb0ZcghHUb3DrZ046JiiJY/BOaTTpbwdHq2VObPCBV8M2GPh7sgrJ3AQ8Ey468LJw==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "devOptional": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "ant-plus": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/ant-plus/-/ant-plus-0.1.24.tgz", - "integrity": "sha512-otEIAN+9jtu/1mwHL81au0sO7muJT1QrWOm9j29NEg3x1Y+ZsSIYX+LSdY+BBr2mLA4hT/vpqv5pWX9KDWceVg==", - "requires": { - "usb": "^1.6.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "devOptional": true - }, - "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "devOptional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", - "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", - "dev": true - }, - "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - } - }, - "as-table": { - "version": "1.0.55", - "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", - "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", - "dev": true, - "requires": { - "printable-characters": "^1.0.42" - } - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.7" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "devOptional": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "devOptional": true - }, - "bin-links": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-2.3.0.tgz", - "integrity": "sha512-JzrOLHLwX2zMqKdyYZjkDgQGT+kHDkIhv2/IK2lJ00qLxV4TmFoHi8drDBb6H5Zrz1YfgHkai4e2MGPqnoUhqA==", - "dev": true, - "requires": { - "cmd-shim": "^4.0.1", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^2.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^3.0.3" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "bplist-parser": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.0.tgz", - "integrity": "sha512-zgmaRvT6AN1JpPPV+S0a1/FAtoxSreYDccZGIqEMSvZl9DMe70mJ7MFzpxa1X+gHVdkToE2haRUHHMiW1OdejA==", - "optional": true, - "requires": { - "big-integer": "1.6.x" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "devOptional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "brotli-size": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-4.0.0.tgz", - "integrity": "sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==", - "dev": true, - "requires": { - "duplexer": "0.1.1" - } - }, - "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "devOptional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true - }, - "builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", - "dev": true - }, - "cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "dev": true, - "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - } - } - }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true - }, - "cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001311", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001311.tgz", - "integrity": "sha512-mleTFtFKfykEeW34EyfhGIFjGCqzhh38Y0LhdQ9aWF+HorZTtdgKV/1hEE0NlFkG2ubvisPV6l400tlbPys98A==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "charcodes": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz", - "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==", - "dev": true - }, - "cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, - "requires": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - } - }, - "cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "requires": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "devOptional": true - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "clean-css": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", - "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", - "dev": true, - "requires": { - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "cmd-shim": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz", - "integrity": "sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw==", - "dev": true, - "requires": { - "mkdirp-infer-owner": "^2.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "devOptional": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "optional": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - }, - "common-ancestor-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "devOptional": true - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "devOptional": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "core-js-compat": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", - "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", - "dev": true, - "requires": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "devOptional": true - }, - "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "dependencies": { - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - } - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, - "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", - "dev": true - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "devOptional": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "default-browser-id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-2.0.0.tgz", - "integrity": "sha1-AezONxpx6F8VoXF354YwR+c9vn0=", - "dev": true, - "requires": { - "bplist-parser": "^0.1.0", - "pify": "^2.3.0", - "untildify": "^2.0.0" - }, - "dependencies": { - "bplist-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", - "integrity": "sha1-1g1dzCDLptx+HymbNdPh+V2vuuY=", - "dev": true, - "requires": { - "big-integer": "^1.6.7" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "devOptional": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "dequal": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz", - "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==", - "dev": true - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "optional": true - }, - "detect-port": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", - "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", - "dev": true, - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dev": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "electron-to-chromium": { - "version": "1.4.68", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz", - "integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "devOptional": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "requires": { - "iconv-lite": "^0.6.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true - }, - "env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true - }, - "err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-module-lexer": { - "version": "0.3.26", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz", - "integrity": "sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==", - "dev": true - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "esbuild": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.9.7.tgz", - "integrity": "sha512-VtUf6aQ89VTmMLKrWHYG50uByMF4JQlVysb8dmg6cOgW8JnFCipmz7p+HNBl+RR3LLCuBxFGVauAe2wfnF9bLg==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esinstall": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/esinstall/-/esinstall-1.1.7.tgz", - "integrity": "sha512-irDsrIF7fZ5BCQEAV5gmH+4nsK6JhnkI9C9VloXdmzJLbM1EcshPw8Ap95UUGc4ZJdzGeOrjV+jgKjQ/Z7Q3pg==", - "dev": true, - "requires": { - "@rollup/plugin-commonjs": "^16.0.0", - "@rollup/plugin-inject": "^4.0.2", - "@rollup/plugin-json": "^4.0.0", - "@rollup/plugin-node-resolve": "^10.0.0", - "@rollup/plugin-replace": "^2.4.2", - "builtin-modules": "^3.2.0", - "cjs-module-lexer": "^1.2.1", - "es-module-lexer": "^0.6.0", - "execa": "^5.1.1", - "is-valid-identifier": "^2.0.2", - "kleur": "^4.1.1", - "mkdirp": "^1.0.3", - "picomatch": "^2.3.0", - "resolve": "^1.20.0", - "rimraf": "^3.0.0", - "rollup": "~2.37.1", - "rollup-plugin-polyfill-node": "^0.6.2", - "slash": "~3.0.0", - "validate-npm-package-name": "^3.0.0", - "vm2": "^3.9.2" - }, - "dependencies": { - "@rollup/plugin-commonjs": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz", - "integrity": "sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - } - }, - "@rollup/plugin-node-resolve": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-10.0.0.tgz", - "integrity": "sha512-sNijGta8fqzwA1VwUEtTvWCx2E7qC70NMsDh4ZG13byAXYigBNZMxALhKUSycBks5gupJdq0lFrKumFrRZ8H3A==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.17.0" - } - }, - "es-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.6.0.tgz", - "integrity": "sha512-f8kcHX1ArhllUtb/wVSyvygoKCznIjnxhLxy7TCvIiMdT7fL4ZDTIKaadMe6eLvOXg6Wk02UeoFgUoZ2EKZZUA==", - "dev": true - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "rollup": { - "version": "2.37.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.37.1.tgz", - "integrity": "sha512-V3ojEeyGeSdrMSuhP3diBb06P+qV4gKQeanbDv+Qh/BZbhdZ7kHV0xAt8Yjk4GFshq/WjO7R4c7DFM20AwTFVQ==", - "dev": true, - "requires": { - "fsevents": "~2.1.2" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, - "eslint": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", - "integrity": "sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.1.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "eslint-config-standard": { - "version": "17.0.0-0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0-0.tgz", - "integrity": "sha512-sf9udec8fkLTnH82SmhZQ3E31e4eJaMW09Mt9fbN3OccXFtvSSbGrltpQgGFVooGHoIdiMzDfp6ZNFd+I6Ob+w==", - "dev": true, - "requires": {} - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", - "dev": true, - "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", - "dev": true, - "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-plugin-lit": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.6.1.tgz", - "integrity": "sha512-BpPoWVhf8dQ/Sz5Pi9NlqbGoH5BcMcVyXhi2XTx2XGMAO9U2lS+GTSsqJjI5hL3OuxCicNiUEWXazAwi9cAGxQ==", - "dev": true, - "requires": { - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "requireindex": "^1.2.0" - } - }, - "eslint-plugin-n": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-14.0.0.tgz", - "integrity": "sha512-mNwplPLsbaKhHyA0fa/cy8j+oF6bF6l81hzBTWa6JOvPcMNAuIogk2ih6d9tYvWYzyUG+7ZFeChqbzdFpg2QrQ==", - "dev": true, - "requires": { - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.3.0", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - } - }, - "eslint-plugin-promise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", - "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", - "dev": true, - "requires": {} - }, - "eslint-plugin-wc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-1.3.2.tgz", - "integrity": "sha512-/Tt3kIXBp1jh06xYtRqPwAvpNxVVk9YtbcFCKEgLa5l3GY+urZyn376pISaaZxkm9HVD3AIPOF5i9/uFwyF0Zw==", - "dev": true, - "requires": { - "is-valid-element-name": "^1.0.0", - "js-levenshtein-esm": "^1.2.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", - "dev": true, - "requires": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - } - } - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fdir": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-5.2.0.tgz", - "integrity": "sha512-skyI2Laxtj9GYzmktPgY6DT8uswXq+VoxH26SskykvEhTSbi7tRM/787uZt/p8maxrQCJdzC90zX1btbxiJ6lw==", - "dev": true - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "filesize": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz", - "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==", - "dev": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "follow-redirects": { - "version": "1.14.8", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "devOptional": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "devOptional": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "devOptional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "devOptional": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "devOptional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "generic-names": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", - "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", - "dev": true, - "requires": { - "loader-utils": "^3.2.0" - } - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "devOptional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - }, - "dependencies": { - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - } - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globby": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-12.1.0.tgz", - "integrity": "sha512-YULDaNwsoUZkRy9TWSY/M7Obh0abamTKoKzTfOI3uU+hfpX2FZqOq8LFDxsjYheF1RH7ITdArgbQnsNBFgcdBA==", - "dev": true, - "requires": { - "array-union": "^3.0.1", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.7", - "ignore": "^5.1.9", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", - "dev": true, - "requires": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "dev": true, - "requires": { - "duplexer": "^0.1.2" - }, - "dependencies": { - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "devOptional": true - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "requires": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "http2-proxy": { - "version": "5.0.53", - "resolved": "https://registry.npmjs.org/http2-proxy/-/http2-proxy-5.0.53.tgz", - "integrity": "sha512-k9OUKrPWau/YeViJGv5peEFgSGPE2n8CDyk/G3f+JfaaJzbFMPAK5PJTd99QYSUvgUwVBGNbZJCY/BEb+kUZNQ==", - "dev": true - }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - } - }, - "httpie": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/httpie/-/httpie-1.1.2.tgz", - "integrity": "sha512-VQ82oXG95oY1fQw/XecHuvcFBA+lZQ9Vwj1RfLcO8a7HpDd4cc2ukwpJt+TUlFaLUAzZErylxWu6wclJ1rUhUQ==", - "dev": true - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "devOptional": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "dev": true, - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", - "dev": true - }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true - }, - "ignore-walk": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", - "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", - "devOptional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "devOptional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "devOptional": true - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "devOptional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", - "dev": true - }, - "is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-valid-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-element-name/-/is-valid-element-name-1.0.0.tgz", - "integrity": "sha1-Ju8/12zfHxItEFQG4y01sN4AWYE=", - "dev": true, - "requires": { - "is-potential-custom-element-name": "^1.0.0" - } - }, - "is-valid-identifier": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-valid-identifier/-/is-valid-identifier-2.0.2.tgz", - "integrity": "sha512-mpS5EGqXOwzXtKAg6I44jIAqeBfntFLxpAth1rrKbxtKyI6LPktyDYpHBI+tHlduhhX/SF26mFXmxQu995QVqg==", - "dev": true, - "requires": { - "assert": "^1.4.1" - } - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "devOptional": true - }, - "isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-levenshtein-esm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-1.2.0.tgz", - "integrity": "sha512-fzreKVq1eD7eGcQr7MtRpQH94f8gIfhdrc7yeih38xh684TNMK9v5aAu2wxfIRMk/GpAJRrzcirMAPIaSDaByQ==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-nice": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", - "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "jsonschema": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.11.tgz", - "integrity": "sha512-XNZHs3N1IOa3lPKm//npxMhOdaoPw+MvEV0NIgxcER83GTJcG13rehtWmpBCfEt8DrtYwIkMTs8bdXoYs4fvnQ==", - "dev": true - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "just-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-3.1.1.tgz", - "integrity": "sha512-sdMWKjRq8qWZEjDcVA6llnUT8RDEBIfOiGpYFPYa9u+2c39JCsejktSP7mj5eRid5EIvTzIpQ2kDOCw1Nq9BjQ==", - "dev": true - }, - "just-diff-apply": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-3.1.2.tgz", - "integrity": "sha512-TCa7ZdxCeq6q3Rgms2JCRHTCfWAETPZ8SzYUbkYF6KR3I03sN29DaOIC+xyWboIcMvjAsD5iG2u/RWzHD8XpgQ==", - "dev": true - }, - "keyv": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", - "integrity": "sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kleur": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", - "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", - "dev": true - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.0" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "lit": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/lit/-/lit-2.1.3.tgz", - "integrity": "sha512-46KtKy7iDoY3wZ5VSqBlXll6J/tli5gRMPFRWi5qQ01lvIqcO+dYQwb1l1NYZjbzcHnGnCKrMb8nDv7/ZE4Y4g==", - "requires": { - "@lit/reactive-element": "^1.1.0", - "lit-element": "^3.1.0", - "lit-html": "^2.1.0" - } - }, - "lit-element": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.1.2.tgz", - "integrity": "sha512-5VLn5a7anAFH7oz6d7TRG3KiTZQ5GEFsAgOKB8Yc+HDyuDUGOT2cL1CYTz/U4b/xlJxO+euP14pyji+z3Z3kOg==", - "requires": { - "@lit/reactive-element": "^1.1.0", - "lit-html": "^2.1.0" - } - }, - "lit-html": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.1.3.tgz", - "integrity": "sha512-WgvdwiNeuoT0mYEEJI+AAV2DEtlqzVM4lyDSaeQSg5ZwhS/CkGJBO/4n66alApEuSS9WXw9+ADBp8SPvtDEKSg==", - "requires": { - "@types/trusted-types": "^2.0.2" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", - "dev": true - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "dev": true - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "loglevel": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", - "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==" - }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "requires": { - "tslib": "^2.0.3" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "devOptional": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "devOptional": true, - "requires": { - "semver": "^6.0.0" - } - }, - "make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dev": true, - "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - }, - "markdownlint": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.25.1.tgz", - "integrity": "sha512-AG7UkLzNa1fxiOv5B+owPsPhtM4D6DoODhsJgiaNg1xowXovrYgOnLqAgOOFQpWOlHFVQUzjMY5ypNNTeov92g==", - "dev": true, - "requires": { - "markdown-it": "12.3.2" - } - }, - "markdownlint-cli2": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.4.0.tgz", - "integrity": "sha512-EcwP5tAbyzzL3ACI0L16LqbNctmh8wNX56T+aVvIxWyTAkwbYNx2V7IheRkXS3mE7R/pnaApZ/RSXcXuzRVPjg==", - "dev": true, - "requires": { - "globby": "12.1.0", - "markdownlint": "0.25.1", - "markdownlint-cli2-formatter-default": "0.0.3", - "markdownlint-rule-helpers": "0.16.0", - "micromatch": "4.0.4", - "strip-json-comments": "4.0.0", - "yaml": "1.10.2" - }, - "dependencies": { - "strip-json-comments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-4.0.0.tgz", - "integrity": "sha512-LzWcbfMbAsEDTRmhjWIioe8GcDRl0fa35YMXFoJKDdiD/quGFmjJjdgPjFJJNwCMaLyQqFIDqCdHD2V4HfLgYA==", - "dev": true - } - } - }, - "markdownlint-cli2-formatter-default": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.3.tgz", - "integrity": "sha512-QEAJitT5eqX1SNboOD+SO/LNBpu4P4je8JlR02ug2cLQAqmIhh8IJnSK7AcaHBHhNADqdGydnPpQOpsNcEEqCw==", - "dev": true, - "requires": {} - }, - "markdownlint-rule-helpers": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.16.0.tgz", - "integrity": "sha512-oEacRUVeTJ5D5hW1UYd2qExYI0oELdYK72k1TKGvIeYJIbqQWAz476NAc7LNixSySUhcNl++d02DvX0ccDk9/w==", - "dev": true - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "meriyah": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-3.1.6.tgz", - "integrity": "sha512-JDOSi6DIItDc33U5N52UdV6P8v+gn+fqZKfbAfHzdWApRQyQWdcvxPvAr9t01bI2rBxGvSrKRQSCg3SkZC1qeg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "requires": { - "mime-db": "1.51.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "devOptional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "devOptional": true - }, - "minipass": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", - "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", - "devOptional": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, - "requires": { - "encoding": "^0.1.12", - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - } - }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "requires": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "devOptional": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mkdirp-infer-owner": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz", - "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", - "dev": true, - "requires": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - } - } - }, - "mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" - }, - "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", - "dev": true - }, - "napi-thread-safe-callback": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/napi-thread-safe-callback/-/napi-thread-safe-callback-0.0.6.tgz", - "integrity": "sha512-X7uHCOCdY4u0yamDxDrv3jF2NtYc8A1nvPzBQgvpoSX+WB3jAe2cVNsY448V1ucq7Whf9Wdy02HEUoLW5rJKWg==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "needle": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", - "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "optional": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "optional": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-gyp": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", - "dev": true, - "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" - }, - "dependencies": { - "nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "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==" - }, - "node-pre-gyp": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.17.0.tgz", - "integrity": "sha512-abzZt1hmOjkZez29ppg+5gGqdPLUuJeAEwVPtHYEJgx0qzttCbcKFpxrCQn2HYbwCv2c+7JwH4BgEzFkUGpn4A==", - "optional": true, - "requires": { - "detect-libc": "^1.0.3", - "mkdirp": "^0.5.5", - "needle": "^2.5.2", - "nopt": "^4.0.3", - "npm-packlist": "^1.4.8", - "npmlog": "^4.1.2", - "rc": "^1.2.8", - "rimraf": "^2.7.1", - "semver": "^5.7.1", - "tar": "^4.4.13" - }, - "dependencies": { - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "optional": true - }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "optional": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "optional": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "optional": true - }, - "tar": { - "version": "4.4.19", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", - "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", - "optional": true, - "requires": { - "chownr": "^1.1.4", - "fs-minipass": "^1.2.7", - "minipass": "^2.9.0", - "minizlib": "^1.3.3", - "mkdirp": "^0.5.5", - "safe-buffer": "^5.2.1", - "yallist": "^3.1.1" - } - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "optional": true - } - } - }, - "node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", - "dev": true - }, - "nodemon": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", - "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", - "dev": true, - "requires": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true - }, - "nosleep.js": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/nosleep.js/-/nosleep.js-0.12.0.tgz", - "integrity": "sha512-9d1HbpKLh3sdWlhXMhU6MMH+wQzKkrgfRkYV0EBdvt99YJfj0ilCJrWRDYG2130Tm4GXbEoTCx5b34JSaP+HhA==" - }, - "npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", - "devOptional": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-install-checks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", - "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", - "dev": true, - "requires": { - "semver": "^7.1.1" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "devOptional": true - }, - "npm-package-arg": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", - "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" - }, - "dependencies": { - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "npm-packlist": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-pick-manifest": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", - "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", - "dev": true, - "requires": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "npm-registry-fetch": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", - "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", - "dev": true, - "requires": { - "make-fetch-happen": "^9.0.1", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" - } - }, - "npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "devOptional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "devOptional": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "devOptional": true - }, - "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "devOptional": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dev": true, - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "devOptional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "optional": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-queue": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", - "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.4", - "p-timeout": "^3.2.0" - } - }, - "p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "dependencies": { - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - } - } - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - }, - "dependencies": { - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - } - } - } - } - }, - "pacote": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz", - "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", - "dev": true, - "requires": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "npm-packlist": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz", - "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", - "dev": true, - "requires": { - "glob": "^7.1.6", - "ignore-walk": "^3.0.3", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - } - } - } - }, - "param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-conflict-json": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-1.1.1.tgz", - "integrity": "sha512-4gySviBiW5TRl7XHvp1agcS7SOe0KZOjC//71dzZVWJrY9hCrgtvl5v3SyIxCZ4fZF47TxD9nfzmxcx76xmbUw==", - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.0", - "just-diff": "^3.0.1", - "just-diff-apply": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "requires": { - "parse5": "^6.0.1" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "devOptional": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "periscopic": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-2.0.3.tgz", - "integrity": "sha512-FuCZe61mWxQOJAQFEfmt9FjzebRlcpFz8sFPbyaCKtdusPkMEbA9ey0eARnRav5zAhmXznhaQkKGFAPn7X9NUw==", - "dev": true, - "requires": { - "estree-walker": "^2.0.2", - "is-reference": "^1.1.4" - } - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "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", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } - } - }, - "postcss": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", - "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", - "dev": true, - "requires": { - "nanoid": "^3.2.0", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-modules": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.0.tgz", - "integrity": "sha512-zoUttLDSsbWDinJM9jH37o7hulLRyEgH6fZm2PchxN7AZ8rkdWiALyNhnQ7+jg7cX9f10m6y5VhHsrjO0Mf/DA==", - "dev": true, - "requires": { - "generic-names": "^4.0.0", - "icss-replace-symbols": "^1.1.0", - "lodash.camelcase": "^4.3.0", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "string-hash": "^1.1.1" - } - }, - "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "requires": {} - }, - "postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "printable-characters": { - "version": "1.0.42", - "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", - "integrity": "sha1-Pxjpd6m9jrN/zE/1ZZ176Qhos9g=", - "dev": true - }, - "proc-log": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-1.0.0.tgz", - "integrity": "sha512-aCk8AO51s+4JyuYGg3Q/a6gnrlDO09NpVWePtjp7xwphcoQ04x5WAfCyugcsbLooWcMJ87CLkD4+604IckEdhg==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "devOptional": true - }, - "promise-all-reject-late": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", - "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", - "dev": true - }, - "promise-call-limit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.1.tgz", - "integrity": "sha512-3+hgaa19jzCGLuSCbieeRsu5C2joKfYn8pY6JAuXFRVfF4IO+L7UPpFWNTeWT9pM7uhskvbPPd/oEOktCn317Q==", - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "requires": { - "escape-goat": "^2.0.0" - } - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "devOptional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "devOptional": true - } - } - }, - "read-cmd-shim": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz", - "integrity": "sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw==", - "dev": true - }, - "read-package-json-fast": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", - "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "dependencies": { - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - } - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "devOptional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "dev": true, - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "dev": true, - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", - "dev": true - }, - "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - } - } - }, - "requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", - "dev": true - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "devOptional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "2.67.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.2.tgz", - "integrity": "sha512-hoEiBWwZtf1QdK3jZIq59L0FJj4Fiv4RplCO4pvCRC86qsoFurWB4hKQIjoRf3WvJmk5UZ9b0y5ton+62fC7Tw==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "rollup-plugin-filesize": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-filesize/-/rollup-plugin-filesize-9.1.2.tgz", - "integrity": "sha512-m2fE9hFaKgWKisJzyWXctOFKlgMRelo/58HgeC0lXUK/qykxiqkr6bsrotlvo2bvrwPsjgT7scNdQSr6qtl37A==", - "dev": true, - "requires": { - "@babel/runtime": "^7.13.8", - "boxen": "^5.0.0", - "brotli-size": "4.0.0", - "colors": "1.4.0", - "filesize": "^6.1.0", - "gzip-size": "^6.0.0", - "pacote": "^11.2.7", - "terser": "^5.6.0" - } - }, - "rollup-plugin-polyfill-node": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.6.2.tgz", - "integrity": "sha512-gMCVuR0zsKq0jdBn8pSXN1Ejsc458k2QsFFvQdbHoM0Pot5hEnck+pBP/FDwFS6uAi77pD3rDTytsaUStsOMlA==", - "dev": true, - "requires": { - "@rollup/plugin-inject": "^4.0.0" - } - }, - "rollup-plugin-summary": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-summary/-/rollup-plugin-summary-1.3.0.tgz", - "integrity": "sha512-81g5aS/3IYdpNydrEZzrJaezibU2L5RCGY1bq3iQtq0vUAxg1Nw9jKL/J0G1McOXfwcQkVh1VfvmKAXmD+BoLg==", - "dev": true, - "requires": { - "as-table": "^1.0.55", - "chalk": "^4.1.0", - "rollup-plugin-filesize": "^9.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, - "requires": { - "mri": "^1.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "devOptional": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "devOptional": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "devOptional": true - }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "requires": { - "semver": "^6.3.0" - } - }, - "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, - "requires": { - "randombytes": "^2.1.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "devOptional": true - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "node_modules/simple-git-hooks": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/simple-git-hooks/-/simple-git-hooks-2.13.0.tgz", + "integrity": "sha512-N+goiLxlkHJlyaYEglFypzVNMaNplPAk5syu0+OPp/Bk6dwVoXF6FfOw2vO0Dp+JHsBaI+w6cm8TnFl2Hw6tDA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "simple-git-hooks": "cli.js" + } }, - "shebang-command": { + "node_modules/simple-update-notifier": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, - "requires": { - "shebang-regex": "^3.0.0" + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" } }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "devOptional": true - }, - "simple-git-hooks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/simple-git-hooks/-/simple-git-hooks-2.7.0.tgz", - "integrity": "sha512-nQe6ASMO9zn5/htIrU37xEIHGr9E6wikXelLbOeTcfsX2O++DHaVug7RSQoq+kO7DvZTH37WA5gW49hN9HTDmQ==", - "dev": true - }, - "skypack": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/skypack/-/skypack-0.3.2.tgz", - "integrity": "sha512-je1pix0QYER6iHuUGbgcafRJT5TI+EGUIBfzBLMqo3Wi22I2SzB9TVHQqwKCw8pzJMuHqhVTFEHc3Ey+ra25Sw==", + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, - "requires": { - "cacache": "^15.0.0", - "cachedir": "^2.3.0", - "esinstall": "^1.0.0", - "etag": "^1.8.1", - "find-up": "^5.0.0", - "got": "^11.1.4", - "kleur": "^4.1.0", - "mkdirp": "^1.0.3", - "p-queue": "^6.2.1", - "rimraf": "^3.0.0", - "rollup": "^2.23.0", - "validate-npm-package-name": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - }, - "smart-buffer": { + "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true - }, - "snowpack": { - "version": "3.8.8", - "resolved": "https://registry.npmjs.org/snowpack/-/snowpack-3.8.8.tgz", - "integrity": "sha512-Y/4V8FdzzYpwmJU2TgXRRFytz+GFSliWULK9J5O6C72KyK60w20JKqCdRtVs1S6BuobCedF5vSBD1Gvtm+gsJg==", - "dev": true, - "requires": { - "@npmcli/arborist": "^2.6.4", - "bufferutil": "^4.0.2", - "cachedir": "^2.3.0", - "cheerio": "1.0.0-rc.10", - "chokidar": "^3.4.0", - "cli-spinners": "^2.5.0", - "compressible": "^2.0.18", - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "default-browser-id": "^2.0.0", - "detect-port": "^1.3.0", - "es-module-lexer": "^0.3.24", - "esbuild": "~0.9.0", - "esinstall": "^1.1.7", - "estree-walker": "^2.0.2", - "etag": "^1.8.1", - "execa": "^5.1.1", - "fdir": "^5.0.0", - "find-cache-dir": "^3.3.1", - "find-up": "^5.0.0", - "fsevents": "^2.3.2", - "glob": "^7.1.7", - "httpie": "^1.1.2", - "is-plain-object": "^5.0.0", - "is-reference": "^1.2.1", - "isbinaryfile": "^4.0.6", - "jsonschema": "~1.2.5", - "kleur": "^4.1.1", - "magic-string": "^0.25.7", - "meriyah": "^3.1.6", - "mime-types": "^2.1.26", - "mkdirp": "^1.0.3", - "npm-run-path": "^4.0.1", - "open": "^8.2.1", - "pacote": "^11.3.4", - "periscopic": "^2.0.3", - "picomatch": "^2.3.0", - "postcss": "^8.3.5", - "postcss-modules": "^4.0.0", - "resolve": "^1.20.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "rollup": "~2.37.1", - "signal-exit": "^3.0.3", - "skypack": "^0.3.2", - "slash": "~3.0.0", - "source-map": "^0.7.3", - "strip-ansi": "^6.0.0", - "strip-comments": "^2.0.1", - "utf-8-validate": "^5.0.3", - "ws": "^7.3.0", - "yargs-parser": "^20.0.0" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "rollup": { - "version": "2.37.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.37.1.tgz", - "integrity": "sha512-V3ojEeyGeSdrMSuhP3diBb06P+qV4gKQeanbDv+Qh/BZbhdZ7kHV0xAt8Yjk4GFshq/WjO7R4c7DFM20AwTFVQ==", - "dev": true, - "requires": { - "fsevents": "~2.1.2" - }, - "dependencies": { - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - } - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - }, - "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "requires": {} - } + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" } }, - "socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", "dev": true, - "requires": { - "ip": "^1.1.5", + "license": "MIT" + }, + "node_modules/socks": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.5.tgz", + "integrity": "sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" } }, - "socks-proxy-agent": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "source-map-support": { + "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, - "spdx-expression-parse": { + "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", - "dev": true - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "license": "CC0-1.0" + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" } }, - "ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, - "requires": { - "minipass": "^3.1.1" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" } }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "devOptional": true, - "requires": { - "safe-buffer": "~5.1.0" + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "string-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", - "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", - "dev": true + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "devOptional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "devOptional": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "devOptional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "string.prototype.padend": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz", - "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==", + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "strip-ansi": { + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "strip-bom": { + "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "strip-json-comments": { + "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { - "has-flag": "^3.0.0" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "supports-preserve-symlinks-flag": { + "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "devOptional": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "devOptional": true - } + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "node_modules/terser": { + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.14.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" } }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" }, - "to-regex-range": { + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "toidentifier": { + "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "requires": { - "nopt": "~1.0.10" - }, - "dependencies": { - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "requires": { - "abbrev": "1" - } - } + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" } }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "optional": true - }, - "treeverse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-1.0.4.tgz", - "integrity": "sha512-whw60l7r+8ZU8Tu/Uc2yxtc4ZTZbR/PF3u1IPNKGQ6p8EICLb3Z2lAgoqw9bqYd8IkgnsaOcLzYHFckjqNsf0g==", - "dev": true + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, - "tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, - "requires": { - "safe-buffer": "^5.0.1" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" } }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, - "requires": { - "prelude-ls": "^1.2.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, - "requires": { - "is-typedarray": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "undefsafe": { + "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true + "dev": true, + "license": "MIT" }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true + "node_modules/undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "unicode-match-property-ecmascript": { + "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, - "requires": { - "unique-slug": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, - "requires": { - "imurmurhash": "^0.1.4" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "untildify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz", - "integrity": "sha1-F+soB5h/dpUunASF/DEdBqgmouA=", + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, - "requires": { - "os-homedir": "^1.0.0" - } - }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, - "usb": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/usb/-/usb-1.9.2.tgz", - "integrity": "sha512-dryNz030LWBPAf6gj8vyq0Iev3vPbCLHCT8dBw3gQRXRzVNsIdeuU+VjPp3ksmSPkeMAl1k+kQ14Ij0QHyeiAg==", - "requires": { - "node-addon-api": "^4.2.0", - "node-gyp-build": "^4.3.0" - }, + "license": "BSD-2-Clause", "dependencies": { - "node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" - } + "punycode": "^2.1.0" } }, - "utf-8-validate": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz", - "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==", - "devOptional": true, - "requires": { - "node-gyp-build": "^4.3.0" + "node_modules/usb": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.15.0.tgz", + "integrity": "sha512-BA9r7PFxyYp99wps1N70lIqdPb2Utcl2KkWohDtWUmhDBeM5hDH1Zl/L/CZvWxd5W3RUCNm1g+b+DEKZ6cHzqg==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">=12.22.0 <13.0 || >=14.17.0" } }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - } + "node_modules/usb/node_modules/node-addon-api": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.4.0.tgz", + "integrity": "sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^18 || ^20 || >= 21" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "devOptional": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, - "uvu": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.3.tgz", - "integrity": "sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw==", + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "dequal": "^2.0.0", "diff": "^5.0.0", "kleur": "^4.0.3", "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" } }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "validate-npm-package-license": { + "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, - "validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", - "dev": true, - "requires": { - "builtins": "^1.0.3" + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - } + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "vm2": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.7.tgz", - "integrity": "sha512-g/GZ7V0Mlmch3eDVOATvAXr1GsJNg6kQ5PjvYy3HbJMCRn5slNbo/u73Uy7r5yUej1cRa3ZjtoVwcWSQuQ/fow==", + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, - "requires": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "walk-up-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz", - "integrity": "sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "optional": true + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "optional": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, - "requires": { - "isexe": "^2.0.0" + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "devOptional": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" + "node_modules/worker-timers": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz", + "integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.5", + "tslib": "^2.6.2", + "worker-timers-broker": "^6.1.8", + "worker-timers-worker": "^7.0.71" } }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" - }, + "node_modules/worker-timers-broker": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz", + "integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==", + "license": "MIT", "dependencies": { - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - } + "@babel/runtime": "^7.24.5", + "fast-unique-numbers": "^8.0.13", + "tslib": "^2.6.2", + "worker-timers-worker": "^7.0.71" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "node_modules/worker-timers-worker": { + "version": "7.0.71", + "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz", + "integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.5", + "tslib": "^2.6.2" + } }, - "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", - "dev": true + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, - "wrap-ansi": { + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } + "utf-8-validate": { + "optional": true } } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "devOptional": true + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } + "license": "ISC" }, - "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "requires": {} + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, - "xpc-connect": { - "version": "npm:debug@4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "optional": true, - "requires": { - "ms": "2.1.2" + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index e59db4080f..6f3c705d84 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,17 @@ { - "name": "openrowingmonitor", - "version": "0.8.2", + "name": "OpenRowingMonitor", + "version": "0.9.6", "description": "A free and open source performance monitor for rowing machines", "main": "app/server.js", - "author": "Lars Berning", + "author": "Jaap van Ekris", "license": "GPL-3.0", "repository": { "type": "git", - "url": "https://github.com/laberning/openrowingmonitor.git" + "url": "https://github.com/JaapvanEkris/openrowingmonitor.git" }, "type": "module", "engines": { - "node": ">=14" + "node": ">=20" }, "files": [ "*", @@ -20,9 +20,6 @@ "scripts": { "lint": "eslint ./app ./config && markdownlint-cli2 '**/*.md' '#node_modules'", "start": "node app/server.js", - "dev": "npm-run-all --parallel dev:backend dev:frontend", - "dev:backend": "nodemon --ignore 'app/client/**/*' app/server.js", - "dev:frontend": "snowpack dev", "build": "rollup -c", "build:watch": "rollup -cw", "test": "uvu" @@ -30,57 +27,45 @@ "simple-git-hooks": { "pre-commit": "npm run lint && npm test" }, + "//fix1Comment": "We install lit@2.8.0 as lit@3.0.0 breaks the webpage displaying metrics", "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", - "lit": "2.1.3", - "loglevel": "1.8.0", + "@markw65/fit-file-writer": "^0.1.6", + "ble-host": "^1.0.3", + "chart.js": "^4.5.0", + "chartjs-plugin-datalabels": "^2.2.0", + "finalhandler": "^2.1.0", + "incyclist-ant-plus": "^0.3.5", + "lit": "^2.8.0", + "loglevel": "^1.9.1", + "mqtt": "^5.13.1", + "node-fetch": "^3.3.2", "nosleep.js": "0.12.0", "pigpio": "3.3.1", - "serve-static": "1.14.2", - "ws": "8.5.0", - "xml2js": "0.4.23" - }, - "//fix1Comment": "version 0.5.3-8 currently does not work with bleno", - "optionalDependencies": { - "@abandonware/bluetooth-hci-socket": "0.5.3-7" - }, - "//fix2Comment": "a hacky fix to not install the optional dependency xpc-connect which has a security issue", - "overrides": { - "@abandonware/bleno": { - "xpc-connect@": "npm:debug" - } + "replace-in-file": "^8.3.0", + "serve-static": "^2.2.0", + "ws": "^8.18.3" }, "devDependencies": { - "@babel/eslint-parser": "7.17.0", - "@babel/plugin-proposal-decorators": "7.17.2", - "@babel/preset-env": "7.16.11", - "@rollup/plugin-babel": "5.3.0", - "@rollup/plugin-commonjs": "21.0.1", - "@rollup/plugin-node-resolve": "13.1.3", - "@snowpack/plugin-babel": "2.1.7", - "@web/rollup-plugin-html": "1.10.1", - "axios": "0.25.0", - "eslint": "8.9.0", - "eslint-config-standard": "17.0.0-0", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-lit": "1.6.1", - "eslint-plugin-n": "14.0.0", - "eslint-plugin-promise": "6.0.0", - "eslint-plugin-wc": "1.3.2", + "@babel/eslint-parser": "^7.27.5", + "@babel/plugin-proposal-decorators": "^7.23.9", + "@babel/preset-env": "^7.27.2", + "@eslint/js": "^9.30.0", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^28.0.6", + "@rollup/plugin-node-resolve": "^16.0.0", + "@rollup/plugin-terser": "^0.4.4", + "@stylistic/eslint-plugin": "^5.1.0", + "@web/rollup-plugin-html": "^2.1.2", + "eslint": "^9.30.0", + "globals": "^16.2.0", "http2-proxy": "5.0.53", - "markdownlint-cli2": "0.4.0", - "nodemon": "2.0.15", + "markdownlint-cli2": "^0.18.1", + "nodemon": "^3.0.3", "npm-run-all": "4.1.5", - "rollup": "2.67.2", - "rollup-plugin-summary": "1.3.0", - "rollup-plugin-terser": "7.0.2", - "simple-git-hooks": "2.7.0", - "snowpack": "3.8.8", - "tar": "6.1.11", - "uvu": "0.5.3" + "rollup": "^4.44.1", + "rollup-plugin-summary": "^3.0.0", + "simple-git-hooks": "^2.9.0", + "tar": "^7.4.3", + "uvu": "^0.5.6" } } diff --git a/recordings/Concept2_Model_C.csv b/recordings/Concept2_Model_C.csv new file mode 100644 index 0000000000..f12c4bcca9 --- /dev/null +++ b/recordings/Concept2_Model_C.csv @@ -0,0 +1,7471 @@ +0.023929999999836582 +0.023895000000038635 +0.024149999999963256 +0.024381000000175845 +0.024294999999938227 +0.024319999999988795 +0.024570000000039727 +0.024429999999938445 +0.049320000000079744 +0.02476499999988846 +0.024620000000140863 +0.024934999999913998 +0.024785000000065338 +0.025120000000015352 +0.025024999999914144 +0.025155000000040673 +0.025069999999914216 +0.02542000000016742 +0.02512099999989914 +0.025394999999889478 +0.025540000000091823 +0.025515000000041255 +0.025650000000041473 +0.02557499999988977 +0.025525000000016007 +0.025620000000117216 +0.025939999999991414 +0.02575499999989006 +0.026014999999915744 +0.026164999999991778 +0.02598500000021886 +0.026074999999991633 +0.026365999999825362 +0.026123999999981606 +0.0263710000001538 +0.026389999999992142 +0.026534999999967113 +0.026474999999891224 +0.02676000000019485 +0.02670999999986634 +0.026644999999916763 +0.026935000000094078 +0.026824999999917054 +0.026960000000144646 +0.027084999999942738 +0.027074999999967986 +0.02719999999999345 +0.02726099999995313 +0.027215000000069267 +0.027360000000044238 +0.02761000000009517 +0.02762499999994361 +0.027394999999842184 +0.0276850000000195 +0.0278600000001461 +0.027704999999969004 +0.02843000000007123 +0.027354999999943175 +0.028069999999843276 +0.028120000000171785 +0.02835000000004584 +0.02814499999999498 +0.02819099999987884 +0.028414999999995416 +0.028444999999919673 +0.028590000000122018 +0.028645000000096843 +0.028709999999819047 +0.02870500000017273 +0.028734999999869615 +0.0288949999999204 +0.02902500000004693 +0.02906499999994594 +0.02904500000022381 +0.029439999999794964 +0.02909599999998136 +0.029325000000198997 +0.029749999999921783 +0.02927500000009786 +0.029494999999997162 +0.02990999999997257 +0.05945999999994456 +0.029510000000072978 +0.029869999999846186 +0.02948500000002241 +0.029710000000022774 +0.02976000000012391 +0.02895999999986998 +0.029316000000108033 +0.028724999999894862 +0.028209999999944557 +0.028160000000070795 +0.027595000000019354 +0.027329999999892607 +0.02680000000009386 +0.026460000000042783 +0.02595500000006723 +0.025619999999889842 +0.025235000000066066 +0.024809999999888532 +0.024429999999938445 +0.024390000000039436 +0.023576000000048225 +0.023613999999952284 +0.023251000000072963 +0.022895000000062282 +0.022944999999936044 +0.022760000000062064 +0.02215499999988424 +0.022615000000087093 +0.021849999999858483 +0.0220400000000609 +0.022089999999934662 +0.021910000000161745 +0.022134999999934735 +0.022275000000036016 +0.022204999999985375 +0.02225500000008651 +0.022304999999960273 +0.022534999999834326 +0.022476000000096974 +0.022484000000076776 +0.0224759999998696 +0.022619999999960783 +0.02282500000001164 +0.022660000000087166 +0.02271999999993568 +0.022979999999961365 +0.023385000000189393 +0.022979999999961365 +0.022739999999885185 +0.022760000000062064 +0.023255000000062864 +0.02328999999986081 +0.02317500000003747 +0.023300000000062937 +0.023509999999987485 +0.023535000000038053 +0.023394999999936772 +0.02359100000012404 +0.023554999999987558 +0.023669999999810898 +0.02383500000019012 +0.023725000000013097 +0.02388499999983651 +0.023965000000089276 +0.023930000000063956 +0.024114999999937936 +0.024089999999887368 +0.024245000000064465 +0.024165000000039072 +0.024390000000039436 +0.02458499999988817 +0.02422999999998865 +0.0245150000000649 +0.02440599999999904 +0.024640000000090367 +0.0246599999998125 +0.04967500000020664 +0.02486999999996442 +0.024884999999812862 +0.025040000000217333 +0.024989999999888823 +0.025159999999914362 +0.02503500000011627 +0.02571999999986474 +0.02507000000014159 +0.02525500000001557 +0.025709999999889988 +0.025161000000025524 +0.02566500000011729 +0.025589999999965585 +0.025744999999915308 +0.025730000000066866 +0.02584999999999127 +0.02602999999999156 +0.052005000000008295 +0.026094999999941138 +0.02589499999999134 +0.026430000000118525 +0.026364999999941574 +0.026350000000093132 +0.02670999999986634 +0.026211000000103013 +0.026404999999840584 +0.027160000000094442 +0.026325000000042564 +0.026629999999840948 +0.027064999999993233 +0.02690500000016982 +0.02674000000001797 +0.027179999999816573 +0.027410000000145374 +0.026724999999942156 +0.027859999999918728 +0.026890000000094005 +0.02764999999999418 +0.02737000000001899 +0.027280999999902633 +0.02779000000009546 +0.027509999999892898 +0.027660000000196305 +0.027910000000019863 +0.027924999999868305 +0.0557650000000649 +0.02825499999994463 +0.0281800000000203 +0.028135000000020227 +0.028620000000046275 +0.028229999999894062 +0.028005000000121072 +0.02836499999989428 +0.028440999999929772 +0.02821000000017193 +0.028129999999919164 +0.027745000000095388 +0.027559999999994034 +0.027769999999918582 +0.027315000000044165 +0.02733499999999367 +0.026685000000043146 +0.027039999999942665 +0.026119999999991705 +0.025944999999865104 +0.025976000000127897 +0.025179999999863867 +0.025375000000167347 +0.024734999999964202 +0.02450500000009015 +0.024329999999963547 +0.02402499999993779 +0.023684999999886713 +0.023535000000038053 +0.023355000000037762 +0.023020000000087748 +0.022909999999910724 +0.022799999999961074 +0.02260500000011234 +0.022524999999859574 +0.02250000000003638 +0.022490000000061627 +0.022629999999935535 +0.022590000000036525 +0.022666000000072017 +0.022805000000062137 +0.022699999999986176 +0.022849999999834836 +0.023024999999961437 +0.02299000000016349 +0.02292999999986023 +0.02331000000003769 +0.023005000000011933 +0.023149999999986903 +0.0232499999999618 +0.023464999999987413 +0.023265000000037617 +0.023519999999962238 +0.02345500000001266 +0.02373000000011416 +0.023496000000022832 +0.023705000000063592 +0.023729999999886786 +0.023944999999912397 +0.0238000000001648 +0.02381999999988693 +0.024069999999937863 +0.023925000000190266 +0.02412499999991269 +0.024214999999912834 +0.024570000000039727 +0.023869999999988067 +0.02443000000016582 +0.024419999999963693 +0.024434999999812135 +0.024695000000065193 +0.024450000000115324 +0.049610999999913474 +0.024805000000014843 +0.02468500000009044 +0.025104999999939537 +0.02472999999986314 +0.025195000000167056 +0.0250549999998384 +0.02520500000014181 +0.025165000000015425 +0.025394999999889478 +0.025319999999965148 +0.025235000000066066 +0.025744999999915308 +0.02542000000016742 +0.025705999999900087 +0.02567999999996573 +0.025804999999991196 +0.025610000000142463 +0.025984999999991487 +0.02595999999994092 +0.025900000000092405 +0.02617999999984022 +0.0262000000000171 +0.026275000000168802 +0.0264199999999164 +0.026370000000042637 +0.026184999999941283 +0.026495000000068103 +0.02645499999994172 +0.026624999999967258 +0.026741000000129134 +0.02667499999984102 +0.026884999999992942 +0.026865000000043437 +0.02687500000001819 +0.0269149999999172 +0.027235000000018772 +0.027250000000094587 +0.02737499999989268 +0.027064999999993233 +0.02747500000009495 +0.02722999999991771 +0.02747999999996864 +0.027739999999994325 +0.027530000000069776 +0.027800999999954 +0.027569999999968786 +0.027945000000045184 +0.02790000000004511 +0.028170000000045547 +0.027919999999994616 +0.028099999999994907 +0.028305000000045766 +0.028270000000020445 +0.028304999999818392 +0.028445000000147047 +0.028389999999944848 +0.028724999999894862 +0.028500000000121872 +0.028696000000081767 +0.029009999999971114 +0.028729999999995925 +0.028864999999996144 +0.029089999999996508 +0.028869999999869833 +0.029054999999971187 +0.057575000000042564 +0.02852500000017244 +0.028444999999919673 +0.028160000000070795 +0.028199999999969805 +0.027934999999843058 +0.026935999999977867 +0.02722500000004402 +0.02674000000001797 +0.026425000000017462 +0.026049999999941065 +0.025900000000092405 +0.02529000000004089 +0.025034999999888896 +0.024785000000065338 +0.02436000000011518 +0.02405999999996311 +0.023899999999912325 +0.023580000000038126 +0.023265000000037617 +0.0231300000000374 +0.023155999999971755 +0.02240499999993517 +0.022490000000061627 +0.02233000000001084 +0.022344999999859283 +0.022159999999985303 +0.02211000000011154 +0.022024999999985084 +0.022289999999884458 +0.022415000000137297 +0.022064999999884094 +0.022545000000036453 +0.022345000000086657 +0.022490000000061627 +0.022559999999884894 +0.02257000000008702 +0.022739999999885185 +0.02271100000007209 +0.022784999999885258 +0.0457850000000235 +0.023040000000037253 +0.022895000000062282 +0.023255000000062864 +0.022969999999986612 +0.023029999999835127 +0.023470000000088476 +0.046474999999873035 +0.02369000000021515 +0.02323999999998705 +0.023514999999861175 +0.02370999999993728 +0.02359500000011394 +0.023719999999912034 +0.02394100000014987 +0.02370999999993728 +0.024034999999912543 +0.023850000000038563 +0.023969999999962965 +0.024135000000114815 +0.024139999999988504 +0.024274999999988722 +0.024145000000089567 +0.024434999999812135 +0.024364999999988868 +0.024340000000165674 +0.024670000000014625 +0.02451999999993859 +0.02465000000006512 +0.02472499999998945 +0.024750999999923806 +0.025200000000040745 +0.024709999999913634 +0.024750000000040018 +0.025055000000065775 +0.02508999999986372 +0.025190000000065993 +0.02507500000001528 +0.02543999999988955 +0.02531500000009146 +0.025335000000040964 +0.025624999999990905 +0.025415000000066357 +0.025624999999990905 +0.02571499999999105 +0.02571100000000115 +0.02571499999999105 +0.02585999999996602 +0.02606500000001688 +0.026094999999941138 +0.025910000000067157 +0.026149999999915963 +0.026094999999941138 +0.026455000000169093 +0.026124999999865395 +0.02666999999996733 +0.026335000000017317 +0.026405000000067957 +0.02656000000001768 +0.026810000000068612 +0.02656499999989137 +0.026820999999927153 +0.027035000000068976 +0.02680499999996755 +0.02704500000004373 +0.027139999999917563 +0.02719999999999345 +0.027035000000068976 +0.027344999999968422 +0.027375000000120053 +0.02734999999984211 +0.027530000000069776 +0.027565000000095097 +0.027669999999943684 +0.02775599999995393 +0.027640000000019427 +0.028150000000096043 +0.02769999999986794 +0.028375000000096406 +0.0276850000000195 +0.02819499999986874 +0.028095000000121217 +0.028164999999944484 +0.028559999999970387 +0.02828999999996995 +0.028829999999970823 +0.028279999999995198 +0.028515000000197688 +0.028724999999894862 +0.02891100000010738 +0.028764999999793872 +0.028800000000046566 +0.028945000000021537 +0.028520000000071377 +0.028284999999868887 +0.028435000000172295 +0.027959999999893625 +0.02765999999996893 +0.027305000000069413 +0.02715499999999338 +0.026724999999942156 +0.026565000000118744 +0.025979999999890424 +0.025865999999950873 +0.025260000000116634 +0.025055000000065775 +0.024715000000014697 +0.024289999999837164 +0.02391499999998814 +0.023715000000038344 +0.0233499999999367 +0.02317500000003747 +0.022855000000163272 +0.022524999999859574 +0.022339999999985594 +0.022095000000035725 +0.021940000000086002 +0.021714999999858264 +0.021600000000034925 +0.021425000000135697 +0.021374999999807187 +0.021356000000196218 +0.02155999999990854 +0.021169999999983702 +0.02143500000011045 +0.021554999999807478 +0.02167500000018663 +0.02145499999983258 +0.02189500000008593 +0.02186000000006061 +0.021499999999832653 +0.021900000000186992 +0.021794999999883657 +0.021960000000035507 +0.022345000000086657 +0.021884999999883803 +0.022024999999985084 +0.02214500000013686 +0.022199999999884312 +0.02236100000004626 +0.022414999999909924 +0.02235500000006141 +0.022420000000010987 +0.022639999999910287 +0.022505000000137443 +0.022699999999986176 +0.02268000000003667 +0.022764999999935753 +0.022795000000087384 +0.022844999999961146 +0.023059999999986758 +0.02317500000003747 +0.0228549999999359 +0.023054999999885695 +0.023211000000173954 +0.023218999999926382 +0.023235999999997148 +0.023390000000063083 +0.023369999999886204 +0.02370999999993728 +0.023365000000012515 +0.0236250000000382 +0.02366000000006352 +0.023605000000088694 +0.02380999999991218 +0.023869999999988067 +0.023850000000038563 +0.024075000000038926 +0.024074999999811553 +0.02387000000021544 +0.0243399999999383 +0.024075000000038926 +0.024460999999973865 +0.024259999999912907 +0.024290000000064538 +0.02447000000006483 +0.02487499999983811 +0.024305000000140353 +0.024604999999837673 +0.0247900000001664 +0.02459499999986292 +0.025174999999990177 +0.024565000000166037 +0.025029999999787833 +0.024905000000217115 +0.025234999999838692 +0.025020000000040454 +0.025419999999940046 +0.02518000000009124 +0.02532100000007631 +0.025424999999813735 +0.02542000000016742 +0.025634999999965657 +0.025505000000066502 +0.025769999999965876 +0.0256499999998141 +0.02577000000019325 +0.02600999999981468 +0.025825000000168075 +0.026404999999840584 +0.02570000000014261 +0.026114999999890642 +0.026225000000067666 +0.026221000000077765 +0.026404999999840584 +0.026420000000143773 +0.026404999999840584 +0.02670499999999265 +0.026460000000042783 +0.02673000000004322 +0.02674000000001797 +0.02683999999999287 +0.026785000000018044 +0.026924999999891952 +0.02705000000014479 +0.027014999999892098 +0.027305000000069413 +0.027254999999968277 +0.02729599999997845 +0.027174999999942884 +0.0275850000000446 +0.027450000000044383 +0.0275850000000446 +0.027474999999867578 +0.02817500000014661 +0.02726499999994303 +0.027665000000069995 +0.027439999999842257 +0.027580000000170912 +0.027434999999968568 +0.054120000000011714 +0.02673000000004322 +0.0265359999998509 +0.052170000000160144 +0.025564999999915017 +0.025314999999864085 +0.024840000000040163 +0.024565000000166037 +0.02402999999981148 +0.023865000000114378 +0.023584999999911815 +0.0230300000000625 +0.022774999999910506 +0.022635000000036598 +0.022155000000111613 +0.02193499999998494 +0.021784999999908905 +0.0214410000000953 +0.021268999999847438 +0.021071000000119966 +0.020944999999983338 +0.02073999999993248 +0.020740000000159853 +0.020839999999907377 +0.020404999999982465 +0.02062999999998283 +0.020670000000109212 +0.02066500000000815 +0.02088499999990745 +0.020694999999932406 +0.02091000000018539 +0.020890000000008513 +0.021039999999857173 +0.021070000000008804 +0.02129600000012033 +0.021018999999796506 +0.021326000000044587 +0.021110000000135187 +0.021420000000034634 +0.021374999999807187 +0.021349999999983993 +0.02147000000013577 +0.02143999999998414 +0.021829999999908978 +0.02148499999998421 +0.021754999999984648 +0.02200500000003558 +0.021560000000135915 +0.022015000000010332 +0.021790000000009968 +0.02183999999988373 +0.022050000000035652 +0.022165000000086366 +0.04444999999986976 +0.02208599999994476 +0.02253000000018801 +0.02233499999988453 +0.02236500000003616 +0.022480000000086875 +0.022459999999909996 +0.022905000000037035 +0.02243999999996049 +0.022725000000036744 +0.02279499999986001 +0.023059999999986758 +0.022685000000137734 +0.022940000000062355 +0.023044999999910942 +0.023079999999936263 +0.02313500000013846 +0.02327999999988606 +0.023220000000037544 +0.023220999999921332 +0.023505000000113796 +0.02328499999998712 +0.02349000000003798 +0.023649999999861393 +0.023500000000012733 +0.023824999999987995 +0.023650000000088767 +0.02377000000001317 +0.023909999999887077 +0.023869999999988067 +0.023905000000013388 +0.024240000000190776 +0.024109999999836873 +0.024184999999988577 +0.02405599999997321 +0.024415000000090004 +0.024345000000039363 +0.02440999999998894 +0.024564999999938664 +0.02426500000001397 +0.025090000000091095 +0.02424499999983709 +0.049815000000080545 +0.024599999999963984 +0.024730000000090513 +0.0251100000000406 +0.024919999999838183 +0.025170000000116488 +0.02514500000006592 +0.025214999999889187 +0.025380999999924825 +0.02529000000004089 +0.02553499999999076 +0.02531500000009146 +0.025615000000016153 +0.051375000000007276 +0.025619999999889842 +0.02612500000009277 +0.02546499999994012 +0.0261000000000422 +0.026004999999940992 +0.025980000000117798 +0.026259999999865613 +0.02613500000006752 +0.026190999999926134 +0.02652000000011867 +0.026254999999991924 +0.02649499999984073 +0.026569999999992433 +0.026530000000093423 +0.026714999999967404 +0.026810000000068612 +0.026640000000043074 +0.026785000000018044 +0.026724999999942156 +0.02652999999986605 +0.02652000000011867 +0.026405000000067957 +0.02599499999996624 +0.02606599999990067 +0.025645000000167784 +0.02549999999996544 +0.025129999999990105 +0.025024999999914144 +0.024474999999938518 +0.02433500000006461 +0.023834999999962747 +0.023795000000063737 +0.023149999999986903 +0.0230300000000625 +0.02268000000003667 +0.022319999999808715 +0.022140000000035798 +0.02178500000013628 +0.021610000000009677 +0.021405999999842606 +0.021179000000074666 +0.020886000000018612 +0.020790000000033615 +0.02052000000003318 +0.02028999999993175 +0.02035499999988133 +0.02013000000010834 +0.020125000000007276 +0.020299999999906504 +0.02005500000018401 +0.02013499999998203 +0.020234999999956926 +0.020269999999982247 +0.020414999999957217 +0.020324999999957072 +0.020485000000007858 +0.020465000000058353 +0.020579999999881693 +0.02066000000013446 +0.02066500000000815 +0.02073100000006889 +0.02074499999980617 +0.02077000000008411 +0.020925000000033833 +0.020890000000008513 +0.020974999999907595 +0.021115000000008877 +0.02106000000003405 +0.02141499999993357 +0.020995000000084474 +0.021154999999907886 +0.02136500000005981 +0.02130499999998392 +0.021385000000009313 +0.021404999999958818 +0.021565000000009604 +0.021660000000110813 +0.021600000000034925 +0.02170099999989361 +0.021700000000009823 +0.02172500000006039 +0.02194499999995969 +0.021880000000010114 +0.02197499999988395 +0.0220400000000609 +0.022190000000136934 +0.022074999999858846 +0.02211000000011154 +0.022275000000036016 +0.022199999999884312 +0.02239000000008673 +0.02261499999985972 +0.02225500000008651 +0.022580000000061773 +0.022549999999910142 +0.02268499999991036 +0.022661000000198328 +0.022699999999986176 +0.022879999999986467 +0.022934999999961292 +0.022870000000011714 +0.0229749999998603 +0.023085000000037326 +0.023305000000164 +0.02292999999986023 +0.023335000000088257 +0.023234999999885986 +0.023280000000113432 +0.023479999999835854 +0.023385000000189393 +0.02352999999993699 +0.023645999999871492 +0.02362400000015441 +0.023721000000023196 +0.023715000000038344 +0.023779999999987922 +0.02395499999988715 +0.023920000000089203 +0.024040000000013606 +0.023969999999962965 +0.024245000000064465 +0.024119999999811625 +0.024255000000039217 +0.024355000000014115 +0.02426500000001397 +0.024564999999938664 +0.024415000000090004 +0.024605000000065047 +0.02450999999996384 +0.024744999999938955 +0.02471600000012586 +0.024884999999812862 +0.024845000000141226 +0.024879999999939173 +0.025010000000065702 +0.025084999999990032 +0.02500499999996464 +0.025249999999914507 +0.025305000000116706 +0.0253299999999399 +0.02543500000001586 +0.025394999999889478 +0.02543500000001586 +0.025575000000117143 +0.0256010000000515 +0.025724999999965803 +0.026204999999890788 +0.025485000000116997 +0.025819999999839638 +0.0258800000001429 +0.02621499999986554 +0.025910000000067157 +0.02612500000009277 +0.026460000000042783 +0.02604499999984 +0.026465000000143846 +0.02638499999989108 +0.026444999999966967 +0.026534999999967113 +0.026876000000129352 +0.02642999999989115 +0.026425000000017462 +0.026475000000118598 +0.026339999999891006 +0.026180000000067594 +0.026020000000016807 +0.025939999999991414 +0.02557499999988977 +0.02546000000006643 +0.02535499999999047 +0.024474999999938518 +0.024640000000090367 +0.02419499999996333 +0.02370999999993728 +0.02365500000018983 +0.02323999999998705 +0.022810999999819614 +0.022830000000112705 +0.02218999999990956 +0.02194499999995969 +0.021765000000186774 +0.021754999999984648 +0.02098999999998341 +0.021105000000034124 +0.02110499999980675 +0.020335000000159198 +0.0204999999998563 +0.020510000000058426 +0.02013000000010834 +0.020305000000007567 +0.020189999999956854 +0.020094999999855645 +0.0202350000001843 +0.020256000000017593 +0.020305000000007567 +0.02042499999993197 +0.020404999999982465 +0.020465000000058353 +0.02056999999990694 +0.020584999999982756 +0.02062500000010914 +0.020794999999907304 +0.020684999999957654 +0.020780000000058862 +0.02091500000005908 +0.020949999999857027 +0.020870000000059008 +0.021044999999958236 +0.0209500000000844 +0.021144999999933134 +0.021240000000034343 +0.021210999999993874 +0.021279999999933352 +0.02126500000008491 +0.02158000000008542 +0.021254999999882784 +0.021560000000135915 +0.021504999999933716 +0.021610000000009677 +0.021719999999959327 +0.021614999999883366 +0.02175500000021202 +0.043794999999818174 +0.021915000000035434 +0.022024999999985084 +0.021960000000035507 +0.022100000000136788 +0.02226499999983389 +0.022169999999960055 +0.022245999999995547 +0.022805000000062137 +0.021995000000060827 +0.022414999999909924 +0.022455000000036307 +0.02267000000006192 +0.0224799999998595 +0.022765000000163127 +0.022674999999935608 +0.022760000000062064 +0.022879999999986467 +0.02292499999998654 +0.022940000000062355 +0.023114999999961583 +0.022989999999936117 +0.023079999999936263 +0.023255000000062864 +0.02328499999998712 +0.023255000000062864 +0.023496000000022832 +0.023320000000012442 +0.023449999999911597 +0.02369999999996253 +0.02359500000011394 +0.023504999999886422 +0.023895000000038635 +0.02373499999998785 +0.023865000000114378 +0.023869999999988067 +0.023899999999912325 +0.024145000000089567 +0.023959999999988213 +0.024314999999887732 +0.02405999999996311 +0.024290000000064538 +0.0243359999999484 +0.0243950000001405 +0.02448499999991327 +0.024495000000115397 +0.024634999999989304 +0.024719999999888387 +0.02472499999998945 +0.024660000000039872 +0.024889999999913925 +0.02474500000016633 +0.025109999999813226 +0.024945000000116124 +0.025194999999939682 +0.02500000000009095 +0.025335000000040964 +0.025134999999863794 +0.02539600000000064 +0.025335000000040964 +0.02564000000006672 +0.02529000000004089 +0.025669999999990978 +0.025739999999814245 +0.025650000000041473 +0.025855000000092332 +0.025844999999890206 +0.02591500000016822 +0.026054999999814754 +0.02584999999999127 +0.02623000000016873 +0.026155000000017026 +0.026279999999815118 +0.02624100000002727 +0.026420000000143773 +0.02674499999989166 +0.026425000000017462 +0.02638000000001739 +0.02665999999999258 +0.026685000000043146 +0.02688999999986663 +0.02670499999999265 +0.02704500000004373 +0.02658500000006825 +0.026575000000093496 +0.026514999999790234 +0.02616000000011809 +0.025941000000102576 +0.025693999999930384 +0.02547099999992497 +0.04987000000005537 +0.02430000000003929 +0.02430499999991298 +0.023464999999987413 +0.023400000000037835 +0.02296000000001186 +0.022600000000011278 +0.02233499999988453 +0.022055000000136715 +0.021754999999984648 +0.021500000000060027 +0.021244999999908032 +0.020929999999907523 +0.020825000000058935 +0.020580000000109067 +0.020301000000017666 +0.020264999999881184 +0.020019999999931315 +0.01985000000013315 +0.019774999999981446 +0.019624999999905413 +0.019545000000107393 +0.019569999999930587 +0.01957500000003165 +0.019524999999930515 +0.01963500000010754 +0.019729999999981374 +0.019665000000031796 +0.01979499999993095 +0.019739999999956126 +0.019864999999981592 +0.019940000000133296 +0.019945000000006985 +0.020049999999855572 +0.02009600000019418 +0.020094999999855645 +0.020189999999956854 +0.020250000000032742 +0.02053000000000793 +0.020075000000133514 +0.02031999999985601 +0.02048000000013417 +0.02045999999995729 +0.020539999999982683 +0.020559999999932188 +0.020684999999957654 +0.020715000000109285 +0.020839999999907377 +0.02073500000005879 +0.020909999999958018 +0.0207749999999578 +0.021105000000034124 +0.020965000000160217 +0.020995999999968262 +0.021154999999907886 +0.021255000000110158 +0.02120999999988271 +0.021314999999958673 +0.021630000000186556 +0.021049999999831925 +0.021529999999984284 +0.02151000000003478 +0.021590000000060172 +0.021565000000009604 +0.021719999999959327 +0.02175000000011096 +0.021679999999832944 +0.021915000000035434 +0.02194499999995969 +0.021880000000010114 +0.022095000000035725 +0.022020000000111395 +0.022035999999843625 +0.02228000000013708 +0.022449999999935244 +0.022214999999960128 +0.02221000000008644 +0.022455000000036307 +0.022399999999834108 +0.022600000000011278 +0.022529999999960637 +0.02264000000013766 +0.022735000000011496 +0.022690000000011423 +0.022884999999860156 +0.02285000000006221 +0.02299500000003718 +0.02281999999991058 +0.023145000000113214 +0.02332499999988613 +0.022906000000148197 +0.02335999999991145 +0.023230000000012296 +0.0232499999999618 +0.07118500000001404 +0.02292000000011285 +0.023719999999912034 +0.023640000000114014 +0.023769999999785796 +0.023810000000139553 +0.023909999999887077 +0.023895000000038635 +0.024215000000140208 +0.023824999999987995 +0.02416599999992286 +0.024220000000013897 +0.024255000000039217 +0.02458999999998923 +0.024179999999887514 +0.024520000000165965 +0.02444999999988795 +0.02465499999993881 +0.02447000000006483 +0.024879999999939173 +0.024655000000166183 +0.04973999999992884 +0.024920000000065556 +0.024934999999913998 +0.025335999999924752 +0.024959999999964566 +0.0251100000000406 +0.025319999999965148 +0.05074500000000626 +0.050950000000057116 +0.025610000000142463 +0.025809999999864885 +0.025575000000117143 +0.025774999999839565 +0.025935000000117725 +0.05203499999993255 +0.025890000000117652 +0.026230999999825144 +0.02574500000014268 +0.02628499999991618 +0.025669999999990978 +0.025705000000016298 +0.025589999999965585 +0.02525500000001557 +0.025104999999939537 +0.02490000000011605 +0.024490000000014334 +0.02430499999991298 +0.02405999999996311 +0.023675000000139335 +0.023334999999860884 +0.023059999999986758 +0.022795000000087384 +0.022545000000036453 +0.022091000000045824 +0.02194999999983338 +0.021695000000136133 +0.021574999999984357 +0.021459999999933643 +0.020935000000008586 +0.0209500000000844 +0.020684999999957654 +0.02049499999998261 +0.020504999999957363 +0.04043000000001484 +0.01998500000013337 +0.020129999999880965 +0.02010500000005777 +0.019700000000057116 +0.01999999999998181 +0.019864999999981592 +0.020049999999855572 +0.020001000000092972 +0.02013499999998203 +0.020175000000108412 +0.020274999999855936 +0.020230000000083237 +0.020375000000058208 +0.020344999999906577 +0.02060499999993226 +0.0204550000000836 +0.020465000000058353 +0.020559999999932188 +0.02071499999988191 +0.020650000000159707 +0.02098000000000866 +0.020839999999907377 +0.020705000000134532 +0.020769999999856736 +0.021110000000135187 +0.021019999999907668 +0.020976000000018757 +0.021169999999983702 +0.021244999999908032 +0.021175000000084765 +0.021459999999933643 +0.02119500000003427 +0.021425000000135697 +0.021579999999858046 +0.021380000000135624 +0.02152000000000953 +0.021684999999934007 +0.02162499999985812 +0.02171000000021195 +0.021989999999959764 +0.021684999999934007 +0.02197999999998501 +0.02189500000008593 +0.021964999999909196 +0.022060000000010405 +0.02221600000007129 +0.022179999999934807 +0.022124999999959982 +0.022860000000036962 +0.021940000000086002 +0.02233499999988453 +0.02250000000003638 +0.022449999999935244 +0.02260999999998603 +0.022695000000112486 +0.022659999999859792 +0.022730000000137807 +0.0228549999999359 +0.022860000000036962 +0.022834999999986394 +0.023110000000087894 +0.02299599999992097 +0.023169999999936408 +0.023220000000037544 +0.023095000000012078 +0.02320000000008804 +0.023659999999836145 +0.023145000000113214 +0.02345500000001266 +0.023615000000063446 +0.023619999999937136 +0.023519999999962238 +0.023729999999886786 +0.024385000000165746 +0.023199999999860665 +0.023895000000038635 +0.023924999999962893 +0.024000999999998385 +0.024044000000003507 +0.02418600000009974 +0.024065000000064174 +0.024319999999988795 +0.024345000000039363 +0.024324999999862484 +0.02448000000003958 +0.024464999999963766 +0.024585000000115542 +0.024699999999938882 +0.04951499999992848 +0.02472000000011576 +0.02496999999993932 +0.024734999999964202 +0.02514999999993961 +0.02521500000011656 +0.024961000000075728 +0.025064999999813153 +0.025409999999965294 +0.025335000000040964 +0.02531500000009146 +0.025319999999965148 +0.025595000000066648 +0.025654999999915162 +0.025585000000091895 +0.02560999999991509 +0.026045000000067375 +0.025579999999990832 +0.025930000000016662 +0.02602999999999156 +0.025984999999991487 +0.026114999999890642 +0.026116000000001804 +0.02623000000016873 +0.026329999999916254 +0.02662000000009357 +0.026129999999966458 +0.0266950000000179 +0.02600999999981468 +0.026180000000067594 +0.025984999999991487 +0.026190000000042346 +0.025840000000016516 +0.025660000000016225 +0.02593499999989035 +0.025195000000167056 +0.025374999999939973 +0.024985999999898922 +0.025174999999990177 +0.024240000000190776 +0.024434999999812135 +0.023920000000089203 +0.023789999999962674 +0.023300000000062937 +0.023124999999936335 +0.02260999999998603 +0.022650000000112414 +0.02253999999993539 +0.043159999999943466 +0.06375500000012835 +0.02046099999984108 +0.020533999999997832 +0.02039100000001781 +0.02059000000008382 +0.020099999999956708 +0.020120000000133587 +0.020304999999780193 +0.020425000000159343 +0.020324999999957072 +0.020399999999881402 +0.020395000000007713 +0.02058500000021013 +0.02062999999998283 +0.02067999999985659 +0.020655000000033397 +0.0207749999999578 +0.021065000000135115 +0.020634999999856518 +0.020970000000033906 +0.020936000000119748 +0.020999999999958163 +0.02106000000003405 +0.02116000000000895 +0.021244999999908032 +0.021250000000009095 +0.021259999999983847 +0.02143500000011045 +0.021409999999832507 +0.02144999999995889 +0.0215450000000601 +0.021610000000009677 +0.021560000000135915 +0.02172999999993408 +0.02186000000006061 +0.02166999999985819 +0.021844999999984793 +0.022214999999960128 +0.021705000000110886 +0.02204499999993459 +0.02208100000007107 +0.022095000000035725 +0.022275000000036016 +0.02228500000001077 +0.022195000000010623 +0.02242999999998574 +0.022494999999935317 +0.022555000000011205 +0.022424999999884676 +0.02267000000006192 +0.022635000000036598 +0.022774999999910506 +0.022754999999961 +0.022800000000188447 +0.02295600000002196 +0.02296400000000176 +0.0229749999998603 +0.023255999999946653 +0.02298000000018874 +0.023169999999936408 +0.023469999999861102 +0.02316000000018903 +0.023309999999810316 +0.023645000000215077 +0.02335499999981039 +0.023480000000063228 +0.023785000000088985 +0.023549999999886495 +0.023689999999987776 +0.023920000000089203 +0.023789999999962674 +0.02401000000008935 +0.024034999999912543 +0.02395000000001346 +0.024116000000049098 +0.024109999999836873 +0.024375000000190994 +0.024144999999862193 +0.02450500000009015 +0.02430000000003929 +0.024569999999812353 +0.02443000000016582 +0.024639999999862994 +0.024735000000191576 +0.024684999999863066 +0.024850000000014916 +0.024920000000065556 +0.025020000000040454 +0.024899999999888678 +0.050306000000091444 +0.025279999999838765 +0.02496000000019194 +0.02536999999983891 +0.025335000000040964 +0.02539999999999054 +0.025654999999915162 +0.0513100000000577 +0.02553000000011707 +0.025734999999940555 +0.026110000000016953 +0.025560000000041327 +0.026155000000017026 +0.025809999999864885 +0.02673600000002807 +0.025755000000117434 +0.026204999999890788 +0.02628499999991618 +0.02638000000001739 +0.02627000000006774 +0.02658500000006825 +0.026464999999916472 +0.026145000000042273 +0.026294999999890933 +0.02588500000001659 +0.02582000000006701 +0.025804999999991196 +0.025525000000016007 +0.025170000000116488 +0.024885999999924024 +0.024744999999938955 +0.024249999999938154 +0.024280000000089785 +0.023680000000013024 +0.023410000000012587 +0.023159999999961656 +0.022834999999986394 +0.022470000000112123 +0.022240000000010696 +0.021964999999909196 +0.021700000000009823 +0.021469999999908396 +0.021250000000009095 +0.021065000000135115 +0.020751000000018394 +0.02048899999999776 +0.02046499999983098 +0.02023600000006809 +0.02007000000003245 +0.019990000000007058 +0.019909999999981665 +0.01975999999990563 +0.019830000000183645 +0.01992999999993117 +0.0196849999999813 +0.01989000000003216 +0.01992999999993117 +0.020015000000057626 +0.0199600000000828 +0.020154999999931533 +0.020199999999931606 +0.02013499999998203 +0.020260000000007494 +0.02027500000008331 +0.020315999999866108 +0.020434000000022934 +0.020506000000068525 +0.020434000000022934 +0.020575999999891792 +0.02062500000010914 +0.020634999999856518 +0.02076500000021042 +0.020729999999957727 +0.02080999999998312 +0.02101500000003398 +0.020864999999957945 +0.02091999999993277 +0.02102500000000873 +0.0210500000000593 +0.02119999999990796 +0.021255000000110158 +0.021189999999933207 +0.021169999999983702 +0.02161599999999453 +0.021355000000085056 +0.02133400000002439 +0.021580999999969208 +0.021645000000034997 +0.021499999999832653 +0.021735000000035143 +0.021740000000136206 +0.021724999999833017 +0.021950000000060754 +0.021850000000085856 +0.02215000000001055 +0.021925000000010186 +0.02205499999990934 +0.02204499999993459 +0.02221000000008644 +0.022179999999934807 +0.022435000000086802 +0.02264999999988504 +0.022050000000035652 +0.022580000000061773 +0.02246100000002116 +0.022564999999985957 +0.022635000000036598 +0.022770000000036816 +0.02286499999991065 +0.02260999999998603 +0.02303499999993619 +0.022805000000062137 +0.022979999999961365 +0.023149999999986903 +0.022965000000112923 +0.023224999999911233 +0.02327500000001237 +0.023290000000088185 +0.02327999999988606 +0.02344600000014907 +0.023383999999850857 +0.02359599999999773 +0.023570000000063374 +0.02363500000001295 +0.023779999999987922 +0.023644999999987704 +0.02397500000006403 +0.023764999999912106 +0.023955000000114524 +0.024079999999912616 +0.023909999999887077 +0.024290000000064538 +0.024120000000039 +0.024180000000114887 +0.024824999999964348 +0.023899999999912325 +0.025171000000000276 +0.02391499999998814 +0.024464999999963766 +0.024805000000014843 +0.04927500000007967 +0.02496999999993932 +0.024730000000090513 +0.024954999999863503 +0.025025000000141517 +0.025065000000040527 +0.02501499999993939 +0.025409999999965294 +0.02511499999991429 +0.0253850000001421 +0.02539000000001579 +0.025756000000001222 +0.025104999999939537 +0.025615000000016153 +0.02581499999996595 +0.025544999999965512 +0.025970000000143045 +0.025764999999864813 +0.02584999999999127 +0.025800000000117507 +0.026219999999966603 +0.02613999999994121 +0.026074999999991633 +0.026229999999941356 +0.02628000000004249 +0.02634000000011838 +0.0264199999999164 +0.026566000000002532 +0.02613999999994121 +0.02634000000011838 +0.02581499999996595 +0.02585999999996602 +0.025630000000091968 +0.02539999999999054 +0.025034999999888896 +0.02472499999998945 +0.02451999999993859 +0.023959999999988213 +0.023890000000164946 +0.023339999999961947 +0.023099999999885767 +0.022686000000021522 +0.0225350000000617 +0.022105000000010477 +0.02246500000001106 +0.02108500000008462 +0.021430000000009386 +0.021289999999908105 +0.02101500000003398 +0.02088499999990745 +0.020610000000033324 +0.020410000000083528 +0.020274999999855936 +0.020330000000058135 +0.019990000000007058 +0.019849999999905776 +0.019865000000208966 +0.019884999999931097 +0.019639999999981228 +0.019845000000032087 +0.019690999999966152 +0.019743999999946027 +0.019874999999956344 +0.019901000000118074 +0.019919999999956417 +0.02010500000005777 +0.019945000000006985 +0.040369999999938955 +0.02013499999998203 +0.02017000000000735 +0.020365000000083455 +0.02028499999983069 +0.020440000000007785 +0.04104500000016742 +0.020440000000007785 +0.020649999999932334 +0.020659999999907086 +0.02066000000013446 +0.020864999999957945 +0.02077600000006896 +0.021044999999958236 +0.02084500000000844 +0.02091500000005908 +0.021205000000009022 +0.020969999999806532 +0.02101500000003398 +0.021255000000110158 +0.0212699999999586 +0.021320000000059736 +0.021299999999882857 +0.021465000000034706 +0.021680000000060318 +0.02130499999998392 +0.021700000000009823 +0.02143999999998414 +0.02169499999990876 +0.02179999999998472 +0.021754999999984648 +0.021801000000095883 +0.02189999999995962 +0.022055000000136715 +0.022134999999934735 +0.021939999999858628 +0.02215000000001055 +0.022095000000035725 +0.022310000000061336 +0.02222499999993488 +0.022339999999985594 +0.02267000000006192 +0.02229499999998552 +0.022484999999960564 +0.022545000000036453 +0.02260500000011234 +0.02275999999983469 +0.02278000000001157 +0.022754999999961 +0.02284600000007231 +0.023124999999936335 +0.02282500000001164 +0.02314000000001215 +0.023014999999986685 +0.023110000000087894 +0.02320499999996173 +0.02334500000006301 +0.023269999999911306 +0.023374999999987267 +0.02355000000011387 +0.02342499999986103 +0.023675000000139335 +0.023629999999911888 +0.023619999999937136 +0.023700000000189902 +0.02389099999982136 +0.02384000000006381 +0.023895000000038635 +0.02405999999996311 +0.02408000000013999 +0.024019999999836728 +0.024385000000165746 +0.023984999999811407 +0.02433500000006461 +0.024425000000064756 +0.024345000000039363 +0.02455499999996391 +0.024549999999862848 +0.02457500000014079 +0.02462999999988824 +0.0247900000001664 +0.02479999999991378 +0.024781000000075437 +0.025094999999964784 +0.04993500000000495 +0.05057999999985441 +0.02497500000004038 +0.02543500000001586 +0.02529000000004089 +0.025239999999939755 +0.051089999999931024 +0.025650000000041473 +0.026290000000017244 +0.02500499999996464 +0.025656000000026324 +0.02557000000001608 +0.025440000000116925 +0.025139999999964857 +0.025139999999964857 +0.02494000000001506 +0.024609999999938736 +0.024380000000064683 +0.024284999999963475 +0.023760000000038417 +0.02366499999993721 +0.0238449999999375 +0.022440000000187865 +0.022714999999834617 +0.022470000000112123 +0.02208599999994476 +0.021889999999984866 +0.02161999999998443 +0.02136500000005981 +0.021770000000060463 +0.020549999999957436 +0.02088499999990745 +0.020760000000109358 +0.020379999999931897 +0.020324999999957072 +0.020230000000083237 +0.020160000000032596 +0.019939999999905922 +0.019990000000007058 +0.020080000000007203 +0.02014499999995678 +0.019665000000031796 +0.01996499999995649 +0.02010000000018408 +0.020069999999805077 +0.0201759999999922 +0.020144000000072992 +0.020361000000093554 +0.020340000000032887 +0.020344999999906577 +0.020635000000083892 +0.020419999999830907 +0.020470000000159416 +0.020909999999958018 +0.020285000000058062 +0.020710000000008222 +0.0207749999999578 +0.0207749999999578 +0.020825000000058935 +0.020970000000033906 +0.02120499999978165 +0.020680000000083965 +0.021259999999983847 +0.042220000000043 +0.021255999999993946 +0.021705000000110886 +0.02098000000000866 +0.02120499999978165 +0.021555000000034852 +0.021854999999959546 +0.021130000000084692 +0.02179500000011103 +0.021479999999883148 +0.021774999999934153 +0.021670000000085565 +0.02187000000003536 +0.02200500000003558 +0.021915000000035434 +0.022004999999808206 +0.022030000000086147 +0.022089999999934662 +0.02210600000012164 +0.02228900000000067 +0.022205999999869164 +0.022375000000010914 +0.02242500000011205 +0.02267000000006192 +0.022339999999985594 +0.022919999999885476 +0.022335000000111904 +0.022534999999834326 +0.0228100000001632 +0.022859999999809588 +0.022745000000213622 +0.022884999999860156 +0.023005000000011933 +0.023114999999961583 +0.02309000000013839 +0.02310499999998683 +0.04654600000003484 +0.023444999999810534 +0.023220000000037544 +0.023410000000012587 +0.02356499999996231 +0.04725500000017746 +0.04730499999982385 +0.023795000000063737 +0.023715000000038344 +0.024165000000039072 +0.023794999999836364 +0.02418500000021595 +0.02391499999998814 +0.024264999999786596 +0.024145000000089567 +0.02433100000007471 +0.024464999999963766 +0.024384999999938373 +0.024454999999989013 +0.024595000000090295 +0.02461999999991349 +0.024605000000065047 +0.025284999999939828 +0.02422500000011496 +0.024844999999913853 +0.024990000000116197 +0.024924999999939246 +0.02504999999996471 +0.025235000000066066 +0.02511499999991429 +0.025186000000076092 +0.025284999999939828 +0.025585000000091895 +0.0251549999998133 +0.025669999999990978 +0.02546000000006643 +0.025595000000066648 +0.025764999999864813 +0.02577500000006694 +0.025790000000142754 +0.025904999999966094 +0.026149999999915963 +0.02582000000006701 +0.026084999999966385 +0.026155000000017026 +0.026114999999890642 +0.02603599999997641 +0.026015000000143118 +0.02578500000004169 +0.02584999999999127 +0.02567999999996573 +0.025374999999939973 +0.025305000000116706 +0.024974999999813008 +0.024765000000115833 +0.02451999999993859 +0.024170000000140135 +0.024014999999963038 +0.023719999999912034 +0.023374999999987267 +0.02296000000001186 +0.02268499999991036 +0.022451000000046406 +0.022190000000136934 +0.02197000000001026 +0.02165500000000975 +0.021359999999958745 +0.02116499999988264 +0.020944999999983338 +0.020775000000185173 +0.020519999999805805 +0.02038500000003296 +0.020185000000083164 +0.02007000000003245 +0.019954999999981737 +0.019874999999956344 +0.01978000000008251 +0.01982499999985521 +0.019694999999956053 +0.01989000000003216 +0.019830000000183645 +0.0199009999998907 +0.020050000000082946 +0.020025000000032378 +0.0200049999998555 +0.020230000000083237 +0.020324999999957072 +0.020115000000032524 +0.020334999999931824 +0.020285000000058062 +0.02038500000003296 +0.02046499999983098 +0.02048000000013417 +0.02049499999998261 +0.020710000000008222 +0.02060499999993226 +0.0207749999999578 +0.02073500000005879 +0.0207749999999578 +0.020775000000185173 +0.02110499999980675 +0.020846000000119602 +0.0210500000000593 +0.021149999999806823 +0.02119000000016058 +0.021105000000034124 +0.02165500000000975 +0.020839999999907377 +0.021455000000059954 +0.021534999999857973 +0.021349999999983993 +0.02147500000000946 +0.021630000000186556 +0.021574999999984357 +0.021604999999908614 +0.02197499999988395 +0.02175000000011096 +0.021840000000111104 +0.02183999999988373 +0.02193499999998494 +0.022005999999919368 +0.02213500000016211 +0.02211499999998523 +0.02222000000006119 +0.022234999999909633 +0.022474999999985812 +0.02218999999990956 +0.022435000000086802 +0.022445000000061555 +0.022584999999935462 +0.022635000000036598 +0.022545000000036453 +0.022764999999935753 +0.023024999999961437 +0.022664999999960855 +0.023114999999961583 +0.022625000000061846 +0.02320600000007289 +0.022799999999961074 +0.023194999999986976 +0.02320499999996173 +0.023155000000087966 +0.02345500000001266 +0.023334999999860884 +0.023300000000062937 +0.0236250000000382 +0.02356000000008862 +0.02345999999988635 +0.023785000000088985 +0.02359999999998763 +0.047814999999900465 +0.02438099999994847 +0.023499000000128945 +0.023926000000074055 +0.02409499999998843 +0.02413499999988744 +0.02422500000011496 +0.024289999999837164 +0.024255000000039217 +0.02465000000006512 +0.024259999999912907 +0.024585000000115542 +0.024850000000014916 +0.024504999999862775 +0.0246150000000398 +0.024769999999989523 +0.024855999999999767 +0.02493000000004031 +0.024989000000005035 +0.02493600000002516 +0.025204999999914435 +0.025084999999990032 +0.025245000000040818 +0.025239999999939755 +0.02549999999996544 +0.025380000000041036 +0.025475000000142245 +0.025589999999965585 +0.025554999999940264 +0.02567999999996573 +0.0258800000001429 +0.02581499999996595 +0.025799999999890133 +0.026129999999966458 +0.025881000000026688 +0.02591500000016822 +0.026129999999966458 +0.02627499999994143 +0.026530000000093423 +0.02600999999981468 +0.026794999999992797 +0.026000000000067303 +0.02648999999996704 +0.026285000000143555 +0.026269999999840365 +0.02620500000011816 +0.02634499999999207 +0.025564999999915017 +0.025806000000102358 +0.02536999999983891 +0.02521999999999025 +0.024950000000217187 +0.02437999999983731 +0.02404999999998836 +0.023779999999987922 +0.023530000000164364 +0.022879999999986467 +0.02275999999983469 +0.022445000000061555 +0.02186000000006061 +0.02187000000003536 +0.021424999999908323 +0.02109999999993306 +0.021345000000110304 +0.02035499999988133 +0.020425000000159343 +0.020299999999906504 +0.020056000000067797 +0.01985999999988053 +0.01981500000010783 +0.01961000000005697 +0.019524999999930515 +0.019450000000006185 +0.019459999999980937 +0.019315000000005966 +0.019450000000006185 +0.019350000000031287 +0.01937499999985448 +0.019530000000031578 +0.019545000000107393 +0.019489999999905194 +0.0197849999999562 +0.01964500000008229 +0.019739999999956126 +0.0200600000000577 +0.019624999999905413 +0.019880000000057407 +0.01996099999996659 +0.019990000000007058 +0.0202350000001843 +0.020024999999805004 +0.020150000000057844 +0.02013000000010834 +0.02021999999988111 +0.020300000000133878 +0.02031499999998232 +0.020509999999831052 +0.020435000000134096 +0.020449999999982538 +0.020719999999982974 +0.020545000000083746 +0.02063999999995758 +0.020764999999983047 +0.02081499999985681 +0.020800000000008367 +0.02090500000008433 +0.020970000000033906 +0.020966000000044005 +0.021084999999857246 +0.021095000000059372 +0.02108500000008462 +0.02127499999983229 +0.02123000000005959 +0.021355000000085056 +0.02144999999995889 +0.021330000000034488 +0.02148499999998421 +0.02152000000000953 +0.02161999999998443 +0.021715000000085638 +0.021684999999934007 +0.021709999999984575 +0.021784999999908905 +0.021940000000086002 +0.02187000000003536 +0.022030999999969936 +0.022144999999909487 +0.02189500000008593 +0.02229499999998552 +0.022240000000010696 +0.022240000000010696 +0.02218500000003587 +0.02246500000001106 +0.022455000000036307 +0.022524999999859574 +0.022619999999960783 +0.022405000000162545 +0.022844999999961146 +0.022659999999859792 +0.022760000000062064 +0.02306500000008782 +0.02285600000004706 +0.022838999999976295 +0.022960999999895648 +0.02309000000013839 +0.023044999999910942 +0.023124999999936335 +0.023370000000113578 +0.02327500000001237 +0.02345500000001266 +0.02356499999996231 +0.023344999999835636 +0.023465000000214786 +0.023694999999861466 +0.023685000000114087 +0.023729999999886786 +0.023869999999988067 +0.02370999999993728 +0.024200000000064392 +0.023824999999987995 +0.02388599999994767 +0.024075000000038926 +0.024175000000013824 +0.024319999999988795 +0.024145000000089567 +0.024459999999862703 +0.02443500000003951 +0.024415000000090004 +0.024550000000090222 +0.024549999999862848 +0.024605000000065047 +0.024769999999989523 +0.024789999999939027 +0.02476000000001477 +0.025126000000000204 +0.024844999999913853 +0.025050000000192085 +0.02504999999996471 +0.025144999999838547 +0.02518000000009124 +0.025309999999990396 +0.02549500000009175 +0.025249999999914507 +0.025779999999940628 +0.02527500000019245 +0.025689999999940483 +0.025695000000041546 +0.025699999999915235 +0.025759999999991123 +0.02613999999994121 +0.02574600000002647 +0.02606000000014319 +0.026004999999940992 +0.025909999999839783 +0.025610000000142463 +0.025854999999864958 +0.02535499999999047 +0.025295000000141954 +0.025174999999990177 +0.024920000000065556 +0.02459499999986292 +0.024380000000064683 +0.023924999999962893 +0.023615000000063446 +0.023439999999936845 +0.023016000000097847 +0.02289499999983491 +0.022085000000060973 +0.02207999999995991 +0.021595000000161235 +0.02144999999995889 +0.02105499999993299 +0.02090500000008433 +0.020724999999856664 +0.02038000000015927 +0.020174999999881038 +0.020150000000057844 +0.019735000000082437 +0.01961499999993066 +0.019630000000006476 +0.01939500000003136 +0.019234999999980573 +0.019274999999879583 +0.019144999999980428 +0.019130000000131986 +0.0191859999999906 +0.0191899999999805 +0.019234999999980573 +0.01932499999998072 +0.019310000000132277 +0.01939999999990505 +0.01946999999995569 +0.019485000000031505 +0.01992500000005748 +0.01921500000003107 +0.01992999999993117 +0.01936999999998079 +0.019839999999931024 +0.019915000000082728 +0.019870000000082655 +0.019849999999905776 +0.020129999999880965 +0.02003500000000713 +0.019800000000032014 +0.02038100000004306 +0.019835000000057335 +0.020348999999896478 +0.020406000000093627 +0.02009500000008302 +0.020409999999856154 +0.020584999999982756 +0.020230000000083237 +0.02053499999988162 +0.020615000000134387 +0.0205550000000585 +0.02071499999988191 +0.020715000000109285 +0.020899999999983265 +0.020710000000008222 +0.020939999999882275 +0.020909999999958018 +0.02101500000003398 +0.021110000000135187 +0.021039999999857173 +0.021220999999968626 +0.021460000000161017 +0.04232999999999265 +0.021434999999883075 +0.021574999999984357 +0.02136500000005981 +0.02155999999990854 +0.021555000000034852 +0.021625000000085493 +0.021664999999984502 +0.021819999999934225 +0.02183500000001004 +0.021850000000085856 +0.021915000000035434 +0.021960000000035507 +0.022074999999858846 +0.02211000000011154 +0.02227099999981874 +0.022099000000025626 +0.022249999999985448 +0.0224310000000969 +0.022490000000061627 +0.022234999999909633 +0.022549999999910142 +0.02263000000016291 +0.022529999999960637 +0.022725000000036744 +0.02264500000001135 +0.023050000000012005 +0.02264500000001135 +0.023059999999986758 +0.022809999999935826 +0.023040000000037253 +0.0230300000000625 +0.023164999999835345 +0.02327500000001237 +0.023221000000148706 +0.023334999999860884 +0.023390000000063083 +0.023394999999936772 +0.02359000000001288 +0.023464999999987413 +0.02359000000001288 +0.02373499999998785 +0.023920000000089203 +0.023644999999987704 +0.023924999999962893 +0.02387999999996282 +0.024014999999963038 +0.023955000000114524 +0.024319999999988795 +0.02402499999993779 +0.02420099999994818 +0.024420000000191067 +0.02426999999988766 +0.024390000000039436 +0.02448499999991327 +0.024609999999938736 +0.02450000000021646 +0.02483999999981279 +0.02458000000001448 +0.024779999999964275 +0.024915000000191867 +0.024844999999913853 +0.02494499999988875 +0.02510500000016691 +0.025099999999838474 +0.025210000000015498 +0.0253810000001522 +0.025245000000040818 +0.025244999999813444 +0.025575000000117143 +0.02540499999986423 +0.025900000000092405 +0.025260000000116634 +0.025834999999915453 +0.026159999999890715 +0.02542500000004111 +0.02645000000006803 +0.02512499999988904 +0.02584500000011758 +0.025840000000016516 +0.02550499999983913 +0.02578500000004169 +0.025296000000025742 +0.025115000000141663 +0.024989999999888823 +0.024824999999964348 +0.02419000000008964 +0.024274999999988722 +0.023689999999987776 +0.0233499999999367 +0.023149999999986903 +0.022770000000036816 +0.022349999999960346 +0.022270000000162327 +0.021994999999833453 +0.021460000000161017 +0.021374999999807187 +0.021115000000008877 +0.020835000000033688 +0.020750000000134605 +0.02046599999994214 +0.020285000000058062 +0.02007499999990614 +0.020019999999931315 +0.019729999999981374 +0.019795000000158325 +0.019499999999879947 +0.019450000000006185 +0.019410000000107175 +0.019344999999930224 +0.019485000000031505 +0.01936499999987973 +0.01935500000013235 +0.019499999999879947 +0.01960000000008222 +0.019555000000082146 +0.01965499999982967 +0.01970500000015818 +0.019800000000032014 +0.01989600000001701 +0.019704999999930806 +0.019990000000007058 +0.01992500000005748 +0.019945000000006985 +0.020239999999830616 +0.019874999999956344 +0.02024000000005799 +0.020224999999982174 +0.020185000000083164 +0.020379999999931897 +0.02066500000000815 +0.020050000000082946 +0.02066999999988184 +0.020355000000108703 +0.02056999999990694 +0.020610000000033324 +0.020670000000109212 +0.020800000000008367 +0.020699999999806096 +0.02084100000001854 +0.020885000000134823 +0.02141000000005988 +0.020589999999856445 +0.02109999999993306 +0.021110000000135187 +0.0210500000000593 +0.0212699999999586 +0.021264999999857537 +0.021240000000034343 +0.021560000000135915 +0.021424999999908323 +0.021330000000034488 +0.021500000000060027 +0.02183500000001004 +0.021904999999833308 +0.02123000000005959 +0.022030000000086147 +0.02155599999991864 +0.021999999999934516 +0.022140000000035798 +0.02172500000006039 +0.022034999999959837 +0.0220400000000609 +0.02218999999990956 +0.02215000000001055 +0.02233000000001084 +0.02225500000008651 +0.022314999999935026 +0.023024999999961437 +0.02214500000013686 +0.022534999999834326 +0.045055000000047585 +0.022805000000062137 +0.02292499999998654 +0.02264599999989514 +0.02299000000016349 +0.0459849999999733 +0.0231300000000374 +0.023095000000012078 +0.023114999999961583 +0.023445000000037908 +0.02323999999998705 +0.04662499999994907 +0.04704500000002554 +0.02377000000001317 +0.023759999999811043 +0.023555000000214932 +0.023729999999886786 +0.023901000000023487 +0.02384000000006381 +0.024104999999963184 +0.023940000000038708 +0.02413499999988744 +0.024315000000115106 +0.024154999999836946 +0.0242950000001656 +0.02476499999988846 +0.023855000000139626 +0.02469499999983782 +0.024235000000089713 +0.024809999999888532 +0.04930500000000393 +0.024800000000141154 +0.02469599999994898 +0.02494499999988875 +0.024949999999989814 +0.0501200000001063 +0.05033000000003085 +0.02557000000001608 +0.025020000000040454 +0.025604999999814027 +0.025335000000040964 +0.02566500000011729 +0.0254299999999148 +0.025660000000016225 +0.02582000000006701 +0.025656000000026324 +0.025874999999814463 +0.025555000000167638 +0.025669999999990978 +0.025484999999889624 +0.025444999999990614 +0.025430000000142172 +0.024850000000014916 +0.024899999999888678 +0.02447000000006483 +0.04837499999985084 +0.02359999999998763 +0.0230300000000625 +0.0228549999999359 +0.02246500000001106 +0.022240000000010696 +0.021766000000070562 +0.021635000000060245 +0.02116499999988264 +0.021079999999983556 +0.02073500000005879 +0.020365000000083455 +0.0205550000000585 +0.01989499999990585 +0.019884999999931097 +0.019915000000082728 +0.019604999999955908 +0.019305000000031214 +0.01939999999990505 +0.019170000000030996 +0.019199999999955253 +0.0191899999999805 +0.0191450000002078 +0.019344999999930224 +0.01915000000008149 +0.019359999999778665 +0.019376000000193017 +0.0194099999998798 +0.019475000000056752 +0.019585000000006403 +0.019655000000057044 +0.019594999999981155 +0.01992999999993117 +0.019534999999905267 +0.019790000000057262 +0.01970500000015818 +0.01994499999977961 +0.019965000000183863 +0.01989499999990585 +0.020175000000108412 +0.020444999999881475 +0.019835000000057335 +0.020164999999906286 +0.020279999999957 +0.02023600000006809 +0.020355000000108703 +0.02035499999988133 +0.020500000000083674 +0.02053499999988162 +0.02053000000000793 +0.020925000000033833 +0.02045999999995729 +0.02069500000015978 +0.020689999999831343 +0.020885000000134823 +0.02091999999993277 +0.020819999999957872 +0.02106000000003405 +0.02108500000008462 +0.021034999999983484 +0.02120999999988271 +0.021205000000009022 +0.0212250000001859 +0.021329999999807114 +0.021420000000034634 +0.02133600000001934 +0.021494999999958964 +0.021525000000110595 +0.021735000000035143 +0.022144999999909487 +0.02119500000003427 +0.021574999999984357 +0.02189999999995962 +0.021885000000111177 +0.02187499999990905 +0.02204499999993459 +0.022010000000136642 +0.02205499999990934 +0.022695000000112486 +0.021809999999959473 +0.022130000000061045 +0.022339999999985594 +0.022425999999995838 +0.022389999999859356 +0.022529999999960637 +0.022470000000112123 +0.02268000000003667 +0.02289999999993597 +0.022470000000112123 +0.02296000000001186 +0.022834999999986394 +0.02279499999986001 +0.022865000000138025 +0.023149999999986903 +0.023050000000012005 +0.023149999999986903 +0.04655499999989843 +0.023169999999936408 +0.02345000000013897 +0.02341599999999744 +0.023580000000038126 +0.023584999999911815 +0.023504999999886422 +0.023685000000114087 +0.023779999999987922 +0.023785000000088985 +0.023799999999937427 +0.023995000000013533 +0.02395499999988715 +0.02397500000006403 +0.024329999999963547 +0.024454999999989013 +0.023920000000089203 +0.04877499999997781 +0.024065999999947962 +0.0246150000000398 +0.024429999999938445 +0.024634999999989304 +0.024675000000115688 +0.024885000000040236 +0.024564999999938664 +0.0251100000000406 +0.024805000000014843 +0.02494000000001506 +0.025174999999990177 +0.02507500000001528 +0.02514999999993961 +0.025235000000066066 +0.025444999999990614 +0.02529499999991458 +0.02546600000005128 +0.02543500000001586 +0.02547499999991487 +0.025650000000041473 +0.025699999999915235 +0.025855000000092332 +0.025744999999915308 +0.02591500000016822 +0.025624999999990905 +0.02588999999989028 +0.025470000000041182 +0.02558499999986452 +0.024955000000090877 +0.02521500000011656 +0.02440999999998894 +0.024494999999888023 +0.02422599999999875 +0.02335999999991145 +0.02380500000003849 +0.02267000000006192 +0.0225350000000617 +0.02246500000001106 +0.04403499999989435 +0.02129000000013548 +0.021409999999832507 +0.0205550000000585 +0.020819999999957872 +0.020395000000007713 +0.0201799999999821 +0.020175000000108412 +0.019864999999981592 +0.019790000000057262 +0.019549999999981083 +0.01951599999983955 +0.01907500000015716 +0.019384999999829233 +0.019000000000005457 +0.01908000000003085 +0.0191899999999805 +0.018925000000081127 +0.019090000000005602 +0.019109999999955107 +0.019170000000030996 +0.01922500000000582 +0.019315000000005966 +0.019330000000081782 +0.019354999999904976 +0.019475000000056752 +0.019419999999854554 +0.01967500000000655 +0.019830000000183645 +0.019344999999930224 +0.01971000000003187 +0.019696000000067215 +0.019754999999804568 +0.01975500000003194 +0.019990000000007058 +0.019905000000107975 +0.01992999999993117 +0.0201799999999821 +0.020050000000082946 +0.020029999999906067 +0.020224999999982174 +0.02027500000008331 +0.02021500000000742 +0.020340000000032887 +0.020409999999856154 +0.020460000000184664 +0.02049499999998261 +0.02053000000000793 +0.02064499999983127 +0.020899999999983265 +0.02087600000004386 +0.020379999999931897 +0.020825000000058935 +0.020819999999957872 +0.020895000000109576 +0.021105000000034124 +0.021105000000034124 +0.020854999999983193 +0.021319999999832362 +0.021075000000109867 +0.021224999999958527 +0.021324999999933425 +0.02126500000008491 +0.021424999999908323 +0.021450000000186265 +0.021494999999958964 +0.02162499999985812 +0.021620000000211803 +0.02169999999978245 +0.02165000000013606 +0.021921000000020285 +0.022124999999959982 +0.02148499999998421 +0.02224500000011176 +0.022074999999858846 +0.02176000000008571 +0.022580000000061773 +0.021664999999984502 +0.022214999999960128 +0.022349999999960346 +0.022459999999909996 +0.022635000000036598 +0.02225500000008651 +0.022375000000010914 +0.022600000000011278 +0.02274499999998625 +0.02261499999985972 +0.02264500000001135 +0.022906000000148197 +0.022849999999834836 +0.02282500000001164 +0.023040000000037253 +0.023005000000011933 +0.02313500000013846 +0.02374999999983629 +0.022725000000036744 +0.023124999999936335 +0.023395000000164146 +0.02339999999981046 +0.023355000000037762 +0.023519999999962238 +0.04719000000000051 +0.023815000000013242 +0.04743100000018785 +0.024164999999811698 +0.04768000000012762 +0.024189999999862266 +0.02387500000008913 +0.02440999999998894 +0.024210000000039145 +0.04861000000005333 +0.024400000000014188 +0.024754999999913707 +0.024315000000115106 +0.04911499999980151 +0.04965600000014092 +0.024879999999939173 +0.024840000000040163 +0.024989999999888823 +0.02496000000019194 +0.025129999999990105 +0.02519999999981337 +0.025150000000166983 +0.025314999999864085 +0.0253299999999399 +0.025485000000116997 +0.02536499999996522 +0.025689999999940483 +0.025500000000192813 +0.025874999999814463 +0.025545000000192886 +0.025740999999925407 +0.025529999999889696 +0.025790000000142754 +0.05062499999985448 +0.025274999999965075 +0.024545000000216532 +0.024569999999812353 +0.024195000000190703 +0.023904999999786014 +0.023465000000214786 +0.023164999999835345 +0.02277500000013788 +0.02239499999996042 +0.02239499999996042 +0.021610999999893465 +0.021320000000059736 +0.021150000000034197 +0.0207749999999578 +0.02060000000005857 +0.020399999999881402 +0.02014000000008309 +0.01985500000000684 +0.020115000000032524 +0.0191899999999805 +0.019450000000006185 +0.019279999999980646 +0.01911999999992986 +0.018925000000081127 +0.0189700000000812 +0.018779999999878783 +0.01871500000015658 +0.0186949999999797 +0.018614999999954307 +0.018855000000030486 +0.018439999999827705 +0.018851000000040585 +0.018565000000080545 +0.018869999999878928 +0.018855000000030486 +0.01886000000013155 +0.019000000000005457 +0.018919999999980064 +0.019039999999904467 +0.01911500000005617 +0.019195000000081563 +0.01915499999995518 +0.01929500000005646 +0.01922500000000582 +0.01932499999998072 +0.019450000000006185 +0.019394999999803986 +0.019490000000132568 +0.01957100000004175 +0.01954899999986992 +0.019954999999981737 +0.019495000000006257 +0.019650000000183354 +0.019715999999789346 +0.019870000000082655 +0.01989000000003216 +0.01989000000003216 +0.0200600000000577 +0.01996999999983018 +0.02007000000003245 +0.020690000000058717 +0.019659999999930733 +0.020410000000083528 +0.02028999999993175 +0.02028999999993175 +0.02031499999998232 +0.020425000000159343 +0.0205550000000585 +0.020440000000007785 +0.02066999999988184 +0.021005999999943015 +0.02031499999998232 +0.020890000000008513 +0.02066500000000815 +0.020895000000109576 +0.020970000000033906 +0.02095499999995809 +0.021039999999857173 +0.021055000000160362 +0.02109999999993306 +0.021420000000034634 +0.021009999999932916 +0.0212699999999586 +0.021355000000085056 +0.021465000000034706 +0.021459999999933643 +0.021380000000135624 +0.02166999999985819 +0.021770000000060463 +0.021600000000034925 +0.022034999999959837 +0.021390999999994165 +0.02182500000003529 +0.02193499999998494 +0.021844999999984793 +0.022089999999934662 +0.022120000000086293 +0.022424999999884676 +0.021950000000060754 +0.022300000000086584 +0.022144999999909487 +0.02236500000003616 +0.022324999999909778 +0.022455000000036307 +0.022511000000122294 +0.02254399999992529 +0.02260999999998603 +0.02299999999991087 +0.02260599999999613 +0.02274000000011256 +0.02278999999998632 +0.023075000000062573 +0.022804999999834763 +0.02313500000013846 +0.04612999999994827 +0.023365000000012515 +0.023445000000037908 +0.023199999999860665 +0.02345000000013897 +0.023474999999962165 +0.023265000000037617 +0.02359000000001288 +0.02370999999993728 +0.023650000000088767 +0.047570999999834385 +0.04778000000010252 +0.024089999999887368 +0.024060000000190485 +0.024089999999887368 +0.024030000000038854 +0.024460000000090076 +0.024289999999837164 +0.02440999999998894 +0.02437000000008993 +0.024384999999938373 +0.04906600000003891 +0.0494499999999789 +0.024885000000040236 +0.0246150000000398 +0.025034999999888896 +0.024970000000166692 +0.02504999999996471 +0.025129999999990105 +0.025339999999914653 +0.024949999999989814 +0.025689999999940483 +0.025365000000192595 +0.024994999999989886 +0.05028999999990447 +0.04977499999995416 +0.024286000000074637 +0.04811500000005253 +0.023909999999887077 +0.023889999999937572 +0.02268000000003667 +0.04581000000007407 +0.022015000000010332 +0.04359499999986838 +0.02147000000013577 +0.021385000000009313 +0.021264999999857537 +0.02006500000015876 +0.02063999999995758 +0.020500000000083674 +0.039775999999847045 +0.01961000000005697 +0.020019999999931315 +0.018905000000131622 +0.019315000000005966 +0.01908499999990454 +0.019000000000005457 +0.018945000000030632 +0.019135000000005675 +0.018559999999979482 +0.03774999999995998 +0.019035000000030777 +0.019164999999929933 +0.01883500000008098 +0.019095000000106666 +0.01900999999998021 +0.019234999999980573 +0.01933999999982916 +0.019420000000081927 +0.019101000000091517 +0.01933499999995547 +0.01943499999993037 +0.01957500000003165 +0.019624999999905413 +0.019760000000133005 +0.019254999999930078 +0.039485000000013315 +0.01981500000010783 +0.019984999999905995 +0.019700000000057116 +0.0201799999999821 +0.019804999999905704 +0.020305000000007567 +0.01972000000000662 +0.020234999999956926 +0.02007000000003245 +0.020336000000042986 +0.020195000000057917 +0.02035000000000764 +0.020440000000007785 +0.020375000000058208 +0.020589999999856445 +0.020800000000008367 +0.040995000000066284 +0.021039999999857173 +0.02049000000010892 +0.020755000000008295 +0.020870000000059008 +0.02105499999993299 +0.021314999999958673 +0.02059499999995751 +0.021425000000135697 +0.020899999999983265 +0.021259999999983847 +0.02108999999995831 +0.021255000000110158 +0.021355999999968844 +0.02187499999990905 +0.021140000000059445 +0.02151000000003478 +0.043159999999943466 +0.02172500000006039 +0.02180499999985841 +0.02169000000003507 +0.02214500000013686 +0.02165500000000975 +0.02194999999983338 +0.021960000000035507 +0.022140000000035798 +0.022089999999934662 +0.0222599999999602 +0.02233000000001084 +0.02214100000014696 +0.022588999999925363 +0.022296000000096683 +0.022420000000010987 +0.0225799999998344 +0.022590000000036525 +0.022600000000011278 +0.022754999999961 +0.022664999999960855 +0.02292000000011285 +0.022860000000036962 +0.022954999999910797 +0.022940000000062355 +0.023189999999885913 +0.023014999999986685 +0.02313500000013846 +0.023320000000012442 +0.02331499999991138 +0.023325999999997293 +0.023574999999937063 +0.02327500000001237 +0.02352000000018961 +0.023815000000013242 +0.02335999999991145 +0.023740000000088912 +0.023854999999912252 +0.023754999999937354 +0.023889999999937572 +0.02391000000011445 +0.024239999999963402 +0.048054999999976644 +0.024470999999948617 +0.0485190000001694 +0.024144999999862193 +0.024456000000100175 +0.02458999999998923 +0.024625000000014552 +0.024400000000014188 +0.02494000000001506 +0.024549999999862848 +0.024835000000166474 +0.02529499999991458 +0.024560000000064974 +0.024959999999964566 +0.02518499999996493 +0.02504999999996471 +0.0253850000001421 +0.02507999999988897 +0.025446000000101776 +0.025274999999965075 +0.02557499999988977 +0.025734999999940555 +0.025185000000192304 +0.025394999999889478 +0.025419999999940046 +0.025015000000166765 +0.02503999999998996 +0.024649999999837746 +0.024570000000039727 +0.024284999999963475 +0.024105000000190557 +0.023549999999886495 +0.02349000000003798 +0.023009999999885622 +0.022631000000046697 +0.02236500000003616 +0.022204999999985375 +0.02152000000000953 +0.021295000000009168 +0.021079999999983556 +0.020835000000033688 +0.02053499999988162 +0.020320000000083382 +0.020119999999906213 +0.019965000000183863 +0.019874999999956344 +0.019379999999955544 +0.01946999999995569 +0.019144999999980428 +0.019099999999980355 +0.018975000000182263 +0.018824999999878855 +0.01869000000010601 +0.01876500000003034 +0.01856099999986327 +0.01865999999995438 +0.01883500000008098 +0.01848999999992884 +0.018720000000030268 +0.018794999999954598 +0.01886000000013155 +0.018859999999904176 +0.01897499999995489 +0.018955000000005384 +0.018964999999980137 +0.01926000000003114 +0.01907500000015716 +0.019094999999879292 +0.038569999999936044 +0.01939500000003136 +0.019630000000006476 +0.019125000000030923 +0.019510000000082073 +0.019464999999854626 +0.019576000000142812 +0.019599999999854845 +0.01974500000005719 +0.019639999999981228 +0.019765000000006694 +0.019895000000133223 +0.01983499999982996 +0.019895000000133223 +0.019954999999981737 +0.020015000000057626 +0.020099999999956708 +0.02017000000000735 +0.02045999999995729 +0.019935000000032232 +0.020645000000058644 +0.019909999999981665 +0.02046499999983098 +0.02038500000003296 +0.02045999999995729 +0.020580000000109067 +0.020610999999917112 +0.02062999999998283 +0.021090000000185682 +0.020404999999982465 +0.020929999999907523 +0.020615000000134387 +0.021014999999806605 +0.020870000000059008 +0.021030000000109794 +0.02113499999995838 +0.021084999999857246 +0.021165000000110012 +0.0212699999999586 +0.02130000000011023 +0.02134000000000924 +0.021369999999933498 +0.021359999999958745 +0.0215450000000601 +0.02161599999999453 +0.021590000000060172 +0.02159999999980755 +0.02213500000016211 +0.02143999999998414 +0.04369999999994434 +0.02200500000003558 +0.021849999999858483 +0.02207500000008622 +0.022155000000111613 +0.02215499999988424 +0.022275000000036016 +0.02222499999993488 +0.022400000000061482 +0.04487999999992098 +0.02232000000003609 +0.023159999999961656 +0.022236000000020795 +0.022550000000137516 +0.022784999999885258 +0.022764999999935753 +0.022865000000138025 +0.02281999999991058 +0.023010000000112996 +0.023005000000011933 +0.023134999999911088 +0.023124999999936335 +0.02313500000013846 +0.023320000000012442 +0.0233499999999367 +0.02331000000003769 +0.023439999999936845 +0.023500000000012733 +0.02351500000008855 +0.023700999999846317 +0.02363500000001295 +0.023675000000139335 +0.023854999999912252 +0.023895000000038635 +0.023834999999962747 +0.024040000000013606 +0.023959999999988213 +0.024090000000114742 +0.024289999999837164 +0.024135000000114815 +0.024324999999862484 +0.024329999999963547 +0.0246150000000398 +0.0242950000001656 +0.02458000000001448 +0.02448599999979706 +0.024655000000166183 +0.024819999999863285 +0.024695000000065193 +0.02514500000006592 +0.02472999999986314 +0.024920000000065556 +0.025165000000015425 +0.02500000000009095 +0.025094999999964784 +0.025200000000040745 +0.025144999999838547 +0.025284999999939828 +0.02478000000019165 +0.025139999999964857 +0.0245559999998477 +0.024735000000191576 +0.02420499999993808 +0.024214999999912834 +0.023834999999962747 +0.023705000000063592 +0.023230000000012296 +0.022940000000062355 +0.022725000000036744 +0.022424999999884676 +0.022050000000035652 +0.02183500000001004 +0.021490000000085274 +0.021244999999908032 +0.02101500000003398 +0.02080999999998312 +0.020399999999881402 +0.020541000000093845 +0.01992900000004738 +0.019876000000067506 +0.019594999999981155 +0.019524999999930515 +0.01929999999993015 +0.019230000000106884 +0.019029999999929714 +0.018990000000030705 +0.018849999999929423 +0.01882999999997992 +0.018604999999979555 +0.018845000000055734 +0.018610000000080618 +0.018810000000030414 +0.018859999999904176 +0.019230000000106884 +0.018614999999954307 +0.019144999999980428 +0.01882999999997992 +0.019164999999929933 +0.019065000000182408 +0.01916599999981372 +0.019240000000081636 +0.01971000000003187 +0.01897499999995489 +0.019315000000005966 +0.01968000000010761 +0.019284999999854335 +0.01946999999995569 +0.01957500000003165 +0.01963500000010754 +0.019974999999931242 +0.019669999999905485 +0.01961000000005697 +0.01992500000005748 +0.01971000000003187 +0.019884999999931097 +0.019954999999981737 +0.020120000000133587 +0.019984999999905995 +0.02017000000000735 +0.020191000000068016 +0.020295000000032815 +0.02018499999985579 +0.020430000000033033 +0.020344999999906577 +0.020620000000008076 +0.02034500000013395 +0.02067999999985659 +0.020435000000134096 +0.020755000000008295 +0.020690000000058717 +0.020719999999982974 +0.020835000000033688 +0.0207749999999578 +0.02112999999985732 +0.020895000000109576 +0.02098000000000866 +0.021070000000008804 +0.021189999999933207 +0.021179999999958454 +0.021271000000069762 +0.021254999999882784 +0.02133500000013555 +0.02136500000005981 +0.021569999999883294 +0.02161999999998443 +0.02152000000000953 +0.021565000000009604 +0.021680000000060318 +0.02172500000006039 +0.021824999999807915 +0.021865000000161672 +0.021904999999833308 +0.021935000000212312 +0.022004999999808206 +0.02218500000003587 +0.02211499999998523 +0.02213500000016211 +0.02222099999994498 +0.022310000000061336 +0.022399999999834108 +0.022339999999985594 +0.022545000000036453 +0.023024999999961437 +0.022095000000035725 +0.022940000000062355 +0.02242999999998574 +0.022699999999986176 +0.022979999999961365 +0.02275000000008731 +0.022954999999910797 +0.02306500000008782 +0.023075000000062573 +0.023304999999936626 +0.022989999999936117 +0.023255999999946653 +0.023294999999961874 +0.02337500000021464 +0.02331499999991138 +0.023484999999936917 +0.023720000000139407 +0.023449999999911597 +0.023644999999987704 +0.047634999999900174 +0.02369000000021515 +0.02404999999998836 +0.024224999999887586 +0.023680000000013024 +0.024065000000064174 +0.024224999999887586 +0.024014999999963038 +0.024346000000150525 +0.02458000000001448 +0.024214999999912834 +0.02437499999996362 +0.024429999999938445 +0.04934000000002925 +0.024845000000141226 +0.024999999999863576 +0.02472499999998945 +0.02448000000003958 +0.05018500000005588 +0.05013099999996484 +0.02532399999995505 +0.02517600000010134 +0.02540499999986423 +0.025520000000142318 +0.02496999999993932 +0.025084999999990032 +0.025090000000091095 +0.025065000000040527 +0.024494999999888023 +0.024284999999963475 +0.02430000000003929 +0.0238449999999375 +0.023605000000088694 +0.0231300000000374 +0.022735000000011496 +0.02253999999993539 +0.022085000000060973 +0.02172599999994418 +0.021500000000060027 +0.02112999999985732 +0.0207300000001851 +0.02063999999995758 +0.020359999999982392 +0.020064999999931388 +0.020189999999956854 +0.019414999999980864 +0.019485000000031505 +0.01933499999995547 +0.019165000000157306 +0.01943499999993037 +0.018385000000080254 +0.018744999999853462 +0.01886000000013155 +0.018264999999928477 +0.01858500000003005 +0.018409999999903448 +0.01847600000019156 +0.01845399999979236 +0.01851600000009057 +0.018534999999928914 +0.018535000000156288 +0.01865999999995438 +0.018749999999954525 +0.018704999999954453 +0.018950000000131695 +0.01873499999987871 +0.018945000000030632 +0.018784999999979846 +0.019095000000106666 +0.018959999999879074 +0.019095000000106666 +0.019174999999904685 +0.0192899999999554 +0.019070000000056098 +0.019590000000107466 +0.01904500000000553 +0.0194099999998798 +0.019565000000056898 +0.01939500000003136 +0.019420999999965716 +0.019604999999955908 +0.01961499999993066 +0.01964500000008229 +0.019765000000006694 +0.01975999999990563 +0.019945000000006985 +0.01977500000020882 +0.01996999999983018 +0.02021500000000742 +0.019805000000133077 +0.020139999999855718 +0.020015000000057626 +0.02024499999993168 +0.02016500000013366 +0.02024499999993168 +0.02042499999993197 +0.02035000000000764 +0.020410000000083528 +0.020584999999982756 +0.020500999999967462 +0.020559999999932188 +0.020635000000083892 +0.02073999999993248 +0.020715000000109285 +0.020860000000084256 +0.020844999999781066 +0.021115000000008877 +0.02090500000008433 +0.02088000000003376 +0.021105000000034124 +0.021189999999933207 +0.02112000000010994 +0.021229999999832216 +0.02129000000013548 +0.021345999999994092 +0.02147899999999936 +0.021459999999933643 +0.022165999999970154 +0.020964999999932843 +0.021530000000211658 +0.02159499999993386 +0.021754999999984648 +0.021999999999934516 +0.02165500000000975 +0.021915000000035434 +0.021989999999959764 +0.021920000000136497 +0.0220849999998336 +0.022190000000136934 +0.022144999999909487 +0.02218500000003587 +0.022339999999985594 +0.02239000000008673 +0.022379999999884603 +0.02243999999996049 +0.02257099999997081 +0.022505000000137443 +0.02264500000001135 +0.02271999999993568 +0.022774999999910506 +0.0228100000001632 +0.02275999999983469 +0.023040000000037253 +0.023014999999986685 +0.022965000000112923 +0.023054999999885695 +0.023205000000189102 +0.023224999999911233 +0.02317500000003747 +0.023445000000037908 +0.02349499999991167 +0.02331600000002254 +0.02356499999996231 +0.02349499999991167 +0.023644999999987704 +0.02366000000006352 +0.023750000000063665 +0.023830000000089058 +0.02381999999988693 +0.02397500000006403 +0.024019999999836728 +0.024035000000139917 +0.024089999999887368 +0.024160000000165383 +0.02426999999988766 +0.024319999999988795 +0.024355000000014115 +0.024356000000125277 +0.02445399999987785 +0.024566000000049826 +0.02462999999988824 +0.024655000000166183 +0.024625000000014552 +0.02486999999996442 +0.024774999999863212 +0.024949999999989814 +0.024985000000015134 +0.025025000000141517 +0.02511499999991429 +0.02500000000009095 +0.02494000000001506 +0.024959999999964566 +0.024674999999888314 +0.024595000000090295 +0.024355999999897904 +0.024274999999988722 +0.023855000000139626 +0.02378499999986161 +0.023365000000012515 +0.022969999999986612 +0.022830000000112705 +0.022494999999935317 +0.02221000000008644 +0.021745000000009895 +0.021614999999883366 +0.021115000000008877 +0.02106000000003405 +0.02070499999990716 +0.020500000000083674 +0.020305000000007567 +0.020080000000007203 +0.019874999999956344 +0.019616000000041822 +0.019510000000082073 +0.019384999999829233 +0.019125000000030923 +0.019144999999980428 +0.01889500000015687 +0.01873000000000502 +0.018834999999853608 +0.018739999999979773 +0.018625000000156433 +0.018739999999979773 +0.01880000000005566 +0.018544999999903666 +0.018814999999904103 +0.01879500000018197 +0.01890499999990425 +0.019019999999954962 +0.018919999999980064 +0.018995000000131768 +0.01915999999982887 +0.019095000000106666 +0.019215999999914857 +0.01921500000003107 +0.019275000000106957 +0.0192899999999554 +0.019405000000006112 +0.01943000000005668 +0.01947499999982938 +0.019655000000057044 +0.01950000000010732 +0.01964999999995598 +0.019679999999880238 +0.019795000000158325 +0.0196849999999813 +0.019874999999956344 +0.019845000000032087 +0.019919999999956417 +0.02007499999990614 +0.019996000000219283 +0.020053999999845473 +0.020185000000083164 +0.020189999999956854 +0.020365999999967244 +0.020199999999931606 +0.020320000000083382 +0.02042000000005828 +0.020444999999881475 +0.020460000000184664 +0.020559999999932188 +0.020659999999907086 +0.0206749999999829 +0.020680000000083965 +0.020964999999932843 +0.02069500000015978 +0.02092499999980646 +0.02090500000008433 +0.02095499999995809 +0.02105600000004415 +0.021109000000024025 +0.021179999999958454 +0.02108100000009472 +0.021444999999857828 +0.02126500000008491 +0.021275000000059663 +0.02141499999993357 +0.021504999999933716 +0.02143500000011045 +0.021859999999833235 +0.021515000000135842 +0.021844999999984793 +0.021529999999984284 +0.022095000000035725 +0.02158000000008542 +0.02194499999995969 +0.022134999999934735 +0.021790000000009968 +0.022204999999985375 +0.02205499999990934 +0.022760000000062064 +0.021956000000045606 +0.04443500000002132 +0.022619999999960783 +0.022625000000061846 +0.022379999999884603 +0.022510000000011132 +0.022685000000137734 +0.022674999999935608 +0.02289999999993597 +0.022674999999935608 +0.022875000000112777 +0.023014999999986685 +0.023014999999986685 +0.023089999999911015 +0.02323500000011336 +0.023089999999911015 +0.023149999999986903 +0.023406000000022686 +0.023370000000113578 +0.023355000000037762 +0.023479999999835854 +0.02349000000003798 +0.02366499999993721 +0.023710000000164655 +0.024019999999836728 +0.02359999999998763 +0.023760000000038417 +0.023824999999987995 +0.02404500000011467 +0.023905000000013388 +0.024200000000064392 +0.023964999999861902 +0.024525000000039654 +0.024071000000049025 +0.024349999999913052 +0.02437000000008993 +0.024355000000014115 +0.024609999999938736 +0.024535000000014406 +0.024750000000040018 +0.024609999999938736 +0.024814999999989595 +0.02490499999998974 +0.024744999999938955 +0.025010000000065702 +0.02501499999993939 +0.024959999999964566 +0.0252850000001672 +0.025165000000015425 +0.025515999999925043 +0.025139999999964857 +0.025300000000015643 +0.025395000000116852 +0.025394999999889478 +0.024959999999964566 +0.025094999999964784 +0.024390000000039436 +0.025020000000040454 +0.023920000000089203 +0.024154999999836946 +0.023820000000114305 +0.023609999999962383 +0.023320000000012442 +0.023014999999986685 +0.022709999999960928 +0.022501000000147542 +0.04399499999999534 +0.0428599999997914 +0.021110000000135187 +0.020794999999907304 +0.02053000000000793 +0.020295000000032815 +0.020279999999957 +0.019840000000158398 +0.019914999999855354 +0.01950499999998101 +0.019290000000182772 +0.01919499999985419 +0.019199999999955253 +0.018960000000106447 +0.018929999999954816 +0.01887499999997999 +0.018770000000131404 +0.018715999999812993 +0.018845000000055734 +0.019090000000005602 +0.018614999999954307 +0.037900000000036016 +0.01890000000003056 +0.01928500000008171 +0.018889999999828433 +0.01928000000020802 +0.019329999999854408 +0.019050000000106593 +0.019440000000031432 +0.019254999999930078 +0.019385000000056607 +0.01948499999980413 +0.019445000000132495 +0.019559999999955835 +0.01957100000004175 +0.019714999999905558 +0.01967000000013286 +0.019765000000006694 +0.019864999999981592 +0.0398450000000139 +0.02007000000003245 +0.01981999999998152 +0.019994999999880747 +0.02010500000005777 +0.02021500000000742 +0.020154999999931533 +0.020335000000159198 +0.020369999999957145 +0.020309999999881256 +0.020435000000134096 +0.020474999999805732 +0.020390000000134023 +0.020720999999866763 +0.02059400000007372 +0.020651000000043496 +0.02136500000005981 +0.020305000000007567 +0.02070499999990716 +0.02136500000005981 +0.020729999999957727 +0.020755000000008295 +0.02123000000005959 +0.02095499999995809 +0.021115000000008877 +0.021240000000034343 +0.021264999999857537 +0.021664999999984502 +0.021285000000034415 +0.02137000000016087 +0.02162499999985812 +0.021246000000019194 +0.02168400000005022 +0.021590000000060172 +0.02184599999986858 +0.021660000000110813 +0.02176999999983309 +0.02200000000016189 +0.021849999999858483 +0.02200000000016189 +0.022144999999909487 +0.02200999999990927 +0.022140000000035798 +0.02235500000006141 +0.022275000000036016 +0.02232000000003609 +0.022314999999935026 +0.02246500000001106 +0.02278999999998632 +0.02228500000001077 +0.022615000000087093 +0.02264599999989514 +0.02292499999998654 +0.02281500000003689 +0.022694999999885113 +0.02310499999998683 +0.02281500000003689 +0.02296000000001186 +0.02323500000011336 +0.023050000000012005 +0.023079999999936263 +0.023539999999911743 +0.09350500000005013 +0.023545000000012806 +0.023754999999937354 +0.023706000000174754 +0.02360899999985122 +0.024241000000074564 +0.023425000000088403 +0.02399499999978616 +0.024635000000216678 +0.023299999999835563 +0.024415000000090004 +0.04826499999990119 +0.024705000000039945 +0.023830000000089058 +0.024625000000014552 +0.024439999999913198 +0.02448000000003958 +0.04930999999987762 +0.02492100000017672 +0.024499999999989086 +0.024789999999939027 +0.02514500000006592 +0.02489500000001499 +0.024914999999964493 +0.025174999999990177 +0.02571499999999105 +0.024564999999938664 +0.050905000000057044 +0.025200000000040745 +0.025769999999965876 +0.025249999999914507 +0.02546000000006643 +0.025296000000025742 +0.02539000000001579 +0.02473999999983789 +0.025100000000065847 +0.024609999999938736 +0.024235000000089713 +0.024044999999887295 +0.023650000000088767 +0.02338499999996202 +0.023024999999961437 +0.022590000000036525 +0.022235000000137006 +0.022089999999934662 +0.02151000000003478 +0.021314999999958673 +0.020929999999907523 +0.020711000000119384 +0.020469000000048254 +0.020340999999916676 +0.02007000000003245 +0.019735000000082437 +0.020174999999881038 +0.01893999999992957 +0.03845000000001164 +0.018919999999980064 +0.01886500000000524 +0.0187500000001819 +0.018859999999904176 +0.018225000000029468 +0.018505000000004657 +0.018665000000055443 +0.01809499999990294 +0.018389999999953943 +0.018389999999953943 +0.01840000000015607 +0.018469999999979336 +0.018510999999989508 +0.01859999999987849 +0.01869400000009591 +0.01866599999993923 +0.01882999999997992 +0.018940000000156942 +0.018619999999827996 +0.01886000000013155 +0.01891000000000531 +0.01900999999998021 +0.01897499999995489 +0.019095000000106666 +0.019144999999980428 +0.019125000000030923 +0.019294999999829088 +0.0192450000001827 +0.019599999999854845 +0.01917500000013206 +0.01943499999993037 +0.019354999999904976 +0.01954000000000633 +0.019576000000142812 +0.019603999999844746 +0.019706000000041968 +0.019725000000107684 +0.01972499999988031 +0.019880000000057407 +0.02014499999995678 +0.03963500000008935 +0.020094999999855645 +0.0199600000000828 +0.020195000000057917 +0.02020500000003267 +0.020279999999957 +0.02024000000005799 +0.02028999999993175 +0.02036499999985608 +0.02058500000021013 +0.020519999999805805 +0.020400000000108776 +0.02062999999998283 +0.02077000000008411 +0.02049099999999271 +0.0207749999999578 +0.02102500000000873 +0.02066500000000815 +0.021044999999958236 +0.020864999999957945 +0.02115500000013526 +0.021044999999958236 +0.021279999999933352 +0.02112499999998363 +0.021285000000034415 +0.02106499999990774 +0.0213250000001608 +0.02148499999998421 +0.021444999999857828 +0.021450000000186265 +0.021629999999959182 +0.021585999999842898 +0.021605000000135988 +0.021829999999908978 +0.04369999999994434 +0.021900000000186992 +0.02207999999995991 +0.02197499999988395 +0.021925000000010186 +0.022100000000136788 +0.022389999999859356 +0.02207999999995991 +0.022225000000162254 +0.022624999999834472 +0.022295000000212895 +0.022304999999960273 +0.022594999999910215 +0.02260100000012244 +0.02254399999992529 +0.02267600000004677 +0.022944999999936044 +0.022725000000036744 +0.02274499999998625 +0.022989999999936117 +0.023024999999961437 +0.023035000000163564 +0.023174999999810098 +0.023149999999986903 +0.023075000000062573 +0.023370000000113578 +0.023429999999962092 +0.02331000000003769 +0.023549999999886495 +0.023429999999962092 +0.023685000000114087 +0.04741599999988466 +0.023665000000164582 +0.04761999999982436 +0.02398000000016509 +0.02423499999986234 +0.023860000000013315 +0.02426500000001397 +0.02405500000008942 +0.02444500000001426 +0.024184999999988577 +0.02430499999991298 +0.024609999999938736 +0.024319999999988795 +0.04916100000014012 +0.04947999999990316 +0.049775000000181535 +0.025064999999813153 +0.02489500000001499 +0.025094999999964784 +0.05029500000000553 +0.025170000000116488 +0.024670000000014625 +0.024734999999964202 +0.024644999999964057 +0.024585000000115542 +0.04833099999996193 +0.023850000000038563 +0.023609999999962383 +0.023169999999936408 +0.022969999999986612 +0.022709999999960928 +0.022420000000010987 +0.022015000000010332 +0.021709999999984575 +0.021455000000059954 +0.021214999999983775 +0.020925000000033833 +0.02073500000005879 +0.020409999999856154 +0.020300000000133878 +0.020164999999906286 +0.019625000000132786 +0.019754999999804568 +0.019315000000005966 +0.019336000000066633 +0.019160000000056243 +0.01898499999992964 +0.01891000000000531 +0.018794999999954598 +0.0186949999999797 +0.018780000000106156 +0.01845499999990352 +0.0184750000000804 +0.01852499999995416 +0.018610000000080618 +0.01852499999995416 +0.018724999999903957 +0.018665000000055443 +0.018710000000055516 +0.018929999999954816 +0.018794999999954598 +0.01891000000000531 +0.019050000000106593 +0.01894999999990432 +0.019030000000157088 +0.019131000000015774 +0.019129999999904612 +0.019170000000030996 +0.019319999999879656 +0.019275000000106957 +0.019270000000005894 +0.01954499999988002 +0.019410000000107175 +0.019454999999879874 +0.01968000000010761 +0.019475000000056752 +0.019594999999981155 +0.01975500000003194 +0.019704999999930806 +0.019790000000057262 +0.019874999999956344 +0.019884999999931097 +0.01992500000005748 +0.02009500000008302 +0.019994999999880747 +0.020076000000017302 +0.020185000000083164 +0.0201799999999821 +0.020264999999881184 +0.020340000000032887 +0.020355000000108703 +0.02038500000003296 +0.0204999999998563 +0.02052000000003318 +0.020620000000008076 +0.020610000000033324 +0.020645000000058644 +0.0206749999999829 +0.020859999999856882 +0.0207749999999578 +0.020925000000033833 +0.02097500000013497 +0.021004999999831853 +0.021055000000160362 +0.02113499999995838 +0.021154999999907886 +0.021085999999968408 +0.021385000000009313 +0.021305000000211294 +0.021339999999781867 +0.021515000000135842 +0.021954999999934444 +0.021150000000034197 +0.021809999999959473 +0.021385000000009313 +0.021684999999934007 +0.021740000000136206 +0.02183500000001004 +0.021919999999909123 +0.021925000000010186 +0.021985000000086075 +0.021950000000060754 +0.022199999999884312 +0.02250499999991007 +0.02179100000012113 +0.02239499999996042 +0.022200000000111686 +0.02236999999990985 +0.02253999999993539 +0.022600000000011278 +0.022525000000086948 +0.02251499999988482 +0.022660000000087166 +0.022770000000036816 +0.02285000000006221 +0.02274499999998625 +0.022954999999910797 +0.02299999999991087 +0.022985000000062428 +0.023081000000047425 +0.023228999999901134 +0.023141000000123313 +0.023339999999961947 +0.023320000000012442 +0.02331000000003769 +0.023504999999886422 +0.023545000000012806 +0.02366000000006352 +0.023519999999962238 +0.02363500000001295 +0.023799999999937427 +0.023775000000114233 +0.02395499999988715 +0.023860000000013315 +0.02419000000008964 +0.023995000000013533 +0.024075000000038926 +0.02409099999999853 +0.02427999999986241 +0.02426000000014028 +0.02441499999986263 +0.02443500000003951 +0.024419999999963693 +0.02458000000001448 +0.024605000000065047 +0.024814999999989595 +0.0246150000000398 +0.02490499999998974 +0.02476499999988846 +0.02497500000004038 +0.02501499999993939 +0.025125000000116415 +0.025319999999965148 +0.02508100000000013 +0.025024999999914144 +0.025210000000015498 +0.02521999999999025 +0.024850000000014916 +0.02483000000006541 +0.025020000000040454 +0.024314999999887732 +0.02436000000011518 +0.02409499999998843 +0.024104999999963184 +0.023449999999911597 +0.023255000000062864 +0.023149999999986903 +0.022560000000112268 +0.022584999999935462 +0.021989999999959764 +0.021960999999919295 +0.021485000000211585 +0.02113999999983207 +0.021005000000059226 +0.020829999999932625 +0.020535000000108994 +0.020489999999881547 +0.01992000000018379 +0.019849999999905776 +0.019700000000057116 +0.0195099999998547 +0.019279999999980646 +0.019195000000081563 +0.019095000000106666 +0.018919999999980064 +0.018779999999878783 +0.018770000000131404 +0.018715999999812993 +0.018504000000120868 +0.018689999999878637 +0.018600000000105865 +0.0185910000000149 +0.018820000000005166 +0.01865500000008069 +0.018759999999929278 +0.018855000000030486 +0.01886500000000524 +0.019029999999929714 +0.01900500000010652 +0.01900999999998021 +0.019090000000005602 +0.019209999999930005 +0.019184999999879437 +0.019165000000157306 +0.038710000000037326 +0.01929999999993015 +0.01975999999990563 +0.019195000000081563 +0.01954499999988002 +0.0392460000000483 +0.019930000000158543 +0.019424999999955617 +0.019864999999981592 +0.019765000000006694 +0.019919999999956417 +0.019950000000108048 +0.01996999999983018 +0.020430000000033033 +0.01972000000000662 +0.020220000000108485 +0.04037999999991371 +0.020365000000083455 +0.020684999999957654 +0.020199999999931606 +0.040829999999914435 +0.020720000000210348 +0.020654999999806023 +0.020506000000068525 +0.020899999999983265 +0.02062500000010914 +0.020894999999882202 +0.020750000000134605 +0.02098999999998341 +0.02095999999983178 +0.021105000000034124 +0.021044999999958236 +0.021405000000186192 +0.021079999999983556 +0.02123499999993328 +0.02130000000011023 +0.021394999999984066 +0.021409999999832507 +0.021480000000110522 +0.021534999999857973 +0.04329500000017106 +0.021720999999843116 +0.021630000000186556 +0.0219849999998587 +0.0217649999999594 +0.021915000000035434 +0.022055000000136715 +0.02194499999995969 +0.02236999999990985 +0.02214500000013686 +0.02204499999993459 +0.022130000000061045 +0.022474999999985812 +0.022519999999985885 +0.04485999999997148 +0.022510000000011132 +0.02267600000004677 +0.022510000000011132 +0.022764999999935753 +0.022774999999910506 +0.022900000000163345 +0.02304999999978463 +0.022900000000163345 +0.023050000000012005 +0.02296499999988555 +0.023149999999986903 +0.02327500000001237 +0.02323999999998705 +0.023265000000037617 +0.023470000000088476 +0.02335999999991145 +0.023480000000063228 +0.02366600000004837 +0.02370999999993728 +0.023584999999911815 +0.023675000000139335 +0.023860000000013315 +0.02381999999988693 +0.023895000000038635 +0.024294999999938227 +0.023689999999987776 +0.02426000000014028 +0.024119999999811625 +0.02413000000001375 +0.02444000000014057 +0.024224999999887586 +0.02443500000003951 +0.024485000000140644 +0.024604999999837673 +0.024464999999963766 +0.024761000000125932 +0.02466499999991356 +0.02472499999998945 +0.04990999999995438 +0.025025000000141517 +0.02529499999991458 +0.024885000000040236 +0.025030000000015207 +0.02528000000006614 +0.05058499999995547 +0.05103000000008251 +0.02568499999983942 +0.025419999999940046 +0.02591100000017832 +0.025324999999838838 +0.025560000000041327 +0.025345000000015716 +0.025055000000065775 +0.0251100000000406 +0.02466499999991356 +0.024769999999989523 +0.024000000000114596 +0.024184999999988577 +0.02342499999986103 +0.023400000000037835 +0.022895000000062282 +0.022709999999960928 +0.022414999999909924 +0.022050000000035652 +0.021770000000060463 +0.02159099999994396 +0.02144999999995889 +0.021020000000135042 +0.0207749999999578 +0.02049000000010892 +0.020299999999906504 +0.020199999999931606 +0.01992500000005748 +0.01972000000000662 +0.020115000000032524 +0.019074999999929787 +0.019459999999980937 +0.019120000000157233 +0.018924999999853753 +0.018894999999929496 +0.018975000000182263 +0.018834999999853608 +0.018784999999979846 +0.018975000000182263 +0.01911599999993996 +0.018665000000055443 +0.01898999999980333 +0.0189700000000812 +0.019050000000106593 +0.01926000000003114 +0.019039999999904467 +0.01926000000003114 +0.019559999999955835 +0.019135000000005675 +0.019254999999930078 +0.019620000000031723 +0.01929999999993015 +0.01953500000013264 +0.019559999999955835 +0.01964999999995598 +0.019729999999981374 +0.019729999999981374 +0.01967000000013286 +0.020029999999906067 +0.020044999999981883 +0.019626000000016575 +0.0199600000000828 +0.019919999999956417 +0.020305000000007567 +0.01999500000010812 +0.020339999999805514 +0.020175000000108412 +0.02017000000000735 +0.020504999999957363 +0.020279999999957 +0.020335000000159198 +0.020504999999957363 +0.020575000000008004 +0.020649999999932334 +0.02059499999995751 +0.0206749999999829 +0.020725000000084037 +0.020825000000058935 +0.020870999999942796 +0.020874999999932697 +0.02097500000013497 +0.02109999999993306 +0.020964999999932843 +0.021240000000034343 +0.021205000000009022 +0.02112000000010994 +0.021404999999958818 +0.02130499999998392 +0.02130999999985761 +0.021585000000186483 +0.02141999999980726 +0.02152000000000953 +0.021664999999984502 +0.021845000000212167 +0.02152499999988322 +0.021919999999909123 +0.02172100000007049 +0.021983999999974912 +0.08815100000015264 +0.022274999999808642 +0.044520000000147775 +0.02226499999983389 +0.022415000000137297 +0.04500000000007276 +0.02253999999993539 +0.022674999999935608 +0.022584999999935462 +0.02267000000006192 +0.022875999999996566 +0.02287900000010268 +0.045950999999831765 +0.046105000000125074 +0.023519999999962238 +0.022930000000087603 +0.023224999999911233 +0.023329999999987194 +0.02338499999996202 +0.02338499999996202 +0.02369000000021515 +0.02345999999988635 +0.023754999999937354 +0.023644999999987704 +0.023725000000013097 +0.023685000000114087 +0.024045999999998457 +0.023940000000038708 +0.023944999999912397 +0.04828500000007807 +0.024104999999963184 +0.024419999999963693 +0.024910000000090804 +0.023559999999861247 +0.024450000000115324 +0.02454499999998916 +0.024709999999913634 +0.024495000000115397 +0.024715000000014697 +0.024609999999938736 +0.024844999999913853 +0.024906000000100903 +0.024750000000040018 +0.025319999999965148 +0.024784999999837964 +0.025500000000192813 +0.024999999999863576 +0.025274999999965075 +0.025174999999990177 +0.02536000000009153 +0.025450000000091677 +0.025494999999864376 +0.050629999999955544 +0.025260000000116634 +0.05009999999992942 +0.025036000000000058 +0.023990000000139844 +0.024139999999988504 +0.02374999999983629 +0.023554999999987558 +0.023225000000138607 +0.02296499999988555 +0.022754999999961 +0.02233000000001084 +0.022010000000136642 +0.021939999999858628 +0.021380000000135624 +0.02169499999990876 +0.02052000000003318 +0.041245000000117216 +0.020350999999891428 +0.019984000000022206 +0.01985999999988053 +0.019696000000067215 +0.020234999999956926 +0.018630000000030122 +0.01950499999998101 +0.018855000000030486 +0.018929999999954816 +0.018925000000081127 +0.018814999999904103 +0.018855000000030486 +0.01882500000010623 +0.018784999999979846 +0.018929999999954816 +0.0191899999999805 +0.018739999999979773 +0.01904500000000553 +0.01904000000013184 +0.019054999999980282 +0.019109999999955107 +0.019254999999930078 +0.019365000000107102 +0.019266000000015993 +0.019414999999980864 +0.01946999999995569 +0.01929500000005646 +0.019994999999880747 +0.019275000000106957 +0.019495000000006257 +0.01972000000000662 +0.01961499999993066 +0.019765000000006694 +0.019835000000057335 +0.01986999999985528 +0.019895000000133223 +0.020080000000007203 +0.019880000000057407 +0.020024999999805004 +0.020115000000032524 +0.02016500000013366 +0.020279999999957 +0.02024600000004284 +0.020379999999931897 +0.020285000000058062 +0.020430000000033033 +0.020874999999932697 +0.02010999999993146 +0.04124000000001615 +0.02070000000003347 +0.020694999999932406 +0.020760000000109358 +0.020870000000059008 +0.020979999999781285 +0.02091500000005908 +0.02106000000003405 +0.021030000000109794 +0.02109999999993306 +0.02112499999998363 +0.021244999999908032 +0.02126500000008491 +0.021351000000095155 +0.021579999999858046 +0.021664999999984502 +0.021140000000059445 +0.02158000000008542 +0.021565000000009604 +0.021679999999832944 +0.021765000000186774 +0.02173499999980777 +0.021850000000085856 +0.021915000000035434 +0.02193499999998494 +0.021995000000060827 +0.02233000000001084 +0.021925000000010186 +0.02204499999993459 +0.022384999999985666 +0.022275000000036016 +0.022250999999869236 +0.02264500000001135 +0.022310000000061336 +0.02243999999996049 +0.022629999999935535 +0.022660000000087166 +0.022930000000087603 +0.022494999999935317 +0.02292499999998654 +0.02281999999991058 +0.022969999999986612 +0.023075000000062573 +0.022840000000087457 +0.02323999999998705 +0.023189999999885913 +0.023050000000012005 +0.02338000000008833 +0.023400999999921623 +0.023245000000088112 +0.0236250000000382 +0.023449999999911597 +0.023685000000114087 +0.023680000000013024 +0.023649999999861393 +0.023750000000063665 +0.02378499999986161 +0.023920000000089203 +0.02398500000003878 +0.024069999999937863 +0.024125000000140062 +0.0240649999998368 +0.02433500000006461 +0.02404500000011467 +0.024465999999847554 +0.024319999999988795 +0.02436000000011518 +0.0245599999998376 +0.024730000000090513 +0.024605000000065047 +0.02455499999996391 +0.02496999999993932 +0.025059999999939464 +0.024555000000191285 +0.0250549999998384 +0.02500000000009095 +0.025135000000091168 +0.025854999999864958 +0.024319999999988795 +0.025340000000142027 +0.025309999999990396 +0.025370999999950072 +0.025335000000040964 +0.025529999999889696 +0.025419999999940046 +0.025264999999990323 +0.025560000000041327 +0.02493000000004031 +0.025020000000040454 +0.024719999999888387 +0.024560000000064974 +0.024390000000039436 +0.02412499999991269 +0.02380500000003849 +0.02356499999996231 +0.023155000000087966 +0.04539099999988139 +0.02225500000008651 +0.021790000000009968 +0.021915000000035434 +0.021119999999882566 +0.021065000000135115 +0.02066500000000815 +0.02056500000003325 +0.020260000000007494 +0.02011499999980515 +0.019915000000082728 +0.01974500000005719 +0.01936499999987973 +0.019375000000081855 +0.019184999999879437 +0.019205000000056316 +0.018794999999954598 +0.01873000000000502 +0.018649999999979627 +0.01875500000005559 +0.018614999999954307 +0.018621000000166532 +0.018704999999954453 +0.018739999999979773 +0.018720000000030268 +0.018855000000030486 +0.018824999999878855 +0.01893500000005588 +0.019029999999929714 +0.018985000000157015 +0.019125000000030923 +0.019114999999828797 +0.01915000000008149 +0.019160000000056243 +0.01936499999987973 +0.019375000000081855 +0.019239999999854263 +0.01946000000020831 +0.019379999999955544 +0.019479999999930442 +0.01964999999995598 +0.019521000000167987 +0.019644999999854917 +0.01981500000010783 +0.01967500000000655 +0.019849999999905776 +0.019849999999905776 +0.019970000000057553 +0.019919999999956417 +0.02003500000000713 +0.020044999999981883 +0.020075000000133514 +0.02021999999988111 +0.020365000000083455 +0.02014000000008309 +0.02036499999985608 +0.020355000000108703 +0.020504999999957363 +0.020440000000007785 +0.02049099999999271 +0.020549999999957436 +0.020725000000084037 +0.02070499999990716 +0.020670000000109212 +0.020829999999932625 +0.020815000000084183 +0.020899999999983265 +0.020939999999882275 +0.02098500000010972 +0.021119999999882566 +0.02116000000000895 +0.021145000000160508 +0.02123499999993328 +0.021349999999983993 +0.02123000000005959 +0.021359999999958745 +0.021610000000009677 +0.021359999999958745 +0.021569999999883294 +0.021711000000095737 +0.02154999999993379 +0.021695000000136133 +0.02179999999998472 +0.021864999999934298 +0.021840000000111104 +0.02197999999998501 +0.02197499999988395 +0.02200500000003558 +0.02224500000011176 +0.022234999999909633 +0.022064999999884094 +0.022295000000212895 +0.022414999999909924 +0.022265000000061264 +0.022494999999935317 +0.022510000000011132 +0.02257499999996071 +0.022650999999996202 +0.022760000000062064 +0.0225350000000617 +0.02290499999980966 +0.022795000000087384 +0.023044999999910942 +0.022895000000062282 +0.02299999999991087 +0.023005000000011933 +0.023245000000088112 +0.023185000000012224 +0.023224999999911233 +0.02341500000011365 +0.023470000000088476 +0.023344999999835636 +0.023575000000164437 +0.02339999999981046 +0.02355600000009872 +0.02377499999988686 +0.02369500000008884 +0.023740000000088912 +0.024074999999811553 +0.023785000000088985 +0.024014999999963038 +0.02397500000006403 +0.02415500000006432 +0.02408500000001368 +0.02427999999986241 +0.024255000000039217 +0.02444500000001426 +0.024359999999887805 +0.02448000000003958 +0.02447000000006483 +0.024855999999999767 +0.02462999999988824 +0.02444000000014057 +0.024789999999939027 +0.02500499999996464 +0.024734999999964202 +0.0251100000000406 +0.02494000000001506 +0.025170000000116488 +0.025099999999838474 +0.02535499999999047 +0.025135000000091168 +0.025415000000066357 +0.025409999999965294 +0.02536000000009153 +0.025654999999915162 +0.025560999999925116 +0.025599999999940337 +0.02598500000021886 +0.02550499999983913 +0.025779999999940628 +0.02556500000014239 +0.025419999999940046 +0.025190000000065993 +0.025104999999939537 +0.02465000000006512 +0.024670000000014625 +0.02419999999983702 +0.024290000000064538 +0.023370000000113578 +0.023304999999936626 +0.023054999999885695 +0.022721000000046843 +0.022400000000061482 +0.022234999999909633 +0.02185500000018692 +0.021689999999807696 +0.02148499999998421 +0.020995000000084474 +0.020899999999983265 +0.020725000000084037 +0.02038999999990665 +0.020265000000108557 +0.02007499999990614 +0.01981500000010783 +0.019779999999855136 +0.019639999999981228 +0.01932499999998072 +0.019435000000157743 +0.01911500000005617 +0.01911999999992986 +0.019166000000041095 +0.018889999999828433 +0.01891000000000531 +0.018995000000131768 +0.018884999999954744 +0.019029999999929714 +0.019130000000131986 +0.019094999999879292 +0.019240000000081636 +0.01921500000003107 +0.019284999999854335 +0.01932000000010703 +0.01943499999993037 +0.01943000000005668 +0.019495000000006257 +0.01946999999995569 +0.01957500000003165 +0.0196849999999813 +0.019690000000082364 +0.01972099999989041 +0.019764000000122905 +0.019800999999915803 +0.019984999999905995 +0.019875000000183718 +0.01996999999983018 +0.01999500000010812 +0.020084999999880893 +0.020175000000108412 +0.020430000000033033 +0.019994999999880747 +0.020505000000184737 +0.020139999999855718 +0.02031499999998232 +0.020539999999982683 +0.020485000000007858 +0.020449999999982538 +0.02066000000013446 +0.02063999999995758 +0.020760000000109358 +0.020709999999780848 +0.020810000000210493 +0.020885999999791238 +0.02094500000021071 +0.021109999999907814 +0.02091999999993277 +0.02108500000008462 +0.021500000000060027 +0.020724999999856664 +0.02151000000003478 +0.021109999999907814 +0.021355000000085056 +0.021459999999933643 +0.021455000000059954 +0.021504999999933716 +0.021600000000034925 +0.021635000000060245 +0.021719999999959327 +0.021735000000035143 +0.02193000000011125 +0.022060999999894193 +0.02158499999995911 +0.021999999999934516 +0.02200000000016189 +0.022134999999934735 +0.022085000000060973 +0.022169999999960055 +0.022895000000062282 +0.04416500000002088 +0.022510000000011132 +0.0223599999999351 +0.022584999999935462 +0.022505000000137443 +0.02268499999991036 +0.04571499999997286 +0.0230260000000726 +0.022494999999935317 +0.02299500000003718 +0.0229749999998603 +0.023050000000012005 +0.023295000000189248 +0.023114999999961583 +0.0231300000000374 +0.023344999999835636 +0.023445000000037908 +0.023339999999961947 +0.02355000000011387 +0.023469999999861102 +0.023565000000189684 +0.023789999999962674 +0.024079999999912616 +0.023329999999987194 +0.024135000000114815 +0.023580999999921914 +0.024079999999912616 +0.02401000000008935 +0.024114999999937936 +0.024415000000090004 +0.02409499999998843 +0.0243399999999383 +0.024090000000114742 +0.024464999999963766 +0.024504999999862775 +0.02483000000006541 +0.024175000000013824 +0.02465000000006512 +0.02466499999991356 +0.024846000000025015 +0.025124000000005253 +0.02465600000004997 +0.025300000000015643 +0.024750000000040018 +0.024949999999989814 +0.025249999999914507 +0.025210000000015498 +0.025274999999965075 +0.025419999999940046 +0.025485000000116997 +0.0253299999999399 +0.025595000000066648 +0.025564999999915017 +0.02570000000014261 +0.025834999999915453 +0.02589499999999134 +0.025666000000001077 +0.025939999999991414 +0.02546000000006643 +0.02550999999994019 +0.025450000000091677 +0.025314999999864085 +0.024935000000141372 +0.024954999999863503 +0.024535000000014406 +0.024274999999988722 +0.024040000000013606 +0.023815000000013242 +0.023220000000037544 +0.023009999999885622 +0.022720000000163054 +0.022399999999834108 +0.022376000000122076 +0.021664999999984502 +0.02152499999988322 +0.021280000000160726 +0.02106000000003405 +0.020759999999881984 +0.020549999999957436 +0.02038000000015927 +0.02029499999980544 +0.03985499999998865 +0.01939000000015767 +0.01964999999995598 +0.01939500000003136 +0.019305000000031214 +0.019274999999879583 +0.019240000000081636 +0.01926000000003114 +0.01933499999995547 +0.0192899999999554 +0.01929500000005646 +0.019526000000041677 +0.019585000000006403 +0.019350000000031287 +0.019639999999981228 +0.01982499999985521 +0.019559999999955835 +0.019665000000031796 +0.019845000000032087 +0.019739999999956126 +0.020190000000184227 +0.01982999999995627 +0.01979499999993095 +0.020044999999981883 +0.02007000000003245 +0.020080000000007203 +0.02024000000005799 +0.020399999999881402 +0.020224999999982174 +0.020291000000042914 +0.020369000000073356 +0.02043099999991682 +0.02052500000013424 +0.02109999999993306 +0.020029999999906067 +0.020755000000008295 +0.020575000000008004 +0.020780000000058862 +0.020909999999958018 +0.020784999999932552 +0.02102500000000873 +0.020944999999983338 +0.02101500000003398 +0.02106000000003405 +0.021200000000135333 +0.021144999999933134 +0.021214999999983775 +0.021314999999958673 +0.021394999999984066 +0.021545999999943888 +0.021455000000059954 +0.02143999999998414 +0.021525000000110595 +0.021664999999984502 +0.021719999999959327 +0.021704999999883512 +0.02182500000003529 +0.022325000000137152 +0.02147500000000946 +0.022039999999833526 +0.02193000000011125 +0.022064999999884094 +0.02218000000016218 +0.022124999999959982 +0.022379999999884603 +0.02225500000008651 +0.044750999999905616 +0.022550000000137516 +0.022474999999985812 +0.022559999999884894 +0.02267000000006192 +0.022735000000011496 +0.022725000000036744 +0.023095000000012078 +0.02264999999988504 +0.02314000000001215 +0.022940000000062355 +0.023089999999911015 +0.023010000000112996 +0.02320000000008804 +0.02321499999993648 +0.023369999999886204 +0.046790999999984706 +0.023410000000012587 +0.02359000000001288 +0.02359000000001288 +0.02358500000013919 +0.023824999999987995 +0.02377000000001317 +0.023874999999861757 +0.023930000000063956 +0.024014999999963038 +0.023854999999912252 +0.02428500000019085 +0.024154999999836946 +0.024210000000039145 +0.02419000000008964 +0.024324999999862484 +0.024516000000176064 +0.024474999999938518 +0.02448499999991327 +0.024605000000065047 +0.024824999999964348 +0.02448000000003958 +0.024885000000040236 +0.024840000000040163 +0.04979000000002998 +0.02540499999986423 +0.024859999999989668 +0.025395000000116852 +0.024934999999913998 +0.02539000000001579 +0.025264999999990323 +0.02547099999992497 +0.025454999999965366 +0.025615000000016153 +0.025624999999990905 +0.02564000000006672 +0.02574000000004162 +0.025799999999890133 +0.02584500000011758 +0.02596999999991567 +0.026105000000143264 +0.02600999999981468 +0.025730000000066866 +0.025835000000142827 +0.025529999999889696 +0.02554099999997561 +0.025254000000131782 +0.02494099999989885 +0.02468999999996413 +0.024595000000090295 +0.02391499999998814 +0.023864999999887004 +0.02338000000008833 +0.023124999999936335 +0.022635000000036598 +0.02250000000003638 +0.022089999999934662 +0.021605000000135988 +0.02159999999980755 +0.021480000000110522 +0.020584999999982756 +0.020694999999932406 +0.020359999999982392 +0.02016500000013366 +0.020019999999931315 +0.01978600000006736 +0.019779999999855136 +0.01925500000015745 +0.01922999999987951 +0.019030000000157088 +0.019029999999929714 +0.01891000000000531 +0.018700000000080763 +0.018784999999979846 +0.018714999999929205 +0.018610000000080618 +0.018799999999828287 +0.01879000000008091 +0.018990000000030705 +0.018685000000004948 +0.018779999999878783 +0.01890000000003056 +0.019019999999954962 +0.019025000000056025 +0.019125000000030923 +0.0194610000000921 +0.018944999999803258 +0.019435000000157743 +0.019319999999879656 +0.019170000000030996 +0.019265000000132204 +0.01965499999982967 +0.01967500000000655 +0.01917500000013206 +0.01954499999988002 +0.01961000000005697 +0.019639999999981228 +0.01981500000010783 +0.019810000000006767 +0.01983499999982996 +0.019864999999981592 +0.019935000000032232 +0.019990000000007058 +0.020091000000093118 +0.02003899999999703 +0.02010500000005777 +0.020335999999815613 +0.020250000000032742 +0.020189999999956854 +0.0204550000000836 +0.02052000000003318 +0.02031499999998232 +0.02052000000003318 +0.02056999999990694 +0.02063999999995758 +0.020670000000109212 +0.020694999999932406 +0.020705000000134532 +0.020925000000033833 +0.02109999999993306 +0.020655000000033397 +0.021115000000008877 +0.021034999999983484 +0.021070000000008804 +0.02112999999985732 +0.021210999999993874 +0.021430000000009386 +0.021185000000059517 +0.02130000000011023 +0.021430000000009386 +0.021544999999832726 +0.021550000000161162 +0.021529999999984284 +0.021719999999959327 +0.021574999999984357 +0.02200500000003558 +0.02166999999985819 +0.022105000000010477 +0.02161500000011074 +0.02205499999990934 +0.022055000000136715 +0.022204999999985375 +0.02208599999994476 +0.022034999999959837 +0.022410000000036234 +0.02236999999990985 +0.022349999999960346 +0.022375000000010914 +0.02257000000008702 +0.022515000000112195 +0.02257499999996071 +0.02260999999998603 +0.022664999999960855 +0.0228549999999359 +0.022834999999986394 +0.02295500000013817 +0.022884999999860156 +0.02306500000008782 +0.023005000000011933 +0.02310599999987062 +0.023284000000103333 +0.023220999999921332 +0.02341500000011365 +0.023265000000037617 +0.023464999999987413 +0.023484999999936917 +0.02351500000008855 +0.02359999999998763 +0.023654999999962456 +0.023905000000013388 +0.02359000000001288 +0.024089999999887368 +0.023760000000038417 +0.024000000000114596 +0.023949999999786087 +0.024140000000215878 +0.02416999999991276 +0.024116000000049098 +0.024429999999938445 +0.024245000000064465 +0.024474999999938518 +0.02444500000001426 +0.02450999999996384 +0.024605000000065047 +0.024649999999837746 +0.024725000000216824 +0.024734999999964202 +0.024949999999989814 +0.024824999999964348 +0.025564999999915017 +0.024425000000064756 +0.05050000000005639 +0.025090999999974883 +0.025309999999990396 +0.02536499999996522 +0.025374999999939973 +0.025595000000066648 +0.025374999999939973 +0.025769999999965876 +0.025730000000066866 +0.02570000000014261 +0.05177499999990687 +0.025415000000066357 +0.02602999999999156 +0.051060999999890555 +0.025368999999955122 +0.025306000000000495 +0.024644999999964057 +0.02485500000011598 +0.02458499999988817 +0.02401000000008935 +0.023779999999987922 +0.02352999999993699 +0.023020000000087748 +0.022844999999961146 +0.02246000000013737 +0.022174999999833744 +0.02179999999998472 +0.021590000000060172 +0.02123000000005959 +0.021070000000008804 +0.02071499999988191 +0.02048000000013417 +0.020305999999891355 +0.02010500000005777 +0.01982999999995627 +0.02013499999998203 +0.019195000000081563 +0.019315000000005966 +0.01929999999993015 +0.019070000000056098 +0.018994999999904394 +0.01900500000010652 +0.018855000000030486 +0.01880000000005566 +0.018849999999929423 +0.01876999999990403 +0.018870000000106302 +0.01883999999995467 +0.01891000000000531 +0.01904500000000553 +0.019004999999879146 +0.019021000000066124 +0.019130000000131986 +0.019319999999879656 +0.01943000000005668 +0.01911999999992986 +0.038675000000012005 +0.01935500000013235 +0.01968999999985499 +0.019344999999930224 +0.019480000000157816 +0.019800000000032014 +0.019549999999981083 +0.01971000000003187 +0.0197849999999562 +0.019810000000006767 +0.020194999999830543 +0.01975500000003194 +0.01986099999999169 +0.020009000000072774 +0.020119999999906213 +0.020106000000168933 +0.020154999999931533 +0.02028999999993175 +0.020820000000185246 +0.019804999999905704 +0.020575000000008004 +0.020305000000007567 +0.020469999999932043 +0.020570000000134314 +0.020589999999856445 +0.02069500000015978 +0.020689999999831343 +0.02073500000005879 +0.020925000000033833 +0.02074999999990723 +0.02106000000003405 +0.020795000000134678 +0.02105499999993299 +0.02123600000004444 +0.02120999999988271 +0.02112499999998363 +0.02165500000000975 +0.0206749999999829 +0.042844999999942956 +0.021450000000186265 +0.021569999999883294 +0.021515000000135842 +0.021529999999984284 +0.021689999999807696 +0.021840000000111104 +0.02205499999990934 +0.021605000000135988 +0.043895000000020445 +0.044065000000045984 +0.02243499999985943 +0.02183100000002014 +0.022310000000061336 +0.022095000000035725 +0.022674999999935608 +0.044744999999920765 +0.04517499999997199 +0.022445000000061555 +0.02292499999998654 +0.022930000000087603 +0.02292999999986023 +0.022490000000061627 +0.04592500000012478 +0.04606499999999869 +0.023270999999795094 +0.023105000000214204 +0.02331499999991138 +0.02335999999991145 +0.02341500000011365 +0.04695500000002539 +0.04725499999995009 +0.02373499999998785 +0.023760000000038417 +0.023815000000013242 +0.023815000000013242 +0.024154999999836946 +0.024015000000190412 +0.023779999999987922 +0.024369999999862557 +0.02409099999999853 +0.024245000000064465 +0.024325000000089858 +0.02430999999978667 +0.024620000000140863 +0.024364999999988868 +0.02468500000009044 +0.04935499999987769 +0.024564999999938664 +0.024875000000065484 +0.024850000000014916 +0.025010000000065702 +0.024985000000015134 +0.025280999999949927 +0.02490999999986343 +0.025230000000192376 +0.02525500000001557 +0.02571999999986474 +0.02518499999996493 +0.025505000000066502 +0.02529499999991458 +0.025690000000167856 +0.05155500000000757 +0.025480000000015934 +0.02588999999989028 +0.025709999999889988 +0.026045000000067375 +0.02539000000001579 +0.025650000000041473 +0.025210999999899286 +0.02556500000014239 +0.02472499999998945 +0.024785000000065338 +0.02437999999983731 +0.04807500000015352 +0.023584999999911815 +0.023014999999986685 +0.02274499999998625 +0.022420000000010987 +0.022120000000086293 +0.02211499999998523 +0.021094999999831998 +0.021125000000211003 +0.020729999999957727 +0.02062999999998283 +0.020269999999982247 +0.020130999999992127 +0.019974999999931242 +0.019700000000057116 +0.01954499999988002 +0.019485000000031505 +0.019144999999980428 +0.01925000000005639 +0.019025000000056025 +0.018824999999878855 +0.018810000000030414 +0.01872500000013133 +0.01876999999990403 +0.01873000000000502 +0.018990000000030705 +0.018555000000105792 +0.01908499999990454 +0.0186949999999797 +0.01900999999998021 +0.019109999999955107 +0.01876000000015665 +0.019239999999854263 +0.018996000000015556 +0.019279999999980646 +0.019170000000030996 +0.019244999999955326 +0.019475000000056752 +0.01936000000000604 +0.019420000000081927 +0.03938500000003842 +0.019319999999879656 +0.019585000000006403 +0.01961000000005697 +0.01972000000000662 +0.019790000000057262 +0.020054999999956635 +0.01972499999988031 +0.01999500000010812 +0.01989499999990585 +0.0200600000000577 +0.02028999999993175 +0.020046000000093045 +0.02010999999993146 +0.020340000000032887 +0.020189999999956854 +0.020729999999957727 +0.02009500000008302 +0.04091500000004089 +0.02052000000003318 +0.021039999999857173 +0.02038500000003296 +0.020549999999957436 +0.0207300000001851 +0.020769999999856736 +0.021020000000135042 +0.021289999999908105 +0.020725000000084037 +0.0209909999998672 +0.021314000000074884 +0.020800999999892156 +0.06381499999997686 +0.04281000000014501 +0.021704999999883512 +0.021169999999983702 +0.021745000000009895 +0.02147000000013577 +0.02194999999983338 +0.021535000000085347 +0.021790000000009968 +0.022085000000060973 +0.021679999999832944 +0.022100000000136788 +0.02197499999988395 +0.021986000000197237 +0.022149999999783176 +0.02228000000013708 +0.02218999999990956 +0.02249500000016269 +0.02222999999980857 +0.022415000000137297 +0.022559999999884894 +0.02249500000016269 +0.022600000000011278 +0.02257499999996071 +0.02281500000003689 +0.022754999999961 +0.022725000000036744 +0.02299999999991087 +0.023014999999986685 +0.022940000000062355 +0.023085000000037326 +0.02307599999994636 +0.0231300000000374 +0.023320000000012442 +0.023294999999961874 +0.02325499999983549 +0.023640000000114014 +0.02351500000008855 +0.023309999999810316 +0.023750000000063665 +0.02355000000011387 +0.023719999999912034 +0.02391499999998814 +0.023685000000114087 +0.024014999999963038 +0.023869999999988067 +0.024071000000049025 +0.024063999999953012 +0.02420099999994818 +0.02422500000011496 +0.02430499999991298 +0.02422999999998865 +0.024364999999988868 +0.024474999999938518 +0.024660000000039872 +0.02444500000001426 +0.024630000000115615 +0.024814999999989595 +0.024674999999888314 +0.02479999999991378 +0.02496500000006563 +0.0248900000001413 +0.05030599999986407 +0.025065000000040527 +0.025129999999990105 +0.0253299999999399 +0.02521999999999025 +0.0253850000001421 +0.02546499999994012 +0.025470000000041182 +0.02586499999983971 +0.025445000000217988 +0.025764999999864813 +0.025595000000066648 +0.02585999999996602 +0.025564999999915017 +0.025505000000066502 +0.025450000000091677 +0.025324999999838838 +0.024906000000100903 +0.024914999999964493 +0.02454000000011547 +0.024349999999913052 +0.024114999999937936 +0.023785000000088985 +0.02345999999988635 +0.023360000000138825 +0.022669999999834545 +0.022519999999985885 +0.02225500000008651 +0.02187000000003536 +0.02165999999988344 +0.021390000000110376 +0.021030000000109794 +0.02088499999990745 +0.02056999999990694 +0.020535999999992782 +0.020075000000133514 +0.019900000000006912 +0.0200049999998555 +0.019300000000157524 +0.019454999999879874 +0.019195000000081563 +0.019209999999930005 +0.01917500000013206 +0.018759999999929278 +0.018890000000055807 +0.018779999999878783 +0.01873000000000502 +0.01872500000013133 +0.01882999999997992 +0.018834999999853608 +0.018890000000055807 +0.018980000000055952 +0.019209999999930005 +0.018816000000015265 +0.01915499999995518 +0.019064999999955035 +0.019155000000182554 +0.01932499999998072 +0.01922999999987951 +0.01936000000000604 +0.01936000000000604 +0.01963500000010754 +0.01926000000003114 +0.019594999999981155 +0.019774999999981446 +0.019475000000056752 +0.03930499999978565 +0.019865000000208966 +0.020224999999982174 +0.019479999999930442 +0.01985500000000684 +0.02013499999998203 +0.020305000000007567 +0.020121000000017375 +0.019700000000057116 +0.020269999999982247 +0.020104999999830397 +0.0204550000000836 +0.020729999999957727 +0.019900000000006912 +0.020465000000058353 +0.020444999999881475 +0.020580000000109067 +0.020829999999932625 +0.020449999999982538 +0.02069500000015978 +0.020729999999957727 +0.020859999999856882 +0.020785000000159926 +0.02106499999990774 +0.020864999999957945 +0.020965000000160217 +0.021119999999882566 +0.021181000000069616 +0.021169999999983702 +0.021250000000009095 +0.021500000000060027 +0.02113999999983207 +0.02136000000018612 +0.021424999999908323 +0.021494999999958964 +0.021864999999934298 +0.021425000000135697 +0.02169000000003507 +0.021724999999833017 +0.02172500000006039 +0.021815000000060536 +0.02193499999998494 +0.021940000000086002 +0.021989999999959764 +0.044216000000005806 +0.022214999999960128 +0.022214999999960128 +0.022195000000010623 +0.022335000000111904 +0.022629999999935535 +0.022389999999859356 +0.022440000000187865 +0.022654999999986103 +0.02296499999988555 +0.0223599999999351 +0.022830000000112705 +0.022699999999986176 +0.02320000000008804 +0.022600000000011278 +0.023054999999885695 +0.022860000000036962 +0.023265000000037617 +0.023120999999946434 +0.023194999999986976 +0.023255000000062864 +0.023244999999860738 +0.023425000000088403 +0.02351500000008855 +0.02341999999998734 +0.02366499999993721 +0.023615000000063446 +0.023649999999861393 +0.02394500000013977 +0.023860000000013315 +0.07178499999986343 +0.04797099999996135 +0.024280000000089785 +0.02450999999996384 +0.024069999999937863 +0.024375000000190994 +0.024504999999862775 +0.024329999999963547 +0.025084999999990032 +0.02428500000019085 +0.0492749999998523 +0.04966500000000451 +0.02500000000009095 +0.024859999999989668 +0.025249999999914507 +0.024951000000100976 +0.050389999999879365 +0.025560000000041327 +0.025210000000015498 +0.025300000000015643 +0.025624999999990905 +0.02539999999999054 +0.02531500000009146 +0.02567999999996573 +0.024699999999938882 +0.025139999999964857 +0.024765000000115833 +0.025030000000015207 +0.02409999999986212 +0.04827500000010332 +0.023690999999871565 +0.02348500000016429 +0.02293999999983498 +0.022699999999986176 +0.022519999999985885 +0.022120000000086293 +0.02176000000008571 +0.021579999999858046 +0.021205000000009022 +0.02098999999998341 +0.020885000000134823 +0.02042000000005828 +0.02011499999980515 +0.0398200000001907 +0.019529999999804204 +0.019580000000132713 +0.019205000000056316 +0.019079999999803476 +0.01907100000016726 +0.019019999999954962 +0.019070000000056098 +0.018509999999878346 +0.018940000000156942 +0.018849999999929423 +0.01858500000003005 +0.01902499999982865 +0.01917500000013206 +0.018644999999878564 +0.01911000000018248 +0.019000000000005457 +0.019219999999904758 +0.038324999999986176 +0.019485000000031505 +0.019315999999889755 +0.01939400000014757 +0.01943499999993037 +0.0192899999999554 +0.019516000000066924 +0.01974500000005719 +0.019669999999905485 +0.019479999999930442 +0.019825000000082582 +0.019974999999931242 +0.01956000000018321 +0.020339999999805514 +0.01942500000018299 +0.020080000000007203 +0.02024499999993168 +0.019949999999880674 +0.019980000000032305 +0.020234999999956926 +0.02035000000000764 +0.02049000000010892 +0.02014499999995678 +0.020260000000007494 +0.02045999999995729 +0.020475000000033106 +0.020670999999993 +0.020435000000134096 +0.020794999999907304 +0.020680000000083965 +0.020649999999932334 +0.020870000000059008 +0.020869999999831634 +0.02106000000003405 +0.020999999999958163 +0.020835000000033688 +0.021110000000135187 +0.02112499999998363 +0.021150000000034197 +0.02116000000000895 +0.021394999999984066 +0.02134000000000924 +0.021295000000009168 +0.02161999999998443 +0.02177599999981794 +0.06460500000002867 +0.021995000000060827 +0.02161500000011074 +0.021614999999883366 +0.022024999999985084 +0.021960000000035507 +0.021844999999984793 +0.02218500000003587 +0.02201999999988402 +0.02215000000001055 +0.022204999999985375 +0.02228500000001077 +0.022435000000086802 +0.02228500000001077 +0.022515999999995984 +0.02250499999991007 +0.022735000000011496 +0.022529999999960637 +0.0228100000001632 +0.022699999999986176 +0.022774999999910506 +0.022799999999961074 +0.022834999999986394 +0.023115000000188957 +0.02327500000001237 +0.02271999999993568 +0.02359000000001288 +0.022944999999936044 +0.023194999999986976 +0.023445000000037908 +0.023255000000062864 +0.02349499999991167 +0.023781000000099084 +0.023594999999886568 +0.023370000000113578 +0.02377499999988686 +0.023609999999962383 +0.023855000000139626 +0.023979999999937718 +0.023850000000038563 +0.023944999999912397 +0.02408500000001368 +0.02415500000006432 +0.02420499999993808 +0.024245000000064465 +0.024355000000014115 +0.02419499999996333 +0.024805000000014843 +0.02423499999986234 +0.024511000000075 +0.024625000000014552 +0.024779999999964275 +0.024630000000115615 +0.02486999999996442 +0.024914999999964493 +0.02486999999996442 +0.024885000000040236 +0.02512499999988904 +0.025055000000065775 +0.025515000000041255 +0.025034999999888896 +0.025245000000040818 +0.025340000000142027 +0.02551099999982398 +0.025380000000041036 +0.025624999999990905 +0.02567500000009204 +0.025615000000016153 +0.02560999999991509 +0.025174999999990177 +0.025340000000142027 +0.024999999999863576 +0.025129999999990105 +0.024340000000165674 +0.024699999999938882 +0.023964999999861902 +0.023855000000139626 +0.023580000000038126 +0.023365000000012515 +0.022800999999844862 +0.022635000000036598 +0.022560000000112268 +0.0215899999998328 +0.021910000000161745 +0.021224999999958527 +0.02106000000003405 +0.020800000000008367 +0.020564999999805877 +0.020305000000007567 +0.02020500000003267 +0.019935000000032232 +0.019735000000082437 +0.01981999999998152 +0.019375000000081855 +0.01933499999995547 +0.019454999999879874 +0.01915000000008149 +0.01908000000003085 +0.01911999999992986 +0.019131000000015774 +0.019074000000046 +0.019325999999864507 +0.019070000000056098 +0.01926000000003114 +0.019344999999930224 +0.019315000000005966 +0.01939000000015767 +0.019594999999981155 +0.020129999999880965 +0.01890000000003056 +0.019620000000031723 +0.019659999999930733 +0.019840000000158398 +0.019669999999905485 +0.019735000000082437 +0.019810000000006767 +0.020014999999830252 +0.019954999999981737 +0.019975000000158616 +0.02003100000001723 +0.020088999999870794 +0.020146000000067943 +0.020269999999982247 +0.02020500000003267 +0.020340000000032887 +0.020409999999856154 +0.020395000000007713 +0.02044500000010885 +0.020504999999957363 +0.020620000000008076 +0.020690000000058717 +0.020689999999831343 +0.020685000000185028 +0.02074999999990723 +0.0209500000000844 +0.02084500000000844 +0.020914999999831707 +0.021055000000160362 +0.021040999999968335 +0.021074999999882493 +0.02119500000003427 +0.02115500000013526 +0.02130999999985761 +0.02137500000003456 +0.021345000000110304 +0.0214899999998579 +0.02141499999993357 +0.02154000000018641 +0.021610000000009677 +0.021700000000009823 +0.02226499999983389 +0.021210000000110085 +0.02180499999985841 +0.021845000000212167 +0.02193499999998494 +0.02205499999990934 +0.022056000000020504 +0.022015000000010332 +0.022195000000010623 +0.022209999999859065 +0.02228000000013708 +0.02233499999988453 +0.02236500000003616 +0.02236500000003616 +0.022650000000112414 +0.022449999999935244 +0.022559999999884894 +0.022965000000112923 +0.02261499999985972 +0.022695000000112486 +0.022795000000087384 +0.02299999999991087 +0.02285000000006221 +0.023044999999910942 +0.023110999999971682 +0.02310499999998683 +0.02314000000001215 +0.023535000000038053 +0.023149999999986903 +0.023335000000088257 +0.02341999999998734 +0.023445000000037908 +0.02363999999988664 +0.02367000000003827 +0.023464999999987413 +0.02380500000003849 +0.024054999999862048 +0.02359999999998763 +0.024110000000064247 +0.02370999999993728 +0.024110000000064247 +0.024075000000038926 +0.024386000000049535 +0.024034999999912543 +0.024454999999989013 +0.024139999999988504 +0.024364999999988868 +0.02443000000016582 +0.02455499999996391 +0.024769999999989523 +0.024604999999837673 +0.02450000000021646 +0.024829999999838037 +0.02486999999996442 +0.0248900000001413 +0.024889999999913925 +0.025059999999939464 +0.02515100000005077 +0.02539999999999054 +0.025065000000040527 +0.05052500000010696 +0.025239999999939755 +0.02557000000001608 +0.02549999999996544 +0.025589999999965585 +0.025624999999990905 +0.025689999999940483 +0.025759999999991123 +0.025759999999991123 +0.025645000000167784 +0.025560000000041327 +0.025349999999889405 +0.025075999999899068 +0.02513000000021748 +0.02468999999996413 +0.025084999999990032 +0.023689999999987776 +0.024149999999963256 +0.023185000000012224 +0.02321499999993648 +0.022820000000137952 +0.02251499999988482 +0.02222000000006119 +0.02197499999988395 +0.02147000000013577 +0.02141499999993357 +0.021169999999983702 +0.020890000000008513 +0.020485000000007858 +0.020404999999982465 +0.02010599999994156 +0.02007000000003245 +0.019774999999981446 +0.019604999999955908 +0.0196400000002086 +0.01930499999980384 +0.019235000000207947 +0.019209999999930005 +0.018964999999980137 +0.01900999999998021 +0.018964999999980137 +0.0189700000000812 +0.01882999999997992 +0.01905999999985397 +0.01904000000013184 +0.01904999999987922 +0.019120000000157233 +0.01936499999987973 +0.019035000000030777 +0.019240000000081636 +0.019320999999990818 +0.019305000000031214 +0.01954499999988002 +0.019405000000006112 +0.01975500000003194 +0.01933499999995547 +0.01961000000005697 +0.019585000000006403 +0.019769999999880383 +0.0200600000000577 +0.01950000000010732 +0.019914999999855354 +0.019800000000032014 +0.019945000000006985 +0.02007000000003245 +0.020054999999956635 +0.02017000000000735 +0.02016500000013366 +0.02018099999986589 +0.020328999999946973 +0.020301000000017666 +0.020320000000083382 +0.020475000000033106 +0.020485000000007858 +0.020469999999932043 +0.020725000000084037 +0.02056500000003325 +0.020864999999957945 +0.020984999999882348 +0.0205550000000585 +0.02074999999990723 +0.020870000000059008 +0.020890000000008513 +0.02098500000010972 +0.021264999999857537 +0.02101500000003398 +0.04231500000014421 +0.021479999999883148 +0.021705999999994674 +0.020935000000008586 +0.021529999999984284 +0.02126500000008491 +0.021754999999984648 +0.021704999999883512 +0.021565000000009604 +0.021790000000009968 +0.021645000000034997 +0.021840000000111104 +0.021719999999959327 +0.022249999999985448 +0.02211999999985892 +0.021780000000035216 +0.022375000000010914 +0.021940000000086002 +0.022024999999985084 +0.02229499999998552 +0.022455999999920095 +0.022275000000036016 +0.022619999999960783 +0.022415000000137297 +0.022529999999960637 +0.045270000000073196 +0.045459999999820866 +0.04584500000009939 +0.04591000000004897 +0.02325499999983549 +0.04634500000020125 +0.023555999999871347 +0.02296000000001186 +0.04673500000012609 +0.0944649999999001 +0.047420000000101936 +0.024329999999963547 +0.023474999999962165 +0.024189999999862266 +0.023820000000114305 +0.02419000000008964 +0.024444999999786887 +0.02387100000009923 +0.02430400000002919 +0.02422599999999875 +0.02447000000006483 +0.02444999999988795 +0.02451999999993859 +0.025125000000116415 +0.024369999999862557 +0.02458000000001448 +0.024785000000065338 +0.02494000000001506 +0.024744999999938955 +0.025155000000040673 +0.024914999999964493 +0.025139999999964857 +0.025345000000015716 +0.025230000000192376 +0.02511999999978798 +0.02541600000017752 +0.025444999999990614 +0.02549999999996544 +0.025595000000066648 +0.02557000000001608 +0.02584999999999127 +0.025629999999864594 +0.02630999999996675 +0.025475000000142245 +0.025689999999940483 +0.02581499999996595 +0.025380000000041036 +0.025529999999889696 +0.02518000000009124 +0.02497500000004038 +0.024615999999923588 +0.02437000000008993 +0.023934999999937645 +0.02373499999998785 +0.02320499999996173 +0.02275000000008731 +0.022600000000011278 +0.022029999999858774 +0.0218200000001616 +0.021404999999958818 +0.02101500000003398 +0.020684999999957654 +0.02056500000003325 +0.020229999999855863 +0.020080000000007203 +0.019770000000107757 +0.01972499999988031 +0.019485000000031505 +0.019265000000132204 +0.019100999999864143 +0.01900500000010652 +0.01891000000000531 +0.018744999999853462 +0.018645000000105938 +0.01862000000005537 +0.01852499999995416 +0.018569999999954234 +0.018559999999979482 +0.01854500000013104 +0.01862499999992906 +0.018704999999954453 +0.018710000000055516 +0.018714999999929205 +0.018880000000081054 +0.01886500000000524 +0.01887499999997999 +0.019019999999954962 +0.018990000000030705 +0.019129999999904612 +0.019085000000131913 +0.019135999999889464 +0.019155000000182554 +0.01933499999995547 +0.019244999999955326 +0.019330000000081782 +0.01948499999980413 +0.019410000000107175 +0.019485000000031505 +0.019585000000006403 +0.019665000000031796 +0.019589999999880092 +0.019735000000082437 +0.020064999999931388 +0.019765000000006694 +0.01964999999995598 +0.019825000000082582 +0.019994999999880747 +0.01999500000010812 +0.02014000000008309 +0.0200049999998555 +0.0207709999999679 +0.019655000000057044 +0.020195000000057917 +0.020375000000058208 +0.020340000000032887 +0.020379999999931897 +0.02070499999990716 +0.020355000000108703 +0.02053499999988162 +0.021095000000059372 +0.020324999999957072 +0.020684999999957654 +0.020870000000059008 +0.02077000000008411 +0.02081499999985681 +0.02101000000016029 +0.021004999999831853 +0.02102500000000873 +0.021275000000059663 +0.021105999999917913 +0.02116000000000895 +0.02136500000005981 +0.021245000000135406 +0.02165999999988344 +0.021330000000034488 +0.021254999999882784 +0.02161500000011074 +0.021680000000060318 +0.021499999999832653 +0.02213500000016211 +0.021409999999832507 +0.021775000000161526 +0.02194499999995969 +0.021999999999934516 +0.022015000000010332 +0.021850000000085856 +0.022164999999858992 +0.02221600000007129 +0.022124999999959982 +0.02243999999996049 +0.022240000000010696 +0.02235500000006141 +0.022470000000112123 +0.02296499999988555 +0.022124999999959982 +0.02271500000006199 +0.022459999999909996 +0.023070000000188884 +0.045419999999921856 +0.023059999999986758 +0.022785000000112632 +0.023009999999885622 +0.02310499999998683 +0.023126000000047497 +0.02327500000001237 +0.023099999999885767 +0.02351500000008855 +0.02331499999991138 +0.023429999999962092 +0.023420000000214714 +0.023649999999861393 +0.023574999999937063 +0.023715000000038344 +0.023740000000088912 +0.023729999999886786 +0.02393500000016502 +0.02395499999988715 +0.02387999999996282 +0.024100000000089494 +0.02405500000008942 +0.024260999999796695 +0.024090000000114742 +0.024425000000064756 +0.024294999999938227 +0.024535000000014406 +0.02430499999991298 +0.025129999999990105 +0.024184999999988577 +0.024485000000140644 +0.024744999999938955 +0.024840000000040163 +0.024844999999913853 +0.024879999999939173 +0.025030000000015207 +0.024970000000166692 +0.025129999999990105 +0.025405999999975393 +0.025020000000040454 +0.025165000000015425 +0.02550499999983913 +0.025375000000167347 +0.025409999999965294 +0.02560999999991509 +0.025059999999939464 +0.025100000000065847 +0.025129999999990105 +0.024699999999938882 +0.024644999999964057 +0.024290000000064538 +0.023965000000089276 +0.02370999999993728 +0.023474999999962165 +0.02307599999994636 +0.0225350000000617 +0.022380000000111977 +0.02197499999988395 +0.02152000000000953 +0.021345000000110304 +0.021049999999831925 +0.020575000000008004 +0.020465000000058353 +0.02028999999993175 +0.019900000000006912 +0.019750000000158252 +0.01951999999982945 +0.01926000000003114 +0.019195000000081563 +0.01890000000003056 +0.018834999999853608 +0.01873000000000502 +0.018565000000080545 +0.018505000000004657 +0.018334999999979118 +0.01830100000006496 +0.018180000000029395 +0.018244999999978972 +0.018170000000054642 +0.018174999999928332 +0.01823999999987791 +0.01836500000013075 +0.018299999999953798 +0.018455000000130894 +0.018469999999979336 +0.018449999999802458 +0.01855000000000473 +0.018520000000080472 +0.018645000000105938 +0.018724999999903957 +0.019029999999929714 +0.018590000000131113 +0.01876500000003034 +0.018969999999853826 +0.01876000000015665 +0.019010999999863998 +0.018980000000055952 +0.019094999999879292 +0.01911500000005617 +0.019180000000005748 +0.019160000000056243 +0.01936999999998079 +0.01926000000003114 +0.01932499999998072 +0.019485000000031505 +0.0194099999998798 +0.01957500000003165 +0.019559999999955835 +0.019980000000032305 +0.019205000000056316 +0.02007499999990614 +0.019435000000157743 +0.01974999999993088 +0.019905000000107975 +0.019889999999804786 +0.020046000000093045 +0.020064999999931388 +0.02038500000003296 +0.019615000000158034 +0.020264999999881184 +0.020189999999956854 +0.020260000000007494 +0.020395000000007713 +0.020395000000007713 +0.020340000000032887 +0.020549999999957436 +0.020430000000033033 +0.02063999999995758 +0.020684999999957654 +0.020500000000083674 +0.02105499999993299 +0.020650000000159707 +0.020759999999881984 +0.021140999999943233 +0.020713999999998123 +0.021106000000145286 +0.02098999999998341 +0.021074999999882493 +0.021070000000008804 +0.021285000000034415 +0.021385000000009313 +0.021205000000009022 +0.042905000000018845 +0.021455000000059954 +0.021404999999958818 +0.021819999999934225 +0.02151000000003478 +0.021780000000035216 +0.04349499999989348 +0.02190500000006068 +0.022020999999995183 +0.02186000000006061 +0.022034999999959837 +0.022230000000035943 +0.022029999999858774 +0.02213500000016211 +0.04464499999994587 +0.02242999999998574 +0.04502999999999702 +0.022480000000086875 +0.022704999999859865 +0.02274499999998625 +0.022690000000011423 +0.04542500000002292 +0.0459600000001501 +0.02296599999999671 +0.023044999999910942 +0.02320499999996173 +0.04629999999997381 +0.02358500000013919 +0.023134999999911088 +0.047109999999975116 +0.047170000000051004 +0.023580000000038126 +0.023654999999962456 +0.02380500000003849 +0.02385099999992235 +0.023859000000129527 +0.024274999999988722 +0.023750999999947453 +0.048344999999926586 +0.04841000000010354 +0.024454999999989013 +0.02476000000001477 +0.024139999999988504 +0.024679999999989377 +0.024404999999887877 +0.02454000000011547 +0.02486999999996442 +0.024705000000039945 +0.0248349999999391 +0.025525000000016007 +0.024251000000049316 +0.025309999999990396 +0.05023499999992964 +0.07509499999991931 +0.025669999999990978 +0.024140000000215878 +0.024034999999912543 +0.024034999999912543 +0.023505000000113796 +0.023474999999962165 +0.023095000000012078 +0.02197999999998501 +0.02218999999990956 +0.04324500000006992 +0.02140600000006998 +0.020264999999881184 +0.07992500000000291 +0.01998500000013337 +0.01876500000003034 +0.018969999999853826 +0.018540000000029977 +0.01841500000000451 +0.018299999999953798 +0.018280000000004293 +0.01823000000013053 +0.017724999999927604 +0.017900000000054206 +0.017619999999851643 +0.01784500000007938 +0.01756599999998798 +0.01745899999991707 +0.017591000000038548 +0.017794999999978245 +0.017295000000103755 +0.017759999999952925 +0.017655000000104337 +0.01767499999982647 +0.01783500000010463 +0.01792000000000371 +0.017839999999978318 +0.017865000000028886 +0.01812500000005457 +0.017859999999927823 +0.018080000000054497 +0.01847999999995409 +0.017804999999952997 +0.018289999999979045 +0.018145000000004075 +0.018360000000029686 +0.01834499999995387 +0.018424999999979264 +0.018350000000054933 +0.01841500000000451 +0.018590000000131113 +0.018575999999939086 +0.01880499999992935 +0.018520000000080472 +0.01880499999992935 +0.018640000000004875 +0.037974999999960346 +0.018735000000106083 +0.018890000000055807 +0.019099999999980355 +0.019169999999803622 +0.01900500000010652 +0.019344999999930224 +0.0382600000000366 +0.019450000000006185 +0.01914000000010674 +0.01944499999990512 +0.01943499999993037 +0.019405000000006112 +0.019661000000041895 +0.01964500000008229 +0.019485000000031505 +0.02017000000000735 +0.01930499999980384 +0.02020500000003267 +0.020010000000183936 +0.019694999999956053 +0.020129999999880965 +0.019559999999955835 +0.020000000000209184 +0.020064999999931388 +0.02021999999988111 +0.02016500000013366 +0.02049499999998261 +0.02007000000003245 +0.0204999999998563 +0.0409060000001773 +0.020758999999998196 +0.020170999999891137 +0.041560000000117725 +0.020589999999856445 +0.062374999999974534 +0.02136500000005981 +0.04208500000004278 +0.02101500000003398 +0.04221999999981563 +0.042575000000169894 +0.021295000000009168 +0.04289999999991778 +0.021525000000110595 +0.021715999999969426 +0.021479999999883148 +0.02229499999998552 +0.043145000000095024 +0.021680000000060318 +0.022195000000010623 +0.02194499999995969 +0.021814999999833162 +0.0225350000000617 +0.021735000000035143 +0.022169999999960055 +0.022325000000137152 +0.04476499999987027 +0.02235500000006141 +0.022494999999935317 +0.045341000000007625 +0.022515000000112195 +0.0225799999998344 +0.022879999999986467 +0.022795000000087384 +0.022879999999986467 +0.023075000000062573 +0.023124999999936335 +0.022910000000138098 +0.02318499999978485 +0.023495000000139044 +0.02292999999986023 +0.023350000000164073 +0.04662499999994907 +0.02387500000008913 +0.02367499999991196 +0.023200999999971827 +0.023654999999962456 +0.023824999999987995 +0.02363500000001295 +0.02391000000011445 +0.02381999999988693 +0.024070000000165237 +0.07281499999999141 +0.07242999999994026 +0.024369999999862557 +0.024270000000115033 +0.024705999999923733 +0.024390000000039436 +0.024810000000115906 +0.02444500000001426 +0.024864999999863358 +0.024879999999939173 +0.024859999999989668 +0.02510500000016691 +0.02444500000001426 +0.024699999999938882 +0.02437499999996362 +0.02430499999991298 +0.02373000000011416 +0.023715000000038344 +0.023754999999937354 +0.022410000000036234 +0.022445000000061555 +0.022300999999970372 +0.02172999999993408 +0.021500000000060027 +0.02117499999985739 +0.02084500000000844 +0.02091000000018539 +0.020239999999830616 +0.02009500000008302 +0.019639999999981228 +0.019765000000006694 +0.019344999999930224 +0.01914000000010674 +0.01873499999987871 +0.0186949999999797 +0.018605000000206928 +0.018404999999802385 +0.01823000000013053 +0.01816499999995358 +0.01798499999995329 +0.01791000000002896 +0.017900999999937994 +0.017715000000180225 +0.01768499999980122 +0.01784000000020569 +0.017659999999978027 +0.01766999999995278 +0.017869999999902575 +0.017790000000104556 +0.017839999999978318 +0.054024999999910506 +0.018535000000156288 +0.017664999999851716 +0.03638999999998305 +0.018280000000004293 +0.018320000000130676 +0.01830999999992855 +0.018735000000106083 +0.019054999999980282 +0.01764099999991231 +0.018469999999979336 +0.018565000000080545 +0.018710000000055516 +0.018644999999878564 +0.018925000000081127 +0.018609999999853244 +0.03767000000016196 +0.019329999999854408 +0.018559999999979482 +0.01907500000015716 +0.019029999999929714 +0.01911500000005617 +0.019160000000056243 +0.019450000000006185 +0.019144999999980428 +0.01922500000000582 +0.01943999999980406 +0.019365000000107102 +0.019514999999955762 +0.019524999999930515 +0.019546000000218555 +0.019589999999880092 +0.019704999999930806 +0.01972000000000662 +0.019700000000057116 +0.01989000000003216 +0.019849999999905776 +0.01988500000015847 +0.020024999999805004 +0.019980000000032305 +0.0200600000000577 +0.0201799999999821 +0.020120000000133587 +0.020260000000007494 +0.020260000000007494 +0.020334999999931824 +0.02038999999990665 +0.021040000000084547 +0.019990000000007058 +0.020371000000068307 +0.020614999999907013 +0.020694999999932406 +0.021075000000109867 +0.04115000000001601 +0.020764999999983047 +0.020964999999932843 +0.021034999999983484 +0.020930000000134896 +0.02112499999998363 +0.02102999999988242 +0.02136500000005981 +0.021264999999857537 +0.021285000000034415 +0.021040000000084547 +0.021850000000085856 +0.021149999999806823 +0.021396000000095228 +0.021680000000060318 +0.021749999999883585 +0.02165500000000975 +0.0220400000000609 +0.043229999999994106 +0.021950000000060754 +0.021604999999908614 +0.04433500000004642 +0.02186000000006061 +0.0220849999998336 +0.02260999999998603 +0.02196500000013657 +0.022254999999859137 +0.022380000000111977 +0.022451000000046406 +0.02254399999992529 +0.022621000000071945 +0.022529999999960637 +0.023050000000012005 +0.022600000000011278 +0.022510000000011132 +0.02296499999988555 +0.022879999999986467 +0.023120000000062646 +0.022785000000112632 +0.0233499999999367 +0.02288999999996122 +0.023269999999911306 +0.023325000000113505 +0.02328499999998712 +0.02338000000008833 +0.02345599999989645 +0.023864000000003216 +0.02313600000002225 +0.04732999999987442 +0.024120000000039 +0.0236250000000382 +0.04740500000002612 +0.02405500000008942 +0.024009999999861975 +0.04885000000012951 +0.023729999999886786 +0.02444000000014057 +0.04854499999987638 +0.024380000000064683 +0.024734999999964202 +0.04935599999998885 +0.024840000000040163 +0.02459499999986292 +0.04991000000018175 +0.025214999999889187 +0.024165000000039072 +0.024564999999938664 +0.02433500000006461 +0.04820500000005268 +0.04693999999994958 +0.023404999999911524 +0.022100000000136788 +0.02229999999985921 +0.022171000000071217 +0.021330000000034488 +0.021884999999883803 +0.02062500000010914 +0.04108500000006643 +0.01979999999980464 +0.019715000000132932 +0.01950499999998101 +0.019410000000107175 +0.018994999999904394 +0.018784999999979846 +0.018724999999903957 +0.018445000000156142 +0.01827000000002954 +0.018364999999903375 +0.017949999999927968 +0.017929999999978463 +0.017985000000180662 +0.017629999999826396 +0.017686000000139757 +0.017720000000053915 +0.01756000000000313 +0.01770999999985179 +0.017645000000129585 +0.017859999999927823 +0.01763000000005377 +0.017899999999826832 +0.01795000000015534 +0.01795999999990272 +0.0178800000001047 +0.017965000000003783 +0.018180000000029395 +0.018184999999903084 +0.018174999999928332 +0.01801500000010492 +0.018299999999953798 +0.01823500000000422 +0.01837999999997919 +0.018389999999953943 +0.018465999999989435 +0.01843900000017129 +0.018535999999812702 +0.018590000000131113 +0.018634999999903812 +0.018850000000156797 +0.018619999999827996 +0.01861500000018168 +0.018894999999929496 +0.018945000000030632 +0.018794999999954598 +0.019060000000081345 +0.01891000000000531 +0.019019999999954962 +0.0191899999999805 +0.019094999999879292 +0.019265000000132204 +0.019270000000005894 +0.019270000000005894 +0.01936000000000604 +0.019459999999980937 +0.019479999999930442 +0.019441000000142594 +0.019564999999829524 +0.01961000000005697 +0.01963500000010754 +0.01979499999993095 +0.019729999999981374 +0.019810000000006767 +0.019835000000057335 +0.01986999999985528 +0.01998500000013337 +0.020019999999931315 +0.020015000000057626 +0.020139999999855718 +0.02020000000015898 +0.020194999999830543 +0.020260000000007494 +0.02037000000018452 +0.020344999999906577 +0.02038999999990665 +0.020500000000083674 +0.020496000000093773 +0.020614999999907013 +0.020684999999957654 +0.020635000000083892 +0.02070000000003347 +0.020864999999957945 +0.02080999999998312 +0.020909999999958018 +0.02098500000010972 +0.0209949999998571 +0.021055000000160362 +0.021109999999907814 +0.021189999999933207 +0.021224999999958527 +0.021305000000211294 +0.02130999999985761 +0.02137500000003456 +0.021480000000110522 +0.02141499999993357 +0.02159099999994396 +0.02161500000011074 +0.021614999999883366 +0.021770000000060463 +0.021819999999934225 +0.021809999999959473 +0.02178500000013628 +0.022029999999858774 +0.022060000000010405 +0.02207500000008622 +0.022034999999959837 +0.022120000000086293 +0.022230000000035943 +0.02233499999988453 +0.02229000000011183 +0.022375000000010914 +0.022529999999960637 +0.02251099999989492 +0.022529999999960637 +0.022685000000137734 +0.02264500000001135 +0.022714999999834617 +0.022820000000137952 +0.022860000000036962 +0.02296000000001186 +0.02296000000001186 +0.02303999999980988 +0.023070000000188884 +0.02314499999988584 +0.023169999999936408 +0.023290000000088185 +0.02338499999996202 +0.023325000000113505 +0.023474999999962165 +0.02349499999991167 +0.023615999999947235 +0.023650000000088767 +0.023650000000088767 +0.0237449999999626 +0.02378499999986161 +0.0239000000001397 +0.023944999999912397 +0.02391499999998814 +0.02408500000001368 +0.024145000000089567 +0.02409999999986212 +0.024380000000064683 +0.024214999999912834 +0.024390000000039436 +0.02444500000001426 +0.024490000000014334 +0.024499999999989086 +0.024726000000100612 +0.02455499999996391 +0.024824999999964348 +0.024744999999938955 +0.0247900000001664 +0.024989999999888823 +0.024990000000116197 +0.025030000000015207 +0.025059999999939464 +0.025279999999838765 +0.025305000000116706 +0.025159999999914362 +0.025489999999990687 +0.02514500000006592 +0.02536000000009153 +0.02479500000004009 +0.024690999999847918 +0.024495000000115397 +0.024149999999963256 +0.02369999999996253 +0.023335000000088257 +0.023054999999885695 +0.022510000000011132 +0.02207500000008622 +0.021925000000010186 +0.021329999999807114 +0.02108500000008462 +0.020825000000058935 +0.02038999999990665 +0.02020500000003267 +0.019915000000082728 +0.019585000000006403 +0.019379999999955544 +0.019184999999879437 +0.0189660000000913 +0.018735000000106083 +0.01859999999987849 +0.01837999999997919 +0.018385000000080254 +0.01816499999995358 +0.018045000000029177 +0.01795999999990272 +0.017965000000003783 +0.017830000000003565 +0.017820000000028813 +0.01790500000015527 +0.017734999999902357 +0.017865000000028886 +0.018024999999852298 +0.01794000000018059 +0.017989999999826978 +0.018185000000130458 +0.018045000000029177 +0.018154999999978827 +0.018294999999852735 +0.01826600000003964 +0.018190000000004147 +0.018469999999979336 +0.018355000000155997 +0.01844499999992877 +0.01876999999990403 +0.01847000000020671 +0.018389999999953943 +0.01884499999982836 +0.018780000000106156 +0.018704999999954453 +0.018614999999954307 +0.01878500000020722 +0.01900999999998021 +0.01902499999982865 +0.018739999999979773 +0.018975000000182263 +0.01911999999992986 +0.019105000000081418 +0.019149999999854117 +0.019244999999955326 +0.019296000000167624 +0.019315000000005966 +0.01936000000000604 +0.019389999999930296 +0.01943499999993037 +0.01957500000003165 +0.019524999999930515 +0.01961000000005697 +0.019700000000057116 +0.019765000000006694 +0.019704999999930806 +0.019835000000057335 +0.019864999999981592 +0.019884999999931097 +0.020010000000183936 +0.020014999999830252 +0.020015000000057626 +0.020199999999931606 +0.020160000000032596 +0.020195000000057917 +0.020535999999992782 +0.020164999999906286 +0.020300000000133878 +0.02052000000003318 +0.020434999999906722 +0.02044500000010885 +0.0206749999999829 +0.020599999999831198 +0.020715000000109285 +0.020794999999907304 +0.020750000000134605 +0.02106000000003405 +0.02082499999983156 +0.020899999999983265 +0.020970000000033906 +0.021169999999983702 +0.0210500000000593 +0.021165000000110012 +0.0212699999999586 +0.021279999999933352 +0.021316000000069835 +0.02145499999983258 +0.021440000000211512 +0.0214899999998579 +0.02158000000008542 +0.021600000000034925 +0.021639999999933934 +0.021844999999984793 +0.02172500000006039 +0.02180499999985841 +0.021920000000136497 +0.02197000000001026 +0.022015000000010332 +0.022109999999884167 +0.022085000000060973 +0.022095000000035725 +0.022354999999834035 +0.022695999999996275 +0.021845000000212167 +0.022529999999960637 +0.022799999999961074 +0.022199999999884312 +0.0225350000000617 +0.02260999999998603 +0.022730000000137807 +0.022749999999859938 +0.02278999999998632 +0.023145000000113214 +0.022809999999935826 +0.022830000000112705 +0.02300499999978456 +0.023240000000214422 +0.02303499999993619 +0.023265000000037617 +0.023344999999835636 +0.023321000000123604 +0.02338499999996202 +0.023549999999886495 +0.02345500000001266 +0.023535000000038053 +0.023720000000139407 +0.023644999999987704 +0.02378499999986161 +0.023869999999988067 +0.023785000000088985 +0.024075000000038926 +0.023959999999988213 +0.02413000000001375 +0.024014999999963038 +0.02458999999998923 +0.02405999999996311 +0.024166000000150234 +0.024479999999812208 +0.024290000000064538 +0.024824999999964348 +0.024675000000115688 +0.024824999999964348 +0.02415500000006432 +0.02489500000001499 +0.024794999999812717 +0.024805000000014843 +0.025015000000166765 +0.02503999999998996 +0.024964999999838255 +0.025229999999965003 +0.025174999999990177 +0.02532500000006621 +0.025441000000000713 +0.025295000000141954 +0.025314999999864085 +0.025759999999991123 +0.025480000000015934 +0.024994999999989886 +0.025045000000091022 +0.024859999999989668 +0.02465000000006512 +0.024284999999963475 +0.023924999999962893 +0.023594999999886568 +0.023260000000163927 +0.022754999999961 +0.022420000000010987 +0.02208599999994476 +0.043220000000019354 +0.020755000000008295 +0.0204550000000836 +0.02031999999985601 +0.02053000000000793 +0.019510000000082073 +0.019585000000006403 +0.01939999999990505 +0.019099999999980355 +0.019340000000056534 +0.01852499999995416 +0.018669999999929132 +0.0184750000000804 +0.01837000000000444 +0.01823000000013053 +0.01813999999990301 +0.01816000000007989 +0.017974999999978536 +0.017965000000003783 +0.017890999999963242 +0.01798899999994319 +0.01784599999996317 +0.018109999999978754 +0.017974999999978536 +0.018150000000105138 +0.018540000000029977 +0.017820000000028813 +0.018149999999877764 +0.01837999999997919 +0.01826500000015585 +0.01844499999992877 +0.018915000000106375 +0.018149999999877764 +0.01837000000000444 +0.018640000000004875 +0.018595000000004802 +0.018540000000029977 +0.01882999999997992 +0.018869999999878928 +0.018635000000131186 +0.01894999999990432 +0.01914000000010674 +0.018650999999863416 +0.019055000000207656 +0.019029999999929714 +0.019309999999904903 +0.01893500000005588 +0.019440000000031432 +0.01897499999995489 +0.01946999999995569 +0.01918500000010681 +0.019414999999980864 +0.019630000000006476 +0.019330000000081782 +0.01958499999977903 +0.019565000000056898 +0.01972000000000662 +0.019580000000132713 +0.019879999999830034 +0.019810000000006767 +0.019765000000006694 +0.019926000000168642 +0.01989499999990585 +0.020029999999906067 +0.02005500000018401 +0.020164999999906286 +0.020050000000082946 +0.020239999999830616 +0.0202350000001843 +0.02031999999985601 +0.020440000000007785 +0.020549999999957436 +0.020305000000007567 +0.020580000000109067 +0.020759999999881984 +0.020365000000083455 +0.02077000000008411 +0.02059499999995751 +0.02081499999985681 +0.020890000000008513 +0.020944999999983338 +0.02094000000010965 +0.02091100000006918 +0.021105000000034124 +0.020984999999882348 +0.02119500000003427 +0.02119999999990796 +0.021270000000185973 +0.02141499999993357 +0.021314999999958673 +0.021275000000059663 +0.021565000000009604 +0.021604999999908614 +0.021490000000085274 +0.0217649999999594 +0.021614999999883366 +0.02167500000018663 +0.021854999999959546 +0.021849999999858483 +0.02213500000016211 +0.02179599999999482 +0.022034999999959837 +0.02200999999990927 +0.022455000000036307 +0.022099999999909414 +0.022125000000187356 +0.022694999999885113 +0.02196500000013657 +0.022639999999910287 +0.022300000000086584 +0.02264500000001135 +0.022659999999859792 +0.022584999999935462 +0.02257000000008702 +0.022860000000036962 +0.022940000000062355 +0.022739999999885185 +0.02288999999996122 +0.02306100000009792 +0.0235250000000633 +0.02261499999985972 +0.02317500000003747 +0.023280000000113432 +0.02328999999986081 +0.02370999999993728 +0.04657000000020162 +0.023544999999785432 +0.023630000000139262 +0.023554999999987558 +0.02387999999996282 +0.02369500000008884 +0.023760000000038417 +0.024104999999963184 +0.02376600000002327 +0.024329999999963547 +0.02381999999988693 +0.02419000000008964 +0.02413000000001375 +0.024310000000014043 +0.024334999999837237 +0.024364999999988868 +0.02454000000011547 +0.02444500000001426 +0.02465000000006512 +0.024715000000014697 +0.02458499999988817 +0.024709999999913634 +0.0248900000001413 +0.02487099999984821 +0.02489900000000489 +0.02514100000007602 +0.02507500000001528 +0.025104999999939537 +0.025305000000116706 +0.025374999999939973 +0.025270000000091386 +0.025339999999914653 +0.025519999999914944 +0.02542000000016742 +0.02568499999983942 +0.02577000000019325 +0.025554999999940264 +0.0259249999999156 +0.025720999999975902 +0.02613500000006752 +0.025855000000092332 +0.02617499999996653 +0.026254999999991924 +0.026024999999890497 +0.02620999999999185 +0.026315000000067812 +0.026364999999941574 +0.026565000000118744 +0.026374999999916326 +0.02665500000011889 +0.026934999999866704 +0.026534999999967113 +0.026855000000068685 +0.026855999999952473 +0.026924000000008164 +0.02709099999992759 +0.02705000000014479 +0.02709499999991749 +0.027285000000119908 +0.027049999999917418 +0.027450000000044383 +0.02744000000006963 +0.027399999999943248 +0.027460000000019136 +0.027814999999918655 +0.027694999999994252 +0.027894999999944048 +0.02764500000012049 +0.0279049999999188 +0.056201000000100976 +0.028305000000045766 +0.027824999999893407 +0.028274999999894135 +0.02839500000004591 +0.02839500000004591 +0.028559999999970387 +0.02867000000014741 +0.028449999999793363 +0.02871000000004642 +0.02877000000012231 +0.028695999999854394 +0.02906400000006215 +0.02896099999998114 +0.029420000000072832 +0.02906499999994594 +0.02891500000009728 +0.029404999999997017 +0.029369999999971697 +0.02944999999999709 +0.029404999999997017 +0.029755000000022847 +0.02956499999982043 +0.02954000000022461 +0.029899999999997817 +0.029829999999947177 +0.03005099999995764 +0.03018500000007407 +0.030194999999821448 +0.030100000000174987 +0.030354999999872234 +0.030300000000124783 +0.03026499999987209 +0.03058000000009997 +0.030555000000049404 +0.030674999999973807 +0.030804999999872962 +0.030705000000125438 +0.030809999999974025 +0.030915999999933774 +0.031195000000025175 +0.031240000000025248 +0.031304999999974825 +0.03125 +0.031054999999923893 +0.03139000000010128 +0.031549999999924694 +0.03145500000005086 +0.03188500000010208 +0.06378499999982523 +0.03167099999996026 +0.03197500000010223 +0.03209500000002663 +0.03221499999995103 +0.06455499999992753 +0.03230500000017855 +0.03253499999982523 +0.032565000000204236 +0.032614999999850625 +0.03300500000000284 +0.03269999999997708 +0.03282000000012886 +0.03316599999993741 +0.03302499999995234 +0.033590000000003783 +0.03282500000000255 +0.03350999999997839 +0.03305500000010397 +0.03344500000002881 +0.033664999999928114 +0.03357000000005428 +0.03413999999997941 +0.033355999999912456 +0.03407500000002983 +0.034080000000130894 +0.03388999999992848 +0.034445000000005166 +0.034099999999853026 +0.03453500000000531 +0.03498500000000604 +0.03374500000018088 +0.034764999999879365 +0.06939499999998588 +0.034755000000131986 +0.03510099999994054 +0.034969999999930224 +0.03528499999993073 +0.07067000000006374 +0.03515500000003158 +0.03556000000003223 +0.03568999999993139 +0.03575500000010834 +0.036415000000033615 +0.03577999999993153 +0.035636000000067725 +0.03655499999990752 +0.035859999999956926 +0.03603500000008353 +0.036380000000008295 +0.036595000000033906 +0.03665000000000873 +0.03677499999980682 +0.07383500000014465 +0.0366710000000694 +0.036674999999831925 +0.036984999999958745 +0.03765500000008615 +0.03725000000008549 +0.07476499999984298 +0.03731000000016138 +0.038000000000010914 +0.03763499999990927 +0.03834499999993568 +0.03770600000007107 +0.037624999999934516 +0.03833499999996093 +0.03823000000011234 +0.03811500000006163 +0.03850499999998647 +0.03851999999983491 +0.038525000000163345 +0.03879499999993641 +0.0388749999999618 +0.03886000000011336 +0.03933099999994738 +0.03880000000003747 +0.039029999999911524 +0.03917500000011387 +0.03926000000001295 +0.039594999999962965 +0.039599999999836655 +0.03994500000021617 +0.07951099999991129 +0.04019500000003973 +0.039655000000038854 +0.040549999999939246 +0.12073499999996784 +0.24568599999997787 +0.12315000000012333 +0.08412999999995918 +0.08267000000000735 +0.042215999999825726 +0.04186000000004242 +0.04205000000001746 +0.04196500000011838 +0.04268499999989217 +0.04223000000001775 +0.04365000000007058 +0.041579999999839856 +0.042554999999993015 +0.04317600000013044 +0.08597000000008848 +0.08678999999983716 +0.04330000000004475 +0.08707499999991342 +0.04353500000001986 +0.044531000000006316 +0.08750000000009095 +0.043754999999919164 +0.08848499999999149 +0.04475000000002183 +0.04467999999997119 +0.04453000000012253 +0.0451309999998557 +0.04472000000009757 +0.045055000000047585 +0.09006499999986772 +0.045830000000023574 +0.04508499999997184 +0.04562500000020009 +0.04642499999999927 +0.09116099999982907 +0.04609500000015032 +0.04680999999982305 +0.045790000000124564 +0.04653499999994892 +0.09309000000007472 +0.04704999999989923 +0.04711599999995997 +0.04668000000015127 +0.04695999999989908 +0.09515499999997701 +0.047025000000076034 +0.04843499999992673 +0.04679499999997461 +0.04859600000008868 +0.09531999999990148 +0.04810500000007778 +0.04877000000010412 +0.04833999999982552 +0.048615000000154396 +0.10005099999989397 +0.14508999999998196 +0.049054999999953 +0.04932500000018081 +0.04956499999980224 +0.050070000000005166 +0.04966100000001461 +0.04979000000002998 +0.050070000000005166 +0.05030499999998028 +0.05064500000003136 +0.10112500000013824 +0.10292099999992388 +0.10045999999988453 +0.05248500000016065 +0.05064500000003136 +0.051344999999855645 +0.10393500000009226 +0.05198599999994258 +0.05138499999998203 +0.10615000000007058 +0.05064999999990505 +0.053139999999984866 +0.10569099999997889 +0.05259000000000924 +0.10627999999996973 +0.05321000000003551 +0.10683500000004642 +0.05460100000004786 +0.05508499999996275 +0.1078899999999976 +0.053380000000061045 +0.10874999999987267 +0.10959600000001046 +0.11022500000012769 +0.11122999999997774 +0.11067499999990105 +0.11322600000016791 +0.0551949999999124 +0.16926499999999578 +0.05728500000009262 +2.3263909999998305 +0.1263810000000376 +0.2527299999999286 +0.1269760000000133 +0.12876500000015767 +0.06391499999995176 +0.12936999999988075 +0.06599500000015723 +0.19367099999999482 +0.06567500000005566 \ No newline at end of file diff --git a/recordings/KayakFirst_Blue_4x500m.csv b/recordings/KayakFirst_Blue_4x500m.csv new file mode 100644 index 0000000000..7bd9705115 --- /dev/null +++ b/recordings/KayakFirst_Blue_4x500m.csv @@ -0,0 +1,133595 @@ +10.039285 +0.108441 +0.089488 +0.078972 +0.069602 +0.059785 +0.051281 +0.044888 +0.041137 +0.038945 +0.036936 +0.03543 +0.033769 +0.032528 +0.031172 +0.02991 +0.028248 +0.02712 +0.025808 +0.025056 +0.024442 +0.023533 +0.022793 +0.022107 +0.021401 +0.020939 +0.020753 +0.020272 +0.019904 +0.019549 +0.019232 +0.019073 +0.019138 +0.019016 +0.019082 +0.019075 +0.018902 +0.019041 +0.019261 +0.019198 +0.019325 +0.019323 +0.019285 +0.019359 +0.019534 +0.019507 +0.000001 +0.019562 +0.019509 +0.019475 +0.019655 +0.019932 +0.019901 +0.019962 +0.019889 +0.019927 +0.020013 +0.020203 +0.020051 +0.019954 +0.019702 +0.019419 +0.019227 +0.019102 +0.018771 +0.018524 +0.01821 +0.017891 +0.017701 +0.017605 +0.017333 +0.017115 +0.016842 +0.016569 +0.01642 +0.01636 +0.016126 +0.015953 +0.015739 +0.015521 +0.015422 +0.015397 +0.015227 +0.015111 +0.014937 +0.014771 +0.014721 +0.014742 +0.014614 +0.014553 +0.014431 +0.01432 +0.014314 +0.014389 +0.014302 +0.014295 +0.014216 +0.014171 +0.014224 +0.014375 +0.014354 +0.014397 +0.014367 +0.014335 +0.014413 +0.014561 +0.014545 +0.014599 +0.014553 +0.014538 +0.014616 +0.000002 +0.014759 +0.014748 +0.014797 +0.014764 +0.01474 +0.014839 +0.014994 +0.01499 +0.015069 +0.015003 +0.01502 +0.015128 +0.015123 +0.015073 +0.015113 +0.015035 +0.014958 +0.014938 +0.014824 +0.014641 +0.014553 +0.014265 +0.014099 +0.013984 +0.013973 +0.013872 +0.013771 +0.013524 +0.013429 +0.013373 +0.013358 +0.013269 +0.013217 +0.01303 +0.012924 +0.012855 +0.012915 +0.012834 +0.012805 +0.0127 +0.012546 +0.012568 +0.012631 +0.012572 +0.012563 +0.01251 +0.012426 +0.01241 +0.01249 +0.012485 +0.012517 +0.012487 +0.012471 +0.01255 +0.012677 +0.01267 +0.012705 +0.012667 +0.012652 +0.012738 +0.01287 +0.012831 +0.000003 +0.012871 +0.012827 +0.012797 +0.012854 +0.012951 +0.012894 +0.012922 +0.012896 +0.012876 +0.01294 +0.013138 +0.013149 +0.013181 +0.013135 +0.013092 +0.013159 +0.01326 +0.013255 +0.013319 +0.01323 +0.013137 +0.013134 +0.013198 +0.013094 +0.013033 +0.012891 +0.012752 +0.01272 +0.012722 +0.012603 +0.012536 +0.012386 +0.012258 +0.012225 +0.012225 +0.012124 +0.012075 +0.011947 +0.011844 +0.011829 +0.01186 +0.011781 +0.011754 +0.011655 +0.011565 +0.011567 +0.011619 +0.011552 +0.011546 +0.011461 +0.011399 +0.011427 +0.011497 +0.011461 +0.011483 +0.011427 +0.01141 +0.011469 +0.01156 +0.011543 +0.011586 +0.01156 +0.01154 +0.011604 +0.011702 +0.011687 +0.011704 +0.011671 +0.011681 +0.000004 +0.011726 +0.011843 +0.011815 +0.011859 +0.011817 +0.011799 +0.011857 +0.011986 +0.011968 +0.012018 +0.011984 +0.011973 +0.012047 +0.012179 +0.012155 +0.01219 +0.012041 +0.012006 +0.012053 +0.012127 +0.012034 +0.011987 +0.011818 +0.011755 +0.011734 +0.011737 +0.011639 +0.011636 +0.01151 +0.011357 +0.011348 +0.011418 +0.011322 +0.011341 +0.011247 +0.011102 +0.011108 +0.011162 +0.011116 +0.011128 +0.011054 +0.011026 +0.010974 +0.011043 +0.010965 +0.011027 +0.010946 +0.010936 +0.010955 +0.011043 +0.010986 +0.01102 +0.010933 +0.010916 +0.010989 +0.011073 +0.011042 +0.011111 +0.011064 +0.011055 +0.011114 +0.011223 +0.011197 +0.011256 +0.000005 +0.011203 +0.011193 +0.01125 +0.011321 +0.01129 +0.011334 +0.011298 +0.011269 +0.011325 +0.011414 +0.011389 +0.011432 +0.011401 +0.01141 +0.011502 +0.011603 +0.011577 +0.011606 +0.011574 +0.01154 +0.011632 +0.011722 +0.011698 +0.011719 +0.011648 +0.011567 +0.011585 +0.011626 +0.011538 +0.011504 +0.011372 +0.011266 +0.011251 +0.011264 +0.011171 +0.011126 +0.011004 +0.010911 +0.010903 +0.010926 +0.010841 +0.010811 +0.010702 +0.010628 +0.010639 +0.010681 +0.010617 +0.010603 +0.01052 +0.010449 +0.010478 +0.010531 +0.010484 +0.01048 +0.010406 +0.010361 +0.010397 +0.010468 +0.010444 +0.010466 +0.010421 +0.010391 +0.010449 +0.010547 +0.010541 +0.010563 +0.010533 +0.010502 +0.01057 +0.010665 +0.010661 +0.010673 +0.000006 +0.010645 +0.010632 +0.010678 +0.010789 +0.010769 +0.010809 +0.010768 +0.010756 +0.010815 +0.010925 +0.010888 +0.010949 +0.010902 +0.010896 +0.010962 +0.011075 +0.011045 +0.011103 +0.011022 +0.010953 +0.010997 +0.011113 +0.011075 +0.011105 +0.011035 +0.010985 +0.011004 +0.011068 +0.010893 +0.010839 +0.010747 +0.010645 +0.010595 +0.010654 +0.010579 +0.010569 +0.010487 +0.010393 +0.010333 +0.010397 +0.010338 +0.010329 +0.010264 +0.010209 +0.010241 +0.010249 +0.010177 +0.010206 +0.010129 +0.010111 +0.010109 +0.010192 +0.010125 +0.010172 +0.010101 +0.010088 +0.010079 +0.010171 +0.010142 +0.010177 +0.010137 +0.010134 +0.010184 +0.010279 +0.010249 +0.010298 +0.010265 +0.010255 +0.010317 +0.010394 +0.000007 +0.010369 +0.010415 +0.010377 +0.010363 +0.01039 +0.010472 +0.010437 +0.010481 +0.010429 +0.010414 +0.010462 +0.010564 +0.010548 +0.01064 +0.010596 +0.010582 +0.010623 +0.010722 +0.010699 +0.01074 +0.01072 +0.010694 +0.010741 +0.010851 +0.010828 +0.010864 +0.010815 +0.010776 +0.010772 +0.010843 +0.01076 +0.010731 +0.010637 +0.010552 +0.010523 +0.010574 +0.010482 +0.010439 +0.010345 +0.010265 +0.010238 +0.010294 +0.01021 +0.010182 +0.010104 +0.010041 +0.010032 +0.010107 +0.01004 +0.010036 +0.009968 +0.009923 +0.009927 +0.010012 +0.00996 +0.009966 +0.009908 +0.009871 +0.009886 +0.009983 +0.009942 +0.009962 +0.009919 +0.009896 +0.009933 +0.010041 +0.010013 +0.010056 +0.010011 +0.01 +0.010042 +0.010143 +0.010126 +0.010156 +0.010125 +0.000008 +0.01011 +0.010153 +0.010253 +0.010227 +0.010278 +0.010229 +0.01022 +0.010268 +0.010377 +0.010351 +0.010386 +0.010346 +0.01034 +0.010392 +0.010499 +0.010483 +0.010519 +0.010486 +0.010474 +0.01054 +0.010614 +0.010541 +0.010583 +0.010556 +0.010548 +0.010576 +0.010633 +0.010574 +0.010599 +0.01052 +0.010423 +0.010364 +0.010411 +0.010337 +0.010348 +0.010264 +0.010209 +0.010129 +0.010146 +0.010072 +0.010082 +0.01001 +0.009975 +0.009961 +0.009977 +0.009905 +0.009926 +0.009872 +0.0098 +0.009792 +0.009845 +0.009805 +0.009835 +0.009784 +0.009758 +0.0098 +0.009879 +0.009839 +0.009862 +0.009783 +0.009743 +0.009799 +0.009894 +0.009848 +0.009891 +0.009869 +0.009851 +0.009909 +0.010008 +0.009973 +0.010012 +0.009987 +0.009955 +0.000009 +0.010022 +0.010128 +0.010094 +0.010128 +0.010083 +0.01007 +0.010105 +0.010198 +0.010155 +0.010183 +0.01014 +0.010115 +0.010173 +0.010292 +0.010311 +0.010356 +0.0103 +0.010285 +0.010332 +0.010428 +0.0104 +0.010436 +0.01041 +0.010397 +0.010432 +0.010516 +0.010456 +0.010472 +0.010371 +0.010301 +0.010297 +0.010332 +0.010248 +0.010229 +0.01012 +0.010046 +0.010035 +0.010075 +0.009999 +0.009997 +0.009908 +0.009841 +0.00985 +0.009905 +0.009839 +0.00985 +0.009782 +0.009727 +0.009736 +0.009805 +0.009756 +0.009776 +0.009711 +0.009667 +0.009686 +0.009759 +0.009714 +0.009746 +0.009691 +0.009658 +0.009692 +0.009782 +0.009739 +0.009791 +0.00975 +0.009731 +0.009779 +0.009873 +0.009847 +0.009896 +0.00984 +0.009836 +0.009891 +0.00001 +0.009973 +0.009956 +0.009984 +0.009964 +0.009949 +0.009994 +0.010086 +0.010066 +0.010099 +0.01006 +0.010046 +0.010106 +0.010192 +0.010178 +0.01022 +0.010163 +0.010156 +0.010218 +0.010304 +0.010296 +0.010336 +0.010296 +0.010287 +0.010362 +0.010458 +0.010434 +0.010481 +0.010352 +0.010315 +0.010363 +0.010427 +0.01036 +0.010348 +0.010212 +0.010146 +0.010136 +0.010161 +0.010102 +0.010096 +0.010011 +0.009915 +0.009902 +0.009947 +0.009913 +0.009905 +0.009837 +0.009789 +0.009754 +0.009815 +0.00976 +0.009792 +0.009734 +0.009693 +0.009734 +0.009795 +0.009749 +0.009714 +0.009689 +0.009638 +0.009702 +0.009766 +0.009747 +0.009771 +0.009735 +0.009695 +0.009712 +0.009807 +0.009784 +0.009815 +0.009803 +0.009786 +0.009845 +0.009929 +0.009914 +0.009947 +0.000011 +0.009918 +0.009903 +0.009959 +0.010057 +0.010028 +0.010069 +0.01003 +0.010015 +0.010062 +0.010161 +0.010114 +0.010145 +0.0101 +0.010083 +0.010126 +0.010226 +0.010199 +0.010283 +0.010254 +0.010235 +0.010268 +0.010381 +0.01034 +0.010379 +0.010331 +0.010339 +0.010379 +0.01047 +0.01042 +0.010409 +0.010325 +0.01028 +0.010271 +0.010309 +0.010239 +0.010221 +0.010116 +0.01005 +0.010035 +0.010073 +0.010005 +0.009992 +0.009897 +0.00984 +0.009836 +0.009895 +0.009831 +0.009837 +0.009763 +0.00972 +0.009726 +0.0098 +0.009751 +0.009761 +0.009701 +0.009668 +0.009674 +0.009753 +0.00972 +0.009733 +0.009682 +0.009669 +0.009677 +0.009766 +0.009753 +0.009786 +0.009749 +0.009734 +0.009772 +0.009874 +0.009845 +0.009892 +0.009875 +0.009817 +0.00988 +0.000012 +0.009981 +0.009958 +0.009997 +0.009963 +0.009945 +0.009989 +0.010088 +0.010068 +0.010105 +0.01006 +0.010045 +0.0101 +0.010197 +0.010174 +0.010218 +0.01018 +0.010165 +0.010222 +0.010329 +0.010296 +0.010343 +0.010302 +0.010287 +0.01035 +0.010461 +0.010418 +0.01044 +0.010368 +0.010355 +0.010405 +0.010502 +0.010453 +0.010509 +0.010467 +0.010451 +0.010504 +0.0106 +0.010588 +0.010634 +0.010585 +0.010566 +0.010618 +0.010728 +0.010714 +0.010759 +0.010711 +0.010699 +0.010755 +0.010859 +0.010841 +0.01088 +0.010836 +0.010835 +0.010888 +0.010991 +0.010965 +0.011009 +0.010969 +0.010973 +0.010998 +0.011065 +0.011025 +0.01107 +0.011031 +0.011022 +0.011086 +0.011191 +0.011158 +0.011204 +0.011161 +0.011151 +0.011211 +0.011314 +0.011288 +0.011332 +0.011289 +0.011273 +0.011332 +0.011437 +0.011413 +0.011456 +0.011412 +0.011395 +0.011452 +0.01156 +0.01153 +0.011577 +0.011534 +0.011519 +0.011579 +0.011687 +0.011655 +0.0117 +0.011658 +0.01164 +0.011704 +0.011811 +0.01178 +0.011829 +0.011777 +0.011766 +0.011829 +0.011936 +0.011904 +0.01195 +0.011905 +0.011889 +0.011952 +0.012067 +0.012032 +0.012081 +0.012031 +0.012017 +0.012083 +0.012202 +0.012161 +0.012209 +0.012164 +0.012152 +0.012211 +0.012331 +0.012299 +0.012347 +0.012296 +0.012293 +0.012354 +0.012474 +0.012438 +0.012484 +0.012442 +0.012429 +0.012487 +0.012613 +0.012576 +0.012635 +0.012573 +0.012568 +0.01263 +0.012758 +0.012724 +0.012769 +0.01272 +0.012701 +0.012774 +0.012901 +0.012863 +0.012913 +0.012859 +0.012852 +0.012924 +0.013045 +0.013015 +0.01306 +0.013014 +0.013003 +0.013066 +0.0132 +0.013155 +0.01321 +0.013162 +0.013149 +0.013223 +0.013353 +0.013316 +0.013365 +0.013324 +0.013313 +0.013369 +0.013505 +0.013468 +0.013517 +0.013471 +0.013457 +0.013529 +0.013663 +0.013634 +0.01369 +0.013639 +0.013628 +0.013712 +0.013843 +0.01381 +0.01387 +0.013834 +0.013832 +0.013925 +0.01406 +0.013993 +0.014011 +0.013956 +0.013964 +0.014039 +0.014173 +0.01415 +0.014202 +0.014169 +0.014061 +0.013996 +0.01408 +0.013967 +0.013921 +0.013669 +0.013488 +0.013324 +0.01332 +0.013107 +0.012871 +0.012695 +0.012488 +0.012341 +0.012313 +0.012195 +0.012106 +0.011896 +0.011756 +0.01169 +0.011694 +0.011596 +0.011539 +0.01136 +0.011258 +0.011214 +0.011248 +0.011165 +0.011156 +0.011012 +0.010965 +0.010922 +0.011029 +0.010972 +0.011008 +0.010954 +0.010944 +0.011006 +0.011121 +0.011097 +0.011148 +0.011097 +0.011086 +0.011152 +0.011257 +0.011228 +0.011249 +0.000013 +0.011194 +0.011172 +0.011243 +0.01134 +0.011312 +0.011351 +0.011313 +0.011282 +0.011336 +0.011436 +0.011414 +0.01147 +0.011484 +0.011469 +0.011533 +0.01162 +0.011604 +0.011631 +0.011591 +0.011552 +0.01163 +0.011733 +0.011682 +0.01166 +0.011579 +0.011498 +0.011481 +0.011504 +0.011401 +0.011349 +0.011226 +0.011113 +0.011076 +0.011095 +0.010992 +0.01095 +0.010831 +0.010726 +0.010713 +0.010735 +0.010653 +0.010631 +0.010539 +0.010461 +0.010461 +0.010505 +0.010437 +0.010431 +0.010357 +0.010293 +0.010311 +0.010361 +0.010316 +0.010326 +0.010268 +0.010226 +0.010267 +0.010345 +0.010316 +0.010357 +0.010324 +0.010295 +0.010361 +0.010449 +0.010437 +0.010458 +0.010436 +0.010423 +0.01047 +0.010575 +0.000014 +0.010555 +0.010588 +0.010545 +0.01052 +0.01057 +0.010687 +0.010675 +0.010718 +0.010672 +0.010653 +0.010716 +0.010815 +0.010796 +0.01085 +0.01081 +0.010812 +0.010866 +0.010974 +0.010963 +0.010909 +0.010823 +0.010815 +0.010852 +0.010915 +0.010835 +0.010842 +0.010711 +0.010551 +0.010549 +0.010597 +0.010501 +0.01051 +0.010351 +0.010273 +0.010259 +0.0103 +0.010232 +0.010245 +0.010128 +0.01006 +0.010025 +0.01011 +0.010044 +0.01007 +0.009989 +0.009941 +0.009897 +0.009966 +0.009906 +0.009957 +0.009877 +0.009856 +0.009878 +0.009942 +0.009893 +0.009911 +0.009852 +0.009813 +0.009855 +0.00995 +0.00991 +0.009953 +0.009931 +0.009916 +0.009965 +0.010065 +0.010042 +0.010085 +0.010047 +0.010034 +0.010092 +0.000015 +0.010187 +0.010152 +0.010195 +0.010158 +0.010115 +0.010136 +0.010228 +0.010196 +0.010237 +0.010202 +0.010191 +0.010258 +0.010402 +0.010386 +0.010413 +0.010367 +0.010349 +0.010384 +0.010492 +0.010461 +0.010521 +0.010481 +0.010466 +0.010484 +0.010562 +0.010511 +0.0105 +0.010398 +0.010351 +0.010317 +0.010362 +0.010288 +0.010259 +0.010148 +0.010084 +0.01007 +0.010104 +0.010041 +0.010039 +0.009932 +0.009888 +0.009889 +0.009941 +0.009887 +0.009894 +0.009814 +0.009779 +0.00979 +0.009852 +0.009807 +0.009818 +0.009756 +0.009727 +0.009752 +0.00983 +0.009802 +0.009819 +0.009776 +0.009771 +0.0098 +0.009893 +0.009879 +0.009911 +0.009877 +0.009862 +0.00991 +0.009995 +0.009993 +0.010023 +0.000016 +0.009984 +0.009968 +0.010013 +0.010119 +0.010097 +0.010134 +0.010094 +0.010083 +0.010132 +0.010226 +0.010203 +0.010246 +0.010205 +0.010189 +0.010251 +0.01035 +0.010327 +0.010374 +0.010335 +0.010326 +0.010398 +0.0105 +0.010464 +0.010489 +0.010381 +0.010371 +0.010415 +0.010487 +0.010426 +0.010426 +0.010345 +0.010224 +0.010185 +0.010229 +0.010171 +0.010177 +0.010082 +0.010033 +0.009987 +0.010001 +0.009954 +0.009964 +0.009879 +0.009848 +0.009837 +0.009873 +0.009796 +0.009826 +0.009756 +0.009726 +0.009723 +0.009792 +0.00974 +0.009773 +0.009714 +0.009688 +0.009677 +0.009761 +0.009715 +0.009768 +0.009719 +0.009706 +0.00977 +0.009854 +0.00983 +0.009876 +0.009833 +0.009818 +0.009875 +0.009958 +0.009914 +0.000017 +0.00995 +0.009922 +0.009906 +0.009965 +0.010058 +0.010035 +0.010064 +0.010041 +0.010009 +0.010041 +0.010116 +0.010091 +0.010117 +0.010092 +0.010072 +0.010128 +0.010261 +0.01027 +0.0103 +0.010256 +0.010229 +0.010281 +0.010379 +0.010359 +0.010382 +0.01036 +0.010353 +0.0104 +0.010496 +0.010473 +0.010496 +0.010446 +0.010369 +0.010368 +0.010403 +0.010318 +0.010281 +0.010184 +0.010088 +0.010076 +0.010115 +0.010034 +0.010013 +0.009936 +0.009853 +0.00986 +0.009919 +0.009846 +0.009838 +0.009771 +0.009703 +0.009717 +0.009788 +0.009738 +0.009736 +0.009688 +0.009635 +0.009646 +0.009727 +0.009686 +0.009692 +0.009652 +0.009609 +0.009635 +0.009712 +0.009696 +0.00972 +0.009692 +0.009663 +0.009708 +0.009804 +0.009784 +0.009824 +0.009802 +0.009757 +0.009812 +0.00991 +0.000018 +0.009896 +0.00993 +0.009893 +0.009874 +0.009923 +0.010024 +0.010001 +0.010037 +0.010001 +0.009987 +0.010035 +0.010131 +0.010111 +0.010147 +0.010106 +0.010095 +0.010142 +0.010237 +0.010221 +0.010266 +0.010226 +0.010215 +0.010271 +0.01038 +0.010355 +0.010401 +0.010379 +0.010368 +0.01035 +0.010386 +0.010329 +0.010356 +0.01028 +0.010225 +0.010234 +0.010297 +0.01022 +0.010093 +0.009982 +0.009928 +0.00995 +0.010004 +0.009937 +0.009943 +0.009787 +0.009736 +0.009773 +0.009828 +0.009783 +0.009757 +0.009681 +0.009648 +0.009667 +0.009748 +0.009686 +0.009729 +0.009647 +0.009606 +0.009584 +0.009683 +0.009636 +0.009672 +0.009636 +0.00961 +0.009665 +0.009758 +0.009715 +0.009768 +0.009738 +0.009718 +0.00971 +0.009795 +0.009769 +0.009814 +0.009778 +0.009765 +0.000019 +0.00983 +0.009909 +0.009907 +0.009928 +0.009907 +0.009886 +0.009947 +0.010041 +0.010021 +0.010049 +0.010012 +0.009989 +0.010039 +0.010125 +0.010107 +0.010133 +0.010099 +0.01009 +0.010166 +0.010262 +0.010247 +0.010272 +0.010234 +0.010208 +0.010272 +0.010373 +0.010359 +0.010383 +0.01036 +0.010331 +0.010388 +0.01047 +0.010437 +0.010439 +0.010352 +0.010274 +0.01028 +0.010308 +0.010233 +0.010207 +0.010106 +0.010024 +0.010028 +0.010062 +0.009999 +0.009993 +0.009912 +0.009852 +0.009863 +0.009918 +0.009857 +0.009863 +0.009795 +0.009741 +0.009776 +0.009839 +0.009794 +0.009801 +0.009749 +0.009703 +0.009743 +0.009813 +0.009783 +0.009797 +0.009752 +0.00972 +0.009771 +0.009855 +0.009838 +0.009871 +0.009833 +0.009811 +0.009869 +0.009958 +0.009949 +0.009985 +0.009932 +0.00002 +0.009926 +0.009974 +0.010059 +0.010066 +0.010086 +0.010058 +0.010025 +0.010088 +0.010178 +0.010174 +0.010195 +0.010168 +0.010141 +0.010203 +0.010286 +0.010281 +0.010307 +0.010273 +0.010245 +0.010323 +0.0104 +0.010407 +0.010429 +0.010406 +0.010384 +0.010458 +0.010557 +0.010558 +0.010585 +0.010503 +0.010418 +0.010473 +0.01052 +0.010473 +0.010451 +0.010321 +0.010215 +0.010179 +0.010203 +0.010149 +0.010128 +0.010034 +0.009916 +0.009917 +0.009971 +0.009921 +0.00991 +0.009866 +0.009774 +0.00977 +0.009803 +0.009785 +0.009777 +0.009745 +0.009687 +0.00975 +0.009811 +0.009793 +0.009787 +0.009692 +0.009662 +0.009698 +0.009774 +0.009748 +0.009762 +0.00974 +0.009717 +0.009787 +0.00986 +0.009854 +0.009857 +0.009812 +0.009789 +0.00987 +0.009952 +0.009921 +0.009954 +0.000021 +0.009924 +0.00991 +0.009966 +0.010068 +0.010037 +0.010067 +0.01004 +0.010016 +0.010081 +0.010166 +0.010123 +0.010149 +0.010114 +0.010083 +0.010139 +0.010228 +0.010212 +0.010233 +0.01022 +0.010243 +0.010308 +0.010403 +0.010372 +0.010401 +0.01037 +0.01033 +0.010389 +0.010474 +0.010483 +0.01051 +0.01045 +0.010389 +0.01038 +0.010425 +0.010367 +0.010337 +0.010233 +0.010165 +0.01016 +0.010191 +0.010131 +0.01012 +0.010012 +0.009963 +0.00997 +0.010008 +0.009957 +0.009951 +0.009872 +0.009823 +0.009846 +0.009911 +0.009869 +0.009865 +0.009803 +0.00977 +0.009793 +0.009868 +0.009837 +0.009845 +0.009793 +0.009766 +0.009801 +0.00989 +0.009881 +0.009896 +0.009859 +0.00984 +0.009888 +0.009984 +0.009983 +0.009998 +0.009966 +0.009944 +0.010004 +0.000022 +0.010095 +0.010085 +0.010106 +0.010091 +0.010058 +0.01012 +0.010204 +0.010196 +0.010221 +0.010202 +0.010172 +0.010232 +0.010322 +0.01032 +0.010344 +0.010307 +0.010287 +0.010354 +0.010446 +0.010438 +0.010479 +0.010447 +0.010425 +0.010514 +0.010599 +0.010527 +0.010529 +0.010495 +0.010444 +0.010497 +0.010534 +0.010469 +0.010399 +0.010294 +0.010224 +0.010248 +0.010239 +0.010165 +0.010171 +0.010112 +0.009978 +0.009973 +0.010026 +0.009968 +0.009968 +0.009925 +0.009866 +0.009879 +0.009882 +0.009836 +0.009856 +0.009818 +0.009774 +0.009828 +0.009889 +0.009843 +0.009816 +0.009755 +0.009736 +0.009791 +0.009844 +0.009838 +0.009852 +0.009826 +0.009824 +0.00986 +0.009909 +0.009903 +0.009928 +0.009913 +0.00988 +0.00995 +0.010053 +0.010021 +0.000023 +0.010057 +0.010024 +0.010012 +0.010075 +0.010175 +0.010131 +0.010171 +0.010137 +0.010114 +0.010161 +0.010233 +0.010192 +0.01022 +0.010189 +0.010164 +0.010226 +0.010319 +0.010357 +0.010398 +0.01037 +0.010338 +0.010391 +0.010479 +0.010463 +0.010491 +0.010436 +0.010424 +0.010503 +0.010592 +0.010551 +0.010558 +0.010474 +0.010401 +0.010397 +0.010425 +0.010353 +0.010329 +0.010226 +0.010147 +0.010153 +0.010185 +0.010117 +0.01011 +0.010022 +0.009957 +0.009971 +0.010022 +0.00997 +0.009981 +0.009904 +0.009851 +0.00988 +0.009934 +0.009894 +0.00991 +0.009845 +0.0098 +0.009836 +0.009903 +0.009875 +0.009887 +0.00985 +0.009812 +0.009857 +0.009934 +0.009923 +0.009959 +0.009918 +0.009904 +0.009949 +0.010036 +0.010034 +0.010062 +0.010034 +0.010002 +0.000024 +0.010065 +0.010156 +0.010146 +0.010164 +0.010149 +0.010119 +0.010178 +0.010268 +0.010257 +0.010292 +0.010262 +0.010228 +0.010294 +0.010382 +0.010381 +0.010404 +0.010386 +0.010351 +0.010439 +0.010529 +0.010511 +0.010553 +0.010537 +0.010515 +0.010515 +0.010539 +0.010524 +0.010552 +0.010498 +0.010444 +0.01047 +0.010522 +0.010462 +0.010443 +0.010256 +0.010159 +0.010192 +0.01025 +0.010184 +0.010106 +0.010029 +0.009982 +0.010007 +0.010031 +0.009998 +0.009978 +0.009927 +0.009835 +0.009868 +0.009922 +0.009894 +0.009901 +0.009864 +0.009819 +0.009893 +0.009954 +0.009946 +0.009924 +0.009855 +0.009834 +0.009895 +0.009986 +0.009975 +0.009996 +0.00997 +0.009957 +0.010023 +0.010105 +0.010087 +0.010122 +0.000025 +0.010099 +0.010069 +0.010122 +0.010181 +0.010163 +0.010193 +0.010174 +0.010146 +0.010213 +0.010293 +0.010283 +0.010303 +0.010277 +0.010237 +0.010295 +0.010379 +0.010387 +0.010453 +0.010435 +0.0104 +0.010456 +0.010537 +0.010521 +0.010546 +0.010513 +0.010496 +0.010571 +0.010661 +0.010637 +0.010658 +0.010608 +0.01053 +0.010539 +0.010563 +0.010489 +0.010447 +0.010353 +0.010254 +0.01025 +0.010283 +0.010223 +0.010195 +0.010123 +0.010044 +0.010064 +0.010106 +0.010062 +0.010053 +0.009992 +0.009924 +0.009958 +0.010006 +0.009972 +0.00998 +0.009929 +0.009868 +0.009915 +0.009972 +0.009945 +0.009968 +0.009926 +0.009879 +0.009926 +0.009993 +0.009982 +0.010017 +0.009989 +0.009952 +0.010019 +0.010095 +0.010082 +0.01012 +0.010065 +0.010069 +0.000026 +0.010128 +0.010207 +0.010206 +0.010217 +0.010195 +0.010173 +0.010242 +0.010319 +0.010312 +0.010337 +0.010319 +0.010296 +0.010353 +0.01044 +0.010433 +0.010459 +0.010432 +0.010398 +0.010481 +0.010564 +0.010569 +0.0106 +0.010569 +0.010552 +0.010642 +0.010719 +0.010642 +0.010651 +0.010626 +0.010568 +0.010553 +0.01057 +0.010518 +0.010507 +0.010432 +0.01034 +0.010265 +0.010285 +0.010227 +0.010211 +0.010152 +0.010083 +0.010084 +0.010089 +0.01002 +0.010028 +0.009967 +0.009864 +0.009875 +0.009927 +0.009916 +0.009909 +0.009874 +0.009842 +0.009879 +0.009972 +0.009914 +0.009889 +0.009841 +0.009803 +0.009882 +0.009943 +0.009932 +0.009961 +0.009932 +0.00991 +0.009971 +0.010029 +0.010007 +0.010058 +0.010022 +0.009999 +0.010066 +0.000027 +0.010152 +0.010138 +0.010169 +0.01014 +0.010093 +0.01013 +0.010215 +0.010199 +0.010231 +0.010211 +0.010184 +0.010245 +0.010333 +0.010318 +0.010346 +0.010346 +0.010333 +0.010398 +0.010484 +0.010473 +0.010489 +0.010458 +0.010427 +0.010513 +0.010597 +0.01059 +0.010609 +0.010596 +0.010551 +0.010588 +0.010641 +0.010579 +0.01054 +0.010452 +0.010349 +0.010334 +0.01036 +0.010286 +0.010239 +0.010165 +0.01007 +0.010068 +0.010109 +0.010049 +0.010025 +0.009966 +0.009893 +0.00991 +0.009961 +0.009913 +0.009902 +0.009851 +0.009791 +0.009822 +0.009871 +0.009837 +0.009829 +0.009795 +0.009739 +0.00978 +0.009852 +0.009826 +0.009824 +0.009808 +0.009763 +0.009816 +0.009905 +0.009897 +0.009912 +0.009899 +0.009858 +0.009933 +0.010002 +0.010007 +0.010043 +0.009991 +0.000028 +0.009979 +0.010032 +0.010112 +0.010116 +0.010143 +0.010116 +0.010087 +0.010148 +0.01023 +0.010227 +0.010256 +0.010228 +0.010199 +0.01026 +0.010353 +0.010341 +0.010371 +0.01034 +0.010331 +0.010395 +0.010479 +0.010487 +0.010511 +0.010492 +0.010478 +0.010482 +0.010501 +0.010472 +0.010495 +0.010424 +0.010359 +0.010387 +0.010426 +0.010341 +0.010183 +0.010115 +0.010063 +0.010086 +0.010123 +0.010075 +0.00999 +0.009898 +0.009855 +0.009881 +0.009931 +0.009858 +0.009855 +0.009773 +0.009729 +0.009755 +0.009817 +0.009765 +0.009796 +0.009737 +0.009715 +0.009753 +0.009809 +0.009772 +0.009776 +0.009776 +0.009713 +0.009753 +0.009836 +0.00981 +0.009834 +0.00982 +0.009795 +0.009862 +0.009944 +0.009941 +0.009968 +0.00995 +0.009908 +0.000029 +0.009978 +0.010071 +0.010049 +0.010086 +0.010059 +0.010044 +0.010069 +0.010129 +0.010106 +0.010143 +0.010111 +0.010088 +0.010138 +0.010228 +0.010215 +0.010272 +0.010272 +0.010247 +0.010299 +0.01039 +0.010363 +0.010386 +0.010361 +0.010339 +0.010413 +0.010497 +0.010488 +0.010506 +0.010469 +0.010424 +0.010427 +0.010476 +0.010416 +0.010389 +0.01029 +0.010218 +0.010213 +0.010247 +0.010184 +0.010163 +0.010078 +0.01001 +0.010015 +0.010064 +0.01001 +0.010007 +0.009938 +0.009877 +0.009899 +0.009965 +0.009927 +0.009932 +0.009879 +0.009828 +0.009855 +0.009936 +0.009903 +0.009918 +0.00987 +0.009839 +0.009872 +0.009955 +0.009946 +0.00997 +0.009936 +0.009921 +0.00996 +0.010056 +0.010043 +0.010098 +0.010032 +0.010026 +0.00003 +0.010081 +0.010162 +0.010156 +0.010186 +0.01016 +0.010136 +0.010194 +0.010277 +0.010271 +0.010298 +0.010275 +0.010246 +0.010314 +0.010398 +0.010391 +0.010428 +0.010389 +0.01037 +0.010437 +0.010544 +0.010528 +0.010564 +0.010549 +0.010534 +0.010528 +0.01055 +0.010517 +0.01053 +0.010469 +0.010403 +0.010438 +0.01048 +0.010405 +0.010256 +0.010185 +0.010132 +0.010165 +0.010208 +0.01017 +0.010093 +0.010003 +0.009963 +0.009989 +0.010048 +0.009983 +0.009983 +0.009905 +0.009852 +0.009873 +0.009925 +0.009905 +0.009892 +0.009872 +0.009827 +0.009895 +0.009981 +0.009946 +0.009973 +0.009894 +0.009854 +0.009909 +0.009984 +0.009978 +0.010006 +0.009976 +0.009953 +0.010031 +0.010122 +0.010088 +0.010128 +0.000031 +0.0101 +0.010086 +0.010121 +0.010193 +0.010167 +0.010214 +0.01018 +0.010165 +0.010229 +0.010321 +0.0103 +0.010336 +0.010301 +0.010281 +0.010336 +0.010419 +0.010379 +0.010412 +0.010378 +0.010356 +0.010406 +0.010499 +0.010493 +0.010566 +0.010545 +0.01052 +0.010569 +0.01066 +0.010638 +0.010657 +0.010622 +0.010594 +0.010639 +0.010691 +0.010606 +0.010577 +0.010486 +0.010393 +0.010375 +0.010421 +0.010341 +0.01031 +0.010228 +0.01015 +0.01014 +0.010199 +0.010133 +0.010113 +0.010052 +0.009988 +0.009997 +0.010049 +0.009997 +0.010002 +0.009954 +0.009898 +0.009909 +0.009988 +0.009938 +0.009945 +0.009907 +0.009852 +0.009888 +0.009968 +0.009933 +0.009954 +0.009926 +0.009899 +0.009938 +0.01004 +0.010015 +0.010047 +0.010027 +0.01 +0.010055 +0.010141 +0.010138 +0.000032 +0.010154 +0.010129 +0.010112 +0.010162 +0.010263 +0.010241 +0.010279 +0.010243 +0.010228 +0.010278 +0.010369 +0.010356 +0.010401 +0.010355 +0.010346 +0.010402 +0.010502 +0.010488 +0.010539 +0.010493 +0.010497 +0.010561 +0.010668 +0.010579 +0.010598 +0.010553 +0.010546 +0.010555 +0.010609 +0.010541 +0.010544 +0.010455 +0.010334 +0.010307 +0.010346 +0.010281 +0.010294 +0.010215 +0.010146 +0.0101 +0.010134 +0.010084 +0.010102 +0.010027 +0.009999 +0.010019 +0.010103 +0.010009 +0.010017 +0.009931 +0.009916 +0.009944 +0.010039 +0.009979 +0.010031 +0.009943 +0.009928 +0.009945 +0.01005 +0.010003 +0.010054 +0.01003 +0.010014 +0.01007 +0.010177 +0.010142 +0.010177 +0.010155 +0.010138 +0.000033 +0.010196 +0.010276 +0.010234 +0.010282 +0.010249 +0.010234 +0.010255 +0.010341 +0.010312 +0.010363 +0.010319 +0.010309 +0.010356 +0.01045 +0.010428 +0.010469 +0.010453 +0.010458 +0.010511 +0.010609 +0.01058 +0.010612 +0.010568 +0.010577 +0.010617 +0.01073 +0.010692 +0.010739 +0.010684 +0.010647 +0.010628 +0.010692 +0.010604 +0.010578 +0.010477 +0.010398 +0.010377 +0.010425 +0.010341 +0.010327 +0.010238 +0.010171 +0.010165 +0.010226 +0.010161 +0.010155 +0.010084 +0.010026 +0.010033 +0.010113 +0.010064 +0.01007 +0.01001 +0.009968 +0.00998 +0.010063 +0.010021 +0.010038 +0.009987 +0.009951 +0.009977 +0.010069 +0.010038 +0.010074 +0.010039 +0.010016 +0.01006 +0.010164 +0.010129 +0.010184 +0.010149 +0.010127 +0.010175 +0.010273 +0.000034 +0.010251 +0.010286 +0.010256 +0.010245 +0.010295 +0.010399 +0.010364 +0.010408 +0.010357 +0.010346 +0.010403 +0.010507 +0.010484 +0.010525 +0.010486 +0.010474 +0.010524 +0.010627 +0.010607 +0.010655 +0.010605 +0.010588 +0.010644 +0.010752 +0.010726 +0.010774 +0.010717 +0.010703 +0.010757 +0.010855 +0.010813 +0.010854 +0.010809 +0.010793 +0.010845 +0.010941 +0.010909 +0.010957 +0.010916 +0.010908 +0.010961 +0.011056 +0.011029 +0.011077 +0.011034 +0.011024 +0.011073 +0.01118 +0.011154 +0.011199 +0.011159 +0.011149 +0.011201 +0.011316 +0.011272 +0.011329 +0.011285 +0.011269 +0.01133 +0.011434 +0.011402 +0.011452 +0.011403 +0.011396 +0.011454 +0.01156 +0.011527 +0.011574 +0.01153 +0.011515 +0.011572 +0.011681 +0.011642 +0.011686 +0.011641 +0.011625 +0.011688 +0.011794 +0.01176 +0.01181 +0.011765 +0.011755 +0.011814 +0.011929 +0.011896 +0.011948 +0.0119 +0.01189 +0.011955 +0.01207 +0.012039 +0.012088 +0.012042 +0.012028 +0.012085 +0.012205 +0.012166 +0.012215 +0.012169 +0.012152 +0.012216 +0.012332 +0.012299 +0.012346 +0.0123 +0.012286 +0.012339 +0.012464 +0.012438 +0.012483 +0.012437 +0.01242 +0.012482 +0.012605 +0.01258 +0.012626 +0.012578 +0.012572 +0.012621 +0.012752 +0.012727 +0.012778 +0.012728 +0.012713 +0.012775 +0.012904 +0.012877 +0.012928 +0.012877 +0.012862 +0.012927 +0.01305 +0.013025 +0.01308 +0.013013 +0.013005 +0.01307 +0.013193 +0.013168 +0.013219 +0.01317 +0.013151 +0.013219 +0.013347 +0.013321 +0.013374 +0.013322 +0.013307 +0.013373 +0.013503 +0.01348 +0.01353 +0.013478 +0.013463 +0.013534 +0.013665 +0.013641 +0.013695 +0.013642 +0.013625 +0.013699 +0.013831 +0.013802 +0.013863 +0.013809 +0.013793 +0.013864 +0.014008 +0.013969 +0.014028 +0.013976 +0.013957 +0.014031 +0.014171 +0.014133 +0.014189 +0.014137 +0.014127 +0.014207 +0.014328 +0.014312 +0.014368 +0.014326 +0.014299 +0.014379 +0.014521 +0.014485 +0.014557 +0.014496 +0.014484 +0.014555 +0.0147 +0.014673 +0.014733 +0.014683 +0.014676 +0.014765 +0.014916 +0.014882 +0.014949 +0.014903 +0.014894 +0.014981 +0.015143 +0.015084 +0.0151 +0.015041 +0.015044 +0.015147 +0.015301 +0.015254 +0.015319 +0.015307 +0.015263 +0.015298 +0.01542 +0.015329 +0.01532 +0.015178 +0.014998 +0.014778 +0.01478 +0.014581 +0.014461 +0.014028 +0.013808 +0.013653 +0.013577 +0.013382 +0.013235 +0.012996 +0.012831 +0.01271 +0.012661 +0.012545 +0.012496 +0.01231 +0.012104 +0.012045 +0.012092 +0.011963 +0.011863 +0.011703 +0.011631 +0.01161 +0.011638 +0.011537 +0.011573 +0.011453 +0.011374 +0.011402 +0.011488 +0.011472 +0.011516 +0.011481 +0.011475 +0.011542 +0.011655 +0.01162 +0.011674 +0.01164 +0.011623 +0.011629 +0.011729 +0.011701 +0.000035 +0.01176 +0.011704 +0.011694 +0.011752 +0.011868 +0.011841 +0.011939 +0.011909 +0.011891 +0.01194 +0.012052 +0.012021 +0.012074 +0.012039 +0.012034 +0.012085 +0.012203 +0.012166 +0.012212 +0.012133 +0.01206 +0.012056 +0.012094 +0.011971 +0.011922 +0.01177 +0.011643 +0.011602 +0.011618 +0.01149 +0.011443 +0.011305 +0.011205 +0.011176 +0.011209 +0.011111 +0.01109 +0.010963 +0.010889 +0.010884 +0.010939 +0.010852 +0.010849 +0.010754 +0.01068 +0.010688 +0.010748 +0.010678 +0.010694 +0.010621 +0.010559 +0.010579 +0.010672 +0.010633 +0.010671 +0.010627 +0.010606 +0.010657 +0.010753 +0.010739 +0.010792 +0.010746 +0.010726 +0.010782 +0.010897 +0.010846 +0.000036 +0.010889 +0.010871 +0.010858 +0.010908 +0.011011 +0.010991 +0.011023 +0.010986 +0.01096 +0.01102 +0.011129 +0.011119 +0.011143 +0.011123 +0.011108 +0.011179 +0.011297 +0.011255 +0.011321 +0.011291 +0.011278 +0.011237 +0.011264 +0.011193 +0.011194 +0.011122 +0.011022 +0.01101 +0.010942 +0.010843 +0.010849 +0.010757 +0.010606 +0.010578 +0.010607 +0.010526 +0.010532 +0.01045 +0.010343 +0.010299 +0.010314 +0.010273 +0.010267 +0.010212 +0.010164 +0.010193 +0.010202 +0.010116 +0.010148 +0.01009 +0.010019 +0.010018 +0.010075 +0.010053 +0.010071 +0.01005 +0.010021 +0.010085 +0.010174 +0.010139 +0.010179 +0.010159 +0.010137 +0.010203 +0.0103 +0.010275 +0.010301 +0.010232 +0.000037 +0.010223 +0.010253 +0.010361 +0.010321 +0.01037 +0.010328 +0.010321 +0.010381 +0.010483 +0.010451 +0.010486 +0.010444 +0.010422 +0.010471 +0.010572 +0.010543 +0.010603 +0.010588 +0.010574 +0.010619 +0.01072 +0.010697 +0.010727 +0.01069 +0.010688 +0.010739 +0.010845 +0.010801 +0.010827 +0.010739 +0.010673 +0.010652 +0.010685 +0.010599 +0.010564 +0.010453 +0.010379 +0.010356 +0.010398 +0.010321 +0.010304 +0.010205 +0.010153 +0.010147 +0.01019 +0.010134 +0.010129 +0.010037 +0.009996 +0.010008 +0.010069 +0.010026 +0.010024 +0.009955 +0.009924 +0.009937 +0.010011 +0.009979 +0.009994 +0.009926 +0.009912 +0.009941 +0.010029 +0.010012 +0.010043 +0.009994 +0.009989 +0.010028 +0.010131 +0.010109 +0.010155 +0.010109 +0.010091 +0.010143 +0.000038 +0.010237 +0.010227 +0.010259 +0.010224 +0.010204 +0.01026 +0.010358 +0.010339 +0.010371 +0.010344 +0.010323 +0.010384 +0.010484 +0.010447 +0.010487 +0.010454 +0.010427 +0.010488 +0.010585 +0.010574 +0.010612 +0.010581 +0.010552 +0.010632 +0.010734 +0.010721 +0.010763 +0.010706 +0.010593 +0.010618 +0.01067 +0.010617 +0.010608 +0.010515 +0.010372 +0.010313 +0.01035 +0.010301 +0.010287 +0.010212 +0.010145 +0.010072 +0.010112 +0.010056 +0.010064 +0.010013 +0.009944 +0.00996 +0.009965 +0.009937 +0.00994 +0.00991 +0.00982 +0.009819 +0.009872 +0.009846 +0.00986 +0.009831 +0.009793 +0.009826 +0.009924 +0.00988 +0.009904 +0.009823 +0.009784 +0.009846 +0.009936 +0.009901 +0.009948 +0.009924 +0.009895 +0.00996 +0.01005 +0.010031 +0.010074 +0.010028 +0.000039 +0.010013 +0.010089 +0.01017 +0.010151 +0.01017 +0.010128 +0.010094 +0.010167 +0.010225 +0.010206 +0.010226 +0.010205 +0.010164 +0.010237 +0.010323 +0.010332 +0.010395 +0.010379 +0.010329 +0.010386 +0.010479 +0.010467 +0.010483 +0.010471 +0.01045 +0.010521 +0.010587 +0.010561 +0.010554 +0.010488 +0.010395 +0.010396 +0.010414 +0.010344 +0.01031 +0.010216 +0.010128 +0.010128 +0.010155 +0.010094 +0.010075 +0.009996 +0.009919 +0.009937 +0.00997 +0.009926 +0.009922 +0.00985 +0.009794 +0.009831 +0.009875 +0.009845 +0.009845 +0.009795 +0.009748 +0.009787 +0.009853 +0.009821 +0.009833 +0.0098 +0.00977 +0.009816 +0.009893 +0.009876 +0.009899 +0.009878 +0.009857 +0.009916 +0.01 +0.009988 +0.010025 +0.009958 +0.00004 +0.009951 +0.01001 +0.010113 +0.010105 +0.010123 +0.01009 +0.010062 +0.010122 +0.010212 +0.010212 +0.010236 +0.010206 +0.010181 +0.010244 +0.010329 +0.01032 +0.010339 +0.010312 +0.010296 +0.010351 +0.010441 +0.010442 +0.010464 +0.010445 +0.010415 +0.010493 +0.010589 +0.010574 +0.010618 +0.010595 +0.01057 +0.010533 +0.010575 +0.010544 +0.010552 +0.010481 +0.010406 +0.010434 +0.010477 +0.010422 +0.01026 +0.010164 +0.010103 +0.010142 +0.010169 +0.010122 +0.010114 +0.009977 +0.009912 +0.009907 +0.009946 +0.009898 +0.009898 +0.009862 +0.009806 +0.009841 +0.009841 +0.00981 +0.009806 +0.009787 +0.009738 +0.009776 +0.009821 +0.009769 +0.0098 +0.009772 +0.009735 +0.009779 +0.009835 +0.009804 +0.009838 +0.009832 +0.009794 +0.009863 +0.009944 +0.009938 +0.009964 +0.009946 +0.009916 +0.009985 +0.000041 +0.010076 +0.010053 +0.010086 +0.01006 +0.010032 +0.010037 +0.01012 +0.010095 +0.010137 +0.010107 +0.010088 +0.010147 +0.010237 +0.010219 +0.01027 +0.01026 +0.010245 +0.010295 +0.010384 +0.010363 +0.010391 +0.010357 +0.010325 +0.010382 +0.010504 +0.010482 +0.010514 +0.01048 +0.010465 +0.010497 +0.010577 +0.01053 +0.0105 +0.010396 +0.010319 +0.010295 +0.010341 +0.010253 +0.010214 +0.010128 +0.010052 +0.010045 +0.010089 +0.010032 +0.010009 +0.009935 +0.009879 +0.009895 +0.009952 +0.009892 +0.009894 +0.009846 +0.009797 +0.009808 +0.00988 +0.009845 +0.009849 +0.009805 +0.009746 +0.009781 +0.009862 +0.009828 +0.009855 +0.009814 +0.009788 +0.009821 +0.00992 +0.009906 +0.009936 +0.009909 +0.009879 +0.009938 +0.010021 +0.010014 +0.010048 +0.000042 +0.010005 +0.01 +0.010044 +0.010139 +0.010118 +0.01016 +0.010123 +0.010111 +0.010155 +0.010258 +0.010235 +0.010273 +0.010232 +0.010222 +0.010275 +0.010378 +0.010355 +0.010405 +0.01036 +0.010359 +0.010413 +0.010529 +0.010496 +0.010549 +0.010497 +0.010404 +0.010444 +0.010539 +0.01051 +0.010535 +0.010459 +0.010422 +0.010447 +0.010516 +0.010414 +0.010302 +0.010225 +0.010176 +0.010192 +0.010249 +0.010165 +0.010116 +0.009996 +0.009941 +0.009976 +0.010034 +0.009956 +0.009927 +0.009827 +0.009815 +0.009834 +0.009906 +0.009834 +0.009875 +0.009782 +0.009745 +0.009755 +0.009817 +0.009791 +0.009821 +0.009769 +0.009771 +0.009812 +0.009908 +0.009885 +0.009923 +0.009882 +0.009869 +0.009925 +0.010031 +0.010004 +0.010035 +0.000043 +0.01 +0.009958 +0.009967 +0.010064 +0.010038 +0.01009 +0.010056 +0.010047 +0.010101 +0.010204 +0.010179 +0.010222 +0.010176 +0.010162 +0.010208 +0.010303 +0.010283 +0.01034 +0.010312 +0.010292 +0.010334 +0.010433 +0.010407 +0.010467 +0.010419 +0.010403 +0.010458 +0.010553 +0.010538 +0.010581 +0.010518 +0.010487 +0.010488 +0.010533 +0.010458 +0.010434 +0.010322 +0.010248 +0.010224 +0.01025 +0.01018 +0.010169 +0.010058 +0.010005 +0.009998 +0.01004 +0.009981 +0.00998 +0.009894 +0.009852 +0.009856 +0.009922 +0.009852 +0.009873 +0.009801 +0.009762 +0.009778 +0.009846 +0.009806 +0.009821 +0.009763 +0.009743 +0.009761 +0.009839 +0.009813 +0.009848 +0.009801 +0.009789 +0.009825 +0.009923 +0.009913 +0.009935 +0.009924 +0.009875 +0.009941 +0.010033 +0.000044 +0.010015 +0.01005 +0.010016 +0.010007 +0.01005 +0.010145 +0.010124 +0.010165 +0.010126 +0.010119 +0.01016 +0.01026 +0.010235 +0.010276 +0.010233 +0.010217 +0.010266 +0.010358 +0.010342 +0.010386 +0.01035 +0.010343 +0.010392 +0.010502 +0.010484 +0.010532 +0.010495 +0.010486 +0.010551 +0.010555 +0.010443 +0.01044 +0.010356 +0.010272 +0.01019 +0.010232 +0.010152 +0.010166 +0.010086 +0.01002 +0.009952 +0.009985 +0.009901 +0.009934 +0.009851 +0.009812 +0.0098 +0.009836 +0.00976 +0.009805 +0.009741 +0.009712 +0.00968 +0.009763 +0.009705 +0.009753 +0.009695 +0.009668 +0.009712 +0.009788 +0.009752 +0.009789 +0.009695 +0.009679 +0.009726 +0.009805 +0.009768 +0.009826 +0.009777 +0.009771 +0.00983 +0.00993 +0.00989 +0.009933 +0.0099 +0.000045 +0.009892 +0.009959 +0.010057 +0.010016 +0.010051 +0.009993 +0.009967 +0.010019 +0.010106 +0.010078 +0.010116 +0.010079 +0.010054 +0.010111 +0.0102 +0.010181 +0.010219 +0.010186 +0.010185 +0.010265 +0.010356 +0.010338 +0.010363 +0.010329 +0.0103 +0.01034 +0.010464 +0.010445 +0.010477 +0.010425 +0.010375 +0.010391 +0.010427 +0.010357 +0.010317 +0.010221 +0.010129 +0.010133 +0.010144 +0.010075 +0.010055 +0.00997 +0.009884 +0.009894 +0.009943 +0.009873 +0.009873 +0.009818 +0.009764 +0.009761 +0.009831 +0.009777 +0.009794 +0.00975 +0.009706 +0.009728 +0.009791 +0.009746 +0.00977 +0.009738 +0.009703 +0.009738 +0.009815 +0.009778 +0.009804 +0.009754 +0.009748 +0.009809 +0.009899 +0.009875 +0.009911 +0.009863 +0.009852 +0.009907 +0.010018 +0.000046 +0.009973 +0.010013 +0.009978 +0.009967 +0.010017 +0.010113 +0.010088 +0.010124 +0.010097 +0.010083 +0.010127 +0.010225 +0.010202 +0.010238 +0.010195 +0.010187 +0.010234 +0.010333 +0.010317 +0.01036 +0.010318 +0.010317 +0.01037 +0.010473 +0.010466 +0.010504 +0.010477 +0.010424 +0.010375 +0.010435 +0.010374 +0.010383 +0.010288 +0.010232 +0.010238 +0.010221 +0.010085 +0.01008 +0.009983 +0.009895 +0.009869 +0.009927 +0.009865 +0.009858 +0.009794 +0.009688 +0.009695 +0.009743 +0.009707 +0.009713 +0.009667 +0.009617 +0.009668 +0.009708 +0.009663 +0.009669 +0.009593 +0.009575 +0.009592 +0.009672 +0.00964 +0.009663 +0.009628 +0.009616 +0.009659 +0.009749 +0.009727 +0.009753 +0.009694 +0.009675 +0.009734 +0.009834 +0.009791 +0.009831 +0.009806 +0.000047 +0.009784 +0.009845 +0.00995 +0.009913 +0.009957 +0.009925 +0.009913 +0.009927 +0.010017 +0.009975 +0.010017 +0.009979 +0.009963 +0.010008 +0.010105 +0.010082 +0.010125 +0.010116 +0.010118 +0.010161 +0.010257 +0.010233 +0.010266 +0.010221 +0.010204 +0.010271 +0.010368 +0.010349 +0.010377 +0.010333 +0.010304 +0.010298 +0.010353 +0.01028 +0.010252 +0.010148 +0.010074 +0.010047 +0.010086 +0.010008 +0.009989 +0.009892 +0.009834 +0.009822 +0.009874 +0.009813 +0.009809 +0.009731 +0.009684 +0.009683 +0.009748 +0.009696 +0.009711 +0.009631 +0.009601 +0.009609 +0.009682 +0.009644 +0.009659 +0.009611 +0.009588 +0.009611 +0.009688 +0.009662 +0.009698 +0.009661 +0.00965 +0.009685 +0.009785 +0.009755 +0.009789 +0.009771 +0.009748 +0.00979 +0.009897 +0.000048 +0.009863 +0.009899 +0.009861 +0.009847 +0.009901 +0.010001 +0.009978 +0.010013 +0.009969 +0.009955 +0.010007 +0.010112 +0.010085 +0.010125 +0.010084 +0.010066 +0.010118 +0.010221 +0.010191 +0.010248 +0.010199 +0.010201 +0.01025 +0.010357 +0.010339 +0.010384 +0.010341 +0.010248 +0.010266 +0.01035 +0.010295 +0.010296 +0.010209 +0.010155 +0.010166 +0.01012 +0.010012 +0.009999 +0.009927 +0.009855 +0.009782 +0.00984 +0.009762 +0.00978 +0.009693 +0.009651 +0.009635 +0.009664 +0.009598 +0.009623 +0.009551 +0.009524 +0.009491 +0.009566 +0.009507 +0.009548 +0.009485 +0.009458 +0.009509 +0.00958 +0.009516 +0.009525 +0.009464 +0.009442 +0.009507 +0.009596 +0.009549 +0.009597 +0.009562 +0.009546 +0.009588 +0.009686 +0.009646 +0.009686 +0.009648 +0.009633 +0.009701 +0.000049 +0.00979 +0.009762 +0.009793 +0.009763 +0.009726 +0.009754 +0.009839 +0.009821 +0.00986 +0.009825 +0.009808 +0.009862 +0.009947 +0.009929 +0.00997 +0.009965 +0.009954 +0.010005 +0.010096 +0.010069 +0.010101 +0.010054 +0.010039 +0.01011 +0.010199 +0.010186 +0.010211 +0.010183 +0.010159 +0.010176 +0.010234 +0.010182 +0.010157 +0.010063 +0.009989 +0.009973 +0.010005 +0.009941 +0.009912 +0.009829 +0.009769 +0.009753 +0.009808 +0.009749 +0.009738 +0.009674 +0.009617 +0.009627 +0.009694 +0.009645 +0.009635 +0.009579 +0.009546 +0.00956 +0.009623 +0.009587 +0.009604 +0.009559 +0.009524 +0.009552 +0.009632 +0.009613 +0.009633 +0.009604 +0.009586 +0.009629 +0.009719 +0.009701 +0.009721 +0.009713 +0.009683 +0.009741 +0.009827 +0.00005 +0.009805 +0.00984 +0.009793 +0.009781 +0.009847 +0.009933 +0.009916 +0.009951 +0.009904 +0.009896 +0.009936 +0.010043 +0.010021 +0.01006 +0.010012 +0.010002 +0.010051 +0.010144 +0.010122 +0.010171 +0.010121 +0.010123 +0.010172 +0.010278 +0.010263 +0.010302 +0.010263 +0.010262 +0.010333 +0.01035 +0.010255 +0.010261 +0.010194 +0.010137 +0.010082 +0.01009 +0.01001 +0.010014 +0.009921 +0.009842 +0.009781 +0.009817 +0.009738 +0.009756 +0.009687 +0.009629 +0.009603 +0.009629 +0.009565 +0.009597 +0.009534 +0.009513 +0.009503 +0.009557 +0.009484 +0.009542 +0.009467 +0.009472 +0.009498 +0.009586 +0.009527 +0.009521 +0.009463 +0.009454 +0.00951 +0.009605 +0.009561 +0.009601 +0.009571 +0.009554 +0.009607 +0.009703 +0.009675 +0.009726 +0.009681 +0.000051 +0.009651 +0.009704 +0.009777 +0.00975 +0.009788 +0.009769 +0.009751 +0.009815 +0.00989 +0.009865 +0.009904 +0.009873 +0.009852 +0.009907 +0.009981 +0.009947 +0.009973 +0.009934 +0.009915 +0.009966 +0.01005 +0.010035 +0.010084 +0.010089 +0.010074 +0.010134 +0.010213 +0.010199 +0.010218 +0.010165 +0.010127 +0.010137 +0.010217 +0.010146 +0.010111 +0.010019 +0.009944 +0.009919 +0.00996 +0.009895 +0.009865 +0.009788 +0.009722 +0.009712 +0.009767 +0.00971 +0.009687 +0.009626 +0.009572 +0.009576 +0.009641 +0.009597 +0.009596 +0.009545 +0.009502 +0.009518 +0.009587 +0.009552 +0.009556 +0.00952 +0.009484 +0.009509 +0.009582 +0.009552 +0.00957 +0.009548 +0.009519 +0.00956 +0.009654 +0.009625 +0.009648 +0.009629 +0.009613 +0.009669 +0.009749 +0.009735 +0.000052 +0.009757 +0.009726 +0.009709 +0.009763 +0.009864 +0.009835 +0.00987 +0.009835 +0.009824 +0.009867 +0.009967 +0.009946 +0.009987 +0.009947 +0.009933 +0.009979 +0.010068 +0.010058 +0.010093 +0.010048 +0.010047 +0.010092 +0.010199 +0.010183 +0.010217 +0.010187 +0.01019 +0.010254 +0.010349 +0.010249 +0.010266 +0.010202 +0.010156 +0.010103 +0.010147 +0.010069 +0.010067 +0.009968 +0.009835 +0.009813 +0.009877 +0.009804 +0.009802 +0.009726 +0.009616 +0.009599 +0.009666 +0.009605 +0.009616 +0.009562 +0.009517 +0.009504 +0.009539 +0.009501 +0.009516 +0.009482 +0.009444 +0.009487 +0.009546 +0.009504 +0.00953 +0.009448 +0.009451 +0.00948 +0.009568 +0.009537 +0.009569 +0.009542 +0.009537 +0.009578 +0.00968 +0.009644 +0.009694 +0.009643 +0.00963 +0.000053 +0.009671 +0.009753 +0.009712 +0.009756 +0.009723 +0.009711 +0.009767 +0.009864 +0.009837 +0.00987 +0.009838 +0.009817 +0.00987 +0.00995 +0.009923 +0.009949 +0.009913 +0.009895 +0.009943 +0.010039 +0.010057 +0.010097 +0.010062 +0.010033 +0.010082 +0.010175 +0.010155 +0.010185 +0.01016 +0.010114 +0.010113 +0.010155 +0.010089 +0.010059 +0.009968 +0.009883 +0.009869 +0.009902 +0.009829 +0.009799 +0.00972 +0.009646 +0.009643 +0.009693 +0.009633 +0.009608 +0.009552 +0.009481 +0.009497 +0.009569 +0.009505 +0.009518 +0.009467 +0.009422 +0.009436 +0.009507 +0.009477 +0.009484 +0.009443 +0.009406 +0.009432 +0.009513 +0.00949 +0.009518 +0.009485 +0.009458 +0.0095 +0.009591 +0.009574 +0.009613 +0.009582 +0.009558 +0.009598 +0.009697 +0.000054 +0.009674 +0.009722 +0.009682 +0.009663 +0.009701 +0.009805 +0.009782 +0.009827 +0.009787 +0.009771 +0.00981 +0.009908 +0.009891 +0.009932 +0.009887 +0.009877 +0.009925 +0.01002 +0.009999 +0.010048 +0.010001 +0.010004 +0.010056 +0.010156 +0.010139 +0.010189 +0.010152 +0.010068 +0.01006 +0.010126 +0.010069 +0.010073 +0.009987 +0.00994 +0.009944 +0.009933 +0.009822 +0.009821 +0.009741 +0.009657 +0.009637 +0.009686 +0.009601 +0.009626 +0.009568 +0.009518 +0.009543 +0.009542 +0.009482 +0.009504 +0.009453 +0.00943 +0.00944 +0.009499 +0.009429 +0.009459 +0.00941 +0.009395 +0.009433 +0.009473 +0.009433 +0.009476 +0.009431 +0.009427 +0.009485 +0.009568 +0.009536 +0.00959 +0.009546 +0.009541 +0.009587 +0.009685 +0.009655 +0.000055 +0.009687 +0.009635 +0.009609 +0.009659 +0.009732 +0.009712 +0.009752 +0.009718 +0.009701 +0.009761 +0.009843 +0.00982 +0.009848 +0.009809 +0.00979 +0.00984 +0.009941 +0.009951 +0.009993 +0.00995 +0.009925 +0.00998 +0.010067 +0.01005 +0.010082 +0.01007 +0.010034 +0.010097 +0.010176 +0.010154 +0.010183 +0.010116 +0.010039 +0.010047 +0.010063 +0.009983 +0.009958 +0.00985 +0.009762 +0.009761 +0.009787 +0.009713 +0.009703 +0.009613 +0.009535 +0.009546 +0.009582 +0.009524 +0.009523 +0.009456 +0.009399 +0.009418 +0.009478 +0.009424 +0.00944 +0.009391 +0.009337 +0.009356 +0.009418 +0.009386 +0.009404 +0.009356 +0.009319 +0.009359 +0.009434 +0.009403 +0.009448 +0.009397 +0.009381 +0.009436 +0.009514 +0.009514 +0.009522 +0.009506 +0.009483 +0.009537 +0.009619 +0.000056 +0.009603 +0.009638 +0.009607 +0.009596 +0.00964 +0.009724 +0.009707 +0.009746 +0.0097 +0.009691 +0.009734 +0.009837 +0.009815 +0.009854 +0.00981 +0.009796 +0.009842 +0.009943 +0.009915 +0.009968 +0.009921 +0.009916 +0.009977 +0.010078 +0.010045 +0.010099 +0.01007 +0.009982 +0.009973 +0.010043 +0.009978 +0.009977 +0.009892 +0.009842 +0.009824 +0.009781 +0.00969 +0.009679 +0.009606 +0.009558 +0.009499 +0.009522 +0.009461 +0.00947 +0.009403 +0.009377 +0.009372 +0.009398 +0.0093 +0.009341 +0.009275 +0.009266 +0.009296 +0.00939 +0.009313 +0.009311 +0.00923 +0.009221 +0.009274 +0.009342 +0.009321 +0.009339 +0.009297 +0.009283 +0.009293 +0.009375 +0.009359 +0.009401 +0.00936 +0.009351 +0.009409 +0.009498 +0.009478 +0.009508 +0.000057 +0.009476 +0.00947 +0.00952 +0.009619 +0.009585 +0.009626 +0.009588 +0.009582 +0.009629 +0.009725 +0.009675 +0.00971 +0.009655 +0.00964 +0.009681 +0.009768 +0.009733 +0.009768 +0.009728 +0.009719 +0.009763 +0.009906 +0.009903 +0.009932 +0.009885 +0.00987 +0.009906 +0.009986 +0.009959 +0.009972 +0.00991 +0.009852 +0.009832 +0.009864 +0.009801 +0.00978 +0.009669 +0.009606 +0.009601 +0.009647 +0.009573 +0.009572 +0.009485 +0.009437 +0.009433 +0.009491 +0.009436 +0.009444 +0.009371 +0.009337 +0.009343 +0.009409 +0.009371 +0.009394 +0.009326 +0.009301 +0.009322 +0.009394 +0.009365 +0.009398 +0.009344 +0.009329 +0.009366 +0.009447 +0.009431 +0.009469 +0.009424 +0.009419 +0.009452 +0.009551 +0.009532 +0.009567 +0.000058 +0.009524 +0.009521 +0.00956 +0.009655 +0.009627 +0.009676 +0.009631 +0.009619 +0.009662 +0.009758 +0.00974 +0.009775 +0.009735 +0.009728 +0.00976 +0.009865 +0.00984 +0.00988 +0.009838 +0.009824 +0.009881 +0.009975 +0.009959 +0.009997 +0.009968 +0.00996 +0.010014 +0.010121 +0.0101 +0.010068 +0.009958 +0.009926 +0.00994 +0.009997 +0.009926 +0.009908 +0.009742 +0.009678 +0.009693 +0.009735 +0.009663 +0.00962 +0.009524 +0.009481 +0.009497 +0.009531 +0.009478 +0.009475 +0.009384 +0.00934 +0.009357 +0.00942 +0.00938 +0.009404 +0.009358 +0.009291 +0.009309 +0.009374 +0.009351 +0.00938 +0.009345 +0.009332 +0.009364 +0.009457 +0.009433 +0.009469 +0.009426 +0.009429 +0.009447 +0.009524 +0.009489 +0.009543 +0.009492 +0.000059 +0.009489 +0.009538 +0.009633 +0.009605 +0.009655 +0.009615 +0.009601 +0.009654 +0.009751 +0.009714 +0.009753 +0.009717 +0.009705 +0.009748 +0.009825 +0.00978 +0.009812 +0.009772 +0.009759 +0.0098 +0.009897 +0.009868 +0.009914 +0.009912 +0.009924 +0.009962 +0.010057 +0.010033 +0.010053 +0.010014 +0.009993 +0.010023 +0.010116 +0.010086 +0.010085 +0.009997 +0.009921 +0.009909 +0.009953 +0.009861 +0.009839 +0.009759 +0.009692 +0.00968 +0.009745 +0.009673 +0.009659 +0.009592 +0.009542 +0.009539 +0.009603 +0.00955 +0.009548 +0.009489 +0.009444 +0.009453 +0.009536 +0.00948 +0.009497 +0.009443 +0.009414 +0.009436 +0.009525 +0.00949 +0.009522 +0.00948 +0.009461 +0.009497 +0.009596 +0.009573 +0.009612 +0.00957 +0.009562 +0.009606 +0.009692 +0.00967 +0.00006 +0.009719 +0.009676 +0.009665 +0.009708 +0.009801 +0.00978 +0.009823 +0.009788 +0.009767 +0.009813 +0.009907 +0.009888 +0.009936 +0.009882 +0.009879 +0.009921 +0.010014 +0.009999 +0.010043 +0.009987 +0.009989 +0.010036 +0.010145 +0.010123 +0.01016 +0.010133 +0.010126 +0.010189 +0.010267 +0.010183 +0.010219 +0.010157 +0.010109 +0.010073 +0.010119 +0.01005 +0.010038 +0.00992 +0.009808 +0.009796 +0.009845 +0.009772 +0.009787 +0.009704 +0.009618 +0.009604 +0.009646 +0.00961 +0.009615 +0.009563 +0.009522 +0.009531 +0.009571 +0.009534 +0.00955 +0.009507 +0.009467 +0.009496 +0.009549 +0.009512 +0.009545 +0.00949 +0.009488 +0.009521 +0.009602 +0.009562 +0.009603 +0.009558 +0.00956 +0.009608 +0.009694 +0.009667 +0.009713 +0.009677 +0.009646 +0.000061 +0.009674 +0.009744 +0.009738 +0.009779 +0.009747 +0.009728 +0.009789 +0.009878 +0.00986 +0.009894 +0.009857 +0.009835 +0.009883 +0.009966 +0.009946 +0.009972 +0.009945 +0.009936 +0.010012 +0.010106 +0.010085 +0.010113 +0.010077 +0.010056 +0.010114 +0.010222 +0.010186 +0.010228 +0.010194 +0.010155 +0.010183 +0.010246 +0.010171 +0.010162 +0.010067 +0.009985 +0.009983 +0.010018 +0.00995 +0.009938 +0.00986 +0.009783 +0.009798 +0.009851 +0.009794 +0.009798 +0.009727 +0.009669 +0.00969 +0.009747 +0.0097 +0.00971 +0.009658 +0.009608 +0.009638 +0.009705 +0.009661 +0.009682 +0.009641 +0.009604 +0.009648 +0.009726 +0.009703 +0.009731 +0.009706 +0.009683 +0.009743 +0.009821 +0.009808 +0.009836 +0.009801 +0.009782 +0.000062 +0.009847 +0.009928 +0.009919 +0.00994 +0.009922 +0.009896 +0.009949 +0.010032 +0.010028 +0.010054 +0.01003 +0.010002 +0.010063 +0.010144 +0.010143 +0.010163 +0.010132 +0.010108 +0.01017 +0.01025 +0.010257 +0.010278 +0.010261 +0.010231 +0.010313 +0.010399 +0.010391 +0.010417 +0.010416 +0.010372 +0.010325 +0.010365 +0.010321 +0.010322 +0.010249 +0.010185 +0.010205 +0.010244 +0.010094 +0.010042 +0.009978 +0.009903 +0.009897 +0.009905 +0.009852 +0.009856 +0.009808 +0.009713 +0.009695 +0.009709 +0.009694 +0.009693 +0.009653 +0.009593 +0.009647 +0.009675 +0.009656 +0.009624 +0.009581 +0.009538 +0.009585 +0.009633 +0.009609 +0.009627 +0.009605 +0.009594 +0.009657 +0.009718 +0.00971 +0.009726 +0.009693 +0.009661 +0.009707 +0.009784 +0.009748 +0.009784 +0.000063 +0.009764 +0.009747 +0.009818 +0.009903 +0.009889 +0.009912 +0.009895 +0.009865 +0.009933 +0.010015 +0.01 +0.010018 +0.009991 +0.009952 +0.010014 +0.010093 +0.010075 +0.010094 +0.010071 +0.010043 +0.010123 +0.01023 +0.010228 +0.010247 +0.010216 +0.010172 +0.010241 +0.010322 +0.010321 +0.010349 +0.010293 +0.010222 +0.010244 +0.010273 +0.010204 +0.01017 +0.010074 +0.009985 +0.009983 +0.010004 +0.009944 +0.009921 +0.009842 +0.009762 +0.009783 +0.009818 +0.009768 +0.009761 +0.009699 +0.009629 +0.009659 +0.009709 +0.009676 +0.00968 +0.009629 +0.009576 +0.00961 +0.009665 +0.00965 +0.009656 +0.009619 +0.00958 +0.009632 +0.0097 +0.009687 +0.009722 +0.009692 +0.009663 +0.00972 +0.009796 +0.009798 +0.009831 +0.009785 +0.009769 +0.000064 +0.009833 +0.009904 +0.009897 +0.009921 +0.009908 +0.00988 +0.009931 +0.010017 +0.010015 +0.010035 +0.010013 +0.009982 +0.010041 +0.010132 +0.010117 +0.010146 +0.01012 +0.010089 +0.010155 +0.010244 +0.010235 +0.010273 +0.010248 +0.010219 +0.010302 +0.010399 +0.010386 +0.010403 +0.010288 +0.010233 +0.010278 +0.010338 +0.010268 +0.010245 +0.010112 +0.010019 +0.010019 +0.01005 +0.009969 +0.009963 +0.009848 +0.009767 +0.009786 +0.009816 +0.009762 +0.009756 +0.009672 +0.009602 +0.00961 +0.009668 +0.009618 +0.009622 +0.009576 +0.009529 +0.009597 +0.009637 +0.009594 +0.009573 +0.009533 +0.009497 +0.00953 +0.009606 +0.00959 +0.009593 +0.009589 +0.00956 +0.009608 +0.009676 +0.009657 +0.009685 +0.009658 +0.009647 +0.009705 +0.009789 +0.00977 +0.009796 +0.000065 +0.009776 +0.009758 +0.009825 +0.009879 +0.009856 +0.009881 +0.009866 +0.009837 +0.009906 +0.009979 +0.009947 +0.009972 +0.009939 +0.009913 +0.009971 +0.01005 +0.010034 +0.010058 +0.010076 +0.010069 +0.01013 +0.010203 +0.010199 +0.010204 +0.010184 +0.010145 +0.010186 +0.010277 +0.010239 +0.010204 +0.010128 +0.010044 +0.010033 +0.010061 +0.00999 +0.009952 +0.009875 +0.009792 +0.009799 +0.009837 +0.009781 +0.009754 +0.009698 +0.009623 +0.009638 +0.009687 +0.009643 +0.009631 +0.00959 +0.009537 +0.009563 +0.009614 +0.009594 +0.009591 +0.009547 +0.009504 +0.009541 +0.009612 +0.009591 +0.009598 +0.009575 +0.009544 +0.009591 +0.00968 +0.009667 +0.009689 +0.009669 +0.009639 +0.009702 +0.009778 +0.009776 +0.009802 +0.000066 +0.009767 +0.009751 +0.009801 +0.009896 +0.009871 +0.009911 +0.009879 +0.009857 +0.009907 +0.010001 +0.009987 +0.010014 +0.009983 +0.009964 +0.010023 +0.010111 +0.010088 +0.010128 +0.010086 +0.010077 +0.010134 +0.010236 +0.01022 +0.010252 +0.010227 +0.010214 +0.010288 +0.010372 +0.010268 +0.010255 +0.010196 +0.010137 +0.010081 +0.010102 +0.010027 +0.010006 +0.009865 +0.009768 +0.009787 +0.009817 +0.009737 +0.009736 +0.009611 +0.009553 +0.009542 +0.00959 +0.009548 +0.009522 +0.009477 +0.009413 +0.009414 +0.009463 +0.009434 +0.009448 +0.009391 +0.00935 +0.009405 +0.009482 +0.009424 +0.009417 +0.009345 +0.00934 +0.009393 +0.009472 +0.009461 +0.009488 +0.009452 +0.009442 +0.009498 +0.009573 +0.009568 +0.009595 +0.009561 +0.009543 +0.000067 +0.009612 +0.009696 +0.009671 +0.009687 +0.009636 +0.009618 +0.009683 +0.009757 +0.009738 +0.009764 +0.009741 +0.009714 +0.00977 +0.009847 +0.009831 +0.009855 +0.009828 +0.009796 +0.009859 +0.009936 +0.009949 +0.009994 +0.00998 +0.009945 +0.009992 +0.010084 +0.010061 +0.010084 +0.010047 +0.010018 +0.010066 +0.010097 +0.010033 +0.010005 +0.009914 +0.009821 +0.009825 +0.009841 +0.009767 +0.009742 +0.009663 +0.009586 +0.009602 +0.00964 +0.009584 +0.009571 +0.009508 +0.009446 +0.009474 +0.009524 +0.009491 +0.009485 +0.009424 +0.009373 +0.009417 +0.009466 +0.009443 +0.009444 +0.009404 +0.009359 +0.009408 +0.009475 +0.009469 +0.009482 +0.00945 +0.00942 +0.009484 +0.009558 +0.009555 +0.009569 +0.009546 +0.009524 +0.009577 +0.009659 +0.000068 +0.009651 +0.009678 +0.009651 +0.009625 +0.009679 +0.009764 +0.009754 +0.009785 +0.009753 +0.009733 +0.009782 +0.009871 +0.009869 +0.009886 +0.009859 +0.009835 +0.009889 +0.009978 +0.009967 +0.009992 +0.009967 +0.009946 +0.010017 +0.010107 +0.010091 +0.010133 +0.010105 +0.010092 +0.010155 +0.010168 +0.010071 +0.010058 +0.009976 +0.009874 +0.009804 +0.009839 +0.009768 +0.009742 +0.009666 +0.009531 +0.009521 +0.009553 +0.009488 +0.00949 +0.009412 +0.009299 +0.009299 +0.009321 +0.009288 +0.009286 +0.009238 +0.009202 +0.00924 +0.009319 +0.009255 +0.009199 +0.009136 +0.009113 +0.009167 +0.009242 +0.009207 +0.009217 +0.009194 +0.009152 +0.009201 +0.00926 +0.009231 +0.009261 +0.009243 +0.009214 +0.009263 +0.009356 +0.009321 +0.009362 +0.009332 +0.009318 +0.009374 +0.000069 +0.009469 +0.009418 +0.009464 +0.009436 +0.009408 +0.009424 +0.009509 +0.00948 +0.00952 +0.009483 +0.00948 +0.009517 +0.009612 +0.009593 +0.009638 +0.009625 +0.009622 +0.009662 +0.009753 +0.009725 +0.009762 +0.009712 +0.009692 +0.009739 +0.009837 +0.009835 +0.009867 +0.009814 +0.009783 +0.009791 +0.009844 +0.009777 +0.009753 +0.009656 +0.00959 +0.009557 +0.0096 +0.009532 +0.009514 +0.009426 +0.009376 +0.009365 +0.009408 +0.00936 +0.009349 +0.00927 +0.009228 +0.009223 +0.009285 +0.00924 +0.009251 +0.009183 +0.00916 +0.009167 +0.009237 +0.009207 +0.009228 +0.009174 +0.009156 +0.009179 +0.009267 +0.009235 +0.009266 +0.009235 +0.009231 +0.009251 +0.009355 +0.009329 +0.009368 +0.009309 +0.009303 +0.009361 +0.00007 +0.009451 +0.009426 +0.009459 +0.009428 +0.009395 +0.009456 +0.009544 +0.00953 +0.009561 +0.009521 +0.009506 +0.00956 +0.009642 +0.00963 +0.009658 +0.009624 +0.009609 +0.009658 +0.009751 +0.009736 +0.00976 +0.009736 +0.009714 +0.009788 +0.009873 +0.009859 +0.009904 +0.009864 +0.009858 +0.009853 +0.009892 +0.009856 +0.009871 +0.009811 +0.009761 +0.00978 +0.009834 +0.009749 +0.009638 +0.009546 +0.009497 +0.009533 +0.009584 +0.009503 +0.009457 +0.009387 +0.009339 +0.00933 +0.009353 +0.009277 +0.009303 +0.009238 +0.009209 +0.009255 +0.009326 +0.009289 +0.009289 +0.009229 +0.009149 +0.009188 +0.009258 +0.009233 +0.009254 +0.009211 +0.009195 +0.009243 +0.00933 +0.009318 +0.009347 +0.009303 +0.009305 +0.009356 +0.009433 +0.009403 +0.009437 +0.000071 +0.009396 +0.009374 +0.009402 +0.009482 +0.009454 +0.009496 +0.009462 +0.009455 +0.009508 +0.009602 +0.009575 +0.009616 +0.009573 +0.009561 +0.009601 +0.009695 +0.009669 +0.009704 +0.009664 +0.009668 +0.009723 +0.009815 +0.0098 +0.009821 +0.009782 +0.009784 +0.009818 +0.009926 +0.0099 +0.009929 +0.009882 +0.009839 +0.00984 +0.009904 +0.009829 +0.009804 +0.009716 +0.009646 +0.009626 +0.009685 +0.00961 +0.009578 +0.009505 +0.00945 +0.009437 +0.009498 +0.009433 +0.009424 +0.009352 +0.009309 +0.009305 +0.00938 +0.009333 +0.009333 +0.009274 +0.009242 +0.009247 +0.009331 +0.00929 +0.009305 +0.009258 +0.009231 +0.009252 +0.009342 +0.009314 +0.009343 +0.009305 +0.00929 +0.009324 +0.009425 +0.009397 +0.009439 +0.009416 +0.009367 +0.009424 +0.009519 +0.000072 +0.009499 +0.009541 +0.009497 +0.009481 +0.009534 +0.009623 +0.009601 +0.009636 +0.009604 +0.0096 +0.009624 +0.00972 +0.009705 +0.009741 +0.009703 +0.009689 +0.009732 +0.009823 +0.009813 +0.009845 +0.009805 +0.009802 +0.009861 +0.009947 +0.009942 +0.009978 +0.009936 +0.009944 +0.009989 +0.009988 +0.009917 +0.009934 +0.00986 +0.009814 +0.009827 +0.009837 +0.00972 +0.00973 +0.009605 +0.009538 +0.00952 +0.009573 +0.009489 +0.009496 +0.009437 +0.009369 +0.009326 +0.009387 +0.009303 +0.009339 +0.009266 +0.009262 +0.009282 +0.009376 +0.009313 +0.009346 +0.009246 +0.009222 +0.009219 +0.009313 +0.009267 +0.009297 +0.009258 +0.00924 +0.009292 +0.00938 +0.009348 +0.009395 +0.009352 +0.009346 +0.009404 +0.009491 +0.009453 +0.009457 +0.000073 +0.009414 +0.009424 +0.009454 +0.009555 +0.009524 +0.009556 +0.009524 +0.009518 +0.009572 +0.009666 +0.009633 +0.009667 +0.00962 +0.009609 +0.009652 +0.009739 +0.009698 +0.009731 +0.009687 +0.009684 +0.009706 +0.009816 +0.00983 +0.009887 +0.009847 +0.009833 +0.009871 +0.009958 +0.00994 +0.009962 +0.009907 +0.009893 +0.009916 +0.009972 +0.009904 +0.00989 +0.009775 +0.009721 +0.009687 +0.009732 +0.009666 +0.009644 +0.009554 +0.009502 +0.00949 +0.009543 +0.009489 +0.009487 +0.009405 +0.009371 +0.009368 +0.009438 +0.009393 +0.009402 +0.009339 +0.009312 +0.009325 +0.009391 +0.009369 +0.009391 +0.009323 +0.009313 +0.009337 +0.009414 +0.009403 +0.009436 +0.009395 +0.009387 +0.009418 +0.009507 +0.009487 +0.009566 +0.009468 +0.009481 +0.000074 +0.009523 +0.009612 +0.009592 +0.009623 +0.009583 +0.009565 +0.009631 +0.009719 +0.009706 +0.009729 +0.009694 +0.009671 +0.00972 +0.009811 +0.009802 +0.009834 +0.009802 +0.009784 +0.009828 +0.009923 +0.00991 +0.009938 +0.009911 +0.009896 +0.009962 +0.010066 +0.010032 +0.010073 +0.010051 +0.010012 +0.009976 +0.01003 +0.009985 +0.009988 +0.009912 +0.009863 +0.009874 +0.00992 +0.009799 +0.009698 +0.009623 +0.009579 +0.009609 +0.009648 +0.00959 +0.009555 +0.009443 +0.009414 +0.009436 +0.009508 +0.009433 +0.009455 +0.009374 +0.00934 +0.009336 +0.009414 +0.009362 +0.009396 +0.009348 +0.009336 +0.009379 +0.009464 +0.009449 +0.009469 +0.009449 +0.009429 +0.009464 +0.009534 +0.0095 +0.009536 +0.009521 +0.009495 +0.000075 +0.00955 +0.009631 +0.009612 +0.009637 +0.009617 +0.009594 +0.009656 +0.009725 +0.009694 +0.009725 +0.009701 +0.009675 +0.009742 +0.009827 +0.009804 +0.009831 +0.009802 +0.00977 +0.009831 +0.00991 +0.009885 +0.009906 +0.00988 +0.009848 +0.009902 +0.009993 +0.010033 +0.010066 +0.010024 +0.010002 +0.010052 +0.010138 +0.010112 +0.010114 +0.010071 +0.010023 +0.010042 +0.010081 +0.010013 +0.009978 +0.009893 +0.009803 +0.009807 +0.009835 +0.009775 +0.009743 +0.009681 +0.009602 +0.009617 +0.009668 +0.009619 +0.009594 +0.009551 +0.009489 +0.009508 +0.009577 +0.009546 +0.009534 +0.009486 +0.009427 +0.009469 +0.009538 +0.009514 +0.009509 +0.009481 +0.009425 +0.009475 +0.009558 +0.009541 +0.009553 +0.009531 +0.009497 +0.009546 +0.009636 +0.00963 +0.00965 +0.009626 +0.009599 +0.009649 +0.000076 +0.009743 +0.009729 +0.009756 +0.009723 +0.009705 +0.009756 +0.009848 +0.009833 +0.009865 +0.009829 +0.009815 +0.009861 +0.009957 +0.009936 +0.009976 +0.00994 +0.00992 +0.009972 +0.010067 +0.010046 +0.010074 +0.010046 +0.010022 +0.010093 +0.010177 +0.010173 +0.010208 +0.01018 +0.010166 +0.010243 +0.010299 +0.010208 +0.010226 +0.010171 +0.010111 +0.010086 +0.010104 +0.010034 +0.010029 +0.009956 +0.009868 +0.009826 +0.009862 +0.009795 +0.009796 +0.009746 +0.009695 +0.009681 +0.009686 +0.009617 +0.009639 +0.009587 +0.009569 +0.009591 +0.00966 +0.0096 +0.009591 +0.009529 +0.009518 +0.009508 +0.009576 +0.009531 +0.009546 +0.009528 +0.009498 +0.009554 +0.009651 +0.009621 +0.009644 +0.009617 +0.009599 +0.009658 +0.009752 +0.009737 +0.009776 +0.009732 +0.000077 +0.009666 +0.009695 +0.009788 +0.009771 +0.009812 +0.009779 +0.00977 +0.00982 +0.009917 +0.009894 +0.009937 +0.009893 +0.009883 +0.009919 +0.010013 +0.009984 +0.010022 +0.009985 +0.009992 +0.010044 +0.010144 +0.010113 +0.010155 +0.010125 +0.010111 +0.010147 +0.010255 +0.010235 +0.010272 +0.010225 +0.01019 +0.010197 +0.010264 +0.01019 +0.010175 +0.010078 +0.010002 +0.009978 +0.010028 +0.00994 +0.009927 +0.009841 +0.009778 +0.009764 +0.009834 +0.009755 +0.009756 +0.009687 +0.00964 +0.009648 +0.009727 +0.009676 +0.009688 +0.009643 +0.009609 +0.009628 +0.009719 +0.009684 +0.009697 +0.009657 +0.009636 +0.009664 +0.009758 +0.00973 +0.009764 +0.009725 +0.009709 +0.009751 +0.009853 +0.009831 +0.009864 +0.009822 +0.000078 +0.009818 +0.009855 +0.009959 +0.009937 +0.00997 +0.009936 +0.009924 +0.009966 +0.010064 +0.010043 +0.010087 +0.010047 +0.010028 +0.010073 +0.010178 +0.010152 +0.010196 +0.010149 +0.010132 +0.010181 +0.010287 +0.010259 +0.010316 +0.010269 +0.010265 +0.010322 +0.010418 +0.010399 +0.010459 +0.010428 +0.010396 +0.010301 +0.010349 +0.010279 +0.010282 +0.010206 +0.010142 +0.010147 +0.010152 +0.010005 +0.010011 +0.009934 +0.00983 +0.009826 +0.009888 +0.009817 +0.009839 +0.009756 +0.009701 +0.009667 +0.009747 +0.009685 +0.0097 +0.009637 +0.009614 +0.009642 +0.009742 +0.009703 +0.009708 +0.009607 +0.009566 +0.00962 +0.009705 +0.009663 +0.009715 +0.009671 +0.009645 +0.00971 +0.009796 +0.009762 +0.00979 +0.009739 +0.009719 +0.00977 +0.00986 +0.009841 +0.000079 +0.009877 +0.009841 +0.009823 +0.009886 +0.009984 +0.00996 +0.009998 +0.009963 +0.009942 +0.009965 +0.01005 +0.010018 +0.010059 +0.010017 +0.010003 +0.010049 +0.010144 +0.010121 +0.010162 +0.010152 +0.010153 +0.010193 +0.010292 +0.010271 +0.010307 +0.01027 +0.010267 +0.010303 +0.010399 +0.010374 +0.010379 +0.010274 +0.010212 +0.010179 +0.01021 +0.010103 +0.010079 +0.009959 +0.009892 +0.009874 +0.009922 +0.009859 +0.00985 +0.009765 +0.009714 +0.009713 +0.009771 +0.009715 +0.009717 +0.00965 +0.009614 +0.009617 +0.009691 +0.009648 +0.009663 +0.009604 +0.00958 +0.009591 +0.009667 +0.00964 +0.009661 +0.009611 +0.009599 +0.009624 +0.009716 +0.00969 +0.009722 +0.009693 +0.009674 +0.009715 +0.009819 +0.00979 +0.009823 +0.009786 +0.00008 +0.009787 +0.009821 +0.009918 +0.009897 +0.009942 +0.009898 +0.009884 +0.009929 +0.010033 +0.010006 +0.01005 +0.010008 +0.009993 +0.010039 +0.01014 +0.010121 +0.01015 +0.010112 +0.010108 +0.010151 +0.010268 +0.010242 +0.010279 +0.01025 +0.010238 +0.0103 +0.010413 +0.010346 +0.010302 +0.010249 +0.010215 +0.010226 +0.010277 +0.010159 +0.01009 +0.01 +0.009942 +0.009887 +0.009944 +0.009859 +0.009872 +0.009804 +0.009746 +0.009705 +0.00974 +0.009695 +0.009711 +0.009676 +0.009631 +0.009658 +0.009721 +0.009683 +0.009693 +0.009615 +0.009578 +0.009604 +0.009677 +0.009624 +0.009669 +0.009624 +0.009622 +0.009661 +0.009761 +0.009725 +0.009752 +0.009728 +0.009713 +0.009717 +0.009809 +0.009762 +0.009811 +0.009778 +0.000081 +0.009773 +0.009818 +0.009913 +0.009897 +0.009934 +0.00991 +0.009891 +0.009946 +0.010039 +0.010017 +0.010044 +0.010016 +0.009988 +0.010042 +0.010126 +0.010081 +0.010109 +0.010078 +0.010052 +0.010111 +0.010203 +0.010223 +0.010274 +0.010238 +0.010224 +0.010251 +0.010354 +0.010322 +0.010355 +0.010308 +0.010279 +0.010316 +0.01036 +0.010282 +0.010268 +0.010167 +0.010078 +0.010065 +0.010104 +0.01002 +0.010011 +0.009926 +0.009855 +0.009865 +0.009916 +0.009851 +0.009858 +0.00979 +0.009726 +0.009751 +0.009811 +0.009759 +0.009772 +0.009719 +0.00967 +0.009701 +0.009773 +0.009737 +0.009758 +0.009714 +0.009681 +0.009719 +0.009801 +0.009779 +0.009813 +0.009779 +0.009753 +0.009811 +0.009892 +0.009878 +0.009925 +0.009875 +0.009855 +0.000082 +0.009918 +0.00999 +0.010003 +0.01001 +0.009993 +0.009962 +0.010025 +0.010108 +0.010101 +0.010126 +0.010103 +0.010072 +0.010135 +0.010215 +0.010215 +0.010243 +0.010207 +0.010186 +0.010251 +0.010344 +0.010331 +0.010376 +0.010352 +0.010323 +0.010405 +0.010488 +0.010399 +0.010395 +0.010339 +0.010262 +0.010222 +0.010258 +0.010208 +0.01018 +0.010119 +0.009983 +0.009975 +0.010002 +0.009976 +0.009949 +0.009903 +0.009845 +0.009816 +0.009845 +0.009781 +0.009794 +0.009736 +0.009701 +0.009732 +0.009812 +0.009758 +0.009723 +0.009661 +0.009613 +0.009671 +0.009728 +0.009698 +0.009715 +0.009687 +0.009664 +0.00969 +0.009736 +0.009711 +0.009743 +0.009731 +0.009697 +0.009769 +0.009849 +0.009831 +0.009861 +0.009838 +0.009811 +0.009886 +0.000083 +0.009969 +0.009954 +0.009983 +0.009955 +0.009929 +0.009975 +0.01005 +0.010017 +0.010056 +0.01002 +0.010016 +0.010079 +0.010144 +0.010142 +0.010166 +0.010124 +0.010116 +0.010165 +0.010246 +0.01022 +0.010254 +0.010222 +0.010197 +0.010242 +0.010339 +0.010318 +0.01035 +0.010344 +0.010343 +0.010391 +0.010479 +0.010466 +0.010479 +0.010434 +0.010397 +0.010386 +0.010403 +0.010309 +0.010257 +0.010131 +0.010034 +0.010008 +0.010021 +0.009958 +0.009932 +0.009836 +0.009764 +0.009763 +0.009791 +0.009734 +0.009726 +0.009649 +0.009608 +0.009613 +0.009674 +0.009636 +0.009625 +0.009571 +0.009539 +0.009554 +0.009615 +0.009585 +0.009592 +0.009537 +0.009508 +0.009536 +0.009609 +0.009586 +0.009606 +0.009571 +0.009556 +0.009599 +0.00968 +0.009672 +0.009697 +0.009686 +0.009636 +0.009699 +0.009789 +0.009772 +0.000084 +0.009811 +0.00977 +0.009757 +0.009798 +0.009896 +0.009877 +0.00992 +0.009879 +0.009868 +0.009903 +0.010004 +0.009981 +0.010018 +0.009983 +0.009967 +0.010018 +0.010123 +0.0101 +0.010148 +0.010109 +0.010098 +0.010157 +0.010274 +0.010246 +0.010277 +0.010145 +0.010116 +0.010142 +0.010204 +0.010116 +0.010093 +0.009955 +0.009884 +0.009843 +0.00988 +0.009816 +0.009807 +0.009727 +0.009648 +0.009598 +0.009649 +0.009601 +0.009608 +0.009553 +0.009495 +0.00952 +0.009538 +0.009507 +0.009515 +0.009483 +0.009398 +0.009421 +0.00949 +0.009448 +0.009489 +0.009446 +0.009436 +0.009472 +0.009557 +0.009535 +0.009557 +0.009533 +0.00953 +0.009538 +0.009598 +0.009576 +0.009616 +0.009582 +0.009576 +0.009626 +0.000085 +0.009724 +0.009693 +0.009733 +0.0097 +0.009682 +0.009744 +0.009836 +0.009817 +0.009847 +0.009814 +0.009794 +0.009849 +0.009933 +0.009901 +0.00992 +0.009889 +0.009864 +0.009914 +0.009996 +0.009972 +0.010007 +0.009984 +0.009995 +0.010059 +0.010155 +0.010125 +0.010153 +0.010109 +0.010067 +0.010099 +0.010173 +0.010113 +0.010096 +0.010019 +0.009944 +0.009956 +0.01 +0.009925 +0.009911 +0.009845 +0.009773 +0.009779 +0.009842 +0.009783 +0.009773 +0.009711 +0.009658 +0.009665 +0.009737 +0.009693 +0.009695 +0.009651 +0.009609 +0.009633 +0.009703 +0.009674 +0.009689 +0.00965 +0.009614 +0.009659 +0.009736 +0.009714 +0.009744 +0.009717 +0.009688 +0.009743 +0.009829 +0.00981 +0.009846 +0.009816 +0.009795 +0.000086 +0.009848 +0.009932 +0.009926 +0.009939 +0.009926 +0.0099 +0.009959 +0.010034 +0.010032 +0.010054 +0.010033 +0.010006 +0.010068 +0.010146 +0.010142 +0.010165 +0.010136 +0.010114 +0.010174 +0.010259 +0.01025 +0.010277 +0.01026 +0.010239 +0.010307 +0.010403 +0.010396 +0.010429 +0.01041 +0.010333 +0.010278 +0.010322 +0.010273 +0.010256 +0.010184 +0.010115 +0.010105 +0.010049 +0.009982 +0.00997 +0.009917 +0.009833 +0.009804 +0.009816 +0.009767 +0.009771 +0.009712 +0.009682 +0.009705 +0.009718 +0.009656 +0.009672 +0.009629 +0.009619 +0.009636 +0.009679 +0.00963 +0.009638 +0.009618 +0.009579 +0.009662 +0.009721 +0.009699 +0.009719 +0.00967 +0.00965 +0.009676 +0.009747 +0.009745 +0.009767 +0.009752 +0.009719 +0.009791 +0.009874 +0.000087 +0.009858 +0.0099 +0.009869 +0.00985 +0.00991 +0.009999 +0.009976 +0.010017 +0.009978 +0.009966 +0.010024 +0.010109 +0.010064 +0.010089 +0.010052 +0.010028 +0.010078 +0.010164 +0.010137 +0.010165 +0.010144 +0.010156 +0.010228 +0.010334 +0.010299 +0.010335 +0.010277 +0.010257 +0.010276 +0.010331 +0.010292 +0.010284 +0.010176 +0.010094 +0.010096 +0.010125 +0.010044 +0.010011 +0.009915 +0.009865 +0.009872 +0.00991 +0.009851 +0.009839 +0.009765 +0.009711 +0.009732 +0.009787 +0.009748 +0.009754 +0.009691 +0.009655 +0.009684 +0.009751 +0.009719 +0.009729 +0.009677 +0.009649 +0.009685 +0.009764 +0.00974 +0.009761 +0.009723 +0.009711 +0.009746 +0.009841 +0.009833 +0.009853 +0.00982 +0.009822 +0.009839 +0.009949 +0.000088 +0.009939 +0.009957 +0.009934 +0.009901 +0.009969 +0.010058 +0.01005 +0.010068 +0.010041 +0.010013 +0.010079 +0.010164 +0.010162 +0.010176 +0.010147 +0.010123 +0.010192 +0.010269 +0.010257 +0.010292 +0.010262 +0.010239 +0.010321 +0.010404 +0.010402 +0.010428 +0.010408 +0.010397 +0.010454 +0.01042 +0.010344 +0.010334 +0.010275 +0.010203 +0.010173 +0.010156 +0.010082 +0.010081 +0.010015 +0.00995 +0.009937 +0.009944 +0.009868 +0.009864 +0.009826 +0.009758 +0.009759 +0.009785 +0.009726 +0.009731 +0.009692 +0.009651 +0.009707 +0.009777 +0.009736 +0.009721 +0.009646 +0.0096 +0.009678 +0.009747 +0.009715 +0.009735 +0.009694 +0.009673 +0.009698 +0.009766 +0.009765 +0.009791 +0.009761 +0.009742 +0.009809 +0.009888 +0.009888 +0.009903 +0.000089 +0.009887 +0.009866 +0.009926 +0.010021 +0.009997 +0.010024 +0.009999 +0.009983 +0.010051 +0.010146 +0.010108 +0.010097 +0.010052 +0.010027 +0.010085 +0.010173 +0.010148 +0.010178 +0.010147 +0.010142 +0.010239 +0.010339 +0.010327 +0.010347 +0.010299 +0.010288 +0.010316 +0.010426 +0.010393 +0.01043 +0.010385 +0.010321 +0.010317 +0.010374 +0.01029 +0.010256 +0.010163 +0.010075 +0.010059 +0.010111 +0.010042 +0.010012 +0.009942 +0.009868 +0.009868 +0.009933 +0.009861 +0.009848 +0.009793 +0.009733 +0.009751 +0.009829 +0.009785 +0.009786 +0.009743 +0.009697 +0.009724 +0.009817 +0.009786 +0.009799 +0.009759 +0.00972 +0.009762 +0.00987 +0.009852 +0.009874 +0.009849 +0.009809 +0.009864 +0.00995 +0.009949 +0.009981 +0.00009 +0.009947 +0.009913 +0.009981 +0.010061 +0.01006 +0.010085 +0.010056 +0.010031 +0.010088 +0.010173 +0.010168 +0.010197 +0.010167 +0.010136 +0.01021 +0.01028 +0.010287 +0.01031 +0.010275 +0.010255 +0.01032 +0.01042 +0.010414 +0.010443 +0.010429 +0.0104 +0.010485 +0.010503 +0.010442 +0.010448 +0.010391 +0.010325 +0.010296 +0.010295 +0.010238 +0.010207 +0.01016 +0.010063 +0.010016 +0.010061 +0.010008 +0.009995 +0.009951 +0.009884 +0.009905 +0.009911 +0.009848 +0.00987 +0.009815 +0.009792 +0.009776 +0.009829 +0.009785 +0.00981 +0.009776 +0.009736 +0.009785 +0.009868 +0.009837 +0.009833 +0.00978 +0.009747 +0.009816 +0.009892 +0.009864 +0.009902 +0.009861 +0.009848 +0.009931 +0.010002 +0.009983 +0.010026 +0.000091 +0.009982 +0.009965 +0.010028 +0.010107 +0.01009 +0.010117 +0.010089 +0.010052 +0.010101 +0.010162 +0.010153 +0.010184 +0.010159 +0.010127 +0.010183 +0.010269 +0.010268 +0.010334 +0.01033 +0.010279 +0.010341 +0.010418 +0.010411 +0.010423 +0.01042 +0.01039 +0.010445 +0.010504 +0.010452 +0.010429 +0.010349 +0.010247 +0.01024 +0.01026 +0.010184 +0.010141 +0.010062 +0.00997 +0.009972 +0.010005 +0.009952 +0.009936 +0.009864 +0.009792 +0.009819 +0.009855 +0.00981 +0.00981 +0.009769 +0.009709 +0.009737 +0.009796 +0.009766 +0.009775 +0.009745 +0.009682 +0.009739 +0.009803 +0.009785 +0.009798 +0.009785 +0.009751 +0.009806 +0.00989 +0.009878 +0.009896 +0.009878 +0.009828 +0.009906 +0.010004 +0.000092 +0.00997 +0.010009 +0.00997 +0.009958 +0.010013 +0.010102 +0.010084 +0.010114 +0.010086 +0.010071 +0.010123 +0.010215 +0.010198 +0.010223 +0.010191 +0.010175 +0.010238 +0.010329 +0.010308 +0.010347 +0.010308 +0.010298 +0.01036 +0.010467 +0.010435 +0.010484 +0.010455 +0.010448 +0.010484 +0.010473 +0.010416 +0.010425 +0.010355 +0.010288 +0.010314 +0.010333 +0.010198 +0.010153 +0.010054 +0.010001 +0.009984 +0.010003 +0.009941 +0.00994 +0.009874 +0.009835 +0.009816 +0.00983 +0.009741 +0.009771 +0.00971 +0.00969 +0.009727 +0.009809 +0.009774 +0.009782 +0.009738 +0.009699 +0.00977 +0.009783 +0.009732 +0.009739 +0.009699 +0.009692 +0.009741 +0.00983 +0.009811 +0.009833 +0.009814 +0.009793 +0.009851 +0.009928 +0.009906 +0.009937 +0.009897 +0.009868 +0.000093 +0.009923 +0.009992 +0.009973 +0.009999 +0.009985 +0.009959 +0.010029 +0.01012 +0.010099 +0.01013 +0.010101 +0.01007 +0.010127 +0.010209 +0.010198 +0.010218 +0.010198 +0.010188 +0.010265 +0.010349 +0.010336 +0.010347 +0.010331 +0.0103 +0.010371 +0.010463 +0.010447 +0.010466 +0.010437 +0.01037 +0.010378 +0.01042 +0.010332 +0.010285 +0.010192 +0.010081 +0.010073 +0.010094 +0.010023 +0.009984 +0.009913 +0.009833 +0.009842 +0.009889 +0.009839 +0.009818 +0.009768 +0.009707 +0.009734 +0.009807 +0.009766 +0.009762 +0.009725 +0.009677 +0.009708 +0.009791 +0.00976 +0.009763 +0.009731 +0.009696 +0.009733 +0.009823 +0.009813 +0.009823 +0.009809 +0.009777 +0.009841 +0.009905 +0.009909 +0.009945 +0.009905 +0.000094 +0.009879 +0.009941 +0.010019 +0.010021 +0.010046 +0.010026 +0.009983 +0.010049 +0.010132 +0.010128 +0.010157 +0.010128 +0.010102 +0.010162 +0.010243 +0.01024 +0.010272 +0.010236 +0.010206 +0.010285 +0.010368 +0.01037 +0.0104 +0.010367 +0.010355 +0.010434 +0.010527 +0.010472 +0.010415 +0.010357 +0.010306 +0.010332 +0.010377 +0.010306 +0.010202 +0.010113 +0.010046 +0.010047 +0.010062 +0.010006 +0.009983 +0.009899 +0.009813 +0.009809 +0.009871 +0.009812 +0.009837 +0.009767 +0.009678 +0.009696 +0.009779 +0.009737 +0.009777 +0.00972 +0.00968 +0.009671 +0.009728 +0.009714 +0.009728 +0.009716 +0.009669 +0.009731 +0.009814 +0.009786 +0.00982 +0.009799 +0.009764 +0.009852 +0.009902 +0.009882 +0.009916 +0.00988 +0.000095 +0.009839 +0.009881 +0.00997 +0.009945 +0.009985 +0.009959 +0.009929 +0.009996 +0.010087 +0.010072 +0.010117 +0.010061 +0.010049 +0.010099 +0.010184 +0.010172 +0.01019 +0.010184 +0.010177 +0.010229 +0.010326 +0.010293 +0.010326 +0.010309 +0.01029 +0.010336 +0.010429 +0.010418 +0.010443 +0.010364 +0.010303 +0.010278 +0.010318 +0.010252 +0.010212 +0.010102 +0.010026 +0.01001 +0.010039 +0.009981 +0.009969 +0.009876 +0.009827 +0.009831 +0.009876 +0.009829 +0.009826 +0.009762 +0.009718 +0.009737 +0.0098 +0.009772 +0.009759 +0.009717 +0.009685 +0.009708 +0.009778 +0.009761 +0.009774 +0.009727 +0.009708 +0.009745 +0.009827 +0.00982 +0.009846 +0.009808 +0.009798 +0.009839 +0.009934 +0.009916 +0.009958 +0.000096 +0.009914 +0.009904 +0.009946 +0.010043 +0.010022 +0.010071 +0.010022 +0.010012 +0.010057 +0.010157 +0.010131 +0.010177 +0.010133 +0.01012 +0.010167 +0.010272 +0.010241 +0.010281 +0.010244 +0.01023 +0.010284 +0.010397 +0.010369 +0.010414 +0.010378 +0.010374 +0.010425 +0.010553 +0.010466 +0.010446 +0.010379 +0.010338 +0.010352 +0.010399 +0.010311 +0.010233 +0.010144 +0.010081 +0.01007 +0.010109 +0.010027 +0.010038 +0.009967 +0.009888 +0.009857 +0.009905 +0.009863 +0.009875 +0.009793 +0.009766 +0.009785 +0.009895 +0.009841 +0.009802 +0.00972 +0.009683 +0.009733 +0.00981 +0.009793 +0.009813 +0.009781 +0.009752 +0.009799 +0.009897 +0.009862 +0.009915 +0.009875 +0.00984 +0.009853 +0.009915 +0.009895 +0.009951 +0.000097 +0.009918 +0.009908 +0.009956 +0.010055 +0.010039 +0.010087 +0.010047 +0.010032 +0.010083 +0.010183 +0.01016 +0.010201 +0.010158 +0.010144 +0.010187 +0.010283 +0.010248 +0.010284 +0.010239 +0.010226 +0.010271 +0.010394 +0.010382 +0.010414 +0.010367 +0.010368 +0.01041 +0.010519 +0.010481 +0.010525 +0.010479 +0.010428 +0.010434 +0.01048 +0.010377 +0.010358 +0.010233 +0.010143 +0.010118 +0.010159 +0.01007 +0.010061 +0.009973 +0.009908 +0.009914 +0.009967 +0.009905 +0.009909 +0.009835 +0.009789 +0.009811 +0.009887 +0.009833 +0.009856 +0.0098 +0.009758 +0.009795 +0.009882 +0.009836 +0.009865 +0.009821 +0.009795 +0.009833 +0.00993 +0.009905 +0.009951 +0.009908 +0.009893 +0.009937 +0.010038 +0.010027 +0.010049 +0.000098 +0.010009 +0.010005 +0.010045 +0.01014 +0.010126 +0.010168 +0.010128 +0.010111 +0.010152 +0.01025 +0.010232 +0.010276 +0.010238 +0.010229 +0.010278 +0.010375 +0.010368 +0.010394 +0.010364 +0.010354 +0.01043 +0.010534 +0.010499 +0.010475 +0.010394 +0.010374 +0.010407 +0.010466 +0.010394 +0.010382 +0.010244 +0.010127 +0.01011 +0.010171 +0.010092 +0.010078 +0.010004 +0.009885 +0.00986 +0.009943 +0.009862 +0.009882 +0.009804 +0.009751 +0.009696 +0.009758 +0.009695 +0.009737 +0.009671 +0.009658 +0.009678 +0.009762 +0.009723 +0.009732 +0.009708 +0.009666 +0.009629 +0.009701 +0.009642 +0.009702 +0.009663 +0.009645 +0.009704 +0.009793 +0.009767 +0.009817 +0.00977 +0.009767 +0.00981 +0.009922 +0.009887 +0.009931 +0.000099 +0.009888 +0.009875 +0.009951 +0.010046 +0.01 +0.009985 +0.00995 +0.009927 +0.009994 +0.010083 +0.010061 +0.010073 +0.010048 +0.010026 +0.010081 +0.010173 +0.010158 +0.010221 +0.010198 +0.010183 +0.010228 +0.010317 +0.0103 +0.010329 +0.010312 +0.010285 +0.010332 +0.010396 +0.010339 +0.010338 +0.010225 +0.01014 +0.01012 +0.010144 +0.010053 +0.010027 +0.009926 +0.009847 +0.009847 +0.009884 +0.009813 +0.009803 +0.009722 +0.009654 +0.009667 +0.009723 +0.009663 +0.009663 +0.009607 +0.009555 +0.009576 +0.009641 +0.009604 +0.009618 +0.009561 +0.009526 +0.009558 +0.009629 +0.009604 +0.009634 +0.009591 +0.009555 +0.009614 +0.009688 +0.009675 +0.009719 +0.009678 +0.00966 +0.009703 +0.009799 +0.009774 +0.009816 +0.0001 +0.009786 +0.009754 +0.00982 +0.009892 +0.009895 +0.009917 +0.00989 +0.009864 +0.009923 +0.010009 +0.010002 +0.010018 +0.009993 +0.009961 +0.010041 +0.010108 +0.010104 +0.010134 +0.010106 +0.010091 +0.010153 +0.01025 +0.010242 +0.010265 +0.01025 +0.010233 +0.010258 +0.010225 +0.010179 +0.010182 +0.010103 +0.010036 +0.010074 +0.010091 +0.009965 +0.009907 +0.009844 +0.00979 +0.009764 +0.009798 +0.009749 +0.009739 +0.009699 +0.009642 +0.009586 +0.009621 +0.009566 +0.009592 +0.009544 +0.009517 +0.009559 +0.009628 +0.009584 +0.009609 +0.009563 +0.009552 +0.009571 +0.009578 +0.009549 +0.009563 +0.009553 +0.009529 +0.009587 +0.009678 +0.009663 +0.00968 +0.009663 +0.009639 +0.009703 +0.009783 +0.009781 +0.009803 +0.009777 +0.000101 +0.009747 +0.009815 +0.009907 +0.009882 +0.009918 +0.009866 +0.009819 +0.009859 +0.009944 +0.009914 +0.009954 +0.00992 +0.0099 +0.009954 +0.010051 +0.010046 +0.010111 +0.010083 +0.010058 +0.010099 +0.010194 +0.01017 +0.010193 +0.010171 +0.010151 +0.010212 +0.01029 +0.010238 +0.010239 +0.010146 +0.010062 +0.010045 +0.010075 +0.009991 +0.009959 +0.009868 +0.009784 +0.009785 +0.009826 +0.009758 +0.009747 +0.009675 +0.009607 +0.009624 +0.009685 +0.009633 +0.009632 +0.009583 +0.009532 +0.009555 +0.009628 +0.0096 +0.009608 +0.00956 +0.009526 +0.009561 +0.009645 +0.009621 +0.009646 +0.009612 +0.009584 +0.009635 +0.009726 +0.009709 +0.009748 +0.009705 +0.009696 +0.009728 +0.000102 +0.009834 +0.009806 +0.009852 +0.009809 +0.009797 +0.009839 +0.009937 +0.009917 +0.009962 +0.009914 +0.009902 +0.009945 +0.010041 +0.010022 +0.010068 +0.010016 +0.01001 +0.010057 +0.010149 +0.010138 +0.010173 +0.010133 +0.010127 +0.01019 +0.010291 +0.01027 +0.010315 +0.010281 +0.010251 +0.010196 +0.010258 +0.010207 +0.010226 +0.01014 +0.010089 +0.010102 +0.010165 +0.010095 +0.010012 +0.009885 +0.009849 +0.009861 +0.009928 +0.009864 +0.009862 +0.00978 +0.009677 +0.009699 +0.009751 +0.009728 +0.009737 +0.00968 +0.009647 +0.009667 +0.009738 +0.00969 +0.009737 +0.009624 +0.00961 +0.009647 +0.00972 +0.009685 +0.009736 +0.009689 +0.009693 +0.009729 +0.009794 +0.009768 +0.009808 +0.009775 +0.009777 +0.009813 +0.009873 +0.000103 +0.009847 +0.009894 +0.00986 +0.009844 +0.009905 +0.010008 +0.009972 +0.010017 +0.009963 +0.009962 +0.010018 +0.010112 +0.010082 +0.01011 +0.010064 +0.010045 +0.01009 +0.010186 +0.010153 +0.010187 +0.010147 +0.010137 +0.010223 +0.01034 +0.010313 +0.010346 +0.010294 +0.010282 +0.01031 +0.01039 +0.010359 +0.010365 +0.010243 +0.010176 +0.010155 +0.010193 +0.010106 +0.010088 +0.009984 +0.009926 +0.009918 +0.009971 +0.009909 +0.009903 +0.009822 +0.009775 +0.009786 +0.009856 +0.009813 +0.009816 +0.009745 +0.009724 +0.009748 +0.009826 +0.009791 +0.009807 +0.009747 +0.009728 +0.009753 +0.00985 +0.009828 +0.009856 +0.009801 +0.009789 +0.009837 +0.009937 +0.009926 +0.009958 +0.00991 +0.009887 +0.000104 +0.009941 +0.010034 +0.010033 +0.010054 +0.010029 +0.009992 +0.010054 +0.010149 +0.010134 +0.010165 +0.010135 +0.010113 +0.010169 +0.010259 +0.010245 +0.01028 +0.010242 +0.010229 +0.010283 +0.010373 +0.010369 +0.010401 +0.010375 +0.010365 +0.010433 +0.010517 +0.010511 +0.010553 +0.010414 +0.010351 +0.010381 +0.010446 +0.010364 +0.010305 +0.010201 +0.010124 +0.010102 +0.010142 +0.010077 +0.010069 +0.009998 +0.009953 +0.009906 +0.009937 +0.009888 +0.009887 +0.009848 +0.009794 +0.009835 +0.009904 +0.009861 +0.009817 +0.009766 +0.009731 +0.009788 +0.009867 +0.009817 +0.009847 +0.009795 +0.009758 +0.00977 +0.009845 +0.009832 +0.009863 +0.009826 +0.009831 +0.009865 +0.009967 +0.009961 +0.009983 +0.00995 +0.009946 +0.000105 +0.009998 +0.010085 +0.010072 +0.010109 +0.010085 +0.010057 +0.010128 +0.01021 +0.010191 +0.010218 +0.010156 +0.010115 +0.010169 +0.010246 +0.010226 +0.010248 +0.010227 +0.010198 +0.010272 +0.010406 +0.01041 +0.010425 +0.010392 +0.010357 +0.010419 +0.010484 +0.010472 +0.010493 +0.01041 +0.010317 +0.010309 +0.010339 +0.010266 +0.010214 +0.010124 +0.010034 +0.010036 +0.010067 +0.010024 +0.01 +0.009918 +0.009853 +0.009877 +0.009917 +0.009883 +0.009879 +0.009821 +0.009766 +0.009805 +0.009869 +0.009848 +0.009851 +0.009808 +0.009762 +0.00981 +0.009878 +0.009869 +0.009881 +0.009846 +0.009815 +0.009864 +0.009946 +0.009953 +0.00997 +0.009939 +0.009914 +0.009982 +0.01005 +0.000106 +0.010048 +0.010081 +0.010043 +0.010033 +0.010081 +0.010164 +0.010153 +0.0102 +0.010158 +0.010141 +0.010187 +0.010283 +0.010265 +0.010298 +0.010274 +0.010251 +0.010306 +0.010399 +0.010392 +0.010416 +0.010391 +0.010367 +0.010447 +0.010535 +0.010525 +0.010568 +0.010541 +0.010502 +0.010448 +0.010511 +0.010461 +0.010464 +0.010378 +0.010306 +0.01031 +0.010354 +0.010187 +0.010126 +0.010047 +0.009998 +0.009966 +0.009997 +0.009942 +0.009943 +0.009903 +0.009782 +0.009802 +0.009838 +0.009808 +0.009818 +0.009788 +0.009744 +0.009796 +0.009857 +0.009826 +0.009832 +0.009756 +0.009697 +0.00973 +0.009826 +0.009778 +0.009813 +0.009776 +0.009756 +0.009828 +0.009902 +0.009887 +0.009923 +0.009852 +0.009851 +0.009887 +0.009964 +0.009945 +0.000107 +0.00999 +0.009952 +0.009937 +0.009999 +0.010097 +0.010074 +0.010104 +0.010073 +0.010059 +0.010113 +0.01021 +0.01017 +0.010204 +0.010155 +0.010137 +0.010184 +0.010276 +0.010244 +0.010289 +0.010259 +0.010276 +0.010335 +0.010443 +0.010404 +0.010437 +0.010395 +0.010372 +0.010395 +0.010484 +0.010435 +0.010411 +0.010298 +0.010218 +0.010184 +0.010216 +0.010125 +0.010095 +0.009992 +0.009927 +0.009914 +0.009969 +0.009903 +0.009896 +0.009819 +0.00977 +0.009776 +0.009845 +0.009791 +0.009799 +0.009739 +0.009711 +0.00971 +0.009801 +0.009757 +0.009764 +0.009714 +0.009685 +0.009709 +0.0098 +0.009772 +0.009793 +0.009753 +0.009743 +0.009772 +0.009877 +0.00986 +0.009892 +0.009856 +0.009849 +0.00988 +0.009976 +0.000108 +0.009969 +0.009998 +0.009963 +0.00994 +0.009999 +0.010088 +0.010073 +0.010112 +0.010075 +0.010049 +0.010099 +0.010204 +0.010175 +0.010217 +0.010185 +0.010168 +0.010216 +0.010307 +0.0103 +0.010339 +0.010302 +0.010295 +0.010361 +0.010461 +0.01045 +0.01049 +0.010389 +0.010296 +0.01033 +0.010395 +0.01032 +0.010271 +0.010145 +0.010066 +0.010081 +0.010101 +0.010023 +0.010003 +0.009937 +0.009828 +0.009807 +0.009872 +0.009805 +0.009814 +0.009752 +0.009654 +0.009649 +0.009724 +0.00967 +0.009696 +0.009635 +0.009615 +0.009642 +0.009704 +0.009641 +0.009672 +0.009633 +0.009573 +0.0096 +0.009667 +0.009653 +0.00968 +0.009646 +0.009642 +0.009689 +0.009784 +0.009773 +0.009795 +0.009774 +0.00976 +0.00981 +0.009904 +0.000109 +0.009878 +0.009927 +0.009884 +0.009874 +0.009931 +0.010004 +0.009949 +0.009997 +0.009959 +0.009944 +0.009997 +0.010095 +0.010045 +0.010081 +0.010037 +0.010026 +0.010057 +0.01016 +0.010135 +0.010183 +0.010181 +0.010183 +0.010232 +0.010327 +0.010293 +0.010333 +0.010275 +0.010267 +0.0103 +0.010424 +0.010383 +0.010363 +0.010269 +0.010199 +0.010168 +0.01021 +0.0101 +0.010069 +0.00997 +0.009894 +0.009876 +0.009928 +0.009848 +0.009836 +0.00976 +0.009696 +0.009693 +0.009755 +0.009694 +0.009697 +0.009638 +0.009597 +0.009607 +0.009684 +0.009644 +0.009653 +0.009603 +0.009576 +0.009592 +0.009686 +0.00965 +0.009671 +0.009633 +0.009617 +0.009653 +0.009748 +0.009727 +0.009763 +0.009726 +0.009704 +0.009762 +0.009845 +0.009843 +0.00011 +0.009851 +0.009833 +0.00982 +0.009856 +0.009954 +0.009932 +0.009978 +0.009936 +0.009921 +0.009961 +0.010055 +0.010038 +0.010084 +0.010043 +0.010032 +0.010076 +0.010176 +0.010161 +0.010193 +0.010161 +0.010146 +0.010207 +0.010322 +0.010292 +0.010331 +0.010281 +0.010199 +0.010232 +0.010298 +0.010235 +0.010237 +0.010162 +0.010101 +0.010031 +0.010022 +0.009946 +0.009947 +0.009867 +0.009824 +0.009813 +0.009847 +0.009739 +0.009757 +0.009654 +0.009572 +0.009605 +0.009656 +0.009624 +0.009634 +0.009573 +0.009481 +0.009505 +0.009569 +0.009529 +0.009561 +0.009502 +0.009493 +0.009528 +0.009616 +0.009585 +0.009605 +0.009525 +0.009515 +0.009541 +0.009648 +0.009611 +0.00965 +0.009616 +0.00961 +0.009653 +0.009744 +0.009728 +0.009767 +0.000111 +0.009731 +0.009712 +0.009769 +0.009862 +0.009838 +0.009865 +0.009838 +0.009817 +0.009838 +0.009914 +0.009879 +0.009922 +0.009892 +0.009868 +0.009921 +0.010014 +0.009996 +0.010063 +0.010042 +0.010023 +0.010067 +0.01016 +0.010137 +0.010161 +0.010128 +0.010114 +0.010175 +0.010265 +0.010252 +0.010255 +0.010195 +0.010137 +0.010119 +0.010146 +0.010068 +0.01003 +0.009928 +0.009851 +0.009834 +0.009871 +0.009815 +0.009797 +0.009722 +0.009668 +0.009674 +0.009724 +0.009681 +0.009672 +0.009611 +0.009571 +0.009585 +0.009653 +0.009625 +0.009624 +0.009574 +0.009549 +0.009571 +0.009647 +0.009633 +0.00965 +0.0096 +0.00959 +0.00963 +0.009715 +0.00971 +0.009736 +0.009712 +0.009679 +0.009729 +0.009841 +0.009795 +0.000112 +0.009846 +0.009814 +0.009779 +0.00985 +0.009927 +0.009919 +0.009949 +0.009921 +0.009898 +0.009954 +0.010033 +0.010024 +0.010052 +0.010032 +0.009998 +0.01006 +0.010145 +0.010141 +0.010162 +0.010127 +0.010105 +0.01017 +0.010256 +0.010255 +0.010288 +0.010252 +0.010238 +0.010308 +0.010403 +0.010397 +0.01041 +0.010286 +0.010232 +0.010267 +0.010321 +0.010251 +0.010172 +0.010069 +0.009996 +0.010002 +0.009989 +0.009939 +0.009928 +0.009852 +0.009762 +0.009737 +0.009791 +0.009753 +0.009729 +0.009694 +0.009637 +0.009661 +0.00967 +0.009649 +0.009647 +0.009621 +0.009567 +0.009618 +0.009652 +0.009612 +0.009641 +0.009599 +0.009576 +0.009579 +0.009624 +0.009619 +0.009642 +0.009626 +0.009609 +0.009668 +0.009747 +0.009745 +0.009766 +0.009742 +0.009718 +0.009786 +0.009879 +0.000113 +0.009855 +0.009891 +0.009847 +0.009835 +0.009901 +0.009995 +0.009972 +0.010002 +0.009968 +0.009921 +0.009934 +0.010024 +0.009981 +0.010022 +0.009997 +0.009975 +0.010046 +0.010181 +0.010178 +0.010201 +0.010157 +0.010134 +0.010182 +0.010273 +0.01025 +0.010302 +0.010274 +0.010238 +0.010272 +0.010325 +0.010271 +0.010247 +0.010147 +0.010056 +0.010047 +0.010073 +0.009998 +0.009976 +0.009876 +0.009808 +0.009818 +0.009861 +0.009802 +0.009799 +0.009717 +0.009653 +0.009675 +0.009731 +0.009683 +0.009687 +0.009627 +0.009582 +0.0096 +0.009664 +0.009634 +0.009647 +0.009594 +0.009561 +0.009591 +0.00966 +0.009638 +0.009672 +0.009625 +0.009594 +0.009645 +0.009729 +0.009718 +0.009748 +0.00971 +0.009698 +0.009739 +0.009837 +0.009814 +0.000114 +0.009857 +0.009817 +0.009797 +0.009845 +0.009948 +0.009926 +0.009959 +0.009921 +0.009909 +0.009953 +0.010051 +0.010031 +0.010068 +0.010032 +0.01002 +0.010063 +0.010165 +0.01015 +0.010181 +0.010151 +0.010144 +0.010195 +0.010308 +0.010286 +0.010331 +0.01028 +0.010156 +0.010167 +0.010234 +0.010164 +0.010158 +0.010079 +0.010015 +0.009914 +0.009944 +0.00988 +0.009873 +0.009784 +0.009751 +0.009748 +0.009729 +0.009668 +0.009655 +0.009612 +0.009567 +0.009566 +0.009598 +0.009544 +0.009565 +0.009522 +0.00949 +0.009546 +0.00961 +0.009576 +0.009565 +0.009497 +0.009484 +0.009519 +0.009628 +0.009573 +0.009609 +0.009584 +0.009557 +0.009614 +0.009705 +0.009662 +0.009716 +0.009678 +0.009652 +0.009693 +0.009786 +0.000115 +0.009748 +0.009786 +0.009763 +0.009746 +0.009799 +0.009893 +0.009857 +0.009903 +0.009868 +0.009853 +0.009906 +0.009996 +0.009955 +0.010001 +0.009938 +0.009932 +0.009977 +0.010075 +0.010032 +0.010087 +0.01008 +0.010088 +0.01012 +0.010221 +0.010188 +0.010227 +0.010163 +0.010122 +0.010147 +0.010222 +0.010149 +0.010132 +0.010021 +0.009956 +0.009945 +0.009977 +0.009899 +0.009893 +0.009798 +0.009738 +0.009748 +0.009803 +0.009735 +0.009748 +0.009657 +0.009619 +0.009624 +0.0097 +0.009651 +0.009662 +0.00959 +0.009558 +0.009584 +0.009661 +0.009618 +0.009645 +0.009584 +0.009555 +0.00959 +0.009677 +0.009654 +0.009685 +0.009635 +0.009618 +0.009664 +0.009761 +0.009739 +0.009791 +0.009725 +0.009724 +0.009769 +0.000116 +0.009862 +0.009846 +0.009877 +0.00985 +0.009828 +0.009874 +0.009969 +0.009956 +0.009983 +0.009965 +0.009926 +0.009985 +0.010072 +0.010063 +0.010101 +0.010047 +0.010037 +0.0101 +0.010178 +0.010181 +0.010209 +0.01018 +0.010165 +0.010225 +0.010341 +0.010314 +0.010361 +0.010315 +0.010196 +0.010214 +0.010271 +0.01022 +0.010205 +0.010129 +0.010073 +0.010029 +0.009985 +0.009905 +0.009907 +0.009838 +0.009772 +0.009778 +0.00976 +0.009693 +0.009713 +0.009651 +0.009622 +0.009577 +0.009632 +0.009561 +0.009601 +0.009549 +0.009533 +0.009572 +0.009649 +0.0096 +0.009626 +0.009535 +0.0095 +0.009541 +0.009598 +0.009571 +0.009603 +0.009559 +0.009547 +0.009607 +0.009697 +0.00968 +0.009716 +0.009678 +0.009659 +0.009728 +0.009814 +0.009787 +0.000117 +0.009829 +0.009794 +0.009786 +0.009842 +0.009926 +0.009877 +0.009912 +0.009862 +0.009851 +0.009891 +0.009976 +0.009939 +0.009978 +0.009935 +0.00992 +0.009968 +0.010065 +0.010047 +0.010124 +0.010097 +0.010083 +0.010117 +0.010218 +0.010193 +0.010221 +0.010185 +0.010173 +0.010218 +0.010314 +0.010242 +0.010236 +0.010144 +0.010059 +0.01003 +0.010066 +0.009969 +0.009934 +0.009839 +0.009765 +0.009755 +0.009812 +0.009742 +0.009736 +0.009664 +0.009615 +0.009609 +0.009684 +0.009634 +0.009642 +0.009591 +0.009551 +0.009566 +0.009649 +0.009609 +0.009636 +0.009569 +0.009551 +0.009573 +0.009659 +0.009629 +0.009659 +0.009616 +0.009599 +0.009636 +0.009734 +0.009709 +0.00975 +0.009718 +0.009685 +0.009741 +0.009842 +0.000118 +0.009807 +0.009854 +0.009811 +0.009805 +0.009846 +0.00994 +0.009918 +0.009961 +0.009924 +0.009907 +0.009954 +0.010048 +0.01003 +0.010071 +0.010029 +0.010022 +0.010057 +0.010164 +0.010141 +0.010186 +0.010139 +0.010129 +0.010193 +0.010295 +0.010272 +0.010318 +0.010286 +0.01028 +0.010289 +0.0103 +0.010229 +0.010245 +0.010165 +0.010115 +0.010118 +0.010126 +0.009979 +0.009983 +0.009894 +0.009802 +0.009772 +0.009842 +0.00976 +0.009763 +0.009701 +0.009652 +0.009623 +0.009664 +0.009598 +0.009628 +0.009562 +0.00955 +0.009575 +0.009671 +0.009614 +0.009641 +0.009591 +0.009502 +0.009526 +0.009603 +0.009565 +0.009609 +0.009562 +0.009552 +0.009608 +0.009697 +0.009674 +0.009717 +0.009672 +0.009675 +0.009726 +0.009811 +0.00979 +0.000119 +0.009827 +0.009789 +0.009755 +0.009768 +0.009852 +0.009819 +0.009868 +0.009831 +0.009825 +0.00988 +0.009977 +0.009955 +0.009992 +0.009952 +0.009948 +0.009994 +0.01011 +0.010086 +0.010115 +0.010071 +0.010053 +0.010104 +0.010219 +0.010193 +0.01023 +0.010178 +0.010181 +0.010216 +0.010306 +0.010263 +0.010262 +0.010165 +0.010103 +0.010081 +0.010117 +0.010029 +0.010005 +0.009896 +0.009833 +0.009815 +0.00986 +0.009795 +0.00978 +0.009689 +0.009638 +0.00964 +0.009697 +0.00965 +0.009654 +0.009591 +0.009555 +0.009567 +0.009646 +0.009615 +0.009627 +0.009569 +0.009555 +0.009563 +0.00965 +0.009632 +0.009651 +0.009605 +0.009593 +0.009622 +0.009718 +0.009705 +0.009734 +0.009701 +0.009679 +0.009724 +0.009835 +0.009799 +0.00012 +0.009831 +0.009808 +0.009785 +0.009834 +0.009928 +0.009921 +0.009942 +0.009912 +0.009895 +0.009942 +0.010038 +0.010021 +0.010051 +0.010017 +0.009998 +0.010057 +0.010141 +0.010129 +0.010169 +0.010124 +0.010117 +0.010172 +0.010273 +0.010263 +0.010296 +0.010264 +0.010256 +0.010312 +0.010306 +0.010242 +0.010246 +0.010175 +0.010099 +0.010125 +0.010098 +0.009985 +0.00998 +0.0099 +0.0098 +0.009777 +0.009811 +0.009745 +0.009755 +0.009676 +0.009635 +0.009614 +0.009648 +0.00959 +0.009595 +0.009533 +0.009501 +0.009536 +0.009635 +0.009566 +0.009534 +0.009484 +0.009443 +0.009516 +0.009579 +0.00955 +0.009586 +0.009532 +0.009526 +0.00958 +0.009647 +0.009612 +0.009656 +0.009621 +0.009588 +0.00963 +0.009706 +0.009668 +0.009733 +0.000121 +0.00968 +0.009677 +0.009727 +0.009827 +0.009805 +0.009844 +0.009805 +0.0098 +0.009848 +0.009947 +0.009922 +0.009959 +0.00992 +0.009904 +0.009944 +0.010035 +0.009997 +0.010031 +0.009989 +0.009971 +0.010013 +0.010109 +0.010104 +0.010178 +0.010132 +0.010124 +0.010152 +0.010251 +0.010216 +0.010226 +0.010169 +0.010111 +0.010084 +0.01012 +0.010045 +0.010001 +0.009896 +0.009824 +0.009798 +0.009851 +0.009784 +0.009779 +0.009696 +0.009656 +0.00965 +0.009716 +0.009664 +0.00967 +0.009602 +0.009572 +0.009584 +0.00965 +0.009615 +0.009636 +0.00958 +0.009554 +0.009577 +0.009659 +0.009628 +0.009655 +0.009616 +0.009597 +0.00963 +0.009725 +0.009703 +0.009734 +0.009706 +0.009687 +0.009741 +0.009813 +0.009805 +0.000122 +0.009846 +0.009806 +0.009788 +0.009839 +0.009936 +0.00991 +0.009957 +0.009906 +0.009902 +0.009943 +0.010042 +0.010019 +0.010061 +0.010025 +0.010003 +0.010053 +0.010151 +0.010138 +0.010172 +0.010139 +0.010125 +0.010185 +0.010283 +0.010277 +0.01032 +0.010278 +0.010235 +0.01021 +0.010285 +0.01024 +0.010264 +0.010181 +0.010136 +0.010145 +0.010212 +0.010138 +0.010011 +0.009935 +0.009887 +0.009894 +0.009972 +0.009896 +0.009841 +0.00976 +0.009714 +0.009756 +0.009783 +0.009723 +0.009718 +0.009677 +0.009651 +0.009701 +0.009794 +0.009727 +0.009739 +0.009646 +0.009638 +0.009683 +0.009763 +0.009732 +0.00975 +0.009715 +0.009694 +0.009703 +0.009795 +0.009764 +0.009801 +0.009778 +0.009762 +0.009808 +0.009922 +0.009891 +0.00992 +0.009895 +0.000123 +0.009888 +0.009938 +0.010033 +0.010007 +0.01006 +0.010012 +0.010013 +0.010066 +0.010167 +0.010093 +0.010127 +0.010077 +0.010061 +0.010105 +0.010193 +0.010158 +0.010199 +0.010158 +0.010142 +0.010209 +0.010357 +0.010341 +0.010366 +0.010319 +0.010301 +0.010328 +0.010415 +0.010367 +0.010376 +0.010288 +0.010203 +0.010188 +0.010242 +0.010158 +0.010136 +0.010054 +0.009994 +0.009989 +0.010051 +0.009986 +0.009986 +0.009911 +0.009858 +0.009861 +0.009936 +0.009881 +0.00988 +0.009827 +0.009787 +0.009798 +0.00989 +0.009849 +0.009858 +0.00981 +0.00978 +0.009801 +0.009902 +0.009872 +0.009896 +0.009855 +0.009844 +0.009877 +0.009983 +0.009964 +0.009997 +0.009965 +0.009944 +0.00999 +0.000124 +0.010088 +0.010066 +0.010114 +0.01007 +0.010048 +0.010101 +0.010202 +0.010184 +0.010221 +0.01018 +0.010165 +0.010213 +0.010311 +0.010293 +0.01033 +0.01029 +0.010288 +0.010334 +0.010442 +0.01042 +0.010477 +0.01043 +0.010431 +0.0105 +0.010592 +0.010486 +0.0105 +0.01043 +0.010386 +0.010355 +0.010387 +0.010311 +0.010319 +0.010228 +0.010162 +0.010095 +0.010128 +0.010088 +0.010094 +0.010003 +0.009978 +0.009991 +0.01009 +0.009991 +0.009935 +0.009858 +0.009841 +0.009876 +0.009978 +0.009915 +0.00995 +0.009889 +0.009867 +0.009868 +0.009946 +0.009888 +0.009943 +0.009876 +0.009873 +0.009917 +0.010014 +0.009985 +0.010016 +0.009969 +0.00994 +0.009972 +0.010069 +0.010034 +0.01009 +0.01006 +0.000125 +0.010027 +0.010091 +0.010203 +0.010169 +0.010215 +0.010173 +0.010162 +0.010219 +0.01032 +0.010288 +0.01033 +0.010288 +0.010266 +0.01031 +0.010399 +0.010355 +0.010401 +0.010345 +0.010337 +0.010376 +0.010503 +0.010522 +0.010566 +0.010515 +0.010491 +0.010535 +0.010629 +0.010572 +0.010596 +0.010513 +0.010438 +0.010418 +0.01043 +0.010347 +0.010324 +0.010211 +0.010137 +0.010139 +0.01018 +0.010111 +0.010113 +0.010024 +0.009972 +0.009974 +0.010033 +0.009972 +0.009991 +0.009908 +0.009858 +0.009885 +0.009961 +0.009912 +0.009939 +0.009873 +0.009832 +0.009868 +0.009952 +0.009912 +0.009954 +0.009896 +0.009867 +0.00991 +0.010007 +0.009983 +0.010033 +0.009982 +0.00997 +0.010011 +0.010101 +0.010108 +0.000126 +0.010119 +0.010091 +0.010083 +0.010115 +0.010212 +0.010201 +0.010252 +0.010204 +0.010188 +0.010229 +0.010333 +0.010303 +0.010355 +0.010324 +0.010304 +0.010353 +0.01045 +0.010438 +0.010471 +0.01044 +0.010431 +0.010505 +0.010609 +0.010574 +0.010619 +0.010508 +0.010485 +0.010534 +0.010628 +0.010539 +0.010548 +0.010456 +0.010328 +0.010283 +0.010338 +0.010267 +0.010251 +0.010176 +0.010121 +0.01007 +0.010084 +0.010023 +0.010045 +0.009964 +0.00994 +0.009938 +0.009988 +0.009907 +0.009949 +0.009861 +0.009817 +0.009821 +0.009897 +0.009842 +0.009886 +0.009826 +0.00983 +0.009859 +0.009958 +0.009911 +0.009934 +0.009909 +0.009881 +0.009884 +0.009966 +0.009914 +0.009983 +0.009934 +0.009928 +0.00999 +0.01009 +0.010067 +0.010108 +0.01007 +0.000127 +0.010065 +0.010112 +0.01021 +0.010193 +0.01023 +0.010198 +0.010176 +0.01023 +0.010333 +0.010297 +0.010334 +0.010286 +0.01026 +0.010306 +0.010395 +0.010362 +0.010401 +0.010359 +0.010375 +0.010443 +0.010548 +0.010521 +0.010553 +0.010504 +0.010481 +0.010509 +0.010583 +0.010508 +0.010475 +0.010362 +0.010271 +0.010239 +0.010259 +0.01017 +0.010133 +0.010025 +0.009958 +0.009937 +0.009989 +0.009921 +0.009914 +0.009827 +0.009779 +0.009783 +0.009849 +0.009806 +0.009804 +0.009749 +0.009707 +0.00973 +0.009806 +0.009763 +0.009775 +0.009722 +0.009693 +0.009717 +0.00981 +0.009781 +0.009797 +0.00975 +0.009742 +0.009781 +0.009879 +0.009857 +0.00989 +0.009859 +0.009837 +0.009885 +0.00999 +0.009961 +0.000128 +0.009995 +0.009968 +0.009951 +0.009998 +0.010077 +0.010075 +0.010107 +0.010082 +0.010047 +0.010105 +0.010197 +0.010187 +0.010221 +0.010181 +0.010159 +0.010224 +0.010315 +0.010299 +0.010342 +0.010309 +0.010294 +0.010368 +0.010462 +0.01044 +0.010486 +0.010402 +0.010341 +0.010399 +0.010462 +0.010407 +0.010404 +0.010311 +0.010186 +0.010175 +0.010223 +0.010147 +0.010147 +0.010068 +0.009942 +0.009931 +0.01 +0.009937 +0.00995 +0.009887 +0.009827 +0.009805 +0.009856 +0.009811 +0.009813 +0.009776 +0.009741 +0.009789 +0.009863 +0.009826 +0.009858 +0.00979 +0.009711 +0.009745 +0.009822 +0.009796 +0.009828 +0.009787 +0.009782 +0.00984 +0.009922 +0.009913 +0.009946 +0.009902 +0.009894 +0.009973 +0.01005 +0.000129 +0.010026 +0.010056 +0.010001 +0.009982 +0.010002 +0.010096 +0.010064 +0.010118 +0.010075 +0.010075 +0.01012 +0.010224 +0.010193 +0.010228 +0.010184 +0.010171 +0.010212 +0.010323 +0.010333 +0.010372 +0.010319 +0.010298 +0.01035 +0.010448 +0.01044 +0.010474 +0.010431 +0.010398 +0.010413 +0.010469 +0.01039 +0.010358 +0.010248 +0.010159 +0.010128 +0.010165 +0.010068 +0.010062 +0.009944 +0.009885 +0.009881 +0.009933 +0.009867 +0.009864 +0.009788 +0.009736 +0.009736 +0.009814 +0.009759 +0.009775 +0.009713 +0.009673 +0.009686 +0.009764 +0.009724 +0.00974 +0.009687 +0.009662 +0.009678 +0.009765 +0.009737 +0.009767 +0.009728 +0.009712 +0.009748 +0.009847 +0.009824 +0.009861 +0.009849 +0.009793 +0.009858 +0.009944 +0.00013 +0.009937 +0.009973 +0.009928 +0.00992 +0.009966 +0.010062 +0.010039 +0.010079 +0.010036 +0.010029 +0.010077 +0.010172 +0.010155 +0.010189 +0.010145 +0.01013 +0.010182 +0.010289 +0.010245 +0.010306 +0.010262 +0.010258 +0.010321 +0.010419 +0.010388 +0.01045 +0.010408 +0.010407 +0.010353 +0.01037 +0.010313 +0.010323 +0.010236 +0.010181 +0.010185 +0.010237 +0.0101 +0.010017 +0.009938 +0.009886 +0.009905 +0.009926 +0.009843 +0.009843 +0.009722 +0.009687 +0.009684 +0.009764 +0.009695 +0.009729 +0.009631 +0.009606 +0.00959 +0.009682 +0.009628 +0.009667 +0.00962 +0.009586 +0.00964 +0.009719 +0.009669 +0.00971 +0.009629 +0.009606 +0.009671 +0.00976 +0.009718 +0.009777 +0.009744 +0.009723 +0.009779 +0.009881 +0.009859 +0.000131 +0.009878 +0.009847 +0.009837 +0.009867 +0.009952 +0.009912 +0.009956 +0.009917 +0.009913 +0.00996 +0.01006 +0.010029 +0.010066 +0.010018 +0.010002 +0.010046 +0.010148 +0.010112 +0.010161 +0.010152 +0.010156 +0.010182 +0.010277 +0.010264 +0.01029 +0.010251 +0.010243 +0.010263 +0.01035 +0.010268 +0.010234 +0.010133 +0.010063 +0.010031 +0.010073 +0.009986 +0.009969 +0.009861 +0.009806 +0.009801 +0.009861 +0.009793 +0.009783 +0.009709 +0.009649 +0.009654 +0.009719 +0.009661 +0.009671 +0.009618 +0.009573 +0.009585 +0.009663 +0.00962 +0.009634 +0.009589 +0.009558 +0.009576 +0.009662 +0.009625 +0.009656 +0.009618 +0.009605 +0.009623 +0.009736 +0.00971 +0.009744 +0.00971 +0.009693 +0.009743 +0.009829 +0.009833 +0.000132 +0.009839 +0.009809 +0.009797 +0.009844 +0.009941 +0.009921 +0.009954 +0.009918 +0.00991 +0.009947 +0.010049 +0.010026 +0.010067 +0.010023 +0.010017 +0.010066 +0.010168 +0.010136 +0.010178 +0.010148 +0.010132 +0.010201 +0.010309 +0.010277 +0.010319 +0.010264 +0.010174 +0.010197 +0.010263 +0.010204 +0.010214 +0.010124 +0.010075 +0.010024 +0.010013 +0.009929 +0.009948 +0.009871 +0.009821 +0.009815 +0.009856 +0.009761 +0.009792 +0.009675 +0.009623 +0.009633 +0.009714 +0.009657 +0.009671 +0.009616 +0.00959 +0.009589 +0.009663 +0.009612 +0.009655 +0.009596 +0.009565 +0.009611 +0.009684 +0.009659 +0.009685 +0.009613 +0.009606 +0.009655 +0.009734 +0.009713 +0.009764 +0.009723 +0.009719 +0.009785 +0.009868 +0.000133 +0.00984 +0.009854 +0.009845 +0.009813 +0.009821 +0.009907 +0.009878 +0.00993 +0.009894 +0.009884 +0.009936 +0.010033 +0.010009 +0.010044 +0.010011 +0.010016 +0.010068 +0.010167 +0.010141 +0.010178 +0.010134 +0.010125 +0.010174 +0.010277 +0.010257 +0.010288 +0.010257 +0.010237 +0.01029 +0.010383 +0.010344 +0.010358 +0.010267 +0.010189 +0.010177 +0.0102 +0.01011 +0.010085 +0.009968 +0.009896 +0.009882 +0.009923 +0.009857 +0.009855 +0.009761 +0.009707 +0.009713 +0.009769 +0.009709 +0.009718 +0.009648 +0.009607 +0.009619 +0.009689 +0.009648 +0.009666 +0.009601 +0.009573 +0.009597 +0.009678 +0.009638 +0.009671 +0.009616 +0.009604 +0.009645 +0.009732 +0.009717 +0.009752 +0.009709 +0.009711 +0.009733 +0.009844 +0.009833 +0.009842 +0.000134 +0.009821 +0.009798 +0.009848 +0.009944 +0.009929 +0.009965 +0.009925 +0.009908 +0.009954 +0.010054 +0.010026 +0.010069 +0.010032 +0.010019 +0.010065 +0.010167 +0.010149 +0.010189 +0.010149 +0.010147 +0.010198 +0.010316 +0.010289 +0.010333 +0.010236 +0.010166 +0.0102 +0.010273 +0.010198 +0.01021 +0.010123 +0.009992 +0.009941 +0.009997 +0.009937 +0.009934 +0.009844 +0.00978 +0.009718 +0.009774 +0.009718 +0.009723 +0.009664 +0.009618 +0.009637 +0.009643 +0.009602 +0.009619 +0.009562 +0.009541 +0.00957 +0.009647 +0.00958 +0.009607 +0.009529 +0.009507 +0.009556 +0.009637 +0.00959 +0.009635 +0.009584 +0.009583 +0.009633 +0.009706 +0.009687 +0.009721 +0.009693 +0.009657 +0.009697 +0.009778 +0.000135 +0.009747 +0.009796 +0.009769 +0.009754 +0.009799 +0.009895 +0.009873 +0.009918 +0.009876 +0.009869 +0.009915 +0.010009 +0.009973 +0.010011 +0.009963 +0.009951 +0.009993 +0.010083 +0.010056 +0.010092 +0.010057 +0.010071 +0.010132 +0.010226 +0.010202 +0.010233 +0.010186 +0.010162 +0.0102 +0.0103 +0.01021 +0.010198 +0.010116 +0.010035 +0.010016 +0.010065 +0.009984 +0.009958 +0.009864 +0.009793 +0.009793 +0.00985 +0.009775 +0.009767 +0.009686 +0.009623 +0.009633 +0.0097 +0.009639 +0.009646 +0.009582 +0.009539 +0.009551 +0.009626 +0.009581 +0.0096 +0.009545 +0.009505 +0.009535 +0.009617 +0.009587 +0.00962 +0.00957 +0.009555 +0.009598 +0.009691 +0.009668 +0.009715 +0.009667 +0.009652 +0.009694 +0.009808 +0.009767 +0.000136 +0.009813 +0.00977 +0.009756 +0.009801 +0.009902 +0.009883 +0.00992 +0.009877 +0.009867 +0.009902 +0.010009 +0.00999 +0.010022 +0.009983 +0.009968 +0.010011 +0.01011 +0.010096 +0.010129 +0.010097 +0.010082 +0.01014 +0.010247 +0.010221 +0.010262 +0.010239 +0.010236 +0.010216 +0.010218 +0.010145 +0.010144 +0.010063 +0.010006 +0.009979 +0.009943 +0.00984 +0.009855 +0.009773 +0.009672 +0.009635 +0.009674 +0.009614 +0.009631 +0.009559 +0.009527 +0.00951 +0.00951 +0.009473 +0.009489 +0.009456 +0.009411 +0.009463 +0.009518 +0.009482 +0.009463 +0.009391 +0.009386 +0.009412 +0.009495 +0.009449 +0.009479 +0.009449 +0.009434 +0.009458 +0.009542 +0.009501 +0.009532 +0.009509 +0.009502 +0.009547 +0.009641 +0.009617 +0.009667 +0.00961 +0.000137 +0.0096 +0.00967 +0.009751 +0.009731 +0.009758 +0.009733 +0.009708 +0.009738 +0.009815 +0.009774 +0.009819 +0.009782 +0.009763 +0.009818 +0.009899 +0.009883 +0.00992 +0.0099 +0.009901 +0.00996 +0.010044 +0.010022 +0.010049 +0.010022 +0.010001 +0.010059 +0.010155 +0.010133 +0.010154 +0.010111 +0.010054 +0.010052 +0.010095 +0.00999 +0.009957 +0.009858 +0.009763 +0.009744 +0.00978 +0.009702 +0.009682 +0.009608 +0.009534 +0.009534 +0.009593 +0.009531 +0.009518 +0.009462 +0.009412 +0.009422 +0.009493 +0.009454 +0.009455 +0.009411 +0.009369 +0.009395 +0.009475 +0.009445 +0.009457 +0.009419 +0.009392 +0.009433 +0.009519 +0.0095 +0.009527 +0.009501 +0.009474 +0.009529 +0.009612 +0.009602 +0.009631 +0.009598 +0.000138 +0.00957 +0.009634 +0.00971 +0.009703 +0.009732 +0.009704 +0.00968 +0.009735 +0.009816 +0.009812 +0.009833 +0.009811 +0.009783 +0.009841 +0.009921 +0.009923 +0.009938 +0.009905 +0.009886 +0.009948 +0.01003 +0.010022 +0.010063 +0.010034 +0.010009 +0.010091 +0.010182 +0.010162 +0.010072 +0.010004 +0.009934 +0.009968 +0.009995 +0.009937 +0.009809 +0.009718 +0.009663 +0.00969 +0.009687 +0.009639 +0.009611 +0.009536 +0.00945 +0.009466 +0.009501 +0.009458 +0.009446 +0.009418 +0.009371 +0.009441 +0.009457 +0.009423 +0.009408 +0.009387 +0.009343 +0.009339 +0.009407 +0.00937 +0.009383 +0.009364 +0.009328 +0.009397 +0.009478 +0.009455 +0.009483 +0.009459 +0.009432 +0.009494 +0.009584 +0.009567 +0.009591 +0.009572 +0.000139 +0.009554 +0.009611 +0.009664 +0.009638 +0.009666 +0.009631 +0.009616 +0.009668 +0.009748 +0.009719 +0.009755 +0.009724 +0.009711 +0.009759 +0.009843 +0.009813 +0.009848 +0.009803 +0.009787 +0.00984 +0.009926 +0.009909 +0.00996 +0.009948 +0.009933 +0.009975 +0.010069 +0.010043 +0.010069 +0.010021 +0.009985 +0.010006 +0.010037 +0.009962 +0.009937 +0.009828 +0.009739 +0.009734 +0.009759 +0.009688 +0.009674 +0.009594 +0.009526 +0.009551 +0.009585 +0.009539 +0.009535 +0.009475 +0.009422 +0.009453 +0.009513 +0.009477 +0.009482 +0.009429 +0.00939 +0.009426 +0.009495 +0.009464 +0.009481 +0.009436 +0.009399 +0.009452 +0.009528 +0.009506 +0.009544 +0.009496 +0.009469 +0.009533 +0.009613 +0.009603 +0.009629 +0.009603 +0.009575 +0.00014 +0.009634 +0.009702 +0.009709 +0.009732 +0.009705 +0.009677 +0.009736 +0.009813 +0.009814 +0.009836 +0.009809 +0.00978 +0.009842 +0.009917 +0.009919 +0.009935 +0.009908 +0.009877 +0.009952 +0.010017 +0.010024 +0.010046 +0.010027 +0.009998 +0.01007 +0.010161 +0.010153 +0.010184 +0.010151 +0.010109 +0.01002 +0.010034 +0.00997 +0.009951 +0.009869 +0.009786 +0.009802 +0.009744 +0.009663 +0.00964 +0.009585 +0.009479 +0.009471 +0.009501 +0.009467 +0.009456 +0.009416 +0.009359 +0.009358 +0.009391 +0.009353 +0.00937 +0.009307 +0.009273 +0.009326 +0.009379 +0.009374 +0.009367 +0.009275 +0.009245 +0.009287 +0.009353 +0.009348 +0.009367 +0.009332 +0.009321 +0.009375 +0.009444 +0.009433 +0.009463 +0.009438 +0.009414 +0.009452 +0.009513 +0.000141 +0.009487 +0.009521 +0.009508 +0.009478 +0.009535 +0.009625 +0.009614 +0.009641 +0.009612 +0.00959 +0.00965 +0.009747 +0.009718 +0.009751 +0.009709 +0.00969 +0.009738 +0.009824 +0.009795 +0.009812 +0.009777 +0.009754 +0.009804 +0.009881 +0.009865 +0.009899 +0.009884 +0.009894 +0.009954 +0.010037 +0.010006 +0.010027 +0.009961 +0.009901 +0.009919 +0.009948 +0.009841 +0.009802 +0.009713 +0.009621 +0.009621 +0.009655 +0.009582 +0.009568 +0.009495 +0.009435 +0.00944 +0.009493 +0.009447 +0.009441 +0.009378 +0.009329 +0.009358 +0.009418 +0.009378 +0.009387 +0.009332 +0.009296 +0.009327 +0.009402 +0.009366 +0.009386 +0.009343 +0.009312 +0.009363 +0.009442 +0.00942 +0.009453 +0.009415 +0.009393 +0.009449 +0.009528 +0.009525 +0.009545 +0.009513 +0.000142 +0.009492 +0.009546 +0.009648 +0.009612 +0.009654 +0.009607 +0.009595 +0.009642 +0.009748 +0.009719 +0.009762 +0.00971 +0.0097 +0.009736 +0.009846 +0.009823 +0.009858 +0.009816 +0.009804 +0.009845 +0.009944 +0.009922 +0.009962 +0.009922 +0.009916 +0.009966 +0.010066 +0.010052 +0.010097 +0.010057 +0.01005 +0.010016 +0.010016 +0.009941 +0.009943 +0.009858 +0.009804 +0.009811 +0.009786 +0.009679 +0.009677 +0.009615 +0.009551 +0.009526 +0.009562 +0.009495 +0.009523 +0.009447 +0.009422 +0.009425 +0.009483 +0.009426 +0.009434 +0.009384 +0.009347 +0.009354 +0.009427 +0.009407 +0.009426 +0.009392 +0.009355 +0.009398 +0.009495 +0.009449 +0.009485 +0.009417 +0.009398 +0.009458 +0.009546 +0.009501 +0.009557 +0.009519 +0.009504 +0.009562 +0.009659 +0.000143 +0.009621 +0.00965 +0.009628 +0.009613 +0.009673 +0.009759 +0.009723 +0.009757 +0.009718 +0.00969 +0.00974 +0.009826 +0.009797 +0.00983 +0.009793 +0.009769 +0.009826 +0.009899 +0.009885 +0.009916 +0.009885 +0.00988 +0.009967 +0.010063 +0.010037 +0.010068 +0.010024 +0.010005 +0.01004 +0.010125 +0.010102 +0.010106 +0.010013 +0.00993 +0.009908 +0.009936 +0.009844 +0.0098 +0.00971 +0.009626 +0.009615 +0.009664 +0.00961 +0.009584 +0.00951 +0.009461 +0.009468 +0.009523 +0.009484 +0.009483 +0.009426 +0.009384 +0.009403 +0.009477 +0.009441 +0.009453 +0.009408 +0.009376 +0.009408 +0.009483 +0.00947 +0.009491 +0.009454 +0.009438 +0.009482 +0.009557 +0.00955 +0.009581 +0.009554 +0.009521 +0.009576 +0.000144 +0.009669 +0.009653 +0.009682 +0.009645 +0.009638 +0.009675 +0.009768 +0.009752 +0.009793 +0.00975 +0.009735 +0.009781 +0.00988 +0.009859 +0.009897 +0.009843 +0.009838 +0.009889 +0.009986 +0.009959 +0.009998 +0.00996 +0.009946 +0.010004 +0.010102 +0.010087 +0.010126 +0.010089 +0.010089 +0.010155 +0.010208 +0.010112 +0.010129 +0.01006 +0.009997 +0.009936 +0.009964 +0.009888 +0.009886 +0.009786 +0.009669 +0.009651 +0.009716 +0.009637 +0.009655 +0.009583 +0.009486 +0.009486 +0.00953 +0.009491 +0.009505 +0.00945 +0.009414 +0.009437 +0.009509 +0.009438 +0.009437 +0.009379 +0.009355 +0.009394 +0.009454 +0.009414 +0.009446 +0.009421 +0.009393 +0.009449 +0.009508 +0.009462 +0.009515 +0.009475 +0.009461 +0.009525 +0.00962 +0.009581 +0.009621 +0.009595 +0.000145 +0.009574 +0.009627 +0.009725 +0.00969 +0.009721 +0.0097 +0.009681 +0.009702 +0.009776 +0.009753 +0.009789 +0.00976 +0.009736 +0.009789 +0.009873 +0.009852 +0.009882 +0.009855 +0.009848 +0.009927 +0.010021 +0.009997 +0.01002 +0.009989 +0.009969 +0.010023 +0.010124 +0.010104 +0.010123 +0.010068 +0.010002 +0.009972 +0.010018 +0.009927 +0.009869 +0.009757 +0.009668 +0.009644 +0.009678 +0.009607 +0.009584 +0.009509 +0.009441 +0.009455 +0.009494 +0.009452 +0.00944 +0.009391 +0.009347 +0.009357 +0.009437 +0.00941 +0.009419 +0.009381 +0.009353 +0.009382 +0.009468 +0.009453 +0.009469 +0.009447 +0.009422 +0.009469 +0.009561 +0.009536 +0.009572 +0.009541 +0.009523 +0.000146 +0.009575 +0.009655 +0.009648 +0.009661 +0.009637 +0.00962 +0.00968 +0.009754 +0.009749 +0.009775 +0.009747 +0.009718 +0.009779 +0.009861 +0.009861 +0.009886 +0.009855 +0.009829 +0.009892 +0.009973 +0.00997 +0.009995 +0.009968 +0.009939 +0.010008 +0.010089 +0.010076 +0.010095 +0.010067 +0.010043 +0.010114 +0.010195 +0.010165 +0.010184 +0.010147 +0.01011 +0.010175 +0.01025 +0.010229 +0.010261 +0.010231 +0.010205 +0.010278 +0.010358 +0.010352 +0.010377 +0.010352 +0.010321 +0.010389 +0.01047 +0.01046 +0.01049 +0.010456 +0.010432 +0.010505 +0.010582 +0.010578 +0.010597 +0.010569 +0.010543 +0.01061 +0.010696 +0.010687 +0.010713 +0.010692 +0.010664 +0.010728 +0.01081 +0.010808 +0.010835 +0.010803 +0.010779 +0.010855 +0.010946 +0.01092 +0.010947 +0.010914 +0.010892 +0.010943 +0.011009 +0.010985 +0.011013 +0.01099 +0.010959 +0.011035 +0.011121 +0.011107 +0.011142 +0.01112 +0.011086 +0.011159 +0.011252 +0.011247 +0.011273 +0.011247 +0.011218 +0.011292 +0.011384 +0.01138 +0.011407 +0.011376 +0.011352 +0.011431 +0.011524 +0.011512 +0.011536 +0.011506 +0.011486 +0.011566 +0.011663 +0.011626 +0.011626 +0.011581 +0.011554 +0.011636 +0.011722 +0.011693 +0.011721 +0.011699 +0.011667 +0.011749 +0.011837 +0.011826 +0.011857 +0.011824 +0.011803 +0.011875 +0.011972 +0.011958 +0.011995 +0.011964 +0.011937 +0.012013 +0.012112 +0.012105 +0.012137 +0.012104 +0.012077 +0.012154 +0.012261 +0.01225 +0.012287 +0.012252 +0.012226 +0.012305 +0.012407 +0.012388 +0.012414 +0.012389 +0.012354 +0.012418 +0.012487 +0.012469 +0.012509 +0.012481 +0.012451 +0.012543 +0.012645 +0.012635 +0.012674 +0.012645 +0.012612 +0.012704 +0.012807 +0.012789 +0.01282 +0.012794 +0.012765 +0.012855 +0.012965 +0.012942 +0.012979 +0.012953 +0.012922 +0.013016 +0.013124 +0.013106 +0.01314 +0.013115 +0.013086 +0.013176 +0.013286 +0.013265 +0.013305 +0.013273 +0.013243 +0.013332 +0.013451 +0.013421 +0.013474 +0.013438 +0.01341 +0.013476 +0.013581 +0.013566 +0.013622 +0.013583 +0.013578 +0.013652 +0.013738 +0.01374 +0.013735 +0.013656 +0.013509 +0.013387 +0.013429 +0.013284 +0.013124 +0.012931 +0.01277 +0.01269 +0.012616 +0.01251 +0.012406 +0.012199 +0.012074 +0.011987 +0.011995 +0.011878 +0.011855 +0.011666 +0.011564 +0.011514 +0.011567 +0.011482 +0.011474 +0.011365 +0.011265 +0.011287 +0.011353 +0.011315 +0.011356 +0.01131 +0.011274 +0.011366 +0.011458 +0.011437 +0.011474 +0.011441 +0.011415 +0.011459 +0.011553 +0.011514 +0.011572 +0.000147 +0.011532 +0.011514 +0.011601 +0.011687 +0.011662 +0.011697 +0.011652 +0.011627 +0.011686 +0.011793 +0.011807 +0.011884 +0.011826 +0.011798 +0.011863 +0.011963 +0.011941 +0.01198 +0.011874 +0.011773 +0.011744 +0.011738 +0.011624 +0.01156 +0.011391 +0.01126 +0.011211 +0.011206 +0.011101 +0.01105 +0.010918 +0.010808 +0.010787 +0.010812 +0.010722 +0.010702 +0.0106 +0.010526 +0.01053 +0.010573 +0.010512 +0.010511 +0.010426 +0.010371 +0.010391 +0.010444 +0.010407 +0.010422 +0.010362 +0.01032 +0.010372 +0.010447 +0.010429 +0.010466 +0.010422 +0.010408 +0.010459 +0.010555 +0.010542 +0.010577 +0.010534 +0.01052 +0.010581 +0.000148 +0.010664 +0.010666 +0.010685 +0.010663 +0.01064 +0.010695 +0.010783 +0.010781 +0.010812 +0.01079 +0.010756 +0.010818 +0.010907 +0.010908 +0.010931 +0.010915 +0.010887 +0.010973 +0.011062 +0.01105 +0.01109 +0.011064 +0.010913 +0.010925 +0.010969 +0.010903 +0.010864 +0.010771 +0.010654 +0.01053 +0.010524 +0.010458 +0.010441 +0.010345 +0.010267 +0.010228 +0.010217 +0.010159 +0.010142 +0.010082 +0.009959 +0.00997 +0.009996 +0.009974 +0.009962 +0.009909 +0.009857 +0.009882 +0.009904 +0.009871 +0.009887 +0.00982 +0.00976 +0.009768 +0.009839 +0.00982 +0.009837 +0.00982 +0.009775 +0.009848 +0.009928 +0.009899 +0.009941 +0.009914 +0.00988 +0.009955 +0.010012 +0.009992 +0.010008 +0.009994 +0.000149 +0.009975 +0.010034 +0.010126 +0.010093 +0.010136 +0.010096 +0.010088 +0.010145 +0.01025 +0.010187 +0.01022 +0.010184 +0.010154 +0.010211 +0.010297 +0.010269 +0.0103 +0.010266 +0.010249 +0.010361 +0.010468 +0.010445 +0.010466 +0.010428 +0.010386 +0.01039 +0.010447 +0.010369 +0.01035 +0.010236 +0.010129 +0.010109 +0.010132 +0.010039 +0.010012 +0.00991 +0.009826 +0.00983 +0.009873 +0.009801 +0.009787 +0.009715 +0.009649 +0.009671 +0.009733 +0.009677 +0.009679 +0.009631 +0.009577 +0.009607 +0.009685 +0.00965 +0.009648 +0.009609 +0.009576 +0.009617 +0.009696 +0.009688 +0.009685 +0.009667 +0.009639 +0.009691 +0.009787 +0.009766 +0.009799 +0.009768 +0.009737 +0.009785 +0.009895 +0.00015 +0.009868 +0.009906 +0.009869 +0.009846 +0.009898 +0.009997 +0.00997 +0.010011 +0.009973 +0.009961 +0.01 +0.010107 +0.010078 +0.010125 +0.010079 +0.010062 +0.010119 +0.010215 +0.010187 +0.010241 +0.010195 +0.010196 +0.010248 +0.010361 +0.010334 +0.010382 +0.010317 +0.010221 +0.010257 +0.010326 +0.010262 +0.010255 +0.010165 +0.010095 +0.00999 +0.010006 +0.009912 +0.009932 +0.00984 +0.009782 +0.009815 +0.009826 +0.009728 +0.009714 +0.009633 +0.009582 +0.009566 +0.009622 +0.009577 +0.009588 +0.009549 +0.009507 +0.009554 +0.009628 +0.009565 +0.009545 +0.00948 +0.009484 +0.009513 +0.009596 +0.009558 +0.00958 +0.009543 +0.009529 +0.009528 +0.009628 +0.009586 +0.009629 +0.009603 +0.009589 +0.009637 +0.009737 +0.009726 +0.009747 +0.009719 +0.000151 +0.0097 +0.009758 +0.009854 +0.009829 +0.009869 +0.009829 +0.009817 +0.009868 +0.00997 +0.009936 +0.009976 +0.009929 +0.009909 +0.009954 +0.010047 +0.010007 +0.010031 +0.009988 +0.009975 +0.010018 +0.01011 +0.010079 +0.010141 +0.010145 +0.010123 +0.010178 +0.010258 +0.010226 +0.01024 +0.010144 +0.01008 +0.010073 +0.010104 +0.010008 +0.009975 +0.009861 +0.009784 +0.009771 +0.009814 +0.009745 +0.009737 +0.009647 +0.009595 +0.009596 +0.009656 +0.009597 +0.009599 +0.009526 +0.009489 +0.009499 +0.009571 +0.009537 +0.009547 +0.009479 +0.009447 +0.009476 +0.009553 +0.009514 +0.00954 +0.009482 +0.009463 +0.009491 +0.00958 +0.00956 +0.009599 +0.009547 +0.009539 +0.009577 +0.009672 +0.009659 +0.009702 +0.009644 +0.009634 +0.000152 +0.009684 +0.009779 +0.009761 +0.009788 +0.009758 +0.009743 +0.00979 +0.009878 +0.00986 +0.009896 +0.009861 +0.009845 +0.009895 +0.009987 +0.009969 +0.009994 +0.009963 +0.009943 +0.009998 +0.010093 +0.01008 +0.01012 +0.010086 +0.010067 +0.010141 +0.010244 +0.010216 +0.010225 +0.010107 +0.010076 +0.010114 +0.010172 +0.010094 +0.010038 +0.00991 +0.009853 +0.009842 +0.009865 +0.009797 +0.009797 +0.009744 +0.009636 +0.009629 +0.009675 +0.009621 +0.009636 +0.009574 +0.009545 +0.00955 +0.009588 +0.009541 +0.009558 +0.009524 +0.009477 +0.009498 +0.009537 +0.009512 +0.009531 +0.009499 +0.009486 +0.009531 +0.009605 +0.009588 +0.009603 +0.009585 +0.009555 +0.009557 +0.009645 +0.009622 +0.009655 +0.00963 +0.00962 +0.00968 +0.009761 +0.000153 +0.009748 +0.009794 +0.00975 +0.009738 +0.009783 +0.009882 +0.009864 +0.009906 +0.009863 +0.00985 +0.009901 +0.009989 +0.009958 +0.009993 +0.009946 +0.00993 +0.009972 +0.010064 +0.010029 +0.010066 +0.010029 +0.010016 +0.010086 +0.010206 +0.010174 +0.010208 +0.010149 +0.010131 +0.010154 +0.010219 +0.01014 +0.010102 +0.009985 +0.009901 +0.009866 +0.009899 +0.009817 +0.009796 +0.009698 +0.009642 +0.009629 +0.009687 +0.009627 +0.00962 +0.009542 +0.009501 +0.009506 +0.009569 +0.009533 +0.009539 +0.009476 +0.009454 +0.009468 +0.009543 +0.009514 +0.009525 +0.009471 +0.009453 +0.009478 +0.009566 +0.009544 +0.00957 +0.009526 +0.009521 +0.009556 +0.009651 +0.009638 +0.009677 +0.009625 +0.009605 +0.009667 +0.000154 +0.009748 +0.009751 +0.009761 +0.00973 +0.009717 +0.009765 +0.009864 +0.009833 +0.009875 +0.009838 +0.009816 +0.009874 +0.009965 +0.009949 +0.009978 +0.009946 +0.009925 +0.009974 +0.010068 +0.010054 +0.010082 +0.010053 +0.010035 +0.010099 +0.010193 +0.010182 +0.01021 +0.010198 +0.010174 +0.010248 +0.01027 +0.010198 +0.010211 +0.010151 +0.010087 +0.010064 +0.010067 +0.009998 +0.009988 +0.009908 +0.009789 +0.009766 +0.009828 +0.009762 +0.009757 +0.0097 +0.009626 +0.009588 +0.009623 +0.009592 +0.009593 +0.009551 +0.009512 +0.009553 +0.009634 +0.009585 +0.009618 +0.009564 +0.009516 +0.009492 +0.009578 +0.00955 +0.009578 +0.009555 +0.009529 +0.009586 +0.009675 +0.009648 +0.009695 +0.009658 +0.009639 +0.009707 +0.009796 +0.009764 +0.0098 +0.000155 +0.009781 +0.00975 +0.009817 +0.009913 +0.009889 +0.009892 +0.009828 +0.009799 +0.009871 +0.009961 +0.009941 +0.009964 +0.009935 +0.009907 +0.009969 +0.010042 +0.010032 +0.010049 +0.01003 +0.010001 +0.010082 +0.010186 +0.010179 +0.010199 +0.010159 +0.010137 +0.010183 +0.010257 +0.010241 +0.01021 +0.010114 +0.010025 +0.010007 +0.01001 +0.009941 +0.00989 +0.009793 +0.009716 +0.009717 +0.009753 +0.009704 +0.009672 +0.009607 +0.009545 +0.00955 +0.009602 +0.00957 +0.00955 +0.009499 +0.00945 +0.009483 +0.009543 +0.009526 +0.009512 +0.009458 +0.009425 +0.009463 +0.009525 +0.009513 +0.009511 +0.009477 +0.009443 +0.0095 +0.009578 +0.009577 +0.009586 +0.009563 +0.009538 +0.009587 +0.00968 +0.009669 +0.009697 +0.000156 +0.009659 +0.00963 +0.009705 +0.009777 +0.009774 +0.00979 +0.009769 +0.009746 +0.009802 +0.00988 +0.009871 +0.009893 +0.009873 +0.009849 +0.009909 +0.009985 +0.00999 +0.009999 +0.009978 +0.009949 +0.010032 +0.010096 +0.010106 +0.010134 +0.010104 +0.010095 +0.010172 +0.010203 +0.010152 +0.010158 +0.010118 +0.01006 +0.010074 +0.010062 +0.009991 +0.009972 +0.009846 +0.009769 +0.009761 +0.009791 +0.009739 +0.009723 +0.00967 +0.009602 +0.009584 +0.00961 +0.009566 +0.009578 +0.009522 +0.009488 +0.009535 +0.009598 +0.009572 +0.009552 +0.009491 +0.00944 +0.009496 +0.00956 +0.009521 +0.009544 +0.009509 +0.009479 +0.009543 +0.009588 +0.009561 +0.009599 +0.009567 +0.009537 +0.009621 +0.00969 +0.009666 +0.009719 +0.009674 +0.009652 +0.000157 +0.009718 +0.009812 +0.009789 +0.009813 +0.00976 +0.00973 +0.009776 +0.009855 +0.009839 +0.009872 +0.009842 +0.009819 +0.00988 +0.009953 +0.009943 +0.009966 +0.009948 +0.009942 +0.010013 +0.010092 +0.010083 +0.010099 +0.010067 +0.010053 +0.010115 +0.010199 +0.010184 +0.010207 +0.010145 +0.010063 +0.010071 +0.010091 +0.010005 +0.009964 +0.009871 +0.009772 +0.009779 +0.009814 +0.009749 +0.009732 +0.009674 +0.009585 +0.009617 +0.009662 +0.009621 +0.009607 +0.009559 +0.009498 +0.009535 +0.009603 +0.009577 +0.009579 +0.009534 +0.009484 +0.009538 +0.009599 +0.009582 +0.009593 +0.009555 +0.009518 +0.009569 +0.009644 +0.009642 +0.009668 +0.009633 +0.009599 +0.009666 +0.00974 +0.009757 +0.009747 +0.000158 +0.009734 +0.009707 +0.009763 +0.009852 +0.009834 +0.009866 +0.009842 +0.009811 +0.009875 +0.009948 +0.009943 +0.009972 +0.009941 +0.009916 +0.009969 +0.010063 +0.010052 +0.010082 +0.010044 +0.010033 +0.010083 +0.010188 +0.010168 +0.010214 +0.010181 +0.010164 +0.010239 +0.010331 +0.010235 +0.010236 +0.010172 +0.010115 +0.010079 +0.010117 +0.010031 +0.010026 +0.009924 +0.009807 +0.009809 +0.009853 +0.009804 +0.009807 +0.009728 +0.009688 +0.009635 +0.009697 +0.009635 +0.009658 +0.009595 +0.009569 +0.009608 +0.009675 +0.00965 +0.009656 +0.009611 +0.009533 +0.009543 +0.009626 +0.009595 +0.009617 +0.009592 +0.009566 +0.00962 +0.009721 +0.009694 +0.009723 +0.009698 +0.009671 +0.009744 +0.00983 +0.009805 +0.009843 +0.000159 +0.009814 +0.009776 +0.009804 +0.009868 +0.009848 +0.009881 +0.009863 +0.009839 +0.009906 +0.009986 +0.009979 +0.010002 +0.009978 +0.009948 +0.010005 +0.010083 +0.010073 +0.010107 +0.010102 +0.010075 +0.010129 +0.010203 +0.0102 +0.010219 +0.0102 +0.010186 +0.010237 +0.010311 +0.010293 +0.010296 +0.010216 +0.01014 +0.010131 +0.010144 +0.010079 +0.01003 +0.009936 +0.009853 +0.009855 +0.009887 +0.009841 +0.009821 +0.009754 +0.009689 +0.009704 +0.009747 +0.009712 +0.009705 +0.009652 +0.009607 +0.009634 +0.009693 +0.009677 +0.009668 +0.009631 +0.009596 +0.009631 +0.009695 +0.009689 +0.009693 +0.009662 +0.009637 +0.009688 +0.009758 +0.009765 +0.00978 +0.009758 +0.009727 +0.009788 +0.009876 +0.009859 +0.00016 +0.009881 +0.009865 +0.009831 +0.009891 +0.009979 +0.009963 +0.009994 +0.009965 +0.009939 +0.009994 +0.010086 +0.010075 +0.010104 +0.010076 +0.010044 +0.010105 +0.01019 +0.010187 +0.010208 +0.010181 +0.010156 +0.010231 +0.010311 +0.010321 +0.01034 +0.010315 +0.010302 +0.010383 +0.010408 +0.010325 +0.010315 +0.010252 +0.010183 +0.010135 +0.010137 +0.010069 +0.010054 +0.010001 +0.009924 +0.009882 +0.009896 +0.009842 +0.009834 +0.009797 +0.009728 +0.009792 +0.009795 +0.00975 +0.009736 +0.009696 +0.009618 +0.009654 +0.009705 +0.009668 +0.009696 +0.009644 +0.00963 +0.00968 +0.009745 +0.009732 +0.009735 +0.009724 +0.009685 +0.009675 +0.009759 +0.009736 +0.009764 +0.009757 +0.00973 +0.009794 +0.009888 +0.009876 +0.000161 +0.0099 +0.009879 +0.009874 +0.009909 +0.010005 +0.009999 +0.010027 +0.010007 +0.009978 +0.01005 +0.010133 +0.010114 +0.01014 +0.010112 +0.010081 +0.010111 +0.010167 +0.010142 +0.010162 +0.010137 +0.010103 +0.010174 +0.010292 +0.010316 +0.010338 +0.010314 +0.010268 +0.010328 +0.010405 +0.01036 +0.010367 +0.010285 +0.010175 +0.010163 +0.010178 +0.010096 +0.01005 +0.009949 +0.009849 +0.009859 +0.009888 +0.009832 +0.009819 +0.009744 +0.009663 +0.00969 +0.009731 +0.009694 +0.009689 +0.009641 +0.009579 +0.009613 +0.009668 +0.009644 +0.00965 +0.009601 +0.009554 +0.0096 +0.009662 +0.009644 +0.009661 +0.009626 +0.009588 +0.00965 +0.009724 +0.009719 +0.009749 +0.009715 +0.009687 +0.009749 +0.009828 +0.009822 +0.000162 +0.009853 +0.009813 +0.009799 +0.009847 +0.009933 +0.009922 +0.009961 +0.009926 +0.009903 +0.009951 +0.010043 +0.010027 +0.010068 +0.010035 +0.010015 +0.010069 +0.010155 +0.010139 +0.010175 +0.010135 +0.010119 +0.01018 +0.010286 +0.010262 +0.010301 +0.010278 +0.010263 +0.010292 +0.010322 +0.010284 +0.010311 +0.010249 +0.010192 +0.010208 +0.01026 +0.010169 +0.010037 +0.009953 +0.009883 +0.009928 +0.009958 +0.009871 +0.00984 +0.00975 +0.009722 +0.009699 +0.009765 +0.009687 +0.009711 +0.009652 +0.009627 +0.009668 +0.00975 +0.009707 +0.009674 +0.009611 +0.009584 +0.009618 +0.009707 +0.009656 +0.009688 +0.009643 +0.009607 +0.009637 +0.009699 +0.009671 +0.009722 +0.009686 +0.009662 +0.009728 +0.009822 +0.0098 +0.009834 +0.009811 +0.009789 +0.000163 +0.00984 +0.009941 +0.009922 +0.009958 +0.009922 +0.009911 +0.009965 +0.010065 +0.010029 +0.010075 +0.010038 +0.010007 +0.009996 +0.010076 +0.010045 +0.010095 +0.010055 +0.010053 +0.010143 +0.010262 +0.010237 +0.010269 +0.010221 +0.010198 +0.010247 +0.01034 +0.010301 +0.01035 +0.010263 +0.010183 +0.010154 +0.010193 +0.010092 +0.010064 +0.00995 +0.009866 +0.009854 +0.009904 +0.009834 +0.009834 +0.009747 +0.009689 +0.009688 +0.009751 +0.009696 +0.009705 +0.00963 +0.009591 +0.009616 +0.009684 +0.009643 +0.009671 +0.009612 +0.009584 +0.009619 +0.009708 +0.009675 +0.009715 +0.00967 +0.009649 +0.009699 +0.009789 +0.009771 +0.009817 +0.009774 +0.009746 +0.009797 +0.000164 +0.009901 +0.009875 +0.009922 +0.009871 +0.009854 +0.009907 +0.010004 +0.009985 +0.010025 +0.009981 +0.009965 +0.010009 +0.010108 +0.010093 +0.010136 +0.010091 +0.010072 +0.010128 +0.01023 +0.010202 +0.010259 +0.010207 +0.010211 +0.01026 +0.01038 +0.010358 +0.010378 +0.010232 +0.010189 +0.010208 +0.01027 +0.010189 +0.010128 +0.010002 +0.009937 +0.009908 +0.009938 +0.009869 +0.009863 +0.009719 +0.009672 +0.009657 +0.009699 +0.00965 +0.009651 +0.009583 +0.009486 +0.009498 +0.00955 +0.009516 +0.009528 +0.009479 +0.009446 +0.009465 +0.009548 +0.009493 +0.009504 +0.009443 +0.009411 +0.009462 +0.00956 +0.009512 +0.009562 +0.009532 +0.009509 +0.009563 +0.009664 +0.009629 +0.009671 +0.009621 +0.009619 +0.009677 +0.000165 +0.009746 +0.009718 +0.009742 +0.009731 +0.009704 +0.009763 +0.009836 +0.0098 +0.009832 +0.009812 +0.009797 +0.009861 +0.00995 +0.009925 +0.00996 +0.009922 +0.009903 +0.009953 +0.010036 +0.009995 +0.010029 +0.009995 +0.00997 +0.010022 +0.010101 +0.010079 +0.010156 +0.010142 +0.010131 +0.010164 +0.010232 +0.010176 +0.010134 +0.01002 +0.009941 +0.00991 +0.00991 +0.009811 +0.009763 +0.009649 +0.009562 +0.009546 +0.009584 +0.009506 +0.009469 +0.009395 +0.009325 +0.009314 +0.009361 +0.009317 +0.009303 +0.009242 +0.009199 +0.009207 +0.009265 +0.009237 +0.009238 +0.009186 +0.009146 +0.009169 +0.009238 +0.009218 +0.009228 +0.009187 +0.009161 +0.0092 +0.009282 +0.009277 +0.009291 +0.009271 +0.009246 +0.009293 +0.009369 +0.009361 +0.009395 +0.009366 +0.000166 +0.009338 +0.009393 +0.009475 +0.009463 +0.00948 +0.009461 +0.009438 +0.009494 +0.009575 +0.009566 +0.009583 +0.009555 +0.009523 +0.009595 +0.009654 +0.009655 +0.009681 +0.009663 +0.009623 +0.009703 +0.009783 +0.009775 +0.009808 +0.009782 +0.009764 +0.009835 +0.009928 +0.009854 +0.009787 +0.009745 +0.009687 +0.009715 +0.009744 +0.009677 +0.009607 +0.009534 +0.009467 +0.009457 +0.009493 +0.009431 +0.009428 +0.009376 +0.00931 +0.009307 +0.009306 +0.009287 +0.00927 +0.009244 +0.0092 +0.009249 +0.009304 +0.009265 +0.00929 +0.009232 +0.009164 +0.009197 +0.009253 +0.009234 +0.009251 +0.009222 +0.009207 +0.009266 +0.009337 +0.009337 +0.00935 +0.009323 +0.009306 +0.009373 +0.009452 +0.009431 +0.009466 +0.000167 +0.009439 +0.009409 +0.009447 +0.00949 +0.009473 +0.009503 +0.009497 +0.009463 +0.009531 +0.009611 +0.009594 +0.009624 +0.009597 +0.009563 +0.009625 +0.009701 +0.00969 +0.009706 +0.009682 +0.009659 +0.009734 +0.009826 +0.009828 +0.009825 +0.009801 +0.009776 +0.00983 +0.00993 +0.009917 +0.009932 +0.009888 +0.009828 +0.009839 +0.009863 +0.009794 +0.009749 +0.009652 +0.009548 +0.009546 +0.009563 +0.009502 +0.009473 +0.0094 +0.009319 +0.009334 +0.009365 +0.009324 +0.009307 +0.009253 +0.009185 +0.009218 +0.009263 +0.009234 +0.009241 +0.009188 +0.009139 +0.00918 +0.009235 +0.009213 +0.009224 +0.009186 +0.009142 +0.00919 +0.009256 +0.009245 +0.009263 +0.009236 +0.009202 +0.009264 +0.009331 +0.00933 +0.009359 +0.009337 +0.009297 +0.009346 +0.000168 +0.009441 +0.009426 +0.009455 +0.00942 +0.009405 +0.009451 +0.009533 +0.009527 +0.009558 +0.009521 +0.009497 +0.009547 +0.009634 +0.009627 +0.009655 +0.009617 +0.009599 +0.009655 +0.009747 +0.009728 +0.00976 +0.009741 +0.009721 +0.009784 +0.009883 +0.00987 +0.009906 +0.009804 +0.00975 +0.009795 +0.00986 +0.009794 +0.009785 +0.009708 +0.009577 +0.009563 +0.009607 +0.009545 +0.009555 +0.00947 +0.009366 +0.009355 +0.009399 +0.009346 +0.009362 +0.009287 +0.009261 +0.009277 +0.00931 +0.009271 +0.009285 +0.00924 +0.009179 +0.009197 +0.009267 +0.009233 +0.009271 +0.009236 +0.009203 +0.009266 +0.009343 +0.009312 +0.009347 +0.009319 +0.0093 +0.009367 +0.00945 +0.00941 +0.009414 +0.009379 +0.000169 +0.009369 +0.009416 +0.009516 +0.009484 +0.009522 +0.009481 +0.009469 +0.009527 +0.009626 +0.009588 +0.009626 +0.009587 +0.009571 +0.009601 +0.00968 +0.00964 +0.009682 +0.009641 +0.009629 +0.00967 +0.009768 +0.009744 +0.009816 +0.009791 +0.00978 +0.009821 +0.009911 +0.009876 +0.009921 +0.00986 +0.009854 +0.009899 +0.009973 +0.0099 +0.009881 +0.009782 +0.009695 +0.009669 +0.009697 +0.009616 +0.009594 +0.009495 +0.00944 +0.009434 +0.009482 +0.009426 +0.009422 +0.009342 +0.00929 +0.009296 +0.009357 +0.009307 +0.009312 +0.009246 +0.009215 +0.009236 +0.009301 +0.009265 +0.009282 +0.009222 +0.009194 +0.009223 +0.009302 +0.009268 +0.009295 +0.009245 +0.009225 +0.009269 +0.009361 +0.009335 +0.009377 +0.009328 +0.009321 +0.009355 +0.00946 +0.009437 +0.00017 +0.009465 +0.009436 +0.00941 +0.009459 +0.009552 +0.00954 +0.009565 +0.009533 +0.009511 +0.009559 +0.009646 +0.009636 +0.009668 +0.009631 +0.009604 +0.009658 +0.00975 +0.009736 +0.009779 +0.009731 +0.009728 +0.009777 +0.009885 +0.009862 +0.009906 +0.009871 +0.009857 +0.009813 +0.009843 +0.009793 +0.00981 +0.009738 +0.009684 +0.0097 +0.00976 +0.009677 +0.009566 +0.00951 +0.009462 +0.009482 +0.009547 +0.009488 +0.009484 +0.00937 +0.009322 +0.00936 +0.009411 +0.009375 +0.009383 +0.009315 +0.009273 +0.009292 +0.009369 +0.009325 +0.00937 +0.009313 +0.00929 +0.009344 +0.009413 +0.009404 +0.009389 +0.009346 +0.009327 +0.009377 +0.009472 +0.009446 +0.009474 +0.009463 +0.009441 +0.009484 +0.000171 +0.00958 +0.009561 +0.009582 +0.009557 +0.009532 +0.009609 +0.009689 +0.009673 +0.009693 +0.009668 +0.009642 +0.009668 +0.009731 +0.009707 +0.00973 +0.009706 +0.009678 +0.009742 +0.009822 +0.009852 +0.009895 +0.009867 +0.00984 +0.009891 +0.009962 +0.00996 +0.009964 +0.00995 +0.009901 +0.009959 +0.010014 +0.00995 +0.009904 +0.00983 +0.009724 +0.009707 +0.009729 +0.009667 +0.009611 +0.009551 +0.009475 +0.009471 +0.009522 +0.009473 +0.009448 +0.009393 +0.009332 +0.009344 +0.009404 +0.00937 +0.009358 +0.009315 +0.009272 +0.009301 +0.00936 +0.009339 +0.009336 +0.009303 +0.009261 +0.009299 +0.009372 +0.009354 +0.009361 +0.009341 +0.009307 +0.009354 +0.009438 +0.00943 +0.009444 +0.00943 +0.009395 +0.00946 +0.009544 +0.000172 +0.009514 +0.009545 +0.009528 +0.009499 +0.009554 +0.009628 +0.009622 +0.009651 +0.009626 +0.009596 +0.009653 +0.009731 +0.009729 +0.009752 +0.009725 +0.009694 +0.009757 +0.009843 +0.009835 +0.009866 +0.009827 +0.009815 +0.009879 +0.009972 +0.009979 +0.009986 +0.009978 +0.009882 +0.009891 +0.009953 +0.009924 +0.009923 +0.009871 +0.009803 +0.00983 +0.009889 +0.009796 +0.009707 +0.009649 +0.00959 +0.009637 +0.009657 +0.009602 +0.009605 +0.009522 +0.009456 +0.00948 +0.009517 +0.009497 +0.009494 +0.009465 +0.009409 +0.009475 +0.009541 +0.009509 +0.009534 +0.009437 +0.009419 +0.009468 +0.009535 +0.009523 +0.009541 +0.00952 +0.009493 +0.009554 +0.009644 +0.009625 +0.009652 +0.009625 +0.009585 +0.000173 +0.009608 +0.009695 +0.009667 +0.009716 +0.009684 +0.009663 +0.009722 +0.00981 +0.009797 +0.009833 +0.009801 +0.009776 +0.009838 +0.009915 +0.009894 +0.009922 +0.009886 +0.009862 +0.009919 +0.010016 +0.010015 +0.010045 +0.010005 +0.009988 +0.010047 +0.01013 +0.01012 +0.010147 +0.010119 +0.010091 +0.010111 +0.010173 +0.010107 +0.010081 +0.009981 +0.009896 +0.009876 +0.009909 +0.009838 +0.009815 +0.009733 +0.009662 +0.009666 +0.009723 +0.009663 +0.009655 +0.009595 +0.009543 +0.009555 +0.009621 +0.009584 +0.009584 +0.009543 +0.009498 +0.00952 +0.009593 +0.009566 +0.009577 +0.009538 +0.009506 +0.009536 +0.00962 +0.009603 +0.009628 +0.009597 +0.009575 +0.009619 +0.009714 +0.009692 +0.009728 +0.009696 +0.009671 +0.000174 +0.009726 +0.009811 +0.0098 +0.00983 +0.009803 +0.009778 +0.00983 +0.009914 +0.009907 +0.009934 +0.009909 +0.00988 +0.009936 +0.010015 +0.010015 +0.010038 +0.010009 +0.009985 +0.010053 +0.010136 +0.010134 +0.010162 +0.010132 +0.010124 +0.010199 +0.010289 +0.010258 +0.010166 +0.010114 +0.010058 +0.010103 +0.010139 +0.010076 +0.010001 +0.009894 +0.009831 +0.009851 +0.009878 +0.009824 +0.009782 +0.009694 +0.009643 +0.009656 +0.009681 +0.009653 +0.009631 +0.009611 +0.009555 +0.009602 +0.009632 +0.009589 +0.009605 +0.00957 +0.009548 +0.00957 +0.00962 +0.009596 +0.009605 +0.009602 +0.009567 +0.009627 +0.009715 +0.009686 +0.009707 +0.009702 +0.009668 +0.009702 +0.009777 +0.00974 +0.009774 +0.000175 +0.009765 +0.009731 +0.009801 +0.00988 +0.009867 +0.009897 +0.009868 +0.009848 +0.00991 +0.00999 +0.009975 +0.009992 +0.00996 +0.009929 +0.009989 +0.010071 +0.010056 +0.01009 +0.01009 +0.010071 +0.01012 +0.010198 +0.010192 +0.010207 +0.010184 +0.010155 +0.010223 +0.010281 +0.010236 +0.010205 +0.010144 +0.010029 +0.010033 +0.010058 +0.009988 +0.009953 +0.009878 +0.009795 +0.009805 +0.009853 +0.009799 +0.009789 +0.009732 +0.009662 +0.009684 +0.00974 +0.009701 +0.009695 +0.009656 +0.009599 +0.009627 +0.009691 +0.009663 +0.009664 +0.009628 +0.009578 +0.009613 +0.009687 +0.009662 +0.009673 +0.009648 +0.009616 +0.009661 +0.009747 +0.009736 +0.009762 +0.009736 +0.009705 +0.009777 +0.009839 +0.009853 +0.000176 +0.00986 +0.009832 +0.009814 +0.00987 +0.009955 +0.009945 +0.009975 +0.009941 +0.009921 +0.009976 +0.010062 +0.010047 +0.010076 +0.010049 +0.010022 +0.010079 +0.01018 +0.010165 +0.010202 +0.010175 +0.010155 +0.010223 +0.010335 +0.010306 +0.010283 +0.010156 +0.010113 +0.010141 +0.010202 +0.010139 +0.010062 +0.009953 +0.009895 +0.009888 +0.009921 +0.009848 +0.009851 +0.0098 +0.009703 +0.009693 +0.009722 +0.009693 +0.0097 +0.009665 +0.009615 +0.00967 +0.009731 +0.009705 +0.009722 +0.009665 +0.009595 +0.009611 +0.009695 +0.00966 +0.009694 +0.009665 +0.00964 +0.009702 +0.009791 +0.00977 +0.009799 +0.009765 +0.009744 +0.00982 +0.009904 +0.009875 +0.000177 +0.009925 +0.009883 +0.009843 +0.009851 +0.009944 +0.00991 +0.009959 +0.00992 +0.009927 +0.009965 +0.010065 +0.010044 +0.010084 +0.010047 +0.010028 +0.010076 +0.01017 +0.010165 +0.010211 +0.010169 +0.010149 +0.010189 +0.010285 +0.010278 +0.010322 +0.010273 +0.010259 +0.01031 +0.010382 +0.010326 +0.010327 +0.010219 +0.010132 +0.010109 +0.010133 +0.010039 +0.010022 +0.009906 +0.00984 +0.009839 +0.009889 +0.009822 +0.009822 +0.009739 +0.009685 +0.009688 +0.009747 +0.009694 +0.009717 +0.009632 +0.009605 +0.009621 +0.009692 +0.009646 +0.009672 +0.009602 +0.009578 +0.009598 +0.009675 +0.009641 +0.009668 +0.00962 +0.009604 +0.009639 +0.009725 +0.009714 +0.009752 +0.009703 +0.009701 +0.009733 +0.009838 +0.009811 +0.009852 +0.000178 +0.009818 +0.009789 +0.009847 +0.009942 +0.009917 +0.009956 +0.009919 +0.009906 +0.009948 +0.010048 +0.010024 +0.010063 +0.010023 +0.010009 +0.010068 +0.010163 +0.010149 +0.010192 +0.010146 +0.010144 +0.010204 +0.010317 +0.010294 +0.010262 +0.010153 +0.010124 +0.010149 +0.01021 +0.010137 +0.010094 +0.00996 +0.009908 +0.009911 +0.009942 +0.009858 +0.009868 +0.009772 +0.009674 +0.00969 +0.009731 +0.009689 +0.009696 +0.009645 +0.009603 +0.009616 +0.009655 +0.009609 +0.009641 +0.009586 +0.009573 +0.009605 +0.009694 +0.00965 +0.009673 +0.009607 +0.009575 +0.009627 +0.009726 +0.009675 +0.009739 +0.009679 +0.009676 +0.009744 +0.009834 +0.009797 +0.009858 +0.009804 +0.000179 +0.009782 +0.009863 +0.009941 +0.009906 +0.009935 +0.009888 +0.009873 +0.009914 +0.010001 +0.009964 +0.010002 +0.009972 +0.009953 +0.010004 +0.010093 +0.010072 +0.010109 +0.010098 +0.010092 +0.010143 +0.010228 +0.010217 +0.010242 +0.010223 +0.0102 +0.010253 +0.010326 +0.0103 +0.010304 +0.010209 +0.01013 +0.010116 +0.010138 +0.010061 +0.010026 +0.009925 +0.009854 +0.009848 +0.00989 +0.009836 +0.009822 +0.009745 +0.009689 +0.009698 +0.009749 +0.009701 +0.009704 +0.009645 +0.009608 +0.009636 +0.009684 +0.009673 +0.009668 +0.009624 +0.009597 +0.009627 +0.0097 +0.009683 +0.009694 +0.009662 +0.009642 +0.009692 +0.009761 +0.00976 +0.009783 +0.009757 +0.00974 +0.009781 +0.009872 +0.009861 +0.00018 +0.009891 +0.00987 +0.009828 +0.009895 +0.009972 +0.009971 +0.009996 +0.009967 +0.00994 +0.01 +0.010086 +0.010076 +0.010099 +0.010069 +0.010045 +0.010116 +0.010194 +0.010198 +0.010221 +0.010207 +0.010177 +0.010256 +0.010353 +0.010347 +0.010328 +0.010214 +0.010165 +0.010206 +0.010257 +0.010195 +0.010167 +0.010024 +0.009945 +0.009956 +0.009998 +0.009923 +0.009909 +0.009824 +0.009729 +0.009752 +0.009801 +0.009757 +0.009753 +0.00971 +0.009614 +0.009627 +0.009691 +0.009663 +0.009674 +0.009652 +0.009598 +0.009659 +0.009726 +0.009694 +0.009725 +0.009692 +0.009631 +0.00964 +0.00969 +0.009693 +0.009724 +0.009694 +0.009683 +0.009741 +0.009819 +0.00982 +0.00984 +0.009821 +0.009801 +0.009851 +0.000181 +0.009945 +0.009938 +0.009957 +0.009934 +0.009918 +0.009984 +0.010071 +0.010046 +0.010065 +0.01003 +0.009973 +0.010013 +0.010085 +0.010071 +0.010086 +0.010074 +0.010046 +0.010135 +0.010253 +0.010249 +0.01027 +0.010225 +0.010203 +0.010252 +0.010333 +0.010301 +0.01031 +0.010241 +0.010142 +0.010134 +0.010152 +0.010078 +0.01003 +0.009947 +0.00986 +0.009862 +0.009901 +0.009848 +0.009821 +0.009757 +0.009683 +0.009701 +0.00975 +0.009707 +0.009688 +0.009645 +0.00959 +0.009612 +0.009676 +0.009652 +0.009644 +0.009603 +0.009557 +0.009589 +0.009661 +0.00964 +0.009642 +0.009609 +0.009576 +0.009615 +0.009696 +0.009692 +0.009704 +0.009681 +0.009647 +0.009699 +0.009798 +0.009778 +0.009823 +0.009765 +0.009754 +0.000182 +0.00981 +0.009891 +0.00989 +0.009915 +0.009884 +0.009853 +0.009915 +0.01 +0.010004 +0.010012 +0.009992 +0.009964 +0.010023 +0.010101 +0.010094 +0.010124 +0.010094 +0.010066 +0.010143 +0.010213 +0.010219 +0.010252 +0.010222 +0.010203 +0.010281 +0.010377 +0.010358 +0.010273 +0.01019 +0.01013 +0.01016 +0.010203 +0.010141 +0.010059 +0.009941 +0.009875 +0.009896 +0.009929 +0.009863 +0.009849 +0.009756 +0.009675 +0.009714 +0.00974 +0.009713 +0.009704 +0.00967 +0.009607 +0.009618 +0.009657 +0.009643 +0.009656 +0.009616 +0.009593 +0.009628 +0.00971 +0.00968 +0.009695 +0.009677 +0.009617 +0.009618 +0.00969 +0.009666 +0.009709 +0.00969 +0.009658 +0.009731 +0.009808 +0.009804 +0.009832 +0.009809 +0.009779 +0.009848 +0.000183 +0.009939 +0.009922 +0.009953 +0.009923 +0.009908 +0.009976 +0.010064 +0.010039 +0.010067 +0.010016 +0.009956 +0.009998 +0.010084 +0.010056 +0.010076 +0.010055 +0.010036 +0.010136 +0.010254 +0.010234 +0.010266 +0.010215 +0.010192 +0.010236 +0.010283 +0.010237 +0.010239 +0.010125 +0.010031 +0.010016 +0.010045 +0.009959 +0.009935 +0.009829 +0.00976 +0.00976 +0.009796 +0.009746 +0.009731 +0.009649 +0.009591 +0.009604 +0.009654 +0.009613 +0.00962 +0.009555 +0.009515 +0.009532 +0.009596 +0.009572 +0.00958 +0.009526 +0.009493 +0.009518 +0.009586 +0.009578 +0.009584 +0.009541 +0.009518 +0.009563 +0.009647 +0.009629 +0.009664 +0.009621 +0.009613 +0.00965 +0.009753 +0.009742 +0.009752 +0.000184 +0.009727 +0.009712 +0.009756 +0.009852 +0.009831 +0.009874 +0.009834 +0.009817 +0.009856 +0.009958 +0.009937 +0.009979 +0.009937 +0.009919 +0.009967 +0.010056 +0.010043 +0.010081 +0.010033 +0.010035 +0.01008 +0.01019 +0.010169 +0.010205 +0.010167 +0.010172 +0.010241 +0.010308 +0.010186 +0.010206 +0.010132 +0.010074 +0.010048 +0.010068 +0.009992 +0.009989 +0.009902 +0.009798 +0.009785 +0.009827 +0.009791 +0.00979 +0.009719 +0.009691 +0.00965 +0.0097 +0.009637 +0.00967 +0.009605 +0.009583 +0.009609 +0.009695 +0.009648 +0.009664 +0.009612 +0.009548 +0.009546 +0.009643 +0.009594 +0.009636 +0.00958 +0.009566 +0.009619 +0.009718 +0.009684 +0.009727 +0.009689 +0.009675 +0.009727 +0.009837 +0.009805 +0.009832 +0.000185 +0.009811 +0.00976 +0.00976 +0.009866 +0.009842 +0.009886 +0.009849 +0.00984 +0.009892 +0.009991 +0.009967 +0.010001 +0.009962 +0.009948 +0.009991 +0.010089 +0.010074 +0.01013 +0.010089 +0.010068 +0.010107 +0.010217 +0.010196 +0.010239 +0.010203 +0.010178 +0.010224 +0.010322 +0.010273 +0.010277 +0.010184 +0.010101 +0.010074 +0.01011 +0.01001 +0.009978 +0.009875 +0.009791 +0.009786 +0.009842 +0.00977 +0.009755 +0.009683 +0.009624 +0.009626 +0.009699 +0.009645 +0.009643 +0.009583 +0.009542 +0.00955 +0.009632 +0.009588 +0.009601 +0.009546 +0.009512 +0.00953 +0.009613 +0.009579 +0.009607 +0.009564 +0.009537 +0.009574 +0.009668 +0.009644 +0.00969 +0.009646 +0.009624 +0.009672 +0.009761 +0.009772 +0.009765 +0.000186 +0.009751 +0.009727 +0.009771 +0.009874 +0.009852 +0.009894 +0.009849 +0.009834 +0.009883 +0.009981 +0.009958 +0.009991 +0.009949 +0.009935 +0.009991 +0.010085 +0.010061 +0.01011 +0.010064 +0.010064 +0.010102 +0.010223 +0.010196 +0.010238 +0.010203 +0.010202 +0.010172 +0.010179 +0.010123 +0.010142 +0.010046 +0.009993 +0.010009 +0.010052 +0.009901 +0.009877 +0.009788 +0.009754 +0.009703 +0.009755 +0.00969 +0.0097 +0.009635 +0.009605 +0.009598 +0.009613 +0.009549 +0.009572 +0.009517 +0.009494 +0.009532 +0.0096 +0.009566 +0.009575 +0.009539 +0.009466 +0.009467 +0.009555 +0.009514 +0.009557 +0.009509 +0.009491 +0.009556 +0.00964 +0.009615 +0.009669 +0.009608 +0.009608 +0.009664 +0.009757 +0.009731 +0.009775 +0.000187 +0.009733 +0.009718 +0.009756 +0.009815 +0.009785 +0.00982 +0.009788 +0.009774 +0.009829 +0.009921 +0.009894 +0.009926 +0.009891 +0.009868 +0.009918 +0.009999 +0.009982 +0.010038 +0.01003 +0.010011 +0.010058 +0.010148 +0.010112 +0.010151 +0.01011 +0.01011 +0.010153 +0.010231 +0.010197 +0.010189 +0.010103 +0.010032 +0.010021 +0.010049 +0.009986 +0.009956 +0.009867 +0.009809 +0.009811 +0.009858 +0.00982 +0.009809 +0.009745 +0.0097 +0.009717 +0.009784 +0.009754 +0.009753 +0.009702 +0.009659 +0.009687 +0.009763 +0.009735 +0.009749 +0.009689 +0.009657 +0.009675 +0.009743 +0.009743 +0.009763 +0.009718 +0.009693 +0.009733 +0.009807 +0.009806 +0.009842 +0.00981 +0.009787 +0.009834 +0.00992 +0.009895 +0.000188 +0.009936 +0.00991 +0.009893 +0.009936 +0.010035 +0.010006 +0.010042 +0.010002 +0.009997 +0.01004 +0.010142 +0.010118 +0.010157 +0.010106 +0.010095 +0.010155 +0.010245 +0.010233 +0.010271 +0.010238 +0.010225 +0.010285 +0.010408 +0.010364 +0.010408 +0.010333 +0.010231 +0.010239 +0.010314 +0.01024 +0.010239 +0.010156 +0.010038 +0.010002 +0.010065 +0.009995 +0.010017 +0.009926 +0.009866 +0.009814 +0.009854 +0.009808 +0.009827 +0.009772 +0.009728 +0.009769 +0.009832 +0.00979 +0.009743 +0.009706 +0.009674 +0.009718 +0.009805 +0.009752 +0.00981 +0.009747 +0.009742 +0.009801 +0.009878 +0.009857 +0.009846 +0.009799 +0.009795 +0.009842 +0.009948 +0.009908 +0.00995 +0.000189 +0.009918 +0.009908 +0.009957 +0.010064 +0.010033 +0.010073 +0.010026 +0.010026 +0.010086 +0.010187 +0.010141 +0.010174 +0.010108 +0.010089 +0.010145 +0.010237 +0.010192 +0.010237 +0.010185 +0.010176 +0.010215 +0.010322 +0.01035 +0.010403 +0.010365 +0.010336 +0.010357 +0.010434 +0.010347 +0.010321 +0.010243 +0.010165 +0.010129 +0.010165 +0.010073 +0.01004 +0.009946 +0.009879 +0.00987 +0.009931 +0.009857 +0.00985 +0.009779 +0.009718 +0.009719 +0.009789 +0.009727 +0.009735 +0.009674 +0.009628 +0.009635 +0.009715 +0.009671 +0.009686 +0.009635 +0.009603 +0.009617 +0.009704 +0.009672 +0.009703 +0.009664 +0.009642 +0.009673 +0.009774 +0.009749 +0.009791 +0.009758 +0.00973 +0.009778 +0.00987 +0.009857 +0.00019 +0.009892 +0.009859 +0.009839 +0.009882 +0.00998 +0.009961 +0.010002 +0.009964 +0.009946 +0.009989 +0.010089 +0.010066 +0.010099 +0.010066 +0.010054 +0.0101 +0.010194 +0.010184 +0.010217 +0.010186 +0.010174 +0.010229 +0.010344 +0.010315 +0.010361 +0.010326 +0.010257 +0.010236 +0.010306 +0.010263 +0.010272 +0.010195 +0.010146 +0.010159 +0.010226 +0.010103 +0.010018 +0.009959 +0.0099 +0.009923 +0.009991 +0.009907 +0.009887 +0.009784 +0.009764 +0.009772 +0.009848 +0.009772 +0.0098 +0.009748 +0.009694 +0.009685 +0.00974 +0.009713 +0.009742 +0.009687 +0.009683 +0.009722 +0.009798 +0.009776 +0.009803 +0.009766 +0.009764 +0.009811 +0.00991 +0.009852 +0.009857 +0.009828 +0.009816 +0.000191 +0.009857 +0.00997 +0.009926 +0.009962 +0.009936 +0.009928 +0.009978 +0.010077 +0.010039 +0.010098 +0.010044 +0.010034 +0.010084 +0.010168 +0.01012 +0.010155 +0.010108 +0.010088 +0.01014 +0.010237 +0.010207 +0.010251 +0.010242 +0.010257 +0.010288 +0.010394 +0.01036 +0.010375 +0.01031 +0.010262 +0.010239 +0.010274 +0.01017 +0.010135 +0.010023 +0.009934 +0.009905 +0.009949 +0.009864 +0.009848 +0.009766 +0.009704 +0.009695 +0.009758 +0.009689 +0.0097 +0.009617 +0.009574 +0.00958 +0.009661 +0.009603 +0.009608 +0.009564 +0.00953 +0.009539 +0.00962 +0.00958 +0.009604 +0.009555 +0.009532 +0.009558 +0.00965 +0.009625 +0.009655 +0.009625 +0.009605 +0.009651 +0.009739 +0.009715 +0.009761 +0.009723 +0.000192 +0.009709 +0.009752 +0.009837 +0.009828 +0.009856 +0.009828 +0.009806 +0.009859 +0.009946 +0.00993 +0.009958 +0.009934 +0.009917 +0.009966 +0.010052 +0.010036 +0.010073 +0.010038 +0.010017 +0.010086 +0.01017 +0.01017 +0.010206 +0.010169 +0.010164 +0.010231 +0.010235 +0.010173 +0.01018 +0.010117 +0.010069 +0.010055 +0.010057 +0.009973 +0.009969 +0.009901 +0.009794 +0.009761 +0.009806 +0.009746 +0.009743 +0.00969 +0.009644 +0.009657 +0.009669 +0.009602 +0.009612 +0.009575 +0.009528 +0.009586 +0.00962 +0.009573 +0.009599 +0.009552 +0.009542 +0.009577 +0.009641 +0.009596 +0.009612 +0.00959 +0.009555 +0.009614 +0.009692 +0.009649 +0.009692 +0.009661 +0.009634 +0.009683 +0.009759 +0.009716 +0.009767 +0.009736 +0.000193 +0.009713 +0.009781 +0.009864 +0.009848 +0.009877 +0.00985 +0.009826 +0.009898 +0.009983 +0.009964 +0.009988 +0.009967 +0.009937 +0.009995 +0.01007 +0.010039 +0.010058 +0.010032 +0.01 +0.010057 +0.010132 +0.010124 +0.010149 +0.010164 +0.010162 +0.01021 +0.010295 +0.010265 +0.010259 +0.0102 +0.010109 +0.01012 +0.010151 +0.010056 +0.009997 +0.009908 +0.009802 +0.009792 +0.00982 +0.009753 +0.009717 +0.009648 +0.009569 +0.009569 +0.009612 +0.009558 +0.00954 +0.00949 +0.009419 +0.009439 +0.009501 +0.009469 +0.009458 +0.00942 +0.00937 +0.009399 +0.009466 +0.009443 +0.009446 +0.009417 +0.009375 +0.00942 +0.009495 +0.009473 +0.009496 +0.009479 +0.009446 +0.009499 +0.009581 +0.009567 +0.009598 +0.009573 +0.009554 +0.000194 +0.009593 +0.009683 +0.009669 +0.009701 +0.00967 +0.009652 +0.0097 +0.009788 +0.009776 +0.009803 +0.009775 +0.009757 +0.009809 +0.00989 +0.009876 +0.009904 +0.009876 +0.009856 +0.009909 +0.010003 +0.009991 +0.010028 +0.009996 +0.009989 +0.010055 +0.010153 +0.010133 +0.010113 +0.01001 +0.009964 +0.010007 +0.010067 +0.009996 +0.009989 +0.009866 +0.009759 +0.009762 +0.009826 +0.009765 +0.009748 +0.009675 +0.009593 +0.009574 +0.009635 +0.009593 +0.009588 +0.009547 +0.009484 +0.009525 +0.009553 +0.009533 +0.009533 +0.009502 +0.009447 +0.009463 +0.009525 +0.009501 +0.009535 +0.00948 +0.009468 +0.009513 +0.009591 +0.009576 +0.009598 +0.00958 +0.009558 +0.009597 +0.009676 +0.009641 +0.009662 +0.009647 +0.000195 +0.009638 +0.009683 +0.009779 +0.009749 +0.00979 +0.009749 +0.009737 +0.009758 +0.009841 +0.009813 +0.009856 +0.009813 +0.009806 +0.009846 +0.009942 +0.009915 +0.009949 +0.009913 +0.009932 +0.009989 +0.010091 +0.010062 +0.010099 +0.010046 +0.010029 +0.010075 +0.010184 +0.010176 +0.010201 +0.010139 +0.010107 +0.010105 +0.010148 +0.01007 +0.010033 +0.009919 +0.009843 +0.009813 +0.009851 +0.009779 +0.00976 +0.009677 +0.009626 +0.009623 +0.009689 +0.00964 +0.009639 +0.009563 +0.009532 +0.009541 +0.00962 +0.00959 +0.009603 +0.009545 +0.009524 +0.009545 +0.009639 +0.009602 +0.009632 +0.009582 +0.00957 +0.0096 +0.009693 +0.009682 +0.009712 +0.009673 +0.009659 +0.009713 +0.009788 +0.000196 +0.009773 +0.009822 +0.009773 +0.009774 +0.009801 +0.009897 +0.009886 +0.009924 +0.009882 +0.009865 +0.009914 +0.010013 +0.009992 +0.010023 +0.009989 +0.009973 +0.010023 +0.010111 +0.010099 +0.010145 +0.01009 +0.010093 +0.010135 +0.010246 +0.010225 +0.010271 +0.010233 +0.010232 +0.01026 +0.010261 +0.010189 +0.010196 +0.010131 +0.010083 +0.010048 +0.010047 +0.009967 +0.009965 +0.009888 +0.009793 +0.009762 +0.009815 +0.009768 +0.009773 +0.00972 +0.009678 +0.009666 +0.009703 +0.009643 +0.009682 +0.009615 +0.009601 +0.009635 +0.009696 +0.009652 +0.009676 +0.009607 +0.009571 +0.009601 +0.009664 +0.009629 +0.009675 +0.009625 +0.009631 +0.009672 +0.009765 +0.009743 +0.009775 +0.009747 +0.009738 +0.00979 +0.00988 +0.000197 +0.00986 +0.009895 +0.009856 +0.009827 +0.009823 +0.009924 +0.009888 +0.009942 +0.009901 +0.009895 +0.009945 +0.01004 +0.010019 +0.01006 +0.010017 +0.010014 +0.01007 +0.010175 +0.010149 +0.010181 +0.010132 +0.010133 +0.010181 +0.010277 +0.010259 +0.010294 +0.010252 +0.010229 +0.010234 +0.010294 +0.010216 +0.010184 +0.010069 +0.009984 +0.009952 +0.009981 +0.009901 +0.009879 +0.009782 +0.009734 +0.009705 +0.009767 +0.009705 +0.009698 +0.009615 +0.009569 +0.009564 +0.009634 +0.009587 +0.009591 +0.009535 +0.009506 +0.009509 +0.009586 +0.009555 +0.009574 +0.009519 +0.009501 +0.009525 +0.009607 +0.00959 +0.009629 +0.009574 +0.009573 +0.00961 +0.009711 +0.009678 +0.009723 +0.009686 +0.009676 +0.000198 +0.009714 +0.009813 +0.009784 +0.009818 +0.009788 +0.009771 +0.009825 +0.009906 +0.009896 +0.009925 +0.009895 +0.009876 +0.009936 +0.01001 +0.009999 +0.010039 +0.010006 +0.009979 +0.010049 +0.010136 +0.010125 +0.010164 +0.010125 +0.010124 +0.010191 +0.010228 +0.010177 +0.010217 +0.01019 +0.010163 +0.010216 +0.010294 +0.010241 +0.010239 +0.010131 +0.010083 +0.010098 +0.010134 +0.010072 +0.010083 +0.010007 +0.009969 +0.009919 +0.009962 +0.009905 +0.009935 +0.009863 +0.009842 +0.009865 +0.009949 +0.009891 +0.009911 +0.009793 +0.009762 +0.009795 +0.009896 +0.009835 +0.009883 +0.009836 +0.009829 +0.009882 +0.009936 +0.00992 +0.009941 +0.00993 +0.009896 +0.009989 +0.010038 +0.010023 +0.010067 +0.000199 +0.010024 +0.01001 +0.010075 +0.010174 +0.010137 +0.010165 +0.010126 +0.010101 +0.010144 +0.010239 +0.010199 +0.010232 +0.010186 +0.010188 +0.01024 +0.010386 +0.010357 +0.010376 +0.010311 +0.010238 +0.010236 +0.010308 +0.010218 +0.010186 +0.010085 +0.009992 +0.009971 +0.010008 +0.009917 +0.009889 +0.009789 +0.009714 +0.009704 +0.009755 +0.009674 +0.009662 +0.009585 +0.009522 +0.009526 +0.009606 +0.009547 +0.009547 +0.009482 +0.009438 +0.00945 +0.009533 +0.009485 +0.0095 +0.009444 +0.009417 +0.009428 +0.009516 +0.009491 +0.009522 +0.009482 +0.009462 +0.009499 +0.009598 +0.009569 +0.009618 +0.009588 +0.009545 +0.009596 +0.009704 +0.00968 +0.0002 +0.009711 +0.009674 +0.009664 +0.009701 +0.0098 +0.009781 +0.009816 +0.009778 +0.009766 +0.009809 +0.009901 +0.009882 +0.009909 +0.009878 +0.009859 +0.009907 +0.010009 +0.00999 +0.010035 +0.009993 +0.009982 +0.010047 +0.01014 +0.010128 +0.010168 +0.010123 +0.010011 +0.009984 +0.010033 +0.009979 +0.00998 +0.009883 +0.009834 +0.009775 +0.009754 +0.009689 +0.009699 +0.009618 +0.009583 +0.009598 +0.009664 +0.009551 +0.009536 +0.00947 +0.009429 +0.009424 +0.009482 +0.009437 +0.009465 +0.009404 +0.009391 +0.009417 +0.009513 +0.009467 +0.009495 +0.009445 +0.009401 +0.009398 +0.00947 +0.009428 +0.009486 +0.009436 +0.00942 +0.009481 +0.009568 +0.009542 +0.009593 +0.009551 +0.009533 +0.009594 +0.009682 +0.009658 +0.000201 +0.009695 +0.009659 +0.009654 +0.009709 +0.009803 +0.009772 +0.009807 +0.009736 +0.009717 +0.009745 +0.009839 +0.009797 +0.00984 +0.009795 +0.009784 +0.009832 +0.00993 +0.009941 +0.010004 +0.009956 +0.009932 +0.00998 +0.010073 +0.010041 +0.010081 +0.010041 +0.010041 +0.010081 +0.010166 +0.010107 +0.0101 +0.010009 +0.009924 +0.009892 +0.009926 +0.00983 +0.009805 +0.009706 +0.009639 +0.009624 +0.009685 +0.009617 +0.009612 +0.009545 +0.009493 +0.009488 +0.009563 +0.009507 +0.009517 +0.009466 +0.009429 +0.009441 +0.009519 +0.009474 +0.009499 +0.009453 +0.00943 +0.009451 +0.009536 +0.009509 +0.009538 +0.009504 +0.009494 +0.009528 +0.009627 +0.009596 +0.009631 +0.009622 +0.009572 +0.009635 +0.000202 +0.009721 +0.009697 +0.009743 +0.009701 +0.009684 +0.009732 +0.009831 +0.009797 +0.009846 +0.009804 +0.009792 +0.009833 +0.009929 +0.009907 +0.009945 +0.009904 +0.0099 +0.009943 +0.010035 +0.010023 +0.010061 +0.010016 +0.010003 +0.01007 +0.010167 +0.010153 +0.010193 +0.010157 +0.010113 +0.010075 +0.010148 +0.010105 +0.010122 +0.010042 +0.009982 +0.009989 +0.010048 +0.009975 +0.009832 +0.00972 +0.009678 +0.009701 +0.009746 +0.009692 +0.009687 +0.00964 +0.009552 +0.009506 +0.009571 +0.009526 +0.009551 +0.009504 +0.009466 +0.009506 +0.009574 +0.009543 +0.009571 +0.009531 +0.009504 +0.009475 +0.00953 +0.009481 +0.009531 +0.009499 +0.009473 +0.009515 +0.009615 +0.009576 +0.00962 +0.009589 +0.009573 +0.009622 +0.009729 +0.0097 +0.009714 +0.009689 +0.000203 +0.009688 +0.009736 +0.009811 +0.009768 +0.0098 +0.009764 +0.009758 +0.009813 +0.009907 +0.009867 +0.009901 +0.009859 +0.009839 +0.009879 +0.009972 +0.009934 +0.009975 +0.009934 +0.009922 +0.009983 +0.010112 +0.010095 +0.010135 +0.010078 +0.010063 +0.010106 +0.010203 +0.010182 +0.010205 +0.01012 +0.010031 +0.010018 +0.010043 +0.009946 +0.009912 +0.009796 +0.009712 +0.009696 +0.009731 +0.009654 +0.009655 +0.009558 +0.009502 +0.009511 +0.009563 +0.009498 +0.009496 +0.00944 +0.009399 +0.009416 +0.009491 +0.009432 +0.009456 +0.009403 +0.00937 +0.00939 +0.009481 +0.009427 +0.009464 +0.00941 +0.009385 +0.009428 +0.009513 +0.009486 +0.00953 +0.009488 +0.009467 +0.009518 +0.009602 +0.009592 +0.009633 +0.009581 +0.000204 +0.009565 +0.009616 +0.009705 +0.009692 +0.00972 +0.009695 +0.009662 +0.009721 +0.009805 +0.009794 +0.009823 +0.009795 +0.009774 +0.009823 +0.009909 +0.009892 +0.009931 +0.009892 +0.009872 +0.009937 +0.01002 +0.010018 +0.01005 +0.010017 +0.010009 +0.010074 +0.010173 +0.010136 +0.010069 +0.010013 +0.009974 +0.010011 +0.010058 +0.009988 +0.009976 +0.009848 +0.009731 +0.009715 +0.009754 +0.0097 +0.009686 +0.009622 +0.009547 +0.009495 +0.009564 +0.009503 +0.009521 +0.009455 +0.009421 +0.009452 +0.009538 +0.009469 +0.009443 +0.009382 +0.009357 +0.009412 +0.009466 +0.009434 +0.009446 +0.009403 +0.009384 +0.009379 +0.009444 +0.009427 +0.009455 +0.00942 +0.009413 +0.009467 +0.009547 +0.009544 +0.009573 +0.009541 +0.009519 +0.00959 +0.009665 +0.000205 +0.009648 +0.009684 +0.009651 +0.009644 +0.009699 +0.009798 +0.009765 +0.009804 +0.009765 +0.009746 +0.009742 +0.009811 +0.009773 +0.009815 +0.009782 +0.009774 +0.009832 +0.009974 +0.009956 +0.009999 +0.009936 +0.00993 +0.009964 +0.010055 +0.010033 +0.010071 +0.010046 +0.010028 +0.010041 +0.010087 +0.010016 +0.009991 +0.009884 +0.009808 +0.009777 +0.009813 +0.009734 +0.009704 +0.009612 +0.009562 +0.009541 +0.0096 +0.009551 +0.009545 +0.009466 +0.009426 +0.009428 +0.009491 +0.009455 +0.00946 +0.009395 +0.009367 +0.009373 +0.009447 +0.009421 +0.009433 +0.009372 +0.009355 +0.009367 +0.009452 +0.009435 +0.009461 +0.009416 +0.009402 +0.00943 +0.009523 +0.009514 +0.009547 +0.009515 +0.009502 +0.009521 +0.009618 +0.000206 +0.00961 +0.009642 +0.009619 +0.009587 +0.009634 +0.009723 +0.009709 +0.009736 +0.009714 +0.009694 +0.009744 +0.009831 +0.009811 +0.009841 +0.009802 +0.009783 +0.009834 +0.009927 +0.0099 +0.009951 +0.009908 +0.009901 +0.009954 +0.010055 +0.010041 +0.010073 +0.010059 +0.010037 +0.01011 +0.010106 +0.010037 +0.010027 +0.00999 +0.009915 +0.00993 +0.009914 +0.009838 +0.009839 +0.009741 +0.009644 +0.009625 +0.009682 +0.009611 +0.009605 +0.009551 +0.009454 +0.009434 +0.009476 +0.009444 +0.009448 +0.009409 +0.009357 +0.009411 +0.009471 +0.009453 +0.00945 +0.009365 +0.009327 +0.009361 +0.009453 +0.009406 +0.009446 +0.009413 +0.009392 +0.00946 +0.009532 +0.009513 +0.009534 +0.009478 +0.009474 +0.009523 +0.009585 +0.009581 +0.000207 +0.0096 +0.009579 +0.00956 +0.009622 +0.0097 +0.009691 +0.009721 +0.009698 +0.009661 +0.009732 +0.009812 +0.009795 +0.009812 +0.009787 +0.009751 +0.009808 +0.009876 +0.009855 +0.009879 +0.00985 +0.00982 +0.009886 +0.009999 +0.01001 +0.010028 +0.010007 +0.009964 +0.010024 +0.010097 +0.010057 +0.01007 +0.009996 +0.009904 +0.009894 +0.009914 +0.009838 +0.009796 +0.009696 +0.009599 +0.009591 +0.009612 +0.009555 +0.009529 +0.009455 +0.009368 +0.009379 +0.009409 +0.009364 +0.009351 +0.009291 +0.00923 +0.009267 +0.009305 +0.00928 +0.009289 +0.009246 +0.009197 +0.009244 +0.009303 +0.009283 +0.009303 +0.009267 +0.00923 +0.00929 +0.009365 +0.009357 +0.009387 +0.009353 +0.009332 +0.009381 +0.009463 +0.009463 +0.009479 +0.000208 +0.009459 +0.009416 +0.009479 +0.00957 +0.009544 +0.009585 +0.009548 +0.009525 +0.009577 +0.009671 +0.009654 +0.009676 +0.009644 +0.009619 +0.009679 +0.00977 +0.009752 +0.009785 +0.009762 +0.009735 +0.009803 +0.009883 +0.00988 +0.009903 +0.009896 +0.009869 +0.009878 +0.009918 +0.009887 +0.009926 +0.009909 +0.009884 +0.009922 +0.010005 +0.009969 +0.009976 +0.009918 +0.009882 +0.009914 +0.009981 +0.009893 +0.009814 +0.00978 +0.009729 +0.009777 +0.009833 +0.009798 +0.00981 +0.009734 +0.009664 +0.009685 +0.009768 +0.009708 +0.009754 +0.009701 +0.009683 +0.00973 +0.00981 +0.009792 +0.009778 +0.009727 +0.009732 +0.009759 +0.009864 +0.009835 +0.009875 +0.009852 +0.009833 +0.009883 +0.000209 +0.009983 +0.009944 +0.009988 +0.009959 +0.00995 +0.010001 +0.010099 +0.010065 +0.0101 +0.010051 +0.010033 +0.010072 +0.010165 +0.010135 +0.010157 +0.010114 +0.010114 +0.010186 +0.010316 +0.01028 +0.010291 +0.010227 +0.010163 +0.010149 +0.010213 +0.010131 +0.0101 +0.009996 +0.009919 +0.009887 +0.009934 +0.009845 +0.009825 +0.009728 +0.009655 +0.009636 +0.009692 +0.009616 +0.009596 +0.009528 +0.00947 +0.00947 +0.009543 +0.00949 +0.009498 +0.009424 +0.009402 +0.009413 +0.009495 +0.00946 +0.009475 +0.009428 +0.009402 +0.009436 +0.009528 +0.009506 +0.009533 +0.009497 +0.009477 +0.009522 +0.00962 +0.00959 +0.009639 +0.009594 +0.009579 +0.00021 +0.009627 +0.009711 +0.009702 +0.009736 +0.009695 +0.009678 +0.009734 +0.009819 +0.009806 +0.009836 +0.009804 +0.00979 +0.009825 +0.009919 +0.009908 +0.009937 +0.009899 +0.009886 +0.009946 +0.010026 +0.010025 +0.010057 +0.010026 +0.010009 +0.010074 +0.010185 +0.010158 +0.010194 +0.010069 +0.010023 +0.010066 +0.010135 +0.010052 +0.010051 +0.009931 +0.009834 +0.009838 +0.009874 +0.009807 +0.009799 +0.009741 +0.009642 +0.009614 +0.00967 +0.009604 +0.00963 +0.009553 +0.009537 +0.009557 +0.009602 +0.009535 +0.009566 +0.009508 +0.00945 +0.009477 +0.009524 +0.009504 +0.009529 +0.00948 +0.009472 +0.009515 +0.009596 +0.009573 +0.009593 +0.009577 +0.009562 +0.009582 +0.009657 +0.009621 +0.009648 +0.009635 +0.009621 +0.009666 +0.000211 +0.009756 +0.00975 +0.009769 +0.009747 +0.009726 +0.009801 +0.009881 +0.009856 +0.00988 +0.009858 +0.009834 +0.009896 +0.009966 +0.009932 +0.009953 +0.009921 +0.009887 +0.009951 +0.010012 +0.010002 +0.010033 +0.010012 +0.010018 +0.010103 +0.01018 +0.01016 +0.010174 +0.010108 +0.010041 +0.010058 +0.010086 +0.010012 +0.009968 +0.009878 +0.009782 +0.009777 +0.009811 +0.009756 +0.009731 +0.009653 +0.009582 +0.009595 +0.009632 +0.009589 +0.009574 +0.009512 +0.009455 +0.009483 +0.009535 +0.009508 +0.009506 +0.009451 +0.009404 +0.009431 +0.009488 +0.009462 +0.009464 +0.009417 +0.009377 +0.009418 +0.009481 +0.009466 +0.009486 +0.009449 +0.009422 +0.00948 +0.009553 +0.009553 +0.009575 +0.009557 +0.00951 +0.009569 +0.009665 +0.000212 +0.009649 +0.009681 +0.009635 +0.009628 +0.009673 +0.009759 +0.009752 +0.009785 +0.009745 +0.009727 +0.009771 +0.00986 +0.009849 +0.009879 +0.009836 +0.009825 +0.009879 +0.009971 +0.009956 +0.009997 +0.009959 +0.009948 +0.010023 +0.010108 +0.010097 +0.010132 +0.010034 +0.009941 +0.009957 +0.010014 +0.009934 +0.009921 +0.009778 +0.009702 +0.009678 +0.009723 +0.009652 +0.009642 +0.00957 +0.009471 +0.009459 +0.009523 +0.009464 +0.009472 +0.009419 +0.009382 +0.009398 +0.009427 +0.009377 +0.009395 +0.009349 +0.00933 +0.009326 +0.009388 +0.009341 +0.009366 +0.009343 +0.009306 +0.009375 +0.009445 +0.009411 +0.009456 +0.009414 +0.009371 +0.0094 +0.009469 +0.009451 +0.009495 +0.009463 +0.009445 +0.009505 +0.009595 +0.000213 +0.009575 +0.009617 +0.009573 +0.009569 +0.009621 +0.009713 +0.009693 +0.00973 +0.009688 +0.009674 +0.009719 +0.00981 +0.009769 +0.009806 +0.009759 +0.009735 +0.009778 +0.009874 +0.009844 +0.009902 +0.009888 +0.009874 +0.009922 +0.010004 +0.009986 +0.010008 +0.009943 +0.009921 +0.009931 +0.009968 +0.009874 +0.009857 +0.009739 +0.009667 +0.009644 +0.009678 +0.009608 +0.009591 +0.009501 +0.00945 +0.009438 +0.009497 +0.009438 +0.009433 +0.009351 +0.00932 +0.009315 +0.009369 +0.009331 +0.009347 +0.009279 +0.00925 +0.009255 +0.009323 +0.009295 +0.009314 +0.009259 +0.009244 +0.009267 +0.009352 +0.009328 +0.009361 +0.009318 +0.009315 +0.009348 +0.009439 +0.00942 +0.009446 +0.009423 +0.009399 +0.009448 +0.000214 +0.009541 +0.009512 +0.009544 +0.009523 +0.009503 +0.009549 +0.009631 +0.009617 +0.009655 +0.009617 +0.009598 +0.00965 +0.009733 +0.009719 +0.009752 +0.009715 +0.009695 +0.009757 +0.009835 +0.009834 +0.009855 +0.009838 +0.009817 +0.00988 +0.009982 +0.00996 +0.009995 +0.0099 +0.009855 +0.009887 +0.00996 +0.009905 +0.0099 +0.009824 +0.009766 +0.009696 +0.009712 +0.009651 +0.009649 +0.009591 +0.009536 +0.00955 +0.009568 +0.009496 +0.009501 +0.009448 +0.009357 +0.009371 +0.009417 +0.00939 +0.009401 +0.009368 +0.009335 +0.009382 +0.009453 +0.009409 +0.009447 +0.009398 +0.009386 +0.00936 +0.009416 +0.009391 +0.009413 +0.009403 +0.009386 +0.009434 +0.009534 +0.009508 +0.009536 +0.009515 +0.009495 +0.009552 +0.009639 +0.009614 +0.000215 +0.009652 +0.009628 +0.0096 +0.009666 +0.009745 +0.009739 +0.009759 +0.009739 +0.009716 +0.009777 +0.009826 +0.009791 +0.009807 +0.009781 +0.009748 +0.009803 +0.00988 +0.009867 +0.009893 +0.009904 +0.009895 +0.00995 +0.010033 +0.010016 +0.010041 +0.010011 +0.009984 +0.010021 +0.010065 +0.010015 +0.009954 +0.009872 +0.009772 +0.009766 +0.009779 +0.009717 +0.009684 +0.009605 +0.009529 +0.009542 +0.009577 +0.00953 +0.009521 +0.009459 +0.009403 +0.009421 +0.009455 +0.009422 +0.009428 +0.009373 +0.009329 +0.009357 +0.009404 +0.009378 +0.009387 +0.009338 +0.009303 +0.009337 +0.009397 +0.009385 +0.009396 +0.009365 +0.009337 +0.009387 +0.009462 +0.009455 +0.00948 +0.009453 +0.009434 +0.009476 +0.009565 +0.00955 +0.000216 +0.009592 +0.009548 +0.009526 +0.00958 +0.009664 +0.009652 +0.009685 +0.00965 +0.009632 +0.009678 +0.009768 +0.009752 +0.00978 +0.009749 +0.009735 +0.009784 +0.00987 +0.009862 +0.009891 +0.009865 +0.00984 +0.009905 +0.010008 +0.00999 +0.010022 +0.01 +0.009962 +0.009913 +0.00997 +0.009926 +0.009934 +0.009863 +0.009789 +0.009811 +0.009862 +0.009791 +0.009658 +0.009569 +0.009518 +0.009557 +0.009598 +0.009552 +0.00955 +0.009464 +0.009385 +0.009371 +0.009447 +0.009394 +0.009411 +0.009356 +0.009331 +0.009362 +0.009447 +0.009405 +0.009431 +0.00939 +0.009301 +0.009325 +0.009388 +0.009355 +0.009396 +0.009358 +0.009345 +0.0094 +0.009475 +0.009466 +0.009496 +0.009463 +0.009451 +0.00951 +0.009595 +0.00957 +0.009602 +0.000217 +0.009586 +0.009554 +0.009629 +0.009696 +0.009679 +0.009664 +0.00963 +0.009602 +0.009668 +0.009751 +0.009733 +0.009751 +0.009728 +0.009693 +0.009752 +0.009831 +0.009827 +0.009878 +0.009869 +0.009841 +0.009891 +0.009969 +0.009957 +0.009971 +0.00997 +0.009938 +0.009983 +0.010054 +0.010016 +0.010003 +0.009924 +0.009831 +0.009818 +0.009843 +0.009768 +0.009723 +0.009648 +0.009559 +0.009557 +0.009598 +0.009552 +0.009526 +0.009472 +0.009408 +0.009416 +0.009472 +0.009432 +0.009413 +0.009383 +0.009312 +0.009347 +0.009405 +0.009381 +0.009381 +0.009342 +0.0093 +0.009337 +0.009409 +0.009385 +0.009399 +0.009374 +0.009334 +0.009389 +0.009474 +0.009461 +0.009483 +0.009461 +0.009428 +0.009489 +0.009578 +0.009549 +0.000218 +0.009583 +0.009555 +0.009535 +0.009587 +0.009661 +0.009665 +0.009678 +0.009661 +0.00963 +0.009687 +0.009764 +0.009763 +0.009789 +0.009761 +0.009731 +0.009795 +0.009869 +0.00987 +0.009894 +0.00987 +0.009846 +0.00992 +0.010009 +0.009996 +0.010031 +0.010015 +0.009927 +0.009927 +0.009991 +0.009961 +0.009964 +0.009908 +0.009844 +0.009881 +0.009929 +0.009854 +0.009734 +0.009669 +0.009622 +0.009671 +0.009698 +0.009653 +0.009603 +0.009526 +0.009503 +0.009506 +0.00956 +0.009502 +0.009516 +0.009473 +0.009443 +0.009495 +0.009571 +0.009521 +0.009517 +0.009446 +0.009435 +0.009473 +0.009554 +0.009518 +0.009525 +0.009519 +0.009478 +0.00956 +0.009635 +0.009604 +0.009644 +0.009618 +0.009578 +0.009615 +0.009691 +0.000219 +0.009647 +0.009694 +0.009674 +0.009654 +0.009719 +0.009796 +0.009789 +0.009816 +0.009792 +0.009766 +0.009829 +0.009911 +0.009898 +0.009922 +0.009892 +0.009857 +0.00992 +0.009995 +0.009991 +0.010034 +0.010008 +0.009973 +0.010027 +0.010115 +0.010106 +0.010144 +0.01011 +0.010083 +0.010136 +0.010196 +0.010174 +0.010145 +0.010065 +0.009981 +0.00997 +0.009984 +0.009922 +0.009877 +0.009799 +0.009723 +0.009728 +0.009769 +0.009722 +0.009705 +0.009647 +0.00959 +0.009605 +0.00966 +0.009628 +0.009612 +0.00957 +0.009534 +0.009561 +0.00962 +0.009593 +0.009594 +0.009566 +0.009529 +0.009564 +0.009631 +0.009621 +0.009635 +0.009608 +0.009578 +0.009631 +0.009713 +0.009707 +0.009725 +0.009708 +0.009678 +0.009738 +0.009809 +0.00022 +0.00981 +0.009835 +0.009801 +0.009784 +0.009832 +0.009924 +0.009907 +0.009937 +0.009907 +0.009888 +0.009937 +0.010024 +0.010013 +0.010039 +0.010007 +0.009992 +0.010045 +0.010133 +0.010132 +0.010153 +0.010128 +0.010109 +0.010177 +0.010285 +0.010252 +0.010296 +0.010255 +0.010133 +0.010152 +0.010208 +0.010156 +0.01014 +0.010066 +0.010004 +0.009966 +0.009933 +0.00986 +0.00987 +0.009797 +0.009742 +0.009751 +0.009749 +0.009708 +0.009708 +0.009658 +0.009566 +0.00956 +0.009622 +0.009582 +0.0096 +0.00956 +0.009526 +0.009568 +0.009634 +0.009606 +0.009612 +0.009582 +0.009493 +0.009509 +0.009592 +0.009559 +0.009594 +0.009561 +0.009541 +0.0096 +0.009689 +0.009664 +0.009703 +0.009673 +0.009652 +0.009707 +0.009813 +0.009768 +0.000221 +0.009816 +0.009773 +0.00977 +0.009827 +0.009928 +0.009878 +0.009914 +0.009838 +0.009826 +0.009881 +0.009975 +0.009939 +0.009972 +0.009931 +0.009912 +0.009964 +0.01005 +0.010025 +0.010069 +0.010055 +0.010058 +0.010109 +0.010199 +0.01017 +0.010207 +0.010157 +0.010145 +0.010193 +0.010262 +0.010192 +0.010168 +0.010065 +0.009983 +0.009956 +0.009987 +0.009895 +0.009871 +0.009767 +0.009698 +0.009696 +0.009738 +0.009669 +0.009663 +0.009587 +0.009532 +0.009534 +0.009593 +0.009543 +0.009551 +0.009474 +0.009446 +0.009462 +0.009524 +0.009485 +0.009507 +0.009449 +0.009415 +0.009444 +0.00952 +0.009489 +0.009519 +0.009476 +0.009452 +0.009502 +0.009588 +0.00956 +0.009602 +0.009554 +0.009559 +0.009588 +0.009692 +0.009671 +0.000222 +0.009688 +0.009657 +0.009647 +0.009696 +0.009792 +0.009759 +0.009805 +0.009762 +0.009751 +0.009794 +0.009892 +0.009872 +0.009909 +0.009867 +0.009856 +0.009902 +0.01 +0.009978 +0.010012 +0.009981 +0.009962 +0.010028 +0.010123 +0.010101 +0.010144 +0.010111 +0.010109 +0.010117 +0.010131 +0.010074 +0.010102 +0.010012 +0.009963 +0.009978 +0.010032 +0.009879 +0.00984 +0.009762 +0.009709 +0.009679 +0.009725 +0.009657 +0.009656 +0.009602 +0.009566 +0.009537 +0.009578 +0.009501 +0.009536 +0.009471 +0.009458 +0.009484 +0.00958 +0.009517 +0.009554 +0.009457 +0.009442 +0.00943 +0.009526 +0.009488 +0.009514 +0.009482 +0.00946 +0.009506 +0.00961 +0.00957 +0.009616 +0.009586 +0.009573 +0.009617 +0.009721 +0.00969 +0.009715 +0.000223 +0.009681 +0.009673 +0.009696 +0.009766 +0.009733 +0.009773 +0.00974 +0.009731 +0.009782 +0.00988 +0.009854 +0.009887 +0.009846 +0.00983 +0.009874 +0.00997 +0.009944 +0.009991 +0.009973 +0.009961 +0.010002 +0.010099 +0.010057 +0.010105 +0.010061 +0.010072 +0.010091 +0.010173 +0.01013 +0.010117 +0.010016 +0.009956 +0.009926 +0.009956 +0.009877 +0.009847 +0.009737 +0.009676 +0.009657 +0.009706 +0.009637 +0.009621 +0.009539 +0.009494 +0.009492 +0.009541 +0.0095 +0.009497 +0.009433 +0.009405 +0.009412 +0.009472 +0.009434 +0.009451 +0.009385 +0.009366 +0.009383 +0.009451 +0.009425 +0.009447 +0.009391 +0.009382 +0.009409 +0.009496 +0.009471 +0.009505 +0.009466 +0.00946 +0.009495 +0.009591 +0.009563 +0.009605 +0.00957 +0.000224 +0.009552 +0.009598 +0.009681 +0.009673 +0.009704 +0.009668 +0.00965 +0.0097 +0.009787 +0.009775 +0.009804 +0.00978 +0.009749 +0.009805 +0.00989 +0.009878 +0.009914 +0.009868 +0.009859 +0.009913 +0.01001 +0.009991 +0.010034 +0.01001 +0.009991 +0.010055 +0.010132 +0.010031 +0.010053 +0.010001 +0.009941 +0.009917 +0.009942 +0.009873 +0.009864 +0.009789 +0.009667 +0.009643 +0.009701 +0.009641 +0.009629 +0.009582 +0.009529 +0.009537 +0.009545 +0.00948 +0.009494 +0.009433 +0.0094 +0.009412 +0.009469 +0.009413 +0.00944 +0.009397 +0.009359 +0.009413 +0.00945 +0.009423 +0.009431 +0.009409 +0.009379 +0.009432 +0.009504 +0.009457 +0.009492 +0.009466 +0.009435 +0.00951 +0.009594 +0.009565 +0.009601 +0.009573 +0.00955 +0.000225 +0.009603 +0.009705 +0.009673 +0.009709 +0.009644 +0.009633 +0.009667 +0.009765 +0.00972 +0.009768 +0.009731 +0.009717 +0.009765 +0.009845 +0.009818 +0.00986 +0.009826 +0.009843 +0.009899 +0.009999 +0.009959 +0.010002 +0.00995 +0.009945 +0.00997 +0.010086 +0.010053 +0.010054 +0.009968 +0.009909 +0.009895 +0.009933 +0.00984 +0.009817 +0.009713 +0.009631 +0.009607 +0.009663 +0.00958 +0.009563 +0.009487 +0.009434 +0.009413 +0.009483 +0.00943 +0.009414 +0.009361 +0.009319 +0.009332 +0.009394 +0.009349 +0.009359 +0.009308 +0.009274 +0.009291 +0.009375 +0.009326 +0.009345 +0.009304 +0.009277 +0.009304 +0.009395 +0.009363 +0.009393 +0.00936 +0.009344 +0.009381 +0.009482 +0.009454 +0.009513 +0.009438 +0.009439 +0.009481 +0.000226 +0.009576 +0.009559 +0.009587 +0.009556 +0.00954 +0.009583 +0.009674 +0.009657 +0.009691 +0.009658 +0.009637 +0.009687 +0.009771 +0.009758 +0.009792 +0.009753 +0.009729 +0.009791 +0.009872 +0.009868 +0.009893 +0.009874 +0.009855 +0.009913 +0.010009 +0.009981 +0.010029 +0.009993 +0.009932 +0.009862 +0.0099 +0.00984 +0.009837 +0.009755 +0.009692 +0.009714 +0.00972 +0.009602 +0.009587 +0.009539 +0.009461 +0.009426 +0.009484 +0.009431 +0.009437 +0.009382 +0.009333 +0.009365 +0.009386 +0.009353 +0.009366 +0.009323 +0.009282 +0.009276 +0.00935 +0.00931 +0.009345 +0.009302 +0.009268 +0.009329 +0.009399 +0.009369 +0.009415 +0.009376 +0.009346 +0.009373 +0.00943 +0.009402 +0.009452 +0.009427 +0.009407 +0.00946 +0.009549 +0.000227 +0.009525 +0.009567 +0.009526 +0.00952 +0.009569 +0.009667 +0.009642 +0.009679 +0.009639 +0.009628 +0.009683 +0.009772 +0.009735 +0.009766 +0.009716 +0.009698 +0.009739 +0.00983 +0.009795 +0.009832 +0.009789 +0.009772 +0.009843 +0.009973 +0.009948 +0.009984 +0.009927 +0.00991 +0.009935 +0.009995 +0.009936 +0.009936 +0.009821 +0.009733 +0.009709 +0.009736 +0.009644 +0.009615 +0.00952 +0.009451 +0.00945 +0.009499 +0.009443 +0.009433 +0.009354 +0.009308 +0.009314 +0.009378 +0.009337 +0.009342 +0.00927 +0.009238 +0.009263 +0.009336 +0.009303 +0.009323 +0.009264 +0.009244 +0.009273 +0.00935 +0.009334 +0.009364 +0.009319 +0.009313 +0.009338 +0.009443 +0.009415 +0.009452 +0.009422 +0.009399 +0.009439 +0.000228 +0.009533 +0.009523 +0.009549 +0.00951 +0.009501 +0.009543 +0.009637 +0.009611 +0.00965 +0.009615 +0.009601 +0.009643 +0.009736 +0.009717 +0.009753 +0.00971 +0.009696 +0.00974 +0.009838 +0.00981 +0.009857 +0.00981 +0.009802 +0.009845 +0.009957 +0.009935 +0.009976 +0.009943 +0.009941 +0.010002 +0.010029 +0.009915 +0.009911 +0.009833 +0.009752 +0.009685 +0.009712 +0.009623 +0.009639 +0.009549 +0.00948 +0.00943 +0.009476 +0.009413 +0.009416 +0.009362 +0.009324 +0.009351 +0.009375 +0.009297 +0.009332 +0.009256 +0.009216 +0.00922 +0.009284 +0.009244 +0.009265 +0.009225 +0.009207 +0.009236 +0.009335 +0.009278 +0.009304 +0.009272 +0.009243 +0.009221 +0.009294 +0.009246 +0.009301 +0.009267 +0.009258 +0.00931 +0.009403 +0.009372 +0.009424 +0.009381 +0.00937 +0.009417 +0.009517 +0.009482 +0.000229 +0.009523 +0.009493 +0.009484 +0.009542 +0.009625 +0.009593 +0.009633 +0.009603 +0.009583 +0.00959 +0.009652 +0.009623 +0.009653 +0.009622 +0.009608 +0.009658 +0.009773 +0.009788 +0.009814 +0.009775 +0.009746 +0.009802 +0.009886 +0.009879 +0.009918 +0.009883 +0.009845 +0.009883 +0.009947 +0.009881 +0.009861 +0.00976 +0.009664 +0.009645 +0.009666 +0.009576 +0.009558 +0.009463 +0.009396 +0.009401 +0.00945 +0.009376 +0.009378 +0.009316 +0.009255 +0.009271 +0.009334 +0.009295 +0.009293 +0.009243 +0.009199 +0.009223 +0.009296 +0.009268 +0.009267 +0.009226 +0.009193 +0.009221 +0.009303 +0.009279 +0.009309 +0.009274 +0.009249 +0.009296 +0.009377 +0.009361 +0.009407 +0.009364 +0.00935 +0.009382 +0.009483 +0.00023 +0.009455 +0.009485 +0.009457 +0.00945 +0.009484 +0.009578 +0.009555 +0.009589 +0.009551 +0.009543 +0.009585 +0.009678 +0.009655 +0.009691 +0.009653 +0.00964 +0.009688 +0.009784 +0.009755 +0.0098 +0.009753 +0.009745 +0.009793 +0.009904 +0.009879 +0.009917 +0.009891 +0.00988 +0.009908 +0.009907 +0.009836 +0.009846 +0.009776 +0.009708 +0.009709 +0.009674 +0.009585 +0.009592 +0.009518 +0.009443 +0.009402 +0.009447 +0.009391 +0.009395 +0.009344 +0.009301 +0.00932 +0.009314 +0.009269 +0.009271 +0.009235 +0.009201 +0.009225 +0.009262 +0.009208 +0.009241 +0.009192 +0.00918 +0.009212 +0.009242 +0.009205 +0.009233 +0.009196 +0.009177 +0.00923 +0.009286 +0.009247 +0.009295 +0.009256 +0.009243 +0.009294 +0.009379 +0.009322 +0.00937 +0.009346 +0.009327 +0.009387 +0.000231 +0.009465 +0.009451 +0.009479 +0.009448 +0.009434 +0.00947 +0.009545 +0.009506 +0.009545 +0.009524 +0.009506 +0.009557 +0.009638 +0.009609 +0.009637 +0.009603 +0.009583 +0.009633 +0.009714 +0.009707 +0.00976 +0.00974 +0.009724 +0.009758 +0.009856 +0.009835 +0.00986 +0.009816 +0.009808 +0.009846 +0.009901 +0.009841 +0.009813 +0.009715 +0.009639 +0.009613 +0.009642 +0.00957 +0.009548 +0.009457 +0.009405 +0.009401 +0.009449 +0.009397 +0.009384 +0.009306 +0.009273 +0.009284 +0.009335 +0.009309 +0.009307 +0.009248 +0.009218 +0.009243 +0.009312 +0.009288 +0.009293 +0.009248 +0.009221 +0.009255 +0.009334 +0.009321 +0.009343 +0.009299 +0.009289 +0.009331 +0.009418 +0.009407 +0.009427 +0.009407 +0.009377 +0.00944 +0.000232 +0.009513 +0.009504 +0.009523 +0.0095 +0.009474 +0.009539 +0.009607 +0.009608 +0.009628 +0.009601 +0.009574 +0.009633 +0.009712 +0.009707 +0.009726 +0.009704 +0.009666 +0.009738 +0.009808 +0.0098 +0.009831 +0.009795 +0.00978 +0.009833 +0.009931 +0.009923 +0.009946 +0.009927 +0.009906 +0.009978 +0.01006 +0.009969 +0.009875 +0.009818 +0.009738 +0.009728 +0.009717 +0.009629 +0.009614 +0.009519 +0.009412 +0.009433 +0.009462 +0.009427 +0.009409 +0.009345 +0.009264 +0.009257 +0.009308 +0.009267 +0.009277 +0.00924 +0.009201 +0.009247 +0.0093 +0.009276 +0.00923 +0.009191 +0.009156 +0.009193 +0.009263 +0.009213 +0.00923 +0.009213 +0.009175 +0.009245 +0.009321 +0.009293 +0.009316 +0.009299 +0.009267 +0.009292 +0.009365 +0.009345 +0.009371 +0.009353 +0.009343 +0.000233 +0.009385 +0.009468 +0.009461 +0.009497 +0.00947 +0.009443 +0.009501 +0.009583 +0.009572 +0.009594 +0.009573 +0.009548 +0.009607 +0.009677 +0.009649 +0.009668 +0.009641 +0.009607 +0.00967 +0.009744 +0.009733 +0.009745 +0.009735 +0.009741 +0.009811 +0.009875 +0.009867 +0.00988 +0.009835 +0.009794 +0.009829 +0.009862 +0.009794 +0.009746 +0.009656 +0.009566 +0.00956 +0.009578 +0.009529 +0.009495 +0.009414 +0.009357 +0.009371 +0.009405 +0.009367 +0.009348 +0.009283 +0.009232 +0.00925 +0.009297 +0.009275 +0.00927 +0.009214 +0.009174 +0.009214 +0.009269 +0.009246 +0.009254 +0.009217 +0.009188 +0.009233 +0.009302 +0.009299 +0.009319 +0.009282 +0.009262 +0.009319 +0.009398 +0.009391 +0.009409 +0.009382 +0.009359 +0.000234 +0.00941 +0.009497 +0.009488 +0.009509 +0.009482 +0.009451 +0.009509 +0.009594 +0.009591 +0.009606 +0.009581 +0.009551 +0.009618 +0.009694 +0.009691 +0.009709 +0.009678 +0.009649 +0.009714 +0.009789 +0.00978 +0.009811 +0.009778 +0.009763 +0.009823 +0.009908 +0.009909 +0.009933 +0.009906 +0.009889 +0.009956 +0.009941 +0.009869 +0.009858 +0.009798 +0.009705 +0.009657 +0.009667 +0.009599 +0.009604 +0.009547 +0.009467 +0.009458 +0.00946 +0.009427 +0.009426 +0.00938 +0.009337 +0.009326 +0.009359 +0.009319 +0.009336 +0.009305 +0.009265 +0.009313 +0.00934 +0.009317 +0.009324 +0.009308 +0.009244 +0.009245 +0.009318 +0.009284 +0.00931 +0.009293 +0.009257 +0.00933 +0.009399 +0.009382 +0.009415 +0.009387 +0.009373 +0.009418 +0.009515 +0.009491 +0.00952 +0.000235 +0.0095 +0.00948 +0.009535 +0.009622 +0.009598 +0.009618 +0.009549 +0.009527 +0.009584 +0.009675 +0.009648 +0.009686 +0.009653 +0.009629 +0.009683 +0.009766 +0.009743 +0.009766 +0.009739 +0.009719 +0.009771 +0.009878 +0.00988 +0.0099 +0.009868 +0.009847 +0.009899 +0.009999 +0.009967 +0.009999 +0.009957 +0.009901 +0.009889 +0.00994 +0.009851 +0.009803 +0.009708 +0.009608 +0.009589 +0.009633 +0.009554 +0.009534 +0.009468 +0.0094 +0.009399 +0.00946 +0.009409 +0.009398 +0.009345 +0.00929 +0.009311 +0.009373 +0.009339 +0.009343 +0.009309 +0.009254 +0.009287 +0.009367 +0.009335 +0.009351 +0.009316 +0.009285 +0.009325 +0.009413 +0.009396 +0.009426 +0.009387 +0.009371 +0.009421 +0.0095 +0.009487 +0.009523 +0.000236 +0.009484 +0.00947 +0.009512 +0.009604 +0.009588 +0.009624 +0.009583 +0.00957 +0.009611 +0.009708 +0.009687 +0.009726 +0.009684 +0.009668 +0.009713 +0.009817 +0.009793 +0.009827 +0.009781 +0.009775 +0.009816 +0.009904 +0.009896 +0.009927 +0.009893 +0.009885 +0.00994 +0.010046 +0.01002 +0.010063 +0.010015 +0.010006 +0.009937 +0.009959 +0.009891 +0.009899 +0.009793 +0.009754 +0.00977 +0.009772 +0.00965 +0.009648 +0.009555 +0.009499 +0.009486 +0.009531 +0.009483 +0.009486 +0.009426 +0.009385 +0.009387 +0.009423 +0.009384 +0.0094 +0.00935 +0.009316 +0.009346 +0.009413 +0.00936 +0.009403 +0.009317 +0.009297 +0.009315 +0.009383 +0.009361 +0.009397 +0.009354 +0.009356 +0.009393 +0.009484 +0.009462 +0.009497 +0.009455 +0.009465 +0.009511 +0.009592 +0.000237 +0.009569 +0.00958 +0.009534 +0.009515 +0.009574 +0.009667 +0.009642 +0.009671 +0.00964 +0.009619 +0.009688 +0.009777 +0.009748 +0.009777 +0.009726 +0.009703 +0.009753 +0.009837 +0.00981 +0.009839 +0.009804 +0.009781 +0.00984 +0.009969 +0.009966 +0.009998 +0.009949 +0.00993 +0.009962 +0.010038 +0.01 +0.010001 +0.009914 +0.009839 +0.009804 +0.00985 +0.00977 +0.009725 +0.009642 +0.009572 +0.009548 +0.009602 +0.009545 +0.009523 +0.009443 +0.009398 +0.009404 +0.009465 +0.00942 +0.009415 +0.009361 +0.00933 +0.009345 +0.009413 +0.009395 +0.009402 +0.00935 +0.009321 +0.009357 +0.009445 +0.009428 +0.009443 +0.009411 +0.009396 +0.009437 +0.009525 +0.009519 +0.009546 +0.009502 +0.00948 +0.009544 +0.000238 +0.009623 +0.009628 +0.009633 +0.009608 +0.009583 +0.009643 +0.00973 +0.009721 +0.009738 +0.009713 +0.009684 +0.009739 +0.009821 +0.009822 +0.009847 +0.009816 +0.009786 +0.009846 +0.009932 +0.009917 +0.009941 +0.009923 +0.009885 +0.009968 +0.010046 +0.010043 +0.010078 +0.010058 +0.010027 +0.010084 +0.010079 +0.010023 +0.010015 +0.009975 +0.009894 +0.009903 +0.009889 +0.009807 +0.009796 +0.009715 +0.009624 +0.009628 +0.00969 +0.009632 +0.009645 +0.009597 +0.009505 +0.009503 +0.009544 +0.009518 +0.009532 +0.009491 +0.009458 +0.009499 +0.009571 +0.009539 +0.009558 +0.009519 +0.009491 +0.00949 +0.009518 +0.00951 +0.009526 +0.009505 +0.009483 +0.009535 +0.009631 +0.009605 +0.009632 +0.009621 +0.009588 +0.009653 +0.009743 +0.009722 +0.009747 +0.000239 +0.009723 +0.009709 +0.00977 +0.009844 +0.009802 +0.009826 +0.009805 +0.009781 +0.009803 +0.009896 +0.00987 +0.009893 +0.009866 +0.009845 +0.009895 +0.009992 +0.009964 +0.010032 +0.010014 +0.009995 +0.010038 +0.01012 +0.010101 +0.010145 +0.010113 +0.010104 +0.010123 +0.010207 +0.010171 +0.010151 +0.010042 +0.009969 +0.009938 +0.009959 +0.009885 +0.009849 +0.009757 +0.009683 +0.009677 +0.009721 +0.009674 +0.009642 +0.009572 +0.009518 +0.009519 +0.009565 +0.009527 +0.009521 +0.009455 +0.009417 +0.009439 +0.009503 +0.009482 +0.009491 +0.009443 +0.009417 +0.009457 +0.009525 +0.009521 +0.009544 +0.009506 +0.009482 +0.009538 +0.009618 +0.009612 +0.009632 +0.009612 +0.009579 +0.00024 +0.00964 +0.009709 +0.009717 +0.009737 +0.009707 +0.009684 +0.00974 +0.009821 +0.009812 +0.009838 +0.009817 +0.009785 +0.009846 +0.00992 +0.009923 +0.009937 +0.009917 +0.009883 +0.009951 +0.01003 +0.010024 +0.010054 +0.010024 +0.010001 +0.010066 +0.010166 +0.010164 +0.010191 +0.010158 +0.010094 +0.010041 +0.01008 +0.010041 +0.010041 +0.00997 +0.009893 +0.009931 +0.009974 +0.009879 +0.009803 +0.009746 +0.009694 +0.009701 +0.009717 +0.00969 +0.009671 +0.009637 +0.009582 +0.009625 +0.009636 +0.009611 +0.0096 +0.009578 +0.009525 +0.009595 +0.009657 +0.009612 +0.00959 +0.009537 +0.009524 +0.009568 +0.009639 +0.009624 +0.009635 +0.009599 +0.009585 +0.00961 +0.009672 +0.009668 +0.00969 +0.009664 +0.009653 +0.009715 +0.009798 +0.009779 +0.000241 +0.009813 +0.009793 +0.009757 +0.009829 +0.00992 +0.009904 +0.009924 +0.009899 +0.009872 +0.00994 +0.010029 +0.010001 +0.010028 +0.009988 +0.009949 +0.010002 +0.010081 +0.010052 +0.01007 +0.010044 +0.010012 +0.010082 +0.010211 +0.010217 +0.010247 +0.010201 +0.010165 +0.010203 +0.010245 +0.010178 +0.010158 +0.010054 +0.009943 +0.00993 +0.009939 +0.009862 +0.00983 +0.009738 +0.009654 +0.009663 +0.0097 +0.009653 +0.00964 +0.009569 +0.009509 +0.009532 +0.009579 +0.00955 +0.009553 +0.009502 +0.009462 +0.009496 +0.009549 +0.00953 +0.009541 +0.0095 +0.00946 +0.009504 +0.009572 +0.009564 +0.009581 +0.009553 +0.009524 +0.009584 +0.009655 +0.00966 +0.009683 +0.009648 +0.009621 +0.000242 +0.009687 +0.009759 +0.009763 +0.009776 +0.009751 +0.009734 +0.009784 +0.009865 +0.009857 +0.009876 +0.009857 +0.009829 +0.009892 +0.009958 +0.009961 +0.009986 +0.009957 +0.009925 +0.009992 +0.010077 +0.01007 +0.010102 +0.01008 +0.010048 +0.010133 +0.010222 +0.01021 +0.010236 +0.010181 +0.01006 +0.010086 +0.010131 +0.01008 +0.010054 +0.009987 +0.009907 +0.009826 +0.009845 +0.009789 +0.009793 +0.009729 +0.009674 +0.009713 +0.00976 +0.009697 +0.009612 +0.009579 +0.009527 +0.009587 +0.009614 +0.009596 +0.009594 +0.009563 +0.009484 +0.009507 +0.009558 +0.009536 +0.009562 +0.009522 +0.00951 +0.009564 +0.009636 +0.009631 +0.00964 +0.009631 +0.009602 +0.009666 +0.009779 +0.00972 +0.009753 +0.000243 +0.00969 +0.009656 +0.009721 +0.009815 +0.009788 +0.009814 +0.009787 +0.009765 +0.00984 +0.009921 +0.009902 +0.009928 +0.009897 +0.009866 +0.009928 +0.010001 +0.009982 +0.010001 +0.009976 +0.009944 +0.010005 +0.010114 +0.010124 +0.010142 +0.010116 +0.010078 +0.010137 +0.010212 +0.010181 +0.010162 +0.010071 +0.009965 +0.009949 +0.009955 +0.009864 +0.009821 +0.009724 +0.009632 +0.009634 +0.009666 +0.009606 +0.009582 +0.009512 +0.009438 +0.009458 +0.009501 +0.00946 +0.009454 +0.009399 +0.009342 +0.009378 +0.00944 +0.009409 +0.009421 +0.009369 +0.009326 +0.009372 +0.009435 +0.009415 +0.009432 +0.00939 +0.00935 +0.009415 +0.009477 +0.009472 +0.009497 +0.00947 +0.009439 +0.009502 +0.009566 +0.009591 +0.009578 +0.000244 +0.00957 +0.009543 +0.009588 +0.009684 +0.00967 +0.009695 +0.00967 +0.009641 +0.00969 +0.009781 +0.009767 +0.009801 +0.009765 +0.009744 +0.009799 +0.00988 +0.009866 +0.00991 +0.009859 +0.009844 +0.009906 +0.009994 +0.009984 +0.010028 +0.009992 +0.009978 +0.010046 +0.010143 +0.010079 +0.010009 +0.009937 +0.009895 +0.009919 +0.009941 +0.009849 +0.009776 +0.009683 +0.00962 +0.00963 +0.009645 +0.009577 +0.009587 +0.009509 +0.009462 +0.009423 +0.00946 +0.009423 +0.009426 +0.009376 +0.009333 +0.00937 +0.009448 +0.009396 +0.009421 +0.009306 +0.009286 +0.009322 +0.009402 +0.00937 +0.009386 +0.009361 +0.009336 +0.009354 +0.009429 +0.009401 +0.009436 +0.009417 +0.009396 +0.009439 +0.009541 +0.009514 +0.009543 +0.009517 +0.000245 +0.0095 +0.009553 +0.009647 +0.009616 +0.009653 +0.009618 +0.009613 +0.009663 +0.009756 +0.009713 +0.009752 +0.009697 +0.009677 +0.009712 +0.009799 +0.009754 +0.009793 +0.009752 +0.00974 +0.009791 +0.009928 +0.009925 +0.009958 +0.009916 +0.00989 +0.009937 +0.010026 +0.009974 +0.010002 +0.009916 +0.009832 +0.009809 +0.00985 +0.009738 +0.009728 +0.009623 +0.009542 +0.009532 +0.009578 +0.009503 +0.009498 +0.009409 +0.009354 +0.009352 +0.009408 +0.009349 +0.009356 +0.009285 +0.009245 +0.009266 +0.009332 +0.009292 +0.009314 +0.009251 +0.009217 +0.009256 +0.009333 +0.009303 +0.009336 +0.009283 +0.009264 +0.009311 +0.009403 +0.009378 +0.009423 +0.009372 +0.009366 +0.009405 +0.009491 +0.009475 +0.000246 +0.009522 +0.00947 +0.00946 +0.009503 +0.009582 +0.009575 +0.009616 +0.009573 +0.00956 +0.009595 +0.009694 +0.00967 +0.009712 +0.009672 +0.009651 +0.009702 +0.009795 +0.009772 +0.009814 +0.00978 +0.009762 +0.009823 +0.009909 +0.0099 +0.009937 +0.009906 +0.009907 +0.00996 +0.009996 +0.009937 +0.009958 +0.009904 +0.009869 +0.009896 +0.009916 +0.009836 +0.009811 +0.009722 +0.009666 +0.009674 +0.009725 +0.009667 +0.009675 +0.009605 +0.009545 +0.009523 +0.009589 +0.009542 +0.009562 +0.009506 +0.009477 +0.009509 +0.009597 +0.009544 +0.009581 +0.009517 +0.009454 +0.009461 +0.00954 +0.009526 +0.009551 +0.009507 +0.00951 +0.009547 +0.009641 +0.009625 +0.009654 +0.009625 +0.009614 +0.009665 +0.009757 +0.009736 +0.000247 +0.00977 +0.009729 +0.009729 +0.009782 +0.00984 +0.0098 +0.009834 +0.009804 +0.009791 +0.009845 +0.00994 +0.0099 +0.00994 +0.0099 +0.009882 +0.009911 +0.010009 +0.009972 +0.010013 +0.009977 +0.009975 +0.010053 +0.010157 +0.010137 +0.01016 +0.010123 +0.010097 +0.010134 +0.010218 +0.01017 +0.010172 +0.010052 +0.00997 +0.009943 +0.009973 +0.009872 +0.009849 +0.00974 +0.009661 +0.009654 +0.009705 +0.00963 +0.00963 +0.009549 +0.009497 +0.009496 +0.009561 +0.009505 +0.009524 +0.009459 +0.009428 +0.00944 +0.009514 +0.009471 +0.009501 +0.009439 +0.009416 +0.009447 +0.009532 +0.009498 +0.009533 +0.009491 +0.009466 +0.009513 +0.009606 +0.009584 +0.009628 +0.009583 +0.009562 +0.009607 +0.000248 +0.009716 +0.009677 +0.009727 +0.00968 +0.009667 +0.009716 +0.009801 +0.009787 +0.009827 +0.009787 +0.009772 +0.009813 +0.009908 +0.009891 +0.009935 +0.00989 +0.009878 +0.009922 +0.010013 +0.010004 +0.010036 +0.009986 +0.009986 +0.010036 +0.01014 +0.010128 +0.010162 +0.010121 +0.010127 +0.010178 +0.010182 +0.010111 +0.010116 +0.010042 +0.009987 +0.009988 +0.009966 +0.009866 +0.009861 +0.00978 +0.009686 +0.00966 +0.009732 +0.009658 +0.009666 +0.009611 +0.009558 +0.009547 +0.009574 +0.009536 +0.009545 +0.009496 +0.00946 +0.009505 +0.009569 +0.009533 +0.009544 +0.009433 +0.009428 +0.009454 +0.009543 +0.009502 +0.009522 +0.009496 +0.009472 +0.009475 +0.009568 +0.009522 +0.009564 +0.009538 +0.009524 +0.009572 +0.009678 +0.009643 +0.009683 +0.009653 +0.009641 +0.000249 +0.009687 +0.009786 +0.009757 +0.009798 +0.009765 +0.009753 +0.009805 +0.009901 +0.009865 +0.009905 +0.009845 +0.009817 +0.009838 +0.009924 +0.00989 +0.009936 +0.009896 +0.009891 +0.00995 +0.01009 +0.01007 +0.010103 +0.010061 +0.010042 +0.010083 +0.010169 +0.010143 +0.010177 +0.0101 +0.010037 +0.01001 +0.010041 +0.009967 +0.009925 +0.009804 +0.009742 +0.009705 +0.009751 +0.009682 +0.009676 +0.009578 +0.009536 +0.009531 +0.009596 +0.009544 +0.009549 +0.009466 +0.009448 +0.009454 +0.009518 +0.009485 +0.009503 +0.009437 +0.009414 +0.009434 +0.009512 +0.00948 +0.009501 +0.009446 +0.009434 +0.009461 +0.009545 +0.009525 +0.00956 +0.009516 +0.009512 +0.009544 +0.009644 +0.009615 +0.009677 +0.009609 +0.00025 +0.009604 +0.009643 +0.00974 +0.009734 +0.009757 +0.009723 +0.009703 +0.009758 +0.009837 +0.009834 +0.009865 +0.009831 +0.009811 +0.009861 +0.009947 +0.009927 +0.009962 +0.009926 +0.009898 +0.009967 +0.01005 +0.010046 +0.010075 +0.010041 +0.010038 +0.010097 +0.010195 +0.01018 +0.01022 +0.010103 +0.010017 +0.010035 +0.01009 +0.01001 +0.009926 +0.009816 +0.009752 +0.009764 +0.00976 +0.009694 +0.0097 +0.009613 +0.009525 +0.009509 +0.009571 +0.009523 +0.009529 +0.009471 +0.009437 +0.009432 +0.009475 +0.009421 +0.009457 +0.009402 +0.009378 +0.009409 +0.009453 +0.009417 +0.009435 +0.009407 +0.009346 +0.00936 +0.009441 +0.009404 +0.009453 +0.009422 +0.009394 +0.009464 +0.009541 +0.009522 +0.009568 +0.009529 +0.009506 +0.009572 +0.009657 +0.000251 +0.009633 +0.009672 +0.009636 +0.009626 +0.009682 +0.009781 +0.00974 +0.009783 +0.00972 +0.009695 +0.009714 +0.009802 +0.009765 +0.009805 +0.009766 +0.009758 +0.00981 +0.009943 +0.009943 +0.00998 +0.009923 +0.009902 +0.009951 +0.010038 +0.010019 +0.010047 +0.01003 +0.009995 +0.010002 +0.010058 +0.009973 +0.009952 +0.009847 +0.009762 +0.009726 +0.009771 +0.009681 +0.009674 +0.009579 +0.009526 +0.00951 +0.009585 +0.00952 +0.009514 +0.009446 +0.0094 +0.009396 +0.009473 +0.009429 +0.009435 +0.009375 +0.009343 +0.009354 +0.009446 +0.009403 +0.00942 +0.009374 +0.009348 +0.009373 +0.009473 +0.009447 +0.009478 +0.00944 +0.009424 +0.009454 +0.009564 +0.009534 +0.009585 +0.009531 +0.009519 +0.000252 +0.009561 +0.009652 +0.009644 +0.009669 +0.009643 +0.009612 +0.009665 +0.009757 +0.009742 +0.009774 +0.009738 +0.009721 +0.009768 +0.009857 +0.009852 +0.009865 +0.009837 +0.00982 +0.009873 +0.009952 +0.009949 +0.009978 +0.009942 +0.009933 +0.009994 +0.010081 +0.010079 +0.010106 +0.010079 +0.010065 +0.010125 +0.010122 +0.010063 +0.010055 +0.010001 +0.009938 +0.009963 +0.009994 +0.009852 +0.009825 +0.009728 +0.009684 +0.009663 +0.009706 +0.009651 +0.009636 +0.009594 +0.00953 +0.009519 +0.009544 +0.009504 +0.009508 +0.009472 +0.009431 +0.009475 +0.009542 +0.009505 +0.009528 +0.009426 +0.009401 +0.009409 +0.009487 +0.009457 +0.009474 +0.00945 +0.00943 +0.009478 +0.009583 +0.009549 +0.009576 +0.009549 +0.009543 +0.009586 +0.009701 +0.009651 +0.009693 +0.000253 +0.009631 +0.009609 +0.00964 +0.00973 +0.009698 +0.009741 +0.009705 +0.009702 +0.009745 +0.009844 +0.009818 +0.009859 +0.009815 +0.009797 +0.009841 +0.009932 +0.009909 +0.009956 +0.009937 +0.009925 +0.009965 +0.010054 +0.010031 +0.01007 +0.010034 +0.010028 +0.010061 +0.010162 +0.010129 +0.010128 +0.010047 +0.009972 +0.009941 +0.00998 +0.00988 +0.009846 +0.009734 +0.009658 +0.009639 +0.009691 +0.009618 +0.00961 +0.009528 +0.009476 +0.00947 +0.009538 +0.009479 +0.009477 +0.00942 +0.009381 +0.009388 +0.00946 +0.009424 +0.00944 +0.009385 +0.00936 +0.009377 +0.009464 +0.009427 +0.009455 +0.009412 +0.009391 +0.009424 +0.009525 +0.009496 +0.009528 +0.009501 +0.00948 +0.009528 +0.009609 +0.009604 +0.000254 +0.009632 +0.009594 +0.009579 +0.00962 +0.009722 +0.009699 +0.009732 +0.009696 +0.009685 +0.009728 +0.009828 +0.009788 +0.009835 +0.009801 +0.009784 +0.009829 +0.009918 +0.009904 +0.009944 +0.009897 +0.009896 +0.009941 +0.010045 +0.010022 +0.010067 +0.010041 +0.010034 +0.010081 +0.010098 +0.010037 +0.01006 +0.00999 +0.009943 +0.009955 +0.00996 +0.009863 +0.009842 +0.009726 +0.009667 +0.009653 +0.009697 +0.009617 +0.009641 +0.009564 +0.00952 +0.009502 +0.009528 +0.009475 +0.009496 +0.009428 +0.009415 +0.009439 +0.009536 +0.009471 +0.009486 +0.009387 +0.00938 +0.009418 +0.009488 +0.009449 +0.009465 +0.009435 +0.009412 +0.009462 +0.00957 +0.009524 +0.009568 +0.009522 +0.009493 +0.009512 +0.009619 +0.009578 +0.00963 +0.009597 +0.000255 +0.009585 +0.009629 +0.009725 +0.009712 +0.009747 +0.00971 +0.009694 +0.00975 +0.009838 +0.009816 +0.009846 +0.009811 +0.009784 +0.009837 +0.009914 +0.009887 +0.009902 +0.009879 +0.009848 +0.009903 +0.009998 +0.010017 +0.010062 +0.010034 +0.009997 +0.010052 +0.010132 +0.010093 +0.010102 +0.010023 +0.009969 +0.00997 +0.009988 +0.009905 +0.009879 +0.009771 +0.009693 +0.009694 +0.009733 +0.009662 +0.009659 +0.009581 +0.009522 +0.009532 +0.009587 +0.009538 +0.009538 +0.009474 +0.009434 +0.009454 +0.009506 +0.009473 +0.0095 +0.009438 +0.009405 +0.009433 +0.009505 +0.009479 +0.009502 +0.009463 +0.009436 +0.009483 +0.009563 +0.009545 +0.009582 +0.009543 +0.009533 +0.009567 +0.009666 +0.009645 +0.009681 +0.000256 +0.009638 +0.009631 +0.009679 +0.009761 +0.00974 +0.009782 +0.009747 +0.009734 +0.009771 +0.009869 +0.009847 +0.009887 +0.009843 +0.009834 +0.009877 +0.009969 +0.009944 +0.009995 +0.009941 +0.009936 +0.009987 +0.010087 +0.010068 +0.010117 +0.01008 +0.010068 +0.010132 +0.010238 +0.01012 +0.010091 +0.01002 +0.009975 +0.009934 +0.009966 +0.009881 +0.009868 +0.009768 +0.009675 +0.009648 +0.009702 +0.009651 +0.009638 +0.009572 +0.009512 +0.009461 +0.009511 +0.009458 +0.009464 +0.009411 +0.009373 +0.009413 +0.009479 +0.009445 +0.00944 +0.009346 +0.009335 +0.009344 +0.009442 +0.009385 +0.009409 +0.009379 +0.009348 +0.009386 +0.009472 +0.009417 +0.009461 +0.00943 +0.009415 +0.009457 +0.009563 +0.009525 +0.009556 +0.00953 +0.009522 +0.000257 +0.00957 +0.009656 +0.009618 +0.009664 +0.00963 +0.009592 +0.009617 +0.009709 +0.009679 +0.009728 +0.009692 +0.009677 +0.009729 +0.009819 +0.009788 +0.009828 +0.009783 +0.009795 +0.009853 +0.009952 +0.009924 +0.009952 +0.009908 +0.009907 +0.009955 +0.010049 +0.010028 +0.010069 +0.01003 +0.010004 +0.010016 +0.010084 +0.010008 +0.009967 +0.009858 +0.00976 +0.009715 +0.009747 +0.009654 +0.009616 +0.009527 +0.009461 +0.009435 +0.009476 +0.009411 +0.009403 +0.009322 +0.009268 +0.00927 +0.009335 +0.009283 +0.009285 +0.009235 +0.0092 +0.009215 +0.009295 +0.009244 +0.009263 +0.009215 +0.009186 +0.009211 +0.009302 +0.009269 +0.009295 +0.009259 +0.009247 +0.009281 +0.009384 +0.009355 +0.009392 +0.00937 +0.009329 +0.009377 +0.009474 +0.000258 +0.009452 +0.009489 +0.009456 +0.009437 +0.009474 +0.009572 +0.009555 +0.00959 +0.009548 +0.009538 +0.009576 +0.009675 +0.009649 +0.009691 +0.009648 +0.009635 +0.009678 +0.009771 +0.009745 +0.009781 +0.009743 +0.009736 +0.009773 +0.009875 +0.009852 +0.009891 +0.009851 +0.009834 +0.009895 +0.009989 +0.00997 +0.010022 +0.00998 +0.009969 +0.010012 +0.010029 +0.009983 +0.010005 +0.009937 +0.009894 +0.009904 +0.009951 +0.00981 +0.009776 +0.009686 +0.009623 +0.009583 +0.009623 +0.009549 +0.009563 +0.009475 +0.009446 +0.009438 +0.00946 +0.009383 +0.009405 +0.009342 +0.009317 +0.009341 +0.009408 +0.009351 +0.009367 +0.009277 +0.009275 +0.009296 +0.009381 +0.009328 +0.009378 +0.009318 +0.009324 +0.00937 +0.009475 +0.009428 +0.009469 +0.009433 +0.009412 +0.009445 +0.009517 +0.009481 +0.000259 +0.009526 +0.009496 +0.009481 +0.00953 +0.009619 +0.009602 +0.009646 +0.009606 +0.009594 +0.009646 +0.009737 +0.009714 +0.00975 +0.009709 +0.009698 +0.009744 +0.009839 +0.009804 +0.00984 +0.009802 +0.00979 +0.009823 +0.009918 +0.009884 +0.009923 +0.00988 +0.009866 +0.009917 +0.010008 +0.009976 +0.010016 +0.00997 +0.009961 +0.010006 +0.010099 +0.010076 +0.010122 +0.010087 +0.01008 +0.010133 +0.010224 +0.0102 +0.010241 +0.010193 +0.010177 +0.010227 +0.010322 +0.010295 +0.010334 +0.010284 +0.010275 +0.010325 +0.010429 +0.010381 +0.010426 +0.01038 +0.010366 +0.010416 +0.010515 +0.010482 +0.010524 +0.010473 +0.010465 +0.010509 +0.010612 +0.010583 +0.010625 +0.010581 +0.010568 +0.010618 +0.010728 +0.010696 +0.01075 +0.010698 +0.010691 +0.010742 +0.010845 +0.010825 +0.010861 +0.010815 +0.010801 +0.010852 +0.010956 +0.010928 +0.01097 +0.010919 +0.010904 +0.010953 +0.011056 +0.011027 +0.011067 +0.011018 +0.011002 +0.011056 +0.011162 +0.011133 +0.011177 +0.011127 +0.011113 +0.011166 +0.011267 +0.011248 +0.011282 +0.011236 +0.011222 +0.011276 +0.01138 +0.011361 +0.011401 +0.011352 +0.011341 +0.011394 +0.011502 +0.011484 +0.011525 +0.011475 +0.011457 +0.011514 +0.011622 +0.0116 +0.011647 +0.011594 +0.011577 +0.011634 +0.011739 +0.011718 +0.011762 +0.011709 +0.011692 +0.011745 +0.011856 +0.011833 +0.011879 +0.011824 +0.011808 +0.011865 +0.011977 +0.011955 +0.012003 +0.011953 +0.011943 +0.011984 +0.012109 +0.012087 +0.012132 +0.012082 +0.012063 +0.012125 +0.012242 +0.012218 +0.012268 +0.012212 +0.0122 +0.012258 +0.01237 +0.012346 +0.012392 +0.012344 +0.012329 +0.012386 +0.012502 +0.012475 +0.012526 +0.012477 +0.012456 +0.012522 +0.012637 +0.012613 +0.012658 +0.012607 +0.01259 +0.012649 +0.012776 +0.01274 +0.012793 +0.012736 +0.012721 +0.012784 +0.012904 +0.012875 +0.012921 +0.012869 +0.012853 +0.01292 +0.013041 +0.013004 +0.013056 +0.012999 +0.012988 +0.013056 +0.013173 +0.013141 +0.013193 +0.013137 +0.013123 +0.013188 +0.013314 +0.013279 +0.013329 +0.013283 +0.013258 +0.013329 +0.013448 +0.013417 +0.013475 +0.013415 +0.013403 +0.013468 +0.013595 +0.013568 +0.013626 +0.01357 +0.013553 +0.013622 +0.013753 +0.013728 +0.013776 +0.013725 +0.013706 +0.013779 +0.013907 +0.013877 +0.013926 +0.013871 +0.013855 +0.013925 +0.014054 +0.014022 +0.014077 +0.014022 +0.014004 +0.01407 +0.014207 +0.014174 +0.014229 +0.014175 +0.014153 +0.014229 +0.014358 +0.014332 +0.014388 +0.014332 +0.014311 +0.014387 +0.014518 +0.014495 +0.014551 +0.014488 +0.014478 +0.014547 +0.014698 +0.014654 +0.014719 +0.014659 +0.014649 +0.014716 +0.014869 +0.014843 +0.014902 +0.014848 +0.014826 +0.014903 +0.015047 +0.015028 +0.015089 +0.015045 +0.015021 +0.015102 +0.01525 +0.015222 +0.015284 +0.01523 +0.015222 +0.015298 +0.01545 +0.015427 +0.015498 +0.015436 +0.015418 +0.015506 +0.015658 +0.015634 +0.015706 +0.01565 +0.015634 +0.015715 +0.015879 +0.015843 +0.015926 +0.015864 +0.015836 +0.015915 +0.016089 +0.016063 +0.016126 +0.016085 +0.016064 +0.016155 +0.016314 +0.016288 +0.016387 +0.016306 +0.016245 +0.016169 +0.01605 +0.015689 +0.015333 +0.014851 +0.014446 +0.014179 +0.013977 +0.013627 +0.013373 +0.013034 +0.012779 +0.01262 +0.012505 +0.012272 +0.012114 +0.011873 +0.011699 +0.011615 +0.011572 +0.011397 +0.01129 +0.011109 +0.010965 +0.010918 +0.010901 +0.010786 +0.010719 +0.010583 +0.010472 +0.010453 +0.010476 +0.010397 +0.010367 +0.010273 +0.010204 +0.010208 +0.010262 +0.01022 +0.010229 +0.010169 +0.01014 +0.01018 +0.010274 +0.010252 +0.010291 +0.010261 +0.010232 +0.010292 +0.010379 +0.010354 +0.010398 +0.01037 +0.010344 +0.010403 +0.00026 +0.010496 +0.010489 +0.010505 +0.010472 +0.010445 +0.010518 +0.010601 +0.010605 +0.010625 +0.010607 +0.010587 +0.010663 +0.01076 +0.010747 +0.010665 +0.010542 +0.010456 +0.010482 +0.010492 +0.010339 +0.010221 +0.010117 +0.010005 +0.009923 +0.009922 +0.009836 +0.009814 +0.009658 +0.009544 +0.009529 +0.009541 +0.009483 +0.009403 +0.009301 +0.009232 +0.009237 +0.009275 +0.009208 +0.009157 +0.009089 +0.009014 +0.009055 +0.009079 +0.009048 +0.00902 +0.00895 +0.008907 +0.00893 +0.008979 +0.008961 +0.00897 +0.008952 +0.008939 +0.008984 +0.009059 +0.009053 +0.009065 +0.00904 +0.009014 +0.009066 +0.009124 +0.009104 +0.009133 +0.009112 +0.009081 +0.000261 +0.009138 +0.009226 +0.009207 +0.009233 +0.009202 +0.009182 +0.009229 +0.009307 +0.009283 +0.009307 +0.009278 +0.009259 +0.009318 +0.009416 +0.009407 +0.009436 +0.00939 +0.009374 +0.00942 +0.009511 +0.009471 +0.009457 +0.009382 +0.009304 +0.009274 +0.009306 +0.009215 +0.009174 +0.009073 +0.008975 +0.00895 +0.008966 +0.008892 +0.008858 +0.008769 +0.008689 +0.008673 +0.008707 +0.008646 +0.008619 +0.008559 +0.008494 +0.008496 +0.008549 +0.008498 +0.00849 +0.008444 +0.008399 +0.00841 +0.008478 +0.008443 +0.008447 +0.008409 +0.00838 +0.008411 +0.008488 +0.008466 +0.008489 +0.008461 +0.00844 +0.008482 +0.008561 +0.008546 +0.008571 +0.008563 +0.008501 +0.008573 +0.008641 +0.000262 +0.008625 +0.008655 +0.008622 +0.008611 +0.008646 +0.008738 +0.008704 +0.008745 +0.00871 +0.008696 +0.008736 +0.008821 +0.008803 +0.008837 +0.008803 +0.008792 +0.008848 +0.008933 +0.008909 +0.008953 +0.008918 +0.0089 +0.008857 +0.008924 +0.008874 +0.008889 +0.008812 +0.008765 +0.008775 +0.008823 +0.008706 +0.008622 +0.008533 +0.008486 +0.008499 +0.008518 +0.008434 +0.008439 +0.008331 +0.008292 +0.00827 +0.008337 +0.00826 +0.008279 +0.00821 +0.008196 +0.008178 +0.00822 +0.008174 +0.008188 +0.00815 +0.008121 +0.008158 +0.00822 +0.00819 +0.008209 +0.008168 +0.008135 +0.008124 +0.008212 +0.00818 +0.008215 +0.008189 +0.008174 +0.008212 +0.008304 +0.008279 +0.008315 +0.008278 +0.008271 +0.008322 +0.008383 +0.008376 +0.000263 +0.008403 +0.008369 +0.008358 +0.0084 +0.008483 +0.008458 +0.00849 +0.008447 +0.008434 +0.008464 +0.008542 +0.008514 +0.008543 +0.00851 +0.008494 +0.008524 +0.008606 +0.008609 +0.008655 +0.008626 +0.008606 +0.008639 +0.008709 +0.00865 +0.008656 +0.008565 +0.00851 +0.008499 +0.008545 +0.008444 +0.008429 +0.008338 +0.008273 +0.008254 +0.008291 +0.008222 +0.008215 +0.008136 +0.008088 +0.008085 +0.008125 +0.00807 +0.00808 +0.008007 +0.007975 +0.007983 +0.008048 +0.00799 +0.00802 +0.007968 +0.00794 +0.007959 +0.008028 +0.007996 +0.008031 +0.007987 +0.00797 +0.008004 +0.008087 +0.00805 +0.008095 +0.008048 +0.00805 +0.008074 +0.008159 +0.008131 +0.008187 +0.008124 +0.000264 +0.008117 +0.008165 +0.008238 +0.008221 +0.008239 +0.008207 +0.008191 +0.008238 +0.008316 +0.008304 +0.008324 +0.008295 +0.008271 +0.008318 +0.008395 +0.00838 +0.008401 +0.008379 +0.008359 +0.008414 +0.008482 +0.00848 +0.0085 +0.008469 +0.008467 +0.008527 +0.008566 +0.00852 +0.008519 +0.008482 +0.008443 +0.008428 +0.008441 +0.008382 +0.008366 +0.008273 +0.008182 +0.008176 +0.008205 +0.008137 +0.008144 +0.008068 +0.00801 +0.007975 +0.008011 +0.007963 +0.007962 +0.007915 +0.007881 +0.007896 +0.007947 +0.00789 +0.007886 +0.007841 +0.007799 +0.007836 +0.007885 +0.007852 +0.007875 +0.007834 +0.00782 +0.007865 +0.00794 +0.007918 +0.007932 +0.007897 +0.007868 +0.007896 +0.007969 +0.007951 +0.007974 +0.007951 +0.007944 +0.007989 +0.008062 +0.008032 +0.000265 +0.008059 +0.008041 +0.00802 +0.008079 +0.008137 +0.00813 +0.008146 +0.008136 +0.00809 +0.008154 +0.008211 +0.008194 +0.008205 +0.008182 +0.008154 +0.008205 +0.008267 +0.008258 +0.008274 +0.008246 +0.008227 +0.008305 +0.008376 +0.008377 +0.00838 +0.008338 +0.0083 +0.008317 +0.008326 +0.008284 +0.00826 +0.008185 +0.008111 +0.008097 +0.008109 +0.008062 +0.008023 +0.007954 +0.007896 +0.007895 +0.007917 +0.007887 +0.00786 +0.007805 +0.007757 +0.007768 +0.007801 +0.007789 +0.007757 +0.007725 +0.007688 +0.007713 +0.007763 +0.007748 +0.00775 +0.007713 +0.007691 +0.007722 +0.007783 +0.007781 +0.007793 +0.007768 +0.007748 +0.007788 +0.00786 +0.00785 +0.007862 +0.007856 +0.007816 +0.007853 +0.007934 +0.000266 +0.007921 +0.007945 +0.007915 +0.007899 +0.007939 +0.008008 +0.00799 +0.008018 +0.007998 +0.007969 +0.008016 +0.008087 +0.008072 +0.008097 +0.008071 +0.008051 +0.008095 +0.008163 +0.008155 +0.008176 +0.008155 +0.008132 +0.008198 +0.008265 +0.008252 +0.008285 +0.008241 +0.008181 +0.0082 +0.008266 +0.008226 +0.008236 +0.008178 +0.008138 +0.008137 +0.008193 +0.008081 +0.008021 +0.00798 +0.007929 +0.007914 +0.007951 +0.007879 +0.007884 +0.007834 +0.007778 +0.007768 +0.00779 +0.007752 +0.007758 +0.007716 +0.007688 +0.007708 +0.007776 +0.007729 +0.007757 +0.007688 +0.007644 +0.007676 +0.00773 +0.007709 +0.007727 +0.007698 +0.007693 +0.007729 +0.007795 +0.007792 +0.007799 +0.007775 +0.007768 +0.007809 +0.007875 +0.007859 +0.007885 +0.007854 +0.000267 +0.007847 +0.007887 +0.007962 +0.007941 +0.007962 +0.007908 +0.0079 +0.007931 +0.008011 +0.007979 +0.008014 +0.00798 +0.007973 +0.008007 +0.008082 +0.008052 +0.00809 +0.008035 +0.008033 +0.008065 +0.008146 +0.008128 +0.008187 +0.008151 +0.008136 +0.008175 +0.008247 +0.008217 +0.008241 +0.00817 +0.008135 +0.008131 +0.00816 +0.008083 +0.008078 +0.007986 +0.007923 +0.007909 +0.007946 +0.007881 +0.007876 +0.007806 +0.007758 +0.007755 +0.007804 +0.00775 +0.007755 +0.007686 +0.007649 +0.00766 +0.007713 +0.007668 +0.007693 +0.00764 +0.00762 +0.007642 +0.007704 +0.007673 +0.007697 +0.007648 +0.007641 +0.007677 +0.007751 +0.007724 +0.00776 +0.007714 +0.007706 +0.007736 +0.007813 +0.007793 +0.007837 +0.007785 +0.007778 +0.000268 +0.007815 +0.007888 +0.007877 +0.007896 +0.007864 +0.00785 +0.00789 +0.007962 +0.007947 +0.007972 +0.007945 +0.007926 +0.007966 +0.008037 +0.008025 +0.008052 +0.00802 +0.007992 +0.00805 +0.008115 +0.008107 +0.008132 +0.008107 +0.008089 +0.008145 +0.008229 +0.008209 +0.008229 +0.008159 +0.008101 +0.008127 +0.008177 +0.008125 +0.008116 +0.008054 +0.007955 +0.007938 +0.007967 +0.007909 +0.007906 +0.007839 +0.007759 +0.00773 +0.007783 +0.007725 +0.007739 +0.007677 +0.007653 +0.007619 +0.007648 +0.007599 +0.007616 +0.007567 +0.00755 +0.007575 +0.007635 +0.007608 +0.00762 +0.007592 +0.007562 +0.007567 +0.007616 +0.007582 +0.007622 +0.00759 +0.00757 +0.007624 +0.007686 +0.007668 +0.007693 +0.007671 +0.007654 +0.007697 +0.007778 +0.007759 +0.007769 +0.000269 +0.007753 +0.007728 +0.007777 +0.007848 +0.007836 +0.007854 +0.007837 +0.007815 +0.007866 +0.007929 +0.007911 +0.007925 +0.007897 +0.007871 +0.00792 +0.007971 +0.007956 +0.007966 +0.007955 +0.007915 +0.007965 +0.008019 +0.008025 +0.008034 +0.008039 +0.008025 +0.008071 +0.008118 +0.008081 +0.008061 +0.007995 +0.007928 +0.007933 +0.007948 +0.007884 +0.007857 +0.007796 +0.007723 +0.007726 +0.007744 +0.007697 +0.007675 +0.007621 +0.007567 +0.007593 +0.007611 +0.007587 +0.007569 +0.007526 +0.007479 +0.007511 +0.007561 +0.007537 +0.00754 +0.007508 +0.007475 +0.00752 +0.007574 +0.007562 +0.007573 +0.007552 +0.00752 +0.007579 +0.007641 +0.007632 +0.007649 +0.007619 +0.007616 +0.00762 +0.007701 +0.00769 +0.00027 +0.007706 +0.007695 +0.007673 +0.007721 +0.007784 +0.007776 +0.007792 +0.007771 +0.007739 +0.007785 +0.007845 +0.007837 +0.007853 +0.007831 +0.007805 +0.007854 +0.007913 +0.007916 +0.007929 +0.007909 +0.007886 +0.007935 +0.008004 +0.007998 +0.008017 +0.008003 +0.007977 +0.008038 +0.00811 +0.008102 +0.008084 +0.007987 +0.007933 +0.007957 +0.007991 +0.007949 +0.007897 +0.007813 +0.007752 +0.007765 +0.007769 +0.007723 +0.007718 +0.007652 +0.007576 +0.007579 +0.0076 +0.007573 +0.007562 +0.007532 +0.007482 +0.00752 +0.007534 +0.007494 +0.00751 +0.007471 +0.007425 +0.00744 +0.007481 +0.007467 +0.00747 +0.007454 +0.007432 +0.007476 +0.007544 +0.007531 +0.007539 +0.007532 +0.007507 +0.007551 +0.007614 +0.007606 +0.007631 +0.007589 +0.007582 +0.000271 +0.00764 +0.007696 +0.007681 +0.007698 +0.007685 +0.007645 +0.007679 +0.007721 +0.007706 +0.007728 +0.00772 +0.007678 +0.007739 +0.007796 +0.00779 +0.007804 +0.007788 +0.00777 +0.007838 +0.007904 +0.007901 +0.007909 +0.007881 +0.007858 +0.007901 +0.007958 +0.007956 +0.007965 +0.007947 +0.007925 +0.007966 +0.008 +0.007967 +0.007935 +0.007877 +0.007808 +0.007814 +0.007824 +0.007771 +0.007743 +0.007688 +0.007628 +0.007621 +0.007648 +0.00762 +0.007596 +0.007553 +0.007498 +0.007511 +0.00755 +0.007521 +0.007504 +0.007467 +0.007429 +0.007453 +0.00751 +0.00749 +0.007482 +0.00746 +0.00742 +0.007458 +0.007525 +0.007514 +0.00752 +0.007504 +0.007474 +0.007512 +0.007582 +0.007578 +0.007591 +0.00757 +0.007544 +0.007596 +0.007646 +0.007636 +0.000272 +0.007668 +0.007637 +0.007612 +0.007655 +0.007727 +0.007716 +0.007737 +0.007704 +0.00769 +0.00773 +0.007799 +0.007789 +0.007808 +0.007779 +0.00776 +0.007805 +0.007871 +0.00786 +0.00789 +0.007852 +0.007841 +0.007889 +0.007962 +0.007939 +0.007973 +0.007948 +0.007937 +0.007998 +0.008045 +0.007974 +0.007996 +0.007944 +0.007912 +0.007911 +0.007933 +0.007878 +0.007868 +0.007779 +0.007722 +0.007709 +0.007747 +0.007705 +0.007686 +0.007636 +0.007585 +0.00755 +0.007593 +0.007543 +0.007557 +0.007514 +0.007479 +0.00751 +0.007542 +0.007491 +0.007505 +0.007445 +0.007437 +0.007441 +0.00749 +0.007465 +0.007472 +0.007456 +0.007434 +0.007475 +0.007548 +0.007524 +0.007552 +0.007529 +0.007504 +0.00755 +0.00762 +0.0076 +0.007627 +0.007592 +0.007582 +0.000273 +0.007639 +0.007694 +0.007684 +0.007693 +0.007677 +0.007654 +0.007699 +0.00774 +0.00773 +0.007739 +0.007724 +0.007699 +0.007746 +0.0078 +0.007789 +0.007805 +0.007784 +0.007762 +0.007806 +0.007872 +0.007887 +0.007916 +0.007895 +0.007862 +0.007913 +0.007967 +0.007963 +0.007965 +0.007929 +0.007888 +0.007914 +0.007945 +0.007902 +0.007864 +0.007797 +0.007734 +0.00773 +0.007747 +0.007702 +0.007678 +0.007613 +0.007559 +0.007571 +0.007602 +0.007571 +0.007562 +0.007516 +0.007469 +0.007489 +0.007524 +0.007507 +0.007502 +0.007465 +0.007433 +0.007459 +0.007508 +0.007497 +0.007495 +0.007473 +0.007445 +0.007487 +0.007541 +0.00754 +0.007552 +0.007528 +0.007508 +0.007551 +0.007615 +0.007611 +0.007631 +0.007586 +0.007575 +0.000274 +0.007621 +0.007689 +0.007683 +0.007693 +0.00767 +0.007643 +0.007693 +0.007755 +0.00775 +0.007771 +0.007741 +0.007721 +0.007766 +0.007829 +0.007827 +0.007839 +0.007815 +0.00779 +0.007844 +0.007896 +0.0079 +0.007917 +0.007889 +0.007873 +0.007929 +0.007987 +0.007989 +0.008008 +0.00799 +0.007967 +0.008026 +0.008028 +0.007969 +0.007961 +0.007918 +0.007852 +0.007834 +0.007852 +0.007798 +0.007783 +0.007714 +0.007651 +0.00765 +0.007671 +0.007646 +0.007624 +0.007594 +0.007515 +0.007521 +0.007542 +0.007517 +0.007512 +0.007489 +0.007441 +0.007485 +0.007525 +0.007501 +0.007491 +0.007434 +0.007418 +0.007453 +0.007506 +0.007503 +0.007488 +0.007485 +0.007462 +0.007508 +0.007566 +0.007547 +0.007557 +0.007552 +0.007519 +0.007551 +0.007611 +0.007597 +0.007616 +0.007607 +0.000275 +0.007566 +0.007641 +0.007689 +0.007677 +0.007703 +0.007669 +0.007657 +0.007702 +0.007768 +0.007753 +0.007772 +0.007744 +0.007729 +0.007761 +0.00783 +0.007809 +0.00783 +0.0078 +0.007778 +0.007821 +0.007894 +0.007891 +0.007927 +0.007905 +0.00788 +0.007913 +0.007975 +0.007947 +0.007946 +0.007896 +0.007833 +0.007828 +0.007851 +0.007791 +0.007772 +0.007701 +0.00764 +0.007636 +0.007669 +0.007612 +0.007596 +0.007541 +0.007496 +0.007501 +0.007541 +0.007498 +0.007496 +0.007449 +0.007407 +0.00742 +0.007474 +0.007443 +0.007455 +0.007427 +0.007396 +0.007422 +0.007486 +0.007462 +0.007484 +0.00744 +0.007428 +0.007471 +0.007538 +0.007522 +0.007547 +0.007516 +0.007498 +0.007537 +0.007603 +0.007602 +0.007605 +0.000276 +0.007583 +0.007577 +0.007611 +0.007682 +0.007658 +0.007689 +0.007654 +0.007642 +0.00767 +0.007759 +0.007722 +0.007764 +0.007725 +0.007721 +0.00775 +0.007829 +0.007804 +0.007838 +0.007805 +0.007792 +0.007822 +0.007914 +0.007873 +0.007923 +0.007882 +0.007885 +0.007925 +0.008002 +0.007987 +0.007983 +0.007907 +0.007889 +0.007908 +0.007967 +0.007914 +0.007902 +0.007838 +0.007768 +0.007731 +0.00776 +0.007707 +0.007712 +0.007657 +0.007613 +0.007613 +0.007621 +0.007558 +0.007574 +0.007523 +0.007504 +0.007456 +0.007519 +0.007455 +0.007482 +0.007429 +0.007413 +0.007441 +0.007496 +0.007474 +0.007489 +0.007453 +0.007445 +0.007436 +0.007502 +0.007461 +0.007499 +0.007472 +0.007461 +0.007506 +0.007577 +0.00754 +0.00758 +0.007544 +0.007534 +0.007571 +0.007657 +0.007623 +0.007651 +0.000277 +0.007626 +0.007607 +0.007654 +0.007725 +0.007704 +0.007726 +0.007696 +0.007684 +0.007721 +0.00778 +0.007756 +0.007769 +0.007742 +0.007728 +0.00777 +0.00783 +0.007804 +0.007822 +0.007806 +0.00779 +0.007832 +0.007925 +0.007925 +0.007947 +0.007906 +0.00788 +0.007915 +0.007977 +0.00795 +0.007937 +0.007876 +0.007813 +0.007796 +0.007831 +0.007778 +0.007747 +0.007679 +0.007623 +0.007614 +0.007644 +0.007596 +0.007586 +0.007533 +0.007488 +0.007487 +0.007539 +0.007495 +0.007492 +0.00745 +0.007414 +0.007428 +0.007482 +0.007462 +0.007468 +0.007437 +0.007411 +0.00744 +0.007507 +0.007488 +0.007504 +0.007484 +0.007463 +0.0075 +0.007573 +0.007556 +0.007581 +0.007558 +0.007524 +0.007559 +0.007649 +0.000278 +0.007623 +0.00765 +0.007616 +0.00761 +0.00764 +0.007714 +0.007697 +0.007728 +0.007687 +0.007676 +0.007709 +0.007782 +0.007767 +0.0078 +0.007759 +0.007754 +0.007783 +0.007857 +0.007846 +0.007873 +0.007835 +0.007834 +0.007864 +0.007946 +0.007919 +0.007966 +0.007924 +0.00793 +0.007979 +0.008027 +0.007957 +0.007967 +0.00792 +0.00789 +0.007872 +0.007913 +0.007851 +0.007834 +0.007751 +0.007712 +0.007688 +0.007718 +0.007669 +0.007668 +0.007614 +0.007573 +0.007553 +0.007582 +0.007519 +0.007548 +0.007482 +0.007482 +0.007482 +0.007533 +0.007475 +0.007501 +0.007451 +0.007426 +0.007439 +0.007489 +0.007466 +0.007488 +0.007448 +0.007451 +0.007474 +0.00756 +0.007532 +0.007565 +0.007536 +0.007523 +0.007555 +0.007639 +0.007622 +0.007629 +0.007605 +0.000279 +0.007602 +0.007643 +0.00772 +0.007687 +0.007718 +0.007688 +0.007685 +0.007705 +0.007762 +0.007724 +0.007756 +0.007727 +0.007713 +0.007749 +0.007823 +0.007795 +0.007827 +0.00779 +0.00778 +0.007815 +0.007897 +0.007901 +0.007933 +0.007905 +0.007895 +0.007905 +0.007994 +0.007962 +0.007976 +0.007925 +0.007903 +0.007886 +0.007948 +0.007888 +0.007858 +0.007777 +0.007728 +0.007712 +0.007735 +0.007678 +0.007661 +0.007581 +0.007542 +0.007534 +0.007577 +0.007527 +0.007523 +0.007462 +0.007426 +0.00742 +0.007476 +0.007442 +0.007449 +0.0074 +0.00738 +0.007392 +0.007456 +0.007433 +0.007451 +0.007413 +0.007401 +0.007421 +0.007496 +0.007478 +0.007506 +0.007476 +0.007461 +0.00749 +0.007568 +0.007543 +0.007591 +0.007525 +0.007528 +0.00028 +0.007568 +0.007631 +0.007622 +0.007643 +0.007615 +0.007598 +0.007636 +0.007707 +0.007692 +0.007714 +0.007684 +0.007669 +0.007711 +0.00778 +0.007764 +0.007785 +0.00776 +0.007743 +0.007785 +0.007855 +0.007842 +0.007867 +0.007844 +0.007828 +0.007877 +0.00795 +0.007931 +0.007955 +0.007943 +0.007894 +0.007882 +0.007927 +0.007887 +0.007895 +0.007847 +0.007794 +0.007812 +0.007859 +0.007815 +0.007767 +0.007665 +0.007618 +0.00762 +0.007672 +0.007621 +0.007617 +0.007516 +0.00748 +0.007507 +0.007533 +0.007506 +0.007497 +0.00746 +0.007434 +0.007426 +0.007479 +0.007438 +0.007458 +0.007424 +0.007397 +0.007449 +0.007501 +0.007472 +0.007505 +0.007475 +0.007469 +0.007482 +0.007522 +0.007511 +0.007532 +0.007508 +0.007497 +0.00755 +0.007607 +0.007591 +0.007619 +0.007593 +0.000281 +0.007578 +0.007621 +0.007688 +0.007667 +0.007705 +0.007665 +0.007661 +0.007691 +0.007777 +0.007741 +0.007776 +0.007742 +0.007726 +0.007762 +0.007842 +0.007799 +0.00783 +0.007793 +0.007786 +0.007815 +0.007888 +0.007873 +0.007907 +0.00788 +0.007879 +0.007907 +0.007983 +0.007959 +0.00797 +0.007914 +0.007885 +0.00788 +0.007914 +0.007854 +0.007838 +0.007756 +0.007708 +0.007687 +0.007726 +0.007672 +0.007659 +0.00758 +0.007553 +0.007546 +0.00759 +0.007547 +0.007547 +0.007484 +0.00746 +0.007458 +0.007517 +0.007485 +0.007497 +0.007445 +0.007438 +0.007441 +0.00751 +0.007491 +0.007508 +0.007467 +0.007461 +0.007483 +0.007562 +0.007541 +0.007568 +0.007531 +0.007526 +0.007549 +0.007636 +0.007612 +0.007651 +0.007595 +0.000282 +0.007588 +0.007627 +0.007698 +0.007691 +0.007702 +0.007679 +0.007661 +0.007704 +0.00777 +0.00776 +0.00778 +0.007753 +0.007734 +0.007773 +0.007842 +0.007832 +0.007866 +0.007815 +0.00781 +0.007858 +0.00792 +0.007918 +0.007931 +0.007916 +0.007893 +0.007945 +0.008025 +0.00801 +0.008032 +0.008017 +0.007923 +0.007944 +0.007988 +0.007952 +0.007952 +0.007901 +0.007855 +0.007872 +0.007931 +0.007845 +0.007761 +0.00771 +0.00768 +0.007688 +0.007735 +0.007682 +0.007664 +0.007581 +0.007541 +0.007576 +0.007601 +0.007581 +0.007571 +0.007541 +0.007491 +0.007504 +0.007554 +0.007521 +0.007547 +0.007507 +0.007498 +0.007528 +0.007587 +0.007578 +0.00759 +0.007575 +0.007558 +0.007601 +0.007676 +0.007656 +0.00766 +0.007644 +0.007629 +0.007665 +0.000283 +0.007708 +0.007699 +0.007713 +0.007705 +0.007678 +0.007732 +0.007792 +0.007777 +0.007794 +0.007783 +0.007746 +0.007806 +0.007867 +0.007848 +0.007863 +0.00784 +0.007819 +0.007865 +0.007925 +0.007907 +0.007917 +0.007895 +0.00787 +0.007923 +0.008005 +0.008012 +0.008025 +0.008002 +0.00797 +0.008012 +0.008058 +0.008022 +0.008012 +0.007953 +0.007882 +0.007875 +0.007903 +0.007853 +0.007815 +0.007754 +0.00769 +0.007692 +0.00771 +0.007673 +0.007666 +0.007608 +0.007551 +0.007577 +0.007609 +0.007569 +0.007562 +0.007529 +0.007486 +0.007514 +0.007561 +0.007542 +0.007549 +0.007523 +0.007487 +0.00753 +0.007581 +0.00757 +0.007585 +0.007568 +0.00754 +0.007586 +0.007647 +0.007636 +0.007655 +0.007642 +0.0076 +0.007648 +0.007726 +0.000284 +0.007704 +0.007725 +0.007713 +0.007678 +0.007722 +0.007792 +0.007781 +0.007803 +0.007776 +0.007752 +0.007797 +0.007867 +0.007852 +0.007875 +0.007845 +0.007831 +0.007872 +0.007937 +0.007922 +0.007954 +0.007917 +0.007908 +0.007943 +0.008023 +0.00801 +0.008047 +0.008003 +0.007997 +0.008055 +0.008119 +0.008107 +0.008078 +0.007979 +0.007933 +0.007956 +0.007995 +0.007938 +0.007901 +0.007799 +0.007753 +0.007764 +0.007797 +0.007735 +0.007722 +0.007639 +0.007607 +0.007595 +0.007644 +0.007595 +0.007609 +0.007552 +0.007526 +0.007522 +0.007563 +0.007534 +0.007542 +0.007519 +0.00749 +0.007505 +0.007546 +0.007509 +0.007546 +0.007512 +0.007493 +0.007548 +0.007611 +0.00759 +0.007617 +0.00759 +0.00756 +0.007614 +0.007683 +0.007666 +0.007689 +0.007659 +0.000285 +0.007654 +0.007687 +0.007772 +0.00774 +0.007763 +0.007709 +0.007703 +0.007727 +0.00781 +0.007781 +0.007809 +0.007777 +0.007768 +0.0078 +0.007879 +0.007847 +0.007879 +0.007844 +0.00783 +0.00786 +0.007953 +0.007951 +0.007982 +0.007947 +0.007937 +0.007958 +0.008038 +0.008008 +0.008042 +0.008007 +0.007984 +0.007992 +0.00803 +0.00796 +0.007952 +0.00788 +0.007826 +0.007808 +0.007847 +0.007772 +0.00778 +0.007709 +0.00766 +0.007659 +0.007711 +0.007663 +0.007671 +0.007608 +0.007569 +0.007583 +0.007637 +0.007595 +0.007607 +0.007557 +0.00753 +0.007556 +0.00762 +0.007588 +0.007624 +0.007564 +0.007555 +0.007589 +0.007664 +0.007638 +0.007674 +0.007638 +0.007625 +0.007661 +0.00773 +0.007714 +0.007753 +0.007689 +0.000286 +0.007695 +0.007732 +0.007804 +0.007794 +0.007814 +0.007781 +0.007763 +0.0078 +0.007875 +0.007858 +0.007891 +0.007859 +0.007838 +0.007881 +0.007949 +0.007937 +0.007961 +0.007926 +0.007915 +0.007959 +0.008028 +0.008021 +0.008043 +0.008012 +0.008002 +0.00805 +0.00813 +0.008123 +0.008143 +0.008055 +0.007998 +0.008012 +0.008063 +0.007997 +0.008001 +0.007939 +0.007832 +0.007831 +0.007864 +0.007812 +0.007808 +0.007772 +0.007721 +0.007709 +0.007719 +0.007686 +0.007686 +0.007651 +0.007623 +0.007645 +0.007699 +0.007655 +0.00762 +0.007591 +0.007558 +0.007601 +0.007655 +0.007623 +0.007644 +0.007605 +0.007599 +0.007638 +0.007684 +0.007677 +0.00769 +0.00767 +0.007646 +0.007663 +0.007738 +0.007708 +0.007737 +0.007716 +0.007715 +0.007756 +0.007816 +0.007801 +0.000287 +0.007827 +0.007796 +0.007792 +0.007824 +0.007906 +0.007881 +0.007914 +0.007876 +0.007863 +0.007895 +0.00797 +0.007939 +0.007965 +0.00793 +0.00792 +0.007957 +0.008032 +0.008008 +0.008063 +0.008033 +0.00802 +0.008051 +0.00813 +0.008093 +0.008102 +0.008034 +0.007984 +0.007983 +0.008019 +0.007943 +0.007929 +0.007849 +0.007792 +0.007778 +0.007814 +0.007743 +0.007743 +0.007676 +0.007631 +0.007627 +0.007677 +0.007624 +0.007631 +0.007577 +0.00754 +0.007552 +0.007608 +0.007571 +0.007591 +0.007549 +0.007532 +0.007557 +0.007632 +0.007601 +0.007629 +0.007588 +0.007578 +0.007602 +0.007688 +0.007668 +0.007706 +0.007655 +0.007656 +0.007674 +0.007768 +0.007728 +0.000288 +0.007768 +0.007738 +0.007722 +0.007756 +0.00783 +0.007817 +0.007838 +0.007807 +0.007802 +0.007826 +0.007903 +0.007888 +0.007911 +0.00788 +0.007863 +0.007909 +0.007977 +0.007965 +0.007988 +0.007965 +0.007947 +0.007993 +0.008069 +0.00805 +0.008078 +0.008056 +0.008044 +0.008097 +0.008152 +0.008083 +0.008083 +0.008033 +0.007981 +0.007961 +0.00799 +0.007935 +0.007906 +0.007807 +0.007764 +0.007752 +0.007767 +0.007739 +0.007716 +0.007672 +0.00759 +0.007594 +0.007619 +0.007588 +0.007586 +0.007542 +0.007507 +0.007544 +0.007582 +0.007544 +0.007518 +0.007469 +0.007453 +0.00748 +0.007547 +0.007512 +0.007531 +0.007513 +0.007485 +0.007537 +0.007606 +0.00758 +0.007611 +0.007572 +0.007541 +0.007574 +0.007632 +0.007607 +0.007646 +0.007623 +0.007605 +0.007652 +0.000289 +0.007717 +0.007693 +0.007726 +0.00769 +0.007682 +0.007718 +0.007794 +0.007768 +0.007804 +0.007768 +0.007758 +0.007787 +0.007862 +0.007835 +0.007862 +0.007822 +0.007813 +0.007844 +0.007923 +0.007927 +0.007955 +0.007924 +0.00791 +0.007942 +0.008009 +0.007976 +0.007982 +0.007915 +0.007884 +0.007866 +0.007895 +0.007831 +0.007821 +0.00773 +0.007682 +0.007668 +0.007702 +0.007642 +0.007646 +0.007571 +0.007537 +0.007524 +0.007575 +0.007533 +0.007535 +0.007476 +0.007459 +0.007451 +0.00751 +0.007479 +0.007503 +0.007452 +0.007438 +0.007462 +0.007522 +0.007503 +0.007529 +0.007486 +0.007483 +0.007516 +0.007584 +0.007573 +0.007592 +0.007562 +0.007556 +0.007576 +0.007645 +0.007644 +0.00029 +0.007663 +0.007631 +0.007619 +0.00766 +0.007726 +0.007707 +0.007733 +0.007703 +0.007687 +0.007731 +0.007796 +0.007785 +0.007809 +0.00778 +0.007755 +0.007806 +0.007861 +0.007862 +0.007882 +0.00785 +0.007838 +0.00788 +0.007957 +0.00794 +0.007979 +0.007943 +0.007932 +0.007992 +0.008066 +0.00799 +0.007964 +0.00792 +0.007873 +0.007902 +0.007927 +0.007848 +0.007814 +0.00775 +0.007692 +0.00769 +0.007717 +0.007669 +0.007653 +0.00759 +0.007526 +0.007525 +0.007569 +0.007526 +0.007528 +0.007489 +0.007443 +0.007427 +0.007479 +0.007439 +0.00745 +0.007427 +0.007397 +0.007442 +0.007493 +0.007477 +0.007484 +0.007455 +0.007437 +0.007455 +0.007503 +0.007491 +0.007514 +0.007486 +0.007477 +0.007519 +0.007581 +0.007572 +0.007597 +0.007572 +0.007558 +0.007602 +0.000291 +0.007667 +0.007655 +0.007681 +0.007644 +0.007638 +0.007672 +0.007751 +0.007727 +0.007764 +0.007716 +0.007715 +0.007745 +0.007817 +0.007781 +0.007802 +0.007769 +0.007759 +0.007795 +0.007862 +0.007836 +0.007871 +0.007841 +0.007842 +0.007894 +0.007975 +0.007935 +0.007957 +0.007899 +0.007855 +0.007853 +0.0079 +0.007841 +0.00783 +0.007742 +0.007685 +0.007684 +0.007719 +0.007655 +0.007636 +0.007559 +0.007524 +0.007513 +0.007566 +0.007514 +0.007523 +0.007454 +0.007424 +0.007437 +0.007497 +0.00745 +0.007473 +0.007425 +0.007408 +0.007433 +0.007502 +0.007472 +0.007502 +0.00746 +0.007439 +0.007471 +0.007545 +0.007532 +0.007566 +0.007526 +0.007518 +0.007541 +0.00764 +0.007589 +0.007623 +0.000292 +0.007593 +0.00758 +0.007622 +0.007689 +0.007677 +0.0077 +0.007672 +0.007656 +0.007689 +0.007757 +0.007748 +0.00777 +0.007741 +0.007722 +0.007766 +0.007833 +0.007818 +0.00784 +0.007816 +0.007801 +0.00784 +0.007916 +0.007901 +0.00793 +0.007897 +0.007886 +0.007942 +0.008016 +0.007999 +0.008019 +0.007938 +0.007909 +0.007927 +0.007974 +0.007919 +0.007914 +0.007862 +0.007772 +0.007748 +0.00778 +0.007733 +0.007732 +0.007669 +0.007587 +0.007586 +0.007611 +0.007585 +0.007584 +0.00755 +0.007514 +0.007524 +0.007545 +0.007494 +0.007496 +0.007474 +0.007445 +0.007476 +0.007544 +0.007507 +0.007506 +0.007458 +0.007451 +0.007482 +0.007551 +0.007538 +0.00756 +0.007544 +0.007522 +0.007567 +0.007638 +0.00761 +0.007632 +0.007608 +0.007596 +0.007642 +0.000293 +0.007705 +0.007692 +0.007713 +0.007693 +0.007662 +0.007699 +0.007741 +0.007733 +0.007752 +0.007735 +0.007714 +0.007763 +0.007825 +0.007807 +0.00782 +0.007797 +0.007772 +0.007821 +0.007889 +0.007901 +0.007926 +0.007901 +0.007872 +0.00791 +0.007988 +0.007973 +0.007999 +0.00797 +0.007938 +0.007986 +0.00803 +0.00799 +0.007973 +0.007908 +0.007846 +0.007855 +0.007865 +0.007822 +0.00779 +0.00773 +0.007669 +0.007687 +0.007711 +0.007671 +0.007668 +0.007621 +0.007569 +0.007593 +0.007627 +0.007602 +0.007605 +0.007564 +0.007528 +0.007563 +0.007608 +0.007594 +0.007606 +0.00758 +0.007545 +0.007595 +0.007644 +0.007635 +0.007657 +0.007641 +0.007607 +0.007659 +0.00771 +0.007718 +0.007737 +0.007692 +0.007673 +0.000294 +0.007729 +0.007789 +0.007789 +0.007801 +0.007777 +0.007744 +0.007807 +0.00786 +0.007867 +0.00787 +0.007848 +0.007826 +0.007881 +0.007937 +0.007937 +0.00795 +0.007923 +0.007901 +0.007954 +0.008017 +0.008005 +0.008027 +0.008007 +0.007978 +0.008037 +0.008098 +0.008099 +0.008116 +0.008096 +0.008075 +0.008141 +0.008206 +0.008148 +0.008116 +0.008065 +0.00802 +0.008038 +0.008051 +0.007995 +0.007941 +0.007868 +0.007815 +0.007823 +0.007839 +0.007794 +0.007779 +0.007741 +0.00768 +0.007666 +0.007703 +0.00767 +0.00768 +0.007634 +0.007608 +0.007633 +0.007688 +0.007665 +0.007625 +0.007596 +0.007556 +0.007614 +0.007664 +0.007651 +0.007663 +0.007637 +0.007625 +0.007671 +0.007738 +0.007725 +0.007728 +0.007724 +0.007695 +0.007696 +0.007772 +0.007754 +0.007776 +0.000295 +0.00776 +0.007741 +0.007794 +0.007853 +0.007844 +0.007859 +0.007838 +0.007819 +0.007875 +0.007932 +0.007928 +0.007945 +0.007919 +0.007892 +0.007942 +0.008001 +0.007991 +0.008 +0.007979 +0.00796 +0.008009 +0.008071 +0.008066 +0.008096 +0.008079 +0.008047 +0.0081 +0.008162 +0.008154 +0.008165 +0.008125 +0.008087 +0.008113 +0.008133 +0.008094 +0.008062 +0.007996 +0.007928 +0.007934 +0.007956 +0.007908 +0.007887 +0.007841 +0.007781 +0.007793 +0.007827 +0.007804 +0.007801 +0.007754 +0.007713 +0.007744 +0.007785 +0.007766 +0.007771 +0.007741 +0.007714 +0.007756 +0.00781 +0.007804 +0.007817 +0.007788 +0.007763 +0.007815 +0.007879 +0.007876 +0.007884 +0.007879 +0.007828 +0.00788 +0.00795 +0.000296 +0.007942 +0.00797 +0.007931 +0.007923 +0.007954 +0.008026 +0.008018 +0.00804 +0.008009 +0.007996 +0.008029 +0.008103 +0.00809 +0.008115 +0.008083 +0.008078 +0.008109 +0.008182 +0.008178 +0.008199 +0.008171 +0.00816 +0.008211 +0.00828 +0.008276 +0.008301 +0.008276 +0.008209 +0.0082 +0.008228 +0.00819 +0.008193 +0.008139 +0.008091 +0.008117 +0.008155 +0.008041 +0.008013 +0.007958 +0.007925 +0.00793 +0.007949 +0.007896 +0.007889 +0.007863 +0.007797 +0.007797 +0.00783 +0.007799 +0.007804 +0.007778 +0.007742 +0.00779 +0.007843 +0.007821 +0.00782 +0.007789 +0.00775 +0.007759 +0.007841 +0.007807 +0.007842 +0.007813 +0.007801 +0.007847 +0.007905 +0.007898 +0.007919 +0.00789 +0.007882 +0.007932 +0.007987 +0.00797 +0.000297 +0.008016 +0.007968 +0.007963 +0.007999 +0.008078 +0.008059 +0.008086 +0.008052 +0.00804 +0.008077 +0.008156 +0.008128 +0.008157 +0.008107 +0.008101 +0.008137 +0.008207 +0.008172 +0.008201 +0.008168 +0.008158 +0.008182 +0.008265 +0.008232 +0.008296 +0.008273 +0.008277 +0.008302 +0.008367 +0.008329 +0.008326 +0.008249 +0.00821 +0.008199 +0.008241 +0.008177 +0.008158 +0.008082 +0.008039 +0.008028 +0.008066 +0.008015 +0.008016 +0.007953 +0.007925 +0.007925 +0.007974 +0.007938 +0.007938 +0.00788 +0.007865 +0.007876 +0.00794 +0.007913 +0.007924 +0.007878 +0.007874 +0.007896 +0.007966 +0.007946 +0.007968 +0.007932 +0.007932 +0.007958 +0.008045 +0.00802 +0.008064 +0.007997 +0.007991 +0.008027 +0.000298 +0.00811 +0.008094 +0.008119 +0.008092 +0.00807 +0.00811 +0.008188 +0.008167 +0.008201 +0.00816 +0.00815 +0.008191 +0.008267 +0.008259 +0.00827 +0.00824 +0.008224 +0.008271 +0.00834 +0.00833 +0.008356 +0.008328 +0.008316 +0.008371 +0.008439 +0.008434 +0.008458 +0.008422 +0.008338 +0.008289 +0.008321 +0.008257 +0.008252 +0.008194 +0.008087 +0.008056 +0.008083 +0.008019 +0.008015 +0.00795 +0.007912 +0.00791 +0.007914 +0.007833 +0.007842 +0.00778 +0.007758 +0.007737 +0.007778 +0.007725 +0.007733 +0.007705 +0.007667 +0.007685 +0.007719 +0.007676 +0.0077 +0.007661 +0.007643 +0.007687 +0.007748 +0.00773 +0.007748 +0.007717 +0.00772 +0.007741 +0.007814 +0.007783 +0.007802 +0.007792 +0.00776 +0.007791 +0.007866 +0.007836 +0.000299 +0.007864 +0.007833 +0.007826 +0.007871 +0.007942 +0.007916 +0.007952 +0.007916 +0.007908 +0.007945 +0.00802 +0.007989 +0.008025 +0.007979 +0.007973 +0.008003 +0.008084 +0.008053 +0.008089 +0.008057 +0.008057 +0.008099 +0.008183 +0.008161 +0.008186 +0.008141 +0.008129 +0.008141 +0.008199 +0.008144 +0.008137 +0.008045 +0.007992 +0.007967 +0.007996 +0.007926 +0.007897 +0.007816 +0.007771 +0.007762 +0.007794 +0.007753 +0.007739 +0.007666 +0.007637 +0.00764 +0.007686 +0.007643 +0.007646 +0.007586 +0.007566 +0.007578 +0.007641 +0.007617 +0.007632 +0.007587 +0.007571 +0.007586 +0.007661 +0.007647 +0.007674 +0.007634 +0.007626 +0.007651 +0.007733 +0.007716 +0.007743 +0.007725 +0.007673 +0.00773 +0.0003 +0.0078 +0.007786 +0.007819 +0.007779 +0.007763 +0.007797 +0.007875 +0.007858 +0.007889 +0.007851 +0.00784 +0.00787 +0.00795 +0.007933 +0.007964 +0.007925 +0.007912 +0.007946 +0.008029 +0.008006 +0.008041 +0.008007 +0.007994 +0.008039 +0.008123 +0.008098 +0.008133 +0.008107 +0.008101 +0.008095 +0.008088 +0.008026 +0.008028 +0.007965 +0.007924 +0.007934 +0.007956 +0.007834 +0.00783 +0.007764 +0.007711 +0.007708 +0.007733 +0.007676 +0.007684 +0.007629 +0.007602 +0.007567 +0.007611 +0.007554 +0.00758 +0.007527 +0.007513 +0.00753 +0.007593 +0.007554 +0.007572 +0.007535 +0.007506 +0.007511 +0.007568 +0.007539 +0.007572 +0.007536 +0.007535 +0.007565 +0.007635 +0.007613 +0.007645 +0.007611 +0.0076 +0.007641 +0.007723 +0.007694 +0.00772 +0.000301 +0.007692 +0.007682 +0.007723 +0.007795 +0.007774 +0.007794 +0.007771 +0.007758 +0.007808 +0.007871 +0.007842 +0.007846 +0.007818 +0.00779 +0.007839 +0.007906 +0.007884 +0.007904 +0.00788 +0.007861 +0.007903 +0.00797 +0.007957 +0.008011 +0.007989 +0.00797 +0.008013 +0.008075 +0.008061 +0.00807 +0.008016 +0.007978 +0.007984 +0.008014 +0.00796 +0.00792 +0.007834 +0.007785 +0.007766 +0.007789 +0.007739 +0.007723 +0.007653 +0.007607 +0.007608 +0.007642 +0.007605 +0.007605 +0.007542 +0.007507 +0.00752 +0.007565 +0.007539 +0.007544 +0.007502 +0.007484 +0.007517 +0.007576 +0.00756 +0.007571 +0.007533 +0.007523 +0.007545 +0.007621 +0.007618 +0.007636 +0.007604 +0.007588 +0.00762 +0.007709 +0.007665 +0.007698 +0.000302 +0.007682 +0.007654 +0.007705 +0.007763 +0.007754 +0.007769 +0.007752 +0.007728 +0.007776 +0.007841 +0.007828 +0.007842 +0.007823 +0.007794 +0.007848 +0.00791 +0.007908 +0.007927 +0.007897 +0.007876 +0.007933 +0.00799 +0.007994 +0.008001 +0.007991 +0.007966 +0.008027 +0.008103 +0.008093 +0.008046 +0.008015 +0.007976 +0.008017 +0.008054 +0.008005 +0.008 +0.007949 +0.007844 +0.007843 +0.007868 +0.007828 +0.007823 +0.007762 +0.007665 +0.007685 +0.007716 +0.00769 +0.007677 +0.007651 +0.007591 +0.00757 +0.007608 +0.007576 +0.00758 +0.007566 +0.00752 +0.007571 +0.007617 +0.007602 +0.007606 +0.00758 +0.007566 +0.007609 +0.007634 +0.00763 +0.00764 +0.007632 +0.007605 +0.007642 +0.00771 +0.007689 +0.0077 +0.007692 +0.00767 +0.007723 +0.00779 +0.015562 +0.000303 +0.007762 +0.007752 +0.007785 +0.007867 +0.007835 +0.007867 +0.007836 +0.007827 +0.007858 +0.007929 +0.007893 +0.007918 +0.007883 +0.007868 +0.0079 +0.00798 +0.00795 +0.007987 +0.007954 +0.007956 +0.008005 +0.008097 +0.008064 +0.0081 +0.008054 +0.008029 +0.008045 +0.008092 +0.008027 +0.008031 +0.007945 +0.007887 +0.007872 +0.007909 +0.00784 +0.007838 +0.007762 +0.00771 +0.007719 +0.007764 +0.007708 +0.007722 +0.007659 +0.007621 +0.007639 +0.007692 +0.007649 +0.007664 +0.007611 +0.00759 +0.00762 +0.007689 +0.007653 +0.007684 +0.00764 +0.007621 +0.007655 +0.007731 +0.007714 +0.007743 +0.007703 +0.007691 +0.007731 +0.007796 +0.007808 +0.007799 +0.007771 +0.000304 +0.007762 +0.007803 +0.007879 +0.007858 +0.007892 +0.007851 +0.007838 +0.00787 +0.007955 +0.007926 +0.007966 +0.007927 +0.007917 +0.00795 +0.008035 +0.008 +0.008038 +0.007995 +0.007987 +0.008024 +0.008097 +0.008086 +0.008114 +0.00808 +0.008074 +0.008117 +0.008193 +0.008175 +0.008219 +0.008179 +0.008172 +0.008197 +0.008189 +0.008118 +0.008122 +0.008055 +0.008015 +0.007975 +0.007986 +0.007919 +0.007931 +0.007858 +0.007834 +0.007794 +0.007833 +0.007765 +0.007789 +0.007734 +0.007701 +0.007665 +0.007722 +0.007663 +0.007697 +0.007645 +0.007626 +0.007659 +0.007719 +0.007694 +0.007707 +0.007677 +0.007669 +0.007683 +0.007747 +0.007705 +0.007747 +0.007714 +0.007699 +0.007737 +0.007798 +0.007767 +0.00781 +0.007767 +0.007765 +0.007806 +0.00788 +0.00786 +0.00788 +0.000305 +0.007851 +0.007843 +0.007879 +0.007956 +0.007933 +0.007967 +0.007931 +0.00792 +0.007957 +0.00804 +0.008001 +0.008036 +0.007995 +0.007986 +0.008016 +0.00809 +0.008052 +0.008082 +0.008051 +0.008041 +0.008072 +0.008144 +0.00813 +0.008169 +0.00816 +0.008145 +0.008176 +0.00824 +0.008178 +0.008169 +0.008086 +0.008018 +0.008004 +0.008048 +0.007975 +0.007964 +0.007882 +0.007841 +0.007839 +0.007884 +0.007832 +0.007833 +0.007767 +0.007734 +0.007743 +0.007801 +0.007751 +0.007761 +0.007712 +0.007687 +0.007714 +0.007778 +0.007751 +0.007776 +0.007734 +0.007716 +0.007749 +0.007826 +0.007799 +0.007832 +0.007795 +0.007784 +0.007818 +0.007895 +0.007868 +0.00792 +0.007852 +0.007863 +0.000306 +0.007883 +0.007968 +0.007952 +0.007971 +0.007949 +0.007926 +0.007968 +0.008044 +0.008033 +0.008053 +0.008021 +0.007999 +0.008043 +0.008122 +0.008105 +0.008129 +0.008098 +0.00808 +0.00812 +0.008194 +0.008184 +0.008207 +0.008173 +0.008161 +0.008202 +0.008287 +0.00827 +0.0083 +0.00828 +0.008266 +0.008315 +0.008395 +0.008309 +0.00827 +0.008221 +0.008183 +0.008197 +0.008212 +0.008143 +0.008087 +0.008016 +0.007963 +0.007986 +0.007992 +0.007929 +0.00794 +0.007879 +0.007854 +0.007819 +0.007868 +0.007823 +0.00782 +0.00778 +0.007758 +0.007779 +0.007854 +0.00782 +0.00784 +0.007779 +0.007747 +0.007777 +0.007835 +0.007818 +0.007842 +0.007813 +0.007807 +0.007844 +0.007919 +0.007892 +0.007918 +0.007899 +0.007875 +0.007926 +0.008 +0.00798 +0.000307 +0.008012 +0.007975 +0.007971 +0.008007 +0.008088 +0.008053 +0.008088 +0.008056 +0.008059 +0.008057 +0.008126 +0.008095 +0.008128 +0.008099 +0.008085 +0.008124 +0.0082 +0.008171 +0.008201 +0.008168 +0.008157 +0.008205 +0.008306 +0.008291 +0.008313 +0.008275 +0.008255 +0.00829 +0.008365 +0.008342 +0.008355 +0.008277 +0.008223 +0.00821 +0.008248 +0.008182 +0.008169 +0.008084 +0.008037 +0.008033 +0.008072 +0.008017 +0.00802 +0.007943 +0.007908 +0.007919 +0.007969 +0.007926 +0.007933 +0.007872 +0.007839 +0.00786 +0.007927 +0.0079 +0.007926 +0.007873 +0.007856 +0.007882 +0.007948 +0.007925 +0.007962 +0.007925 +0.007918 +0.007952 +0.008022 +0.008009 +0.008041 +0.007994 +0.007976 +0.008021 +0.000308 +0.008085 +0.008084 +0.008111 +0.008079 +0.008062 +0.008107 +0.008172 +0.00816 +0.008182 +0.00815 +0.008129 +0.008179 +0.008256 +0.008245 +0.008272 +0.00822 +0.008211 +0.008259 +0.008334 +0.00832 +0.00835 +0.008317 +0.008298 +0.008351 +0.00843 +0.008414 +0.008455 +0.008424 +0.008408 +0.008431 +0.008422 +0.008376 +0.008357 +0.008314 +0.008275 +0.008258 +0.008248 +0.008184 +0.008172 +0.008121 +0.008056 +0.008017 +0.008066 +0.008007 +0.008032 +0.007972 +0.007941 +0.007958 +0.007978 +0.007921 +0.007943 +0.007893 +0.007867 +0.00787 +0.007923 +0.007895 +0.007918 +0.00789 +0.007865 +0.007915 +0.007979 +0.007962 +0.00799 +0.007962 +0.007951 +0.007986 +0.008064 +0.008051 +0.008057 +0.008036 +0.000309 +0.008032 +0.00807 +0.008144 +0.008126 +0.008153 +0.008116 +0.008102 +0.008117 +0.008193 +0.00816 +0.008196 +0.008166 +0.008153 +0.008198 +0.008276 +0.008248 +0.00828 +0.00824 +0.008229 +0.008261 +0.008346 +0.008324 +0.008352 +0.008343 +0.008331 +0.008378 +0.00845 +0.008426 +0.008459 +0.00841 +0.008381 +0.008383 +0.008449 +0.008389 +0.00838 +0.008289 +0.008223 +0.00821 +0.008251 +0.008183 +0.008173 +0.008103 +0.008054 +0.00805 +0.008108 +0.008049 +0.00806 +0.008 +0.007961 +0.007969 +0.00803 +0.007986 +0.008002 +0.007952 +0.007933 +0.007948 +0.008031 +0.007983 +0.008021 +0.007983 +0.007963 +0.007999 +0.00808 +0.008055 +0.00809 +0.008051 +0.008037 +0.008075 +0.008158 +0.008141 +0.008162 +0.00031 +0.008124 +0.008117 +0.00815 +0.008234 +0.008216 +0.008244 +0.008207 +0.008194 +0.008229 +0.008315 +0.008297 +0.008328 +0.008282 +0.008274 +0.008312 +0.008394 +0.008371 +0.008402 +0.00837 +0.008355 +0.008391 +0.008478 +0.008459 +0.008498 +0.008456 +0.008455 +0.008499 +0.008588 +0.00856 +0.008595 +0.008518 +0.008419 +0.008429 +0.008471 +0.008408 +0.008416 +0.008331 +0.008227 +0.008209 +0.008256 +0.008178 +0.008205 +0.008112 +0.008058 +0.008018 +0.008081 +0.008023 +0.008038 +0.007976 +0.007952 +0.007953 +0.008021 +0.007951 +0.007953 +0.007893 +0.007873 +0.007908 +0.007965 +0.007916 +0.00796 +0.007914 +0.007904 +0.007957 +0.008027 +0.007998 +0.008003 +0.007949 +0.00795 +0.007992 +0.008064 +0.008043 +0.008079 +0.008044 +0.008029 +0.000311 +0.008087 +0.008145 +0.008123 +0.008154 +0.008124 +0.008121 +0.008158 +0.008237 +0.008207 +0.008242 +0.008205 +0.008194 +0.008238 +0.008314 +0.008283 +0.008309 +0.008272 +0.008265 +0.008287 +0.008372 +0.00834 +0.00836 +0.008322 +0.008324 +0.008362 +0.008467 +0.008455 +0.008477 +0.008422 +0.008389 +0.008404 +0.008444 +0.008379 +0.008356 +0.008259 +0.008207 +0.008187 +0.00822 +0.008149 +0.008138 +0.008051 +0.008005 +0.008002 +0.008048 +0.007998 +0.008 +0.007927 +0.00789 +0.007892 +0.007943 +0.007908 +0.007924 +0.007869 +0.007846 +0.007866 +0.007929 +0.007898 +0.007926 +0.007881 +0.007868 +0.007893 +0.007971 +0.007943 +0.007981 +0.00794 +0.007934 +0.007965 +0.008041 +0.008021 +0.008058 +0.008008 +0.008003 +0.000312 +0.008042 +0.008118 +0.008099 +0.008129 +0.008095 +0.008081 +0.008121 +0.00819 +0.00818 +0.008204 +0.008178 +0.008161 +0.0082 +0.008272 +0.008257 +0.008288 +0.008251 +0.008231 +0.008283 +0.00835 +0.008348 +0.008368 +0.008345 +0.008328 +0.00838 +0.008465 +0.008448 +0.008467 +0.008365 +0.00829 +0.008302 +0.008346 +0.008288 +0.008255 +0.008145 +0.008091 +0.00809 +0.008111 +0.008043 +0.008055 +0.007989 +0.007931 +0.007899 +0.00794 +0.007903 +0.007896 +0.007861 +0.007813 +0.007852 +0.007883 +0.007837 +0.007851 +0.007795 +0.007775 +0.007784 +0.007853 +0.007826 +0.007837 +0.00782 +0.007799 +0.00784 +0.007922 +0.007891 +0.007924 +0.007892 +0.007874 +0.007928 +0.007997 +0.007976 +0.008 +0.007976 +0.000313 +0.007961 +0.007996 +0.008063 +0.008023 +0.008055 +0.008018 +0.008012 +0.008063 +0.008142 +0.008104 +0.008142 +0.008106 +0.008096 +0.008138 +0.008212 +0.008177 +0.008209 +0.008167 +0.008159 +0.008189 +0.008265 +0.008234 +0.008269 +0.008232 +0.008231 +0.008293 +0.008385 +0.00835 +0.008372 +0.008307 +0.008266 +0.008263 +0.008298 +0.008233 +0.008208 +0.008112 +0.008056 +0.008047 +0.008082 +0.008014 +0.008006 +0.007924 +0.007882 +0.007887 +0.007933 +0.007885 +0.007891 +0.007808 +0.007778 +0.00779 +0.007848 +0.007819 +0.007838 +0.007784 +0.007759 +0.007784 +0.007846 +0.007823 +0.007856 +0.007814 +0.007792 +0.00783 +0.007903 +0.007887 +0.007924 +0.007884 +0.007877 +0.007918 +0.007967 +0.007953 +0.000314 +0.007989 +0.007943 +0.007948 +0.007976 +0.008054 +0.008041 +0.00807 +0.00803 +0.008017 +0.008051 +0.008133 +0.008118 +0.008146 +0.008108 +0.008107 +0.008122 +0.008208 +0.008197 +0.008223 +0.008182 +0.008181 +0.00821 +0.008299 +0.008273 +0.008314 +0.008276 +0.008273 +0.008325 +0.008407 +0.00837 +0.008312 +0.008222 +0.008185 +0.008185 +0.008247 +0.008163 +0.008095 +0.008027 +0.007986 +0.007965 +0.008005 +0.007943 +0.00793 +0.007863 +0.007797 +0.007796 +0.007842 +0.007793 +0.007796 +0.007755 +0.007714 +0.007745 +0.007773 +0.007728 +0.007759 +0.00771 +0.007703 +0.007698 +0.007761 +0.007725 +0.007754 +0.007727 +0.007716 +0.007755 +0.007832 +0.007802 +0.00784 +0.007795 +0.00779 +0.007835 +0.007907 +0.007899 +0.007915 +0.000315 +0.007889 +0.007876 +0.007918 +0.007999 +0.007968 +0.008 +0.007964 +0.007956 +0.007962 +0.008025 +0.007996 +0.008036 +0.007993 +0.007988 +0.00802 +0.0081 +0.008079 +0.008112 +0.008099 +0.008095 +0.008129 +0.008217 +0.008186 +0.008225 +0.008178 +0.008168 +0.008188 +0.008249 +0.008225 +0.008235 +0.008154 +0.008108 +0.008089 +0.008122 +0.008064 +0.008044 +0.007964 +0.007917 +0.007906 +0.007941 +0.007893 +0.007889 +0.007815 +0.007786 +0.007786 +0.007832 +0.007798 +0.007797 +0.007739 +0.007722 +0.007737 +0.007796 +0.007773 +0.00779 +0.007754 +0.007736 +0.007759 +0.007835 +0.007813 +0.007842 +0.007808 +0.007799 +0.007828 +0.00791 +0.007883 +0.007928 +0.00787 +0.007872 +0.000316 +0.007904 +0.007982 +0.007964 +0.007986 +0.007959 +0.007947 +0.007986 +0.008055 +0.008046 +0.008063 +0.008034 +0.008016 +0.008055 +0.00813 +0.00812 +0.008149 +0.008112 +0.008091 +0.008137 +0.008211 +0.008203 +0.008218 +0.008191 +0.008186 +0.008229 +0.008314 +0.008297 +0.008328 +0.00831 +0.008256 +0.008217 +0.008251 +0.008203 +0.008206 +0.008148 +0.008082 +0.008109 +0.008142 +0.008028 +0.007983 +0.007927 +0.007879 +0.007888 +0.007928 +0.007868 +0.007867 +0.007796 +0.007739 +0.007761 +0.007797 +0.007765 +0.007764 +0.007718 +0.00771 +0.007707 +0.007761 +0.007727 +0.007742 +0.007711 +0.007684 +0.007711 +0.007763 +0.007727 +0.007772 +0.007725 +0.007715 +0.00777 +0.00783 +0.007805 +0.007838 +0.0078 +0.007793 +0.007846 +0.007927 +0.007888 +0.000317 +0.007911 +0.007891 +0.007857 +0.007889 +0.007949 +0.007935 +0.007955 +0.007938 +0.007918 +0.007968 +0.008033 +0.008023 +0.008036 +0.008016 +0.007991 +0.008036 +0.008101 +0.008094 +0.008124 +0.008116 +0.00809 +0.008136 +0.00819 +0.008199 +0.008194 +0.008187 +0.00816 +0.008214 +0.008266 +0.008246 +0.008241 +0.008184 +0.008118 +0.008126 +0.00814 +0.008083 +0.008065 +0.007989 +0.007917 +0.007929 +0.007953 +0.007906 +0.007895 +0.007847 +0.007782 +0.007807 +0.007837 +0.007807 +0.007804 +0.007759 +0.007712 +0.007746 +0.007787 +0.007765 +0.007775 +0.00775 +0.007703 +0.00775 +0.007801 +0.007789 +0.007811 +0.007784 +0.007755 +0.007807 +0.007868 +0.007857 +0.007877 +0.007866 +0.007827 +0.00788 +0.007939 +0.007927 +0.000318 +0.007954 +0.007929 +0.007909 +0.007952 +0.008022 +0.00801 +0.008029 +0.007997 +0.00798 +0.008033 +0.008089 +0.008085 +0.008111 +0.008075 +0.008055 +0.008101 +0.008177 +0.00816 +0.008188 +0.008161 +0.008139 +0.008193 +0.008268 +0.008251 +0.008284 +0.008256 +0.008243 +0.008291 +0.008341 +0.008255 +0.008242 +0.008188 +0.008132 +0.008117 +0.00814 +0.008077 +0.008074 +0.007992 +0.007929 +0.007918 +0.007951 +0.007913 +0.007903 +0.007869 +0.00782 +0.007804 +0.007821 +0.007781 +0.007799 +0.007757 +0.007724 +0.007755 +0.007805 +0.007782 +0.007785 +0.007767 +0.007705 +0.007725 +0.007786 +0.007752 +0.007787 +0.00775 +0.007745 +0.00778 +0.00785 +0.007833 +0.007852 +0.007832 +0.007816 +0.007855 +0.007928 +0.00792 +0.007932 +0.007902 +0.000319 +0.007895 +0.007941 +0.008015 +0.007991 +0.008017 +0.007983 +0.007975 +0.007996 +0.008059 +0.008026 +0.00806 +0.008024 +0.008012 +0.008049 +0.008124 +0.008095 +0.008126 +0.0081 +0.008119 +0.008154 +0.008241 +0.008224 +0.008243 +0.008201 +0.008188 +0.008199 +0.008257 +0.008207 +0.008203 +0.008139 +0.008091 +0.00806 +0.0081 +0.008046 +0.008024 +0.007951 +0.007906 +0.007897 +0.00794 +0.007898 +0.007892 +0.007827 +0.007794 +0.007801 +0.007857 +0.007816 +0.007818 +0.007769 +0.007741 +0.007755 +0.007821 +0.007794 +0.007811 +0.007763 +0.007749 +0.007773 +0.007847 +0.00783 +0.007856 +0.007819 +0.007813 +0.00784 +0.007917 +0.007896 +0.007931 +0.007908 +0.007871 +0.007906 +0.00032 +0.007996 +0.007978 +0.008004 +0.007966 +0.007958 +0.007988 +0.008067 +0.00805 +0.008088 +0.008041 +0.00803 +0.008066 +0.008143 +0.008125 +0.008156 +0.00812 +0.008108 +0.008143 +0.008228 +0.008203 +0.008245 +0.008201 +0.008205 +0.00824 +0.008324 +0.008308 +0.008339 +0.008306 +0.008284 +0.008224 +0.008271 +0.008213 +0.008227 +0.008166 +0.00812 +0.008124 +0.00817 +0.008048 +0.008022 +0.007955 +0.007918 +0.007938 +0.007983 +0.007938 +0.007895 +0.00785 +0.007814 +0.007839 +0.007896 +0.00784 +0.007864 +0.007801 +0.007768 +0.007793 +0.007846 +0.007818 +0.007841 +0.007813 +0.007792 +0.007841 +0.007907 +0.007885 +0.007917 +0.00788 +0.007876 +0.007905 +0.007993 +0.00797 +0.007969 +0.007936 +0.000321 +0.007936 +0.00796 +0.008038 +0.007996 +0.00805 +0.008008 +0.008 +0.008037 +0.008115 +0.00809 +0.008123 +0.008086 +0.008077 +0.008112 +0.008191 +0.008158 +0.008189 +0.008148 +0.008141 +0.008174 +0.008249 +0.008228 +0.008277 +0.008258 +0.008245 +0.00829 +0.008354 +0.00834 +0.008351 +0.008295 +0.008265 +0.008254 +0.008307 +0.008254 +0.008233 +0.008145 +0.008099 +0.008074 +0.008108 +0.008057 +0.008036 +0.007957 +0.007926 +0.007922 +0.007964 +0.007921 +0.007919 +0.007852 +0.00782 +0.007825 +0.007879 +0.007843 +0.007849 +0.007794 +0.007777 +0.007788 +0.007853 +0.007827 +0.007844 +0.007796 +0.007787 +0.007808 +0.007883 +0.007866 +0.007891 +0.007852 +0.007851 +0.007873 +0.007958 +0.007934 +0.00798 +0.007923 +0.007912 +0.000322 +0.007954 +0.008033 +0.008012 +0.008038 +0.008012 +0.007989 +0.008041 +0.008097 +0.00809 +0.008119 +0.008088 +0.008072 +0.008114 +0.008183 +0.008173 +0.008196 +0.008166 +0.008145 +0.008191 +0.008264 +0.008252 +0.008287 +0.008255 +0.008237 +0.008299 +0.008375 +0.008357 +0.008378 +0.008289 +0.008236 +0.008269 +0.008311 +0.008264 +0.008233 +0.008151 +0.008073 +0.008083 +0.008109 +0.008059 +0.008038 +0.007962 +0.0079 +0.0079 +0.007951 +0.007893 +0.007906 +0.007854 +0.007809 +0.007787 +0.007841 +0.007801 +0.007809 +0.007783 +0.007746 +0.007796 +0.007853 +0.007823 +0.007843 +0.007802 +0.007797 +0.007836 +0.00791 +0.00789 +0.00787 +0.007848 +0.007824 +0.007861 +0.007946 +0.007919 +0.007944 +0.007921 +0.007909 +0.007951 +0.008024 +0.008019 +0.000323 +0.00803 +0.007998 +0.00799 +0.008029 +0.00811 +0.008087 +0.008124 +0.00809 +0.008072 +0.008114 +0.008191 +0.008156 +0.008186 +0.008145 +0.008134 +0.008172 +0.008243 +0.00821 +0.008235 +0.008199 +0.0082 +0.00822 +0.008325 +0.00832 +0.008348 +0.008291 +0.008249 +0.008246 +0.008285 +0.008223 +0.008211 +0.008118 +0.008051 +0.008043 +0.008078 +0.008009 +0.008003 +0.00793 +0.007875 +0.007881 +0.007938 +0.007886 +0.007887 +0.007829 +0.00779 +0.007806 +0.007869 +0.00783 +0.007848 +0.007799 +0.007781 +0.007804 +0.007885 +0.007858 +0.007891 +0.007847 +0.007827 +0.007861 +0.007948 +0.007929 +0.007962 +0.007921 +0.007909 +0.007956 +0.008003 +0.007999 +0.000324 +0.008025 +0.007979 +0.007984 +0.008018 +0.008098 +0.008084 +0.008108 +0.008072 +0.008059 +0.008089 +0.008168 +0.008146 +0.008182 +0.00815 +0.008142 +0.008172 +0.008259 +0.008224 +0.008261 +0.008228 +0.008214 +0.008251 +0.00834 +0.008313 +0.00836 +0.008313 +0.008316 +0.008355 +0.008439 +0.00842 +0.008435 +0.008321 +0.008307 +0.008318 +0.008384 +0.008316 +0.008324 +0.008232 +0.008165 +0.008155 +0.008205 +0.008148 +0.008162 +0.008091 +0.008031 +0.00801 +0.008053 +0.008016 +0.008023 +0.007977 +0.00794 +0.00797 +0.008023 +0.007969 +0.007949 +0.007899 +0.007891 +0.007897 +0.007972 +0.00792 +0.007941 +0.007911 +0.00789 +0.007937 +0.008004 +0.007975 +0.008015 +0.007976 +0.007972 +0.00801 +0.008069 +0.008041 +0.008082 +0.008041 +0.008029 +0.000325 +0.008079 +0.008127 +0.008105 +0.008133 +0.008112 +0.008099 +0.008147 +0.008209 +0.008192 +0.008218 +0.008193 +0.008176 +0.008221 +0.008288 +0.008269 +0.00829 +0.008257 +0.008233 +0.008273 +0.008345 +0.008348 +0.008386 +0.008365 +0.008344 +0.008379 +0.008443 +0.008428 +0.008437 +0.008387 +0.00834 +0.008331 +0.008359 +0.008304 +0.008279 +0.008193 +0.008134 +0.008128 +0.008164 +0.008116 +0.008098 +0.008041 +0.007998 +0.008006 +0.00805 +0.00802 +0.008013 +0.00796 +0.007926 +0.007939 +0.007991 +0.007968 +0.007978 +0.007934 +0.007911 +0.007936 +0.007995 +0.007982 +0.007989 +0.007963 +0.007947 +0.00798 +0.008047 +0.008046 +0.008058 +0.008036 +0.008013 +0.008054 +0.008132 +0.008113 +0.008133 +0.000326 +0.008114 +0.008086 +0.008139 +0.008203 +0.008196 +0.008211 +0.008189 +0.008168 +0.008217 +0.008278 +0.008277 +0.008296 +0.008273 +0.008251 +0.008299 +0.008356 +0.008358 +0.008377 +0.008347 +0.008331 +0.008384 +0.00846 +0.008455 +0.008469 +0.008455 +0.008437 +0.008501 +0.008522 +0.008469 +0.008459 +0.008426 +0.008375 +0.008367 +0.008379 +0.008328 +0.008289 +0.008219 +0.008166 +0.008137 +0.00817 +0.008126 +0.008122 +0.008086 +0.008027 +0.00803 +0.008031 +0.008005 +0.007994 +0.007971 +0.007918 +0.007965 +0.008015 +0.007983 +0.008 +0.007937 +0.007903 +0.007924 +0.007977 +0.007963 +0.007974 +0.007954 +0.00793 +0.007972 +0.008047 +0.008034 +0.008046 +0.008034 +0.00801 +0.008059 +0.00813 +0.008119 +0.008127 +0.008106 +0.000327 +0.008083 +0.008104 +0.008153 +0.008138 +0.008168 +0.008146 +0.008135 +0.008173 +0.008253 +0.008239 +0.008263 +0.008238 +0.008218 +0.008263 +0.008331 +0.008322 +0.008358 +0.008334 +0.008314 +0.008349 +0.008428 +0.008408 +0.008432 +0.008403 +0.008393 +0.008424 +0.008468 +0.00843 +0.008424 +0.008345 +0.00828 +0.008265 +0.008293 +0.008235 +0.008215 +0.008138 +0.008087 +0.008086 +0.008128 +0.008075 +0.008065 +0.008008 +0.007968 +0.007984 +0.008026 +0.007994 +0.007995 +0.007943 +0.007918 +0.007939 +0.008002 +0.007994 +0.007992 +0.007957 +0.007934 +0.007968 +0.008042 +0.008032 +0.008053 +0.008019 +0.008006 +0.008041 +0.008115 +0.008106 +0.008143 +0.008087 +0.008073 +0.000328 +0.00812 +0.008194 +0.008189 +0.008201 +0.00818 +0.008156 +0.008204 +0.008265 +0.008271 +0.008278 +0.008263 +0.008237 +0.008281 +0.008352 +0.008344 +0.008365 +0.008339 +0.008313 +0.008361 +0.008434 +0.008423 +0.008452 +0.008424 +0.00841 +0.008471 +0.008537 +0.008527 +0.008543 +0.008515 +0.008404 +0.00839 +0.008428 +0.008368 +0.008363 +0.00831 +0.008191 +0.008178 +0.008212 +0.008157 +0.008145 +0.008111 +0.008051 +0.008062 +0.008056 +0.008031 +0.008018 +0.008 +0.007942 +0.007988 +0.008003 +0.007974 +0.007978 +0.007951 +0.007927 +0.00795 +0.008003 +0.007969 +0.007988 +0.007968 +0.007939 +0.007993 +0.008047 +0.008046 +0.008051 +0.008045 +0.008016 +0.008067 +0.008133 +0.008112 +0.008117 +0.00811 +0.000329 +0.008084 +0.008129 +0.008203 +0.008171 +0.008196 +0.008174 +0.008164 +0.008211 +0.008284 +0.008253 +0.008277 +0.008244 +0.008239 +0.008282 +0.00835 +0.008323 +0.008339 +0.008305 +0.00828 +0.008329 +0.008403 +0.008387 +0.008418 +0.008403 +0.008404 +0.00844 +0.008501 +0.008475 +0.008462 +0.008393 +0.008349 +0.008338 +0.008352 +0.008298 +0.008273 +0.008194 +0.008141 +0.00815 +0.008167 +0.008123 +0.008112 +0.008054 +0.008009 +0.008017 +0.008066 +0.008034 +0.008029 +0.00797 +0.007946 +0.007964 +0.008019 +0.008 +0.00801 +0.007974 +0.007953 +0.007981 +0.008045 +0.008031 +0.00805 +0.008028 +0.008002 +0.008044 +0.008115 +0.008103 +0.008125 +0.008109 +0.00807 +0.008118 +0.00033 +0.008197 +0.008175 +0.00821 +0.008172 +0.008161 +0.008198 +0.008278 +0.008256 +0.008286 +0.008247 +0.00824 +0.008277 +0.008358 +0.008333 +0.008368 +0.008324 +0.008315 +0.00836 +0.008437 +0.008421 +0.008461 +0.00841 +0.008414 +0.008456 +0.008533 +0.008524 +0.00856 +0.008521 +0.008511 +0.008485 +0.00849 +0.008432 +0.008439 +0.008373 +0.008338 +0.00835 +0.008344 +0.008258 +0.008247 +0.008199 +0.00813 +0.008125 +0.00817 +0.008123 +0.008133 +0.008077 +0.008057 +0.008062 +0.008094 +0.008054 +0.008067 +0.008038 +0.008018 +0.008031 +0.008086 +0.008031 +0.008072 +0.008033 +0.008017 +0.008071 +0.00814 +0.008127 +0.008149 +0.008119 +0.008113 +0.008143 +0.008234 +0.008208 +0.008228 +0.000331 +0.008193 +0.008169 +0.008184 +0.008273 +0.008236 +0.008272 +0.008241 +0.008238 +0.008279 +0.008357 +0.008331 +0.008364 +0.008327 +0.008319 +0.008356 +0.008434 +0.008413 +0.008443 +0.008409 +0.008412 +0.008446 +0.008533 +0.00851 +0.008536 +0.008503 +0.008489 +0.008531 +0.008605 +0.008562 +0.008568 +0.008491 +0.008422 +0.008414 +0.008433 +0.008355 +0.00834 +0.008247 +0.008195 +0.008182 +0.008223 +0.008151 +0.008157 +0.008087 +0.008038 +0.008049 +0.008101 +0.008054 +0.008061 +0.007991 +0.007956 +0.007976 +0.008048 +0.008017 +0.008039 +0.00799 +0.007966 +0.007994 +0.008062 +0.008037 +0.008082 +0.008041 +0.008029 +0.008062 +0.008142 +0.008117 +0.008149 +0.008123 +0.008086 +0.008138 +0.000332 +0.008217 +0.0082 +0.008225 +0.008191 +0.008184 +0.008212 +0.008295 +0.008274 +0.008309 +0.00827 +0.00826 +0.008294 +0.00838 +0.008361 +0.008392 +0.008351 +0.008334 +0.008381 +0.008467 +0.008429 +0.008477 +0.008435 +0.00844 +0.008473 +0.008565 +0.008549 +0.008579 +0.008536 +0.008525 +0.008475 +0.008522 +0.008454 +0.008466 +0.008397 +0.008359 +0.008374 +0.00842 +0.0083 +0.008263 +0.008197 +0.00817 +0.008155 +0.008196 +0.008135 +0.008131 +0.008062 +0.008008 +0.008017 +0.008063 +0.008016 +0.008032 +0.007985 +0.007972 +0.007994 +0.008067 +0.008017 +0.008021 +0.007991 +0.007971 +0.007986 +0.008072 +0.008022 +0.008069 +0.008038 +0.008023 +0.00807 +0.008146 +0.008109 +0.008154 +0.008129 +0.0081 +0.008148 +0.008239 +0.000333 +0.008204 +0.008239 +0.008195 +0.008197 +0.008225 +0.008286 +0.008253 +0.008285 +0.008253 +0.008243 +0.008285 +0.008368 +0.008338 +0.008365 +0.008327 +0.008311 +0.008344 +0.008423 +0.008411 +0.008467 +0.008433 +0.00843 +0.008454 +0.008531 +0.008501 +0.008515 +0.008469 +0.008423 +0.008409 +0.008449 +0.008372 +0.008352 +0.008271 +0.00821 +0.0082 +0.008253 +0.008187 +0.008177 +0.008121 +0.008083 +0.008081 +0.008143 +0.008091 +0.0081 +0.008045 +0.008018 +0.008006 +0.00808 +0.008043 +0.008068 +0.008027 +0.008005 +0.008022 +0.008099 +0.008066 +0.008092 +0.008065 +0.00806 +0.008077 +0.008169 +0.008136 +0.008168 +0.008145 +0.00811 +0.008157 +0.008239 +0.008221 +0.000334 +0.00825 +0.008205 +0.008203 +0.008236 +0.008319 +0.0083 +0.008327 +0.008288 +0.00828 +0.008316 +0.008401 +0.008374 +0.008408 +0.008371 +0.00836 +0.008392 +0.00848 +0.008464 +0.008491 +0.008461 +0.008448 +0.008488 +0.008581 +0.008565 +0.008604 +0.008554 +0.008529 +0.008501 +0.008483 +0.008407 +0.008413 +0.008347 +0.008297 +0.008242 +0.008249 +0.008182 +0.008171 +0.008132 +0.008076 +0.008096 +0.008133 +0.008029 +0.00802 +0.007967 +0.007929 +0.007922 +0.007963 +0.007924 +0.007934 +0.007889 +0.007874 +0.007896 +0.007977 +0.007909 +0.007927 +0.007884 +0.007867 +0.007909 +0.007984 +0.007946 +0.007989 +0.007942 +0.007938 +0.007978 +0.008043 +0.008023 +0.008062 +0.008024 +0.008018 +0.00805 +0.000335 +0.008107 +0.008074 +0.008107 +0.008088 +0.00807 +0.008115 +0.008187 +0.008167 +0.008193 +0.008166 +0.008148 +0.008195 +0.008266 +0.008249 +0.008272 +0.00823 +0.008215 +0.008255 +0.008322 +0.008311 +0.008375 +0.008334 +0.008319 +0.008352 +0.008421 +0.008387 +0.008383 +0.008338 +0.008274 +0.008255 +0.008275 +0.008205 +0.008178 +0.008097 +0.008031 +0.008026 +0.008063 +0.007992 +0.007974 +0.007922 +0.007871 +0.007872 +0.007923 +0.007874 +0.007865 +0.007819 +0.007784 +0.007785 +0.007856 +0.007826 +0.007829 +0.007799 +0.007772 +0.0078 +0.007875 +0.007853 +0.00787 +0.007843 +0.007823 +0.007867 +0.007936 +0.007919 +0.007944 +0.007916 +0.007908 +0.007929 +0.008003 +0.000336 +0.007999 +0.008017 +0.007994 +0.007976 +0.008019 +0.008079 +0.008076 +0.008092 +0.008071 +0.008046 +0.008106 +0.008151 +0.008154 +0.008171 +0.008146 +0.008121 +0.008177 +0.008241 +0.008233 +0.008258 +0.008228 +0.00821 +0.008264 +0.008331 +0.008326 +0.008355 +0.008336 +0.008316 +0.008376 +0.008379 +0.008328 +0.008312 +0.008267 +0.008217 +0.008229 +0.008217 +0.008161 +0.008137 +0.008066 +0.008016 +0.008008 +0.008037 +0.007989 +0.007974 +0.007945 +0.00787 +0.007858 +0.007904 +0.007863 +0.007864 +0.007824 +0.007785 +0.007836 +0.007883 +0.00787 +0.007865 +0.007857 +0.007787 +0.007812 +0.007877 +0.007857 +0.007876 +0.007863 +0.00784 +0.007897 +0.007954 +0.007947 +0.007964 +0.007937 +0.007921 +0.007983 +0.008033 +0.008024 +0.000337 +0.008053 +0.008024 +0.008007 +0.008049 +0.008125 +0.008109 +0.008135 +0.008109 +0.008101 +0.00813 +0.008198 +0.008173 +0.008188 +0.008156 +0.008136 +0.008173 +0.008239 +0.008214 +0.008232 +0.008212 +0.008196 +0.008228 +0.008317 +0.008322 +0.008362 +0.008325 +0.00829 +0.008302 +0.008342 +0.008281 +0.008263 +0.008191 +0.008118 +0.008109 +0.008139 +0.008082 +0.008076 +0.008007 +0.007945 +0.007953 +0.007988 +0.007943 +0.007949 +0.007888 +0.007838 +0.007853 +0.007904 +0.007853 +0.007869 +0.007829 +0.007801 +0.007829 +0.007888 +0.007863 +0.007877 +0.007838 +0.007816 +0.007862 +0.007934 +0.007918 +0.007935 +0.007907 +0.007888 +0.007938 +0.008012 +0.008004 +0.007996 +0.00798 +0.000338 +0.007962 +0.008005 +0.008083 +0.008065 +0.008101 +0.008054 +0.008043 +0.008077 +0.008161 +0.008142 +0.008171 +0.008135 +0.00813 +0.00816 +0.008241 +0.008221 +0.008246 +0.008207 +0.008202 +0.008238 +0.00831 +0.008306 +0.00833 +0.00829 +0.008283 +0.008332 +0.008412 +0.008395 +0.008443 +0.008392 +0.008392 +0.008435 +0.008458 +0.008391 +0.008402 +0.008345 +0.008313 +0.008327 +0.008379 +0.008265 +0.008244 +0.008185 +0.008153 +0.008131 +0.008161 +0.008119 +0.008124 +0.008062 +0.00802 +0.008005 +0.008043 +0.008008 +0.00802 +0.007972 +0.007947 +0.007982 +0.008054 +0.008017 +0.008044 +0.008002 +0.007963 +0.007988 +0.008051 +0.008033 +0.008065 +0.008032 +0.008024 +0.008059 +0.00815 +0.008116 +0.008146 +0.008124 +0.008112 +0.008141 +0.000339 +0.008219 +0.008207 +0.008234 +0.0082 +0.008183 +0.008229 +0.0083 +0.008285 +0.008312 +0.008279 +0.008257 +0.008302 +0.008371 +0.008349 +0.008373 +0.008339 +0.008319 +0.008365 +0.00843 +0.008422 +0.00846 +0.008444 +0.008426 +0.00846 +0.008528 +0.008513 +0.00852 +0.008466 +0.008422 +0.008416 +0.008431 +0.008363 +0.008343 +0.008259 +0.008193 +0.008195 +0.008208 +0.008159 +0.008139 +0.008076 +0.008033 +0.008034 +0.008069 +0.00802 +0.008022 +0.007962 +0.007919 +0.007939 +0.007977 +0.007954 +0.007961 +0.007914 +0.007888 +0.007917 +0.007976 +0.007944 +0.007971 +0.007944 +0.007912 +0.007953 +0.008016 +0.008007 +0.008036 +0.008004 +0.007991 +0.008025 +0.008097 +0.008085 +0.008116 +0.008061 +0.00034 +0.008063 +0.008111 +0.008167 +0.008168 +0.008179 +0.008158 +0.008126 +0.008181 +0.008251 +0.008243 +0.008263 +0.008229 +0.00821 +0.008259 +0.008322 +0.008318 +0.008341 +0.008314 +0.008288 +0.008342 +0.008409 +0.008403 +0.008427 +0.008406 +0.008381 +0.008453 +0.008514 +0.008503 +0.008515 +0.008451 +0.008345 +0.008362 +0.008394 +0.008352 +0.00834 +0.008232 +0.008159 +0.008178 +0.008208 +0.008153 +0.008141 +0.008103 +0.008046 +0.008015 +0.008056 +0.008005 +0.008008 +0.007974 +0.007929 +0.007979 +0.008024 +0.007985 +0.007946 +0.007919 +0.007894 +0.007943 +0.008003 +0.007975 +0.007988 +0.007949 +0.007947 +0.00797 +0.008033 +0.008021 +0.008033 +0.008022 +0.007991 +0.008043 +0.00811 +0.008094 +0.008111 +0.008095 +0.008077 +0.000341 +0.008128 +0.008188 +0.008176 +0.008198 +0.008174 +0.008152 +0.008211 +0.008274 +0.00826 +0.008278 +0.008256 +0.008229 +0.008275 +0.008332 +0.008312 +0.008326 +0.008308 +0.008276 +0.008322 +0.008392 +0.008385 +0.008414 +0.008419 +0.008392 +0.008441 +0.008483 +0.008456 +0.008433 +0.008362 +0.008287 +0.008295 +0.008324 +0.008263 +0.008229 +0.008165 +0.008105 +0.008102 +0.008131 +0.008079 +0.008062 +0.008008 +0.007947 +0.007962 +0.007997 +0.007957 +0.007941 +0.0079 +0.007852 +0.007876 +0.007926 +0.007901 +0.007904 +0.007875 +0.007842 +0.007871 +0.007935 +0.007914 +0.007922 +0.007909 +0.007885 +0.007928 +0.007998 +0.007985 +0.008003 +0.007977 +0.007952 +0.007995 +0.008067 +0.008076 +0.008066 +0.000342 +0.00805 +0.008033 +0.008079 +0.008147 +0.008134 +0.008151 +0.008127 +0.008112 +0.008152 +0.008232 +0.008216 +0.008236 +0.008207 +0.008188 +0.008233 +0.008299 +0.008289 +0.008324 +0.008293 +0.008265 +0.008329 +0.008393 +0.008396 +0.008416 +0.008387 +0.008384 +0.008418 +0.008423 +0.008365 +0.008365 +0.008321 +0.008286 +0.008268 +0.008273 +0.008212 +0.008226 +0.008155 +0.008105 +0.008076 +0.008109 +0.008054 +0.008071 +0.008013 +0.007985 +0.007997 +0.008048 +0.007971 +0.007966 +0.007906 +0.00789 +0.007896 +0.007948 +0.007917 +0.00792 +0.007894 +0.007854 +0.007904 +0.007965 +0.007934 +0.007967 +0.007904 +0.007885 +0.007912 +0.007969 +0.007968 +0.007981 +0.007958 +0.007949 +0.007988 +0.008066 +0.008044 +0.008073 +0.008048 +0.008024 +0.008076 +0.000343 +0.008144 +0.008125 +0.008155 +0.008125 +0.008119 +0.008159 +0.008237 +0.008209 +0.008243 +0.008208 +0.008195 +0.008234 +0.008306 +0.008265 +0.008295 +0.008257 +0.008245 +0.008277 +0.008354 +0.008322 +0.00836 +0.008314 +0.008328 +0.00838 +0.008459 +0.008425 +0.008419 +0.008334 +0.008288 +0.008262 +0.00831 +0.008257 +0.008231 +0.008138 +0.008098 +0.008083 +0.008121 +0.008073 +0.008065 +0.007991 +0.007958 +0.007959 +0.008011 +0.007964 +0.007969 +0.007911 +0.007888 +0.007899 +0.007965 +0.007944 +0.007963 +0.007912 +0.0079 +0.007925 +0.007994 +0.007986 +0.008012 +0.00797 +0.007964 +0.00799 +0.008068 +0.008056 +0.008096 +0.008048 +0.008028 +0.000344 +0.008073 +0.008138 +0.008136 +0.008163 +0.00813 +0.008108 +0.008153 +0.008218 +0.008209 +0.008243 +0.008202 +0.00819 +0.00823 +0.0083 +0.008291 +0.008312 +0.008287 +0.008264 +0.008311 +0.008388 +0.008375 +0.008399 +0.008372 +0.008353 +0.008409 +0.008487 +0.008471 +0.008505 +0.008478 +0.00847 +0.008452 +0.008476 +0.008439 +0.008448 +0.008399 +0.008358 +0.008373 +0.008419 +0.00837 +0.008349 +0.008229 +0.008175 +0.008188 +0.008238 +0.008189 +0.008191 +0.008109 +0.008058 +0.008075 +0.008115 +0.008089 +0.00808 +0.008043 +0.008019 +0.008051 +0.008119 +0.008072 +0.008082 +0.00803 +0.008026 +0.008056 +0.008143 +0.0081 +0.008135 +0.008109 +0.008094 +0.00814 +0.008222 +0.00819 +0.008227 +0.008193 +0.008175 +0.000345 +0.008222 +0.00828 +0.008257 +0.008278 +0.008253 +0.008233 +0.008298 +0.008357 +0.008341 +0.008359 +0.008337 +0.008306 +0.008359 +0.008423 +0.008406 +0.00842 +0.008398 +0.00837 +0.008431 +0.008479 +0.008479 +0.008519 +0.008507 +0.008488 +0.008527 +0.008598 +0.008581 +0.008588 +0.008555 +0.0085 +0.008521 +0.008512 +0.008449 +0.008414 +0.008332 +0.008247 +0.008247 +0.008268 +0.008214 +0.008188 +0.008132 +0.008073 +0.008094 +0.008118 +0.008078 +0.008069 +0.00802 +0.007962 +0.007983 +0.00803 +0.008009 +0.008006 +0.007974 +0.007934 +0.007977 +0.008031 +0.008018 +0.008015 +0.008004 +0.00797 +0.008022 +0.008083 +0.008074 +0.008095 +0.008069 +0.008047 +0.008095 +0.008162 +0.008165 +0.008176 +0.000346 +0.008128 +0.008129 +0.00817 +0.008242 +0.008224 +0.00825 +0.008224 +0.008207 +0.008249 +0.00832 +0.008309 +0.008338 +0.00829 +0.008281 +0.008327 +0.008396 +0.008395 +0.00841 +0.008383 +0.008371 +0.008413 +0.008499 +0.00848 +0.008519 +0.008488 +0.008468 +0.008498 +0.008489 +0.00841 +0.008402 +0.008337 +0.008247 +0.008217 +0.008255 +0.008202 +0.008182 +0.008136 +0.008075 +0.008041 +0.00807 +0.008018 +0.008028 +0.007982 +0.007945 +0.007943 +0.007945 +0.007916 +0.007915 +0.007883 +0.007872 +0.007887 +0.00797 +0.007927 +0.007945 +0.007893 +0.007849 +0.007885 +0.007949 +0.007914 +0.007947 +0.007915 +0.007896 +0.007949 +0.00801 +0.007995 +0.008024 +0.00799 +0.007982 +0.00803 +0.008097 +0.008074 +0.000347 +0.008104 +0.008077 +0.00805 +0.008118 +0.008175 +0.008165 +0.008184 +0.008165 +0.008141 +0.008185 +0.00823 +0.008214 +0.008226 +0.00821 +0.008182 +0.008236 +0.00829 +0.008275 +0.008291 +0.008271 +0.008248 +0.008322 +0.008406 +0.008408 +0.008414 +0.008383 +0.00834 +0.00836 +0.008401 +0.00835 +0.008334 +0.008286 +0.008215 +0.008218 +0.00825 +0.008214 +0.008187 +0.00813 +0.008069 +0.008082 +0.008125 +0.008087 +0.00807 +0.008025 +0.007968 +0.007982 +0.008035 +0.008005 +0.007998 +0.007961 +0.007921 +0.007943 +0.008004 +0.007997 +0.007988 +0.007966 +0.00793 +0.007965 +0.008031 +0.008035 +0.008031 +0.008024 +0.007992 +0.008033 +0.008108 +0.008093 +0.008115 +0.008104 +0.008066 +0.008101 +0.000348 +0.008189 +0.008172 +0.008194 +0.00817 +0.00815 +0.008193 +0.008268 +0.008241 +0.008272 +0.008245 +0.008229 +0.008271 +0.008342 +0.008331 +0.00835 +0.008321 +0.008312 +0.00835 +0.00843 +0.008421 +0.008451 +0.008414 +0.008411 +0.008462 +0.008535 +0.008522 +0.008545 +0.008436 +0.008375 +0.008393 +0.008436 +0.008386 +0.008379 +0.008282 +0.008197 +0.008218 +0.008271 +0.00822 +0.008209 +0.00817 +0.008114 +0.008106 +0.008132 +0.008102 +0.008104 +0.008067 +0.008027 +0.008069 +0.008125 +0.008096 +0.008104 +0.008083 +0.008055 +0.008069 +0.008112 +0.008081 +0.008113 +0.008085 +0.008074 +0.00812 +0.008187 +0.008181 +0.008201 +0.008176 +0.008158 +0.008208 +0.008282 +0.008261 +0.008287 +0.000349 +0.008264 +0.008241 +0.008304 +0.00837 +0.008354 +0.008371 +0.008355 +0.008329 +0.008359 +0.008411 +0.008392 +0.008413 +0.008394 +0.008372 +0.008423 +0.008482 +0.008469 +0.008485 +0.008458 +0.008437 +0.00851 +0.008592 +0.008594 +0.0086 +0.00856 +0.008526 +0.008539 +0.008581 +0.008536 +0.008502 +0.008423 +0.008358 +0.008361 +0.008383 +0.008343 +0.008323 +0.008266 +0.008216 +0.008219 +0.008264 +0.00824 +0.008224 +0.00817 +0.008121 +0.008143 +0.008194 +0.008171 +0.008159 +0.008121 +0.008088 +0.008125 +0.008181 +0.008168 +0.008172 +0.008139 +0.008111 +0.008155 +0.008222 +0.008222 +0.008233 +0.008213 +0.008184 +0.008228 +0.008303 +0.008279 +0.008327 +0.008276 +0.00035 +0.008261 +0.008311 +0.00837 +0.008374 +0.008389 +0.008367 +0.008339 +0.008387 +0.008456 +0.008454 +0.008474 +0.008449 +0.008424 +0.008476 +0.008542 +0.008534 +0.008549 +0.008531 +0.008499 +0.008551 +0.008622 +0.008619 +0.008646 +0.008623 +0.008598 +0.008674 +0.008732 +0.008723 +0.008732 +0.008642 +0.008533 +0.00854 +0.008561 +0.008508 +0.008484 +0.008362 +0.008303 +0.008316 +0.008317 +0.008289 +0.008269 +0.008235 +0.008175 +0.008167 +0.00818 +0.008139 +0.008138 +0.008101 +0.008058 +0.008101 +0.008146 +0.008137 +0.008124 +0.008109 +0.008069 +0.008062 +0.008113 +0.008084 +0.008097 +0.008085 +0.008048 +0.008111 +0.008172 +0.008158 +0.008183 +0.00816 +0.00813 +0.008193 +0.008257 +0.00825 +0.008262 +0.008247 +0.008226 +0.000351 +0.008267 +0.008355 +0.008333 +0.008357 +0.008323 +0.008309 +0.008361 +0.008426 +0.008395 +0.00843 +0.00838 +0.008371 +0.008394 +0.008466 +0.008432 +0.008457 +0.00843 +0.008418 +0.008461 +0.008542 +0.008563 +0.008597 +0.008564 +0.008531 +0.008566 +0.008623 +0.008566 +0.008551 +0.008475 +0.008406 +0.0084 +0.008422 +0.008347 +0.008337 +0.008267 +0.008207 +0.008213 +0.00824 +0.008198 +0.008208 +0.00814 +0.008091 +0.008108 +0.008157 +0.008112 +0.008114 +0.008073 +0.008026 +0.008055 +0.008113 +0.008083 +0.008094 +0.008054 +0.008023 +0.008056 +0.008121 +0.008101 +0.008129 +0.008101 +0.008075 +0.008123 +0.008188 +0.008173 +0.008196 +0.008175 +0.008137 +0.008191 +0.008276 +0.000352 +0.008254 +0.008282 +0.008245 +0.008234 +0.008269 +0.008339 +0.00832 +0.008365 +0.008327 +0.008318 +0.008352 +0.008434 +0.008412 +0.008443 +0.008407 +0.008403 +0.008424 +0.008517 +0.00849 +0.008535 +0.00849 +0.0085 +0.008539 +0.008625 +0.008599 +0.008625 +0.008514 +0.008478 +0.008497 +0.008558 +0.008501 +0.008494 +0.008386 +0.008327 +0.008322 +0.008382 +0.008338 +0.008328 +0.008275 +0.008247 +0.008212 +0.008257 +0.008206 +0.008221 +0.008183 +0.008149 +0.008183 +0.008242 +0.008211 +0.008227 +0.008188 +0.008183 +0.008178 +0.008237 +0.008183 +0.008227 +0.008183 +0.008186 +0.008223 +0.008309 +0.008282 +0.008304 +0.008276 +0.008267 +0.008301 +0.008393 +0.008379 +0.008383 +0.000353 +0.008368 +0.008358 +0.008398 +0.008477 +0.008445 +0.008487 +0.008452 +0.008442 +0.008449 +0.008518 +0.008483 +0.008519 +0.008494 +0.008474 +0.008515 +0.008594 +0.008571 +0.008602 +0.008581 +0.008592 +0.008622 +0.008711 +0.008681 +0.008718 +0.008671 +0.008646 +0.008662 +0.008705 +0.008633 +0.008621 +0.008523 +0.008452 +0.008436 +0.008469 +0.008391 +0.008384 +0.008295 +0.008236 +0.008234 +0.008272 +0.008221 +0.008219 +0.008144 +0.008103 +0.008111 +0.008158 +0.008112 +0.008129 +0.008074 +0.008046 +0.008066 +0.008138 +0.008104 +0.008131 +0.008081 +0.008055 +0.008092 +0.008171 +0.008147 +0.00818 +0.008139 +0.008121 +0.008162 +0.008245 +0.008215 +0.008263 +0.00821 +0.008198 +0.000354 +0.008241 +0.00832 +0.008302 +0.00833 +0.0083 +0.008283 +0.008315 +0.00839 +0.008382 +0.008413 +0.008384 +0.008364 +0.008406 +0.008482 +0.008468 +0.008494 +0.008454 +0.008434 +0.008487 +0.008552 +0.008543 +0.008581 +0.008544 +0.008539 +0.008583 +0.008661 +0.008661 +0.008675 +0.008651 +0.008597 +0.008544 +0.00858 +0.008525 +0.008523 +0.008473 +0.008417 +0.008426 +0.008422 +0.008359 +0.00833 +0.00829 +0.008248 +0.008233 +0.00825 +0.008222 +0.008214 +0.008178 +0.008131 +0.008145 +0.008171 +0.008147 +0.008147 +0.008121 +0.008087 +0.008131 +0.008193 +0.008166 +0.008187 +0.008118 +0.008107 +0.008135 +0.008193 +0.008184 +0.008209 +0.008179 +0.008163 +0.008206 +0.008289 +0.008263 +0.008287 +0.008275 +0.008247 +0.008293 +0.000355 +0.008379 +0.008348 +0.008384 +0.008337 +0.008336 +0.008383 +0.008465 +0.008431 +0.008462 +0.008403 +0.008396 +0.008434 +0.008505 +0.008468 +0.008513 +0.008457 +0.008458 +0.008481 +0.008576 +0.008551 +0.008603 +0.008593 +0.00858 +0.008613 +0.008687 +0.00864 +0.008635 +0.008556 +0.008489 +0.008483 +0.008526 +0.008447 +0.008426 +0.008342 +0.008295 +0.00828 +0.00832 +0.008258 +0.008258 +0.008192 +0.008147 +0.00815 +0.008203 +0.00815 +0.008158 +0.008099 +0.00807 +0.008086 +0.008159 +0.008121 +0.008145 +0.008096 +0.008075 +0.008103 +0.008182 +0.008151 +0.008185 +0.008149 +0.008135 +0.008175 +0.008249 +0.008228 +0.008264 +0.008232 +0.008205 +0.008237 +0.000356 +0.008335 +0.008305 +0.008346 +0.0083 +0.008289 +0.008329 +0.008418 +0.008381 +0.008424 +0.008381 +0.008379 +0.008406 +0.008494 +0.008473 +0.008504 +0.008464 +0.008449 +0.008491 +0.008568 +0.008551 +0.008593 +0.008545 +0.008548 +0.008589 +0.008672 +0.008656 +0.008697 +0.008667 +0.008649 +0.008651 +0.008632 +0.008571 +0.008579 +0.008507 +0.008474 +0.008464 +0.008462 +0.008392 +0.008388 +0.008325 +0.008295 +0.008289 +0.008315 +0.008254 +0.008259 +0.008217 +0.00816 +0.008152 +0.008197 +0.00817 +0.008173 +0.008141 +0.008123 +0.008153 +0.008229 +0.008185 +0.00822 +0.008169 +0.00816 +0.008205 +0.008278 +0.008248 +0.008224 +0.008188 +0.008186 +0.008217 +0.008313 +0.008282 +0.008312 +0.008288 +0.00828 +0.00831 +0.0084 +0.008377 +0.000357 +0.008402 +0.008372 +0.008357 +0.008413 +0.00849 +0.008468 +0.008494 +0.008462 +0.008447 +0.008495 +0.00856 +0.008521 +0.008542 +0.008515 +0.008497 +0.008531 +0.008601 +0.008583 +0.008604 +0.008581 +0.008588 +0.008644 +0.008721 +0.008681 +0.008656 +0.008591 +0.008515 +0.008497 +0.008553 +0.008496 +0.008466 +0.008396 +0.008325 +0.008329 +0.008371 +0.008312 +0.008299 +0.008249 +0.008198 +0.008204 +0.008256 +0.008219 +0.008214 +0.008173 +0.008137 +0.008158 +0.00823 +0.008206 +0.008207 +0.008179 +0.008145 +0.008185 +0.008258 +0.008238 +0.008256 +0.008231 +0.008212 +0.008247 +0.008333 +0.008317 +0.008343 +0.008314 +0.008281 +0.008322 +0.000358 +0.008418 +0.008395 +0.008421 +0.00839 +0.008372 +0.00841 +0.008503 +0.00847 +0.008507 +0.008469 +0.008457 +0.008495 +0.008583 +0.008552 +0.00859 +0.00855 +0.008544 +0.008583 +0.008666 +0.008649 +0.008679 +0.008649 +0.008642 +0.008691 +0.008783 +0.00876 +0.008792 +0.00871 +0.008621 +0.008628 +0.008683 +0.008622 +0.008623 +0.008519 +0.008443 +0.008437 +0.008471 +0.008413 +0.008423 +0.008362 +0.008327 +0.00833 +0.008329 +0.008282 +0.008284 +0.008247 +0.008213 +0.008252 +0.008307 +0.008259 +0.008244 +0.008194 +0.008192 +0.008214 +0.008296 +0.008249 +0.008269 +0.008243 +0.008228 +0.00826 +0.008336 +0.008288 +0.008329 +0.008294 +0.008275 +0.008332 +0.008406 +0.008378 +0.008423 +0.008392 +0.000359 +0.008359 +0.00842 +0.008495 +0.008438 +0.008482 +0.00846 +0.008451 +0.008488 +0.008572 +0.008532 +0.008571 +0.008529 +0.008524 +0.008556 +0.008643 +0.008591 +0.008629 +0.008591 +0.00858 +0.008611 +0.008682 +0.008669 +0.008715 +0.008702 +0.008702 +0.008737 +0.008797 +0.008755 +0.008751 +0.008654 +0.008592 +0.008579 +0.008594 +0.008517 +0.008494 +0.008396 +0.008333 +0.008319 +0.008346 +0.008274 +0.008271 +0.008187 +0.008139 +0.008135 +0.008183 +0.00813 +0.008137 +0.008053 +0.00804 +0.00806 +0.008123 +0.008092 +0.00811 +0.008058 +0.008034 +0.008067 +0.008145 +0.008123 +0.008155 +0.008095 +0.008096 +0.00813 +0.008213 +0.008199 +0.008226 +0.008201 +0.008155 +0.008203 +0.008286 +0.00036 +0.008274 +0.008299 +0.00827 +0.008253 +0.008284 +0.008369 +0.008349 +0.008384 +0.008348 +0.008336 +0.00837 +0.008453 +0.008429 +0.008464 +0.008422 +0.00841 +0.00845 +0.008533 +0.008516 +0.008546 +0.008515 +0.008502 +0.008553 +0.008638 +0.008616 +0.008657 +0.008631 +0.00862 +0.008618 +0.008627 +0.008571 +0.00859 +0.008513 +0.008476 +0.008484 +0.00854 +0.008418 +0.008392 +0.008311 +0.008282 +0.008277 +0.008298 +0.008251 +0.008253 +0.008181 +0.00813 +0.008135 +0.008174 +0.008143 +0.008139 +0.008109 +0.008081 +0.008114 +0.008191 +0.008136 +0.008159 +0.00809 +0.008069 +0.008122 +0.008189 +0.008156 +0.008185 +0.008135 +0.008121 +0.008153 +0.008214 +0.008192 +0.008233 +0.008195 +0.008188 +0.008239 +0.008318 +0.008294 +0.008315 +0.000361 +0.008289 +0.008275 +0.008318 +0.008401 +0.00838 +0.008414 +0.008377 +0.008362 +0.008402 +0.008487 +0.008452 +0.00848 +0.008439 +0.008428 +0.008453 +0.00853 +0.008499 +0.00853 +0.008488 +0.008477 +0.008515 +0.008625 +0.008622 +0.008649 +0.008582 +0.008539 +0.008516 +0.008551 +0.008488 +0.008487 +0.00839 +0.00833 +0.00831 +0.008357 +0.008288 +0.008287 +0.008205 +0.008159 +0.008166 +0.008216 +0.008169 +0.008166 +0.008104 +0.008069 +0.00808 +0.008141 +0.00811 +0.008132 +0.008082 +0.008058 +0.008087 +0.00815 +0.008125 +0.00816 +0.008117 +0.008101 +0.008136 +0.008211 +0.008195 +0.008233 +0.00819 +0.008187 +0.008226 +0.008282 +0.00826 +0.000362 +0.008312 +0.00827 +0.00826 +0.008299 +0.008377 +0.008357 +0.008377 +0.008341 +0.008331 +0.008374 +0.008463 +0.008434 +0.008469 +0.008427 +0.008417 +0.008453 +0.008538 +0.00852 +0.008555 +0.008522 +0.008503 +0.008556 +0.00864 +0.008618 +0.008662 +0.008631 +0.008606 +0.008576 +0.008584 +0.00852 +0.00853 +0.008481 +0.008432 +0.008449 +0.008491 +0.008354 +0.008355 +0.008298 +0.008268 +0.008275 +0.008304 +0.008263 +0.008251 +0.008189 +0.008147 +0.008171 +0.008213 +0.008181 +0.008193 +0.008142 +0.008139 +0.008139 +0.008207 +0.008167 +0.008189 +0.008149 +0.008139 +0.008169 +0.008257 +0.008212 +0.008244 +0.008221 +0.008197 +0.008206 +0.00828 +0.008236 +0.008285 +0.008242 +0.008242 +0.008292 +0.008366 +0.008349 +0.008385 +0.008342 +0.000363 +0.008336 +0.008387 +0.008445 +0.008438 +0.008471 +0.008435 +0.008428 +0.008461 +0.008546 +0.008515 +0.008549 +0.008501 +0.008493 +0.008524 +0.008605 +0.008585 +0.008613 +0.008596 +0.008588 +0.008626 +0.008702 +0.008662 +0.008681 +0.008597 +0.008556 +0.00854 +0.008567 +0.008497 +0.008482 +0.008392 +0.008337 +0.008328 +0.008365 +0.00831 +0.008302 +0.00823 +0.008192 +0.008195 +0.008243 +0.008196 +0.008205 +0.008141 +0.008112 +0.008131 +0.008198 +0.008165 +0.008198 +0.008136 +0.00812 +0.008148 +0.00822 +0.008193 +0.008226 +0.008181 +0.008167 +0.008201 +0.008279 +0.008266 +0.008293 +0.008253 +0.008248 +0.008295 +0.008354 +0.008333 +0.000364 +0.008377 +0.00834 +0.008325 +0.008364 +0.008448 +0.00842 +0.008452 +0.008412 +0.008405 +0.008448 +0.00853 +0.008507 +0.008543 +0.008499 +0.008488 +0.008524 +0.008609 +0.008581 +0.008621 +0.008579 +0.008579 +0.008616 +0.008715 +0.008684 +0.008722 +0.008696 +0.00869 +0.008713 +0.0087 +0.00863 +0.008646 +0.008561 +0.008526 +0.008532 +0.008513 +0.008432 +0.008442 +0.008365 +0.008302 +0.008281 +0.00832 +0.008254 +0.008267 +0.008201 +0.008179 +0.008143 +0.008183 +0.008121 +0.008146 +0.008095 +0.008071 +0.008111 +0.008174 +0.008141 +0.008158 +0.008123 +0.008111 +0.008118 +0.008172 +0.008141 +0.008164 +0.008133 +0.008128 +0.008163 +0.008245 +0.008217 +0.008248 +0.008219 +0.008216 +0.008242 +0.008337 +0.008309 +0.00833 +0.000365 +0.008303 +0.008296 +0.008337 +0.008413 +0.00839 +0.008425 +0.00839 +0.00838 +0.008419 +0.008499 +0.008461 +0.008489 +0.008446 +0.008427 +0.008466 +0.008543 +0.008506 +0.008536 +0.008502 +0.008494 +0.008538 +0.008648 +0.008627 +0.008635 +0.008561 +0.008494 +0.008481 +0.008511 +0.008452 +0.008449 +0.008366 +0.008295 +0.008285 +0.008336 +0.008275 +0.008278 +0.008203 +0.008161 +0.008156 +0.008217 +0.008163 +0.008168 +0.008108 +0.00807 +0.00809 +0.008153 +0.008118 +0.00814 +0.008091 +0.008074 +0.008082 +0.008169 +0.008139 +0.008168 +0.008127 +0.008111 +0.008145 +0.00823 +0.008208 +0.008242 +0.008198 +0.00819 +0.008224 +0.008321 +0.008276 +0.000366 +0.00832 +0.008284 +0.008261 +0.008311 +0.008389 +0.008368 +0.008395 +0.008369 +0.008346 +0.00839 +0.008463 +0.008452 +0.008481 +0.008445 +0.008425 +0.008475 +0.008547 +0.008528 +0.00856 +0.008532 +0.008521 +0.008578 +0.008646 +0.008642 +0.008672 +0.008646 +0.008613 +0.008616 +0.008597 +0.008528 +0.008533 +0.008473 +0.008436 +0.00842 +0.008403 +0.008348 +0.008347 +0.008299 +0.008248 +0.00828 +0.008333 +0.008228 +0.008219 +0.008166 +0.008138 +0.008132 +0.008187 +0.008128 +0.008161 +0.008107 +0.008088 +0.008133 +0.00819 +0.008156 +0.00817 +0.008131 +0.008097 +0.008111 +0.008189 +0.008151 +0.008184 +0.008158 +0.008138 +0.008195 +0.008264 +0.008246 +0.00828 +0.008241 +0.008231 +0.008284 +0.008356 +0.008328 +0.000367 +0.008365 +0.008331 +0.008322 +0.008365 +0.008449 +0.008418 +0.008451 +0.008416 +0.008405 +0.008417 +0.008489 +0.008449 +0.008483 +0.008445 +0.008429 +0.008467 +0.008552 +0.008546 +0.008614 +0.008569 +0.008561 +0.008592 +0.008665 +0.008622 +0.008629 +0.008547 +0.008498 +0.008492 +0.008528 +0.008449 +0.008434 +0.008351 +0.008293 +0.008284 +0.008318 +0.008258 +0.008263 +0.008189 +0.008143 +0.008144 +0.008194 +0.00814 +0.008155 +0.008078 +0.008056 +0.008074 +0.008132 +0.008091 +0.008113 +0.008065 +0.00805 +0.008079 +0.008143 +0.00811 +0.008144 +0.008106 +0.008099 +0.008138 +0.008215 +0.008194 +0.008225 +0.008191 +0.00815 +0.008191 +0.008277 +0.000368 +0.008248 +0.008284 +0.008259 +0.008248 +0.008289 +0.008369 +0.008343 +0.008371 +0.008332 +0.008319 +0.008353 +0.008435 +0.008415 +0.008453 +0.008419 +0.00841 +0.008439 +0.008534 +0.00851 +0.008543 +0.008511 +0.008494 +0.008552 +0.008631 +0.00861 +0.008661 +0.008615 +0.008562 +0.008552 +0.008626 +0.00858 +0.008592 +0.008523 +0.008487 +0.008492 +0.008551 +0.008469 +0.008363 +0.008313 +0.008276 +0.008272 +0.008342 +0.008282 +0.008302 +0.008233 +0.008134 +0.008136 +0.008201 +0.008155 +0.008167 +0.008108 +0.008093 +0.008109 +0.008198 +0.008146 +0.008161 +0.008096 +0.008063 +0.008105 +0.00818 +0.00814 +0.008175 +0.00813 +0.008132 +0.008173 +0.008239 +0.008219 +0.008244 +0.008213 +0.008201 +0.008208 +0.008288 +0.008263 +0.008295 +0.000369 +0.008264 +0.008253 +0.008299 +0.008377 +0.008355 +0.008395 +0.008352 +0.008351 +0.008389 +0.008473 +0.00845 +0.008477 +0.008438 +0.008425 +0.008459 +0.008538 +0.00851 +0.008538 +0.008506 +0.008513 +0.008556 +0.008652 +0.008621 +0.008643 +0.008581 +0.008554 +0.008561 +0.008628 +0.008564 +0.00854 +0.008455 +0.008395 +0.008381 +0.008421 +0.008356 +0.008346 +0.008272 +0.008217 +0.008218 +0.008272 +0.008212 +0.008214 +0.008153 +0.008112 +0.008117 +0.008181 +0.008138 +0.008153 +0.008104 +0.008079 +0.0081 +0.008183 +0.008138 +0.008161 +0.008123 +0.008099 +0.008137 +0.008216 +0.008192 +0.008223 +0.008188 +0.00817 +0.008213 +0.008291 +0.008287 +0.008287 +0.008269 +0.00037 +0.008248 +0.008292 +0.008377 +0.00834 +0.008387 +0.008346 +0.008336 +0.008368 +0.008458 +0.008422 +0.008465 +0.008431 +0.008419 +0.008452 +0.008535 +0.00852 +0.008555 +0.008512 +0.008511 +0.008545 +0.008639 +0.008608 +0.008653 +0.008623 +0.008621 +0.008647 +0.008684 +0.008639 +0.008662 +0.008606 +0.008568 +0.008585 +0.008635 +0.008523 +0.008494 +0.008423 +0.008377 +0.008354 +0.008394 +0.008338 +0.008335 +0.00828 +0.008257 +0.008243 +0.008271 +0.008207 +0.008228 +0.008174 +0.00815 +0.008169 +0.008247 +0.008199 +0.008201 +0.008134 +0.008118 +0.008155 +0.008224 +0.008191 +0.008218 +0.008174 +0.008175 +0.0082 +0.008287 +0.008256 +0.008272 +0.008242 +0.008224 +0.008247 +0.008336 +0.008301 +0.008334 +0.00831 +0.008301 +0.000371 +0.008341 +0.008416 +0.0084 +0.008431 +0.008394 +0.008382 +0.008426 +0.008512 +0.008484 +0.008519 +0.008475 +0.008464 +0.008496 +0.008578 +0.008539 +0.008568 +0.008526 +0.008521 +0.008554 +0.008637 +0.008642 +0.008693 +0.00864 +0.008616 +0.008618 +0.008657 +0.008585 +0.008568 +0.008482 +0.008435 +0.008409 +0.008435 +0.008371 +0.008365 +0.008278 +0.00823 +0.008227 +0.008269 +0.00821 +0.008224 +0.008141 +0.008111 +0.008112 +0.008166 +0.008125 +0.008141 +0.008088 +0.008066 +0.008085 +0.00815 +0.008123 +0.008155 +0.008098 +0.008089 +0.008122 +0.008196 +0.008177 +0.00821 +0.008174 +0.008163 +0.008199 +0.008279 +0.008275 +0.008269 +0.008243 +0.000372 +0.008232 +0.008262 +0.008357 +0.008338 +0.008368 +0.008327 +0.008314 +0.008349 +0.008437 +0.008413 +0.00845 +0.008412 +0.008393 +0.008435 +0.008517 +0.008499 +0.008533 +0.008488 +0.008489 +0.008526 +0.008611 +0.008592 +0.008633 +0.008591 +0.008593 +0.008651 +0.008728 +0.00862 +0.008634 +0.008574 +0.008543 +0.008523 +0.008565 +0.008501 +0.00851 +0.008439 +0.008354 +0.008336 +0.008397 +0.008333 +0.008346 +0.00829 +0.00825 +0.008258 +0.008271 +0.00822 +0.008238 +0.008183 +0.00816 +0.00819 +0.008221 +0.008191 +0.008197 +0.008172 +0.008156 +0.008175 +0.008258 +0.008212 +0.008243 +0.008208 +0.008188 +0.008225 +0.008291 +0.008259 +0.008295 +0.008262 +0.008256 +0.0083 +0.008377 +0.00835 +0.008394 +0.008353 +0.000373 +0.008342 +0.008383 +0.008466 +0.008446 +0.008471 +0.008449 +0.008436 +0.008471 +0.008552 +0.00853 +0.008555 +0.008524 +0.008502 +0.008544 +0.008619 +0.008586 +0.008607 +0.008571 +0.008559 +0.00859 +0.008663 +0.008654 +0.008691 +0.008684 +0.008664 +0.00868 +0.008714 +0.008652 +0.008609 +0.008517 +0.008453 +0.008459 +0.008493 +0.008435 +0.0084 +0.008324 +0.008281 +0.008275 +0.008318 +0.008277 +0.008266 +0.008195 +0.008164 +0.008163 +0.008212 +0.00819 +0.008186 +0.008136 +0.008109 +0.008133 +0.008197 +0.008183 +0.008197 +0.008155 +0.008134 +0.008166 +0.008246 +0.008239 +0.008262 +0.008229 +0.008209 +0.008251 +0.008318 +0.008325 +0.00831 +0.008295 +0.000374 +0.008286 +0.008331 +0.0084 +0.008385 +0.008421 +0.008384 +0.008373 +0.008402 +0.008487 +0.008463 +0.008495 +0.008458 +0.008452 +0.008481 +0.008567 +0.008549 +0.008592 +0.008545 +0.008535 +0.008585 +0.008672 +0.00864 +0.008687 +0.008652 +0.008654 +0.0087 +0.008774 +0.008668 +0.008681 +0.008628 +0.00859 +0.00858 +0.008605 +0.008541 +0.008552 +0.00848 +0.008413 +0.008397 +0.00843 +0.008387 +0.008389 +0.008333 +0.008318 +0.008325 +0.008353 +0.008285 +0.008301 +0.008249 +0.008229 +0.008215 +0.008281 +0.008223 +0.008263 +0.008205 +0.0082 +0.00823 +0.008304 +0.008276 +0.008295 +0.008263 +0.008249 +0.008299 +0.008372 +0.008325 +0.00836 +0.008313 +0.008301 +0.008355 +0.008413 +0.008381 +0.000375 +0.008423 +0.008392 +0.008378 +0.00842 +0.00851 +0.008472 +0.008512 +0.008478 +0.008468 +0.008509 +0.00859 +0.00856 +0.008586 +0.008546 +0.008527 +0.008564 +0.008658 +0.008613 +0.008651 +0.008613 +0.008624 +0.008679 +0.008771 +0.008745 +0.008752 +0.008691 +0.008644 +0.008628 +0.008654 +0.008599 +0.008579 +0.008476 +0.008418 +0.008399 +0.008445 +0.008374 +0.008357 +0.008287 +0.008239 +0.008234 +0.008282 +0.008231 +0.008233 +0.008171 +0.008137 +0.008141 +0.008204 +0.008166 +0.008188 +0.008143 +0.008123 +0.008143 +0.008213 +0.008194 +0.008214 +0.00818 +0.008174 +0.008195 +0.008282 +0.008259 +0.0083 +0.008265 +0.008238 +0.008287 +0.008357 +0.00834 +0.000376 +0.008366 +0.008334 +0.008332 +0.008363 +0.008444 +0.008426 +0.008461 +0.008418 +0.0084 +0.008435 +0.008516 +0.008496 +0.008536 +0.008497 +0.008493 +0.008536 +0.008611 +0.008596 +0.00863 +0.00859 +0.008584 +0.008626 +0.008725 +0.008696 +0.008746 +0.008679 +0.008608 +0.008626 +0.008688 +0.008631 +0.008628 +0.008566 +0.008515 +0.008474 +0.008475 +0.008405 +0.008403 +0.008358 +0.008316 +0.008326 +0.008389 +0.008311 +0.008267 +0.008204 +0.008182 +0.008192 +0.008266 +0.008196 +0.008229 +0.008172 +0.008145 +0.008138 +0.008178 +0.008148 +0.00817 +0.008129 +0.008128 +0.008153 +0.008239 +0.008205 +0.008231 +0.008204 +0.008192 +0.00823 +0.008314 +0.008277 +0.00833 +0.008288 +0.008276 +0.008338 +0.000377 +0.008392 +0.008354 +0.008386 +0.008337 +0.008325 +0.008373 +0.008441 +0.00841 +0.008441 +0.008411 +0.008399 +0.008446 +0.008524 +0.008497 +0.008519 +0.008491 +0.008472 +0.008513 +0.008586 +0.00858 +0.008633 +0.008602 +0.008584 +0.008618 +0.008694 +0.008663 +0.008663 +0.008613 +0.008555 +0.00854 +0.008571 +0.008501 +0.00848 +0.008408 +0.008342 +0.008344 +0.008386 +0.008331 +0.008315 +0.008271 +0.008208 +0.008225 +0.008267 +0.008228 +0.008226 +0.008184 +0.008139 +0.008158 +0.008218 +0.008189 +0.008208 +0.008173 +0.008142 +0.008168 +0.008237 +0.008214 +0.008239 +0.008216 +0.008197 +0.008231 +0.008313 +0.00829 +0.008317 +0.0083 +0.008251 +0.008294 +0.008375 +0.000378 +0.00836 +0.008404 +0.008365 +0.008357 +0.00839 +0.008468 +0.008445 +0.008481 +0.008434 +0.008432 +0.008456 +0.008549 +0.00853 +0.008566 +0.008524 +0.008513 +0.008549 +0.008633 +0.008618 +0.008643 +0.008619 +0.008606 +0.008654 +0.008743 +0.008724 +0.008767 +0.008731 +0.008647 +0.008636 +0.008692 +0.008638 +0.008651 +0.008577 +0.008535 +0.008527 +0.008508 +0.008427 +0.008432 +0.008382 +0.00834 +0.0083 +0.008334 +0.008264 +0.008284 +0.008225 +0.008198 +0.008176 +0.008209 +0.008154 +0.008182 +0.008125 +0.008117 +0.008128 +0.0082 +0.008145 +0.008164 +0.008122 +0.008092 +0.008117 +0.008179 +0.008153 +0.008184 +0.008151 +0.008148 +0.008175 +0.008265 +0.008238 +0.008265 +0.008248 +0.008233 +0.008281 +0.008349 +0.008326 +0.000379 +0.008362 +0.008324 +0.00832 +0.00836 +0.008445 +0.008415 +0.00845 +0.00841 +0.008402 +0.008406 +0.008476 +0.008438 +0.008475 +0.008439 +0.008429 +0.008466 +0.008554 +0.008565 +0.008608 +0.008575 +0.008561 +0.00859 +0.008676 +0.008635 +0.008651 +0.008572 +0.00854 +0.008512 +0.00856 +0.0085 +0.008472 +0.008386 +0.008337 +0.008323 +0.008366 +0.008313 +0.008303 +0.008222 +0.008188 +0.008196 +0.008239 +0.008198 +0.0082 +0.008137 +0.008111 +0.008118 +0.008178 +0.008155 +0.00818 +0.008126 +0.008114 +0.008132 +0.008197 +0.008178 +0.008202 +0.008167 +0.008167 +0.008197 +0.008274 +0.008259 +0.008283 +0.008265 +0.00822 +0.008261 +0.00038 +0.008343 +0.008324 +0.008365 +0.008337 +0.008322 +0.008352 +0.008439 +0.008408 +0.008441 +0.0084 +0.008384 +0.008422 +0.008507 +0.008494 +0.008524 +0.008489 +0.008476 +0.008513 +0.008601 +0.008574 +0.008611 +0.008585 +0.008571 +0.008631 +0.008712 +0.00869 +0.008721 +0.00867 +0.008585 +0.008591 +0.008646 +0.0086 +0.008606 +0.00854 +0.008475 +0.008407 +0.00845 +0.008389 +0.008409 +0.008345 +0.008296 +0.00832 +0.008339 +0.008253 +0.008274 +0.008194 +0.008161 +0.008147 +0.008204 +0.008154 +0.008178 +0.008123 +0.008114 +0.008135 +0.008217 +0.008174 +0.0082 +0.008166 +0.00812 +0.008135 +0.0082 +0.008175 +0.008214 +0.008176 +0.008173 +0.008212 +0.008284 +0.008276 +0.008304 +0.008265 +0.008261 +0.008312 +0.008374 +0.000381 +0.008358 +0.008396 +0.008357 +0.00835 +0.008389 +0.008476 +0.008452 +0.008488 +0.008442 +0.008436 +0.008471 +0.008547 +0.00851 +0.008534 +0.008502 +0.008489 +0.008514 +0.00859 +0.00857 +0.008601 +0.008591 +0.008588 +0.008627 +0.008694 +0.008641 +0.008649 +0.008574 +0.008513 +0.008501 +0.008531 +0.008448 +0.008447 +0.008347 +0.008284 +0.008272 +0.008312 +0.008245 +0.00824 +0.008169 +0.008118 +0.008115 +0.00817 +0.00812 +0.008123 +0.008061 +0.008029 +0.00806 +0.008126 +0.008087 +0.008108 +0.008053 +0.008026 +0.008052 +0.00813 +0.008106 +0.00814 +0.008098 +0.008078 +0.008113 +0.008193 +0.008168 +0.008204 +0.00816 +0.008174 +0.008177 +0.008273 +0.008253 +0.000382 +0.008279 +0.008251 +0.008228 +0.008271 +0.00835 +0.008338 +0.00836 +0.008326 +0.008311 +0.008353 +0.00843 +0.008414 +0.008438 +0.008411 +0.008398 +0.00843 +0.008503 +0.008502 +0.008521 +0.008496 +0.008475 +0.008532 +0.0086 +0.008599 +0.008626 +0.008599 +0.008584 +0.008633 +0.008683 +0.008586 +0.008578 +0.008522 +0.008451 +0.008428 +0.008454 +0.008397 +0.008386 +0.008323 +0.008268 +0.008213 +0.008248 +0.008204 +0.008207 +0.008167 +0.008111 +0.008155 +0.008157 +0.008112 +0.008115 +0.008066 +0.008035 +0.008022 +0.008084 +0.008046 +0.008064 +0.008036 +0.008009 +0.008054 +0.008121 +0.008095 +0.00813 +0.008095 +0.008077 +0.008131 +0.008192 +0.008173 +0.008209 +0.008162 +0.008155 +0.008203 +0.000383 +0.008229 +0.008216 +0.008245 +0.00822 +0.008197 +0.00825 +0.008322 +0.008311 +0.008325 +0.008307 +0.008281 +0.008336 +0.008402 +0.00839 +0.008408 +0.008381 +0.008354 +0.008402 +0.008467 +0.008458 +0.008474 +0.008449 +0.008447 +0.008506 +0.008576 +0.008578 +0.008579 +0.008558 +0.008515 +0.008539 +0.008577 +0.008522 +0.008499 +0.008435 +0.008365 +0.008344 +0.008371 +0.008323 +0.008287 +0.008228 +0.008166 +0.008172 +0.008199 +0.008172 +0.008157 +0.008106 +0.008062 +0.008078 +0.008119 +0.008094 +0.008086 +0.00806 +0.00803 +0.008062 +0.008115 +0.008112 +0.008093 +0.008074 +0.008042 +0.008084 +0.008158 +0.008159 +0.00817 +0.008146 +0.008121 +0.008163 +0.008235 +0.008223 +0.008254 +0.008201 +0.000384 +0.008195 +0.008249 +0.008324 +0.008314 +0.008316 +0.008298 +0.008274 +0.008318 +0.008384 +0.008379 +0.008402 +0.008388 +0.00836 +0.008407 +0.008471 +0.008466 +0.00848 +0.008462 +0.008433 +0.008484 +0.008557 +0.008551 +0.008578 +0.008543 +0.008527 +0.008583 +0.008665 +0.008653 +0.008678 +0.008654 +0.008616 +0.008587 +0.008602 +0.008562 +0.008559 +0.008504 +0.008441 +0.008477 +0.008478 +0.008377 +0.008349 +0.008317 +0.008224 +0.008231 +0.008262 +0.008215 +0.008226 +0.008172 +0.008135 +0.008121 +0.008156 +0.008117 +0.008129 +0.008097 +0.008062 +0.008106 +0.008154 +0.008141 +0.008142 +0.008126 +0.008095 +0.008106 +0.008163 +0.008141 +0.008156 +0.008151 +0.008113 +0.008174 +0.008244 +0.008226 +0.008249 +0.008236 +0.00821 +0.008263 +0.008339 +0.008319 +0.000385 +0.008342 +0.00832 +0.008296 +0.008354 +0.008424 +0.008409 +0.008428 +0.008409 +0.008372 +0.008435 +0.008504 +0.008482 +0.008496 +0.008467 +0.008437 +0.008479 +0.008534 +0.008529 +0.008553 +0.00853 +0.008493 +0.008547 +0.008648 +0.00865 +0.008663 +0.008613 +0.008542 +0.008557 +0.008571 +0.0085 +0.008467 +0.008419 +0.008333 +0.008344 +0.008378 +0.008323 +0.008311 +0.00826 +0.008209 +0.008227 +0.008272 +0.008246 +0.008249 +0.008206 +0.00815 +0.008186 +0.008233 +0.008222 +0.008234 +0.008199 +0.008162 +0.008198 +0.008258 +0.008242 +0.008271 +0.00825 +0.00822 +0.008274 +0.008335 +0.008326 +0.008338 +0.008317 +0.00829 +0.008327 +0.000386 +0.008409 +0.00841 +0.008432 +0.008394 +0.008384 +0.008416 +0.008492 +0.008478 +0.008502 +0.008472 +0.008458 +0.008499 +0.008574 +0.008565 +0.008586 +0.00856 +0.008543 +0.008586 +0.008671 +0.008652 +0.008686 +0.008654 +0.008644 +0.008706 +0.008788 +0.008754 +0.008689 +0.008596 +0.008539 +0.008561 +0.0086 +0.008517 +0.008455 +0.008376 +0.008325 +0.008339 +0.008382 +0.008309 +0.008277 +0.008201 +0.008159 +0.00815 +0.008187 +0.008139 +0.008135 +0.00808 +0.008058 +0.008038 +0.008065 +0.008042 +0.008044 +0.00801 +0.007985 +0.008016 +0.008077 +0.008064 +0.008076 +0.008045 +0.008038 +0.008057 +0.008103 +0.00808 +0.008098 +0.008066 +0.008058 +0.008103 +0.00818 +0.008163 +0.008182 +0.008152 +0.008155 +0.008196 +0.008264 +0.000387 +0.008242 +0.008281 +0.008242 +0.00823 +0.008276 +0.008367 +0.008329 +0.008362 +0.00831 +0.008291 +0.008312 +0.008384 +0.008354 +0.008387 +0.008357 +0.008348 +0.008385 +0.008472 +0.008459 +0.008516 +0.008484 +0.008462 +0.008503 +0.00858 +0.008541 +0.008562 +0.008489 +0.008436 +0.008439 +0.008474 +0.008396 +0.008372 +0.008293 +0.008236 +0.008224 +0.008265 +0.008204 +0.008204 +0.008128 +0.008089 +0.008098 +0.008137 +0.008084 +0.008103 +0.008034 +0.007998 +0.008012 +0.008071 +0.008041 +0.008063 +0.008016 +0.007989 +0.008022 +0.008085 +0.008059 +0.008095 +0.008051 +0.008041 +0.008074 +0.008152 +0.008127 +0.008164 +0.008137 +0.008094 +0.008145 +0.008233 +0.008204 +0.000388 +0.008247 +0.008195 +0.008197 +0.008228 +0.008307 +0.008281 +0.008319 +0.00828 +0.008272 +0.008307 +0.008388 +0.008368 +0.008399 +0.008354 +0.008345 +0.008386 +0.00847 +0.008449 +0.008484 +0.008445 +0.00843 +0.008479 +0.00856 +0.00854 +0.008585 +0.00855 +0.00854 +0.008592 +0.008656 +0.00856 +0.008556 +0.00849 +0.008452 +0.008416 +0.008437 +0.008378 +0.008378 +0.008304 +0.008235 +0.008204 +0.008229 +0.008167 +0.008199 +0.008118 +0.008104 +0.008103 +0.008122 +0.00805 +0.008065 +0.008006 +0.007996 +0.007986 +0.008042 +0.007985 +0.008013 +0.007968 +0.007947 +0.007986 +0.008056 +0.008007 +0.008055 +0.008009 +0.008014 +0.00801 +0.008071 +0.008047 +0.00807 +0.008041 +0.008041 +0.008075 +0.008157 +0.008144 +0.008164 +0.008137 +0.008126 +0.000389 +0.008164 +0.008244 +0.008221 +0.008257 +0.008217 +0.00821 +0.008248 +0.008333 +0.008307 +0.008338 +0.008299 +0.008285 +0.008321 +0.008394 +0.008367 +0.008393 +0.008355 +0.008341 +0.008382 +0.008463 +0.008467 +0.0085 +0.008456 +0.008435 +0.008447 +0.008504 +0.008441 +0.008434 +0.008349 +0.00829 +0.008271 +0.008307 +0.00824 +0.008222 +0.008143 +0.008088 +0.008083 +0.008138 +0.008068 +0.008067 +0.008004 +0.007959 +0.007957 +0.008017 +0.007976 +0.007979 +0.007929 +0.007905 +0.007917 +0.007991 +0.007963 +0.007983 +0.007942 +0.007925 +0.007951 +0.008033 +0.008014 +0.00804 +0.00801 +0.007994 +0.008026 +0.008106 +0.008082 +0.00814 +0.008075 +0.008062 +0.00039 +0.008107 +0.00818 +0.008168 +0.008194 +0.008165 +0.008144 +0.008183 +0.00826 +0.008246 +0.00827 +0.008244 +0.008224 +0.008266 +0.008344 +0.008325 +0.008351 +0.008318 +0.008309 +0.008348 +0.008425 +0.008415 +0.008437 +0.008405 +0.008398 +0.008452 +0.008538 +0.008519 +0.00854 +0.00844 +0.008391 +0.008414 +0.008456 +0.008409 +0.0084 +0.008307 +0.00821 +0.008209 +0.008249 +0.008192 +0.008184 +0.008121 +0.008084 +0.008072 +0.008095 +0.008026 +0.008031 +0.007989 +0.007949 +0.007945 +0.007983 +0.00793 +0.007964 +0.007913 +0.0079 +0.007928 +0.008005 +0.007964 +0.007975 +0.007961 +0.007909 +0.007939 +0.008 +0.007977 +0.008015 +0.007978 +0.00797 +0.008014 +0.008081 +0.008069 +0.008098 +0.008073 +0.008058 +0.008098 +0.008164 +0.000391 +0.008166 +0.008185 +0.008162 +0.008137 +0.00819 +0.008255 +0.008252 +0.008264 +0.00825 +0.008223 +0.008279 +0.008343 +0.008322 +0.008331 +0.008302 +0.008269 +0.008316 +0.008383 +0.008369 +0.008378 +0.008356 +0.008333 +0.008389 +0.008471 +0.00848 +0.008469 +0.008406 +0.00834 +0.008332 +0.008338 +0.008304 +0.008267 +0.008184 +0.008114 +0.008123 +0.008151 +0.008101 +0.008078 +0.008015 +0.007963 +0.007985 +0.008004 +0.00798 +0.007963 +0.007913 +0.007874 +0.007898 +0.007949 +0.007934 +0.00794 +0.0079 +0.007871 +0.00791 +0.007964 +0.007963 +0.007974 +0.007944 +0.007921 +0.007968 +0.008029 +0.008037 +0.00804 +0.008023 +0.007994 +0.008056 +0.008096 +0.008102 +0.000392 +0.008124 +0.008099 +0.008077 +0.008115 +0.008189 +0.008176 +0.008204 +0.008171 +0.008156 +0.008194 +0.008268 +0.008254 +0.008282 +0.008254 +0.008236 +0.008278 +0.008348 +0.008344 +0.008374 +0.008327 +0.008324 +0.008363 +0.008448 +0.008426 +0.008459 +0.008445 +0.008425 +0.008474 +0.008496 +0.008444 +0.008457 +0.008405 +0.00836 +0.008377 +0.008395 +0.008317 +0.00829 +0.008208 +0.008152 +0.008149 +0.008185 +0.008117 +0.008132 +0.008079 +0.008016 +0.007987 +0.008033 +0.007996 +0.008002 +0.007958 +0.007933 +0.007954 +0.008025 +0.007984 +0.00801 +0.007953 +0.007899 +0.00793 +0.007987 +0.007971 +0.007988 +0.007962 +0.007959 +0.007987 +0.008066 +0.008045 +0.008063 +0.008041 +0.008025 +0.008064 +0.008153 +0.008123 +0.008149 +0.000393 +0.008125 +0.008111 +0.00816 +0.008225 +0.008207 +0.008228 +0.008213 +0.008194 +0.008221 +0.008269 +0.008242 +0.008267 +0.008252 +0.008222 +0.008275 +0.008338 +0.008324 +0.008341 +0.008331 +0.008321 +0.008386 +0.008451 +0.008443 +0.008457 +0.008424 +0.008382 +0.008419 +0.008461 +0.008426 +0.008402 +0.008327 +0.008253 +0.008275 +0.008302 +0.008244 +0.00823 +0.008168 +0.008113 +0.008136 +0.00818 +0.008147 +0.008144 +0.008092 +0.008041 +0.008075 +0.008118 +0.008101 +0.008099 +0.008063 +0.00802 +0.00806 +0.008111 +0.008104 +0.008121 +0.008088 +0.008058 +0.008104 +0.008162 +0.008164 +0.008187 +0.008159 +0.008134 +0.008179 +0.008256 +0.008228 +0.008243 +0.000394 +0.008232 +0.008207 +0.008251 +0.008327 +0.008325 +0.008328 +0.008314 +0.008287 +0.008337 +0.008401 +0.008394 +0.008419 +0.008394 +0.008366 +0.008416 +0.008483 +0.008482 +0.008501 +0.008465 +0.008447 +0.0085 +0.00856 +0.008568 +0.00858 +0.008567 +0.008542 +0.008602 +0.008678 +0.00867 +0.008688 +0.008591 +0.00851 +0.008532 +0.008569 +0.008522 +0.008487 +0.008376 +0.0083 +0.008328 +0.00835 +0.008289 +0.008287 +0.008225 +0.008131 +0.008143 +0.008167 +0.008148 +0.008132 +0.008102 +0.008051 +0.00808 +0.008098 +0.008066 +0.008073 +0.008041 +0.008021 +0.00805 +0.008092 +0.008067 +0.008072 +0.008064 +0.00803 +0.00809 +0.008156 +0.008129 +0.008156 +0.008138 +0.008102 +0.008157 +0.00821 +0.008184 +0.00822 +0.008195 +0.000395 +0.00817 +0.008226 +0.008297 +0.008283 +0.008298 +0.008284 +0.008248 +0.008316 +0.008388 +0.008369 +0.008389 +0.008363 +0.00834 +0.008366 +0.008423 +0.008398 +0.008418 +0.008398 +0.008383 +0.008427 +0.008494 +0.008515 +0.008555 +0.008532 +0.008503 +0.008546 +0.008595 +0.008564 +0.008548 +0.008469 +0.0084 +0.008409 +0.008438 +0.008374 +0.008349 +0.008278 +0.008215 +0.008219 +0.008252 +0.008215 +0.008199 +0.008139 +0.008085 +0.008101 +0.008135 +0.008105 +0.008099 +0.008052 +0.008016 +0.008041 +0.00809 +0.008077 +0.00809 +0.008057 +0.008028 +0.008077 +0.008114 +0.008122 +0.008142 +0.008116 +0.008097 +0.008142 +0.008204 +0.008204 +0.008228 +0.008174 +0.008156 +0.000396 +0.008213 +0.00827 +0.008282 +0.008297 +0.008268 +0.008244 +0.008295 +0.008359 +0.008354 +0.008368 +0.008351 +0.008327 +0.008376 +0.008441 +0.008436 +0.008453 +0.00843 +0.008401 +0.008452 +0.008524 +0.008521 +0.008537 +0.008517 +0.008489 +0.008555 +0.008615 +0.008617 +0.00864 +0.008615 +0.008598 +0.008659 +0.008712 +0.008625 +0.008613 +0.008552 +0.008489 +0.008484 +0.008486 +0.008438 +0.008429 +0.008392 +0.008298 +0.008282 +0.008316 +0.008268 +0.008278 +0.008238 +0.008193 +0.008192 +0.008204 +0.00816 +0.008176 +0.008138 +0.008108 +0.008149 +0.008199 +0.008186 +0.008187 +0.008157 +0.008112 +0.008128 +0.008186 +0.008175 +0.008191 +0.008179 +0.008148 +0.008205 +0.008276 +0.008263 +0.00828 +0.008268 +0.008235 +0.008297 +0.008364 +0.008352 +0.000397 +0.008367 +0.008351 +0.008326 +0.008376 +0.00846 +0.008433 +0.008461 +0.008433 +0.008416 +0.008447 +0.008499 +0.008476 +0.008508 +0.008476 +0.008454 +0.008501 +0.008572 +0.008551 +0.008576 +0.008548 +0.008533 +0.008603 +0.008691 +0.008681 +0.008697 +0.008658 +0.008625 +0.00863 +0.008681 +0.008601 +0.008582 +0.008516 +0.008438 +0.008423 +0.008451 +0.008392 +0.008366 +0.008305 +0.008245 +0.008252 +0.008299 +0.008252 +0.008248 +0.008196 +0.008148 +0.008157 +0.00822 +0.008187 +0.008191 +0.008156 +0.008123 +0.008151 +0.008219 +0.008197 +0.008212 +0.008184 +0.008157 +0.008188 +0.008268 +0.008256 +0.008273 +0.008247 +0.008224 +0.008265 +0.008357 +0.008321 +0.008346 +0.000398 +0.008326 +0.008303 +0.008349 +0.00842 +0.008417 +0.008427 +0.008407 +0.008386 +0.008433 +0.008501 +0.008497 +0.008516 +0.008491 +0.008463 +0.008516 +0.008581 +0.008579 +0.008595 +0.008567 +0.008541 +0.0086 +0.008664 +0.008671 +0.008689 +0.008664 +0.008641 +0.008702 +0.008772 +0.008771 +0.008782 +0.008743 +0.008643 +0.0086 +0.008621 +0.008577 +0.008571 +0.008506 +0.008444 +0.008418 +0.008399 +0.008339 +0.008352 +0.008304 +0.008256 +0.008296 +0.008329 +0.008303 +0.008218 +0.008175 +0.008133 +0.008176 +0.008236 +0.008186 +0.008205 +0.008127 +0.008114 +0.008148 +0.008204 +0.008183 +0.00818 +0.008178 +0.008139 +0.008199 +0.008249 +0.008226 +0.008252 +0.008227 +0.008212 +0.008235 +0.008287 +0.008281 +0.008302 +0.008284 +0.008269 +0.008315 +0.000399 +0.008385 +0.008376 +0.008391 +0.008385 +0.008351 +0.008406 +0.00848 +0.008466 +0.008484 +0.008464 +0.00844 +0.008491 +0.008552 +0.008543 +0.008549 +0.008528 +0.008494 +0.008548 +0.008613 +0.008603 +0.008618 +0.008623 +0.008602 +0.008651 +0.008715 +0.008678 +0.008662 +0.008605 +0.008536 +0.008535 +0.008557 +0.008491 +0.008464 +0.008396 +0.008313 +0.008317 +0.008357 +0.008304 +0.008275 +0.00823 +0.008169 +0.008179 +0.008221 +0.00818 +0.008172 +0.008134 +0.008088 +0.008115 +0.008172 +0.008149 +0.008155 +0.008137 +0.0081 +0.008137 +0.008205 +0.008191 +0.008212 +0.008192 +0.008164 +0.008216 +0.008279 +0.008267 +0.00831 +0.00824 +0.008236 +0.008279 +0.0004 +0.00835 +0.00835 +0.008372 +0.008344 +0.008313 +0.008364 +0.008434 +0.008433 +0.00845 +0.008423 +0.008396 +0.008457 +0.008508 +0.008512 +0.008533 +0.008504 +0.00848 +0.008539 +0.008602 +0.008596 +0.008623 +0.008593 +0.008579 +0.008642 +0.008706 +0.008712 +0.008731 +0.008709 +0.008641 +0.008617 +0.008647 +0.00861 +0.008597 +0.008538 +0.008476 +0.008516 +0.008496 +0.008396 +0.008381 +0.008342 +0.008271 +0.008262 +0.008292 +0.008243 +0.008249 +0.008193 +0.008159 +0.008137 +0.00817 +0.008121 +0.008132 +0.008101 +0.008068 +0.008121 +0.008167 +0.00815 +0.00815 +0.008131 +0.00811 +0.008154 +0.0082 +0.008169 +0.0082 +0.008179 +0.008141 +0.00821 +0.008268 +0.008249 +0.00828 +0.008258 +0.008238 +0.008295 +0.000401 +0.008372 +0.00833 +0.008361 +0.008348 +0.008323 +0.008374 +0.00843 +0.00841 +0.008432 +0.008414 +0.008385 +0.008441 +0.008505 +0.00848 +0.008494 +0.00847 +0.008447 +0.008488 +0.008549 +0.00855 +0.008563 +0.008563 +0.008552 +0.008607 +0.008658 +0.008621 +0.008604 +0.008536 +0.008466 +0.008467 +0.008479 +0.008421 +0.008392 +0.008322 +0.008247 +0.008263 +0.00828 +0.008232 +0.008217 +0.008151 +0.008094 +0.008117 +0.00815 +0.00811 +0.008103 +0.008058 +0.008009 +0.008048 +0.008096 +0.008078 +0.008085 +0.00805 +0.008011 +0.008058 +0.008114 +0.008106 +0.008117 +0.008095 +0.008066 +0.008118 +0.008178 +0.008178 +0.008192 +0.008184 +0.008141 +0.008179 +0.008265 +0.000402 +0.008249 +0.008278 +0.008245 +0.008226 +0.008266 +0.008343 +0.008331 +0.008358 +0.008327 +0.008303 +0.00835 +0.008426 +0.008411 +0.008434 +0.0084 +0.008384 +0.008432 +0.008501 +0.00849 +0.008521 +0.008485 +0.008478 +0.008522 +0.008605 +0.008593 +0.00862 +0.008591 +0.008574 +0.008619 +0.008632 +0.008533 +0.008511 +0.00844 +0.008378 +0.008345 +0.008368 +0.008311 +0.008309 +0.008246 +0.008201 +0.00822 +0.008215 +0.008156 +0.008171 +0.008102 +0.008059 +0.008038 +0.008105 +0.008046 +0.008071 +0.008021 +0.007999 +0.008037 +0.008097 +0.008071 +0.00808 +0.008058 +0.008004 +0.008025 +0.008094 +0.008061 +0.0081 +0.008065 +0.00805 +0.008101 +0.008164 +0.008155 +0.008182 +0.008152 +0.008145 +0.008193 +0.008255 +0.000403 +0.008239 +0.008277 +0.008236 +0.008228 +0.008265 +0.00835 +0.008327 +0.008361 +0.008329 +0.008317 +0.008361 +0.008439 +0.008402 +0.008418 +0.008367 +0.008352 +0.008397 +0.00847 +0.008432 +0.00846 +0.008428 +0.008421 +0.008474 +0.008585 +0.008568 +0.00859 +0.008533 +0.008498 +0.008492 +0.008531 +0.008466 +0.00846 +0.008372 +0.008316 +0.008307 +0.008352 +0.008291 +0.00828 +0.00822 +0.008175 +0.008164 +0.008229 +0.008187 +0.008192 +0.008128 +0.008094 +0.008098 +0.008171 +0.008136 +0.008155 +0.008111 +0.008085 +0.008105 +0.008175 +0.00815 +0.008181 +0.008138 +0.008121 +0.008143 +0.008233 +0.008214 +0.008245 +0.008215 +0.008194 +0.008234 +0.008306 +0.008303 +0.0083 +0.000404 +0.00829 +0.008281 +0.008314 +0.008408 +0.008366 +0.008401 +0.008359 +0.008346 +0.008383 +0.008471 +0.008459 +0.00849 +0.008455 +0.008441 +0.008476 +0.008556 +0.008535 +0.00857 +0.008522 +0.008522 +0.008564 +0.008656 +0.008627 +0.008673 +0.008632 +0.008633 +0.00868 +0.008735 +0.008647 +0.008647 +0.008599 +0.008542 +0.008494 +0.008541 +0.008474 +0.008482 +0.008397 +0.008309 +0.008296 +0.008358 +0.008292 +0.008312 +0.008241 +0.008218 +0.008161 +0.008215 +0.008161 +0.008181 +0.008129 +0.008114 +0.008135 +0.008208 +0.008168 +0.008192 +0.00816 +0.008132 +0.008145 +0.008202 +0.008155 +0.008198 +0.008159 +0.008148 +0.008198 +0.008275 +0.008242 +0.008282 +0.008235 +0.008234 +0.008283 +0.008359 +0.008336 +0.00836 +0.000405 +0.008321 +0.008292 +0.008316 +0.008406 +0.008371 +0.008408 +0.008373 +0.00837 +0.008404 +0.008489 +0.008467 +0.008495 +0.008458 +0.008445 +0.008482 +0.008564 +0.008555 +0.008593 +0.008561 +0.008547 +0.008579 +0.008664 +0.008644 +0.00868 +0.008644 +0.008617 +0.008632 +0.008692 +0.008621 +0.008603 +0.008516 +0.008444 +0.008423 +0.008466 +0.008396 +0.008385 +0.008311 +0.008266 +0.008262 +0.008306 +0.00826 +0.008268 +0.008205 +0.008166 +0.008174 +0.008237 +0.008195 +0.008213 +0.008168 +0.008143 +0.008162 +0.008236 +0.008204 +0.008233 +0.008193 +0.008174 +0.008208 +0.008288 +0.008263 +0.008297 +0.008263 +0.008248 +0.008288 +0.008362 +0.00836 +0.008364 +0.000406 +0.008338 +0.008329 +0.008368 +0.008441 +0.008425 +0.008464 +0.008423 +0.008413 +0.008443 +0.008525 +0.008507 +0.008549 +0.008501 +0.008497 +0.008535 +0.008614 +0.008592 +0.008625 +0.008587 +0.008575 +0.008619 +0.008702 +0.008684 +0.008724 +0.008686 +0.008684 +0.008734 +0.008821 +0.008785 +0.008736 +0.008659 +0.00862 +0.008641 +0.008693 +0.008619 +0.008552 +0.008462 +0.00842 +0.008435 +0.008499 +0.008419 +0.008406 +0.008301 +0.008281 +0.008304 +0.008351 +0.008301 +0.008308 +0.008224 +0.008204 +0.008209 +0.008291 +0.008239 +0.008267 +0.008224 +0.008203 +0.008243 +0.00831 +0.008286 +0.00832 +0.008261 +0.00824 +0.008252 +0.008334 +0.008309 +0.008336 +0.008313 +0.008301 +0.008341 +0.008434 +0.008421 +0.008424 +0.008409 +0.000407 +0.008398 +0.00843 +0.008521 +0.008497 +0.008531 +0.008492 +0.008484 +0.008532 +0.008612 +0.008581 +0.008618 +0.008573 +0.008562 +0.008593 +0.008675 +0.008638 +0.008675 +0.008623 +0.008618 +0.008642 +0.008733 +0.008709 +0.008776 +0.008736 +0.008712 +0.008723 +0.008764 +0.008697 +0.008682 +0.008591 +0.008519 +0.008496 +0.008525 +0.008457 +0.008441 +0.008361 +0.008308 +0.008301 +0.008336 +0.008287 +0.008292 +0.008217 +0.00818 +0.008186 +0.008236 +0.008194 +0.008213 +0.008159 +0.008149 +0.008158 +0.008226 +0.008199 +0.008211 +0.008166 +0.00816 +0.008201 +0.008278 +0.008255 +0.008287 +0.008242 +0.008237 +0.008259 +0.00834 +0.008319 +0.008342 +0.008327 +0.008289 +0.000408 +0.00835 +0.008438 +0.008406 +0.008445 +0.008404 +0.008385 +0.008417 +0.008503 +0.008477 +0.008512 +0.008473 +0.00847 +0.008509 +0.008593 +0.008572 +0.008608 +0.008561 +0.00855 +0.008598 +0.008672 +0.008657 +0.008695 +0.008657 +0.008648 +0.008704 +0.008796 +0.008772 +0.008801 +0.008696 +0.008625 +0.008626 +0.008675 +0.008609 +0.008586 +0.008458 +0.00841 +0.008408 +0.008438 +0.008368 +0.008378 +0.008309 +0.008217 +0.008217 +0.008256 +0.008217 +0.008217 +0.008174 +0.00813 +0.008134 +0.008154 +0.008119 +0.008144 +0.008097 +0.008088 +0.008109 +0.008189 +0.008147 +0.008162 +0.008145 +0.008125 +0.008143 +0.008209 +0.008164 +0.00821 +0.00817 +0.008158 +0.008201 +0.008278 +0.008253 +0.008297 +0.008254 +0.00825 +0.008296 +0.008377 +0.000409 +0.008349 +0.008374 +0.00835 +0.008338 +0.008382 +0.008452 +0.008431 +0.008459 +0.008429 +0.008417 +0.008465 +0.008517 +0.008487 +0.008505 +0.008472 +0.00845 +0.008497 +0.008566 +0.008555 +0.008573 +0.008572 +0.008564 +0.008619 +0.008686 +0.008649 +0.008645 +0.008574 +0.008505 +0.008516 +0.008547 +0.008486 +0.008468 +0.008392 +0.008321 +0.008328 +0.008363 +0.008305 +0.008296 +0.008231 +0.008172 +0.008191 +0.008235 +0.00819 +0.008182 +0.008131 +0.008089 +0.008126 +0.00819 +0.00816 +0.008171 +0.00813 +0.0081 +0.008134 +0.008215 +0.008197 +0.008229 +0.00819 +0.008167 +0.008213 +0.008281 +0.00827 +0.008291 +0.008263 +0.008246 +0.008292 +0.00041 +0.008371 +0.00836 +0.008375 +0.008334 +0.008327 +0.008372 +0.008447 +0.008438 +0.008453 +0.008429 +0.00841 +0.008454 +0.008527 +0.008518 +0.008531 +0.008511 +0.008492 +0.008537 +0.008619 +0.008604 +0.008636 +0.008602 +0.008599 +0.008651 +0.008734 +0.008713 +0.008733 +0.00861 +0.008545 +0.008561 +0.0086 +0.008553 +0.00851 +0.008409 +0.008368 +0.008352 +0.008382 +0.008337 +0.008323 +0.008261 +0.008186 +0.008164 +0.008209 +0.008172 +0.008169 +0.008133 +0.008075 +0.008067 +0.008107 +0.008067 +0.008101 +0.008044 +0.008032 +0.008064 +0.00813 +0.008109 +0.008112 +0.008098 +0.008071 +0.008121 +0.008187 +0.008146 +0.008185 +0.008137 +0.008119 +0.008169 +0.008226 +0.008199 +0.008242 +0.008216 +0.008195 +0.000411 +0.008252 +0.008317 +0.008299 +0.008329 +0.008288 +0.008283 +0.00833 +0.008414 +0.008381 +0.008421 +0.008369 +0.008367 +0.008402 +0.00848 +0.00844 +0.008474 +0.008423 +0.008419 +0.008452 +0.008524 +0.008502 +0.008548 +0.008538 +0.008533 +0.008571 +0.008627 +0.008571 +0.00857 +0.008479 +0.008426 +0.008427 +0.008461 +0.008382 +0.008382 +0.008299 +0.008251 +0.008244 +0.008277 +0.008225 +0.008235 +0.008165 +0.008119 +0.008128 +0.008179 +0.008132 +0.008143 +0.008092 +0.008066 +0.008092 +0.008155 +0.008118 +0.008147 +0.008095 +0.008071 +0.008101 +0.008185 +0.00816 +0.008192 +0.008151 +0.008138 +0.008184 +0.008263 +0.008245 +0.008268 +0.008233 +0.008209 +0.000412 +0.008251 +0.008325 +0.008326 +0.008343 +0.008313 +0.008295 +0.008341 +0.008414 +0.008397 +0.008424 +0.008392 +0.008376 +0.008423 +0.008499 +0.008483 +0.008509 +0.008473 +0.008455 +0.008499 +0.008582 +0.008564 +0.008594 +0.00856 +0.008548 +0.008594 +0.008682 +0.008663 +0.008696 +0.00867 +0.008652 +0.008688 +0.008674 +0.008602 +0.008598 +0.008549 +0.00848 +0.008442 +0.008475 +0.008428 +0.008424 +0.008362 +0.008332 +0.008335 +0.008353 +0.008311 +0.00829 +0.00824 +0.008183 +0.008213 +0.008246 +0.00822 +0.008217 +0.008193 +0.008165 +0.008184 +0.008231 +0.008185 +0.00821 +0.008174 +0.008152 +0.008211 +0.008257 +0.008251 +0.008267 +0.008237 +0.008234 +0.008275 +0.008336 +0.008317 +0.008334 +0.008311 +0.008296 +0.00833 +0.000413 +0.008382 +0.008373 +0.008389 +0.008375 +0.008356 +0.008411 +0.008473 +0.008466 +0.008484 +0.008468 +0.008442 +0.008495 +0.008563 +0.008547 +0.008564 +0.00854 +0.008504 +0.00856 +0.008624 +0.008615 +0.008636 +0.008642 +0.008616 +0.00867 +0.008729 +0.008719 +0.008719 +0.008662 +0.008615 +0.008628 +0.008653 +0.008605 +0.008588 +0.008518 +0.008458 +0.008462 +0.008493 +0.008454 +0.008435 +0.008377 +0.008323 +0.008347 +0.008367 +0.008344 +0.008335 +0.008286 +0.008242 +0.00827 +0.008314 +0.008298 +0.008299 +0.008268 +0.008231 +0.008272 +0.008321 +0.008313 +0.008327 +0.0083 +0.008271 +0.008318 +0.00838 +0.008382 +0.008397 +0.008369 +0.008346 +0.008408 +0.008462 +0.008451 +0.000414 +0.008482 +0.008451 +0.008433 +0.008478 +0.008556 +0.008528 +0.008559 +0.00853 +0.008515 +0.00856 +0.008637 +0.00862 +0.008645 +0.008614 +0.008595 +0.008641 +0.008721 +0.008703 +0.00873 +0.008706 +0.008682 +0.008746 +0.008821 +0.008807 +0.008843 +0.008811 +0.008798 +0.008807 +0.008775 +0.008715 +0.008714 +0.008662 +0.008603 +0.008571 +0.008573 +0.008519 +0.008508 +0.008459 +0.008415 +0.008425 +0.008453 +0.008391 +0.00838 +0.008322 +0.008278 +0.008288 +0.008336 +0.008293 +0.008311 +0.008265 +0.008253 +0.008276 +0.008343 +0.008298 +0.0083 +0.008265 +0.008241 +0.008264 +0.008345 +0.008307 +0.008339 +0.008317 +0.008295 +0.008336 +0.008423 +0.008393 +0.008426 +0.008412 +0.008378 +0.008431 +0.008524 +0.000415 +0.008482 +0.008514 +0.008489 +0.008482 +0.008503 +0.008568 +0.008531 +0.008578 +0.008538 +0.008529 +0.008568 +0.008647 +0.008614 +0.008648 +0.008608 +0.0086 +0.008637 +0.008719 +0.008715 +0.008769 +0.008728 +0.008716 +0.008744 +0.008823 +0.008782 +0.008778 +0.008701 +0.008662 +0.008641 +0.008685 +0.008603 +0.008588 +0.008505 +0.008453 +0.008435 +0.008479 +0.008425 +0.008421 +0.008347 +0.008311 +0.008309 +0.00836 +0.008309 +0.008318 +0.008264 +0.008239 +0.008243 +0.008309 +0.008277 +0.008293 +0.008256 +0.008234 +0.008256 +0.008326 +0.008305 +0.008325 +0.008298 +0.00829 +0.008319 +0.008413 +0.008371 +0.008407 +0.008372 +0.008349 +0.008399 +0.008488 +0.000416 +0.008457 +0.008497 +0.008446 +0.008439 +0.008478 +0.008559 +0.00854 +0.008572 +0.008538 +0.008528 +0.008564 +0.008652 +0.008622 +0.008662 +0.008615 +0.008611 +0.008649 +0.008727 +0.008716 +0.008749 +0.008724 +0.008706 +0.008757 +0.008859 +0.008822 +0.008857 +0.00878 +0.008695 +0.008708 +0.008771 +0.008709 +0.00872 +0.00866 +0.008561 +0.008541 +0.008601 +0.008557 +0.008553 +0.008494 +0.008474 +0.008439 +0.008465 +0.008409 +0.008422 +0.00838 +0.008347 +0.008369 +0.0084 +0.008365 +0.008376 +0.008335 +0.008322 +0.008331 +0.008408 +0.008362 +0.008401 +0.008359 +0.008349 +0.008393 +0.00847 +0.008451 +0.008468 +0.008445 +0.008433 +0.008475 +0.008568 +0.008527 +0.008569 +0.000417 +0.008538 +0.008493 +0.00853 +0.008599 +0.008567 +0.008613 +0.008583 +0.008564 +0.008614 +0.008691 +0.00868 +0.008701 +0.008674 +0.008652 +0.008696 +0.008776 +0.008755 +0.008803 +0.008778 +0.00876 +0.00879 +0.008874 +0.008853 +0.008888 +0.008851 +0.008819 +0.008832 +0.008875 +0.008812 +0.0088 +0.00872 +0.008647 +0.00864 +0.008672 +0.008614 +0.008585 +0.008519 +0.008463 +0.00847 +0.008505 +0.008457 +0.008455 +0.008393 +0.008342 +0.00836 +0.008411 +0.008374 +0.008381 +0.008339 +0.008301 +0.008338 +0.00839 +0.008368 +0.008392 +0.008358 +0.008326 +0.00837 +0.00844 +0.008422 +0.008454 +0.008422 +0.008402 +0.008448 +0.008513 +0.008511 +0.00854 +0.0085 +0.000418 +0.008479 +0.008536 +0.008599 +0.008592 +0.008602 +0.008593 +0.008565 +0.008616 +0.008684 +0.008676 +0.008692 +0.008677 +0.008649 +0.00871 +0.008763 +0.008764 +0.008788 +0.008764 +0.008731 +0.008798 +0.008861 +0.008867 +0.008883 +0.008868 +0.008847 +0.008908 +0.008986 +0.008912 +0.008858 +0.008805 +0.008748 +0.008787 +0.00878 +0.008736 +0.008668 +0.008597 +0.008534 +0.008573 +0.008585 +0.008525 +0.008535 +0.008479 +0.008387 +0.008408 +0.008443 +0.008417 +0.008411 +0.008374 +0.008343 +0.008387 +0.008453 +0.00842 +0.008439 +0.008386 +0.008339 +0.008391 +0.008425 +0.008424 +0.008434 +0.008419 +0.008391 +0.008446 +0.008521 +0.008503 +0.008521 +0.008504 +0.008476 +0.00855 +0.008623 +0.008582 +0.000419 +0.008626 +0.008596 +0.008567 +0.008636 +0.008686 +0.008659 +0.008678 +0.008655 +0.00863 +0.008698 +0.008765 +0.008745 +0.008766 +0.008736 +0.008703 +0.008753 +0.00882 +0.008802 +0.008818 +0.008796 +0.008776 +0.008831 +0.008932 +0.008935 +0.008923 +0.00887 +0.008799 +0.008778 +0.008815 +0.008762 +0.008716 +0.008642 +0.008559 +0.00856 +0.008586 +0.008536 +0.008503 +0.008452 +0.008387 +0.00839 +0.008423 +0.008397 +0.008381 +0.00833 +0.008276 +0.008305 +0.00836 +0.008346 +0.008341 +0.008306 +0.008269 +0.008299 +0.008368 +0.008362 +0.00837 +0.008346 +0.008315 +0.008356 +0.008433 +0.008428 +0.008445 +0.008426 +0.008387 +0.00845 +0.008506 +0.008508 +0.00042 +0.008531 +0.008503 +0.008483 +0.008522 +0.008593 +0.008582 +0.008613 +0.008583 +0.008562 +0.008609 +0.008677 +0.008668 +0.008699 +0.008666 +0.008649 +0.008699 +0.008761 +0.008761 +0.008782 +0.00875 +0.008741 +0.008792 +0.008871 +0.008862 +0.008889 +0.008863 +0.008853 +0.008893 +0.008872 +0.008819 +0.008823 +0.008765 +0.008711 +0.008731 +0.008706 +0.008624 +0.008629 +0.008565 +0.008471 +0.008477 +0.008513 +0.008457 +0.008468 +0.008407 +0.008382 +0.008355 +0.008387 +0.008339 +0.008349 +0.008313 +0.008281 +0.008324 +0.00837 +0.008344 +0.00834 +0.00828 +0.008272 +0.008288 +0.008343 +0.008326 +0.008339 +0.008322 +0.008296 +0.008341 +0.008426 +0.008394 +0.008422 +0.008397 +0.008377 +0.008431 +0.008511 +0.008481 +0.008508 +0.000421 +0.00848 +0.008451 +0.008465 +0.008543 +0.008522 +0.008559 +0.008525 +0.008516 +0.008558 +0.008644 +0.008619 +0.008654 +0.008614 +0.008604 +0.008637 +0.008719 +0.008716 +0.008756 +0.008723 +0.00871 +0.008737 +0.00883 +0.008797 +0.008828 +0.008791 +0.008767 +0.008775 +0.008819 +0.008738 +0.008742 +0.008639 +0.008577 +0.008569 +0.008605 +0.008533 +0.008534 +0.008459 +0.008403 +0.008413 +0.008463 +0.008408 +0.008418 +0.008353 +0.008317 +0.008331 +0.008395 +0.008359 +0.008382 +0.008331 +0.008309 +0.008342 +0.008416 +0.008383 +0.008422 +0.008378 +0.008358 +0.0084 +0.008482 +0.008457 +0.008494 +0.008447 +0.008439 +0.008493 +0.008548 +0.000422 +0.008545 +0.008567 +0.008539 +0.008526 +0.00857 +0.008634 +0.008625 +0.008654 +0.008624 +0.008606 +0.008656 +0.008722 +0.008708 +0.008737 +0.008712 +0.008698 +0.008735 +0.008816 +0.008802 +0.008831 +0.008799 +0.008778 +0.008843 +0.008899 +0.008903 +0.008932 +0.008901 +0.008898 +0.008951 +0.008989 +0.008893 +0.00889 +0.008837 +0.00878 +0.008734 +0.008768 +0.008705 +0.008692 +0.008619 +0.008569 +0.008522 +0.008552 +0.008516 +0.008513 +0.008475 +0.008418 +0.008433 +0.008428 +0.008394 +0.008395 +0.00836 +0.008342 +0.008357 +0.008417 +0.00836 +0.00838 +0.008342 +0.00831 +0.008347 +0.008381 +0.008353 +0.008389 +0.008349 +0.008337 +0.008385 +0.008453 +0.008442 +0.008457 +0.008443 +0.008421 +0.00847 +0.008557 +0.008527 +0.008542 +0.000423 +0.008521 +0.008508 +0.008515 +0.008604 +0.008565 +0.008604 +0.008566 +0.008559 +0.008602 +0.008691 +0.008662 +0.008697 +0.008659 +0.008645 +0.008677 +0.00876 +0.00874 +0.008795 +0.00877 +0.00876 +0.008785 +0.008872 +0.008842 +0.008859 +0.008819 +0.008784 +0.008785 +0.008829 +0.008751 +0.008733 +0.008653 +0.008589 +0.008565 +0.008617 +0.008554 +0.008534 +0.008464 +0.008418 +0.008417 +0.008474 +0.008418 +0.008425 +0.008368 +0.008332 +0.008334 +0.008415 +0.008371 +0.008394 +0.008357 +0.008336 +0.008352 +0.008433 +0.0084 +0.008433 +0.008403 +0.008388 +0.008421 +0.008509 +0.008478 +0.008511 +0.008474 +0.008448 +0.008493 +0.008578 +0.000424 +0.008564 +0.008595 +0.008556 +0.008544 +0.008578 +0.008667 +0.008647 +0.008679 +0.00864 +0.008627 +0.008665 +0.008751 +0.008731 +0.008767 +0.008727 +0.008716 +0.008755 +0.008836 +0.008817 +0.008857 +0.008814 +0.008811 +0.00885 +0.008947 +0.008928 +0.008963 +0.008925 +0.008922 +0.008908 +0.008913 +0.00885 +0.008855 +0.008791 +0.00874 +0.008711 +0.0087 +0.008625 +0.008628 +0.008562 +0.00853 +0.008519 +0.008522 +0.008468 +0.008471 +0.008422 +0.00839 +0.008383 +0.008419 +0.00838 +0.008387 +0.008354 +0.008324 +0.008344 +0.008413 +0.008357 +0.008379 +0.008354 +0.008334 +0.008351 +0.008425 +0.008377 +0.008407 +0.008382 +0.00837 +0.008407 +0.008503 +0.008458 +0.008489 +0.008466 +0.008458 +0.00847 +0.008557 +0.008524 +0.000425 +0.008541 +0.008517 +0.008521 +0.008549 +0.008635 +0.00861 +0.008651 +0.008618 +0.008607 +0.00865 +0.008733 +0.008699 +0.008734 +0.008687 +0.00868 +0.008708 +0.008794 +0.008762 +0.008796 +0.008757 +0.008741 +0.008805 +0.008903 +0.008884 +0.008899 +0.008825 +0.008774 +0.008757 +0.008791 +0.008729 +0.008703 +0.008606 +0.008549 +0.008539 +0.008577 +0.008521 +0.008507 +0.00843 +0.00839 +0.008386 +0.008434 +0.008387 +0.008391 +0.008323 +0.008289 +0.008296 +0.00836 +0.008332 +0.008355 +0.008299 +0.008283 +0.008298 +0.008371 +0.00835 +0.008379 +0.008334 +0.008326 +0.00835 +0.008427 +0.008413 +0.008438 +0.008403 +0.0084 +0.008443 +0.0085 +0.008485 +0.000426 +0.008531 +0.008488 +0.008478 +0.008518 +0.008594 +0.008572 +0.008604 +0.008566 +0.008567 +0.008593 +0.008682 +0.008662 +0.008691 +0.008652 +0.008644 +0.008678 +0.008759 +0.008739 +0.008781 +0.008739 +0.008739 +0.008775 +0.008869 +0.008847 +0.00888 +0.008851 +0.008845 +0.008889 +0.008943 +0.008834 +0.008826 +0.00875 +0.008703 +0.008671 +0.008685 +0.008623 +0.008642 +0.008564 +0.008502 +0.00848 +0.008496 +0.008449 +0.008458 +0.008411 +0.008375 +0.008375 +0.008414 +0.008364 +0.008369 +0.008311 +0.008282 +0.008281 +0.008357 +0.00831 +0.008347 +0.008306 +0.008283 +0.008333 +0.008404 +0.008375 +0.008406 +0.008367 +0.008366 +0.008381 +0.008447 +0.008412 +0.008445 +0.008422 +0.008412 +0.008463 +0.008541 +0.000427 +0.0085 +0.008538 +0.008515 +0.008501 +0.008535 +0.00863 +0.008601 +0.008634 +0.008598 +0.008587 +0.008633 +0.008713 +0.008681 +0.008708 +0.008662 +0.008646 +0.008681 +0.008754 +0.008734 +0.00876 +0.008719 +0.008714 +0.008745 +0.008869 +0.008855 +0.008873 +0.008798 +0.008754 +0.008726 +0.008765 +0.008693 +0.008685 +0.008597 +0.008539 +0.008528 +0.008581 +0.008528 +0.008517 +0.008444 +0.008414 +0.008415 +0.00848 +0.008433 +0.00844 +0.008383 +0.008353 +0.008358 +0.008427 +0.0084 +0.008424 +0.008373 +0.008351 +0.008366 +0.008443 +0.008409 +0.008432 +0.008409 +0.008395 +0.008424 +0.008511 +0.008482 +0.008512 +0.008478 +0.008456 +0.008499 +0.008584 +0.008572 +0.000428 +0.008595 +0.008569 +0.008543 +0.008587 +0.00867 +0.008655 +0.008681 +0.008652 +0.008629 +0.008676 +0.008754 +0.008739 +0.008769 +0.008733 +0.008713 +0.008759 +0.008841 +0.008823 +0.008849 +0.008828 +0.008807 +0.008871 +0.008942 +0.008932 +0.008969 +0.008938 +0.008923 +0.008961 +0.008948 +0.008871 +0.008871 +0.008794 +0.008731 +0.008688 +0.008727 +0.008685 +0.008677 +0.008609 +0.00858 +0.008569 +0.008577 +0.008516 +0.008523 +0.008473 +0.00843 +0.008446 +0.008467 +0.008436 +0.008445 +0.00841 +0.008393 +0.008386 +0.008443 +0.008408 +0.008437 +0.008404 +0.008376 +0.008435 +0.008497 +0.008474 +0.008504 +0.008465 +0.008466 +0.008509 +0.00858 +0.008556 +0.008556 +0.008534 +0.008518 +0.000429 +0.008558 +0.008654 +0.008611 +0.008645 +0.008622 +0.008612 +0.008651 +0.008738 +0.00871 +0.008744 +0.00871 +0.0087 +0.008713 +0.008787 +0.008747 +0.008783 +0.00874 +0.008729 +0.008776 +0.008872 +0.008883 +0.008928 +0.00888 +0.008871 +0.008894 +0.008972 +0.008932 +0.008926 +0.008842 +0.008801 +0.008787 +0.008815 +0.008747 +0.008741 +0.008646 +0.008594 +0.008582 +0.008638 +0.008581 +0.008573 +0.008502 +0.008468 +0.008463 +0.008526 +0.00848 +0.008482 +0.008421 +0.008397 +0.008411 +0.008489 +0.008453 +0.00847 +0.008429 +0.008407 +0.008426 +0.008508 +0.008481 +0.008516 +0.00848 +0.008465 +0.008493 +0.008581 +0.008554 +0.008591 +0.008554 +0.008544 +0.008589 +0.00043 +0.008661 +0.008651 +0.00867 +0.008641 +0.008611 +0.008668 +0.008747 +0.008738 +0.00876 +0.008722 +0.008712 +0.00876 +0.008832 +0.008823 +0.008837 +0.008813 +0.008793 +0.008836 +0.008922 +0.00891 +0.008944 +0.008909 +0.008901 +0.008954 +0.009041 +0.009013 +0.009047 +0.008971 +0.008864 +0.008877 +0.008919 +0.008858 +0.008854 +0.008768 +0.008654 +0.008665 +0.008703 +0.008629 +0.008654 +0.008595 +0.00856 +0.00854 +0.008546 +0.008499 +0.008504 +0.008459 +0.008432 +0.008456 +0.008534 +0.008491 +0.0085 +0.008471 +0.008431 +0.00845 +0.00849 +0.008453 +0.008483 +0.008443 +0.008433 +0.008472 +0.008545 +0.008533 +0.00855 +0.008531 +0.008512 +0.008557 +0.008652 +0.008609 +0.008642 +0.008622 +0.000431 +0.008596 +0.008612 +0.008694 +0.00864 +0.008684 +0.008661 +0.008653 +0.008695 +0.008784 +0.008751 +0.008793 +0.00876 +0.008745 +0.008782 +0.00886 +0.008838 +0.008874 +0.008833 +0.008834 +0.008875 +0.008971 +0.008943 +0.008972 +0.008938 +0.008929 +0.008951 +0.00904 +0.008988 +0.008983 +0.008901 +0.008834 +0.008813 +0.008846 +0.008778 +0.008758 +0.008675 +0.008618 +0.008613 +0.008666 +0.008605 +0.008607 +0.008536 +0.008493 +0.008497 +0.008564 +0.008512 +0.008515 +0.008467 +0.008438 +0.008459 +0.008533 +0.008498 +0.008513 +0.008469 +0.008452 +0.008474 +0.00856 +0.008534 +0.008558 +0.008526 +0.008512 +0.008546 +0.008634 +0.008612 +0.008655 +0.008601 +0.008591 +0.000432 +0.008639 +0.008712 +0.008699 +0.008725 +0.008701 +0.008676 +0.008719 +0.008798 +0.00879 +0.008814 +0.008784 +0.008763 +0.00881 +0.008882 +0.008869 +0.0089 +0.00887 +0.00885 +0.008905 +0.008981 +0.008979 +0.009004 +0.008978 +0.008975 +0.009015 +0.009101 +0.008978 +0.008913 +0.008844 +0.008795 +0.008786 +0.008772 +0.008693 +0.008693 +0.008622 +0.008528 +0.008519 +0.008557 +0.0085 +0.008508 +0.008443 +0.008348 +0.008347 +0.008388 +0.008351 +0.008361 +0.008308 +0.008291 +0.008313 +0.008388 +0.008348 +0.008337 +0.008279 +0.008248 +0.008303 +0.008362 +0.008336 +0.008361 +0.008316 +0.008319 +0.00834 +0.008401 +0.008381 +0.008398 +0.008385 +0.008363 +0.008409 +0.008491 +0.008462 +0.008502 +0.008467 +0.000433 +0.008446 +0.00851 +0.008576 +0.008559 +0.008579 +0.008556 +0.008531 +0.008591 +0.00864 +0.008622 +0.00864 +0.008613 +0.008586 +0.008633 +0.0087 +0.008682 +0.008698 +0.008679 +0.008668 +0.008742 +0.008823 +0.008811 +0.008825 +0.008785 +0.00874 +0.00877 +0.008796 +0.008752 +0.008721 +0.008643 +0.008569 +0.008573 +0.008602 +0.008552 +0.008535 +0.008469 +0.008408 +0.008435 +0.008472 +0.008436 +0.008438 +0.008386 +0.008334 +0.008361 +0.008407 +0.008389 +0.008401 +0.008366 +0.008329 +0.008376 +0.008418 +0.008404 +0.008416 +0.008389 +0.008363 +0.008424 +0.00849 +0.008478 +0.008499 +0.008464 +0.00845 +0.008508 +0.008562 +0.008563 +0.000434 +0.008577 +0.008553 +0.008534 +0.008583 +0.008654 +0.008639 +0.008666 +0.008639 +0.008626 +0.008656 +0.008739 +0.008727 +0.008757 +0.00872 +0.008705 +0.008744 +0.00883 +0.008811 +0.00884 +0.008812 +0.008791 +0.008838 +0.008928 +0.008915 +0.008947 +0.008926 +0.008911 +0.008964 +0.008993 +0.0089 +0.008896 +0.008838 +0.00876 +0.008736 +0.008772 +0.008726 +0.008715 +0.008651 +0.00859 +0.008546 +0.008582 +0.008551 +0.008548 +0.008505 +0.00846 +0.008456 +0.008484 +0.008422 +0.008449 +0.008396 +0.008374 +0.008399 +0.008435 +0.008402 +0.008411 +0.008385 +0.008353 +0.008408 +0.008473 +0.008448 +0.008473 +0.008425 +0.008403 +0.008424 +0.008501 +0.008483 +0.008504 +0.008491 +0.008473 +0.008507 +0.008598 +0.008581 +0.008598 +0.000435 +0.008578 +0.008561 +0.008614 +0.008679 +0.008675 +0.008691 +0.00867 +0.008647 +0.008702 +0.008772 +0.008754 +0.008771 +0.008744 +0.008711 +0.008761 +0.008822 +0.008816 +0.008828 +0.008814 +0.008799 +0.008871 +0.008941 +0.008926 +0.008919 +0.008867 +0.008806 +0.008809 +0.008847 +0.008805 +0.008766 +0.008696 +0.008628 +0.008627 +0.00866 +0.008633 +0.008603 +0.008545 +0.008496 +0.008518 +0.008561 +0.008532 +0.008518 +0.008469 +0.00842 +0.008454 +0.008509 +0.008492 +0.008491 +0.008452 +0.008418 +0.00845 +0.008518 +0.00852 +0.008524 +0.008494 +0.00847 +0.008513 +0.008582 +0.008584 +0.008592 +0.008581 +0.008541 +0.008601 +0.00867 +0.008666 +0.000436 +0.00869 +0.008657 +0.008633 +0.008678 +0.008755 +0.008747 +0.008779 +0.008743 +0.008723 +0.00877 +0.008847 +0.008831 +0.008858 +0.008821 +0.008805 +0.008853 +0.008927 +0.008926 +0.008945 +0.008926 +0.008906 +0.008966 +0.009054 +0.009027 +0.009036 +0.008955 +0.008814 +0.008818 +0.008867 +0.008798 +0.008769 +0.00865 +0.0086 +0.008596 +0.008626 +0.008577 +0.008559 +0.008508 +0.008412 +0.008413 +0.008458 +0.008414 +0.008411 +0.008372 +0.008332 +0.008376 +0.00843 +0.0084 +0.008398 +0.008321 +0.008308 +0.008342 +0.008415 +0.008387 +0.008408 +0.008385 +0.008357 +0.008413 +0.008469 +0.008451 +0.008478 +0.008444 +0.008424 +0.008441 +0.008509 +0.008486 +0.00852 +0.008498 +0.008484 +0.000437 +0.008522 +0.008614 +0.008588 +0.008623 +0.008588 +0.008578 +0.008623 +0.008706 +0.008682 +0.008718 +0.00868 +0.00867 +0.008702 +0.008785 +0.008754 +0.00879 +0.008746 +0.008732 +0.008788 +0.00888 +0.008861 +0.008886 +0.008836 +0.008813 +0.00883 +0.008884 +0.008822 +0.008798 +0.008722 +0.008666 +0.008651 +0.008704 +0.00864 +0.008629 +0.008563 +0.008517 +0.008519 +0.008585 +0.008536 +0.008544 +0.008485 +0.008451 +0.008455 +0.008521 +0.008486 +0.00849 +0.008442 +0.008416 +0.008431 +0.008507 +0.008474 +0.008493 +0.008451 +0.008431 +0.008456 +0.008543 +0.008515 +0.008551 +0.008516 +0.008502 +0.008535 +0.008619 +0.00859 +0.00865 +0.008599 +0.008566 +0.000438 +0.008628 +0.008695 +0.008699 +0.008701 +0.008678 +0.008659 +0.008709 +0.008782 +0.00878 +0.008793 +0.00877 +0.00875 +0.008797 +0.008865 +0.008859 +0.00889 +0.008848 +0.00884 +0.008888 +0.00898 +0.008967 +0.00899 +0.008973 +0.008955 +0.009015 +0.00903 +0.008945 +0.008939 +0.008875 +0.0088 +0.008753 +0.008794 +0.008717 +0.00872 +0.008636 +0.008562 +0.008542 +0.008606 +0.008543 +0.008554 +0.008495 +0.008404 +0.008423 +0.008456 +0.008426 +0.008434 +0.008387 +0.008364 +0.008392 +0.008472 +0.008423 +0.008444 +0.00839 +0.008352 +0.008394 +0.008451 +0.008435 +0.008455 +0.00843 +0.008421 +0.008462 +0.008544 +0.008522 +0.008543 +0.008524 +0.008502 +0.00856 +0.008635 +0.000439 +0.008612 +0.008641 +0.008621 +0.008589 +0.008636 +0.008687 +0.008667 +0.008687 +0.008669 +0.008642 +0.008705 +0.008774 +0.00876 +0.008775 +0.008746 +0.008718 +0.008767 +0.008833 +0.008844 +0.008884 +0.008866 +0.008838 +0.008884 +0.008939 +0.008926 +0.008929 +0.008867 +0.008811 +0.008806 +0.008826 +0.008779 +0.008753 +0.008685 +0.008613 +0.008629 +0.008661 +0.008625 +0.008613 +0.008561 +0.008513 +0.008534 +0.008568 +0.008544 +0.008539 +0.008494 +0.008453 +0.008477 +0.008533 +0.008518 +0.008523 +0.008489 +0.008466 +0.008507 +0.008563 +0.008556 +0.008574 +0.008555 +0.008531 +0.00858 +0.00865 +0.008646 +0.008669 +0.008612 +0.008598 +0.00044 +0.008661 +0.008734 +0.00873 +0.00875 +0.00872 +0.008686 +0.008746 +0.008802 +0.00881 +0.008833 +0.008808 +0.008779 +0.008839 +0.008896 +0.008894 +0.00891 +0.008891 +0.008864 +0.008918 +0.009002 +0.008995 +0.009025 +0.008992 +0.008977 +0.00904 +0.009117 +0.009111 +0.009126 +0.009 +0.008943 +0.008962 +0.008999 +0.008946 +0.008882 +0.008771 +0.008716 +0.008747 +0.008751 +0.008688 +0.008687 +0.008582 +0.008534 +0.008551 +0.008584 +0.008543 +0.008537 +0.008483 +0.008428 +0.008425 +0.008476 +0.008452 +0.008461 +0.00844 +0.0084 +0.008436 +0.008513 +0.008482 +0.008501 +0.008482 +0.008455 +0.008528 +0.008583 +0.008554 +0.008556 +0.008516 +0.008518 +0.008548 +0.008629 +0.008623 +0.008636 +0.000441 +0.008629 +0.008591 +0.008649 +0.008728 +0.008717 +0.008735 +0.008708 +0.008686 +0.008726 +0.008787 +0.008765 +0.008788 +0.008767 +0.008737 +0.008791 +0.008855 +0.008847 +0.008866 +0.008843 +0.008826 +0.00891 +0.008982 +0.008983 +0.008983 +0.008952 +0.008908 +0.008916 +0.008946 +0.008895 +0.008862 +0.008771 +0.008688 +0.008682 +0.008701 +0.008638 +0.008593 +0.008529 +0.008455 +0.008452 +0.008491 +0.008444 +0.008417 +0.008361 +0.0083 +0.008309 +0.008359 +0.008332 +0.008326 +0.008286 +0.008239 +0.008269 +0.008329 +0.008319 +0.008318 +0.008291 +0.008255 +0.008297 +0.008374 +0.008367 +0.008378 +0.008365 +0.008325 +0.008374 +0.008441 +0.008434 +0.008477 +0.00842 +0.008412 +0.000442 +0.008463 +0.008525 +0.008518 +0.008537 +0.008514 +0.008487 +0.008542 +0.008612 +0.008607 +0.008622 +0.008599 +0.00857 +0.008623 +0.008692 +0.008689 +0.008707 +0.008678 +0.008658 +0.008716 +0.008792 +0.008783 +0.008813 +0.008793 +0.00876 +0.008825 +0.008893 +0.008837 +0.008738 +0.00868 +0.00861 +0.008647 +0.008676 +0.008586 +0.008542 +0.008487 +0.008422 +0.008412 +0.008457 +0.008405 +0.008393 +0.008327 +0.008248 +0.00827 +0.008293 +0.008274 +0.008262 +0.008245 +0.008194 +0.008244 +0.008289 +0.008259 +0.008253 +0.008203 +0.008189 +0.008235 +0.008289 +0.008276 +0.008285 +0.008273 +0.008241 +0.008302 +0.008372 +0.008343 +0.008371 +0.008357 +0.00832 +0.008356 +0.008418 +0.000443 +0.008392 +0.008423 +0.008404 +0.008383 +0.008433 +0.008507 +0.008495 +0.008522 +0.008496 +0.008474 +0.008524 +0.008596 +0.008581 +0.008605 +0.008572 +0.008552 +0.008595 +0.008669 +0.00865 +0.008672 +0.00865 +0.008644 +0.008693 +0.008777 +0.008757 +0.008768 +0.008731 +0.008701 +0.008701 +0.008753 +0.008684 +0.008658 +0.008587 +0.008512 +0.008502 +0.008548 +0.008488 +0.008471 +0.008413 +0.008366 +0.00835 +0.008406 +0.008366 +0.008368 +0.008304 +0.00825 +0.008268 +0.00833 +0.008293 +0.008296 +0.008261 +0.008228 +0.00825 +0.008326 +0.008297 +0.008313 +0.008287 +0.008257 +0.008296 +0.008379 +0.008363 +0.008387 +0.008356 +0.008329 +0.008381 +0.008451 +0.008463 +0.008449 +0.000444 +0.008434 +0.008426 +0.008453 +0.008541 +0.00852 +0.008555 +0.008517 +0.008511 +0.008533 +0.008623 +0.008603 +0.008643 +0.008599 +0.008592 +0.008617 +0.008714 +0.008686 +0.008716 +0.008684 +0.008673 +0.008727 +0.008809 +0.008788 +0.008833 +0.008794 +0.008774 +0.00881 +0.008812 +0.008723 +0.00872 +0.008617 +0.008575 +0.008528 +0.008559 +0.008487 +0.008506 +0.008432 +0.008397 +0.008416 +0.00843 +0.008366 +0.008358 +0.008319 +0.008271 +0.008259 +0.0083 +0.00826 +0.008275 +0.008239 +0.008218 +0.008242 +0.00832 +0.008269 +0.008302 +0.008228 +0.008214 +0.00823 +0.008298 +0.008267 +0.008297 +0.008271 +0.008255 +0.008298 +0.008383 +0.008349 +0.008397 +0.008359 +0.008344 +0.008405 +0.008466 +0.000445 +0.008441 +0.00848 +0.008451 +0.008444 +0.008473 +0.008561 +0.008539 +0.008573 +0.00853 +0.008496 +0.008512 +0.008588 +0.008564 +0.00859 +0.00856 +0.008555 +0.008582 +0.008693 +0.008698 +0.008733 +0.00869 +0.008677 +0.00871 +0.008786 +0.00876 +0.008771 +0.008698 +0.008666 +0.008653 +0.008685 +0.008614 +0.008596 +0.008504 +0.008455 +0.008449 +0.008489 +0.008434 +0.008436 +0.008361 +0.008325 +0.008326 +0.008378 +0.008337 +0.008345 +0.008279 +0.008253 +0.008265 +0.008325 +0.008301 +0.00832 +0.008273 +0.008261 +0.008271 +0.008353 +0.008331 +0.008357 +0.008315 +0.008312 +0.008341 +0.008421 +0.008404 +0.008429 +0.00842 +0.008373 +0.008423 +0.008495 +0.000446 +0.008483 +0.008519 +0.008477 +0.008472 +0.008506 +0.00858 +0.008562 +0.008601 +0.008563 +0.00855 +0.008591 +0.008669 +0.008652 +0.008686 +0.008647 +0.008634 +0.008667 +0.008754 +0.008735 +0.008769 +0.008741 +0.008726 +0.008779 +0.008866 +0.008838 +0.008875 +0.008831 +0.008804 +0.008777 +0.008778 +0.008703 +0.008701 +0.008653 +0.008599 +0.008553 +0.008573 +0.008513 +0.008508 +0.008469 +0.008425 +0.008384 +0.008395 +0.008331 +0.008358 +0.008299 +0.008273 +0.008287 +0.008356 +0.008313 +0.008326 +0.008295 +0.008217 +0.008234 +0.0083 +0.008266 +0.008309 +0.008263 +0.008258 +0.008293 +0.008365 +0.008348 +0.008375 +0.008347 +0.008334 +0.008377 +0.008465 +0.008442 +0.008464 +0.008442 +0.000447 +0.008426 +0.008467 +0.008556 +0.008524 +0.008547 +0.00849 +0.008484 +0.008525 +0.008589 +0.008569 +0.008599 +0.008569 +0.008552 +0.008601 +0.00867 +0.008654 +0.008674 +0.008645 +0.008626 +0.00867 +0.008749 +0.008765 +0.008798 +0.008761 +0.008745 +0.008772 +0.008824 +0.008781 +0.008756 +0.008669 +0.008617 +0.008611 +0.008629 +0.008563 +0.008546 +0.00847 +0.008415 +0.008405 +0.008448 +0.008412 +0.008402 +0.008336 +0.008296 +0.00831 +0.008345 +0.008321 +0.008316 +0.008261 +0.008233 +0.008256 +0.008323 +0.008301 +0.008306 +0.008269 +0.008244 +0.008274 +0.008347 +0.008339 +0.00836 +0.008328 +0.008307 +0.008345 +0.008428 +0.008414 +0.00846 +0.008394 +0.008384 +0.000448 +0.008427 +0.008508 +0.0085 +0.008518 +0.008501 +0.008469 +0.00852 +0.008582 +0.008576 +0.0086 +0.008581 +0.008557 +0.008607 +0.008678 +0.00867 +0.008685 +0.008663 +0.008633 +0.008684 +0.008761 +0.008754 +0.008787 +0.008752 +0.008739 +0.00881 +0.008872 +0.008858 +0.008856 +0.008746 +0.008689 +0.008721 +0.008743 +0.008678 +0.008616 +0.008532 +0.008463 +0.008487 +0.008528 +0.008477 +0.008406 +0.008366 +0.008287 +0.008318 +0.00835 +0.008303 +0.008293 +0.008251 +0.008174 +0.008196 +0.008238 +0.008206 +0.008219 +0.008184 +0.008156 +0.008201 +0.008256 +0.008238 +0.008252 +0.008229 +0.008189 +0.008196 +0.008265 +0.00824 +0.008261 +0.008257 +0.00822 +0.008282 +0.008353 +0.008344 +0.008362 +0.008352 +0.008319 +0.008375 +0.000449 +0.008447 +0.008426 +0.008462 +0.008428 +0.008414 +0.008462 +0.008542 +0.008528 +0.008549 +0.008524 +0.008502 +0.008542 +0.008619 +0.008578 +0.008604 +0.008577 +0.008558 +0.008592 +0.008654 +0.008642 +0.008659 +0.00864 +0.008628 +0.008685 +0.008758 +0.008701 +0.00867 +0.008588 +0.008501 +0.0085 +0.008537 +0.008481 +0.00845 +0.008385 +0.008319 +0.008324 +0.008363 +0.008316 +0.008306 +0.008244 +0.008198 +0.008203 +0.008262 +0.00822 +0.008213 +0.008178 +0.008139 +0.008167 +0.008232 +0.008216 +0.008216 +0.00819 +0.008157 +0.008194 +0.00828 +0.008255 +0.008281 +0.008253 +0.008229 +0.008273 +0.008349 +0.008335 +0.008366 +0.008344 +0.008296 +0.00045 +0.008348 +0.008432 +0.008421 +0.008449 +0.008407 +0.008392 +0.008427 +0.008508 +0.008495 +0.008531 +0.008492 +0.008484 +0.008524 +0.008607 +0.008578 +0.008618 +0.008575 +0.008565 +0.008617 +0.008699 +0.00869 +0.008721 +0.00869 +0.008667 +0.008619 +0.008662 +0.008591 +0.008592 +0.008529 +0.008478 +0.008497 +0.008507 +0.008363 +0.008369 +0.008305 +0.008275 +0.008268 +0.008292 +0.00823 +0.008215 +0.008174 +0.008115 +0.008108 +0.008151 +0.008115 +0.008121 +0.008092 +0.008061 +0.008099 +0.008165 +0.008135 +0.008156 +0.008121 +0.008109 +0.008126 +0.008192 +0.008138 +0.008174 +0.008134 +0.008131 +0.008177 +0.00824 +0.008228 +0.00826 +0.008221 +0.008224 +0.008261 +0.008343 +0.00832 +0.000451 +0.008337 +0.00831 +0.0083 +0.008333 +0.008406 +0.008377 +0.008416 +0.008373 +0.00837 +0.008409 +0.00849 +0.00845 +0.008485 +0.008437 +0.008427 +0.008458 +0.008544 +0.00851 +0.008547 +0.008492 +0.008502 +0.008559 +0.008666 +0.00864 +0.008665 +0.008613 +0.008586 +0.008591 +0.008647 +0.008585 +0.00859 +0.008496 +0.00844 +0.008435 +0.008492 +0.008426 +0.008407 +0.008329 +0.008277 +0.008276 +0.008337 +0.008284 +0.008278 +0.008217 +0.008171 +0.008177 +0.008239 +0.008201 +0.008216 +0.008165 +0.008135 +0.008153 +0.00823 +0.008205 +0.00823 +0.008191 +0.008168 +0.0082 +0.008285 +0.008265 +0.008299 +0.008266 +0.008245 +0.008284 +0.008356 +0.008351 +0.008361 +0.000452 +0.008346 +0.008325 +0.008359 +0.008449 +0.008421 +0.008451 +0.008416 +0.008403 +0.008443 +0.008528 +0.008505 +0.00854 +0.008499 +0.008493 +0.008528 +0.008612 +0.008585 +0.008628 +0.008583 +0.008578 +0.00862 +0.008711 +0.008685 +0.008729 +0.008694 +0.008689 +0.008729 +0.008743 +0.008647 +0.00865 +0.008565 +0.008499 +0.008468 +0.008504 +0.008444 +0.008451 +0.008384 +0.008298 +0.008287 +0.008335 +0.008271 +0.008294 +0.008231 +0.008214 +0.008215 +0.008229 +0.008189 +0.008195 +0.008158 +0.008143 +0.008174 +0.00825 +0.008205 +0.0082 +0.008149 +0.008148 +0.008179 +0.00827 +0.008228 +0.008262 +0.008223 +0.008215 +0.008266 +0.008344 +0.008302 +0.008357 +0.008302 +0.008278 +0.000453 +0.008308 +0.008385 +0.008356 +0.008384 +0.008356 +0.008349 +0.0084 +0.008469 +0.008457 +0.008485 +0.008453 +0.008437 +0.008491 +0.008554 +0.008543 +0.008566 +0.008536 +0.008512 +0.008556 +0.008628 +0.008628 +0.008656 +0.008634 +0.008602 +0.008656 +0.008721 +0.00871 +0.008736 +0.00868 +0.008636 +0.008636 +0.008662 +0.008608 +0.008584 +0.008496 +0.008432 +0.008434 +0.008461 +0.008405 +0.008399 +0.008331 +0.008277 +0.008295 +0.008327 +0.008298 +0.008294 +0.008234 +0.008192 +0.008222 +0.008263 +0.008248 +0.00826 +0.008213 +0.008182 +0.008217 +0.008282 +0.008269 +0.008292 +0.008252 +0.008235 +0.008275 +0.008353 +0.008335 +0.008363 +0.008331 +0.008329 +0.008341 +0.008421 +0.000454 +0.008421 +0.008446 +0.00842 +0.008387 +0.008444 +0.008507 +0.0085 +0.008516 +0.008498 +0.008473 +0.008529 +0.008584 +0.008585 +0.008603 +0.008585 +0.008556 +0.008607 +0.008672 +0.008676 +0.008688 +0.008668 +0.008648 +0.00871 +0.008776 +0.008778 +0.008798 +0.008774 +0.008756 +0.008781 +0.008754 +0.008706 +0.008692 +0.008648 +0.008591 +0.00856 +0.008531 +0.008477 +0.008472 +0.008431 +0.00837 +0.008397 +0.008411 +0.008333 +0.008343 +0.008292 +0.008224 +0.008233 +0.008267 +0.008242 +0.008246 +0.008213 +0.008182 +0.008221 +0.008285 +0.00825 +0.008278 +0.008246 +0.008214 +0.008221 +0.008259 +0.008248 +0.008264 +0.008256 +0.008228 +0.008285 +0.008357 +0.008346 +0.008364 +0.008352 +0.00832 +0.008374 +0.008452 +0.008436 +0.000455 +0.008455 +0.008434 +0.008414 +0.00847 +0.008538 +0.008529 +0.008549 +0.008525 +0.008502 +0.008557 +0.008623 +0.008608 +0.008617 +0.008594 +0.008562 +0.008607 +0.008666 +0.008653 +0.008662 +0.008639 +0.008618 +0.008671 +0.008761 +0.00877 +0.008762 +0.008704 +0.008639 +0.008641 +0.008655 +0.008628 +0.008592 +0.008518 +0.008458 +0.008469 +0.008496 +0.008463 +0.008446 +0.008391 +0.008338 +0.008358 +0.008402 +0.008378 +0.008357 +0.008309 +0.008268 +0.008302 +0.008347 +0.008334 +0.008338 +0.008299 +0.008263 +0.008308 +0.008367 +0.008372 +0.008368 +0.008343 +0.008326 +0.008372 +0.008433 +0.008436 +0.008449 +0.00843 +0.008415 +0.008433 +0.008517 +0.000456 +0.008525 +0.00853 +0.008504 +0.008482 +0.008533 +0.008601 +0.008598 +0.008615 +0.008595 +0.008562 +0.008617 +0.008688 +0.008684 +0.008702 +0.008677 +0.008647 +0.008703 +0.008774 +0.008764 +0.008796 +0.00876 +0.008749 +0.008802 +0.008881 +0.008876 +0.008894 +0.008872 +0.008832 +0.008842 +0.008813 +0.008755 +0.008744 +0.008703 +0.008604 +0.008574 +0.008601 +0.008568 +0.008558 +0.008503 +0.008463 +0.008429 +0.008442 +0.008407 +0.008404 +0.008381 +0.008317 +0.008363 +0.008396 +0.008377 +0.008328 +0.0083 +0.008262 +0.008308 +0.00838 +0.008342 +0.008362 +0.008329 +0.008304 +0.008322 +0.008369 +0.008367 +0.00837 +0.008365 +0.00834 +0.00839 +0.00846 +0.008455 +0.008471 +0.008457 +0.008434 +0.008485 +0.008556 +0.000457 +0.00855 +0.008567 +0.008538 +0.00852 +0.008572 +0.008648 +0.008636 +0.008661 +0.008627 +0.008611 +0.008659 +0.008732 +0.008712 +0.008722 +0.008696 +0.008671 +0.008711 +0.008782 +0.008752 +0.008783 +0.008757 +0.008733 +0.008797 +0.008894 +0.008861 +0.008848 +0.008781 +0.008715 +0.008719 +0.008761 +0.008691 +0.008666 +0.008602 +0.008551 +0.008542 +0.008587 +0.008551 +0.008543 +0.008493 +0.008446 +0.008466 +0.008525 +0.008487 +0.008485 +0.008443 +0.008408 +0.008431 +0.008505 +0.00848 +0.008487 +0.008454 +0.008427 +0.008467 +0.008544 +0.008527 +0.008549 +0.008524 +0.008495 +0.008543 +0.008621 +0.008607 +0.008652 +0.008586 +0.008575 +0.000458 +0.008632 +0.008699 +0.0087 +0.008717 +0.008689 +0.008658 +0.008709 +0.008782 +0.008784 +0.008799 +0.008777 +0.008754 +0.008799 +0.008872 +0.008864 +0.00888 +0.008861 +0.008827 +0.008883 +0.008959 +0.008954 +0.008987 +0.008959 +0.008929 +0.009008 +0.009075 +0.009064 +0.009051 +0.008923 +0.008859 +0.00886 +0.008912 +0.008845 +0.008777 +0.008714 +0.008666 +0.008678 +0.008723 +0.008675 +0.008632 +0.008575 +0.008529 +0.008577 +0.00859 +0.008556 +0.008567 +0.008526 +0.008487 +0.008478 +0.008541 +0.008503 +0.008527 +0.008496 +0.008471 +0.008518 +0.008585 +0.008563 +0.008594 +0.00856 +0.008545 +0.008595 +0.008659 +0.008653 +0.008667 +0.008634 +0.008622 +0.008675 +0.000459 +0.008746 +0.008746 +0.008762 +0.008739 +0.008708 +0.008768 +0.008842 +0.008827 +0.00885 +0.008832 +0.008803 +0.008827 +0.008878 +0.008854 +0.008873 +0.008854 +0.008835 +0.008884 +0.008953 +0.008979 +0.009017 +0.009001 +0.008966 +0.008996 +0.009058 +0.009007 +0.008977 +0.008905 +0.008832 +0.008856 +0.008897 +0.008842 +0.008807 +0.008753 +0.008677 +0.008701 +0.008742 +0.008696 +0.008681 +0.008636 +0.00858 +0.008588 +0.008634 +0.008605 +0.008595 +0.008559 +0.008499 +0.008534 +0.008596 +0.008574 +0.008573 +0.008543 +0.008494 +0.008538 +0.008613 +0.008601 +0.008608 +0.00858 +0.008553 +0.008603 +0.00868 +0.008671 +0.008687 +0.008666 +0.00863 +0.008686 +0.008766 +0.00046 +0.008751 +0.008779 +0.008739 +0.008722 +0.008773 +0.008855 +0.008835 +0.008863 +0.008833 +0.008817 +0.008857 +0.008934 +0.008923 +0.008951 +0.008922 +0.008898 +0.008954 +0.009029 +0.009015 +0.009054 +0.009008 +0.008999 +0.009044 +0.009143 +0.009125 +0.009158 +0.009138 +0.009111 +0.009081 +0.0091 +0.009041 +0.009051 +0.008987 +0.008934 +0.008949 +0.008988 +0.008836 +0.008839 +0.008789 +0.008732 +0.008747 +0.008774 +0.008737 +0.00875 +0.008685 +0.00863 +0.008625 +0.008694 +0.008645 +0.008667 +0.00863 +0.008601 +0.008649 +0.00871 +0.008685 +0.008695 +0.008672 +0.008653 +0.00866 +0.008721 +0.008687 +0.008709 +0.008693 +0.00867 +0.008729 +0.008798 +0.008781 +0.008813 +0.008783 +0.008771 +0.008823 +0.008906 +0.000461 +0.008871 +0.008904 +0.008881 +0.008852 +0.008923 +0.008997 +0.008979 +0.009001 +0.008976 +0.008946 +0.009002 +0.009069 +0.00904 +0.009053 +0.009026 +0.008999 +0.009044 +0.009106 +0.009109 +0.009132 +0.009131 +0.009108 +0.009126 +0.009148 +0.00909 +0.009036 +0.00896 +0.008899 +0.008886 +0.0089 +0.008847 +0.008822 +0.00875 +0.008687 +0.008699 +0.008723 +0.008694 +0.008671 +0.008601 +0.008563 +0.008578 +0.008618 +0.008589 +0.00859 +0.008551 +0.008522 +0.008552 +0.008607 +0.008595 +0.008582 +0.00856 +0.008545 +0.008599 +0.008663 +0.00866 +0.008669 +0.008641 +0.008613 +0.008656 +0.008731 +0.008712 +0.008736 +0.008734 +0.000462 +0.008697 +0.008752 +0.008824 +0.008818 +0.008834 +0.008802 +0.008777 +0.00883 +0.008915 +0.008904 +0.008925 +0.008891 +0.008871 +0.008916 +0.008992 +0.008982 +0.009013 +0.008976 +0.008967 +0.009012 +0.009099 +0.009083 +0.009128 +0.00909 +0.009075 +0.009135 +0.009208 +0.009142 +0.00904 +0.00898 +0.008928 +0.008952 +0.008988 +0.00889 +0.008803 +0.008758 +0.008694 +0.008717 +0.008752 +0.008675 +0.008647 +0.008576 +0.008533 +0.008545 +0.008569 +0.008529 +0.008527 +0.00849 +0.008453 +0.00849 +0.008547 +0.008485 +0.00851 +0.008458 +0.00843 +0.008447 +0.008502 +0.008489 +0.008499 +0.008474 +0.008463 +0.008503 +0.008577 +0.00856 +0.008581 +0.008557 +0.008543 +0.008595 +0.008664 +0.008663 +0.008678 +0.000463 +0.008646 +0.008638 +0.008677 +0.008774 +0.008744 +0.008783 +0.008735 +0.008712 +0.008715 +0.008799 +0.00877 +0.008805 +0.008767 +0.00876 +0.008794 +0.008883 +0.00888 +0.008937 +0.008904 +0.008891 +0.008912 +0.009013 +0.008988 +0.009006 +0.008955 +0.008925 +0.008932 +0.008988 +0.008906 +0.008879 +0.008792 +0.008728 +0.008703 +0.008744 +0.008671 +0.008664 +0.008591 +0.008542 +0.00854 +0.008597 +0.008541 +0.008532 +0.008474 +0.008431 +0.008432 +0.0085 +0.008453 +0.008462 +0.008417 +0.008389 +0.008405 +0.00848 +0.008451 +0.008469 +0.00843 +0.008411 +0.008438 +0.008525 +0.0085 +0.008527 +0.0085 +0.008484 +0.008522 +0.008602 +0.008582 +0.008631 +0.008573 +0.000464 +0.008565 +0.008609 +0.008685 +0.008669 +0.008697 +0.00867 +0.008653 +0.008694 +0.008771 +0.008764 +0.008779 +0.008753 +0.008739 +0.008784 +0.008859 +0.008856 +0.008877 +0.008837 +0.00883 +0.008878 +0.008965 +0.008943 +0.008984 +0.008953 +0.008937 +0.008999 +0.009058 +0.008966 +0.008954 +0.008896 +0.008832 +0.008807 +0.008848 +0.008769 +0.00877 +0.008684 +0.008599 +0.008603 +0.008633 +0.008594 +0.008603 +0.008537 +0.00847 +0.008448 +0.008499 +0.008444 +0.00847 +0.008421 +0.00839 +0.008424 +0.008495 +0.008459 +0.008469 +0.008449 +0.008379 +0.008392 +0.00846 +0.008426 +0.008463 +0.008426 +0.008408 +0.008464 +0.008537 +0.008519 +0.008555 +0.008523 +0.008502 +0.008555 +0.008644 +0.008614 +0.00863 +0.000465 +0.008618 +0.008595 +0.008651 +0.008714 +0.008717 +0.008729 +0.008711 +0.008685 +0.008748 +0.008822 +0.008797 +0.008778 +0.008735 +0.008704 +0.008762 +0.008841 +0.008832 +0.008849 +0.008823 +0.008822 +0.008898 +0.008977 +0.008968 +0.008985 +0.008943 +0.008899 +0.008917 +0.008938 +0.008876 +0.008845 +0.00878 +0.008694 +0.008682 +0.008695 +0.008649 +0.008622 +0.008549 +0.008479 +0.008498 +0.00853 +0.008495 +0.008481 +0.008427 +0.008369 +0.0084 +0.008435 +0.008422 +0.008422 +0.008381 +0.008342 +0.008383 +0.008444 +0.008432 +0.008439 +0.008404 +0.008379 +0.008431 +0.008499 +0.008498 +0.008514 +0.008482 +0.00846 +0.008502 +0.008573 +0.008567 +0.008596 +0.000466 +0.008561 +0.008548 +0.008587 +0.008665 +0.008647 +0.008675 +0.008646 +0.008625 +0.008669 +0.008749 +0.008738 +0.008764 +0.008733 +0.008709 +0.008758 +0.008832 +0.008819 +0.008851 +0.008819 +0.008802 +0.00886 +0.008938 +0.008932 +0.008952 +0.00893 +0.008918 +0.008981 +0.009055 +0.008952 +0.008941 +0.008887 +0.008827 +0.008802 +0.008845 +0.008783 +0.008768 +0.008672 +0.008605 +0.008611 +0.008652 +0.008604 +0.008613 +0.008529 +0.008471 +0.008468 +0.008516 +0.008469 +0.008491 +0.008436 +0.00842 +0.008447 +0.008521 +0.008472 +0.008468 +0.008419 +0.00839 +0.008449 +0.008508 +0.008473 +0.008499 +0.008457 +0.008455 +0.008495 +0.008573 +0.008572 +0.00857 +0.00855 +0.008519 +0.00854 +0.008616 +0.008598 +0.008621 +0.000467 +0.008607 +0.008595 +0.008643 +0.00871 +0.0087 +0.008734 +0.008695 +0.00868 +0.008731 +0.008817 +0.008787 +0.00882 +0.008783 +0.008764 +0.008794 +0.008881 +0.008854 +0.008884 +0.008842 +0.008838 +0.008886 +0.008992 +0.008962 +0.008975 +0.008914 +0.008877 +0.008856 +0.008917 +0.008833 +0.00881 +0.008727 +0.008659 +0.008631 +0.008673 +0.008616 +0.008595 +0.008528 +0.008473 +0.00847 +0.008529 +0.008477 +0.008469 +0.008409 +0.008369 +0.008375 +0.008444 +0.0084 +0.008412 +0.008364 +0.008344 +0.008349 +0.008434 +0.008403 +0.008423 +0.008383 +0.008364 +0.008396 +0.008482 +0.008458 +0.00849 +0.008455 +0.008437 +0.008481 +0.008558 +0.008562 +0.008553 +0.008536 +0.000468 +0.00852 +0.008558 +0.008646 +0.008624 +0.008656 +0.00862 +0.008616 +0.008637 +0.008727 +0.008709 +0.008745 +0.008702 +0.008691 +0.008731 +0.008817 +0.008796 +0.008825 +0.008793 +0.008778 +0.008829 +0.008908 +0.008902 +0.008929 +0.008894 +0.008893 +0.008945 +0.009016 +0.008897 +0.008864 +0.008794 +0.008749 +0.008725 +0.008741 +0.008673 +0.008679 +0.008596 +0.00853 +0.008513 +0.008548 +0.008495 +0.008509 +0.008449 +0.008421 +0.008376 +0.00843 +0.008365 +0.008399 +0.00835 +0.00833 +0.008358 +0.008418 +0.008389 +0.008403 +0.00837 +0.008325 +0.008313 +0.008398 +0.008353 +0.008393 +0.008359 +0.008344 +0.008394 +0.008467 +0.008446 +0.008488 +0.008445 +0.008442 +0.008483 +0.008568 +0.008541 +0.008571 +0.000469 +0.008546 +0.008516 +0.008579 +0.008653 +0.008633 +0.008656 +0.008643 +0.008617 +0.008669 +0.00875 +0.008722 +0.008734 +0.008686 +0.008656 +0.008704 +0.008778 +0.008749 +0.008773 +0.008749 +0.008729 +0.008766 +0.008864 +0.00888 +0.008913 +0.008852 +0.008804 +0.008807 +0.00884 +0.008767 +0.00874 +0.008684 +0.008594 +0.008596 +0.008638 +0.008578 +0.008566 +0.008504 +0.00845 +0.008456 +0.008517 +0.00847 +0.008468 +0.008422 +0.008367 +0.008389 +0.008453 +0.008423 +0.008435 +0.008397 +0.008364 +0.008395 +0.008472 +0.008449 +0.008463 +0.008433 +0.00841 +0.008451 +0.008533 +0.008514 +0.008546 +0.008511 +0.008489 +0.008534 +0.008612 +0.008596 +0.00047 +0.008633 +0.008586 +0.008578 +0.008615 +0.008699 +0.008681 +0.008718 +0.008672 +0.008663 +0.008699 +0.008784 +0.008768 +0.008801 +0.008763 +0.008751 +0.008787 +0.008867 +0.008845 +0.008886 +0.008839 +0.008843 +0.008878 +0.008977 +0.008951 +0.008992 +0.008957 +0.00895 +0.008994 +0.009073 +0.008976 +0.008941 +0.00887 +0.008825 +0.00881 +0.008817 +0.008735 +0.008759 +0.008676 +0.008598 +0.008585 +0.008625 +0.008586 +0.008583 +0.008533 +0.008497 +0.008474 +0.008502 +0.008456 +0.008469 +0.008435 +0.008399 +0.008439 +0.008502 +0.008458 +0.008488 +0.008392 +0.008382 +0.008396 +0.008463 +0.008437 +0.008463 +0.008419 +0.008414 +0.008448 +0.008532 +0.008517 +0.008539 +0.008503 +0.008504 +0.008541 +0.008619 +0.008607 +0.008618 +0.000471 +0.008584 +0.008565 +0.008587 +0.008664 +0.008631 +0.00868 +0.008637 +0.008638 +0.008677 +0.008759 +0.008736 +0.008771 +0.008726 +0.00872 +0.008753 +0.008839 +0.008817 +0.008866 +0.008835 +0.008824 +0.008856 +0.008942 +0.00892 +0.008957 +0.008916 +0.008907 +0.008921 +0.008977 +0.008927 +0.00892 +0.008827 +0.008766 +0.008736 +0.008775 +0.008708 +0.008679 +0.008603 +0.008563 +0.008541 +0.00858 +0.008537 +0.008543 +0.008456 +0.008426 +0.008422 +0.008483 +0.008442 +0.008441 +0.008385 +0.008366 +0.008378 +0.008458 +0.008411 +0.008442 +0.008391 +0.008385 +0.008403 +0.008486 +0.008471 +0.008498 +0.008456 +0.00845 +0.008479 +0.008573 +0.008544 +0.008586 +0.008542 +0.008528 +0.000472 +0.008566 +0.008645 +0.008632 +0.008663 +0.008627 +0.008608 +0.008654 +0.008736 +0.008714 +0.008747 +0.008712 +0.008692 +0.008737 +0.00882 +0.008812 +0.008824 +0.008805 +0.008788 +0.008832 +0.008921 +0.008905 +0.008935 +0.008918 +0.008897 +0.008953 +0.009014 +0.008917 +0.008891 +0.008846 +0.008778 +0.008752 +0.008786 +0.008722 +0.008713 +0.008646 +0.008587 +0.008546 +0.008576 +0.008544 +0.008537 +0.008496 +0.008441 +0.008466 +0.008501 +0.008451 +0.008448 +0.008385 +0.008346 +0.008375 +0.008419 +0.008395 +0.008407 +0.008376 +0.008353 +0.008385 +0.008476 +0.008427 +0.008452 +0.008431 +0.008394 +0.008419 +0.008481 +0.008452 +0.008498 +0.008466 +0.008447 +0.008508 +0.008584 +0.008555 +0.008586 +0.008556 +0.000473 +0.008543 +0.008593 +0.00868 +0.008654 +0.008686 +0.008647 +0.008636 +0.008679 +0.008772 +0.008732 +0.008768 +0.008724 +0.008712 +0.008746 +0.00883 +0.008795 +0.008826 +0.008785 +0.008777 +0.008805 +0.008921 +0.008912 +0.008946 +0.008891 +0.008852 +0.008859 +0.008904 +0.008824 +0.008825 +0.008733 +0.008665 +0.008651 +0.008696 +0.008621 +0.008616 +0.008541 +0.00849 +0.008488 +0.008545 +0.008497 +0.0085 +0.008437 +0.008393 +0.008397 +0.008466 +0.008421 +0.00844 +0.008391 +0.008361 +0.008383 +0.008455 +0.008425 +0.008453 +0.00841 +0.00839 +0.008422 +0.008508 +0.008484 +0.008519 +0.008479 +0.008464 +0.008504 +0.00859 +0.008565 +0.008611 +0.008557 +0.000474 +0.008544 +0.00859 +0.008669 +0.008653 +0.00868 +0.008652 +0.008631 +0.008676 +0.00875 +0.008742 +0.008771 +0.008725 +0.008713 +0.008761 +0.008837 +0.008818 +0.008854 +0.008818 +0.008804 +0.008857 +0.008936 +0.008921 +0.008956 +0.008928 +0.008917 +0.008966 +0.009042 +0.008957 +0.008885 +0.008821 +0.008765 +0.00879 +0.008785 +0.008709 +0.00867 +0.008579 +0.008534 +0.008532 +0.00857 +0.008515 +0.008498 +0.008423 +0.008365 +0.008382 +0.008419 +0.008374 +0.008381 +0.008345 +0.0083 +0.008335 +0.008366 +0.008339 +0.008347 +0.008314 +0.00829 +0.008291 +0.00836 +0.008328 +0.008351 +0.008332 +0.008305 +0.008362 +0.008429 +0.0084 +0.008434 +0.0084 +0.008384 +0.008443 +0.008525 +0.008501 +0.008517 +0.000475 +0.008493 +0.008482 +0.008518 +0.008612 +0.008582 +0.008614 +0.00858 +0.008563 +0.008593 +0.008653 +0.008616 +0.008653 +0.008612 +0.008607 +0.008645 +0.008727 +0.008705 +0.008747 +0.008729 +0.00873 +0.008763 +0.008854 +0.008817 +0.008858 +0.008792 +0.008769 +0.008791 +0.008842 +0.008768 +0.008761 +0.008672 +0.00861 +0.008602 +0.008646 +0.008574 +0.008568 +0.008491 +0.008444 +0.008448 +0.008503 +0.008446 +0.00846 +0.008391 +0.008352 +0.00836 +0.008423 +0.008378 +0.008408 +0.008347 +0.008324 +0.008353 +0.008423 +0.008388 +0.008421 +0.008377 +0.008362 +0.008402 +0.008479 +0.008458 +0.008496 +0.008452 +0.008447 +0.008473 +0.008571 +0.008534 +0.008578 +0.000476 +0.008534 +0.008523 +0.008565 +0.008643 +0.008625 +0.008653 +0.008623 +0.008605 +0.008648 +0.008726 +0.008715 +0.008738 +0.008705 +0.008686 +0.008736 +0.008804 +0.008798 +0.008819 +0.008792 +0.00878 +0.008823 +0.008912 +0.008894 +0.008932 +0.008898 +0.008881 +0.008947 +0.009034 +0.00901 +0.008948 +0.008888 +0.008838 +0.008872 +0.008916 +0.008855 +0.008848 +0.008725 +0.00865 +0.008648 +0.00869 +0.008628 +0.008621 +0.008573 +0.00852 +0.0085 +0.00852 +0.008464 +0.008477 +0.008429 +0.008394 +0.008424 +0.00848 +0.008454 +0.008404 +0.008377 +0.008325 +0.008382 +0.008447 +0.008415 +0.008442 +0.0084 +0.008398 +0.008442 +0.008517 +0.0085 +0.008513 +0.008494 +0.008468 +0.00852 +0.008589 +0.008575 +0.00859 +0.000477 +0.008568 +0.008541 +0.008583 +0.008645 +0.008623 +0.008649 +0.00863 +0.008606 +0.008665 +0.008732 +0.008717 +0.008734 +0.008711 +0.008692 +0.008735 +0.008803 +0.008799 +0.008838 +0.008826 +0.008794 +0.00885 +0.00891 +0.008909 +0.00891 +0.008869 +0.008834 +0.008852 +0.008879 +0.00883 +0.008791 +0.008716 +0.008644 +0.008629 +0.008652 +0.00861 +0.008574 +0.008511 +0.008456 +0.008464 +0.008502 +0.008468 +0.008448 +0.008394 +0.008348 +0.008367 +0.00841 +0.008395 +0.008389 +0.008346 +0.008316 +0.008346 +0.0084 +0.008395 +0.008404 +0.00837 +0.008348 +0.008387 +0.008453 +0.008458 +0.008467 +0.008445 +0.008419 +0.008466 +0.008542 +0.008543 +0.008543 +0.000478 +0.008515 +0.008507 +0.008547 +0.008621 +0.008612 +0.008639 +0.008606 +0.008585 +0.008629 +0.008707 +0.008694 +0.008723 +0.008689 +0.008669 +0.008714 +0.008794 +0.008783 +0.008807 +0.008773 +0.008764 +0.008806 +0.008885 +0.008878 +0.008906 +0.008878 +0.00887 +0.008924 +0.009003 +0.008985 +0.008951 +0.008845 +0.008797 +0.008823 +0.008869 +0.008786 +0.008722 +0.008648 +0.008598 +0.008593 +0.008615 +0.00856 +0.008557 +0.008482 +0.008404 +0.0084 +0.008452 +0.008406 +0.008405 +0.008368 +0.008328 +0.008361 +0.008374 +0.008338 +0.008349 +0.008311 +0.008294 +0.008327 +0.0084 +0.008357 +0.008379 +0.008333 +0.008304 +0.008336 +0.008398 +0.008377 +0.00841 +0.008373 +0.008362 +0.008411 +0.008483 +0.00847 +0.008503 +0.008479 +0.008447 +0.008495 +0.000479 +0.008583 +0.008565 +0.008594 +0.008557 +0.008549 +0.008588 +0.008676 +0.008659 +0.008691 +0.008655 +0.008645 +0.008684 +0.008766 +0.008736 +0.008761 +0.008718 +0.0087 +0.008733 +0.008819 +0.008778 +0.008825 +0.008775 +0.008769 +0.008821 +0.0089 +0.008852 +0.008843 +0.008744 +0.008689 +0.008689 +0.008725 +0.008652 +0.008646 +0.008561 +0.008511 +0.008507 +0.008561 +0.008511 +0.008513 +0.008431 +0.0084 +0.008407 +0.008462 +0.00842 +0.00843 +0.008368 +0.008342 +0.008372 +0.008439 +0.008411 +0.008433 +0.00838 +0.008365 +0.00839 +0.008472 +0.008454 +0.008487 +0.008443 +0.008431 +0.008462 +0.008547 +0.008539 +0.008563 +0.008543 +0.008499 +0.00048 +0.008543 +0.008632 +0.008613 +0.00865 +0.008608 +0.008592 +0.00863 +0.008718 +0.0087 +0.008735 +0.008696 +0.00868 +0.008717 +0.008799 +0.008779 +0.008812 +0.008776 +0.00877 +0.008807 +0.008905 +0.008885 +0.008923 +0.008883 +0.00888 +0.00893 +0.009022 +0.008994 +0.008929 +0.008862 +0.008827 +0.008844 +0.008896 +0.008833 +0.008819 +0.008691 +0.008652 +0.008629 +0.008672 +0.008616 +0.008632 +0.008555 +0.008511 +0.008459 +0.008506 +0.008463 +0.008467 +0.008426 +0.008393 +0.00842 +0.00849 +0.008429 +0.008449 +0.008369 +0.008353 +0.008383 +0.008453 +0.008417 +0.008444 +0.008396 +0.008398 +0.008421 +0.008514 +0.008474 +0.008496 +0.008458 +0.008438 +0.008474 +0.008573 +0.008533 +0.008571 +0.008537 +0.008534 +0.008575 +0.000481 +0.008642 +0.008627 +0.008656 +0.008616 +0.008613 +0.008669 +0.008749 +0.008711 +0.008749 +0.008702 +0.008689 +0.008713 +0.008785 +0.008751 +0.008785 +0.00875 +0.008737 +0.00877 +0.00887 +0.008885 +0.008926 +0.008889 +0.008867 +0.008894 +0.008967 +0.008915 +0.0089 +0.008818 +0.008762 +0.00876 +0.008796 +0.008723 +0.008713 +0.008634 +0.008581 +0.008575 +0.008641 +0.00857 +0.00857 +0.008511 +0.008465 +0.008467 +0.008533 +0.008493 +0.008494 +0.008444 +0.00841 +0.008433 +0.008515 +0.008476 +0.008492 +0.008452 +0.008428 +0.008452 +0.008543 +0.008517 +0.008546 +0.008506 +0.008493 +0.008525 +0.008615 +0.008594 +0.008635 +0.008586 +0.008573 +0.000482 +0.008614 +0.008694 +0.008686 +0.008709 +0.008674 +0.008658 +0.0087 +0.008776 +0.008769 +0.008801 +0.008766 +0.008743 +0.008791 +0.008865 +0.008851 +0.008882 +0.008849 +0.008825 +0.008886 +0.008956 +0.00895 +0.008978 +0.008957 +0.008941 +0.009 +0.009095 +0.009033 +0.008956 +0.008891 +0.008847 +0.008867 +0.00891 +0.00885 +0.008773 +0.00869 +0.008627 +0.008642 +0.008706 +0.008637 +0.00862 +0.008532 +0.008476 +0.008496 +0.008548 +0.008493 +0.008505 +0.008424 +0.008378 +0.008401 +0.008452 +0.008421 +0.008435 +0.00839 +0.008366 +0.008398 +0.008479 +0.008436 +0.008462 +0.008423 +0.008374 +0.008401 +0.008481 +0.008453 +0.008483 +0.008462 +0.008435 +0.008499 +0.008564 +0.008552 +0.00858 +0.008563 +0.008532 +0.008575 +0.000483 +0.008677 +0.008644 +0.008679 +0.008643 +0.00864 +0.008681 +0.008766 +0.008735 +0.008769 +0.008731 +0.008722 +0.008748 +0.008816 +0.008766 +0.008802 +0.008766 +0.008749 +0.008783 +0.008875 +0.008859 +0.008923 +0.008894 +0.008887 +0.008904 +0.008974 +0.008917 +0.0089 +0.00881 +0.008764 +0.008752 +0.008775 +0.008703 +0.008692 +0.00862 +0.008566 +0.008553 +0.008607 +0.008559 +0.008553 +0.008493 +0.008464 +0.008457 +0.00852 +0.008472 +0.008479 +0.008431 +0.00841 +0.008423 +0.008493 +0.008456 +0.00848 +0.008437 +0.008425 +0.00845 +0.00853 +0.008506 +0.008534 +0.008498 +0.008497 +0.008524 +0.008614 +0.008586 +0.00863 +0.008572 +0.000484 +0.008571 +0.008615 +0.008698 +0.008681 +0.008699 +0.008669 +0.008649 +0.008697 +0.008778 +0.008762 +0.008788 +0.008756 +0.008742 +0.008788 +0.008866 +0.00885 +0.008882 +0.008846 +0.008824 +0.008881 +0.00896 +0.008953 +0.008988 +0.008947 +0.008938 +0.008998 +0.009083 +0.009041 +0.008959 +0.008887 +0.008834 +0.008857 +0.008899 +0.008803 +0.008729 +0.008675 +0.008617 +0.008616 +0.008653 +0.008603 +0.008591 +0.008519 +0.00845 +0.008453 +0.008495 +0.008459 +0.008458 +0.008427 +0.008379 +0.008426 +0.008467 +0.008422 +0.008455 +0.008392 +0.008373 +0.008385 +0.008448 +0.008431 +0.008447 +0.008422 +0.008406 +0.008443 +0.00852 +0.008501 +0.008524 +0.00849 +0.008484 +0.00853 +0.008609 +0.0086 +0.008611 +0.000485 +0.008577 +0.008558 +0.008571 +0.008649 +0.008612 +0.008662 +0.00863 +0.008623 +0.008661 +0.008745 +0.008721 +0.008758 +0.008726 +0.008711 +0.008747 +0.008833 +0.008811 +0.008854 +0.008824 +0.008811 +0.008849 +0.008926 +0.008911 +0.008938 +0.008897 +0.008879 +0.008886 +0.008927 +0.008869 +0.008852 +0.008766 +0.008708 +0.008692 +0.008736 +0.008676 +0.008659 +0.008586 +0.008547 +0.008538 +0.008593 +0.008547 +0.008548 +0.008485 +0.008453 +0.008455 +0.008516 +0.008484 +0.008501 +0.008448 +0.008429 +0.008444 +0.008518 +0.008495 +0.008524 +0.008479 +0.008473 +0.008498 +0.008582 +0.008563 +0.008591 +0.008567 +0.008545 +0.008588 +0.008656 +0.008647 +0.000486 +0.008681 +0.008647 +0.008632 +0.008666 +0.008752 +0.00873 +0.008768 +0.00873 +0.008718 +0.008751 +0.008841 +0.008814 +0.00885 +0.008816 +0.008799 +0.008847 +0.008926 +0.008903 +0.008947 +0.008901 +0.008897 +0.008941 +0.00904 +0.009015 +0.009054 +0.00902 +0.008997 +0.008956 +0.00895 +0.008875 +0.008881 +0.008813 +0.008756 +0.008676 +0.008705 +0.008633 +0.00865 +0.008568 +0.008547 +0.008558 +0.008632 +0.00856 +0.008491 +0.00841 +0.008389 +0.008403 +0.00848 +0.008417 +0.008444 +0.008389 +0.008362 +0.008384 +0.008419 +0.008373 +0.008406 +0.008358 +0.008348 +0.008388 +0.008453 +0.008431 +0.008444 +0.008393 +0.008387 +0.008399 +0.008473 +0.008458 +0.008489 +0.008451 +0.008452 +0.00849 +0.008565 +0.008555 +0.00859 +0.008545 +0.000487 +0.008534 +0.008594 +0.008668 +0.008646 +0.008673 +0.008648 +0.008633 +0.008681 +0.008756 +0.008738 +0.008752 +0.00872 +0.008696 +0.00874 +0.008818 +0.008788 +0.008809 +0.008776 +0.008756 +0.008795 +0.008882 +0.008896 +0.008918 +0.008853 +0.008798 +0.008778 +0.008814 +0.008727 +0.008701 +0.008616 +0.00855 +0.00853 +0.008561 +0.008503 +0.008477 +0.008415 +0.008364 +0.008365 +0.008401 +0.008354 +0.008346 +0.008292 +0.008247 +0.008255 +0.008319 +0.008292 +0.008296 +0.008261 +0.008232 +0.008258 +0.008327 +0.008308 +0.008336 +0.008306 +0.008287 +0.008322 +0.008403 +0.008386 +0.008403 +0.008387 +0.008332 +0.008393 +0.008477 +0.008465 +0.000488 +0.008498 +0.008446 +0.008445 +0.008473 +0.008561 +0.008543 +0.008576 +0.008536 +0.008528 +0.008561 +0.008644 +0.008625 +0.008655 +0.008617 +0.008611 +0.00865 +0.00873 +0.008708 +0.00875 +0.008706 +0.008709 +0.008746 +0.008842 +0.008819 +0.008852 +0.008814 +0.008802 +0.008781 +0.008772 +0.008708 +0.008707 +0.008638 +0.008594 +0.008523 +0.008547 +0.008491 +0.008487 +0.008435 +0.008398 +0.008408 +0.008462 +0.008355 +0.008371 +0.008285 +0.008264 +0.008247 +0.008313 +0.008255 +0.008286 +0.008234 +0.008215 +0.008257 +0.008321 +0.008287 +0.008314 +0.008269 +0.008249 +0.008233 +0.008299 +0.008271 +0.008307 +0.008276 +0.008274 +0.008309 +0.008401 +0.008377 +0.00841 +0.008371 +0.008364 +0.0084 +0.008485 +0.008473 +0.000489 +0.008496 +0.008463 +0.008453 +0.008502 +0.008578 +0.008562 +0.008588 +0.008563 +0.008546 +0.008602 +0.008675 +0.008646 +0.008652 +0.008594 +0.008573 +0.008615 +0.008691 +0.008666 +0.008709 +0.008659 +0.008644 +0.008722 +0.008817 +0.008806 +0.008822 +0.008757 +0.008704 +0.008707 +0.008726 +0.008667 +0.008664 +0.008571 +0.008509 +0.008512 +0.008544 +0.008491 +0.008483 +0.008417 +0.008372 +0.008386 +0.008434 +0.008395 +0.008395 +0.008336 +0.008298 +0.008323 +0.008379 +0.008356 +0.008378 +0.008322 +0.008298 +0.008338 +0.008405 +0.008392 +0.00842 +0.008368 +0.008364 +0.008401 +0.008473 +0.008469 +0.008492 +0.008461 +0.008436 +0.008488 +0.008554 +0.00049 +0.008555 +0.008568 +0.008551 +0.008522 +0.008571 +0.008633 +0.008636 +0.008657 +0.008633 +0.008605 +0.008657 +0.008725 +0.008718 +0.008738 +0.008711 +0.008689 +0.008741 +0.008805 +0.008807 +0.008833 +0.008802 +0.008792 +0.008843 +0.008918 +0.00892 +0.008938 +0.008916 +0.008887 +0.008918 +0.008891 +0.008825 +0.008806 +0.008758 +0.008692 +0.008643 +0.008665 +0.008615 +0.008597 +0.008557 +0.0085 +0.008517 +0.008503 +0.008455 +0.008456 +0.008415 +0.008363 +0.008379 +0.008396 +0.008369 +0.008372 +0.008337 +0.008314 +0.008334 +0.008382 +0.008349 +0.008352 +0.008345 +0.008302 +0.008349 +0.008409 +0.008379 +0.008398 +0.008381 +0.008345 +0.008378 +0.00844 +0.008416 +0.008451 +0.008429 +0.008404 +0.008463 +0.008534 +0.00852 +0.008552 +0.008517 +0.000491 +0.008499 +0.008552 +0.008623 +0.008622 +0.008639 +0.008617 +0.008591 +0.008646 +0.008722 +0.008707 +0.008721 +0.008693 +0.008665 +0.00872 +0.00879 +0.008774 +0.00877 +0.008743 +0.00872 +0.008766 +0.008845 +0.008833 +0.008875 +0.008835 +0.008774 +0.008773 +0.008789 +0.00872 +0.008699 +0.00861 +0.008531 +0.008529 +0.008546 +0.00849 +0.008472 +0.00841 +0.008342 +0.008361 +0.008395 +0.008348 +0.008334 +0.008295 +0.008239 +0.008261 +0.008312 +0.008289 +0.00829 +0.008256 +0.008213 +0.008255 +0.008315 +0.008301 +0.008314 +0.008293 +0.008258 +0.00831 +0.008378 +0.00837 +0.008385 +0.008365 +0.008338 +0.008389 +0.00846 +0.008464 +0.008459 +0.000492 +0.008439 +0.008422 +0.008471 +0.008545 +0.008526 +0.008561 +0.008516 +0.008509 +0.008549 +0.008626 +0.008614 +0.00864 +0.008606 +0.008591 +0.008637 +0.008719 +0.008708 +0.008729 +0.008708 +0.008681 +0.008747 +0.008826 +0.008818 +0.008849 +0.00881 +0.00872 +0.008745 +0.008793 +0.008741 +0.00874 +0.008671 +0.008626 +0.008618 +0.008584 +0.0085 +0.008509 +0.008448 +0.008399 +0.008367 +0.008388 +0.00835 +0.00833 +0.008295 +0.008229 +0.008227 +0.008228 +0.008193 +0.008193 +0.008158 +0.008132 +0.008153 +0.008223 +0.008173 +0.008162 +0.008121 +0.008088 +0.008107 +0.008185 +0.008144 +0.008167 +0.008143 +0.008118 +0.008167 +0.008253 +0.008224 +0.008243 +0.008228 +0.008206 +0.008246 +0.008323 +0.008307 +0.008318 +0.008293 +0.000493 +0.008279 +0.008298 +0.008363 +0.008332 +0.008372 +0.008343 +0.008335 +0.008379 +0.00846 +0.008437 +0.008474 +0.008438 +0.008413 +0.008452 +0.008532 +0.008527 +0.008572 +0.008538 +0.008518 +0.008549 +0.008637 +0.008601 +0.008647 +0.008609 +0.00859 +0.008618 +0.008667 +0.008601 +0.008588 +0.008505 +0.008443 +0.008439 +0.008466 +0.008388 +0.008393 +0.008315 +0.008256 +0.008257 +0.008312 +0.008263 +0.008269 +0.008197 +0.008159 +0.008182 +0.00824 +0.008198 +0.008213 +0.00816 +0.008136 +0.008168 +0.008239 +0.008207 +0.008234 +0.008189 +0.008178 +0.008217 +0.008297 +0.008277 +0.008306 +0.008263 +0.00826 +0.008281 +0.008375 +0.008362 +0.008378 +0.000494 +0.008348 +0.008335 +0.008375 +0.008451 +0.008434 +0.00846 +0.008434 +0.008416 +0.008458 +0.008531 +0.008516 +0.008543 +0.008514 +0.008506 +0.008535 +0.008617 +0.008601 +0.008637 +0.008601 +0.008586 +0.00864 +0.008721 +0.008699 +0.008744 +0.008714 +0.008694 +0.00868 +0.008669 +0.008619 +0.008602 +0.00855 +0.008499 +0.008521 +0.008514 +0.008421 +0.008417 +0.008361 +0.008295 +0.008294 +0.008333 +0.008282 +0.008298 +0.00824 +0.008184 +0.008159 +0.00821 +0.008165 +0.008183 +0.008133 +0.008117 +0.00814 +0.00821 +0.008168 +0.00819 +0.008156 +0.008124 +0.00813 +0.008174 +0.008159 +0.008179 +0.008161 +0.008146 +0.008185 +0.008265 +0.008246 +0.008275 +0.00825 +0.008228 +0.008277 +0.008359 +0.008332 +0.008359 +0.000495 +0.008341 +0.008313 +0.008368 +0.008439 +0.008437 +0.008448 +0.008424 +0.0084 +0.008455 +0.008521 +0.00851 +0.008523 +0.008495 +0.008472 +0.008519 +0.008585 +0.008556 +0.008569 +0.008548 +0.008521 +0.008568 +0.008647 +0.008665 +0.008671 +0.00862 +0.00856 +0.008546 +0.008578 +0.008525 +0.008496 +0.008419 +0.008354 +0.008348 +0.008373 +0.008323 +0.008295 +0.008246 +0.008185 +0.008197 +0.008235 +0.008205 +0.008175 +0.008135 +0.008085 +0.008105 +0.008155 +0.008134 +0.008137 +0.008105 +0.008072 +0.008107 +0.008163 +0.00816 +0.008173 +0.008154 +0.008126 +0.008172 +0.008237 +0.008233 +0.008246 +0.008229 +0.008217 +0.008235 +0.008316 +0.008307 +0.000496 +0.008329 +0.008307 +0.008282 +0.008334 +0.008398 +0.008395 +0.008401 +0.008381 +0.008357 +0.008413 +0.008484 +0.008478 +0.008494 +0.008466 +0.008437 +0.008495 +0.00856 +0.008556 +0.008565 +0.008557 +0.008524 +0.008596 +0.008657 +0.008655 +0.008682 +0.008659 +0.008623 +0.008603 +0.00858 +0.008523 +0.008502 +0.008471 +0.008378 +0.008323 +0.00835 +0.008305 +0.008273 +0.008228 +0.008186 +0.008189 +0.008201 +0.008131 +0.008117 +0.008064 +0.008001 +0.008008 +0.00803 +0.007992 +0.007992 +0.007953 +0.007922 +0.007952 +0.008011 +0.007956 +0.007932 +0.007892 +0.007862 +0.00792 +0.007963 +0.007954 +0.007961 +0.007941 +0.007912 +0.007954 +0.007996 +0.007984 +0.008003 +0.007988 +0.007965 +0.008024 +0.008087 +0.008077 +0.008088 +0.008071 +0.008064 +0.000497 +0.008095 +0.008172 +0.008154 +0.008178 +0.008152 +0.008138 +0.008184 +0.008257 +0.008229 +0.008254 +0.008222 +0.008199 +0.008241 +0.008315 +0.008287 +0.008308 +0.008274 +0.008264 +0.008302 +0.008391 +0.008392 +0.008421 +0.008371 +0.008337 +0.008349 +0.008387 +0.008326 +0.008306 +0.008224 +0.008156 +0.008155 +0.008177 +0.008117 +0.008104 +0.008032 +0.007968 +0.007973 +0.008006 +0.007965 +0.007959 +0.00789 +0.007849 +0.007862 +0.007901 +0.00787 +0.007879 +0.007829 +0.007798 +0.007829 +0.007889 +0.007867 +0.007888 +0.007848 +0.007826 +0.007864 +0.007939 +0.007917 +0.00795 +0.007913 +0.0079 +0.007934 +0.00801 +0.007994 +0.008037 +0.007981 +0.007966 +0.000498 +0.008016 +0.008075 +0.008082 +0.008091 +0.00807 +0.00804 +0.008092 +0.008156 +0.008153 +0.008175 +0.008146 +0.008124 +0.008175 +0.008238 +0.008231 +0.008245 +0.00823 +0.008203 +0.008253 +0.008324 +0.008318 +0.00834 +0.00832 +0.008299 +0.008367 +0.008444 +0.008375 +0.008306 +0.008255 +0.008203 +0.008229 +0.008261 +0.008221 +0.008117 +0.008038 +0.007987 +0.008019 +0.008038 +0.007983 +0.007947 +0.007845 +0.007803 +0.007824 +0.007844 +0.007804 +0.007773 +0.007729 +0.007675 +0.007682 +0.00773 +0.00769 +0.007707 +0.007666 +0.007644 +0.007692 +0.007738 +0.007729 +0.007727 +0.007693 +0.007672 +0.007705 +0.007761 +0.007754 +0.007762 +0.007752 +0.007728 +0.00779 +0.007831 +0.007836 +0.007854 +0.007835 +0.007808 +0.000499 +0.00786 +0.007931 +0.007914 +0.007938 +0.007913 +0.007889 +0.007935 +0.008006 +0.007991 +0.008017 +0.007984 +0.007969 +0.008013 +0.008084 +0.008057 +0.008075 +0.008043 +0.008022 +0.008056 +0.008126 +0.008117 +0.008135 +0.008104 +0.008089 +0.008156 +0.008231 +0.008215 +0.008223 +0.008154 +0.00811 +0.008108 +0.008148 +0.008104 +0.008086 +0.008009 +0.007959 +0.007963 +0.007995 +0.007953 +0.007933 +0.007866 +0.007832 +0.007843 +0.007885 +0.007858 +0.007868 +0.007805 +0.007775 +0.007797 +0.007845 +0.007825 +0.007846 +0.007812 +0.007793 +0.007826 +0.007885 +0.007874 +0.007893 +0.007857 +0.007844 +0.007879 +0.007957 +0.007946 +0.007967 +0.007953 +0.007906 +0.007957 +0.0005 +0.008034 +0.008013 +0.008051 +0.008012 +0.007999 +0.008031 +0.008111 +0.008094 +0.008122 +0.008084 +0.008079 +0.008114 +0.008184 +0.008166 +0.008206 +0.008167 +0.008156 +0.008185 +0.008274 +0.008248 +0.008287 +0.008245 +0.008248 +0.008288 +0.008368 +0.008352 +0.008392 +0.008339 +0.008237 +0.008234 +0.008285 +0.008225 +0.008222 +0.008162 +0.008098 +0.008026 +0.008078 +0.008005 +0.008022 +0.007949 +0.007916 +0.007916 +0.007912 +0.007864 +0.007865 +0.007817 +0.007748 +0.007748 +0.007788 +0.007744 +0.007762 +0.007713 +0.007697 +0.00771 +0.0078 +0.007748 +0.007758 +0.007694 +0.007677 +0.007717 +0.007787 +0.007756 +0.007792 +0.007747 +0.007744 +0.00778 +0.007848 +0.007833 +0.007869 +0.007837 +0.007815 +0.007874 +0.007945 +0.000501 +0.007913 +0.00794 +0.00791 +0.007889 +0.007902 +0.007975 +0.007945 +0.007985 +0.007949 +0.00794 +0.007983 +0.008057 +0.008035 +0.008062 +0.008028 +0.008024 +0.008064 +0.008158 +0.008141 +0.008174 +0.00813 +0.008116 +0.008148 +0.008223 +0.008189 +0.008225 +0.008182 +0.008159 +0.008163 +0.008195 +0.008125 +0.008129 +0.008043 +0.00799 +0.007984 +0.008023 +0.007963 +0.007955 +0.007883 +0.007838 +0.007847 +0.007883 +0.00784 +0.007859 +0.007788 +0.007754 +0.007763 +0.00782 +0.007779 +0.007801 +0.007757 +0.007741 +0.007772 +0.007837 +0.007807 +0.007838 +0.007793 +0.007787 +0.00783 +0.007901 +0.007883 +0.007911 +0.007891 +0.00784 +0.007889 +0.007967 +0.000502 +0.007949 +0.007985 +0.007949 +0.00794 +0.007972 +0.008047 +0.00803 +0.008058 +0.00802 +0.008005 +0.008039 +0.008122 +0.008103 +0.008137 +0.008096 +0.008091 +0.008125 +0.008198 +0.008186 +0.008215 +0.008172 +0.008171 +0.008208 +0.008299 +0.00828 +0.008312 +0.008272 +0.008275 +0.008309 +0.008315 +0.008237 +0.008243 +0.008188 +0.008137 +0.008111 +0.008132 +0.008055 +0.00805 +0.007997 +0.007923 +0.007889 +0.007953 +0.007892 +0.007914 +0.007847 +0.007811 +0.007777 +0.007804 +0.007758 +0.007771 +0.007724 +0.0077 +0.00772 +0.007793 +0.007738 +0.007774 +0.007726 +0.007698 +0.007689 +0.007737 +0.007712 +0.00774 +0.007709 +0.007706 +0.007736 +0.007812 +0.007793 +0.007823 +0.007785 +0.007786 +0.007819 +0.007895 +0.007884 +0.007903 +0.007879 +0.000503 +0.007861 +0.007899 +0.007987 +0.007953 +0.007994 +0.00796 +0.007946 +0.007987 +0.008065 +0.008037 +0.008067 +0.00803 +0.008007 +0.008013 +0.008082 +0.00805 +0.008084 +0.008046 +0.008042 +0.008083 +0.00819 +0.008182 +0.00822 +0.008172 +0.008158 +0.008184 +0.008253 +0.008216 +0.008218 +0.008148 +0.008108 +0.008096 +0.008129 +0.008066 +0.008061 +0.007971 +0.007929 +0.007919 +0.007962 +0.007909 +0.007915 +0.007832 +0.007805 +0.007807 +0.007859 +0.007823 +0.007829 +0.007765 +0.007746 +0.007765 +0.007834 +0.007811 +0.007833 +0.007783 +0.007775 +0.007796 +0.007866 +0.007857 +0.007892 +0.007853 +0.007848 +0.007873 +0.007955 +0.007931 +0.00797 +0.007909 +0.000504 +0.007906 +0.007936 +0.008004 +0.008008 +0.008036 +0.008008 +0.007996 +0.008025 +0.008103 +0.008083 +0.008104 +0.008071 +0.008052 +0.008091 +0.00816 +0.008149 +0.008169 +0.008147 +0.008133 +0.008175 +0.008251 +0.008239 +0.008269 +0.008238 +0.008228 +0.008272 +0.008354 +0.008336 +0.008363 +0.008317 +0.008217 +0.008188 +0.008235 +0.008178 +0.008172 +0.008134 +0.008062 +0.008003 +0.00804 +0.008001 +0.007983 +0.007943 +0.007906 +0.007906 +0.00791 +0.007851 +0.007867 +0.007811 +0.007786 +0.007797 +0.007858 +0.007806 +0.007813 +0.007755 +0.007735 +0.007767 +0.007826 +0.007805 +0.007813 +0.007794 +0.007775 +0.007816 +0.007889 +0.007859 +0.007892 +0.007857 +0.007841 +0.007901 +0.007965 +0.007942 +0.007964 +0.000505 +0.007937 +0.007926 +0.007942 +0.008016 +0.007987 +0.008016 +0.007988 +0.007979 +0.008022 +0.008098 +0.008071 +0.008104 +0.008065 +0.00806 +0.008095 +0.008173 +0.008141 +0.008173 +0.008133 +0.008123 +0.008159 +0.008242 +0.008233 +0.008278 +0.00823 +0.008224 +0.008246 +0.008321 +0.008293 +0.008309 +0.008237 +0.008198 +0.008176 +0.00822 +0.008162 +0.008149 +0.00807 +0.008025 +0.008021 +0.00806 +0.008016 +0.008015 +0.007952 +0.007922 +0.007924 +0.007981 +0.007946 +0.007951 +0.007893 +0.007874 +0.007884 +0.007955 +0.007926 +0.00795 +0.007898 +0.00789 +0.007912 +0.007988 +0.007972 +0.008003 +0.007967 +0.007958 +0.007982 +0.008074 +0.008035 +0.008089 +0.008026 +0.008027 +0.000506 +0.008067 +0.008136 +0.008131 +0.008146 +0.008117 +0.008104 +0.008145 +0.008223 +0.008194 +0.008223 +0.008197 +0.00818 +0.008221 +0.008295 +0.008287 +0.0083 +0.008279 +0.00826 +0.008304 +0.008383 +0.008371 +0.00839 +0.008363 +0.00836 +0.008415 +0.00849 +0.008476 +0.00844 +0.008345 +0.008296 +0.00832 +0.008375 +0.008312 +0.008254 +0.00818 +0.008141 +0.008134 +0.008171 +0.008102 +0.008104 +0.007999 +0.007941 +0.007943 +0.007978 +0.007921 +0.00792 +0.007868 +0.007808 +0.007803 +0.007838 +0.0078 +0.007815 +0.007784 +0.00775 +0.007787 +0.007847 +0.007827 +0.007833 +0.007806 +0.007772 +0.007779 +0.00785 +0.007826 +0.007845 +0.007831 +0.007814 +0.007856 +0.007936 +0.007918 +0.007943 +0.007923 +0.007909 +0.007947 +0.008009 +0.000507 +0.008005 +0.008037 +0.007997 +0.007988 +0.008025 +0.008108 +0.008087 +0.008118 +0.008079 +0.008072 +0.008108 +0.008181 +0.008152 +0.00818 +0.00814 +0.008125 +0.008167 +0.00824 +0.008205 +0.008246 +0.008199 +0.008214 +0.008251 +0.008329 +0.008296 +0.008293 +0.00822 +0.008168 +0.008143 +0.008177 +0.008127 +0.008105 +0.008019 +0.007969 +0.007949 +0.008004 +0.007919 +0.007919 +0.007853 +0.007821 +0.007812 +0.007867 +0.007831 +0.007829 +0.007767 +0.007744 +0.007749 +0.007816 +0.007793 +0.00781 +0.007766 +0.007751 +0.007768 +0.007842 +0.007825 +0.007859 +0.007821 +0.007815 +0.007842 +0.007921 +0.007896 +0.007927 +0.007898 +0.00786 +0.0079 +0.000508 +0.007991 +0.007975 +0.008005 +0.007967 +0.007956 +0.007989 +0.008068 +0.008045 +0.008072 +0.008032 +0.008024 +0.008059 +0.008145 +0.008128 +0.008159 +0.008122 +0.00811 +0.008153 +0.008229 +0.008217 +0.008241 +0.008216 +0.008208 +0.00825 +0.008346 +0.008286 +0.008252 +0.008199 +0.008164 +0.00819 +0.008246 +0.008177 +0.008169 +0.008047 +0.007998 +0.007999 +0.008053 +0.007987 +0.007984 +0.007896 +0.007834 +0.007842 +0.007864 +0.007829 +0.007817 +0.00778 +0.007727 +0.007723 +0.007755 +0.007699 +0.007727 +0.00768 +0.00766 +0.007692 +0.007756 +0.007724 +0.007728 +0.007657 +0.007662 +0.007692 +0.007761 +0.007743 +0.00776 +0.007724 +0.007727 +0.007753 +0.007829 +0.007812 +0.007847 +0.007812 +0.007812 +0.007843 +0.007921 +0.000509 +0.007894 +0.007916 +0.00789 +0.007874 +0.007927 +0.007995 +0.007966 +0.007989 +0.007959 +0.007935 +0.00796 +0.008028 +0.008001 +0.008028 +0.008 +0.007982 +0.008022 +0.008096 +0.008099 +0.008144 +0.008112 +0.008094 +0.008133 +0.0082 +0.008187 +0.008201 +0.008167 +0.008133 +0.00815 +0.008181 +0.008115 +0.008102 +0.008045 +0.007966 +0.007973 +0.008002 +0.007947 +0.00793 +0.007882 +0.007813 +0.00783 +0.007874 +0.007828 +0.007831 +0.007784 +0.007745 +0.007751 +0.007808 +0.007775 +0.007789 +0.007754 +0.007726 +0.007762 +0.007823 +0.007804 +0.007832 +0.007804 +0.007785 +0.00783 +0.007902 +0.007875 +0.007906 +0.007868 +0.007841 +0.007899 +0.007962 +0.00051 +0.007964 +0.007971 +0.007949 +0.007925 +0.007975 +0.008037 +0.008029 +0.008047 +0.008027 +0.008004 +0.008054 +0.008115 +0.008111 +0.008129 +0.008103 +0.008078 +0.008136 +0.008196 +0.008186 +0.008208 +0.008184 +0.008171 +0.008226 +0.008296 +0.008291 +0.008306 +0.008282 +0.008209 +0.008211 +0.008242 +0.008207 +0.008203 +0.008138 +0.008085 +0.008115 +0.008105 +0.008018 +0.007999 +0.007924 +0.007879 +0.007877 +0.007902 +0.007855 +0.007834 +0.007799 +0.007711 +0.007728 +0.007741 +0.007723 +0.007722 +0.007676 +0.00765 +0.007679 +0.007729 +0.007696 +0.007679 +0.007661 +0.007625 +0.007668 +0.007735 +0.007708 +0.007727 +0.007717 +0.007683 +0.007736 +0.007804 +0.007784 +0.007793 +0.007786 +0.007766 +0.007808 +0.007865 +0.00784 +0.000511 +0.007873 +0.007844 +0.007829 +0.007875 +0.007943 +0.007921 +0.007943 +0.007921 +0.007898 +0.007943 +0.008016 +0.007991 +0.008014 +0.007986 +0.007964 +0.007995 +0.008064 +0.008044 +0.008065 +0.008033 +0.008028 +0.00808 +0.008171 +0.008164 +0.00817 +0.008125 +0.00809 +0.008104 +0.008153 +0.008087 +0.008074 +0.007997 +0.007942 +0.007947 +0.007972 +0.007925 +0.007904 +0.00784 +0.007774 +0.007782 +0.007823 +0.007787 +0.007766 +0.007724 +0.007665 +0.007693 +0.007743 +0.00771 +0.007721 +0.007677 +0.007647 +0.00768 +0.007741 +0.007724 +0.007742 +0.007704 +0.007679 +0.007723 +0.007791 +0.007779 +0.007807 +0.007772 +0.007752 +0.007801 +0.007849 +0.007848 +0.007884 +0.000512 +0.007836 +0.007832 +0.007862 +0.007937 +0.007922 +0.007956 +0.007917 +0.007904 +0.007935 +0.008018 +0.007993 +0.00803 +0.007991 +0.007982 +0.008015 +0.008096 +0.008077 +0.008102 +0.008065 +0.008055 +0.008097 +0.008181 +0.008167 +0.008193 +0.008166 +0.008162 +0.008205 +0.008266 +0.008167 +0.008171 +0.008099 +0.00807 +0.008038 +0.008065 +0.008012 +0.008004 +0.007906 +0.007863 +0.007845 +0.007879 +0.007814 +0.007842 +0.007768 +0.007735 +0.007692 +0.007732 +0.007677 +0.007691 +0.007638 +0.007623 +0.007631 +0.007698 +0.007664 +0.007674 +0.007652 +0.007601 +0.007608 +0.007672 +0.007639 +0.007676 +0.007646 +0.007631 +0.007673 +0.007742 +0.007721 +0.007753 +0.007718 +0.007707 +0.007751 +0.007827 +0.007802 +0.007834 +0.000513 +0.007806 +0.007792 +0.007821 +0.007904 +0.007882 +0.007911 +0.007885 +0.00786 +0.007899 +0.007981 +0.007959 +0.007984 +0.007957 +0.007937 +0.007981 +0.008037 +0.008016 +0.008031 +0.007999 +0.007978 +0.008023 +0.008093 +0.008072 +0.008096 +0.008075 +0.00807 +0.008115 +0.008152 +0.008108 +0.008091 +0.008014 +0.007949 +0.00796 +0.007988 +0.007939 +0.007925 +0.00786 +0.007804 +0.007811 +0.007863 +0.007807 +0.007817 +0.007761 +0.007715 +0.007739 +0.007799 +0.007754 +0.007765 +0.007728 +0.007694 +0.007726 +0.007785 +0.007775 +0.007787 +0.00776 +0.007734 +0.007775 +0.007841 +0.007827 +0.007865 +0.007823 +0.00781 +0.007845 +0.007927 +0.007883 +0.007924 +0.000514 +0.007912 +0.007876 +0.007926 +0.007983 +0.007988 +0.007997 +0.007969 +0.007943 +0.007995 +0.008062 +0.008063 +0.008078 +0.008057 +0.008017 +0.008072 +0.008135 +0.008136 +0.008151 +0.008124 +0.008105 +0.008155 +0.008228 +0.008217 +0.008245 +0.008219 +0.008194 +0.008258 +0.008321 +0.008257 +0.008191 +0.008142 +0.00809 +0.008106 +0.008128 +0.008077 +0.00803 +0.007963 +0.007908 +0.007945 +0.007962 +0.007918 +0.007887 +0.007826 +0.007789 +0.007792 +0.007835 +0.00779 +0.007794 +0.007759 +0.007711 +0.007747 +0.007772 +0.007754 +0.007763 +0.007735 +0.007713 +0.00775 +0.007821 +0.00779 +0.007812 +0.007797 +0.00775 +0.00779 +0.007834 +0.007826 +0.007848 +0.007828 +0.007815 +0.007863 +0.007927 +0.00793 +0.007941 +0.007918 +0.000515 +0.007895 +0.007943 +0.008014 +0.008002 +0.008021 +0.007994 +0.007977 +0.008025 +0.008092 +0.008079 +0.008108 +0.008065 +0.008054 +0.008098 +0.008165 +0.008141 +0.008158 +0.008128 +0.00811 +0.00815 +0.008244 +0.008231 +0.008256 +0.008212 +0.008173 +0.008196 +0.00824 +0.008183 +0.008166 +0.008102 +0.008038 +0.008043 +0.008081 +0.008025 +0.008017 +0.007961 +0.007893 +0.007911 +0.007959 +0.00792 +0.007921 +0.00787 +0.007833 +0.007844 +0.007904 +0.007873 +0.007885 +0.007841 +0.007814 +0.007842 +0.007913 +0.007897 +0.007909 +0.007884 +0.007862 +0.00791 +0.007966 +0.007958 +0.007983 +0.007945 +0.00795 +0.007966 +0.00804 +0.008036 +0.000516 +0.008059 +0.008033 +0.008004 +0.008059 +0.008128 +0.00811 +0.008129 +0.008102 +0.008076 +0.008133 +0.008197 +0.008199 +0.008213 +0.008186 +0.008162 +0.008215 +0.008278 +0.008277 +0.008284 +0.008264 +0.008244 +0.0083 +0.008373 +0.008369 +0.008378 +0.008369 +0.008346 +0.00837 +0.008351 +0.008291 +0.008282 +0.008234 +0.008168 +0.008198 +0.00819 +0.008096 +0.008085 +0.008049 +0.007958 +0.007961 +0.008 +0.007953 +0.007953 +0.007891 +0.007828 +0.007826 +0.007868 +0.007827 +0.007837 +0.007798 +0.007759 +0.007812 +0.007854 +0.007842 +0.007848 +0.007816 +0.007771 +0.007789 +0.007848 +0.007829 +0.007846 +0.007833 +0.007801 +0.007855 +0.007923 +0.007911 +0.007934 +0.007914 +0.007887 +0.007941 +0.008016 +0.007987 +0.008013 +0.000517 +0.007996 +0.007968 +0.008022 +0.008083 +0.008085 +0.0081 +0.008078 +0.008053 +0.008107 +0.008175 +0.00816 +0.008179 +0.008156 +0.008127 +0.008169 +0.008227 +0.008203 +0.008215 +0.00818 +0.00817 +0.008219 +0.008268 +0.008264 +0.008279 +0.008275 +0.008236 +0.008261 +0.008282 +0.008227 +0.008197 +0.00814 +0.008074 +0.008085 +0.008104 +0.008053 +0.008046 +0.007994 +0.007921 +0.007946 +0.00799 +0.007961 +0.007951 +0.007913 +0.007866 +0.007896 +0.007946 +0.007925 +0.007931 +0.007903 +0.007866 +0.007915 +0.007978 +0.007968 +0.007984 +0.00796 +0.007933 +0.00798 +0.008041 +0.008037 +0.008054 +0.008044 +0.008002 +0.008043 +0.008132 +0.000518 +0.008107 +0.008131 +0.008108 +0.008085 +0.008126 +0.008204 +0.008195 +0.008211 +0.008179 +0.008164 +0.008208 +0.008278 +0.008263 +0.008293 +0.008262 +0.00824 +0.008297 +0.008369 +0.008354 +0.008391 +0.008347 +0.008344 +0.008406 +0.008477 +0.008458 +0.008415 +0.008317 +0.00827 +0.00828 +0.008331 +0.008278 +0.008247 +0.008136 +0.008086 +0.008078 +0.008121 +0.008065 +0.008055 +0.007967 +0.007912 +0.007906 +0.00793 +0.007896 +0.007891 +0.00786 +0.007803 +0.007807 +0.007842 +0.007784 +0.007818 +0.00778 +0.007759 +0.007797 +0.007852 +0.007836 +0.007849 +0.007824 +0.00781 +0.007846 +0.007907 +0.007871 +0.007897 +0.007876 +0.007853 +0.00791 +0.007983 +0.007964 +0.007986 +0.007956 +0.000519 +0.007949 +0.00799 +0.008065 +0.008034 +0.008051 +0.008026 +0.008015 +0.008032 +0.008102 +0.008072 +0.008112 +0.008074 +0.008062 +0.008098 +0.008169 +0.008151 +0.008187 +0.008167 +0.008177 +0.008201 +0.008286 +0.008256 +0.008283 +0.008224 +0.008198 +0.008213 +0.008256 +0.008193 +0.008191 +0.008113 +0.008065 +0.008061 +0.008104 +0.008046 +0.008052 +0.007981 +0.007937 +0.007946 +0.008 +0.007951 +0.007967 +0.007905 +0.007876 +0.007889 +0.007949 +0.00791 +0.007932 +0.007881 +0.007862 +0.007895 +0.007964 +0.007933 +0.007968 +0.007928 +0.007915 +0.007953 +0.008025 +0.008005 +0.008034 +0.008008 +0.007983 +0.008024 +0.008104 +0.008081 +0.00052 +0.008111 +0.008079 +0.008069 +0.008101 +0.008179 +0.00816 +0.008192 +0.008157 +0.008145 +0.008179 +0.008259 +0.008237 +0.008273 +0.008233 +0.008224 +0.008268 +0.008352 +0.008326 +0.008366 +0.008323 +0.008328 +0.008366 +0.008455 +0.008432 +0.008435 +0.008305 +0.008274 +0.008269 +0.008327 +0.00828 +0.008264 +0.008148 +0.008099 +0.00809 +0.008128 +0.00807 +0.008083 +0.008008 +0.007984 +0.00797 +0.007968 +0.007912 +0.00792 +0.007872 +0.007845 +0.007853 +0.007894 +0.007837 +0.007867 +0.007809 +0.007786 +0.007781 +0.007838 +0.007809 +0.007836 +0.007799 +0.007788 +0.007819 +0.007901 +0.007864 +0.007901 +0.007866 +0.007853 +0.007901 +0.007979 +0.007947 +0.007996 +0.007943 +0.007936 +0.000521 +0.007994 +0.008058 +0.008025 +0.008066 +0.008032 +0.008004 +0.00802 +0.00808 +0.008063 +0.008084 +0.008067 +0.008047 +0.008092 +0.008172 +0.008141 +0.008178 +0.008171 +0.008163 +0.0082 +0.008278 +0.008255 +0.00827 +0.00823 +0.008186 +0.008196 +0.008245 +0.008208 +0.008188 +0.008126 +0.008071 +0.008081 +0.008121 +0.008065 +0.00806 +0.008011 +0.007959 +0.007968 +0.008019 +0.007979 +0.007974 +0.00793 +0.007886 +0.007898 +0.007953 +0.00792 +0.007931 +0.007891 +0.007859 +0.007889 +0.007955 +0.007931 +0.007939 +0.007921 +0.007896 +0.007943 +0.00801 +0.007996 +0.008023 +0.007994 +0.007964 +0.008012 +0.008074 +0.008073 +0.008072 +0.000522 +0.008059 +0.008053 +0.008088 +0.008166 +0.008143 +0.008174 +0.008136 +0.008124 +0.008155 +0.008235 +0.008209 +0.008245 +0.008209 +0.00821 +0.008237 +0.008315 +0.008301 +0.008334 +0.00829 +0.008285 +0.008327 +0.00841 +0.008399 +0.008428 +0.008392 +0.00838 +0.008369 +0.008358 +0.008287 +0.008289 +0.008227 +0.008186 +0.008135 +0.008148 +0.008077 +0.008077 +0.00801 +0.007983 +0.007987 +0.008049 +0.007975 +0.007919 +0.00785 +0.007832 +0.00784 +0.007924 +0.007843 +0.007875 +0.007802 +0.007764 +0.007788 +0.007841 +0.007815 +0.00783 +0.007795 +0.007783 +0.00781 +0.007891 +0.00786 +0.007891 +0.00786 +0.007844 +0.007895 +0.00796 +0.007936 +0.007976 +0.007927 +0.007934 +0.000523 +0.007971 +0.008023 +0.008005 +0.008028 +0.007997 +0.007988 +0.008023 +0.008076 +0.008057 +0.00808 +0.00806 +0.00804 +0.008094 +0.008166 +0.008144 +0.008171 +0.008125 +0.008108 +0.008148 +0.008228 +0.008222 +0.00827 +0.008235 +0.008219 +0.00825 +0.008308 +0.008289 +0.008272 +0.008219 +0.008181 +0.008176 +0.008198 +0.008157 +0.008143 +0.00807 +0.008025 +0.008025 +0.008061 +0.008009 +0.008007 +0.007952 +0.007909 +0.007916 +0.007964 +0.007931 +0.007928 +0.007877 +0.007846 +0.007864 +0.007922 +0.007896 +0.007915 +0.007878 +0.007861 +0.007887 +0.007952 +0.007938 +0.007964 +0.007939 +0.007923 +0.007959 +0.008037 +0.008013 +0.008058 +0.007984 +0.00798 +0.000524 +0.008036 +0.008088 +0.008102 +0.008111 +0.00809 +0.008061 +0.008106 +0.008176 +0.008172 +0.008189 +0.008166 +0.008139 +0.008193 +0.008252 +0.008251 +0.008267 +0.008244 +0.008223 +0.008277 +0.008338 +0.00834 +0.00836 +0.008337 +0.008319 +0.008372 +0.008429 +0.008386 +0.008294 +0.008223 +0.008173 +0.008198 +0.00823 +0.008172 +0.008135 +0.008069 +0.008017 +0.008051 +0.008094 +0.008043 +0.007998 +0.007939 +0.007906 +0.00791 +0.007955 +0.007914 +0.007919 +0.00788 +0.00785 +0.007854 +0.007895 +0.007865 +0.007883 +0.007848 +0.007829 +0.007866 +0.007936 +0.007918 +0.00793 +0.007919 +0.007886 +0.007945 +0.008001 +0.007996 +0.008012 +0.007991 +0.007982 +0.008023 +0.000525 +0.008098 +0.008084 +0.008115 +0.008046 +0.008026 +0.008066 +0.008129 +0.008108 +0.008134 +0.008108 +0.008097 +0.008148 +0.008206 +0.008193 +0.008222 +0.008184 +0.008176 +0.008237 +0.008325 +0.008308 +0.008326 +0.008293 +0.008277 +0.008295 +0.008376 +0.008347 +0.008352 +0.008312 +0.008261 +0.008256 +0.008287 +0.008236 +0.008222 +0.008157 +0.008092 +0.00809 +0.008142 +0.00809 +0.008071 +0.008025 +0.00798 +0.007993 +0.008051 +0.008016 +0.008014 +0.00797 +0.007935 +0.007947 +0.00801 +0.007985 +0.008004 +0.007973 +0.007948 +0.007975 +0.008045 +0.00803 +0.00805 +0.008022 +0.007999 +0.008042 +0.008108 +0.008101 +0.008129 +0.008106 +0.008078 +0.000526 +0.008113 +0.008193 +0.008177 +0.008213 +0.008176 +0.008161 +0.008196 +0.008275 +0.008251 +0.008286 +0.008254 +0.008244 +0.008284 +0.008369 +0.00834 +0.008385 +0.008344 +0.008326 +0.008377 +0.008462 +0.008429 +0.008481 +0.008443 +0.008414 +0.00837 +0.008419 +0.008357 +0.008364 +0.008305 +0.008264 +0.00827 +0.008333 +0.008186 +0.008163 +0.008104 +0.00807 +0.008078 +0.008134 +0.008065 +0.008023 +0.007944 +0.007924 +0.007939 +0.00801 +0.007944 +0.007952 +0.007862 +0.007843 +0.007871 +0.007921 +0.007895 +0.007905 +0.007865 +0.007857 +0.007881 +0.007941 +0.007911 +0.007927 +0.007901 +0.007886 +0.007899 +0.007976 +0.007943 +0.007968 +0.007948 +0.007939 +0.007972 +0.008063 +0.008034 +0.008064 +0.008037 +0.008022 +0.000527 +0.008059 +0.008144 +0.008122 +0.008153 +0.008112 +0.008104 +0.008143 +0.008222 +0.008198 +0.008221 +0.008186 +0.008173 +0.008201 +0.008284 +0.008248 +0.008275 +0.008236 +0.008231 +0.008251 +0.00834 +0.00833 +0.008383 +0.008339 +0.00831 +0.008308 +0.008354 +0.008281 +0.008265 +0.008198 +0.008154 +0.008142 +0.008184 +0.008116 +0.008117 +0.008058 +0.008012 +0.008008 +0.008059 +0.008014 +0.008022 +0.00797 +0.007937 +0.007945 +0.008006 +0.007965 +0.007977 +0.00793 +0.007907 +0.007935 +0.008018 +0.007983 +0.008011 +0.007964 +0.007954 +0.007987 +0.008068 +0.008045 +0.008082 +0.008038 +0.008034 +0.008065 +0.008163 +0.008114 +0.000528 +0.008147 +0.008122 +0.008103 +0.008151 +0.008222 +0.008208 +0.008227 +0.008197 +0.00818 +0.008225 +0.0083 +0.008294 +0.008309 +0.008283 +0.008265 +0.008308 +0.008389 +0.008364 +0.008394 +0.008363 +0.008347 +0.008407 +0.008481 +0.008472 +0.008499 +0.008464 +0.008407 +0.008334 +0.008373 +0.008329 +0.00833 +0.008264 +0.008234 +0.008232 +0.008197 +0.00814 +0.008142 +0.00808 +0.008048 +0.008021 +0.008038 +0.007992 +0.007991 +0.007954 +0.007909 +0.00795 +0.007985 +0.00795 +0.007917 +0.007867 +0.007853 +0.007875 +0.007949 +0.007911 +0.007925 +0.007909 +0.007886 +0.007936 +0.008012 +0.007977 +0.00801 +0.007973 +0.007953 +0.007993 +0.008058 +0.008033 +0.008073 +0.008045 +0.000529 +0.008031 +0.008079 +0.008144 +0.008123 +0.008141 +0.008131 +0.008099 +0.008135 +0.008198 +0.008182 +0.008201 +0.00818 +0.008152 +0.008208 +0.008266 +0.008252 +0.008269 +0.008245 +0.008231 +0.008277 +0.008359 +0.008371 +0.008376 +0.008356 +0.008321 +0.008372 +0.008436 +0.008402 +0.008382 +0.008324 +0.008259 +0.008262 +0.008295 +0.008247 +0.008222 +0.008167 +0.008107 +0.008113 +0.008151 +0.008113 +0.008102 +0.008056 +0.008002 +0.008026 +0.00807 +0.008045 +0.008035 +0.007999 +0.007951 +0.007992 +0.008057 +0.008034 +0.008041 +0.008009 +0.007974 +0.008021 +0.008093 +0.008081 +0.008089 +0.008074 +0.00804 +0.008098 +0.008159 +0.008156 +0.008185 +0.008134 +0.008122 +0.00053 +0.008171 +0.008239 +0.008233 +0.008249 +0.008229 +0.008202 +0.008247 +0.008317 +0.008311 +0.008326 +0.008304 +0.008279 +0.008337 +0.008397 +0.008393 +0.008419 +0.008396 +0.008373 +0.008425 +0.008507 +0.008487 +0.00851 +0.008498 +0.008451 +0.008394 +0.008409 +0.008362 +0.008342 +0.008304 +0.008244 +0.008231 +0.008206 +0.008158 +0.008128 +0.00809 +0.008052 +0.008066 +0.008107 +0.00802 +0.007965 +0.007921 +0.00787 +0.007898 +0.007941 +0.007901 +0.007882 +0.007817 +0.007792 +0.007813 +0.007853 +0.007833 +0.007832 +0.007804 +0.007781 +0.007823 +0.00789 +0.007874 +0.00787 +0.007853 +0.007812 +0.007864 +0.007929 +0.007913 +0.007926 +0.007924 +0.007893 +0.00795 +0.008017 +0.008006 +0.008016 +0.000531 +0.007989 +0.007989 +0.008028 +0.008097 +0.00807 +0.008091 +0.008069 +0.008053 +0.008077 +0.008142 +0.008106 +0.008128 +0.008101 +0.008091 +0.008129 +0.008203 +0.008212 +0.008257 +0.008226 +0.008207 +0.008237 +0.008296 +0.008262 +0.008262 +0.008201 +0.008146 +0.008141 +0.00816 +0.008104 +0.008094 +0.008017 +0.007961 +0.00797 +0.00799 +0.007946 +0.007933 +0.007876 +0.007834 +0.007851 +0.007881 +0.007847 +0.00785 +0.007797 +0.007764 +0.007786 +0.007848 +0.007812 +0.007828 +0.007801 +0.007776 +0.007811 +0.007881 +0.007862 +0.007889 +0.007856 +0.007839 +0.007876 +0.00795 +0.007941 +0.007968 +0.007919 +0.007914 +0.000532 +0.007958 +0.00803 +0.008015 +0.008029 +0.008011 +0.00798 +0.008033 +0.008099 +0.008095 +0.008111 +0.008085 +0.008058 +0.008108 +0.008173 +0.008171 +0.008193 +0.008167 +0.008142 +0.008203 +0.008255 +0.008259 +0.008272 +0.008268 +0.008237 +0.008294 +0.008353 +0.008305 +0.00821 +0.008137 +0.008086 +0.008114 +0.008135 +0.008049 +0.007992 +0.007932 +0.007869 +0.007896 +0.007934 +0.007871 +0.007868 +0.00777 +0.007707 +0.007726 +0.007769 +0.007729 +0.007708 +0.007651 +0.007609 +0.007619 +0.007651 +0.007638 +0.007636 +0.007608 +0.007583 +0.007616 +0.007681 +0.007665 +0.007667 +0.007648 +0.007602 +0.007624 +0.007689 +0.007669 +0.007685 +0.00768 +0.007653 +0.007709 +0.007771 +0.007762 +0.007779 +0.007766 +0.007746 +0.007782 +0.000533 +0.007856 +0.007857 +0.007863 +0.007841 +0.007819 +0.00787 +0.007932 +0.007926 +0.007947 +0.007921 +0.007896 +0.007943 +0.008002 +0.007989 +0.007994 +0.007976 +0.007951 +0.00799 +0.008062 +0.008043 +0.008067 +0.008055 +0.00802 +0.008049 +0.008079 +0.008026 +0.008002 +0.007943 +0.007881 +0.007888 +0.007913 +0.007864 +0.007846 +0.007792 +0.007729 +0.007745 +0.007775 +0.007735 +0.007734 +0.007689 +0.007633 +0.007661 +0.007698 +0.007672 +0.007676 +0.00764 +0.007602 +0.007644 +0.007691 +0.007677 +0.007695 +0.007678 +0.007642 +0.007696 +0.007754 +0.007738 +0.007763 +0.007737 +0.00772 +0.007762 +0.007829 +0.007828 +0.007823 +0.000534 +0.007801 +0.007794 +0.007835 +0.007909 +0.007889 +0.007918 +0.007882 +0.007866 +0.007906 +0.007979 +0.00795 +0.007978 +0.007946 +0.00793 +0.007975 +0.008052 +0.00805 +0.008058 +0.008039 +0.008017 +0.008064 +0.008135 +0.008135 +0.008158 +0.008132 +0.00812 +0.008169 +0.008165 +0.008101 +0.008089 +0.00803 +0.007993 +0.00794 +0.007962 +0.007917 +0.007916 +0.007842 +0.007798 +0.007772 +0.007782 +0.007726 +0.007739 +0.007681 +0.007655 +0.007664 +0.007691 +0.007615 +0.007626 +0.00758 +0.00755 +0.007572 +0.007605 +0.007571 +0.007589 +0.007548 +0.007548 +0.007572 +0.007634 +0.007623 +0.007638 +0.007608 +0.00761 +0.007644 +0.007687 +0.007673 +0.007695 +0.007662 +0.007653 +0.007709 +0.007764 +0.007752 +0.000535 +0.007773 +0.007758 +0.007725 +0.007748 +0.007811 +0.007793 +0.007811 +0.007795 +0.007772 +0.007823 +0.007887 +0.007879 +0.007895 +0.007876 +0.007847 +0.007898 +0.007971 +0.00797 +0.00799 +0.00797 +0.007925 +0.00799 +0.008052 +0.00805 +0.008057 +0.008026 +0.007986 +0.008008 +0.008041 +0.008004 +0.007988 +0.007922 +0.007864 +0.007877 +0.007907 +0.007875 +0.007851 +0.007795 +0.007746 +0.007766 +0.007798 +0.00778 +0.00777 +0.007723 +0.007684 +0.007712 +0.007757 +0.007746 +0.007744 +0.007711 +0.007683 +0.007721 +0.007779 +0.007781 +0.007789 +0.007763 +0.007738 +0.007778 +0.007839 +0.007844 +0.007855 +0.007838 +0.007819 +0.007846 +0.007906 +0.007919 +0.000536 +0.007931 +0.007907 +0.007884 +0.007926 +0.007991 +0.007987 +0.008005 +0.007983 +0.007959 +0.008004 +0.008066 +0.008067 +0.008081 +0.008061 +0.008032 +0.008093 +0.008155 +0.008149 +0.008172 +0.008141 +0.008129 +0.008186 +0.008254 +0.00825 +0.008271 +0.008209 +0.008121 +0.008139 +0.008175 +0.00813 +0.008127 +0.008068 +0.007978 +0.007963 +0.007979 +0.007922 +0.007925 +0.007882 +0.007812 +0.007837 +0.007822 +0.007785 +0.007766 +0.007715 +0.007654 +0.007658 +0.007687 +0.007666 +0.007658 +0.007637 +0.007602 +0.00764 +0.0077 +0.007673 +0.007688 +0.007663 +0.007612 +0.007647 +0.007696 +0.007677 +0.007707 +0.007683 +0.00766 +0.007718 +0.007771 +0.007768 +0.00779 +0.007772 +0.007744 +0.007808 +0.007866 +0.000537 +0.007855 +0.007875 +0.007852 +0.007836 +0.007871 +0.007942 +0.007931 +0.00795 +0.007926 +0.007912 +0.007951 +0.008015 +0.007994 +0.008012 +0.007982 +0.007961 +0.007999 +0.008073 +0.008043 +0.008061 +0.00804 +0.008017 +0.008073 +0.008162 +0.008114 +0.008109 +0.008044 +0.007974 +0.007966 +0.00801 +0.007956 +0.007942 +0.007874 +0.007813 +0.007816 +0.007862 +0.007814 +0.007794 +0.007741 +0.007694 +0.007701 +0.007755 +0.007718 +0.007724 +0.007666 +0.007633 +0.007651 +0.007712 +0.007692 +0.007708 +0.007677 +0.007653 +0.00768 +0.007751 +0.007734 +0.007759 +0.007733 +0.007713 +0.007752 +0.007819 +0.007806 +0.007827 +0.00781 +0.00778 +0.007819 +0.000538 +0.007892 +0.007876 +0.007909 +0.007873 +0.007869 +0.007888 +0.007973 +0.007955 +0.00798 +0.007943 +0.007932 +0.007963 +0.008047 +0.00803 +0.008061 +0.008024 +0.00802 +0.008053 +0.008128 +0.008115 +0.008145 +0.008116 +0.008112 +0.008149 +0.008235 +0.008207 +0.008187 +0.008075 +0.008028 +0.00805 +0.008104 +0.008031 +0.007986 +0.007908 +0.007872 +0.007862 +0.007913 +0.007858 +0.007854 +0.00776 +0.007726 +0.007704 +0.007762 +0.007698 +0.007713 +0.007669 +0.007636 +0.007637 +0.007685 +0.007636 +0.007649 +0.007616 +0.007596 +0.007627 +0.007684 +0.007647 +0.007682 +0.00764 +0.007632 +0.00767 +0.007719 +0.007698 +0.007727 +0.007685 +0.007692 +0.007727 +0.007801 +0.007787 +0.00781 +0.007775 +0.000539 +0.007768 +0.007816 +0.007888 +0.007853 +0.007883 +0.007859 +0.007847 +0.00789 +0.007964 +0.007924 +0.007956 +0.007922 +0.007905 +0.007918 +0.007992 +0.007962 +0.007994 +0.007958 +0.007945 +0.007984 +0.008079 +0.008092 +0.008123 +0.008075 +0.008052 +0.008048 +0.008093 +0.00803 +0.008003 +0.007917 +0.007881 +0.007881 +0.007924 +0.007869 +0.007856 +0.007788 +0.00775 +0.007746 +0.007793 +0.007756 +0.007767 +0.007696 +0.007674 +0.00767 +0.007718 +0.007687 +0.0077 +0.00765 +0.007637 +0.007647 +0.007707 +0.007686 +0.007712 +0.007671 +0.007665 +0.007688 +0.007757 +0.007744 +0.007765 +0.007728 +0.007721 +0.007753 +0.007836 +0.00783 +0.007836 +0.007806 +0.00054 +0.007795 +0.00783 +0.007902 +0.007883 +0.007927 +0.007882 +0.007874 +0.007903 +0.00798 +0.007958 +0.007991 +0.007951 +0.007941 +0.007975 +0.008056 +0.00804 +0.008072 +0.008032 +0.008026 +0.008057 +0.008145 +0.008118 +0.008163 +0.008124 +0.008118 +0.008162 +0.00825 +0.008201 +0.008128 +0.00804 +0.008012 +0.008016 +0.008078 +0.008013 +0.007978 +0.007873 +0.007838 +0.007845 +0.007897 +0.007839 +0.007832 +0.007782 +0.007693 +0.007683 +0.007731 +0.007694 +0.007701 +0.007654 +0.007629 +0.007663 +0.007709 +0.007652 +0.00769 +0.007633 +0.007616 +0.007631 +0.007697 +0.007676 +0.007705 +0.007667 +0.007672 +0.007703 +0.007778 +0.00776 +0.007793 +0.007749 +0.007758 +0.007784 +0.007854 +0.000541 +0.007843 +0.007867 +0.007841 +0.007827 +0.007869 +0.007941 +0.007931 +0.007957 +0.007915 +0.007906 +0.00795 +0.00802 +0.007998 +0.008019 +0.007966 +0.007957 +0.007995 +0.008061 +0.008037 +0.008064 +0.008034 +0.008018 +0.008061 +0.008127 +0.008111 +0.008133 +0.008104 +0.008087 +0.008129 +0.008203 +0.008197 +0.008241 +0.008206 +0.008198 +0.008228 +0.008303 +0.008291 +0.008312 +0.00828 +0.008262 +0.008299 +0.008368 +0.00835 +0.008374 +0.008342 +0.008327 +0.008381 +0.008459 +0.00845 +0.008469 +0.008436 +0.008419 +0.008461 +0.008536 +0.008528 +0.008552 +0.00852 +0.008501 +0.008544 +0.008615 +0.008605 +0.008631 +0.0086 +0.008589 +0.008615 +0.008696 +0.008683 +0.008714 +0.008683 +0.008664 +0.00871 +0.008784 +0.008772 +0.008792 +0.008761 +0.008742 +0.008788 +0.008865 +0.008848 +0.008877 +0.008842 +0.008821 +0.008871 +0.008945 +0.00893 +0.008958 +0.008924 +0.008905 +0.008953 +0.00903 +0.009011 +0.009033 +0.009 +0.00898 +0.009036 +0.009111 +0.009096 +0.00912 +0.009088 +0.009067 +0.009122 +0.009197 +0.009179 +0.009205 +0.009173 +0.009151 +0.009201 +0.009281 +0.009262 +0.009289 +0.009257 +0.009237 +0.009288 +0.00937 +0.009341 +0.009365 +0.009335 +0.009316 +0.009373 +0.00945 +0.009425 +0.009447 +0.009412 +0.009399 +0.009449 +0.009532 +0.009503 +0.009532 +0.009502 +0.009483 +0.009539 +0.009617 +0.009596 +0.009626 +0.009591 +0.009566 +0.009627 +0.009715 +0.009693 +0.009723 +0.009687 +0.009666 +0.009722 +0.009793 +0.009773 +0.009807 +0.009778 +0.00976 +0.00982 +0.009895 +0.009867 +0.009896 +0.009861 +0.009846 +0.009909 +0.009992 +0.009959 +0.009999 +0.009952 +0.00994 +0.01 +0.010082 +0.010047 +0.010083 +0.01005 +0.010026 +0.010093 +0.010177 +0.010147 +0.010176 +0.010139 +0.010121 +0.010187 +0.010261 +0.010239 +0.01027 +0.010231 +0.010209 +0.010279 +0.010362 +0.010334 +0.010367 +0.010336 +0.010313 +0.010385 +0.010454 +0.010437 +0.010469 +0.010435 +0.010414 +0.010478 +0.010564 +0.010535 +0.010571 +0.010537 +0.010512 +0.010579 +0.010663 +0.010639 +0.010671 +0.010636 +0.010621 +0.010687 +0.010772 +0.010747 +0.010783 +0.010743 +0.010727 +0.010794 +0.010886 +0.010852 +0.010888 +0.010843 +0.01083 +0.010856 +0.010932 +0.010921 +0.010955 +0.010923 +0.010906 +0.010971 +0.011066 +0.011052 +0.011087 +0.011049 +0.011036 +0.011091 +0.01119 +0.011178 +0.011209 +0.011168 +0.011151 +0.011208 +0.011312 +0.011289 +0.011324 +0.011287 +0.011263 +0.011325 +0.011423 +0.011399 +0.011435 +0.011395 +0.01137 +0.011435 +0.011531 +0.011506 +0.011537 +0.011498 +0.011475 +0.011535 +0.011635 +0.011607 +0.01164 +0.011601 +0.011577 +0.011637 +0.011742 +0.011713 +0.01175 +0.011709 +0.011682 +0.011749 +0.011852 +0.011826 +0.011869 +0.011828 +0.011803 +0.011874 +0.011992 +0.011986 +0.012015 +0.011973 +0.011945 +0.012014 +0.012111 +0.012096 +0.012126 +0.012082 +0.012056 +0.012119 +0.012222 +0.012203 +0.012242 +0.012197 +0.012171 +0.012254 +0.012362 +0.012345 +0.01238 +0.012339 +0.012315 +0.012383 +0.012496 +0.01248 +0.012516 +0.012473 +0.012458 +0.012519 +0.012618 +0.012617 +0.012673 +0.012643 +0.012631 +0.012685 +0.012778 +0.012735 +0.012777 +0.012747 +0.012721 +0.012775 +0.012892 +0.012871 +0.012953 +0.012912 +0.012876 +0.012946 +0.01305 +0.013032 +0.013068 +0.013046 +0.013021 +0.013093 +0.0132 +0.013183 +0.013237 +0.013192 +0.013166 +0.013242 +0.013362 +0.01334 +0.01339 +0.013351 +0.013322 +0.013399 +0.013525 +0.013498 +0.013561 +0.013521 +0.013484 +0.013564 +0.013691 +0.013685 +0.013724 +0.0137 +0.013667 +0.01372 +0.013856 +0.01384 +0.013881 +0.013849 +0.013811 +0.013895 +0.01403 +0.014008 +0.014074 +0.014032 +0.01399 +0.014061 +0.014211 +0.014201 +0.01424 +0.014205 +0.014185 +0.014247 +0.014388 +0.014399 +0.014458 +0.014405 +0.014388 +0.014437 +0.014561 +0.014502 +0.014576 +0.014586 +0.014544 +0.01462 +0.014761 +0.014717 +0.014771 +0.014776 +0.014732 +0.014818 +0.014921 +0.014887 +0.014975 +0.014951 +0.014911 +0.014986 +0.01514 +0.015124 +0.015171 +0.015141 +0.015109 +0.015193 +0.015339 +0.015319 +0.015384 +0.015342 +0.015312 +0.015396 +0.015556 +0.015524 +0.015583 +0.015552 +0.015519 +0.01561 +0.015747 +0.015736 +0.015807 +0.015757 +0.015727 +0.015828 +0.01597 +0.015953 +0.016024 +0.015977 +0.015958 +0.016036 +0.016188 +0.016181 +0.016246 +0.016199 +0.01617 +0.016271 +0.016428 +0.016414 +0.016465 +0.016431 +0.016404 +0.01649 +0.01666 +0.016638 +0.01671 +0.016663 +0.016633 +0.016735 +0.016901 +0.016878 +0.016945 +0.016908 +0.016874 +0.016979 +0.017143 +0.017125 +0.017199 +0.017148 +0.017128 +0.017226 +0.017397 +0.017378 +0.017458 +0.017398 +0.017377 +0.017487 +0.01765 +0.017638 +0.017716 +0.017658 +0.017641 +0.017749 +0.017917 +0.017905 +0.017989 +0.017926 +0.017903 +0.018016 +0.018189 +0.018181 +0.01826 +0.018201 +0.018185 +0.018292 +0.018477 +0.018458 +0.018547 +0.018493 +0.01846 +0.018586 +0.018764 +0.018749 +0.01884 +0.018779 +0.018765 +0.018876 +0.019065 +0.019054 +0.019142 +0.019088 +0.019068 +0.019193 +0.019377 +0.019366 +0.019456 +0.019405 +0.019387 +0.019507 +0.019703 +0.019692 +0.019788 +0.019725 +0.019712 +0.019834 +0.020038 +0.020022 +0.020119 +0.020071 +0.020046 +0.020177 +0.02038 +0.020368 +0.020475 +0.020407 +0.0204 +0.020528 +0.020744 +0.02072 +0.020829 +0.020776 +0.020758 +0.020893 +0.021109 +0.021098 +0.021205 +0.021149 +0.021143 +0.021275 +0.021498 +0.021489 +0.021599 +0.021542 +0.021531 +0.021674 +0.021902 +0.021889 +0.022001 +0.021957 +0.021938 +0.022087 +0.022321 +0.022313 +0.022433 +0.022372 +0.022365 +0.022519 +0.022757 +0.022745 +0.022864 +0.022827 +0.022799 +0.022966 +0.02321 +0.023204 +0.023326 +0.023282 +0.023275 +0.023436 +0.023692 +0.023677 +0.023806 +0.023778 +0.023745 +0.023929 +0.024186 +0.024177 +0.024312 +0.024276 +0.024263 +0.024436 +0.024705 +0.024705 +0.024841 +0.024794 +0.024801 +0.024975 +0.025248 +0.025255 +0.025398 +0.02536 +0.025356 +0.025548 +0.025831 +0.025834 +0.025979 +0.025955 +0.025947 +0.02614 +0.026445 +0.026439 +0.026598 +0.02658 +0.026572 +0.026785 +0.027073 +0.027097 +0.027256 +0.027233 +0.027234 +0.027442 +0.027761 +0.027776 +0.027941 +0.027931 +0.027929 +0.028152 +0.028469 +0.028503 +0.028668 +0.028665 +0.028675 +0.028905 +0.029235 +0.029285 +0.029459 +0.029464 +0.029482 +0.029728 +0.030078 +0.03012 +0.030305 +0.030312 +0.030337 +0.030594 +0.030954 +0.031012 +0.031214 +0.031221 +0.031272 +0.031526 +0.031911 +0.031976 +0.032177 +0.032202 +0.032239 +0.032524 +0.032921 +0.032987 +0.033227 +0.033246 +0.033316 +0.033605 +0.034033 +0.034117 +0.034359 +0.034392 +0.034469 +0.034784 +0.035229 +0.035332 +0.035607 +0.03565 +0.035741 +0.036087 +0.036555 +0.036671 +0.036962 +0.037016 +0.037131 +0.037502 +0.038004 +0.038147 +0.038452 +0.038551 +0.038675 +0.039071 +0.039622 +0.03977 +0.040117 +0.040227 +0.040395 +0.040816 +0.041417 +0.041603 +0.041989 +0.042154 +0.042339 +0.042812 +0.043469 +0.043692 +0.04412 +0.044301 +0.044539 +0.045059 +0.045781 +0.046061 +0.046538 +0.046781 +0.047071 +0.04767 +0.048463 +0.048784 +0.049337 +0.049648 +0.04999 +0.050685 +0.051589 +0.052011 +0.05268 +0.053138 +0.053576 +0.054399 +0.055436 +0.055951 +0.056753 +0.057292 +0.057877 +0.058874 +0.060124 +0.060815 +0.061841 +0.062613 +0.063424 +0.06466 +0.066228 +0.067161 +0.06844 +0.069521 +0.07066 +0.072284 +0.074311 +0.075689 +0.077538 +0.07925 +0.081021 +0.083375 +0.086321 +0.088519 +0.091352 +0.094357 +0.094821 +0.095675 +0.099797 +0.103297 +0.108872 +0.113759 +0.119428 +0.129752 +0.136203 +0.118511 +0.09629 +0.080008 +0.06807 +0.061261 +0.056946 +0.052926 +0.049257 +0.04636 +0.04358 +0.041778 +0.040575 +0.038975 +0.037905 +0.036892 +0.035885 +0.035491 +0.035293 +0.034661 +0.034372 +0.033942 +0.033682 +0.033624 +0.034096 +0.034067 +0.034321 +0.034358 +0.034351 +0.034456 +0.035003 +0.000542 +0.03517 +0.035365 +0.035331 +0.035446 +0.035701 +0.036352 +0.036209 +0.036477 +0.036376 +0.036467 +0.036691 +0.037313 +0.037558 +0.037431 +0.036097 +0.034582 +0.033231 +0.031958 +0.030498 +0.029287 +0.028084 +0.02709 +0.026388 +0.025891 +0.025227 +0.024674 +0.02402 +0.0235 +0.023167 +0.022978 +0.022604 +0.022331 +0.021942 +0.021619 +0.021455 +0.021406 +0.021174 +0.021015 +0.020746 +0.02052 +0.020441 +0.020455 +0.020284 +0.020192 +0.019999 +0.019823 +0.01982 +0.019886 +0.019779 +0.019759 +0.019658 +0.019584 +0.019685 +0.019868 +0.01988 +0.019954 +0.019924 +0.019881 +0.020035 +0.020237 +0.000543 +0.02023 +0.020328 +0.020253 +0.020256 +0.020395 +0.020635 +0.020644 +0.020758 +0.020666 +0.020542 +0.02017 +0.020042 +0.019843 +0.019756 +0.01956 +0.019203 +0.018949 +0.018986 +0.018764 +0.018717 +0.018328 +0.018094 +0.017998 +0.017998 +0.017857 +0.017778 +0.017483 +0.0174 +0.01728 +0.017366 +0.017236 +0.01724 +0.017097 +0.016918 +0.016811 +0.016943 +0.016826 +0.016837 +0.016735 +0.016661 +0.016676 +0.016666 +0.016632 +0.016652 +0.016576 +0.016552 +0.016633 +0.016784 +0.016724 +0.016776 +0.01673 +0.016689 +0.016795 +0.016965 +0.016921 +0.016988 +0.000544 +0.016963 +0.016955 +0.01706 +0.017205 +0.017156 +0.017196 +0.017131 +0.017101 +0.017278 +0.017519 +0.01747 +0.017523 +0.01746 +0.017426 +0.017431 +0.017489 +0.01737 +0.017296 +0.017102 +0.016945 +0.016897 +0.016915 +0.01677 +0.016674 +0.016487 +0.016337 +0.0163 +0.01633 +0.016216 +0.016163 +0.016009 +0.015884 +0.01588 +0.015937 +0.015851 +0.015814 +0.015695 +0.015601 +0.015615 +0.015693 +0.015637 +0.015616 +0.015507 +0.015443 +0.01547 +0.015576 +0.015531 +0.015556 +0.015468 +0.015439 +0.015509 +0.015643 +0.01564 +0.015689 +0.015647 +0.015625 +0.01572 +0.015864 +0.015866 +0.000545 +0.015926 +0.015869 +0.015848 +0.015948 +0.0161 +0.01609 +0.016152 +0.01611 +0.016088 +0.016193 +0.016382 +0.016364 +0.016434 +0.016419 +0.016374 +0.016312 +0.016265 +0.016181 +0.016166 +0.016046 +0.015953 +0.015912 +0.015881 +0.015779 +0.015765 +0.015634 +0.015478 +0.015408 +0.015487 +0.015417 +0.015399 +0.015308 +0.015223 +0.015225 +0.0152 +0.015152 +0.015141 +0.015079 +0.015001 +0.014969 +0.015023 +0.014942 +0.014991 +0.014893 +0.014861 +0.014914 +0.014956 +0.014889 +0.01491 +0.014863 +0.014794 +0.014803 +0.014901 +0.014916 +0.014962 +0.014939 +0.014923 +0.015027 +0.015176 +0.015157 +0.015226 +0.000546 +0.015175 +0.01518 +0.015273 +0.015418 +0.015378 +0.015393 +0.0153 +0.01526 +0.015342 +0.015457 +0.015435 +0.015517 +0.015592 +0.01557 +0.015626 +0.015784 +0.015736 +0.015792 +0.015764 +0.01569 +0.015686 +0.015762 +0.015628 +0.015587 +0.015442 +0.015318 +0.015297 +0.015339 +0.015208 +0.015172 +0.015034 +0.014916 +0.014923 +0.014978 +0.014884 +0.014882 +0.014772 +0.014679 +0.014707 +0.014799 +0.014719 +0.014739 +0.014644 +0.014576 +0.014613 +0.014713 +0.014638 +0.014664 +0.014587 +0.014522 +0.014579 +0.014695 +0.01465 +0.014707 +0.014657 +0.014616 +0.014713 +0.014839 +0.014818 +0.014895 +0.000547 +0.014841 +0.014824 +0.014905 +0.015041 +0.01503 +0.015096 +0.015051 +0.01503 +0.015111 +0.015261 +0.015242 +0.015295 +0.015254 +0.015233 +0.015322 +0.015496 +0.015483 +0.015555 +0.015503 +0.01551 +0.015639 +0.015755 +0.015562 +0.01557 +0.015469 +0.015328 +0.015316 +0.015407 +0.015328 +0.015347 +0.015259 +0.015176 +0.015083 +0.015144 +0.015065 +0.015088 +0.014991 +0.01495 +0.014998 +0.015048 +0.014931 +0.014958 +0.014837 +0.014763 +0.014772 +0.01488 +0.014807 +0.014862 +0.014777 +0.014745 +0.014748 +0.01482 +0.01476 +0.014799 +0.014718 +0.014691 +0.014734 +0.014807 +0.014762 +0.014808 +0.014773 +0.014736 +0.01481 +0.014905 +0.014903 +0.014949 +0.014938 +0.000548 +0.014907 +0.015025 +0.015151 +0.015123 +0.0152 +0.015143 +0.015105 +0.015182 +0.015293 +0.015246 +0.015283 +0.015233 +0.015212 +0.015368 +0.015577 +0.015523 +0.015542 +0.015415 +0.015293 +0.015274 +0.015237 +0.015036 +0.014879 +0.014619 +0.014384 +0.014267 +0.014192 +0.013968 +0.013843 +0.013616 +0.013433 +0.013364 +0.013335 +0.013156 +0.013059 +0.012869 +0.012697 +0.012646 +0.012637 +0.012497 +0.012435 +0.012283 +0.012145 +0.012115 +0.012132 +0.011993 +0.01196 +0.01183 +0.011722 +0.011729 +0.011764 +0.011687 +0.011684 +0.011604 +0.011537 +0.01158 +0.011666 +0.01164 +0.011688 +0.011644 +0.011615 +0.011681 +0.011788 +0.011769 +0.011821 +0.011786 +0.011745 +0.011809 +0.011931 +0.011912 +0.000549 +0.011959 +0.01191 +0.011896 +0.011945 +0.012067 +0.012037 +0.012079 +0.012039 +0.012029 +0.012092 +0.012207 +0.012194 +0.01224 +0.012202 +0.012204 +0.01227 +0.012361 +0.012236 +0.01203 +0.011884 +0.011744 +0.011566 +0.011514 +0.01137 +0.011298 +0.011073 +0.010917 +0.010816 +0.010829 +0.010704 +0.010601 +0.010451 +0.010334 +0.010293 +0.010276 +0.010183 +0.010144 +0.010055 +0.009898 +0.009857 +0.00989 +0.009802 +0.009792 +0.009647 +0.009549 +0.009516 +0.009564 +0.009506 +0.009485 +0.009359 +0.00932 +0.009308 +0.009371 +0.009309 +0.009331 +0.009245 +0.0092 +0.009224 +0.009306 +0.009278 +0.009313 +0.009278 +0.009273 +0.009321 +0.009413 +0.009382 +0.009422 +0.009388 +0.009372 +0.009432 +0.009509 +0.009481 +0.009523 +0.00055 +0.009485 +0.009477 +0.009521 +0.0096 +0.009557 +0.009598 +0.009562 +0.009555 +0.009604 +0.009685 +0.009648 +0.009683 +0.009641 +0.009632 +0.009674 +0.009764 +0.00973 +0.009767 +0.009727 +0.009718 +0.00978 +0.009893 +0.009878 +0.009906 +0.009862 +0.009847 +0.009881 +0.009992 +0.009964 +0.010013 +0.009964 +0.009945 +0.009969 +0.010037 +0.009959 +0.009933 +0.009821 +0.009737 +0.009705 +0.009727 +0.009631 +0.009599 +0.009492 +0.009415 +0.009377 +0.009405 +0.00931 +0.009269 +0.009162 +0.009087 +0.009051 +0.009078 +0.009008 +0.008982 +0.008897 +0.008846 +0.008824 +0.008867 +0.008808 +0.008796 +0.008718 +0.008685 +0.008684 +0.008753 +0.008716 +0.008724 +0.008675 +0.008662 +0.008687 +0.008776 +0.008754 +0.008785 +0.008757 +0.008737 +0.008779 +0.008854 +0.008844 +0.008878 +0.008841 +0.008824 +0.008872 +0.008938 +0.000551 +0.008933 +0.008967 +0.008924 +0.008913 +0.008955 +0.009032 +0.009022 +0.009057 +0.009021 +0.009001 +0.009048 +0.009125 +0.00911 +0.009137 +0.0091 +0.009082 +0.009129 +0.009208 +0.009204 +0.009226 +0.009191 +0.00918 +0.009223 +0.009312 +0.009289 +0.009333 +0.009294 +0.009279 +0.009346 +0.009433 +0.00941 +0.009445 +0.009384 +0.009261 +0.009272 +0.009315 +0.009239 +0.00923 +0.009119 +0.008965 +0.008948 +0.008957 +0.008911 +0.008872 +0.008738 +0.008663 +0.008639 +0.008669 +0.008613 +0.008582 +0.008485 +0.008403 +0.008415 +0.008432 +0.008388 +0.008386 +0.008322 +0.00824 +0.008217 +0.008273 +0.008224 +0.008229 +0.008187 +0.008146 +0.008156 +0.008182 +0.008132 +0.008143 +0.008104 +0.008087 +0.008116 +0.008162 +0.008127 +0.008154 +0.008129 +0.008113 +0.008154 +0.008227 +0.008189 +0.008223 +0.008198 +0.008189 +0.008237 +0.008317 +0.008299 +0.008287 +0.008263 +0.000552 +0.008304 +0.00836 +0.008338 +0.008361 +0.008346 +0.008318 +0.008379 +0.008441 +0.008442 +0.00844 +0.008429 +0.008401 +0.008455 +0.008518 +0.008509 +0.008527 +0.008502 +0.008474 +0.008527 +0.008594 +0.008597 +0.008622 +0.008601 +0.008577 +0.00862 +0.008694 +0.008682 +0.008696 +0.008673 +0.00865 +0.00871 +0.008774 +0.008776 +0.008782 +0.008768 +0.008734 +0.008781 +0.008829 +0.008785 +0.008763 +0.008674 +0.008581 +0.008566 +0.008562 +0.00849 +0.008453 +0.008367 +0.008277 +0.00827 +0.008282 +0.008221 +0.008192 +0.00812 +0.008044 +0.008048 +0.008067 +0.008024 +0.008005 +0.007951 +0.007896 +0.007923 +0.007958 +0.007935 +0.007917 +0.007881 +0.007836 +0.007877 +0.007928 +0.007907 +0.007928 +0.0079 +0.007867 +0.007925 +0.007978 +0.007979 +0.007992 +0.007964 +0.007947 +0.007994 +0.008055 +0.008056 +0.008084 +0.00804 +0.000553 +0.008015 +0.00807 +0.008131 +0.008125 +0.008148 +0.008128 +0.008102 +0.008151 +0.008216 +0.008209 +0.008227 +0.008198 +0.00817 +0.008222 +0.008288 +0.008288 +0.008308 +0.008287 +0.008244 +0.008301 +0.008367 +0.008364 +0.008378 +0.008351 +0.008331 +0.00838 +0.008444 +0.008449 +0.008466 +0.008444 +0.008419 +0.00848 +0.008538 +0.008547 +0.008562 +0.008537 +0.008531 +0.008585 +0.008613 +0.008562 +0.008565 +0.008527 +0.008476 +0.008503 +0.00851 +0.008441 +0.008404 +0.008323 +0.008259 +0.008227 +0.008248 +0.008213 +0.008189 +0.008119 +0.008032 +0.008038 +0.008071 +0.008036 +0.008036 +0.007988 +0.007948 +0.007943 +0.007956 +0.007928 +0.007927 +0.007899 +0.007852 +0.007899 +0.00795 +0.007919 +0.007941 +0.007917 +0.007875 +0.007882 +0.007928 +0.007913 +0.007931 +0.007911 +0.007894 +0.00795 +0.00801 +0.008005 +0.008022 +0.008003 +0.007978 +0.008034 +0.008107 +0.008084 +0.008105 +0.000554 +0.008088 +0.008064 +0.008116 +0.008184 +0.008169 +0.008191 +0.00817 +0.00815 +0.008205 +0.008272 +0.00825 +0.008268 +0.008247 +0.008212 +0.008232 +0.008283 +0.008273 +0.008288 +0.008277 +0.008246 +0.008303 +0.008372 +0.008396 +0.008423 +0.008403 +0.008374 +0.008423 +0.008493 +0.008487 +0.008483 +0.008466 +0.00844 +0.00848 +0.008547 +0.008537 +0.00857 +0.008549 +0.008536 +0.008582 +0.008637 +0.008623 +0.00861 +0.008547 +0.008495 +0.008493 +0.008497 +0.008446 +0.008409 +0.008332 +0.008268 +0.008267 +0.008289 +0.008245 +0.008213 +0.008159 +0.008102 +0.008108 +0.008134 +0.00811 +0.008078 +0.008033 +0.007992 +0.008013 +0.008061 +0.008055 +0.008032 +0.008004 +0.007971 +0.008004 +0.008062 +0.008049 +0.00806 +0.008033 +0.008009 +0.008053 +0.008119 +0.008112 +0.008128 +0.008113 +0.008081 +0.008134 +0.008193 +0.008206 +0.008199 +0.000555 +0.008189 +0.008166 +0.008204 +0.008279 +0.008266 +0.00829 +0.008266 +0.008244 +0.008289 +0.00836 +0.008347 +0.00837 +0.008338 +0.008315 +0.008365 +0.008441 +0.008429 +0.008449 +0.008424 +0.008396 +0.008444 +0.008512 +0.008504 +0.008531 +0.008499 +0.00847 +0.008526 +0.008594 +0.008592 +0.008611 +0.008593 +0.00856 +0.008617 +0.008699 +0.008684 +0.008711 +0.008692 +0.008675 +0.00873 +0.008762 +0.008687 +0.00868 +0.008622 +0.008558 +0.008508 +0.008523 +0.008458 +0.008447 +0.008366 +0.008259 +0.00824 +0.008277 +0.008217 +0.008228 +0.008151 +0.008066 +0.008055 +0.008096 +0.008046 +0.008056 +0.008007 +0.007973 +0.007997 +0.008016 +0.00798 +0.007978 +0.007934 +0.007886 +0.007881 +0.007948 +0.007904 +0.007922 +0.007891 +0.00787 +0.007895 +0.007961 +0.007947 +0.007958 +0.007906 +0.007884 +0.007929 +0.007998 +0.007971 +0.007998 +0.007975 +0.007955 +0.008001 +0.008077 +0.008061 +0.008086 +0.008064 +0.000556 +0.008048 +0.008082 +0.008169 +0.008138 +0.008173 +0.008141 +0.008129 +0.008172 +0.008255 +0.008218 +0.008253 +0.008211 +0.0082 +0.008244 +0.00831 +0.00828 +0.008309 +0.00827 +0.008259 +0.008296 +0.00837 +0.008335 +0.008369 +0.00833 +0.008321 +0.008356 +0.00844 +0.008428 +0.008484 +0.008448 +0.008433 +0.00846 +0.008546 +0.008528 +0.008552 +0.008513 +0.008512 +0.008527 +0.008579 +0.008526 +0.008511 +0.008428 +0.008362 +0.008326 +0.008357 +0.008284 +0.008267 +0.008179 +0.008134 +0.008113 +0.008146 +0.008098 +0.008092 +0.008017 +0.007971 +0.007966 +0.008004 +0.007957 +0.007961 +0.007899 +0.007875 +0.007881 +0.007937 +0.007904 +0.007919 +0.00787 +0.007857 +0.007874 +0.007945 +0.007921 +0.007946 +0.007907 +0.007908 +0.007931 +0.008016 +0.007992 +0.008019 +0.008002 +0.00795 +0.008008 +0.00809 +0.008066 +0.000557 +0.008103 +0.008056 +0.008049 +0.008083 +0.00817 +0.008146 +0.008176 +0.008135 +0.008129 +0.008167 +0.008247 +0.008223 +0.008259 +0.008214 +0.008211 +0.008231 +0.008327 +0.008307 +0.008336 +0.008295 +0.008281 +0.008313 +0.008399 +0.008377 +0.008409 +0.008375 +0.008366 +0.008401 +0.008478 +0.008459 +0.008494 +0.00845 +0.008441 +0.008476 +0.008558 +0.008534 +0.008571 +0.008533 +0.008517 +0.008556 +0.008638 +0.008617 +0.00865 +0.008609 +0.008595 +0.008642 +0.008734 +0.008708 +0.008738 +0.008708 +0.008697 +0.008733 +0.008835 +0.008801 +0.008826 +0.008806 +0.008789 +0.008769 +0.008852 +0.008809 +0.008863 +0.008824 +0.00882 +0.008866 +0.008958 +0.008926 +0.008974 +0.008928 +0.00893 +0.008968 +0.009052 +0.009027 +0.009048 +0.009002 +0.008983 +0.009013 +0.009104 +0.009058 +0.00899 +0.008923 +0.008885 +0.008933 +0.009003 +0.00897 +0.008985 +0.008951 +0.008918 +0.008964 +0.009041 +0.009009 +0.009035 +0.008987 +0.00892 +0.008958 +0.009027 +0.009002 +0.009039 +0.008997 +0.008996 +0.009035 +0.009124 +0.009101 +0.009137 +0.009096 +0.009097 +0.009142 +0.000558 +0.00922 +0.009197 +0.009239 +0.009202 +0.009193 +0.00924 +0.009333 +0.009297 +0.009336 +0.009276 +0.009248 +0.009282 +0.009373 +0.00934 +0.009384 +0.009344 +0.009338 +0.009387 +0.009477 +0.009455 +0.009495 +0.009456 +0.009444 +0.009492 +0.00958 +0.00955 +0.009589 +0.009549 +0.009534 +0.009581 +0.009667 +0.009635 +0.009675 +0.009628 +0.009616 +0.009656 +0.009749 +0.009725 +0.009768 +0.009744 +0.009732 +0.009773 +0.009869 +0.009842 +0.009874 +0.00983 +0.009815 +0.009853 +0.009961 +0.009944 +0.009984 +0.009939 +0.009926 +0.009972 +0.010077 +0.010042 +0.010078 +0.010052 +0.010029 +0.010061 +0.010147 +0.010097 +0.010113 +0.010044 +0.009988 +0.010005 +0.010071 +0.010008 +0.010005 +0.00995 +0.009901 +0.009914 +0.00999 +0.009934 +0.009946 +0.009891 +0.009845 +0.009864 +0.009947 +0.009899 +0.009913 +0.009868 +0.009838 +0.009867 +0.009961 +0.009925 +0.009957 +0.009918 +0.009899 +0.009937 +0.010054 +0.010004 +0.01005 +0.010008 +0.00999 +0.010051 +0.000559 +0.010139 +0.010127 +0.010147 +0.010115 +0.010093 +0.010153 +0.010248 +0.01023 +0.010248 +0.010232 +0.01021 +0.010259 +0.010349 +0.010336 +0.010375 +0.01034 +0.010317 +0.010369 +0.01047 +0.010458 +0.010476 +0.010454 +0.010425 +0.010484 +0.010581 +0.010552 +0.010586 +0.01055 +0.010538 +0.010599 +0.010691 +0.010672 +0.01071 +0.010678 +0.010657 +0.010714 +0.010822 +0.010803 +0.010836 +0.010811 +0.010782 +0.010872 +0.01095 +0.010894 +0.010906 +0.01087 +0.010858 +0.01091 +0.010986 +0.01097 +0.011004 +0.010948 +0.010913 +0.010965 +0.011048 +0.010983 +0.010941 +0.010847 +0.010794 +0.010822 +0.010903 +0.010836 +0.010851 +0.010779 +0.010684 +0.010699 +0.010772 +0.01072 +0.010752 +0.010693 +0.010672 +0.01071 +0.010805 +0.010746 +0.010782 +0.01069 +0.010633 +0.010672 +0.010745 +0.01072 +0.010742 +0.010706 +0.010691 +0.010744 +0.010838 +0.00056 +0.010814 +0.010846 +0.010815 +0.010803 +0.010846 +0.010896 +0.010884 +0.010932 +0.010885 +0.010875 +0.010943 +0.011043 +0.011011 +0.011054 +0.011018 +0.011015 +0.011076 +0.011182 +0.011148 +0.011193 +0.011149 +0.011137 +0.011143 +0.011238 +0.0112 +0.011249 +0.011208 +0.011192 +0.011247 +0.011365 +0.011349 +0.011428 +0.011388 +0.011365 +0.011416 +0.011522 +0.011496 +0.011533 +0.011481 +0.011482 +0.011543 +0.011661 +0.011632 +0.011664 +0.011638 +0.011616 +0.011674 +0.011786 +0.011758 +0.011783 +0.01171 +0.011667 +0.011693 +0.011763 +0.011719 +0.011744 +0.011649 +0.011582 +0.011584 +0.011656 +0.011586 +0.011588 +0.011504 +0.011452 +0.011453 +0.011545 +0.011487 +0.011503 +0.011432 +0.011384 +0.011404 +0.011501 +0.011457 +0.011489 +0.011425 +0.011402 +0.011438 +0.011536 +0.01151 +0.011558 +0.0115 +0.011485 +0.011536 +0.011651 +0.011635 +0.011673 +0.000561 +0.011634 +0.011617 +0.011665 +0.011786 +0.011768 +0.011807 +0.011767 +0.011755 +0.011803 +0.011921 +0.011902 +0.011955 +0.011911 +0.011912 +0.011955 +0.012079 +0.012058 +0.012107 +0.012071 +0.012067 +0.012132 +0.012248 +0.01223 +0.012277 +0.012208 +0.012128 +0.012166 +0.012273 +0.012271 +0.012323 +0.012292 +0.012278 +0.01234 +0.012473 +0.012441 +0.012511 +0.012454 +0.012448 +0.012511 +0.012641 +0.012621 +0.012668 +0.012629 +0.012605 +0.012693 +0.012741 +0.012713 +0.012752 +0.012709 +0.012705 +0.012769 +0.012906 +0.012867 +0.012915 +0.012876 +0.012853 +0.01293 +0.013063 +0.013002 +0.013068 +0.013012 +0.012984 +0.013067 +0.013169 +0.013123 +0.013201 +0.013133 +0.013128 +0.013224 +0.013343 +0.01329 +0.013343 +0.013303 +0.01328 +0.013368 +0.013509 +0.013469 +0.013508 +0.013445 +0.01342 +0.013511 +0.013651 +0.013609 +0.013645 +0.013588 +0.013573 +0.013646 +0.013786 +0.013742 +0.013781 +0.013726 +0.013709 +0.013785 +0.01392 +0.013862 +0.013922 +0.013863 +0.013852 +0.013934 +0.014065 +0.014064 +0.014134 +0.014075 +0.014066 +0.014136 +0.014263 +0.014209 +0.014282 +0.014219 +0.014205 +0.014269 +0.014393 +0.014365 +0.014436 +0.014398 +0.014375 +0.014443 +0.014575 +0.01456 +0.014617 +0.014558 +0.014535 +0.014617 +0.014767 +0.014746 +0.014802 +0.014732 +0.014709 +0.014787 +0.014926 +0.014897 +0.014959 +0.014894 +0.014893 +0.014974 +0.015122 +0.015089 +0.015149 +0.015084 +0.015065 +0.015142 +0.015283 +0.015259 +0.015334 +0.01528 +0.015257 +0.015334 +0.015481 +0.015462 +0.015522 +0.015467 +0.01545 +0.015528 +0.015679 +0.01566 +0.015711 +0.015663 +0.015645 +0.01573 +0.01588 +0.015856 +0.015915 +0.015849 +0.015843 +0.015934 +0.016082 +0.016056 +0.016119 +0.016058 +0.016049 +0.016133 +0.016289 +0.016268 +0.016328 +0.016268 +0.016251 +0.016347 +0.016505 +0.016475 +0.016541 +0.01648 +0.016468 +0.016562 +0.016716 +0.016692 +0.016761 +0.016709 +0.016692 +0.016777 +0.016939 +0.016912 +0.016983 +0.016918 +0.016919 +0.017005 +0.01717 +0.017144 +0.017216 +0.017149 +0.017142 +0.017229 +0.017405 +0.017384 +0.017448 +0.01739 +0.017365 +0.017476 +0.017645 +0.017627 +0.017694 +0.017629 +0.017606 +0.017712 +0.017893 +0.017871 +0.017939 +0.017871 +0.017854 +0.017959 +0.01815 +0.018114 +0.018188 +0.018124 +0.018105 +0.018215 +0.018399 +0.018375 +0.018454 +0.018382 +0.018369 +0.018479 +0.018664 +0.018644 +0.018716 +0.018647 +0.018647 +0.018748 +0.018936 +0.018913 +0.018996 +0.018946 +0.018933 +0.019031 +0.019218 +0.019193 +0.01927 +0.019227 +0.019207 +0.019314 +0.019503 +0.019482 +0.019571 +0.019523 +0.019506 +0.019612 +0.019799 +0.019776 +0.019865 +0.01982 +0.019799 +0.01991 +0.020112 +0.020086 +0.020179 +0.020131 +0.020108 +0.020223 +0.020416 +0.020407 +0.020502 +0.020456 +0.020433 +0.02056 +0.020745 +0.020731 +0.020824 +0.020788 +0.020761 +0.02088 +0.021087 +0.021076 +0.021156 +0.021128 +0.021113 +0.021229 +0.021432 +0.021423 +0.021503 +0.021461 +0.021456 +0.021576 +0.021797 +0.021782 +0.021892 +0.021846 +0.02181 +0.021952 +0.022185 +0.022171 +0.022269 +0.022206 +0.02222 +0.022375 +0.022565 +0.022551 +0.022646 +0.022582 +0.022568 +0.022757 +0.022989 +0.022952 +0.023039 +0.022994 +0.022958 +0.023153 +0.023391 +0.023373 +0.023457 +0.023405 +0.0234 +0.023568 +0.023812 +0.023807 +0.023897 +0.023845 +0.023855 +0.024 +0.024265 +0.024256 +0.024353 +0.024325 +0.024304 +0.024476 +0.024734 +0.02472 +0.024828 +0.024802 +0.024786 +0.024942 +0.025191 +0.02521 +0.025343 +0.025287 +0.025278 +0.025455 +0.025728 +0.025734 +0.025834 +0.02582 +0.025809 +0.025973 +0.026239 +0.02627 +0.026391 +0.02638 +0.026388 +0.026518 +0.026787 +0.026802 +0.026925 +0.026939 +0.026933 +0.027076 +0.027372 +0.027369 +0.027539 +0.027521 +0.027476 +0.027662 +0.02797 +0.027997 +0.028159 +0.028114 +0.028111 +0.028329 +0.028648 +0.028654 +0.028782 +0.028777 +0.028771 +0.02898 +0.029296 +0.029325 +0.029489 +0.02947 +0.02947 +0.029681 +0.030024 +0.030037 +0.030217 +0.030215 +0.030219 +0.030421 +0.030791 +0.030808 +0.030984 +0.030977 +0.03099 +0.031242 +0.0316 +0.031636 +0.031837 +0.031827 +0.031846 +0.03209 +0.032477 +0.032508 +0.032703 +0.032713 +0.032728 +0.032991 +0.033401 +0.033435 +0.033633 +0.033654 +0.03367 +0.03396 +0.034386 +0.034416 +0.034642 +0.034673 +0.034686 +0.035014 +0.035429 +0.035492 +0.035746 +0.035776 +0.035813 +0.036092 +0.036578 +0.036629 +0.036907 +0.036956 +0.036997 +0.037362 +0.037811 +0.037902 +0.038199 +0.038244 +0.038307 +0.038678 +0.039182 +0.039311 +0.039614 +0.039681 +0.039776 +0.040161 +0.040706 +0.04079 +0.041155 +0.04122 +0.041326 +0.041764 +0.042342 +0.042478 +0.042849 +0.042947 +0.043074 +0.043554 +0.044152 +0.044331 +0.044741 +0.044866 +0.045018 +0.045546 +0.046191 +0.046423 +0.046877 +0.04703 +0.047236 +0.047815 +0.04854 +0.048815 +0.049314 +0.049522 +0.049819 +0.050476 +0.051275 +0.051579 +0.052172 +0.052466 +0.052826 +0.053545 +0.054467 +0.054878 +0.055571 +0.055967 +0.056384 +0.057231 +0.058255 +0.058801 +0.059613 +0.060085 +0.060653 +0.061661 +0.062875 +0.063588 +0.064594 +0.065253 +0.066028 +0.067267 +0.068726 +0.069653 +0.070953 +0.071869 +0.072984 +0.074591 +0.076535 +0.077882 +0.079686 +0.081139 +0.082782 +0.085023 +0.087723 +0.089749 +0.092384 +0.094811 +0.097607 +0.101163 +0.105495 +0.109342 +0.114169 +0.119314 +0.125312 +0.133503 +0.144164 +0.158142 +0.173485 +0.194588 +0.191964 +0.122407 +0.090014 +0.072793 +0.062668 +0.055669 +0.050715 +0.047355 +0.045043 +0.042411 +0.040411 +0.038548 +0.036783 +0.035656 +0.034823 +0.033631 +0.032609 +0.031602 +0.030618 +0.030065 +0.029695 +0.028951 +0.028387 +0.027801 +0.027245 +0.026998 +0.026952 +0.026573 +0.026282 +0.026018 +0.025754 +0.025739 +0.025975 +0.025885 +0.026032 +0.026046 +0.025895 +0.026052 +0.02636 +0.026385 +0.026623 +0.026608 +0.000562 +0.026616 +0.026776 +0.027027 +0.026949 +0.027038 +0.027005 +0.027185 +0.027485 +0.027759 +0.027827 +0.028 +0.027983 +0.027996 +0.028198 +0.028438 +0.028293 +0.028163 +0.027805 +0.027477 +0.027307 +0.027311 +0.027001 +0.026784 +0.026455 +0.026134 +0.025972 +0.025942 +0.025637 +0.025425 +0.025077 +0.024755 +0.024617 +0.024624 +0.024348 +0.02421 +0.023935 +0.023649 +0.023574 +0.02362 +0.023388 +0.02326 +0.023009 +0.022766 +0.022717 +0.022785 +0.022596 +0.022504 +0.022322 +0.022127 +0.022131 +0.022252 +0.022137 +0.022112 +0.021991 +0.021887 +0.021961 +0.022167 +0.022138 +0.022215 +0.022198 +0.022166 +0.02235 +0.000563 +0.02257 +0.022598 +0.022698 +0.022665 +0.022632 +0.022799 +0.023061 +0.023071 +0.023133 +0.023099 +0.02314 +0.023277 +0.023479 +0.023446 +0.023583 +0.023506 +0.023534 +0.023729 +0.023989 +0.024027 +0.024152 +0.024132 +0.024165 +0.023814 +0.023854 +0.023641 +0.023152 +0.022773 +0.022283 +0.021948 +0.021962 +0.021656 +0.021139 +0.020791 +0.020505 +0.020215 +0.020214 +0.019978 +0.019696 +0.019319 +0.019178 +0.019007 +0.01895 +0.018802 +0.018699 +0.018429 +0.01819 +0.01811 +0.018151 +0.018024 +0.018006 +0.017888 +0.017604 +0.017611 +0.017735 +0.017655 +0.017672 +0.017619 +0.017576 +0.01758 +0.01768 +0.017693 +0.017768 +0.017752 +0.01774 +0.017857 +0.018034 +0.018015 +0.018085 +0.000564 +0.018037 +0.018008 +0.018095 +0.018208 +0.018183 +0.018255 +0.018308 +0.018338 +0.018417 +0.018587 +0.018556 +0.018686 +0.018595 +0.018531 +0.018549 +0.018605 +0.018477 +0.018393 +0.01819 +0.018042 +0.017973 +0.017991 +0.017828 +0.017743 +0.017534 +0.017388 +0.017333 +0.017362 +0.017236 +0.017175 +0.017001 +0.016881 +0.016864 +0.016915 +0.016803 +0.016766 +0.016611 +0.016517 +0.016517 +0.01658 +0.016493 +0.016476 +0.016339 +0.016268 +0.016292 +0.016383 +0.016329 +0.016343 +0.016236 +0.016209 +0.016256 +0.016401 +0.016375 +0.016433 +0.016371 +0.016366 +0.016449 +0.016619 +0.016594 +0.016673 +0.016611 +0.000565 +0.016604 +0.016699 +0.016862 +0.016851 +0.016926 +0.016874 +0.016844 +0.016949 +0.017118 +0.017097 +0.017167 +0.017146 +0.017115 +0.017253 +0.017427 +0.017424 +0.017521 +0.017482 +0.017444 +0.017309 +0.017434 +0.017332 +0.017308 +0.017167 +0.017045 +0.016995 +0.016857 +0.016715 +0.016686 +0.016525 +0.01623 +0.016194 +0.016279 +0.016141 +0.016131 +0.015943 +0.015776 +0.015727 +0.015799 +0.015713 +0.015704 +0.015605 +0.015417 +0.015353 +0.015462 +0.015363 +0.015393 +0.015292 +0.015241 +0.015274 +0.015239 +0.015198 +0.015212 +0.015148 +0.015112 +0.015181 +0.015309 +0.01524 +0.015292 +0.015237 +0.015191 +0.015265 +0.015403 +0.015374 +0.015451 +0.015428 +0.015405 +0.015507 +0.000566 +0.015659 +0.015649 +0.015711 +0.015664 +0.015625 +0.015694 +0.015822 +0.015768 +0.015811 +0.015768 +0.015853 +0.015959 +0.016102 +0.016044 +0.016047 +0.015962 +0.015874 +0.015875 +0.015948 +0.015799 +0.015746 +0.015583 +0.015433 +0.015404 +0.015437 +0.015295 +0.015227 +0.015079 +0.014939 +0.014924 +0.014984 +0.014871 +0.01483 +0.014707 +0.014591 +0.014597 +0.014667 +0.014575 +0.014553 +0.014454 +0.014365 +0.014388 +0.014488 +0.014405 +0.014409 +0.014323 +0.014243 +0.01429 +0.014401 +0.014358 +0.014385 +0.014335 +0.014283 +0.014361 +0.014499 +0.014478 +0.014543 +0.01449 +0.014463 +0.014561 +0.014686 +0.000567 +0.014667 +0.014744 +0.014688 +0.014667 +0.01475 +0.014902 +0.014871 +0.014943 +0.014887 +0.014872 +0.014947 +0.015077 +0.015069 +0.015142 +0.0151 +0.015084 +0.015182 +0.015359 +0.015347 +0.015422 +0.015357 +0.015147 +0.0151 +0.015205 +0.015094 +0.015081 +0.01497 +0.014896 +0.01476 +0.014779 +0.014695 +0.014699 +0.014568 +0.014487 +0.014471 +0.014447 +0.014378 +0.014389 +0.014294 +0.014236 +0.014189 +0.014245 +0.014159 +0.014195 +0.014103 +0.014056 +0.014039 +0.014069 +0.014023 +0.014036 +0.013987 +0.013946 +0.014002 +0.014126 +0.014022 +0.014036 +0.013963 +0.013939 +0.014049 +0.014166 +0.014116 +0.014203 +0.014162 +0.014133 +0.014162 +0.014307 +0.000568 +0.014287 +0.01435 +0.014293 +0.014289 +0.014387 +0.014533 +0.014509 +0.014558 +0.014513 +0.014474 +0.01455 +0.01465 +0.014614 +0.014661 +0.014619 +0.014615 +0.014775 +0.014916 +0.014891 +0.014918 +0.014871 +0.014824 +0.014929 +0.015048 +0.014944 +0.01494 +0.014823 +0.014703 +0.014712 +0.014757 +0.01465 +0.0146 +0.014457 +0.014324 +0.014304 +0.014351 +0.014231 +0.014201 +0.014074 +0.013964 +0.013974 +0.014036 +0.013954 +0.013942 +0.013843 +0.013756 +0.013783 +0.013871 +0.013797 +0.013812 +0.013711 +0.013647 +0.013686 +0.01378 +0.013727 +0.013751 +0.013688 +0.013631 +0.013708 +0.01382 +0.013791 +0.013839 +0.013801 +0.013759 +0.013855 +0.013984 +0.01397 +0.000569 +0.014027 +0.013979 +0.013941 +0.01404 +0.014172 +0.014155 +0.014205 +0.014169 +0.014144 +0.014218 +0.014365 +0.014348 +0.014412 +0.014356 +0.014349 +0.014444 +0.014586 +0.014583 +0.014638 +0.014607 +0.014589 +0.014499 +0.014577 +0.014515 +0.014508 +0.014389 +0.014296 +0.014304 +0.014323 +0.014077 +0.014044 +0.013867 +0.01373 +0.01369 +0.013731 +0.013626 +0.013646 +0.013496 +0.013348 +0.013345 +0.013439 +0.013357 +0.013367 +0.013248 +0.013127 +0.013095 +0.013206 +0.01313 +0.013134 +0.013083 +0.013022 +0.013087 +0.013123 +0.013069 +0.013125 +0.013054 +0.013045 +0.013099 +0.013211 +0.01318 +0.013213 +0.013187 +0.013132 +0.013169 +0.0133 +0.01327 +0.013336 +0.00057 +0.013302 +0.013285 +0.013371 +0.013504 +0.013487 +0.013529 +0.013489 +0.01346 +0.013521 +0.013635 +0.01361 +0.013657 +0.013624 +0.013637 +0.013712 +0.013835 +0.013825 +0.013873 +0.013837 +0.0138 +0.013891 +0.013991 +0.013918 +0.013922 +0.013799 +0.013695 +0.013699 +0.013722 +0.013614 +0.013582 +0.013447 +0.013327 +0.013333 +0.013366 +0.013268 +0.013251 +0.013124 +0.013026 +0.013046 +0.0131 +0.013023 +0.01303 +0.012925 +0.012854 +0.012892 +0.012957 +0.012902 +0.012918 +0.01284 +0.012772 +0.012825 +0.012903 +0.012853 +0.012886 +0.012817 +0.012763 +0.012834 +0.012944 +0.012904 +0.012969 +0.01292 +0.01289 +0.012962 +0.013079 +0.01308 +0.013112 +0.000571 +0.013076 +0.013054 +0.013115 +0.013246 +0.013241 +0.013281 +0.013242 +0.013217 +0.013288 +0.013423 +0.013404 +0.013443 +0.013404 +0.013385 +0.013453 +0.013572 +0.013583 +0.013628 +0.013581 +0.013576 +0.013661 +0.013797 +0.013792 +0.013859 +0.013815 +0.013671 +0.013664 +0.013759 +0.013685 +0.013656 +0.013565 +0.01347 +0.013457 +0.013371 +0.013252 +0.013241 +0.013123 +0.013013 +0.012905 +0.012954 +0.012865 +0.012852 +0.012762 +0.012677 +0.01264 +0.012674 +0.012603 +0.012616 +0.012521 +0.012489 +0.01248 +0.012515 +0.012439 +0.012478 +0.012396 +0.012374 +0.012421 +0.012526 +0.012471 +0.012438 +0.012406 +0.012378 +0.012461 +0.012578 +0.012542 +0.012601 +0.012566 +0.012541 +0.012613 +0.012745 +0.012712 +0.000572 +0.012754 +0.012727 +0.012705 +0.012786 +0.012898 +0.012862 +0.012893 +0.012846 +0.012801 +0.012848 +0.012953 +0.012928 +0.012984 +0.012954 +0.012993 +0.013084 +0.013205 +0.013164 +0.013205 +0.013149 +0.013126 +0.013201 +0.013261 +0.013165 +0.013148 +0.01304 +0.01292 +0.012932 +0.012952 +0.012851 +0.01282 +0.012676 +0.012568 +0.012579 +0.012607 +0.012521 +0.012507 +0.01239 +0.012304 +0.012331 +0.012378 +0.012306 +0.012309 +0.012213 +0.012137 +0.012171 +0.012241 +0.012179 +0.012207 +0.012119 +0.012049 +0.012103 +0.012181 +0.012137 +0.012173 +0.012106 +0.012058 +0.012123 +0.012227 +0.012206 +0.012253 +0.012207 +0.012181 +0.01225 +0.012364 +0.012365 +0.012381 +0.000573 +0.012348 +0.012324 +0.012402 +0.01252 +0.012491 +0.012545 +0.012501 +0.012479 +0.012549 +0.012671 +0.012647 +0.012696 +0.012651 +0.012626 +0.012693 +0.012818 +0.01281 +0.012851 +0.012815 +0.012786 +0.012872 +0.013003 +0.012984 +0.01305 +0.013008 +0.013004 +0.012955 +0.013003 +0.012939 +0.012948 +0.012835 +0.012758 +0.012774 +0.012783 +0.0126 +0.012586 +0.012442 +0.012346 +0.012319 +0.01237 +0.012286 +0.012276 +0.012207 +0.012033 +0.01204 +0.012102 +0.012045 +0.012065 +0.011983 +0.011944 +0.011992 +0.012053 +0.011958 +0.011945 +0.011877 +0.011843 +0.011808 +0.011926 +0.011863 +0.0119 +0.011868 +0.011833 +0.011901 +0.012014 +0.011969 +0.012033 +0.01199 +0.011972 +0.012015 +0.012094 +0.01205 +0.012124 +0.000574 +0.012087 +0.012059 +0.012138 +0.012261 +0.012244 +0.012282 +0.012249 +0.012231 +0.0123 +0.012416 +0.012357 +0.012392 +0.012342 +0.012298 +0.012357 +0.012464 +0.012453 +0.012527 +0.012527 +0.012512 +0.012581 +0.012678 +0.012659 +0.012681 +0.012643 +0.012627 +0.012623 +0.012691 +0.012609 +0.01257 +0.012454 +0.012347 +0.012321 +0.012347 +0.012247 +0.01221 +0.01209 +0.012001 +0.011994 +0.012028 +0.01194 +0.011926 +0.011832 +0.011766 +0.011784 +0.01184 +0.011781 +0.011774 +0.011697 +0.011634 +0.011659 +0.011731 +0.011674 +0.011667 +0.01161 +0.011559 +0.011587 +0.011685 +0.011649 +0.011655 +0.011611 +0.01159 +0.011635 +0.011748 +0.011737 +0.01176 +0.011722 +0.01171 +0.011781 +0.011886 +0.011872 +0.000575 +0.011893 +0.011849 +0.011838 +0.011908 +0.012025 +0.011996 +0.012046 +0.011987 +0.011982 +0.012048 +0.012166 +0.012138 +0.01218 +0.012135 +0.012116 +0.012165 +0.012292 +0.012275 +0.012333 +0.012284 +0.012276 +0.012342 +0.012478 +0.012471 +0.01252 +0.012484 +0.012354 +0.012302 +0.012367 +0.012281 +0.012261 +0.012148 +0.012059 +0.011937 +0.01193 +0.011856 +0.011842 +0.011751 +0.011678 +0.011684 +0.011704 +0.01157 +0.011606 +0.011498 +0.011436 +0.011399 +0.011497 +0.011438 +0.011469 +0.011393 +0.011355 +0.011398 +0.011456 +0.011398 +0.011382 +0.011322 +0.011279 +0.011321 +0.011439 +0.011378 +0.011429 +0.01136 +0.011328 +0.011369 +0.011471 +0.011437 +0.011502 +0.011448 +0.011441 +0.011521 +0.011619 +0.0116 +0.000576 +0.01165 +0.011611 +0.011599 +0.011663 +0.01178 +0.011746 +0.011801 +0.011761 +0.011743 +0.011736 +0.011821 +0.011778 +0.01183 +0.011791 +0.011805 +0.011913 +0.012047 +0.012015 +0.012053 +0.011995 +0.011984 +0.012024 +0.01214 +0.012143 +0.012204 +0.012137 +0.012104 +0.01215 +0.012267 +0.012233 +0.012229 +0.01212 +0.012074 +0.012075 +0.012119 +0.01204 +0.012045 +0.011926 +0.011859 +0.011865 +0.011922 +0.011852 +0.011852 +0.011749 +0.011685 +0.011708 +0.011782 +0.011721 +0.011746 +0.011666 +0.011632 +0.011661 +0.011743 +0.011713 +0.011739 +0.011679 +0.011653 +0.011701 +0.011802 +0.011777 +0.011826 +0.011774 +0.011763 +0.011822 +0.011919 +0.011909 +0.000577 +0.01195 +0.011923 +0.011887 +0.011962 +0.012056 +0.012046 +0.0121 +0.012053 +0.012027 +0.012096 +0.012213 +0.012191 +0.012239 +0.012201 +0.012174 +0.012246 +0.012347 +0.01234 +0.012388 +0.012342 +0.012321 +0.012407 +0.012517 +0.012524 +0.012556 +0.012525 +0.012524 +0.012618 +0.012728 +0.012582 +0.012594 +0.012514 +0.012392 +0.012364 +0.012415 +0.012335 +0.01233 +0.012241 +0.012095 +0.01203 +0.012087 +0.012017 +0.012019 +0.011931 +0.011859 +0.011875 +0.011857 +0.011799 +0.011819 +0.011753 +0.011706 +0.01174 +0.011774 +0.011734 +0.011744 +0.011717 +0.011656 +0.011637 +0.011724 +0.011674 +0.011727 +0.011681 +0.011644 +0.011729 +0.011829 +0.011802 +0.011858 +0.011814 +0.011798 +0.011858 +0.011918 +0.01189 +0.000578 +0.011947 +0.011901 +0.011886 +0.011967 +0.012072 +0.012044 +0.012094 +0.012065 +0.012049 +0.012123 +0.012224 +0.01219 +0.012218 +0.012161 +0.012132 +0.01218 +0.012289 +0.012261 +0.01231 +0.012294 +0.012314 +0.012402 +0.012496 +0.012478 +0.012505 +0.012467 +0.012438 +0.012482 +0.012539 +0.012452 +0.012433 +0.012316 +0.012219 +0.012215 +0.012249 +0.012164 +0.012114 +0.012017 +0.011919 +0.011921 +0.011973 +0.011888 +0.011873 +0.01179 +0.011714 +0.011739 +0.011806 +0.011745 +0.011747 +0.011676 +0.011615 +0.011654 +0.011725 +0.01168 +0.011693 +0.011634 +0.011581 +0.011634 +0.011729 +0.011688 +0.011724 +0.011678 +0.011644 +0.011706 +0.011822 +0.011791 +0.011838 +0.011804 +0.011775 +0.011843 +0.000579 +0.011945 +0.011925 +0.011974 +0.011942 +0.011905 +0.011983 +0.012083 +0.012078 +0.012114 +0.012084 +0.012053 +0.012119 +0.01223 +0.012221 +0.012248 +0.012226 +0.012198 +0.01227 +0.012386 +0.012372 +0.012426 +0.012388 +0.012376 +0.012471 +0.012587 +0.012572 +0.012475 +0.012411 +0.012377 +0.012432 +0.012487 +0.012409 +0.012394 +0.012266 +0.012091 +0.012096 +0.012138 +0.012064 +0.01206 +0.011969 +0.011803 +0.011797 +0.011858 +0.011786 +0.011795 +0.011722 +0.011682 +0.011721 +0.011797 +0.011688 +0.011686 +0.011615 +0.011571 +0.011555 +0.01164 +0.011603 +0.011615 +0.011596 +0.011553 +0.011627 +0.011728 +0.011687 +0.011729 +0.011717 +0.011678 +0.011732 +0.011798 +0.011758 +0.011806 +0.011786 +0.00058 +0.011765 +0.011828 +0.01196 +0.011926 +0.011971 +0.011931 +0.011916 +0.012001 +0.012113 +0.012081 +0.012119 +0.012079 +0.012041 +0.012095 +0.012175 +0.012138 +0.012178 +0.012145 +0.01212 +0.012204 +0.012377 +0.012382 +0.012401 +0.012347 +0.012327 +0.012373 +0.012481 +0.012472 +0.012456 +0.01234 +0.01227 +0.012264 +0.012298 +0.012224 +0.012195 +0.012064 +0.011978 +0.011981 +0.012017 +0.011949 +0.011935 +0.011819 +0.011747 +0.011772 +0.011827 +0.011773 +0.011777 +0.011681 +0.011626 +0.011666 +0.011721 +0.01169 +0.0117 +0.011625 +0.011576 +0.011624 +0.011705 +0.011678 +0.011692 +0.011633 +0.011599 +0.011653 +0.011755 +0.011744 +0.011774 +0.01172 +0.011706 +0.011771 +0.011891 +0.011861 +0.000581 +0.011898 +0.011874 +0.011833 +0.01191 +0.012022 +0.012011 +0.012042 +0.012012 +0.011976 +0.012048 +0.012166 +0.012155 +0.012187 +0.01215 +0.012118 +0.012198 +0.012297 +0.012302 +0.012333 +0.012304 +0.012279 +0.012371 +0.012473 +0.012482 +0.012517 +0.012503 +0.012479 +0.01243 +0.012458 +0.01242 +0.012425 +0.012347 +0.01227 +0.012296 +0.012362 +0.012209 +0.012111 +0.012027 +0.011957 +0.011958 +0.01196 +0.011893 +0.011897 +0.011827 +0.011698 +0.011687 +0.011744 +0.011703 +0.011708 +0.011645 +0.011598 +0.011646 +0.011748 +0.011701 +0.011645 +0.011561 +0.011515 +0.011602 +0.011675 +0.011668 +0.011684 +0.011654 +0.011641 +0.011707 +0.01183 +0.011793 +0.011833 +0.011778 +0.011737 +0.000582 +0.011769 +0.011887 +0.011868 +0.011904 +0.011878 +0.011857 +0.011946 +0.012046 +0.012036 +0.01207 +0.01204 +0.012004 +0.012071 +0.012163 +0.012143 +0.012178 +0.012149 +0.012149 +0.012232 +0.01234 +0.012321 +0.012348 +0.012329 +0.012298 +0.012346 +0.012438 +0.012384 +0.012338 +0.012255 +0.012147 +0.012137 +0.012177 +0.012086 +0.012037 +0.011937 +0.011826 +0.011833 +0.01186 +0.011784 +0.011753 +0.011657 +0.011572 +0.011606 +0.01166 +0.011607 +0.011591 +0.011535 +0.011473 +0.011495 +0.011583 +0.011545 +0.011531 +0.011488 +0.011434 +0.011477 +0.01158 +0.011561 +0.01156 +0.011516 +0.011487 +0.011555 +0.011658 +0.011646 +0.011665 +0.011628 +0.011603 +0.011679 +0.011801 +0.000583 +0.011765 +0.01181 +0.011748 +0.011734 +0.011808 +0.01192 +0.01191 +0.01194 +0.011896 +0.011872 +0.011949 +0.012058 +0.012037 +0.012091 +0.012044 +0.012015 +0.012082 +0.012195 +0.012176 +0.012214 +0.012184 +0.012159 +0.012238 +0.012359 +0.012339 +0.012385 +0.012361 +0.012357 +0.012438 +0.012422 +0.012334 +0.012339 +0.012269 +0.01216 +0.012075 +0.012121 +0.012064 +0.01205 +0.011961 +0.011891 +0.011834 +0.01185 +0.011776 +0.011779 +0.011704 +0.011631 +0.01163 +0.011663 +0.01163 +0.011637 +0.01158 +0.011524 +0.011552 +0.011594 +0.011563 +0.011574 +0.011525 +0.011467 +0.011471 +0.011564 +0.011518 +0.011562 +0.011514 +0.011479 +0.011566 +0.011671 +0.011642 +0.011696 +0.011648 +0.011622 +0.011714 +0.011815 +0.000584 +0.011782 +0.011796 +0.011731 +0.011712 +0.011784 +0.011908 +0.011883 +0.011925 +0.011891 +0.011872 +0.011941 +0.012042 +0.012001 +0.012024 +0.011979 +0.011961 +0.012019 +0.012129 +0.012161 +0.012232 +0.012194 +0.01214 +0.012213 +0.01231 +0.01227 +0.012296 +0.012233 +0.012149 +0.012135 +0.012183 +0.012089 +0.012064 +0.011946 +0.011846 +0.011851 +0.011887 +0.011789 +0.011779 +0.011667 +0.011577 +0.011601 +0.011649 +0.011585 +0.011574 +0.011495 +0.011421 +0.01146 +0.011527 +0.011464 +0.011467 +0.011403 +0.011335 +0.011375 +0.011462 +0.011416 +0.01143 +0.011357 +0.011316 +0.011375 +0.011463 +0.011436 +0.011476 +0.011432 +0.0114 +0.011475 +0.011575 +0.011567 +0.011607 +0.011549 +0.011524 +0.000585 +0.011604 +0.011709 +0.011712 +0.011725 +0.01169 +0.011653 +0.011746 +0.011839 +0.011844 +0.011864 +0.011829 +0.011787 +0.011872 +0.011986 +0.011979 +0.012 +0.011974 +0.011943 +0.012019 +0.012134 +0.012134 +0.012163 +0.012143 +0.012119 +0.012217 +0.012304 +0.012209 +0.012231 +0.012183 +0.012092 +0.012048 +0.012098 +0.012031 +0.011997 +0.011924 +0.011799 +0.011726 +0.01177 +0.011711 +0.011682 +0.011634 +0.011545 +0.011542 +0.011554 +0.011509 +0.011526 +0.011458 +0.011403 +0.011464 +0.011502 +0.011489 +0.011458 +0.011393 +0.01134 +0.011404 +0.011508 +0.011461 +0.011471 +0.011405 +0.011363 +0.011467 +0.011548 +0.011532 +0.011574 +0.011529 +0.011519 +0.011596 +0.011686 +0.011691 +0.000586 +0.011706 +0.011674 +0.011644 +0.011654 +0.011755 +0.01175 +0.011795 +0.011758 +0.011744 +0.011821 +0.011931 +0.011902 +0.011943 +0.0119 +0.01187 +0.011944 +0.012078 +0.012067 +0.012102 +0.012052 +0.012031 +0.012116 +0.012215 +0.012208 +0.012247 +0.012176 +0.012116 +0.012121 +0.01216 +0.01207 +0.012028 +0.011896 +0.011799 +0.011787 +0.011813 +0.011731 +0.011699 +0.011583 +0.011488 +0.011499 +0.011547 +0.011482 +0.011471 +0.01138 +0.011312 +0.011331 +0.011411 +0.011365 +0.011358 +0.011289 +0.011234 +0.011264 +0.011343 +0.011315 +0.011316 +0.011251 +0.011219 +0.011265 +0.011354 +0.011342 +0.011375 +0.011334 +0.011308 +0.01135 +0.011464 +0.011457 +0.011494 +0.011456 +0.011419 +0.000587 +0.011494 +0.011602 +0.011585 +0.011619 +0.011604 +0.011554 +0.01162 +0.011732 +0.011736 +0.011753 +0.011722 +0.011686 +0.011762 +0.011863 +0.011858 +0.011893 +0.011858 +0.011829 +0.011915 +0.012009 +0.01201 +0.012041 +0.01202 +0.012007 +0.012087 +0.012197 +0.012169 +0.012074 +0.012029 +0.011976 +0.012016 +0.012087 +0.012016 +0.012006 +0.01187 +0.01176 +0.011763 +0.01183 +0.011766 +0.011752 +0.011686 +0.011593 +0.011522 +0.011589 +0.011535 +0.011544 +0.01149 +0.011424 +0.011485 +0.011557 +0.011525 +0.011464 +0.011365 +0.011326 +0.011383 +0.011466 +0.011426 +0.011461 +0.011418 +0.011375 +0.011422 +0.011472 +0.01146 +0.011507 +0.011464 +0.011444 +0.011513 +0.011609 +0.011617 +0.011646 +0.011598 +0.000588 +0.011594 +0.011664 +0.011767 +0.011746 +0.011766 +0.011706 +0.011688 +0.011759 +0.011863 +0.011833 +0.011874 +0.011824 +0.011795 +0.011844 +0.01195 +0.011929 +0.011985 +0.011997 +0.011989 +0.012046 +0.012153 +0.012126 +0.012154 +0.01211 +0.012096 +0.012149 +0.012209 +0.012118 +0.012104 +0.012009 +0.011889 +0.011895 +0.011933 +0.011821 +0.011809 +0.011683 +0.011587 +0.011589 +0.011623 +0.011543 +0.011532 +0.011433 +0.01135 +0.011379 +0.011435 +0.01137 +0.011385 +0.011298 +0.011226 +0.011257 +0.011323 +0.011268 +0.01129 +0.011219 +0.011154 +0.011193 +0.011278 +0.011242 +0.011269 +0.011223 +0.011193 +0.011237 +0.011332 +0.011322 +0.011375 +0.011328 +0.011306 +0.011352 +0.011456 +0.011458 +0.000589 +0.011497 +0.011466 +0.011431 +0.011491 +0.011591 +0.011566 +0.011624 +0.011595 +0.011569 +0.011621 +0.011723 +0.011713 +0.011754 +0.011708 +0.011693 +0.01177 +0.011871 +0.011865 +0.011917 +0.011876 +0.01186 +0.011949 +0.012062 +0.012 +0.011877 +0.0118 +0.011745 +0.011764 +0.011824 +0.011716 +0.011643 +0.01154 +0.01147 +0.011414 +0.011469 +0.011403 +0.011395 +0.011311 +0.011267 +0.011279 +0.011269 +0.011203 +0.011201 +0.011153 +0.011084 +0.011143 +0.011166 +0.01114 +0.011129 +0.011061 +0.011001 +0.011046 +0.011124 +0.011084 +0.011134 +0.011077 +0.011051 +0.011127 +0.011224 +0.0112 +0.011239 +0.011189 +0.011155 +0.011186 +0.011269 +0.011257 +0.00059 +0.011313 +0.011273 +0.011248 +0.011323 +0.011437 +0.011424 +0.011464 +0.011421 +0.011403 +0.011477 +0.011582 +0.011568 +0.011591 +0.01155 +0.011514 +0.011568 +0.01167 +0.011643 +0.01168 +0.011636 +0.011639 +0.011738 +0.011848 +0.011807 +0.011854 +0.011798 +0.011785 +0.011857 +0.01193 +0.01188 +0.01189 +0.011785 +0.011675 +0.01169 +0.01171 +0.0116 +0.011568 +0.011435 +0.011332 +0.011337 +0.011361 +0.011272 +0.01125 +0.011139 +0.011052 +0.011079 +0.011122 +0.011065 +0.011061 +0.010981 +0.010918 +0.01095 +0.011024 +0.010979 +0.010991 +0.010912 +0.010867 +0.010916 +0.010998 +0.010964 +0.010996 +0.01094 +0.010901 +0.010964 +0.011063 +0.011054 +0.011086 +0.01104 +0.011021 +0.011076 +0.011174 +0.011178 +0.000591 +0.011219 +0.011174 +0.011138 +0.011203 +0.011291 +0.011275 +0.011339 +0.011303 +0.011277 +0.011332 +0.011429 +0.011412 +0.011446 +0.011413 +0.011401 +0.011459 +0.011556 +0.011559 +0.011586 +0.011569 +0.011543 +0.011619 +0.01173 +0.011717 +0.011765 +0.011736 +0.011614 +0.011586 +0.011645 +0.011579 +0.011561 +0.01147 +0.011393 +0.011372 +0.011318 +0.011226 +0.011235 +0.011158 +0.011081 +0.011017 +0.011052 +0.010983 +0.01099 +0.010928 +0.01087 +0.010921 +0.010932 +0.010883 +0.010889 +0.010855 +0.010756 +0.010775 +0.010833 +0.010804 +0.01083 +0.010783 +0.010762 +0.010817 +0.010904 +0.010879 +0.010908 +0.010876 +0.010873 +0.010897 +0.010946 +0.010938 +0.010962 +0.010932 +0.01094 +0.000592 +0.010991 +0.011088 +0.01107 +0.011118 +0.011074 +0.011064 +0.011124 +0.011237 +0.011205 +0.011254 +0.011206 +0.011198 +0.011249 +0.011342 +0.011297 +0.011324 +0.011276 +0.011266 +0.011314 +0.011414 +0.011391 +0.011481 +0.011465 +0.01144 +0.011478 +0.011585 +0.011564 +0.011607 +0.011515 +0.011464 +0.011452 +0.011489 +0.01139 +0.011364 +0.011228 +0.011143 +0.011122 +0.011152 +0.011063 +0.011052 +0.010943 +0.010883 +0.010882 +0.010936 +0.010865 +0.010881 +0.01079 +0.010751 +0.010765 +0.010836 +0.010781 +0.010798 +0.010726 +0.010694 +0.010714 +0.010793 +0.010746 +0.010769 +0.01071 +0.010689 +0.010716 +0.010801 +0.010773 +0.010816 +0.010765 +0.010754 +0.010804 +0.010901 +0.010887 +0.010929 +0.010888 +0.010869 +0.000593 +0.010926 +0.011028 +0.011004 +0.011044 +0.011022 +0.010993 +0.011049 +0.011158 +0.01114 +0.011169 +0.011131 +0.011116 +0.011182 +0.011287 +0.011268 +0.011292 +0.011257 +0.011239 +0.011293 +0.011412 +0.011391 +0.011433 +0.011403 +0.011385 +0.011465 +0.011584 +0.011559 +0.011571 +0.011428 +0.011373 +0.011393 +0.011437 +0.011354 +0.01126 +0.011158 +0.011076 +0.011041 +0.01108 +0.011008 +0.01101 +0.010926 +0.010871 +0.010804 +0.010843 +0.010791 +0.010805 +0.010737 +0.010683 +0.010733 +0.010795 +0.010758 +0.010695 +0.010633 +0.010594 +0.010636 +0.010723 +0.010674 +0.010714 +0.010663 +0.010599 +0.010603 +0.010678 +0.010657 +0.010696 +0.010668 +0.010644 +0.010705 +0.01081 +0.010791 +0.01083 +0.010794 +0.010787 +0.010856 +0.000594 +0.010929 +0.010921 +0.010974 +0.010934 +0.010928 +0.010981 +0.011087 +0.011058 +0.011075 +0.010983 +0.010982 +0.011034 +0.011139 +0.011096 +0.011143 +0.011092 +0.011085 +0.011134 +0.011279 +0.011281 +0.011318 +0.011272 +0.011251 +0.011296 +0.011417 +0.011398 +0.011452 +0.011387 +0.01136 +0.011377 +0.011427 +0.011337 +0.011307 +0.011178 +0.011092 +0.01107 +0.011106 +0.011015 +0.011003 +0.010894 +0.010826 +0.010827 +0.010885 +0.010817 +0.010815 +0.010726 +0.010673 +0.010688 +0.010766 +0.010712 +0.010714 +0.010644 +0.010607 +0.01063 +0.010708 +0.010665 +0.010677 +0.010612 +0.010579 +0.010611 +0.010708 +0.010677 +0.010705 +0.010648 +0.010633 +0.010679 +0.010783 +0.010769 +0.010803 +0.01076 +0.010738 +0.010797 +0.010908 +0.000595 +0.010883 +0.010921 +0.010877 +0.010861 +0.010914 +0.011028 +0.011006 +0.011051 +0.011005 +0.01099 +0.011034 +0.011154 +0.011131 +0.011173 +0.011126 +0.01111 +0.011154 +0.011263 +0.011247 +0.011286 +0.011251 +0.011234 +0.011298 +0.01142 +0.011397 +0.011444 +0.011406 +0.011407 +0.011465 +0.011449 +0.011327 +0.011325 +0.011227 +0.011148 +0.011033 +0.011056 +0.01097 +0.010958 +0.010875 +0.010809 +0.010736 +0.01073 +0.010656 +0.010655 +0.010581 +0.010535 +0.010528 +0.010547 +0.010465 +0.010498 +0.010427 +0.010408 +0.010421 +0.010465 +0.010384 +0.01043 +0.010365 +0.010352 +0.010329 +0.010403 +0.010352 +0.010386 +0.010357 +0.010348 +0.010389 +0.010502 +0.010466 +0.01051 +0.010478 +0.010461 +0.010515 +0.01063 +0.010596 +0.010634 +0.000596 +0.010595 +0.010585 +0.010653 +0.010725 +0.010683 +0.010722 +0.010686 +0.010679 +0.010722 +0.010807 +0.010771 +0.010797 +0.010764 +0.010731 +0.010794 +0.010889 +0.010898 +0.01098 +0.01094 +0.010909 +0.010971 +0.011052 +0.01104 +0.011058 +0.011024 +0.010988 +0.010978 +0.011009 +0.010926 +0.010897 +0.010778 +0.010686 +0.010668 +0.010689 +0.0106 +0.010577 +0.01048 +0.0104 +0.010401 +0.010441 +0.010367 +0.010357 +0.010276 +0.010213 +0.010227 +0.010288 +0.010241 +0.010235 +0.010171 +0.010134 +0.010157 +0.010226 +0.010193 +0.010207 +0.010154 +0.010124 +0.01016 +0.010252 +0.010232 +0.010251 +0.010208 +0.010188 +0.010245 +0.010341 +0.010328 +0.010348 +0.010318 +0.010285 +0.010365 +0.000597 +0.010447 +0.010433 +0.01046 +0.01044 +0.010403 +0.010472 +0.010557 +0.010549 +0.010578 +0.010553 +0.010522 +0.010579 +0.01067 +0.010664 +0.010696 +0.010673 +0.010625 +0.010696 +0.010783 +0.010776 +0.010798 +0.010779 +0.010746 +0.010823 +0.010912 +0.010917 +0.010942 +0.010917 +0.010907 +0.010992 +0.011083 +0.010979 +0.010948 +0.01089 +0.010813 +0.010767 +0.010794 +0.010715 +0.010709 +0.010637 +0.010533 +0.010462 +0.01048 +0.010442 +0.010429 +0.010357 +0.010292 +0.010312 +0.010288 +0.010247 +0.010243 +0.010194 +0.010121 +0.010104 +0.010175 +0.010136 +0.010164 +0.010112 +0.01008 +0.010118 +0.010193 +0.010161 +0.010202 +0.010115 +0.010065 +0.010108 +0.010187 +0.010176 +0.010197 +0.010185 +0.010155 +0.010224 +0.010315 +0.010304 +0.010331 +0.010295 +0.000598 +0.010276 +0.010357 +0.010439 +0.010427 +0.010439 +0.010421 +0.010392 +0.010472 +0.010566 +0.010537 +0.010562 +0.010509 +0.010472 +0.010536 +0.010612 +0.010576 +0.010611 +0.010581 +0.010548 +0.010616 +0.01074 +0.010762 +0.010796 +0.010753 +0.010714 +0.010783 +0.01086 +0.010855 +0.010864 +0.010833 +0.010773 +0.010773 +0.010781 +0.010739 +0.010693 +0.010582 +0.010488 +0.010483 +0.010502 +0.010434 +0.010402 +0.010306 +0.010231 +0.010235 +0.010268 +0.010234 +0.010197 +0.010136 +0.010072 +0.01009 +0.010139 +0.010123 +0.010111 +0.01005 +0.009996 +0.010037 +0.010092 +0.010072 +0.010074 +0.010021 +0.009983 +0.01003 +0.010107 +0.010101 +0.010111 +0.010068 +0.010046 +0.010108 +0.010196 +0.010194 +0.010204 +0.010185 +0.01015 +0.0102 +0.010303 +0.000599 +0.010297 +0.010322 +0.010283 +0.010264 +0.010315 +0.010412 +0.0104 +0.010443 +0.010393 +0.010372 +0.01043 +0.010528 +0.010513 +0.010555 +0.010515 +0.010489 +0.010545 +0.010636 +0.010625 +0.010663 +0.010618 +0.010613 +0.01067 +0.010778 +0.010763 +0.010799 +0.010778 +0.010763 +0.01084 +0.010829 +0.010771 +0.010779 +0.010716 +0.010659 +0.010628 +0.01063 +0.010555 +0.01055 +0.010475 +0.010356 +0.010324 +0.010367 +0.010311 +0.010309 +0.010235 +0.010164 +0.01013 +0.01015 +0.010097 +0.010123 +0.010046 +0.009995 +0.010039 +0.010115 +0.01008 +0.010037 +0.00995 +0.00991 +0.00997 +0.010053 +0.010009 +0.010051 +0.009978 +0.009963 +0.010017 +0.010078 +0.010058 +0.01009 +0.01005 +0.010034 +0.010103 +0.010194 +0.01016 +0.010201 +0.010167 +0.0006 +0.010151 +0.010173 +0.010263 +0.010234 +0.010285 +0.010246 +0.010238 +0.010287 +0.01039 +0.010361 +0.010406 +0.010361 +0.010344 +0.010387 +0.01048 +0.010449 +0.010492 +0.01045 +0.01044 +0.010511 +0.010633 +0.0106 +0.010642 +0.010599 +0.010571 +0.010622 +0.01072 +0.010714 +0.010756 +0.010667 +0.010615 +0.010598 +0.010629 +0.010566 +0.010534 +0.010401 +0.010322 +0.010312 +0.010341 +0.010267 +0.010253 +0.01014 +0.010071 +0.010074 +0.010121 +0.01006 +0.010055 +0.009974 +0.009932 +0.009939 +0.010014 +0.00997 +0.009985 +0.009908 +0.009875 +0.009897 +0.009975 +0.009928 +0.009946 +0.009886 +0.009863 +0.009889 +0.009972 +0.009951 +0.009984 +0.009929 +0.009913 +0.009958 +0.010062 +0.010044 +0.010073 +0.010037 +0.010022 +0.010058 +0.010172 +0.000601 +0.010156 +0.01018 +0.01014 +0.010124 +0.010173 +0.010282 +0.010257 +0.010295 +0.010253 +0.010233 +0.010287 +0.010394 +0.010371 +0.010411 +0.010365 +0.01035 +0.010395 +0.010502 +0.010475 +0.010519 +0.010478 +0.010461 +0.010526 +0.01063 +0.010603 +0.010659 +0.010622 +0.010621 +0.010691 +0.010725 +0.010632 +0.01064 +0.010577 +0.010526 +0.010485 +0.010506 +0.010417 +0.010425 +0.010338 +0.01027 +0.010203 +0.010248 +0.010188 +0.010195 +0.010111 +0.010079 +0.01006 +0.010062 +0.010001 +0.010013 +0.009963 +0.009912 +0.00996 +0.010021 +0.009984 +0.009998 +0.009906 +0.009862 +0.00988 +0.009971 +0.009912 +0.009958 +0.009909 +0.009888 +0.009958 +0.010048 +0.010007 +0.010055 +0.010009 +0.009997 +0.01006 +0.010151 +0.010107 +0.010137 +0.000602 +0.010112 +0.010086 +0.010107 +0.010191 +0.010176 +0.010219 +0.010187 +0.010166 +0.010231 +0.010322 +0.010306 +0.010343 +0.010307 +0.010285 +0.010341 +0.010429 +0.010407 +0.010444 +0.010406 +0.010386 +0.010458 +0.010559 +0.010548 +0.010566 +0.010538 +0.010524 +0.010572 +0.010665 +0.010658 +0.010699 +0.010655 +0.010629 +0.01066 +0.010732 +0.010691 +0.010672 +0.010577 +0.010505 +0.010496 +0.010533 +0.010465 +0.010439 +0.010355 +0.010278 +0.01029 +0.010343 +0.01029 +0.010281 +0.010205 +0.010157 +0.010171 +0.010234 +0.010205 +0.010191 +0.010139 +0.010096 +0.01012 +0.010197 +0.010166 +0.010168 +0.010107 +0.010074 +0.010104 +0.010184 +0.010153 +0.01017 +0.010121 +0.010095 +0.01014 +0.010228 +0.010218 +0.010236 +0.010205 +0.010187 +0.010233 +0.010341 +0.010318 +0.010356 +0.000603 +0.010311 +0.010303 +0.010343 +0.01045 +0.010437 +0.010466 +0.010422 +0.01041 +0.010464 +0.010568 +0.010546 +0.010586 +0.010546 +0.010528 +0.010573 +0.01068 +0.010661 +0.01071 +0.010662 +0.010638 +0.010698 +0.010799 +0.010773 +0.010825 +0.010772 +0.01077 +0.010831 +0.01093 +0.010919 +0.010972 +0.01093 +0.010933 +0.010909 +0.010925 +0.010876 +0.010881 +0.010792 +0.010737 +0.010735 +0.010774 +0.010603 +0.010584 +0.010495 +0.010411 +0.010368 +0.010411 +0.010353 +0.010347 +0.010261 +0.01022 +0.010128 +0.010189 +0.010126 +0.010171 +0.010083 +0.010064 +0.010083 +0.010175 +0.010119 +0.010167 +0.010095 +0.010077 +0.010015 +0.010064 +0.010037 +0.010074 +0.010033 +0.010027 +0.01007 +0.010159 +0.010134 +0.010175 +0.010138 +0.010137 +0.01019 +0.010284 +0.010268 +0.010287 +0.010262 +0.000604 +0.010251 +0.010315 +0.010422 +0.010376 +0.010362 +0.010315 +0.01031 +0.010379 +0.010479 +0.010427 +0.010477 +0.010427 +0.010414 +0.010462 +0.010561 +0.010535 +0.010574 +0.010529 +0.010544 +0.010614 +0.010727 +0.010696 +0.01073 +0.010676 +0.010655 +0.010692 +0.010808 +0.010804 +0.010821 +0.010748 +0.010676 +0.010655 +0.010718 +0.010626 +0.010586 +0.010476 +0.010394 +0.010359 +0.010418 +0.010333 +0.010311 +0.010215 +0.010153 +0.010129 +0.010208 +0.010142 +0.010136 +0.010063 +0.010011 +0.010019 +0.010108 +0.010064 +0.010069 +0.010011 +0.009974 +0.009992 +0.010086 +0.010044 +0.010068 +0.01002 +0.009993 +0.010017 +0.010119 +0.010101 +0.010138 +0.010103 +0.010077 +0.010116 +0.010221 +0.010183 +0.010244 +0.0102 +0.000605 +0.010189 +0.010227 +0.010322 +0.010308 +0.010345 +0.010311 +0.010293 +0.010341 +0.010432 +0.010421 +0.010457 +0.010432 +0.010398 +0.010454 +0.010547 +0.010526 +0.010563 +0.010533 +0.010512 +0.010566 +0.010655 +0.01065 +0.010682 +0.01065 +0.010622 +0.010701 +0.010796 +0.010783 +0.010826 +0.010793 +0.010792 +0.010824 +0.010812 +0.010743 +0.010753 +0.010675 +0.010601 +0.010541 +0.010518 +0.010431 +0.010406 +0.010321 +0.010202 +0.010115 +0.010125 +0.01007 +0.010036 +0.009943 +0.009854 +0.009741 +0.009781 +0.00969 +0.0097 +0.009613 +0.009563 +0.00955 +0.009537 +0.009437 +0.009451 +0.009383 +0.009318 +0.009291 +0.0093 +0.009258 +0.009273 +0.009221 +0.009183 +0.009235 +0.009297 +0.009258 +0.00924 +0.009198 +0.009181 +0.009241 +0.009321 +0.009289 +0.009322 +0.009301 +0.009286 +0.00934 +0.009424 +0.009401 +0.009435 +0.009396 +0.009378 +0.000606 +0.009443 +0.009523 +0.009512 +0.009522 +0.009502 +0.009473 +0.009543 +0.009613 +0.009588 +0.009611 +0.009583 +0.009548 +0.009613 +0.009686 +0.009662 +0.009675 +0.00965 +0.009622 +0.009683 +0.009761 +0.009768 +0.009825 +0.009801 +0.009765 +0.00982 +0.009901 +0.009887 +0.009897 +0.009875 +0.009852 +0.009936 +0.010004 +0.009986 +0.00998 +0.00992 +0.009848 +0.009877 +0.009913 +0.00985 +0.009822 +0.009762 +0.009686 +0.009696 +0.009745 +0.009701 +0.009688 +0.009628 +0.009564 +0.009591 +0.009647 +0.009607 +0.009584 +0.009549 +0.009502 +0.009543 +0.009599 +0.009572 +0.00957 +0.009539 +0.009492 +0.009539 +0.009611 +0.009591 +0.009596 +0.009563 +0.009527 +0.009599 +0.00967 +0.009662 +0.009683 +0.009654 +0.009617 +0.009682 +0.009766 +0.009779 +0.000607 +0.009778 +0.009756 +0.009724 +0.009774 +0.009865 +0.009853 +0.00989 +0.009862 +0.009835 +0.009884 +0.009972 +0.009954 +0.009987 +0.009964 +0.009941 +0.009994 +0.010081 +0.010066 +0.0101 +0.010052 +0.010035 +0.010083 +0.010175 +0.010167 +0.010195 +0.010166 +0.010139 +0.010205 +0.010298 +0.010287 +0.010331 +0.010301 +0.010285 +0.010351 +0.010454 +0.010381 +0.010292 +0.010224 +0.010169 +0.010192 +0.010218 +0.010107 +0.01005 +0.009956 +0.009888 +0.00987 +0.009899 +0.009817 +0.009841 +0.009754 +0.009711 +0.009666 +0.009697 +0.009652 +0.009658 +0.009617 +0.009577 +0.009617 +0.009684 +0.009629 +0.009652 +0.009569 +0.009506 +0.009511 +0.009589 +0.009545 +0.009566 +0.009532 +0.00951 +0.009565 +0.009642 +0.009623 +0.009648 +0.009625 +0.009608 +0.009659 +0.009754 +0.009733 +0.009735 +0.009681 +0.000608 +0.00967 +0.009732 +0.00983 +0.009791 +0.009823 +0.00979 +0.009782 +0.009836 +0.009933 +0.009894 +0.009941 +0.009901 +0.009888 +0.009938 +0.010025 +0.009976 +0.010014 +0.009962 +0.009954 +0.009996 +0.010091 +0.010063 +0.010108 +0.01011 +0.010107 +0.010159 +0.010251 +0.010215 +0.010255 +0.010197 +0.010181 +0.010227 +0.01035 +0.010314 +0.010334 +0.010249 +0.010187 +0.010195 +0.010235 +0.010141 +0.010141 +0.010022 +0.009947 +0.00995 +0.010003 +0.009925 +0.009921 +0.009849 +0.009789 +0.0098 +0.009867 +0.009812 +0.009817 +0.009747 +0.009711 +0.00974 +0.009818 +0.009769 +0.009787 +0.009741 +0.009702 +0.009737 +0.009824 +0.009787 +0.009807 +0.009753 +0.009735 +0.009779 +0.009877 +0.009851 +0.009883 +0.009837 +0.009823 +0.009882 +0.00997 +0.009966 +0.000609 +0.009971 +0.00995 +0.009928 +0.009979 +0.010083 +0.010057 +0.010091 +0.010055 +0.010039 +0.010088 +0.01019 +0.010163 +0.01021 +0.010168 +0.010151 +0.010197 +0.010305 +0.010266 +0.010316 +0.010266 +0.010247 +0.010302 +0.010403 +0.010376 +0.010434 +0.010382 +0.010373 +0.010436 +0.010535 +0.01051 +0.010567 +0.010521 +0.010508 +0.010505 +0.010488 +0.010409 +0.010431 +0.010355 +0.010293 +0.010285 +0.010287 +0.010199 +0.010217 +0.010139 +0.010072 +0.010027 +0.010064 +0.010019 +0.010026 +0.009946 +0.009918 +0.009932 +0.010029 +0.009927 +0.009914 +0.009837 +0.009815 +0.009845 +0.009931 +0.009879 +0.00987 +0.009815 +0.009782 +0.009826 +0.009931 +0.009887 +0.009925 +0.009876 +0.009855 +0.009875 +0.009977 +0.009939 +0.009983 +0.009953 +0.009945 +0.009994 +0.010084 +0.01007 +0.00061 +0.01012 +0.010068 +0.010062 +0.010111 +0.010213 +0.010189 +0.010233 +0.010195 +0.010185 +0.010235 +0.010336 +0.010291 +0.010324 +0.010281 +0.010253 +0.010303 +0.010393 +0.010346 +0.010396 +0.010339 +0.010329 +0.010383 +0.010526 +0.010526 +0.010556 +0.010508 +0.010479 +0.010531 +0.010617 +0.010584 +0.010598 +0.010495 +0.010414 +0.010417 +0.010446 +0.010362 +0.010338 +0.010221 +0.010147 +0.010141 +0.010187 +0.010112 +0.010111 +0.010018 +0.009956 +0.009973 +0.01003 +0.009976 +0.009987 +0.009912 +0.009865 +0.009892 +0.009965 +0.009916 +0.00994 +0.009874 +0.009838 +0.009873 +0.009959 +0.009914 +0.009951 +0.009898 +0.009878 +0.009919 +0.010008 +0.009987 +0.010033 +0.009988 +0.009972 +0.010014 +0.010111 +0.010115 +0.000611 +0.010122 +0.010098 +0.010073 +0.01012 +0.010226 +0.010206 +0.010244 +0.010205 +0.010185 +0.010231 +0.010342 +0.010321 +0.010356 +0.010309 +0.010292 +0.010343 +0.010446 +0.010432 +0.010466 +0.010418 +0.010413 +0.01046 +0.010571 +0.010547 +0.010596 +0.010551 +0.010541 +0.010613 +0.010732 +0.010703 +0.010673 +0.010557 +0.010531 +0.010555 +0.010612 +0.010545 +0.010528 +0.010371 +0.010322 +0.010299 +0.010347 +0.010271 +0.010274 +0.010193 +0.010126 +0.010079 +0.010123 +0.010059 +0.010079 +0.010004 +0.009977 +0.010005 +0.010101 +0.010038 +0.010076 +0.009993 +0.009922 +0.009915 +0.010017 +0.009966 +0.009997 +0.009955 +0.009924 +0.00999 +0.010086 +0.010045 +0.010094 +0.010051 +0.010024 +0.010103 +0.010177 +0.010137 +0.010176 +0.010142 +0.000612 +0.01011 +0.01013 +0.010231 +0.010204 +0.010254 +0.01021 +0.010198 +0.010254 +0.010357 +0.010334 +0.010379 +0.010332 +0.010317 +0.010369 +0.010453 +0.010434 +0.010476 +0.010457 +0.010449 +0.010495 +0.01058 +0.010556 +0.010619 +0.01057 +0.010559 +0.010593 +0.010697 +0.010658 +0.010655 +0.010559 +0.010488 +0.010464 +0.010506 +0.010406 +0.010382 +0.010275 +0.010199 +0.010178 +0.010216 +0.010143 +0.010125 +0.010024 +0.009971 +0.009946 +0.010008 +0.009938 +0.009942 +0.009863 +0.009822 +0.009827 +0.009901 +0.009852 +0.009853 +0.009794 +0.009764 +0.009775 +0.009852 +0.009822 +0.009823 +0.00978 +0.009758 +0.009779 +0.009876 +0.009847 +0.009876 +0.009836 +0.009826 +0.009864 +0.009969 +0.009948 +0.009978 +0.009941 +0.009917 +0.009985 +0.000613 +0.010067 +0.010055 +0.010089 +0.010045 +0.010023 +0.010084 +0.010181 +0.010163 +0.010191 +0.010161 +0.010138 +0.010191 +0.010278 +0.010269 +0.010309 +0.010268 +0.01024 +0.010307 +0.010396 +0.010385 +0.010427 +0.010383 +0.010371 +0.010436 +0.010534 +0.01052 +0.010562 +0.010532 +0.010481 +0.010454 +0.010507 +0.010469 +0.010474 +0.010385 +0.010324 +0.010335 +0.010389 +0.010283 +0.010142 +0.010063 +0.010008 +0.010038 +0.010075 +0.010014 +0.01001 +0.00985 +0.009808 +0.009819 +0.009887 +0.009822 +0.009839 +0.009771 +0.009696 +0.009717 +0.009794 +0.009741 +0.009778 +0.009717 +0.009686 +0.009726 +0.009784 +0.009758 +0.009752 +0.009698 +0.009674 +0.00974 +0.009809 +0.009788 +0.009835 +0.009804 +0.009784 +0.009841 +0.009936 +0.009905 +0.009947 +0.009898 +0.000614 +0.009895 +0.009965 +0.010049 +0.010014 +0.010041 +0.010011 +0.009957 +0.010028 +0.010108 +0.010088 +0.010101 +0.010085 +0.01005 +0.010111 +0.010196 +0.010186 +0.010203 +0.010191 +0.010186 +0.010261 +0.010337 +0.010332 +0.010351 +0.010317 +0.010296 +0.010371 +0.010435 +0.010432 +0.010433 +0.010378 +0.010291 +0.010311 +0.010345 +0.010293 +0.010261 +0.010172 +0.010094 +0.010103 +0.010135 +0.01008 +0.010067 +0.009988 +0.009916 +0.009922 +0.009971 +0.009934 +0.009921 +0.009865 +0.009812 +0.009832 +0.009894 +0.00987 +0.009874 +0.009825 +0.009784 +0.009814 +0.009883 +0.009871 +0.009884 +0.009847 +0.009821 +0.009865 +0.009937 +0.00994 +0.009961 +0.009936 +0.009911 +0.009956 +0.010047 +0.010038 +0.000615 +0.010071 +0.010035 +0.010025 +0.010057 +0.01015 +0.010142 +0.010187 +0.010143 +0.010121 +0.010171 +0.010265 +0.010247 +0.010288 +0.01025 +0.010229 +0.010285 +0.010384 +0.010355 +0.010389 +0.010357 +0.010332 +0.010405 +0.010497 +0.010496 +0.010524 +0.010484 +0.010482 +0.010558 +0.010655 +0.010563 +0.010567 +0.010505 +0.010466 +0.010479 +0.01051 +0.010436 +0.0104 +0.010288 +0.010222 +0.010206 +0.010234 +0.010173 +0.010176 +0.010101 +0.010034 +0.009982 +0.010005 +0.009963 +0.009968 +0.009926 +0.009866 +0.009921 +0.009968 +0.00994 +0.009943 +0.009906 +0.009796 +0.009807 +0.00989 +0.009848 +0.009878 +0.009845 +0.009815 +0.009878 +0.009965 +0.009929 +0.009973 +0.009941 +0.009919 +0.009986 +0.010084 +0.010049 +0.010064 +0.010014 +0.000616 +0.01 +0.010033 +0.010136 +0.010097 +0.010147 +0.010108 +0.010095 +0.010155 +0.010254 +0.010218 +0.010266 +0.010228 +0.010205 +0.010255 +0.010349 +0.01031 +0.010345 +0.010302 +0.010282 +0.01033 +0.010465 +0.010468 +0.010509 +0.010448 +0.010435 +0.010477 +0.010569 +0.010546 +0.010575 +0.010493 +0.010426 +0.010407 +0.01046 +0.010387 +0.010347 +0.010236 +0.010166 +0.010137 +0.010182 +0.010115 +0.010092 +0.010004 +0.00994 +0.009932 +0.00999 +0.009934 +0.009932 +0.009855 +0.009813 +0.009813 +0.00988 +0.009841 +0.009855 +0.009783 +0.00975 +0.009762 +0.00984 +0.009802 +0.009821 +0.009769 +0.009745 +0.009768 +0.009847 +0.009824 +0.00986 +0.009821 +0.009814 +0.009849 +0.009953 +0.009913 +0.009953 +0.009911 +0.009888 +0.009964 +0.000617 +0.010044 +0.010029 +0.01006 +0.010022 +0.010004 +0.010055 +0.010154 +0.010139 +0.010165 +0.010131 +0.010115 +0.010167 +0.010259 +0.010243 +0.010271 +0.010245 +0.010214 +0.010271 +0.010376 +0.010355 +0.010404 +0.010363 +0.010351 +0.010423 +0.010519 +0.010507 +0.010546 +0.010447 +0.010378 +0.010412 +0.010465 +0.010396 +0.010391 +0.010311 +0.010179 +0.010165 +0.010206 +0.010145 +0.010144 +0.010061 +0.009996 +0.009963 +0.009968 +0.009887 +0.009908 +0.009835 +0.009801 +0.009831 +0.009896 +0.009844 +0.009822 +0.009736 +0.009702 +0.009743 +0.009822 +0.009758 +0.009789 +0.009741 +0.009719 +0.00972 +0.009776 +0.009762 +0.009787 +0.009752 +0.009752 +0.009801 +0.009885 +0.009882 +0.009905 +0.009872 +0.009868 +0.009929 +0.009992 +0.000618 +0.009983 +0.01003 +0.009995 +0.009978 +0.01003 +0.010131 +0.010092 +0.010134 +0.010066 +0.010046 +0.010093 +0.01018 +0.010133 +0.010175 +0.010129 +0.010119 +0.010167 +0.010282 +0.010297 +0.010342 +0.010295 +0.010267 +0.010315 +0.010419 +0.010399 +0.010444 +0.010388 +0.010333 +0.010331 +0.010386 +0.010298 +0.010276 +0.010173 +0.010088 +0.01006 +0.01011 +0.010023 +0.010004 +0.009919 +0.009838 +0.009833 +0.009898 +0.009822 +0.009832 +0.009744 +0.009699 +0.009709 +0.009789 +0.009729 +0.009727 +0.009673 +0.009638 +0.009645 +0.009722 +0.009683 +0.009693 +0.009639 +0.009608 +0.009635 +0.009733 +0.009701 +0.009717 +0.009672 +0.009643 +0.009688 +0.009806 +0.009781 +0.009814 +0.009771 +0.009754 +0.00979 +0.009884 +0.009864 +0.000619 +0.009908 +0.009874 +0.009852 +0.009903 +0.009988 +0.009975 +0.010012 +0.009992 +0.009946 +0.010004 +0.010094 +0.010092 +0.010119 +0.010092 +0.01007 +0.010131 +0.010202 +0.010191 +0.010227 +0.010188 +0.010168 +0.010235 +0.010331 +0.010313 +0.010352 +0.010318 +0.010307 +0.010382 +0.010439 +0.010367 +0.010391 +0.010338 +0.010284 +0.010267 +0.010286 +0.010208 +0.010215 +0.010132 +0.010019 +0.010012 +0.010064 +0.010013 +0.010001 +0.009952 +0.009874 +0.009817 +0.009877 +0.009835 +0.009843 +0.009793 +0.009745 +0.009787 +0.00985 +0.009818 +0.009821 +0.009734 +0.009673 +0.009735 +0.009806 +0.009768 +0.0098 +0.009757 +0.009732 +0.009735 +0.009804 +0.009797 +0.009836 +0.0098 +0.009798 +0.00985 +0.009928 +0.009924 +0.009963 +0.009922 +0.009901 +0.00062 +0.009965 +0.010065 +0.010034 +0.010073 +0.010034 +0.010019 +0.01008 +0.010182 +0.010141 +0.010152 +0.010094 +0.010084 +0.010129 +0.010225 +0.010174 +0.010222 +0.010183 +0.010177 +0.010225 +0.010368 +0.010353 +0.010394 +0.010344 +0.010321 +0.010369 +0.010452 +0.010442 +0.010488 +0.010415 +0.010349 +0.010335 +0.010376 +0.010305 +0.010276 +0.010156 +0.010083 +0.010071 +0.010109 +0.010036 +0.010032 +0.009935 +0.009871 +0.009875 +0.009932 +0.00987 +0.009875 +0.009796 +0.009752 +0.009758 +0.009829 +0.009788 +0.009803 +0.009734 +0.009702 +0.009712 +0.009789 +0.009759 +0.009782 +0.009724 +0.009703 +0.009731 +0.009813 +0.009789 +0.009832 +0.009785 +0.009777 +0.009808 +0.009902 +0.009887 +0.009924 +0.009899 +0.009863 +0.000621 +0.009926 +0.010003 +0.009994 +0.010041 +0.009985 +0.009975 +0.010025 +0.010119 +0.010096 +0.01014 +0.010102 +0.010081 +0.010126 +0.010224 +0.010213 +0.010245 +0.010208 +0.010187 +0.010241 +0.010326 +0.010307 +0.01035 +0.010308 +0.010299 +0.010353 +0.010451 +0.01044 +0.010478 +0.010444 +0.010434 +0.010518 +0.010608 +0.0105 +0.010484 +0.01042 +0.010378 +0.010351 +0.01038 +0.010306 +0.010309 +0.01023 +0.010142 +0.010093 +0.010131 +0.010054 +0.010073 +0.010006 +0.009946 +0.009987 +0.010037 +0.009981 +0.009912 +0.009874 +0.009831 +0.009874 +0.009952 +0.009893 +0.00993 +0.009878 +0.009831 +0.009809 +0.00987 +0.009841 +0.009879 +0.009831 +0.00981 +0.009866 +0.009946 +0.009927 +0.009972 +0.009927 +0.009905 +0.009971 +0.010063 +0.010046 +0.010068 +0.010035 +0.000622 +0.010035 +0.01006 +0.010147 +0.010104 +0.010149 +0.010104 +0.010094 +0.010153 +0.010247 +0.010215 +0.010259 +0.010222 +0.010205 +0.010247 +0.010338 +0.010299 +0.010338 +0.010298 +0.010282 +0.010333 +0.010449 +0.010458 +0.010497 +0.010449 +0.010425 +0.010469 +0.010567 +0.010547 +0.010585 +0.010504 +0.010442 +0.010416 +0.010457 +0.010365 +0.010331 +0.010215 +0.010133 +0.010121 +0.010169 +0.010096 +0.010089 +0.009998 +0.009937 +0.009943 +0.010009 +0.009946 +0.009945 +0.009871 +0.009826 +0.009837 +0.009915 +0.009866 +0.009877 +0.009812 +0.009778 +0.009788 +0.00988 +0.009839 +0.009858 +0.009806 +0.009785 +0.009803 +0.009898 +0.009865 +0.009915 +0.009876 +0.009861 +0.009892 +0.009991 +0.009964 +0.009996 +0.009957 +0.009934 +0.000623 +0.010005 +0.010099 +0.010079 +0.010107 +0.01007 +0.010048 +0.010105 +0.010203 +0.010186 +0.010219 +0.010186 +0.010166 +0.010215 +0.010304 +0.010291 +0.010323 +0.010293 +0.010276 +0.01032 +0.010423 +0.010407 +0.010438 +0.010407 +0.010392 +0.010449 +0.010558 +0.010546 +0.010586 +0.010545 +0.01054 +0.010501 +0.010536 +0.010488 +0.010493 +0.010414 +0.010359 +0.010364 +0.010414 +0.01033 +0.010185 +0.01011 +0.010064 +0.010089 +0.010134 +0.010081 +0.010002 +0.009913 +0.009859 +0.009913 +0.009968 +0.009925 +0.009915 +0.009838 +0.009796 +0.009806 +0.009891 +0.009839 +0.009855 +0.009806 +0.009766 +0.009827 +0.009891 +0.00984 +0.009853 +0.009813 +0.009781 +0.009834 +0.009922 +0.009892 +0.009919 +0.009899 +0.009883 +0.009935 +0.010043 +0.010007 +0.010037 +0.009999 +0.000624 +0.009993 +0.010053 +0.010121 +0.010097 +0.010132 +0.010102 +0.010075 +0.010146 +0.010233 +0.010205 +0.01023 +0.010201 +0.010165 +0.010225 +0.010302 +0.010276 +0.010303 +0.010274 +0.010239 +0.010308 +0.010445 +0.010446 +0.010469 +0.010433 +0.010395 +0.010445 +0.01051 +0.010462 +0.010448 +0.010358 +0.010252 +0.010249 +0.010266 +0.010187 +0.010146 +0.010059 +0.009968 +0.009972 +0.010014 +0.009945 +0.009923 +0.009863 +0.009786 +0.009805 +0.009861 +0.009817 +0.009804 +0.009761 +0.009702 +0.009728 +0.009795 +0.009757 +0.00975 +0.009709 +0.009662 +0.009691 +0.009772 +0.009751 +0.009744 +0.009716 +0.009675 +0.009733 +0.009823 +0.009809 +0.009823 +0.009793 +0.009762 +0.00983 +0.009919 +0.009904 +0.009941 +0.009885 +0.000625 +0.009872 +0.009931 +0.010019 +0.010012 +0.01004 +0.009995 +0.009978 +0.010031 +0.010131 +0.010116 +0.010145 +0.010112 +0.010089 +0.010148 +0.010226 +0.010217 +0.010249 +0.010216 +0.010201 +0.01024 +0.010354 +0.010333 +0.010378 +0.010331 +0.010324 +0.010392 +0.010494 +0.010472 +0.010515 +0.010456 +0.010355 +0.010383 +0.010444 +0.010374 +0.01036 +0.010282 +0.010172 +0.010092 +0.010128 +0.010058 +0.010054 +0.009988 +0.009929 +0.009878 +0.009897 +0.00983 +0.009822 +0.009786 +0.009724 +0.009766 +0.009789 +0.009744 +0.009742 +0.009692 +0.009625 +0.009649 +0.0097 +0.00967 +0.00969 +0.009649 +0.009623 +0.009673 +0.009745 +0.009724 +0.00974 +0.009702 +0.009684 +0.009684 +0.009741 +0.009728 +0.009776 +0.009745 +0.009721 +0.009792 +0.009879 +0.009863 +0.009901 +0.009861 +0.000626 +0.009852 +0.009904 +0.009996 +0.009991 +0.010009 +0.00999 +0.009964 +0.010033 +0.010115 +0.010097 +0.010109 +0.010078 +0.010045 +0.010098 +0.010182 +0.01016 +0.010179 +0.010149 +0.010122 +0.010223 +0.010325 +0.010303 +0.010328 +0.010287 +0.010262 +0.010303 +0.01036 +0.010345 +0.010321 +0.010221 +0.010133 +0.010138 +0.010164 +0.010094 +0.010051 +0.00997 +0.009896 +0.009891 +0.009938 +0.0099 +0.009875 +0.009807 +0.009752 +0.009759 +0.009817 +0.00979 +0.009782 +0.009735 +0.009691 +0.009717 +0.009772 +0.009766 +0.009769 +0.00973 +0.009686 +0.009728 +0.009792 +0.009794 +0.00981 +0.009778 +0.009752 +0.009804 +0.009878 +0.009882 +0.009904 +0.009885 +0.009846 +0.009904 +0.000627 +0.009988 +0.009984 +0.01001 +0.009984 +0.009953 +0.010004 +0.010101 +0.010096 +0.01012 +0.010085 +0.010063 +0.010115 +0.01021 +0.010199 +0.010232 +0.010196 +0.010175 +0.010231 +0.010316 +0.010301 +0.010341 +0.010295 +0.010287 +0.01035 +0.010445 +0.01044 +0.01047 +0.010433 +0.010432 +0.010501 +0.010534 +0.010462 +0.010467 +0.010412 +0.010357 +0.010374 +0.010385 +0.010305 +0.010306 +0.010227 +0.010142 +0.010129 +0.010178 +0.010131 +0.010141 +0.010062 +0.010018 +0.010014 +0.010041 +0.00997 +0.009993 +0.009936 +0.009908 +0.009943 +0.010032 +0.009981 +0.009997 +0.009968 +0.009874 +0.009889 +0.009966 +0.009932 +0.009967 +0.00993 +0.009905 +0.009979 +0.010062 +0.010036 +0.010084 +0.010038 +0.010024 +0.010089 +0.010187 +0.010152 +0.010203 +0.000628 +0.010161 +0.010145 +0.010175 +0.01026 +0.010215 +0.010264 +0.01022 +0.010211 +0.01027 +0.01037 +0.010341 +0.010377 +0.010331 +0.010314 +0.010351 +0.010455 +0.010424 +0.010468 +0.010422 +0.010426 +0.010498 +0.010612 +0.010578 +0.010614 +0.010561 +0.010549 +0.01059 +0.010706 +0.010688 +0.010698 +0.010612 +0.010564 +0.010557 +0.010611 +0.010542 +0.010521 +0.010423 +0.010357 +0.010347 +0.010405 +0.01035 +0.010346 +0.010254 +0.010218 +0.010216 +0.010279 +0.010243 +0.010248 +0.010175 +0.010145 +0.010163 +0.010248 +0.010213 +0.010229 +0.010165 +0.010143 +0.010165 +0.010252 +0.010224 +0.010246 +0.010189 +0.010171 +0.010207 +0.010308 +0.010295 +0.010327 +0.01027 +0.010269 +0.010312 +0.010418 +0.010396 +0.000629 +0.010442 +0.010389 +0.010379 +0.010422 +0.010534 +0.010513 +0.010553 +0.010508 +0.010489 +0.010538 +0.010653 +0.010632 +0.010669 +0.010627 +0.01061 +0.010654 +0.010768 +0.010731 +0.01078 +0.010741 +0.010728 +0.010791 +0.010891 +0.010882 +0.010927 +0.010881 +0.010873 +0.010952 +0.01105 +0.010929 +0.010907 +0.010803 +0.010741 +0.010663 +0.01069 +0.01061 +0.010598 +0.01051 +0.010466 +0.010387 +0.010422 +0.010371 +0.010379 +0.010294 +0.010262 +0.010269 +0.010324 +0.010233 +0.010252 +0.010155 +0.010136 +0.010129 +0.010216 +0.010152 +0.010186 +0.010126 +0.01009 +0.010132 +0.010174 +0.010128 +0.01017 +0.010113 +0.0101 +0.010154 +0.010242 +0.010218 +0.010248 +0.010181 +0.010188 +0.010215 +0.010308 +0.010283 +0.010318 +0.010291 +0.00063 +0.010279 +0.010334 +0.010428 +0.010406 +0.01046 +0.010419 +0.010407 +0.010462 +0.010564 +0.010529 +0.010573 +0.01053 +0.010506 +0.010551 +0.010648 +0.010587 +0.010633 +0.010588 +0.010568 +0.010614 +0.010735 +0.010758 +0.010804 +0.010761 +0.010731 +0.010778 +0.010869 +0.010806 +0.010822 +0.010729 +0.010647 +0.010627 +0.010672 +0.010572 +0.010556 +0.010444 +0.01036 +0.010353 +0.010401 +0.010316 +0.010316 +0.010222 +0.010165 +0.010146 +0.010227 +0.01016 +0.010173 +0.010104 +0.01006 +0.010075 +0.010144 +0.010101 +0.010129 +0.010063 +0.010023 +0.010053 +0.010142 +0.010099 +0.010135 +0.010086 +0.010062 +0.010101 +0.010196 +0.010172 +0.010222 +0.010176 +0.010155 +0.010208 +0.010299 +0.010289 +0.000631 +0.010316 +0.010287 +0.010266 +0.010309 +0.01042 +0.010398 +0.010437 +0.010394 +0.01038 +0.010426 +0.010537 +0.010513 +0.010558 +0.010512 +0.010494 +0.010543 +0.010643 +0.010629 +0.010661 +0.010626 +0.010614 +0.01068 +0.010775 +0.010763 +0.010811 +0.010764 +0.010762 +0.010841 +0.010912 +0.010791 +0.010799 +0.01072 +0.01064 +0.010606 +0.010653 +0.010596 +0.010613 +0.010531 +0.010486 +0.010502 +0.010585 +0.010461 +0.010416 +0.010327 +0.010308 +0.010286 +0.010351 +0.010286 +0.010316 +0.010249 +0.010227 +0.010251 +0.010318 +0.010243 +0.010273 +0.010184 +0.010149 +0.010171 +0.010242 +0.010194 +0.010242 +0.010195 +0.010179 +0.010253 +0.010344 +0.010299 +0.010354 +0.01031 +0.010298 +0.010366 +0.010472 +0.010428 +0.000632 +0.010458 +0.010442 +0.01041 +0.010421 +0.0105 +0.010479 +0.010527 +0.010496 +0.010477 +0.010543 +0.010638 +0.010618 +0.010645 +0.010615 +0.010581 +0.010661 +0.010779 +0.010764 +0.010789 +0.010747 +0.010733 +0.010792 +0.01089 +0.010884 +0.010911 +0.010876 +0.010847 +0.010862 +0.010913 +0.010851 +0.010813 +0.010702 +0.010617 +0.010603 +0.010636 +0.010556 +0.010522 +0.010435 +0.010362 +0.010356 +0.010418 +0.010357 +0.010336 +0.010267 +0.010219 +0.010221 +0.010296 +0.010259 +0.010254 +0.010192 +0.010152 +0.010183 +0.010264 +0.010232 +0.010241 +0.010193 +0.010165 +0.010205 +0.010308 +0.010295 +0.010319 +0.010286 +0.010259 +0.010304 +0.010407 +0.010401 +0.010435 +0.010402 +0.000633 +0.01037 +0.010427 +0.010507 +0.010512 +0.010544 +0.010519 +0.01048 +0.010544 +0.010626 +0.010619 +0.010644 +0.010624 +0.010593 +0.010658 +0.010744 +0.010737 +0.010763 +0.01074 +0.010703 +0.010769 +0.010848 +0.010843 +0.010871 +0.010837 +0.010808 +0.010874 +0.010955 +0.010943 +0.010975 +0.010938 +0.010913 +0.010977 +0.011061 +0.011058 +0.011086 +0.011054 +0.011028 +0.011093 +0.011181 +0.011177 +0.011205 +0.011172 +0.011146 +0.011214 +0.011308 +0.011295 +0.011326 +0.011294 +0.01126 +0.011332 +0.011423 +0.011417 +0.011445 +0.011412 +0.011384 +0.011458 +0.011555 +0.011542 +0.011569 +0.01154 +0.011504 +0.011579 +0.011667 +0.011645 +0.011681 +0.011644 +0.011615 +0.011691 +0.011784 +0.011762 +0.011785 +0.011759 +0.011733 +0.011813 +0.011906 +0.011884 +0.011912 +0.011883 +0.011861 +0.011937 +0.012041 +0.012016 +0.012051 +0.012015 +0.011986 +0.012067 +0.012164 +0.012139 +0.012179 +0.012146 +0.012122 +0.012199 +0.012301 +0.012279 +0.012318 +0.012288 +0.01226 +0.012347 +0.012446 +0.012427 +0.012464 +0.012431 +0.012399 +0.012484 +0.012581 +0.012561 +0.012602 +0.012568 +0.012535 +0.012616 +0.012724 +0.012704 +0.012735 +0.012708 +0.012679 +0.012758 +0.012872 +0.01285 +0.012882 +0.012854 +0.012817 +0.012913 +0.013019 +0.013006 +0.013032 +0.013003 +0.012976 +0.013064 +0.013174 +0.013154 +0.01319 +0.013158 +0.01313 +0.01322 +0.01333 +0.013308 +0.013349 +0.013316 +0.013289 +0.013379 +0.013491 +0.013468 +0.013511 +0.013475 +0.013448 +0.01354 +0.013655 +0.013634 +0.013668 +0.013636 +0.013606 +0.013702 +0.013812 +0.013788 +0.013837 +0.013804 +0.013782 +0.013875 +0.013992 +0.013975 +0.014014 +0.013975 +0.013945 +0.014046 +0.014169 +0.014145 +0.014191 +0.014137 +0.014105 +0.014207 +0.014331 +0.014303 +0.014345 +0.01431 +0.014294 +0.014392 +0.014525 +0.014495 +0.014553 +0.014522 +0.0145 +0.014592 +0.014727 +0.014705 +0.014756 +0.014718 +0.014682 +0.014772 +0.014907 +0.014881 +0.014931 +0.014902 +0.014866 +0.014969 +0.015101 +0.015071 +0.015134 +0.015083 +0.015062 +0.015154 +0.015284 +0.015259 +0.015315 +0.015276 +0.015255 +0.015367 +0.015511 +0.015476 +0.01553 +0.015497 +0.01548 +0.015593 +0.015715 +0.015685 +0.015744 +0.015718 +0.015671 +0.015733 +0.015874 +0.015862 +0.015931 +0.015901 +0.015887 +0.016014 +0.016162 +0.016149 +0.016211 +0.016183 +0.016163 +0.016279 +0.016427 +0.016399 +0.016399 +0.016347 +0.016331 +0.016444 +0.016598 +0.016584 +0.016653 +0.01662 +0.016599 +0.016717 +0.016878 +0.016866 +0.016928 +0.016901 +0.016884 +0.017006 +0.017149 +0.017132 +0.017186 +0.017148 +0.017097 +0.017163 +0.017326 +0.017327 +0.017396 +0.017385 +0.017369 +0.017513 +0.017673 +0.017677 +0.017741 +0.017716 +0.017697 +0.017829 +0.017993 +0.017964 +0.017994 +0.017921 +0.017907 +0.018045 +0.01821 +0.018193 +0.018272 +0.018241 +0.018228 +0.018365 +0.018535 +0.018523 +0.0186 +0.018562 +0.01854 +0.01868 +0.018855 +0.018823 +0.018894 +0.018853 +0.018839 +0.018954 +0.019141 +0.019114 +0.019195 +0.019156 +0.019151 +0.019293 +0.019486 +0.01946 +0.019542 +0.019502 +0.019498 +0.019637 +0.019829 +0.019788 +0.019882 +0.019837 +0.019823 +0.019962 +0.020164 +0.020156 +0.020228 +0.020173 +0.020175 +0.020321 +0.020506 +0.02047 +0.020569 +0.020525 +0.020505 +0.020666 +0.020869 +0.020852 +0.020945 +0.020906 +0.0209 +0.021059 +0.021247 +0.021225 +0.021321 +0.021272 +0.021268 +0.021415 +0.02163 +0.021613 +0.021731 +0.021715 +0.021674 +0.021695 +0.021947 +0.021933 +0.022091 +0.022068 +0.022097 +0.022165 +0.022151 +0.021575 +0.020974 +0.020358 +0.019668 +0.019108 +0.018829 +0.018184 +0.017685 +0.01723 +0.016718 +0.0164 +0.016243 +0.015803 +0.01548 +0.015129 +0.014792 +0.014529 +0.014494 +0.014188 +0.01394 +0.013705 +0.013452 +0.013286 +0.013284 +0.013111 +0.012921 +0.012731 +0.012617 +0.012552 +0.01253 +0.012439 +0.012447 +0.012331 +0.012237 +0.012256 +0.01235 +0.012331 +0.012398 +0.012334 +0.012326 +0.012398 +0.012521 +0.012502 +0.012546 +0.012504 +0.012495 +0.012555 +0.012677 +0.000634 +0.012637 +0.012672 +0.012604 +0.012584 +0.012653 +0.012765 +0.01275 +0.012847 +0.012824 +0.012779 +0.012854 +0.012964 +0.012953 +0.012998 +0.012924 +0.012828 +0.012811 +0.012838 +0.012678 +0.012589 +0.012413 +0.012255 +0.012165 +0.012159 +0.011997 +0.011916 +0.011764 +0.011615 +0.011563 +0.011563 +0.011437 +0.011377 +0.011247 +0.011133 +0.011098 +0.011119 +0.011013 +0.010971 +0.010858 +0.010761 +0.010743 +0.010771 +0.010678 +0.010644 +0.010554 +0.010475 +0.010475 +0.010537 +0.010466 +0.010456 +0.010393 +0.010339 +0.01037 +0.010464 +0.010441 +0.01046 +0.010427 +0.010391 +0.010455 +0.01056 +0.010549 +0.010571 +0.010532 +0.010508 +0.010571 +0.010668 +0.010649 +0.000635 +0.010688 +0.01065 +0.010632 +0.010692 +0.010798 +0.01077 +0.010808 +0.010756 +0.010748 +0.010796 +0.010917 +0.01088 +0.010937 +0.010869 +0.010867 +0.010943 +0.011053 +0.011026 +0.011026 +0.010883 +0.010832 +0.010815 +0.010824 +0.01069 +0.01057 +0.01043 +0.010318 +0.010218 +0.010229 +0.010118 +0.010069 +0.009893 +0.009795 +0.009731 +0.00976 +0.009659 +0.009631 +0.00948 +0.009399 +0.009388 +0.009411 +0.009326 +0.009326 +0.009216 +0.009119 +0.0091 +0.009151 +0.009079 +0.009082 +0.009017 +0.008969 +0.008928 +0.008965 +0.008908 +0.008939 +0.008884 +0.008872 +0.008914 +0.008993 +0.008962 +0.009009 +0.008967 +0.008954 +0.009007 +0.009082 +0.009056 +0.009107 +0.009051 +0.009033 +0.009057 +0.00912 +0.000636 +0.009108 +0.009138 +0.009113 +0.0091 +0.009148 +0.009222 +0.009208 +0.009236 +0.009206 +0.009186 +0.009255 +0.009349 +0.009332 +0.009357 +0.009322 +0.009302 +0.00934 +0.00942 +0.009424 +0.009459 +0.009422 +0.009396 +0.009438 +0.009521 +0.009506 +0.0095 +0.009422 +0.009348 +0.009335 +0.009353 +0.00928 +0.00923 +0.009122 +0.009043 +0.009017 +0.009037 +0.008967 +0.008926 +0.008825 +0.008755 +0.008737 +0.008766 +0.008709 +0.008679 +0.0086 +0.008548 +0.008537 +0.008585 +0.008543 +0.008527 +0.008464 +0.008419 +0.00842 +0.008471 +0.00844 +0.008442 +0.00839 +0.008358 +0.008383 +0.008444 +0.008429 +0.008455 +0.008407 +0.008398 +0.008436 +0.008514 +0.008505 +0.008524 +0.008495 +0.008477 +0.008519 +0.008603 +0.008591 +0.008615 +0.008567 +0.000637 +0.008564 +0.0086 +0.008687 +0.008666 +0.008702 +0.008667 +0.00865 +0.008691 +0.008769 +0.008757 +0.008796 +0.008734 +0.008731 +0.00878 +0.008858 +0.008846 +0.008879 +0.008843 +0.008834 +0.008879 +0.008977 +0.008959 +0.008987 +0.008938 +0.008836 +0.008833 +0.008878 +0.008806 +0.008812 +0.008729 +0.008643 +0.008578 +0.008599 +0.008537 +0.00854 +0.008445 +0.008417 +0.00838 +0.008366 +0.008302 +0.008296 +0.008238 +0.008199 +0.008146 +0.00819 +0.008123 +0.008137 +0.008085 +0.008058 +0.008076 +0.008112 +0.008066 +0.008063 +0.008009 +0.007993 +0.007988 +0.008067 +0.008032 +0.008059 +0.008026 +0.008022 +0.008055 +0.00813 +0.008113 +0.008153 +0.008104 +0.008103 +0.008148 +0.00823 +0.008213 +0.008218 +0.008183 +0.000638 +0.008183 +0.008232 +0.008312 +0.008277 +0.008313 +0.00828 +0.008265 +0.008285 +0.00835 +0.008316 +0.008351 +0.008313 +0.0083 +0.008337 +0.00842 +0.008396 +0.008445 +0.008422 +0.008424 +0.008459 +0.008538 +0.008509 +0.00854 +0.008502 +0.008484 +0.008534 +0.008617 +0.008584 +0.008609 +0.008543 +0.00849 +0.008481 +0.008516 +0.008438 +0.008424 +0.00833 +0.008266 +0.008253 +0.008283 +0.008211 +0.008197 +0.008109 +0.008059 +0.008052 +0.008093 +0.00803 +0.00803 +0.007957 +0.007918 +0.007921 +0.007981 +0.00794 +0.007961 +0.007907 +0.007875 +0.0079 +0.007958 +0.007926 +0.00796 +0.007904 +0.007884 +0.007917 +0.007991 +0.007965 +0.008001 +0.007958 +0.007956 +0.007984 +0.00806 +0.008042 +0.008077 +0.00804 +0.008025 +0.008062 +0.000639 +0.008139 +0.008126 +0.008146 +0.008119 +0.008104 +0.008141 +0.008218 +0.008202 +0.008228 +0.008201 +0.008184 +0.008226 +0.0083 +0.008282 +0.008307 +0.008277 +0.008255 +0.008306 +0.008366 +0.008365 +0.008382 +0.008365 +0.008342 +0.008396 +0.008476 +0.008447 +0.008494 +0.008464 +0.00845 +0.008485 +0.008479 +0.008422 +0.008413 +0.008348 +0.008295 +0.008254 +0.008252 +0.008185 +0.008167 +0.008112 +0.008067 +0.008022 +0.008038 +0.007976 +0.007969 +0.00793 +0.007875 +0.007885 +0.007873 +0.007831 +0.007822 +0.007784 +0.007749 +0.007778 +0.007809 +0.007758 +0.007771 +0.007719 +0.007707 +0.007712 +0.007754 +0.007734 +0.007749 +0.007718 +0.007711 +0.007743 +0.007818 +0.007791 +0.007811 +0.007783 +0.007785 +0.007804 +0.007862 +0.007839 +0.007876 +0.00785 +0.007842 +0.007863 +0.007938 +0.00064 +0.00793 +0.007948 +0.007931 +0.007908 +0.007959 +0.008024 +0.008012 +0.008023 +0.008009 +0.007984 +0.008029 +0.008091 +0.008085 +0.008077 +0.008063 +0.008036 +0.008082 +0.008146 +0.008139 +0.008155 +0.008149 +0.008139 +0.008187 +0.008259 +0.008245 +0.00826 +0.008229 +0.0082 +0.008242 +0.008275 +0.008247 +0.008204 +0.008131 +0.008067 +0.008058 +0.008078 +0.008025 +0.007992 +0.007924 +0.007857 +0.007852 +0.007869 +0.007839 +0.007815 +0.007751 +0.007699 +0.007706 +0.007734 +0.007706 +0.007697 +0.00765 +0.007611 +0.00764 +0.007684 +0.007673 +0.007671 +0.007634 +0.007609 +0.007652 +0.00771 +0.007705 +0.007711 +0.007686 +0.007663 +0.007711 +0.007779 +0.007774 +0.007781 +0.007767 +0.007742 +0.007782 +0.007848 +0.000641 +0.007842 +0.007866 +0.00784 +0.007807 +0.007861 +0.007927 +0.00792 +0.007939 +0.007913 +0.007889 +0.007938 +0.007998 +0.007993 +0.00801 +0.00799 +0.007964 +0.008016 +0.008074 +0.008071 +0.008094 +0.008065 +0.008049 +0.008101 +0.008168 +0.008162 +0.00819 +0.008166 +0.008148 +0.00821 +0.008248 +0.008191 +0.008189 +0.008145 +0.008091 +0.008091 +0.008092 +0.008038 +0.008026 +0.007932 +0.007869 +0.007868 +0.007892 +0.007841 +0.00782 +0.007769 +0.007681 +0.007667 +0.007707 +0.007666 +0.007652 +0.007615 +0.007556 +0.007578 +0.007593 +0.007565 +0.007571 +0.007542 +0.007516 +0.007552 +0.007614 +0.007579 +0.007583 +0.007552 +0.007524 +0.007566 +0.007626 +0.007605 +0.007623 +0.007607 +0.007585 +0.007631 +0.007694 +0.007686 +0.007701 +0.007699 +0.007653 +0.007708 +0.000642 +0.007785 +0.007759 +0.007783 +0.007759 +0.007737 +0.007784 +0.007854 +0.00784 +0.007864 +0.007842 +0.007812 +0.007864 +0.007928 +0.007897 +0.007919 +0.007889 +0.007873 +0.007906 +0.00797 +0.007944 +0.007967 +0.007941 +0.007937 +0.00796 +0.008043 +0.008065 +0.008087 +0.008057 +0.008031 +0.008073 +0.008134 +0.008112 +0.00812 +0.008069 +0.008027 +0.008025 +0.008054 +0.00801 +0.007994 +0.007916 +0.007861 +0.00786 +0.007894 +0.007841 +0.007835 +0.007771 +0.00773 +0.007738 +0.007782 +0.007748 +0.007741 +0.007683 +0.007653 +0.007673 +0.007725 +0.007703 +0.007714 +0.00767 +0.00765 +0.007679 +0.007741 +0.00773 +0.00775 +0.007712 +0.007697 +0.007739 +0.007804 +0.007801 +0.007824 +0.007784 +0.007774 +0.007799 +0.007872 +0.000643 +0.007877 +0.007887 +0.007869 +0.007839 +0.00788 +0.007953 +0.00795 +0.007963 +0.00794 +0.007913 +0.00796 +0.008025 +0.008021 +0.008042 +0.008017 +0.00799 +0.008039 +0.008099 +0.008096 +0.008111 +0.008093 +0.008063 +0.008115 +0.008182 +0.008174 +0.008198 +0.008169 +0.008151 +0.008206 +0.00828 +0.008271 +0.008284 +0.00828 +0.008264 +0.008302 +0.008279 +0.008232 +0.008219 +0.008174 +0.008122 +0.008122 +0.008102 +0.008034 +0.008016 +0.007963 +0.007891 +0.007867 +0.007893 +0.007839 +0.00784 +0.007786 +0.007746 +0.00772 +0.007736 +0.007697 +0.007695 +0.007667 +0.007627 +0.00766 +0.007721 +0.007679 +0.007698 +0.007657 +0.007615 +0.007622 +0.007671 +0.007656 +0.007666 +0.007654 +0.007625 +0.007679 +0.007745 +0.007727 +0.007739 +0.007729 +0.007702 +0.00775 +0.007821 +0.007829 +0.007817 +0.007805 +0.000644 +0.007791 +0.007838 +0.007911 +0.00788 +0.007903 +0.007874 +0.007842 +0.007873 +0.007939 +0.007915 +0.007945 +0.007917 +0.007897 +0.007936 +0.008008 +0.00799 +0.00802 +0.007996 +0.007995 +0.008041 +0.008116 +0.008097 +0.008119 +0.008088 +0.008075 +0.008113 +0.008187 +0.008175 +0.008201 +0.008159 +0.008121 +0.008148 +0.008169 +0.008125 +0.008103 +0.008025 +0.007963 +0.007963 +0.007986 +0.007934 +0.007922 +0.007846 +0.007795 +0.007816 +0.007833 +0.007803 +0.007796 +0.007738 +0.007694 +0.007705 +0.007745 +0.007718 +0.00773 +0.007681 +0.00765 +0.007679 +0.00773 +0.007708 +0.007729 +0.007694 +0.007668 +0.007706 +0.007766 +0.007753 +0.007784 +0.007754 +0.00774 +0.007775 +0.007843 +0.007831 +0.007853 +0.007814 +0.007802 +0.000645 +0.007851 +0.007921 +0.007908 +0.007921 +0.007902 +0.007875 +0.007925 +0.007988 +0.007988 +0.008 +0.007984 +0.007944 +0.007996 +0.00806 +0.008059 +0.008082 +0.00806 +0.008031 +0.00808 +0.008146 +0.008144 +0.008155 +0.008148 +0.008103 +0.008176 +0.008232 +0.008242 +0.00825 +0.00824 +0.008224 +0.008216 +0.008249 +0.008219 +0.008223 +0.008185 +0.008131 +0.008149 +0.008188 +0.008134 +0.008107 +0.007975 +0.007911 +0.007929 +0.007963 +0.00793 +0.007903 +0.007824 +0.007763 +0.00777 +0.007813 +0.007778 +0.00777 +0.007733 +0.007697 +0.00771 +0.007742 +0.00771 +0.007726 +0.007693 +0.007676 +0.007715 +0.007774 +0.007752 +0.007759 +0.007748 +0.007715 +0.007741 +0.007784 +0.007768 +0.007789 +0.007776 +0.007746 +0.007807 +0.007869 +0.00786 +0.007879 +0.007864 +0.00784 +0.007887 +0.000646 +0.007965 +0.00793 +0.007962 +0.007941 +0.007918 +0.007972 +0.008036 +0.00803 +0.008044 +0.008023 +0.007998 +0.008046 +0.008105 +0.008094 +0.008108 +0.008084 +0.008053 +0.008105 +0.008159 +0.008152 +0.008166 +0.008165 +0.008144 +0.008196 +0.008264 +0.00825 +0.008264 +0.008239 +0.008196 +0.008232 +0.008274 +0.008225 +0.0082 +0.008136 +0.008057 +0.008061 +0.008085 +0.008034 +0.007994 +0.007943 +0.007878 +0.007889 +0.007928 +0.007887 +0.007873 +0.007827 +0.007771 +0.007792 +0.007828 +0.007809 +0.007803 +0.007772 +0.00773 +0.00776 +0.007816 +0.007792 +0.007806 +0.007789 +0.007752 +0.007798 +0.00785 +0.007843 +0.007864 +0.007847 +0.007817 +0.007871 +0.007926 +0.007918 +0.007944 +0.007907 +0.007894 +0.000647 +0.007944 +0.008006 +0.007997 +0.008012 +0.007989 +0.00797 +0.00802 +0.008081 +0.008073 +0.008089 +0.00807 +0.008044 +0.008096 +0.008155 +0.008151 +0.008166 +0.008144 +0.008126 +0.008173 +0.008237 +0.008228 +0.008248 +0.008222 +0.008203 +0.008254 +0.008333 +0.008333 +0.008329 +0.008327 +0.008306 +0.008371 +0.008427 +0.008343 +0.008331 +0.008278 +0.008214 +0.008189 +0.008198 +0.008141 +0.008116 +0.008041 +0.007964 +0.007946 +0.007978 +0.007933 +0.007911 +0.007865 +0.007795 +0.007777 +0.007789 +0.007764 +0.007747 +0.00773 +0.007665 +0.007712 +0.007763 +0.007729 +0.007709 +0.007656 +0.00763 +0.007676 +0.007724 +0.007712 +0.007715 +0.007691 +0.007681 +0.007724 +0.00777 +0.007769 +0.007768 +0.007745 +0.007733 +0.007764 +0.007816 +0.00781 +0.007833 +0.007815 +0.007789 +0.007861 +0.000648 +0.007903 +0.007883 +0.007913 +0.007886 +0.007869 +0.007918 +0.007991 +0.007974 +0.007997 +0.00797 +0.00795 +0.007997 +0.008065 +0.00804 +0.008051 +0.008026 +0.008009 +0.00805 +0.008121 +0.008084 +0.008115 +0.008087 +0.008062 +0.008111 +0.008207 +0.008203 +0.00823 +0.008188 +0.008152 +0.00818 +0.008223 +0.008171 +0.008158 +0.008078 +0.008003 +0.008008 +0.008043 +0.007978 +0.007957 +0.00789 +0.007832 +0.007832 +0.007874 +0.007834 +0.007828 +0.007764 +0.007712 +0.007729 +0.007778 +0.007744 +0.007759 +0.0077 +0.00767 +0.007698 +0.007756 +0.007735 +0.007754 +0.007719 +0.007683 +0.007721 +0.007787 +0.007776 +0.007804 +0.007778 +0.007761 +0.007791 +0.007863 +0.007848 +0.007872 +0.007831 +0.007808 +0.000649 +0.00786 +0.007925 +0.007937 +0.007948 +0.007924 +0.007901 +0.007951 +0.007999 +0.007997 +0.008014 +0.007989 +0.00796 +0.008011 +0.008078 +0.008079 +0.008098 +0.008077 +0.008052 +0.008105 +0.008159 +0.008152 +0.008173 +0.008151 +0.008121 +0.008182 +0.008242 +0.008243 +0.008259 +0.008237 +0.008223 +0.008284 +0.008351 +0.008307 +0.008283 +0.008249 +0.0082 +0.008219 +0.008239 +0.008177 +0.008106 +0.008039 +0.007979 +0.00797 +0.007981 +0.00793 +0.007912 +0.007852 +0.007812 +0.00779 +0.007808 +0.007767 +0.007757 +0.007723 +0.007666 +0.007681 +0.007706 +0.007668 +0.007686 +0.007637 +0.007621 +0.007641 +0.007685 +0.007656 +0.007663 +0.007647 +0.007617 +0.007679 +0.007736 +0.007719 +0.007744 +0.007702 +0.007671 +0.007716 +0.007765 +0.007751 +0.00778 +0.007762 +0.007738 +0.007803 +0.00785 +0.00065 +0.007839 +0.007864 +0.007836 +0.007819 +0.007869 +0.007935 +0.007922 +0.00795 +0.007918 +0.007903 +0.007944 +0.008019 +0.007988 +0.008011 +0.007979 +0.007958 +0.007998 +0.00807 +0.008048 +0.008074 +0.008038 +0.008022 +0.008087 +0.008165 +0.008164 +0.008173 +0.008135 +0.008103 +0.008115 +0.008171 +0.00812 +0.008112 +0.008038 +0.007977 +0.007972 +0.008014 +0.007962 +0.007937 +0.007864 +0.007811 +0.007806 +0.00785 +0.007817 +0.007791 +0.007732 +0.007685 +0.007694 +0.007745 +0.00772 +0.007713 +0.007668 +0.007638 +0.007662 +0.00773 +0.007712 +0.007724 +0.007688 +0.007668 +0.007698 +0.007771 +0.007769 +0.007783 +0.007762 +0.007739 +0.007775 +0.007848 +0.007826 +0.007853 +0.00781 +0.000651 +0.007796 +0.007845 +0.007919 +0.007913 +0.007925 +0.007907 +0.007878 +0.00792 +0.007984 +0.00799 +0.00801 +0.007983 +0.007959 +0.008002 +0.008065 +0.008062 +0.008072 +0.00805 +0.008029 +0.008075 +0.008136 +0.008134 +0.008159 +0.008129 +0.008108 +0.008165 +0.008219 +0.008227 +0.008246 +0.008221 +0.008207 +0.008261 +0.00833 +0.008325 +0.008333 +0.008235 +0.008177 +0.008195 +0.008231 +0.008185 +0.008131 +0.008036 +0.007967 +0.007973 +0.00801 +0.00796 +0.007923 +0.007888 +0.007804 +0.007802 +0.007836 +0.007806 +0.007807 +0.007759 +0.007729 +0.007727 +0.007763 +0.007731 +0.007737 +0.007723 +0.00768 +0.007737 +0.007777 +0.007752 +0.007771 +0.007739 +0.007727 +0.007752 +0.007796 +0.007794 +0.007804 +0.007785 +0.00777 +0.007812 +0.007881 +0.007874 +0.007888 +0.007883 +0.00784 +0.007901 +0.000652 +0.007969 +0.00795 +0.007977 +0.007951 +0.007936 +0.007981 +0.008053 +0.008032 +0.008061 +0.008032 +0.008016 +0.008061 +0.00813 +0.008108 +0.008123 +0.008086 +0.008069 +0.008103 +0.008175 +0.008146 +0.008169 +0.008141 +0.008133 +0.008152 +0.008241 +0.008255 +0.00828 +0.008247 +0.008197 +0.008192 +0.008231 +0.008162 +0.008135 +0.008079 +0.008016 +0.007996 +0.008033 +0.007972 +0.007958 +0.007899 +0.007847 +0.007847 +0.007893 +0.007847 +0.007842 +0.007794 +0.007744 +0.007765 +0.007804 +0.007775 +0.007783 +0.007752 +0.007717 +0.007742 +0.007807 +0.007783 +0.007795 +0.007775 +0.00775 +0.007785 +0.007857 +0.00784 +0.007863 +0.007836 +0.007811 +0.007859 +0.00793 +0.007921 +0.00793 +0.007905 +0.000653 +0.007899 +0.007935 +0.008009 +0.007993 +0.008027 +0.007972 +0.00797 +0.008 +0.008082 +0.008063 +0.008097 +0.008061 +0.008053 +0.008083 +0.008165 +0.008139 +0.008175 +0.008132 +0.008122 +0.008163 +0.008235 +0.008212 +0.008252 +0.008211 +0.008202 +0.008244 +0.00833 +0.008305 +0.008353 +0.008307 +0.008301 +0.008346 +0.008421 +0.008372 +0.008312 +0.008201 +0.008144 +0.008157 +0.008201 +0.008088 +0.008073 +0.007987 +0.007936 +0.007914 +0.007967 +0.007896 +0.007892 +0.007842 +0.007747 +0.007747 +0.007802 +0.007747 +0.007767 +0.007712 +0.007691 +0.007724 +0.007771 +0.007732 +0.007723 +0.00768 +0.007675 +0.007694 +0.007776 +0.007732 +0.007761 +0.007741 +0.007726 +0.007768 +0.007849 +0.007809 +0.007835 +0.00783 +0.007792 +0.007826 +0.007911 +0.007881 +0.000654 +0.007911 +0.007877 +0.007874 +0.007895 +0.007963 +0.007923 +0.007963 +0.007926 +0.007929 +0.007965 +0.008048 +0.008023 +0.008056 +0.008015 +0.008008 +0.008035 +0.008114 +0.008085 +0.008114 +0.008082 +0.008071 +0.008112 +0.008201 +0.008192 +0.008215 +0.008175 +0.008167 +0.008204 +0.008278 +0.008249 +0.008264 +0.008193 +0.008147 +0.00814 +0.008176 +0.008116 +0.008104 +0.008021 +0.007969 +0.007957 +0.007999 +0.007946 +0.007937 +0.007859 +0.007821 +0.007825 +0.007867 +0.007824 +0.007834 +0.007763 +0.007737 +0.007746 +0.007802 +0.007782 +0.0078 +0.007753 +0.007736 +0.007763 +0.007827 +0.007804 +0.007837 +0.007799 +0.007795 +0.007826 +0.007894 +0.007881 +0.007905 +0.007882 +0.00785 +0.007887 +0.007977 +0.000655 +0.007946 +0.007983 +0.007954 +0.007944 +0.007962 +0.008048 +0.008027 +0.00806 +0.008024 +0.008012 +0.00805 +0.008124 +0.008106 +0.00814 +0.008104 +0.008089 +0.008126 +0.0082 +0.008179 +0.008218 +0.008175 +0.008163 +0.008212 +0.008292 +0.008272 +0.008306 +0.008266 +0.008265 +0.008312 +0.008394 +0.008368 +0.00838 +0.008245 +0.00819 +0.008172 +0.008209 +0.008145 +0.008079 +0.007991 +0.007943 +0.007907 +0.007939 +0.007871 +0.007864 +0.007805 +0.00777 +0.00777 +0.007775 +0.007727 +0.007725 +0.007685 +0.00765 +0.007651 +0.007703 +0.00765 +0.007687 +0.007638 +0.007631 +0.007665 +0.007721 +0.007697 +0.007725 +0.007669 +0.007676 +0.007677 +0.007747 +0.007726 +0.007748 +0.007727 +0.007718 +0.007751 +0.007832 +0.007819 +0.007832 +0.007803 +0.00781 +0.000656 +0.00783 +0.00791 +0.007894 +0.007929 +0.007886 +0.007879 +0.007913 +0.008 +0.007977 +0.00801 +0.007973 +0.007967 +0.008004 +0.008085 +0.008051 +0.008081 +0.008043 +0.008028 +0.00806 +0.008134 +0.008103 +0.008119 +0.008079 +0.008073 +0.0081 +0.008177 +0.008157 +0.008204 +0.008185 +0.008171 +0.008184 +0.008222 +0.008151 +0.008131 +0.008038 +0.008 +0.007984 +0.008016 +0.007944 +0.007938 +0.007859 +0.007811 +0.007799 +0.007846 +0.007788 +0.007793 +0.00772 +0.007684 +0.007688 +0.00774 +0.007699 +0.00771 +0.007652 +0.007632 +0.007651 +0.007719 +0.00769 +0.007712 +0.007663 +0.007643 +0.007676 +0.007748 +0.007734 +0.007761 +0.007721 +0.007708 +0.00774 +0.007817 +0.0078 +0.007826 +0.007798 +0.007783 +0.007813 +0.000657 +0.007888 +0.007882 +0.007901 +0.007877 +0.007843 +0.007895 +0.007966 +0.007954 +0.007978 +0.007954 +0.00793 +0.007962 +0.008043 +0.008031 +0.008055 +0.008023 +0.008009 +0.008043 +0.008116 +0.008104 +0.008133 +0.008098 +0.008084 +0.008131 +0.008205 +0.008188 +0.008224 +0.008196 +0.00818 +0.008236 +0.008308 +0.008285 +0.008224 +0.008148 +0.008097 +0.008114 +0.008165 +0.008099 +0.008034 +0.00795 +0.007904 +0.007936 +0.007965 +0.007905 +0.007871 +0.0078 +0.007772 +0.007767 +0.007805 +0.007756 +0.007764 +0.007718 +0.007693 +0.007678 +0.007738 +0.007703 +0.007704 +0.007689 +0.007662 +0.007705 +0.00776 +0.007734 +0.007753 +0.007721 +0.007721 +0.007731 +0.007789 +0.007771 +0.007788 +0.007763 +0.007757 +0.007792 +0.007863 +0.007855 +0.007878 +0.007851 +0.007839 +0.000658 +0.007897 +0.007939 +0.007932 +0.007961 +0.007928 +0.007923 +0.007967 +0.008049 +0.008022 +0.008047 +0.008012 +0.008 +0.008025 +0.008089 +0.008048 +0.008077 +0.008041 +0.008032 +0.008069 +0.008153 +0.00812 +0.008162 +0.008158 +0.008147 +0.008186 +0.008261 +0.008219 +0.008235 +0.008163 +0.008108 +0.008105 +0.008143 +0.008069 +0.00806 +0.007977 +0.007923 +0.007913 +0.007953 +0.007887 +0.007887 +0.00782 +0.00777 +0.007771 +0.007822 +0.007764 +0.007771 +0.00771 +0.007673 +0.007686 +0.007746 +0.007704 +0.007733 +0.007686 +0.007662 +0.007687 +0.007752 +0.007721 +0.007751 +0.007722 +0.007714 +0.007738 +0.007822 +0.007794 +0.007832 +0.007793 +0.007771 +0.007802 +0.007878 +0.007865 +0.000659 +0.007895 +0.007861 +0.007857 +0.007889 +0.007965 +0.007947 +0.007974 +0.007933 +0.007923 +0.007952 +0.008031 +0.008012 +0.008056 +0.008015 +0.008005 +0.008038 +0.008122 +0.008099 +0.008124 +0.008091 +0.008084 +0.008115 +0.0082 +0.008175 +0.008218 +0.008182 +0.008174 +0.008229 +0.008315 +0.008264 +0.008233 +0.008181 +0.008157 +0.00817 +0.008219 +0.008141 +0.00813 +0.007991 +0.007949 +0.007933 +0.007975 +0.007902 +0.007911 +0.007825 +0.007767 +0.007749 +0.007797 +0.007751 +0.007762 +0.007708 +0.007683 +0.00767 +0.007725 +0.007664 +0.007695 +0.007661 +0.007639 +0.007684 +0.007745 +0.007708 +0.007736 +0.007689 +0.007689 +0.007692 +0.007751 +0.007731 +0.007755 +0.007732 +0.007722 +0.007756 +0.007839 +0.007814 +0.007848 +0.00781 +0.007811 +0.007861 +0.00066 +0.007903 +0.007899 +0.007935 +0.007895 +0.007889 +0.007922 +0.008004 +0.007986 +0.008023 +0.007979 +0.007976 +0.008012 +0.008093 +0.008057 +0.008083 +0.008039 +0.008024 +0.008049 +0.008126 +0.008086 +0.008116 +0.008075 +0.00807 +0.008099 +0.008194 +0.008196 +0.008242 +0.008195 +0.008164 +0.008167 +0.008216 +0.008139 +0.008126 +0.008044 +0.008002 +0.007989 +0.008025 +0.007958 +0.007954 +0.007879 +0.007823 +0.007815 +0.007853 +0.007801 +0.007804 +0.007732 +0.007687 +0.007685 +0.007735 +0.007691 +0.007703 +0.007658 +0.007632 +0.00764 +0.0077 +0.007667 +0.007682 +0.00764 +0.007631 +0.007654 +0.007728 +0.007699 +0.00773 +0.007692 +0.007677 +0.007714 +0.007789 +0.007753 +0.007794 +0.007764 +0.00776 +0.007799 +0.007865 +0.000661 +0.007846 +0.007871 +0.007838 +0.007824 +0.007853 +0.007927 +0.007903 +0.007937 +0.007898 +0.007898 +0.007935 +0.008016 +0.007995 +0.008027 +0.007983 +0.007974 +0.008005 +0.008087 +0.008064 +0.0081 +0.008053 +0.008045 +0.008093 +0.008168 +0.008152 +0.008183 +0.008151 +0.008143 +0.008194 +0.008279 +0.008196 +0.0082 +0.008133 +0.0081 +0.008074 +0.0081 +0.008043 +0.00804 +0.007944 +0.007872 +0.007849 +0.007899 +0.007838 +0.007838 +0.007783 +0.007746 +0.007745 +0.007739 +0.007697 +0.007697 +0.007662 +0.007634 +0.007647 +0.00772 +0.007665 +0.007697 +0.007621 +0.007621 +0.007635 +0.007703 +0.007682 +0.007696 +0.007672 +0.007668 +0.007703 +0.007787 +0.007746 +0.00779 +0.007754 +0.007753 +0.007771 +0.00784 +0.00781 +0.000662 +0.007835 +0.007819 +0.007806 +0.007851 +0.007923 +0.007895 +0.007921 +0.007897 +0.007873 +0.007909 +0.007971 +0.007959 +0.007978 +0.007955 +0.007935 +0.007973 +0.008041 +0.008015 +0.008046 +0.00801 +0.007998 +0.008046 +0.008106 +0.008117 +0.008144 +0.008126 +0.008099 +0.008142 +0.008208 +0.008187 +0.008206 +0.008164 +0.008124 +0.008135 +0.008155 +0.008095 +0.008089 +0.00802 +0.007956 +0.007957 +0.007987 +0.007942 +0.007932 +0.007875 +0.007836 +0.007855 +0.007896 +0.007848 +0.007856 +0.007812 +0.007784 +0.0078 +0.007852 +0.00782 +0.007829 +0.007796 +0.007774 +0.007816 +0.007873 +0.007845 +0.007859 +0.007821 +0.007795 +0.007841 +0.007917 +0.007906 +0.007937 +0.007897 +0.007882 +0.007913 +0.007984 +0.007978 +0.008 +0.000663 +0.007978 +0.007967 +0.007994 +0.008081 +0.008051 +0.00808 +0.008042 +0.008029 +0.008061 +0.00815 +0.008128 +0.008163 +0.008122 +0.008114 +0.008147 +0.008238 +0.008201 +0.008239 +0.008206 +0.008192 +0.008225 +0.008303 +0.00828 +0.008318 +0.008276 +0.008277 +0.008317 +0.008402 +0.008384 +0.008418 +0.00839 +0.008381 +0.008375 +0.008357 +0.008289 +0.008278 +0.008204 +0.008144 +0.008069 +0.008105 +0.008031 +0.008042 +0.007969 +0.007917 +0.007938 +0.007948 +0.00788 +0.007857 +0.007781 +0.007758 +0.007754 +0.007814 +0.007761 +0.007762 +0.007705 +0.007676 +0.007691 +0.007746 +0.00771 +0.007734 +0.007685 +0.007676 +0.007706 +0.007775 +0.007753 +0.00779 +0.007751 +0.007746 +0.007742 +0.007803 +0.007788 +0.007814 +0.007781 +0.007785 +0.007822 +0.007901 +0.007873 +0.007905 +0.000664 +0.007875 +0.007868 +0.007908 +0.007963 +0.007951 +0.007988 +0.007956 +0.007946 +0.007981 +0.008062 +0.008039 +0.008069 +0.008029 +0.00802 +0.008057 +0.008125 +0.008096 +0.00812 +0.008081 +0.008077 +0.008103 +0.008185 +0.008158 +0.008193 +0.008172 +0.008176 +0.008208 +0.008294 +0.008248 +0.008258 +0.008191 +0.008138 +0.008123 +0.008169 +0.008104 +0.008089 +0.008009 +0.007958 +0.007943 +0.007988 +0.007904 +0.007905 +0.007846 +0.0078 +0.007798 +0.007848 +0.007793 +0.007784 +0.00773 +0.007698 +0.007711 +0.007776 +0.007733 +0.00774 +0.007695 +0.007665 +0.00768 +0.007757 +0.00773 +0.007753 +0.007715 +0.007701 +0.007727 +0.007808 +0.007784 +0.007814 +0.007779 +0.007759 +0.007794 +0.007871 +0.007859 +0.00789 +0.007849 +0.000665 +0.007829 +0.007882 +0.007947 +0.007933 +0.007957 +0.007926 +0.007906 +0.007948 +0.008022 +0.008014 +0.008034 +0.008 +0.007983 +0.008026 +0.008104 +0.008088 +0.008117 +0.008079 +0.008058 +0.008108 +0.008174 +0.008162 +0.008191 +0.008157 +0.008142 +0.008197 +0.008269 +0.008253 +0.008291 +0.00826 +0.008258 +0.008279 +0.008281 +0.008216 +0.008208 +0.008149 +0.008098 +0.008067 +0.008062 +0.008004 +0.00799 +0.007932 +0.007856 +0.007833 +0.007867 +0.007822 +0.007818 +0.007778 +0.007713 +0.007694 +0.007725 +0.007691 +0.007688 +0.007666 +0.007621 +0.007663 +0.007718 +0.007694 +0.007702 +0.007675 +0.007655 +0.007665 +0.007725 +0.007699 +0.007718 +0.007708 +0.007684 +0.007739 +0.007795 +0.00777 +0.007803 +0.007776 +0.007761 +0.00781 +0.007896 +0.007853 +0.000666 +0.00787 +0.007856 +0.007837 +0.007875 +0.007923 +0.007906 +0.007929 +0.007928 +0.007882 +0.00794 +0.008003 +0.007986 +0.008007 +0.007984 +0.007962 +0.008009 +0.00807 +0.008061 +0.008072 +0.008051 +0.008024 +0.008097 +0.008171 +0.008164 +0.008181 +0.008146 +0.008125 +0.008158 +0.008209 +0.008199 +0.008185 +0.008119 +0.008055 +0.008048 +0.008071 +0.008028 +0.007995 +0.007927 +0.007874 +0.007866 +0.00789 +0.007856 +0.007838 +0.007781 +0.007731 +0.00775 +0.007789 +0.007765 +0.007744 +0.007695 +0.007653 +0.007682 +0.007736 +0.00773 +0.007727 +0.007691 +0.007661 +0.007691 +0.007742 +0.007737 +0.007744 +0.007731 +0.007711 +0.007755 +0.007812 +0.007809 +0.007818 +0.007806 +0.007769 +0.007813 +0.007878 +0.007883 +0.000667 +0.007894 +0.007878 +0.007852 +0.007895 +0.007963 +0.007945 +0.007965 +0.00794 +0.007926 +0.007969 +0.008042 +0.008028 +0.008055 +0.00801 +0.008 +0.008044 +0.008115 +0.008107 +0.008129 +0.0081 +0.008079 +0.008118 +0.008196 +0.00818 +0.008207 +0.008174 +0.008165 +0.00821 +0.008291 +0.008275 +0.008299 +0.008274 +0.008266 +0.008297 +0.008277 +0.00821 +0.00821 +0.008153 +0.008094 +0.008092 +0.00807 +0.007987 +0.007988 +0.007928 +0.007885 +0.00788 +0.007916 +0.007847 +0.007826 +0.007784 +0.00773 +0.007737 +0.007765 +0.007728 +0.007742 +0.0077 +0.007682 +0.007717 +0.007774 +0.007754 +0.007759 +0.007738 +0.007717 +0.007745 +0.0078 +0.00777 +0.007799 +0.007776 +0.007752 +0.007811 +0.007867 +0.007845 +0.007885 +0.007849 +0.007847 +0.007882 +0.000668 +0.00796 +0.007944 +0.00795 +0.007939 +0.007907 +0.007939 +0.007996 +0.007984 +0.008004 +0.007985 +0.00796 +0.008018 +0.008081 +0.008071 +0.008079 +0.008058 +0.008035 +0.008081 +0.008147 +0.00814 +0.008151 +0.008137 +0.00812 +0.008179 +0.008245 +0.008233 +0.008253 +0.008228 +0.008205 +0.008243 +0.008306 +0.008282 +0.008262 +0.008195 +0.008133 +0.008134 +0.008154 +0.008106 +0.008082 +0.008016 +0.007955 +0.007972 +0.007994 +0.00796 +0.007941 +0.007901 +0.007856 +0.007866 +0.00791 +0.007885 +0.007876 +0.007833 +0.007795 +0.007826 +0.007883 +0.007866 +0.007868 +0.007838 +0.007807 +0.007837 +0.007903 +0.0079 +0.007912 +0.007889 +0.007865 +0.007904 +0.007974 +0.007966 +0.007984 +0.007971 +0.007929 +0.007983 +0.000669 +0.008049 +0.008044 +0.008064 +0.008031 +0.008016 +0.008061 +0.00812 +0.008117 +0.008139 +0.008111 +0.008094 +0.008133 +0.008205 +0.008191 +0.008219 +0.008199 +0.008158 +0.008209 +0.008288 +0.00827 +0.008296 +0.008264 +0.008254 +0.008291 +0.008369 +0.008358 +0.008389 +0.008358 +0.008354 +0.008399 +0.008482 +0.008453 +0.008434 +0.0083 +0.00826 +0.008283 +0.008315 +0.008227 +0.008173 +0.008099 +0.008055 +0.008054 +0.008077 +0.008009 +0.008019 +0.007956 +0.007897 +0.007868 +0.007928 +0.007867 +0.007878 +0.007826 +0.007806 +0.007827 +0.00788 +0.007847 +0.007813 +0.007786 +0.00776 +0.007784 +0.007855 +0.007817 +0.007829 +0.00781 +0.007792 +0.007829 +0.00791 +0.007883 +0.007902 +0.007887 +0.007871 +0.007906 +0.007977 +0.007945 +0.007978 +0.007938 +0.00067 +0.007936 +0.007968 +0.00801 +0.008004 +0.008024 +0.008011 +0.007977 +0.008034 +0.008101 +0.008093 +0.008111 +0.008091 +0.008066 +0.008115 +0.008175 +0.008164 +0.008179 +0.008157 +0.008131 +0.008199 +0.008262 +0.008263 +0.008272 +0.008253 +0.008226 +0.008277 +0.008347 +0.008339 +0.008338 +0.008296 +0.008238 +0.008228 +0.008247 +0.008191 +0.008148 +0.008075 +0.008001 +0.007992 +0.008015 +0.007971 +0.00794 +0.007881 +0.007833 +0.007842 +0.007877 +0.007842 +0.007828 +0.007783 +0.00773 +0.007751 +0.007802 +0.007786 +0.00778 +0.007747 +0.007713 +0.007741 +0.007804 +0.007791 +0.007798 +0.007773 +0.007745 +0.007783 +0.007847 +0.007843 +0.007857 +0.007838 +0.007809 +0.007852 +0.007922 +0.007912 +0.007948 +0.007896 +0.000671 +0.007887 +0.007931 +0.007996 +0.00799 +0.008006 +0.007987 +0.007963 +0.008007 +0.008073 +0.008066 +0.008086 +0.008064 +0.008039 +0.008087 +0.008149 +0.008142 +0.008159 +0.008138 +0.008117 +0.008161 +0.008226 +0.008224 +0.00824 +0.008229 +0.008192 +0.008251 +0.008326 +0.008321 +0.008343 +0.008319 +0.008305 +0.008346 +0.008328 +0.008268 +0.008245 +0.00819 +0.008105 +0.008068 +0.008087 +0.00805 +0.008033 +0.007968 +0.007913 +0.007899 +0.00788 +0.00786 +0.007844 +0.007821 +0.007761 +0.007794 +0.007806 +0.007772 +0.007756 +0.007734 +0.007692 +0.007697 +0.007751 +0.007713 +0.007731 +0.007704 +0.007666 +0.007726 +0.007779 +0.007767 +0.00779 +0.007766 +0.007745 +0.007803 +0.007854 +0.007842 +0.007877 +0.007817 +0.007818 +0.00788 +0.000672 +0.007936 +0.007906 +0.007911 +0.007892 +0.007857 +0.007914 +0.007971 +0.007965 +0.007988 +0.00797 +0.007947 +0.008004 +0.008063 +0.008053 +0.008059 +0.008042 +0.008011 +0.008065 +0.008117 +0.00811 +0.008123 +0.008104 +0.008083 +0.008129 +0.00821 +0.00822 +0.008242 +0.008204 +0.008177 +0.008225 +0.008268 +0.008242 +0.008236 +0.008178 +0.008103 +0.00811 +0.008127 +0.008077 +0.008053 +0.007983 +0.007908 +0.007924 +0.007952 +0.00793 +0.00788 +0.007846 +0.007793 +0.007816 +0.007845 +0.007816 +0.007816 +0.007773 +0.007726 +0.00776 +0.007805 +0.00779 +0.007796 +0.007763 +0.007731 +0.007774 +0.007825 +0.007817 +0.007838 +0.007813 +0.007791 +0.007839 +0.007886 +0.007892 +0.007911 +0.007866 +0.00785 +0.007901 +0.000673 +0.00797 +0.007963 +0.007979 +0.007957 +0.007931 +0.007984 +0.008042 +0.008044 +0.008051 +0.008034 +0.008008 +0.008061 +0.008123 +0.008118 +0.008134 +0.00811 +0.008084 +0.008133 +0.008203 +0.008194 +0.008209 +0.008188 +0.008162 +0.008209 +0.008278 +0.00827 +0.008297 +0.00827 +0.008253 +0.008311 +0.008383 +0.008375 +0.008389 +0.008361 +0.008301 +0.008233 +0.008246 +0.008191 +0.008173 +0.008125 +0.008042 +0.007987 +0.007997 +0.007945 +0.007926 +0.007899 +0.007827 +0.007863 +0.007839 +0.007796 +0.007777 +0.007751 +0.007696 +0.007698 +0.007721 +0.007694 +0.0077 +0.007668 +0.007644 +0.007686 +0.007731 +0.007718 +0.007724 +0.0077 +0.00769 +0.007726 +0.007776 +0.00775 +0.007764 +0.007753 +0.007724 +0.00778 +0.007847 +0.007825 +0.007847 +0.007839 +0.007809 +0.000674 +0.007846 +0.007918 +0.007873 +0.0079 +0.007886 +0.007866 +0.007923 +0.007988 +0.007972 +0.007985 +0.007967 +0.007942 +0.007993 +0.00806 +0.008046 +0.00806 +0.008035 +0.00801 +0.008062 +0.008112 +0.008099 +0.008114 +0.008096 +0.008064 +0.008126 +0.00821 +0.00821 +0.008228 +0.008199 +0.008157 +0.008194 +0.008225 +0.008188 +0.008166 +0.008082 +0.007999 +0.008009 +0.008031 +0.007966 +0.007947 +0.00788 +0.007809 +0.007814 +0.007837 +0.007804 +0.007779 +0.007729 +0.007664 +0.007686 +0.007723 +0.007695 +0.00768 +0.007641 +0.007599 +0.007635 +0.007686 +0.007672 +0.00768 +0.007648 +0.007606 +0.007653 +0.007712 +0.007709 +0.00773 +0.007703 +0.007674 +0.007724 +0.007779 +0.007776 +0.007788 +0.007764 +0.007751 +0.000675 +0.007772 +0.007854 +0.007851 +0.00787 +0.00784 +0.007823 +0.00786 +0.00793 +0.007916 +0.007941 +0.007916 +0.007897 +0.007929 +0.008006 +0.007995 +0.008024 +0.007993 +0.007972 +0.008013 +0.008084 +0.008077 +0.008096 +0.008065 +0.008055 +0.008093 +0.008178 +0.008161 +0.008193 +0.008178 +0.00815 +0.008199 +0.008238 +0.008191 +0.008192 +0.008153 +0.008097 +0.00808 +0.008089 +0.008024 +0.008029 +0.007967 +0.007874 +0.007853 +0.007902 +0.00784 +0.007837 +0.007787 +0.007757 +0.007723 +0.007763 +0.007707 +0.007711 +0.007674 +0.007639 +0.007653 +0.007699 +0.007661 +0.007671 +0.007643 +0.007612 +0.007638 +0.007682 +0.00766 +0.007689 +0.007654 +0.007653 +0.007688 +0.007759 +0.007734 +0.007754 +0.007727 +0.007719 +0.007759 +0.00785 +0.007806 +0.007845 +0.000676 +0.007812 +0.007798 +0.007857 +0.007913 +0.007894 +0.007899 +0.00787 +0.007851 +0.007896 +0.007952 +0.007942 +0.007956 +0.007941 +0.007913 +0.007966 +0.008026 +0.008013 +0.008026 +0.008006 +0.007981 +0.008031 +0.008089 +0.008103 +0.008135 +0.008118 +0.008086 +0.008137 +0.008195 +0.008182 +0.008193 +0.008148 +0.0081 +0.008124 +0.008157 +0.008105 +0.00808 +0.00802 +0.007953 +0.007968 +0.007976 +0.00794 +0.007928 +0.007861 +0.007796 +0.007815 +0.007849 +0.007809 +0.007797 +0.007745 +0.007695 +0.007721 +0.007755 +0.00773 +0.007741 +0.007703 +0.007664 +0.007703 +0.007751 +0.007743 +0.007742 +0.007719 +0.007692 +0.007746 +0.007799 +0.007798 +0.007814 +0.007783 +0.007764 +0.00781 +0.00787 +0.007867 +0.007894 +0.007854 +0.000677 +0.007838 +0.007882 +0.007949 +0.007943 +0.007957 +0.007935 +0.007912 +0.007959 +0.008025 +0.008021 +0.008035 +0.008016 +0.007985 +0.008033 +0.008094 +0.008093 +0.008115 +0.008091 +0.008063 +0.008117 +0.008182 +0.008173 +0.008194 +0.008172 +0.008143 +0.008207 +0.008274 +0.008266 +0.008292 +0.008273 +0.008252 +0.008281 +0.008284 +0.008245 +0.008227 +0.008178 +0.008113 +0.008119 +0.008139 +0.008023 +0.00798 +0.007928 +0.007892 +0.00787 +0.007872 +0.007848 +0.00782 +0.007786 +0.007734 +0.007712 +0.007723 +0.007681 +0.007682 +0.007644 +0.007611 +0.007645 +0.007691 +0.007678 +0.007668 +0.007656 +0.007614 +0.007622 +0.007665 +0.007637 +0.007657 +0.007642 +0.007608 +0.007671 +0.007727 +0.007716 +0.007732 +0.007714 +0.00769 +0.007737 +0.007804 +0.00781 +0.0078 +0.00779 +0.007779 +0.000678 +0.007825 +0.007892 +0.007872 +0.007901 +0.007868 +0.007862 +0.007912 +0.007981 +0.007949 +0.007936 +0.007906 +0.007893 +0.007932 +0.008001 +0.007975 +0.008001 +0.007975 +0.007951 +0.007999 +0.008094 +0.0081 +0.008121 +0.008083 +0.008066 +0.008099 +0.008173 +0.008156 +0.008193 +0.008155 +0.008125 +0.008145 +0.008189 +0.008146 +0.008139 +0.008065 +0.008006 +0.00801 +0.008041 +0.007993 +0.00798 +0.007912 +0.007868 +0.007863 +0.007908 +0.007871 +0.007876 +0.007812 +0.007772 +0.007797 +0.007829 +0.007805 +0.00782 +0.007778 +0.007744 +0.007775 +0.007831 +0.007811 +0.007831 +0.007791 +0.007777 +0.007811 +0.007885 +0.007861 +0.007897 +0.007859 +0.007852 +0.007885 +0.007953 +0.007945 +0.007956 +0.007932 +0.000679 +0.007925 +0.007954 +0.008037 +0.008013 +0.008044 +0.008006 +0.007998 +0.008032 +0.008114 +0.008093 +0.008133 +0.008078 +0.008075 +0.008109 +0.008189 +0.008172 +0.008202 +0.008153 +0.008146 +0.00819 +0.008266 +0.008251 +0.008289 +0.008249 +0.008239 +0.00829 +0.008374 +0.008351 +0.008388 +0.008341 +0.008317 +0.008241 +0.008279 +0.008205 +0.008206 +0.008143 +0.008092 +0.008055 +0.008042 +0.007976 +0.007978 +0.007916 +0.007878 +0.007884 +0.007919 +0.007837 +0.007844 +0.007768 +0.007756 +0.007739 +0.007788 +0.007742 +0.007752 +0.007719 +0.007699 +0.007724 +0.007804 +0.00775 +0.007764 +0.007726 +0.007713 +0.007736 +0.007816 +0.007779 +0.007815 +0.007784 +0.007764 +0.007818 +0.007886 +0.007855 +0.007901 +0.007878 +0.007831 +0.007893 +0.00068 +0.007982 +0.007931 +0.007969 +0.007945 +0.007941 +0.007975 +0.008063 +0.008005 +0.008031 +0.007995 +0.007982 +0.008028 +0.008104 +0.00807 +0.008103 +0.008063 +0.008049 +0.008084 +0.008162 +0.008135 +0.008166 +0.008131 +0.008129 +0.008186 +0.008272 +0.008256 +0.008273 +0.008235 +0.008223 +0.008238 +0.008303 +0.008262 +0.008264 +0.008165 +0.008116 +0.008106 +0.008149 +0.008084 +0.008075 +0.007995 +0.007954 +0.007936 +0.007989 +0.007941 +0.00794 +0.007877 +0.007839 +0.007834 +0.007898 +0.007851 +0.007858 +0.007809 +0.00778 +0.007795 +0.007867 +0.007836 +0.007846 +0.007804 +0.007783 +0.00781 +0.007889 +0.007869 +0.007893 +0.007861 +0.007849 +0.007863 +0.007955 +0.007937 +0.007971 +0.007934 +0.007931 +0.007936 +0.000681 +0.008029 +0.008012 +0.00804 +0.008015 +0.007995 +0.008029 +0.008101 +0.008088 +0.008117 +0.008091 +0.008077 +0.008107 +0.008183 +0.008167 +0.008192 +0.008162 +0.008144 +0.008182 +0.008258 +0.008248 +0.00827 +0.008242 +0.008224 +0.008274 +0.008345 +0.008344 +0.008367 +0.008335 +0.008329 +0.00839 +0.008445 +0.008411 +0.008345 +0.008252 +0.008203 +0.008224 +0.008258 +0.008171 +0.008142 +0.008079 +0.008031 +0.008026 +0.008075 +0.008011 +0.00802 +0.007944 +0.007886 +0.007892 +0.007942 +0.007901 +0.00791 +0.007861 +0.007842 +0.007873 +0.007939 +0.007916 +0.007918 +0.007867 +0.007835 +0.007853 +0.007934 +0.007905 +0.007923 +0.007905 +0.007883 +0.007934 +0.008002 +0.007966 +0.008001 +0.00797 +0.007955 +0.008024 +0.008072 +0.008042 +0.000682 +0.008086 +0.008054 +0.008036 +0.008041 +0.008121 +0.008092 +0.008129 +0.008092 +0.008086 +0.008131 +0.008211 +0.008184 +0.008218 +0.008181 +0.008173 +0.008205 +0.008281 +0.008257 +0.008291 +0.008261 +0.008261 +0.008293 +0.008378 +0.008351 +0.008382 +0.008351 +0.008339 +0.008378 +0.008449 +0.008407 +0.008418 +0.008347 +0.008289 +0.008273 +0.008304 +0.008232 +0.008222 +0.008132 +0.008078 +0.008066 +0.008109 +0.008047 +0.008043 +0.007969 +0.00793 +0.007921 +0.007975 +0.007924 +0.007927 +0.007861 +0.007825 +0.007848 +0.007908 +0.007872 +0.007892 +0.007841 +0.007819 +0.007836 +0.007905 +0.007882 +0.007916 +0.00787 +0.007851 +0.007887 +0.00796 +0.007939 +0.00797 +0.00793 +0.007925 +0.007962 +0.008035 +0.008012 +0.008049 +0.000683 +0.008008 +0.008004 +0.008028 +0.00811 +0.008094 +0.008131 +0.008083 +0.008076 +0.008108 +0.008193 +0.008166 +0.008206 +0.008165 +0.008157 +0.00819 +0.008267 +0.008246 +0.008282 +0.008238 +0.008231 +0.008274 +0.008358 +0.008339 +0.008375 +0.008334 +0.00833 +0.008378 +0.008465 +0.008435 +0.00841 +0.008295 +0.008262 +0.008272 +0.008329 +0.008254 +0.008211 +0.008118 +0.008092 +0.008083 +0.008122 +0.008064 +0.008058 +0.007968 +0.007919 +0.007901 +0.007971 +0.007901 +0.007921 +0.007852 +0.00784 +0.007835 +0.007882 +0.007844 +0.007862 +0.007817 +0.007802 +0.007838 +0.007896 +0.00785 +0.007887 +0.00784 +0.007833 +0.007855 +0.007914 +0.007893 +0.007924 +0.007887 +0.00789 +0.007927 +0.008001 +0.007978 +0.008033 +0.007969 +0.007973 +0.000684 +0.008007 +0.008091 +0.008069 +0.008094 +0.008067 +0.008051 +0.008101 +0.00818 +0.008154 +0.008173 +0.008153 +0.008134 +0.008149 +0.008208 +0.008179 +0.0082 +0.008179 +0.008155 +0.008208 +0.00827 +0.008278 +0.008322 +0.008299 +0.008279 +0.008313 +0.008385 +0.008369 +0.008373 +0.008326 +0.008295 +0.008272 +0.008303 +0.008245 +0.008205 +0.00813 +0.008071 +0.00806 +0.008075 +0.008027 +0.008004 +0.007941 +0.007895 +0.007894 +0.007933 +0.007888 +0.007879 +0.007819 +0.007779 +0.007785 +0.007835 +0.007806 +0.007809 +0.007768 +0.007744 +0.007762 +0.00782 +0.007797 +0.007805 +0.00778 +0.007766 +0.007796 +0.007865 +0.007853 +0.007859 +0.007837 +0.007817 +0.007847 +0.007924 +0.007901 +0.00794 +0.00791 +0.0079 +0.007937 +0.000685 +0.008 +0.007988 +0.008014 +0.007974 +0.007967 +0.008001 +0.008084 +0.008065 +0.008094 +0.008053 +0.008044 +0.00808 +0.008162 +0.008142 +0.008179 +0.008133 +0.00812 +0.008166 +0.008232 +0.00822 +0.008256 +0.008221 +0.00821 +0.008262 +0.008338 +0.008313 +0.00835 +0.008321 +0.008299 +0.008243 +0.008291 +0.008237 +0.008248 +0.008178 +0.008133 +0.008144 +0.008191 +0.008072 +0.00804 +0.007975 +0.007938 +0.007927 +0.007963 +0.007892 +0.007906 +0.007845 +0.007776 +0.007788 +0.007834 +0.007793 +0.007811 +0.007765 +0.007753 +0.00777 +0.007855 +0.007806 +0.007845 +0.007806 +0.007787 +0.007805 +0.007852 +0.007832 +0.007863 +0.007829 +0.007831 +0.007862 +0.007937 +0.007916 +0.007953 +0.007914 +0.007906 +0.007949 +0.000686 +0.008038 +0.007991 +0.008027 +0.008 +0.007981 +0.008034 +0.008107 +0.008081 +0.008114 +0.008088 +0.008062 +0.00812 +0.008183 +0.008157 +0.008161 +0.008129 +0.008108 +0.008148 +0.008214 +0.008196 +0.00822 +0.008184 +0.008168 +0.008211 +0.008311 +0.008315 +0.008342 +0.008308 +0.008269 +0.00829 +0.008341 +0.008284 +0.008262 +0.008206 +0.008143 +0.008138 +0.008177 +0.008119 +0.00812 +0.008033 +0.007983 +0.007983 +0.008031 +0.007991 +0.007985 +0.007942 +0.007874 +0.007896 +0.007942 +0.007909 +0.007919 +0.007879 +0.007842 +0.007862 +0.007921 +0.007897 +0.007917 +0.007884 +0.007848 +0.007878 +0.007943 +0.007926 +0.007958 +0.007934 +0.0079 +0.007952 +0.008018 +0.008 +0.008024 +0.007985 +0.007971 +0.007994 +0.000687 +0.008082 +0.00807 +0.008108 +0.008073 +0.008067 +0.008083 +0.008164 +0.008146 +0.008176 +0.008137 +0.008124 +0.008161 +0.008238 +0.008226 +0.008263 +0.008223 +0.008214 +0.008246 +0.008332 +0.008308 +0.008342 +0.008304 +0.008305 +0.008334 +0.008434 +0.008408 +0.008445 +0.008407 +0.008356 +0.00835 +0.008405 +0.008353 +0.008359 +0.008291 +0.00825 +0.008262 +0.008307 +0.008148 +0.008144 +0.008072 +0.008046 +0.008033 +0.008053 +0.008002 +0.007999 +0.007955 +0.007918 +0.007897 +0.007928 +0.007869 +0.007884 +0.007853 +0.007818 +0.007855 +0.007914 +0.007875 +0.007903 +0.007849 +0.007847 +0.007865 +0.007905 +0.00788 +0.007905 +0.007865 +0.007871 +0.007907 +0.007975 +0.007955 +0.007987 +0.007946 +0.007941 +0.007989 +0.008065 +0.008052 +0.008054 +0.000688 +0.008033 +0.008024 +0.008066 +0.008141 +0.008121 +0.008154 +0.008114 +0.008101 +0.008117 +0.008186 +0.008159 +0.008192 +0.008158 +0.008146 +0.008182 +0.008258 +0.008233 +0.008258 +0.008231 +0.008241 +0.008293 +0.00837 +0.008346 +0.008366 +0.00833 +0.008314 +0.008337 +0.008412 +0.008352 +0.008348 +0.008276 +0.008213 +0.008204 +0.008256 +0.008183 +0.008171 +0.008107 +0.008058 +0.008034 +0.008089 +0.008046 +0.008049 +0.00799 +0.007944 +0.00795 +0.008009 +0.007964 +0.007975 +0.007928 +0.007904 +0.007907 +0.007982 +0.007943 +0.007963 +0.007924 +0.007903 +0.007919 +0.008 +0.007976 +0.008006 +0.007972 +0.007958 +0.007988 +0.00807 +0.008039 +0.008074 +0.00804 +0.008016 +0.008057 +0.008149 +0.000689 +0.008122 +0.008154 +0.008116 +0.0081 +0.008132 +0.008219 +0.008206 +0.008233 +0.008193 +0.00818 +0.008215 +0.008295 +0.008276 +0.008312 +0.008279 +0.008263 +0.008299 +0.008385 +0.008355 +0.00839 +0.008358 +0.00835 +0.00839 +0.008483 +0.008456 +0.008491 +0.008465 +0.00846 +0.008449 +0.008445 +0.00838 +0.008387 +0.008322 +0.008276 +0.008288 +0.008309 +0.008204 +0.008191 +0.008121 +0.008078 +0.008066 +0.008096 +0.008046 +0.008049 +0.007993 +0.00794 +0.007911 +0.007965 +0.007904 +0.00793 +0.007874 +0.007856 +0.007886 +0.00794 +0.007893 +0.007869 +0.007833 +0.007816 +0.007843 +0.007926 +0.007879 +0.007921 +0.00788 +0.007861 +0.007882 +0.007948 +0.007912 +0.007958 +0.00792 +0.007914 +0.00796 +0.008034 +0.008026 +0.00803 +0.008007 +0.00069 +0.007999 +0.008032 +0.008119 +0.008096 +0.008128 +0.008093 +0.008085 +0.008115 +0.008201 +0.008169 +0.008204 +0.008164 +0.008147 +0.008174 +0.008252 +0.008218 +0.008244 +0.008207 +0.008194 +0.008233 +0.008311 +0.008299 +0.008363 +0.008321 +0.008324 +0.008332 +0.008397 +0.008358 +0.008348 +0.008265 +0.008229 +0.008211 +0.008237 +0.008176 +0.008164 +0.008076 +0.008026 +0.008008 +0.008046 +0.007995 +0.007993 +0.007923 +0.007894 +0.007888 +0.007933 +0.007892 +0.007896 +0.00784 +0.007826 +0.007837 +0.0079 +0.007871 +0.00789 +0.00784 +0.007833 +0.007857 +0.007929 +0.007908 +0.007935 +0.007896 +0.007897 +0.007924 +0.008003 +0.007985 +0.00801 +0.007973 +0.007948 +0.007997 +0.000691 +0.008071 +0.008075 +0.008075 +0.008056 +0.008034 +0.00807 +0.008143 +0.008136 +0.008163 +0.008132 +0.008113 +0.008156 +0.008228 +0.008217 +0.008238 +0.0082 +0.008188 +0.008235 +0.00831 +0.008308 +0.008313 +0.008292 +0.008281 +0.008318 +0.008402 +0.008392 +0.008412 +0.008399 +0.008381 +0.008434 +0.008471 +0.008409 +0.008415 +0.008357 +0.008308 +0.008291 +0.008304 +0.008249 +0.008243 +0.008157 +0.008086 +0.008074 +0.008117 +0.008061 +0.008055 +0.008016 +0.007966 +0.007968 +0.007975 +0.007929 +0.007934 +0.007891 +0.007857 +0.007896 +0.007948 +0.007927 +0.007906 +0.007855 +0.007841 +0.007871 +0.007947 +0.007921 +0.007933 +0.007918 +0.007896 +0.007941 +0.00802 +0.007989 +0.008009 +0.008004 +0.007937 +0.007978 +0.008053 +0.008019 +0.000692 +0.008059 +0.008033 +0.008025 +0.008055 +0.008143 +0.008118 +0.008151 +0.008109 +0.00811 +0.008146 +0.00823 +0.008198 +0.008237 +0.008195 +0.008187 +0.008224 +0.008295 +0.008269 +0.008299 +0.008262 +0.008246 +0.008277 +0.008364 +0.008356 +0.008396 +0.008359 +0.008341 +0.008378 +0.008456 +0.008413 +0.008443 +0.008373 +0.008323 +0.008314 +0.008351 +0.008283 +0.008277 +0.008192 +0.008139 +0.008131 +0.008168 +0.008104 +0.008108 +0.008038 +0.007999 +0.008005 +0.00806 +0.008003 +0.008018 +0.007957 +0.007932 +0.007948 +0.008009 +0.007973 +0.007991 +0.007942 +0.007926 +0.00795 +0.008017 +0.007984 +0.008016 +0.007978 +0.007963 +0.007999 +0.008072 +0.00805 +0.008083 +0.008037 +0.008034 +0.008064 +0.00816 +0.008132 +0.008149 +0.000693 +0.008119 +0.008109 +0.008155 +0.008222 +0.008208 +0.008241 +0.008194 +0.008183 +0.008232 +0.008304 +0.008291 +0.008313 +0.008281 +0.00826 +0.008306 +0.008381 +0.008372 +0.008397 +0.008365 +0.008343 +0.008399 +0.008466 +0.00846 +0.008483 +0.008464 +0.008447 +0.008498 +0.008586 +0.008565 +0.008527 +0.008442 +0.008385 +0.008405 +0.008451 +0.008389 +0.008317 +0.008242 +0.008189 +0.008188 +0.008245 +0.008174 +0.008157 +0.00812 +0.008066 +0.008037 +0.008089 +0.008029 +0.008048 +0.007993 +0.007967 +0.00799 +0.008056 +0.00802 +0.008009 +0.007959 +0.00793 +0.007969 +0.008038 +0.007993 +0.008032 +0.007983 +0.007979 +0.008025 +0.00808 +0.008061 +0.00808 +0.008041 +0.008038 +0.008043 +0.008118 +0.008104 +0.008125 +0.008105 +0.0081 +0.00815 +0.000694 +0.008192 +0.00819 +0.008223 +0.008185 +0.008178 +0.008215 +0.008299 +0.008277 +0.00831 +0.008268 +0.008258 +0.008297 +0.008368 +0.008344 +0.008377 +0.008326 +0.008318 +0.008355 +0.008436 +0.008422 +0.00847 +0.008442 +0.008426 +0.008455 +0.008536 +0.008508 +0.008531 +0.008475 +0.008459 +0.008455 +0.008498 +0.008431 +0.008416 +0.008335 +0.008287 +0.00826 +0.008294 +0.008229 +0.008215 +0.008142 +0.008101 +0.008093 +0.008135 +0.008087 +0.008083 +0.008019 +0.007999 +0.008006 +0.008057 +0.008023 +0.008036 +0.007993 +0.007982 +0.008 +0.008075 +0.008042 +0.008059 +0.008019 +0.008008 +0.008041 +0.00813 +0.008109 +0.008136 +0.008095 +0.008085 +0.00811 +0.008198 +0.008177 +0.008211 +0.000695 +0.008174 +0.008166 +0.008203 +0.008275 +0.008259 +0.008291 +0.008247 +0.008239 +0.008276 +0.00836 +0.008342 +0.008373 +0.008322 +0.00832 +0.00836 +0.008445 +0.008426 +0.008456 +0.008412 +0.008403 +0.008445 +0.008519 +0.008507 +0.008538 +0.0085 +0.008494 +0.008548 +0.008634 +0.0086 +0.008638 +0.008602 +0.008515 +0.008507 +0.008544 +0.008487 +0.008487 +0.008401 +0.008367 +0.008283 +0.008294 +0.008232 +0.008239 +0.008175 +0.008123 +0.008151 +0.008196 +0.008106 +0.00808 +0.008016 +0.007995 +0.007993 +0.008061 +0.008003 +0.008029 +0.007986 +0.007945 +0.007962 +0.008013 +0.007976 +0.008015 +0.007968 +0.007964 +0.007995 +0.008065 +0.008047 +0.00807 +0.008046 +0.008036 +0.008069 +0.008153 +0.00813 +0.008169 +0.008114 +0.00812 +0.000696 +0.008152 +0.008208 +0.008191 +0.008215 +0.008183 +0.008168 +0.008218 +0.008294 +0.008269 +0.008295 +0.008268 +0.008259 +0.008288 +0.008363 +0.008327 +0.008353 +0.008322 +0.008299 +0.00835 +0.008419 +0.008402 +0.008423 +0.008386 +0.008386 +0.008447 +0.008533 +0.008528 +0.008542 +0.008498 +0.00847 +0.008483 +0.008524 +0.008466 +0.008445 +0.008375 +0.008307 +0.008286 +0.008316 +0.00826 +0.008233 +0.008167 +0.008112 +0.008111 +0.008159 +0.008115 +0.008103 +0.008046 +0.008009 +0.008016 +0.008066 +0.008036 +0.00804 +0.007996 +0.007973 +0.007993 +0.008056 +0.008033 +0.00804 +0.008002 +0.007992 +0.008024 +0.008096 +0.008082 +0.008098 +0.008069 +0.008052 +0.008081 +0.008164 +0.008141 +0.008174 +0.00815 +0.008126 +0.000697 +0.008168 +0.008251 +0.00822 +0.008254 +0.008214 +0.008201 +0.008239 +0.008328 +0.008308 +0.008337 +0.008293 +0.008284 +0.008323 +0.008407 +0.008382 +0.008415 +0.008375 +0.008367 +0.0084 +0.00848 +0.008463 +0.008498 +0.008455 +0.008452 +0.008491 +0.008575 +0.008562 +0.008595 +0.00855 +0.008557 +0.008602 +0.008679 +0.008576 +0.008535 +0.008459 +0.008417 +0.008402 +0.008407 +0.008325 +0.008323 +0.008223 +0.008171 +0.008153 +0.0082 +0.008137 +0.008137 +0.008098 +0.008028 +0.008005 +0.008034 +0.007991 +0.00801 +0.007947 +0.007936 +0.00795 +0.008031 +0.007981 +0.00801 +0.007966 +0.007945 +0.007979 +0.008014 +0.007972 +0.008002 +0.00796 +0.007966 +0.00797 +0.008039 +0.008026 +0.00802 +0.008012 +0.008005 +0.008038 +0.008125 +0.008096 +0.008128 +0.008093 +0.008093 +0.00813 +0.000698 +0.008208 +0.008175 +0.008211 +0.00818 +0.008173 +0.008216 +0.008292 +0.008262 +0.008292 +0.008256 +0.008239 +0.008272 +0.008343 +0.008306 +0.008336 +0.0083 +0.008286 +0.008314 +0.008395 +0.008377 +0.008414 +0.008407 +0.008405 +0.008443 +0.008513 +0.008468 +0.00848 +0.008395 +0.008339 +0.008341 +0.008372 +0.008302 +0.008285 +0.008201 +0.008149 +0.008135 +0.008171 +0.00811 +0.008109 +0.008042 +0.008008 +0.008008 +0.00805 +0.008006 +0.008009 +0.007943 +0.007922 +0.007943 +0.008004 +0.007968 +0.007984 +0.007927 +0.007914 +0.007944 +0.008011 +0.007992 +0.00802 +0.007967 +0.007966 +0.008 +0.008086 +0.008052 +0.008091 +0.008053 +0.008029 +0.008065 +0.008158 +0.000699 +0.008134 +0.008168 +0.008126 +0.008114 +0.008151 +0.008232 +0.008205 +0.008249 +0.008208 +0.008198 +0.008225 +0.008311 +0.008291 +0.008326 +0.008288 +0.008278 +0.008308 +0.008392 +0.008372 +0.00841 +0.008361 +0.008352 +0.008389 +0.008474 +0.008452 +0.008499 +0.008446 +0.008445 +0.008496 +0.008583 +0.008551 +0.008586 +0.008547 +0.008518 +0.008459 +0.008472 +0.0084 +0.008398 +0.008336 +0.008287 +0.008234 +0.00823 +0.008164 +0.008174 +0.008108 +0.008074 +0.008088 +0.008141 +0.008101 +0.008035 +0.007964 +0.007917 +0.007947 +0.008016 +0.007959 +0.007996 +0.007924 +0.007916 +0.007896 +0.007967 +0.007934 +0.007954 +0.007926 +0.00791 +0.007946 +0.00802 +0.007987 +0.008027 +0.007983 +0.007977 +0.008018 +0.008097 +0.008069 +0.008119 +0.008056 +0.008053 +0.0007 +0.008098 +0.008143 +0.008108 +0.008144 +0.008124 +0.008097 +0.008148 +0.008216 +0.008204 +0.008233 +0.008204 +0.00819 +0.008235 +0.008302 +0.008277 +0.008298 +0.008266 +0.008256 +0.008288 +0.008365 +0.00836 +0.008389 +0.008384 +0.008346 +0.008395 +0.008465 +0.008451 +0.008462 +0.008414 +0.008383 +0.00839 +0.008415 +0.008361 +0.008332 +0.008256 +0.008193 +0.008182 +0.008207 +0.008155 +0.008141 +0.008076 +0.008029 +0.008023 +0.008072 +0.008038 +0.008022 +0.007969 +0.007935 +0.007949 +0.008001 +0.007976 +0.007983 +0.007937 +0.007915 +0.007943 +0.007994 +0.007979 +0.00799 +0.007956 +0.007942 +0.007972 +0.008045 +0.008031 +0.008051 +0.008022 +0.008005 +0.008045 +0.00812 +0.008108 +0.008127 +0.008096 +0.000701 +0.008089 +0.008123 +0.008204 +0.008176 +0.008213 +0.008176 +0.008166 +0.008202 +0.00828 +0.008263 +0.00829 +0.008256 +0.008245 +0.008281 +0.008365 +0.008343 +0.008371 +0.008334 +0.008326 +0.008355 +0.008442 +0.008421 +0.008454 +0.008417 +0.008419 +0.008455 +0.008556 +0.00852 +0.008561 +0.008517 +0.008503 +0.008457 +0.008453 +0.008395 +0.008395 +0.008325 +0.008286 +0.008279 +0.008241 +0.008177 +0.008192 +0.008122 +0.008085 +0.008107 +0.008164 +0.008092 +0.008036 +0.007983 +0.007951 +0.007976 +0.008032 +0.007988 +0.007996 +0.007915 +0.007904 +0.00791 +0.007992 +0.007949 +0.007969 +0.007945 +0.007921 +0.007963 +0.008038 +0.008006 +0.00804 +0.007978 +0.007964 +0.008013 +0.008085 +0.008054 +0.008099 +0.008059 +0.008051 +0.008117 +0.000702 +0.008163 +0.00813 +0.00818 +0.008145 +0.008134 +0.008156 +0.008236 +0.008203 +0.008234 +0.008201 +0.008193 +0.008231 +0.008307 +0.008277 +0.008313 +0.008269 +0.008262 +0.008294 +0.008373 +0.008349 +0.008383 +0.008358 +0.008367 +0.008406 +0.008479 +0.008463 +0.00849 +0.008439 +0.008416 +0.008422 +0.008481 +0.008425 +0.00841 +0.008319 +0.008269 +0.008254 +0.008286 +0.008227 +0.008212 +0.008137 +0.008099 +0.00809 +0.008141 +0.008099 +0.008098 +0.008028 +0.008001 +0.008011 +0.008064 +0.008034 +0.008041 +0.007991 +0.007978 +0.007994 +0.00807 +0.008046 +0.008063 +0.008016 +0.008012 +0.008037 +0.008118 +0.008103 +0.008129 +0.008087 +0.008083 +0.008105 +0.008189 +0.008176 +0.008196 +0.000703 +0.008165 +0.008158 +0.008185 +0.008274 +0.008247 +0.00828 +0.008246 +0.008239 +0.008271 +0.00835 +0.008329 +0.00836 +0.008319 +0.008313 +0.00835 +0.00844 +0.008405 +0.008445 +0.008405 +0.008391 +0.008427 +0.008519 +0.008487 +0.00852 +0.008486 +0.008478 +0.008522 +0.008619 +0.008585 +0.008628 +0.008593 +0.008579 +0.008607 +0.008607 +0.008497 +0.008502 +0.008409 +0.008337 +0.008306 +0.008336 +0.008257 +0.008259 +0.008204 +0.00812 +0.008096 +0.008149 +0.008077 +0.008098 +0.00802 +0.00795 +0.007938 +0.007994 +0.007936 +0.00797 +0.00791 +0.007897 +0.007907 +0.007937 +0.007907 +0.007926 +0.007876 +0.007881 +0.007881 +0.007938 +0.007911 +0.007938 +0.007901 +0.007904 +0.007935 +0.008007 +0.007992 +0.008012 +0.007976 +0.007981 +0.008019 +0.008099 +0.008082 +0.000704 +0.008093 +0.008072 +0.008055 +0.008064 +0.008148 +0.008114 +0.008145 +0.008113 +0.008103 +0.008144 +0.008229 +0.008202 +0.008234 +0.008203 +0.008186 +0.008222 +0.008299 +0.008271 +0.0083 +0.008261 +0.008268 +0.008314 +0.008402 +0.008375 +0.008404 +0.00836 +0.008352 +0.008372 +0.008474 +0.008446 +0.008455 +0.008395 +0.008351 +0.008341 +0.008383 +0.008307 +0.008291 +0.008211 +0.00815 +0.008138 +0.008178 +0.008114 +0.008096 +0.00803 +0.007979 +0.007975 +0.008029 +0.007973 +0.007972 +0.007917 +0.007876 +0.007889 +0.007961 +0.007914 +0.007939 +0.007898 +0.007879 +0.007899 +0.007971 +0.00794 +0.007978 +0.007947 +0.007931 +0.007962 +0.008048 +0.00801 +0.008053 +0.008014 +0.007986 +0.008024 +0.008102 +0.000705 +0.008089 +0.008129 +0.008089 +0.008083 +0.008115 +0.008198 +0.008164 +0.008201 +0.008161 +0.008148 +0.008178 +0.008259 +0.008237 +0.008278 +0.008245 +0.008235 +0.008274 +0.008357 +0.008331 +0.008359 +0.008322 +0.008317 +0.008348 +0.00844 +0.008409 +0.008454 +0.008416 +0.008418 +0.008465 +0.00853 +0.008461 +0.008475 +0.00841 +0.008375 +0.008366 +0.008401 +0.008327 +0.008322 +0.008221 +0.008151 +0.008137 +0.008194 +0.00814 +0.008118 +0.008073 +0.007987 +0.007975 +0.008028 +0.007972 +0.007995 +0.007925 +0.007917 +0.007909 +0.007955 +0.007889 +0.007911 +0.007873 +0.007848 +0.007878 +0.007922 +0.007883 +0.007916 +0.007876 +0.00787 +0.00791 +0.007982 +0.007958 +0.007978 +0.00793 +0.007936 +0.007951 +0.008016 +0.008001 +0.00803 +0.007995 +0.008 +0.008024 +0.000706 +0.008101 +0.00808 +0.008109 +0.008088 +0.008072 +0.008114 +0.008187 +0.008169 +0.008197 +0.008166 +0.008152 +0.008195 +0.008266 +0.008243 +0.008261 +0.008232 +0.008211 +0.008248 +0.008324 +0.008309 +0.00833 +0.008292 +0.008289 +0.00835 +0.008432 +0.008412 +0.008431 +0.008381 +0.008332 +0.008351 +0.00836 +0.008311 +0.0083 +0.008215 +0.00815 +0.008144 +0.008175 +0.008121 +0.00811 +0.008036 +0.007988 +0.007999 +0.008041 +0.007991 +0.007995 +0.007937 +0.007894 +0.00791 +0.007956 +0.007926 +0.007946 +0.0079 +0.007877 +0.007908 +0.007964 +0.007941 +0.007957 +0.007918 +0.007899 +0.00795 +0.008017 +0.008005 +0.008028 +0.007988 +0.007977 +0.008013 +0.008081 +0.008073 +0.008077 +0.008055 +0.000707 +0.008043 +0.00809 +0.008173 +0.008148 +0.008183 +0.008136 +0.008126 +0.008155 +0.00824 +0.008218 +0.008254 +0.008216 +0.008206 +0.00824 +0.008321 +0.008303 +0.008338 +0.008294 +0.008282 +0.008327 +0.008402 +0.008387 +0.008417 +0.008381 +0.008368 +0.008425 +0.008507 +0.008489 +0.008513 +0.00848 +0.008447 +0.00838 +0.008407 +0.008345 +0.008352 +0.00828 +0.008234 +0.008247 +0.008217 +0.008128 +0.008135 +0.008063 +0.008034 +0.008016 +0.008041 +0.007967 +0.007964 +0.007922 +0.007878 +0.007882 +0.007917 +0.007865 +0.007891 +0.007835 +0.007833 +0.007833 +0.007886 +0.007843 +0.007857 +0.007828 +0.007816 +0.007847 +0.007931 +0.007898 +0.007918 +0.007878 +0.007867 +0.007882 +0.007961 +0.00794 +0.007967 +0.007938 +0.007935 +0.00799 +0.008036 +0.008016 +0.000708 +0.008052 +0.008026 +0.008015 +0.008052 +0.008135 +0.008102 +0.00814 +0.008105 +0.008097 +0.00814 +0.008205 +0.008174 +0.008202 +0.008165 +0.008153 +0.008185 +0.008257 +0.008223 +0.008254 +0.008216 +0.008205 +0.008238 +0.008328 +0.008294 +0.008353 +0.008341 +0.008325 +0.008365 +0.008427 +0.00839 +0.008394 +0.00831 +0.00825 +0.008239 +0.008277 +0.008207 +0.008187 +0.008098 +0.008047 +0.008041 +0.008087 +0.008015 +0.008015 +0.007938 +0.007901 +0.007917 +0.007965 +0.007911 +0.007918 +0.007851 +0.007825 +0.007844 +0.007912 +0.007877 +0.0079 +0.007842 +0.007821 +0.007848 +0.007911 +0.007889 +0.007933 +0.007874 +0.007869 +0.007901 +0.007977 +0.007953 +0.007987 +0.007952 +0.007929 +0.007963 +0.008048 +0.008026 +0.000709 +0.008068 +0.008025 +0.008019 +0.008055 +0.008127 +0.008106 +0.008145 +0.008089 +0.008084 +0.008117 +0.008204 +0.008184 +0.008213 +0.008179 +0.008169 +0.00821 +0.008291 +0.008265 +0.008298 +0.008257 +0.008243 +0.008294 +0.008361 +0.008352 +0.008383 +0.008356 +0.008352 +0.008403 +0.008478 +0.008394 +0.0084 +0.008338 +0.008307 +0.008301 +0.008326 +0.008249 +0.008218 +0.008132 +0.008081 +0.008062 +0.008108 +0.008042 +0.008039 +0.007992 +0.007938 +0.007902 +0.007942 +0.00789 +0.007902 +0.007853 +0.007816 +0.007845 +0.007899 +0.007857 +0.007859 +0.007776 +0.007773 +0.007792 +0.007857 +0.007828 +0.007846 +0.007805 +0.007809 +0.007826 +0.007876 +0.007854 +0.007875 +0.007847 +0.007842 +0.007869 +0.007965 +0.007919 +0.007956 +0.007927 +0.007928 +0.00796 +0.008035 +0.00071 +0.00802 +0.008033 +0.008007 +0.008004 +0.008029 +0.008095 +0.008064 +0.008099 +0.008064 +0.008056 +0.008093 +0.008168 +0.008132 +0.008162 +0.008124 +0.008112 +0.008148 +0.00823 +0.008206 +0.008243 +0.008229 +0.008231 +0.00826 +0.008347 +0.008314 +0.008336 +0.008289 +0.008252 +0.008244 +0.008293 +0.008219 +0.008216 +0.00813 +0.00807 +0.008053 +0.008093 +0.008025 +0.008011 +0.007932 +0.007895 +0.00789 +0.007941 +0.007889 +0.007887 +0.007829 +0.00779 +0.007795 +0.007854 +0.007804 +0.007827 +0.007791 +0.007768 +0.007768 +0.007847 +0.007806 +0.007825 +0.007779 +0.00777 +0.0078 +0.007885 +0.007855 +0.007881 +0.007842 +0.00783 +0.007863 +0.007936 +0.007913 +0.007954 +0.007927 +0.007903 +0.007945 +0.000711 +0.008017 +0.008002 +0.008028 +0.007986 +0.007974 +0.008012 +0.008089 +0.008072 +0.008104 +0.00807 +0.00806 +0.008098 +0.008174 +0.008157 +0.008185 +0.00814 +0.008133 +0.008169 +0.008249 +0.008235 +0.008263 +0.008232 +0.008227 +0.008261 +0.008355 +0.008329 +0.00837 +0.008321 +0.008232 +0.008234 +0.008285 +0.00822 +0.00823 +0.008162 +0.00813 +0.008091 +0.008102 +0.008037 +0.008041 +0.007979 +0.007959 +0.007969 +0.008024 +0.007945 +0.007896 +0.007844 +0.007819 +0.007834 +0.007888 +0.007837 +0.007843 +0.007783 +0.007762 +0.00777 +0.007848 +0.007799 +0.007829 +0.007793 +0.007774 +0.007822 +0.007893 +0.007866 +0.007901 +0.007859 +0.007865 +0.007897 +0.00796 +0.007959 +0.007939 +0.007928 +0.000712 +0.007915 +0.007937 +0.008001 +0.007982 +0.008013 +0.007981 +0.007968 +0.008012 +0.008094 +0.00807 +0.008106 +0.008067 +0.008058 +0.008097 +0.00817 +0.008141 +0.008169 +0.008131 +0.008119 +0.008158 +0.008256 +0.008241 +0.008262 +0.008226 +0.008216 +0.008251 +0.008332 +0.008316 +0.008331 +0.00828 +0.008254 +0.008252 +0.008294 +0.008237 +0.008227 +0.008138 +0.008096 +0.008081 +0.008124 +0.008064 +0.008063 +0.007994 +0.007958 +0.00796 +0.008009 +0.007977 +0.00798 +0.007923 +0.007899 +0.007906 +0.007968 +0.00794 +0.007963 +0.007912 +0.007905 +0.007923 +0.007995 +0.00797 +0.007992 +0.007953 +0.007958 +0.007983 +0.008062 +0.008047 +0.008067 +0.00804 +0.008015 +0.008054 +0.000713 +0.008131 +0.008118 +0.008146 +0.008116 +0.0081 +0.008137 +0.008219 +0.008191 +0.008222 +0.008184 +0.008172 +0.008212 +0.008294 +0.008272 +0.008303 +0.008261 +0.008253 +0.008289 +0.008376 +0.008357 +0.008388 +0.008346 +0.008342 +0.008378 +0.008458 +0.008439 +0.008477 +0.008441 +0.008455 +0.008493 +0.008582 +0.008493 +0.008496 +0.008429 +0.008387 +0.008393 +0.008449 +0.008334 +0.008282 +0.008225 +0.008163 +0.008129 +0.008164 +0.008106 +0.008106 +0.008038 +0.008019 +0.008001 +0.008031 +0.007955 +0.00798 +0.007924 +0.0079 +0.007888 +0.007946 +0.007901 +0.007927 +0.007895 +0.007869 +0.007899 +0.00795 +0.007912 +0.007948 +0.007905 +0.007915 +0.007949 +0.008027 +0.007996 +0.008015 +0.007984 +0.007966 +0.007991 +0.008075 +0.008047 +0.008075 +0.000714 +0.00807 +0.008032 +0.008075 +0.008148 +0.008125 +0.008164 +0.008128 +0.00812 +0.008163 +0.008247 +0.008213 +0.008246 +0.00821 +0.008192 +0.008229 +0.008304 +0.008267 +0.008295 +0.008259 +0.008251 +0.00827 +0.008356 +0.008336 +0.008371 +0.008363 +0.008361 +0.008401 +0.00848 +0.008429 +0.008457 +0.008384 +0.008341 +0.008331 +0.008384 +0.008322 +0.008313 +0.008229 +0.008179 +0.008172 +0.008203 +0.008152 +0.008153 +0.008082 +0.00805 +0.00806 +0.008109 +0.008054 +0.008062 +0.008006 +0.00798 +0.008004 +0.00806 +0.008023 +0.008045 +0.007989 +0.007966 +0.008001 +0.008079 +0.008049 +0.008084 +0.008038 +0.00803 +0.008075 +0.008147 +0.008132 +0.008158 +0.008118 +0.008101 +0.008139 +0.008213 +0.000715 +0.008204 +0.008227 +0.008204 +0.008185 +0.008223 +0.008298 +0.008285 +0.008308 +0.008275 +0.008259 +0.008304 +0.008379 +0.008371 +0.008378 +0.008359 +0.008336 +0.008385 +0.008453 +0.008446 +0.00847 +0.008439 +0.008424 +0.008469 +0.008548 +0.008546 +0.008574 +0.00854 +0.008528 +0.008582 +0.008637 +0.008526 +0.008499 +0.008433 +0.008374 +0.008328 +0.008351 +0.008296 +0.008298 +0.008221 +0.008166 +0.008159 +0.008171 +0.008126 +0.008133 +0.008079 +0.008035 +0.008003 +0.008041 +0.007991 +0.008008 +0.007955 +0.007934 +0.007967 +0.008025 +0.008003 +0.007989 +0.007943 +0.007911 +0.007935 +0.008016 +0.007984 +0.008009 +0.007983 +0.007947 +0.00799 +0.008049 +0.008018 +0.008054 +0.008026 +0.008015 +0.008069 +0.008137 +0.008114 +0.008155 +0.008102 +0.000716 +0.008097 +0.008144 +0.008215 +0.00821 +0.008227 +0.008209 +0.008182 +0.008237 +0.008306 +0.008285 +0.008295 +0.008258 +0.008224 +0.008275 +0.008337 +0.008322 +0.008337 +0.008316 +0.00829 +0.008333 +0.008424 +0.008448 +0.008458 +0.008437 +0.008403 +0.008455 +0.008512 +0.008498 +0.008494 +0.008443 +0.008382 +0.008382 +0.008394 +0.008341 +0.008324 +0.008248 +0.008182 +0.008203 +0.008215 +0.008183 +0.008162 +0.008108 +0.008064 +0.008086 +0.008122 +0.00809 +0.008083 +0.00804 +0.008 +0.008032 +0.008082 +0.008067 +0.00807 +0.008032 +0.008005 +0.008046 +0.008101 +0.008093 +0.008105 +0.00808 +0.008054 +0.008104 +0.008164 +0.008165 +0.008174 +0.008151 +0.008141 +0.008174 +0.008246 +0.000717 +0.008241 +0.008252 +0.008233 +0.008208 +0.008259 +0.008332 +0.008322 +0.008337 +0.008319 +0.008274 +0.008337 +0.008407 +0.008404 +0.008418 +0.008389 +0.008368 +0.008415 +0.00849 +0.008495 +0.008493 +0.00848 +0.008453 +0.008511 +0.008581 +0.008579 +0.008597 +0.00859 +0.008563 +0.008628 +0.008668 +0.008592 +0.008569 +0.008519 +0.008469 +0.008443 +0.008445 +0.008394 +0.00839 +0.008324 +0.008239 +0.008224 +0.008259 +0.008227 +0.008212 +0.008182 +0.008118 +0.008119 +0.008118 +0.008083 +0.008078 +0.008054 +0.008002 +0.008051 +0.008111 +0.00808 +0.008092 +0.008046 +0.007999 +0.008028 +0.008075 +0.008075 +0.008089 +0.008069 +0.008046 +0.008096 +0.008157 +0.008146 +0.008155 +0.008146 +0.008124 +0.008192 +0.008241 +0.008237 +0.000718 +0.008254 +0.008219 +0.008212 +0.008238 +0.008301 +0.00827 +0.008301 +0.008286 +0.008261 +0.008313 +0.008382 +0.008356 +0.008387 +0.008359 +0.008338 +0.008381 +0.008451 +0.008433 +0.008453 +0.008428 +0.008431 +0.008483 +0.008563 +0.008547 +0.008563 +0.008524 +0.008506 +0.008532 +0.008604 +0.008565 +0.008542 +0.008469 +0.008403 +0.008396 +0.008426 +0.008364 +0.008342 +0.00827 +0.008211 +0.008204 +0.008251 +0.008206 +0.008197 +0.008138 +0.008092 +0.0081 +0.008152 +0.008115 +0.008115 +0.008074 +0.00804 +0.00806 +0.008123 +0.008098 +0.008105 +0.008075 +0.008047 +0.008073 +0.008144 +0.008128 +0.008142 +0.008117 +0.008098 +0.00813 +0.008209 +0.008193 +0.008218 +0.008194 +0.008173 +0.008215 +0.008277 +0.000719 +0.008271 +0.008303 +0.00826 +0.008255 +0.008289 +0.008368 +0.00835 +0.008383 +0.008343 +0.008333 +0.008373 +0.008451 +0.008431 +0.008462 +0.008422 +0.008416 +0.008449 +0.00853 +0.008511 +0.008551 +0.008504 +0.0085 +0.008539 +0.00863 +0.008607 +0.008643 +0.00861 +0.008612 +0.008655 +0.008747 +0.00865 +0.008623 +0.008553 +0.008516 +0.008532 +0.008558 +0.008484 +0.008455 +0.008386 +0.008356 +0.008322 +0.008372 +0.00832 +0.008333 +0.008264 +0.00824 +0.008202 +0.008259 +0.008194 +0.008226 +0.008163 +0.008152 +0.008171 +0.008247 +0.00821 +0.008226 +0.008197 +0.008165 +0.008185 +0.008235 +0.008201 +0.008244 +0.008201 +0.008199 +0.00824 +0.008312 +0.008294 +0.00832 +0.008286 +0.00829 +0.008324 +0.00842 +0.008385 +0.00072 +0.008408 +0.008382 +0.008362 +0.00843 +0.008496 +0.008476 +0.008495 +0.008438 +0.008418 +0.008465 +0.008538 +0.008512 +0.008533 +0.008504 +0.008486 +0.008524 +0.008599 +0.00859 +0.008649 +0.008629 +0.008603 +0.00865 +0.008719 +0.008703 +0.008724 +0.008666 +0.008643 +0.008667 +0.008692 +0.008636 +0.008628 +0.008539 +0.008491 +0.008486 +0.008507 +0.008453 +0.008442 +0.008376 +0.00833 +0.008338 +0.008364 +0.008327 +0.008323 +0.008263 +0.008228 +0.008246 +0.008289 +0.008252 +0.008253 +0.008215 +0.008188 +0.008219 +0.008275 +0.008246 +0.008262 +0.008219 +0.008201 +0.008254 +0.008323 +0.008312 +0.008337 +0.008297 +0.008284 +0.008314 +0.008394 +0.008373 +0.008409 +0.008372 +0.000721 +0.00837 +0.008417 +0.008483 +0.008476 +0.008487 +0.00847 +0.008431 +0.008484 +0.008551 +0.008544 +0.008558 +0.008541 +0.008525 +0.008584 +0.008652 +0.008649 +0.008661 +0.008644 +0.008627 +0.008684 +0.008773 +0.008763 +0.00876 +0.008683 +0.008645 +0.008686 +0.008739 +0.008692 +0.008678 +0.00863 +0.008517 +0.008502 +0.00854 +0.008494 +0.00848 +0.008427 +0.008373 +0.008362 +0.008355 +0.008318 +0.008317 +0.008266 +0.008229 +0.008225 +0.008243 +0.008187 +0.008199 +0.008158 +0.008131 +0.008177 +0.008233 +0.008205 +0.00819 +0.008148 +0.008113 +0.008153 +0.008225 +0.008193 +0.008212 +0.008192 +0.008162 +0.008228 +0.008284 +0.008267 +0.008298 +0.008273 +0.008248 +0.008322 +0.008377 +0.008364 +0.000722 +0.008372 +0.008343 +0.008315 +0.008349 +0.008427 +0.008398 +0.00844 +0.008392 +0.008384 +0.008427 +0.008507 +0.008485 +0.008511 +0.008479 +0.008467 +0.008525 +0.008613 +0.008601 +0.008627 +0.008585 +0.00857 +0.008604 +0.008683 +0.008655 +0.00867 +0.008632 +0.00858 +0.008576 +0.008616 +0.008558 +0.008538 +0.008455 +0.008396 +0.008387 +0.008417 +0.008367 +0.008337 +0.008287 +0.008233 +0.008235 +0.008284 +0.008239 +0.008229 +0.008183 +0.008144 +0.00816 +0.008215 +0.008179 +0.00819 +0.008155 +0.008121 +0.008144 +0.008212 +0.008186 +0.008199 +0.008173 +0.008149 +0.008187 +0.008261 +0.008246 +0.008265 +0.00824 +0.008211 +0.008269 +0.008332 +0.008325 +0.008347 +0.008317 +0.000723 +0.008296 +0.008346 +0.008419 +0.008409 +0.008419 +0.008404 +0.008365 +0.008429 +0.008498 +0.008492 +0.008506 +0.008482 +0.008456 +0.008508 +0.008569 +0.008572 +0.008593 +0.008573 +0.008544 +0.008603 +0.008679 +0.008676 +0.008693 +0.008676 +0.008663 +0.008709 +0.008692 +0.008647 +0.008635 +0.008586 +0.008534 +0.008556 +0.008532 +0.008472 +0.008455 +0.0084 +0.008316 +0.0083 +0.008333 +0.008286 +0.008265 +0.008235 +0.008148 +0.008131 +0.008155 +0.008126 +0.008113 +0.008098 +0.008035 +0.008091 +0.008143 +0.008111 +0.00813 +0.008088 +0.008029 +0.00807 +0.00812 +0.008114 +0.008127 +0.008115 +0.008091 +0.008143 +0.008202 +0.0082 +0.008218 +0.008192 +0.00818 +0.008251 +0.008286 +0.008283 +0.000724 +0.008313 +0.00828 +0.008261 +0.008307 +0.008395 +0.00837 +0.008399 +0.008368 +0.008341 +0.008348 +0.008415 +0.008398 +0.008424 +0.0084 +0.008379 +0.008432 +0.008493 +0.008488 +0.008538 +0.008517 +0.008496 +0.008543 +0.008612 +0.008596 +0.008621 +0.00859 +0.008572 +0.008625 +0.008662 +0.008621 +0.008612 +0.008534 +0.008473 +0.008461 +0.008478 +0.008414 +0.008397 +0.008326 +0.008272 +0.008284 +0.008319 +0.008264 +0.008265 +0.008208 +0.008167 +0.008184 +0.008221 +0.008178 +0.008185 +0.008143 +0.00811 +0.008145 +0.008195 +0.008169 +0.008183 +0.008137 +0.008108 +0.008154 +0.008227 +0.008203 +0.008231 +0.008193 +0.008175 +0.008222 +0.008293 +0.00829 +0.008298 +0.008284 +0.008244 +0.008303 +0.000725 +0.008383 +0.008359 +0.008391 +0.008346 +0.008335 +0.008372 +0.008458 +0.00844 +0.008469 +0.008433 +0.00842 +0.008465 +0.008544 +0.00853 +0.008559 +0.008517 +0.008513 +0.008554 +0.008642 +0.008608 +0.00865 +0.008615 +0.008618 +0.00866 +0.008748 +0.008677 +0.008689 +0.008635 +0.008611 +0.008598 +0.008644 +0.008575 +0.008565 +0.008448 +0.008405 +0.008382 +0.008415 +0.00835 +0.008348 +0.008289 +0.008228 +0.008201 +0.008229 +0.008173 +0.00819 +0.008128 +0.008097 +0.008112 +0.008161 +0.008117 +0.008101 +0.00806 +0.00803 +0.00807 +0.008131 +0.008084 +0.008126 +0.008076 +0.008083 +0.008115 +0.008196 +0.008168 +0.008183 +0.008145 +0.00814 +0.00816 +0.008248 +0.00822 +0.008252 +0.008218 +0.000726 +0.008234 +0.008247 +0.008313 +0.008305 +0.008332 +0.008311 +0.008292 +0.008338 +0.008411 +0.008391 +0.008421 +0.008379 +0.008366 +0.008408 +0.008483 +0.008454 +0.008475 +0.00844 +0.008428 +0.008462 +0.008538 +0.008517 +0.008549 +0.008539 +0.008541 +0.00858 +0.008652 +0.008632 +0.00861 +0.008556 +0.008495 +0.008478 +0.008522 +0.008463 +0.00843 +0.008345 +0.008293 +0.008288 +0.008323 +0.00827 +0.008246 +0.008194 +0.008152 +0.008156 +0.008197 +0.008154 +0.008147 +0.008103 +0.00807 +0.008087 +0.008144 +0.008118 +0.00812 +0.008091 +0.008071 +0.008096 +0.008162 +0.008143 +0.008147 +0.008127 +0.008117 +0.008155 +0.008238 +0.00822 +0.008229 +0.00821 +0.008176 +0.008221 +0.008293 +0.00827 +0.000727 +0.008297 +0.008273 +0.008263 +0.008305 +0.008394 +0.008366 +0.008394 +0.008356 +0.008339 +0.008376 +0.008458 +0.008437 +0.008468 +0.008438 +0.008432 +0.008455 +0.008548 +0.008522 +0.008555 +0.008512 +0.008504 +0.008545 +0.008627 +0.008615 +0.008646 +0.008611 +0.008607 +0.008643 +0.00874 +0.008719 +0.008753 +0.008708 +0.008609 +0.008602 +0.008658 +0.008595 +0.008602 +0.008536 +0.00847 +0.00841 +0.008447 +0.008384 +0.008391 +0.008342 +0.008301 +0.008311 +0.00837 +0.008267 +0.008274 +0.008206 +0.008184 +0.008173 +0.008235 +0.008183 +0.008221 +0.008161 +0.008164 +0.008179 +0.008261 +0.00823 +0.008247 +0.008219 +0.008184 +0.008185 +0.008259 +0.008222 +0.008274 +0.008237 +0.008223 +0.00827 +0.008348 +0.008325 +0.008361 +0.008335 +0.008324 +0.00837 +0.008437 +0.000728 +0.008411 +0.008451 +0.008413 +0.008403 +0.008448 +0.008533 +0.00851 +0.008537 +0.008499 +0.008487 +0.008524 +0.008604 +0.008561 +0.00859 +0.008549 +0.008538 +0.008576 +0.008656 +0.008622 +0.008663 +0.008646 +0.008661 +0.008679 +0.008766 +0.008726 +0.008722 +0.008643 +0.008589 +0.008567 +0.008614 +0.008534 +0.008503 +0.008421 +0.008373 +0.008345 +0.00839 +0.008329 +0.008317 +0.008244 +0.008209 +0.008202 +0.008256 +0.008205 +0.008206 +0.008149 +0.008125 +0.008132 +0.0082 +0.008161 +0.00818 +0.008134 +0.008117 +0.008136 +0.008211 +0.008183 +0.008212 +0.008176 +0.008169 +0.008195 +0.008283 +0.008252 +0.008286 +0.008255 +0.008232 +0.008278 +0.008358 +0.008338 +0.000729 +0.008366 +0.008321 +0.008321 +0.008361 +0.008447 +0.008413 +0.00845 +0.008409 +0.008397 +0.00843 +0.008523 +0.008504 +0.008532 +0.008492 +0.008484 +0.008516 +0.008604 +0.008572 +0.008616 +0.008573 +0.008568 +0.008611 +0.008695 +0.008674 +0.008722 +0.008679 +0.008671 +0.008724 +0.00881 +0.008719 +0.008702 +0.00864 +0.008601 +0.00858 +0.008614 +0.008545 +0.008547 +0.008476 +0.008398 +0.008385 +0.008421 +0.008373 +0.008382 +0.008313 +0.008292 +0.008302 +0.008325 +0.008258 +0.008271 +0.008219 +0.008194 +0.008179 +0.008249 +0.00819 +0.008231 +0.008183 +0.008167 +0.008207 +0.008282 +0.008252 +0.008283 +0.008243 +0.008243 +0.008275 +0.00836 +0.008336 +0.008367 +0.008331 +0.008329 +0.008374 +0.00073 +0.00845 +0.00841 +0.008419 +0.008385 +0.008375 +0.008423 +0.008493 +0.00847 +0.008503 +0.008472 +0.008459 +0.008504 +0.008576 +0.008553 +0.008576 +0.008546 +0.008529 +0.00856 +0.008638 +0.008616 +0.008639 +0.008608 +0.008599 +0.008665 +0.008759 +0.00875 +0.008762 +0.008714 +0.008674 +0.008689 +0.008715 +0.00865 +0.008645 +0.008553 +0.008475 +0.008475 +0.0085 +0.008437 +0.00842 +0.008347 +0.008291 +0.008299 +0.008347 +0.008285 +0.008286 +0.008225 +0.008177 +0.008192 +0.008244 +0.00821 +0.008219 +0.008173 +0.008139 +0.008173 +0.008235 +0.008212 +0.008236 +0.00818 +0.008162 +0.008206 +0.008274 +0.008256 +0.008283 +0.008241 +0.008222 +0.008265 +0.008337 +0.008341 +0.008346 +0.008324 +0.008301 +0.000731 +0.008349 +0.00843 +0.008405 +0.008443 +0.0084 +0.008384 +0.008424 +0.008514 +0.00849 +0.008524 +0.008483 +0.008471 +0.008506 +0.008592 +0.008574 +0.008606 +0.008562 +0.008551 +0.008594 +0.008673 +0.008662 +0.008695 +0.008664 +0.008649 +0.0087 +0.008793 +0.008764 +0.008798 +0.008755 +0.008669 +0.008621 +0.008664 +0.008607 +0.008598 +0.008536 +0.008495 +0.008433 +0.008451 +0.008383 +0.008412 +0.008342 +0.008297 +0.008324 +0.008336 +0.008271 +0.008273 +0.008193 +0.00817 +0.008156 +0.008223 +0.008171 +0.008203 +0.008154 +0.008129 +0.008174 +0.008235 +0.008209 +0.008232 +0.008172 +0.008158 +0.008165 +0.00825 +0.008222 +0.008247 +0.008227 +0.008212 +0.008252 +0.008335 +0.008316 +0.008353 +0.008325 +0.008304 +0.000732 +0.008338 +0.008423 +0.008409 +0.008438 +0.008397 +0.008393 +0.008436 +0.008522 +0.008499 +0.008532 +0.008481 +0.008478 +0.008516 +0.008592 +0.008551 +0.008574 +0.008534 +0.008527 +0.008561 +0.008631 +0.008597 +0.008646 +0.008587 +0.008595 +0.008659 +0.008741 +0.008701 +0.008695 +0.008594 +0.008531 +0.008503 +0.008537 +0.008482 +0.008466 +0.008367 +0.008313 +0.00831 +0.008357 +0.008303 +0.008294 +0.008224 +0.008187 +0.008194 +0.008248 +0.008204 +0.008219 +0.008153 +0.00813 +0.008152 +0.008217 +0.008198 +0.008223 +0.008162 +0.008152 +0.008178 +0.008255 +0.00824 +0.008273 +0.008228 +0.008221 +0.008252 +0.008328 +0.008314 +0.008344 +0.008307 +0.000733 +0.008291 +0.008338 +0.008403 +0.008401 +0.008422 +0.00839 +0.008377 +0.008412 +0.00849 +0.008478 +0.008506 +0.008474 +0.008453 +0.008498 +0.008575 +0.008561 +0.008586 +0.008558 +0.008537 +0.008583 +0.008657 +0.008648 +0.008667 +0.008639 +0.008621 +0.008675 +0.008751 +0.00875 +0.00878 +0.008754 +0.008727 +0.008789 +0.008808 +0.008738 +0.008733 +0.008677 +0.008609 +0.008557 +0.008585 +0.008524 +0.008515 +0.008468 +0.008388 +0.008352 +0.008394 +0.008338 +0.008361 +0.008307 +0.008259 +0.008291 +0.008339 +0.008253 +0.008264 +0.008207 +0.008179 +0.008193 +0.008241 +0.008212 +0.00822 +0.0082 +0.008173 +0.008219 +0.008296 +0.008272 +0.008296 +0.00827 +0.008245 +0.008301 +0.008367 +0.008348 +0.008394 +0.008341 +0.00833 +0.000734 +0.008403 +0.008462 +0.008442 +0.008463 +0.008408 +0.008382 +0.008441 +0.008505 +0.008481 +0.008504 +0.008489 +0.008469 +0.008523 +0.00859 +0.008575 +0.008592 +0.008569 +0.008538 +0.00858 +0.008653 +0.008647 +0.008659 +0.008655 +0.008648 +0.008696 +0.008765 +0.008751 +0.008752 +0.008716 +0.008665 +0.008676 +0.008705 +0.008651 +0.008624 +0.008571 +0.008483 +0.008493 +0.008526 +0.008482 +0.008441 +0.008389 +0.008327 +0.008336 +0.008371 +0.008334 +0.008322 +0.008273 +0.008223 +0.00824 +0.008293 +0.008272 +0.008269 +0.008245 +0.008208 +0.008243 +0.008304 +0.008286 +0.008284 +0.008273 +0.008248 +0.008299 +0.008372 +0.008358 +0.008369 +0.008351 +0.008318 +0.008375 +0.008421 +0.008428 +0.000735 +0.008434 +0.008423 +0.008406 +0.008456 +0.008532 +0.008509 +0.008533 +0.008503 +0.008483 +0.008524 +0.008597 +0.008591 +0.008624 +0.008592 +0.00857 +0.008611 +0.008688 +0.008676 +0.008707 +0.008666 +0.008651 +0.00871 +0.008767 +0.00877 +0.008798 +0.008768 +0.008765 +0.008819 +0.008902 +0.008865 +0.008799 +0.008725 +0.008676 +0.008698 +0.008744 +0.008643 +0.008591 +0.008521 +0.008457 +0.008464 +0.008491 +0.008439 +0.00843 +0.008343 +0.008287 +0.008271 +0.008328 +0.008278 +0.008278 +0.008227 +0.008195 +0.008218 +0.008271 +0.008222 +0.008227 +0.008184 +0.008145 +0.00818 +0.008227 +0.008195 +0.008229 +0.008191 +0.008169 +0.008224 +0.008291 +0.008265 +0.008295 +0.008265 +0.008248 +0.008301 +0.008385 +0.008373 +0.008362 +0.008356 +0.000736 +0.008347 +0.008353 +0.008421 +0.008399 +0.008435 +0.008403 +0.008393 +0.008441 +0.008514 +0.008495 +0.008526 +0.00849 +0.008475 +0.008511 +0.00859 +0.008564 +0.008598 +0.00856 +0.008548 +0.008574 +0.008689 +0.008676 +0.008714 +0.00866 +0.008642 +0.008656 +0.00871 +0.008657 +0.008652 +0.008557 +0.008505 +0.008489 +0.00852 +0.008463 +0.008449 +0.008356 +0.008315 +0.008309 +0.008351 +0.0083 +0.008304 +0.008228 +0.008198 +0.008198 +0.008251 +0.008212 +0.008226 +0.008171 +0.008156 +0.008173 +0.008245 +0.008217 +0.008239 +0.008186 +0.008176 +0.008215 +0.008287 +0.00827 +0.0083 +0.008252 +0.00825 +0.008281 +0.008372 +0.008349 +0.008365 +0.000737 +0.00834 +0.008327 +0.008367 +0.008455 +0.00842 +0.008461 +0.008419 +0.008406 +0.008443 +0.008533 +0.008511 +0.008545 +0.008499 +0.008494 +0.008526 +0.00862 +0.008585 +0.008626 +0.008589 +0.008573 +0.008614 +0.0087 +0.00868 +0.008714 +0.008677 +0.008671 +0.008713 +0.008812 +0.008783 +0.008824 +0.008785 +0.008753 +0.008682 +0.008707 +0.008649 +0.008656 +0.008583 +0.008539 +0.008548 +0.008525 +0.008435 +0.008452 +0.008391 +0.008347 +0.008337 +0.008369 +0.008301 +0.008329 +0.008262 +0.008241 +0.008254 +0.008324 +0.008243 +0.00826 +0.008201 +0.008186 +0.008199 +0.008265 +0.008225 +0.008241 +0.008211 +0.008202 +0.008229 +0.00832 +0.008286 +0.008298 +0.008263 +0.008241 +0.008273 +0.008366 +0.008326 +0.008368 +0.008341 +0.008326 +0.008379 +0.008437 +0.000738 +0.008415 +0.008443 +0.008424 +0.008413 +0.008449 +0.00854 +0.008512 +0.008544 +0.008497 +0.008478 +0.008496 +0.008582 +0.008549 +0.00858 +0.008546 +0.008528 +0.008567 +0.008649 +0.008632 +0.008688 +0.008662 +0.008659 +0.008688 +0.008766 +0.008741 +0.008775 +0.008734 +0.008729 +0.008769 +0.008837 +0.008768 +0.008763 +0.008664 +0.008606 +0.008586 +0.00861 +0.008533 +0.008521 +0.008438 +0.008392 +0.008391 +0.008429 +0.008374 +0.008381 +0.00831 +0.008277 +0.00827 +0.008327 +0.008283 +0.008294 +0.008239 +0.008218 +0.008243 +0.008308 +0.008273 +0.008301 +0.008251 +0.008246 +0.008278 +0.008352 +0.008327 +0.008361 +0.008314 +0.008319 +0.008355 +0.008435 +0.008424 +0.008433 +0.008398 +0.000739 +0.008392 +0.008418 +0.008503 +0.00849 +0.008525 +0.008485 +0.008475 +0.008504 +0.008592 +0.008566 +0.008604 +0.008566 +0.008555 +0.008595 +0.008675 +0.008649 +0.008691 +0.008644 +0.00863 +0.008671 +0.008754 +0.00873 +0.008774 +0.008731 +0.008725 +0.008761 +0.00886 +0.008835 +0.008875 +0.008829 +0.00883 +0.008854 +0.008847 +0.008752 +0.008746 +0.008668 +0.008558 +0.008517 +0.008554 +0.008499 +0.008493 +0.008412 +0.008375 +0.008361 +0.008386 +0.008338 +0.008336 +0.008246 +0.008194 +0.008212 +0.008261 +0.008221 +0.008227 +0.008196 +0.008123 +0.008132 +0.008189 +0.00815 +0.008177 +0.008127 +0.008123 +0.008138 +0.008232 +0.008194 +0.008217 +0.008189 +0.008169 +0.008197 +0.008262 +0.008222 +0.008262 +0.008233 +0.008219 +0.008258 +0.008341 +0.008328 +0.008327 +0.008304 +0.00074 +0.008299 +0.008338 +0.008423 +0.008394 +0.008426 +0.008389 +0.008377 +0.008413 +0.008496 +0.008469 +0.008498 +0.008455 +0.00844 +0.008472 +0.008557 +0.008527 +0.008576 +0.008557 +0.008556 +0.008585 +0.008673 +0.008637 +0.008645 +0.008585 +0.00854 +0.008544 +0.0086 +0.008531 +0.008522 +0.008436 +0.008393 +0.008379 +0.00842 +0.00835 +0.008349 +0.00826 +0.008212 +0.008206 +0.008259 +0.008195 +0.008193 +0.008135 +0.008096 +0.008102 +0.00816 +0.008119 +0.008132 +0.008089 +0.008067 +0.008079 +0.008158 +0.008118 +0.008143 +0.008114 +0.008093 +0.008123 +0.008201 +0.008175 +0.008201 +0.008173 +0.008162 +0.008199 +0.008281 +0.008255 +0.008287 +0.008248 +0.000741 +0.008229 +0.008274 +0.008354 +0.008346 +0.00836 +0.008328 +0.008313 +0.008358 +0.008431 +0.008424 +0.008448 +0.008414 +0.008392 +0.008435 +0.008508 +0.008501 +0.008527 +0.008494 +0.008478 +0.00852 +0.00859 +0.008584 +0.008608 +0.008581 +0.008557 +0.008622 +0.008688 +0.008684 +0.008716 +0.008678 +0.008667 +0.008706 +0.008711 +0.008609 +0.008604 +0.008536 +0.008449 +0.008434 +0.008472 +0.008418 +0.008419 +0.008356 +0.008276 +0.008278 +0.008315 +0.008277 +0.008287 +0.008226 +0.00819 +0.008151 +0.008213 +0.008162 +0.008197 +0.008139 +0.008132 +0.008156 +0.008222 +0.008197 +0.008209 +0.008185 +0.008156 +0.008203 +0.008253 +0.008207 +0.008242 +0.008211 +0.008182 +0.008221 +0.008291 +0.008253 +0.008295 +0.008266 +0.008246 +0.008302 +0.008377 +0.008356 +0.008389 +0.008348 +0.000742 +0.008336 +0.0084 +0.008448 +0.008447 +0.008468 +0.008454 +0.00842 +0.008482 +0.008551 +0.00853 +0.008541 +0.008514 +0.008486 +0.008536 +0.008587 +0.008571 +0.008594 +0.008567 +0.008539 +0.008583 +0.008662 +0.008679 +0.00872 +0.008689 +0.008653 +0.008686 +0.00871 +0.008677 +0.008635 +0.008584 +0.008518 +0.008517 +0.008535 +0.00848 +0.008459 +0.008389 +0.008327 +0.008341 +0.008372 +0.008328 +0.008323 +0.00827 +0.008217 +0.008242 +0.008279 +0.008257 +0.008267 +0.008228 +0.008198 +0.008241 +0.008289 +0.008278 +0.008287 +0.00825 +0.008226 +0.008284 +0.008347 +0.008338 +0.008352 +0.008323 +0.008301 +0.00835 +0.00842 +0.008425 +0.008425 +0.000743 +0.00841 +0.008384 +0.008438 +0.008506 +0.008495 +0.008521 +0.008488 +0.008466 +0.00852 +0.008596 +0.008577 +0.008603 +0.00857 +0.008556 +0.008608 +0.008673 +0.008662 +0.008689 +0.008654 +0.00864 +0.008688 +0.008766 +0.00874 +0.008769 +0.008746 +0.008722 +0.008786 +0.00887 +0.00885 +0.008875 +0.008835 +0.008797 +0.008781 +0.008731 +0.008676 +0.008667 +0.008603 +0.008495 +0.00847 +0.008505 +0.008456 +0.008442 +0.008385 +0.008347 +0.008367 +0.008375 +0.008288 +0.0083 +0.008253 +0.008215 +0.008222 +0.008268 +0.008225 +0.008248 +0.0082 +0.008192 +0.008222 +0.008297 +0.008254 +0.008284 +0.008252 +0.008219 +0.008248 +0.008297 +0.008272 +0.0083 +0.008271 +0.008264 +0.008303 +0.008385 +0.00837 +0.00839 +0.008376 +0.008356 +0.008398 +0.008489 +0.000744 +0.008451 +0.008486 +0.008457 +0.008436 +0.008498 +0.008568 +0.008558 +0.008563 +0.008547 +0.00852 +0.00857 +0.008636 +0.008602 +0.008617 +0.008594 +0.008563 +0.008615 +0.008677 +0.008677 +0.008688 +0.008702 +0.008684 +0.008735 +0.008797 +0.008757 +0.008744 +0.008687 +0.008612 +0.008626 +0.00866 +0.008605 +0.008565 +0.008505 +0.008439 +0.008444 +0.008475 +0.008421 +0.008408 +0.008351 +0.008295 +0.00831 +0.008349 +0.008306 +0.008299 +0.008262 +0.008216 +0.008246 +0.008299 +0.008273 +0.008268 +0.00825 +0.008197 +0.008251 +0.008315 +0.008299 +0.008307 +0.008285 +0.008252 +0.00831 +0.00838 +0.008371 +0.008387 +0.008358 +0.008342 +0.008391 +0.00847 +0.008448 +0.000745 +0.008475 +0.00844 +0.008418 +0.008469 +0.008543 +0.008534 +0.008552 +0.00853 +0.0085 +0.008557 +0.008627 +0.008622 +0.008635 +0.008613 +0.008585 +0.008641 +0.008701 +0.008706 +0.008725 +0.008697 +0.008674 +0.008734 +0.008805 +0.008813 +0.008826 +0.008797 +0.008751 +0.008787 +0.00876 +0.008644 +0.008637 +0.008572 +0.00848 +0.008476 +0.008502 +0.008453 +0.008443 +0.00839 +0.008347 +0.00836 +0.008355 +0.008314 +0.008288 +0.008266 +0.008197 +0.008229 +0.008254 +0.008236 +0.008226 +0.008214 +0.008165 +0.008213 +0.008241 +0.008227 +0.008232 +0.008206 +0.008183 +0.008225 +0.008303 +0.008273 +0.00829 +0.008252 +0.008216 +0.008283 +0.008343 +0.008319 +0.008349 +0.008324 +0.008301 +0.008383 +0.008412 +0.008409 +0.000746 +0.008445 +0.008403 +0.008389 +0.008443 +0.008525 +0.008496 +0.008524 +0.008486 +0.00846 +0.008489 +0.00856 +0.008531 +0.008558 +0.008521 +0.008508 +0.008553 +0.008646 +0.008659 +0.008693 +0.008659 +0.008623 +0.008676 +0.008751 +0.008744 +0.00877 +0.008735 +0.008707 +0.008725 +0.008776 +0.008721 +0.008701 +0.008628 +0.008564 +0.008549 +0.008583 +0.008525 +0.008499 +0.008433 +0.008378 +0.008374 +0.008422 +0.008371 +0.008364 +0.008306 +0.008261 +0.008271 +0.008328 +0.0083 +0.008302 +0.008261 +0.008232 +0.008255 +0.008327 +0.008306 +0.008325 +0.008293 +0.008273 +0.008307 +0.008387 +0.008374 +0.008393 +0.00837 +0.008345 +0.008391 +0.008475 +0.008444 +0.008471 +0.000747 +0.008458 +0.008424 +0.008478 +0.008543 +0.008536 +0.008561 +0.008541 +0.008512 +0.008559 +0.008629 +0.008627 +0.00863 +0.008616 +0.008593 +0.008645 +0.008717 +0.008715 +0.008739 +0.008709 +0.008684 +0.008741 +0.00881 +0.008802 +0.008841 +0.008823 +0.008795 +0.008823 +0.008797 +0.008755 +0.008739 +0.008691 +0.008633 +0.008646 +0.008627 +0.008561 +0.008531 +0.008475 +0.008396 +0.00839 +0.008418 +0.008376 +0.008388 +0.008332 +0.008289 +0.008305 +0.008336 +0.008299 +0.008301 +0.00827 +0.008215 +0.008233 +0.008298 +0.008264 +0.008295 +0.008262 +0.008238 +0.008284 +0.008351 +0.008346 +0.008359 +0.008349 +0.008324 +0.008373 +0.008451 +0.008438 +0.008438 +0.00839 +0.000748 +0.008379 +0.008432 +0.0085 +0.008469 +0.0085 +0.008479 +0.008461 +0.008509 +0.008576 +0.008561 +0.008588 +0.008561 +0.008542 +0.008595 +0.008656 +0.00864 +0.008667 +0.008627 +0.008604 +0.008651 +0.008716 +0.008707 +0.008748 +0.008733 +0.008725 +0.008761 +0.008836 +0.008826 +0.008823 +0.008784 +0.008739 +0.008749 +0.008785 +0.008719 +0.008715 +0.008634 +0.008569 +0.008561 +0.008594 +0.008539 +0.008524 +0.008454 +0.008398 +0.008405 +0.008446 +0.008402 +0.008398 +0.008327 +0.008289 +0.008312 +0.008367 +0.008336 +0.008343 +0.008306 +0.008279 +0.00831 +0.008373 +0.008344 +0.008362 +0.008338 +0.00832 +0.008365 +0.008443 +0.008418 +0.008454 +0.008404 +0.008388 +0.00843 +0.008513 +0.008494 +0.000749 +0.008529 +0.008497 +0.008473 +0.008521 +0.008588 +0.008587 +0.008607 +0.008584 +0.008555 +0.008607 +0.008678 +0.008669 +0.008689 +0.008669 +0.008644 +0.008696 +0.008758 +0.00876 +0.008781 +0.008748 +0.008731 +0.008783 +0.00886 +0.008846 +0.008873 +0.008857 +0.008837 +0.008897 +0.008971 +0.008916 +0.008823 +0.008765 +0.008703 +0.008735 +0.008773 +0.00871 +0.008625 +0.008566 +0.008498 +0.008536 +0.008582 +0.008527 +0.008533 +0.008455 +0.008357 +0.008391 +0.008416 +0.0084 +0.008399 +0.008364 +0.008322 +0.008348 +0.008384 +0.008345 +0.00837 +0.008343 +0.0083 +0.008349 +0.008385 +0.008359 +0.008386 +0.008358 +0.008339 +0.008399 +0.008447 +0.008448 +0.008463 +0.008437 +0.008425 +0.008484 +0.008547 +0.008543 +0.00075 +0.008559 +0.008513 +0.008498 +0.008521 +0.008589 +0.00857 +0.008611 +0.008579 +0.008561 +0.008614 +0.008683 +0.008668 +0.008696 +0.008664 +0.008643 +0.008687 +0.008763 +0.008751 +0.008784 +0.008766 +0.008748 +0.008788 +0.00887 +0.008847 +0.00888 +0.008846 +0.008835 +0.008861 +0.008916 +0.008875 +0.008851 +0.008765 +0.0087 +0.008686 +0.008707 +0.00865 +0.008621 +0.00854 +0.008494 +0.008475 +0.008511 +0.008477 +0.008454 +0.008388 +0.008345 +0.008348 +0.008398 +0.008369 +0.008361 +0.008316 +0.008291 +0.008312 +0.008371 +0.008356 +0.008368 +0.00833 +0.008312 +0.008342 +0.008405 +0.0084 +0.008423 +0.008385 +0.008374 +0.008413 +0.008484 +0.008475 +0.008499 +0.008468 +0.008444 +0.000751 +0.008501 +0.008563 +0.008561 +0.008578 +0.008553 +0.008533 +0.008583 +0.008648 +0.008644 +0.00866 +0.008641 +0.008616 +0.008668 +0.008736 +0.008728 +0.008749 +0.008724 +0.008696 +0.008752 +0.008822 +0.008822 +0.008837 +0.008818 +0.008796 +0.008859 +0.008937 +0.008932 +0.008945 +0.008916 +0.008821 +0.008776 +0.008798 +0.00875 +0.008731 +0.008672 +0.008595 +0.008521 +0.008552 +0.008507 +0.008493 +0.008439 +0.008397 +0.008424 +0.00847 +0.0084 +0.008326 +0.0083 +0.008249 +0.0083 +0.008325 +0.008303 +0.008296 +0.008276 +0.008217 +0.008241 +0.008294 +0.008265 +0.00828 +0.008262 +0.008236 +0.008296 +0.00835 +0.008358 +0.008356 +0.008344 +0.008324 +0.00838 +0.008446 +0.008455 +0.008446 +0.008433 +0.000752 +0.008426 +0.008467 +0.008545 +0.008516 +0.008522 +0.008477 +0.008463 +0.008518 +0.008588 +0.00857 +0.008595 +0.008565 +0.008551 +0.008594 +0.008669 +0.008641 +0.008665 +0.008632 +0.008613 +0.008658 +0.008758 +0.008761 +0.008784 +0.008752 +0.008724 +0.008771 +0.008845 +0.00883 +0.008846 +0.008779 +0.008711 +0.008722 +0.008753 +0.008696 +0.008678 +0.008599 +0.008541 +0.00855 +0.008592 +0.008546 +0.008552 +0.008473 +0.008431 +0.008447 +0.008498 +0.008458 +0.008467 +0.008415 +0.008378 +0.00841 +0.008474 +0.008449 +0.008472 +0.008429 +0.008399 +0.008441 +0.008507 +0.008486 +0.008517 +0.00848 +0.008459 +0.008505 +0.008574 +0.008567 +0.0086 +0.008555 +0.008539 +0.000753 +0.008584 +0.008665 +0.008653 +0.008671 +0.008654 +0.008624 +0.008672 +0.008747 +0.008744 +0.008753 +0.008738 +0.008711 +0.008762 +0.008832 +0.008823 +0.00884 +0.008816 +0.008796 +0.008849 +0.008917 +0.008922 +0.00893 +0.008915 +0.008878 +0.008952 +0.009024 +0.009017 +0.009045 +0.009021 +0.008986 +0.009027 +0.008995 +0.008923 +0.008909 +0.008855 +0.00874 +0.008724 +0.008746 +0.008697 +0.008685 +0.008621 +0.008571 +0.00858 +0.008562 +0.008517 +0.008502 +0.008468 +0.008412 +0.008438 +0.008439 +0.008418 +0.008415 +0.00839 +0.008347 +0.008395 +0.008429 +0.008389 +0.008415 +0.008379 +0.008353 +0.008395 +0.008432 +0.008416 +0.008427 +0.008409 +0.008396 +0.008445 +0.00852 +0.008508 +0.008526 +0.008508 +0.008489 +0.008537 +0.008608 +0.000754 +0.008609 +0.008605 +0.008591 +0.008568 +0.008635 +0.008711 +0.008684 +0.008703 +0.00865 +0.008629 +0.008677 +0.008745 +0.00872 +0.008743 +0.008709 +0.008694 +0.00874 +0.008825 +0.008828 +0.008876 +0.008851 +0.008826 +0.008856 +0.008932 +0.008896 +0.008866 +0.0088 +0.008744 +0.008743 +0.00878 +0.008706 +0.008692 +0.008617 +0.008551 +0.008543 +0.008583 +0.008529 +0.008503 +0.008445 +0.008389 +0.008389 +0.008434 +0.00839 +0.008385 +0.008342 +0.008299 +0.00832 +0.008381 +0.008353 +0.008357 +0.008325 +0.008301 +0.008325 +0.008396 +0.008367 +0.008398 +0.008374 +0.008353 +0.008389 +0.008464 +0.008449 +0.00847 +0.008452 +0.008419 +0.008474 +0.008557 +0.000755 +0.008529 +0.008561 +0.008518 +0.008508 +0.008548 +0.008637 +0.008615 +0.008643 +0.008603 +0.008595 +0.008639 +0.008731 +0.008699 +0.008735 +0.008694 +0.00868 +0.008717 +0.0088 +0.008783 +0.008814 +0.008774 +0.008768 +0.00881 +0.008899 +0.008887 +0.008915 +0.008878 +0.008876 +0.008919 +0.008997 +0.008909 +0.00884 +0.008767 +0.00871 +0.008711 +0.008716 +0.008624 +0.008623 +0.008544 +0.008478 +0.008448 +0.008495 +0.008447 +0.008449 +0.00839 +0.008314 +0.008303 +0.008349 +0.00831 +0.008322 +0.00828 +0.008247 +0.008277 +0.00834 +0.0083 +0.008332 +0.008263 +0.008237 +0.008239 +0.008315 +0.00829 +0.008316 +0.008292 +0.008275 +0.008312 +0.008404 +0.008374 +0.008404 +0.008382 +0.008369 +0.008426 +0.008485 +0.008464 +0.000756 +0.008492 +0.008461 +0.008456 +0.008484 +0.008547 +0.008512 +0.008553 +0.008523 +0.00851 +0.008552 +0.008637 +0.008588 +0.008626 +0.008589 +0.008572 +0.008609 +0.008691 +0.008678 +0.008717 +0.0087 +0.008695 +0.008725 +0.008811 +0.008782 +0.008789 +0.008728 +0.008687 +0.008679 +0.008718 +0.008643 +0.008628 +0.008541 +0.008487 +0.008471 +0.008503 +0.008446 +0.00844 +0.008368 +0.008324 +0.008322 +0.008371 +0.008322 +0.008317 +0.008261 +0.008234 +0.008238 +0.008307 +0.008259 +0.008276 +0.008238 +0.008224 +0.008242 +0.008313 +0.008283 +0.008306 +0.008263 +0.008268 +0.0083 +0.008389 +0.008358 +0.008382 +0.008353 +0.00833 +0.008372 +0.008434 +0.008419 +0.000757 +0.008449 +0.008424 +0.008419 +0.00846 +0.008547 +0.008516 +0.008547 +0.008507 +0.008495 +0.008522 +0.008619 +0.008575 +0.008625 +0.008594 +0.008585 +0.008621 +0.0087 +0.008683 +0.008719 +0.008672 +0.008672 +0.008707 +0.008797 +0.008774 +0.008817 +0.008785 +0.008774 +0.00882 +0.008878 +0.008782 +0.008784 +0.008709 +0.008638 +0.008573 +0.008607 +0.008549 +0.008543 +0.008415 +0.008364 +0.008355 +0.008387 +0.008326 +0.008347 +0.008263 +0.008188 +0.008175 +0.008227 +0.008172 +0.008183 +0.008123 +0.008105 +0.008123 +0.008196 +0.008127 +0.008144 +0.008089 +0.008063 +0.008111 +0.008179 +0.008145 +0.008182 +0.00813 +0.00813 +0.008136 +0.008215 +0.00819 +0.008226 +0.008181 +0.008188 +0.008227 +0.008308 +0.008293 +0.008306 +0.000758 +0.00828 +0.008264 +0.008311 +0.008392 +0.00838 +0.008392 +0.008368 +0.008352 +0.008402 +0.008474 +0.008453 +0.008475 +0.008438 +0.008415 +0.008455 +0.008529 +0.008502 +0.008523 +0.008492 +0.008476 +0.008512 +0.008609 +0.00861 +0.008645 +0.008603 +0.008562 +0.008581 +0.008627 +0.008574 +0.00855 +0.008481 +0.008407 +0.008404 +0.008441 +0.008371 +0.008355 +0.008284 +0.008223 +0.008222 +0.008258 +0.00821 +0.008209 +0.00814 +0.008087 +0.008105 +0.008154 +0.008114 +0.008128 +0.008088 +0.008052 +0.008083 +0.008147 +0.008119 +0.008134 +0.008098 +0.008079 +0.008125 +0.008198 +0.008177 +0.0082 +0.008168 +0.008146 +0.008195 +0.008257 +0.008253 +0.008284 +0.008246 +0.000759 +0.008222 +0.008282 +0.008337 +0.008335 +0.008357 +0.008333 +0.008306 +0.008355 +0.008422 +0.008417 +0.008436 +0.008415 +0.008389 +0.008441 +0.008503 +0.008502 +0.008516 +0.008495 +0.00846 +0.008525 +0.00858 +0.008586 +0.008598 +0.008579 +0.008556 +0.008623 +0.008693 +0.008681 +0.008708 +0.008681 +0.008652 +0.008668 +0.008614 +0.008564 +0.008541 +0.008478 +0.008388 +0.008344 +0.008354 +0.008307 +0.008285 +0.008226 +0.008173 +0.008183 +0.008178 +0.008104 +0.008091 +0.008055 +0.007955 +0.007973 +0.007997 +0.007964 +0.007958 +0.007922 +0.007893 +0.007938 +0.007985 +0.00795 +0.007925 +0.007899 +0.007862 +0.007923 +0.00799 +0.007965 +0.007995 +0.00797 +0.007939 +0.008004 +0.008065 +0.008045 +0.008079 +0.00804 +0.008035 +0.008084 +0.008122 +0.00076 +0.008119 +0.008128 +0.008117 +0.008082 +0.008145 +0.008203 +0.008197 +0.008209 +0.008193 +0.008168 +0.008218 +0.008275 +0.008257 +0.008272 +0.008247 +0.008217 +0.008272 +0.00834 +0.008326 +0.008342 +0.008336 +0.008332 +0.008378 +0.008451 +0.008436 +0.008449 +0.008413 +0.00836 +0.008375 +0.008412 +0.00836 +0.008328 +0.008256 +0.008179 +0.008181 +0.008206 +0.008149 +0.00812 +0.008071 +0.008001 +0.008013 +0.008046 +0.008005 +0.00799 +0.007944 +0.007885 +0.007906 +0.007949 +0.007923 +0.007929 +0.007902 +0.007857 +0.007897 +0.00795 +0.007932 +0.007938 +0.007916 +0.007891 +0.007943 +0.008008 +0.007992 +0.008007 +0.007989 +0.007955 +0.00801 +0.008065 +0.008068 +0.008073 +0.008059 +0.000761 +0.008042 +0.008091 +0.008157 +0.008143 +0.008165 +0.008132 +0.008109 +0.008152 +0.008229 +0.008217 +0.008244 +0.008218 +0.008194 +0.008239 +0.008314 +0.008296 +0.008327 +0.008293 +0.008273 +0.008315 +0.008392 +0.008374 +0.008409 +0.008375 +0.008361 +0.008411 +0.008486 +0.008479 +0.008504 +0.008492 +0.008454 +0.008444 +0.008437 +0.008382 +0.008375 +0.008323 +0.008271 +0.008286 +0.008275 +0.00819 +0.008189 +0.008135 +0.008093 +0.008075 +0.008115 +0.008056 +0.00807 +0.008023 +0.007976 +0.007974 +0.007999 +0.007959 +0.007974 +0.007927 +0.007922 +0.007931 +0.008013 +0.007968 +0.007987 +0.007954 +0.00793 +0.00798 +0.008013 +0.007984 +0.00801 +0.007976 +0.007976 +0.008013 +0.008078 +0.008063 +0.008085 +0.008057 +0.008053 +0.008106 +0.008173 +0.00816 +0.000762 +0.008155 +0.008147 +0.008133 +0.008147 +0.008222 +0.008189 +0.008228 +0.008193 +0.008183 +0.008224 +0.008305 +0.008265 +0.008298 +0.008261 +0.008252 +0.008282 +0.00837 +0.008374 +0.008414 +0.008371 +0.008354 +0.00839 +0.008469 +0.008444 +0.008483 +0.008434 +0.008403 +0.008415 +0.008462 +0.0084 +0.008403 +0.008321 +0.008274 +0.008262 +0.008302 +0.008239 +0.008238 +0.00816 +0.008111 +0.008113 +0.008159 +0.008108 +0.008108 +0.008042 +0.008004 +0.008021 +0.008072 +0.008036 +0.008058 +0.008005 +0.00798 +0.008006 +0.008067 +0.008041 +0.008067 +0.008029 +0.008011 +0.008046 +0.008116 +0.008092 +0.008133 +0.008089 +0.008085 +0.008121 +0.008194 +0.008187 +0.008195 +0.000763 +0.008171 +0.008165 +0.008196 +0.008282 +0.008255 +0.00828 +0.008243 +0.008241 +0.008277 +0.008363 +0.00834 +0.00837 +0.00833 +0.008317 +0.008349 +0.008428 +0.008413 +0.008445 +0.008398 +0.008395 +0.008433 +0.008513 +0.008502 +0.008532 +0.008498 +0.008489 +0.008536 +0.008622 +0.008597 +0.008636 +0.008592 +0.008537 +0.008464 +0.00851 +0.00844 +0.008448 +0.008388 +0.008339 +0.008281 +0.008281 +0.008212 +0.008233 +0.008161 +0.008123 +0.00815 +0.008191 +0.008147 +0.00809 +0.008014 +0.008001 +0.008003 +0.008082 +0.008021 +0.008046 +0.007998 +0.007978 +0.007962 +0.008019 +0.007989 +0.008009 +0.007982 +0.007969 +0.007999 +0.008083 +0.008046 +0.008082 +0.008045 +0.008034 +0.00807 +0.008157 +0.008125 +0.008171 +0.008119 +0.008121 +0.000764 +0.008174 +0.008228 +0.008216 +0.008244 +0.008219 +0.008206 +0.008211 +0.008278 +0.008254 +0.008283 +0.008258 +0.008238 +0.008283 +0.008354 +0.008335 +0.008361 +0.008326 +0.008308 +0.00836 +0.008446 +0.008447 +0.008476 +0.00843 +0.008415 +0.00845 +0.008528 +0.008506 +0.008515 +0.008466 +0.008404 +0.008406 +0.00844 +0.008383 +0.008355 +0.008289 +0.008215 +0.008218 +0.008256 +0.008195 +0.008183 +0.008127 +0.008075 +0.008084 +0.008139 +0.008097 +0.008091 +0.008041 +0.007994 +0.008019 +0.008085 +0.008059 +0.008067 +0.008024 +0.007993 +0.008017 +0.008088 +0.008074 +0.008089 +0.008059 +0.008032 +0.008069 +0.008148 +0.008131 +0.008152 +0.008125 +0.008103 +0.00815 +0.008225 +0.008207 +0.008224 +0.000765 +0.008207 +0.008175 +0.008227 +0.008299 +0.008294 +0.008297 +0.008285 +0.008261 +0.008311 +0.008373 +0.008367 +0.008387 +0.008361 +0.008338 +0.008388 +0.008455 +0.008453 +0.008468 +0.008444 +0.008413 +0.008474 +0.008535 +0.008539 +0.008553 +0.008532 +0.008515 +0.00857 +0.008648 +0.008643 +0.008664 +0.008627 +0.008508 +0.008524 +0.00856 +0.008513 +0.008505 +0.008451 +0.008387 +0.008347 +0.008345 +0.008294 +0.008281 +0.008243 +0.008196 +0.008217 +0.008257 +0.008231 +0.008161 +0.008105 +0.008053 +0.008081 +0.008119 +0.008084 +0.008082 +0.008058 +0.008019 +0.00804 +0.008075 +0.008061 +0.008053 +0.008045 +0.008014 +0.008066 +0.008126 +0.008107 +0.008137 +0.008105 +0.008081 +0.008139 +0.008196 +0.008184 +0.00823 +0.008176 +0.008153 +0.000766 +0.008179 +0.008234 +0.008217 +0.00824 +0.008228 +0.0082 +0.008267 +0.00833 +0.008326 +0.008344 +0.008321 +0.008293 +0.008344 +0.008415 +0.008415 +0.008433 +0.008411 +0.008386 +0.008434 +0.008503 +0.008499 +0.008519 +0.008486 +0.008467 +0.008518 +0.008583 +0.008571 +0.008557 +0.008501 +0.00844 +0.008448 +0.008465 +0.008418 +0.008392 +0.008323 +0.008244 +0.008253 +0.008279 +0.008234 +0.008213 +0.008162 +0.008106 +0.008117 +0.008152 +0.008128 +0.008112 +0.008061 +0.008025 +0.00805 +0.008103 +0.008088 +0.008085 +0.008053 +0.008015 +0.008054 +0.0081 +0.008103 +0.008114 +0.008084 +0.008058 +0.008098 +0.008167 +0.008164 +0.00817 +0.008157 +0.008127 +0.008182 +0.008258 +0.008229 +0.000767 +0.008257 +0.008235 +0.008201 +0.008259 +0.008316 +0.008306 +0.008335 +0.008318 +0.008289 +0.008337 +0.008406 +0.008393 +0.008413 +0.008385 +0.00836 +0.008421 +0.00848 +0.008482 +0.008497 +0.008475 +0.008449 +0.0085 +0.008578 +0.008568 +0.008592 +0.008576 +0.008551 +0.008619 +0.008691 +0.008627 +0.00857 +0.008518 +0.008455 +0.008473 +0.008482 +0.008422 +0.008367 +0.008299 +0.008223 +0.008217 +0.008248 +0.008195 +0.008178 +0.008127 +0.008017 +0.008029 +0.008059 +0.008016 +0.008021 +0.007972 +0.007934 +0.007927 +0.007959 +0.00792 +0.007929 +0.007904 +0.007866 +0.007907 +0.007957 +0.007946 +0.00795 +0.007929 +0.007882 +0.007901 +0.007966 +0.007944 +0.007965 +0.007956 +0.007925 +0.007975 +0.00805 +0.008043 +0.00806 +0.008048 +0.008022 +0.008084 +0.008127 +0.000768 +0.008117 +0.008152 +0.008123 +0.008105 +0.008154 +0.008225 +0.008214 +0.008237 +0.00822 +0.00818 +0.008232 +0.0083 +0.008279 +0.008303 +0.008273 +0.008242 +0.008283 +0.008343 +0.008333 +0.008352 +0.008322 +0.00831 +0.008366 +0.008453 +0.008433 +0.008432 +0.008363 +0.008311 +0.008295 +0.008332 +0.008287 +0.008259 +0.008174 +0.008112 +0.00811 +0.008141 +0.008091 +0.008064 +0.008007 +0.007967 +0.007965 +0.008002 +0.007967 +0.007964 +0.007908 +0.007874 +0.007888 +0.007946 +0.007924 +0.007933 +0.007889 +0.007866 +0.007891 +0.007954 +0.007944 +0.007965 +0.007922 +0.007912 +0.007941 +0.00802 +0.007998 +0.008025 +0.007996 +0.007977 +0.008022 +0.008086 +0.008074 +0.000769 +0.00811 +0.008067 +0.008057 +0.008091 +0.008177 +0.008143 +0.008184 +0.008151 +0.008134 +0.008173 +0.008246 +0.00823 +0.008262 +0.008221 +0.008214 +0.008248 +0.00833 +0.008311 +0.008342 +0.008301 +0.008292 +0.008337 +0.008416 +0.0084 +0.008439 +0.0084 +0.0084 +0.008446 +0.008543 +0.008481 +0.008426 +0.008361 +0.008319 +0.00833 +0.008381 +0.008315 +0.008271 +0.008154 +0.008116 +0.00813 +0.008178 +0.008102 +0.008079 +0.007993 +0.007949 +0.007964 +0.008003 +0.007961 +0.007939 +0.007871 +0.007841 +0.007853 +0.007907 +0.00787 +0.007902 +0.007839 +0.007837 +0.007824 +0.007899 +0.00785 +0.00788 +0.007853 +0.007834 +0.007875 +0.007949 +0.007917 +0.007951 +0.007919 +0.007904 +0.00795 +0.008033 +0.008014 +0.008028 +0.007999 +0.007995 +0.00077 +0.008029 +0.008108 +0.008088 +0.008112 +0.008076 +0.008044 +0.008061 +0.008145 +0.008109 +0.008149 +0.008114 +0.008107 +0.00814 +0.008216 +0.008198 +0.008234 +0.008217 +0.008212 +0.008254 +0.008326 +0.008297 +0.008326 +0.008291 +0.008283 +0.008314 +0.008405 +0.008374 +0.008393 +0.008331 +0.008296 +0.008286 +0.008329 +0.00826 +0.008255 +0.008176 +0.008128 +0.008122 +0.008153 +0.008092 +0.008102 +0.00803 +0.007992 +0.008002 +0.008052 +0.007999 +0.008007 +0.007952 +0.007926 +0.007937 +0.008005 +0.007962 +0.00799 +0.007937 +0.007923 +0.007955 +0.008033 +0.007988 +0.008019 +0.007973 +0.007957 +0.008 +0.008083 +0.008061 +0.008094 +0.008049 +0.008038 +0.008071 +0.008153 +0.008122 +0.000771 +0.008159 +0.008114 +0.008125 +0.008152 +0.008229 +0.008209 +0.008238 +0.008197 +0.008186 +0.008224 +0.008309 +0.008287 +0.008322 +0.008281 +0.008266 +0.008306 +0.008391 +0.008368 +0.008396 +0.008361 +0.00835 +0.008383 +0.008471 +0.00845 +0.008488 +0.008445 +0.008448 +0.008487 +0.008575 +0.008559 +0.008588 +0.008551 +0.008457 +0.008457 +0.008501 +0.008442 +0.00845 +0.008386 +0.008352 +0.008341 +0.008328 +0.008249 +0.008267 +0.008209 +0.008176 +0.008203 +0.008249 +0.008175 +0.008158 +0.008085 +0.00808 +0.008075 +0.008141 +0.008071 +0.008114 +0.008057 +0.008057 +0.008062 +0.008131 +0.008079 +0.008113 +0.008079 +0.008067 +0.008116 +0.008181 +0.008166 +0.008184 +0.008155 +0.008145 +0.008178 +0.008257 +0.008238 +0.008241 +0.000772 +0.008234 +0.008219 +0.008235 +0.008321 +0.008281 +0.008322 +0.008285 +0.008283 +0.008323 +0.008403 +0.008374 +0.008404 +0.008369 +0.008359 +0.008398 +0.008478 +0.008451 +0.008479 +0.008446 +0.008421 +0.008463 +0.008542 +0.008513 +0.008577 +0.008542 +0.008537 +0.008565 +0.00863 +0.008593 +0.008594 +0.008511 +0.008464 +0.008477 +0.008519 +0.008465 +0.008452 +0.008376 +0.008347 +0.008349 +0.008399 +0.008351 +0.008362 +0.008306 +0.008287 +0.008295 +0.008354 +0.008317 +0.008328 +0.008276 +0.008257 +0.008292 +0.008359 +0.008331 +0.008353 +0.008297 +0.008291 +0.008315 +0.008398 +0.00838 +0.008407 +0.008358 +0.008354 +0.008383 +0.008471 +0.008463 +0.008474 +0.008437 +0.000773 +0.008427 +0.00846 +0.008554 +0.008535 +0.008566 +0.008525 +0.008509 +0.008547 +0.008631 +0.008611 +0.008643 +0.008605 +0.008598 +0.008637 +0.008723 +0.008702 +0.008735 +0.008694 +0.008687 +0.00871 +0.008798 +0.008779 +0.008812 +0.008775 +0.00876 +0.008814 +0.008896 +0.008877 +0.008916 +0.008879 +0.00887 +0.008921 +0.008988 +0.008877 +0.008805 +0.00872 +0.00867 +0.008668 +0.008644 +0.008571 +0.008586 +0.008503 +0.008447 +0.008458 +0.008459 +0.008396 +0.008421 +0.008352 +0.008311 +0.008275 +0.008323 +0.008271 +0.008296 +0.008237 +0.008224 +0.008245 +0.008333 +0.008276 +0.008314 +0.008264 +0.008235 +0.008232 +0.008288 +0.008269 +0.008296 +0.00826 +0.008262 +0.008288 +0.00837 +0.008345 +0.008378 +0.008345 +0.008343 +0.008381 +0.008475 +0.008437 +0.008467 +0.000774 +0.008436 +0.008422 +0.008474 +0.008551 +0.008535 +0.00856 +0.008541 +0.00851 +0.008565 +0.008637 +0.008605 +0.008626 +0.008592 +0.008579 +0.008617 +0.008678 +0.008646 +0.008675 +0.008636 +0.008632 +0.00867 +0.008751 +0.008753 +0.008753 +0.008679 +0.00862 +0.008591 +0.008632 +0.008588 +0.008554 +0.008474 +0.00841 +0.008404 +0.008444 +0.008392 +0.008373 +0.008313 +0.008277 +0.008265 +0.008312 +0.008273 +0.008269 +0.008216 +0.008185 +0.008208 +0.008255 +0.008241 +0.008251 +0.008202 +0.008193 +0.008209 +0.008283 +0.008273 +0.008285 +0.008251 +0.00824 +0.008277 +0.008353 +0.008341 +0.00836 +0.008336 +0.008314 +0.008366 +0.008426 +0.000775 +0.008417 +0.008448 +0.008411 +0.008398 +0.008436 +0.008523 +0.008497 +0.008529 +0.008491 +0.008483 +0.008521 +0.008612 +0.008575 +0.008615 +0.00857 +0.008561 +0.008602 +0.008686 +0.008665 +0.008705 +0.00866 +0.008653 +0.008702 +0.008782 +0.008769 +0.00881 +0.008768 +0.008767 +0.00879 +0.008766 +0.008678 +0.008678 +0.008594 +0.008504 +0.008451 +0.008491 +0.008427 +0.008415 +0.008337 +0.008308 +0.008233 +0.008271 +0.008204 +0.008207 +0.008154 +0.008106 +0.008064 +0.0081 +0.008037 +0.008063 +0.008011 +0.007982 +0.008019 +0.008075 +0.00803 +0.008052 +0.008008 +0.007985 +0.007995 +0.008041 +0.008 +0.008039 +0.007999 +0.007989 +0.008028 +0.008114 +0.00808 +0.008116 +0.008089 +0.008078 +0.008114 +0.008196 +0.008195 +0.008199 +0.008158 +0.000776 +0.008161 +0.008213 +0.008296 +0.008251 +0.008289 +0.008263 +0.008249 +0.008244 +0.008316 +0.008274 +0.00832 +0.008286 +0.008279 +0.008315 +0.008397 +0.008374 +0.00841 +0.008394 +0.008392 +0.008429 +0.008505 +0.008486 +0.008513 +0.008464 +0.008461 +0.008504 +0.008579 +0.008549 +0.008547 +0.008468 +0.008427 +0.008415 +0.008445 +0.00838 +0.008362 +0.008279 +0.008231 +0.008217 +0.008256 +0.008213 +0.008202 +0.008138 +0.008105 +0.008106 +0.008159 +0.008118 +0.008125 +0.008072 +0.00805 +0.008066 +0.008131 +0.008105 +0.008122 +0.008082 +0.008074 +0.008097 +0.008171 +0.008149 +0.008177 +0.008141 +0.008138 +0.008166 +0.008248 +0.008223 +0.008253 +0.008216 +0.008196 +0.000777 +0.008249 +0.008321 +0.008314 +0.008337 +0.008287 +0.00828 +0.008329 +0.008402 +0.008392 +0.008413 +0.008381 +0.008358 +0.008402 +0.008484 +0.008475 +0.008498 +0.008465 +0.008449 +0.008491 +0.008571 +0.008558 +0.008576 +0.008557 +0.008532 +0.008596 +0.008672 +0.008661 +0.008697 +0.008654 +0.008618 +0.008566 +0.008612 +0.008567 +0.008569 +0.008511 +0.008463 +0.008485 +0.00847 +0.008384 +0.008382 +0.008324 +0.008279 +0.008251 +0.008267 +0.008225 +0.008223 +0.008173 +0.008137 +0.008119 +0.008144 +0.008096 +0.008103 +0.008084 +0.008045 +0.008085 +0.008146 +0.0081 +0.008121 +0.008096 +0.00805 +0.008066 +0.008131 +0.008097 +0.008133 +0.008108 +0.008092 +0.008132 +0.008207 +0.008188 +0.008224 +0.008195 +0.008177 +0.008228 +0.008317 +0.008269 +0.000778 +0.008306 +0.008287 +0.008266 +0.008318 +0.008389 +0.008382 +0.008401 +0.008382 +0.008335 +0.008346 +0.008408 +0.008395 +0.008419 +0.008401 +0.008375 +0.008425 +0.008496 +0.008497 +0.008539 +0.008517 +0.008497 +0.00854 +0.008605 +0.008602 +0.008613 +0.008579 +0.008557 +0.008587 +0.008618 +0.008574 +0.008535 +0.008469 +0.008411 +0.008411 +0.008426 +0.008382 +0.008358 +0.0083 +0.008248 +0.008252 +0.008286 +0.008258 +0.008234 +0.008188 +0.008144 +0.008167 +0.008205 +0.008184 +0.00818 +0.008142 +0.008112 +0.008153 +0.008209 +0.008196 +0.008195 +0.008159 +0.008137 +0.008184 +0.008251 +0.008247 +0.00826 +0.008228 +0.008199 +0.008253 +0.008296 +0.008304 +0.008314 +0.008299 +0.008277 +0.000779 +0.008333 +0.008399 +0.008392 +0.008406 +0.008377 +0.008352 +0.008404 +0.008475 +0.008481 +0.00848 +0.008463 +0.008433 +0.00849 +0.008557 +0.008559 +0.008574 +0.008546 +0.008519 +0.008578 +0.008642 +0.008638 +0.008652 +0.008634 +0.008609 +0.008679 +0.008758 +0.008749 +0.008764 +0.008719 +0.008613 +0.008617 +0.008631 +0.008589 +0.008571 +0.008499 +0.008364 +0.008346 +0.008366 +0.008326 +0.00832 +0.008262 +0.008211 +0.008249 +0.008227 +0.008171 +0.008166 +0.008138 +0.008069 +0.008073 +0.008098 +0.008074 +0.008091 +0.008051 +0.008024 +0.008059 +0.008103 +0.008098 +0.008101 +0.008076 +0.008059 +0.008089 +0.008106 +0.008089 +0.008101 +0.008084 +0.008068 +0.008118 +0.008182 +0.008175 +0.008189 +0.008167 +0.008152 +0.008202 +0.008266 +0.008268 +0.008275 +0.00078 +0.008249 +0.008241 +0.008292 +0.008361 +0.00834 +0.00836 +0.008344 +0.008318 +0.00832 +0.008387 +0.008367 +0.008395 +0.008367 +0.008349 +0.008392 +0.008471 +0.008486 +0.008527 +0.008496 +0.008473 +0.008515 +0.008585 +0.008565 +0.008594 +0.008532 +0.008507 +0.008533 +0.00857 +0.008506 +0.008495 +0.008394 +0.008343 +0.008337 +0.008366 +0.008312 +0.008298 +0.008222 +0.008173 +0.008178 +0.008219 +0.008179 +0.008174 +0.008112 +0.008071 +0.008087 +0.008139 +0.008108 +0.008128 +0.008072 +0.008054 +0.008085 +0.008144 +0.008124 +0.008141 +0.008108 +0.008085 +0.008131 +0.008201 +0.008188 +0.008209 +0.00817 +0.00816 +0.008195 +0.008287 +0.008256 +0.008282 +0.000781 +0.008259 +0.008236 +0.008283 +0.008355 +0.008346 +0.008362 +0.008344 +0.008315 +0.008367 +0.008435 +0.008429 +0.008445 +0.00843 +0.008393 +0.008451 +0.008514 +0.008511 +0.008526 +0.008499 +0.008479 +0.008534 +0.008597 +0.008599 +0.008617 +0.008602 +0.008561 +0.008642 +0.0087 +0.008702 +0.008723 +0.008704 +0.008629 +0.008568 +0.008592 +0.008537 +0.008523 +0.008477 +0.008408 +0.008381 +0.008355 +0.008302 +0.008306 +0.008267 +0.008201 +0.008252 +0.008269 +0.008249 +0.008158 +0.008117 +0.008072 +0.008105 +0.00815 +0.008127 +0.008124 +0.008089 +0.008033 +0.008051 +0.00811 +0.008079 +0.008106 +0.008077 +0.008047 +0.008103 +0.008152 +0.008149 +0.008164 +0.008147 +0.008128 +0.008178 +0.008243 +0.008233 +0.008264 +0.008192 +0.008186 +0.000782 +0.008213 +0.008274 +0.008269 +0.00829 +0.008269 +0.008242 +0.0083 +0.008369 +0.00836 +0.008378 +0.008357 +0.008336 +0.008387 +0.008451 +0.008441 +0.008454 +0.00843 +0.008403 +0.008458 +0.008515 +0.008528 +0.008556 +0.008529 +0.008494 +0.008553 +0.008617 +0.008622 +0.00863 +0.008595 +0.00856 +0.008591 +0.008607 +0.008571 +0.008537 +0.008466 +0.008396 +0.008396 +0.00842 +0.008386 +0.008351 +0.008293 +0.008245 +0.008259 +0.008292 +0.008265 +0.008256 +0.008205 +0.008166 +0.008182 +0.008227 +0.008211 +0.00821 +0.008178 +0.008143 +0.008176 +0.008222 +0.008214 +0.00822 +0.008197 +0.008171 +0.008212 +0.008268 +0.008268 +0.008283 +0.008265 +0.008241 +0.008291 +0.008356 +0.008343 +0.008367 +0.008328 +0.000783 +0.008322 +0.00837 +0.008439 +0.008437 +0.008447 +0.00842 +0.008389 +0.008445 +0.008517 +0.008512 +0.008531 +0.008506 +0.008477 +0.008529 +0.008604 +0.00859 +0.00861 +0.008586 +0.008559 +0.008613 +0.008682 +0.008674 +0.008704 +0.008684 +0.008657 +0.008719 +0.008792 +0.008789 +0.008785 +0.008741 +0.008602 +0.008595 +0.008618 +0.008558 +0.008551 +0.008438 +0.008348 +0.008362 +0.00841 +0.008349 +0.008325 +0.008286 +0.008183 +0.008202 +0.008232 +0.008202 +0.008198 +0.008153 +0.008106 +0.008157 +0.008198 +0.00818 +0.008127 +0.008109 +0.008069 +0.008119 +0.008188 +0.008158 +0.008177 +0.008156 +0.008124 +0.00818 +0.008222 +0.008204 +0.008228 +0.008203 +0.008181 +0.008247 +0.008331 +0.008264 +0.008316 +0.008295 +0.000784 +0.008271 +0.008317 +0.008379 +0.008359 +0.008375 +0.008358 +0.008332 +0.008396 +0.00846 +0.008441 +0.008461 +0.00844 +0.008416 +0.008464 +0.008528 +0.008505 +0.00852 +0.008492 +0.008466 +0.008523 +0.008591 +0.008578 +0.008619 +0.008615 +0.008586 +0.008634 +0.008697 +0.008668 +0.008649 +0.00859 +0.008525 +0.008525 +0.008541 +0.008479 +0.008441 +0.008377 +0.008306 +0.008305 +0.008332 +0.008285 +0.00826 +0.008216 +0.008156 +0.008177 +0.008209 +0.008174 +0.008157 +0.008114 +0.008071 +0.00811 +0.008161 +0.008141 +0.008137 +0.008107 +0.008064 +0.0081 +0.008165 +0.008156 +0.008164 +0.008143 +0.008112 +0.00816 +0.008231 +0.008222 +0.008239 +0.008215 +0.008181 +0.008241 +0.008301 +0.008304 +0.000785 +0.008323 +0.0083 +0.008269 +0.008308 +0.008388 +0.008372 +0.008392 +0.008375 +0.008347 +0.008401 +0.008472 +0.00846 +0.008482 +0.00845 +0.008429 +0.008477 +0.00855 +0.008538 +0.008568 +0.00854 +0.008505 +0.008563 +0.008632 +0.008631 +0.008653 +0.008626 +0.008617 +0.008664 +0.008751 +0.008723 +0.008734 +0.008637 +0.008532 +0.008527 +0.008566 +0.008504 +0.008479 +0.008356 +0.008296 +0.008325 +0.008346 +0.00829 +0.008293 +0.008198 +0.008146 +0.008136 +0.008198 +0.008137 +0.00814 +0.008091 +0.008066 +0.008087 +0.008136 +0.008092 +0.008105 +0.008072 +0.008033 +0.008062 +0.00811 +0.008087 +0.008113 +0.00808 +0.008069 +0.008111 +0.008177 +0.00817 +0.008186 +0.008165 +0.00815 +0.00819 +0.008284 +0.008256 +0.008255 +0.000786 +0.008252 +0.00823 +0.008236 +0.008308 +0.008281 +0.008323 +0.008283 +0.008276 +0.008317 +0.008401 +0.008372 +0.008408 +0.008371 +0.00836 +0.008396 +0.008476 +0.008455 +0.008503 +0.008475 +0.008461 +0.008494 +0.008578 +0.008555 +0.008577 +0.008538 +0.008532 +0.008567 +0.008637 +0.008587 +0.008575 +0.008496 +0.008447 +0.008436 +0.008484 +0.008411 +0.008387 +0.008326 +0.00828 +0.008266 +0.008304 +0.008254 +0.008253 +0.008189 +0.008148 +0.008146 +0.008209 +0.008148 +0.008155 +0.008106 +0.008083 +0.008098 +0.008168 +0.008135 +0.008143 +0.008095 +0.008071 +0.008103 +0.008186 +0.008158 +0.00818 +0.008139 +0.008126 +0.008153 +0.008247 +0.008223 +0.008254 +0.008216 +0.008201 +0.008244 +0.008315 +0.000787 +0.008302 +0.008338 +0.008291 +0.008285 +0.008321 +0.008401 +0.00838 +0.008414 +0.008378 +0.008364 +0.008402 +0.008484 +0.008463 +0.008496 +0.008459 +0.008452 +0.008491 +0.008563 +0.008548 +0.008584 +0.008534 +0.008533 +0.008568 +0.008664 +0.008638 +0.008681 +0.008643 +0.008636 +0.008683 +0.008773 +0.008706 +0.008672 +0.008609 +0.008579 +0.008597 +0.008634 +0.008546 +0.008492 +0.00841 +0.008357 +0.008362 +0.008389 +0.00832 +0.008318 +0.008253 +0.008171 +0.008175 +0.008217 +0.008174 +0.008175 +0.00813 +0.008096 +0.008128 +0.008168 +0.00811 +0.008138 +0.008084 +0.008076 +0.008078 +0.008133 +0.008105 +0.008138 +0.008092 +0.008092 +0.008121 +0.008202 +0.008176 +0.008206 +0.008174 +0.008164 +0.008205 +0.008295 +0.008278 +0.008281 +0.008266 +0.000788 +0.008255 +0.008291 +0.008384 +0.008348 +0.008362 +0.008307 +0.008305 +0.008352 +0.008432 +0.008395 +0.008437 +0.008377 +0.00837 +0.008408 +0.008486 +0.008463 +0.008496 +0.008456 +0.008453 +0.00852 +0.008613 +0.008589 +0.00862 +0.008564 +0.008551 +0.008564 +0.008627 +0.008561 +0.008542 +0.008477 +0.008427 +0.008413 +0.008456 +0.008382 +0.008378 +0.008297 +0.008246 +0.008236 +0.008288 +0.008236 +0.008234 +0.008169 +0.008131 +0.008133 +0.008191 +0.008145 +0.008157 +0.008115 +0.008086 +0.008108 +0.008182 +0.008141 +0.00816 +0.008116 +0.008095 +0.008134 +0.008223 +0.008193 +0.00822 +0.008186 +0.008166 +0.0082 +0.008285 +0.008249 +0.00829 +0.008233 +0.008238 +0.000789 +0.008283 +0.008366 +0.008354 +0.008366 +0.00834 +0.008318 +0.008351 +0.008429 +0.008417 +0.008448 +0.008429 +0.008395 +0.008444 +0.008514 +0.008504 +0.008525 +0.008497 +0.008479 +0.00852 +0.008592 +0.008586 +0.008611 +0.008584 +0.008563 +0.008617 +0.0087 +0.008692 +0.008709 +0.008687 +0.00867 +0.008722 +0.008762 +0.008659 +0.008637 +0.008567 +0.008512 +0.008488 +0.008508 +0.008452 +0.008461 +0.008403 +0.008354 +0.008331 +0.008361 +0.008314 +0.008307 +0.008274 +0.008182 +0.00819 +0.008242 +0.008197 +0.008225 +0.008175 +0.008159 +0.008187 +0.008254 +0.008219 +0.008237 +0.00821 +0.008178 +0.008203 +0.008242 +0.008214 +0.008249 +0.008217 +0.008205 +0.008252 +0.00832 +0.008314 +0.008332 +0.008302 +0.008296 +0.008345 +0.008429 +0.008382 +0.00079 +0.008427 +0.008401 +0.008373 +0.008427 +0.008502 +0.00849 +0.008502 +0.008485 +0.00844 +0.008468 +0.008525 +0.008513 +0.008529 +0.00851 +0.008485 +0.008534 +0.008624 +0.008646 +0.008674 +0.008637 +0.008606 +0.00866 +0.008722 +0.008723 +0.008729 +0.008695 +0.008663 +0.008696 +0.00873 +0.008689 +0.00866 +0.008588 +0.00852 +0.008518 +0.008539 +0.008496 +0.008458 +0.008385 +0.008327 +0.008333 +0.008362 +0.008329 +0.0083 +0.008238 +0.008185 +0.008195 +0.008237 +0.008219 +0.008218 +0.008165 +0.008132 +0.008155 +0.008198 +0.008189 +0.008198 +0.008167 +0.008139 +0.008178 +0.008229 +0.008231 +0.008241 +0.008213 +0.008197 +0.008245 +0.008314 +0.008304 +0.00833 +0.008297 +0.008273 +0.000791 +0.008321 +0.008393 +0.008379 +0.008401 +0.008387 +0.00836 +0.008408 +0.008474 +0.008471 +0.008483 +0.008459 +0.008433 +0.008478 +0.00855 +0.008543 +0.00856 +0.008541 +0.008517 +0.008575 +0.008642 +0.008639 +0.008658 +0.008642 +0.008615 +0.008693 +0.008753 +0.008745 +0.008768 +0.008695 +0.008626 +0.008653 +0.008687 +0.008646 +0.008623 +0.008572 +0.008469 +0.008429 +0.00846 +0.008426 +0.008411 +0.008355 +0.008309 +0.00834 +0.008374 +0.008315 +0.00827 +0.008222 +0.008186 +0.008202 +0.008247 +0.008204 +0.008212 +0.008182 +0.008152 +0.008204 +0.008264 +0.008244 +0.008249 +0.008237 +0.0082 +0.008267 +0.008323 +0.008285 +0.008309 +0.008281 +0.008252 +0.0083 +0.008351 +0.008345 +0.008364 +0.008353 +0.008324 +0.000792 +0.008399 +0.008447 +0.008439 +0.008462 +0.008432 +0.008419 +0.00847 +0.008547 +0.00852 +0.008551 +0.008518 +0.008501 +0.008545 +0.008613 +0.008584 +0.008603 +0.008573 +0.008557 +0.008597 +0.008669 +0.008671 +0.008696 +0.008686 +0.008669 +0.008714 +0.008775 +0.008749 +0.008753 +0.008685 +0.008642 +0.008649 +0.008677 +0.008623 +0.008601 +0.008531 +0.008473 +0.008476 +0.008514 +0.008465 +0.008468 +0.00841 +0.008369 +0.008383 +0.008433 +0.008401 +0.00839 +0.008344 +0.008316 +0.008346 +0.008403 +0.008376 +0.00839 +0.008344 +0.008324 +0.008363 +0.008431 +0.00841 +0.008428 +0.008392 +0.008376 +0.008428 +0.008497 +0.008488 +0.008505 +0.008469 +0.008456 +0.008482 +0.000793 +0.00858 +0.008561 +0.008598 +0.008549 +0.008536 +0.008582 +0.008669 +0.008644 +0.008674 +0.008635 +0.008623 +0.008665 +0.00875 +0.00873 +0.008764 +0.008724 +0.008709 +0.008746 +0.008836 +0.008818 +0.00885 +0.008812 +0.008804 +0.008847 +0.008943 +0.008924 +0.008959 +0.00893 +0.008925 +0.008892 +0.008884 +0.008815 +0.008819 +0.008745 +0.008695 +0.008708 +0.008697 +0.008598 +0.008594 +0.008507 +0.008446 +0.008437 +0.008479 +0.008409 +0.008424 +0.008358 +0.008323 +0.008284 +0.008336 +0.008289 +0.008305 +0.008272 +0.008232 +0.008273 +0.008341 +0.008302 +0.008325 +0.008284 +0.008276 +0.008292 +0.008357 +0.008306 +0.008338 +0.008312 +0.008294 +0.008338 +0.008427 +0.00838 +0.008427 +0.008392 +0.008375 +0.008436 +0.008519 +0.008495 +0.000794 +0.008484 +0.00845 +0.00844 +0.008484 +0.008564 +0.008535 +0.008575 +0.008538 +0.008529 +0.008568 +0.00865 +0.008618 +0.008642 +0.008606 +0.008586 +0.008627 +0.008711 +0.00869 +0.008749 +0.008716 +0.008708 +0.008735 +0.008822 +0.008799 +0.008804 +0.008743 +0.008703 +0.008697 +0.008738 +0.008666 +0.008653 +0.008581 +0.008523 +0.008512 +0.008569 +0.008484 +0.008491 +0.008433 +0.008391 +0.008392 +0.008452 +0.0084 +0.008402 +0.008341 +0.008318 +0.008337 +0.008409 +0.008369 +0.00838 +0.008337 +0.008304 +0.008325 +0.00841 +0.008381 +0.008403 +0.008365 +0.008341 +0.008379 +0.008466 +0.008437 +0.008471 +0.00843 +0.008422 +0.008462 +0.008549 +0.008527 +0.008546 +0.000795 +0.00852 +0.008494 +0.008539 +0.008626 +0.008613 +0.008632 +0.008601 +0.008582 +0.008624 +0.008704 +0.008691 +0.00872 +0.008683 +0.008669 +0.008714 +0.008793 +0.008778 +0.008809 +0.008774 +0.008754 +0.008811 +0.008883 +0.008878 +0.008909 +0.00888 +0.008868 +0.008934 +0.009008 +0.008903 +0.008884 +0.008822 +0.008765 +0.008747 +0.008761 +0.008677 +0.008681 +0.008576 +0.008505 +0.008503 +0.00853 +0.008484 +0.008483 +0.008425 +0.008345 +0.008323 +0.008374 +0.008327 +0.008345 +0.008286 +0.00827 +0.008285 +0.008353 +0.008301 +0.008275 +0.00825 +0.008216 +0.008252 +0.008335 +0.008288 +0.008324 +0.008284 +0.008262 +0.008309 +0.008356 +0.008334 +0.008368 +0.008336 +0.008317 +0.008376 +0.008445 +0.008441 +0.008444 +0.008421 +0.000796 +0.00841 +0.008464 +0.008545 +0.008513 +0.008539 +0.008514 +0.008505 +0.008554 +0.008624 +0.008591 +0.00862 +0.00858 +0.008562 +0.008588 +0.008659 +0.008623 +0.008658 +0.008626 +0.00862 +0.008653 +0.008764 +0.008766 +0.008801 +0.008762 +0.008738 +0.008761 +0.008836 +0.008768 +0.00876 +0.008688 +0.008633 +0.008617 +0.008658 +0.008579 +0.008567 +0.008486 +0.008427 +0.008416 +0.008472 +0.008411 +0.008407 +0.00834 +0.008294 +0.008289 +0.008348 +0.008306 +0.008313 +0.008265 +0.008231 +0.008244 +0.008322 +0.008283 +0.008298 +0.00826 +0.008242 +0.008263 +0.008345 +0.008312 +0.008347 +0.008311 +0.008292 +0.008321 +0.008411 +0.008377 +0.008416 +0.008381 +0.008364 +0.008405 +0.008484 +0.000797 +0.008465 +0.008504 +0.008461 +0.008454 +0.008491 +0.00857 +0.008543 +0.008577 +0.008545 +0.008536 +0.008575 +0.00866 +0.008634 +0.008669 +0.008628 +0.008612 +0.008654 +0.008736 +0.008709 +0.008755 +0.008709 +0.00871 +0.008745 +0.008844 +0.008822 +0.00885 +0.008811 +0.008818 +0.008859 +0.008915 +0.008803 +0.008802 +0.008717 +0.008648 +0.008615 +0.008646 +0.008569 +0.008573 +0.008473 +0.008398 +0.008399 +0.008437 +0.008392 +0.008378 +0.008282 +0.008237 +0.008229 +0.008286 +0.00823 +0.008245 +0.008193 +0.008165 +0.008187 +0.008226 +0.008193 +0.008215 +0.008171 +0.008159 +0.008181 +0.008245 +0.008214 +0.008234 +0.008201 +0.0082 +0.008214 +0.00829 +0.008255 +0.008278 +0.00825 +0.008248 +0.008285 +0.008365 +0.008348 +0.00838 +0.008357 +0.000798 +0.008317 +0.00838 +0.008459 +0.00843 +0.008472 +0.008423 +0.008419 +0.008463 +0.008547 +0.008509 +0.008541 +0.008495 +0.008483 +0.00852 +0.008597 +0.008562 +0.008602 +0.008549 +0.008542 +0.008571 +0.008662 +0.00865 +0.008706 +0.00868 +0.008662 +0.00868 +0.008755 +0.008701 +0.008694 +0.008604 +0.008564 +0.008533 +0.008578 +0.008494 +0.008476 +0.008404 +0.008348 +0.008332 +0.008383 +0.008319 +0.008323 +0.008251 +0.008212 +0.008209 +0.008268 +0.008219 +0.00823 +0.008183 +0.008157 +0.008169 +0.008243 +0.008202 +0.008226 +0.008187 +0.008174 +0.008193 +0.008277 +0.008238 +0.008271 +0.00824 +0.008232 +0.008263 +0.008349 +0.008317 +0.008353 +0.008308 +0.008293 +0.00834 +0.000799 +0.008422 +0.008405 +0.008433 +0.008396 +0.008372 +0.00842 +0.008499 +0.008485 +0.008511 +0.008477 +0.008462 +0.00851 +0.008583 +0.008566 +0.008591 +0.008561 +0.008542 +0.008588 +0.00866 +0.008656 +0.008675 +0.008653 +0.008622 +0.00869 +0.008767 +0.008749 +0.008789 +0.008759 +0.008729 +0.008684 +0.008697 +0.008633 +0.008624 +0.008569 +0.008508 +0.008517 +0.008481 +0.0084 +0.008397 +0.008343 +0.008284 +0.008267 +0.008284 +0.008227 +0.008239 +0.008181 +0.008142 +0.00814 +0.008169 +0.008125 +0.008133 +0.008103 +0.00806 +0.008114 +0.008163 +0.00814 +0.008147 +0.008087 +0.008073 +0.008091 +0.008153 +0.008134 +0.00815 +0.008124 +0.008113 +0.008152 +0.008228 +0.008209 +0.008233 +0.008204 +0.008205 +0.008236 +0.008329 +0.008293 +0.0008 +0.008309 +0.008302 +0.008266 +0.008338 +0.008405 +0.008385 +0.008406 +0.008379 +0.008334 +0.008369 +0.00843 +0.008417 +0.008437 +0.008415 +0.008388 +0.008442 +0.008506 +0.008515 +0.008557 +0.008536 +0.008518 +0.008555 +0.008627 +0.008608 +0.008624 +0.008588 +0.008548 +0.008577 +0.008609 +0.008549 +0.008513 +0.008447 +0.00837 +0.008368 +0.008382 +0.008331 +0.008303 +0.008241 +0.00818 +0.008193 +0.008217 +0.008178 +0.008171 +0.00812 +0.008069 +0.008099 +0.008132 +0.008112 +0.008112 +0.00808 +0.008038 +0.008087 +0.008133 +0.008116 +0.008125 +0.008092 +0.008068 +0.008124 +0.00818 +0.008174 +0.008191 +0.008162 +0.008128 +0.008187 +0.008241 +0.008245 +0.008258 +0.008245 +0.000801 +0.008216 +0.008267 +0.008338 +0.008321 +0.008338 +0.008319 +0.008294 +0.008352 +0.008408 +0.008408 +0.008423 +0.008398 +0.008376 +0.008432 +0.008498 +0.008496 +0.008514 +0.008491 +0.008458 +0.008523 +0.008589 +0.00858 +0.0086 +0.008589 +0.008563 +0.008641 +0.008694 +0.008632 +0.008642 +0.00862 +0.008576 +0.008582 +0.008605 +0.008548 +0.008529 +0.008426 +0.008328 +0.008316 +0.008355 +0.008304 +0.008265 +0.008231 +0.008142 +0.008138 +0.008161 +0.00812 +0.008126 +0.008078 +0.008037 +0.008056 +0.008081 +0.008044 +0.008041 +0.008027 +0.007959 +0.007987 +0.008033 +0.008003 +0.008025 +0.00799 +0.007969 +0.008017 +0.008074 +0.008069 +0.00808 +0.008055 +0.00804 +0.008093 +0.008147 +0.00814 +0.008171 +0.008115 +0.008122 +0.000802 +0.008178 +0.00823 +0.008209 +0.00822 +0.008193 +0.008163 +0.008216 +0.008286 +0.00827 +0.008299 +0.008269 +0.008249 +0.008303 +0.008362 +0.008342 +0.008359 +0.008327 +0.008303 +0.008361 +0.008424 +0.00841 +0.008426 +0.008416 +0.00841 +0.008473 +0.008537 +0.008526 +0.008532 +0.008479 +0.008439 +0.008454 +0.008486 +0.008457 +0.008419 +0.008348 +0.008291 +0.008298 +0.008316 +0.008266 +0.008237 +0.008187 +0.008115 +0.008135 +0.008165 +0.008134 +0.008127 +0.008059 +0.008028 +0.008054 +0.008094 +0.008079 +0.008079 +0.008049 +0.008011 +0.008053 +0.008107 +0.008098 +0.008105 +0.008079 +0.008062 +0.008104 +0.008171 +0.008167 +0.008179 +0.008153 +0.00814 +0.00816 +0.008249 +0.008239 +0.000803 +0.008261 +0.008231 +0.008208 +0.008256 +0.008321 +0.00832 +0.00834 +0.008312 +0.008286 +0.008335 +0.008407 +0.008403 +0.008418 +0.008397 +0.008368 +0.008417 +0.008484 +0.00848 +0.008502 +0.008478 +0.00845 +0.008508 +0.008576 +0.008581 +0.008593 +0.00858 +0.008558 +0.00862 +0.008694 +0.008674 +0.008594 +0.008525 +0.008467 +0.008484 +0.008518 +0.008467 +0.008447 +0.008317 +0.00825 +0.008266 +0.008314 +0.008267 +0.008232 +0.008166 +0.008103 +0.008138 +0.008166 +0.008129 +0.008128 +0.008101 +0.008028 +0.008045 +0.008084 +0.008069 +0.008076 +0.008052 +0.00803 +0.008063 +0.008125 +0.008112 +0.00812 +0.008113 +0.008079 +0.008146 +0.008209 +0.008184 +0.008229 +0.008162 +0.008147 +0.008171 +0.000804 +0.008233 +0.008217 +0.008248 +0.008223 +0.008207 +0.008259 +0.008318 +0.008318 +0.00834 +0.008319 +0.008292 +0.008349 +0.00842 +0.008404 +0.008425 +0.008402 +0.008377 +0.008425 +0.008487 +0.008476 +0.00849 +0.00846 +0.008434 +0.008481 +0.008562 +0.00857 +0.008588 +0.008563 +0.008532 +0.008576 +0.008644 +0.008615 +0.008597 +0.008542 +0.008474 +0.008475 +0.008498 +0.008443 +0.00841 +0.008348 +0.008284 +0.008285 +0.008317 +0.008279 +0.008255 +0.008205 +0.008154 +0.008168 +0.008209 +0.00818 +0.008167 +0.008131 +0.008087 +0.008114 +0.008174 +0.008152 +0.008156 +0.008126 +0.008096 +0.00813 +0.008195 +0.008184 +0.008194 +0.008177 +0.008151 +0.008195 +0.008261 +0.008253 +0.008266 +0.008252 +0.008218 +0.008274 +0.000805 +0.008344 +0.00833 +0.008353 +0.008316 +0.008308 +0.008353 +0.008426 +0.008414 +0.008429 +0.008401 +0.008383 +0.008434 +0.00851 +0.008495 +0.008521 +0.008487 +0.008467 +0.008513 +0.008588 +0.008582 +0.008597 +0.008572 +0.008556 +0.008613 +0.008694 +0.008681 +0.008711 +0.008673 +0.008667 +0.008646 +0.008647 +0.008593 +0.008581 +0.008531 +0.008476 +0.008483 +0.008455 +0.008373 +0.00836 +0.008313 +0.008264 +0.00822 +0.008259 +0.008204 +0.008192 +0.008161 +0.008093 +0.008092 +0.008102 +0.008061 +0.008079 +0.008022 +0.008011 +0.008038 +0.008103 +0.008069 +0.008076 +0.008053 +0.00803 +0.008046 +0.0081 +0.008062 +0.008088 +0.008062 +0.008044 +0.008097 +0.008165 +0.008141 +0.008179 +0.008147 +0.008131 +0.008182 +0.008262 +0.008238 +0.008259 +0.000806 +0.008225 +0.008228 +0.008257 +0.008342 +0.008322 +0.008353 +0.008315 +0.008289 +0.008295 +0.008371 +0.008343 +0.00838 +0.008344 +0.008333 +0.00837 +0.008455 +0.008458 +0.0085 +0.008465 +0.008455 +0.008478 +0.008568 +0.008539 +0.008565 +0.008526 +0.008492 +0.008495 +0.008538 +0.008462 +0.008466 +0.008386 +0.008323 +0.00831 +0.00835 +0.008273 +0.008271 +0.008199 +0.008155 +0.00813 +0.008191 +0.008134 +0.008137 +0.008081 +0.008044 +0.00805 +0.008112 +0.008066 +0.008074 +0.008036 +0.008013 +0.008047 +0.008124 +0.00809 +0.008114 +0.008071 +0.008045 +0.008079 +0.008152 +0.00814 +0.008184 +0.008142 +0.008129 +0.008165 +0.008243 +0.008223 +0.008238 +0.000807 +0.008211 +0.00819 +0.008245 +0.008322 +0.008303 +0.008333 +0.008297 +0.008276 +0.008315 +0.008396 +0.008371 +0.008407 +0.008377 +0.008361 +0.008407 +0.008469 +0.008465 +0.00849 +0.008453 +0.008434 +0.008487 +0.008553 +0.00854 +0.008571 +0.008537 +0.008529 +0.008583 +0.00866 +0.008644 +0.008674 +0.008652 +0.008629 +0.008594 +0.008604 +0.008548 +0.008549 +0.008482 +0.00843 +0.008449 +0.008405 +0.00834 +0.008331 +0.008268 +0.008236 +0.008236 +0.008256 +0.008187 +0.008183 +0.008155 +0.008095 +0.008088 +0.008121 +0.008086 +0.008096 +0.008061 +0.008035 +0.008068 +0.00814 +0.00811 +0.00811 +0.00809 +0.008066 +0.008122 +0.008195 +0.008131 +0.008147 +0.008111 +0.00809 +0.008159 +0.008218 +0.008197 +0.008232 +0.008201 +0.00818 +0.008235 +0.008311 +0.008296 +0.000808 +0.008291 +0.008284 +0.008276 +0.008319 +0.008393 +0.008364 +0.008404 +0.008345 +0.00834 +0.008365 +0.008445 +0.008413 +0.008443 +0.008408 +0.008394 +0.008424 +0.00851 +0.008483 +0.008519 +0.008503 +0.008511 +0.008543 +0.008628 +0.008599 +0.00863 +0.008581 +0.008575 +0.00859 +0.008645 +0.008585 +0.008574 +0.008467 +0.008424 +0.008406 +0.008435 +0.008378 +0.008361 +0.008276 +0.008241 +0.008242 +0.008284 +0.008239 +0.008234 +0.008169 +0.008141 +0.008147 +0.008201 +0.008168 +0.00818 +0.008122 +0.008114 +0.008128 +0.008201 +0.008175 +0.008199 +0.008151 +0.008135 +0.008165 +0.008244 +0.008226 +0.00825 +0.008206 +0.0082 +0.008227 +0.008314 +0.008297 +0.008329 +0.008293 +0.000809 +0.008266 +0.008317 +0.008397 +0.008378 +0.008407 +0.008376 +0.008348 +0.008392 +0.008473 +0.008463 +0.008489 +0.008455 +0.008434 +0.008477 +0.008554 +0.008547 +0.008572 +0.008537 +0.008513 +0.008564 +0.008635 +0.008619 +0.008651 +0.008615 +0.008603 +0.008656 +0.008735 +0.008726 +0.008752 +0.00873 +0.008709 +0.008762 +0.008762 +0.008663 +0.008652 +0.008575 +0.008475 +0.008456 +0.008476 +0.008417 +0.00841 +0.008314 +0.008255 +0.008252 +0.008292 +0.008247 +0.008234 +0.008175 +0.008096 +0.008119 +0.008147 +0.008112 +0.008117 +0.008079 +0.008052 +0.008085 +0.008134 +0.008095 +0.0081 +0.008066 +0.008036 +0.008049 +0.008117 +0.008078 +0.008106 +0.008077 +0.008063 +0.008103 +0.008188 +0.008159 +0.008184 +0.008167 +0.008147 +0.008189 +0.008265 +0.008264 +0.008271 +0.00081 +0.00823 +0.008233 +0.008277 +0.00836 +0.008329 +0.00836 +0.00833 +0.008315 +0.008315 +0.008385 +0.008353 +0.008391 +0.008357 +0.008346 +0.00838 +0.008467 +0.008462 +0.008518 +0.008481 +0.008464 +0.008501 +0.008584 +0.008555 +0.008589 +0.008542 +0.008528 +0.008567 +0.008631 +0.008576 +0.008571 +0.008477 +0.00843 +0.008428 +0.008457 +0.008387 +0.008367 +0.008282 +0.008229 +0.008219 +0.008257 +0.008197 +0.008197 +0.00812 +0.008081 +0.008095 +0.008134 +0.008091 +0.008095 +0.008041 +0.008018 +0.008043 +0.00811 +0.008076 +0.008099 +0.008043 +0.008022 +0.008052 +0.008136 +0.00812 +0.008149 +0.008102 +0.00809 +0.008127 +0.008199 +0.00818 +0.008207 +0.008177 +0.00815 +0.008201 +0.000811 +0.00829 +0.008272 +0.008291 +0.008256 +0.008243 +0.008271 +0.008365 +0.008332 +0.008367 +0.008336 +0.008325 +0.00836 +0.008441 +0.00842 +0.008454 +0.008412 +0.0084 +0.008443 +0.00852 +0.008499 +0.008534 +0.008492 +0.008487 +0.008528 +0.008618 +0.008595 +0.008634 +0.008593 +0.008595 +0.008644 +0.008729 +0.008657 +0.008576 +0.00851 +0.008468 +0.008473 +0.008517 +0.008405 +0.00836 +0.008299 +0.008256 +0.008226 +0.008258 +0.008211 +0.008202 +0.008148 +0.00811 +0.008082 +0.00811 +0.008054 +0.008074 +0.008016 +0.00799 +0.008026 +0.008094 +0.008059 +0.008076 +0.008034 +0.008027 +0.00805 +0.008113 +0.008077 +0.00809 +0.008053 +0.008046 +0.008058 +0.008146 +0.008109 +0.008142 +0.008115 +0.008107 +0.008138 +0.00823 +0.008206 +0.008247 +0.008196 +0.008186 +0.000812 +0.008236 +0.008304 +0.008289 +0.008317 +0.008293 +0.008273 +0.008321 +0.008392 +0.008375 +0.008392 +0.008366 +0.008346 +0.00839 +0.008465 +0.008433 +0.008456 +0.008423 +0.00839 +0.008438 +0.008514 +0.008489 +0.008532 +0.008513 +0.008519 +0.008543 +0.008603 +0.008559 +0.008547 +0.008461 +0.008404 +0.008416 +0.008439 +0.008381 +0.008364 +0.008297 +0.008237 +0.008245 +0.008282 +0.008232 +0.008233 +0.008169 +0.008127 +0.008137 +0.00818 +0.008142 +0.008149 +0.008077 +0.00806 +0.008089 +0.008145 +0.00812 +0.008129 +0.00808 +0.008053 +0.008087 +0.008158 +0.008146 +0.008166 +0.008123 +0.008116 +0.008143 +0.008213 +0.008205 +0.008226 +0.008193 +0.008178 +0.008231 +0.0083 +0.000813 +0.008287 +0.008311 +0.008277 +0.008265 +0.00829 +0.008373 +0.008357 +0.008396 +0.00836 +0.008349 +0.00838 +0.008466 +0.008439 +0.008472 +0.008428 +0.008422 +0.008459 +0.008536 +0.008516 +0.008555 +0.008515 +0.0085 +0.008548 +0.008628 +0.00861 +0.00865 +0.008607 +0.008603 +0.008654 +0.008741 +0.008709 +0.00872 +0.008622 +0.008513 +0.008502 +0.008545 +0.008481 +0.008455 +0.008329 +0.008278 +0.008273 +0.008307 +0.008261 +0.00825 +0.008195 +0.008109 +0.0081 +0.008149 +0.008099 +0.008101 +0.008054 +0.008022 +0.00805 +0.008132 +0.008071 +0.008063 +0.008001 +0.007988 +0.00803 +0.008097 +0.008067 +0.008106 +0.008055 +0.008055 +0.008089 +0.008165 +0.008128 +0.008153 +0.008121 +0.008089 +0.008137 +0.008214 +0.008178 +0.008224 +0.000814 +0.008186 +0.008172 +0.008223 +0.008298 +0.008262 +0.008306 +0.008273 +0.008263 +0.008298 +0.008387 +0.008346 +0.00839 +0.008343 +0.008333 +0.008375 +0.008458 +0.008419 +0.008445 +0.008408 +0.00839 +0.008422 +0.008508 +0.008484 +0.008513 +0.008481 +0.008494 +0.008544 +0.00862 +0.008585 +0.008587 +0.008499 +0.008447 +0.008424 +0.008452 +0.008401 +0.008382 +0.008283 +0.008234 +0.008224 +0.008259 +0.008205 +0.008195 +0.008116 +0.008077 +0.00808 +0.008124 +0.008081 +0.00808 +0.008014 +0.007991 +0.008007 +0.008072 +0.008047 +0.008064 +0.008014 +0.007996 +0.008016 +0.00809 +0.008072 +0.0081 +0.008053 +0.008042 +0.00807 +0.008149 +0.00813 +0.008165 +0.008126 +0.008122 +0.008144 +0.00822 +0.000815 +0.008207 +0.008252 +0.008198 +0.008192 +0.00823 +0.0083 +0.008287 +0.008316 +0.008287 +0.008269 +0.008305 +0.008382 +0.008373 +0.008397 +0.008365 +0.008349 +0.008389 +0.008464 +0.008448 +0.008479 +0.00845 +0.008411 +0.008472 +0.00854 +0.008537 +0.008561 +0.008536 +0.00852 +0.008572 +0.008649 +0.008636 +0.008664 +0.008636 +0.008607 +0.008561 +0.008561 +0.008504 +0.008486 +0.008433 +0.008352 +0.008287 +0.008318 +0.00826 +0.008237 +0.008201 +0.008135 +0.008166 +0.008196 +0.008121 +0.008095 +0.008043 +0.007993 +0.008018 +0.008046 +0.00802 +0.008033 +0.007995 +0.007975 +0.007994 +0.008057 +0.008009 +0.00803 +0.008013 +0.007983 +0.00802 +0.008077 +0.008045 +0.008077 +0.008049 +0.00803 +0.008087 +0.00815 +0.00812 +0.008153 +0.008129 +0.008124 +0.008144 +0.000816 +0.008207 +0.00819 +0.008206 +0.008196 +0.008171 +0.008223 +0.008284 +0.008272 +0.008296 +0.008277 +0.008249 +0.008305 +0.00837 +0.008355 +0.008364 +0.008339 +0.008311 +0.008355 +0.008422 +0.008419 +0.00844 +0.008427 +0.008419 +0.008473 +0.008523 +0.008519 +0.008539 +0.008504 +0.008465 +0.008493 +0.008523 +0.008473 +0.008451 +0.008384 +0.008312 +0.00831 +0.008332 +0.008285 +0.008261 +0.0082 +0.008147 +0.00817 +0.008196 +0.008163 +0.008161 +0.008117 +0.008065 +0.008094 +0.008131 +0.008109 +0.008126 +0.008089 +0.008052 +0.008093 +0.008141 +0.008122 +0.00813 +0.008106 +0.008082 +0.008135 +0.008191 +0.008181 +0.008193 +0.008162 +0.00814 +0.008187 +0.008246 +0.008252 +0.00826 +0.00826 +0.000817 +0.008219 +0.00827 +0.008339 +0.008321 +0.00835 +0.008323 +0.008307 +0.008348 +0.00842 +0.008408 +0.008438 +0.008392 +0.008385 +0.008434 +0.008505 +0.0085 +0.008509 +0.008481 +0.00847 +0.008509 +0.008587 +0.008575 +0.008611 +0.008561 +0.008561 +0.008609 +0.008693 +0.008681 +0.008708 +0.008676 +0.008575 +0.008559 +0.008594 +0.008542 +0.008541 +0.008465 +0.008385 +0.008306 +0.008337 +0.008292 +0.008286 +0.008217 +0.008184 +0.008195 +0.008243 +0.008171 +0.008097 +0.008057 +0.008004 +0.008042 +0.00808 +0.008045 +0.008056 +0.008014 +0.007984 +0.007968 +0.008031 +0.007988 +0.008014 +0.007996 +0.007957 +0.008014 +0.008075 +0.008053 +0.008086 +0.008053 +0.008037 +0.008093 +0.008152 +0.008139 +0.008182 +0.008133 +0.008115 +0.000818 +0.00818 +0.008251 +0.008233 +0.008208 +0.008185 +0.008163 +0.008221 +0.008289 +0.008267 +0.008293 +0.008265 +0.008248 +0.008299 +0.008362 +0.008345 +0.008355 +0.008336 +0.008312 +0.008359 +0.00844 +0.00845 +0.008475 +0.008447 +0.008416 +0.008467 +0.008532 +0.008521 +0.008542 +0.008512 +0.008464 +0.008483 +0.008508 +0.008469 +0.008447 +0.00837 +0.008301 +0.008312 +0.008334 +0.008286 +0.008269 +0.008207 +0.008146 +0.008165 +0.008202 +0.008168 +0.008154 +0.008098 +0.008054 +0.00809 +0.008123 +0.008111 +0.008112 +0.008073 +0.008035 +0.008078 +0.008127 +0.008122 +0.008135 +0.008101 +0.008071 +0.008121 +0.008187 +0.008186 +0.008199 +0.008171 +0.008152 +0.008197 +0.008264 +0.008254 +0.008287 +0.000819 +0.00825 +0.008228 +0.008273 +0.008346 +0.008335 +0.008368 +0.008332 +0.008312 +0.008355 +0.008423 +0.008419 +0.008446 +0.008413 +0.008391 +0.008438 +0.008517 +0.008498 +0.00852 +0.008493 +0.008477 +0.008523 +0.0086 +0.008593 +0.008614 +0.008589 +0.008581 +0.008633 +0.008713 +0.008688 +0.008628 +0.008538 +0.008484 +0.008504 +0.008543 +0.00845 +0.00839 +0.008318 +0.00828 +0.008248 +0.008277 +0.008226 +0.008211 +0.008175 +0.008116 +0.008126 +0.008124 +0.008085 +0.008081 +0.008048 +0.008005 +0.008045 +0.008107 +0.008068 +0.008081 +0.00801 +0.007987 +0.008025 +0.008085 +0.008082 +0.008074 +0.008057 +0.00805 +0.008081 +0.008161 +0.008131 +0.008148 +0.008136 +0.00812 +0.008148 +0.008221 +0.008187 +0.008211 +0.00082 +0.008207 +0.008164 +0.008214 +0.008303 +0.008275 +0.00831 +0.00827 +0.008262 +0.008304 +0.008388 +0.008358 +0.008387 +0.008351 +0.008332 +0.008368 +0.008442 +0.008417 +0.008452 +0.008409 +0.008399 +0.008442 +0.008548 +0.008531 +0.008565 +0.008518 +0.008496 +0.008518 +0.008574 +0.008516 +0.008521 +0.008441 +0.008382 +0.008373 +0.008411 +0.008353 +0.008352 +0.008251 +0.008206 +0.008215 +0.008263 +0.008207 +0.00822 +0.008149 +0.008108 +0.008119 +0.008179 +0.008134 +0.008157 +0.008095 +0.00807 +0.008097 +0.008163 +0.008128 +0.008165 +0.008112 +0.008091 +0.008113 +0.008196 +0.008177 +0.008211 +0.008174 +0.008156 +0.008196 +0.008269 +0.008251 +0.008279 +0.008236 +0.008225 +0.000821 +0.008278 +0.008349 +0.008338 +0.00836 +0.008323 +0.008305 +0.008345 +0.00843 +0.00842 +0.00844 +0.008411 +0.008386 +0.008433 +0.008508 +0.008499 +0.008527 +0.00849 +0.008477 +0.008519 +0.008593 +0.008589 +0.008604 +0.008586 +0.008568 +0.008619 +0.008708 +0.008688 +0.008723 +0.008681 +0.008595 +0.008577 +0.008613 +0.008564 +0.008566 +0.008501 +0.008456 +0.008388 +0.008409 +0.00835 +0.00834 +0.008313 +0.008246 +0.008279 +0.00833 +0.00828 +0.008264 +0.008154 +0.008131 +0.008131 +0.00821 +0.008158 +0.008179 +0.008141 +0.0081 +0.008111 +0.008153 +0.008126 +0.00815 +0.00812 +0.008103 +0.008151 +0.008198 +0.008198 +0.008214 +0.00819 +0.008171 +0.008225 +0.008296 +0.008283 +0.008299 +0.008276 +0.008253 +0.000822 +0.008265 +0.00833 +0.008295 +0.008335 +0.008311 +0.008302 +0.00834 +0.008423 +0.008398 +0.008438 +0.008398 +0.008391 +0.008424 +0.008508 +0.008494 +0.008533 +0.008493 +0.00848 +0.008514 +0.008601 +0.008572 +0.008608 +0.008577 +0.008568 +0.008603 +0.008675 +0.008651 +0.008666 +0.008604 +0.00856 +0.008544 +0.008574 +0.008518 +0.008496 +0.008406 +0.008352 +0.008339 +0.008378 +0.008324 +0.008318 +0.008242 +0.00821 +0.008214 +0.008264 +0.008219 +0.008232 +0.00816 +0.008133 +0.008149 +0.008214 +0.008189 +0.008208 +0.008153 +0.008137 +0.008167 +0.008229 +0.008214 +0.008241 +0.008195 +0.008182 +0.008213 +0.00829 +0.008277 +0.008311 +0.008267 +0.008261 +0.008292 +0.008371 +0.000823 +0.008352 +0.008392 +0.008348 +0.008334 +0.008374 +0.008455 +0.008436 +0.008466 +0.008434 +0.008421 +0.008453 +0.008535 +0.00851 +0.00855 +0.008511 +0.008503 +0.00854 +0.00862 +0.008598 +0.008636 +0.008594 +0.008584 +0.008628 +0.008714 +0.008688 +0.008739 +0.008705 +0.008696 +0.008741 +0.008781 +0.008675 +0.008675 +0.008599 +0.008533 +0.00847 +0.008499 +0.008443 +0.00844 +0.008347 +0.008279 +0.008258 +0.008294 +0.008252 +0.008254 +0.008204 +0.008165 +0.008142 +0.008163 +0.008106 +0.008117 +0.008086 +0.008059 +0.008091 +0.008165 +0.00811 +0.008146 +0.008097 +0.00808 +0.008128 +0.008207 +0.008168 +0.008165 +0.008111 +0.008108 +0.008155 +0.008229 +0.008197 +0.00825 +0.008196 +0.008198 +0.008241 +0.008333 +0.008294 +0.000824 +0.008323 +0.008294 +0.008279 +0.008337 +0.008406 +0.00838 +0.008415 +0.008389 +0.008371 +0.008413 +0.008466 +0.008439 +0.008464 +0.008438 +0.008416 +0.008456 +0.008525 +0.008504 +0.00852 +0.00849 +0.008477 +0.008526 +0.008627 +0.008633 +0.008654 +0.008599 +0.008565 +0.008568 +0.00859 +0.008526 +0.008508 +0.008421 +0.008361 +0.008345 +0.008364 +0.008313 +0.008292 +0.008202 +0.008161 +0.008165 +0.0082 +0.008165 +0.008161 +0.008087 +0.008055 +0.008064 +0.008113 +0.008091 +0.008098 +0.008053 +0.008031 +0.008058 +0.008116 +0.008106 +0.008114 +0.008084 +0.008072 +0.008095 +0.008164 +0.008157 +0.008187 +0.008152 +0.008133 +0.008171 +0.008247 +0.008226 +0.008245 +0.000825 +0.008231 +0.008204 +0.008256 +0.00832 +0.008313 +0.008333 +0.008313 +0.00828 +0.008336 +0.008404 +0.008393 +0.008413 +0.008393 +0.008367 +0.008418 +0.00848 +0.008474 +0.008493 +0.008472 +0.008451 +0.008501 +0.008565 +0.008568 +0.008576 +0.008558 +0.008528 +0.008597 +0.00866 +0.008655 +0.008684 +0.008671 +0.008633 +0.008677 +0.008653 +0.008568 +0.008554 +0.008496 +0.008385 +0.008352 +0.008373 +0.008322 +0.008304 +0.008238 +0.008169 +0.008153 +0.008182 +0.008147 +0.008125 +0.008104 +0.007998 +0.008015 +0.008041 +0.008023 +0.008019 +0.008001 +0.007964 +0.008014 +0.008068 +0.008043 +0.008066 +0.008036 +0.008023 +0.008072 +0.008125 +0.008096 +0.008099 +0.008095 +0.008062 +0.008104 +0.008175 +0.00815 +0.00818 +0.008158 +0.008138 +0.000826 +0.008196 +0.00826 +0.008234 +0.00827 +0.008241 +0.008224 +0.008279 +0.008348 +0.008325 +0.00835 +0.008322 +0.008307 +0.008325 +0.008389 +0.008363 +0.008388 +0.008359 +0.008336 +0.008381 +0.00845 +0.00846 +0.00851 +0.008479 +0.008466 +0.008498 +0.008572 +0.008549 +0.008555 +0.008505 +0.008471 +0.008456 +0.008497 +0.008422 +0.008409 +0.008339 +0.008278 +0.008266 +0.0083 +0.008244 +0.008224 +0.008166 +0.008117 +0.008111 +0.008155 +0.008108 +0.008105 +0.008058 +0.008023 +0.008037 +0.008088 +0.008062 +0.008065 +0.008026 +0.00801 +0.008039 +0.008109 +0.008083 +0.008091 +0.008058 +0.008029 +0.008067 +0.008153 +0.008144 +0.00817 +0.008134 +0.008116 +0.008155 +0.008231 +0.00821 +0.008225 +0.000827 +0.008185 +0.008176 +0.008227 +0.008313 +0.008291 +0.008326 +0.008284 +0.008271 +0.008302 +0.008385 +0.008358 +0.008393 +0.008352 +0.008355 +0.008392 +0.008478 +0.008453 +0.008494 +0.008448 +0.008438 +0.00847 +0.008562 +0.008528 +0.008581 +0.008521 +0.008534 +0.008581 +0.008664 +0.008634 +0.008648 +0.008553 +0.008521 +0.008521 +0.008571 +0.008498 +0.008464 +0.008336 +0.008273 +0.008242 +0.008304 +0.00824 +0.008199 +0.008138 +0.008078 +0.008046 +0.008098 +0.008045 +0.008067 +0.007996 +0.007955 +0.007922 +0.007993 +0.007936 +0.007968 +0.007921 +0.007901 +0.007937 +0.008002 +0.007983 +0.008003 +0.007969 +0.007963 +0.007992 +0.00809 +0.008042 +0.008071 +0.008045 +0.008009 +0.008051 +0.008104 +0.008083 +0.000828 +0.008118 +0.008095 +0.008087 +0.008115 +0.008206 +0.008178 +0.008209 +0.008177 +0.008179 +0.008213 +0.008292 +0.008265 +0.008296 +0.008263 +0.008256 +0.00829 +0.008371 +0.008334 +0.008359 +0.008319 +0.008312 +0.008335 +0.008419 +0.008384 +0.008425 +0.008377 +0.008383 +0.008437 +0.008529 +0.008501 +0.00851 +0.008437 +0.008394 +0.00838 +0.008412 +0.008369 +0.00835 +0.008264 +0.008213 +0.008205 +0.008244 +0.008189 +0.008176 +0.008106 +0.00807 +0.008064 +0.008118 +0.008075 +0.008076 +0.008017 +0.007992 +0.008001 +0.00806 +0.008038 +0.008058 +0.008008 +0.007994 +0.008009 +0.008086 +0.008064 +0.008092 +0.008054 +0.008044 +0.008072 +0.00815 +0.008129 +0.00816 +0.008137 +0.008106 +0.008148 +0.008227 +0.000829 +0.008209 +0.00824 +0.008207 +0.008189 +0.008228 +0.008306 +0.008286 +0.008322 +0.008287 +0.008271 +0.008307 +0.008383 +0.00837 +0.008402 +0.008361 +0.008352 +0.008388 +0.008474 +0.008447 +0.008479 +0.008441 +0.008431 +0.008464 +0.008554 +0.00853 +0.008572 +0.008534 +0.008525 +0.008573 +0.008658 +0.008629 +0.008644 +0.008579 +0.008464 +0.008432 +0.008473 +0.00842 +0.008413 +0.008326 +0.008225 +0.008216 +0.008279 +0.008204 +0.00822 +0.008157 +0.008122 +0.008132 +0.008123 +0.008079 +0.008071 +0.008035 +0.008004 +0.008031 +0.008104 +0.008046 +0.008048 +0.007978 +0.007976 +0.008013 +0.008077 +0.008053 +0.008076 +0.008035 +0.008027 +0.008071 +0.008147 +0.008125 +0.008146 +0.008111 +0.008124 +0.008114 +0.008183 +0.008172 +0.00083 +0.008197 +0.008179 +0.008152 +0.00821 +0.008274 +0.008258 +0.008289 +0.008257 +0.008242 +0.008288 +0.008369 +0.00835 +0.008374 +0.008342 +0.008328 +0.008363 +0.008441 +0.008418 +0.008433 +0.008399 +0.008384 +0.008419 +0.008495 +0.008478 +0.008497 +0.008477 +0.008478 +0.008532 +0.008608 +0.008573 +0.00857 +0.008501 +0.00843 +0.008426 +0.008457 +0.008409 +0.008386 +0.008302 +0.008245 +0.008253 +0.008285 +0.008229 +0.008229 +0.008161 +0.008115 +0.008122 +0.008163 +0.008123 +0.008126 +0.008071 +0.008038 +0.008052 +0.008108 +0.008083 +0.0081 +0.008054 +0.008021 +0.008054 +0.008114 +0.008089 +0.008117 +0.008079 +0.008053 +0.008094 +0.008159 +0.008143 +0.008171 +0.00814 +0.008127 +0.008168 +0.008227 +0.008227 +0.008247 +0.000831 +0.008217 +0.008209 +0.008239 +0.008316 +0.008299 +0.008329 +0.0083 +0.008284 +0.008314 +0.008403 +0.008378 +0.008411 +0.008368 +0.008362 +0.008399 +0.008486 +0.00846 +0.008497 +0.008465 +0.008449 +0.008502 +0.008576 +0.008563 +0.008599 +0.008559 +0.008562 +0.008608 +0.008619 +0.008569 +0.00859 +0.008529 +0.0085 +0.008512 +0.008532 +0.008434 +0.008414 +0.008326 +0.008287 +0.008267 +0.008298 +0.008238 +0.008249 +0.008189 +0.008166 +0.008162 +0.008206 +0.008133 +0.00816 +0.008114 +0.00808 +0.00809 +0.008133 +0.008105 +0.008127 +0.008092 +0.008083 +0.00811 +0.008186 +0.008167 +0.008192 +0.008159 +0.008153 +0.008182 +0.008277 +0.008237 +0.008278 +0.008239 +0.008228 +0.000832 +0.008268 +0.008335 +0.008305 +0.008324 +0.008311 +0.008283 +0.008344 +0.008418 +0.008395 +0.008408 +0.008398 +0.008376 +0.008395 +0.008456 +0.008435 +0.008461 +0.008433 +0.008413 +0.008461 +0.008535 +0.008522 +0.008576 +0.008543 +0.008543 +0.008578 +0.008653 +0.008631 +0.008647 +0.008602 +0.008558 +0.008582 +0.008619 +0.00856 +0.008533 +0.008469 +0.008401 +0.0084 +0.00842 +0.008363 +0.008363 +0.008296 +0.008245 +0.008258 +0.008307 +0.008243 +0.00825 +0.00819 +0.008153 +0.008176 +0.008224 +0.008184 +0.008193 +0.008157 +0.008128 +0.008162 +0.008226 +0.00819 +0.008201 +0.008164 +0.008142 +0.008194 +0.00827 +0.008248 +0.008267 +0.008234 +0.008206 +0.00825 +0.00832 +0.008306 +0.00833 +0.00831 +0.008292 +0.000833 +0.008335 +0.008412 +0.008395 +0.008423 +0.008382 +0.008369 +0.008407 +0.008495 +0.008475 +0.008504 +0.008469 +0.008457 +0.008495 +0.008575 +0.008557 +0.008591 +0.008543 +0.008541 +0.008577 +0.008659 +0.008648 +0.008679 +0.008649 +0.008639 +0.008689 +0.008765 +0.008712 +0.008672 +0.008525 +0.008476 +0.008483 +0.008507 +0.008431 +0.008392 +0.008298 +0.008252 +0.00827 +0.008331 +0.00824 +0.008233 +0.008135 +0.008117 +0.008102 +0.008146 +0.00809 +0.008108 +0.008049 +0.008042 +0.008063 +0.008133 +0.008093 +0.008071 +0.008028 +0.007998 +0.008032 +0.008117 +0.00807 +0.008105 +0.008071 +0.008052 +0.008097 +0.008175 +0.008128 +0.008172 +0.008139 +0.008133 +0.00815 +0.008234 +0.008168 +0.008222 +0.000834 +0.008197 +0.00818 +0.008221 +0.008304 +0.008282 +0.008308 +0.008289 +0.008269 +0.008314 +0.008391 +0.008367 +0.008394 +0.008361 +0.008341 +0.008392 +0.008447 +0.00843 +0.008457 +0.008423 +0.008409 +0.008432 +0.008533 +0.008533 +0.008567 +0.008527 +0.008491 +0.008512 +0.008547 +0.008494 +0.008485 +0.008403 +0.008336 +0.008323 +0.008358 +0.008291 +0.008284 +0.008214 +0.008152 +0.008173 +0.008196 +0.008155 +0.008161 +0.008097 +0.008054 +0.00807 +0.00812 +0.008082 +0.008087 +0.008047 +0.008018 +0.008049 +0.00811 +0.008073 +0.008093 +0.008053 +0.008028 +0.008068 +0.008134 +0.008114 +0.008143 +0.00811 +0.008086 +0.008137 +0.008209 +0.008181 +0.008218 +0.008184 +0.008166 +0.000835 +0.008215 +0.008276 +0.008277 +0.008287 +0.008267 +0.008244 +0.008296 +0.00836 +0.008362 +0.008364 +0.008346 +0.008323 +0.008375 +0.008449 +0.008431 +0.008449 +0.008426 +0.008402 +0.00846 +0.008523 +0.008522 +0.008546 +0.008518 +0.008492 +0.008561 +0.008633 +0.008621 +0.008644 +0.008628 +0.008567 +0.008526 +0.008546 +0.008504 +0.008497 +0.008445 +0.008383 +0.00841 +0.008394 +0.0083 +0.008291 +0.008252 +0.008172 +0.008175 +0.008191 +0.008165 +0.008151 +0.008103 +0.008066 +0.008073 +0.008092 +0.008072 +0.008068 +0.008044 +0.008009 +0.008041 +0.008107 +0.008071 +0.008078 +0.008049 +0.00801 +0.008036 +0.008101 +0.008078 +0.008093 +0.008088 +0.008062 +0.008114 +0.008185 +0.008166 +0.008181 +0.008178 +0.008139 +0.008212 +0.008268 +0.000836 +0.008247 +0.008276 +0.008246 +0.008236 +0.008288 +0.008354 +0.00833 +0.008358 +0.008325 +0.008296 +0.008321 +0.00839 +0.008362 +0.008387 +0.008363 +0.008341 +0.00839 +0.008464 +0.008466 +0.008515 +0.008486 +0.008471 +0.00849 +0.008577 +0.008559 +0.00858 +0.008557 +0.008522 +0.008534 +0.008572 +0.008499 +0.008471 +0.008403 +0.008329 +0.008318 +0.008346 +0.008281 +0.008272 +0.00821 +0.008148 +0.008149 +0.008198 +0.00815 +0.008152 +0.008105 +0.008062 +0.008068 +0.00813 +0.008095 +0.008103 +0.008066 +0.008045 +0.008075 +0.008144 +0.00811 +0.00812 +0.008086 +0.008068 +0.008108 +0.008186 +0.008167 +0.008182 +0.008157 +0.00813 +0.008176 +0.008246 +0.008232 +0.008264 +0.008241 +0.000837 +0.008214 +0.008257 +0.008329 +0.008316 +0.008345 +0.0083 +0.008297 +0.008336 +0.008419 +0.008397 +0.008422 +0.008385 +0.008376 +0.008415 +0.008501 +0.008481 +0.008509 +0.00847 +0.008465 +0.008501 +0.008583 +0.008559 +0.008598 +0.00856 +0.008563 +0.008612 +0.008697 +0.008669 +0.008679 +0.008553 +0.008511 +0.008521 +0.008582 +0.008502 +0.008439 +0.008364 +0.008313 +0.008278 +0.008331 +0.008253 +0.008248 +0.008191 +0.008149 +0.008106 +0.008143 +0.008076 +0.0081 +0.00804 +0.008026 +0.008033 +0.008116 +0.008061 +0.008082 +0.008031 +0.007987 +0.008007 +0.008093 +0.008039 +0.008084 +0.008051 +0.008033 +0.008084 +0.008171 +0.008122 +0.00816 +0.008132 +0.008117 +0.008175 +0.008234 +0.008217 +0.008249 +0.000838 +0.00822 +0.008199 +0.008197 +0.008268 +0.008245 +0.008287 +0.008254 +0.008244 +0.008282 +0.008371 +0.008347 +0.008382 +0.008344 +0.008331 +0.008372 +0.008449 +0.008433 +0.008469 +0.008439 +0.008422 +0.008458 +0.008535 +0.008519 +0.008556 +0.008513 +0.008513 +0.008537 +0.008618 +0.008593 +0.008596 +0.008517 +0.008482 +0.00846 +0.008497 +0.008435 +0.008419 +0.008332 +0.008288 +0.008274 +0.008318 +0.008264 +0.008251 +0.008181 +0.00815 +0.00815 +0.008204 +0.008158 +0.008158 +0.0081 +0.008076 +0.008086 +0.008157 +0.008126 +0.00814 +0.008094 +0.008079 +0.008101 +0.008174 +0.008149 +0.008184 +0.008131 +0.00813 +0.008157 +0.008236 +0.008221 +0.008243 +0.008209 +0.008203 +0.008239 +0.008314 +0.000839 +0.008301 +0.008322 +0.008292 +0.008269 +0.008322 +0.008395 +0.008379 +0.008401 +0.008372 +0.00836 +0.008399 +0.008476 +0.008462 +0.008485 +0.008453 +0.008438 +0.008486 +0.008564 +0.008546 +0.008567 +0.008544 +0.008517 +0.008572 +0.008642 +0.008635 +0.008666 +0.008628 +0.008627 +0.008682 +0.008766 +0.008728 +0.008645 +0.008573 +0.008509 +0.008532 +0.008575 +0.008518 +0.008447 +0.008362 +0.008302 +0.008314 +0.008351 +0.008303 +0.008299 +0.008246 +0.008165 +0.008128 +0.008181 +0.008129 +0.008153 +0.008102 +0.00808 +0.008116 +0.008172 +0.00815 +0.008159 +0.008132 +0.008118 +0.008147 +0.00821 +0.008162 +0.008175 +0.008164 +0.008131 +0.008151 +0.008231 +0.008203 +0.008227 +0.008213 +0.008194 +0.00824 +0.008322 +0.008308 +0.008325 +0.008314 +0.00828 +0.00084 +0.00832 +0.008406 +0.008384 +0.008426 +0.008384 +0.008379 +0.00841 +0.008494 +0.008469 +0.008501 +0.008466 +0.008451 +0.008485 +0.008565 +0.008536 +0.008556 +0.008513 +0.008501 +0.008538 +0.008614 +0.008594 +0.008634 +0.008625 +0.008612 +0.008634 +0.0087 +0.008633 +0.008621 +0.008528 +0.008474 +0.008461 +0.0085 +0.00842 +0.008407 +0.008335 +0.008278 +0.008277 +0.008316 +0.008259 +0.008268 +0.008213 +0.008173 +0.008178 +0.00823 +0.008182 +0.008191 +0.008153 +0.008134 +0.008151 +0.008226 +0.008184 +0.008202 +0.008151 +0.00813 +0.008159 +0.008255 +0.008216 +0.008242 +0.008206 +0.008189 +0.008227 +0.008314 +0.008281 +0.008323 +0.00828 +0.008279 +0.008318 +0.008392 +0.000841 +0.008365 +0.008402 +0.008362 +0.008345 +0.008377 +0.008468 +0.008451 +0.00848 +0.008447 +0.008436 +0.008469 +0.008558 +0.008524 +0.008561 +0.008522 +0.008515 +0.008553 +0.008632 +0.008618 +0.008645 +0.008615 +0.008599 +0.00865 +0.008738 +0.008709 +0.008753 +0.008718 +0.008716 +0.008754 +0.008771 +0.008677 +0.008679 +0.00862 +0.008547 +0.008494 +0.008537 +0.008464 +0.00846 +0.008394 +0.008347 +0.008297 +0.008343 +0.008272 +0.008297 +0.008228 +0.0082 +0.008208 +0.008251 +0.008192 +0.008198 +0.008156 +0.008112 +0.00812 +0.008185 +0.008138 +0.008168 +0.008128 +0.008107 +0.008152 +0.008223 +0.008196 +0.00823 +0.008192 +0.008174 +0.008229 +0.008304 +0.008263 +0.008308 +0.008277 +0.008249 +0.00827 +0.000842 +0.008327 +0.008299 +0.008333 +0.008309 +0.00829 +0.008339 +0.008424 +0.008405 +0.008435 +0.008407 +0.008386 +0.008434 +0.008509 +0.008504 +0.008511 +0.008486 +0.008465 +0.008509 +0.00859 +0.008575 +0.008602 +0.008576 +0.008557 +0.008595 +0.008683 +0.008666 +0.008686 +0.008648 +0.008616 +0.008642 +0.008675 +0.008608 +0.00859 +0.008515 +0.008443 +0.008443 +0.008472 +0.008416 +0.008393 +0.008334 +0.008275 +0.008284 +0.008325 +0.008288 +0.008292 +0.008233 +0.008191 +0.008214 +0.00826 +0.008226 +0.008241 +0.0082 +0.008174 +0.008209 +0.008266 +0.008234 +0.008253 +0.008208 +0.008183 +0.008239 +0.008308 +0.008291 +0.008318 +0.00828 +0.00826 +0.008304 +0.008366 +0.008357 +0.008388 +0.008362 +0.000843 +0.00834 +0.008398 +0.008456 +0.008449 +0.008469 +0.008441 +0.008408 +0.008458 +0.008535 +0.008531 +0.008552 +0.008524 +0.008501 +0.008554 +0.008619 +0.008615 +0.008636 +0.008601 +0.008573 +0.008636 +0.0087 +0.008701 +0.008715 +0.0087 +0.008671 +0.008724 +0.008808 +0.008798 +0.008827 +0.008801 +0.008768 +0.008782 +0.008746 +0.008677 +0.008657 +0.008613 +0.008496 +0.008465 +0.008497 +0.008444 +0.008419 +0.008379 +0.008322 +0.008347 +0.008326 +0.008286 +0.008272 +0.008232 +0.008187 +0.008202 +0.008234 +0.008197 +0.008195 +0.008178 +0.008141 +0.008164 +0.008228 +0.008187 +0.008198 +0.008185 +0.008154 +0.008198 +0.00825 +0.008224 +0.008238 +0.00823 +0.008205 +0.008251 +0.00833 +0.008308 +0.008324 +0.008318 +0.008288 +0.008362 +0.000844 +0.008407 +0.008383 +0.008415 +0.008395 +0.008353 +0.008377 +0.008466 +0.008434 +0.008467 +0.008437 +0.008421 +0.008473 +0.008545 +0.008526 +0.008551 +0.008522 +0.008495 +0.008558 +0.008647 +0.008643 +0.008654 +0.008618 +0.008601 +0.00864 +0.008726 +0.008714 +0.008732 +0.008678 +0.008628 +0.008639 +0.008672 +0.008606 +0.008583 +0.0085 +0.008428 +0.008433 +0.008462 +0.008402 +0.008394 +0.00833 +0.008275 +0.008288 +0.008335 +0.008298 +0.008301 +0.008242 +0.008197 +0.008232 +0.008287 +0.008262 +0.008278 +0.008234 +0.008205 +0.008238 +0.008301 +0.008282 +0.008308 +0.008267 +0.00824 +0.008285 +0.008356 +0.00834 +0.008372 +0.008338 +0.008315 +0.008367 +0.008424 +0.008419 +0.000845 +0.008452 +0.008418 +0.008399 +0.008435 +0.008522 +0.008498 +0.008535 +0.0085 +0.008486 +0.008518 +0.008601 +0.008582 +0.00862 +0.008582 +0.008569 +0.008602 +0.00869 +0.008664 +0.008704 +0.008659 +0.008647 +0.008693 +0.00877 +0.008758 +0.008793 +0.008758 +0.008753 +0.008798 +0.008891 +0.008861 +0.008882 +0.008754 +0.008686 +0.008673 +0.008723 +0.008646 +0.008572 +0.008501 +0.008452 +0.008442 +0.008493 +0.00842 +0.008414 +0.008334 +0.008271 +0.008274 +0.008305 +0.008264 +0.008266 +0.008212 +0.008179 +0.008189 +0.008247 +0.008191 +0.008211 +0.008186 +0.00813 +0.008134 +0.008213 +0.008166 +0.008201 +0.008175 +0.008152 +0.008202 +0.008274 +0.008239 +0.008282 +0.008239 +0.008242 +0.008279 +0.00836 +0.008354 +0.008356 +0.008317 +0.000846 +0.008316 +0.0083 +0.008392 +0.008371 +0.008404 +0.008368 +0.008374 +0.008399 +0.00849 +0.008463 +0.008497 +0.008462 +0.008451 +0.008484 +0.008567 +0.008547 +0.008598 +0.008559 +0.008547 +0.008588 +0.008659 +0.00864 +0.008667 +0.008627 +0.008614 +0.008626 +0.008685 +0.008611 +0.008592 +0.008506 +0.008438 +0.008412 +0.008454 +0.008381 +0.008358 +0.008277 +0.008228 +0.008216 +0.008264 +0.00821 +0.008206 +0.008134 +0.008095 +0.008087 +0.008154 +0.008109 +0.00812 +0.008073 +0.008046 +0.008064 +0.008135 +0.008108 +0.008128 +0.00809 +0.008071 +0.008093 +0.008181 +0.008158 +0.008183 +0.008155 +0.008141 +0.00817 +0.008256 +0.008224 +0.008268 +0.008219 +0.008215 +0.000847 +0.00825 +0.008332 +0.008311 +0.008341 +0.008313 +0.00829 +0.008333 +0.008409 +0.008395 +0.008421 +0.008395 +0.008372 +0.008414 +0.00849 +0.008476 +0.008504 +0.008472 +0.008456 +0.008511 +0.00857 +0.008558 +0.008594 +0.008552 +0.008539 +0.008594 +0.008674 +0.008662 +0.00869 +0.008664 +0.008654 +0.008691 +0.008681 +0.008625 +0.008613 +0.008557 +0.008504 +0.008504 +0.008488 +0.008387 +0.008372 +0.008314 +0.008235 +0.008211 +0.008261 +0.008212 +0.008207 +0.008158 +0.008118 +0.008097 +0.00812 +0.008069 +0.008089 +0.008045 +0.008019 +0.008061 +0.008116 +0.008101 +0.008108 +0.008078 +0.008058 +0.0081 +0.008183 +0.008162 +0.008166 +0.008113 +0.008083 +0.008146 +0.008213 +0.008188 +0.008228 +0.008193 +0.008175 +0.008235 +0.000848 +0.008305 +0.008267 +0.008296 +0.008269 +0.008261 +0.008292 +0.008347 +0.008326 +0.008354 +0.008336 +0.008312 +0.008363 +0.00843 +0.008421 +0.008435 +0.008412 +0.008382 +0.00843 +0.008495 +0.008492 +0.008536 +0.008515 +0.008485 +0.00854 +0.008598 +0.008589 +0.008612 +0.008568 +0.00852 +0.008538 +0.00856 +0.008513 +0.008493 +0.008428 +0.008361 +0.008369 +0.00839 +0.008343 +0.008324 +0.008267 +0.008211 +0.00823 +0.00826 +0.008228 +0.008225 +0.008181 +0.008135 +0.008168 +0.008213 +0.008192 +0.008201 +0.008169 +0.008135 +0.008178 +0.008229 +0.008213 +0.008226 +0.00819 +0.008171 +0.00822 +0.008285 +0.00828 +0.008294 +0.00827 +0.008233 +0.008287 +0.008347 +0.008338 +0.000849 +0.008364 +0.008349 +0.008329 +0.008372 +0.00845 +0.008423 +0.008455 +0.008422 +0.008396 +0.008444 +0.008503 +0.008497 +0.00853 +0.008502 +0.008493 +0.008535 +0.00861 +0.008595 +0.00862 +0.008588 +0.008574 +0.008619 +0.008702 +0.008687 +0.008713 +0.008682 +0.008675 +0.00874 +0.008781 +0.00873 +0.008746 +0.008705 +0.008636 +0.008621 +0.008654 +0.008584 +0.008563 +0.008458 +0.008392 +0.008382 +0.008434 +0.00837 +0.008359 +0.008324 +0.008246 +0.008237 +0.008273 +0.008228 +0.008243 +0.008199 +0.008152 +0.008191 +0.008243 +0.008215 +0.008236 +0.00819 +0.008137 +0.008145 +0.008217 +0.008193 +0.008212 +0.008196 +0.008173 +0.008226 +0.008299 +0.008271 +0.008307 +0.008272 +0.008261 +0.008309 +0.008401 +0.00836 +0.00839 +0.00085 +0.008375 +0.008343 +0.008405 +0.008453 +0.008429 +0.008449 +0.008433 +0.008414 +0.008455 +0.008515 +0.008492 +0.008513 +0.008497 +0.008463 +0.008518 +0.008581 +0.008569 +0.008584 +0.008568 +0.008546 +0.008632 +0.008707 +0.008696 +0.008705 +0.008675 +0.008642 +0.008688 +0.00874 +0.008714 +0.008707 +0.008642 +0.008566 +0.008567 +0.008587 +0.008526 +0.00849 +0.008425 +0.008356 +0.008365 +0.008393 +0.008346 +0.008336 +0.008285 +0.008226 +0.008252 +0.008292 +0.008254 +0.008255 +0.008215 +0.008174 +0.008216 +0.008265 +0.008251 +0.008261 +0.008229 +0.008188 +0.008246 +0.008305 +0.008296 +0.008313 +0.008286 +0.008262 +0.008316 +0.00838 +0.008377 +0.0084 +0.008357 +0.000851 +0.008345 +0.008398 +0.008456 +0.008459 +0.008471 +0.00845 +0.008428 +0.008478 +0.008548 +0.008538 +0.008557 +0.008535 +0.00851 +0.008568 +0.008619 +0.008622 +0.008639 +0.008621 +0.008586 +0.008646 +0.008715 +0.008708 +0.008733 +0.008708 +0.008685 +0.008754 +0.008832 +0.008818 +0.00884 +0.008812 +0.008726 +0.008679 +0.008694 +0.008641 +0.008635 +0.008569 +0.008495 +0.008412 +0.008425 +0.008371 +0.008376 +0.008311 +0.008265 +0.008286 +0.008333 +0.008271 +0.008186 +0.008121 +0.008083 +0.008113 +0.008147 +0.008118 +0.008119 +0.008089 +0.008041 +0.008034 +0.008098 +0.008069 +0.00808 +0.00807 +0.008042 +0.008081 +0.008147 +0.008132 +0.008144 +0.008139 +0.0081 +0.008167 +0.008244 +0.008218 +0.008261 +0.008206 +0.008187 +0.000852 +0.008207 +0.008268 +0.008244 +0.008272 +0.008266 +0.008233 +0.00829 +0.008356 +0.008353 +0.00837 +0.008348 +0.008323 +0.00837 +0.008441 +0.00843 +0.008447 +0.008428 +0.008413 +0.00847 +0.008537 +0.008524 +0.008538 +0.00851 +0.008482 +0.008543 +0.008615 +0.008589 +0.008578 +0.008527 +0.00845 +0.008449 +0.008475 +0.008407 +0.008375 +0.008301 +0.008228 +0.008222 +0.008257 +0.008205 +0.008188 +0.008127 +0.008069 +0.008088 +0.008122 +0.008085 +0.008079 +0.008033 +0.007983 +0.008009 +0.008065 +0.008046 +0.008045 +0.008022 +0.00798 +0.00802 +0.008075 +0.008065 +0.008076 +0.008054 +0.008021 +0.008068 +0.008136 +0.008128 +0.008144 +0.008114 +0.008086 +0.008143 +0.00822 +0.008213 +0.008203 +0.000853 +0.008194 +0.008173 +0.008219 +0.008287 +0.008286 +0.008301 +0.008276 +0.00825 +0.0083 +0.008367 +0.008364 +0.008383 +0.008356 +0.008325 +0.008381 +0.008451 +0.008441 +0.008465 +0.008442 +0.008416 +0.008477 +0.008544 +0.00854 +0.008565 +0.008552 +0.00853 +0.008556 +0.008528 +0.008483 +0.008458 +0.008402 +0.008353 +0.008303 +0.008293 +0.008247 +0.008223 +0.008179 +0.008116 +0.008122 +0.008098 +0.008069 +0.008054 +0.008001 +0.007918 +0.007924 +0.007958 +0.007927 +0.007916 +0.007873 +0.00785 +0.007882 +0.007926 +0.007888 +0.007884 +0.007863 +0.007828 +0.007844 +0.007906 +0.00788 +0.007896 +0.007887 +0.007854 +0.007916 +0.007975 +0.007959 +0.007984 +0.007966 +0.00794 +0.008 +0.008077 +0.008034 +0.00806 +0.000854 +0.008043 +0.008016 +0.008082 +0.008145 +0.008129 +0.008143 +0.008132 +0.008099 +0.008152 +0.008212 +0.008188 +0.008204 +0.008184 +0.008156 +0.008204 +0.008255 +0.008229 +0.008252 +0.00823 +0.008205 +0.008262 +0.008328 +0.00835 +0.008373 +0.008328 +0.008275 +0.008284 +0.008301 +0.008245 +0.008207 +0.008139 +0.008083 +0.008089 +0.008104 +0.008053 +0.008049 +0.007985 +0.007925 +0.007938 +0.00797 +0.007933 +0.007936 +0.007886 +0.007836 +0.007863 +0.007898 +0.007885 +0.007875 +0.007851 +0.007817 +0.007855 +0.007906 +0.007887 +0.0079 +0.007875 +0.007847 +0.007895 +0.007954 +0.007948 +0.007965 +0.007938 +0.007923 +0.007963 +0.008029 +0.008029 +0.00804 +0.008011 +0.000855 +0.008001 +0.008035 +0.008111 +0.008099 +0.008119 +0.008084 +0.008065 +0.00811 +0.00819 +0.008175 +0.008198 +0.008162 +0.008146 +0.008191 +0.008263 +0.008251 +0.00827 +0.008247 +0.008225 +0.00827 +0.008348 +0.008335 +0.008363 +0.008337 +0.008325 +0.008383 +0.008456 +0.008441 +0.008439 +0.008323 +0.008271 +0.008274 +0.008326 +0.008281 +0.008191 +0.008127 +0.008073 +0.00807 +0.0081 +0.008034 +0.00804 +0.007964 +0.007898 +0.007876 +0.007907 +0.007878 +0.007869 +0.007837 +0.007784 +0.007774 +0.007802 +0.007767 +0.00779 +0.007745 +0.00773 +0.007755 +0.007824 +0.007793 +0.007806 +0.00779 +0.007766 +0.007783 +0.007839 +0.00781 +0.007838 +0.007814 +0.007794 +0.007847 +0.007917 +0.007909 +0.007925 +0.007908 +0.007887 +0.007929 +0.008016 +0.000856 +0.007981 +0.007998 +0.007984 +0.007965 +0.008022 +0.008087 +0.008078 +0.008081 +0.008065 +0.008038 +0.008091 +0.008143 +0.008132 +0.008144 +0.008112 +0.00809 +0.008138 +0.008191 +0.008191 +0.008201 +0.008203 +0.008188 +0.008226 +0.00828 +0.00824 +0.008211 +0.008153 +0.008077 +0.008088 +0.00812 +0.008069 +0.008034 +0.007986 +0.007913 +0.007935 +0.007966 +0.007922 +0.007909 +0.007867 +0.007815 +0.007835 +0.007879 +0.007852 +0.007843 +0.007814 +0.007767 +0.007797 +0.007863 +0.00785 +0.00785 +0.007839 +0.007788 +0.007837 +0.007903 +0.007893 +0.007905 +0.007888 +0.00786 +0.007911 +0.007966 +0.00796 +0.007982 +0.00796 +0.007937 +0.000857 +0.007973 +0.008053 +0.008042 +0.008051 +0.008034 +0.008012 +0.008059 +0.00812 +0.008114 +0.008137 +0.00811 +0.008091 +0.008131 +0.008202 +0.00819 +0.008213 +0.008188 +0.008165 +0.008211 +0.008282 +0.008273 +0.008293 +0.008267 +0.008252 +0.008304 +0.008373 +0.008365 +0.008402 +0.008376 +0.008351 +0.008367 +0.008351 +0.008286 +0.008274 +0.00822 +0.008181 +0.008131 +0.008133 +0.008067 +0.008063 +0.008006 +0.00796 +0.007957 +0.007954 +0.007914 +0.007909 +0.007846 +0.007788 +0.00778 +0.00783 +0.007785 +0.007786 +0.007752 +0.007725 +0.007764 +0.007819 +0.007796 +0.007772 +0.007721 +0.007715 +0.007753 +0.007815 +0.007802 +0.007817 +0.007802 +0.007784 +0.00782 +0.007898 +0.007874 +0.007895 +0.007891 +0.007864 +0.007882 +0.007966 +0.000858 +0.007929 +0.007956 +0.00793 +0.007927 +0.007957 +0.008035 +0.008006 +0.008043 +0.008006 +0.007997 +0.008032 +0.008111 +0.008072 +0.0081 +0.008059 +0.008047 +0.008088 +0.008164 +0.008137 +0.008177 +0.008153 +0.008161 +0.008195 +0.008256 +0.008222 +0.008232 +0.008154 +0.008119 +0.008104 +0.00815 +0.008096 +0.008083 +0.008004 +0.007963 +0.007961 +0.007992 +0.007937 +0.007938 +0.007867 +0.007832 +0.007832 +0.007881 +0.007837 +0.007843 +0.007777 +0.007757 +0.007765 +0.007819 +0.007795 +0.007811 +0.007758 +0.007749 +0.007764 +0.007828 +0.00781 +0.007836 +0.007794 +0.007788 +0.007816 +0.007891 +0.007872 +0.007898 +0.007862 +0.007862 +0.007892 +0.007959 +0.007949 +0.000859 +0.007967 +0.007944 +0.007928 +0.007963 +0.008041 +0.008029 +0.008044 +0.008015 +0.008 +0.008045 +0.008121 +0.008105 +0.008129 +0.008099 +0.008078 +0.008121 +0.008189 +0.008176 +0.008199 +0.008163 +0.008155 +0.008192 +0.008279 +0.008261 +0.008292 +0.008263 +0.008243 +0.008301 +0.008379 +0.008358 +0.008321 +0.008236 +0.008173 +0.008194 +0.00822 +0.008148 +0.008068 +0.007991 +0.007954 +0.007963 +0.007968 +0.007921 +0.007913 +0.007858 +0.007789 +0.007787 +0.00783 +0.00778 +0.007792 +0.007734 +0.00771 +0.007731 +0.007763 +0.007741 +0.007746 +0.007722 +0.007676 +0.007701 +0.007755 +0.007725 +0.007759 +0.007724 +0.007711 +0.007761 +0.007821 +0.007814 +0.007831 +0.007808 +0.007799 +0.007837 +0.00792 +0.007894 +0.007902 +0.00086 +0.007889 +0.007871 +0.007926 +0.007982 +0.007976 +0.007993 +0.007975 +0.007949 +0.008 +0.008064 +0.008057 +0.008062 +0.008054 +0.008 +0.008029 +0.008083 +0.008069 +0.008084 +0.008069 +0.008045 +0.008108 +0.008191 +0.008204 +0.008213 +0.008187 +0.008149 +0.008182 +0.008228 +0.008182 +0.008159 +0.008107 +0.008028 +0.008033 +0.008056 +0.008007 +0.007986 +0.007929 +0.007862 +0.007871 +0.007913 +0.007875 +0.007855 +0.007816 +0.007768 +0.007785 +0.007831 +0.007802 +0.007796 +0.007767 +0.007726 +0.00776 +0.007819 +0.007806 +0.007806 +0.007784 +0.007752 +0.007794 +0.007856 +0.007849 +0.007857 +0.007846 +0.007814 +0.007857 +0.007927 +0.007915 +0.007938 +0.007918 +0.007886 +0.000861 +0.007932 +0.008001 +0.007991 +0.008011 +0.007986 +0.007968 +0.008006 +0.008083 +0.008058 +0.008094 +0.008062 +0.008043 +0.008084 +0.008156 +0.008141 +0.008167 +0.008135 +0.008119 +0.008157 +0.008224 +0.00822 +0.008238 +0.008218 +0.008198 +0.008258 +0.00833 +0.00832 +0.008338 +0.008311 +0.008294 +0.008309 +0.008298 +0.008234 +0.008193 +0.008098 +0.008052 +0.008 +0.008011 +0.007962 +0.007961 +0.007891 +0.007855 +0.00787 +0.007903 +0.007834 +0.007795 +0.007765 +0.007704 +0.007718 +0.007743 +0.007717 +0.00772 +0.007682 +0.007662 +0.007696 +0.007756 +0.00773 +0.007755 +0.007709 +0.007705 +0.00773 +0.007767 +0.007751 +0.007769 +0.007759 +0.007728 +0.007771 +0.007847 +0.007827 +0.007847 +0.007825 +0.007819 +0.007859 +0.007925 +0.000862 +0.007926 +0.007926 +0.007892 +0.007894 +0.007934 +0.008019 +0.007981 +0.007999 +0.007949 +0.007943 +0.007981 +0.008059 +0.008027 +0.008057 +0.008018 +0.008009 +0.008039 +0.008117 +0.008093 +0.008129 +0.008108 +0.008108 +0.008144 +0.008228 +0.008198 +0.008226 +0.008193 +0.008167 +0.008187 +0.008241 +0.008175 +0.008167 +0.008078 +0.008009 +0.007996 +0.008036 +0.007969 +0.007961 +0.007888 +0.007839 +0.007839 +0.007896 +0.007844 +0.007856 +0.007795 +0.007762 +0.007769 +0.007829 +0.007787 +0.007803 +0.007759 +0.007736 +0.007756 +0.007829 +0.007797 +0.007815 +0.007774 +0.007756 +0.007777 +0.007854 +0.007826 +0.007857 +0.007818 +0.007804 +0.00784 +0.007918 +0.007895 +0.00793 +0.007897 +0.007874 +0.007911 +0.000863 +0.00799 +0.007974 +0.008001 +0.007967 +0.007956 +0.007987 +0.008068 +0.008044 +0.008082 +0.008043 +0.008031 +0.008065 +0.00814 +0.008118 +0.008154 +0.008116 +0.008109 +0.008139 +0.008221 +0.008199 +0.008241 +0.008197 +0.008197 +0.008239 +0.00832 +0.008301 +0.008337 +0.008298 +0.008261 +0.00818 +0.008213 +0.008146 +0.008148 +0.00808 +0.008042 +0.008 +0.007971 +0.007901 +0.007901 +0.00785 +0.007803 +0.007819 +0.007848 +0.007751 +0.007743 +0.007671 +0.007659 +0.007631 +0.00769 +0.00763 +0.007646 +0.007606 +0.007581 +0.007622 +0.007682 +0.007646 +0.007675 +0.007633 +0.007636 +0.007646 +0.007699 +0.007678 +0.0077 +0.00768 +0.007674 +0.0077 +0.007776 +0.007761 +0.007792 +0.007752 +0.007746 +0.007854 +0.000864 +0.007845 +0.007855 +0.00784 +0.007821 +0.007873 +0.007935 +0.007918 +0.007937 +0.007918 +0.007897 +0.007941 +0.007987 +0.007961 +0.007974 +0.007953 +0.007927 +0.007978 +0.008039 +0.008026 +0.008044 +0.008044 +0.008032 +0.008088 +0.008147 +0.008144 +0.008142 +0.008099 +0.008046 +0.008055 +0.008068 +0.008028 +0.008009 +0.007939 +0.007872 +0.00788 +0.007904 +0.007867 +0.007838 +0.007773 +0.007727 +0.007745 +0.007784 +0.007751 +0.00774 +0.00769 +0.007647 +0.007674 +0.007717 +0.007698 +0.007703 +0.007669 +0.007635 +0.007672 +0.00772 +0.007713 +0.007727 +0.007697 +0.007671 +0.007715 +0.007776 +0.007775 +0.007788 +0.007767 +0.007747 +0.007783 +0.007855 +0.007845 +0.007859 +0.000865 +0.007837 +0.007815 +0.007863 +0.00793 +0.007913 +0.007938 +0.007907 +0.007892 +0.007934 +0.008007 +0.007992 +0.008013 +0.007983 +0.007963 +0.008008 +0.00808 +0.008068 +0.008089 +0.008054 +0.008044 +0.008081 +0.00816 +0.008144 +0.00818 +0.008143 +0.008135 +0.008184 +0.00826 +0.008235 +0.008245 +0.008189 +0.008069 +0.008058 +0.008092 +0.008032 +0.008034 +0.007932 +0.007854 +0.007853 +0.00789 +0.007834 +0.007844 +0.007782 +0.007727 +0.007697 +0.007743 +0.007695 +0.007702 +0.007662 +0.007624 +0.007656 +0.007716 +0.007673 +0.007664 +0.007613 +0.00759 +0.007635 +0.007701 +0.00768 +0.007698 +0.007675 +0.007666 +0.007699 +0.007772 +0.007749 +0.007768 +0.007768 +0.007726 +0.007775 +0.007839 +0.007812 +0.000866 +0.007837 +0.007799 +0.007807 +0.007835 +0.007913 +0.007877 +0.007915 +0.007884 +0.007876 +0.007907 +0.007988 +0.007956 +0.007988 +0.007948 +0.007946 +0.007979 +0.008052 +0.008016 +0.008041 +0.008008 +0.007997 +0.008027 +0.008102 +0.008083 +0.008111 +0.008086 +0.008097 +0.008138 +0.008214 +0.008182 +0.008187 +0.00811 +0.008071 +0.008045 +0.008082 +0.008035 +0.008014 +0.007928 +0.007887 +0.007867 +0.007903 +0.007853 +0.007847 +0.007774 +0.007739 +0.007746 +0.007789 +0.007752 +0.007748 +0.007682 +0.007669 +0.007668 +0.007742 +0.007711 +0.007725 +0.007672 +0.007665 +0.007671 +0.007754 +0.007735 +0.007761 +0.007717 +0.007713 +0.007741 +0.007821 +0.007799 +0.007827 +0.007805 +0.007775 +0.007809 +0.007898 +0.000867 +0.00787 +0.007906 +0.00787 +0.007856 +0.007884 +0.007965 +0.007951 +0.007981 +0.007944 +0.007933 +0.007963 +0.008045 +0.008024 +0.008052 +0.008019 +0.008005 +0.008037 +0.008125 +0.0081 +0.008126 +0.0081 +0.008087 +0.008129 +0.008204 +0.008189 +0.00822 +0.008193 +0.008187 +0.008235 +0.008321 +0.008252 +0.0082 +0.008133 +0.0081 +0.008105 +0.008166 +0.008086 +0.008048 +0.007952 +0.007909 +0.007906 +0.007966 +0.007907 +0.007879 +0.007818 +0.00777 +0.007772 +0.007801 +0.007762 +0.007766 +0.007726 +0.007692 +0.00772 +0.007789 +0.007739 +0.00777 +0.007726 +0.00771 +0.007707 +0.007762 +0.007736 +0.007768 +0.007734 +0.007737 +0.00777 +0.007849 +0.007833 +0.007863 +0.007826 +0.007821 +0.007855 +0.00794 +0.007913 +0.000868 +0.007932 +0.007909 +0.007901 +0.007945 +0.008014 +0.007995 +0.008022 +0.007999 +0.007975 +0.008024 +0.008091 +0.008071 +0.008095 +0.00806 +0.008028 +0.008045 +0.008113 +0.008087 +0.008117 +0.008089 +0.008072 +0.008129 +0.008217 +0.008227 +0.008244 +0.008199 +0.00817 +0.008178 +0.008207 +0.008161 +0.008133 +0.008045 +0.008011 +0.008 +0.008028 +0.007988 +0.007973 +0.007905 +0.007856 +0.007859 +0.007905 +0.007877 +0.007874 +0.007816 +0.00778 +0.007788 +0.007836 +0.007814 +0.007824 +0.007783 +0.007762 +0.007785 +0.007843 +0.007823 +0.007828 +0.007804 +0.007792 +0.007822 +0.007888 +0.007881 +0.007897 +0.007872 +0.007847 +0.007882 +0.007959 +0.00794 +0.007979 +0.007945 +0.000869 +0.007923 +0.00797 +0.008034 +0.008029 +0.008041 +0.008014 +0.007993 +0.00804 +0.008107 +0.008106 +0.008123 +0.008098 +0.00807 +0.008122 +0.008186 +0.008183 +0.008201 +0.008177 +0.008149 +0.008204 +0.008264 +0.008256 +0.00828 +0.008253 +0.008237 +0.008305 +0.008355 +0.008361 +0.008378 +0.00835 +0.008302 +0.008252 +0.008231 +0.008191 +0.00817 +0.008125 +0.008006 +0.007982 +0.007991 +0.007959 +0.007933 +0.00788 +0.007838 +0.007857 +0.007899 +0.007798 +0.007779 +0.007721 +0.007688 +0.007707 +0.007763 +0.007722 +0.007725 +0.00769 +0.007638 +0.007671 +0.007727 +0.0077 +0.007725 +0.0077 +0.007664 +0.007727 +0.007778 +0.007767 +0.007795 +0.007778 +0.007748 +0.007813 +0.007866 +0.00786 +0.007861 +0.00087 +0.007846 +0.007829 +0.007865 +0.007927 +0.007897 +0.007918 +0.007889 +0.007886 +0.007926 +0.007994 +0.00797 +0.007999 +0.007981 +0.007957 +0.008005 +0.008073 +0.008046 +0.008069 +0.008039 +0.008015 +0.008059 +0.008129 +0.008111 +0.008138 +0.008108 +0.008091 +0.008157 +0.008233 +0.008228 +0.008235 +0.008188 +0.008151 +0.008148 +0.00818 +0.008121 +0.008108 +0.008034 +0.00797 +0.007971 +0.007985 +0.007949 +0.007914 +0.007844 +0.007804 +0.007801 +0.007839 +0.007806 +0.007795 +0.007735 +0.007699 +0.007707 +0.00776 +0.00774 +0.007741 +0.007695 +0.007673 +0.007699 +0.007758 +0.007748 +0.007763 +0.007729 +0.007712 +0.007743 +0.007819 +0.007811 +0.007828 +0.007801 +0.007782 +0.007823 +0.007886 +0.007871 +0.007911 +0.000871 +0.00787 +0.007855 +0.007895 +0.007963 +0.007949 +0.007986 +0.007945 +0.007934 +0.007961 +0.008039 +0.008024 +0.008062 +0.008021 +0.008011 +0.008042 +0.008124 +0.008097 +0.008131 +0.008088 +0.008078 +0.008118 +0.008198 +0.00818 +0.008219 +0.008166 +0.00817 +0.008207 +0.008291 +0.008278 +0.008306 +0.008277 +0.008262 +0.00828 +0.008267 +0.008192 +0.008187 +0.008127 +0.00805 +0.008013 +0.008055 +0.007984 +0.00799 +0.007929 +0.007858 +0.00784 +0.007885 +0.007846 +0.00786 +0.007796 +0.007732 +0.007726 +0.007785 +0.007733 +0.007755 +0.007717 +0.007697 +0.007726 +0.0078 +0.007757 +0.007791 +0.007745 +0.007737 +0.007771 +0.007824 +0.007802 +0.007838 +0.007792 +0.007795 +0.007818 +0.007891 +0.007864 +0.007897 +0.007863 +0.00787 +0.000872 +0.007907 +0.007966 +0.007948 +0.00798 +0.00795 +0.007934 +0.00798 +0.008055 +0.008033 +0.008051 +0.008013 +0.00799 +0.008035 +0.008103 +0.008079 +0.008104 +0.008073 +0.008055 +0.008097 +0.008165 +0.008145 +0.008167 +0.008146 +0.008145 +0.008203 +0.008276 +0.008265 +0.008266 +0.008213 +0.008168 +0.008162 +0.008182 +0.008139 +0.008113 +0.008026 +0.007971 +0.007958 +0.007991 +0.007944 +0.007923 +0.007856 +0.007817 +0.00783 +0.007868 +0.007835 +0.00783 +0.007773 +0.007744 +0.007751 +0.007802 +0.007786 +0.007792 +0.007749 +0.007728 +0.007748 +0.007817 +0.0078 +0.007818 +0.007782 +0.007774 +0.007797 +0.007868 +0.007862 +0.007881 +0.007859 +0.007833 +0.00788 +0.007943 +0.007934 +0.000873 +0.007961 +0.007924 +0.00791 +0.007949 +0.00803 +0.008 +0.008037 +0.008005 +0.007991 +0.008025 +0.008101 +0.008081 +0.008116 +0.008067 +0.008067 +0.008101 +0.008184 +0.008159 +0.008191 +0.008158 +0.008145 +0.00818 +0.008268 +0.008236 +0.008283 +0.008239 +0.008232 +0.008284 +0.008363 +0.008341 +0.008366 +0.008316 +0.008218 +0.008217 +0.008254 +0.008195 +0.008202 +0.008129 +0.008024 +0.007997 +0.008039 +0.007986 +0.007999 +0.007913 +0.007896 +0.0079 +0.00793 +0.007872 +0.007875 +0.007817 +0.007772 +0.007788 +0.007842 +0.007798 +0.00783 +0.007772 +0.007775 +0.007801 +0.007868 +0.007838 +0.007844 +0.007807 +0.007798 +0.007825 +0.007921 +0.007875 +0.007909 +0.007881 +0.007868 +0.007906 +0.007989 +0.00795 +0.007994 +0.007945 +0.000874 +0.007937 +0.007984 +0.008068 +0.008041 +0.008063 +0.008042 +0.00803 +0.008065 +0.008115 +0.008092 +0.008118 +0.008099 +0.008076 +0.008123 +0.008193 +0.008167 +0.008184 +0.008154 +0.008146 +0.008173 +0.008241 +0.008245 +0.008291 +0.008268 +0.008245 +0.008282 +0.008336 +0.0083 +0.008291 +0.008228 +0.00817 +0.008163 +0.008171 +0.00811 +0.008104 +0.008024 +0.007967 +0.007967 +0.007995 +0.007941 +0.007941 +0.007888 +0.007855 +0.007857 +0.007905 +0.007851 +0.007858 +0.007805 +0.007775 +0.007813 +0.007868 +0.00784 +0.007854 +0.007808 +0.007784 +0.007825 +0.007887 +0.00788 +0.007882 +0.007857 +0.007842 +0.007892 +0.007957 +0.007946 +0.007965 +0.007934 +0.007913 +0.007934 +0.008025 +0.000875 +0.008 +0.00805 +0.008004 +0.007997 +0.008034 +0.008109 +0.008091 +0.008107 +0.008079 +0.008068 +0.008097 +0.008186 +0.008166 +0.008197 +0.00815 +0.008145 +0.008184 +0.008262 +0.008243 +0.008268 +0.00824 +0.008224 +0.008266 +0.008346 +0.008333 +0.008364 +0.008336 +0.008317 +0.008376 +0.008448 +0.008396 +0.008326 +0.008234 +0.008187 +0.008196 +0.008235 +0.008129 +0.0081 +0.008019 +0.007998 +0.007974 +0.008012 +0.007958 +0.007965 +0.007923 +0.007899 +0.007888 +0.00792 +0.007853 +0.007885 +0.007829 +0.007818 +0.007843 +0.007909 +0.007881 +0.007895 +0.007868 +0.007853 +0.007866 +0.007929 +0.007889 +0.007934 +0.007897 +0.007894 +0.007932 +0.008004 +0.00799 +0.008018 +0.007981 +0.007978 +0.008029 +0.000876 +0.00807 +0.008073 +0.008102 +0.008061 +0.008063 +0.008096 +0.008182 +0.008149 +0.008188 +0.008153 +0.008138 +0.00818 +0.008259 +0.008225 +0.008257 +0.008217 +0.008206 +0.008241 +0.008319 +0.008264 +0.00829 +0.008262 +0.008243 +0.008287 +0.00836 +0.008334 +0.008393 +0.008325 +0.008295 +0.008278 +0.0083 +0.008228 +0.008215 +0.008144 +0.008096 +0.008087 +0.008113 +0.008053 +0.008055 +0.007989 +0.00796 +0.007964 +0.008009 +0.007957 +0.007954 +0.007893 +0.007878 +0.007894 +0.007956 +0.00792 +0.007939 +0.00789 +0.007868 +0.007895 +0.007958 +0.007925 +0.007949 +0.007914 +0.007914 +0.007952 +0.008028 +0.00801 +0.008038 +0.007994 +0.007987 +0.00801 +0.008098 +0.008062 +0.000877 +0.008089 +0.008055 +0.008039 +0.008091 +0.008165 +0.00816 +0.00818 +0.008143 +0.008125 +0.008163 +0.008239 +0.008225 +0.008256 +0.008234 +0.008198 +0.008251 +0.008318 +0.008309 +0.008332 +0.008296 +0.008279 +0.00833 +0.008401 +0.008388 +0.008421 +0.008385 +0.00838 +0.008419 +0.008504 +0.008491 +0.008515 +0.008476 +0.008416 +0.008348 +0.008368 +0.008306 +0.008302 +0.008247 +0.008173 +0.008116 +0.008139 +0.008076 +0.008091 +0.008039 +0.008003 +0.008023 +0.008081 +0.008045 +0.008047 +0.00797 +0.0079 +0.007929 +0.007989 +0.007967 +0.007971 +0.007953 +0.007913 +0.007973 +0.008023 +0.008004 +0.008031 +0.007997 +0.007993 +0.008026 +0.008094 +0.008068 +0.008099 +0.008054 +0.008047 +0.008094 +0.008155 +0.000878 +0.008132 +0.00816 +0.00814 +0.008113 +0.008175 +0.00824 +0.008212 +0.008244 +0.008225 +0.008197 +0.008248 +0.00831 +0.008291 +0.008307 +0.008285 +0.008264 +0.008313 +0.008379 +0.008357 +0.008372 +0.008351 +0.008319 +0.008366 +0.008428 +0.008428 +0.008438 +0.008448 +0.008432 +0.008477 +0.008531 +0.008497 +0.008459 +0.008396 +0.008314 +0.008316 +0.008351 +0.008296 +0.008258 +0.008195 +0.008129 +0.00814 +0.008167 +0.008125 +0.008122 +0.008075 +0.00802 +0.00804 +0.008089 +0.008059 +0.008047 +0.008018 +0.007977 +0.008008 +0.008071 +0.008044 +0.00805 +0.008023 +0.007982 +0.008031 +0.008091 +0.008074 +0.008089 +0.00807 +0.008047 +0.008095 +0.00816 +0.008144 +0.008162 +0.008137 +0.008107 +0.008158 +0.00824 +0.000879 +0.008226 +0.008248 +0.008212 +0.008193 +0.008233 +0.008304 +0.008296 +0.008327 +0.008299 +0.008278 +0.008318 +0.008392 +0.008379 +0.0084 +0.00837 +0.008361 +0.00839 +0.008468 +0.008466 +0.008488 +0.008458 +0.00844 +0.00849 +0.008566 +0.008564 +0.008592 +0.008571 +0.008534 +0.008568 +0.008555 +0.008479 +0.008456 +0.008386 +0.008292 +0.008264 +0.008302 +0.00825 +0.008236 +0.008168 +0.008094 +0.008077 +0.008128 +0.008081 +0.008095 +0.008041 +0.007995 +0.007966 +0.008021 +0.007974 +0.007996 +0.007959 +0.007932 +0.007975 +0.008029 +0.008003 +0.00803 +0.007996 +0.007978 +0.008028 +0.008101 +0.008061 +0.008079 +0.008033 +0.008018 +0.008086 +0.008123 +0.008115 +0.008154 +0.008109 +0.00088 +0.008118 +0.008153 +0.008228 +0.008207 +0.008237 +0.008203 +0.008199 +0.008229 +0.008314 +0.00829 +0.00832 +0.008277 +0.008275 +0.008304 +0.008374 +0.008336 +0.008361 +0.008325 +0.008314 +0.008351 +0.008432 +0.008402 +0.008442 +0.008408 +0.008417 +0.008466 +0.008551 +0.008511 +0.008517 +0.008444 +0.008389 +0.00838 +0.008422 +0.008366 +0.008365 +0.008285 +0.008225 +0.008234 +0.008293 +0.008229 +0.008229 +0.008163 +0.008127 +0.008141 +0.008208 +0.008136 +0.008152 +0.0081 +0.008066 +0.008085 +0.008148 +0.008118 +0.008138 +0.008096 +0.008078 +0.0081 +0.008175 +0.008147 +0.008177 +0.00814 +0.008124 +0.008159 +0.008237 +0.008215 +0.008256 +0.008225 +0.008193 +0.008243 +0.000881 +0.008306 +0.008296 +0.008333 +0.008297 +0.008274 +0.008321 +0.008396 +0.008387 +0.008407 +0.008368 +0.008358 +0.008403 +0.008478 +0.008464 +0.008495 +0.008452 +0.008439 +0.00848 +0.008557 +0.008551 +0.008572 +0.008539 +0.008524 +0.008571 +0.008644 +0.008644 +0.00867 +0.008641 +0.00862 +0.008651 +0.0087 +0.008607 +0.0085 +0.008452 +0.008408 +0.008388 +0.008392 +0.008337 +0.008313 +0.008247 +0.00822 +0.008202 +0.008219 +0.008178 +0.008168 +0.008103 +0.008029 +0.008047 +0.008082 +0.008062 +0.008059 +0.008026 +0.007998 +0.008009 +0.008059 +0.008015 +0.008048 +0.008011 +0.007991 +0.008041 +0.008103 +0.008087 +0.008105 +0.008081 +0.008066 +0.008103 +0.008194 +0.008163 +0.008204 +0.008156 +0.008113 +0.000882 +0.008156 +0.00822 +0.008202 +0.008226 +0.008214 +0.008182 +0.008243 +0.008302 +0.008305 +0.008318 +0.008294 +0.008271 +0.008324 +0.008393 +0.00838 +0.008397 +0.008374 +0.008344 +0.008402 +0.008475 +0.008476 +0.008487 +0.008456 +0.008437 +0.00849 +0.008563 +0.008551 +0.008542 +0.008497 +0.008433 +0.008435 +0.008451 +0.008389 +0.008352 +0.008276 +0.008197 +0.008197 +0.008219 +0.008171 +0.008149 +0.008097 +0.00803 +0.008049 +0.008084 +0.008048 +0.00803 +0.007989 +0.00794 +0.007959 +0.008012 +0.007992 +0.007992 +0.007962 +0.007925 +0.007962 +0.008025 +0.008011 +0.008022 +0.008001 +0.007965 +0.008021 +0.008077 +0.008078 +0.008089 +0.008065 +0.008031 +0.008091 +0.008147 +0.008149 +0.000883 +0.008165 +0.00814 +0.008117 +0.00816 +0.008238 +0.008216 +0.008246 +0.00822 +0.0082 +0.00824 +0.008321 +0.008293 +0.008325 +0.008297 +0.008276 +0.008319 +0.008404 +0.008376 +0.008409 +0.008374 +0.008366 +0.008409 +0.008481 +0.00847 +0.008507 +0.008469 +0.008464 +0.008523 +0.008597 +0.008534 +0.008462 +0.008398 +0.008349 +0.00837 +0.008419 +0.008336 +0.008259 +0.008188 +0.008132 +0.008156 +0.008194 +0.008128 +0.008086 +0.008011 +0.007988 +0.007966 +0.008018 +0.007958 +0.007972 +0.007924 +0.007896 +0.007921 +0.007966 +0.007938 +0.007938 +0.007909 +0.007872 +0.007881 +0.007958 +0.007928 +0.007953 +0.007932 +0.007909 +0.007961 +0.008033 +0.008006 +0.008036 +0.008012 +0.00799 +0.008058 +0.008105 +0.008088 +0.000884 +0.00812 +0.008095 +0.008082 +0.008117 +0.008201 +0.008175 +0.008203 +0.008168 +0.008158 +0.008174 +0.008241 +0.008205 +0.008241 +0.00821 +0.008196 +0.008236 +0.008315 +0.008286 +0.008324 +0.008281 +0.008285 +0.008329 +0.008427 +0.008407 +0.008435 +0.008381 +0.008373 +0.008385 +0.008449 +0.008403 +0.008391 +0.008304 +0.008242 +0.008207 +0.008247 +0.008179 +0.008155 +0.008081 +0.008036 +0.008015 +0.008059 +0.008012 +0.008009 +0.007939 +0.007902 +0.007898 +0.007958 +0.007908 +0.007913 +0.007857 +0.007837 +0.00784 +0.007913 +0.007885 +0.007901 +0.007855 +0.007832 +0.007853 +0.007927 +0.007905 +0.007933 +0.007895 +0.007884 +0.007916 +0.007985 +0.007965 +0.007992 +0.007972 +0.00794 +0.007987 +0.008066 +0.000885 +0.008039 +0.008078 +0.00804 +0.008032 +0.008061 +0.008139 +0.008115 +0.008145 +0.008118 +0.008106 +0.008138 +0.008216 +0.008195 +0.008237 +0.00818 +0.008176 +0.00821 +0.008292 +0.008276 +0.008303 +0.008275 +0.008258 +0.008305 +0.008383 +0.008365 +0.008406 +0.008371 +0.008358 +0.00839 +0.008447 +0.00833 +0.008285 +0.008218 +0.008178 +0.00814 +0.008154 +0.008101 +0.008093 +0.00801 +0.007979 +0.007959 +0.007967 +0.007921 +0.00793 +0.007869 +0.0078 +0.007787 +0.00783 +0.007794 +0.007803 +0.007756 +0.007738 +0.007753 +0.007835 +0.007784 +0.007791 +0.007743 +0.007724 +0.007747 +0.007834 +0.007796 +0.007826 +0.007806 +0.007791 +0.007823 +0.007897 +0.007862 +0.00789 +0.007885 +0.007846 +0.007894 +0.007987 +0.000886 +0.007951 +0.007977 +0.007949 +0.007937 +0.007941 +0.008018 +0.007995 +0.008028 +0.007993 +0.007983 +0.008027 +0.008102 +0.008078 +0.00811 +0.008069 +0.008061 +0.00809 +0.008178 +0.00817 +0.008209 +0.008171 +0.008154 +0.008183 +0.00826 +0.00825 +0.008276 +0.008212 +0.008183 +0.00815 +0.008198 +0.008134 +0.008106 +0.008014 +0.007949 +0.007931 +0.007965 +0.007905 +0.007894 +0.007814 +0.007776 +0.007754 +0.007805 +0.00776 +0.007758 +0.007688 +0.007658 +0.007656 +0.007713 +0.007678 +0.007688 +0.007639 +0.00763 +0.00764 +0.00771 +0.007686 +0.007702 +0.007656 +0.007653 +0.007682 +0.007758 +0.007744 +0.007769 +0.007728 +0.007725 +0.007749 +0.007826 +0.007798 +0.007835 +0.000887 +0.007786 +0.007789 +0.007826 +0.007899 +0.007889 +0.007909 +0.007876 +0.007854 +0.007898 +0.007965 +0.00795 +0.007977 +0.007953 +0.00794 +0.007969 +0.008044 +0.008029 +0.008055 +0.008024 +0.008007 +0.008043 +0.008121 +0.008105 +0.008129 +0.008104 +0.008086 +0.008138 +0.008215 +0.0082 +0.008226 +0.008206 +0.00819 +0.008201 +0.008184 +0.008134 +0.008132 +0.008075 +0.008031 +0.008042 +0.008028 +0.007952 +0.007946 +0.007892 +0.007834 +0.007812 +0.007853 +0.007784 +0.007804 +0.007746 +0.007685 +0.00767 +0.007717 +0.007671 +0.007692 +0.007639 +0.007621 +0.007649 +0.007712 +0.007683 +0.007686 +0.007671 +0.007633 +0.007637 +0.007704 +0.007677 +0.007712 +0.007675 +0.00766 +0.007714 +0.007779 +0.007764 +0.007794 +0.007765 +0.007748 +0.007802 +0.007856 +0.007843 +0.000888 +0.007872 +0.007841 +0.007833 +0.007866 +0.007947 +0.007929 +0.007957 +0.007922 +0.007905 +0.007945 +0.00802 +0.00799 +0.008021 +0.007983 +0.007979 +0.007999 +0.00808 +0.008039 +0.008068 +0.008023 +0.008014 +0.008053 +0.008123 +0.008108 +0.008139 +0.008129 +0.008119 +0.008123 +0.008177 +0.0081 +0.008085 +0.007995 +0.007938 +0.007933 +0.007978 +0.007909 +0.007901 +0.007828 +0.007784 +0.007778 +0.007834 +0.007783 +0.007785 +0.00773 +0.007693 +0.007699 +0.007764 +0.007725 +0.007742 +0.007692 +0.007678 +0.007691 +0.007767 +0.007739 +0.00776 +0.007721 +0.00771 +0.007725 +0.007813 +0.007793 +0.007824 +0.007788 +0.007774 +0.0078 +0.007882 +0.007864 +0.007874 +0.007841 +0.000889 +0.007835 +0.007866 +0.007957 +0.007933 +0.007964 +0.007927 +0.007914 +0.007943 +0.008021 +0.008003 +0.00804 +0.007999 +0.007987 +0.008021 +0.008099 +0.008079 +0.008116 +0.008076 +0.008066 +0.008101 +0.008178 +0.008159 +0.008188 +0.008156 +0.008144 +0.008184 +0.008266 +0.00825 +0.008294 +0.008255 +0.008242 +0.00828 +0.008296 +0.008228 +0.008227 +0.008167 +0.008127 +0.008112 +0.008118 +0.008043 +0.008043 +0.007956 +0.007916 +0.007891 +0.00792 +0.007885 +0.007892 +0.007842 +0.007817 +0.0078 +0.007819 +0.007766 +0.007778 +0.007743 +0.007716 +0.007749 +0.007815 +0.007778 +0.00781 +0.007758 +0.007754 +0.007772 +0.00783 +0.007792 +0.007832 +0.007794 +0.007802 +0.00782 +0.007904 +0.007878 +0.007901 +0.007871 +0.007876 +0.007908 +0.007995 +0.00089 +0.007961 +0.007986 +0.007958 +0.007937 +0.007957 +0.00802 +0.007992 +0.008025 +0.008008 +0.007989 +0.00803 +0.008104 +0.008085 +0.008111 +0.008083 +0.008066 +0.008104 +0.008181 +0.008176 +0.008211 +0.008183 +0.00816 +0.008201 +0.008269 +0.008252 +0.008277 +0.008243 +0.008218 +0.008255 +0.008301 +0.008254 +0.00823 +0.008153 +0.008087 +0.008082 +0.008109 +0.008053 +0.008038 +0.007973 +0.007922 +0.007935 +0.007975 +0.007932 +0.007942 +0.007886 +0.007837 +0.007859 +0.007913 +0.007882 +0.007891 +0.007843 +0.007813 +0.007844 +0.007902 +0.007888 +0.007912 +0.007877 +0.00785 +0.007882 +0.007957 +0.007943 +0.007977 +0.007943 +0.00792 +0.007976 +0.008027 +0.00801 +0.008042 +0.000891 +0.008 +0.007989 +0.008021 +0.00811 +0.008095 +0.008121 +0.008087 +0.00807 +0.008103 +0.008187 +0.008162 +0.008203 +0.008163 +0.00815 +0.008184 +0.008264 +0.008238 +0.008271 +0.008236 +0.00823 +0.008261 +0.008346 +0.008317 +0.008357 +0.008309 +0.008313 +0.008341 +0.008443 +0.008408 +0.008451 +0.008422 +0.008417 +0.008461 +0.00851 +0.008404 +0.008405 +0.008331 +0.00827 +0.008219 +0.008254 +0.0082 +0.008187 +0.008077 +0.008033 +0.008023 +0.008055 +0.00802 +0.008018 +0.00798 +0.0079 +0.007897 +0.007931 +0.007897 +0.007909 +0.007857 +0.007851 +0.007871 +0.007946 +0.007906 +0.007929 +0.007895 +0.007877 +0.007906 +0.008 +0.007956 +0.007968 +0.00792 +0.007901 +0.007948 +0.008027 +0.007991 +0.008037 +0.007996 +0.007991 +0.008035 +0.008115 +0.008103 +0.000892 +0.00813 +0.008068 +0.008072 +0.008117 +0.008202 +0.008171 +0.008201 +0.008174 +0.00816 +0.008197 +0.008276 +0.008245 +0.008276 +0.008244 +0.008226 +0.00826 +0.008334 +0.008297 +0.008323 +0.008281 +0.00828 +0.008302 +0.00838 +0.008362 +0.008399 +0.00838 +0.008363 +0.008365 +0.008396 +0.008316 +0.008283 +0.008175 +0.008134 +0.00813 +0.008159 +0.0081 +0.008093 +0.008016 +0.00799 +0.007976 +0.008031 +0.007991 +0.007998 +0.007935 +0.007919 +0.007927 +0.007982 +0.007956 +0.007963 +0.007909 +0.007896 +0.007916 +0.007986 +0.007976 +0.007999 +0.007949 +0.007939 +0.007968 +0.008052 +0.008027 +0.008057 +0.008016 +0.008009 +0.008049 +0.008117 +0.008103 +0.000893 +0.008137 +0.00809 +0.008086 +0.008121 +0.008203 +0.00818 +0.008212 +0.00817 +0.008159 +0.008198 +0.008282 +0.008257 +0.008292 +0.008249 +0.00824 +0.008279 +0.00836 +0.008337 +0.008366 +0.008324 +0.008321 +0.00835 +0.008437 +0.008413 +0.008448 +0.008414 +0.008403 +0.008455 +0.008541 +0.008514 +0.008551 +0.008511 +0.008486 +0.008473 +0.008453 +0.008367 +0.008365 +0.008303 +0.008214 +0.008176 +0.008218 +0.008151 +0.008155 +0.008093 +0.008059 +0.008084 +0.008145 +0.008051 +0.008026 +0.00798 +0.007944 +0.007973 +0.008036 +0.007984 +0.008009 +0.007941 +0.007916 +0.007941 +0.007999 +0.007973 +0.007998 +0.007957 +0.007957 +0.007989 +0.00807 +0.008046 +0.008072 +0.008042 +0.00804 +0.008071 +0.00816 +0.008144 +0.008155 +0.000894 +0.008112 +0.008125 +0.008161 +0.008247 +0.008214 +0.008225 +0.008173 +0.008171 +0.008209 +0.008286 +0.008265 +0.008306 +0.00827 +0.008254 +0.008292 +0.008367 +0.008328 +0.008358 +0.008322 +0.008316 +0.008345 +0.008427 +0.008396 +0.00843 +0.008408 +0.008422 +0.008446 +0.008504 +0.008439 +0.008425 +0.008327 +0.008261 +0.00825 +0.008282 +0.008212 +0.008195 +0.008115 +0.008074 +0.008059 +0.008107 +0.008059 +0.008055 +0.007986 +0.007958 +0.007956 +0.008012 +0.007979 +0.00798 +0.007924 +0.007903 +0.007919 +0.007994 +0.007968 +0.007986 +0.007934 +0.007919 +0.007937 +0.008009 +0.008004 +0.008025 +0.00798 +0.007975 +0.008003 +0.008076 +0.008059 +0.008079 +0.00805 +0.008021 +0.008073 +0.008153 +0.000895 +0.008145 +0.008165 +0.008129 +0.008118 +0.008148 +0.008229 +0.008199 +0.008244 +0.008208 +0.008197 +0.008233 +0.008311 +0.008289 +0.00832 +0.008277 +0.008271 +0.008308 +0.00838 +0.008363 +0.0084 +0.008353 +0.008349 +0.008386 +0.008476 +0.00846 +0.008489 +0.008454 +0.008455 +0.008493 +0.008569 +0.00852 +0.008489 +0.008347 +0.008285 +0.008282 +0.008317 +0.008218 +0.008185 +0.008118 +0.00806 +0.008041 +0.008098 +0.008027 +0.008047 +0.007982 +0.00791 +0.007893 +0.007951 +0.007894 +0.007927 +0.007854 +0.00785 +0.007868 +0.00794 +0.007906 +0.007933 +0.007892 +0.007875 +0.007898 +0.007951 +0.007915 +0.007958 +0.007919 +0.007915 +0.007954 +0.008031 +0.008004 +0.008048 +0.008004 +0.007997 +0.008057 +0.000896 +0.008104 +0.008082 +0.008124 +0.008099 +0.008082 +0.00812 +0.008184 +0.00816 +0.008184 +0.008149 +0.00814 +0.008173 +0.008254 +0.008226 +0.008255 +0.008222 +0.008203 +0.008232 +0.008313 +0.008285 +0.008311 +0.00827 +0.008268 +0.008304 +0.008415 +0.008397 +0.008431 +0.008375 +0.008338 +0.008351 +0.00838 +0.008309 +0.008306 +0.008214 +0.008153 +0.008145 +0.008179 +0.008124 +0.008133 +0.00805 +0.007996 +0.008001 +0.008046 +0.008009 +0.008027 +0.007955 +0.007919 +0.007932 +0.00798 +0.007937 +0.007956 +0.007901 +0.007881 +0.007909 +0.007981 +0.007933 +0.007971 +0.007925 +0.007909 +0.00794 +0.008016 +0.007992 +0.008024 +0.007983 +0.007968 +0.007999 +0.008075 +0.008076 +0.008098 +0.008069 +0.000897 +0.008061 +0.008088 +0.008176 +0.00815 +0.008174 +0.008134 +0.008118 +0.008155 +0.008228 +0.008206 +0.008235 +0.008203 +0.008195 +0.008243 +0.008321 +0.008296 +0.008323 +0.008292 +0.008279 +0.008316 +0.008405 +0.008381 +0.008424 +0.008383 +0.008373 +0.008424 +0.00851 +0.008489 +0.008502 +0.008376 +0.008331 +0.00834 +0.008392 +0.008322 +0.008302 +0.008176 +0.00813 +0.008133 +0.008183 +0.008136 +0.008109 +0.008038 +0.007993 +0.007992 +0.008061 +0.008001 +0.008032 +0.007965 +0.007946 +0.007927 +0.007984 +0.007957 +0.007976 +0.007947 +0.007932 +0.00796 +0.008044 +0.008002 +0.008034 +0.00801 +0.007996 +0.008037 +0.008121 +0.00808 +0.008135 +0.008074 +0.008061 +0.008124 +0.000898 +0.008193 +0.008159 +0.008193 +0.008151 +0.008128 +0.008164 +0.008232 +0.008206 +0.008237 +0.008221 +0.008187 +0.008236 +0.008313 +0.008299 +0.008325 +0.008296 +0.008274 +0.008318 +0.008391 +0.008374 +0.008398 +0.008376 +0.008363 +0.00841 +0.008491 +0.008467 +0.008493 +0.008457 +0.008434 +0.008449 +0.008499 +0.008443 +0.008432 +0.008339 +0.008268 +0.008264 +0.008293 +0.008237 +0.008224 +0.008147 +0.00809 +0.0081 +0.008137 +0.008104 +0.00811 +0.008045 +0.008001 +0.008021 +0.008072 +0.008044 +0.008062 +0.008013 +0.007988 +0.008029 +0.008073 +0.00806 +0.00808 +0.008041 +0.008024 +0.00807 +0.008139 +0.008125 +0.008152 +0.008118 +0.008102 +0.008148 +0.00821 +0.00819 +0.000899 +0.008229 +0.008197 +0.008184 +0.008209 +0.008297 +0.00827 +0.008308 +0.008277 +0.008258 +0.008295 +0.00838 +0.008348 +0.008387 +0.00835 +0.008343 +0.008376 +0.008455 +0.008434 +0.008466 +0.008425 +0.008425 +0.008459 +0.008538 +0.008529 +0.008549 +0.008519 +0.008509 +0.008561 +0.008652 +0.008629 +0.008661 +0.008619 +0.008527 +0.008488 +0.008523 +0.008458 +0.00846 +0.008391 +0.008336 +0.008227 +0.008264 +0.008205 +0.008214 +0.008165 +0.008124 +0.008154 +0.008205 +0.008163 +0.008172 +0.008125 +0.008087 +0.008038 +0.008064 +0.008036 +0.008058 +0.008021 +0.008007 +0.008028 +0.00811 +0.008075 +0.008105 +0.008068 +0.008059 +0.0081 +0.008174 +0.008159 +0.00819 +0.008164 +0.008127 +0.008185 +0.008265 +0.0009 +0.008244 +0.008278 +0.008236 +0.008243 +0.008278 +0.008349 +0.008306 +0.008331 +0.008274 +0.00828 +0.00832 +0.008399 +0.008362 +0.008401 +0.008362 +0.00835 +0.008392 +0.008464 +0.008432 +0.00846 +0.008428 +0.00841 +0.008444 +0.008532 +0.008522 +0.008581 +0.00854 +0.008509 +0.00852 +0.008561 +0.00848 +0.008454 +0.008345 +0.008296 +0.00828 +0.00831 +0.008241 +0.00824 +0.008159 +0.008111 +0.008111 +0.008148 +0.008089 +0.008114 +0.008045 +0.008007 +0.008014 +0.008065 +0.008018 +0.008037 +0.007978 +0.007955 +0.007987 +0.008051 +0.008016 +0.008029 +0.007976 +0.007961 +0.007994 +0.008062 +0.008033 +0.00806 +0.008014 +0.008005 +0.008049 +0.008128 +0.008107 +0.008133 +0.008101 +0.008078 +0.008109 +0.008189 +0.000901 +0.008171 +0.008206 +0.008172 +0.008169 +0.008199 +0.008279 +0.008255 +0.008288 +0.008242 +0.008232 +0.008272 +0.008354 +0.008338 +0.008364 +0.00833 +0.008318 +0.008349 +0.008436 +0.008415 +0.008451 +0.008415 +0.00841 +0.00845 +0.008545 +0.008519 +0.008553 +0.008505 +0.00846 +0.008387 +0.008417 +0.008346 +0.008355 +0.008309 +0.008221 +0.008168 +0.008212 +0.00816 +0.008163 +0.008112 +0.008085 +0.008099 +0.00818 +0.00805 +0.008056 +0.007989 +0.007976 +0.007982 +0.008057 +0.007993 +0.008028 +0.007981 +0.007958 +0.007966 +0.00802 +0.007993 +0.008019 +0.007988 +0.007984 +0.008016 +0.008101 +0.008066 +0.008111 +0.008068 +0.00806 +0.008109 +0.008179 +0.008173 +0.008195 +0.000902 +0.008145 +0.008154 +0.008198 +0.008271 +0.008249 +0.008283 +0.008246 +0.008222 +0.008241 +0.00831 +0.008274 +0.008321 +0.008267 +0.008271 +0.008299 +0.008384 +0.008358 +0.008392 +0.008356 +0.008369 +0.008409 +0.008495 +0.008473 +0.008486 +0.00846 +0.00844 +0.00847 +0.008552 +0.008501 +0.008494 +0.008409 +0.008337 +0.008319 +0.008357 +0.008276 +0.00827 +0.008185 +0.008127 +0.008115 +0.008169 +0.008115 +0.008122 +0.00805 +0.00801 +0.008015 +0.008073 +0.008028 +0.008035 +0.007987 +0.007956 +0.007979 +0.00805 +0.008021 +0.008041 +0.007999 +0.007978 +0.008006 +0.00809 +0.008067 +0.008093 +0.008059 +0.008047 +0.008072 +0.008157 +0.00813 +0.008173 +0.008131 +0.008117 +0.000903 +0.008155 +0.00823 +0.008212 +0.008242 +0.008215 +0.008193 +0.008239 +0.008308 +0.008294 +0.008322 +0.008292 +0.008278 +0.008314 +0.00839 +0.008379 +0.008399 +0.008369 +0.008351 +0.008393 +0.008471 +0.00846 +0.008481 +0.00845 +0.00843 +0.008479 +0.008555 +0.008553 +0.008573 +0.00855 +0.008544 +0.008581 +0.008667 +0.008628 +0.00856 +0.008457 +0.008404 +0.008403 +0.008414 +0.008349 +0.008317 +0.008233 +0.008183 +0.008187 +0.008224 +0.008175 +0.00819 +0.008074 +0.008046 +0.008037 +0.008092 +0.008038 +0.008056 +0.007993 +0.007969 +0.008005 +0.008023 +0.008 +0.008014 +0.007964 +0.007958 +0.007988 +0.008062 +0.00804 +0.008054 +0.008044 +0.00802 +0.00806 +0.008142 +0.008106 +0.00814 +0.008108 +0.008071 +0.008108 +0.008183 +0.000904 +0.008154 +0.008176 +0.008167 +0.008142 +0.00819 +0.00826 +0.008255 +0.008274 +0.008245 +0.008223 +0.008277 +0.008347 +0.008339 +0.008348 +0.008325 +0.008298 +0.008343 +0.008408 +0.008401 +0.008416 +0.008401 +0.008387 +0.008444 +0.008504 +0.0085 +0.00851 +0.008482 +0.008449 +0.008457 +0.00848 +0.008426 +0.008386 +0.008312 +0.008236 +0.008229 +0.008248 +0.008206 +0.008168 +0.008107 +0.008048 +0.008062 +0.008094 +0.008072 +0.008045 +0.007996 +0.007942 +0.007957 +0.008 +0.007986 +0.007984 +0.00795 +0.007916 +0.007944 +0.007988 +0.007971 +0.00798 +0.007962 +0.007938 +0.00798 +0.008041 +0.008034 +0.008044 +0.00802 +0.007992 +0.008034 +0.008101 +0.008088 +0.008111 +0.008095 +0.008073 +0.000905 +0.008122 +0.00819 +0.008174 +0.008197 +0.008168 +0.008143 +0.008196 +0.008259 +0.008255 +0.008278 +0.008244 +0.008235 +0.008267 +0.00834 +0.008335 +0.008356 +0.008325 +0.008307 +0.008355 +0.008425 +0.00842 +0.008443 +0.008415 +0.00841 +0.008463 +0.008534 +0.008502 +0.008503 +0.00838 +0.008282 +0.008301 +0.008344 +0.008264 +0.008207 +0.008158 +0.008076 +0.008076 +0.00812 +0.008058 +0.008062 +0.008009 +0.007978 +0.007938 +0.007966 +0.007908 +0.00792 +0.00787 +0.007841 +0.007869 +0.007931 +0.007905 +0.007908 +0.007886 +0.007859 +0.007875 +0.007935 +0.007898 +0.007917 +0.007896 +0.007874 +0.00792 +0.007984 +0.007947 +0.007971 +0.007953 +0.007934 +0.007983 +0.008063 +0.008037 +0.008074 +0.008032 +0.008019 +0.000906 +0.008066 +0.008133 +0.00813 +0.008135 +0.008117 +0.008092 +0.008149 +0.008192 +0.008177 +0.008194 +0.008171 +0.008149 +0.0082 +0.008263 +0.008242 +0.008255 +0.008239 +0.008208 +0.008257 +0.008333 +0.008353 +0.008365 +0.008358 +0.008313 +0.008352 +0.008398 +0.008361 +0.008326 +0.008252 +0.008187 +0.008169 +0.008182 +0.008121 +0.008091 +0.008015 +0.007949 +0.007952 +0.007985 +0.007954 +0.007933 +0.007881 +0.007836 +0.007845 +0.007883 +0.007859 +0.007852 +0.00782 +0.007786 +0.007816 +0.007869 +0.007861 +0.007859 +0.007828 +0.007806 +0.00785 +0.007909 +0.00791 +0.007916 +0.007897 +0.007873 +0.007918 +0.007982 +0.007971 +0.007995 +0.007957 +0.000907 +0.007952 +0.007998 +0.008064 +0.008054 +0.00807 +0.008047 +0.008015 +0.008058 +0.008125 +0.00812 +0.008133 +0.00812 +0.008097 +0.00815 +0.008211 +0.008207 +0.008221 +0.008197 +0.008173 +0.008219 +0.008292 +0.008281 +0.008295 +0.008275 +0.008255 +0.008321 +0.008381 +0.008379 +0.0084 +0.008384 +0.008344 +0.008313 +0.00832 +0.008275 +0.008267 +0.008216 +0.008162 +0.008193 +0.008169 +0.008083 +0.008065 +0.008025 +0.00797 +0.007961 +0.008001 +0.007943 +0.007958 +0.00791 +0.007838 +0.007845 +0.00788 +0.007844 +0.007861 +0.007823 +0.007798 +0.007839 +0.007882 +0.007865 +0.007862 +0.007846 +0.007824 +0.007868 +0.007943 +0.007917 +0.007894 +0.007877 +0.007845 +0.007897 +0.007967 +0.007952 +0.00797 +0.007959 +0.007937 +0.007984 +0.008045 +0.008058 +0.000908 +0.008056 +0.008027 +0.008016 +0.008066 +0.008134 +0.008125 +0.008145 +0.008117 +0.008099 +0.008146 +0.008218 +0.0082 +0.008224 +0.008189 +0.008175 +0.008212 +0.008282 +0.008254 +0.008278 +0.008249 +0.008224 +0.008279 +0.008351 +0.008325 +0.008349 +0.008317 +0.008298 +0.008338 +0.008414 +0.008398 +0.008427 +0.008406 +0.008397 +0.008442 +0.008513 +0.0085 +0.008521 +0.008492 +0.00847 +0.008514 +0.008593 +0.008562 +0.008591 +0.008555 +0.008536 +0.008583 +0.008667 +0.00865 +0.008675 +0.008642 +0.008615 +0.008675 +0.008752 +0.008743 +0.008766 +0.008732 +0.008713 +0.008757 +0.008833 +0.008809 +0.008833 +0.008801 +0.00878 +0.008834 +0.008905 +0.008885 +0.00891 +0.008874 +0.008854 +0.0089 +0.008978 +0.008964 +0.008994 +0.008954 +0.008935 +0.008985 +0.009064 +0.009058 +0.009085 +0.009049 +0.009029 +0.009079 +0.009154 +0.009138 +0.009165 +0.009134 +0.00911 +0.009162 +0.009239 +0.009222 +0.009246 +0.009213 +0.009194 +0.009247 +0.009322 +0.009305 +0.009332 +0.009294 +0.009275 +0.009331 +0.009412 +0.009385 +0.009419 +0.009384 +0.009363 +0.009413 +0.009492 +0.009469 +0.009502 +0.009469 +0.00945 +0.009503 +0.009581 +0.009558 +0.009585 +0.00955 +0.009531 +0.009591 +0.009665 +0.009645 +0.009668 +0.009631 +0.009613 +0.009672 +0.009752 +0.009728 +0.009758 +0.00972 +0.009696 +0.009755 +0.009838 +0.009816 +0.009848 +0.009808 +0.009789 +0.009839 +0.009932 +0.009912 +0.009945 +0.009909 +0.009888 +0.00994 +0.010026 +0.010013 +0.010044 +0.010011 +0.009984 +0.010042 +0.010128 +0.010113 +0.010144 +0.010105 +0.010085 +0.010147 +0.010231 +0.010211 +0.010244 +0.010211 +0.010189 +0.010254 +0.010338 +0.010314 +0.010345 +0.010307 +0.010282 +0.010351 +0.010432 +0.010397 +0.010435 +0.010393 +0.010368 +0.010438 +0.010516 +0.010483 +0.010518 +0.010476 +0.010452 +0.010519 +0.0106 +0.010576 +0.010608 +0.010571 +0.010546 +0.010608 +0.010698 +0.010678 +0.010713 +0.010675 +0.01065 +0.010716 +0.01082 +0.01081 +0.010843 +0.010795 +0.010779 +0.010836 +0.010928 +0.010912 +0.010939 +0.010898 +0.010883 +0.010937 +0.01103 +0.011011 +0.011041 +0.011 +0.010984 +0.011045 +0.011134 +0.011117 +0.011146 +0.01111 +0.011086 +0.011149 +0.011245 +0.011228 +0.011251 +0.01122 +0.011195 +0.011256 +0.011353 +0.01133 +0.011364 +0.011329 +0.011301 +0.011367 +0.011465 +0.011441 +0.011479 +0.011439 +0.011417 +0.011479 +0.011579 +0.011563 +0.011586 +0.011554 +0.01153 +0.011591 +0.011692 +0.011669 +0.011709 +0.011667 +0.011639 +0.011704 +0.011805 +0.011794 +0.011834 +0.0118 +0.011777 +0.011841 +0.011943 +0.01193 +0.011966 +0.011921 +0.011897 +0.011964 +0.012065 +0.012045 +0.012081 +0.01204 +0.012014 +0.012077 +0.012185 +0.012166 +0.012202 +0.012157 +0.012129 +0.012195 +0.012303 +0.01229 +0.012337 +0.012296 +0.012271 +0.012338 +0.012446 +0.012429 +0.012466 +0.012423 +0.012396 +0.012465 +0.012571 +0.012562 +0.0126 +0.012553 +0.012526 +0.012606 +0.012715 +0.012704 +0.012734 +0.012689 +0.012668 +0.012731 +0.012844 +0.012829 +0.01288 +0.012837 +0.012815 +0.012882 +0.012991 +0.012975 +0.013013 +0.012987 +0.012964 +0.013034 +0.013148 +0.013116 +0.013155 +0.013111 +0.013091 +0.013171 +0.013289 +0.013275 +0.013313 +0.013269 +0.013247 +0.013315 +0.013441 +0.013429 +0.013468 +0.013418 +0.013388 +0.01347 +0.013599 +0.013589 +0.013615 +0.013566 +0.01354 +0.013628 +0.013747 +0.013739 +0.01377 +0.013725 +0.013694 +0.013788 +0.013904 +0.013891 +0.013924 +0.013885 +0.013869 +0.013944 +0.014063 +0.014046 +0.014094 +0.014057 +0.014026 +0.014104 +0.014234 +0.014218 +0.014265 +0.014231 +0.014205 +0.014279 +0.014422 +0.014404 +0.014443 +0.014422 +0.014384 +0.014472 +0.014602 +0.014571 +0.0146 +0.014553 +0.014506 +0.014607 +0.014717 +0.014695 +0.014738 +0.014718 +0.014683 +0.014774 +0.014901 +0.014894 +0.01494 +0.014913 +0.01488 +0.014965 +0.015118 +0.015087 +0.015136 +0.015107 +0.015087 +0.015175 +0.015318 +0.0153 +0.015346 +0.015311 +0.015294 +0.015388 +0.015539 +0.015505 +0.015574 +0.015525 +0.01551 +0.015601 +0.015745 +0.015754 +0.015788 +0.015728 +0.015692 +0.015808 +0.015947 +0.015921 +0.015998 +0.015967 +0.015936 +0.016018 +0.016144 +0.016128 +0.016195 +0.016154 +0.016132 +0.016232 +0.016373 +0.016364 +0.016417 +0.016372 +0.016354 +0.016447 +0.016612 +0.016588 +0.016638 +0.016596 +0.016584 +0.016683 +0.01683 +0.016808 +0.016858 +0.016842 +0.016808 +0.016889 +0.017066 +0.017061 +0.017112 +0.017053 +0.017026 +0.017147 +0.017303 +0.01729 +0.017343 +0.017312 +0.01728 +0.017381 +0.017557 +0.017531 +0.017604 +0.017564 +0.017527 +0.017636 +0.017816 +0.017801 +0.017847 +0.017813 +0.017794 +0.017898 +0.018074 +0.018055 +0.018123 +0.018084 +0.018049 +0.018164 +0.018346 +0.018326 +0.01839 +0.01835 +0.018326 +0.018439 +0.018626 +0.01859 +0.018678 +0.018637 +0.018605 +0.018723 +0.018908 +0.018889 +0.018969 +0.01892 +0.018895 +0.019013 +0.019206 +0.019184 +0.019261 +0.019219 +0.019194 +0.01932 +0.019508 +0.019495 +0.019569 +0.019532 +0.019501 +0.019628 +0.019825 +0.019808 +0.019887 +0.01985 +0.019822 +0.019948 +0.02015 +0.020135 +0.020215 +0.020175 +0.020149 +0.020285 +0.020491 +0.020468 +0.02056 +0.020519 +0.020488 +0.020626 +0.020839 +0.020821 +0.020911 +0.02086 +0.020842 +0.020982 +0.021191 +0.02118 +0.02127 +0.021231 +0.021207 +0.021353 +0.021565 +0.021555 +0.02165 +0.021612 +0.021584 +0.021736 +0.021955 +0.021946 +0.02204 +0.022004 +0.021981 +0.022136 +0.022359 +0.022349 +0.022453 +0.022416 +0.02239 +0.022556 +0.022786 +0.022771 +0.022886 +0.022839 +0.022824 +0.022985 +0.023219 +0.023218 +0.023325 +0.023284 +0.023272 +0.023435 +0.023682 +0.023674 +0.023792 +0.023757 +0.023745 +0.023908 +0.024165 +0.024163 +0.024279 +0.024239 +0.024234 +0.024404 +0.024669 +0.024658 +0.024787 +0.024745 +0.024742 +0.024921 +0.025199 +0.025188 +0.025321 +0.025282 +0.025275 +0.02546 +0.025741 +0.025735 +0.025869 +0.025835 +0.025829 +0.026021 +0.026313 +0.026303 +0.026454 +0.026414 +0.026417 +0.026623 +0.026922 +0.026918 +0.027068 +0.027032 +0.027038 +0.027245 +0.027552 +0.027566 +0.027718 +0.027681 +0.027696 +0.027914 +0.028228 +0.028253 +0.028398 +0.028374 +0.028394 +0.028614 +0.028939 +0.028967 +0.029132 +0.029095 +0.029118 +0.029358 +0.029688 +0.029712 +0.029889 +0.029859 +0.0299 +0.030149 +0.030494 +0.030532 +0.03072 +0.030693 +0.030732 +0.03099 +0.031355 +0.031388 +0.031597 +0.031572 +0.031623 +0.031891 +0.032275 +0.032317 +0.032541 +0.032525 +0.032585 +0.032876 +0.033274 +0.033331 +0.033564 +0.033556 +0.033617 +0.033936 +0.034351 +0.034401 +0.034659 +0.034666 +0.034737 +0.035068 +0.035513 +0.035587 +0.035863 +0.035882 +0.03596 +0.036331 +0.03679 +0.036874 +0.037159 +0.037182 +0.037283 +0.037668 +0.038174 +0.038275 +0.038578 +0.038633 +0.038764 +0.039178 +0.039723 +0.039842 +0.040172 +0.040236 +0.040381 +0.040823 +0.041398 +0.041531 +0.041913 +0.042001 +0.042187 +0.042684 +0.04332 +0.043487 +0.043909 +0.044016 +0.044221 +0.04476 +0.04545 +0.045647 +0.046117 +0.046276 +0.046532 +0.047134 +0.047891 +0.048169 +0.048685 +0.048929 +0.049229 +0.04991 +0.050768 +0.051116 +0.051716 +0.052007 +0.052389 +0.053177 +0.054147 +0.054559 +0.055271 +0.055672 +0.056223 +0.057157 +0.058352 +0.058904 +0.059786 +0.060315 +0.060985 +0.062124 +0.063522 +0.064285 +0.065407 +0.066188 +0.067157 +0.068655 +0.070455 +0.071551 +0.073032 +0.074178 +0.075548 +0.077552 +0.079965 +0.08163 +0.083887 +0.085809 +0.088091 +0.091177 +0.094962 +0.097822 +0.101487 +0.105184 +0.109611 +0.11531 +0.122582 +0.129393 +0.138133 +0.148924 +0.163282 +0.182922 +0.214314 +0.264038 +0.392511 +18.884747 +0.231525 +0.243307 +0.128015 +0.07982 +0.064825 +0.056384 +0.050904 +0.047207 +0.044353 +0.041321 +0.03916 +0.037175 +0.035504 +0.034446 +0.03374 +0.032546 +0.031641 +0.030714 +0.029838 +0.02937 +0.029061 +0.028322 +0.02781 +0.027206 +0.026601 +0.026351 +0.026296 +0.025884 +0.025585 +0.025344 +0.024961 +0.024993 +0.025244 +0.025077 +0.025162 +0.025092 +0.024973 +0.025296 +0.025578 +0.025534 +0.025807 +0.025665 +0.000909 +0.025567 +0.025836 +0.025967 +0.025892 +0.026016 +0.026048 +0.026271 +0.026333 +0.026549 +0.026664 +0.026756 +0.026499 +0.026243 +0.02612 +0.026052 +0.025683 +0.02543 +0.025008 +0.024623 +0.024416 +0.024328 +0.02398 +0.023722 +0.023314 +0.022946 +0.022744 +0.022659 +0.022338 +0.022122 +0.021746 +0.021444 +0.02128 +0.021238 +0.020971 +0.020817 +0.020534 +0.020298 +0.02021 +0.020236 +0.020058 +0.020007 +0.019816 +0.019694 +0.01971 +0.019839 +0.019764 +0.019824 +0.019745 +0.019723 +0.019818 +0.020051 +0.020007 +0.02012 +0.020054 +0.020036 +0.00091 +0.020163 +0.020367 +0.020365 +0.020444 +0.02042 +0.020407 +0.02056 +0.020812 +0.020781 +0.020809 +0.020588 +0.020248 +0.020274 +0.020345 +0.020177 +0.019976 +0.019738 +0.019547 +0.019329 +0.019393 +0.019196 +0.019146 +0.018781 +0.018642 +0.018477 +0.018569 +0.018394 +0.018357 +0.018063 +0.017949 +0.017847 +0.017925 +0.017838 +0.017787 +0.017601 +0.017407 +0.017368 +0.017434 +0.017339 +0.017365 +0.017221 +0.017157 +0.017112 +0.017121 +0.017076 +0.017078 +0.017026 +0.016987 +0.017097 +0.01726 +0.017198 +0.017191 +0.017154 +0.017142 +0.017277 +0.017444 +0.017408 +0.000911 +0.017495 +0.017441 +0.017411 +0.017526 +0.017651 +0.017581 +0.017633 +0.017554 +0.017535 +0.017767 +0.017951 +0.01792 +0.017966 +0.017863 +0.017756 +0.017739 +0.01776 +0.017573 +0.017451 +0.017171 +0.016956 +0.016803 +0.016745 +0.016536 +0.016392 +0.016135 +0.015943 +0.015837 +0.015813 +0.015636 +0.015529 +0.015312 +0.015173 +0.015111 +0.01513 +0.014992 +0.014926 +0.014753 +0.01464 +0.01462 +0.014676 +0.014576 +0.014552 +0.014424 +0.014352 +0.014389 +0.014497 +0.014474 +0.014517 +0.01446 +0.014439 +0.014499 +0.014666 +0.014634 +0.014694 +0.014644 +0.014608 +0.014701 +0.014852 +0.014822 +0.000912 +0.014879 +0.014835 +0.014797 +0.014902 +0.015047 +0.015034 +0.015096 +0.01506 +0.015038 +0.015156 +0.015293 +0.015284 +0.015348 +0.015154 +0.015131 +0.015212 +0.015315 +0.015244 +0.015263 +0.015188 +0.015064 +0.01496 +0.015053 +0.014965 +0.014942 +0.014857 +0.014763 +0.014788 +0.014721 +0.014652 +0.014627 +0.014561 +0.014464 +0.014428 +0.014441 +0.014397 +0.014391 +0.014319 +0.014246 +0.014285 +0.014282 +0.014208 +0.014216 +0.014134 +0.014085 +0.014021 +0.014118 +0.014058 +0.014073 +0.014018 +0.013963 +0.014047 +0.014154 +0.014091 +0.014122 +0.013986 +0.01396 +0.014075 +0.014171 +0.014138 +0.01421 +0.014161 +0.014152 +0.014246 +0.000913 +0.014371 +0.014341 +0.014416 +0.01437 +0.01431 +0.014336 +0.014483 +0.014438 +0.014488 +0.014448 +0.014428 +0.014557 +0.014731 +0.0147 +0.014754 +0.014715 +0.014675 +0.014761 +0.014918 +0.014871 +0.014897 +0.014783 +0.014669 +0.014684 +0.014735 +0.014606 +0.014562 +0.014403 +0.014275 +0.014251 +0.014285 +0.014165 +0.014132 +0.013982 +0.013864 +0.013862 +0.013913 +0.013816 +0.013796 +0.013677 +0.013583 +0.013588 +0.013667 +0.013582 +0.013574 +0.013474 +0.013384 +0.013415 +0.013496 +0.013427 +0.013445 +0.013362 +0.0133 +0.013354 +0.013463 +0.013426 +0.013475 +0.013416 +0.013378 +0.013457 +0.013585 +0.013575 +0.01362 +0.013582 +0.013548 +0.000914 +0.013606 +0.013742 +0.01374 +0.013789 +0.013742 +0.013706 +0.013781 +0.013918 +0.013903 +0.013951 +0.01391 +0.013881 +0.013965 +0.014107 +0.014095 +0.014151 +0.014125 +0.014088 +0.014194 +0.014359 +0.014283 +0.014161 +0.014076 +0.014012 +0.014041 +0.014093 +0.013924 +0.013862 +0.01376 +0.013649 +0.013584 +0.013663 +0.013573 +0.013576 +0.013483 +0.013384 +0.01332 +0.013358 +0.01331 +0.013312 +0.013227 +0.013163 +0.01323 +0.013227 +0.013138 +0.013139 +0.013049 +0.012945 +0.012956 +0.013033 +0.012979 +0.013013 +0.012937 +0.012907 +0.012966 +0.013069 +0.013024 +0.012949 +0.012909 +0.012878 +0.012957 +0.013087 +0.013043 +0.013108 +0.013059 +0.013038 +0.01315 +0.013248 +0.000915 +0.013226 +0.013263 +0.013244 +0.013229 +0.013276 +0.01337 +0.01333 +0.013387 +0.013326 +0.013306 +0.013364 +0.013483 +0.013457 +0.013568 +0.013551 +0.013523 +0.013571 +0.013714 +0.013691 +0.013732 +0.013702 +0.013681 +0.013715 +0.013805 +0.0137 +0.013675 +0.013557 +0.013466 +0.013438 +0.0135 +0.013383 +0.013347 +0.013228 +0.013141 +0.013108 +0.013171 +0.013073 +0.013037 +0.012937 +0.012872 +0.012861 +0.01295 +0.012875 +0.012857 +0.012775 +0.01272 +0.012727 +0.012824 +0.01277 +0.01276 +0.012685 +0.01265 +0.012666 +0.01277 +0.012734 +0.01275 +0.012686 +0.012672 +0.012718 +0.012841 +0.01281 +0.012854 +0.012814 +0.012793 +0.012879 +0.012976 +0.000916 +0.01297 +0.012996 +0.012953 +0.012951 +0.013025 +0.013141 +0.013118 +0.01315 +0.013115 +0.013106 +0.013182 +0.013302 +0.013278 +0.013325 +0.013277 +0.013269 +0.013351 +0.013486 +0.013478 +0.013518 +0.013487 +0.013483 +0.013524 +0.013519 +0.013457 +0.013473 +0.013385 +0.013309 +0.013296 +0.013295 +0.013222 +0.013234 +0.013141 +0.013039 +0.012954 +0.013036 +0.012962 +0.012944 +0.012877 +0.012805 +0.012789 +0.012811 +0.012735 +0.012757 +0.012684 +0.012631 +0.012662 +0.012706 +0.012649 +0.012643 +0.012547 +0.012478 +0.012548 +0.012638 +0.012587 +0.012609 +0.012496 +0.012476 +0.012517 +0.012613 +0.012586 +0.01262 +0.012601 +0.012571 +0.012641 +0.012777 +0.012733 +0.012776 +0.012757 +0.000917 +0.012723 +0.012761 +0.012856 +0.012842 +0.01289 +0.012862 +0.012837 +0.012921 +0.013028 +0.013001 +0.013024 +0.012987 +0.012955 +0.013042 +0.013201 +0.013194 +0.013221 +0.013183 +0.01315 +0.013233 +0.013356 +0.01334 +0.013375 +0.013324 +0.013228 +0.013232 +0.013305 +0.013215 +0.013177 +0.013078 +0.012951 +0.012951 +0.013007 +0.012914 +0.012875 +0.012789 +0.012664 +0.01268 +0.012741 +0.012667 +0.01265 +0.012584 +0.012501 +0.01253 +0.012607 +0.012549 +0.012535 +0.01248 +0.012403 +0.012438 +0.012527 +0.012481 +0.012475 +0.012434 +0.012375 +0.012423 +0.012526 +0.012501 +0.012519 +0.012493 +0.01245 +0.012515 +0.012628 +0.012619 +0.012667 +0.012619 +0.012597 +0.000918 +0.012652 +0.01278 +0.01276 +0.012816 +0.012774 +0.012743 +0.012804 +0.01293 +0.012917 +0.012963 +0.01293 +0.012896 +0.012972 +0.013087 +0.013065 +0.013116 +0.013083 +0.013085 +0.013142 +0.013287 +0.013266 +0.013311 +0.013294 +0.013214 +0.013164 +0.013255 +0.01321 +0.013223 +0.01313 +0.013056 +0.013096 +0.013171 +0.013073 +0.012914 +0.012824 +0.01276 +0.012789 +0.012869 +0.01279 +0.012791 +0.012623 +0.012527 +0.012602 +0.01265 +0.012611 +0.012554 +0.012482 +0.012411 +0.012461 +0.012515 +0.012485 +0.012494 +0.012411 +0.012332 +0.012356 +0.012464 +0.01241 +0.01246 +0.012396 +0.012364 +0.012455 +0.01255 +0.012524 +0.01253 +0.012479 +0.012465 +0.012544 +0.012655 +0.012621 +0.000919 +0.012687 +0.012631 +0.012622 +0.012691 +0.012826 +0.012787 +0.01284 +0.012795 +0.012779 +0.012821 +0.01291 +0.012863 +0.012909 +0.012861 +0.012852 +0.012957 +0.013131 +0.013106 +0.013146 +0.013083 +0.013055 +0.013117 +0.013261 +0.013245 +0.01327 +0.013174 +0.01309 +0.013091 +0.013161 +0.013057 +0.013043 +0.012907 +0.012801 +0.012804 +0.012863 +0.012768 +0.012764 +0.012643 +0.012556 +0.012566 +0.012645 +0.012573 +0.012586 +0.01249 +0.012425 +0.012443 +0.012536 +0.012474 +0.012496 +0.012406 +0.012352 +0.012381 +0.012479 +0.012433 +0.012466 +0.012393 +0.012346 +0.012395 +0.012512 +0.012479 +0.012532 +0.01248 +0.012449 +0.012503 +0.012643 +0.012621 +0.012658 +0.00092 +0.012624 +0.012589 +0.012652 +0.012791 +0.012771 +0.012805 +0.012767 +0.012738 +0.012806 +0.012937 +0.012925 +0.012963 +0.012924 +0.012888 +0.012957 +0.01309 +0.013075 +0.013135 +0.013094 +0.013083 +0.013151 +0.013293 +0.013296 +0.013347 +0.01323 +0.0131 +0.013129 +0.013216 +0.01313 +0.013117 +0.012956 +0.012846 +0.012813 +0.01289 +0.012793 +0.012787 +0.012681 +0.012605 +0.012508 +0.012565 +0.012502 +0.012499 +0.01243 +0.012365 +0.012437 +0.012506 +0.012427 +0.012339 +0.012276 +0.012251 +0.012294 +0.012409 +0.012332 +0.012328 +0.012266 +0.012225 +0.012279 +0.012365 +0.01232 +0.012376 +0.012337 +0.012321 +0.01242 +0.012514 +0.012509 +0.012538 +0.012519 +0.000921 +0.012485 +0.01257 +0.012699 +0.012652 +0.012661 +0.012622 +0.012585 +0.01267 +0.012798 +0.01276 +0.012801 +0.012759 +0.012728 +0.012785 +0.0129 +0.012875 +0.012909 +0.012867 +0.012879 +0.012996 +0.013113 +0.013087 +0.013104 +0.013053 +0.012961 +0.012995 +0.013053 +0.012941 +0.012899 +0.012766 +0.012644 +0.012626 +0.012674 +0.012567 +0.012532 +0.012421 +0.012308 +0.012306 +0.012363 +0.012279 +0.01226 +0.012172 +0.012084 +0.012111 +0.01219 +0.012132 +0.012134 +0.012062 +0.011994 +0.012029 +0.012119 +0.012075 +0.012079 +0.012016 +0.011963 +0.012004 +0.012122 +0.012091 +0.012114 +0.012078 +0.012051 +0.012103 +0.012221 +0.0122 +0.01226 +0.012199 +0.012182 +0.000922 +0.012235 +0.012372 +0.012345 +0.012382 +0.012354 +0.012325 +0.012392 +0.012495 +0.012496 +0.012542 +0.0125 +0.012472 +0.01254 +0.012648 +0.012634 +0.012682 +0.012636 +0.012632 +0.01271 +0.012834 +0.012812 +0.012868 +0.012842 +0.012815 +0.012813 +0.012786 +0.01271 +0.012701 +0.012611 +0.012515 +0.012425 +0.012444 +0.012369 +0.012378 +0.012285 +0.012184 +0.012153 +0.012177 +0.012105 +0.012115 +0.012021 +0.01195 +0.011905 +0.011958 +0.011919 +0.011913 +0.011858 +0.011789 +0.011839 +0.011897 +0.011806 +0.011811 +0.011729 +0.011695 +0.011718 +0.011819 +0.011773 +0.011806 +0.01178 +0.011742 +0.011818 +0.011908 +0.011879 +0.011937 +0.011887 +0.011864 +0.011892 +0.011992 +0.000923 +0.011982 +0.012034 +0.011991 +0.011967 +0.012045 +0.012175 +0.012139 +0.01219 +0.012151 +0.012128 +0.0122 +0.012314 +0.012279 +0.012314 +0.012262 +0.012229 +0.012289 +0.012394 +0.012366 +0.012427 +0.012436 +0.012415 +0.012467 +0.012579 +0.012548 +0.012562 +0.012507 +0.012445 +0.012426 +0.012478 +0.012391 +0.012343 +0.012237 +0.012146 +0.012126 +0.012182 +0.012102 +0.012065 +0.011973 +0.011895 +0.011893 +0.011965 +0.011901 +0.011885 +0.01181 +0.01175 +0.011757 +0.011834 +0.011788 +0.01178 +0.011716 +0.011666 +0.011683 +0.011768 +0.011734 +0.01174 +0.011694 +0.011653 +0.011686 +0.01179 +0.011767 +0.011786 +0.011753 +0.011728 +0.011769 +0.011891 +0.011877 +0.011917 +0.011873 +0.000924 +0.011844 +0.011917 +0.012008 +0.012019 +0.012049 +0.012013 +0.011973 +0.01205 +0.012152 +0.012154 +0.012182 +0.012151 +0.012115 +0.012188 +0.012288 +0.012282 +0.012318 +0.012296 +0.012257 +0.012357 +0.012453 +0.012471 +0.012501 +0.01247 +0.012458 +0.012555 +0.012551 +0.012475 +0.012487 +0.012416 +0.012358 +0.012334 +0.01235 +0.01229 +0.012291 +0.012213 +0.012117 +0.012076 +0.012122 +0.01204 +0.012041 +0.011976 +0.011891 +0.011927 +0.011929 +0.011888 +0.011886 +0.011842 +0.011772 +0.011824 +0.011867 +0.01181 +0.011855 +0.011782 +0.011752 +0.011756 +0.01182 +0.011805 +0.01182 +0.011775 +0.011745 +0.011811 +0.011914 +0.011908 +0.011922 +0.011869 +0.011835 +0.011871 +0.011971 +0.011969 +0.012009 +0.000925 +0.011968 +0.011946 +0.012037 +0.01215 +0.012134 +0.012174 +0.012142 +0.012106 +0.012197 +0.012309 +0.012284 +0.012312 +0.012267 +0.012233 +0.012289 +0.01239 +0.012355 +0.012388 +0.012347 +0.012358 +0.012464 +0.012584 +0.012546 +0.012584 +0.012525 +0.012493 +0.012543 +0.012603 +0.012522 +0.012503 +0.012383 +0.012286 +0.012275 +0.012319 +0.012232 +0.012208 +0.012086 +0.011992 +0.011999 +0.012055 +0.011983 +0.011975 +0.011876 +0.011802 +0.011824 +0.011895 +0.011845 +0.011855 +0.011768 +0.011709 +0.011739 +0.011829 +0.011788 +0.01182 +0.011749 +0.011706 +0.011734 +0.011843 +0.011822 +0.011855 +0.011812 +0.011787 +0.011832 +0.011938 +0.011945 +0.011984 +0.011939 +0.000926 +0.011917 +0.011967 +0.012064 +0.012068 +0.012125 +0.01208 +0.012047 +0.012108 +0.012213 +0.01219 +0.012226 +0.012196 +0.012184 +0.012253 +0.012366 +0.012354 +0.012394 +0.012365 +0.012335 +0.012424 +0.012545 +0.012523 +0.012581 +0.012541 +0.012464 +0.012449 +0.01256 +0.01251 +0.012526 +0.01244 +0.012373 +0.012394 +0.01247 +0.012399 +0.012248 +0.012124 +0.012067 +0.01211 +0.012172 +0.012084 +0.012091 +0.011919 +0.011878 +0.011898 +0.011974 +0.011906 +0.011926 +0.011864 +0.011806 +0.011766 +0.011858 +0.011796 +0.011833 +0.011769 +0.011726 +0.011789 +0.011873 +0.011847 +0.011867 +0.011795 +0.011707 +0.011734 +0.011833 +0.011822 +0.01186 +0.011815 +0.011808 +0.011886 +0.011995 +0.011976 +0.012025 +0.011985 +0.000927 +0.011959 +0.012048 +0.012167 +0.012143 +0.012177 +0.012149 +0.012119 +0.012151 +0.012225 +0.012181 +0.012231 +0.012187 +0.012164 +0.012232 +0.012391 +0.012399 +0.012444 +0.012385 +0.012353 +0.012411 +0.012549 +0.012534 +0.012583 +0.012526 +0.012465 +0.012477 +0.012536 +0.012453 +0.012425 +0.012295 +0.012189 +0.012159 +0.012217 +0.012121 +0.012098 +0.011989 +0.011887 +0.011893 +0.011954 +0.011883 +0.011872 +0.011784 +0.0117 +0.011728 +0.01181 +0.011759 +0.011769 +0.011691 +0.01162 +0.011653 +0.011748 +0.011707 +0.01174 +0.011675 +0.011624 +0.011672 +0.011782 +0.011763 +0.011813 +0.011764 +0.011738 +0.011797 +0.011889 +0.011908 +0.011943 +0.000928 +0.011916 +0.011865 +0.011935 +0.012026 +0.012004 +0.012057 +0.012032 +0.012006 +0.012059 +0.012168 +0.012162 +0.01221 +0.012172 +0.012146 +0.012202 +0.012305 +0.012305 +0.012344 +0.012306 +0.012286 +0.012365 +0.012481 +0.012479 +0.012532 +0.012488 +0.012446 +0.012362 +0.012413 +0.012346 +0.012337 +0.012227 +0.012161 +0.012175 +0.01216 +0.012046 +0.012045 +0.011979 +0.011891 +0.011816 +0.011872 +0.011808 +0.011819 +0.011744 +0.011686 +0.011739 +0.011806 +0.011759 +0.011677 +0.011591 +0.011544 +0.011593 +0.011681 +0.011607 +0.011648 +0.01153 +0.011479 +0.011488 +0.011568 +0.011538 +0.011559 +0.011517 +0.011495 +0.01157 +0.011659 +0.011624 +0.011677 +0.011647 +0.011621 +0.011679 +0.011767 +0.011714 +0.011758 +0.000929 +0.011733 +0.011719 +0.011804 +0.011899 +0.011881 +0.011904 +0.011882 +0.011854 +0.011935 +0.012018 +0.011985 +0.012001 +0.011967 +0.01193 +0.011997 +0.012098 +0.012139 +0.012211 +0.012181 +0.012123 +0.012192 +0.012291 +0.012265 +0.01227 +0.012241 +0.012189 +0.012187 +0.012221 +0.012145 +0.012111 +0.012005 +0.01188 +0.011889 +0.011933 +0.011848 +0.011815 +0.011726 +0.011623 +0.011633 +0.011694 +0.011624 +0.011603 +0.011541 +0.011463 +0.011495 +0.011565 +0.011516 +0.011504 +0.011449 +0.011382 +0.011414 +0.011507 +0.011466 +0.011459 +0.011418 +0.011363 +0.011411 +0.011511 +0.01149 +0.011505 +0.011473 +0.01144 +0.011504 +0.011609 +0.011595 +0.011641 +0.011584 +0.011578 +0.00093 +0.01162 +0.011746 +0.011724 +0.011756 +0.01173 +0.0117 +0.011762 +0.011882 +0.011849 +0.011906 +0.011859 +0.011835 +0.011893 +0.012002 +0.011993 +0.01204 +0.011983 +0.011979 +0.012045 +0.012162 +0.012155 +0.012208 +0.012165 +0.012145 +0.012244 +0.012361 +0.012244 +0.012258 +0.012191 +0.012102 +0.012062 +0.012129 +0.012053 +0.012037 +0.011951 +0.011866 +0.01178 +0.011826 +0.011763 +0.011757 +0.011667 +0.011615 +0.011547 +0.01162 +0.011551 +0.011578 +0.011493 +0.011454 +0.011456 +0.011529 +0.01147 +0.011496 +0.011401 +0.011327 +0.011364 +0.011437 +0.011399 +0.011426 +0.011364 +0.011337 +0.011346 +0.011413 +0.011397 +0.011444 +0.011394 +0.011375 +0.01145 +0.011546 +0.01153 +0.011586 +0.01154 +0.011513 +0.011558 +0.000931 +0.011651 +0.011609 +0.011662 +0.01163 +0.011615 +0.01168 +0.011797 +0.011765 +0.011811 +0.01176 +0.01174 +0.011787 +0.011896 +0.011865 +0.011914 +0.011913 +0.011913 +0.011955 +0.012062 +0.01204 +0.012071 +0.012043 +0.012028 +0.012095 +0.012195 +0.012132 +0.012136 +0.012025 +0.011969 +0.011974 +0.012026 +0.011937 +0.011919 +0.011803 +0.011742 +0.011742 +0.011788 +0.011715 +0.011711 +0.011584 +0.011534 +0.011545 +0.011615 +0.011535 +0.011555 +0.011467 +0.011417 +0.011442 +0.011516 +0.011468 +0.011492 +0.011418 +0.01137 +0.011415 +0.011505 +0.011469 +0.011511 +0.011456 +0.011425 +0.01148 +0.011599 +0.011559 +0.011621 +0.011571 +0.01155 +0.011593 +0.011721 +0.000932 +0.011699 +0.011741 +0.011707 +0.011679 +0.011731 +0.011835 +0.011843 +0.011883 +0.011841 +0.011816 +0.011873 +0.011972 +0.011958 +0.012003 +0.011961 +0.01195 +0.012013 +0.012123 +0.01212 +0.012162 +0.012136 +0.012125 +0.01219 +0.012327 +0.012301 +0.012206 +0.012133 +0.012083 +0.01213 +0.012176 +0.012122 +0.012113 +0.012005 +0.011838 +0.011831 +0.011889 +0.011834 +0.01182 +0.01173 +0.011613 +0.011569 +0.011638 +0.011583 +0.011595 +0.011518 +0.01147 +0.011519 +0.011591 +0.011507 +0.011461 +0.011382 +0.011354 +0.011392 +0.011479 +0.011419 +0.011434 +0.011334 +0.011295 +0.011329 +0.011423 +0.011392 +0.01142 +0.011379 +0.011368 +0.011391 +0.011478 +0.011454 +0.011512 +0.011481 +0.011442 +0.011525 +0.011638 +0.011601 +0.000933 +0.011655 +0.011617 +0.01161 +0.011669 +0.01178 +0.011744 +0.011795 +0.011752 +0.011734 +0.011763 +0.011851 +0.011807 +0.011855 +0.011799 +0.011787 +0.011855 +0.012039 +0.012017 +0.012058 +0.012002 +0.011982 +0.012024 +0.012144 +0.012151 +0.012191 +0.0121 +0.012035 +0.012018 +0.012079 +0.012001 +0.011974 +0.011834 +0.011742 +0.011715 +0.01176 +0.011687 +0.011666 +0.011551 +0.011479 +0.01146 +0.011529 +0.011462 +0.011463 +0.011369 +0.011316 +0.01132 +0.011394 +0.011363 +0.011374 +0.011293 +0.011251 +0.011276 +0.011352 +0.011329 +0.011359 +0.011286 +0.011267 +0.011299 +0.011395 +0.011376 +0.011428 +0.011377 +0.011372 +0.011413 +0.011526 +0.011495 +0.011512 +0.000934 +0.011487 +0.011493 +0.011543 +0.011658 +0.011622 +0.011655 +0.011606 +0.01159 +0.011649 +0.011778 +0.011756 +0.011806 +0.011761 +0.011742 +0.011795 +0.011908 +0.011889 +0.011929 +0.011894 +0.011879 +0.011959 +0.012071 +0.012054 +0.012111 +0.012073 +0.012024 +0.011966 +0.01206 +0.012 +0.012005 +0.011903 +0.01184 +0.011852 +0.011922 +0.011812 +0.011673 +0.011579 +0.011525 +0.011568 +0.011609 +0.011495 +0.011481 +0.011364 +0.011324 +0.011297 +0.011364 +0.011286 +0.011308 +0.011241 +0.011208 +0.011243 +0.011342 +0.011268 +0.011256 +0.011134 +0.01111 +0.011176 +0.011249 +0.0112 +0.011227 +0.011142 +0.011121 +0.011126 +0.011221 +0.011193 +0.011243 +0.011191 +0.011188 +0.011266 +0.011371 +0.011338 +0.011396 +0.011354 +0.011336 +0.000935 +0.011407 +0.011516 +0.0115 +0.01154 +0.011501 +0.011487 +0.01155 +0.011627 +0.011571 +0.011607 +0.011559 +0.011533 +0.011595 +0.011681 +0.011672 +0.011721 +0.011738 +0.011725 +0.011777 +0.011885 +0.011852 +0.011894 +0.011847 +0.011844 +0.011891 +0.01195 +0.011889 +0.011866 +0.011767 +0.011694 +0.011684 +0.011709 +0.011622 +0.011589 +0.011483 +0.011403 +0.011402 +0.011441 +0.011372 +0.011358 +0.011261 +0.011203 +0.011214 +0.011272 +0.011226 +0.011223 +0.011141 +0.0111 +0.01113 +0.011189 +0.011158 +0.011163 +0.011098 +0.011068 +0.01111 +0.0112 +0.01118 +0.011202 +0.011154 +0.01114 +0.011195 +0.011293 +0.011285 +0.011308 +0.01128 +0.011254 +0.011327 +0.000936 +0.01141 +0.011409 +0.011438 +0.011396 +0.011386 +0.011444 +0.011548 +0.011548 +0.011571 +0.011521 +0.011509 +0.01157 +0.011674 +0.011665 +0.011702 +0.011651 +0.01164 +0.011704 +0.011809 +0.011804 +0.011851 +0.011809 +0.011797 +0.011877 +0.01199 +0.011976 +0.012033 +0.011872 +0.0118 +0.011837 +0.011888 +0.011805 +0.011769 +0.011571 +0.011507 +0.011493 +0.011525 +0.011467 +0.011457 +0.011358 +0.011252 +0.011234 +0.011321 +0.011243 +0.011269 +0.011195 +0.011163 +0.011148 +0.011188 +0.011139 +0.011158 +0.011113 +0.011053 +0.011096 +0.011125 +0.011088 +0.011124 +0.011049 +0.010981 +0.010987 +0.011057 +0.011058 +0.011069 +0.011037 +0.011021 +0.011078 +0.01117 +0.011165 +0.011201 +0.011168 +0.011156 +0.011238 +0.011303 +0.011289 +0.000937 +0.011351 +0.011277 +0.011233 +0.011269 +0.011376 +0.011354 +0.011409 +0.011367 +0.011352 +0.011412 +0.01152 +0.011491 +0.011524 +0.011482 +0.011485 +0.011568 +0.011684 +0.011652 +0.011693 +0.01164 +0.011623 +0.011667 +0.011811 +0.011782 +0.011817 +0.011776 +0.011738 +0.011755 +0.011844 +0.011769 +0.011754 +0.011662 +0.011588 +0.011567 +0.011641 +0.011553 +0.01153 +0.011434 +0.011352 +0.01134 +0.011413 +0.011332 +0.011323 +0.011243 +0.011179 +0.011179 +0.011273 +0.011216 +0.011231 +0.011163 +0.011122 +0.011128 +0.011235 +0.011184 +0.011212 +0.011165 +0.011134 +0.011162 +0.011264 +0.011238 +0.011293 +0.011248 +0.011228 +0.011283 +0.011383 +0.011349 +0.01139 +0.000938 +0.011364 +0.011357 +0.011403 +0.011501 +0.011486 +0.011517 +0.011487 +0.011467 +0.011529 +0.011627 +0.011626 +0.011653 +0.011624 +0.011596 +0.011656 +0.011764 +0.011752 +0.011786 +0.011762 +0.011731 +0.011824 +0.011928 +0.011912 +0.011965 +0.011927 +0.011917 +0.011938 +0.011898 +0.011823 +0.011824 +0.011736 +0.011667 +0.011681 +0.011657 +0.011563 +0.011573 +0.011472 +0.011339 +0.011346 +0.011399 +0.011332 +0.011345 +0.011275 +0.011226 +0.011182 +0.011222 +0.011159 +0.011191 +0.011113 +0.011096 +0.011126 +0.011215 +0.011166 +0.011172 +0.011115 +0.011028 +0.011055 +0.011153 +0.011112 +0.011152 +0.011115 +0.011107 +0.011166 +0.011278 +0.011237 +0.011282 +0.011256 +0.011233 +0.011315 +0.01141 +0.000939 +0.011381 +0.011434 +0.011395 +0.011368 +0.011385 +0.011457 +0.01143 +0.011478 +0.011453 +0.011439 +0.011507 +0.011607 +0.011594 +0.011615 +0.011611 +0.011606 +0.011665 +0.011764 +0.011742 +0.011783 +0.011757 +0.01173 +0.011788 +0.011903 +0.011889 +0.011907 +0.011824 +0.011738 +0.011715 +0.011751 +0.011668 +0.011614 +0.011492 +0.011392 +0.011371 +0.011415 +0.011349 +0.011311 +0.011206 +0.011122 +0.01112 +0.011175 +0.011127 +0.011113 +0.011035 +0.010963 +0.010966 +0.011044 +0.01101 +0.011016 +0.010947 +0.0109 +0.010911 +0.010986 +0.010982 +0.011002 +0.01096 +0.010939 +0.010961 +0.011061 +0.011037 +0.011077 +0.011066 +0.011043 +0.011103 +0.011192 +0.011166 +0.00094 +0.011189 +0.011161 +0.011153 +0.011214 +0.01131 +0.011291 +0.011324 +0.011288 +0.011271 +0.011334 +0.011433 +0.011417 +0.011458 +0.011409 +0.01139 +0.011451 +0.011561 +0.011546 +0.011596 +0.011556 +0.011547 +0.011609 +0.011735 +0.011716 +0.011754 +0.011733 +0.011625 +0.011584 +0.011652 +0.011597 +0.011585 +0.011506 +0.011428 +0.011461 +0.011444 +0.011317 +0.011314 +0.011232 +0.011106 +0.011103 +0.011152 +0.011084 +0.011105 +0.011026 +0.010985 +0.010944 +0.010975 +0.010921 +0.01094 +0.010886 +0.010835 +0.010887 +0.010946 +0.010908 +0.010876 +0.010783 +0.010765 +0.010809 +0.010867 +0.010846 +0.01088 +0.010831 +0.010834 +0.010856 +0.01091 +0.010896 +0.010936 +0.010901 +0.010899 +0.010957 +0.011044 +0.011029 +0.011087 +0.000941 +0.011028 +0.011029 +0.011091 +0.011214 +0.011164 +0.011222 +0.011175 +0.011171 +0.011205 +0.011266 +0.011221 +0.011265 +0.011221 +0.011209 +0.01126 +0.011377 +0.011402 +0.01147 +0.01141 +0.011396 +0.011438 +0.011539 +0.011508 +0.011552 +0.011529 +0.011512 +0.01155 +0.011607 +0.011505 +0.011478 +0.011375 +0.01129 +0.011262 +0.01129 +0.011187 +0.01117 +0.011061 +0.01099 +0.010983 +0.011032 +0.010938 +0.010934 +0.010854 +0.010798 +0.010814 +0.010884 +0.010809 +0.010819 +0.010752 +0.010725 +0.010753 +0.010834 +0.010771 +0.010787 +0.010722 +0.010707 +0.010758 +0.010863 +0.010817 +0.010847 +0.010795 +0.010771 +0.010834 +0.010947 +0.010923 +0.01098 +0.010914 +0.010908 +0.000942 +0.010958 +0.011064 +0.011045 +0.011076 +0.011048 +0.011029 +0.011081 +0.01118 +0.011165 +0.01121 +0.011168 +0.011151 +0.01121 +0.011311 +0.011291 +0.011328 +0.011286 +0.011264 +0.011327 +0.011442 +0.011422 +0.011475 +0.011429 +0.011416 +0.011501 +0.011591 +0.01158 +0.011634 +0.011576 +0.011438 +0.011457 +0.011525 +0.011442 +0.011428 +0.011319 +0.011135 +0.011151 +0.011196 +0.011125 +0.011139 +0.01105 +0.010936 +0.010911 +0.010959 +0.010925 +0.010926 +0.010864 +0.010801 +0.010861 +0.010907 +0.010844 +0.010813 +0.010748 +0.010707 +0.010737 +0.01082 +0.010768 +0.010805 +0.010704 +0.010652 +0.010689 +0.010763 +0.010732 +0.010777 +0.010733 +0.010703 +0.010779 +0.010862 +0.010838 +0.010893 +0.010851 +0.010827 +0.010863 +0.010933 +0.000943 +0.010906 +0.010969 +0.010925 +0.010916 +0.010975 +0.011076 +0.011054 +0.011107 +0.011067 +0.011059 +0.011111 +0.011213 +0.011173 +0.01121 +0.011163 +0.011149 +0.01119 +0.011291 +0.011263 +0.011305 +0.01129 +0.011297 +0.011342 +0.011462 +0.011414 +0.011459 +0.011422 +0.011422 +0.011448 +0.011529 +0.011469 +0.011448 +0.011331 +0.011256 +0.011226 +0.011265 +0.011187 +0.011166 +0.011066 +0.011008 +0.011002 +0.011057 +0.010991 +0.010987 +0.010898 +0.010852 +0.010866 +0.010937 +0.010871 +0.010895 +0.010823 +0.010792 +0.010807 +0.01089 +0.010839 +0.01086 +0.010791 +0.010771 +0.010799 +0.010895 +0.010855 +0.010885 +0.010841 +0.010839 +0.010882 +0.010992 +0.010964 +0.010997 +0.010945 +0.01094 +0.011008 +0.000944 +0.011109 +0.011082 +0.011111 +0.011074 +0.011049 +0.011121 +0.011225 +0.011206 +0.011243 +0.011188 +0.011175 +0.011245 +0.011349 +0.011335 +0.011361 +0.011335 +0.011308 +0.011394 +0.011495 +0.011488 +0.01152 +0.01149 +0.01148 +0.011527 +0.011545 +0.0115 +0.011532 +0.011446 +0.011391 +0.011423 +0.011475 +0.011355 +0.011283 +0.011187 +0.011127 +0.011119 +0.011123 +0.011071 +0.011067 +0.011012 +0.010952 +0.010983 +0.010983 +0.01094 +0.010938 +0.0109 +0.010862 +0.010897 +0.010941 +0.010862 +0.010899 +0.010847 +0.010815 +0.010847 +0.010875 +0.010841 +0.010868 +0.010817 +0.01082 +0.010868 +0.010959 +0.010935 +0.010959 +0.010943 +0.01092 +0.010946 +0.011021 +0.010985 +0.011044 +0.011 +0.000945 +0.010996 +0.01106 +0.011177 +0.011138 +0.011183 +0.011146 +0.011141 +0.011195 +0.011302 +0.011274 +0.011307 +0.011258 +0.011232 +0.011284 +0.011392 +0.011362 +0.011403 +0.01139 +0.011388 +0.011435 +0.011552 +0.011499 +0.011555 +0.01151 +0.011508 +0.011542 +0.011604 +0.011551 +0.011539 +0.011423 +0.011361 +0.011339 +0.011376 +0.011306 +0.011289 +0.011174 +0.011121 +0.011107 +0.011151 +0.01108 +0.011085 +0.010984 +0.010936 +0.010944 +0.011001 +0.010953 +0.010972 +0.010894 +0.010865 +0.010886 +0.010955 +0.010906 +0.01094 +0.010871 +0.010855 +0.010895 +0.010983 +0.010944 +0.010972 +0.010937 +0.010947 +0.010991 +0.011097 +0.011071 +0.011092 +0.011041 +0.011009 +0.000946 +0.011077 +0.01118 +0.011188 +0.011216 +0.011176 +0.011159 +0.011221 +0.011324 +0.011303 +0.011329 +0.011291 +0.011282 +0.011347 +0.011449 +0.011428 +0.011475 +0.011424 +0.011417 +0.011489 +0.011601 +0.01158 +0.011631 +0.011595 +0.011579 +0.011603 +0.011646 +0.0116 +0.011612 +0.011539 +0.011474 +0.011499 +0.011544 +0.011392 +0.011324 +0.011248 +0.011165 +0.011115 +0.01117 +0.011105 +0.011086 +0.011029 +0.010965 +0.010977 +0.010963 +0.010912 +0.010908 +0.010862 +0.010813 +0.010864 +0.010909 +0.010831 +0.010849 +0.010758 +0.010724 +0.010718 +0.010792 +0.010763 +0.010778 +0.010739 +0.010725 +0.010779 +0.010882 +0.010858 +0.01088 +0.010855 +0.010841 +0.010905 +0.011007 +0.010966 +0.010966 +0.000947 +0.010954 +0.010931 +0.010947 +0.011049 +0.011018 +0.011067 +0.011026 +0.011022 +0.011078 +0.011196 +0.011169 +0.011217 +0.011168 +0.011148 +0.011201 +0.011316 +0.011308 +0.011355 +0.011305 +0.011285 +0.011344 +0.011456 +0.011432 +0.011471 +0.01143 +0.011422 +0.01147 +0.011555 +0.011504 +0.011504 +0.011382 +0.011315 +0.011297 +0.011332 +0.011245 +0.011223 +0.011108 +0.011041 +0.011033 +0.01107 +0.010986 +0.010984 +0.010874 +0.010817 +0.010839 +0.010893 +0.010821 +0.01083 +0.010759 +0.010724 +0.010756 +0.010824 +0.010772 +0.010804 +0.010722 +0.010704 +0.010744 +0.01083 +0.010782 +0.010813 +0.010753 +0.010744 +0.0108 +0.010898 +0.010872 +0.010913 +0.01085 +0.010846 +0.010899 +0.011032 +0.000948 +0.010985 +0.011028 +0.010992 +0.010942 +0.011016 +0.011127 +0.011118 +0.01115 +0.011104 +0.01109 +0.01115 +0.011251 +0.011239 +0.011273 +0.01123 +0.011212 +0.011278 +0.011375 +0.011379 +0.011409 +0.011384 +0.011362 +0.01143 +0.011554 +0.011525 +0.011573 +0.011453 +0.011406 +0.011446 +0.011516 +0.011453 +0.011452 +0.011367 +0.011226 +0.011195 +0.011257 +0.0112 +0.011195 +0.011108 +0.01104 +0.011043 +0.01101 +0.010961 +0.010949 +0.010885 +0.010812 +0.010863 +0.010868 +0.010831 +0.010827 +0.010737 +0.010681 +0.010679 +0.010763 +0.010704 +0.010736 +0.010681 +0.010635 +0.010704 +0.010796 +0.010751 +0.010733 +0.010675 +0.010643 +0.010731 +0.010821 +0.010795 +0.010842 +0.010807 +0.010785 +0.01085 +0.010961 +0.010947 +0.000949 +0.010961 +0.010929 +0.010921 +0.010982 +0.011091 +0.011054 +0.01111 +0.011047 +0.011014 +0.01102 +0.011121 +0.011082 +0.011138 +0.011093 +0.011117 +0.011206 +0.011337 +0.011301 +0.011336 +0.011278 +0.011261 +0.011301 +0.011406 +0.011383 +0.01144 +0.011372 +0.011298 +0.011284 +0.011338 +0.011277 +0.011246 +0.011135 +0.011058 +0.011049 +0.011107 +0.011018 +0.011014 +0.01092 +0.010855 +0.010853 +0.010937 +0.010834 +0.010854 +0.010774 +0.01072 +0.010744 +0.010836 +0.010771 +0.010783 +0.010723 +0.010683 +0.010707 +0.010801 +0.010763 +0.010796 +0.01073 +0.010705 +0.010751 +0.010863 +0.010832 +0.010874 +0.010829 +0.010807 +0.01087 +0.010975 +0.010955 +0.00095 +0.010979 +0.010951 +0.010936 +0.010981 +0.01109 +0.011074 +0.011117 +0.011075 +0.011049 +0.011104 +0.011216 +0.011195 +0.011244 +0.011191 +0.011177 +0.011236 +0.011339 +0.011312 +0.011373 +0.011322 +0.011322 +0.011375 +0.011492 +0.011472 +0.011523 +0.011489 +0.011477 +0.011447 +0.011482 +0.011415 +0.011433 +0.011344 +0.011278 +0.011286 +0.011368 +0.011172 +0.011142 +0.011057 +0.010975 +0.010923 +0.010997 +0.010913 +0.010931 +0.010854 +0.010801 +0.01078 +0.010806 +0.010761 +0.010786 +0.01072 +0.010682 +0.010698 +0.010787 +0.010713 +0.01069 +0.010619 +0.010581 +0.010638 +0.010718 +0.010678 +0.010733 +0.010669 +0.01065 +0.010668 +0.010748 +0.010712 +0.010783 +0.010726 +0.010715 +0.010779 +0.010881 +0.010857 +0.0109 +0.000951 +0.01087 +0.010852 +0.010911 +0.011006 +0.010992 +0.011032 +0.010997 +0.010976 +0.011039 +0.011134 +0.011091 +0.011111 +0.011071 +0.011047 +0.011095 +0.011184 +0.011164 +0.011206 +0.011207 +0.01121 +0.011267 +0.011369 +0.011336 +0.011378 +0.011322 +0.011323 +0.011369 +0.01144 +0.011368 +0.011346 +0.011234 +0.011157 +0.011143 +0.011173 +0.011109 +0.011082 +0.010978 +0.010922 +0.010926 +0.010967 +0.010918 +0.010895 +0.010802 +0.010755 +0.01077 +0.010832 +0.010792 +0.010802 +0.010726 +0.010676 +0.010711 +0.01078 +0.010754 +0.010764 +0.010703 +0.010667 +0.010698 +0.010786 +0.010772 +0.010796 +0.010746 +0.010726 +0.010777 +0.010876 +0.010871 +0.010896 +0.010877 +0.010822 +0.010894 +0.000952 +0.010996 +0.010985 +0.011026 +0.010976 +0.010956 +0.01101 +0.01112 +0.011108 +0.011144 +0.011096 +0.01109 +0.011143 +0.011248 +0.011219 +0.011267 +0.011211 +0.011208 +0.011255 +0.011379 +0.011357 +0.011404 +0.011365 +0.01135 +0.011413 +0.011539 +0.011519 +0.011569 +0.011451 +0.011351 +0.011353 +0.011437 +0.01134 +0.011309 +0.011148 +0.011095 +0.011089 +0.01112 +0.011037 +0.011051 +0.010962 +0.010906 +0.010874 +0.010881 +0.010835 +0.010828 +0.010768 +0.01072 +0.010776 +0.010837 +0.010779 +0.010715 +0.010659 +0.010632 +0.01064 +0.010719 +0.010654 +0.010677 +0.010641 +0.010612 +0.010663 +0.010784 +0.0107 +0.010717 +0.010671 +0.010655 +0.010727 +0.010819 +0.010767 +0.010825 +0.01078 +0.010775 +0.010843 +0.000953 +0.010942 +0.010903 +0.01095 +0.01091 +0.010898 +0.010967 +0.011062 +0.011026 +0.011064 +0.011024 +0.010997 +0.011053 +0.011137 +0.011104 +0.011132 +0.01109 +0.01107 +0.011123 +0.011259 +0.011284 +0.011322 +0.011266 +0.01124 +0.011295 +0.011391 +0.011379 +0.011407 +0.011316 +0.011226 +0.01124 +0.011271 +0.011197 +0.011176 +0.011075 +0.010995 +0.011005 +0.011034 +0.010968 +0.010961 +0.010868 +0.010795 +0.010814 +0.010862 +0.010797 +0.010805 +0.01073 +0.010681 +0.010714 +0.010783 +0.010715 +0.010731 +0.010671 +0.010632 +0.010675 +0.010747 +0.010704 +0.010709 +0.010666 +0.010639 +0.010701 +0.01079 +0.010762 +0.010796 +0.010743 +0.010717 +0.010802 +0.010894 +0.010885 +0.010903 +0.010865 +0.000954 +0.010836 +0.010897 +0.011013 +0.010987 +0.011027 +0.010987 +0.010977 +0.011028 +0.011133 +0.011109 +0.01115 +0.011105 +0.011097 +0.011148 +0.011258 +0.011234 +0.011275 +0.011236 +0.011226 +0.011276 +0.011392 +0.011379 +0.011417 +0.011389 +0.011375 +0.01144 +0.011565 +0.011498 +0.011451 +0.011381 +0.011346 +0.011369 +0.011449 +0.011367 +0.011279 +0.011177 +0.011122 +0.011108 +0.011154 +0.011068 +0.011065 +0.010988 +0.010932 +0.010835 +0.010896 +0.01082 +0.010851 +0.010768 +0.010752 +0.01076 +0.010863 +0.010789 +0.010819 +0.010662 +0.010633 +0.010661 +0.010726 +0.010671 +0.01069 +0.01064 +0.010632 +0.010674 +0.010743 +0.010693 +0.010721 +0.010673 +0.010668 +0.010664 +0.010748 +0.010727 +0.010787 +0.010742 +0.010741 +0.010793 +0.010903 +0.010885 +0.010933 +0.000955 +0.010893 +0.010881 +0.010942 +0.011047 +0.011026 +0.01107 +0.011025 +0.011011 +0.011073 +0.011168 +0.011128 +0.011158 +0.011112 +0.01109 +0.011139 +0.011233 +0.011209 +0.011262 +0.011255 +0.01125 +0.011295 +0.011394 +0.011368 +0.011406 +0.011365 +0.011329 +0.011332 +0.011356 +0.011286 +0.011257 +0.011134 +0.011048 +0.01103 +0.011048 +0.010974 +0.010958 +0.010855 +0.010789 +0.010784 +0.010818 +0.010764 +0.010756 +0.010668 +0.010619 +0.010645 +0.010702 +0.010654 +0.010661 +0.010596 +0.010559 +0.010591 +0.010658 +0.010621 +0.010644 +0.010585 +0.010559 +0.010608 +0.010691 +0.010672 +0.010698 +0.010656 +0.010649 +0.010709 +0.010795 +0.010781 +0.010807 +0.010771 +0.000956 +0.010753 +0.010821 +0.010913 +0.010897 +0.010918 +0.010895 +0.01087 +0.010942 +0.011028 +0.011013 +0.011048 +0.011018 +0.010996 +0.011059 +0.011155 +0.01114 +0.011167 +0.011156 +0.011111 +0.0112 +0.011289 +0.011295 +0.011317 +0.011292 +0.011281 +0.011359 +0.011378 +0.011322 +0.011329 +0.011276 +0.011215 +0.011186 +0.011188 +0.011125 +0.011114 +0.011051 +0.01098 +0.010931 +0.010946 +0.010908 +0.010899 +0.010834 +0.010777 +0.010784 +0.010808 +0.010744 +0.010752 +0.010704 +0.010628 +0.010614 +0.010678 +0.010655 +0.010663 +0.010637 +0.010584 +0.010626 +0.010712 +0.010673 +0.010688 +0.010646 +0.01055 +0.010586 +0.010679 +0.010659 +0.01069 +0.010671 +0.010653 +0.010718 +0.010804 +0.010801 +0.01083 +0.010799 +0.010782 +0.010852 +0.000957 +0.010942 +0.010918 +0.010964 +0.010934 +0.010918 +0.010977 +0.011054 +0.011017 +0.011059 +0.011024 +0.010999 +0.011049 +0.011135 +0.011103 +0.01113 +0.011094 +0.011071 +0.011122 +0.01127 +0.011294 +0.011319 +0.011274 +0.011246 +0.011297 +0.011377 +0.011348 +0.011363 +0.011247 +0.011154 +0.011152 +0.011175 +0.011105 +0.011065 +0.010959 +0.010883 +0.010879 +0.010918 +0.01086 +0.010848 +0.010747 +0.010687 +0.010695 +0.010743 +0.010705 +0.010713 +0.010638 +0.010587 +0.010615 +0.010678 +0.010649 +0.010667 +0.010602 +0.010566 +0.010598 +0.010676 +0.010648 +0.010685 +0.010628 +0.010602 +0.010649 +0.01073 +0.010728 +0.010768 +0.010726 +0.010708 +0.010756 +0.010847 +0.010819 +0.000958 +0.010881 +0.010835 +0.010826 +0.010873 +0.010974 +0.010944 +0.010988 +0.010955 +0.01095 +0.011 +0.011101 +0.011074 +0.01112 +0.011065 +0.011048 +0.011093 +0.011211 +0.011192 +0.011234 +0.0112 +0.011185 +0.01124 +0.011361 +0.011333 +0.011384 +0.011348 +0.01135 +0.011407 +0.011421 +0.011316 +0.011324 +0.011248 +0.011175 +0.011097 +0.011134 +0.011052 +0.011069 +0.010994 +0.010917 +0.010935 +0.010935 +0.010839 +0.010875 +0.010779 +0.010744 +0.010686 +0.010773 +0.010702 +0.010749 +0.010663 +0.010641 +0.010674 +0.01077 +0.01073 +0.010685 +0.010595 +0.010563 +0.0106 +0.010715 +0.010671 +0.010696 +0.010654 +0.010633 +0.010687 +0.010805 +0.010753 +0.010752 +0.010722 +0.010676 +0.010749 +0.010864 +0.010831 +0.010879 +0.000959 +0.010824 +0.01083 +0.010883 +0.010995 +0.010959 +0.01102 +0.010971 +0.01096 +0.011022 +0.011124 +0.01109 +0.011125 +0.011072 +0.01105 +0.011089 +0.011192 +0.01115 +0.011192 +0.011154 +0.011161 +0.011252 +0.011381 +0.01134 +0.011375 +0.011314 +0.01129 +0.011304 +0.011371 +0.011316 +0.01128 +0.01115 +0.011099 +0.011073 +0.011108 +0.011039 +0.011016 +0.010909 +0.010862 +0.010852 +0.010906 +0.010838 +0.010836 +0.010736 +0.010698 +0.010718 +0.010791 +0.010737 +0.010734 +0.010657 +0.010634 +0.010655 +0.010729 +0.010687 +0.010703 +0.010629 +0.010611 +0.010644 +0.010731 +0.010702 +0.010727 +0.01067 +0.010669 +0.010717 +0.01082 +0.010804 +0.010836 +0.010787 +0.010758 +0.010836 +0.00096 +0.010938 +0.010915 +0.010948 +0.010906 +0.010891 +0.01095 +0.011052 +0.011043 +0.011066 +0.011033 +0.011009 +0.01107 +0.011172 +0.011161 +0.011196 +0.011151 +0.011136 +0.011192 +0.011301 +0.011285 +0.011329 +0.011288 +0.01128 +0.011351 +0.011458 +0.011443 +0.011486 +0.011455 +0.011312 +0.011338 +0.01142 +0.011359 +0.011352 +0.011276 +0.011206 +0.01124 +0.011198 +0.011105 +0.011096 +0.011036 +0.010946 +0.010885 +0.010947 +0.010883 +0.01089 +0.010823 +0.01078 +0.010813 +0.010909 +0.010814 +0.010788 +0.01071 +0.010695 +0.01072 +0.01078 +0.010731 +0.010736 +0.010705 +0.010675 +0.010725 +0.010801 +0.01074 +0.010755 +0.01073 +0.010688 +0.010694 +0.010784 +0.010767 +0.010798 +0.010773 +0.010767 +0.010839 +0.010912 +0.010915 +0.01096 +0.010909 +0.000961 +0.010905 +0.010963 +0.011081 +0.01105 +0.011099 +0.011054 +0.011046 +0.011104 +0.011214 +0.011177 +0.011203 +0.011155 +0.011127 +0.011175 +0.011272 +0.011225 +0.011259 +0.011216 +0.011212 +0.011308 +0.011443 +0.011417 +0.011441 +0.011396 +0.011358 +0.01137 +0.011464 +0.01138 +0.011345 +0.011238 +0.011157 +0.011129 +0.011172 +0.011091 +0.011066 +0.010975 +0.010912 +0.01091 +0.010975 +0.010903 +0.010897 +0.010811 +0.010768 +0.01077 +0.010854 +0.010788 +0.010805 +0.010737 +0.010692 +0.010719 +0.010806 +0.01075 +0.010766 +0.010707 +0.010676 +0.010705 +0.010809 +0.010763 +0.010786 +0.010747 +0.010728 +0.010781 +0.010888 +0.010857 +0.010891 +0.010847 +0.010836 +0.010898 +0.011007 +0.000962 +0.010976 +0.01102 +0.010965 +0.010946 +0.011005 +0.011121 +0.0111 +0.011139 +0.01109 +0.011089 +0.011138 +0.011243 +0.011218 +0.011264 +0.011218 +0.011201 +0.011275 +0.011375 +0.011365 +0.011409 +0.011359 +0.011367 +0.011441 +0.011561 +0.011469 +0.011434 +0.011365 +0.011333 +0.011304 +0.011347 +0.011253 +0.011266 +0.011146 +0.011038 +0.011013 +0.011084 +0.011017 +0.01101 +0.010927 +0.01081 +0.010781 +0.010869 +0.010794 +0.01083 +0.010736 +0.010718 +0.01072 +0.010782 +0.010713 +0.010722 +0.010626 +0.010579 +0.01063 +0.0107 +0.010654 +0.010696 +0.010603 +0.010564 +0.01059 +0.010676 +0.010649 +0.010706 +0.01065 +0.010648 +0.010708 +0.010802 +0.01078 +0.010834 +0.010784 +0.010773 +0.010831 +0.000963 +0.010941 +0.010904 +0.010948 +0.010907 +0.010865 +0.01088 +0.010982 +0.010962 +0.011008 +0.010966 +0.010955 +0.011002 +0.011122 +0.011148 +0.011196 +0.011142 +0.011118 +0.01116 +0.011263 +0.011239 +0.011298 +0.011257 +0.011242 +0.011279 +0.011405 +0.011378 +0.011404 +0.011314 +0.011242 +0.011236 +0.011275 +0.011181 +0.011152 +0.011028 +0.010959 +0.010947 +0.011 +0.010925 +0.010914 +0.010817 +0.010763 +0.010769 +0.010839 +0.010769 +0.010775 +0.010704 +0.010659 +0.010685 +0.010772 +0.010719 +0.010728 +0.010669 +0.010639 +0.010667 +0.010765 +0.010725 +0.010764 +0.010711 +0.010675 +0.010731 +0.010844 +0.010815 +0.01086 +0.010821 +0.010783 +0.010852 +0.010954 +0.000964 +0.010936 +0.010979 +0.01093 +0.010918 +0.010966 +0.011074 +0.011055 +0.011104 +0.011055 +0.011037 +0.011087 +0.0112 +0.011186 +0.011229 +0.011181 +0.011166 +0.011211 +0.011317 +0.011302 +0.011345 +0.01131 +0.011293 +0.011363 +0.011466 +0.011446 +0.011505 +0.011466 +0.011458 +0.011527 +0.011556 +0.011457 +0.011478 +0.011413 +0.011359 +0.011367 +0.011399 +0.011291 +0.01127 +0.01117 +0.011099 +0.011075 +0.011142 +0.011077 +0.011076 +0.011006 +0.010893 +0.010868 +0.010939 +0.010889 +0.010902 +0.010837 +0.010789 +0.010839 +0.010918 +0.010873 +0.010788 +0.010728 +0.010689 +0.01074 +0.01084 +0.010787 +0.010824 +0.010767 +0.010743 +0.010806 +0.010888 +0.010845 +0.010867 +0.010823 +0.010796 +0.01087 +0.010971 +0.010946 +0.010975 +0.010944 +0.000965 +0.010936 +0.010993 +0.011097 +0.011068 +0.011111 +0.011073 +0.011052 +0.011081 +0.011171 +0.011143 +0.011178 +0.011141 +0.011115 +0.011173 +0.011285 +0.011297 +0.011365 +0.011327 +0.011293 +0.011344 +0.01144 +0.01143 +0.011482 +0.011437 +0.011415 +0.011476 +0.011563 +0.011516 +0.011511 +0.0114 +0.011324 +0.011302 +0.011323 +0.011242 +0.011207 +0.011094 +0.011023 +0.011018 +0.011047 +0.010985 +0.010969 +0.01087 +0.010812 +0.010831 +0.010884 +0.010827 +0.010833 +0.010764 +0.010721 +0.010751 +0.010815 +0.010771 +0.010782 +0.010717 +0.010681 +0.010725 +0.010799 +0.01077 +0.01078 +0.010734 +0.010721 +0.010773 +0.010867 +0.010851 +0.010884 +0.010828 +0.010826 +0.01087 +0.010994 +0.01096 +0.000966 +0.011007 +0.010954 +0.010931 +0.010991 +0.011106 +0.011083 +0.011122 +0.01108 +0.011069 +0.01112 +0.011226 +0.011203 +0.011247 +0.011197 +0.011189 +0.011242 +0.011351 +0.011338 +0.01138 +0.011348 +0.011329 +0.011395 +0.01152 +0.011503 +0.011542 +0.011514 +0.011415 +0.011385 +0.011456 +0.011397 +0.011391 +0.01129 +0.011234 +0.011261 +0.011287 +0.011134 +0.011124 +0.011029 +0.010937 +0.010907 +0.010992 +0.010901 +0.010929 +0.010835 +0.010812 +0.010813 +0.01085 +0.010761 +0.010797 +0.010726 +0.010701 +0.010744 +0.010822 +0.010754 +0.01073 +0.010655 +0.010656 +0.010653 +0.010711 +0.010675 +0.010703 +0.010648 +0.010649 +0.010702 +0.010794 +0.010773 +0.010805 +0.010759 +0.010768 +0.010835 +0.010927 +0.010881 +0.010899 +0.000967 +0.010848 +0.010837 +0.010898 +0.011007 +0.010971 +0.011016 +0.010973 +0.010962 +0.011024 +0.011128 +0.011085 +0.01112 +0.01107 +0.011054 +0.0111 +0.011202 +0.011175 +0.011245 +0.011234 +0.011226 +0.011257 +0.01137 +0.011346 +0.011391 +0.011358 +0.011337 +0.011373 +0.011453 +0.011398 +0.011393 +0.01129 +0.011227 +0.011206 +0.01125 +0.011177 +0.011162 +0.011061 +0.011005 +0.010979 +0.011041 +0.010984 +0.01098 +0.010888 +0.010838 +0.010839 +0.010912 +0.010859 +0.010881 +0.010809 +0.010766 +0.010772 +0.010857 +0.010825 +0.010845 +0.010786 +0.010758 +0.01079 +0.010878 +0.010857 +0.010898 +0.010855 +0.010847 +0.010872 +0.010994 +0.010952 +0.011013 +0.010969 +0.010958 +0.000968 +0.011014 +0.011111 +0.011078 +0.011119 +0.011087 +0.01108 +0.011137 +0.011238 +0.011213 +0.011244 +0.011198 +0.011179 +0.011257 +0.011357 +0.011343 +0.011375 +0.011331 +0.011306 +0.011383 +0.011479 +0.011476 +0.011506 +0.011483 +0.011467 +0.011541 +0.011654 +0.011639 +0.011669 +0.011512 +0.011456 +0.011488 +0.011551 +0.011464 +0.011395 +0.01127 +0.011199 +0.011203 +0.011234 +0.011149 +0.011142 +0.011052 +0.010922 +0.0109 +0.010971 +0.01089 +0.010906 +0.010836 +0.010784 +0.010737 +0.010781 +0.010723 +0.010758 +0.010686 +0.010661 +0.010686 +0.010781 +0.010717 +0.010729 +0.010613 +0.010575 +0.010647 +0.010714 +0.010676 +0.010717 +0.010678 +0.010663 +0.010735 +0.010819 +0.010783 +0.010835 +0.010808 +0.010731 +0.010767 +0.010876 +0.000969 +0.010846 +0.010892 +0.010857 +0.01085 +0.010913 +0.011023 +0.010998 +0.011047 +0.011 +0.010991 +0.011045 +0.011151 +0.011121 +0.011162 +0.011108 +0.011096 +0.011143 +0.01126 +0.011251 +0.011302 +0.011245 +0.011245 +0.011284 +0.011402 +0.011365 +0.011429 +0.011369 +0.01133 +0.011349 +0.011393 +0.0113 +0.011279 +0.011141 +0.01106 +0.011026 +0.011058 +0.010974 +0.01095 +0.010833 +0.010767 +0.01076 +0.010806 +0.010738 +0.010747 +0.010643 +0.010581 +0.010609 +0.010674 +0.010615 +0.010642 +0.010562 +0.010512 +0.01054 +0.010619 +0.010576 +0.010609 +0.010546 +0.010511 +0.010543 +0.010643 +0.010613 +0.010672 +0.010621 +0.010598 +0.010649 +0.01074 +0.010709 +0.010768 +0.010731 +0.010703 +0.00097 +0.010758 +0.010845 +0.010847 +0.010886 +0.010843 +0.010822 +0.010881 +0.010974 +0.010956 +0.010984 +0.010961 +0.010942 +0.011001 +0.011098 +0.011079 +0.011112 +0.011071 +0.011047 +0.011109 +0.011216 +0.011201 +0.011241 +0.01121 +0.011188 +0.011266 +0.011376 +0.011364 +0.011391 +0.011338 +0.011217 +0.011135 +0.011186 +0.011104 +0.011101 +0.011005 +0.010937 +0.010898 +0.01089 +0.010822 +0.010818 +0.010719 +0.010655 +0.010608 +0.010613 +0.010572 +0.01057 +0.010509 +0.01046 +0.010475 +0.010517 +0.010439 +0.010467 +0.010408 +0.010342 +0.010319 +0.010401 +0.010343 +0.010374 +0.010338 +0.010295 +0.010358 +0.010442 +0.010395 +0.010435 +0.0104 +0.010366 +0.010451 +0.010485 +0.010436 +0.010492 +0.010461 +0.010441 +0.010501 +0.010611 +0.000971 +0.010577 +0.010616 +0.010579 +0.010568 +0.010628 +0.010728 +0.010697 +0.010748 +0.0107 +0.010661 +0.010681 +0.010782 +0.010754 +0.0108 +0.010757 +0.010744 +0.01079 +0.010901 +0.01092 +0.01098 +0.010929 +0.010905 +0.010949 +0.011053 +0.011019 +0.011077 +0.011042 +0.011027 +0.011069 +0.01117 +0.011122 +0.011119 +0.011008 +0.010944 +0.010912 +0.010954 +0.010859 +0.010829 +0.010713 +0.010629 +0.010613 +0.010667 +0.010571 +0.010558 +0.010473 +0.010411 +0.010403 +0.010471 +0.010406 +0.01041 +0.010339 +0.010293 +0.010315 +0.010397 +0.010336 +0.010343 +0.010295 +0.01027 +0.010292 +0.010383 +0.010342 +0.010363 +0.010326 +0.010315 +0.010356 +0.010464 +0.01043 +0.010461 +0.010433 +0.010387 +0.010468 +0.010569 +0.010545 +0.000972 +0.010572 +0.010534 +0.01051 +0.010578 +0.010684 +0.010656 +0.010689 +0.010642 +0.010628 +0.010687 +0.010787 +0.010769 +0.010806 +0.010765 +0.010764 +0.010801 +0.01091 +0.01088 +0.010936 +0.010886 +0.010875 +0.010935 +0.011045 +0.011026 +0.011082 +0.011036 +0.011029 +0.011089 +0.011113 +0.011045 +0.011055 +0.010978 +0.010923 +0.010891 +0.010894 +0.010801 +0.010793 +0.010704 +0.010616 +0.01056 +0.01062 +0.010559 +0.010558 +0.010466 +0.010423 +0.010346 +0.010405 +0.010338 +0.010362 +0.010285 +0.010248 +0.010277 +0.010368 +0.010298 +0.010256 +0.010175 +0.010163 +0.010195 +0.010292 +0.010244 +0.010272 +0.010229 +0.010202 +0.010218 +0.010296 +0.010242 +0.010302 +0.010256 +0.010239 +0.010305 +0.010407 +0.010376 +0.010417 +0.010385 +0.010375 +0.000973 +0.01044 +0.010518 +0.0105 +0.010553 +0.010505 +0.010496 +0.010539 +0.010615 +0.010576 +0.010622 +0.010578 +0.010564 +0.010611 +0.0107 +0.010665 +0.010705 +0.010664 +0.010651 +0.010726 +0.010854 +0.010839 +0.010875 +0.010821 +0.010803 +0.010852 +0.010968 +0.010956 +0.01099 +0.01092 +0.010901 +0.010908 +0.010957 +0.010899 +0.010874 +0.01076 +0.010699 +0.010675 +0.010707 +0.010643 +0.010626 +0.010517 +0.01047 +0.010466 +0.010518 +0.010457 +0.01046 +0.010368 +0.010331 +0.01035 +0.010431 +0.010376 +0.01039 +0.010326 +0.010307 +0.010332 +0.010426 +0.010383 +0.010422 +0.010365 +0.01035 +0.010399 +0.010495 +0.010476 +0.010508 +0.010461 +0.010458 +0.010497 +0.010611 +0.000974 +0.010576 +0.010627 +0.010574 +0.010571 +0.010618 +0.010717 +0.010695 +0.010743 +0.010696 +0.010676 +0.010725 +0.010835 +0.01082 +0.010864 +0.010813 +0.010798 +0.010851 +0.010954 +0.010925 +0.010975 +0.010932 +0.010919 +0.010976 +0.01109 +0.011079 +0.011113 +0.011082 +0.011077 +0.011141 +0.01126 +0.011195 +0.011108 +0.011033 +0.010988 +0.011006 +0.011068 +0.010947 +0.010879 +0.010791 +0.010743 +0.010726 +0.010744 +0.010669 +0.010687 +0.010591 +0.010477 +0.010455 +0.010505 +0.010457 +0.010462 +0.010393 +0.010353 +0.010333 +0.010393 +0.010324 +0.010363 +0.010286 +0.010242 +0.01021 +0.010289 +0.010248 +0.010278 +0.010234 +0.010194 +0.010243 +0.010338 +0.010291 +0.010338 +0.010291 +0.010215 +0.01026 +0.01036 +0.010325 +0.010378 +0.010351 +0.01033 +0.010389 +0.010502 +0.010461 +0.000975 +0.010508 +0.01048 +0.010455 +0.010518 +0.010623 +0.010588 +0.01063 +0.010603 +0.010579 +0.010646 +0.010729 +0.010691 +0.010716 +0.01067 +0.010646 +0.010695 +0.010783 +0.010762 +0.010799 +0.010783 +0.010801 +0.010872 +0.010954 +0.010928 +0.01096 +0.010911 +0.010896 +0.010953 +0.011045 +0.011007 +0.010988 +0.010895 +0.010824 +0.010808 +0.01083 +0.010762 +0.010718 +0.010609 +0.010542 +0.010535 +0.010568 +0.010521 +0.010511 +0.010406 +0.010353 +0.010369 +0.010417 +0.010381 +0.010378 +0.010315 +0.010269 +0.010287 +0.010354 +0.010331 +0.010341 +0.010282 +0.010249 +0.01028 +0.01036 +0.010344 +0.010371 +0.01033 +0.01031 +0.010354 +0.010439 +0.010427 +0.010466 +0.010442 +0.010408 +0.01046 +0.000976 +0.010556 +0.010535 +0.010561 +0.01054 +0.010531 +0.010575 +0.010679 +0.010655 +0.010687 +0.010638 +0.010637 +0.010693 +0.010798 +0.010773 +0.010806 +0.010761 +0.010746 +0.010801 +0.010893 +0.010879 +0.010933 +0.010876 +0.010874 +0.010927 +0.011041 +0.011026 +0.011061 +0.01103 +0.01102 +0.011089 +0.01121 +0.011103 +0.011068 +0.010993 +0.010935 +0.0109 +0.010937 +0.010851 +0.010851 +0.010751 +0.010616 +0.010617 +0.010664 +0.010588 +0.010593 +0.010501 +0.010425 +0.010362 +0.010415 +0.010353 +0.010358 +0.010285 +0.010236 +0.010278 +0.010357 +0.010304 +0.010251 +0.010151 +0.010139 +0.010173 +0.010263 +0.010212 +0.010228 +0.010189 +0.010135 +0.010113 +0.010214 +0.010173 +0.010214 +0.010179 +0.01017 +0.01022 +0.010326 +0.010302 +0.010342 +0.010299 +0.010291 +0.010352 +0.010445 +0.010421 +0.000977 +0.010466 +0.010424 +0.01042 +0.010479 +0.010586 +0.010557 +0.010595 +0.010519 +0.010482 +0.010527 +0.010625 +0.010574 +0.010619 +0.010574 +0.010569 +0.010621 +0.010767 +0.010766 +0.010799 +0.010755 +0.010732 +0.010773 +0.010884 +0.010847 +0.01091 +0.010863 +0.01082 +0.010826 +0.0109 +0.010825 +0.010819 +0.010718 +0.010654 +0.010637 +0.010679 +0.010606 +0.010591 +0.010504 +0.010449 +0.010432 +0.010494 +0.010426 +0.010424 +0.010345 +0.010294 +0.010312 +0.01039 +0.010332 +0.010341 +0.010281 +0.010251 +0.010281 +0.010362 +0.010318 +0.010345 +0.010293 +0.010272 +0.010309 +0.010415 +0.01038 +0.010413 +0.010373 +0.010359 +0.010418 +0.010516 +0.010497 +0.010518 +0.000978 +0.010482 +0.010467 +0.010528 +0.010631 +0.0106 +0.010643 +0.010596 +0.010585 +0.01064 +0.010743 +0.01072 +0.010757 +0.010718 +0.010701 +0.010756 +0.010857 +0.010836 +0.010866 +0.010832 +0.010816 +0.010878 +0.010986 +0.010977 +0.011013 +0.010961 +0.01097 +0.011045 +0.011154 +0.011084 +0.010995 +0.010903 +0.010862 +0.010892 +0.010951 +0.010838 +0.010791 +0.010705 +0.010652 +0.010611 +0.01065 +0.010582 +0.010578 +0.010494 +0.010466 +0.010439 +0.010471 +0.010384 +0.01041 +0.010331 +0.010306 +0.010337 +0.010414 +0.010315 +0.010334 +0.010248 +0.01022 +0.010212 +0.010282 +0.010243 +0.01026 +0.010213 +0.010201 +0.010252 +0.010346 +0.010321 +0.010348 +0.010301 +0.0103 +0.010364 +0.010467 +0.010424 +0.010431 +0.010378 +0.000979 +0.010359 +0.010425 +0.010528 +0.0105 +0.010546 +0.010498 +0.010499 +0.010544 +0.010655 +0.010624 +0.010668 +0.010624 +0.010597 +0.01065 +0.010739 +0.010698 +0.010731 +0.010689 +0.010667 +0.010716 +0.010822 +0.010847 +0.010914 +0.010867 +0.010835 +0.010892 +0.010983 +0.010958 +0.010987 +0.010953 +0.010938 +0.010936 +0.01099 +0.010894 +0.01087 +0.010765 +0.010684 +0.010658 +0.01071 +0.010626 +0.010617 +0.01053 +0.010464 +0.010462 +0.010521 +0.010459 +0.010458 +0.010377 +0.010328 +0.01034 +0.010417 +0.01036 +0.010377 +0.010317 +0.010273 +0.01029 +0.010377 +0.010328 +0.010354 +0.010294 +0.010271 +0.010301 +0.010401 +0.010365 +0.010395 +0.010367 +0.01035 +0.010393 +0.010502 +0.010472 +0.010506 +0.010466 +0.010461 +0.00098 +0.010512 +0.010608 +0.010594 +0.010612 +0.010578 +0.010565 +0.010633 +0.010732 +0.010696 +0.010732 +0.010694 +0.010676 +0.010748 +0.010841 +0.010821 +0.010851 +0.010815 +0.010795 +0.010853 +0.010964 +0.010952 +0.010984 +0.010955 +0.010933 +0.011008 +0.011127 +0.011111 +0.011064 +0.010953 +0.010902 +0.010922 +0.010966 +0.010891 +0.010792 +0.01067 +0.010612 +0.010638 +0.010676 +0.010574 +0.010545 +0.010433 +0.010373 +0.01036 +0.010393 +0.010354 +0.01034 +0.010289 +0.010239 +0.010256 +0.010276 +0.010241 +0.010235 +0.010199 +0.010142 +0.010196 +0.010227 +0.010178 +0.010221 +0.010152 +0.01013 +0.010177 +0.010234 +0.010198 +0.010248 +0.010202 +0.01017 +0.010244 +0.010327 +0.010282 +0.010323 +0.010316 +0.010267 +0.010333 +0.010437 +0.000981 +0.010405 +0.010455 +0.010413 +0.010401 +0.010439 +0.010528 +0.010489 +0.010541 +0.010505 +0.010493 +0.010547 +0.010643 +0.010604 +0.010638 +0.010592 +0.010573 +0.010624 +0.010721 +0.010704 +0.010789 +0.010755 +0.01074 +0.010784 +0.010879 +0.010849 +0.0109 +0.010859 +0.010865 +0.010898 +0.010987 +0.010941 +0.010924 +0.010838 +0.010778 +0.010739 +0.010775 +0.010695 +0.010662 +0.010558 +0.010504 +0.010481 +0.010537 +0.010469 +0.010458 +0.010367 +0.01032 +0.010323 +0.010387 +0.010334 +0.010342 +0.010269 +0.010242 +0.010262 +0.010343 +0.010306 +0.01032 +0.010262 +0.010244 +0.010267 +0.010362 +0.01033 +0.010369 +0.010302 +0.010305 +0.010347 +0.010452 +0.010428 +0.010463 +0.010432 +0.010407 +0.000982 +0.010469 +0.010559 +0.010542 +0.010579 +0.010545 +0.01052 +0.010584 +0.010676 +0.01066 +0.010702 +0.010667 +0.010642 +0.010686 +0.010789 +0.010781 +0.010824 +0.010774 +0.010753 +0.01082 +0.010914 +0.010916 +0.010939 +0.010919 +0.010897 +0.010957 +0.011075 +0.011057 +0.011103 +0.011018 +0.010906 +0.010917 +0.010977 +0.010904 +0.010899 +0.010802 +0.010652 +0.010631 +0.010678 +0.010621 +0.010621 +0.010541 +0.010478 +0.010489 +0.010487 +0.010414 +0.010431 +0.010352 +0.010304 +0.010273 +0.010335 +0.010291 +0.010312 +0.010251 +0.010199 +0.010266 +0.010325 +0.0103 +0.010318 +0.010191 +0.010154 +0.010212 +0.010297 +0.010266 +0.010305 +0.010261 +0.010229 +0.010284 +0.010349 +0.010319 +0.010365 +0.01035 +0.010295 +0.010373 +0.010479 +0.010446 +0.000983 +0.010487 +0.010458 +0.010442 +0.010492 +0.010607 +0.010559 +0.010612 +0.010577 +0.010565 +0.010619 +0.010714 +0.010664 +0.010699 +0.01065 +0.010631 +0.010681 +0.010775 +0.010735 +0.010783 +0.010754 +0.010791 +0.010846 +0.010942 +0.010909 +0.010948 +0.010877 +0.010851 +0.010864 +0.01092 +0.010845 +0.010819 +0.010703 +0.010644 +0.010611 +0.010657 +0.010592 +0.010577 +0.010475 +0.010433 +0.010428 +0.010482 +0.01043 +0.010433 +0.010341 +0.010314 +0.010327 +0.010391 +0.01035 +0.01037 +0.010294 +0.010273 +0.010294 +0.010375 +0.010339 +0.010359 +0.010301 +0.010289 +0.010324 +0.010423 +0.010396 +0.010427 +0.010379 +0.010386 +0.010428 +0.010535 +0.010528 +0.010519 +0.000984 +0.010482 +0.010492 +0.010535 +0.010652 +0.010624 +0.010652 +0.010608 +0.010591 +0.010651 +0.010757 +0.010734 +0.010778 +0.010728 +0.010718 +0.010775 +0.010873 +0.010848 +0.010901 +0.010846 +0.010841 +0.010901 +0.011018 +0.010993 +0.011038 +0.011002 +0.011004 +0.01106 +0.011064 +0.010976 +0.01099 +0.010905 +0.010856 +0.010818 +0.010808 +0.010731 +0.010743 +0.010656 +0.010597 +0.010568 +0.010586 +0.010514 +0.010542 +0.010459 +0.010429 +0.010416 +0.010465 +0.010385 +0.01044 +0.010366 +0.010342 +0.01031 +0.010383 +0.010336 +0.01037 +0.010325 +0.010307 +0.01034 +0.010427 +0.010392 +0.010426 +0.010384 +0.010383 +0.010364 +0.010426 +0.010397 +0.010461 +0.010414 +0.010421 +0.010466 +0.01057 +0.010546 +0.010599 +0.010553 +0.000985 +0.010556 +0.010597 +0.010696 +0.010683 +0.010724 +0.010686 +0.01067 +0.010734 +0.010828 +0.010807 +0.010832 +0.010795 +0.010764 +0.010818 +0.0109 +0.010865 +0.010891 +0.01085 +0.010833 +0.0109 +0.011039 +0.011047 +0.011058 +0.011023 +0.010986 +0.011017 +0.011091 +0.011047 +0.011014 +0.010916 +0.010838 +0.010821 +0.010863 +0.010794 +0.010762 +0.01068 +0.010616 +0.010625 +0.010679 +0.010611 +0.010607 +0.010536 +0.010475 +0.010499 +0.010569 +0.010514 +0.010509 +0.010461 +0.010418 +0.010442 +0.010523 +0.010478 +0.010489 +0.01044 +0.010404 +0.010448 +0.010543 +0.010497 +0.010511 +0.010478 +0.010464 +0.010517 +0.010619 +0.010593 +0.010617 +0.010582 +0.010563 +0.010622 +0.010734 +0.000986 +0.010705 +0.010749 +0.010692 +0.01067 +0.010736 +0.010844 +0.01082 +0.010864 +0.010819 +0.010808 +0.010856 +0.010968 +0.010944 +0.01098 +0.010937 +0.010927 +0.010981 +0.011091 +0.011076 +0.011124 +0.011084 +0.011085 +0.011148 +0.011266 +0.011169 +0.011112 +0.011025 +0.01099 +0.010955 +0.010989 +0.0109 +0.010898 +0.010811 +0.010693 +0.010676 +0.010732 +0.010663 +0.010668 +0.010583 +0.010552 +0.010479 +0.010522 +0.010438 +0.010487 +0.010403 +0.01038 +0.010413 +0.010482 +0.01044 +0.010446 +0.010327 +0.010302 +0.010341 +0.010416 +0.010375 +0.010411 +0.010353 +0.010348 +0.010363 +0.010438 +0.010382 +0.010455 +0.010405 +0.010395 +0.010469 +0.01056 +0.010538 +0.010583 +0.010545 +0.010529 +0.000987 +0.010593 +0.010691 +0.010659 +0.010711 +0.01066 +0.010644 +0.010723 +0.010823 +0.010776 +0.010814 +0.010763 +0.010735 +0.010749 +0.010847 +0.010807 +0.010857 +0.010815 +0.010819 +0.010917 +0.011044 +0.011012 +0.011035 +0.010993 +0.010969 +0.011016 +0.011104 +0.011076 +0.011064 +0.010951 +0.010871 +0.01086 +0.010898 +0.010799 +0.010777 +0.010659 +0.010589 +0.010589 +0.01065 +0.010564 +0.010564 +0.010473 +0.010419 +0.010429 +0.010497 +0.010433 +0.010447 +0.010366 +0.010319 +0.010349 +0.010431 +0.010377 +0.010395 +0.010328 +0.010285 +0.010321 +0.010414 +0.010368 +0.010401 +0.010347 +0.010318 +0.010371 +0.010473 +0.01044 +0.010492 +0.010442 +0.010421 +0.010475 +0.010576 +0.01057 +0.000988 +0.010596 +0.010559 +0.010541 +0.010585 +0.010701 +0.010671 +0.010725 +0.010679 +0.010656 +0.010703 +0.010806 +0.010789 +0.010841 +0.010797 +0.010784 +0.010828 +0.010933 +0.010914 +0.010953 +0.010917 +0.010905 +0.010979 +0.011081 +0.011054 +0.01111 +0.011067 +0.011045 +0.010987 +0.011059 +0.011003 +0.011016 +0.01091 +0.010851 +0.010851 +0.010922 +0.010797 +0.010686 +0.010589 +0.010557 +0.010564 +0.010633 +0.010554 +0.010471 +0.010405 +0.010346 +0.010392 +0.010448 +0.010383 +0.010408 +0.010295 +0.010276 +0.010281 +0.010349 +0.01031 +0.010331 +0.010283 +0.010254 +0.01027 +0.010344 +0.01029 +0.010318 +0.01028 +0.010233 +0.010233 +0.01033 +0.010308 +0.010351 +0.010324 +0.010309 +0.010353 +0.010474 +0.010441 +0.010488 +0.010473 +0.010422 +0.010489 +0.000989 +0.010603 +0.010571 +0.010615 +0.010576 +0.010562 +0.010626 +0.010728 +0.010682 +0.01071 +0.010637 +0.010617 +0.010665 +0.01076 +0.010728 +0.010771 +0.010725 +0.010741 +0.010836 +0.010947 +0.010909 +0.010949 +0.010894 +0.010869 +0.010886 +0.010947 +0.010899 +0.010873 +0.010758 +0.010678 +0.01066 +0.010692 +0.010608 +0.010607 +0.010485 +0.010429 +0.010434 +0.010491 +0.010406 +0.01043 +0.010344 +0.010291 +0.010308 +0.01038 +0.010332 +0.010361 +0.010288 +0.010251 +0.010285 +0.010359 +0.01031 +0.010354 +0.010289 +0.010268 +0.010296 +0.010393 +0.01036 +0.010404 +0.010355 +0.010334 +0.010394 +0.010491 +0.010458 +0.010515 +0.010461 +0.00099 +0.010448 +0.010501 +0.010605 +0.010578 +0.010617 +0.010581 +0.010562 +0.010619 +0.010725 +0.010705 +0.010731 +0.010692 +0.010671 +0.010739 +0.01084 +0.01082 +0.010863 +0.010813 +0.01079 +0.010855 +0.010952 +0.010944 +0.010982 +0.010953 +0.010931 +0.011008 +0.011115 +0.011104 +0.011115 +0.010979 +0.01094 +0.010976 +0.011026 +0.010958 +0.010881 +0.010773 +0.010717 +0.010691 +0.010735 +0.010659 +0.010661 +0.010597 +0.010541 +0.010565 +0.010563 +0.01049 +0.010501 +0.010443 +0.010403 +0.010455 +0.010505 +0.010469 +0.010455 +0.010395 +0.010357 +0.010361 +0.010442 +0.010399 +0.010419 +0.010379 +0.010351 +0.010405 +0.010504 +0.010472 +0.010493 +0.010465 +0.010451 +0.010463 +0.010537 +0.010504 +0.010545 +0.010518 +0.010497 +0.010572 +0.000991 +0.010666 +0.010644 +0.01069 +0.010657 +0.010624 +0.010706 +0.010799 +0.010781 +0.010808 +0.010781 +0.010755 +0.010829 +0.010909 +0.010879 +0.010896 +0.010857 +0.010828 +0.010883 +0.01096 +0.010949 +0.010977 +0.010992 +0.010984 +0.011052 +0.011131 +0.011109 +0.011125 +0.01106 +0.010998 +0.011018 +0.01104 +0.010978 +0.010943 +0.010842 +0.010756 +0.010774 +0.0108 +0.010738 +0.010725 +0.01064 +0.010558 +0.010596 +0.010634 +0.010583 +0.010584 +0.010513 +0.010454 +0.010496 +0.010555 +0.010519 +0.010529 +0.010465 +0.010415 +0.010463 +0.010529 +0.010509 +0.010529 +0.010485 +0.010433 +0.010502 +0.010582 +0.010576 +0.010608 +0.010572 +0.010543 +0.010609 +0.010692 +0.0107 +0.000992 +0.010717 +0.010692 +0.010665 +0.010712 +0.010815 +0.010814 +0.010842 +0.010805 +0.010782 +0.010841 +0.010936 +0.010928 +0.010968 +0.010926 +0.010905 +0.010965 +0.011054 +0.011051 +0.011078 +0.011045 +0.01103 +0.0111 +0.011202 +0.011198 +0.011233 +0.011198 +0.011196 +0.011258 +0.011262 +0.011182 +0.011181 +0.011096 +0.011035 +0.011007 +0.010986 +0.010906 +0.01089 +0.010796 +0.010686 +0.010667 +0.01072 +0.010673 +0.010658 +0.010609 +0.010474 +0.010475 +0.010529 +0.010496 +0.010508 +0.010448 +0.010414 +0.010443 +0.010518 +0.010486 +0.010463 +0.010348 +0.010321 +0.010372 +0.010446 +0.010422 +0.010463 +0.01041 +0.010392 +0.010467 +0.010545 +0.01053 +0.010569 +0.0105 +0.010476 +0.010509 +0.010618 +0.010576 +0.000993 +0.010627 +0.010604 +0.010583 +0.010637 +0.010757 +0.010718 +0.010764 +0.010718 +0.010714 +0.010775 +0.010875 +0.010839 +0.010882 +0.010829 +0.010813 +0.010855 +0.010958 +0.010919 +0.010956 +0.010911 +0.010897 +0.010959 +0.011106 +0.011089 +0.011117 +0.011072 +0.011042 +0.011054 +0.011145 +0.011064 +0.011033 +0.010923 +0.010843 +0.010815 +0.010856 +0.010777 +0.010751 +0.010647 +0.010584 +0.010581 +0.010634 +0.010561 +0.010567 +0.010484 +0.010422 +0.010419 +0.010502 +0.010454 +0.010459 +0.010391 +0.010356 +0.010372 +0.010449 +0.010396 +0.010427 +0.010375 +0.010329 +0.010354 +0.010445 +0.010402 +0.010445 +0.010412 +0.010389 +0.010428 +0.010533 +0.010498 +0.010527 +0.010498 +0.010485 +0.010556 +0.010652 +0.000994 +0.010624 +0.010657 +0.010603 +0.01059 +0.010641 +0.010756 +0.010739 +0.010782 +0.010728 +0.010714 +0.010768 +0.010873 +0.010852 +0.010902 +0.010846 +0.01083 +0.010899 +0.010992 +0.010992 +0.01103 +0.010988 +0.010994 +0.011054 +0.011173 +0.011138 +0.011054 +0.010963 +0.010942 +0.010964 +0.011008 +0.010928 +0.010924 +0.010753 +0.01068 +0.010659 +0.010737 +0.010654 +0.010647 +0.010595 +0.010471 +0.010454 +0.010511 +0.010467 +0.010466 +0.010426 +0.010382 +0.010425 +0.0105 +0.010445 +0.010477 +0.01034 +0.010327 +0.010344 +0.010417 +0.010385 +0.01041 +0.010363 +0.010359 +0.010374 +0.010439 +0.010408 +0.010446 +0.010422 +0.010409 +0.010453 +0.010568 +0.010519 +0.010579 +0.010542 +0.010516 +0.000995 +0.010584 +0.010655 +0.010614 +0.010672 +0.010629 +0.010622 +0.010679 +0.010772 +0.010741 +0.010785 +0.01074 +0.010722 +0.010773 +0.01086 +0.010822 +0.010863 +0.01082 +0.010801 +0.010865 +0.01102 +0.010994 +0.011042 +0.010979 +0.010964 +0.010984 +0.011055 +0.011012 +0.010989 +0.010863 +0.010802 +0.01078 +0.010816 +0.010739 +0.010722 +0.010605 +0.010535 +0.010539 +0.01058 +0.010519 +0.010514 +0.010419 +0.01036 +0.010365 +0.010433 +0.010394 +0.010399 +0.010316 +0.010279 +0.010297 +0.010364 +0.010332 +0.010349 +0.010283 +0.010255 +0.010278 +0.010367 +0.010353 +0.010391 +0.010333 +0.010329 +0.010367 +0.010465 +0.010463 +0.010492 +0.01046 +0.01043 +0.010487 +0.000996 +0.01058 +0.010566 +0.010608 +0.01057 +0.010549 +0.010599 +0.010696 +0.010677 +0.010718 +0.010677 +0.01066 +0.010718 +0.010821 +0.010801 +0.01083 +0.010791 +0.010774 +0.010836 +0.010934 +0.010913 +0.010948 +0.01091 +0.010875 +0.010946 +0.011042 +0.01103 +0.011072 +0.011026 +0.010995 +0.01106 +0.011156 +0.011149 +0.011189 +0.011144 +0.01112 +0.011181 +0.011278 +0.011268 +0.011308 +0.011269 +0.011243 +0.011304 +0.011399 +0.011376 +0.011417 +0.011375 +0.011361 +0.011426 +0.011524 +0.011509 +0.011543 +0.011496 +0.011478 +0.011537 +0.011635 +0.011631 +0.011673 +0.011633 +0.01161 +0.011677 +0.011771 +0.01176 +0.011804 +0.011752 +0.011738 +0.011808 +0.01191 +0.01189 +0.011937 +0.0119 +0.011892 +0.01196 +0.01207 +0.012061 +0.012101 +0.012014 +0.011968 +0.012022 +0.012145 +0.012115 +0.012113 +0.012049 +0.011999 +0.012022 +0.011992 +0.011876 +0.011858 +0.011755 +0.011649 +0.01158 +0.011608 +0.011548 +0.011516 +0.011453 +0.011378 +0.011393 +0.011359 +0.011265 +0.011264 +0.0112 +0.011137 +0.011147 +0.011134 +0.011072 +0.011066 +0.01101 +0.010949 +0.010973 +0.010964 +0.010915 +0.010931 +0.010858 +0.010843 +0.01088 +0.010968 +0.0109 +0.01087 +0.010837 +0.010819 +0.010847 +0.010937 +0.010902 +0.010937 +0.010912 +0.010911 +0.010974 +0.011074 +0.011056 +0.011094 +0.011061 +0.011038 +0.000997 +0.011115 +0.01121 +0.011203 +0.011229 +0.011203 +0.011187 +0.011271 +0.011359 +0.011309 +0.011324 +0.011288 +0.011255 +0.011327 +0.011411 +0.011379 +0.011407 +0.011381 +0.01134 +0.011417 +0.011515 +0.011517 +0.011596 +0.01157 +0.011531 +0.011599 +0.011693 +0.011668 +0.011701 +0.011659 +0.011641 +0.011734 +0.011833 +0.011821 +0.011852 +0.011805 +0.01177 +0.011856 +0.011929 +0.011891 +0.011849 +0.011756 +0.011663 +0.011654 +0.011671 +0.011599 +0.011553 +0.011442 +0.011358 +0.011359 +0.011382 +0.011328 +0.011292 +0.011198 +0.011124 +0.01114 +0.011175 +0.011136 +0.011126 +0.011041 +0.010985 +0.011017 +0.011074 +0.011038 +0.011042 +0.010985 +0.010941 +0.010985 +0.011062 +0.01105 +0.011075 +0.011034 +0.011008 +0.011079 +0.011159 +0.011167 +0.011182 +0.01117 +0.011127 +0.011202 +0.000998 +0.011299 +0.011274 +0.011324 +0.011286 +0.01126 +0.01132 +0.011423 +0.011416 +0.011453 +0.011419 +0.011386 +0.011454 +0.011562 +0.011547 +0.011586 +0.011549 +0.011532 +0.011591 +0.011702 +0.011688 +0.011727 +0.011689 +0.011673 +0.011723 +0.011836 +0.011821 +0.01186 +0.01181 +0.011786 +0.011847 +0.01195 +0.011937 +0.012003 +0.011956 +0.011938 +0.011995 +0.012108 +0.012089 +0.012131 +0.012083 +0.012061 +0.012125 +0.012235 +0.012216 +0.012255 +0.012215 +0.012186 +0.01226 +0.012362 +0.012344 +0.012392 +0.012341 +0.012323 +0.012386 +0.012502 +0.012486 +0.012527 +0.012486 +0.012458 +0.012528 +0.012652 +0.012625 +0.012671 +0.01263 +0.012603 +0.012675 +0.012791 +0.012773 +0.012819 +0.012766 +0.012747 +0.012817 +0.012936 +0.012914 +0.01296 +0.012913 +0.012886 +0.012958 +0.013075 +0.013052 +0.013098 +0.013054 +0.013022 +0.013098 +0.013212 +0.013196 +0.013242 +0.013199 +0.013172 +0.013255 +0.013379 +0.013379 +0.013427 +0.01338 +0.013364 +0.013436 +0.01356 +0.013538 +0.013578 +0.013535 +0.013518 +0.013601 +0.013727 +0.013689 +0.013736 +0.013686 +0.013657 +0.013736 +0.013858 +0.013821 +0.013872 +0.01383 +0.013813 +0.013924 +0.014047 +0.014003 +0.014082 +0.014007 +0.01397 +0.013991 +0.014109 +0.014022 +0.014004 +0.013894 +0.013783 +0.013615 +0.013563 +0.013478 +0.013422 +0.013279 +0.01313 +0.012973 +0.013017 +0.012928 +0.012892 +0.012776 +0.012588 +0.012542 +0.012579 +0.012515 +0.01247 +0.012373 +0.012185 +0.01219 +0.012235 +0.012176 +0.012143 +0.012058 +0.011933 +0.01192 +0.011998 +0.011924 +0.011957 +0.011876 +0.011844 +0.011898 +0.011958 +0.011914 +0.011947 +0.011881 +0.011859 +0.011915 +0.012014 +0.011992 +0.01205 +0.012012 +0.011991 +0.012061 +0.01218 +0.012163 +0.000999 +0.012199 +0.01217 +0.012155 +0.012226 +0.012349 +0.012315 +0.012357 +0.012302 +0.012277 +0.012345 +0.012453 +0.012402 +0.01244 +0.012386 +0.012358 +0.012417 +0.012545 +0.01254 +0.012643 +0.012597 +0.01257 +0.012634 +0.012753 +0.012709 +0.012787 +0.012737 +0.012688 +0.012712 +0.012779 +0.012673 +0.012658 +0.01252 +0.012393 +0.012356 +0.012384 +0.012274 +0.012256 +0.012128 +0.012038 +0.012015 +0.012052 +0.011958 +0.011948 +0.011841 +0.01178 +0.011782 +0.01184 +0.011774 +0.011782 +0.011694 +0.011638 +0.011659 +0.011729 +0.011664 +0.011703 +0.011629 +0.011592 +0.011642 +0.011735 +0.011694 +0.011745 +0.011706 +0.011693 +0.011752 +0.011857 +0.011837 +0.011862 +0.011832 +0.011826 +0.001 +0.01189 +0.011994 +0.011976 +0.012008 +0.011969 +0.011949 +0.012023 +0.012134 +0.012109 +0.012154 +0.012107 +0.012086 +0.012164 +0.012269 +0.012264 +0.0123 +0.012281 +0.012256 +0.012333 +0.012467 +0.012439 +0.01245 +0.012248 +0.012165 +0.012177 +0.012228 +0.012138 +0.012069 +0.011939 +0.011873 +0.011837 +0.011867 +0.011786 +0.011787 +0.011703 +0.011642 +0.011548 +0.011598 +0.011522 +0.011551 +0.01146 +0.011422 +0.011435 +0.011517 +0.011394 +0.011362 +0.011279 +0.011233 +0.011238 +0.011296 +0.011261 +0.011279 +0.01123 +0.011198 +0.011214 +0.011269 +0.01122 +0.011283 +0.011237 +0.011222 +0.011294 +0.011378 +0.011355 +0.01141 +0.011369 +0.011342 +0.011382 +0.011458 +0.001001 +0.01143 +0.011502 +0.011445 +0.011452 +0.011514 +0.011627 +0.011597 +0.011649 +0.011601 +0.01158 +0.011629 +0.011733 +0.011707 +0.011745 +0.011699 +0.011684 +0.011779 +0.011912 +0.011883 +0.011923 +0.011866 +0.011849 +0.011896 +0.012037 +0.012012 +0.012052 +0.011984 +0.011926 +0.011925 +0.01197 +0.011871 +0.011834 +0.01169 +0.011592 +0.011562 +0.011597 +0.011507 +0.011486 +0.011368 +0.01129 +0.01128 +0.011327 +0.011253 +0.011247 +0.011151 +0.011101 +0.011104 +0.011171 +0.011116 +0.011127 +0.011049 +0.010996 +0.01102 +0.011086 +0.011044 +0.011076 +0.011006 +0.010973 +0.011013 +0.011103 +0.011067 +0.011115 +0.011067 +0.011044 +0.011105 +0.011206 +0.011186 +0.011236 +0.011197 +0.011157 +0.011234 +0.001002 +0.011339 +0.011308 +0.011356 +0.011317 +0.011295 +0.011361 +0.011469 +0.011438 +0.011483 +0.011447 +0.011423 +0.011483 +0.011594 +0.01158 +0.011615 +0.01159 +0.011565 +0.011637 +0.011753 +0.011727 +0.011781 +0.011751 +0.01174 +0.011726 +0.011726 +0.011653 +0.01166 +0.011565 +0.0115 +0.011521 +0.011518 +0.011387 +0.011369 +0.011279 +0.011176 +0.011156 +0.011222 +0.011155 +0.011145 +0.011081 +0.011008 +0.010958 +0.011011 +0.010957 +0.010976 +0.010901 +0.010871 +0.010897 +0.010995 +0.010932 +0.010959 +0.010874 +0.010764 +0.01081 +0.010888 +0.010867 +0.010884 +0.010846 +0.01083 +0.010888 +0.011007 +0.01098 +0.011002 +0.010978 +0.010948 +0.011027 +0.011111 +0.01107 +0.001003 +0.011116 +0.011079 +0.011068 +0.011072 +0.011171 +0.011143 +0.011202 +0.01116 +0.011154 +0.011215 +0.011324 +0.011296 +0.011328 +0.011284 +0.011279 +0.011359 +0.011475 +0.011444 +0.011473 +0.011444 +0.011448 +0.011485 +0.011591 +0.01158 +0.011626 +0.011576 +0.011563 +0.011596 +0.011675 +0.011607 +0.011592 +0.011485 +0.011408 +0.011384 +0.011412 +0.011317 +0.011288 +0.011166 +0.011092 +0.011072 +0.01112 +0.011033 +0.011033 +0.010924 +0.010873 +0.010876 +0.010949 +0.010888 +0.010897 +0.010818 +0.010783 +0.010797 +0.010887 +0.010823 +0.010843 +0.01078 +0.010756 +0.010785 +0.010885 +0.010855 +0.010881 +0.01083 +0.010831 +0.010871 +0.010983 +0.010956 +0.011001 +0.010952 +0.010942 +0.010993 +0.001004 +0.011097 +0.011082 +0.011116 +0.011087 +0.011066 +0.011122 +0.011228 +0.011205 +0.011252 +0.011206 +0.011191 +0.011241 +0.011348 +0.011336 +0.011369 +0.011325 +0.011314 +0.011378 +0.011489 +0.011478 +0.011511 +0.011474 +0.011468 +0.011547 +0.01166 +0.011626 +0.011587 +0.011469 +0.011412 +0.011453 +0.011504 +0.011421 +0.01133 +0.011237 +0.011182 +0.011206 +0.011248 +0.011184 +0.011149 +0.011061 +0.010989 +0.010997 +0.011047 +0.010986 +0.011009 +0.010949 +0.010903 +0.010916 +0.010942 +0.01091 +0.010926 +0.010881 +0.01083 +0.010854 +0.01091 +0.010863 +0.010909 +0.010861 +0.010816 +0.01085 +0.010915 +0.010887 +0.010947 +0.010901 +0.010884 +0.010946 +0.011037 +0.011029 +0.011066 +0.011026 +0.011021 +0.001005 +0.011069 +0.011166 +0.011148 +0.011196 +0.011158 +0.011096 +0.011123 +0.011228 +0.011213 +0.011261 +0.011228 +0.011204 +0.011261 +0.011362 +0.011352 +0.011424 +0.011397 +0.011365 +0.011417 +0.011517 +0.011507 +0.011559 +0.011516 +0.01149 +0.011563 +0.011656 +0.011652 +0.011668 +0.011595 +0.011541 +0.011534 +0.011558 +0.011485 +0.011437 +0.011308 +0.011228 +0.011201 +0.011232 +0.011172 +0.011148 +0.01104 +0.010967 +0.010975 +0.011012 +0.010964 +0.010965 +0.010882 +0.010821 +0.010844 +0.010903 +0.010869 +0.010877 +0.010801 +0.010751 +0.010777 +0.010841 +0.010819 +0.010837 +0.01078 +0.010732 +0.010766 +0.010846 +0.010839 +0.010868 +0.01082 +0.010804 +0.010857 +0.010943 +0.01094 +0.010976 +0.010955 +0.010915 +0.010976 +0.001006 +0.011072 +0.011044 +0.011103 +0.011064 +0.011044 +0.011097 +0.011203 +0.011179 +0.01123 +0.011185 +0.011172 +0.011222 +0.011326 +0.011305 +0.011348 +0.011302 +0.011298 +0.01135 +0.011454 +0.011436 +0.011482 +0.011433 +0.011417 +0.01147 +0.011586 +0.011557 +0.011605 +0.011557 +0.011538 +0.011599 +0.011712 +0.011687 +0.011727 +0.011682 +0.011665 +0.011727 +0.011837 +0.011797 +0.011846 +0.011797 +0.011784 +0.011855 +0.011961 +0.011929 +0.011972 +0.011925 +0.011909 +0.011977 +0.012091 +0.012042 +0.012092 +0.012047 +0.012037 +0.012103 +0.012219 +0.01218 +0.012231 +0.012186 +0.012171 +0.012244 +0.012358 +0.012326 +0.012376 +0.012333 +0.01232 +0.012382 +0.01251 +0.012472 +0.012523 +0.012473 +0.012461 +0.012533 +0.012651 +0.012614 +0.012665 +0.012615 +0.012599 +0.012665 +0.012791 +0.012756 +0.012805 +0.012762 +0.012739 +0.012815 +0.012943 +0.012909 +0.01296 +0.012915 +0.012899 +0.012974 +0.013095 +0.01305 +0.013105 +0.01305 +0.013044 +0.013113 +0.013239 +0.013198 +0.013252 +0.013198 +0.013184 +0.013262 +0.013381 +0.013347 +0.013405 +0.013352 +0.013343 +0.013415 +0.013552 +0.013513 +0.013572 +0.013519 +0.01351 +0.013583 +0.013716 +0.013682 +0.013747 +0.013686 +0.013674 +0.013743 +0.013878 +0.013848 +0.013905 +0.013848 +0.013832 +0.013907 +0.014036 +0.014003 +0.014058 +0.014011 +0.013989 +0.014064 +0.014198 +0.014162 +0.014219 +0.014164 +0.014135 +0.014217 +0.014365 +0.014333 +0.014386 +0.014332 +0.014307 +0.014403 +0.014541 +0.014513 +0.014574 +0.014538 +0.014523 +0.014593 +0.014749 +0.014725 +0.014786 +0.014726 +0.014706 +0.014806 +0.014958 +0.014902 +0.014962 +0.014893 +0.014859 +0.014879 +0.015038 +0.015011 +0.015091 +0.015042 +0.015044 +0.015141 +0.015287 +0.015273 +0.015347 +0.015308 +0.015296 +0.015374 +0.015546 +0.015525 +0.015582 +0.01556 +0.01543 +0.015329 +0.015366 +0.015172 +0.01502 +0.014531 +0.014219 +0.013908 +0.013745 +0.013479 +0.013143 +0.012878 +0.012623 +0.012399 +0.012369 +0.012166 +0.011945 +0.01174 +0.011599 +0.011447 +0.011394 +0.011266 +0.011209 +0.011001 +0.010838 +0.010767 +0.010799 +0.010677 +0.010637 +0.010491 +0.010412 +0.010401 +0.010453 +0.010374 +0.010393 +0.010348 +0.010319 +0.010307 +0.010391 +0.010358 +0.010408 +0.010371 +0.010361 +0.010412 +0.010518 +0.01049 +0.010536 +0.010496 +0.010489 +0.010545 +0.010643 +0.010619 +0.001007 +0.010654 +0.010609 +0.010589 +0.010643 +0.010758 +0.010746 +0.010788 +0.010741 +0.010733 +0.010779 +0.010879 +0.010868 +0.01092 +0.010854 +0.010859 +0.010898 +0.011002 +0.010949 +0.010943 +0.010833 +0.010753 +0.010704 +0.010736 +0.010604 +0.010546 +0.010407 +0.01031 +0.010269 +0.010286 +0.010188 +0.010139 +0.01002 +0.009946 +0.009916 +0.009954 +0.009872 +0.009844 +0.009746 +0.009669 +0.009661 +0.00972 +0.009648 +0.009639 +0.00956 +0.009508 +0.00951 +0.009584 +0.009535 +0.009551 +0.009498 +0.009464 +0.009481 +0.009578 +0.009562 +0.009593 +0.009563 +0.00954 +0.009589 +0.009671 +0.009649 +0.009678 +0.009652 +0.009641 +0.009689 +0.009782 +0.009761 +0.001008 +0.009791 +0.009747 +0.009729 +0.009774 +0.009875 +0.009859 +0.009898 +0.009852 +0.009848 +0.009894 +0.009991 +0.009979 +0.010016 +0.009979 +0.009983 +0.010045 +0.010127 +0.010009 +0.009945 +0.00985 +0.009784 +0.009708 +0.009713 +0.009637 +0.0096 +0.0095 +0.009421 +0.009324 +0.009363 +0.009292 +0.009272 +0.009175 +0.009058 +0.009018 +0.00908 +0.009005 +0.009025 +0.008917 +0.00883 +0.008812 +0.008865 +0.008808 +0.008814 +0.008764 +0.008716 +0.008708 +0.008718 +0.008667 +0.008699 +0.008642 +0.008628 +0.008647 +0.0087 +0.008661 +0.008681 +0.00863 +0.008617 +0.008625 +0.008709 +0.008683 +0.008715 +0.008677 +0.00868 +0.008725 +0.008814 +0.008782 +0.008822 +0.008803 +0.008756 +0.008821 +0.008909 +0.001009 +0.008888 +0.008921 +0.008881 +0.008867 +0.008904 +0.008988 +0.008964 +0.008995 +0.008956 +0.008944 +0.008969 +0.009069 +0.009064 +0.009101 +0.009059 +0.009046 +0.009079 +0.009162 +0.009153 +0.0092 +0.009141 +0.009126 +0.009139 +0.009202 +0.009132 +0.009104 +0.009008 +0.008939 +0.008895 +0.008926 +0.008846 +0.008808 +0.008709 +0.008641 +0.008624 +0.008655 +0.008591 +0.008572 +0.008479 +0.008426 +0.008405 +0.008459 +0.008406 +0.008408 +0.008344 +0.008307 +0.008307 +0.008364 +0.008321 +0.008343 +0.008294 +0.008273 +0.008282 +0.008355 +0.008328 +0.008357 +0.008325 +0.008316 +0.008343 +0.008433 +0.008405 +0.00844 +0.008391 +0.008384 +0.008423 +0.008518 +0.008496 +0.008521 +0.008484 +0.00101 +0.008465 +0.008507 +0.008583 +0.00857 +0.008595 +0.00857 +0.008556 +0.008602 +0.008679 +0.008668 +0.00869 +0.008657 +0.008632 +0.008693 +0.008766 +0.008756 +0.008789 +0.008764 +0.008741 +0.008807 +0.008858 +0.008801 +0.008818 +0.008772 +0.008718 +0.008685 +0.008709 +0.008646 +0.008644 +0.008568 +0.008464 +0.008417 +0.008447 +0.008393 +0.008386 +0.008317 +0.008278 +0.008277 +0.008258 +0.008188 +0.008179 +0.008147 +0.00809 +0.008097 +0.008105 +0.008068 +0.008068 +0.008038 +0.008005 +0.008044 +0.008096 +0.008075 +0.00807 +0.008009 +0.008003 +0.00804 +0.008121 +0.008082 +0.008108 +0.008089 +0.008074 +0.008121 +0.008192 +0.008176 +0.008199 +0.008182 +0.008138 +0.008176 +0.008244 +0.001011 +0.008206 +0.008251 +0.008225 +0.008211 +0.008249 +0.008331 +0.008306 +0.008341 +0.008307 +0.008298 +0.008334 +0.008423 +0.008382 +0.008421 +0.008385 +0.008371 +0.008403 +0.008486 +0.008465 +0.00851 +0.00848 +0.008469 +0.008502 +0.008583 +0.008555 +0.008598 +0.008562 +0.008553 +0.008583 +0.008665 +0.008626 +0.008638 +0.008575 +0.008521 +0.008501 +0.008542 +0.008469 +0.008452 +0.008366 +0.008302 +0.008281 +0.008323 +0.008252 +0.008245 +0.008173 +0.008126 +0.008116 +0.00817 +0.008107 +0.008107 +0.008045 +0.008009 +0.008008 +0.00808 +0.008025 +0.008043 +0.007994 +0.007968 +0.007979 +0.008047 +0.00802 +0.008033 +0.007995 +0.007975 +0.007998 +0.008079 +0.008053 +0.008086 +0.008051 +0.00804 +0.008075 +0.00815 +0.008132 +0.008164 +0.008133 +0.00811 +0.008158 +0.001012 +0.008229 +0.008214 +0.008236 +0.008208 +0.008195 +0.008234 +0.008308 +0.008297 +0.008314 +0.008287 +0.008274 +0.008319 +0.008394 +0.008383 +0.008408 +0.008377 +0.008355 +0.008398 +0.008474 +0.008452 +0.008489 +0.008455 +0.00845 +0.008499 +0.008573 +0.008559 +0.008591 +0.008534 +0.008479 +0.008497 +0.008544 +0.008497 +0.00849 +0.008423 +0.008371 +0.008316 +0.008307 +0.008254 +0.008248 +0.00818 +0.00812 +0.008133 +0.008104 +0.008048 +0.008051 +0.008003 +0.007967 +0.007946 +0.007975 +0.007921 +0.00793 +0.007886 +0.007866 +0.007892 +0.007968 +0.007923 +0.007939 +0.007862 +0.007847 +0.007866 +0.007925 +0.007919 +0.007926 +0.007906 +0.007886 +0.007929 +0.007995 +0.00797 +0.007988 +0.007968 +0.007959 +0.008005 +0.008074 +0.008062 +0.008069 +0.008039 +0.001013 +0.008024 +0.008049 +0.008118 +0.008095 +0.008132 +0.008099 +0.008089 +0.008129 +0.008207 +0.008181 +0.008212 +0.008179 +0.008162 +0.0082 +0.008278 +0.008256 +0.008299 +0.008275 +0.008266 +0.0083 +0.008381 +0.008353 +0.008387 +0.008341 +0.008333 +0.00838 +0.008445 +0.008438 +0.008471 +0.008422 +0.008408 +0.008414 +0.008454 +0.0084 +0.008386 +0.0083 +0.008257 +0.008233 +0.008257 +0.008201 +0.008184 +0.008097 +0.008054 +0.008051 +0.008098 +0.008031 +0.008032 +0.007964 +0.007935 +0.007934 +0.007981 +0.007951 +0.007967 +0.007907 +0.007886 +0.007902 +0.007954 +0.007927 +0.007955 +0.007909 +0.0079 +0.007921 +0.00799 +0.007975 +0.007996 +0.007958 +0.007959 +0.007991 +0.008075 +0.008048 +0.008088 +0.00803 +0.008024 +0.008061 +0.001014 +0.00813 +0.008123 +0.008152 +0.008121 +0.008105 +0.008147 +0.008217 +0.008201 +0.008225 +0.008197 +0.008183 +0.008228 +0.008301 +0.008288 +0.008309 +0.008282 +0.008262 +0.008304 +0.008373 +0.008364 +0.008386 +0.008362 +0.008347 +0.008402 +0.008479 +0.008455 +0.008483 +0.008467 +0.008448 +0.008438 +0.008437 +0.00838 +0.008389 +0.008313 +0.008272 +0.00829 +0.008261 +0.008185 +0.008179 +0.008101 +0.008047 +0.008038 +0.008062 +0.008016 +0.008022 +0.007966 +0.007932 +0.007913 +0.007948 +0.007903 +0.007914 +0.007867 +0.007854 +0.007871 +0.007952 +0.007903 +0.007909 +0.007847 +0.007831 +0.007875 +0.007925 +0.007911 +0.007926 +0.007904 +0.007886 +0.007926 +0.007983 +0.007953 +0.007975 +0.007959 +0.007946 +0.007987 +0.00807 +0.008034 +0.008063 +0.001015 +0.008042 +0.008019 +0.008076 +0.008135 +0.008119 +0.008142 +0.008122 +0.008099 +0.008149 +0.008203 +0.008179 +0.008199 +0.00818 +0.008152 +0.008205 +0.008265 +0.008249 +0.008261 +0.008244 +0.008215 +0.008267 +0.008333 +0.008349 +0.008375 +0.008357 +0.008329 +0.008378 +0.008439 +0.008432 +0.008447 +0.008426 +0.0084 +0.008451 +0.008496 +0.008465 +0.008439 +0.008389 +0.008321 +0.008327 +0.008339 +0.008282 +0.008261 +0.008184 +0.008116 +0.008126 +0.008156 +0.008112 +0.008095 +0.008043 +0.007986 +0.008006 +0.00804 +0.008009 +0.008012 +0.007967 +0.007925 +0.007954 +0.007999 +0.00798 +0.007987 +0.007958 +0.007924 +0.007966 +0.008021 +0.008007 +0.008023 +0.008001 +0.007978 +0.008035 +0.008092 +0.008086 +0.008103 +0.008077 +0.008048 +0.008088 +0.008161 +0.001016 +0.008157 +0.008182 +0.008152 +0.008137 +0.008171 +0.008246 +0.008233 +0.008258 +0.008229 +0.008207 +0.008256 +0.008333 +0.008316 +0.008342 +0.008309 +0.008288 +0.008341 +0.008407 +0.008394 +0.008422 +0.008385 +0.008381 +0.008428 +0.008504 +0.008498 +0.008518 +0.008489 +0.008479 +0.008509 +0.008531 +0.008487 +0.008486 +0.008441 +0.008401 +0.0084 +0.008461 +0.008365 +0.008305 +0.008254 +0.008206 +0.008224 +0.008255 +0.008203 +0.008209 +0.008125 +0.008089 +0.008086 +0.00814 +0.008096 +0.008098 +0.008048 +0.008026 +0.008054 +0.008126 +0.008067 +0.00807 +0.00802 +0.008001 +0.008045 +0.008097 +0.008078 +0.008094 +0.008068 +0.008051 +0.008068 +0.008134 +0.00811 +0.00813 +0.008115 +0.008097 +0.008144 +0.008214 +0.008217 +0.00822 +0.008182 +0.008189 +0.001017 +0.008224 +0.008309 +0.008282 +0.008317 +0.008277 +0.008271 +0.008309 +0.008388 +0.008367 +0.008394 +0.008355 +0.008342 +0.008373 +0.008449 +0.008422 +0.008455 +0.008413 +0.008404 +0.008438 +0.008542 +0.00853 +0.008558 +0.008523 +0.00851 +0.00855 +0.008631 +0.00861 +0.008629 +0.008587 +0.008564 +0.008567 +0.008609 +0.008543 +0.008532 +0.008443 +0.008385 +0.008361 +0.008396 +0.008329 +0.008322 +0.008242 +0.008189 +0.008184 +0.008234 +0.008184 +0.008171 +0.008116 +0.00808 +0.008081 +0.008142 +0.008094 +0.008104 +0.008056 +0.008036 +0.008046 +0.008117 +0.00808 +0.008095 +0.008055 +0.008043 +0.008066 +0.008148 +0.00812 +0.008146 +0.008108 +0.0081 +0.008133 +0.008224 +0.008195 +0.008232 +0.008185 +0.008168 +0.008212 +0.001018 +0.008291 +0.00828 +0.0083 +0.008266 +0.008256 +0.008305 +0.008368 +0.008359 +0.008379 +0.008349 +0.00833 +0.008378 +0.008455 +0.008447 +0.008452 +0.008426 +0.008415 +0.008453 +0.008537 +0.008522 +0.008553 +0.008517 +0.008512 +0.008558 +0.008632 +0.008636 +0.008645 +0.008631 +0.008591 +0.008544 +0.008581 +0.008528 +0.00853 +0.008475 +0.008427 +0.008444 +0.008481 +0.008356 +0.00833 +0.008273 +0.008217 +0.008238 +0.008251 +0.008201 +0.008209 +0.008154 +0.008126 +0.008097 +0.008146 +0.008091 +0.008119 +0.008076 +0.008057 +0.008083 +0.008151 +0.008114 +0.008131 +0.008106 +0.008075 +0.008095 +0.008132 +0.008104 +0.008134 +0.008115 +0.008083 +0.008143 +0.008206 +0.008191 +0.008224 +0.008201 +0.008168 +0.008224 +0.008307 +0.008296 +0.008299 +0.001019 +0.00827 +0.008268 +0.008308 +0.008393 +0.008366 +0.0084 +0.008359 +0.008359 +0.00839 +0.008478 +0.00844 +0.008468 +0.008422 +0.008405 +0.008436 +0.008513 +0.008474 +0.008509 +0.00847 +0.008469 +0.008493 +0.008576 +0.008592 +0.008641 +0.008607 +0.00859 +0.008622 +0.008692 +0.008653 +0.008662 +0.008578 +0.008541 +0.008542 +0.008588 +0.008515 +0.008489 +0.008403 +0.008356 +0.00835 +0.008384 +0.008325 +0.008325 +0.00825 +0.008214 +0.008216 +0.008261 +0.008213 +0.008233 +0.008168 +0.008146 +0.008152 +0.008217 +0.008188 +0.008208 +0.00816 +0.008158 +0.008164 +0.008242 +0.008218 +0.008242 +0.008202 +0.008198 +0.008234 +0.008311 +0.008293 +0.008318 +0.008282 +0.008261 +0.008304 +0.008392 +0.00102 +0.008364 +0.008401 +0.008363 +0.008358 +0.008392 +0.008479 +0.008453 +0.008482 +0.00844 +0.008428 +0.008465 +0.008552 +0.008535 +0.008566 +0.008527 +0.008519 +0.008555 +0.008642 +0.008624 +0.008651 +0.008621 +0.008605 +0.008661 +0.008747 +0.008718 +0.008761 +0.00873 +0.008724 +0.008709 +0.008721 +0.008663 +0.008675 +0.008619 +0.008578 +0.00859 +0.008647 +0.008572 +0.008497 +0.008437 +0.008396 +0.008409 +0.008474 +0.008401 +0.008366 +0.008316 +0.008264 +0.008299 +0.008341 +0.008291 +0.008299 +0.008253 +0.008196 +0.008217 +0.008268 +0.008241 +0.008262 +0.008219 +0.008208 +0.008236 +0.008314 +0.008271 +0.008302 +0.008276 +0.008264 +0.008288 +0.008355 +0.008308 +0.008348 +0.008317 +0.008304 +0.00835 +0.008442 +0.008421 +0.008428 +0.001021 +0.008401 +0.008401 +0.008439 +0.008522 +0.008489 +0.00853 +0.008496 +0.008488 +0.008529 +0.008619 +0.008563 +0.008601 +0.008558 +0.008546 +0.008578 +0.008662 +0.008634 +0.008661 +0.008611 +0.008602 +0.008642 +0.008739 +0.008745 +0.00879 +0.008742 +0.008714 +0.008747 +0.008806 +0.008755 +0.008759 +0.008683 +0.008615 +0.008603 +0.008639 +0.00857 +0.008554 +0.008467 +0.008417 +0.008414 +0.008445 +0.00839 +0.008403 +0.008321 +0.008278 +0.008283 +0.008336 +0.008286 +0.008302 +0.008244 +0.008213 +0.008233 +0.008298 +0.008263 +0.008281 +0.00823 +0.008209 +0.008245 +0.008314 +0.008285 +0.008322 +0.008283 +0.00827 +0.008312 +0.008383 +0.008368 +0.008394 +0.008359 +0.00835 +0.008389 +0.001022 +0.008478 +0.008447 +0.008474 +0.008441 +0.008428 +0.00846 +0.008552 +0.008523 +0.008564 +0.008523 +0.008518 +0.008552 +0.008635 +0.008614 +0.008645 +0.008601 +0.008591 +0.008634 +0.008716 +0.008696 +0.00873 +0.0087 +0.008683 +0.008728 +0.008825 +0.008804 +0.008845 +0.008802 +0.008797 +0.008781 +0.008775 +0.008701 +0.008711 +0.008647 +0.008599 +0.008599 +0.008599 +0.008506 +0.008499 +0.008442 +0.00838 +0.00833 +0.008391 +0.008329 +0.008341 +0.008281 +0.00825 +0.008239 +0.00826 +0.0082 +0.008226 +0.00817 +0.00816 +0.008178 +0.008256 +0.008196 +0.008215 +0.008166 +0.008119 +0.008138 +0.008207 +0.00816 +0.008203 +0.00816 +0.008148 +0.008198 +0.008269 +0.008241 +0.008282 +0.008242 +0.00823 +0.00828 +0.008361 +0.008345 +0.008345 +0.001023 +0.008334 +0.00833 +0.008367 +0.008454 +0.008404 +0.008436 +0.008387 +0.008384 +0.008414 +0.008495 +0.008454 +0.008488 +0.008449 +0.00844 +0.008473 +0.008557 +0.008536 +0.008573 +0.008548 +0.008556 +0.008596 +0.008682 +0.008651 +0.008688 +0.008638 +0.008621 +0.008641 +0.008717 +0.00866 +0.008655 +0.008554 +0.008497 +0.008482 +0.008509 +0.008429 +0.008416 +0.008325 +0.008271 +0.008269 +0.008301 +0.008247 +0.008245 +0.008169 +0.008127 +0.008134 +0.008183 +0.008136 +0.008141 +0.008084 +0.008057 +0.008078 +0.008139 +0.008105 +0.008124 +0.008078 +0.008058 +0.008087 +0.008156 +0.008129 +0.008167 +0.008129 +0.008114 +0.008152 +0.008226 +0.00821 +0.008237 +0.008214 +0.008181 +0.008233 +0.001024 +0.00831 +0.00829 +0.008327 +0.008272 +0.008266 +0.008308 +0.008391 +0.008369 +0.008401 +0.008363 +0.008355 +0.008392 +0.008473 +0.008451 +0.008483 +0.008447 +0.008432 +0.008468 +0.008554 +0.008537 +0.008566 +0.008538 +0.00852 +0.008571 +0.008656 +0.008631 +0.008679 +0.008649 +0.008636 +0.00861 +0.008639 +0.008585 +0.0086 +0.008529 +0.008488 +0.008495 +0.008541 +0.008478 +0.008372 +0.008289 +0.008248 +0.008265 +0.008309 +0.008255 +0.00826 +0.008157 +0.008101 +0.008097 +0.008164 +0.008102 +0.008123 +0.008065 +0.008049 +0.008069 +0.008107 +0.008068 +0.008082 +0.008051 +0.00802 +0.008036 +0.008088 +0.008049 +0.008087 +0.008041 +0.008039 +0.008077 +0.008149 +0.008124 +0.008154 +0.008116 +0.008112 +0.008151 +0.008235 +0.008221 +0.008218 +0.008209 +0.001025 +0.008203 +0.00824 +0.00831 +0.008271 +0.008305 +0.008275 +0.008266 +0.008281 +0.008355 +0.008322 +0.008355 +0.008324 +0.008312 +0.008353 +0.008427 +0.008407 +0.008441 +0.008427 +0.008427 +0.008464 +0.008545 +0.008514 +0.008555 +0.008507 +0.008495 +0.00853 +0.008616 +0.008598 +0.008627 +0.008564 +0.008525 +0.008526 +0.008571 +0.0085 +0.008489 +0.008407 +0.008353 +0.008341 +0.008387 +0.008323 +0.008325 +0.008254 +0.008209 +0.008217 +0.008273 +0.008209 +0.008227 +0.008164 +0.008132 +0.008142 +0.008203 +0.008158 +0.008184 +0.008136 +0.008111 +0.008135 +0.008209 +0.008171 +0.008202 +0.00816 +0.008152 +0.008188 +0.008273 +0.008228 +0.008279 +0.008222 +0.008223 +0.00826 +0.008345 +0.008332 +0.008339 +0.001026 +0.008306 +0.008308 +0.008342 +0.008431 +0.0084 +0.008439 +0.008393 +0.00838 +0.008412 +0.008496 +0.008475 +0.008513 +0.008475 +0.008467 +0.008501 +0.008587 +0.00857 +0.008596 +0.008563 +0.008555 +0.008595 +0.008686 +0.008664 +0.008695 +0.00867 +0.008674 +0.008699 +0.008751 +0.008685 +0.008711 +0.008659 +0.008622 +0.00863 +0.008688 +0.008584 +0.008553 +0.008478 +0.008428 +0.008411 +0.008443 +0.008381 +0.008396 +0.008321 +0.008298 +0.008304 +0.008307 +0.008263 +0.008259 +0.008222 +0.00818 +0.008211 +0.008256 +0.008211 +0.008228 +0.00819 +0.00817 +0.008164 +0.008234 +0.008182 +0.008221 +0.008174 +0.008159 +0.008205 +0.008278 +0.008243 +0.008283 +0.008242 +0.008228 +0.008279 +0.008352 +0.008322 +0.008379 +0.008319 +0.008294 +0.001027 +0.008312 +0.008389 +0.008366 +0.008389 +0.008366 +0.008354 +0.008404 +0.008481 +0.008465 +0.008495 +0.008464 +0.008441 +0.008486 +0.008562 +0.008562 +0.008585 +0.008562 +0.008542 +0.008584 +0.008661 +0.008637 +0.008668 +0.008633 +0.008626 +0.008667 +0.008747 +0.00872 +0.008713 +0.008664 +0.008612 +0.008608 +0.008644 +0.008587 +0.008576 +0.008504 +0.00845 +0.008445 +0.008495 +0.008443 +0.008438 +0.008381 +0.008334 +0.008344 +0.0084 +0.008357 +0.008355 +0.008309 +0.008265 +0.008284 +0.008346 +0.008312 +0.008316 +0.008285 +0.008244 +0.008273 +0.008342 +0.008316 +0.008339 +0.008308 +0.008286 +0.008321 +0.0084 +0.008383 +0.008414 +0.008373 +0.008362 +0.008413 +0.008478 +0.008471 +0.008486 +0.001028 +0.008447 +0.008452 +0.008487 +0.008573 +0.008549 +0.008579 +0.008534 +0.008524 +0.008559 +0.008648 +0.008631 +0.00866 +0.008619 +0.008612 +0.008654 +0.008733 +0.008723 +0.008759 +0.008714 +0.00871 +0.008763 +0.008847 +0.008818 +0.008874 +0.008838 +0.008772 +0.008751 +0.008803 +0.008762 +0.008775 +0.008695 +0.008657 +0.008667 +0.008716 +0.008643 +0.008537 +0.008445 +0.008418 +0.00841 +0.008482 +0.00841 +0.008414 +0.008368 +0.008299 +0.008269 +0.008299 +0.00826 +0.008277 +0.008238 +0.008208 +0.00823 +0.008307 +0.008252 +0.008287 +0.008253 +0.008224 +0.008237 +0.008279 +0.008236 +0.00828 +0.008241 +0.008235 +0.008283 +0.008356 +0.008329 +0.008366 +0.008327 +0.00831 +0.008366 +0.008446 +0.008434 +0.008444 +0.001029 +0.008416 +0.008412 +0.008447 +0.008531 +0.008502 +0.00854 +0.008504 +0.008495 +0.008516 +0.00858 +0.008545 +0.008573 +0.008538 +0.008527 +0.008563 +0.008646 +0.008633 +0.008673 +0.008659 +0.008658 +0.00869 +0.008768 +0.008754 +0.008774 +0.008731 +0.008716 +0.008739 +0.00881 +0.008768 +0.008764 +0.00867 +0.00864 +0.008625 +0.008659 +0.008595 +0.008589 +0.008512 +0.008475 +0.008459 +0.008511 +0.008459 +0.008467 +0.008395 +0.008378 +0.008376 +0.008436 +0.008394 +0.008398 +0.008354 +0.008343 +0.008358 +0.008425 +0.008386 +0.008393 +0.008337 +0.008319 +0.008345 +0.008433 +0.008407 +0.008433 +0.00839 +0.008381 +0.008419 +0.008511 +0.008484 +0.008515 +0.008484 +0.008451 +0.00849 +0.008576 +0.00103 +0.008553 +0.008607 +0.008554 +0.008546 +0.00858 +0.008669 +0.008646 +0.008681 +0.008634 +0.008633 +0.00867 +0.008758 +0.008733 +0.008764 +0.008728 +0.008719 +0.00876 +0.008848 +0.00883 +0.008869 +0.008828 +0.008825 +0.008875 +0.008971 +0.008929 +0.00887 +0.008792 +0.008753 +0.008769 +0.008822 +0.008747 +0.008701 +0.008583 +0.008533 +0.008525 +0.008558 +0.008489 +0.008495 +0.008388 +0.008346 +0.008325 +0.008367 +0.008327 +0.008318 +0.008278 +0.008234 +0.008254 +0.008273 +0.00824 +0.008251 +0.008218 +0.008193 +0.00822 +0.008271 +0.008226 +0.008257 +0.008215 +0.008217 +0.008236 +0.008309 +0.008271 +0.008298 +0.008276 +0.008259 +0.008301 +0.008395 +0.008361 +0.008391 +0.008385 +0.008349 +0.008381 +0.001031 +0.008473 +0.008436 +0.008488 +0.008437 +0.008435 +0.008444 +0.008515 +0.008482 +0.008529 +0.008471 +0.00847 +0.008509 +0.008592 +0.008579 +0.008643 +0.008609 +0.008594 +0.008622 +0.008712 +0.008683 +0.008724 +0.008687 +0.008682 +0.0087 +0.008762 +0.008708 +0.008695 +0.008608 +0.008564 +0.008543 +0.008569 +0.008499 +0.008489 +0.008397 +0.008348 +0.008335 +0.008369 +0.00832 +0.008322 +0.008242 +0.008213 +0.008217 +0.008266 +0.00822 +0.008224 +0.008171 +0.008146 +0.008173 +0.008236 +0.008202 +0.008219 +0.008158 +0.008138 +0.008157 +0.008235 +0.00822 +0.008258 +0.008215 +0.008203 +0.008237 +0.008308 +0.008297 +0.008317 +0.008295 +0.008264 +0.008319 +0.008403 +0.001032 +0.008378 +0.008415 +0.008369 +0.008353 +0.008393 +0.008474 +0.008447 +0.008479 +0.008446 +0.008441 +0.008482 +0.008564 +0.008542 +0.008581 +0.008542 +0.008523 +0.008578 +0.008655 +0.008644 +0.008668 +0.008641 +0.008643 +0.008682 +0.008705 +0.008659 +0.00868 +0.008622 +0.008579 +0.008596 +0.008655 +0.008556 +0.00851 +0.008442 +0.008394 +0.00837 +0.0084 +0.008344 +0.008344 +0.008276 +0.008235 +0.008197 +0.008224 +0.008178 +0.008182 +0.00814 +0.008097 +0.008135 +0.008188 +0.008154 +0.008146 +0.008081 +0.008055 +0.008083 +0.008164 +0.008108 +0.008142 +0.008103 +0.008089 +0.008142 +0.008215 +0.008181 +0.008219 +0.008167 +0.00815 +0.008184 +0.008258 +0.008223 +0.008271 +0.008235 +0.008222 +0.001033 +0.008275 +0.00833 +0.008318 +0.008351 +0.008317 +0.008306 +0.008346 +0.008427 +0.008407 +0.008434 +0.008394 +0.008384 +0.008415 +0.008494 +0.008471 +0.008505 +0.008474 +0.008476 +0.008516 +0.008601 +0.008575 +0.008593 +0.00855 +0.00852 +0.008523 +0.008572 +0.008495 +0.008477 +0.008396 +0.008343 +0.008325 +0.008374 +0.008313 +0.008298 +0.008229 +0.008184 +0.008181 +0.008235 +0.008185 +0.008188 +0.008123 +0.008085 +0.008084 +0.008142 +0.008099 +0.008112 +0.008062 +0.008034 +0.008044 +0.008113 +0.008075 +0.008087 +0.008049 +0.008036 +0.00806 +0.008141 +0.008113 +0.008136 +0.0081 +0.008086 +0.008113 +0.008205 +0.008179 +0.008222 +0.008174 +0.008172 +0.008209 +0.001034 +0.008275 +0.008266 +0.008293 +0.008247 +0.008248 +0.008285 +0.008373 +0.008342 +0.008372 +0.008333 +0.008322 +0.008359 +0.008445 +0.00842 +0.008453 +0.00842 +0.008403 +0.008447 +0.008525 +0.008518 +0.008545 +0.00852 +0.008515 +0.008559 +0.008649 +0.008608 +0.008582 +0.008468 +0.008435 +0.008455 +0.008507 +0.008427 +0.00838 +0.008304 +0.008253 +0.008245 +0.008286 +0.008223 +0.008207 +0.008116 +0.008072 +0.008049 +0.008108 +0.008046 +0.008058 +0.007993 +0.007974 +0.007964 +0.008006 +0.00796 +0.007975 +0.007941 +0.007914 +0.007949 +0.008025 +0.007975 +0.008006 +0.007974 +0.007953 +0.007966 +0.008019 +0.00799 +0.008031 +0.007998 +0.007988 +0.00803 +0.008108 +0.008082 +0.008126 +0.00809 +0.008076 +0.008131 +0.008183 +0.001035 +0.008175 +0.008204 +0.008173 +0.008157 +0.008202 +0.008283 +0.008263 +0.008292 +0.008255 +0.008245 +0.008279 +0.008358 +0.008326 +0.008354 +0.00831 +0.008299 +0.008337 +0.008412 +0.008379 +0.00841 +0.008374 +0.008392 +0.008432 +0.008512 +0.008461 +0.008444 +0.008362 +0.0083 +0.008264 +0.008315 +0.008265 +0.008238 +0.00816 +0.008107 +0.008095 +0.008138 +0.008085 +0.008077 +0.008014 +0.007981 +0.007977 +0.008035 +0.007988 +0.007988 +0.007927 +0.007902 +0.007912 +0.007983 +0.007951 +0.007966 +0.00792 +0.007897 +0.007912 +0.007988 +0.00797 +0.007992 +0.007953 +0.00794 +0.007965 +0.008048 +0.008028 +0.008053 +0.008024 +0.008011 +0.008048 +0.008128 +0.008124 +0.008112 +0.001036 +0.008101 +0.008091 +0.008128 +0.0082 +0.008187 +0.008209 +0.008177 +0.008164 +0.008207 +0.008281 +0.008275 +0.008283 +0.00826 +0.008241 +0.008283 +0.008364 +0.008345 +0.008372 +0.008343 +0.008325 +0.00837 +0.008453 +0.008446 +0.00847 +0.008449 +0.008433 +0.008485 +0.008548 +0.00847 +0.008468 +0.00842 +0.008376 +0.008356 +0.008374 +0.008324 +0.008326 +0.008254 +0.008211 +0.008185 +0.008194 +0.008143 +0.008155 +0.008102 +0.008074 +0.008086 +0.008135 +0.008069 +0.00806 +0.008006 +0.007986 +0.007993 +0.008056 +0.008015 +0.008038 +0.008001 +0.007974 +0.008018 +0.008087 +0.008053 +0.008093 +0.008061 +0.008036 +0.008055 +0.008101 +0.008079 +0.008111 +0.008082 +0.00808 +0.008123 +0.008195 +0.008185 +0.008225 +0.008175 +0.008152 +0.001037 +0.008217 +0.008282 +0.008273 +0.008287 +0.008272 +0.008246 +0.008305 +0.008369 +0.008355 +0.008371 +0.008349 +0.008318 +0.008367 +0.008428 +0.008411 +0.008422 +0.008404 +0.008375 +0.008424 +0.0085 +0.008518 +0.008538 +0.008508 +0.008484 +0.008521 +0.008583 +0.008566 +0.008559 +0.008503 +0.008435 +0.008435 +0.008464 +0.008415 +0.008384 +0.008318 +0.008254 +0.008256 +0.008287 +0.008256 +0.008234 +0.008188 +0.008133 +0.008148 +0.008191 +0.008158 +0.008145 +0.008107 +0.008074 +0.008089 +0.008147 +0.008129 +0.008122 +0.008089 +0.00806 +0.008099 +0.008159 +0.00815 +0.008154 +0.008142 +0.008107 +0.008159 +0.008227 +0.008222 +0.00823 +0.008213 +0.008188 +0.008247 +0.008301 +0.008297 +0.001038 +0.008322 +0.008285 +0.008273 +0.008328 +0.008383 +0.008377 +0.008398 +0.008369 +0.008357 +0.008398 +0.008473 +0.008458 +0.00848 +0.008449 +0.008438 +0.008487 +0.008551 +0.008546 +0.008565 +0.008543 +0.008519 +0.008589 +0.008654 +0.008645 +0.008682 +0.008656 +0.008636 +0.008625 +0.008669 +0.008635 +0.008651 +0.008606 +0.008558 +0.008571 +0.00862 +0.008567 +0.008545 +0.008401 +0.008359 +0.008379 +0.008403 +0.008375 +0.008363 +0.008297 +0.008231 +0.00823 +0.008288 +0.008246 +0.008248 +0.00821 +0.008162 +0.008182 +0.008214 +0.008194 +0.0082 +0.008175 +0.008145 +0.008181 +0.008262 +0.008222 +0.008244 +0.008206 +0.008158 +0.008196 +0.008264 +0.008238 +0.008276 +0.008243 +0.008225 +0.008287 +0.008353 +0.008335 +0.008362 +0.008348 +0.008312 +0.008366 +0.001039 +0.008444 +0.008424 +0.008456 +0.008417 +0.008412 +0.008451 +0.008534 +0.008505 +0.008536 +0.008492 +0.008482 +0.008511 +0.008591 +0.008561 +0.008587 +0.008551 +0.008542 +0.008584 +0.008686 +0.008681 +0.008712 +0.008667 +0.00865 +0.008682 +0.008755 +0.008699 +0.008711 +0.008639 +0.008587 +0.008577 +0.008612 +0.00855 +0.008545 +0.008454 +0.008399 +0.008398 +0.008447 +0.008386 +0.008398 +0.008322 +0.008281 +0.008291 +0.008345 +0.008301 +0.008317 +0.008253 +0.00823 +0.00825 +0.008314 +0.008278 +0.008302 +0.008246 +0.008229 +0.008265 +0.008337 +0.00831 +0.008349 +0.008307 +0.008288 +0.00833 +0.008406 +0.008391 +0.008423 +0.008399 +0.008363 +0.008408 +0.00104 +0.008489 +0.008479 +0.008506 +0.008467 +0.008458 +0.008494 +0.008579 +0.008558 +0.008593 +0.008554 +0.008544 +0.008574 +0.00866 +0.008643 +0.00868 +0.008635 +0.008624 +0.00867 +0.00875 +0.008731 +0.008769 +0.008735 +0.008724 +0.008777 +0.008873 +0.008836 +0.008881 +0.008817 +0.00872 +0.008724 +0.008783 +0.008731 +0.008718 +0.008657 +0.008592 +0.008507 +0.008539 +0.008492 +0.008491 +0.008411 +0.008397 +0.008396 +0.008439 +0.008337 +0.008336 +0.008263 +0.008224 +0.008223 +0.008286 +0.008222 +0.008255 +0.008195 +0.008182 +0.008209 +0.008276 +0.008244 +0.008213 +0.008169 +0.00816 +0.008184 +0.008277 +0.008231 +0.008261 +0.008236 +0.008228 +0.008257 +0.008352 +0.008303 +0.008333 +0.008336 +0.008288 +0.008318 +0.008387 +0.001041 +0.008363 +0.008399 +0.008359 +0.008355 +0.008395 +0.00848 +0.008454 +0.008492 +0.008453 +0.008442 +0.008481 +0.008559 +0.008535 +0.008564 +0.008527 +0.008531 +0.008578 +0.008667 +0.008639 +0.008673 +0.008622 +0.008601 +0.008655 +0.008744 +0.00872 +0.008745 +0.008678 +0.008636 +0.008637 +0.008684 +0.008633 +0.008636 +0.008523 +0.008478 +0.008476 +0.008519 +0.008457 +0.008458 +0.008381 +0.00835 +0.008343 +0.008402 +0.008355 +0.008371 +0.008292 +0.008263 +0.00828 +0.00834 +0.008302 +0.008316 +0.008257 +0.008228 +0.008247 +0.008317 +0.008288 +0.008314 +0.008264 +0.008246 +0.008279 +0.008357 +0.008341 +0.008386 +0.008326 +0.008327 +0.008353 +0.008445 +0.008418 +0.008466 +0.008417 +0.001042 +0.008395 +0.008448 +0.00852 +0.008506 +0.00854 +0.008496 +0.008483 +0.008529 +0.008604 +0.008592 +0.008624 +0.00858 +0.008569 +0.008611 +0.008693 +0.008682 +0.008702 +0.008678 +0.008656 +0.008716 +0.008792 +0.008784 +0.008815 +0.008787 +0.008769 +0.00879 +0.008773 +0.008725 +0.008702 +0.008659 +0.008614 +0.008587 +0.008573 +0.008505 +0.008499 +0.008447 +0.008383 +0.008375 +0.008388 +0.008332 +0.008344 +0.008286 +0.008246 +0.008214 +0.008269 +0.008216 +0.008239 +0.008199 +0.008167 +0.008203 +0.008262 +0.00824 +0.008249 +0.008213 +0.008158 +0.00818 +0.008245 +0.008217 +0.008248 +0.00822 +0.0082 +0.00825 +0.008318 +0.008306 +0.008328 +0.008303 +0.008288 +0.008332 +0.008423 +0.008384 +0.008419 +0.001043 +0.008398 +0.008369 +0.008433 +0.008496 +0.008482 +0.008501 +0.008481 +0.008466 +0.0085 +0.008546 +0.008524 +0.008543 +0.008529 +0.008486 +0.008544 +0.00861 +0.008607 +0.008615 +0.008609 +0.008613 +0.008667 +0.008739 +0.008723 +0.008741 +0.008702 +0.008657 +0.008686 +0.008719 +0.008689 +0.008665 +0.008589 +0.008523 +0.008537 +0.008558 +0.008508 +0.008484 +0.008415 +0.008364 +0.008387 +0.008419 +0.008389 +0.008379 +0.008324 +0.008273 +0.008292 +0.008333 +0.008316 +0.008316 +0.008266 +0.008224 +0.008256 +0.008307 +0.008295 +0.008305 +0.008268 +0.008235 +0.008278 +0.008338 +0.008337 +0.008357 +0.008335 +0.008301 +0.008349 +0.008416 +0.008416 +0.008442 +0.008405 +0.008383 +0.001044 +0.008433 +0.008502 +0.008498 +0.008516 +0.008498 +0.00847 +0.008515 +0.008588 +0.00858 +0.008605 +0.008579 +0.008549 +0.008598 +0.008668 +0.008668 +0.008689 +0.008659 +0.00863 +0.008692 +0.008752 +0.00876 +0.008776 +0.008755 +0.008741 +0.008794 +0.008875 +0.008861 +0.00887 +0.008821 +0.008684 +0.008702 +0.008739 +0.008691 +0.008683 +0.008593 +0.008487 +0.008492 +0.008529 +0.00848 +0.00846 +0.008435 +0.008356 +0.008334 +0.008356 +0.008317 +0.008324 +0.008286 +0.008244 +0.008281 +0.008341 +0.0083 +0.008303 +0.008271 +0.008204 +0.008239 +0.008282 +0.008272 +0.008277 +0.008248 +0.008235 +0.00828 +0.008343 +0.008341 +0.008361 +0.008332 +0.008318 +0.008368 +0.00843 +0.008429 +0.008446 +0.008422 +0.001045 +0.008403 +0.008465 +0.008533 +0.0085 +0.008497 +0.008464 +0.008451 +0.008506 +0.008583 +0.00856 +0.008584 +0.008564 +0.00853 +0.008582 +0.008656 +0.008628 +0.008652 +0.008617 +0.008604 +0.008639 +0.008739 +0.008744 +0.00878 +0.008735 +0.008723 +0.008758 +0.00883 +0.008801 +0.008807 +0.008747 +0.008687 +0.008685 +0.008711 +0.00867 +0.008638 +0.008563 +0.008505 +0.008498 +0.008537 +0.008499 +0.008479 +0.008419 +0.008384 +0.008375 +0.008429 +0.008395 +0.008388 +0.008328 +0.008286 +0.008303 +0.008357 +0.008331 +0.008337 +0.008289 +0.008265 +0.008269 +0.008344 +0.008338 +0.008353 +0.00832 +0.008301 +0.008335 +0.008411 +0.008394 +0.008415 +0.0084 +0.008375 +0.008424 +0.008486 +0.008485 +0.001046 +0.008502 +0.008469 +0.008464 +0.008498 +0.008581 +0.008558 +0.008596 +0.008559 +0.008547 +0.00858 +0.008666 +0.008642 +0.008677 +0.008647 +0.008624 +0.008666 +0.00876 +0.008738 +0.00878 +0.008736 +0.008735 +0.008775 +0.008874 +0.008849 +0.008885 +0.008834 +0.008731 +0.008741 +0.008785 +0.008721 +0.008731 +0.008662 +0.008615 +0.00856 +0.008575 +0.008507 +0.008517 +0.008452 +0.008426 +0.008437 +0.008483 +0.008428 +0.008362 +0.008291 +0.008278 +0.008291 +0.008373 +0.008303 +0.008336 +0.00828 +0.008254 +0.008248 +0.008309 +0.008284 +0.008304 +0.008273 +0.008262 +0.008293 +0.008386 +0.008355 +0.008387 +0.008361 +0.008346 +0.008382 +0.008471 +0.008466 +0.008456 +0.008444 +0.001047 +0.008451 +0.008481 +0.00857 +0.008535 +0.008572 +0.008515 +0.008496 +0.008515 +0.008599 +0.008567 +0.008604 +0.00857 +0.008559 +0.008598 +0.008676 +0.008653 +0.00869 +0.00867 +0.008677 +0.00871 +0.008801 +0.00877 +0.008799 +0.008759 +0.008749 +0.00878 +0.008854 +0.008799 +0.008785 +0.008705 +0.008653 +0.008643 +0.008683 +0.008614 +0.008595 +0.008512 +0.008465 +0.008457 +0.008505 +0.008455 +0.008443 +0.008374 +0.008339 +0.008339 +0.008392 +0.008352 +0.008356 +0.008299 +0.008273 +0.008285 +0.008355 +0.008327 +0.008343 +0.008292 +0.008275 +0.008293 +0.008374 +0.008356 +0.008381 +0.008344 +0.008335 +0.008362 +0.008453 +0.008434 +0.008462 +0.008435 +0.008404 +0.008449 +0.001048 +0.008537 +0.008511 +0.008546 +0.008509 +0.008502 +0.008527 +0.008617 +0.008598 +0.008634 +0.008596 +0.00858 +0.008617 +0.008702 +0.008683 +0.008719 +0.008675 +0.008668 +0.00871 +0.008793 +0.008779 +0.008811 +0.008774 +0.008763 +0.00882 +0.00891 +0.008886 +0.008924 +0.008852 +0.008782 +0.008804 +0.008858 +0.008798 +0.008798 +0.008742 +0.008644 +0.008593 +0.008632 +0.008559 +0.008571 +0.008498 +0.008455 +0.008464 +0.008455 +0.008388 +0.008394 +0.008338 +0.008308 +0.008305 +0.008346 +0.008289 +0.008301 +0.00827 +0.008248 +0.008275 +0.008353 +0.008301 +0.008334 +0.008282 +0.008262 +0.008268 +0.008345 +0.008322 +0.008353 +0.008319 +0.008313 +0.008351 +0.008433 +0.008414 +0.008448 +0.008411 +0.008427 +0.008433 +0.00852 +0.001049 +0.008509 +0.008536 +0.008507 +0.008494 +0.008536 +0.00862 +0.008598 +0.008627 +0.008597 +0.00858 +0.008615 +0.008691 +0.008654 +0.008675 +0.00864 +0.008619 +0.008655 +0.008728 +0.008707 +0.00874 +0.008708 +0.008713 +0.008778 +0.008872 +0.008845 +0.008853 +0.008809 +0.008747 +0.008752 +0.008776 +0.008722 +0.008709 +0.008633 +0.008557 +0.008549 +0.008591 +0.00853 +0.008521 +0.008451 +0.008398 +0.008397 +0.008444 +0.008396 +0.008394 +0.008336 +0.008286 +0.008303 +0.008358 +0.008327 +0.008335 +0.008296 +0.008261 +0.008287 +0.008359 +0.008331 +0.008352 +0.008322 +0.008306 +0.008333 +0.008418 +0.008396 +0.008433 +0.008395 +0.008378 +0.008422 +0.008498 +0.008489 +0.008507 +0.00105 +0.008474 +0.008477 +0.008496 +0.008584 +0.008563 +0.008599 +0.008562 +0.00856 +0.008584 +0.008674 +0.008651 +0.008683 +0.008641 +0.008635 +0.008662 +0.008757 +0.008731 +0.008768 +0.008729 +0.008715 +0.008766 +0.00885 +0.008836 +0.008874 +0.008838 +0.008822 +0.008881 +0.008963 +0.008904 +0.008822 +0.008751 +0.008711 +0.008712 +0.008743 +0.008646 +0.008634 +0.008558 +0.008489 +0.008462 +0.008535 +0.008465 +0.008487 +0.008403 +0.008337 +0.00834 +0.008382 +0.008349 +0.008361 +0.008309 +0.00829 +0.008307 +0.008375 +0.008312 +0.008342 +0.008284 +0.008254 +0.008272 +0.00834 +0.008301 +0.008344 +0.008297 +0.008294 +0.008335 +0.008412 +0.008395 +0.008418 +0.008384 +0.008382 +0.008422 +0.008512 +0.008473 +0.00851 +0.001051 +0.00848 +0.008474 +0.008518 +0.008576 +0.008547 +0.008568 +0.008548 +0.008538 +0.008569 +0.008634 +0.008608 +0.008636 +0.008611 +0.008595 +0.008623 +0.008703 +0.008686 +0.008715 +0.008699 +0.0087 +0.008748 +0.008833 +0.008806 +0.00883 +0.008793 +0.008779 +0.008817 +0.008871 +0.008823 +0.008807 +0.008719 +0.008667 +0.008655 +0.008679 +0.008617 +0.008594 +0.008514 +0.008461 +0.008468 +0.008508 +0.008456 +0.008445 +0.008381 +0.008345 +0.008349 +0.008401 +0.008359 +0.008362 +0.008305 +0.008277 +0.008307 +0.008365 +0.00834 +0.008349 +0.008303 +0.008272 +0.008315 +0.008387 +0.008374 +0.008392 +0.008351 +0.008338 +0.008373 +0.008455 +0.008449 +0.008471 +0.008439 +0.008418 +0.00846 +0.008531 +0.001052 +0.008537 +0.00855 +0.008524 +0.008498 +0.008549 +0.008615 +0.008616 +0.008636 +0.008613 +0.008586 +0.008632 +0.008704 +0.008704 +0.008715 +0.008687 +0.008669 +0.008718 +0.00879 +0.008792 +0.008808 +0.008789 +0.00877 +0.008833 +0.008897 +0.008894 +0.008928 +0.00889 +0.008788 +0.008806 +0.008842 +0.008802 +0.008796 +0.008744 +0.008677 +0.008682 +0.008645 +0.008602 +0.008581 +0.008531 +0.008482 +0.008479 +0.008493 +0.008445 +0.00844 +0.00841 +0.008333 +0.008328 +0.008378 +0.008334 +0.008363 +0.008314 +0.008294 +0.008334 +0.008386 +0.008371 +0.008375 +0.008359 +0.00833 +0.008361 +0.008401 +0.008367 +0.008398 +0.008384 +0.008353 +0.008416 +0.008482 +0.008464 +0.008483 +0.008473 +0.008445 +0.008501 +0.008586 +0.008544 +0.001053 +0.008583 +0.008566 +0.008527 +0.008595 +0.008662 +0.008651 +0.008666 +0.008647 +0.008623 +0.008653 +0.008708 +0.008686 +0.008701 +0.008684 +0.008655 +0.008705 +0.008778 +0.008778 +0.008832 +0.008817 +0.008782 +0.008835 +0.008897 +0.00889 +0.008897 +0.00886 +0.008811 +0.00883 +0.008842 +0.008799 +0.008771 +0.0087 +0.008627 +0.008625 +0.008639 +0.008601 +0.008587 +0.00853 +0.008466 +0.008478 +0.008513 +0.008479 +0.008484 +0.008427 +0.008385 +0.008404 +0.008447 +0.008432 +0.008444 +0.008412 +0.008374 +0.008412 +0.008454 +0.008438 +0.00844 +0.008413 +0.008401 +0.008447 +0.008508 +0.008504 +0.008512 +0.008489 +0.008452 +0.008505 +0.008583 +0.008576 +0.008603 +0.008578 +0.001054 +0.008566 +0.008585 +0.008667 +0.008662 +0.008684 +0.008654 +0.008642 +0.008685 +0.008764 +0.008747 +0.008771 +0.008736 +0.008718 +0.008765 +0.008846 +0.008825 +0.008862 +0.008817 +0.008802 +0.008858 +0.008933 +0.008928 +0.008961 +0.008935 +0.008901 +0.00897 +0.009054 +0.009031 +0.009049 +0.008941 +0.008844 +0.008842 +0.008885 +0.008827 +0.008779 +0.008669 +0.008598 +0.008609 +0.008629 +0.008579 +0.00857 +0.0085 +0.00842 +0.008399 +0.008464 +0.008398 +0.008421 +0.008339 +0.008314 +0.008336 +0.008363 +0.008327 +0.008326 +0.008298 +0.00826 +0.008257 +0.008324 +0.008285 +0.0083 +0.008278 +0.008248 +0.008299 +0.008378 +0.008349 +0.008382 +0.00835 +0.00833 +0.008385 +0.008465 +0.008443 +0.008445 +0.008424 +0.008392 +0.001055 +0.008416 +0.0085 +0.008475 +0.008517 +0.008467 +0.008466 +0.008511 +0.008594 +0.00857 +0.008605 +0.008569 +0.008551 +0.008593 +0.008675 +0.008651 +0.008679 +0.008649 +0.008648 +0.00869 +0.008779 +0.008757 +0.008779 +0.00874 +0.008732 +0.008773 +0.008858 +0.008832 +0.00884 +0.008763 +0.008722 +0.0087 +0.00873 +0.008667 +0.008644 +0.008543 +0.008499 +0.008478 +0.008511 +0.008453 +0.008445 +0.00836 +0.008323 +0.008318 +0.008362 +0.008319 +0.00832 +0.008237 +0.008217 +0.008223 +0.008281 +0.008258 +0.008271 +0.008218 +0.008203 +0.008212 +0.008285 +0.008271 +0.008294 +0.008247 +0.008244 +0.008253 +0.008336 +0.008327 +0.008359 +0.008324 +0.008313 +0.008338 +0.008433 +0.008395 +0.00843 +0.001056 +0.008401 +0.00838 +0.008437 +0.008507 +0.008492 +0.00851 +0.008479 +0.008463 +0.008507 +0.008586 +0.008575 +0.0086 +0.008571 +0.008546 +0.008595 +0.008667 +0.008656 +0.008685 +0.008648 +0.008633 +0.008686 +0.008762 +0.008755 +0.008785 +0.008751 +0.008737 +0.008803 +0.008874 +0.008834 +0.008755 +0.008658 +0.00861 +0.008637 +0.008674 +0.00858 +0.008552 +0.008484 +0.008417 +0.008412 +0.008446 +0.008402 +0.008391 +0.008288 +0.008246 +0.008235 +0.008291 +0.008236 +0.008248 +0.008192 +0.008169 +0.008181 +0.008227 +0.008173 +0.008199 +0.008145 +0.008136 +0.008154 +0.0082 +0.008182 +0.008195 +0.008161 +0.008154 +0.008191 +0.008277 +0.008247 +0.008265 +0.008244 +0.008226 +0.008234 +0.008307 +0.008292 +0.008314 +0.008292 +0.008273 +0.008339 +0.001057 +0.008397 +0.00837 +0.008418 +0.00838 +0.008374 +0.00841 +0.008498 +0.00847 +0.008506 +0.008469 +0.008455 +0.008496 +0.008569 +0.00854 +0.00857 +0.008527 +0.008522 +0.008556 +0.008641 +0.008635 +0.008672 +0.00864 +0.008618 +0.008658 +0.008736 +0.008716 +0.008739 +0.008689 +0.008658 +0.008648 +0.008678 +0.008631 +0.008613 +0.008519 +0.008473 +0.00846 +0.008483 +0.008426 +0.00842 +0.008331 +0.008291 +0.008288 +0.008335 +0.008287 +0.008279 +0.008211 +0.008192 +0.008184 +0.008245 +0.008223 +0.008242 +0.008184 +0.008171 +0.008184 +0.008251 +0.008224 +0.008247 +0.008207 +0.008209 +0.008234 +0.008311 +0.008291 +0.008321 +0.008281 +0.008269 +0.008302 +0.008395 +0.008374 +0.0084 +0.001058 +0.00836 +0.008355 +0.008391 +0.008467 +0.008449 +0.008489 +0.008446 +0.008437 +0.008471 +0.008556 +0.008533 +0.008564 +0.008525 +0.00852 +0.008556 +0.008635 +0.008623 +0.00865 +0.008613 +0.008604 +0.00865 +0.008736 +0.008725 +0.008762 +0.008725 +0.008713 +0.008748 +0.008752 +0.008655 +0.008659 +0.008578 +0.008492 +0.008474 +0.008521 +0.008441 +0.008438 +0.008361 +0.008287 +0.008263 +0.0083 +0.008243 +0.008242 +0.008178 +0.008124 +0.008078 +0.008143 +0.008071 +0.008101 +0.008044 +0.008015 +0.008045 +0.008103 +0.008063 +0.008073 +0.008015 +0.007972 +0.007982 +0.008066 +0.008024 +0.008047 +0.008026 +0.008008 +0.008049 +0.008132 +0.008101 +0.008122 +0.008102 +0.008094 +0.00813 +0.008214 +0.008205 +0.008211 +0.00817 +0.001059 +0.00815 +0.00817 +0.008257 +0.008225 +0.008258 +0.008227 +0.008218 +0.008254 +0.008343 +0.008307 +0.008354 +0.008314 +0.008303 +0.008338 +0.008419 +0.008394 +0.008421 +0.00839 +0.008396 +0.008437 +0.00852 +0.008496 +0.008523 +0.008476 +0.008469 +0.0085 +0.008595 +0.008574 +0.008607 +0.008549 +0.00851 +0.008518 +0.008559 +0.008499 +0.008486 +0.008401 +0.00835 +0.008347 +0.008383 +0.008318 +0.008316 +0.008243 +0.008195 +0.0082 +0.00825 +0.008195 +0.008203 +0.008135 +0.008098 +0.008114 +0.008174 +0.008139 +0.008161 +0.008109 +0.008086 +0.008111 +0.00818 +0.008153 +0.008183 +0.008139 +0.008122 +0.008154 +0.008235 +0.008214 +0.008256 +0.008212 +0.008199 +0.008233 +0.008313 +0.008296 +0.00832 +0.00106 +0.008291 +0.00828 +0.008315 +0.008389 +0.008381 +0.008399 +0.008376 +0.008356 +0.008395 +0.008473 +0.00846 +0.008484 +0.008452 +0.008439 +0.008477 +0.008557 +0.008547 +0.008572 +0.00854 +0.008512 +0.008563 +0.008651 +0.008633 +0.008674 +0.008644 +0.008622 +0.008682 +0.008769 +0.008719 +0.008664 +0.008603 +0.008559 +0.008592 +0.00863 +0.008565 +0.008485 +0.008409 +0.008366 +0.008393 +0.008436 +0.00838 +0.00834 +0.008257 +0.008211 +0.00824 +0.0083 +0.008256 +0.008252 +0.008168 +0.008139 +0.008161 +0.008238 +0.008202 +0.008214 +0.008174 +0.008139 +0.008174 +0.00822 +0.0082 +0.008229 +0.008198 +0.008175 +0.008223 +0.00829 +0.008274 +0.008296 +0.008264 +0.008268 +0.008286 +0.008349 +0.008328 +0.00836 +0.008318 +0.001061 +0.008302 +0.00837 +0.008429 +0.008417 +0.008441 +0.008427 +0.008398 +0.008452 +0.008516 +0.008504 +0.008532 +0.008508 +0.008486 +0.008539 +0.008601 +0.00858 +0.008591 +0.008567 +0.008539 +0.008588 +0.00866 +0.00864 +0.008651 +0.008632 +0.008622 +0.008703 +0.008774 +0.008754 +0.008741 +0.00868 +0.008605 +0.008601 +0.008615 +0.008589 +0.008554 +0.00848 +0.008402 +0.008419 +0.008446 +0.0084 +0.008378 +0.00832 +0.008266 +0.008282 +0.008319 +0.008282 +0.008274 +0.008224 +0.008169 +0.008208 +0.008257 +0.008241 +0.008246 +0.008209 +0.008168 +0.008215 +0.008274 +0.008266 +0.008282 +0.008254 +0.008223 +0.008277 +0.00834 +0.008337 +0.008358 +0.008338 +0.008301 +0.008348 +0.008428 +0.001062 +0.008414 +0.008446 +0.008409 +0.00839 +0.008433 +0.008506 +0.008492 +0.008522 +0.008493 +0.008471 +0.008518 +0.008586 +0.008581 +0.008606 +0.008573 +0.008556 +0.0086 +0.008673 +0.008662 +0.008693 +0.008653 +0.008642 +0.008691 +0.008769 +0.008752 +0.008794 +0.008763 +0.008753 +0.008808 +0.008887 +0.008813 +0.008765 +0.008708 +0.008667 +0.008656 +0.008668 +0.0086 +0.008584 +0.008502 +0.00843 +0.008419 +0.008464 +0.008415 +0.008402 +0.008358 +0.00827 +0.00824 +0.008296 +0.008238 +0.008256 +0.00819 +0.008164 +0.008192 +0.008255 +0.008183 +0.008175 +0.008126 +0.00809 +0.008144 +0.008189 +0.00816 +0.008179 +0.008136 +0.008129 +0.008131 +0.0082 +0.00818 +0.008203 +0.008179 +0.008169 +0.008213 +0.008282 +0.008269 +0.0083 +0.008269 +0.008264 +0.008286 +0.008375 +0.001063 +0.00836 +0.008379 +0.008358 +0.008333 +0.008395 +0.008459 +0.008446 +0.008465 +0.008443 +0.008413 +0.008467 +0.008521 +0.008499 +0.008506 +0.008483 +0.008458 +0.008503 +0.008577 +0.00856 +0.00858 +0.00858 +0.00858 +0.008626 +0.008704 +0.008685 +0.008689 +0.008653 +0.008596 +0.008605 +0.008653 +0.008603 +0.008567 +0.008499 +0.008435 +0.008434 +0.008457 +0.008408 +0.008386 +0.008333 +0.008279 +0.008292 +0.008336 +0.008305 +0.008288 +0.008249 +0.008198 +0.008224 +0.008279 +0.008258 +0.008257 +0.008229 +0.008189 +0.008221 +0.008284 +0.008279 +0.008284 +0.008261 +0.008228 +0.008269 +0.008346 +0.00834 +0.008355 +0.008332 +0.0083 +0.008356 +0.008427 +0.008416 +0.008433 +0.001064 +0.008414 +0.008388 +0.008433 +0.008504 +0.008505 +0.008518 +0.008495 +0.008467 +0.008523 +0.008591 +0.008589 +0.008596 +0.008578 +0.008546 +0.008606 +0.008679 +0.008672 +0.00869 +0.008666 +0.008637 +0.008705 +0.008774 +0.00878 +0.00879 +0.008773 +0.008751 +0.008826 +0.008857 +0.008783 +0.008767 +0.008722 +0.00867 +0.008631 +0.00865 +0.008597 +0.00858 +0.008532 +0.008427 +0.008426 +0.008454 +0.008411 +0.008411 +0.008354 +0.008314 +0.008289 +0.008293 +0.008243 +0.008249 +0.008217 +0.008178 +0.008215 +0.008282 +0.008233 +0.008252 +0.008212 +0.008193 +0.008227 +0.008248 +0.008231 +0.00823 +0.00822 +0.00819 +0.008243 +0.008318 +0.008298 +0.008308 +0.008294 +0.008272 +0.008297 +0.008364 +0.008347 +0.008369 +0.008349 +0.00834 +0.008381 +0.001065 +0.008441 +0.008438 +0.008459 +0.008439 +0.008413 +0.008472 +0.008539 +0.008527 +0.008544 +0.008524 +0.008496 +0.008546 +0.008612 +0.008598 +0.008608 +0.008585 +0.00856 +0.008601 +0.008678 +0.008693 +0.008722 +0.008703 +0.008667 +0.008721 +0.008784 +0.008759 +0.008763 +0.008705 +0.008659 +0.008666 +0.008683 +0.008635 +0.008615 +0.008537 +0.008463 +0.008462 +0.008482 +0.008441 +0.008423 +0.008355 +0.008304 +0.008317 +0.008346 +0.008318 +0.008314 +0.008262 +0.008222 +0.008245 +0.008283 +0.008271 +0.008276 +0.008237 +0.008205 +0.00824 +0.008291 +0.00828 +0.008299 +0.008271 +0.008248 +0.008296 +0.008357 +0.008359 +0.008368 +0.008351 +0.008316 +0.008364 +0.008446 +0.00843 +0.001066 +0.008463 +0.00842 +0.008411 +0.008451 +0.008531 +0.008517 +0.008536 +0.008503 +0.008485 +0.008534 +0.008613 +0.008601 +0.008624 +0.008583 +0.008573 +0.008622 +0.008704 +0.008686 +0.008714 +0.008683 +0.008663 +0.008713 +0.008806 +0.008792 +0.00881 +0.008796 +0.008782 +0.008807 +0.008814 +0.008767 +0.00876 +0.008711 +0.008667 +0.008676 +0.00873 +0.008641 +0.008571 +0.008507 +0.008462 +0.008479 +0.008534 +0.008476 +0.008416 +0.008359 +0.008306 +0.00834 +0.008385 +0.00833 +0.00833 +0.008266 +0.008229 +0.008245 +0.008293 +0.008267 +0.008271 +0.008243 +0.008215 +0.008249 +0.008329 +0.008299 +0.008323 +0.008303 +0.008282 +0.008326 +0.008408 +0.008376 +0.008396 +0.008385 +0.008359 +0.008373 +0.00844 +0.001067 +0.008412 +0.008452 +0.008417 +0.008407 +0.008447 +0.008537 +0.008517 +0.008548 +0.008515 +0.008502 +0.008544 +0.008628 +0.008605 +0.008637 +0.008595 +0.008585 +0.008616 +0.008701 +0.008672 +0.008706 +0.00867 +0.008671 +0.008718 +0.008804 +0.008772 +0.008816 +0.008758 +0.008758 +0.008795 +0.008872 +0.008832 +0.008828 +0.008749 +0.008699 +0.008681 +0.00872 +0.008658 +0.008645 +0.00856 +0.008503 +0.008493 +0.008547 +0.008498 +0.008495 +0.008423 +0.008385 +0.008379 +0.008438 +0.008394 +0.008404 +0.008345 +0.008319 +0.008325 +0.008397 +0.008365 +0.008382 +0.00834 +0.008318 +0.008337 +0.008416 +0.00839 +0.008415 +0.008378 +0.008372 +0.008397 +0.008485 +0.008459 +0.008486 +0.008469 +0.008435 +0.008487 +0.008563 +0.001068 +0.008549 +0.008581 +0.008527 +0.008525 +0.008559 +0.008645 +0.008627 +0.008663 +0.008621 +0.008612 +0.008647 +0.008733 +0.008712 +0.008755 +0.008698 +0.008695 +0.008735 +0.008823 +0.008801 +0.008839 +0.008797 +0.00879 +0.00883 +0.008924 +0.008906 +0.008936 +0.008915 +0.008908 +0.008935 +0.008934 +0.008862 +0.008866 +0.008796 +0.008754 +0.008749 +0.008725 +0.008637 +0.008632 +0.008572 +0.0085 +0.008465 +0.008517 +0.008456 +0.008461 +0.008402 +0.008309 +0.008305 +0.008356 +0.008303 +0.008318 +0.008273 +0.008242 +0.008271 +0.008305 +0.008247 +0.008276 +0.008221 +0.008218 +0.008219 +0.00828 +0.008248 +0.008271 +0.008233 +0.008237 +0.00827 +0.008346 +0.008324 +0.008354 +0.008318 +0.008315 +0.008358 +0.008438 +0.008424 +0.00844 +0.001069 +0.008406 +0.008393 +0.008398 +0.008481 +0.008453 +0.008488 +0.008456 +0.008447 +0.00849 +0.008567 +0.008548 +0.00858 +0.008543 +0.008528 +0.008565 +0.008644 +0.008633 +0.008685 +0.008646 +0.008636 +0.008668 +0.00875 +0.008724 +0.008764 +0.008716 +0.008715 +0.008746 +0.008818 +0.008762 +0.008771 +0.008681 +0.008623 +0.008613 +0.008639 +0.00858 +0.00857 +0.008477 +0.008418 +0.008422 +0.008463 +0.008398 +0.008405 +0.008335 +0.008285 +0.008291 +0.008342 +0.008298 +0.008319 +0.008237 +0.008214 +0.008236 +0.008291 +0.008252 +0.008281 +0.008228 +0.008202 +0.008233 +0.008302 +0.008276 +0.008315 +0.008274 +0.00826 +0.008298 +0.00837 +0.008349 +0.008384 +0.008354 +0.008335 +0.008373 +0.008461 +0.00107 +0.008436 +0.008469 +0.008419 +0.008415 +0.008451 +0.008537 +0.008518 +0.008552 +0.008511 +0.008502 +0.008538 +0.008623 +0.008602 +0.008637 +0.008593 +0.008581 +0.008625 +0.008707 +0.008683 +0.008735 +0.008676 +0.008679 +0.008732 +0.008816 +0.008792 +0.008828 +0.008795 +0.008775 +0.00872 +0.008736 +0.008667 +0.008673 +0.008601 +0.008546 +0.008528 +0.008506 +0.008437 +0.008417 +0.008356 +0.008321 +0.008268 +0.008302 +0.008233 +0.008248 +0.008192 +0.008145 +0.008142 +0.008175 +0.008113 +0.008146 +0.008076 +0.008065 +0.008045 +0.008103 +0.008057 +0.008074 +0.008043 +0.008012 +0.008047 +0.008134 +0.008093 +0.00812 +0.008099 +0.008075 +0.008078 +0.008151 +0.008118 +0.008156 +0.008127 +0.008124 +0.008161 +0.008238 +0.008217 +0.008253 +0.008216 +0.008212 +0.001071 +0.008254 +0.008316 +0.008295 +0.008336 +0.008305 +0.00829 +0.008329 +0.008414 +0.008385 +0.008417 +0.008373 +0.008362 +0.00839 +0.008473 +0.008447 +0.008479 +0.008437 +0.008442 +0.008491 +0.008575 +0.008562 +0.00858 +0.008546 +0.008525 +0.008541 +0.008615 +0.008564 +0.008561 +0.008477 +0.00842 +0.008404 +0.008446 +0.008376 +0.008355 +0.008283 +0.008231 +0.00822 +0.008265 +0.00821 +0.008205 +0.008139 +0.008089 +0.008085 +0.008147 +0.008095 +0.008093 +0.008041 +0.008008 +0.008026 +0.008094 +0.008055 +0.008071 +0.008024 +0.008 +0.008024 +0.008112 +0.008084 +0.00811 +0.008073 +0.008057 +0.008091 +0.008171 +0.00815 +0.00819 +0.008148 +0.008141 +0.008173 +0.008243 +0.001072 +0.008226 +0.008264 +0.008226 +0.008218 +0.008246 +0.008334 +0.008312 +0.008343 +0.008304 +0.008299 +0.008332 +0.008414 +0.008391 +0.008425 +0.008387 +0.008378 +0.008411 +0.008498 +0.008472 +0.008503 +0.008471 +0.008459 +0.008506 +0.008596 +0.00857 +0.00861 +0.008573 +0.008568 +0.008617 +0.008659 +0.008551 +0.008563 +0.008495 +0.008426 +0.0084 +0.008445 +0.008372 +0.008365 +0.00828 +0.008216 +0.008187 +0.00825 +0.008198 +0.008186 +0.008113 +0.008049 +0.008055 +0.0081 +0.008045 +0.008063 +0.008013 +0.007983 +0.008016 +0.008048 +0.008011 +0.008016 +0.00797 +0.007948 +0.007954 +0.008034 +0.007982 +0.008022 +0.007987 +0.007974 +0.008015 +0.008099 +0.008061 +0.008087 +0.008062 +0.008052 +0.008086 +0.008169 +0.008164 +0.008156 +0.008101 +0.001073 +0.008102 +0.008142 +0.008221 +0.008193 +0.008229 +0.008195 +0.008186 +0.008223 +0.008304 +0.008278 +0.008308 +0.008273 +0.008259 +0.008293 +0.008369 +0.008345 +0.008373 +0.008339 +0.008329 +0.008386 +0.00848 +0.008454 +0.008486 +0.008434 +0.008427 +0.008464 +0.008544 +0.008533 +0.008551 +0.008482 +0.008451 +0.008438 +0.00848 +0.008427 +0.008413 +0.008316 +0.00828 +0.008267 +0.008304 +0.008256 +0.008253 +0.008174 +0.008137 +0.008142 +0.008198 +0.008149 +0.008157 +0.00809 +0.008066 +0.008076 +0.008128 +0.008104 +0.008118 +0.008066 +0.008053 +0.008059 +0.008133 +0.008112 +0.008141 +0.008092 +0.008089 +0.008111 +0.008192 +0.008179 +0.008209 +0.008172 +0.008162 +0.008187 +0.008275 +0.008258 +0.008285 +0.001074 +0.008252 +0.008237 +0.008269 +0.008357 +0.008337 +0.00837 +0.008327 +0.008319 +0.008357 +0.008437 +0.008416 +0.008449 +0.008406 +0.008401 +0.008441 +0.008518 +0.008498 +0.008536 +0.008488 +0.008486 +0.008535 +0.008611 +0.008605 +0.008641 +0.0086 +0.008585 +0.008613 +0.008619 +0.008534 +0.008544 +0.00848 +0.008409 +0.008377 +0.008414 +0.008339 +0.008352 +0.008298 +0.008241 +0.008233 +0.008254 +0.008193 +0.008211 +0.008141 +0.008093 +0.008069 +0.008138 +0.008075 +0.008109 +0.008051 +0.008036 +0.008054 +0.008131 +0.008085 +0.008089 +0.008032 +0.008007 +0.008031 +0.008109 +0.008063 +0.008106 +0.008057 +0.008045 +0.008083 +0.008152 +0.008108 +0.008157 +0.008121 +0.008108 +0.008148 +0.008235 +0.0082 +0.008243 +0.008192 +0.001075 +0.008181 +0.008235 +0.008305 +0.008276 +0.008303 +0.008277 +0.008263 +0.008307 +0.008368 +0.008341 +0.008366 +0.00834 +0.008317 +0.008369 +0.008442 +0.008408 +0.00844 +0.008407 +0.008389 +0.008428 +0.008534 +0.008538 +0.008562 +0.008523 +0.008503 +0.008538 +0.008618 +0.008598 +0.008617 +0.008581 +0.008542 +0.008558 +0.00859 +0.00853 +0.008513 +0.00843 +0.008367 +0.008362 +0.0084 +0.008349 +0.008326 +0.00827 +0.008221 +0.008237 +0.008287 +0.008252 +0.00825 +0.008204 +0.008156 +0.008177 +0.008237 +0.008211 +0.008226 +0.008189 +0.008154 +0.008184 +0.008256 +0.008228 +0.008262 +0.008228 +0.008211 +0.008255 +0.008327 +0.008307 +0.008337 +0.008303 +0.008289 +0.008327 +0.008411 +0.001076 +0.008387 +0.008419 +0.008386 +0.008374 +0.008411 +0.008489 +0.008472 +0.008502 +0.008464 +0.008455 +0.008493 +0.008575 +0.008555 +0.008596 +0.008546 +0.008533 +0.008578 +0.008662 +0.008635 +0.008681 +0.008634 +0.008636 +0.008684 +0.008765 +0.008742 +0.008781 +0.008735 +0.008669 +0.00862 +0.00867 +0.008615 +0.008612 +0.008551 +0.008507 +0.008434 +0.008453 +0.008391 +0.008402 +0.008332 +0.008308 +0.008321 +0.008363 +0.008257 +0.008264 +0.008204 +0.008166 +0.008147 +0.008215 +0.008158 +0.008184 +0.00813 +0.008103 +0.008142 +0.008201 +0.008161 +0.008192 +0.008142 +0.008125 +0.008141 +0.008187 +0.008156 +0.008193 +0.008157 +0.008154 +0.008192 +0.008266 +0.008254 +0.008281 +0.008249 +0.008239 +0.008289 +0.008379 +0.008323 +0.001077 +0.008369 +0.00835 +0.008321 +0.008374 +0.00845 +0.008422 +0.008459 +0.008433 +0.008407 +0.008424 +0.008484 +0.008457 +0.008485 +0.008466 +0.008431 +0.008484 +0.008557 +0.008545 +0.008598 +0.008582 +0.008565 +0.008602 +0.008681 +0.008661 +0.008684 +0.008644 +0.008614 +0.008654 +0.008698 +0.008645 +0.008632 +0.008546 +0.008477 +0.008468 +0.00849 +0.008431 +0.008419 +0.00834 +0.008283 +0.008289 +0.008331 +0.008284 +0.00829 +0.008227 +0.008187 +0.0082 +0.00825 +0.008216 +0.00823 +0.008186 +0.008157 +0.008187 +0.008254 +0.008222 +0.00824 +0.008204 +0.00819 +0.008239 +0.008309 +0.008292 +0.008319 +0.008282 +0.008266 +0.008306 +0.008374 +0.008364 +0.008397 +0.001078 +0.008358 +0.008358 +0.008382 +0.008465 +0.008448 +0.008481 +0.008444 +0.008432 +0.00847 +0.00855 +0.00853 +0.008561 +0.008521 +0.008518 +0.008557 +0.008636 +0.008625 +0.00866 +0.008613 +0.008616 +0.008649 +0.008739 +0.008727 +0.008774 +0.008731 +0.008647 +0.008611 +0.008672 +0.008613 +0.008628 +0.008563 +0.008523 +0.00852 +0.00851 +0.008442 +0.00842 +0.008368 +0.008339 +0.00828 +0.008328 +0.008271 +0.008272 +0.008224 +0.008173 +0.008158 +0.008189 +0.008148 +0.008173 +0.008114 +0.0081 +0.008114 +0.008199 +0.008145 +0.008164 +0.008131 +0.008076 +0.00808 +0.008156 +0.008112 +0.008147 +0.008111 +0.008093 +0.008159 +0.008199 +0.008189 +0.008231 +0.008193 +0.008181 +0.008234 +0.008317 +0.008271 +0.008311 +0.008283 +0.001079 +0.008272 +0.008312 +0.008399 +0.008361 +0.008369 +0.008323 +0.008317 +0.00836 +0.008444 +0.008406 +0.00844 +0.0084 +0.008394 +0.008432 +0.008506 +0.008483 +0.008517 +0.008478 +0.008485 +0.008544 +0.00863 +0.008605 +0.008632 +0.008587 +0.008575 +0.008605 +0.008675 +0.008646 +0.008654 +0.008588 +0.008537 +0.008516 +0.008556 +0.008483 +0.008465 +0.008376 +0.008334 +0.008321 +0.00836 +0.008299 +0.0083 +0.00823 +0.008198 +0.008198 +0.008249 +0.008211 +0.008215 +0.008152 +0.008129 +0.008146 +0.008214 +0.008183 +0.008202 +0.008147 +0.008136 +0.008155 +0.008238 +0.008215 +0.008241 +0.008202 +0.008192 +0.008224 +0.008307 +0.00829 +0.008325 +0.008279 +0.008266 +0.008312 +0.00108 +0.008384 +0.00838 +0.008392 +0.008368 +0.008351 +0.008393 +0.00847 +0.008453 +0.00848 +0.008453 +0.008433 +0.00848 +0.008552 +0.008543 +0.008563 +0.008531 +0.008521 +0.008561 +0.00864 +0.008626 +0.008659 +0.008625 +0.00862 +0.008675 +0.008756 +0.008733 +0.008761 +0.008639 +0.00859 +0.008611 +0.008659 +0.008591 +0.008542 +0.008459 +0.008395 +0.008384 +0.008428 +0.008357 +0.008347 +0.008275 +0.008193 +0.008201 +0.00823 +0.008189 +0.008183 +0.008148 +0.008097 +0.0081 +0.008111 +0.008083 +0.008086 +0.008055 +0.008029 +0.008055 +0.008127 +0.008087 +0.008097 +0.008075 +0.008049 +0.008095 +0.008155 +0.008107 +0.008142 +0.008102 +0.008078 +0.00812 +0.00818 +0.008157 +0.008195 +0.008165 +0.00815 +0.0082 +0.008272 +0.008254 +0.008291 +0.008243 +0.001081 +0.00823 +0.008298 +0.00835 +0.008345 +0.008367 +0.008341 +0.008316 +0.008369 +0.008433 +0.008416 +0.008426 +0.008398 +0.008369 +0.008419 +0.008489 +0.008486 +0.008508 +0.008501 +0.008481 +0.008528 +0.008599 +0.008583 +0.008598 +0.008559 +0.008515 +0.008542 +0.00857 +0.008513 +0.008495 +0.008431 +0.008357 +0.008371 +0.008396 +0.008346 +0.008331 +0.008271 +0.008211 +0.008236 +0.008271 +0.008248 +0.008241 +0.008198 +0.008138 +0.008172 +0.008225 +0.008205 +0.008216 +0.008182 +0.008143 +0.008181 +0.008239 +0.008214 +0.008225 +0.008205 +0.008187 +0.008244 +0.008306 +0.008292 +0.008311 +0.008282 +0.008257 +0.008302 +0.008367 +0.008364 +0.001082 +0.008391 +0.008361 +0.008342 +0.008387 +0.008458 +0.008447 +0.008472 +0.008444 +0.008425 +0.008468 +0.00854 +0.008532 +0.008561 +0.008525 +0.008511 +0.00855 +0.008636 +0.008621 +0.008649 +0.008623 +0.008604 +0.008662 +0.00875 +0.008733 +0.008758 +0.008697 +0.008601 +0.008609 +0.008654 +0.008605 +0.008608 +0.008541 +0.008489 +0.008439 +0.008422 +0.008376 +0.008382 +0.008322 +0.008274 +0.008299 +0.008345 +0.008313 +0.008264 +0.00818 +0.008139 +0.008166 +0.008219 +0.008183 +0.008183 +0.008151 +0.008117 +0.008138 +0.008187 +0.008154 +0.008172 +0.008138 +0.008123 +0.00817 +0.008231 +0.008225 +0.008237 +0.008214 +0.008202 +0.008243 +0.008324 +0.008297 +0.008329 +0.008274 +0.008257 +0.001083 +0.008295 +0.008341 +0.008346 +0.008358 +0.008341 +0.008316 +0.008378 +0.008443 +0.008436 +0.008456 +0.008435 +0.008411 +0.008464 +0.008527 +0.008523 +0.008533 +0.008509 +0.008482 +0.008548 +0.008622 +0.008621 +0.008636 +0.008602 +0.008574 +0.008631 +0.008698 +0.008694 +0.008686 +0.008636 +0.008576 +0.008584 +0.008609 +0.00856 +0.008529 +0.008455 +0.008388 +0.008399 +0.008417 +0.008367 +0.008352 +0.008298 +0.008238 +0.008255 +0.008303 +0.008265 +0.008252 +0.008208 +0.008152 +0.008182 +0.008231 +0.00821 +0.008214 +0.008175 +0.00814 +0.008167 +0.008227 +0.008215 +0.008222 +0.008201 +0.008164 +0.008206 +0.008277 +0.008267 +0.008286 +0.008264 +0.008236 +0.00829 +0.00835 +0.008348 +0.008376 +0.00834 +0.001084 +0.008315 +0.008366 +0.008434 +0.00843 +0.008447 +0.008428 +0.008402 +0.00845 +0.008521 +0.008509 +0.008529 +0.008507 +0.008487 +0.008536 +0.008604 +0.008601 +0.008623 +0.008595 +0.008574 +0.008624 +0.008698 +0.008689 +0.00872 +0.008707 +0.008686 +0.008741 +0.008748 +0.008684 +0.008676 +0.008622 +0.008581 +0.008572 +0.008553 +0.008509 +0.008492 +0.008413 +0.008348 +0.008341 +0.008369 +0.008319 +0.008323 +0.008283 +0.008217 +0.008216 +0.008217 +0.008186 +0.008169 +0.008155 +0.008099 +0.008149 +0.00819 +0.008162 +0.008174 +0.008107 +0.008072 +0.008101 +0.008145 +0.008143 +0.008146 +0.008121 +0.008098 +0.008145 +0.008208 +0.0082 +0.008216 +0.008195 +0.008178 +0.008226 +0.008294 +0.008277 +0.008317 +0.008252 +0.001085 +0.008225 +0.008272 +0.008335 +0.008315 +0.008335 +0.008321 +0.008292 +0.008355 +0.008424 +0.008416 +0.008435 +0.008413 +0.008385 +0.00844 +0.008499 +0.008498 +0.008507 +0.008496 +0.008478 +0.00853 +0.008601 +0.008593 +0.008605 +0.008579 +0.008565 +0.008617 +0.008689 +0.008667 +0.008682 +0.008646 +0.008594 +0.008603 +0.008623 +0.008571 +0.008536 +0.008458 +0.008383 +0.008382 +0.0084 +0.008351 +0.008325 +0.008268 +0.008192 +0.008224 +0.008255 +0.008216 +0.008215 +0.008162 +0.008114 +0.008141 +0.008187 +0.008164 +0.008177 +0.008142 +0.008095 +0.008137 +0.008189 +0.008165 +0.008177 +0.008153 +0.00813 +0.008178 +0.008239 +0.008229 +0.008245 +0.008219 +0.008187 +0.008243 +0.008301 +0.008311 +0.008329 +0.008307 +0.001086 +0.008268 +0.008322 +0.008388 +0.008385 +0.008406 +0.008387 +0.008353 +0.008405 +0.00847 +0.008468 +0.00849 +0.008465 +0.008437 +0.008492 +0.008559 +0.008553 +0.008567 +0.008551 +0.008514 +0.008576 +0.008647 +0.008644 +0.008663 +0.008649 +0.008622 +0.008684 +0.00876 +0.008743 +0.008702 +0.008609 +0.008552 +0.00858 +0.008611 +0.008548 +0.008472 +0.008385 +0.008317 +0.00834 +0.008388 +0.008321 +0.008319 +0.008225 +0.008157 +0.008179 +0.008208 +0.00818 +0.008164 +0.008137 +0.008073 +0.008094 +0.008117 +0.008097 +0.0081 +0.008082 +0.008047 +0.008081 +0.008147 +0.008114 +0.008133 +0.008122 +0.008079 +0.008107 +0.008149 +0.008129 +0.008147 +0.008138 +0.008105 +0.008168 +0.008228 +0.008226 +0.00824 +0.008223 +0.008207 +0.008256 +0.008337 +0.008293 +0.001087 +0.008326 +0.008312 +0.008284 +0.008347 +0.0084 +0.008396 +0.008409 +0.008388 +0.008362 +0.008423 +0.008487 +0.008468 +0.00848 +0.008454 +0.008419 +0.008478 +0.008533 +0.00852 +0.008533 +0.008505 +0.008482 +0.008541 +0.00863 +0.008646 +0.008656 +0.008621 +0.00858 +0.0086 +0.00863 +0.008586 +0.00856 +0.00848 +0.008398 +0.008391 +0.008414 +0.008361 +0.00832 +0.008249 +0.008185 +0.008191 +0.008225 +0.008194 +0.00817 +0.00812 +0.008071 +0.008082 +0.008122 +0.008108 +0.008101 +0.008064 +0.00803 +0.008054 +0.00811 +0.00809 +0.008094 +0.008067 +0.008042 +0.008077 +0.008139 +0.008134 +0.00814 +0.008118 +0.008098 +0.008145 +0.008211 +0.008204 +0.008221 +0.008205 +0.008173 +0.008216 +0.001088 +0.008298 +0.008278 +0.008308 +0.008277 +0.008257 +0.0083 +0.008374 +0.008363 +0.008387 +0.008358 +0.008338 +0.00838 +0.008455 +0.008445 +0.008466 +0.008441 +0.00842 +0.008463 +0.008541 +0.008528 +0.008562 +0.008521 +0.008521 +0.008566 +0.008645 +0.008635 +0.008659 +0.008639 +0.00857 +0.008534 +0.008573 +0.008526 +0.008523 +0.00846 +0.008409 +0.00841 +0.00838 +0.008318 +0.00831 +0.008244 +0.008215 +0.008174 +0.008202 +0.008151 +0.008136 +0.008104 +0.008051 +0.008088 +0.00811 +0.008055 +0.008055 +0.008 +0.007983 +0.007987 +0.008053 +0.008009 +0.008026 +0.008001 +0.007974 +0.008014 +0.008094 +0.008062 +0.008075 +0.008058 +0.008038 +0.008053 +0.008113 +0.008088 +0.008111 +0.008089 +0.008081 +0.008129 +0.008195 +0.008176 +0.008204 +0.008181 +0.008164 +0.001089 +0.008226 +0.008269 +0.008261 +0.008297 +0.00826 +0.008247 +0.00829 +0.00837 +0.008339 +0.008369 +0.008322 +0.008311 +0.00834 +0.00842 +0.008393 +0.008422 +0.008391 +0.00838 +0.008412 +0.008517 +0.008514 +0.008542 +0.008506 +0.008485 +0.008507 +0.008573 +0.008519 +0.008501 +0.008432 +0.008393 +0.008361 +0.008408 +0.008337 +0.008321 +0.008239 +0.008167 +0.008163 +0.008214 +0.008157 +0.008146 +0.008087 +0.008041 +0.008039 +0.008106 +0.008054 +0.008063 +0.008012 +0.007984 +0.008003 +0.008075 +0.008038 +0.008053 +0.008008 +0.007989 +0.008014 +0.008099 +0.008069 +0.008091 +0.008057 +0.008043 +0.008077 +0.008158 +0.008136 +0.008172 +0.00813 +0.008125 +0.008159 +0.008232 +0.00109 +0.008218 +0.00825 +0.008216 +0.008193 +0.008234 +0.008312 +0.008305 +0.008327 +0.008293 +0.008278 +0.008314 +0.008398 +0.00837 +0.008404 +0.008378 +0.008362 +0.008406 +0.008468 +0.008464 +0.008484 +0.008462 +0.008436 +0.008501 +0.008573 +0.008564 +0.008596 +0.00856 +0.008558 +0.008584 +0.008582 +0.008525 +0.008513 +0.00846 +0.008411 +0.008417 +0.008421 +0.008315 +0.0083 +0.008243 +0.008173 +0.008159 +0.008197 +0.008154 +0.008153 +0.008092 +0.008059 +0.008017 +0.008064 +0.00801 +0.008035 +0.007984 +0.007956 +0.007992 +0.008047 +0.008023 +0.008022 +0.007996 +0.007961 +0.007955 +0.008029 +0.007993 +0.008019 +0.007996 +0.00797 +0.008022 +0.0081 +0.008074 +0.008099 +0.008079 +0.008063 +0.008105 +0.00818 +0.00818 +0.008177 +0.001091 +0.008154 +0.008145 +0.008193 +0.008275 +0.008244 +0.008278 +0.008237 +0.008217 +0.008227 +0.008302 +0.008271 +0.008319 +0.008271 +0.008275 +0.008294 +0.008382 +0.008358 +0.008396 +0.008379 +0.008374 +0.008409 +0.008493 +0.00847 +0.008497 +0.008452 +0.008446 +0.008487 +0.008579 +0.008545 +0.008569 +0.008508 +0.008467 +0.008463 +0.008498 +0.008427 +0.008409 +0.008321 +0.008263 +0.008256 +0.008295 +0.008236 +0.008239 +0.008156 +0.008121 +0.008137 +0.008188 +0.008138 +0.008145 +0.008085 +0.008052 +0.008068 +0.008138 +0.008101 +0.008122 +0.008074 +0.00805 +0.008076 +0.008156 +0.00813 +0.00816 +0.008118 +0.008099 +0.008137 +0.00822 +0.008198 +0.008235 +0.008193 +0.008181 +0.008221 +0.008286 +0.001092 +0.008282 +0.008316 +0.008266 +0.008272 +0.008285 +0.008372 +0.008357 +0.008398 +0.008354 +0.008341 +0.008378 +0.008453 +0.008437 +0.008469 +0.008428 +0.008421 +0.00846 +0.008538 +0.008521 +0.008559 +0.008512 +0.008506 +0.008545 +0.008639 +0.008612 +0.008659 +0.008622 +0.008631 +0.008659 +0.008721 +0.008619 +0.008624 +0.008561 +0.008521 +0.008481 +0.008511 +0.00845 +0.008446 +0.008349 +0.008303 +0.008272 +0.008312 +0.008276 +0.008269 +0.008227 +0.008159 +0.008126 +0.00817 +0.008113 +0.008132 +0.008083 +0.008048 +0.008085 +0.008145 +0.008096 +0.008114 +0.008027 +0.008008 +0.008042 +0.008098 +0.008075 +0.0081 +0.008049 +0.00804 +0.008048 +0.008112 +0.00808 +0.008124 +0.008083 +0.008075 +0.00812 +0.008194 +0.008164 +0.008207 +0.008178 +0.008165 +0.008221 +0.008274 +0.001093 +0.008261 +0.008294 +0.00826 +0.008251 +0.008294 +0.008374 +0.008348 +0.008381 +0.008344 +0.00832 +0.008325 +0.008398 +0.008365 +0.0084 +0.008365 +0.00836 +0.008401 +0.008516 +0.00851 +0.008539 +0.008505 +0.008481 +0.00852 +0.008598 +0.008574 +0.008585 +0.008511 +0.008479 +0.008478 +0.008517 +0.008442 +0.008418 +0.008322 +0.008275 +0.00825 +0.008286 +0.008232 +0.008211 +0.008136 +0.008101 +0.0081 +0.008147 +0.008102 +0.008097 +0.008028 +0.007999 +0.008003 +0.008069 +0.008036 +0.008047 +0.00799 +0.007976 +0.007986 +0.008065 +0.008037 +0.008062 +0.008015 +0.008006 +0.008032 +0.008113 +0.008103 +0.008129 +0.008089 +0.008078 +0.008102 +0.00819 +0.008182 +0.008203 +0.001094 +0.008171 +0.008159 +0.008193 +0.00827 +0.008246 +0.00828 +0.008241 +0.008226 +0.008267 +0.008348 +0.008334 +0.008366 +0.008326 +0.008311 +0.008346 +0.008427 +0.00841 +0.008446 +0.008403 +0.008389 +0.008431 +0.008505 +0.008491 +0.008524 +0.008495 +0.008485 +0.008529 +0.008621 +0.008596 +0.008634 +0.008587 +0.008552 +0.008476 +0.00851 +0.008449 +0.00845 +0.008399 +0.008296 +0.008256 +0.008284 +0.008233 +0.008222 +0.008173 +0.008133 +0.008114 +0.008116 +0.008052 +0.00806 +0.008005 +0.007966 +0.007982 +0.008018 +0.007961 +0.00799 +0.007919 +0.007906 +0.0079 +0.007957 +0.007928 +0.007948 +0.007903 +0.007904 +0.00793 +0.008006 +0.00798 +0.008005 +0.007973 +0.007977 +0.008002 +0.008087 +0.008058 +0.008097 +0.008046 +0.008019 +0.008041 +0.001095 +0.008104 +0.008092 +0.008117 +0.008094 +0.008076 +0.008121 +0.008203 +0.008185 +0.008214 +0.008181 +0.008165 +0.008214 +0.008284 +0.008275 +0.008298 +0.008264 +0.008245 +0.008282 +0.008356 +0.008338 +0.008364 +0.008335 +0.008326 +0.008376 +0.008448 +0.008436 +0.008456 +0.008431 +0.008411 +0.008451 +0.008521 +0.008503 +0.008505 +0.00845 +0.008384 +0.008377 +0.008416 +0.008358 +0.008329 +0.008256 +0.008198 +0.008195 +0.008235 +0.008174 +0.008164 +0.008101 +0.008054 +0.008064 +0.008113 +0.00807 +0.008071 +0.008024 +0.007978 +0.008002 +0.008067 +0.008043 +0.00806 +0.008018 +0.007987 +0.008019 +0.008091 +0.008074 +0.008101 +0.008069 +0.008046 +0.008088 +0.008157 +0.008146 +0.008183 +0.008144 +0.008125 +0.008153 +0.001096 +0.008237 +0.008224 +0.008256 +0.008215 +0.008209 +0.008241 +0.008319 +0.0083 +0.008339 +0.008288 +0.008286 +0.008322 +0.008404 +0.008381 +0.008417 +0.008368 +0.008366 +0.008401 +0.008477 +0.008466 +0.008502 +0.008455 +0.008448 +0.008498 +0.008588 +0.008565 +0.008599 +0.008567 +0.008548 +0.00852 +0.00851 +0.008435 +0.008446 +0.008373 +0.008335 +0.00833 +0.008294 +0.008221 +0.008241 +0.008167 +0.008145 +0.008155 +0.008223 +0.00817 +0.008148 +0.008055 +0.008023 +0.008041 +0.008109 +0.008055 +0.008079 +0.008026 +0.00799 +0.007997 +0.008062 +0.008025 +0.008042 +0.008012 +0.008001 +0.00803 +0.008116 +0.008078 +0.008118 +0.008075 +0.008065 +0.008115 +0.008185 +0.008159 +0.008197 +0.008126 +0.008126 +0.001097 +0.008157 +0.008225 +0.008198 +0.008234 +0.008208 +0.008188 +0.008238 +0.008309 +0.008299 +0.008325 +0.008297 +0.008279 +0.008333 +0.008398 +0.008377 +0.008407 +0.008376 +0.008358 +0.008397 +0.00847 +0.008445 +0.008467 +0.008434 +0.008418 +0.008457 +0.008528 +0.00852 +0.008571 +0.008546 +0.008535 +0.008557 +0.008637 +0.008608 +0.008619 +0.008565 +0.00851 +0.008505 +0.008531 +0.008469 +0.008443 +0.008362 +0.008307 +0.008295 +0.008344 +0.008297 +0.008301 +0.008248 +0.0082 +0.008224 +0.008274 +0.008241 +0.008245 +0.008206 +0.008173 +0.008204 +0.008258 +0.008243 +0.008258 +0.008228 +0.008206 +0.008243 +0.008318 +0.008296 +0.008326 +0.008298 +0.008274 +0.00832 +0.008391 +0.008392 +0.008395 +0.001098 +0.008372 +0.008362 +0.008397 +0.008483 +0.008453 +0.008493 +0.008455 +0.008442 +0.008483 +0.008561 +0.00854 +0.008576 +0.008535 +0.008527 +0.008565 +0.008648 +0.008628 +0.008655 +0.008618 +0.00861 +0.008644 +0.008728 +0.008709 +0.008744 +0.008706 +0.0087 +0.008734 +0.008838 +0.008809 +0.008852 +0.008817 +0.008813 +0.008799 +0.008791 +0.008724 +0.00872 +0.008657 +0.008615 +0.00861 +0.008593 +0.008502 +0.008507 +0.008461 +0.008414 +0.008431 +0.008495 +0.008447 +0.008408 +0.008329 +0.008278 +0.008315 +0.00837 +0.00833 +0.008349 +0.008307 +0.008272 +0.008294 +0.008327 +0.008304 +0.008316 +0.008287 +0.008263 +0.008314 +0.008378 +0.008362 +0.008382 +0.00836 +0.008343 +0.008351 +0.008418 +0.008385 +0.008434 +0.008395 +0.008388 +0.008431 +0.008526 +0.00848 +0.001099 +0.008513 +0.008494 +0.008477 +0.00852 +0.008595 +0.008583 +0.008609 +0.008577 +0.00856 +0.008598 +0.008675 +0.008665 +0.008699 +0.008668 +0.008648 +0.008692 +0.008753 +0.008744 +0.008783 +0.008746 +0.008735 +0.008768 +0.008857 +0.008821 +0.008828 +0.008759 +0.00869 +0.008671 +0.008693 +0.008631 +0.00859 +0.008513 +0.00844 +0.00842 +0.008457 +0.008402 +0.008385 +0.00832 +0.00826 +0.008254 +0.008295 +0.00825 +0.008236 +0.008178 +0.008139 +0.008145 +0.008203 +0.008169 +0.008163 +0.008127 +0.008089 +0.008113 +0.008172 +0.008149 +0.008159 +0.008119 +0.008091 +0.00812 +0.008191 +0.008175 +0.008195 +0.008165 +0.008142 +0.008183 +0.008261 +0.008247 +0.008271 +0.008238 +0.008218 +0.008272 +0.008331 +0.0011 +0.008321 +0.008359 +0.008314 +0.008311 +0.008343 +0.008423 +0.008402 +0.008428 +0.008396 +0.008385 +0.008423 +0.008505 +0.008487 +0.008517 +0.008476 +0.008467 +0.008502 +0.008584 +0.008577 +0.008602 +0.008573 +0.008563 +0.008614 +0.008692 +0.008682 +0.008716 +0.008677 +0.008592 +0.008545 +0.008599 +0.008536 +0.008539 +0.008485 +0.008436 +0.008417 +0.00842 +0.008353 +0.008353 +0.008299 +0.008276 +0.008273 +0.008301 +0.008232 +0.008245 +0.008194 +0.008143 +0.008125 +0.008186 +0.008133 +0.008166 +0.008102 +0.008096 +0.008115 +0.0082 +0.008151 +0.008178 +0.008141 +0.008127 +0.008162 +0.008192 +0.008162 +0.00819 +0.008161 +0.00816 +0.008189 +0.00828 +0.008268 +0.008257 +0.008249 +0.008243 +0.008281 +0.008359 +0.008342 +0.008374 +0.001101 +0.008333 +0.008322 +0.008367 +0.008455 +0.008423 +0.008452 +0.00841 +0.008388 +0.008403 +0.008485 +0.008452 +0.008487 +0.008451 +0.00844 +0.008472 +0.008565 +0.00858 +0.008624 +0.008584 +0.008573 +0.008598 +0.008682 +0.008652 +0.00869 +0.008638 +0.008603 +0.008626 +0.008685 +0.00863 +0.008622 +0.008535 +0.008483 +0.008472 +0.00851 +0.008448 +0.008447 +0.008367 +0.008322 +0.008326 +0.008372 +0.008328 +0.008341 +0.008271 +0.008238 +0.00825 +0.008304 +0.00827 +0.008293 +0.008233 +0.008213 +0.008223 +0.00829 +0.008257 +0.008292 +0.008242 +0.008229 +0.008258 +0.008332 +0.008307 +0.008349 +0.008305 +0.008299 +0.008326 +0.008413 +0.008391 +0.008424 +0.008396 +0.00837 +0.001102 +0.008416 +0.008489 +0.008478 +0.00851 +0.00848 +0.00845 +0.008495 +0.008573 +0.008564 +0.008594 +0.008559 +0.008542 +0.008584 +0.008657 +0.008641 +0.008677 +0.008641 +0.008617 +0.008673 +0.008744 +0.008742 +0.00877 +0.008743 +0.008732 +0.008788 +0.008868 +0.008845 +0.008847 +0.008721 +0.008675 +0.008701 +0.008741 +0.008674 +0.008632 +0.008536 +0.008489 +0.008519 +0.008559 +0.008495 +0.00849 +0.00841 +0.008379 +0.008357 +0.008424 +0.008373 +0.008382 +0.00833 +0.008306 +0.008326 +0.008372 +0.008335 +0.008347 +0.008321 +0.008267 +0.008297 +0.008356 +0.008321 +0.008354 +0.008314 +0.008286 +0.008343 +0.008411 +0.008382 +0.008419 +0.008388 +0.008368 +0.008423 +0.00847 +0.008442 +0.008495 +0.00844 +0.001103 +0.008426 +0.00849 +0.008563 +0.00854 +0.008554 +0.008537 +0.008523 +0.008573 +0.00864 +0.008616 +0.008637 +0.008614 +0.008586 +0.008644 +0.008704 +0.008678 +0.008692 +0.008675 +0.008634 +0.008699 +0.008763 +0.008756 +0.0088 +0.008795 +0.008777 +0.008816 +0.008871 +0.008841 +0.008812 +0.008748 +0.008676 +0.008691 +0.008722 +0.008669 +0.008637 +0.008577 +0.008501 +0.008508 +0.008538 +0.008506 +0.008484 +0.008434 +0.008384 +0.008402 +0.008449 +0.00842 +0.008404 +0.008366 +0.008331 +0.008357 +0.00841 +0.00839 +0.008389 +0.008357 +0.008325 +0.008356 +0.008425 +0.008421 +0.008436 +0.008412 +0.008385 +0.008428 +0.0085 +0.008492 +0.008503 +0.00849 +0.008486 +0.008493 +0.008587 +0.001104 +0.008572 +0.008596 +0.008571 +0.008552 +0.008596 +0.008679 +0.008658 +0.008683 +0.008656 +0.008633 +0.008687 +0.00876 +0.008748 +0.008777 +0.008741 +0.008716 +0.008765 +0.008848 +0.008832 +0.008857 +0.008834 +0.008818 +0.00887 +0.008961 +0.008943 +0.00897 +0.008934 +0.008893 +0.008827 +0.008856 +0.008808 +0.008807 +0.008746 +0.008707 +0.008688 +0.008678 +0.008616 +0.008634 +0.008587 +0.008533 +0.008541 +0.008552 +0.008498 +0.008522 +0.00846 +0.008443 +0.008464 +0.008535 +0.008472 +0.008471 +0.008418 +0.008392 +0.008434 +0.008495 +0.008471 +0.008485 +0.008445 +0.008435 +0.008451 +0.008505 +0.008489 +0.008511 +0.008489 +0.008468 +0.008507 +0.008601 +0.008571 +0.008599 +0.008587 +0.008563 +0.008609 +0.001105 +0.008712 +0.008658 +0.008681 +0.008643 +0.008627 +0.008671 +0.008736 +0.008717 +0.008739 +0.008716 +0.008693 +0.008755 +0.008821 +0.008807 +0.008821 +0.008795 +0.008768 +0.008823 +0.008917 +0.008926 +0.008941 +0.008908 +0.008882 +0.008935 +0.009011 +0.008996 +0.009 +0.008936 +0.008877 +0.008874 +0.008897 +0.00885 +0.008809 +0.008726 +0.008662 +0.008654 +0.008676 +0.00864 +0.008605 +0.008542 +0.008487 +0.008496 +0.008534 +0.008495 +0.00848 +0.008432 +0.008384 +0.008406 +0.008456 +0.008446 +0.008441 +0.008409 +0.00837 +0.008396 +0.008454 +0.008444 +0.008461 +0.008436 +0.008407 +0.008449 +0.008515 +0.008512 +0.008519 +0.008503 +0.008477 +0.008529 +0.008599 +0.008605 +0.008611 +0.001106 +0.008577 +0.008565 +0.008615 +0.008686 +0.008672 +0.008702 +0.008674 +0.008651 +0.008696 +0.008774 +0.008771 +0.008784 +0.008756 +0.00874 +0.008788 +0.008862 +0.008847 +0.008882 +0.008843 +0.008821 +0.008875 +0.008959 +0.00895 +0.008985 +0.008952 +0.00894 +0.008991 +0.009062 +0.008945 +0.008906 +0.008842 +0.008754 +0.008728 +0.008758 +0.008693 +0.00869 +0.008609 +0.008509 +0.00852 +0.008564 +0.008519 +0.008515 +0.008465 +0.008391 +0.008365 +0.008424 +0.008375 +0.008391 +0.008351 +0.008329 +0.008364 +0.008423 +0.008395 +0.0084 +0.008381 +0.008349 +0.008406 +0.00844 +0.00839 +0.008424 +0.008376 +0.008381 +0.008421 +0.008477 +0.008464 +0.008478 +0.008452 +0.00844 +0.008481 +0.008564 +0.008552 +0.008588 +0.008533 +0.001107 +0.008526 +0.008589 +0.00865 +0.008623 +0.008643 +0.008621 +0.0086 +0.008656 +0.008719 +0.008705 +0.008709 +0.008686 +0.008657 +0.008704 +0.008769 +0.00876 +0.008779 +0.008759 +0.00875 +0.008823 +0.008902 +0.00889 +0.008907 +0.008873 +0.008841 +0.008867 +0.008904 +0.008875 +0.008852 +0.008774 +0.008705 +0.008706 +0.008721 +0.008683 +0.008649 +0.008574 +0.00852 +0.008533 +0.00856 +0.00853 +0.008519 +0.008466 +0.008412 +0.008433 +0.008461 +0.008443 +0.008454 +0.008411 +0.008376 +0.008407 +0.008454 +0.00844 +0.008444 +0.00841 +0.0084 +0.008444 +0.008512 +0.008501 +0.008512 +0.008483 +0.008463 +0.008511 +0.008591 +0.008579 +0.008607 +0.008566 +0.001108 +0.008553 +0.0086 +0.008674 +0.008671 +0.008685 +0.00866 +0.008629 +0.008685 +0.00876 +0.008756 +0.008774 +0.008744 +0.008717 +0.008773 +0.008844 +0.008838 +0.008855 +0.008827 +0.008803 +0.008857 +0.008931 +0.008929 +0.008951 +0.008932 +0.008912 +0.008975 +0.009037 +0.009034 +0.009037 +0.008997 +0.008882 +0.008859 +0.008875 +0.008837 +0.008826 +0.008757 +0.008674 +0.008646 +0.008656 +0.008629 +0.008618 +0.00858 +0.008526 +0.008561 +0.008575 +0.008518 +0.008502 +0.008483 +0.008425 +0.008425 +0.008487 +0.008443 +0.008462 +0.008428 +0.00839 +0.008448 +0.008508 +0.008488 +0.008508 +0.008472 +0.008449 +0.008505 +0.008566 +0.008567 +0.008575 +0.008535 +0.008509 +0.00851 +0.008607 +0.008588 +0.008605 +0.001109 +0.008597 +0.008566 +0.008624 +0.008699 +0.008687 +0.008707 +0.008684 +0.008662 +0.008721 +0.008789 +0.00878 +0.008795 +0.008772 +0.008743 +0.008802 +0.008856 +0.008849 +0.008863 +0.008843 +0.008813 +0.008879 +0.008961 +0.008966 +0.008972 +0.008945 +0.008917 +0.008953 +0.009023 +0.009002 +0.008959 +0.008902 +0.008842 +0.00884 +0.008875 +0.008823 +0.008792 +0.008723 +0.008663 +0.00867 +0.008708 +0.008676 +0.008655 +0.008603 +0.008549 +0.00857 +0.008615 +0.008592 +0.008579 +0.008538 +0.008503 +0.008534 +0.008591 +0.008573 +0.008563 +0.00853 +0.008505 +0.008545 +0.008613 +0.008599 +0.008601 +0.008579 +0.008552 +0.008604 +0.008681 +0.008675 +0.008684 +0.008671 +0.008634 +0.008691 +0.008765 +0.00111 +0.008754 +0.008781 +0.008749 +0.008721 +0.008779 +0.008853 +0.008844 +0.008864 +0.008833 +0.008817 +0.008867 +0.008937 +0.008933 +0.00896 +0.008923 +0.008907 +0.008959 +0.009033 +0.00903 +0.009057 +0.009027 +0.009023 +0.009078 +0.009163 +0.009133 +0.009082 +0.008991 +0.008923 +0.008962 +0.009004 +0.008915 +0.008858 +0.008771 +0.008718 +0.008741 +0.00877 +0.008707 +0.008686 +0.008606 +0.008544 +0.008551 +0.0086 +0.008541 +0.008555 +0.008506 +0.008475 +0.008503 +0.00853 +0.008498 +0.008506 +0.008461 +0.008447 +0.008479 +0.008569 +0.00853 +0.008548 +0.008535 +0.008501 +0.008517 +0.008588 +0.00855 +0.008588 +0.008565 +0.008545 +0.008593 +0.008681 +0.008656 +0.008684 +0.008663 +0.001111 +0.008648 +0.008705 +0.008758 +0.008746 +0.008789 +0.008741 +0.008738 +0.008779 +0.00887 +0.008842 +0.008875 +0.008832 +0.008814 +0.008852 +0.00893 +0.008888 +0.008921 +0.008887 +0.008871 +0.0089 +0.008994 +0.008975 +0.00905 +0.009008 +0.008984 +0.008999 +0.009045 +0.008967 +0.008951 +0.00886 +0.00881 +0.008787 +0.008813 +0.008751 +0.008745 +0.008653 +0.008598 +0.008606 +0.008657 +0.008592 +0.008607 +0.008534 +0.008492 +0.008499 +0.008549 +0.008512 +0.008539 +0.008476 +0.008449 +0.008463 +0.008535 +0.008476 +0.008511 +0.008464 +0.008456 +0.008491 +0.008564 +0.008535 +0.008564 +0.008522 +0.00851 +0.008546 +0.008634 +0.008621 +0.008648 +0.008626 +0.008585 +0.008641 +0.001112 +0.008735 +0.008691 +0.008735 +0.008698 +0.008689 +0.008726 +0.008817 +0.008784 +0.008823 +0.008783 +0.008773 +0.008811 +0.008898 +0.00888 +0.008915 +0.008868 +0.008859 +0.0089 +0.008998 +0.008964 +0.009012 +0.008972 +0.008969 +0.009017 +0.009115 +0.009082 +0.00908 +0.008934 +0.008891 +0.008882 +0.008922 +0.008842 +0.008797 +0.008686 +0.008645 +0.008649 +0.008694 +0.008631 +0.008636 +0.00853 +0.008492 +0.008485 +0.008548 +0.008479 +0.008506 +0.008442 +0.008424 +0.008445 +0.008489 +0.008442 +0.00845 +0.008418 +0.008383 +0.008423 +0.008481 +0.008434 +0.008482 +0.008409 +0.008417 +0.008418 +0.008481 +0.008451 +0.008484 +0.008449 +0.008447 +0.008485 +0.008567 +0.008548 +0.008576 +0.008544 +0.008544 +0.0086 +0.008651 +0.001113 +0.008631 +0.008673 +0.008634 +0.008626 +0.008667 +0.008755 +0.008724 +0.008755 +0.008723 +0.008699 +0.008708 +0.008779 +0.008747 +0.00878 +0.008753 +0.008746 +0.008796 +0.008913 +0.008905 +0.008933 +0.008888 +0.008872 +0.00891 +0.008984 +0.008938 +0.008951 +0.008881 +0.008836 +0.008828 +0.008871 +0.008804 +0.008791 +0.008694 +0.008636 +0.008628 +0.008679 +0.008614 +0.008613 +0.008533 +0.008499 +0.008496 +0.008554 +0.008505 +0.008513 +0.008451 +0.008427 +0.008442 +0.008513 +0.008478 +0.008502 +0.00844 +0.008421 +0.008451 +0.008531 +0.0085 +0.008533 +0.008481 +0.008479 +0.008506 +0.008597 +0.008581 +0.008611 +0.008566 +0.008559 +0.008599 +0.008681 +0.001114 +0.008671 +0.008695 +0.008664 +0.008638 +0.008681 +0.008759 +0.00875 +0.008782 +0.008749 +0.008728 +0.008774 +0.008851 +0.008831 +0.008865 +0.008833 +0.008816 +0.008868 +0.008939 +0.008926 +0.008955 +0.008922 +0.008912 +0.008959 +0.009048 +0.009034 +0.009062 +0.009038 +0.009026 +0.009061 +0.009049 +0.008969 +0.008974 +0.008915 +0.008854 +0.008844 +0.008819 +0.008759 +0.008753 +0.008692 +0.008643 +0.008638 +0.008673 +0.008598 +0.00861 +0.008532 +0.008483 +0.008477 +0.00854 +0.008483 +0.00851 +0.008464 +0.008444 +0.008472 +0.008536 +0.008502 +0.008499 +0.00846 +0.008412 +0.008452 +0.008513 +0.008477 +0.008511 +0.00848 +0.008455 +0.008524 +0.008587 +0.008573 +0.008597 +0.00857 +0.008549 +0.008598 +0.008688 +0.008656 +0.001115 +0.00868 +0.008634 +0.008617 +0.008663 +0.008722 +0.008708 +0.008728 +0.00871 +0.008687 +0.008749 +0.008818 +0.008809 +0.008822 +0.008796 +0.008765 +0.008815 +0.008887 +0.008887 +0.008928 +0.008908 +0.008875 +0.00893 +0.008992 +0.009001 +0.009013 +0.008995 +0.008949 +0.008976 +0.009029 +0.008981 +0.008943 +0.008875 +0.008793 +0.008791 +0.008819 +0.00876 +0.008724 +0.008658 +0.008592 +0.008594 +0.00863 +0.008592 +0.008568 +0.008513 +0.008453 +0.008477 +0.008527 +0.008497 +0.008491 +0.008453 +0.008404 +0.008437 +0.008494 +0.008479 +0.008479 +0.00845 +0.008414 +0.008453 +0.008524 +0.008512 +0.00853 +0.008509 +0.008479 +0.008531 +0.008597 +0.008606 +0.008611 +0.008591 +0.008567 +0.008608 +0.001116 +0.008687 +0.008684 +0.008704 +0.008669 +0.008648 +0.008702 +0.008778 +0.008775 +0.008782 +0.008755 +0.008733 +0.008782 +0.008862 +0.008852 +0.008877 +0.008843 +0.008831 +0.008874 +0.008962 +0.008941 +0.008978 +0.008935 +0.008929 +0.008995 +0.009075 +0.009056 +0.009081 +0.008961 +0.008887 +0.008894 +0.008955 +0.008873 +0.008798 +0.008725 +0.008659 +0.008639 +0.008689 +0.00861 +0.008602 +0.008556 +0.008446 +0.008461 +0.008503 +0.008443 +0.008451 +0.0084 +0.008361 +0.008383 +0.008397 +0.008368 +0.008367 +0.008333 +0.008303 +0.008333 +0.008402 +0.00837 +0.008387 +0.008357 +0.008315 +0.008338 +0.008389 +0.00836 +0.008402 +0.008369 +0.008355 +0.008405 +0.008472 +0.008459 +0.008491 +0.008462 +0.008443 +0.008513 +0.008565 +0.001117 +0.008551 +0.008588 +0.008551 +0.008545 +0.008583 +0.008673 +0.008643 +0.008682 +0.008643 +0.008638 +0.008652 +0.008714 +0.008672 +0.008701 +0.008668 +0.008655 +0.008696 +0.008785 +0.008771 +0.008836 +0.008799 +0.008793 +0.008819 +0.008909 +0.008883 +0.008913 +0.008857 +0.008834 +0.008851 +0.008897 +0.008823 +0.008805 +0.00871 +0.008652 +0.008628 +0.00865 +0.00859 +0.008578 +0.008488 +0.008434 +0.008436 +0.008482 +0.008424 +0.008418 +0.008352 +0.00832 +0.008328 +0.008373 +0.008337 +0.008364 +0.008305 +0.008282 +0.008302 +0.008363 +0.008328 +0.008352 +0.008314 +0.008303 +0.008332 +0.008404 +0.008383 +0.008413 +0.008367 +0.008357 +0.008386 +0.008467 +0.008459 +0.008493 +0.008468 +0.008438 +0.001118 +0.008475 +0.008562 +0.008526 +0.008572 +0.008538 +0.008529 +0.008564 +0.008653 +0.008618 +0.008659 +0.008614 +0.008604 +0.008639 +0.008728 +0.008701 +0.008739 +0.008705 +0.008692 +0.008735 +0.008826 +0.008798 +0.008844 +0.008811 +0.008803 +0.008849 +0.008949 +0.008916 +0.008925 +0.008795 +0.008757 +0.008767 +0.008825 +0.008755 +0.008702 +0.008595 +0.008548 +0.008547 +0.008594 +0.008511 +0.00851 +0.008441 +0.008363 +0.008369 +0.008433 +0.008359 +0.008389 +0.008326 +0.008305 +0.008333 +0.008388 +0.008347 +0.008333 +0.008294 +0.008276 +0.00829 +0.008372 +0.008323 +0.008353 +0.008316 +0.008299 +0.008349 +0.008431 +0.008385 +0.008432 +0.008372 +0.008347 +0.008386 +0.00846 +0.008432 +0.008478 +0.008442 +0.008426 +0.008486 +0.001119 +0.00856 +0.008533 +0.008562 +0.008537 +0.008525 +0.008569 +0.008657 +0.008622 +0.008656 +0.008624 +0.008607 +0.008658 +0.008731 +0.008698 +0.008719 +0.008681 +0.008659 +0.008702 +0.008778 +0.008762 +0.008783 +0.008757 +0.008762 +0.008831 +0.008895 +0.008887 +0.008883 +0.008832 +0.008783 +0.008781 +0.008814 +0.008775 +0.008744 +0.008658 +0.008595 +0.008585 +0.008618 +0.008565 +0.008553 +0.008487 +0.008439 +0.008452 +0.008498 +0.008462 +0.008453 +0.008397 +0.008368 +0.008385 +0.00844 +0.008421 +0.008426 +0.008382 +0.008357 +0.008385 +0.008456 +0.008431 +0.00845 +0.008409 +0.008398 +0.008428 +0.008508 +0.008496 +0.008513 +0.008487 +0.008472 +0.00851 +0.008597 +0.008575 +0.008594 +0.00112 +0.008576 +0.008544 +0.008608 +0.008666 +0.008665 +0.008683 +0.008659 +0.008633 +0.008684 +0.008759 +0.008749 +0.008772 +0.008748 +0.008722 +0.008775 +0.008847 +0.008844 +0.008857 +0.008838 +0.008805 +0.008891 +0.008947 +0.008946 +0.008979 +0.00896 +0.008911 +0.008884 +0.008912 +0.008864 +0.00886 +0.008809 +0.008741 +0.008776 +0.008795 +0.008685 +0.008662 +0.008598 +0.008531 +0.008535 +0.008564 +0.008532 +0.00851 +0.008476 +0.008416 +0.008449 +0.008437 +0.00842 +0.008422 +0.008388 +0.008352 +0.00839 +0.008456 +0.008427 +0.008431 +0.008413 +0.008345 +0.008372 +0.008435 +0.00841 +0.008442 +0.008411 +0.008385 +0.008452 +0.008507 +0.008506 +0.008525 +0.008503 +0.008482 +0.008542 +0.008623 +0.008585 +0.001121 +0.008611 +0.008598 +0.008572 +0.008633 +0.008708 +0.008678 +0.008667 +0.008647 +0.008621 +0.008684 +0.008757 +0.008736 +0.008752 +0.008728 +0.008698 +0.008746 +0.00882 +0.008804 +0.008829 +0.008804 +0.008788 +0.008871 +0.008942 +0.008936 +0.008945 +0.008919 +0.008878 +0.008912 +0.00895 +0.008913 +0.008877 +0.008802 +0.00872 +0.008721 +0.008727 +0.008674 +0.008639 +0.008572 +0.008504 +0.008511 +0.008544 +0.008506 +0.008486 +0.008436 +0.008374 +0.008401 +0.008452 +0.008424 +0.008421 +0.008385 +0.008339 +0.008377 +0.008433 +0.008415 +0.008418 +0.00839 +0.008347 +0.008391 +0.008461 +0.008448 +0.00846 +0.008445 +0.008412 +0.008458 +0.008533 +0.008525 +0.008547 +0.008518 +0.008506 +0.008535 +0.001122 +0.008623 +0.008605 +0.008631 +0.008605 +0.008586 +0.008626 +0.008703 +0.008693 +0.008719 +0.00869 +0.008676 +0.008709 +0.008792 +0.008779 +0.008799 +0.008772 +0.008755 +0.008793 +0.00888 +0.008864 +0.008897 +0.00886 +0.00885 +0.008909 +0.008988 +0.008975 +0.009 +0.00896 +0.008904 +0.008827 +0.008845 +0.00878 +0.00878 +0.008714 +0.008642 +0.008585 +0.008607 +0.008546 +0.008556 +0.008497 +0.008445 +0.008491 +0.00853 +0.008477 +0.008393 +0.008364 +0.008307 +0.008365 +0.008414 +0.008378 +0.008389 +0.00834 +0.008324 +0.008342 +0.008397 +0.008361 +0.008374 +0.008353 +0.008337 +0.008367 +0.008453 +0.008416 +0.008443 +0.008404 +0.008373 +0.008421 +0.008482 +0.008456 +0.008495 +0.008469 +0.008447 +0.00852 +0.008565 +0.001123 +0.008557 +0.008591 +0.008562 +0.008551 +0.008591 +0.008678 +0.008647 +0.008685 +0.008655 +0.008642 +0.008687 +0.008767 +0.008731 +0.008755 +0.008713 +0.008701 +0.008732 +0.008819 +0.008781 +0.008812 +0.008778 +0.008756 +0.008817 +0.008925 +0.008912 +0.008925 +0.00885 +0.008795 +0.008783 +0.008814 +0.00876 +0.00875 +0.008638 +0.008588 +0.008572 +0.008604 +0.008546 +0.008537 +0.008446 +0.008405 +0.008403 +0.008447 +0.00839 +0.008393 +0.008321 +0.008295 +0.008299 +0.008359 +0.008325 +0.008342 +0.008278 +0.008264 +0.00828 +0.00835 +0.008324 +0.008351 +0.008298 +0.008288 +0.008325 +0.008398 +0.008382 +0.008411 +0.008366 +0.008369 +0.008398 +0.008481 +0.008468 +0.008486 +0.001124 +0.008454 +0.008455 +0.008469 +0.00856 +0.008551 +0.008579 +0.008541 +0.008524 +0.008562 +0.00865 +0.008631 +0.008667 +0.008626 +0.008614 +0.008652 +0.008732 +0.00871 +0.008743 +0.008708 +0.008692 +0.008731 +0.008823 +0.008801 +0.008845 +0.008809 +0.008786 +0.008844 +0.008936 +0.008913 +0.008948 +0.008899 +0.008798 +0.008756 +0.008787 +0.008719 +0.008727 +0.008644 +0.008534 +0.008484 +0.008533 +0.008459 +0.008465 +0.008402 +0.008359 +0.008381 +0.008405 +0.008311 +0.008328 +0.008268 +0.008218 +0.00821 +0.008267 +0.008227 +0.008236 +0.008206 +0.008182 +0.008211 +0.008284 +0.008239 +0.008267 +0.008228 +0.008205 +0.008262 +0.008325 +0.008264 +0.008295 +0.00825 +0.008233 +0.008276 +0.008354 +0.008317 +0.00835 +0.008327 +0.00832 +0.008357 +0.00844 +0.008413 +0.008451 +0.008424 +0.001125 +0.008396 +0.008449 +0.008523 +0.008506 +0.008534 +0.008511 +0.008497 +0.008526 +0.008587 +0.008541 +0.008565 +0.008547 +0.00851 +0.008566 +0.00865 +0.008638 +0.008678 +0.008665 +0.008645 +0.008689 +0.008763 +0.008748 +0.008779 +0.008739 +0.008722 +0.008767 +0.008819 +0.008782 +0.008771 +0.008693 +0.008628 +0.008615 +0.008635 +0.008575 +0.008553 +0.008469 +0.008416 +0.008415 +0.008442 +0.008399 +0.008401 +0.008328 +0.008285 +0.008307 +0.008336 +0.008305 +0.008305 +0.008254 +0.008223 +0.008253 +0.008307 +0.008282 +0.008294 +0.008249 +0.008227 +0.008269 +0.008333 +0.008316 +0.008337 +0.008303 +0.008291 +0.008335 +0.008403 +0.008397 +0.008413 +0.008388 +0.008368 +0.008419 +0.001126 +0.008483 +0.008486 +0.008492 +0.008468 +0.00845 +0.0085 +0.008569 +0.008563 +0.00858 +0.008558 +0.008536 +0.008583 +0.008655 +0.008651 +0.008662 +0.00864 +0.008616 +0.008662 +0.008732 +0.008731 +0.008746 +0.008728 +0.0087 +0.008771 +0.008838 +0.008835 +0.008851 +0.008837 +0.008815 +0.00887 +0.008862 +0.008792 +0.008766 +0.008692 +0.008616 +0.008589 +0.008602 +0.008553 +0.008546 +0.008486 +0.008424 +0.008442 +0.008448 +0.00842 +0.008412 +0.008356 +0.008292 +0.008299 +0.008346 +0.008317 +0.008318 +0.008298 +0.008254 +0.008303 +0.008349 +0.008326 +0.0083 +0.008255 +0.008235 +0.008282 +0.008347 +0.008323 +0.00833 +0.008311 +0.008283 +0.008306 +0.008388 +0.00836 +0.00838 +0.008377 +0.008347 +0.008396 +0.008471 +0.008458 +0.008486 +0.008442 +0.001127 +0.008438 +0.008497 +0.008567 +0.008548 +0.008566 +0.008551 +0.008526 +0.008584 +0.008648 +0.008622 +0.008637 +0.008602 +0.008569 +0.008614 +0.008682 +0.008676 +0.008692 +0.008665 +0.008649 +0.008705 +0.008813 +0.00881 +0.008833 +0.008787 +0.008749 +0.008769 +0.008808 +0.008759 +0.008736 +0.008686 +0.008626 +0.008626 +0.008649 +0.008607 +0.008584 +0.008511 +0.008439 +0.008461 +0.008491 +0.008455 +0.008441 +0.008385 +0.008327 +0.008344 +0.008388 +0.008369 +0.008372 +0.00833 +0.00828 +0.008317 +0.008367 +0.008342 +0.00835 +0.008329 +0.0083 +0.008354 +0.008413 +0.008402 +0.008418 +0.00839 +0.008369 +0.008422 +0.008492 +0.008491 +0.00851 +0.008479 +0.008454 +0.001128 +0.008503 +0.008575 +0.008576 +0.008589 +0.008572 +0.008532 +0.008592 +0.008665 +0.008661 +0.008679 +0.008652 +0.008624 +0.008677 +0.008747 +0.00874 +0.008759 +0.008741 +0.008711 +0.008764 +0.008846 +0.00883 +0.008862 +0.008835 +0.008814 +0.008883 +0.008962 +0.008955 +0.008976 +0.00889 +0.008805 +0.008831 +0.008865 +0.008821 +0.008789 +0.008673 +0.008593 +0.008587 +0.008619 +0.008572 +0.00856 +0.008515 +0.008458 +0.008444 +0.008457 +0.008429 +0.008415 +0.008396 +0.008352 +0.008384 +0.008449 +0.008411 +0.008418 +0.008411 +0.008327 +0.008354 +0.008401 +0.008374 +0.008403 +0.008377 +0.008345 +0.008407 +0.008463 +0.008449 +0.008474 +0.008447 +0.008427 +0.008484 +0.008546 +0.008553 +0.008558 +0.008536 +0.001129 +0.008529 +0.008577 +0.008641 +0.008619 +0.008617 +0.008585 +0.008576 +0.008625 +0.0087 +0.00867 +0.008701 +0.008673 +0.008659 +0.008712 +0.008784 +0.008758 +0.008773 +0.008744 +0.008723 +0.008764 +0.008842 +0.008821 +0.008854 +0.008833 +0.008835 +0.008894 +0.008963 +0.008946 +0.008961 +0.008906 +0.008867 +0.008875 +0.00892 +0.008871 +0.008842 +0.008752 +0.0087 +0.008694 +0.008716 +0.008669 +0.008661 +0.008563 +0.008515 +0.008524 +0.008567 +0.008528 +0.00852 +0.008454 +0.008409 +0.008427 +0.008481 +0.008459 +0.00847 +0.008419 +0.008389 +0.00842 +0.008475 +0.008462 +0.008486 +0.008446 +0.008422 +0.00846 +0.008531 +0.008525 +0.008555 +0.008521 +0.008504 +0.008538 +0.008625 +0.008592 +0.008636 +0.00113 +0.008612 +0.008581 +0.008629 +0.008699 +0.008698 +0.008712 +0.008685 +0.00866 +0.008719 +0.008791 +0.008785 +0.0088 +0.008783 +0.00874 +0.0088 +0.008872 +0.008867 +0.008883 +0.008862 +0.008834 +0.008898 +0.00897 +0.008979 +0.008996 +0.008969 +0.008955 +0.00902 +0.009079 +0.008976 +0.008929 +0.008882 +0.008795 +0.008768 +0.008795 +0.008726 +0.008715 +0.008663 +0.008558 +0.00855 +0.008591 +0.008544 +0.008548 +0.008493 +0.008447 +0.008438 +0.00846 +0.008428 +0.00843 +0.008407 +0.008368 +0.008405 +0.008465 +0.008438 +0.008437 +0.008394 +0.008365 +0.008385 +0.008453 +0.008425 +0.008436 +0.008426 +0.008391 +0.008446 +0.008525 +0.008508 +0.008532 +0.008503 +0.008481 +0.008545 +0.008606 +0.008617 +0.001131 +0.008622 +0.008586 +0.008593 +0.008593 +0.008647 +0.008634 +0.008663 +0.008634 +0.008621 +0.008676 +0.008754 +0.008737 +0.008758 +0.008735 +0.008712 +0.008758 +0.008835 +0.008817 +0.008849 +0.008829 +0.008813 +0.008855 +0.008937 +0.008919 +0.008948 +0.008929 +0.008898 +0.008937 +0.00901 +0.008974 +0.008967 +0.008888 +0.008803 +0.008794 +0.008824 +0.008754 +0.008725 +0.008646 +0.008575 +0.008577 +0.008622 +0.008551 +0.008547 +0.008482 +0.008421 +0.008431 +0.008481 +0.008443 +0.008436 +0.008389 +0.008349 +0.00837 +0.008437 +0.008417 +0.008413 +0.00838 +0.008344 +0.008378 +0.008447 +0.00843 +0.008448 +0.008412 +0.008389 +0.008426 +0.008507 +0.008491 +0.008524 +0.008491 +0.008464 +0.008507 +0.008585 +0.008585 +0.001132 +0.008595 +0.008575 +0.008552 +0.008597 +0.008665 +0.008668 +0.008688 +0.008665 +0.008638 +0.008683 +0.008754 +0.008747 +0.008768 +0.008745 +0.008722 +0.00877 +0.00884 +0.008839 +0.008854 +0.008833 +0.008808 +0.00887 +0.008941 +0.008948 +0.008957 +0.008939 +0.008923 +0.009001 +0.009055 +0.008956 +0.008935 +0.008888 +0.008801 +0.008772 +0.008798 +0.008746 +0.008703 +0.008606 +0.008545 +0.008561 +0.008596 +0.008556 +0.008504 +0.008444 +0.00839 +0.008401 +0.008445 +0.008387 +0.008396 +0.008358 +0.008287 +0.008308 +0.008342 +0.008329 +0.008333 +0.008299 +0.008272 +0.008307 +0.008381 +0.008358 +0.008366 +0.008352 +0.008323 +0.00838 +0.008442 +0.008407 +0.008414 +0.008399 +0.008375 +0.008416 +0.008493 +0.008479 +0.008487 +0.00845 +0.008449 +0.001133 +0.008498 +0.008572 +0.008552 +0.00858 +0.008554 +0.008533 +0.008589 +0.008662 +0.008647 +0.008659 +0.008635 +0.008615 +0.008658 +0.008728 +0.008707 +0.008731 +0.008695 +0.008674 +0.008714 +0.008813 +0.008814 +0.008846 +0.008818 +0.008789 +0.00882 +0.008891 +0.008857 +0.008829 +0.008775 +0.008707 +0.008693 +0.008724 +0.008664 +0.008638 +0.008561 +0.008495 +0.008493 +0.008528 +0.008478 +0.008472 +0.008416 +0.008357 +0.008362 +0.008416 +0.008367 +0.008364 +0.008323 +0.008287 +0.00831 +0.008381 +0.008338 +0.00835 +0.008312 +0.008276 +0.008315 +0.008397 +0.008365 +0.00839 +0.008364 +0.00834 +0.008378 +0.008459 +0.008443 +0.008475 +0.008444 +0.008417 +0.00846 +0.008549 +0.001134 +0.00852 +0.00856 +0.00852 +0.008507 +0.00854 +0.00863 +0.008611 +0.008645 +0.008608 +0.008595 +0.008629 +0.008711 +0.008689 +0.008725 +0.008688 +0.00868 +0.008711 +0.008802 +0.008781 +0.008811 +0.008777 +0.008763 +0.008821 +0.008912 +0.008878 +0.008921 +0.008895 +0.008888 +0.008897 +0.008873 +0.008802 +0.008811 +0.008733 +0.00869 +0.008639 +0.00864 +0.008565 +0.008563 +0.008489 +0.00846 +0.008472 +0.008536 +0.008424 +0.008409 +0.008348 +0.008309 +0.008315 +0.008362 +0.008307 +0.00833 +0.008271 +0.008259 +0.008262 +0.008317 +0.008262 +0.008279 +0.008253 +0.008222 +0.008259 +0.008343 +0.008297 +0.008332 +0.008294 +0.008274 +0.008285 +0.008356 +0.008311 +0.008361 +0.008329 +0.008316 +0.008365 +0.008449 +0.008423 +0.008455 +0.008427 +0.008416 +0.001135 +0.00847 +0.008526 +0.008507 +0.008551 +0.008514 +0.008503 +0.008543 +0.008628 +0.008612 +0.008641 +0.008603 +0.008589 +0.008618 +0.0087 +0.008664 +0.008696 +0.008652 +0.00864 +0.008678 +0.008762 +0.008723 +0.008769 +0.008755 +0.008757 +0.008787 +0.008861 +0.008815 +0.008809 +0.008731 +0.008679 +0.008671 +0.008707 +0.008636 +0.008622 +0.008537 +0.00848 +0.008461 +0.008505 +0.00845 +0.008446 +0.008374 +0.008334 +0.008328 +0.008385 +0.008327 +0.008339 +0.008278 +0.008254 +0.008261 +0.008329 +0.008297 +0.008312 +0.008264 +0.008246 +0.008263 +0.008339 +0.008317 +0.008343 +0.008299 +0.008292 +0.008316 +0.008406 +0.008383 +0.008403 +0.008378 +0.008368 +0.008418 +0.008475 +0.008471 +0.001136 +0.008487 +0.008453 +0.008441 +0.008476 +0.00857 +0.008545 +0.008581 +0.008541 +0.00853 +0.008566 +0.008649 +0.008632 +0.00866 +0.008625 +0.008619 +0.008655 +0.008739 +0.008721 +0.008752 +0.008701 +0.008701 +0.008734 +0.008836 +0.008808 +0.008852 +0.008813 +0.008804 +0.008854 +0.008952 +0.008894 +0.008836 +0.008764 +0.008722 +0.008729 +0.008782 +0.008686 +0.008605 +0.008549 +0.008503 +0.008503 +0.008564 +0.008502 +0.008442 +0.008388 +0.00834 +0.008373 +0.008431 +0.008363 +0.008336 +0.008272 +0.008232 +0.008271 +0.008327 +0.008293 +0.008315 +0.008267 +0.008242 +0.008241 +0.008309 +0.008264 +0.008295 +0.00826 +0.008237 +0.00829 +0.00836 +0.00833 +0.008368 +0.008324 +0.00832 +0.00836 +0.008428 +0.008391 +0.008457 +0.008402 +0.008368 +0.001137 +0.008408 +0.008477 +0.008448 +0.008481 +0.008453 +0.008442 +0.008492 +0.008571 +0.00855 +0.008578 +0.008549 +0.008534 +0.008574 +0.008651 +0.008632 +0.008673 +0.008654 +0.008637 +0.008676 +0.008745 +0.008738 +0.008751 +0.008734 +0.008713 +0.00876 +0.008824 +0.00878 +0.008783 +0.008709 +0.008642 +0.008637 +0.008667 +0.008614 +0.008578 +0.008504 +0.008441 +0.008427 +0.008465 +0.008412 +0.008408 +0.008338 +0.00829 +0.008299 +0.008347 +0.008308 +0.008311 +0.008259 +0.008223 +0.00825 +0.008308 +0.008284 +0.008301 +0.008259 +0.008228 +0.008259 +0.008326 +0.008306 +0.008334 +0.008301 +0.008275 +0.00832 +0.008392 +0.008378 +0.008405 +0.008373 +0.008359 +0.008393 +0.008475 +0.001138 +0.008457 +0.008492 +0.008452 +0.008446 +0.008476 +0.008556 +0.008537 +0.008577 +0.008539 +0.008526 +0.008563 +0.008643 +0.008623 +0.008662 +0.008622 +0.008615 +0.008652 +0.008745 +0.008714 +0.00874 +0.00871 +0.008694 +0.00874 +0.008831 +0.00882 +0.008851 +0.008809 +0.008813 +0.008865 +0.008907 +0.008832 +0.008844 +0.008771 +0.008736 +0.00869 +0.008725 +0.008673 +0.008645 +0.008557 +0.00849 +0.008477 +0.008528 +0.008474 +0.008492 +0.008424 +0.008387 +0.00838 +0.008401 +0.008347 +0.00836 +0.008311 +0.008291 +0.008308 +0.00839 +0.008341 +0.008366 +0.008325 +0.008282 +0.008288 +0.008353 +0.008322 +0.008353 +0.008306 +0.008307 +0.008332 +0.00843 +0.008402 +0.008428 +0.008403 +0.008386 +0.008425 +0.008518 +0.008499 +0.008525 +0.001139 +0.00847 +0.008481 +0.008521 +0.008597 +0.008556 +0.008585 +0.00855 +0.008539 +0.008563 +0.008641 +0.008614 +0.008641 +0.008614 +0.008598 +0.008637 +0.008713 +0.008693 +0.008726 +0.008697 +0.008711 +0.008758 +0.008839 +0.008813 +0.008838 +0.008804 +0.008779 +0.008823 +0.008911 +0.008899 +0.008929 +0.008872 +0.008838 +0.008839 +0.008883 +0.008835 +0.008808 +0.008721 +0.008678 +0.008659 +0.008697 +0.008648 +0.008638 +0.008559 +0.008524 +0.00852 +0.008579 +0.008527 +0.008525 +0.008462 +0.008441 +0.008447 +0.008516 +0.008476 +0.008499 +0.008436 +0.008427 +0.008447 +0.008517 +0.008506 +0.008527 +0.008478 +0.008471 +0.008495 +0.008581 +0.008567 +0.008598 +0.008563 +0.008546 +0.008598 +0.008652 +0.008647 +0.00114 +0.008691 +0.008647 +0.00863 +0.008668 +0.008751 +0.008731 +0.008773 +0.008738 +0.008724 +0.008757 +0.008845 +0.008814 +0.008846 +0.008805 +0.008795 +0.008845 +0.008931 +0.008905 +0.008944 +0.008901 +0.008884 +0.008938 +0.009029 +0.009008 +0.009054 +0.009015 +0.009003 +0.009061 +0.009149 +0.009043 +0.009024 +0.008956 +0.008903 +0.008858 +0.008901 +0.00882 +0.008819 +0.008741 +0.008665 +0.008634 +0.0087 +0.008648 +0.00865 +0.008601 +0.008551 +0.00853 +0.008557 +0.008509 +0.008529 +0.008477 +0.008459 +0.008479 +0.008563 +0.008516 +0.008529 +0.008493 +0.008473 +0.008503 +0.008566 +0.008501 +0.008534 +0.008489 +0.008472 +0.008519 +0.008584 +0.008549 +0.008594 +0.008549 +0.008545 +0.008588 +0.008669 +0.008648 +0.00869 +0.008635 +0.008639 +0.001141 +0.008669 +0.008726 +0.0087 +0.008736 +0.00871 +0.008694 +0.00875 +0.008815 +0.008799 +0.008828 +0.008793 +0.008768 +0.008811 +0.008887 +0.008868 +0.008905 +0.008898 +0.008885 +0.008928 +0.008988 +0.008985 +0.009009 +0.008977 +0.008941 +0.008936 +0.008989 +0.008934 +0.008909 +0.00883 +0.008763 +0.00875 +0.008785 +0.008725 +0.008703 +0.008633 +0.008579 +0.008575 +0.008625 +0.008579 +0.008569 +0.008512 +0.008467 +0.008472 +0.008536 +0.008504 +0.008508 +0.008466 +0.00843 +0.008452 +0.008524 +0.0085 +0.008514 +0.008477 +0.008451 +0.008481 +0.008562 +0.008551 +0.008571 +0.008549 +0.008522 +0.008566 +0.008637 +0.00863 +0.008662 +0.008629 +0.001142 +0.008605 +0.008653 +0.008718 +0.008715 +0.008741 +0.008716 +0.008686 +0.008738 +0.008808 +0.008807 +0.008827 +0.008813 +0.00877 +0.008828 +0.008899 +0.008885 +0.008912 +0.008886 +0.008855 +0.008918 +0.008984 +0.008987 +0.009004 +0.008987 +0.008963 +0.009028 +0.009105 +0.009104 +0.009117 +0.009067 +0.008929 +0.008932 +0.008971 +0.008924 +0.008909 +0.008784 +0.008699 +0.008717 +0.008738 +0.00869 +0.008691 +0.008611 +0.008526 +0.008517 +0.008569 +0.008523 +0.00853 +0.008477 +0.008441 +0.008473 +0.008518 +0.008471 +0.008484 +0.008433 +0.008388 +0.008429 +0.00848 +0.008456 +0.008477 +0.008433 +0.008417 +0.008457 +0.008514 +0.008511 +0.008511 +0.008463 +0.008452 +0.008497 +0.008561 +0.008558 +0.008568 +0.008551 +0.008538 +0.008588 +0.008674 +0.008632 +0.001143 +0.008667 +0.008645 +0.008618 +0.008679 +0.008749 +0.008734 +0.008759 +0.008736 +0.008709 +0.008741 +0.008784 +0.008769 +0.008783 +0.008769 +0.008743 +0.008797 +0.008879 +0.008904 +0.008931 +0.0089 +0.008875 +0.008918 +0.008987 +0.008966 +0.008958 +0.008917 +0.008841 +0.008836 +0.008853 +0.008809 +0.008766 +0.008691 +0.008616 +0.008608 +0.008635 +0.008594 +0.008571 +0.008517 +0.008459 +0.008468 +0.008515 +0.008481 +0.008453 +0.008425 +0.008382 +0.008409 +0.008461 +0.008438 +0.008434 +0.008411 +0.008378 +0.008405 +0.008465 +0.008447 +0.00846 +0.008444 +0.008416 +0.008458 +0.008531 +0.008521 +0.008529 +0.008511 +0.008473 +0.008532 +0.008596 +0.008613 +0.008617 +0.001144 +0.008593 +0.008575 +0.008617 +0.008694 +0.008676 +0.008704 +0.008674 +0.008663 +0.008709 +0.008784 +0.008771 +0.008793 +0.008759 +0.008743 +0.008789 +0.008872 +0.008855 +0.008883 +0.008844 +0.00884 +0.008893 +0.008968 +0.008965 +0.009 +0.008964 +0.008929 +0.008867 +0.008887 +0.008832 +0.00883 +0.008766 +0.008709 +0.008702 +0.008668 +0.008595 +0.008587 +0.008525 +0.008485 +0.008447 +0.008477 +0.008408 +0.008418 +0.008377 +0.00833 +0.008308 +0.008347 +0.008293 +0.008324 +0.008279 +0.008259 +0.008287 +0.00835 +0.008323 +0.008331 +0.008304 +0.008284 +0.008324 +0.008392 +0.008339 +0.008355 +0.008332 +0.008307 +0.008333 +0.008415 +0.008386 +0.008408 +0.008393 +0.008376 +0.008423 +0.008496 +0.008488 +0.008518 +0.008471 +0.008461 +0.001145 +0.008512 +0.008584 +0.008574 +0.008593 +0.008575 +0.008545 +0.008607 +0.008678 +0.008662 +0.008677 +0.008651 +0.008619 +0.008671 +0.008736 +0.008715 +0.008728 +0.008702 +0.008682 +0.008728 +0.008793 +0.008815 +0.008842 +0.008837 +0.008788 +0.008839 +0.00889 +0.008852 +0.008831 +0.008758 +0.008695 +0.008697 +0.008715 +0.008648 +0.008635 +0.008567 +0.008491 +0.008513 +0.008544 +0.008505 +0.008502 +0.008455 +0.008398 +0.008424 +0.008469 +0.008439 +0.008449 +0.00841 +0.008369 +0.008406 +0.00846 +0.008444 +0.008452 +0.008427 +0.008393 +0.008441 +0.0085 +0.008491 +0.008508 +0.008493 +0.008461 +0.008522 +0.008579 +0.008577 +0.008592 +0.008558 +0.001146 +0.008533 +0.008598 +0.008663 +0.008657 +0.008677 +0.008649 +0.008621 +0.00868 +0.008751 +0.008745 +0.008757 +0.008737 +0.008711 +0.008767 +0.00884 +0.008829 +0.008851 +0.008817 +0.008792 +0.008851 +0.008917 +0.00892 +0.00894 +0.008922 +0.008889 +0.00896 +0.009031 +0.009015 +0.009044 +0.009019 +0.008981 +0.008964 +0.008945 +0.008891 +0.00889 +0.008836 +0.00877 +0.008763 +0.00873 +0.008683 +0.008688 +0.008639 +0.008582 +0.008625 +0.008659 +0.008633 +0.008545 +0.008505 +0.008445 +0.008497 +0.008541 +0.008518 +0.008515 +0.008491 +0.00845 +0.008492 +0.008529 +0.008487 +0.008523 +0.008496 +0.008458 +0.008498 +0.008538 +0.008531 +0.008549 +0.008529 +0.008512 +0.008567 +0.008632 +0.008631 +0.008648 +0.008625 +0.008611 +0.008658 +0.001147 +0.008719 +0.008709 +0.008738 +0.00871 +0.008686 +0.008749 +0.008825 +0.008814 +0.008816 +0.008792 +0.008761 +0.008835 +0.008896 +0.008878 +0.008887 +0.008858 +0.008827 +0.008876 +0.008939 +0.008932 +0.008948 +0.008922 +0.008898 +0.008966 +0.009063 +0.009051 +0.009041 +0.008968 +0.008897 +0.008889 +0.0089 +0.008872 +0.008845 +0.008765 +0.008696 +0.008707 +0.008742 +0.008717 +0.008709 +0.008663 +0.008604 +0.008631 +0.008674 +0.00865 +0.008655 +0.008612 +0.008569 +0.008598 +0.008646 +0.008637 +0.008651 +0.008611 +0.008581 +0.008616 +0.008665 +0.00866 +0.008672 +0.008656 +0.00863 +0.008677 +0.008734 +0.008735 +0.008738 +0.008716 +0.008706 +0.008749 +0.008835 +0.001148 +0.008811 +0.00884 +0.008803 +0.008779 +0.00884 +0.008914 +0.0089 +0.008923 +0.008897 +0.008878 +0.008928 +0.009005 +0.008991 +0.009014 +0.008985 +0.008955 +0.009004 +0.009087 +0.009071 +0.009099 +0.00907 +0.00905 +0.009109 +0.009194 +0.009179 +0.009209 +0.009185 +0.009167 +0.009214 +0.009285 +0.009206 +0.009107 +0.009042 +0.008987 +0.008982 +0.008963 +0.008895 +0.008882 +0.008826 +0.008751 +0.008739 +0.008739 +0.008682 +0.008687 +0.008623 +0.008588 +0.008594 +0.008616 +0.008552 +0.008569 +0.008514 +0.008488 +0.008471 +0.008528 +0.008474 +0.008501 +0.008475 +0.00843 +0.008483 +0.00855 +0.008521 +0.008539 +0.008512 +0.008487 +0.008552 +0.008624 +0.008579 +0.008591 +0.008559 +0.008536 +0.008587 +0.008677 +0.008649 +0.008666 +0.001149 +0.008639 +0.008638 +0.008676 +0.008756 +0.008723 +0.008767 +0.008735 +0.008726 +0.008766 +0.008838 +0.008798 +0.008835 +0.008797 +0.008782 +0.008823 +0.008902 +0.008875 +0.008905 +0.008866 +0.00885 +0.008883 +0.008978 +0.008978 +0.009032 +0.009 +0.008979 +0.00901 +0.009089 +0.009042 +0.009051 +0.008963 +0.008912 +0.008908 +0.008942 +0.008856 +0.008856 +0.008765 +0.008704 +0.008698 +0.008746 +0.008691 +0.008701 +0.00863 +0.008586 +0.008586 +0.008643 +0.008596 +0.008619 +0.008562 +0.008528 +0.008545 +0.008617 +0.00857 +0.008602 +0.008559 +0.008533 +0.008558 +0.008626 +0.008588 +0.008618 +0.008579 +0.00857 +0.008613 +0.008692 +0.008659 +0.008701 +0.008647 +0.008641 +0.008683 +0.008757 +0.008752 +0.00115 +0.00878 +0.008745 +0.008736 +0.008774 +0.008855 +0.008831 +0.008864 +0.008822 +0.00882 +0.008857 +0.008948 +0.008922 +0.00896 +0.008915 +0.008901 +0.008937 +0.009026 +0.009006 +0.00904 +0.00901 +0.009 +0.009037 +0.009132 +0.00911 +0.009153 +0.009115 +0.009105 +0.009151 +0.009218 +0.009096 +0.009055 +0.008975 +0.008916 +0.008882 +0.008904 +0.008814 +0.008811 +0.008736 +0.008699 +0.008655 +0.008661 +0.008598 +0.008598 +0.008547 +0.008488 +0.008466 +0.008477 +0.008439 +0.008444 +0.008399 +0.00837 +0.00839 +0.008444 +0.00838 +0.008406 +0.008338 +0.008315 +0.008339 +0.008396 +0.00836 +0.008388 +0.008352 +0.00835 +0.008386 +0.008462 +0.008445 +0.008477 +0.008439 +0.008443 +0.008475 +0.008555 +0.008534 +0.008561 +0.001151 +0.008534 +0.008515 +0.00855 +0.008601 +0.008574 +0.008605 +0.008579 +0.008574 +0.008614 +0.008692 +0.008673 +0.008696 +0.008667 +0.008646 +0.008687 +0.008763 +0.008749 +0.008788 +0.008779 +0.008762 +0.008802 +0.00888 +0.008862 +0.008883 +0.008843 +0.008823 +0.008849 +0.008913 +0.008874 +0.008853 +0.00877 +0.008709 +0.008692 +0.008716 +0.008668 +0.008651 +0.00856 +0.008515 +0.008515 +0.008556 +0.008526 +0.008521 +0.008459 +0.008429 +0.008441 +0.008497 +0.008463 +0.008469 +0.008426 +0.00841 +0.008431 +0.008495 +0.008465 +0.008474 +0.008426 +0.008413 +0.008455 +0.00852 +0.008509 +0.008522 +0.008487 +0.008475 +0.008509 +0.008591 +0.008578 +0.008608 +0.008583 +0.00855 +0.001152 +0.008595 +0.008683 +0.008657 +0.008697 +0.008649 +0.008646 +0.008682 +0.008765 +0.008743 +0.008781 +0.008743 +0.008737 +0.008772 +0.008859 +0.008835 +0.008872 +0.008829 +0.008814 +0.008865 +0.008943 +0.008935 +0.008976 +0.008933 +0.008932 +0.008985 +0.009076 +0.008986 +0.008953 +0.008871 +0.008841 +0.008838 +0.008847 +0.008777 +0.008752 +0.008656 +0.008611 +0.008589 +0.008621 +0.008575 +0.008575 +0.008509 +0.00844 +0.008408 +0.008482 +0.008408 +0.008439 +0.008375 +0.008353 +0.008384 +0.008451 +0.008415 +0.008427 +0.008394 +0.008357 +0.008337 +0.008413 +0.008366 +0.008398 +0.008366 +0.008346 +0.008388 +0.008473 +0.008444 +0.008477 +0.008445 +0.008431 +0.008473 +0.008563 +0.008539 +0.008568 +0.008531 +0.001153 +0.008531 +0.008568 +0.008653 +0.008633 +0.008668 +0.008609 +0.008577 +0.008598 +0.008688 +0.008659 +0.008689 +0.008659 +0.008647 +0.008688 +0.008769 +0.008752 +0.008782 +0.008751 +0.008762 +0.008802 +0.008889 +0.008867 +0.0089 +0.008839 +0.008839 +0.008867 +0.008947 +0.008933 +0.008933 +0.008843 +0.008783 +0.008765 +0.008787 +0.008717 +0.008695 +0.00858 +0.008545 +0.008519 +0.008556 +0.008494 +0.008486 +0.00841 +0.008377 +0.008373 +0.008424 +0.008384 +0.008387 +0.008323 +0.008293 +0.008307 +0.008374 +0.008354 +0.008368 +0.008316 +0.008301 +0.008317 +0.008391 +0.008377 +0.008405 +0.008355 +0.008351 +0.008375 +0.008455 +0.008438 +0.008473 +0.008435 +0.008428 +0.008459 +0.00854 +0.001154 +0.008522 +0.008557 +0.008523 +0.008502 +0.008545 +0.008625 +0.008615 +0.008633 +0.008604 +0.008589 +0.008633 +0.00871 +0.008697 +0.008723 +0.008685 +0.008677 +0.008721 +0.008795 +0.008786 +0.008814 +0.008776 +0.008763 +0.008812 +0.0089 +0.00889 +0.008916 +0.008894 +0.008881 +0.008935 +0.008942 +0.008894 +0.008879 +0.008836 +0.008794 +0.008804 +0.008805 +0.008728 +0.008695 +0.008632 +0.008563 +0.008538 +0.008581 +0.008525 +0.008525 +0.008484 +0.008436 +0.008418 +0.008437 +0.008388 +0.008394 +0.008371 +0.008325 +0.008374 +0.008426 +0.008386 +0.008407 +0.00836 +0.008337 +0.008373 +0.008409 +0.00837 +0.008403 +0.008368 +0.008344 +0.008402 +0.00847 +0.008442 +0.008473 +0.008447 +0.008429 +0.008484 +0.008568 +0.008547 +0.008543 +0.008503 +0.001155 +0.008499 +0.008541 +0.008631 +0.008598 +0.008629 +0.008592 +0.008584 +0.008634 +0.008719 +0.008682 +0.008718 +0.008677 +0.008666 +0.008705 +0.008783 +0.008743 +0.008775 +0.008737 +0.008725 +0.008761 +0.008851 +0.008826 +0.008873 +0.008865 +0.008853 +0.008889 +0.008966 +0.008922 +0.008929 +0.008844 +0.008779 +0.008769 +0.008816 +0.008733 +0.008715 +0.008625 +0.008558 +0.008545 +0.008586 +0.008506 +0.008517 +0.008441 +0.008398 +0.008398 +0.008451 +0.008395 +0.008415 +0.008351 +0.008316 +0.008338 +0.008404 +0.008366 +0.008388 +0.008338 +0.008314 +0.008337 +0.008411 +0.008387 +0.008418 +0.008378 +0.008361 +0.008393 +0.008474 +0.008441 +0.008478 +0.008442 +0.008441 +0.008479 +0.008554 +0.008542 +0.001156 +0.008558 +0.008525 +0.008509 +0.008552 +0.008634 +0.008615 +0.00865 +0.008618 +0.008597 +0.008642 +0.008719 +0.00871 +0.008722 +0.008699 +0.008682 +0.008729 +0.008801 +0.008794 +0.008821 +0.008785 +0.008774 +0.008824 +0.008915 +0.008897 +0.008925 +0.008902 +0.008885 +0.00893 +0.008922 +0.008845 +0.008845 +0.008796 +0.008731 +0.008688 +0.008708 +0.008651 +0.008642 +0.008583 +0.00854 +0.008527 +0.008525 +0.008484 +0.008488 +0.008434 +0.008395 +0.008383 +0.008418 +0.00837 +0.00838 +0.008351 +0.008307 +0.008359 +0.008412 +0.008381 +0.0084 +0.008333 +0.00831 +0.00833 +0.008386 +0.008377 +0.008389 +0.008359 +0.008347 +0.008393 +0.008465 +0.008446 +0.00847 +0.008446 +0.008438 +0.008485 +0.008572 +0.008529 +0.001157 +0.008567 +0.008541 +0.008514 +0.008578 +0.008655 +0.00863 +0.008632 +0.008591 +0.008564 +0.008625 +0.0087 +0.008675 +0.008696 +0.008672 +0.008642 +0.008699 +0.008762 +0.008753 +0.008773 +0.008772 +0.008765 +0.008816 +0.008885 +0.00887 +0.008886 +0.008849 +0.008813 +0.008846 +0.008881 +0.008839 +0.008808 +0.00872 +0.008655 +0.008655 +0.008663 +0.008617 +0.008587 +0.008506 +0.008436 +0.008453 +0.00848 +0.008439 +0.008426 +0.008363 +0.008308 +0.008318 +0.008357 +0.008343 +0.008341 +0.0083 +0.008259 +0.008287 +0.008342 +0.008322 +0.008335 +0.008309 +0.008285 +0.008328 +0.00839 +0.008388 +0.008401 +0.00838 +0.008361 +0.008406 +0.008477 +0.008472 +0.008481 +0.008454 +0.001158 +0.008446 +0.008479 +0.008574 +0.008538 +0.008569 +0.008539 +0.008529 +0.008568 +0.008649 +0.008632 +0.008655 +0.008626 +0.008599 +0.008647 +0.008729 +0.008712 +0.00874 +0.008712 +0.008693 +0.008734 +0.008812 +0.008802 +0.008825 +0.0088 +0.008783 +0.008839 +0.008928 +0.008901 +0.008944 +0.00892 +0.008902 +0.008861 +0.008881 +0.008831 +0.00883 +0.00877 +0.008707 +0.008729 +0.008698 +0.008605 +0.008597 +0.008512 +0.008472 +0.008452 +0.008486 +0.008447 +0.008432 +0.008397 +0.008331 +0.008336 +0.008338 +0.008313 +0.008323 +0.008277 +0.008254 +0.008276 +0.008342 +0.008305 +0.008319 +0.008293 +0.008236 +0.008253 +0.008312 +0.008271 +0.008317 +0.008275 +0.008249 +0.00831 +0.008377 +0.008361 +0.00839 +0.008354 +0.008345 +0.008397 +0.008468 +0.008457 +0.008483 +0.001159 +0.008448 +0.00844 +0.008477 +0.008574 +0.008539 +0.008571 +0.008513 +0.008497 +0.008521 +0.008603 +0.008576 +0.008605 +0.008568 +0.008555 +0.008592 +0.008682 +0.008648 +0.008703 +0.008682 +0.008675 +0.00871 +0.008788 +0.008761 +0.008809 +0.008768 +0.008758 +0.00879 +0.008866 +0.008832 +0.008841 +0.008754 +0.00871 +0.008691 +0.008723 +0.008654 +0.008639 +0.008541 +0.008493 +0.008474 +0.008515 +0.008459 +0.008464 +0.008388 +0.008352 +0.008347 +0.0084 +0.00836 +0.008375 +0.008311 +0.008295 +0.008312 +0.008377 +0.008354 +0.008366 +0.008314 +0.008308 +0.008333 +0.008411 +0.008389 +0.008413 +0.008374 +0.008368 +0.008401 +0.008482 +0.008465 +0.008495 +0.008459 +0.008443 +0.00116 +0.008495 +0.008559 +0.008555 +0.008573 +0.008536 +0.008522 +0.00857 +0.008646 +0.008635 +0.008657 +0.008626 +0.008613 +0.008652 +0.008733 +0.008716 +0.008743 +0.008707 +0.008695 +0.008747 +0.008806 +0.008808 +0.00883 +0.008801 +0.008782 +0.008848 +0.008927 +0.008902 +0.008941 +0.00892 +0.0089 +0.008896 +0.008868 +0.008816 +0.008812 +0.008756 +0.008696 +0.008646 +0.008639 +0.008589 +0.008586 +0.00853 +0.008474 +0.008502 +0.008553 +0.008484 +0.008421 +0.008357 +0.008311 +0.008337 +0.008403 +0.008345 +0.008374 +0.008317 +0.008263 +0.00827 +0.008323 +0.008308 +0.00832 +0.008286 +0.008269 +0.008297 +0.008381 +0.008348 +0.008377 +0.008343 +0.008338 +0.008385 +0.008452 +0.008435 +0.008459 +0.008427 +0.008409 +0.008444 +0.001161 +0.008485 +0.008467 +0.008492 +0.008481 +0.008453 +0.008515 +0.008572 +0.008567 +0.008587 +0.008572 +0.008545 +0.008601 +0.008671 +0.008659 +0.008674 +0.008648 +0.00862 +0.008664 +0.00874 +0.008747 +0.00878 +0.008753 +0.008724 +0.008767 +0.008842 +0.008827 +0.008848 +0.008828 +0.008802 +0.008843 +0.008886 +0.008846 +0.008826 +0.008749 +0.008673 +0.008677 +0.008692 +0.008641 +0.008614 +0.00854 +0.008472 +0.008491 +0.008518 +0.008485 +0.008478 +0.00842 +0.008364 +0.008388 +0.008427 +0.008406 +0.008409 +0.00837 +0.008326 +0.008368 +0.00841 +0.008396 +0.008418 +0.008387 +0.008354 +0.008411 +0.008456 +0.00846 +0.008481 +0.008455 +0.008432 +0.00848 +0.008543 +0.008545 +0.008566 +0.001162 +0.008538 +0.008514 +0.008559 +0.008636 +0.008621 +0.008653 +0.008624 +0.008599 +0.008641 +0.008723 +0.008707 +0.008739 +0.008703 +0.008687 +0.008735 +0.008797 +0.008794 +0.008825 +0.00879 +0.008771 +0.008826 +0.008896 +0.008893 +0.00892 +0.008893 +0.008889 +0.008945 +0.009033 +0.008988 +0.00893 +0.008883 +0.008836 +0.008866 +0.008912 +0.008849 +0.008839 +0.008693 +0.008623 +0.008627 +0.008686 +0.008619 +0.008601 +0.008518 +0.008448 +0.00846 +0.00849 +0.008456 +0.008437 +0.0084 +0.008351 +0.008339 +0.008388 +0.008338 +0.008354 +0.008321 +0.00828 +0.00832 +0.008393 +0.008347 +0.00837 +0.00834 +0.008287 +0.008306 +0.008362 +0.008334 +0.008379 +0.008347 +0.008325 +0.008382 +0.008454 +0.008435 +0.00847 +0.008443 +0.008421 +0.008482 +0.008544 +0.008537 +0.001163 +0.008563 +0.008539 +0.008514 +0.008566 +0.008643 +0.008633 +0.008657 +0.008628 +0.008608 +0.008661 +0.008723 +0.008704 +0.008711 +0.00868 +0.008655 +0.008707 +0.00877 +0.008747 +0.008768 +0.008739 +0.008724 +0.008791 +0.008875 +0.00886 +0.008836 +0.008769 +0.008706 +0.008712 +0.008729 +0.008679 +0.008641 +0.008562 +0.008497 +0.008494 +0.008518 +0.008486 +0.008453 +0.008393 +0.008344 +0.008357 +0.008391 +0.008365 +0.00835 +0.008303 +0.008262 +0.008292 +0.008346 +0.008333 +0.008326 +0.008292 +0.008258 +0.0083 +0.008359 +0.008352 +0.008359 +0.00833 +0.008306 +0.008352 +0.00842 +0.008422 +0.008431 +0.008414 +0.008382 +0.008442 +0.008501 +0.008503 +0.001164 +0.008522 +0.008493 +0.008467 +0.008508 +0.008591 +0.008588 +0.008607 +0.008575 +0.008556 +0.008595 +0.008675 +0.008662 +0.008696 +0.008659 +0.00864 +0.00869 +0.008766 +0.008745 +0.008782 +0.008741 +0.008732 +0.008773 +0.00886 +0.008841 +0.008879 +0.008856 +0.008844 +0.0089 +0.00893 +0.00886 +0.008859 +0.008804 +0.008768 +0.008741 +0.008744 +0.008683 +0.008686 +0.008599 +0.00852 +0.008506 +0.008558 +0.008499 +0.008521 +0.008456 +0.008374 +0.008354 +0.008407 +0.008358 +0.008377 +0.008325 +0.008299 +0.00833 +0.008384 +0.008351 +0.008347 +0.008278 +0.008253 +0.008281 +0.008353 +0.008321 +0.008338 +0.008322 +0.008293 +0.008316 +0.008378 +0.008356 +0.00838 +0.008367 +0.008344 +0.008392 +0.008473 +0.008452 +0.008477 +0.008471 +0.008424 +0.001165 +0.008478 +0.008567 +0.00854 +0.008574 +0.008534 +0.008529 +0.008563 +0.008656 +0.008624 +0.008659 +0.008617 +0.0086 +0.008617 +0.008692 +0.008656 +0.008689 +0.008655 +0.008645 +0.008684 +0.008784 +0.00879 +0.008832 +0.008787 +0.008772 +0.008797 +0.008861 +0.008814 +0.008809 +0.008734 +0.008692 +0.008676 +0.008705 +0.008636 +0.008634 +0.00854 +0.00848 +0.008474 +0.008518 +0.00847 +0.008476 +0.008398 +0.008357 +0.008361 +0.008412 +0.008369 +0.008389 +0.008329 +0.008302 +0.008314 +0.008375 +0.00834 +0.008373 +0.008319 +0.008301 +0.008321 +0.008391 +0.008375 +0.008417 +0.008371 +0.008367 +0.008399 +0.008474 +0.008456 +0.008477 +0.008447 +0.008427 +0.008475 +0.001166 +0.008553 +0.008542 +0.008569 +0.00853 +0.008516 +0.008567 +0.008631 +0.008624 +0.008655 +0.008617 +0.008601 +0.008644 +0.00872 +0.008709 +0.008742 +0.008704 +0.008691 +0.008735 +0.008812 +0.008803 +0.008835 +0.008803 +0.008792 +0.008854 +0.008933 +0.008909 +0.008954 +0.008854 +0.00881 +0.008835 +0.008884 +0.008833 +0.008821 +0.008753 +0.008648 +0.008631 +0.00867 +0.008627 +0.008629 +0.008558 +0.008512 +0.008539 +0.008534 +0.008464 +0.008486 +0.008423 +0.008402 +0.008395 +0.008441 +0.008401 +0.008416 +0.008377 +0.008357 +0.008391 +0.008457 +0.008409 +0.00843 +0.008387 +0.008352 +0.008382 +0.008444 +0.008414 +0.008449 +0.008416 +0.008402 +0.008454 +0.008523 +0.008506 +0.008541 +0.008512 +0.008495 +0.008555 +0.008609 +0.001167 +0.008597 +0.008626 +0.008597 +0.008587 +0.008628 +0.008726 +0.008679 +0.008724 +0.008687 +0.008674 +0.00872 +0.008797 +0.008752 +0.008777 +0.008732 +0.008719 +0.008751 +0.008844 +0.008809 +0.008833 +0.008804 +0.008797 +0.008871 +0.008967 +0.00894 +0.00895 +0.00888 +0.008841 +0.008825 +0.008876 +0.008825 +0.008788 +0.008682 +0.008638 +0.008616 +0.008647 +0.008592 +0.008577 +0.00849 +0.008447 +0.008447 +0.008491 +0.008444 +0.008443 +0.008375 +0.008347 +0.008351 +0.008412 +0.008392 +0.0084 +0.008342 +0.008328 +0.008337 +0.008404 +0.00838 +0.008404 +0.008357 +0.008354 +0.008382 +0.00846 +0.00844 +0.008468 +0.008423 +0.008425 +0.008446 +0.008544 +0.008526 +0.008551 +0.008513 +0.001168 +0.008502 +0.008538 +0.008624 +0.008602 +0.008642 +0.008599 +0.008589 +0.008625 +0.008706 +0.008689 +0.008728 +0.008685 +0.008673 +0.008714 +0.008799 +0.00878 +0.008808 +0.008771 +0.00876 +0.008798 +0.008895 +0.008871 +0.008907 +0.008881 +0.008871 +0.008917 +0.009014 +0.008937 +0.008933 +0.00887 +0.008837 +0.008841 +0.008867 +0.008805 +0.008754 +0.008659 +0.008622 +0.008604 +0.008643 +0.008578 +0.008581 +0.008517 +0.00843 +0.008425 +0.008491 +0.008429 +0.008451 +0.008386 +0.008366 +0.008381 +0.008423 +0.008382 +0.008396 +0.008367 +0.00834 +0.008354 +0.008422 +0.008373 +0.008416 +0.008373 +0.008361 +0.008411 +0.008482 +0.008453 +0.008495 +0.008443 +0.008449 +0.008483 +0.008551 +0.008557 +0.008551 +0.001169 +0.008529 +0.00852 +0.008532 +0.008602 +0.008571 +0.008619 +0.008586 +0.008574 +0.008618 +0.0087 +0.008678 +0.008718 +0.008671 +0.008663 +0.008696 +0.008786 +0.008785 +0.008823 +0.008787 +0.008769 +0.0088 +0.008889 +0.008858 +0.008894 +0.008851 +0.008856 +0.008877 +0.008939 +0.008889 +0.008881 +0.008789 +0.008741 +0.008721 +0.008748 +0.008691 +0.008673 +0.008578 +0.008536 +0.008526 +0.008574 +0.00852 +0.008521 +0.008444 +0.008412 +0.008412 +0.008469 +0.008427 +0.008442 +0.008379 +0.008363 +0.008372 +0.008437 +0.008418 +0.008438 +0.008385 +0.008373 +0.008394 +0.008468 +0.008447 +0.008478 +0.008434 +0.008439 +0.008468 +0.008554 +0.008535 +0.008558 +0.008531 +0.008479 +0.00117 +0.008541 +0.008618 +0.008614 +0.008643 +0.00861 +0.00859 +0.008631 +0.008707 +0.008693 +0.008732 +0.008682 +0.008676 +0.008724 +0.008798 +0.008785 +0.008812 +0.008769 +0.008761 +0.008806 +0.008877 +0.008871 +0.008893 +0.008866 +0.008845 +0.008912 +0.008989 +0.008969 +0.009014 +0.00898 +0.008965 +0.008978 +0.00896 +0.008905 +0.008886 +0.008822 +0.008771 +0.008695 +0.008704 +0.008658 +0.008639 +0.008586 +0.008539 +0.008574 +0.008603 +0.008509 +0.008518 +0.00844 +0.008411 +0.00841 +0.008459 +0.008415 +0.008434 +0.00839 +0.008365 +0.008401 +0.008482 +0.008444 +0.008463 +0.008424 +0.008408 +0.008432 +0.008473 +0.008454 +0.008474 +0.008448 +0.008441 +0.008481 +0.008555 +0.008537 +0.008558 +0.008533 +0.008527 +0.008573 +0.008643 +0.00863 +0.001171 +0.008649 +0.008628 +0.008603 +0.00866 +0.00873 +0.008713 +0.008734 +0.008715 +0.008676 +0.008697 +0.008757 +0.00874 +0.008763 +0.008742 +0.008723 +0.008785 +0.008889 +0.008888 +0.008908 +0.008875 +0.008842 +0.008899 +0.008966 +0.00895 +0.008968 +0.00891 +0.008839 +0.008837 +0.008856 +0.008799 +0.008756 +0.008665 +0.008579 +0.008583 +0.008605 +0.00856 +0.008534 +0.00847 +0.008407 +0.008422 +0.008453 +0.008428 +0.008412 +0.008365 +0.008306 +0.008335 +0.008381 +0.008363 +0.008375 +0.008334 +0.008292 +0.008329 +0.008384 +0.008378 +0.008397 +0.008368 +0.008333 +0.008386 +0.00845 +0.00843 +0.00845 +0.008426 +0.008411 +0.008466 +0.008523 +0.008521 +0.008538 +0.001172 +0.008512 +0.008496 +0.008538 +0.008615 +0.008601 +0.008627 +0.008595 +0.008575 +0.008622 +0.008702 +0.008687 +0.008713 +0.008683 +0.008661 +0.008706 +0.008794 +0.008769 +0.008795 +0.008767 +0.008749 +0.008797 +0.008885 +0.008873 +0.008903 +0.008875 +0.008869 +0.008922 +0.009001 +0.008911 +0.008892 +0.008826 +0.008777 +0.008754 +0.008764 +0.008703 +0.0087 +0.008616 +0.008541 +0.008521 +0.008568 +0.00852 +0.008518 +0.00847 +0.008414 +0.008381 +0.008409 +0.00836 +0.008371 +0.00833 +0.008288 +0.008325 +0.008375 +0.008357 +0.008354 +0.008321 +0.00829 +0.008275 +0.008332 +0.008302 +0.008328 +0.008301 +0.008272 +0.008319 +0.008398 +0.008374 +0.008399 +0.008378 +0.008356 +0.008408 +0.008489 +0.008478 +0.008474 +0.008459 +0.008454 +0.001173 +0.008494 +0.008578 +0.008538 +0.008558 +0.008509 +0.0085 +0.008543 +0.008624 +0.008591 +0.008625 +0.008591 +0.008576 +0.008607 +0.008692 +0.008659 +0.008694 +0.008663 +0.008671 +0.008726 +0.008812 +0.008794 +0.008813 +0.008776 +0.008755 +0.008784 +0.008854 +0.008811 +0.008807 +0.00872 +0.008648 +0.008626 +0.008664 +0.008587 +0.008565 +0.008476 +0.008416 +0.00841 +0.008466 +0.00839 +0.008399 +0.008331 +0.008285 +0.008287 +0.008351 +0.00829 +0.008305 +0.008245 +0.008212 +0.008227 +0.008304 +0.008269 +0.008287 +0.008236 +0.008209 +0.008229 +0.008312 +0.008294 +0.008317 +0.008284 +0.008268 +0.008301 +0.008384 +0.008351 +0.00839 +0.008346 +0.008324 +0.008359 +0.008451 +0.008444 +0.001174 +0.008478 +0.008436 +0.008422 +0.008461 +0.008539 +0.008514 +0.008543 +0.008503 +0.008487 +0.008527 +0.008616 +0.008601 +0.008643 +0.008598 +0.008589 +0.008629 +0.008711 +0.008685 +0.008727 +0.008678 +0.008677 +0.008721 +0.008817 +0.008783 +0.00883 +0.008803 +0.008728 +0.008743 +0.008818 +0.008769 +0.008782 +0.008711 +0.008666 +0.008673 +0.008726 +0.008588 +0.008554 +0.008487 +0.008447 +0.008421 +0.008466 +0.008396 +0.008395 +0.008347 +0.008259 +0.008265 +0.008301 +0.00827 +0.00828 +0.00822 +0.008209 +0.008221 +0.008309 +0.008262 +0.008293 +0.008244 +0.008193 +0.00821 +0.008276 +0.008236 +0.008281 +0.008235 +0.008233 +0.008275 +0.008344 +0.008331 +0.00836 +0.008318 +0.008319 +0.008362 +0.008443 +0.008412 +0.00845 +0.001175 +0.008413 +0.008395 +0.008444 +0.00853 +0.0085 +0.008524 +0.008495 +0.008469 +0.008493 +0.008562 +0.008533 +0.008565 +0.008539 +0.008518 +0.008559 +0.008631 +0.008621 +0.008665 +0.008659 +0.00864 +0.008677 +0.008757 +0.008738 +0.008747 +0.008719 +0.008709 +0.008747 +0.008805 +0.008766 +0.008727 +0.008659 +0.008608 +0.008595 +0.00862 +0.008573 +0.008539 +0.008474 +0.008431 +0.008435 +0.008486 +0.008446 +0.008439 +0.008388 +0.008354 +0.008368 +0.008426 +0.008391 +0.008392 +0.008347 +0.008332 +0.008346 +0.008418 +0.008394 +0.008406 +0.008366 +0.008352 +0.008389 +0.008463 +0.008454 +0.008474 +0.008439 +0.008425 +0.008463 +0.008548 +0.008529 +0.008557 +0.001176 +0.00852 +0.008511 +0.008543 +0.008636 +0.008614 +0.008639 +0.008606 +0.008594 +0.008631 +0.008717 +0.008694 +0.008731 +0.008691 +0.008678 +0.008716 +0.008803 +0.008781 +0.008812 +0.008774 +0.008761 +0.008799 +0.008892 +0.008864 +0.008911 +0.008853 +0.008862 +0.008907 +0.008995 +0.008977 +0.009013 +0.00897 +0.008939 +0.00889 +0.008903 +0.008846 +0.008854 +0.008787 +0.008739 +0.008679 +0.008684 +0.008626 +0.008627 +0.008573 +0.008536 +0.008553 +0.008614 +0.008549 +0.00853 +0.008429 +0.00841 +0.008433 +0.008499 +0.008452 +0.008464 +0.008429 +0.008385 +0.008386 +0.008467 +0.008411 +0.008446 +0.008412 +0.008391 +0.008433 +0.008516 +0.008477 +0.008519 +0.008483 +0.008469 +0.008523 +0.008604 +0.008584 +0.008591 +0.008574 +0.001177 +0.008555 +0.008597 +0.008657 +0.008623 +0.008654 +0.00863 +0.008619 +0.008661 +0.008746 +0.008712 +0.008753 +0.008718 +0.008707 +0.008746 +0.008833 +0.00879 +0.00882 +0.008778 +0.008767 +0.008805 +0.008888 +0.00885 +0.008901 +0.008886 +0.008889 +0.008916 +0.008998 +0.008949 +0.008944 +0.008859 +0.008807 +0.008796 +0.00883 +0.008756 +0.008737 +0.008658 +0.008602 +0.008594 +0.008644 +0.008584 +0.008582 +0.008513 +0.008471 +0.008468 +0.008532 +0.008488 +0.008493 +0.00844 +0.008411 +0.008426 +0.008511 +0.00846 +0.008486 +0.008442 +0.008422 +0.008439 +0.00852 +0.008499 +0.008524 +0.008485 +0.008473 +0.008497 +0.008591 +0.008552 +0.008589 +0.008569 +0.008539 +0.008588 +0.008662 +0.001178 +0.008649 +0.008676 +0.008643 +0.008635 +0.008667 +0.008754 +0.008733 +0.008762 +0.008726 +0.008718 +0.00876 +0.008844 +0.008822 +0.008852 +0.008808 +0.0088 +0.008841 +0.008918 +0.008895 +0.008938 +0.008891 +0.008892 +0.008929 +0.009027 +0.009 +0.009036 +0.008997 +0.008998 +0.009051 +0.009131 +0.009081 +0.009011 +0.008912 +0.00886 +0.008868 +0.008915 +0.008797 +0.008763 +0.008678 +0.008632 +0.008602 +0.008663 +0.008583 +0.008596 +0.008529 +0.008444 +0.008448 +0.008495 +0.008454 +0.008474 +0.008412 +0.008393 +0.008419 +0.008488 +0.008439 +0.008431 +0.008384 +0.008372 +0.008387 +0.00848 +0.008438 +0.008464 +0.008427 +0.008424 +0.008424 +0.008501 +0.00847 +0.008498 +0.008483 +0.008468 +0.008508 +0.008599 +0.008575 +0.008598 +0.008572 +0.001179 +0.008566 +0.008601 +0.008676 +0.008662 +0.008695 +0.008665 +0.008651 +0.008686 +0.00877 +0.008749 +0.008772 +0.008735 +0.008716 +0.008758 +0.008826 +0.008805 +0.008833 +0.008801 +0.008777 +0.008849 +0.008935 +0.008933 +0.008944 +0.008898 +0.008866 +0.008862 +0.008912 +0.00887 +0.008842 +0.008756 +0.008701 +0.008693 +0.008729 +0.008678 +0.008663 +0.008604 +0.008544 +0.008558 +0.008607 +0.008576 +0.008572 +0.008514 +0.008477 +0.008491 +0.008541 +0.008524 +0.008531 +0.008492 +0.00845 +0.00848 +0.008545 +0.008525 +0.008543 +0.008508 +0.008489 +0.008525 +0.008596 +0.008587 +0.008607 +0.00859 +0.008557 +0.008606 +0.008685 +0.008669 +0.008691 +0.00118 +0.008663 +0.008649 +0.008689 +0.008769 +0.008751 +0.008787 +0.008748 +0.008736 +0.008773 +0.00886 +0.008843 +0.008872 +0.008832 +0.008822 +0.008863 +0.00895 +0.008926 +0.008959 +0.00893 +0.008903 +0.008964 +0.009048 +0.009034 +0.009072 +0.009037 +0.009024 +0.009078 +0.009136 +0.009027 +0.009025 +0.008955 +0.008873 +0.008827 +0.008883 +0.00881 +0.008795 +0.008694 +0.008623 +0.008617 +0.008657 +0.008606 +0.008615 +0.008532 +0.008485 +0.008442 +0.008502 +0.008442 +0.008462 +0.00841 +0.008376 +0.008417 +0.008478 +0.008445 +0.008461 +0.008421 +0.008414 +0.008438 +0.008496 +0.008439 +0.008472 +0.008445 +0.008428 +0.008478 +0.008563 +0.008518 +0.008564 +0.008526 +0.008512 +0.008558 +0.008634 +0.008605 +0.00861 +0.001181 +0.008597 +0.008589 +0.008626 +0.008708 +0.008686 +0.008721 +0.008684 +0.00867 +0.008712 +0.008799 +0.008762 +0.008797 +0.008759 +0.008742 +0.008776 +0.008859 +0.008827 +0.008866 +0.008818 +0.008814 +0.008854 +0.008974 +0.008955 +0.008992 +0.008937 +0.008911 +0.008927 +0.008977 +0.008912 +0.008914 +0.008818 +0.008753 +0.008739 +0.008775 +0.00871 +0.008705 +0.008621 +0.008579 +0.008577 +0.008626 +0.008586 +0.008585 +0.008518 +0.008482 +0.008496 +0.00855 +0.008508 +0.008528 +0.008469 +0.008445 +0.008472 +0.008532 +0.0085 +0.008524 +0.008473 +0.008461 +0.008494 +0.008569 +0.008541 +0.008574 +0.008532 +0.008526 +0.008567 +0.008648 +0.008628 +0.00866 +0.008616 +0.008601 +0.001182 +0.008655 +0.008729 +0.008715 +0.008739 +0.008707 +0.008689 +0.008736 +0.008817 +0.008803 +0.008826 +0.008794 +0.008773 +0.008828 +0.008911 +0.008893 +0.008921 +0.008881 +0.008867 +0.008913 +0.008989 +0.008979 +0.009005 +0.008983 +0.00897 +0.009019 +0.009107 +0.009092 +0.009122 +0.009071 +0.008957 +0.008963 +0.009016 +0.008942 +0.008928 +0.008837 +0.008699 +0.008701 +0.008732 +0.008675 +0.008674 +0.008586 +0.008505 +0.008506 +0.008549 +0.008514 +0.008503 +0.008469 +0.00841 +0.008426 +0.008455 +0.008422 +0.008429 +0.0084 +0.008366 +0.008408 +0.008455 +0.008411 +0.008447 +0.008402 +0.008355 +0.008384 +0.008444 +0.008434 +0.008454 +0.008426 +0.00842 +0.008458 +0.008535 +0.008527 +0.008554 +0.008524 +0.008507 +0.008565 +0.008625 +0.001183 +0.008612 +0.008646 +0.008612 +0.008607 +0.008645 +0.00873 +0.008709 +0.008737 +0.008701 +0.008694 +0.008735 +0.008816 +0.008777 +0.008804 +0.008762 +0.008745 +0.008776 +0.008856 +0.008827 +0.008851 +0.008813 +0.008815 +0.008851 +0.008975 +0.008954 +0.008972 +0.008911 +0.00886 +0.008847 +0.008896 +0.008833 +0.008811 +0.008724 +0.008658 +0.008639 +0.008683 +0.008617 +0.008597 +0.008529 +0.008476 +0.008471 +0.00852 +0.008469 +0.008471 +0.008406 +0.00837 +0.008372 +0.008447 +0.008411 +0.008428 +0.008378 +0.008355 +0.008367 +0.008441 +0.008408 +0.008446 +0.008407 +0.008391 +0.008413 +0.008501 +0.008471 +0.008492 +0.008459 +0.008445 +0.008484 +0.008568 +0.008551 +0.008598 +0.00854 +0.001184 +0.008533 +0.008571 +0.008647 +0.008643 +0.008667 +0.008632 +0.008616 +0.008669 +0.008734 +0.008721 +0.008746 +0.00872 +0.008698 +0.008748 +0.008829 +0.008814 +0.008842 +0.008802 +0.008792 +0.008831 +0.008917 +0.008905 +0.00894 +0.008903 +0.0089 +0.008955 +0.009037 +0.009022 +0.009011 +0.00889 +0.008844 +0.00885 +0.008903 +0.008831 +0.00876 +0.008667 +0.008612 +0.00861 +0.008638 +0.008574 +0.008556 +0.008447 +0.008401 +0.008393 +0.00843 +0.008382 +0.008379 +0.008317 +0.008246 +0.008255 +0.008314 +0.008275 +0.008296 +0.008251 +0.008226 +0.008268 +0.008327 +0.008305 +0.00832 +0.008281 +0.008251 +0.008252 +0.008311 +0.008302 +0.008327 +0.008295 +0.008286 +0.008329 +0.008406 +0.008394 +0.008427 +0.008396 +0.008382 +0.008437 +0.008489 +0.008484 +0.001185 +0.008516 +0.008477 +0.008473 +0.008507 +0.008599 +0.008571 +0.008608 +0.008569 +0.008555 +0.008602 +0.00868 +0.008639 +0.008671 +0.008624 +0.008613 +0.008638 +0.00873 +0.008698 +0.008723 +0.00868 +0.008674 +0.008709 +0.00882 +0.008822 +0.008854 +0.008788 +0.00876 +0.008755 +0.008791 +0.008718 +0.008715 +0.008615 +0.008553 +0.00854 +0.008563 +0.008506 +0.008499 +0.008413 +0.008371 +0.00837 +0.008421 +0.008375 +0.008373 +0.008303 +0.008283 +0.008269 +0.008341 +0.008312 +0.008334 +0.008275 +0.008262 +0.008281 +0.008344 +0.008327 +0.008363 +0.008317 +0.00831 +0.008336 +0.008414 +0.008399 +0.008423 +0.008387 +0.008369 +0.008399 +0.008493 +0.008474 +0.001186 +0.008516 +0.008472 +0.008455 +0.008496 +0.008573 +0.008548 +0.008589 +0.008556 +0.008544 +0.008578 +0.008663 +0.008638 +0.00867 +0.008632 +0.008627 +0.00867 +0.008757 +0.008728 +0.008768 +0.008725 +0.008713 +0.008764 +0.008848 +0.008838 +0.008877 +0.008836 +0.008832 +0.008845 +0.008866 +0.008801 +0.0088 +0.008749 +0.008697 +0.008701 +0.008763 +0.008626 +0.008568 +0.00849 +0.008451 +0.008458 +0.00848 +0.008426 +0.008396 +0.00832 +0.008279 +0.008252 +0.008305 +0.008236 +0.008259 +0.008209 +0.008175 +0.008219 +0.008277 +0.008244 +0.008262 +0.008191 +0.008181 +0.008173 +0.008262 +0.008228 +0.008252 +0.008225 +0.008217 +0.008254 +0.008341 +0.008309 +0.008335 +0.008306 +0.008297 +0.008353 +0.008402 +0.008401 +0.008431 +0.001187 +0.008387 +0.008388 +0.008394 +0.008464 +0.008428 +0.008471 +0.008438 +0.008433 +0.008468 +0.008555 +0.008528 +0.008566 +0.008529 +0.008524 +0.008547 +0.008634 +0.008609 +0.008653 +0.008629 +0.008618 +0.00865 +0.008738 +0.008712 +0.008733 +0.008702 +0.008691 +0.008738 +0.008812 +0.008771 +0.008778 +0.008695 +0.008633 +0.008627 +0.008643 +0.008569 +0.008554 +0.008465 +0.008399 +0.008393 +0.008433 +0.008368 +0.008374 +0.0083 +0.008256 +0.008261 +0.008307 +0.008259 +0.008273 +0.008207 +0.008177 +0.008198 +0.008261 +0.008226 +0.008248 +0.008196 +0.008173 +0.008204 +0.008274 +0.008247 +0.008276 +0.008233 +0.008213 +0.008253 +0.00833 +0.008306 +0.008343 +0.008301 +0.008303 +0.008324 +0.008423 +0.008383 +0.001188 +0.008417 +0.008386 +0.008375 +0.008419 +0.008489 +0.008472 +0.0085 +0.00847 +0.008455 +0.008499 +0.00858 +0.008551 +0.00858 +0.008553 +0.008539 +0.00859 +0.008658 +0.008648 +0.008676 +0.008638 +0.008624 +0.008668 +0.00876 +0.008742 +0.008776 +0.008752 +0.008732 +0.008788 +0.008825 +0.008766 +0.00877 +0.008711 +0.008669 +0.008667 +0.00867 +0.008605 +0.008563 +0.008476 +0.008416 +0.008406 +0.008425 +0.008364 +0.008375 +0.008305 +0.008265 +0.008251 +0.008256 +0.008204 +0.008195 +0.008159 +0.008125 +0.008145 +0.008215 +0.008167 +0.008144 +0.0081 +0.008067 +0.008102 +0.008178 +0.00813 +0.00815 +0.008129 +0.008097 +0.008116 +0.008189 +0.00816 +0.008183 +0.008166 +0.008144 +0.008189 +0.008273 +0.008253 +0.008278 +0.008253 +0.008246 +0.008295 +0.001189 +0.008356 +0.008323 +0.008374 +0.008336 +0.008329 +0.008372 +0.008453 +0.008422 +0.008453 +0.008419 +0.008406 +0.008442 +0.008519 +0.008482 +0.008509 +0.008468 +0.008455 +0.008484 +0.008565 +0.008537 +0.008566 +0.008531 +0.008524 +0.008588 +0.008681 +0.008653 +0.008659 +0.008578 +0.008532 +0.008506 +0.008533 +0.008479 +0.008456 +0.008352 +0.008297 +0.008281 +0.008318 +0.008255 +0.008238 +0.008166 +0.008131 +0.008128 +0.008178 +0.00813 +0.008131 +0.008064 +0.008046 +0.008053 +0.008119 +0.008092 +0.008103 +0.00805 +0.008037 +0.008058 +0.00813 +0.008105 +0.008134 +0.008083 +0.008081 +0.008105 +0.008182 +0.008169 +0.0082 +0.008156 +0.008153 +0.008191 +0.008255 +0.008241 +0.00119 +0.008283 +0.008235 +0.008232 +0.008266 +0.008343 +0.008319 +0.008356 +0.008322 +0.008309 +0.008347 +0.008424 +0.008401 +0.008437 +0.008395 +0.008389 +0.008431 +0.008515 +0.008488 +0.008534 +0.008481 +0.008471 +0.008519 +0.008597 +0.008584 +0.008628 +0.008587 +0.00859 +0.008623 +0.00864 +0.008581 +0.008589 +0.008517 +0.008482 +0.0085 +0.008504 +0.008426 +0.008408 +0.008314 +0.008281 +0.008266 +0.008298 +0.00822 +0.008255 +0.008167 +0.008116 +0.008089 +0.008129 +0.008082 +0.008086 +0.008035 +0.008009 +0.008028 +0.008114 +0.008048 +0.008026 +0.007979 +0.007954 +0.007992 +0.008076 +0.008026 +0.008062 +0.008027 +0.008014 +0.008051 +0.008148 +0.008104 +0.008138 +0.0081 +0.008092 +0.008093 +0.008169 +0.008138 +0.008184 +0.001191 +0.00815 +0.008138 +0.008198 +0.008254 +0.00823 +0.008276 +0.008238 +0.008236 +0.008257 +0.008351 +0.008325 +0.008361 +0.008323 +0.008311 +0.008347 +0.008427 +0.008397 +0.008426 +0.008383 +0.008376 +0.008408 +0.008494 +0.008472 +0.008515 +0.008485 +0.008473 +0.008499 +0.008588 +0.008562 +0.008586 +0.008537 +0.008498 +0.008485 +0.008526 +0.008466 +0.00845 +0.008368 +0.008314 +0.008302 +0.008343 +0.008282 +0.008286 +0.008224 +0.008183 +0.008178 +0.00824 +0.008188 +0.008194 +0.008138 +0.008111 +0.00812 +0.008192 +0.008147 +0.008166 +0.008119 +0.008105 +0.008121 +0.008199 +0.008174 +0.0082 +0.008162 +0.008148 +0.008176 +0.008267 +0.008225 +0.008268 +0.00824 +0.00822 +0.008272 +0.008326 +0.008319 +0.001192 +0.008344 +0.00831 +0.0083 +0.008335 +0.00842 +0.008399 +0.00843 +0.008387 +0.008382 +0.008418 +0.008507 +0.00848 +0.008512 +0.008469 +0.008456 +0.008492 +0.008579 +0.008557 +0.008592 +0.008553 +0.008542 +0.008586 +0.008672 +0.008656 +0.008688 +0.008651 +0.008652 +0.008698 +0.00878 +0.008737 +0.00871 +0.008579 +0.008541 +0.008557 +0.008609 +0.008508 +0.008479 +0.008413 +0.008368 +0.008341 +0.008403 +0.008338 +0.008337 +0.008292 +0.008205 +0.008207 +0.008238 +0.008198 +0.008209 +0.008162 +0.008133 +0.008168 +0.008232 +0.008181 +0.008215 +0.008166 +0.008116 +0.008127 +0.008183 +0.008161 +0.008193 +0.00815 +0.008151 +0.008184 +0.00826 +0.008243 +0.008273 +0.008236 +0.008237 +0.008274 +0.008367 +0.008341 +0.008347 +0.001193 +0.008336 +0.008314 +0.00837 +0.008443 +0.008416 +0.00844 +0.008385 +0.008371 +0.008414 +0.008486 +0.008464 +0.008478 +0.008459 +0.008436 +0.008483 +0.008554 +0.008536 +0.008557 +0.00853 +0.00852 +0.008586 +0.008671 +0.008653 +0.008681 +0.008636 +0.008622 +0.008654 +0.008719 +0.008703 +0.008696 +0.008607 +0.008551 +0.008534 +0.008559 +0.008504 +0.008472 +0.008385 +0.008327 +0.00832 +0.008355 +0.008316 +0.008303 +0.008238 +0.008199 +0.0082 +0.00825 +0.00822 +0.008219 +0.00817 +0.008141 +0.008158 +0.008222 +0.008203 +0.008216 +0.008173 +0.008154 +0.008179 +0.008249 +0.008243 +0.008258 +0.008229 +0.008212 +0.008244 +0.008321 +0.008311 +0.008333 +0.008319 +0.008284 +0.008325 +0.001194 +0.008401 +0.008384 +0.008425 +0.008373 +0.008375 +0.008411 +0.008483 +0.008468 +0.008498 +0.008464 +0.008447 +0.008489 +0.00857 +0.008547 +0.008585 +0.008547 +0.008538 +0.008575 +0.008655 +0.008644 +0.008668 +0.008631 +0.008622 +0.008673 +0.008758 +0.008747 +0.008787 +0.008747 +0.008739 +0.008694 +0.008725 +0.008668 +0.008682 +0.008618 +0.008567 +0.008579 +0.008644 +0.00856 +0.008472 +0.008404 +0.008364 +0.008378 +0.008432 +0.008387 +0.008385 +0.008303 +0.008251 +0.008256 +0.008318 +0.008268 +0.00829 +0.008248 +0.008218 +0.008263 +0.008319 +0.008295 +0.008312 +0.008273 +0.008259 +0.008251 +0.008321 +0.008267 +0.008311 +0.008279 +0.008261 +0.008307 +0.008387 +0.008357 +0.0084 +0.008365 +0.008352 +0.008401 +0.008479 +0.008459 +0.008477 +0.001195 +0.008455 +0.008446 +0.008487 +0.008573 +0.008541 +0.008575 +0.008543 +0.008529 +0.008572 +0.008632 +0.008596 +0.008627 +0.008587 +0.008572 +0.008608 +0.00869 +0.00866 +0.00869 +0.008655 +0.008641 +0.008699 +0.008802 +0.008797 +0.008818 +0.008778 +0.008751 +0.008756 +0.008818 +0.008757 +0.008755 +0.008665 +0.008598 +0.008574 +0.008616 +0.008549 +0.008524 +0.008438 +0.008391 +0.008388 +0.008437 +0.00838 +0.008378 +0.008309 +0.008272 +0.008276 +0.008342 +0.008302 +0.008312 +0.008258 +0.008236 +0.008248 +0.008329 +0.008303 +0.008322 +0.008279 +0.008266 +0.008283 +0.008376 +0.008355 +0.00838 +0.008345 +0.008332 +0.008368 +0.008457 +0.008428 +0.008471 +0.008419 +0.001196 +0.008417 +0.008451 +0.008534 +0.008518 +0.008538 +0.008509 +0.008498 +0.008541 +0.008614 +0.008602 +0.008626 +0.008596 +0.008578 +0.008624 +0.0087 +0.008689 +0.008717 +0.008682 +0.008659 +0.00872 +0.008787 +0.008786 +0.008807 +0.008781 +0.008779 +0.008833 +0.008917 +0.00887 +0.008784 +0.008719 +0.008666 +0.008691 +0.008732 +0.008646 +0.00857 +0.008505 +0.008434 +0.00846 +0.008514 +0.008455 +0.00841 +0.008328 +0.008266 +0.008302 +0.00833 +0.008286 +0.008273 +0.008237 +0.008168 +0.00818 +0.008227 +0.008198 +0.008209 +0.008164 +0.008148 +0.008176 +0.008248 +0.008217 +0.008232 +0.008208 +0.008185 +0.008221 +0.008273 +0.008233 +0.008261 +0.008242 +0.008228 +0.008261 +0.008353 +0.008328 +0.008354 +0.008332 +0.008319 +0.008359 +0.008435 +0.001197 +0.008435 +0.008438 +0.008406 +0.008404 +0.008444 +0.008536 +0.0085 +0.008527 +0.008472 +0.008461 +0.008494 +0.008569 +0.00853 +0.008565 +0.008526 +0.008524 +0.008548 +0.008642 +0.008625 +0.008692 +0.008657 +0.008646 +0.008667 +0.008752 +0.008733 +0.008754 +0.008695 +0.008673 +0.008662 +0.008689 +0.008623 +0.008605 +0.008505 +0.008449 +0.008428 +0.008464 +0.008407 +0.008398 +0.008316 +0.00828 +0.008266 +0.008317 +0.008272 +0.008271 +0.0082 +0.008178 +0.008188 +0.008238 +0.008213 +0.008225 +0.008174 +0.008169 +0.00817 +0.008244 +0.008227 +0.008242 +0.0082 +0.008194 +0.008221 +0.0083 +0.008278 +0.008306 +0.008262 +0.008263 +0.008293 +0.008383 +0.008367 +0.008376 +0.001198 +0.008348 +0.008343 +0.008378 +0.008458 +0.00844 +0.008465 +0.008429 +0.008421 +0.008459 +0.008548 +0.008521 +0.00855 +0.00851 +0.008502 +0.008543 +0.008624 +0.008604 +0.008634 +0.008596 +0.008585 +0.008632 +0.008709 +0.008699 +0.008732 +0.008704 +0.008694 +0.008739 +0.008833 +0.008804 +0.008777 +0.008662 +0.008623 +0.008641 +0.008692 +0.008613 +0.008547 +0.008461 +0.008424 +0.008423 +0.00846 +0.008394 +0.008391 +0.008306 +0.008248 +0.008234 +0.008302 +0.00823 +0.008253 +0.008188 +0.008173 +0.008188 +0.008228 +0.008178 +0.008187 +0.008158 +0.008138 +0.008165 +0.008246 +0.008194 +0.008218 +0.00818 +0.00814 +0.008174 +0.008246 +0.008215 +0.00826 +0.008224 +0.008209 +0.008257 +0.008342 +0.008305 +0.008342 +0.008334 +0.008286 +0.00834 +0.001199 +0.008433 +0.008391 +0.008438 +0.008399 +0.008386 +0.008426 +0.008516 +0.008488 +0.008524 +0.008485 +0.008474 +0.008509 +0.008594 +0.008542 +0.008572 +0.008527 +0.008521 +0.008557 +0.008636 +0.0086 +0.008638 +0.008598 +0.008594 +0.008651 +0.008754 +0.008715 +0.008713 +0.008636 +0.008573 +0.008549 +0.008598 +0.008536 +0.008503 +0.008409 +0.00835 +0.008334 +0.008389 +0.008329 +0.008315 +0.008242 +0.008204 +0.008203 +0.00826 +0.008206 +0.008205 +0.008141 +0.008116 +0.008132 +0.008206 +0.008167 +0.008189 +0.008146 +0.008122 +0.008142 +0.008223 +0.008199 +0.008229 +0.008194 +0.008178 +0.008203 +0.008291 +0.008262 +0.008296 +0.008267 +0.008241 +0.008283 +0.008368 +0.0012 +0.008347 +0.00838 +0.00834 +0.008332 +0.008363 +0.008447 +0.008428 +0.008467 +0.008416 +0.008414 +0.008448 +0.008535 +0.008513 +0.008541 +0.008502 +0.008494 +0.008526 +0.008604 +0.008588 +0.008625 +0.008579 +0.008577 +0.008613 +0.008706 +0.008679 +0.00872 +0.008687 +0.008685 +0.008729 +0.008809 +0.008758 +0.008689 +0.008565 +0.008522 +0.008543 +0.008589 +0.008472 +0.008432 +0.008356 +0.008304 +0.008307 +0.00836 +0.00828 +0.008285 +0.008183 +0.008141 +0.008162 +0.008191 +0.008155 +0.008153 +0.008119 +0.008087 +0.008092 +0.00813 +0.008089 +0.008119 +0.008072 +0.008065 +0.00809 +0.00816 +0.008134 +0.008152 +0.008133 +0.008119 +0.008138 +0.008207 +0.008168 +0.008196 +0.008172 +0.008166 +0.008198 +0.008288 +0.008263 +0.008292 +0.008253 +0.001201 +0.008251 +0.008306 +0.008352 +0.008339 +0.008378 +0.00834 +0.008338 +0.008382 +0.008467 +0.008429 +0.008459 +0.008422 +0.008409 +0.008419 +0.008491 +0.00846 +0.008494 +0.008464 +0.008451 +0.008472 +0.008577 +0.008595 +0.008626 +0.008593 +0.008571 +0.008597 +0.008673 +0.008625 +0.008625 +0.008549 +0.0085 +0.008497 +0.008531 +0.008457 +0.008447 +0.008362 +0.00831 +0.008304 +0.008347 +0.008284 +0.008292 +0.008228 +0.008178 +0.008184 +0.008239 +0.008195 +0.00821 +0.008149 +0.00812 +0.008138 +0.00821 +0.008177 +0.008194 +0.008152 +0.008129 +0.008151 +0.008232 +0.008204 +0.008239 +0.008202 +0.008185 +0.008219 +0.008299 +0.008268 +0.008307 +0.008263 +0.008258 +0.008284 +0.008383 +0.001202 +0.008355 +0.008389 +0.008345 +0.008331 +0.008368 +0.008452 +0.008437 +0.008473 +0.008427 +0.008423 +0.008453 +0.008537 +0.008513 +0.008552 +0.00851 +0.008498 +0.008534 +0.008625 +0.008596 +0.008638 +0.008597 +0.008599 +0.008643 +0.008727 +0.008705 +0.008741 +0.0087 +0.008646 +0.008575 +0.008629 +0.008562 +0.008568 +0.008504 +0.008467 +0.008434 +0.008419 +0.008347 +0.008349 +0.008287 +0.008246 +0.00824 +0.008233 +0.008167 +0.008181 +0.008116 +0.0081 +0.008115 +0.008182 +0.008109 +0.0081 +0.008054 +0.008024 +0.008073 +0.008139 +0.008087 +0.008124 +0.008079 +0.008066 +0.008094 +0.008143 +0.008117 +0.008153 +0.008109 +0.008112 +0.008148 +0.008224 +0.008199 +0.008234 +0.008198 +0.008203 +0.008219 +0.001203 +0.008312 +0.008284 +0.008305 +0.008287 +0.008274 +0.008322 +0.008389 +0.008363 +0.008389 +0.008358 +0.008341 +0.008371 +0.008436 +0.008404 +0.008429 +0.008399 +0.008379 +0.008421 +0.008502 +0.008509 +0.008557 +0.008527 +0.008507 +0.008535 +0.008618 +0.008598 +0.008605 +0.008573 +0.00853 +0.008535 +0.008573 +0.008488 +0.008487 +0.008405 +0.008331 +0.00833 +0.008373 +0.008299 +0.008298 +0.008242 +0.008186 +0.008195 +0.008244 +0.008203 +0.00821 +0.008157 +0.00811 +0.008124 +0.008181 +0.008152 +0.008174 +0.008129 +0.008098 +0.008123 +0.008184 +0.008159 +0.008167 +0.008154 +0.008138 +0.008183 +0.008258 +0.008234 +0.008261 +0.008223 +0.008203 +0.008244 +0.008317 +0.008291 +0.001204 +0.008314 +0.008296 +0.008273 +0.008335 +0.008403 +0.008398 +0.008416 +0.008382 +0.008355 +0.008403 +0.008472 +0.008461 +0.008474 +0.008455 +0.008432 +0.008497 +0.00856 +0.008552 +0.008578 +0.008551 +0.008524 +0.008586 +0.008661 +0.008657 +0.008687 +0.008666 +0.00863 +0.008616 +0.008656 +0.008624 +0.00862 +0.008579 +0.008522 +0.008545 +0.008587 +0.008528 +0.008426 +0.008369 +0.00831 +0.008339 +0.008393 +0.008345 +0.008347 +0.008309 +0.008208 +0.008209 +0.008231 +0.008212 +0.008208 +0.008181 +0.008134 +0.008178 +0.008231 +0.0082 +0.008218 +0.008181 +0.008157 +0.008168 +0.008201 +0.008196 +0.008205 +0.008188 +0.008173 +0.008223 +0.008282 +0.00828 +0.008289 +0.008276 +0.008256 +0.008308 +0.008396 +0.008355 +0.008391 +0.001205 +0.008358 +0.008345 +0.0084 +0.008469 +0.008449 +0.008482 +0.008446 +0.008396 +0.00843 +0.008494 +0.008483 +0.008503 +0.008492 +0.008448 +0.00851 +0.008578 +0.008579 +0.008618 +0.008607 +0.008574 +0.008621 +0.008691 +0.008681 +0.008697 +0.008671 +0.008656 +0.008696 +0.008739 +0.008708 +0.00867 +0.008602 +0.008535 +0.008521 +0.008528 +0.008475 +0.008443 +0.008371 +0.008317 +0.008313 +0.008336 +0.008303 +0.008289 +0.008235 +0.008189 +0.008206 +0.008244 +0.008221 +0.008207 +0.008169 +0.008142 +0.008173 +0.008227 +0.008217 +0.008217 +0.008184 +0.008165 +0.008201 +0.008262 +0.008251 +0.008262 +0.008238 +0.008221 +0.008261 +0.008327 +0.008323 +0.008332 +0.008324 +0.008288 +0.001206 +0.00834 +0.008411 +0.008401 +0.008416 +0.008389 +0.008379 +0.008419 +0.008497 +0.008482 +0.008502 +0.008469 +0.008452 +0.008494 +0.008578 +0.008564 +0.00859 +0.008555 +0.008535 +0.008582 +0.008659 +0.008642 +0.008678 +0.008639 +0.008634 +0.008685 +0.008768 +0.008759 +0.008779 +0.008767 +0.008734 +0.008711 +0.008725 +0.008679 +0.008684 +0.008618 +0.008563 +0.008578 +0.008627 +0.008495 +0.00845 +0.008383 +0.008338 +0.00835 +0.008378 +0.008305 +0.008304 +0.008249 +0.00817 +0.008185 +0.008206 +0.008174 +0.00819 +0.008134 +0.008114 +0.008134 +0.008204 +0.008164 +0.008151 +0.008113 +0.008084 +0.008105 +0.008189 +0.008149 +0.008169 +0.008151 +0.008131 +0.008173 +0.00826 +0.008223 +0.00825 +0.008234 +0.008209 +0.008224 +0.0083 +0.008272 +0.008299 +0.001207 +0.008286 +0.008247 +0.008308 +0.008385 +0.008361 +0.008396 +0.008364 +0.008355 +0.008393 +0.008478 +0.008453 +0.008484 +0.008445 +0.008432 +0.008468 +0.008548 +0.008524 +0.008556 +0.008516 +0.008522 +0.008564 +0.008648 +0.008629 +0.008651 +0.008613 +0.008594 +0.008613 +0.008686 +0.008649 +0.008638 +0.008559 +0.008498 +0.008477 +0.008512 +0.008444 +0.00843 +0.00835 +0.008297 +0.008282 +0.008326 +0.008277 +0.008272 +0.008206 +0.008166 +0.008165 +0.008223 +0.008172 +0.008173 +0.008116 +0.008096 +0.008113 +0.008179 +0.008144 +0.00815 +0.008103 +0.008089 +0.008114 +0.008195 +0.008161 +0.008183 +0.008145 +0.008132 +0.008169 +0.008261 +0.008231 +0.008263 +0.008222 +0.008208 +0.008243 +0.008324 +0.008308 +0.001208 +0.008343 +0.008306 +0.008289 +0.008329 +0.008401 +0.00839 +0.00842 +0.008388 +0.008374 +0.008413 +0.008489 +0.008481 +0.008493 +0.008462 +0.00844 +0.008493 +0.008574 +0.008542 +0.008585 +0.008549 +0.008541 +0.008586 +0.008673 +0.008657 +0.008677 +0.008655 +0.008643 +0.008691 +0.008702 +0.008618 +0.00861 +0.008565 +0.008492 +0.008458 +0.008489 +0.008427 +0.008424 +0.008364 +0.008328 +0.008324 +0.008337 +0.00829 +0.008277 +0.008241 +0.00817 +0.008175 +0.00822 +0.008187 +0.008189 +0.008158 +0.008128 +0.008169 +0.008236 +0.008195 +0.00822 +0.008173 +0.008138 +0.008159 +0.008208 +0.008201 +0.008221 +0.008192 +0.008185 +0.008228 +0.008297 +0.008283 +0.008308 +0.008281 +0.008273 +0.008333 +0.008382 +0.001209 +0.008371 +0.008409 +0.008366 +0.00836 +0.008397 +0.008492 +0.008463 +0.008496 +0.008455 +0.008446 +0.00848 +0.008542 +0.008507 +0.00854 +0.008498 +0.008487 +0.008523 +0.008603 +0.008572 +0.008601 +0.008566 +0.008562 +0.008613 +0.008723 +0.008696 +0.008726 +0.008663 +0.008624 +0.008622 +0.008663 +0.008603 +0.008601 +0.00851 +0.008449 +0.008443 +0.008493 +0.008429 +0.008419 +0.00834 +0.008295 +0.008303 +0.00836 +0.008312 +0.008322 +0.008258 +0.008222 +0.008238 +0.008303 +0.008266 +0.008294 +0.008246 +0.008219 +0.008241 +0.008309 +0.008289 +0.008315 +0.008275 +0.008252 +0.008284 +0.008362 +0.008335 +0.008376 +0.008337 +0.008321 +0.008373 +0.008429 +0.008425 +0.008453 +0.00121 +0.008422 +0.008405 +0.008439 +0.008524 +0.008499 +0.008535 +0.008504 +0.008486 +0.008521 +0.008605 +0.00859 +0.008626 +0.008581 +0.00857 +0.008609 +0.008693 +0.008669 +0.0087 +0.008666 +0.008652 +0.008699 +0.008786 +0.008771 +0.008803 +0.008771 +0.008764 +0.008814 +0.008899 +0.008842 +0.008777 +0.008699 +0.008667 +0.008677 +0.008721 +0.008622 +0.008595 +0.008523 +0.00848 +0.008458 +0.008519 +0.008458 +0.008469 +0.0084 +0.008326 +0.008332 +0.008387 +0.00834 +0.008357 +0.008314 +0.008276 +0.00832 +0.008385 +0.008352 +0.00837 +0.008309 +0.008292 +0.008299 +0.008383 +0.008351 +0.008379 +0.008356 +0.008336 +0.008382 +0.008467 +0.008431 +0.008477 +0.008438 +0.008438 +0.008472 +0.008558 +0.001211 +0.008535 +0.00856 +0.008534 +0.00852 +0.008557 +0.008614 +0.008592 +0.008621 +0.008598 +0.008568 +0.008623 +0.008699 +0.008672 +0.0087 +0.008673 +0.008651 +0.008695 +0.00877 +0.008747 +0.008764 +0.008739 +0.008716 +0.00876 +0.008855 +0.008873 +0.008888 +0.008853 +0.008822 +0.008842 +0.008881 +0.008826 +0.008811 +0.008718 +0.008665 +0.008648 +0.00867 +0.008626 +0.008609 +0.008509 +0.008466 +0.008466 +0.008504 +0.008467 +0.008463 +0.008402 +0.008361 +0.00837 +0.008415 +0.00838 +0.008379 +0.008335 +0.008324 +0.008347 +0.008411 +0.008389 +0.008392 +0.008352 +0.008342 +0.008384 +0.008455 +0.008447 +0.008462 +0.008426 +0.00841 +0.008445 +0.008521 +0.008516 +0.008554 +0.008518 +0.001212 +0.008485 +0.008538 +0.008615 +0.008602 +0.008611 +0.008596 +0.008569 +0.008623 +0.008695 +0.008689 +0.008706 +0.00868 +0.008654 +0.008706 +0.00877 +0.008772 +0.008796 +0.008764 +0.008747 +0.0088 +0.008883 +0.008868 +0.008899 +0.008873 +0.008847 +0.008922 +0.009004 +0.008988 +0.008896 +0.008861 +0.008812 +0.008847 +0.008881 +0.008838 +0.008826 +0.008739 +0.008609 +0.00862 +0.008654 +0.008607 +0.008591 +0.00855 +0.008455 +0.008432 +0.008471 +0.00843 +0.008439 +0.008387 +0.008352 +0.008384 +0.008422 +0.008398 +0.008374 +0.008347 +0.008305 +0.008362 +0.008416 +0.008388 +0.008414 +0.008384 +0.008369 +0.008429 +0.008488 +0.00848 +0.008497 +0.008489 +0.008438 +0.008479 +0.008536 +0.008525 +0.001213 +0.008566 +0.008518 +0.008509 +0.008565 +0.008637 +0.008618 +0.008644 +0.008622 +0.008606 +0.008656 +0.008734 +0.008709 +0.008734 +0.008702 +0.00868 +0.008729 +0.008802 +0.008783 +0.008806 +0.008774 +0.008749 +0.008786 +0.008864 +0.008883 +0.00891 +0.008887 +0.008859 +0.0089 +0.008965 +0.008922 +0.008916 +0.008839 +0.008783 +0.008778 +0.008796 +0.008733 +0.008713 +0.008629 +0.008562 +0.008571 +0.008598 +0.008549 +0.008551 +0.008482 +0.008436 +0.008442 +0.0085 +0.008452 +0.008457 +0.008406 +0.008374 +0.008406 +0.008478 +0.008431 +0.008449 +0.008399 +0.008365 +0.008415 +0.008479 +0.008452 +0.00847 +0.008425 +0.008401 +0.008457 +0.008528 +0.008512 +0.008537 +0.008503 +0.008493 +0.008533 +0.008611 +0.008596 +0.008619 +0.001214 +0.008579 +0.008578 +0.008618 +0.008701 +0.008673 +0.008707 +0.008665 +0.008662 +0.008702 +0.008789 +0.008764 +0.008802 +0.008753 +0.008737 +0.008778 +0.008866 +0.008843 +0.008883 +0.008839 +0.008839 +0.008874 +0.008969 +0.008946 +0.008986 +0.00895 +0.008938 +0.008955 +0.008953 +0.008858 +0.008857 +0.008796 +0.008696 +0.008659 +0.008716 +0.008635 +0.008646 +0.008569 +0.008515 +0.00848 +0.008524 +0.008482 +0.008484 +0.008428 +0.008388 +0.008417 +0.00845 +0.008408 +0.008408 +0.008355 +0.008328 +0.008339 +0.008411 +0.008363 +0.008392 +0.008345 +0.008334 +0.008378 +0.008448 +0.00842 +0.00845 +0.008402 +0.008403 +0.00842 +0.008477 +0.008447 +0.008487 +0.008452 +0.008447 +0.008494 +0.008586 +0.008539 +0.001215 +0.008573 +0.008549 +0.008533 +0.008579 +0.008661 +0.00864 +0.008669 +0.008631 +0.008616 +0.008668 +0.008756 +0.008715 +0.008744 +0.008708 +0.008686 +0.008726 +0.008806 +0.008782 +0.008805 +0.008769 +0.008744 +0.008792 +0.008895 +0.008903 +0.008926 +0.008867 +0.008818 +0.008826 +0.008846 +0.008775 +0.008757 +0.008686 +0.008612 +0.008607 +0.008626 +0.008579 +0.008569 +0.008495 +0.008447 +0.008464 +0.008507 +0.008467 +0.008471 +0.008411 +0.008373 +0.008394 +0.008451 +0.008417 +0.008439 +0.008388 +0.00836 +0.00839 +0.00845 +0.008437 +0.00846 +0.008418 +0.008397 +0.008435 +0.008502 +0.00849 +0.008522 +0.008486 +0.008474 +0.008518 +0.008583 +0.008573 +0.008601 +0.001216 +0.008568 +0.008563 +0.008589 +0.008681 +0.008656 +0.008685 +0.008647 +0.008643 +0.00868 +0.008763 +0.00874 +0.008771 +0.008735 +0.008726 +0.008771 +0.008863 +0.008825 +0.008869 +0.008828 +0.00881 +0.008863 +0.00895 +0.008933 +0.008977 +0.008936 +0.008928 +0.008959 +0.008983 +0.008941 +0.008958 +0.008893 +0.008857 +0.008859 +0.008912 +0.008818 +0.008722 +0.008639 +0.008602 +0.008625 +0.00866 +0.008591 +0.008568 +0.008479 +0.008462 +0.008472 +0.008535 +0.008471 +0.008479 +0.008393 +0.008382 +0.008394 +0.008463 +0.008419 +0.008434 +0.008396 +0.008363 +0.008398 +0.008473 +0.008432 +0.00845 +0.008397 +0.008371 +0.008412 +0.008506 +0.008464 +0.008499 +0.008472 +0.008459 +0.008503 +0.008598 +0.008559 +0.008598 +0.008552 +0.008547 +0.001217 +0.008592 +0.00866 +0.008647 +0.008667 +0.008641 +0.008619 +0.008641 +0.008713 +0.008694 +0.008718 +0.008692 +0.008672 +0.008726 +0.008791 +0.008779 +0.008807 +0.008795 +0.008789 +0.008836 +0.008912 +0.008889 +0.008921 +0.008879 +0.00885 +0.008886 +0.008926 +0.008861 +0.008833 +0.008747 +0.008675 +0.008667 +0.008686 +0.008625 +0.008614 +0.008531 +0.008483 +0.008481 +0.008526 +0.008488 +0.008494 +0.008433 +0.008389 +0.008413 +0.008462 +0.008425 +0.008442 +0.008396 +0.00838 +0.008396 +0.008465 +0.008438 +0.008457 +0.008407 +0.008393 +0.00844 +0.008506 +0.008486 +0.008508 +0.008468 +0.008448 +0.00849 +0.008565 +0.00856 +0.008584 +0.008551 +0.008538 +0.001218 +0.008578 +0.008653 +0.008647 +0.008659 +0.008642 +0.008617 +0.008667 +0.008735 +0.008733 +0.008748 +0.008726 +0.008704 +0.008757 +0.008826 +0.008817 +0.008834 +0.00881 +0.008782 +0.00884 +0.008904 +0.008905 +0.008923 +0.008897 +0.008869 +0.008939 +0.009011 +0.009005 +0.00903 +0.009002 +0.008966 +0.008997 +0.00898 +0.008876 +0.008828 +0.008766 +0.008683 +0.008654 +0.008676 +0.008616 +0.008615 +0.008557 +0.008505 +0.008535 +0.008525 +0.008474 +0.008458 +0.008428 +0.008344 +0.008363 +0.008394 +0.008374 +0.008373 +0.008351 +0.008308 +0.008348 +0.008412 +0.008383 +0.008386 +0.008377 +0.008339 +0.008398 +0.00842 +0.008388 +0.008413 +0.008391 +0.00837 +0.008434 +0.00849 +0.008479 +0.008504 +0.008478 +0.008455 +0.008524 +0.008589 +0.008573 +0.001219 +0.008602 +0.008575 +0.008545 +0.008551 +0.008628 +0.008607 +0.008641 +0.008615 +0.008595 +0.008649 +0.008719 +0.008703 +0.008732 +0.008705 +0.008686 +0.008755 +0.008838 +0.00882 +0.008836 +0.008813 +0.008772 +0.008821 +0.008893 +0.008888 +0.008911 +0.008852 +0.0088 +0.008788 +0.008815 +0.008761 +0.008739 +0.008633 +0.008587 +0.008578 +0.008602 +0.00855 +0.008541 +0.008481 +0.008423 +0.008436 +0.008476 +0.00844 +0.008445 +0.008374 +0.008356 +0.008374 +0.008438 +0.008416 +0.008427 +0.008378 +0.008358 +0.008393 +0.008461 +0.008444 +0.008456 +0.008416 +0.008406 +0.00844 +0.008512 +0.008505 +0.008525 +0.008488 +0.008479 +0.008516 +0.008604 +0.00122 +0.008573 +0.008602 +0.008579 +0.008562 +0.008606 +0.00868 +0.008674 +0.008685 +0.008659 +0.00863 +0.008681 +0.008751 +0.008755 +0.008777 +0.008751 +0.008724 +0.008781 +0.008851 +0.008837 +0.008856 +0.008843 +0.008801 +0.008871 +0.008944 +0.008951 +0.008964 +0.008942 +0.00893 +0.009 +0.009016 +0.008963 +0.008957 +0.008899 +0.008844 +0.00884 +0.008837 +0.008775 +0.00873 +0.008663 +0.008572 +0.008557 +0.008602 +0.008555 +0.008528 +0.008494 +0.008403 +0.008389 +0.008427 +0.008396 +0.008387 +0.008358 +0.008303 +0.008359 +0.008406 +0.008383 +0.008398 +0.008331 +0.008298 +0.008334 +0.00839 +0.008379 +0.008384 +0.00837 +0.008351 +0.008402 +0.008472 +0.008465 +0.008473 +0.008451 +0.008433 +0.008495 +0.008557 +0.00855 +0.001221 +0.008571 +0.008542 +0.008532 +0.008584 +0.008649 +0.008615 +0.008644 +0.008597 +0.008584 +0.008636 +0.008711 +0.008679 +0.008711 +0.008678 +0.008657 +0.008696 +0.008771 +0.008743 +0.008772 +0.00875 +0.008728 +0.008789 +0.008892 +0.008878 +0.008888 +0.00884 +0.008794 +0.008784 +0.008828 +0.008766 +0.008741 +0.008639 +0.008577 +0.008562 +0.008582 +0.008516 +0.008477 +0.008411 +0.008346 +0.008336 +0.008373 +0.00832 +0.008297 +0.008235 +0.008187 +0.008196 +0.008247 +0.008209 +0.008211 +0.008164 +0.008137 +0.00816 +0.008231 +0.008194 +0.008212 +0.00817 +0.008149 +0.008184 +0.008255 +0.00824 +0.008258 +0.008224 +0.00821 +0.008251 +0.008332 +0.008314 +0.008342 +0.008298 +0.008281 +0.008332 +0.001222 +0.008405 +0.0084 +0.00841 +0.008388 +0.008366 +0.008422 +0.008486 +0.008481 +0.008499 +0.008469 +0.008444 +0.008496 +0.008566 +0.008566 +0.008587 +0.008553 +0.008527 +0.008592 +0.008652 +0.008655 +0.008671 +0.00866 +0.008632 +0.008696 +0.008769 +0.008758 +0.008758 +0.008653 +0.008585 +0.008598 +0.008636 +0.008573 +0.008501 +0.008439 +0.008365 +0.008365 +0.008396 +0.008336 +0.008317 +0.008284 +0.00817 +0.008182 +0.008214 +0.008174 +0.008184 +0.008129 +0.008087 +0.008125 +0.008163 +0.008136 +0.008104 +0.008079 +0.008037 +0.008077 +0.008142 +0.008125 +0.008134 +0.008125 +0.008093 +0.008155 +0.008222 +0.008201 +0.008212 +0.008202 +0.008193 +0.008205 +0.008291 +0.008268 +0.001223 +0.008284 +0.008271 +0.008247 +0.008283 +0.008339 +0.008329 +0.008353 +0.008334 +0.008309 +0.008363 +0.008433 +0.00842 +0.008438 +0.00842 +0.008388 +0.008444 +0.008505 +0.008489 +0.008507 +0.00848 +0.008462 +0.008502 +0.008572 +0.008589 +0.008616 +0.008594 +0.008563 +0.008605 +0.008655 +0.008625 +0.00861 +0.00855 +0.008483 +0.008489 +0.008503 +0.008453 +0.008421 +0.008346 +0.008273 +0.008288 +0.00831 +0.00827 +0.00826 +0.008207 +0.008145 +0.008176 +0.008213 +0.008182 +0.008184 +0.00814 +0.008103 +0.008143 +0.008186 +0.00817 +0.008183 +0.00815 +0.008115 +0.008163 +0.008213 +0.008204 +0.008226 +0.008201 +0.008168 +0.008221 +0.008279 +0.008275 +0.008295 +0.008251 +0.008249 +0.008295 +0.001224 +0.008363 +0.008355 +0.008372 +0.008345 +0.008315 +0.008369 +0.008444 +0.008436 +0.008451 +0.008431 +0.008402 +0.00846 +0.008524 +0.008519 +0.008534 +0.008505 +0.008484 +0.008541 +0.008609 +0.008596 +0.008624 +0.00859 +0.008571 +0.008629 +0.0087 +0.008704 +0.008723 +0.008695 +0.00868 +0.008731 +0.008751 +0.008657 +0.008635 +0.008563 +0.008484 +0.008476 +0.008495 +0.00844 +0.008425 +0.008357 +0.008271 +0.008269 +0.008302 +0.008262 +0.008255 +0.00821 +0.00813 +0.008115 +0.00816 +0.008112 +0.008127 +0.008087 +0.008054 +0.008097 +0.008146 +0.008126 +0.008119 +0.008105 +0.008061 +0.008079 +0.008114 +0.00808 +0.008108 +0.008088 +0.008059 +0.008121 +0.008183 +0.008169 +0.008187 +0.008173 +0.008143 +0.008198 +0.008268 +0.00827 +0.008269 +0.008251 +0.001225 +0.008237 +0.008283 +0.008361 +0.008347 +0.008359 +0.008339 +0.008323 +0.008373 +0.008445 +0.008428 +0.008454 +0.008418 +0.008396 +0.008432 +0.008493 +0.008466 +0.008486 +0.008448 +0.008434 +0.008467 +0.008551 +0.008533 +0.008594 +0.008574 +0.008565 +0.008593 +0.008648 +0.008613 +0.008582 +0.008503 +0.008438 +0.008434 +0.008463 +0.008408 +0.008373 +0.008298 +0.008253 +0.008244 +0.008274 +0.00822 +0.008217 +0.008148 +0.00811 +0.008113 +0.008151 +0.00812 +0.008123 +0.008072 +0.008045 +0.008068 +0.008121 +0.00811 +0.008118 +0.008085 +0.008064 +0.008095 +0.008158 +0.008151 +0.008173 +0.008146 +0.008131 +0.008166 +0.008244 +0.008225 +0.008252 +0.008204 +0.008184 +0.001226 +0.008248 +0.008315 +0.008311 +0.008328 +0.008304 +0.008267 +0.008323 +0.00839 +0.008384 +0.008397 +0.008385 +0.008356 +0.008412 +0.008483 +0.008465 +0.008486 +0.00846 +0.008439 +0.008493 +0.00855 +0.008552 +0.008566 +0.008544 +0.008516 +0.008575 +0.008649 +0.008652 +0.00867 +0.008644 +0.008633 +0.008685 +0.00869 +0.008647 +0.008629 +0.008582 +0.008522 +0.008531 +0.008513 +0.008438 +0.008412 +0.008361 +0.008268 +0.008254 +0.0083 +0.008243 +0.008244 +0.008197 +0.008121 +0.008099 +0.008141 +0.00809 +0.008097 +0.00805 +0.008021 +0.008055 +0.00812 +0.008081 +0.008092 +0.008063 +0.008022 +0.008069 +0.008091 +0.008066 +0.00809 +0.00806 +0.008045 +0.008074 +0.008122 +0.008109 +0.008128 +0.008108 +0.00809 +0.008145 +0.008211 +0.008196 +0.008221 +0.008212 +0.00817 +0.008217 +0.001227 +0.008305 +0.008286 +0.008307 +0.008277 +0.008263 +0.008312 +0.008381 +0.008365 +0.008392 +0.008359 +0.008337 +0.008381 +0.008449 +0.008418 +0.008439 +0.008405 +0.008393 +0.008443 +0.008499 +0.008492 +0.008536 +0.008527 +0.008504 +0.008542 +0.008594 +0.00855 +0.008536 +0.008464 +0.008405 +0.008427 +0.008446 +0.008388 +0.008373 +0.008311 +0.008256 +0.008259 +0.008291 +0.008241 +0.008243 +0.008184 +0.008136 +0.008148 +0.008195 +0.008155 +0.008156 +0.008118 +0.008089 +0.008122 +0.008175 +0.008148 +0.008163 +0.008115 +0.008089 +0.008115 +0.008192 +0.008178 +0.008203 +0.008175 +0.008144 +0.008195 +0.008261 +0.008249 +0.00827 +0.008242 +0.008219 +0.008261 +0.008353 +0.001228 +0.008322 +0.008355 +0.008315 +0.008308 +0.008345 +0.008437 +0.008405 +0.008436 +0.008392 +0.008383 +0.008428 +0.008513 +0.008487 +0.008522 +0.008485 +0.008478 +0.008501 +0.008591 +0.008572 +0.008599 +0.00857 +0.008561 +0.008609 +0.008705 +0.008681 +0.008718 +0.008672 +0.008602 +0.008548 +0.008596 +0.008524 +0.008535 +0.00846 +0.008412 +0.008316 +0.008341 +0.008283 +0.00829 +0.008222 +0.008187 +0.008196 +0.008206 +0.008138 +0.008116 +0.00806 +0.008008 +0.008017 +0.008062 +0.008017 +0.00803 +0.007986 +0.00797 +0.007989 +0.008058 +0.008013 +0.008031 +0.007994 +0.00796 +0.007984 +0.008049 +0.008024 +0.008059 +0.008021 +0.008022 +0.00806 +0.008126 +0.008111 +0.008141 +0.0081 +0.008113 +0.00813 +0.008212 +0.001229 +0.008193 +0.008227 +0.008191 +0.008178 +0.008219 +0.008303 +0.008276 +0.008305 +0.00828 +0.008255 +0.008306 +0.008381 +0.008359 +0.008378 +0.008353 +0.008309 +0.00835 +0.008413 +0.008392 +0.008419 +0.008389 +0.008362 +0.008416 +0.008485 +0.008513 +0.008541 +0.008515 +0.00847 +0.008486 +0.008536 +0.008483 +0.008459 +0.0084 +0.008347 +0.008329 +0.008353 +0.008298 +0.008285 +0.008219 +0.008175 +0.008161 +0.008202 +0.008165 +0.008162 +0.008116 +0.008063 +0.008079 +0.008129 +0.008099 +0.008109 +0.008071 +0.008044 +0.00807 +0.008134 +0.008116 +0.008124 +0.008089 +0.008076 +0.008116 +0.008188 +0.008177 +0.008192 +0.008162 +0.008143 +0.008181 +0.008255 +0.008243 +0.008275 +0.008235 +0.00123 +0.008232 +0.008268 +0.008344 +0.008328 +0.008356 +0.008316 +0.008303 +0.008338 +0.008414 +0.008392 +0.008427 +0.008391 +0.008392 +0.008428 +0.008511 +0.008487 +0.008524 +0.008485 +0.008471 +0.008513 +0.008602 +0.008574 +0.008613 +0.008585 +0.008577 +0.008636 +0.008658 +0.008614 +0.008647 +0.008599 +0.00857 +0.00858 +0.00863 +0.008564 +0.008496 +0.008416 +0.008362 +0.008328 +0.008384 +0.008303 +0.008297 +0.008249 +0.008164 +0.008147 +0.008199 +0.008142 +0.008169 +0.008096 +0.008068 +0.008054 +0.008109 +0.008062 +0.008084 +0.008045 +0.008013 +0.008042 +0.008075 +0.008046 +0.008079 +0.008032 +0.008033 +0.008058 +0.008146 +0.008111 +0.008138 +0.008114 +0.00808 +0.008089 +0.008179 +0.008147 +0.00818 +0.008151 +0.008145 +0.008196 +0.008253 +0.008231 +0.001231 +0.008278 +0.008239 +0.008231 +0.008267 +0.008355 +0.00833 +0.008365 +0.008327 +0.008316 +0.008354 +0.008435 +0.008411 +0.008439 +0.008399 +0.008383 +0.008417 +0.008502 +0.008472 +0.008503 +0.008458 +0.008452 +0.00851 +0.008592 +0.008581 +0.008596 +0.008562 +0.008547 +0.00856 +0.008627 +0.008569 +0.008551 +0.008478 +0.008432 +0.008401 +0.008449 +0.008388 +0.008371 +0.008298 +0.008238 +0.00824 +0.008289 +0.008237 +0.008241 +0.00817 +0.008142 +0.008145 +0.00821 +0.008165 +0.008175 +0.008129 +0.008107 +0.008123 +0.008202 +0.008165 +0.008179 +0.008134 +0.00812 +0.008149 +0.008233 +0.008207 +0.008229 +0.008197 +0.00818 +0.008217 +0.008303 +0.008279 +0.008321 +0.008268 +0.008263 +0.008304 +0.001232 +0.008378 +0.008366 +0.008388 +0.008354 +0.008335 +0.008385 +0.008457 +0.008446 +0.008472 +0.00844 +0.008423 +0.008462 +0.008537 +0.008528 +0.008556 +0.008512 +0.008497 +0.008553 +0.008626 +0.00862 +0.008653 +0.008622 +0.008601 +0.008664 +0.008741 +0.008719 +0.008743 +0.008638 +0.008555 +0.008568 +0.008613 +0.008565 +0.008541 +0.008458 +0.008365 +0.008373 +0.008419 +0.008376 +0.008366 +0.008303 +0.008229 +0.00821 +0.008268 +0.008216 +0.008226 +0.008179 +0.008136 +0.008162 +0.008229 +0.008191 +0.008155 +0.00812 +0.008093 +0.008133 +0.00821 +0.008161 +0.008191 +0.00815 +0.008133 +0.008191 +0.008262 +0.008229 +0.008272 +0.008224 +0.00819 +0.008229 +0.008295 +0.008273 +0.008315 +0.008283 +0.001233 +0.008276 +0.008306 +0.008384 +0.008367 +0.00839 +0.008377 +0.008351 +0.008407 +0.008474 +0.008466 +0.008485 +0.008451 +0.008433 +0.008489 +0.008549 +0.008537 +0.008552 +0.00853 +0.008499 +0.008547 +0.008609 +0.008598 +0.008617 +0.008594 +0.008594 +0.008646 +0.008716 +0.008689 +0.008674 +0.008622 +0.008557 +0.008547 +0.008576 +0.008516 +0.008487 +0.008424 +0.008351 +0.008357 +0.008398 +0.008356 +0.008328 +0.00828 +0.008232 +0.008241 +0.008288 +0.008249 +0.008242 +0.008202 +0.008153 +0.008175 +0.008228 +0.008219 +0.008228 +0.008198 +0.008164 +0.008188 +0.008248 +0.008225 +0.008224 +0.008212 +0.00819 +0.008232 +0.008306 +0.008288 +0.008296 +0.008282 +0.008244 +0.008294 +0.008359 +0.008352 +0.008386 +0.008366 +0.008333 +0.001234 +0.008386 +0.008448 +0.008436 +0.00846 +0.008431 +0.008407 +0.008457 +0.008533 +0.008525 +0.008541 +0.008514 +0.008499 +0.008548 +0.008622 +0.008604 +0.008637 +0.008597 +0.008587 +0.008634 +0.008722 +0.008708 +0.008741 +0.008716 +0.008705 +0.00874 +0.008731 +0.008681 +0.00869 +0.008635 +0.008596 +0.008605 +0.008593 +0.008528 +0.008509 +0.008442 +0.00839 +0.008368 +0.008401 +0.008366 +0.008367 +0.008314 +0.008286 +0.008265 +0.008284 +0.008246 +0.008247 +0.008223 +0.008184 +0.008238 +0.008273 +0.008261 +0.008264 +0.008237 +0.008216 +0.008227 +0.008299 +0.008265 +0.008296 +0.008276 +0.008249 +0.008309 +0.008374 +0.008353 +0.008384 +0.008361 +0.008343 +0.008403 +0.008459 +0.001235 +0.008447 +0.008473 +0.008441 +0.00844 +0.008481 +0.008561 +0.00853 +0.008561 +0.008525 +0.008516 +0.008524 +0.008593 +0.008556 +0.008594 +0.008556 +0.008546 +0.008584 +0.008669 +0.00868 +0.008732 +0.00869 +0.008672 +0.008702 +0.008787 +0.008759 +0.008784 +0.008731 +0.008704 +0.008714 +0.008764 +0.008672 +0.008683 +0.008587 +0.008535 +0.008528 +0.008564 +0.008498 +0.008505 +0.008422 +0.008376 +0.008377 +0.00843 +0.008371 +0.008397 +0.008325 +0.008294 +0.008308 +0.008365 +0.008323 +0.008354 +0.008308 +0.008284 +0.008305 +0.008371 +0.008329 +0.008357 +0.008316 +0.008303 +0.008338 +0.008416 +0.008374 +0.008413 +0.008362 +0.008356 +0.008399 +0.008481 +0.008465 +0.008496 +0.008453 +0.008432 +0.001236 +0.008489 +0.008563 +0.008544 +0.008572 +0.008538 +0.00852 +0.00857 +0.00865 +0.008632 +0.008659 +0.008623 +0.008604 +0.008647 +0.008719 +0.008713 +0.008738 +0.008701 +0.008693 +0.008738 +0.008823 +0.008815 +0.008835 +0.008814 +0.008793 +0.008859 +0.00893 +0.008911 +0.008888 +0.008764 +0.008707 +0.008716 +0.008754 +0.008665 +0.008613 +0.008541 +0.008499 +0.008497 +0.008531 +0.008486 +0.008477 +0.008413 +0.008343 +0.00834 +0.008407 +0.008347 +0.008365 +0.00831 +0.008296 +0.008326 +0.008399 +0.008349 +0.008371 +0.008298 +0.008281 +0.008322 +0.008377 +0.008364 +0.008379 +0.008353 +0.008343 +0.008386 +0.008456 +0.008429 +0.008443 +0.008439 +0.008405 +0.008454 +0.008543 +0.008515 +0.001237 +0.008544 +0.008499 +0.008498 +0.008512 +0.008586 +0.008553 +0.008596 +0.008564 +0.008556 +0.008595 +0.008692 +0.008642 +0.008693 +0.008651 +0.00864 +0.008675 +0.008758 +0.008734 +0.008771 +0.008749 +0.008746 +0.008785 +0.008866 +0.008837 +0.008866 +0.008824 +0.00881 +0.008851 +0.008911 +0.008849 +0.008839 +0.008745 +0.008685 +0.008666 +0.008687 +0.008618 +0.008612 +0.008519 +0.008472 +0.008475 +0.00851 +0.008462 +0.008472 +0.008395 +0.008355 +0.008363 +0.008417 +0.008372 +0.008386 +0.008331 +0.008308 +0.008332 +0.008399 +0.008364 +0.008392 +0.00834 +0.008327 +0.008359 +0.008432 +0.008396 +0.008446 +0.008408 +0.008395 +0.008432 +0.008508 +0.008488 +0.008514 +0.008478 +0.008462 +0.001238 +0.008513 +0.008587 +0.008581 +0.0086 +0.008563 +0.00855 +0.008601 +0.008665 +0.008659 +0.00868 +0.008654 +0.008641 +0.008684 +0.008769 +0.008743 +0.008777 +0.008743 +0.008711 +0.008762 +0.008844 +0.008833 +0.008852 +0.008831 +0.008807 +0.008878 +0.008944 +0.008934 +0.008962 +0.008942 +0.00891 +0.008895 +0.00887 +0.008799 +0.008789 +0.008724 +0.008652 +0.008565 +0.008571 +0.008511 +0.008503 +0.008455 +0.008393 +0.008422 +0.008471 +0.008367 +0.008353 +0.00828 +0.00825 +0.008249 +0.00829 +0.008246 +0.008257 +0.008223 +0.008179 +0.00823 +0.008256 +0.008238 +0.008252 +0.008194 +0.008178 +0.008183 +0.008251 +0.008224 +0.008249 +0.008225 +0.008218 +0.008258 +0.008331 +0.008318 +0.008337 +0.008307 +0.008303 +0.008364 +0.008407 +0.008405 +0.001239 +0.008436 +0.008398 +0.008387 +0.008428 +0.008511 +0.008477 +0.0085 +0.008453 +0.008446 +0.008477 +0.008557 +0.008523 +0.008553 +0.008514 +0.008509 +0.008544 +0.008628 +0.0086 +0.008638 +0.008614 +0.008622 +0.00866 +0.008753 +0.00872 +0.008752 +0.0087 +0.008693 +0.008703 +0.008763 +0.008717 +0.008711 +0.008612 +0.008554 +0.008535 +0.008571 +0.008489 +0.008489 +0.008391 +0.00835 +0.008345 +0.008393 +0.008342 +0.008339 +0.008274 +0.008245 +0.00825 +0.008301 +0.00827 +0.008282 +0.008228 +0.008216 +0.008237 +0.008304 +0.008281 +0.008299 +0.008249 +0.008251 +0.008282 +0.008358 +0.008343 +0.008365 +0.008323 +0.008318 +0.008343 +0.008431 +0.008426 +0.008445 +0.00124 +0.008405 +0.008398 +0.008431 +0.008523 +0.008499 +0.008524 +0.008492 +0.008481 +0.008519 +0.008601 +0.008578 +0.008614 +0.008575 +0.008571 +0.008605 +0.00869 +0.008667 +0.008695 +0.008657 +0.008648 +0.008687 +0.00878 +0.008756 +0.008797 +0.008753 +0.008756 +0.008799 +0.008897 +0.008856 +0.008874 +0.008741 +0.008676 +0.00868 +0.008728 +0.00864 +0.00858 +0.008505 +0.008441 +0.00841 +0.00845 +0.008383 +0.008373 +0.008334 +0.008257 +0.00823 +0.008275 +0.008214 +0.008229 +0.008181 +0.008143 +0.008178 +0.008241 +0.008197 +0.008218 +0.008134 +0.008121 +0.008146 +0.008215 +0.008187 +0.008212 +0.008176 +0.008177 +0.008212 +0.008286 +0.008269 +0.008297 +0.008264 +0.008262 +0.008313 +0.008371 +0.008359 +0.001241 +0.008379 +0.008352 +0.008325 +0.00833 +0.00841 +0.008394 +0.008423 +0.008389 +0.008383 +0.00843 +0.008508 +0.008486 +0.008519 +0.008487 +0.008476 +0.008512 +0.008591 +0.008575 +0.008618 +0.008584 +0.008568 +0.008601 +0.008688 +0.008663 +0.008687 +0.008662 +0.008654 +0.008679 +0.008756 +0.008704 +0.008696 +0.008626 +0.008576 +0.008555 +0.008596 +0.008521 +0.008501 +0.008419 +0.00836 +0.008347 +0.008396 +0.008331 +0.008328 +0.008262 +0.008221 +0.008221 +0.008279 +0.008226 +0.008232 +0.00818 +0.008153 +0.008171 +0.008242 +0.008201 +0.008216 +0.008167 +0.008148 +0.008171 +0.00825 +0.008215 +0.008233 +0.008199 +0.008185 +0.008217 +0.008302 +0.008275 +0.008307 +0.008266 +0.008249 +0.008294 +0.008374 +0.008366 +0.008374 +0.001242 +0.00835 +0.008338 +0.008375 +0.008457 +0.008441 +0.008477 +0.008421 +0.008414 +0.00845 +0.008536 +0.00852 +0.008552 +0.008514 +0.008499 +0.008545 +0.008626 +0.008598 +0.008645 +0.008588 +0.008591 +0.008629 +0.008732 +0.008704 +0.008735 +0.008704 +0.008702 +0.008727 +0.008742 +0.008673 +0.008679 +0.008624 +0.008581 +0.008581 +0.008603 +0.008509 +0.008512 +0.008432 +0.008373 +0.008355 +0.008412 +0.00835 +0.008378 +0.008316 +0.008269 +0.008245 +0.008279 +0.008236 +0.00825 +0.008214 +0.008188 +0.008213 +0.008293 +0.008248 +0.008285 +0.008235 +0.008208 +0.008259 +0.008334 +0.008301 +0.008335 +0.008242 +0.008234 +0.008275 +0.008359 +0.008323 +0.008365 +0.008339 +0.008331 +0.008368 +0.008462 +0.008431 +0.001243 +0.008471 +0.008421 +0.008414 +0.008465 +0.008536 +0.008516 +0.008548 +0.008523 +0.008502 +0.00855 +0.008617 +0.008588 +0.008614 +0.008587 +0.00856 +0.008598 +0.008664 +0.008633 +0.008659 +0.008628 +0.008611 +0.00866 +0.008736 +0.008759 +0.008793 +0.00877 +0.008735 +0.008756 +0.008813 +0.008754 +0.008731 +0.008661 +0.008591 +0.008588 +0.008611 +0.008531 +0.008511 +0.008436 +0.008369 +0.008365 +0.008406 +0.008356 +0.008361 +0.008302 +0.008252 +0.008263 +0.008311 +0.008276 +0.008296 +0.008263 +0.008222 +0.008257 +0.00833 +0.008302 +0.008309 +0.008274 +0.008239 +0.008289 +0.008371 +0.008358 +0.008384 +0.00835 +0.008325 +0.008372 +0.008442 +0.008425 +0.008454 +0.008425 +0.001244 +0.008418 +0.008461 +0.008533 +0.00852 +0.008531 +0.008514 +0.008482 +0.00853 +0.008594 +0.008597 +0.008618 +0.008599 +0.008571 +0.00862 +0.008686 +0.008683 +0.008704 +0.00868 +0.008647 +0.008702 +0.008776 +0.008763 +0.008793 +0.008763 +0.008752 +0.008805 +0.008881 +0.008878 +0.00889 +0.008872 +0.008827 +0.008768 +0.008763 +0.008708 +0.008685 +0.008636 +0.008546 +0.008478 +0.008499 +0.008454 +0.008433 +0.008377 +0.008329 +0.008364 +0.008371 +0.008294 +0.008255 +0.008212 +0.00815 +0.00818 +0.008204 +0.008178 +0.008173 +0.008136 +0.008107 +0.008146 +0.008216 +0.008179 +0.008164 +0.008124 +0.008085 +0.008151 +0.008208 +0.008183 +0.008216 +0.008192 +0.008165 +0.008234 +0.008292 +0.008268 +0.008293 +0.008288 +0.008233 +0.008267 +0.001245 +0.008335 +0.008305 +0.008343 +0.008324 +0.008306 +0.008344 +0.008421 +0.008407 +0.008436 +0.008408 +0.008394 +0.008437 +0.008509 +0.008493 +0.008513 +0.008479 +0.008461 +0.008518 +0.008606 +0.008595 +0.008605 +0.008579 +0.008552 +0.008596 +0.00868 +0.008661 +0.00867 +0.008605 +0.008563 +0.008548 +0.008576 +0.008516 +0.0085 +0.008407 +0.008347 +0.008338 +0.008357 +0.008297 +0.008288 +0.008212 +0.008154 +0.008168 +0.008199 +0.008154 +0.008142 +0.00808 +0.008045 +0.00807 +0.00812 +0.008087 +0.008091 +0.008041 +0.008016 +0.008054 +0.008104 +0.00808 +0.008097 +0.008068 +0.008036 +0.008085 +0.008153 +0.008143 +0.008164 +0.008125 +0.008111 +0.008141 +0.008216 +0.008204 +0.008245 +0.008217 +0.001246 +0.008192 +0.008233 +0.008313 +0.008287 +0.008319 +0.008274 +0.008257 +0.008293 +0.008375 +0.008355 +0.0084 +0.008362 +0.008354 +0.008392 +0.008472 +0.008442 +0.008476 +0.00844 +0.008432 +0.008472 +0.008559 +0.008539 +0.008569 +0.008541 +0.008531 +0.008575 +0.008671 +0.008607 +0.008558 +0.008497 +0.008453 +0.008453 +0.008495 +0.008402 +0.00832 +0.008248 +0.008223 +0.008215 +0.008237 +0.008165 +0.00818 +0.0081 +0.00804 +0.008022 +0.008071 +0.008009 +0.008016 +0.007979 +0.007938 +0.007958 +0.008019 +0.007958 +0.00797 +0.007908 +0.007897 +0.00792 +0.007972 +0.007936 +0.007963 +0.00792 +0.007926 +0.00796 +0.008035 +0.008015 +0.00804 +0.007999 +0.008 +0.008025 +0.008103 +0.008084 +0.008128 +0.008068 +0.001247 +0.008046 +0.008071 +0.008145 +0.00812 +0.008147 +0.008122 +0.008108 +0.008159 +0.008236 +0.008216 +0.008243 +0.008215 +0.008197 +0.008238 +0.008313 +0.008299 +0.008321 +0.008293 +0.008288 +0.008324 +0.008407 +0.008389 +0.008408 +0.008382 +0.008359 +0.008392 +0.008466 +0.008464 +0.008469 +0.008426 +0.00836 +0.008356 +0.008372 +0.008321 +0.008294 +0.008204 +0.008142 +0.008123 +0.008145 +0.008088 +0.008075 +0.008007 +0.007953 +0.007953 +0.007979 +0.007946 +0.007933 +0.007882 +0.007842 +0.007854 +0.007905 +0.007878 +0.007881 +0.00784 +0.007821 +0.007844 +0.007904 +0.007878 +0.007897 +0.007865 +0.007853 +0.007881 +0.007952 +0.007946 +0.007963 +0.007929 +0.007912 +0.00794 +0.00802 +0.00799 +0.00802 +0.007999 +0.001248 +0.007989 +0.008021 +0.008113 +0.008084 +0.008112 +0.008074 +0.008062 +0.008093 +0.008171 +0.008146 +0.008179 +0.00814 +0.008141 +0.008182 +0.008261 +0.008243 +0.00827 +0.008234 +0.008229 +0.00826 +0.008339 +0.00832 +0.008346 +0.008316 +0.008312 +0.008357 +0.008452 +0.008427 +0.008402 +0.008347 +0.008341 +0.008367 +0.008418 +0.008345 +0.008345 +0.008252 +0.008146 +0.008132 +0.008175 +0.0081 +0.008103 +0.008005 +0.007941 +0.007926 +0.007995 +0.007923 +0.007924 +0.007833 +0.007789 +0.007787 +0.007825 +0.007788 +0.007791 +0.007746 +0.007725 +0.00775 +0.007827 +0.007774 +0.007794 +0.00772 +0.007714 +0.007737 +0.007804 +0.007783 +0.007809 +0.007772 +0.007768 +0.007812 +0.007877 +0.007851 +0.00789 +0.007866 +0.007824 +0.00789 +0.007975 +0.007938 +0.001249 +0.007963 +0.00791 +0.007903 +0.007939 +0.008009 +0.007982 +0.00802 +0.007982 +0.007975 +0.00801 +0.008092 +0.00806 +0.008094 +0.008053 +0.008041 +0.008072 +0.008147 +0.008127 +0.008161 +0.008147 +0.008147 +0.008173 +0.008266 +0.008219 +0.008261 +0.008213 +0.008209 +0.008226 +0.008283 +0.008236 +0.00823 +0.00815 +0.008102 +0.008094 +0.008119 +0.008062 +0.008056 +0.007973 +0.007934 +0.00793 +0.007973 +0.007927 +0.007935 +0.007867 +0.007836 +0.007843 +0.007895 +0.007857 +0.007875 +0.007823 +0.007808 +0.007827 +0.007892 +0.007867 +0.007887 +0.007831 +0.007827 +0.007856 +0.007929 +0.007912 +0.007944 +0.0079 +0.007897 +0.00792 +0.007996 +0.007993 +0.008002 +0.007979 +0.00125 +0.007969 +0.008002 +0.008077 +0.008056 +0.008091 +0.008047 +0.008043 +0.008077 +0.00816 +0.00814 +0.008166 +0.008129 +0.008115 +0.008148 +0.008228 +0.008209 +0.008242 +0.008205 +0.008198 +0.008243 +0.00832 +0.008297 +0.00834 +0.008297 +0.008294 +0.008343 +0.008425 +0.008404 +0.008429 +0.008316 +0.008287 +0.008302 +0.008335 +0.008276 +0.008265 +0.008147 +0.008084 +0.008066 +0.008103 +0.008037 +0.008031 +0.007959 +0.007879 +0.007855 +0.007905 +0.007838 +0.007853 +0.007781 +0.007729 +0.00769 +0.007752 +0.007694 +0.00772 +0.007664 +0.007646 +0.007679 +0.007743 +0.007708 +0.007723 +0.007692 +0.007684 +0.007707 +0.007806 +0.007759 +0.007761 +0.007721 +0.007709 +0.007744 +0.007835 +0.007802 +0.00783 +0.007808 +0.007801 +0.007839 +0.007913 +0.007904 +0.001251 +0.007908 +0.007882 +0.007875 +0.007916 +0.007988 +0.00797 +0.008002 +0.00797 +0.007951 +0.007964 +0.00803 +0.007996 +0.008035 +0.00799 +0.007987 +0.00802 +0.008097 +0.00808 +0.008127 +0.008108 +0.008104 +0.00813 +0.008218 +0.008187 +0.008226 +0.008164 +0.008157 +0.008172 +0.008223 +0.008181 +0.008178 +0.008093 +0.008041 +0.008018 +0.008047 +0.007994 +0.007972 +0.007896 +0.007859 +0.007854 +0.007884 +0.00783 +0.007825 +0.007757 +0.007737 +0.007738 +0.007785 +0.007744 +0.007754 +0.007696 +0.007683 +0.007704 +0.00777 +0.007745 +0.007766 +0.007712 +0.007705 +0.00773 +0.007801 +0.007787 +0.007813 +0.007776 +0.007771 +0.0078 +0.007878 +0.007859 +0.007884 +0.007848 +0.00783 +0.001252 +0.007876 +0.00795 +0.007929 +0.007957 +0.007922 +0.007908 +0.007955 +0.008033 +0.008003 +0.008034 +0.007998 +0.00798 +0.008022 +0.008098 +0.008088 +0.008103 +0.008076 +0.008061 +0.008107 +0.008181 +0.008169 +0.008188 +0.008169 +0.008139 +0.008197 +0.008262 +0.008261 +0.008294 +0.008255 +0.008253 +0.008273 +0.00829 +0.008249 +0.008262 +0.008205 +0.008157 +0.008173 +0.008216 +0.008153 +0.008056 +0.007975 +0.007924 +0.00795 +0.007989 +0.007919 +0.007934 +0.007882 +0.007805 +0.007778 +0.007819 +0.00779 +0.007787 +0.007761 +0.007702 +0.007747 +0.007798 +0.007766 +0.007788 +0.007731 +0.007695 +0.007704 +0.007764 +0.007752 +0.007766 +0.007745 +0.007737 +0.007766 +0.007841 +0.00783 +0.007847 +0.007816 +0.007808 +0.00785 +0.007928 +0.007897 +0.007928 +0.001253 +0.007905 +0.007883 +0.007947 +0.007996 +0.007994 +0.008001 +0.007985 +0.007972 +0.008007 +0.008039 +0.008026 +0.008048 +0.00803 +0.008001 +0.008052 +0.008111 +0.008092 +0.00811 +0.008094 +0.00807 +0.008122 +0.008211 +0.00821 +0.00822 +0.008195 +0.00817 +0.008216 +0.008278 +0.00826 +0.008221 +0.008175 +0.008116 +0.008126 +0.00816 +0.008112 +0.008085 +0.008028 +0.007975 +0.007981 +0.008015 +0.007986 +0.007964 +0.007923 +0.007872 +0.007892 +0.007938 +0.007905 +0.007902 +0.007869 +0.007826 +0.007855 +0.007912 +0.00789 +0.007897 +0.007872 +0.007838 +0.007872 +0.007933 +0.007919 +0.007934 +0.007918 +0.007891 +0.007934 +0.008 +0.007991 +0.008006 +0.00798 +0.007963 +0.008015 +0.008075 +0.001254 +0.008061 +0.008088 +0.008055 +0.008036 +0.00808 +0.008156 +0.008143 +0.008163 +0.008132 +0.008118 +0.008162 +0.008232 +0.008221 +0.00824 +0.008214 +0.008195 +0.008236 +0.008314 +0.008314 +0.008321 +0.008299 +0.008287 +0.008327 +0.008418 +0.008411 +0.008432 +0.008377 +0.008278 +0.008292 +0.008337 +0.008286 +0.008282 +0.008228 +0.008177 +0.008135 +0.00813 +0.008075 +0.008067 +0.008028 +0.007979 +0.008006 +0.008044 +0.007958 +0.00793 +0.007872 +0.007849 +0.007865 +0.007893 +0.007845 +0.007863 +0.007809 +0.007797 +0.007816 +0.007852 +0.007822 +0.00783 +0.007809 +0.007783 +0.007826 +0.007899 +0.007867 +0.007902 +0.007876 +0.007852 +0.007887 +0.00794 +0.007912 +0.00795 +0.007943 +0.007889 +0.007951 +0.008037 +0.001255 +0.007998 +0.008032 +0.007996 +0.007996 +0.008033 +0.008108 +0.008081 +0.008109 +0.008076 +0.008067 +0.008104 +0.008175 +0.008147 +0.008174 +0.008136 +0.008124 +0.008152 +0.00824 +0.008212 +0.00824 +0.008219 +0.008233 +0.008251 +0.008321 +0.008273 +0.008264 +0.008187 +0.008132 +0.008127 +0.008167 +0.008106 +0.008084 +0.008006 +0.007964 +0.007953 +0.007996 +0.007945 +0.007944 +0.007873 +0.007847 +0.007851 +0.0079 +0.007863 +0.007871 +0.007818 +0.007792 +0.007806 +0.007874 +0.007849 +0.007872 +0.007824 +0.007816 +0.007827 +0.007908 +0.007883 +0.007911 +0.007875 +0.007874 +0.007886 +0.007976 +0.007952 +0.007992 +0.007949 +0.007934 +0.007974 +0.001256 +0.008047 +0.008027 +0.008055 +0.008026 +0.008011 +0.008051 +0.008125 +0.008112 +0.008135 +0.008103 +0.008084 +0.008122 +0.008195 +0.008187 +0.008212 +0.008181 +0.00816 +0.008217 +0.008287 +0.008282 +0.008304 +0.008276 +0.008258 +0.008317 +0.008408 +0.008377 +0.008351 +0.008257 +0.008217 +0.008238 +0.008276 +0.008226 +0.008198 +0.008092 +0.008043 +0.008039 +0.008067 +0.008017 +0.008022 +0.007937 +0.007866 +0.00787 +0.007908 +0.007879 +0.007864 +0.007834 +0.007761 +0.007764 +0.007795 +0.007769 +0.007783 +0.007751 +0.007729 +0.007759 +0.007828 +0.007796 +0.007819 +0.007791 +0.007769 +0.00783 +0.007888 +0.007882 +0.007897 +0.007862 +0.007858 +0.007872 +0.007931 +0.00791 +0.001257 +0.007922 +0.007913 +0.007898 +0.007952 +0.00801 +0.007993 +0.008015 +0.008002 +0.007975 +0.008027 +0.008089 +0.008081 +0.008098 +0.008077 +0.008052 +0.008094 +0.008156 +0.008147 +0.008154 +0.008133 +0.008108 +0.008167 +0.008213 +0.008227 +0.008256 +0.008239 +0.008203 +0.008234 +0.008281 +0.008244 +0.008215 +0.008162 +0.008097 +0.008107 +0.008118 +0.008078 +0.008057 +0.008 +0.007943 +0.007947 +0.007992 +0.007954 +0.007934 +0.0079 +0.007852 +0.007873 +0.007924 +0.007895 +0.007888 +0.007857 +0.007819 +0.007854 +0.007919 +0.007904 +0.007907 +0.007884 +0.007846 +0.007888 +0.007952 +0.007945 +0.00796 +0.007943 +0.007909 +0.007958 +0.008024 +0.008019 +0.008044 +0.008001 +0.001258 +0.007989 +0.008038 +0.008102 +0.008095 +0.008111 +0.008085 +0.008062 +0.008123 +0.008176 +0.008174 +0.00819 +0.008164 +0.008137 +0.008192 +0.008253 +0.008249 +0.008274 +0.008245 +0.008217 +0.008275 +0.008343 +0.008332 +0.008365 +0.008333 +0.008312 +0.00838 +0.008452 +0.008441 +0.008434 +0.00832 +0.008266 +0.008283 +0.008321 +0.008263 +0.008221 +0.008121 +0.008052 +0.008063 +0.008097 +0.008055 +0.008021 +0.00796 +0.007892 +0.0079 +0.007926 +0.007897 +0.00789 +0.007853 +0.007801 +0.007824 +0.007839 +0.007826 +0.00783 +0.007812 +0.007779 +0.007818 +0.007884 +0.007855 +0.007875 +0.007859 +0.007829 +0.007864 +0.007896 +0.007888 +0.007901 +0.007885 +0.007871 +0.007913 +0.008006 +0.007971 +0.007985 +0.007982 +0.007957 +0.001259 +0.008003 +0.008069 +0.008064 +0.008081 +0.008057 +0.008034 +0.008089 +0.008153 +0.008146 +0.008161 +0.008136 +0.008105 +0.008154 +0.008214 +0.008211 +0.008211 +0.008194 +0.008162 +0.008217 +0.008272 +0.008292 +0.008308 +0.008289 +0.008252 +0.008275 +0.008315 +0.008275 +0.008251 +0.008191 +0.008132 +0.008124 +0.008153 +0.008115 +0.008086 +0.008034 +0.007977 +0.007988 +0.008029 +0.007997 +0.007982 +0.007944 +0.007905 +0.00792 +0.007971 +0.007946 +0.007944 +0.007907 +0.007879 +0.007914 +0.00797 +0.007959 +0.00796 +0.007935 +0.007902 +0.007944 +0.008013 +0.008016 +0.008022 +0.008007 +0.007975 +0.008025 +0.008084 +0.008084 +0.008093 +0.00808 +0.00126 +0.008053 +0.008097 +0.008172 +0.008156 +0.008177 +0.008155 +0.008129 +0.008182 +0.008241 +0.008233 +0.008259 +0.008227 +0.00821 +0.008257 +0.008324 +0.008312 +0.008335 +0.008311 +0.008288 +0.00834 +0.008414 +0.008403 +0.008427 +0.008409 +0.008398 +0.008446 +0.008517 +0.00846 +0.008388 +0.00832 +0.008267 +0.008289 +0.008307 +0.008218 +0.008206 +0.008118 +0.008066 +0.008055 +0.0081 +0.008055 +0.008046 +0.00799 +0.007914 +0.007895 +0.007955 +0.007899 +0.007925 +0.007856 +0.007845 +0.007857 +0.007934 +0.007888 +0.00788 +0.007825 +0.00779 +0.007853 +0.0079 +0.007881 +0.007909 +0.00787 +0.007871 +0.007913 +0.007967 +0.007962 +0.007972 +0.007961 +0.007927 +0.007966 +0.008032 +0.008012 +0.001261 +0.008039 +0.008002 +0.007997 +0.008044 +0.008117 +0.00809 +0.008125 +0.008075 +0.008073 +0.008116 +0.008194 +0.008169 +0.008194 +0.008158 +0.00814 +0.008171 +0.008248 +0.008214 +0.008253 +0.008214 +0.008202 +0.008239 +0.008343 +0.008333 +0.008352 +0.00829 +0.008245 +0.008235 +0.008273 +0.008199 +0.008188 +0.008126 +0.008082 +0.008074 +0.008116 +0.008059 +0.008063 +0.007991 +0.007947 +0.007957 +0.008012 +0.007967 +0.007979 +0.007919 +0.00789 +0.007898 +0.007967 +0.007925 +0.007956 +0.007913 +0.007886 +0.007915 +0.007985 +0.007959 +0.00799 +0.007952 +0.007938 +0.007967 +0.008047 +0.008021 +0.008063 +0.008033 +0.008009 +0.008034 +0.008125 +0.001262 +0.008101 +0.008141 +0.008099 +0.00809 +0.008124 +0.008204 +0.008179 +0.008211 +0.008174 +0.008172 +0.008192 +0.008282 +0.008263 +0.008295 +0.008259 +0.008251 +0.008286 +0.008365 +0.00835 +0.008374 +0.008343 +0.008329 +0.008385 +0.008464 +0.008451 +0.008489 +0.00845 +0.008358 +0.008332 +0.008366 +0.008309 +0.008312 +0.008241 +0.008202 +0.008158 +0.008136 +0.008069 +0.008072 +0.00801 +0.00798 +0.007986 +0.008052 +0.00799 +0.007959 +0.007855 +0.007844 +0.007847 +0.007924 +0.007859 +0.00788 +0.007845 +0.007798 +0.007807 +0.007875 +0.007839 +0.007875 +0.007835 +0.007822 +0.007873 +0.007938 +0.007922 +0.007938 +0.007906 +0.0079 +0.007933 +0.008028 +0.007986 +0.008019 +0.008004 +0.001263 +0.007981 +0.008024 +0.008104 +0.00808 +0.008101 +0.008083 +0.008066 +0.008089 +0.008133 +0.008115 +0.008143 +0.008119 +0.0081 +0.00815 +0.008214 +0.008196 +0.008214 +0.008183 +0.008173 +0.008212 +0.008302 +0.008311 +0.008332 +0.008297 +0.008267 +0.008305 +0.008359 +0.008322 +0.00832 +0.00825 +0.008192 +0.008198 +0.008227 +0.008173 +0.008166 +0.008094 +0.008028 +0.008045 +0.008087 +0.008053 +0.008052 +0.007999 +0.007959 +0.007981 +0.00804 +0.008006 +0.008016 +0.007973 +0.007934 +0.007972 +0.008036 +0.008012 +0.008028 +0.007994 +0.007962 +0.008005 +0.008078 +0.008063 +0.008092 +0.008058 +0.008039 +0.008071 +0.008147 +0.008149 +0.008154 +0.008132 +0.001264 +0.008116 +0.008152 +0.008229 +0.008212 +0.008247 +0.008209 +0.008196 +0.008228 +0.008312 +0.008292 +0.008321 +0.008288 +0.008277 +0.008308 +0.008395 +0.008373 +0.008404 +0.008362 +0.008357 +0.008395 +0.008472 +0.00846 +0.008487 +0.008459 +0.008447 +0.008496 +0.008588 +0.008563 +0.008584 +0.008495 +0.008392 +0.008385 +0.008422 +0.008372 +0.008361 +0.008219 +0.008168 +0.008144 +0.00819 +0.008127 +0.00814 +0.00807 +0.008043 +0.008036 +0.008032 +0.007994 +0.007992 +0.007956 +0.007921 +0.007942 +0.00802 +0.007972 +0.00801 +0.007954 +0.007944 +0.007948 +0.007993 +0.007975 +0.007992 +0.007966 +0.00796 +0.007989 +0.008081 +0.008043 +0.008072 +0.008046 +0.008031 +0.008071 +0.008162 +0.008145 +0.00814 +0.001265 +0.008104 +0.008091 +0.008116 +0.008196 +0.008173 +0.00821 +0.008162 +0.008157 +0.008204 +0.008284 +0.008256 +0.008288 +0.008248 +0.008238 +0.00827 +0.008352 +0.008332 +0.008362 +0.008335 +0.008341 +0.008369 +0.008456 +0.008426 +0.008448 +0.008398 +0.008364 +0.008367 +0.008422 +0.008359 +0.008345 +0.008267 +0.008216 +0.008206 +0.008253 +0.00819 +0.008194 +0.008108 +0.008072 +0.008075 +0.008143 +0.008088 +0.008096 +0.008039 +0.008003 +0.008015 +0.008085 +0.008046 +0.008066 +0.008018 +0.007998 +0.008017 +0.008091 +0.008059 +0.008087 +0.008051 +0.008033 +0.008065 +0.008152 +0.008126 +0.008158 +0.008124 +0.008104 +0.008145 +0.008226 +0.008204 +0.001266 +0.00823 +0.008205 +0.008187 +0.008221 +0.008304 +0.008288 +0.008308 +0.008278 +0.008263 +0.008307 +0.00838 +0.008371 +0.008392 +0.008363 +0.008352 +0.008382 +0.008457 +0.008448 +0.008473 +0.008439 +0.008427 +0.008475 +0.00856 +0.008545 +0.008582 +0.008554 +0.008538 +0.008569 +0.008543 +0.008468 +0.008457 +0.008404 +0.008353 +0.00831 +0.008303 +0.008236 +0.008242 +0.008186 +0.008128 +0.008161 +0.008204 +0.008129 +0.008081 +0.008028 +0.008 +0.008012 +0.00805 +0.007992 +0.008007 +0.00795 +0.007941 +0.007964 +0.007993 +0.007964 +0.007969 +0.007946 +0.007928 +0.007961 +0.008048 +0.008004 +0.008039 +0.008 +0.007956 +0.008006 +0.008058 +0.008044 +0.008067 +0.008041 +0.008038 +0.008081 +0.008162 +0.008124 +0.00816 +0.001267 +0.008137 +0.008108 +0.008168 +0.008236 +0.008224 +0.008241 +0.008221 +0.008192 +0.008247 +0.008313 +0.008295 +0.008313 +0.008288 +0.008257 +0.008304 +0.008363 +0.008352 +0.008374 +0.008355 +0.008334 +0.008408 +0.008473 +0.008462 +0.008453 +0.008407 +0.008343 +0.008355 +0.00838 +0.008331 +0.008296 +0.00823 +0.008159 +0.008175 +0.008204 +0.008158 +0.008131 +0.008082 +0.008026 +0.008056 +0.008089 +0.008058 +0.008054 +0.008003 +0.007954 +0.007989 +0.008031 +0.008023 +0.008034 +0.007995 +0.007954 +0.007998 +0.008043 +0.008035 +0.008056 +0.00803 +0.007992 +0.008045 +0.008104 +0.008103 +0.008124 +0.008099 +0.008064 +0.008122 +0.008184 +0.008178 +0.001268 +0.008205 +0.008173 +0.008146 +0.00819 +0.008267 +0.008258 +0.008282 +0.008249 +0.008232 +0.008269 +0.008344 +0.008337 +0.008361 +0.008326 +0.008311 +0.008349 +0.008422 +0.008408 +0.008444 +0.00841 +0.008392 +0.008438 +0.00852 +0.008505 +0.008533 +0.00851 +0.008494 +0.008532 +0.008571 +0.008447 +0.008393 +0.008336 +0.008278 +0.00824 +0.008243 +0.008186 +0.008182 +0.008119 +0.008061 +0.008061 +0.008057 +0.008026 +0.008024 +0.007979 +0.007918 +0.007886 +0.007939 +0.007891 +0.007906 +0.007866 +0.00784 +0.007883 +0.007935 +0.007913 +0.007917 +0.007894 +0.007868 +0.007916 +0.007992 +0.007955 +0.007952 +0.007908 +0.007896 +0.007945 +0.008006 +0.007998 +0.008016 +0.007999 +0.007986 +0.008029 +0.008099 +0.008106 +0.008096 +0.001269 +0.00808 +0.008065 +0.008108 +0.008194 +0.008166 +0.008197 +0.008159 +0.008149 +0.008189 +0.008265 +0.008237 +0.008262 +0.00822 +0.008208 +0.008239 +0.008322 +0.008297 +0.008319 +0.008287 +0.008279 +0.008332 +0.008426 +0.008406 +0.00842 +0.008364 +0.008333 +0.008324 +0.008369 +0.008314 +0.008313 +0.008229 +0.008181 +0.008163 +0.008203 +0.008155 +0.008147 +0.008076 +0.008046 +0.008045 +0.008104 +0.008067 +0.008071 +0.008014 +0.007991 +0.007998 +0.00807 +0.008038 +0.008059 +0.008014 +0.008 +0.008018 +0.008096 +0.008081 +0.008104 +0.008073 +0.008056 +0.008083 +0.008172 +0.008148 +0.008177 +0.008155 +0.008119 +0.008171 +0.008242 +0.00127 +0.00823 +0.008258 +0.008226 +0.008209 +0.008241 +0.008327 +0.00831 +0.008341 +0.008301 +0.008294 +0.008322 +0.008408 +0.008388 +0.008422 +0.008377 +0.00837 +0.008404 +0.008498 +0.008475 +0.008508 +0.008477 +0.00846 +0.008511 +0.008591 +0.008576 +0.00862 +0.008577 +0.008547 +0.008466 +0.008523 +0.008463 +0.008468 +0.008419 +0.008376 +0.008377 +0.008407 +0.008313 +0.008305 +0.008249 +0.0082 +0.008182 +0.008218 +0.008175 +0.008199 +0.008136 +0.008123 +0.008132 +0.008197 +0.00814 +0.008135 +0.008083 +0.008073 +0.008095 +0.008177 +0.008128 +0.008176 +0.00812 +0.008127 +0.008142 +0.008216 +0.008178 +0.008202 +0.008183 +0.008163 +0.008209 +0.008293 +0.008262 +0.008319 +0.008254 +0.008249 +0.001271 +0.008306 +0.008372 +0.00835 +0.008385 +0.008354 +0.008334 +0.008383 +0.008455 +0.008441 +0.008463 +0.008433 +0.008408 +0.008459 +0.008519 +0.008492 +0.008518 +0.008491 +0.00847 +0.00851 +0.008574 +0.00856 +0.008586 +0.008579 +0.008574 +0.008601 +0.008646 +0.0086 +0.008575 +0.008484 +0.008437 +0.008437 +0.008461 +0.008406 +0.008378 +0.008304 +0.008263 +0.008267 +0.008308 +0.008273 +0.008268 +0.008209 +0.008178 +0.008193 +0.008249 +0.008212 +0.008221 +0.008174 +0.008147 +0.008173 +0.008239 +0.008226 +0.008235 +0.008191 +0.008176 +0.008211 +0.008282 +0.008265 +0.008286 +0.008248 +0.008236 +0.00828 +0.008353 +0.008349 +0.008357 +0.008332 +0.008312 +0.001272 +0.008357 +0.008447 +0.008412 +0.008452 +0.008409 +0.008393 +0.008439 +0.008524 +0.008505 +0.008533 +0.008494 +0.008481 +0.008516 +0.008594 +0.008573 +0.008612 +0.008572 +0.008562 +0.008604 +0.008686 +0.008669 +0.008699 +0.008672 +0.008664 +0.008706 +0.008799 +0.00875 +0.008764 +0.008646 +0.008531 +0.008532 +0.008595 +0.008522 +0.008476 +0.00839 +0.008337 +0.008337 +0.008403 +0.00833 +0.008299 +0.008235 +0.008197 +0.008174 +0.008238 +0.008169 +0.008191 +0.008137 +0.008111 +0.008148 +0.008208 +0.008184 +0.008153 +0.008116 +0.008095 +0.008126 +0.008215 +0.008167 +0.008201 +0.008162 +0.008158 +0.008204 +0.008281 +0.00825 +0.008283 +0.008259 +0.008227 +0.008279 +0.008363 +0.001273 +0.008342 +0.008359 +0.008301 +0.008304 +0.008333 +0.008414 +0.008376 +0.008429 +0.008381 +0.008374 +0.008414 +0.008499 +0.008473 +0.008501 +0.008463 +0.008444 +0.008478 +0.008563 +0.008535 +0.008581 +0.008533 +0.008546 +0.008594 +0.008678 +0.008646 +0.008668 +0.008606 +0.008564 +0.008576 +0.00862 +0.008555 +0.008554 +0.00845 +0.008409 +0.008411 +0.008453 +0.008386 +0.00839 +0.008317 +0.00828 +0.008295 +0.008349 +0.008301 +0.008314 +0.008244 +0.008215 +0.008241 +0.008308 +0.008272 +0.008296 +0.008232 +0.008216 +0.00825 +0.008325 +0.008296 +0.008321 +0.008272 +0.008257 +0.0083 +0.00838 +0.008364 +0.008398 +0.008347 +0.008344 +0.008378 +0.008443 +0.001274 +0.008433 +0.008476 +0.008433 +0.008419 +0.00846 +0.008537 +0.008521 +0.008551 +0.008513 +0.008504 +0.00854 +0.008629 +0.008604 +0.008639 +0.008595 +0.00858 +0.008618 +0.008708 +0.008687 +0.00873 +0.008686 +0.008689 +0.008732 +0.008818 +0.008794 +0.008814 +0.00876 +0.008698 +0.008609 +0.008639 +0.008576 +0.008576 +0.008508 +0.008411 +0.008355 +0.008409 +0.008344 +0.008343 +0.008296 +0.008254 +0.008257 +0.008275 +0.008186 +0.008213 +0.008146 +0.008129 +0.008148 +0.0082 +0.008155 +0.008158 +0.008123 +0.008085 +0.008102 +0.008178 +0.008133 +0.008171 +0.008128 +0.008116 +0.008158 +0.008227 +0.008205 +0.008232 +0.008208 +0.008196 +0.00824 +0.008331 +0.008301 +0.008293 +0.001275 +0.008262 +0.00825 +0.008289 +0.008387 +0.008345 +0.008379 +0.008341 +0.008346 +0.008372 +0.00846 +0.008422 +0.008462 +0.008423 +0.00841 +0.008449 +0.008524 +0.008491 +0.008523 +0.008487 +0.008484 +0.008499 +0.008586 +0.008592 +0.008639 +0.008602 +0.008585 +0.008595 +0.008657 +0.008597 +0.008578 +0.008493 +0.008454 +0.008429 +0.008461 +0.008396 +0.00838 +0.008302 +0.008255 +0.008246 +0.008299 +0.008256 +0.008261 +0.008196 +0.008167 +0.008165 +0.008224 +0.008194 +0.008204 +0.008155 +0.008137 +0.008153 +0.008222 +0.008196 +0.008216 +0.008179 +0.008164 +0.008187 +0.008265 +0.008245 +0.008273 +0.00824 +0.008232 +0.008258 +0.008347 +0.008326 +0.008343 +0.008315 +0.001276 +0.008314 +0.008338 +0.008428 +0.0084 +0.008429 +0.008396 +0.008387 +0.008424 +0.008509 +0.008486 +0.008515 +0.008475 +0.008464 +0.0085 +0.008584 +0.008566 +0.008598 +0.008566 +0.008555 +0.008589 +0.008683 +0.008655 +0.00869 +0.008664 +0.00866 +0.008706 +0.008783 +0.008717 +0.008636 +0.008536 +0.008484 +0.008502 +0.00853 +0.008422 +0.008436 +0.008345 +0.008283 +0.008275 +0.008341 +0.008264 +0.008288 +0.00823 +0.008143 +0.008154 +0.00819 +0.008157 +0.008165 +0.008135 +0.008104 +0.008151 +0.008213 +0.008172 +0.008196 +0.008148 +0.008149 +0.008175 +0.00823 +0.008188 +0.008213 +0.008192 +0.008176 +0.008195 +0.008279 +0.008235 +0.008275 +0.008247 +0.00824 +0.008276 +0.008374 +0.008331 +0.008381 +0.008332 +0.001277 +0.00832 +0.008366 +0.008452 +0.008425 +0.008453 +0.008422 +0.008403 +0.008456 +0.00853 +0.00851 +0.008533 +0.0085 +0.008471 +0.008506 +0.008582 +0.008556 +0.008581 +0.008558 +0.008527 +0.008567 +0.008665 +0.008642 +0.008644 +0.008561 +0.008483 +0.008482 +0.008496 +0.008445 +0.008438 +0.008356 +0.008279 +0.008286 +0.008323 +0.008269 +0.00827 +0.008198 +0.008139 +0.00815 +0.008194 +0.008156 +0.00816 +0.008103 +0.008064 +0.008091 +0.00815 +0.00811 +0.008136 +0.008088 +0.008057 +0.008082 +0.008143 +0.00813 +0.008146 +0.008121 +0.008097 +0.008137 +0.008206 +0.00818 +0.00821 +0.008169 +0.008154 +0.0082 +0.008277 +0.008264 +0.008299 +0.008257 +0.001278 +0.008241 +0.008279 +0.008361 +0.008344 +0.008369 +0.008334 +0.008327 +0.008361 +0.008444 +0.008423 +0.008451 +0.008413 +0.008403 +0.008449 +0.008518 +0.008508 +0.008543 +0.008498 +0.008493 +0.00854 +0.008626 +0.008604 +0.008638 +0.008593 +0.008555 +0.00849 +0.008469 +0.008398 +0.008392 +0.008327 +0.008243 +0.008191 +0.008224 +0.008163 +0.008164 +0.008093 +0.008065 +0.00807 +0.00811 +0.008004 +0.008013 +0.007962 +0.007925 +0.007914 +0.007982 +0.00793 +0.007964 +0.007915 +0.007902 +0.007929 +0.007995 +0.007971 +0.00799 +0.007959 +0.007949 +0.007949 +0.008023 +0.007984 +0.008022 +0.007992 +0.007979 +0.00802 +0.008109 +0.008081 +0.008111 +0.008087 +0.008074 +0.008123 +0.001279 +0.008174 +0.008168 +0.008195 +0.008159 +0.008157 +0.008197 +0.008272 +0.008245 +0.008281 +0.008244 +0.008238 +0.008277 +0.008354 +0.008313 +0.008342 +0.008302 +0.008292 +0.008326 +0.008398 +0.008364 +0.008391 +0.00834 +0.008347 +0.008374 +0.008482 +0.008474 +0.008481 +0.008396 +0.008349 +0.008319 +0.008346 +0.008293 +0.008286 +0.008204 +0.008156 +0.008137 +0.008184 +0.008146 +0.008141 +0.008068 +0.008032 +0.008034 +0.008087 +0.008058 +0.008063 +0.008003 +0.007979 +0.00798 +0.00805 +0.00803 +0.008051 +0.008 +0.007984 +0.007993 +0.008064 +0.008037 +0.00807 +0.008033 +0.00803 +0.008058 +0.008137 +0.008116 +0.008139 +0.008105 +0.008086 +0.008134 +0.008186 +0.008194 +0.00128 +0.008227 +0.008186 +0.00818 +0.008208 +0.008288 +0.008267 +0.008293 +0.008255 +0.008247 +0.008278 +0.008366 +0.008352 +0.008384 +0.008343 +0.008329 +0.008376 +0.008458 +0.008437 +0.008482 +0.008438 +0.00843 +0.008479 +0.008568 +0.008545 +0.008556 +0.008436 +0.008407 +0.008416 +0.00846 +0.008376 +0.008362 +0.008208 +0.008158 +0.008169 +0.008188 +0.008117 +0.008104 +0.008026 +0.007958 +0.007956 +0.007994 +0.007947 +0.007945 +0.007867 +0.007827 +0.007824 +0.007874 +0.007838 +0.007857 +0.007816 +0.007804 +0.007827 +0.007907 +0.007867 +0.007884 +0.007853 +0.007842 +0.007874 +0.007954 +0.007911 +0.007946 +0.007912 +0.007892 +0.007912 +0.007993 +0.007958 +0.007994 +0.007974 +0.007961 +0.007999 +0.008092 +0.001281 +0.008043 +0.008079 +0.008049 +0.008037 +0.008088 +0.008148 +0.008137 +0.008163 +0.008134 +0.008119 +0.008158 +0.008232 +0.008203 +0.008223 +0.008196 +0.008178 +0.008218 +0.00829 +0.008268 +0.008307 +0.008291 +0.008281 +0.00832 +0.00837 +0.008335 +0.008326 +0.008254 +0.008198 +0.008201 +0.008247 +0.008199 +0.008181 +0.00811 +0.008066 +0.008073 +0.008091 +0.00807 +0.008064 +0.008004 +0.007973 +0.007997 +0.008052 +0.008022 +0.008029 +0.007975 +0.007942 +0.007963 +0.008014 +0.008008 +0.008036 +0.008 +0.007973 +0.008011 +0.008069 +0.008055 +0.008072 +0.008035 +0.008025 +0.00806 +0.008132 +0.008136 +0.008156 +0.008127 +0.008103 +0.001282 +0.008148 +0.008211 +0.008201 +0.008241 +0.008192 +0.008189 +0.008219 +0.008299 +0.008283 +0.008318 +0.008286 +0.008274 +0.00831 +0.00839 +0.008366 +0.008399 +0.008352 +0.008335 +0.008388 +0.008463 +0.008458 +0.008486 +0.00846 +0.008452 +0.008498 +0.00858 +0.008481 +0.008441 +0.008376 +0.008334 +0.008299 +0.008325 +0.008259 +0.008252 +0.008156 +0.008104 +0.008082 +0.008121 +0.008084 +0.008084 +0.00803 +0.007991 +0.007937 +0.007973 +0.007909 +0.007924 +0.007886 +0.007854 +0.007883 +0.007952 +0.007891 +0.00792 +0.007867 +0.007855 +0.007888 +0.007936 +0.00789 +0.00792 +0.007872 +0.007872 +0.007883 +0.007948 +0.007929 +0.00796 +0.007927 +0.00793 +0.00796 +0.008042 +0.008022 +0.00805 +0.00803 +0.007996 +0.008045 +0.001283 +0.008126 +0.008096 +0.008137 +0.008099 +0.008089 +0.008127 +0.008204 +0.008175 +0.008209 +0.008174 +0.008166 +0.008187 +0.008253 +0.008209 +0.008243 +0.008203 +0.008201 +0.008234 +0.008311 +0.008297 +0.008355 +0.008336 +0.008316 +0.008332 +0.008389 +0.008326 +0.008307 +0.008227 +0.008162 +0.008154 +0.008212 +0.00814 +0.00812 +0.008054 +0.008007 +0.008003 +0.008051 +0.007988 +0.007993 +0.007946 +0.007913 +0.007923 +0.007979 +0.007937 +0.007944 +0.007897 +0.007868 +0.007888 +0.007965 +0.00794 +0.007966 +0.007928 +0.00791 +0.007938 +0.008019 +0.007992 +0.008022 +0.007994 +0.007987 +0.008014 +0.008105 +0.008073 +0.008103 +0.001284 +0.008052 +0.008042 +0.00808 +0.008163 +0.008156 +0.008185 +0.00814 +0.00813 +0.008166 +0.008238 +0.008223 +0.008249 +0.008223 +0.00821 +0.008252 +0.008326 +0.008311 +0.008336 +0.008315 +0.008287 +0.008337 +0.008422 +0.008404 +0.008444 +0.008406 +0.008396 +0.008442 +0.008462 +0.008401 +0.008406 +0.008349 +0.008308 +0.008295 +0.0083 +0.008239 +0.008241 +0.008185 +0.008114 +0.008088 +0.008113 +0.008053 +0.008059 +0.008005 +0.007956 +0.007933 +0.007948 +0.007911 +0.00792 +0.007878 +0.007857 +0.007881 +0.00794 +0.007904 +0.007907 +0.007879 +0.007845 +0.007874 +0.007945 +0.007915 +0.007944 +0.00792 +0.007901 +0.007956 +0.008017 +0.008006 +0.008029 +0.008013 +0.007984 +0.008037 +0.008105 +0.001285 +0.00809 +0.008119 +0.008077 +0.008071 +0.008117 +0.008197 +0.008166 +0.008202 +0.008142 +0.008131 +0.008157 +0.00823 +0.008202 +0.008238 +0.008202 +0.008194 +0.008226 +0.008308 +0.008277 +0.008312 +0.008283 +0.008297 +0.00834 +0.008426 +0.008391 +0.008411 +0.00837 +0.008343 +0.008354 +0.008406 +0.008349 +0.008328 +0.008241 +0.008182 +0.008174 +0.008207 +0.008135 +0.008132 +0.008058 +0.008007 +0.008014 +0.008072 +0.008008 +0.008025 +0.007973 +0.007943 +0.007954 +0.008021 +0.007982 +0.007989 +0.007948 +0.007943 +0.007971 +0.008059 +0.008031 +0.008052 +0.00802 +0.007997 +0.008029 +0.008105 +0.00808 +0.008112 +0.00808 +0.008063 +0.008099 +0.00819 +0.001286 +0.008175 +0.008196 +0.008158 +0.008151 +0.008181 +0.008268 +0.008245 +0.00828 +0.008243 +0.008234 +0.008272 +0.008353 +0.008331 +0.008371 +0.00832 +0.008315 +0.008355 +0.00844 +0.008423 +0.008452 +0.008419 +0.008418 +0.008456 +0.008547 +0.008514 +0.008533 +0.008459 +0.008449 +0.008487 +0.00858 +0.008548 +0.008579 +0.008542 +0.008548 +0.008586 +0.008667 +0.008635 +0.008677 +0.008635 +0.00863 +0.008677 +0.008785 +0.008732 +0.008765 +0.008739 +0.008722 +0.008763 +0.008847 +0.008826 +0.008838 +0.008781 +0.008771 +0.008825 +0.008906 +0.00887 +0.00891 +0.008884 +0.008874 +0.008916 +0.009001 +0.00897 +0.009016 +0.008973 +0.008966 +0.009004 +0.009096 +0.009071 +0.009108 +0.009049 +0.009043 +0.009091 +0.009185 +0.009151 +0.009185 +0.009138 +0.009133 +0.009182 +0.009269 +0.009229 +0.00927 +0.009231 +0.009216 +0.009263 +0.009352 +0.009314 +0.009359 +0.009317 +0.0093 +0.009345 +0.009426 +0.009396 +0.009435 +0.009397 +0.009381 +0.009427 +0.009509 +0.009481 +0.009523 +0.009485 +0.009473 +0.009513 +0.009602 +0.009569 +0.009609 +0.009566 +0.00956 +0.009605 +0.009691 +0.009664 +0.0097 +0.009652 +0.009641 +0.009691 +0.009785 +0.009754 +0.009795 +0.009753 +0.00975 +0.009796 +0.00989 +0.009866 +0.009901 +0.009863 +0.009834 +0.009884 +0.01 +0.009953 +0.009993 +0.009946 +0.009921 +0.009975 +0.010075 +0.010045 +0.010083 +0.010038 +0.010017 +0.010066 +0.010153 +0.010137 +0.010176 +0.01013 +0.010131 +0.010161 +0.010253 +0.010236 +0.010281 +0.010236 +0.010231 +0.010273 +0.010368 +0.010341 +0.010387 +0.010327 +0.010326 +0.010372 +0.010469 +0.010445 +0.010484 +0.010435 +0.010426 +0.01048 +0.01058 +0.010557 +0.010593 +0.010542 +0.010531 +0.010584 +0.010682 +0.01066 +0.010697 +0.010645 +0.010641 +0.010677 +0.010787 +0.010765 +0.010802 +0.01075 +0.010741 +0.01079 +0.010892 +0.010869 +0.010911 +0.01086 +0.010849 +0.0109 +0.011005 +0.010987 +0.011026 +0.010978 +0.01097 +0.011014 +0.011124 +0.011095 +0.011142 +0.011094 +0.011069 +0.011129 +0.011232 +0.01121 +0.011257 +0.011198 +0.011187 +0.011244 +0.011344 +0.011328 +0.011374 +0.011323 +0.01131 +0.011362 +0.01147 +0.011446 +0.011491 +0.011442 +0.011425 +0.011479 +0.011587 +0.011564 +0.011615 +0.011554 +0.011544 +0.011601 +0.011718 +0.011676 +0.011732 +0.01168 +0.011667 +0.011724 +0.011832 +0.01181 +0.011858 +0.011809 +0.011794 +0.011851 +0.011963 +0.011936 +0.011987 +0.011934 +0.011919 +0.011978 +0.012091 +0.01207 +0.012124 +0.012065 +0.012058 +0.012111 +0.012225 +0.0122 +0.012251 +0.012192 +0.01218 +0.012238 +0.012352 +0.012327 +0.012379 +0.012325 +0.012312 +0.012368 +0.012487 +0.012464 +0.012519 +0.012464 +0.012448 +0.012508 +0.012628 +0.012603 +0.012653 +0.012599 +0.012582 +0.012639 +0.012762 +0.012742 +0.012794 +0.012739 +0.012727 +0.012787 +0.012904 +0.012889 +0.012938 +0.012886 +0.012869 +0.012931 +0.01305 +0.013038 +0.013085 +0.013032 +0.013017 +0.013078 +0.013204 +0.013181 +0.013238 +0.013176 +0.013162 +0.01323 +0.013354 +0.013336 +0.013394 +0.013335 +0.013318 +0.013384 +0.013515 +0.013484 +0.013538 +0.013483 +0.013465 +0.013534 +0.013668 +0.013647 +0.013705 +0.01365 +0.013629 +0.013699 +0.013827 +0.013803 +0.013855 +0.013802 +0.013781 +0.013856 +0.013991 +0.013968 +0.014032 +0.013969 +0.01396 +0.014016 +0.014157 +0.014132 +0.014187 +0.014128 +0.014109 +0.01418 +0.014315 +0.014296 +0.014358 +0.014302 +0.014285 +0.014355 +0.014494 +0.01447 +0.014529 +0.014469 +0.014458 +0.014525 +0.014669 +0.014649 +0.014716 +0.014654 +0.014639 +0.014712 +0.014849 +0.014826 +0.014884 +0.014825 +0.014808 +0.014895 +0.015037 +0.015012 +0.015078 +0.015022 +0.014998 +0.015079 +0.015221 +0.015202 +0.015263 +0.015208 +0.015192 +0.015268 +0.015411 +0.015403 +0.015456 +0.015406 +0.015378 +0.015473 +0.015603 +0.01559 +0.015648 +0.015593 +0.015572 +0.015668 +0.015807 +0.015796 +0.015856 +0.015804 +0.015776 +0.015869 +0.016019 +0.015991 +0.016052 +0.015999 +0.01598 +0.016075 +0.01622 +0.016209 +0.016275 +0.016214 +0.016187 +0.016292 +0.016447 +0.016423 +0.016479 +0.016428 +0.016408 +0.016511 +0.016653 +0.016646 +0.01672 +0.01666 +0.016629 +0.016727 +0.016886 +0.01687 +0.01692 +0.01687 +0.016847 +0.016958 +0.017105 +0.017103 +0.017168 +0.017108 +0.017086 +0.017185 +0.017345 +0.017327 +0.017391 +0.017341 +0.017326 +0.01743 +0.017586 +0.017576 +0.017643 +0.017586 +0.017566 +0.017677 +0.017834 +0.017824 +0.017895 +0.017841 +0.017816 +0.017921 +0.018097 +0.018079 +0.018157 +0.018099 +0.018073 +0.018182 +0.018356 +0.018329 +0.018401 +0.018356 +0.018332 +0.018447 +0.018619 +0.018607 +0.018686 +0.018629 +0.018604 +0.018718 +0.018882 +0.018889 +0.01897 +0.018905 +0.018883 +0.018992 +0.019169 +0.019154 +0.019234 +0.019183 +0.019169 +0.019291 +0.019471 +0.019463 +0.019534 +0.019478 +0.019461 +0.019583 +0.019767 +0.019769 +0.01985 +0.019792 +0.019764 +0.019887 +0.020072 +0.020062 +0.020156 +0.0201 +0.020073 +0.020198 +0.020393 +0.020398 +0.020486 +0.020425 +0.020397 +0.020523 +0.020714 +0.020704 +0.020801 +0.020746 +0.020729 +0.020866 +0.021056 +0.021069 +0.021159 +0.021094 +0.021075 +0.021201 +0.021408 +0.021408 +0.021502 +0.02145 +0.021427 +0.021556 +0.021773 +0.021783 +0.021883 +0.021818 +0.021792 +0.02193 +0.022147 +0.022158 +0.022259 +0.022201 +0.022172 +0.022312 +0.02253 +0.022527 +0.022639 +0.022586 +0.022563 +0.022713 +0.022939 +0.022951 +0.023046 +0.022985 +0.022972 +0.023124 +0.023355 +0.023376 +0.023461 +0.023414 +0.023394 +0.023556 +0.023794 +0.023809 +0.023915 +0.023863 +0.023836 +0.023996 +0.024249 +0.024266 +0.024365 +0.024311 +0.024294 +0.024472 +0.024716 +0.024735 +0.024855 +0.024794 +0.024774 +0.024945 +0.025198 +0.025226 +0.02535 +0.02529 +0.025266 +0.025449 +0.025691 +0.025732 +0.025859 +0.025807 +0.025783 +0.025952 +0.026219 +0.026262 +0.026399 +0.026339 +0.026317 +0.026496 +0.026767 +0.026805 +0.026959 +0.026895 +0.026876 +0.027058 +0.02734 +0.027374 +0.027538 +0.027486 +0.027463 +0.027653 +0.027948 +0.027997 +0.028155 +0.028096 +0.028081 +0.028276 +0.028576 +0.028639 +0.0288 +0.028753 +0.028726 +0.028934 +0.02924 +0.029308 +0.029485 +0.029426 +0.029413 +0.029614 +0.029947 +0.030013 +0.030174 +0.030129 +0.030138 +0.030378 +0.030723 +0.030787 +0.030938 +0.030899 +0.030955 +0.031189 +0.031551 +0.031614 +0.031775 +0.031741 +0.031791 +0.032041 +0.032405 +0.032479 +0.032658 +0.032642 +0.032682 +0.032944 +0.033337 +0.033408 +0.03361 +0.03358 +0.033635 +0.033897 +0.034322 +0.034398 +0.034602 +0.034576 +0.034656 +0.034929 +0.035386 +0.035482 +0.03569 +0.035658 +0.035734 +0.036045 +0.036509 +0.036614 +0.036831 +0.036812 +0.03692 +0.037247 +0.03774 +0.03787 +0.038092 +0.0381 +0.038236 +0.038568 +0.039092 +0.039227 +0.039457 +0.039508 +0.039642 +0.039998 +0.040554 +0.040705 +0.040987 +0.041059 +0.041215 +0.041611 +0.042202 +0.042379 +0.04266 +0.042757 +0.042929 +0.043347 +0.043992 +0.044185 +0.044518 +0.044636 +0.044827 +0.045295 +0.045989 +0.046211 +0.0466 +0.046746 +0.046989 +0.04749 +0.048267 +0.048536 +0.048942 +0.049141 +0.049445 +0.050016 +0.050862 +0.051177 +0.051675 +0.051932 +0.052281 +0.052928 +0.053874 +0.054243 +0.054845 +0.055184 +0.055597 +0.056356 +0.057439 +0.057908 +0.058616 +0.059065 +0.059607 +0.060498 +0.061763 +0.062358 +0.063234 +0.063815 +0.064526 +0.06562 +0.06713 +0.067922 +0.069023 +0.069869 +0.070838 +0.072227 +0.074102 +0.075203 +0.076652 +0.077852 +0.079234 +0.081124 +0.083649 +0.085397 +0.08747 +0.089412 +0.091618 +0.094426 +0.098137 +0.100951 +0.104411 +0.107983 +0.112114 +0.117192 +0.124141 +0.130526 +0.138189 +0.147585 +0.159273 +0.174402 +0.197461 +0.230842 +0.29654 +8.037043 +0.241062 +0.164417 +0.124864 +0.097241 +0.080031 +0.069098 +0.061992 +0.057199 +0.053521 +0.049732 +0.047062 +0.044826 +0.04295 +0.041798 +0.040907 +0.039486 +0.038448 +0.037353 +0.036381 +0.035873 +0.035521 +0.034772 +0.03418 +0.033664 +0.033126 +0.032899 +0.033107 +0.032871 +0.032569 +0.032375 +0.03223 +0.032341 +0.032721 +0.032716 +0.03297 +0.033069 +0.032963 +0.001287 +0.033192 +0.033712 +0.033862 +0.034079 +0.034056 +0.034033 +0.034256 +0.034608 +0.034699 +0.034854 +0.035166 +0.035179 +0.035513 +0.036002 +0.036087 +0.036272 +0.03605 +0.035585 +0.035202 +0.034863 +0.034102 +0.033521 +0.032779 +0.032143 +0.031751 +0.03148 +0.030893 +0.030456 +0.02993 +0.029509 +0.029285 +0.029202 +0.028855 +0.028596 +0.028213 +0.02793 +0.027828 +0.027833 +0.02756 +0.027376 +0.027059 +0.026832 +0.026767 +0.026851 +0.026684 +0.026602 +0.026393 +0.026254 +0.026302 +0.026471 +0.026389 +0.026371 +0.026193 +0.026071 +0.026129 +0.026335 +0.026319 +0.026425 +0.026357 +0.001288 +0.026394 +0.026604 +0.026873 +0.026899 +0.027056 +0.026991 +0.02701 +0.027201 +0.027524 +0.027542 +0.027672 +0.027592 +0.027641 +0.027883 +0.028201 +0.028258 +0.028455 +0.028427 +0.028127 +0.027404 +0.027211 +0.026726 +0.026108 +0.025587 +0.025067 +0.024708 +0.024696 +0.024317 +0.023815 +0.023513 +0.023074 +0.022826 +0.022867 +0.022534 +0.022185 +0.021915 +0.02157 +0.021421 +0.021469 +0.021231 +0.020992 +0.020728 +0.020507 +0.020295 +0.020413 +0.020218 +0.02016 +0.019956 +0.019625 +0.01959 +0.019671 +0.019506 +0.019492 +0.019232 +0.019094 +0.01907 +0.019191 +0.01911 +0.019168 +0.019125 +0.019093 +0.019138 +0.019309 +0.019284 +0.019371 +0.019338 +0.019352 +0.0195 +0.01969 +0.001289 +0.019649 +0.019699 +0.019618 +0.019578 +0.019661 +0.019824 +0.019822 +0.020072 +0.020022 +0.019983 +0.020084 +0.020253 +0.020334 +0.020367 +0.020297 +0.020223 +0.020218 +0.020317 +0.020146 +0.020069 +0.019884 +0.019697 +0.019663 +0.019726 +0.019592 +0.019539 +0.019407 +0.019272 +0.019285 +0.019418 +0.01935 +0.019355 +0.01929 +0.019223 +0.019281 +0.019475 +0.019449 +0.019501 +0.019465 +0.019426 +0.019545 +0.019735 +0.00129 +0.019719 +0.019823 +0.019743 +0.019754 +0.019848 +0.020078 +0.020097 +0.020136 +0.020091 +0.020115 +0.02023 +0.020388 +0.020415 +0.020534 +0.020441 +0.020394 +0.020558 +0.020755 +0.020774 +0.020855 +0.020796 +0.020783 +0.020777 +0.020834 +0.020651 +0.02056 +0.020397 +0.020335 +0.020425 +0.020632 +0.020631 +0.020704 +0.020651 +0.020645 +0.02077 +0.02099 +0.021007 +0.021087 +0.02103 +0.021022 +0.021181 +0.021448 +0.001291 +0.021441 +0.021561 +0.021553 +0.021491 +0.021196 +0.021236 +0.020965 +0.020775 +0.020225 +0.019889 +0.019613 +0.019553 +0.019323 +0.018951 +0.018668 +0.018462 +0.018231 +0.018192 +0.017978 +0.01783 +0.017465 +0.017301 +0.017113 +0.017115 +0.016982 +0.016873 +0.016592 +0.016421 +0.016345 +0.016358 +0.016251 +0.016193 +0.016099 +0.015853 +0.015773 +0.015876 +0.015759 +0.015769 +0.015673 +0.015597 +0.015616 +0.015617 +0.015542 +0.015592 +0.015531 +0.015482 +0.015595 +0.01575 +0.015698 +0.01573 +0.015674 +0.015644 +0.015741 +0.015882 +0.015872 +0.015949 +0.015894 +0.001292 +0.015881 +0.015986 +0.01614 +0.016094 +0.016133 +0.016076 +0.016034 +0.016115 +0.01624 +0.016205 +0.016278 +0.016322 +0.016335 +0.016416 +0.016558 +0.016535 +0.0166 +0.016565 +0.016545 +0.016646 +0.016794 +0.016791 +0.016823 +0.016706 +0.016616 +0.016616 +0.016681 +0.016567 +0.016517 +0.016367 +0.016243 +0.016241 +0.016304 +0.016219 +0.016179 +0.016044 +0.015943 +0.015954 +0.016025 +0.015944 +0.015915 +0.015776 +0.015682 +0.015691 +0.015764 +0.015689 +0.015672 +0.015544 +0.015468 +0.015491 +0.015581 +0.015526 +0.015522 +0.015409 +0.015348 +0.015389 +0.015498 +0.015472 +0.015503 +0.015428 +0.015404 +0.015482 +0.015619 +0.015625 +0.015679 +0.015619 +0.01561 +0.015689 +0.001293 +0.015844 +0.015839 +0.015885 +0.01584 +0.01583 +0.015911 +0.016062 +0.016065 +0.016118 +0.016057 +0.016039 +0.016136 +0.016283 +0.016272 +0.016336 +0.016282 +0.016259 +0.016378 +0.01654 +0.016538 +0.016594 +0.016564 +0.016565 +0.016681 +0.016852 +0.016721 +0.016748 +0.016656 +0.0165 +0.016442 +0.016505 +0.016379 +0.016361 +0.016202 +0.016005 +0.015962 +0.016026 +0.015917 +0.01591 +0.015747 +0.015532 +0.015593 +0.015653 +0.015552 +0.015544 +0.015329 +0.015279 +0.01523 +0.015335 +0.015233 +0.015266 +0.015167 +0.015099 +0.015025 +0.015078 +0.015042 +0.015035 +0.014971 +0.014929 +0.014986 +0.015105 +0.015008 +0.014978 +0.014936 +0.0149 +0.014949 +0.015096 +0.015074 +0.015128 +0.015085 +0.015079 +0.015187 +0.015335 +0.015301 +0.001294 +0.015358 +0.015336 +0.015306 +0.015361 +0.015468 +0.015426 +0.015501 +0.015449 +0.015431 +0.01552 +0.015662 +0.015634 +0.015682 +0.01566 +0.015689 +0.015767 +0.015901 +0.015897 +0.015962 +0.0159 +0.015876 +0.015987 +0.016121 +0.01612 +0.016182 +0.016108 +0.016065 +0.016103 +0.01615 +0.016084 +0.016029 +0.01586 +0.015759 +0.015717 +0.015773 +0.015679 +0.015616 +0.015473 +0.015384 +0.015377 +0.015449 +0.01537 +0.015336 +0.015201 +0.015128 +0.015123 +0.015199 +0.015141 +0.015109 +0.014984 +0.014923 +0.014928 +0.015017 +0.014971 +0.014954 +0.014845 +0.0148 +0.014823 +0.01492 +0.014902 +0.014914 +0.014834 +0.014821 +0.014883 +0.014999 +0.015013 +0.015051 +0.015001 +0.01498 +0.015069 +0.001295 +0.015214 +0.015202 +0.015262 +0.015209 +0.015175 +0.015275 +0.01542 +0.015414 +0.015472 +0.015415 +0.015388 +0.015495 +0.015642 +0.015625 +0.015679 +0.015624 +0.015624 +0.01572 +0.015882 +0.015868 +0.015948 +0.015901 +0.015883 +0.015972 +0.016 +0.015967 +0.015999 +0.015882 +0.015795 +0.015822 +0.015764 +0.01563 +0.015611 +0.015452 +0.015263 +0.015243 +0.015332 +0.015222 +0.0152 +0.015047 +0.014936 +0.014936 +0.015006 +0.014938 +0.014946 +0.014865 +0.014792 +0.014726 +0.01477 +0.014743 +0.01474 +0.014673 +0.014614 +0.014673 +0.01478 +0.014633 +0.014672 +0.014614 +0.014528 +0.014544 +0.014649 +0.014621 +0.014685 +0.01463 +0.014613 +0.014714 +0.014845 +0.014838 +0.014895 +0.014855 +0.014836 +0.001296 +0.014966 +0.015043 +0.014999 +0.015073 +0.015028 +0.014988 +0.015015 +0.015155 +0.015133 +0.015184 +0.015147 +0.015116 +0.015212 +0.015409 +0.015423 +0.01545 +0.0154 +0.015384 +0.015475 +0.015615 +0.015607 +0.015681 +0.015614 +0.015591 +0.015699 +0.015835 +0.015808 +0.015844 +0.015707 +0.0156 +0.015616 +0.015653 +0.01555 +0.01551 +0.015367 +0.015262 +0.015262 +0.015314 +0.015218 +0.015201 +0.015079 +0.015 +0.015021 +0.015096 +0.01502 +0.015005 +0.014895 +0.014815 +0.014841 +0.014923 +0.014849 +0.014846 +0.014735 +0.014669 +0.014695 +0.014774 +0.014717 +0.014722 +0.014623 +0.014576 +0.014622 +0.01473 +0.014698 +0.014731 +0.014661 +0.014643 +0.014729 +0.014853 +0.014847 +0.014912 +0.014847 +0.014827 +0.001297 +0.014909 +0.015054 +0.015057 +0.015105 +0.015049 +0.015025 +0.015127 +0.01527 +0.015253 +0.015323 +0.015265 +0.015235 +0.015313 +0.015457 +0.015473 +0.015528 +0.015489 +0.015477 +0.015578 +0.015744 +0.01574 +0.015807 +0.015767 +0.015609 +0.015655 +0.015797 +0.015732 +0.015725 +0.015614 +0.015517 +0.015529 +0.01546 +0.015342 +0.015347 +0.015223 +0.015055 +0.015023 +0.015108 +0.01502 +0.015037 +0.014926 +0.014837 +0.014743 +0.01481 +0.014762 +0.014753 +0.01469 +0.014613 +0.014687 +0.014767 +0.01467 +0.014564 +0.014513 +0.014445 +0.014496 +0.014608 +0.014535 +0.014573 +0.014487 +0.014423 +0.014445 +0.014578 +0.014538 +0.014598 +0.014574 +0.014551 +0.014656 +0.014791 +0.014774 +0.014839 +0.001298 +0.014799 +0.014788 +0.014887 +0.015027 +0.014991 +0.014982 +0.01492 +0.014907 +0.014994 +0.015123 +0.015078 +0.015131 +0.015089 +0.015063 +0.015228 +0.015406 +0.015371 +0.015413 +0.015349 +0.015314 +0.015433 +0.015597 +0.015572 +0.015631 +0.015575 +0.015567 +0.015631 +0.015737 +0.015665 +0.015621 +0.015487 +0.015386 +0.015352 +0.015416 +0.015311 +0.015257 +0.015123 +0.015021 +0.015005 +0.015084 +0.014997 +0.014963 +0.014853 +0.014778 +0.014777 +0.014876 +0.014805 +0.014783 +0.014683 +0.014615 +0.014632 +0.014728 +0.014679 +0.014657 +0.014572 +0.014512 +0.014534 +0.014649 +0.014609 +0.014606 +0.014535 +0.014492 +0.014539 +0.014666 +0.014656 +0.014682 +0.014633 +0.014624 +0.014695 +0.014837 +0.014826 +0.001299 +0.014886 +0.014827 +0.014809 +0.014901 +0.015032 +0.015029 +0.015079 +0.01503 +0.015016 +0.015101 +0.015248 +0.015225 +0.015276 +0.015222 +0.01522 +0.015304 +0.015464 +0.015446 +0.015533 +0.015477 +0.015462 +0.015571 +0.015753 +0.015728 +0.015586 +0.015513 +0.015435 +0.015461 +0.015525 +0.015419 +0.015257 +0.015102 +0.015022 +0.015016 +0.015033 +0.014922 +0.014817 +0.0147 +0.01462 +0.01459 +0.014664 +0.014571 +0.014572 +0.014441 +0.014316 +0.014308 +0.014396 +0.014323 +0.014331 +0.014248 +0.014199 +0.01414 +0.0142 +0.014169 +0.014183 +0.014138 +0.014084 +0.014168 +0.014301 +0.014248 +0.014311 +0.014258 +0.014146 +0.014198 +0.014351 +0.014325 +0.01438 +0.014347 +0.01434 +0.0013 +0.01444 +0.014573 +0.014559 +0.014621 +0.014586 +0.014563 +0.01466 +0.014793 +0.014757 +0.014776 +0.014718 +0.014674 +0.014756 +0.014876 +0.014858 +0.014986 +0.014961 +0.014923 +0.014993 +0.015126 +0.015132 +0.015211 +0.015145 +0.015121 +0.01519 +0.015353 +0.015343 +0.015371 +0.015265 +0.015169 +0.015165 +0.015226 +0.015121 +0.015076 +0.014936 +0.014823 +0.014808 +0.014862 +0.014763 +0.014725 +0.014595 +0.014493 +0.014497 +0.014562 +0.014492 +0.014474 +0.014366 +0.014284 +0.014297 +0.014378 +0.014315 +0.014315 +0.014212 +0.014145 +0.014168 +0.014255 +0.014211 +0.01423 +0.014142 +0.014095 +0.014145 +0.014249 +0.014228 +0.014261 +0.014205 +0.014178 +0.014255 +0.014384 +0.014377 +0.014435 +0.014376 +0.001301 +0.014356 +0.014442 +0.014578 +0.014561 +0.01462 +0.01457 +0.014541 +0.014635 +0.014769 +0.014756 +0.01482 +0.014774 +0.014735 +0.014812 +0.014945 +0.014955 +0.015009 +0.01498 +0.014964 +0.015065 +0.015224 +0.015217 +0.015275 +0.01522 +0.01498 +0.014967 +0.015053 +0.014956 +0.014937 +0.014839 +0.014737 +0.014618 +0.014668 +0.014585 +0.014571 +0.014487 +0.014427 +0.014449 +0.014464 +0.014346 +0.014364 +0.014294 +0.014129 +0.014151 +0.014235 +0.0142 +0.014191 +0.014142 +0.014073 +0.014159 +0.014186 +0.014121 +0.014136 +0.014035 +0.013986 +0.013996 +0.014128 +0.014066 +0.014111 +0.014079 +0.014051 +0.014133 +0.014277 +0.014233 +0.014307 +0.014242 +0.014177 +0.014226 +0.001302 +0.014383 +0.014348 +0.014403 +0.014377 +0.014365 +0.014458 +0.01459 +0.014583 +0.014637 +0.014582 +0.014548 +0.014625 +0.01474 +0.014705 +0.014744 +0.014704 +0.014734 +0.014857 +0.014981 +0.014957 +0.014984 +0.014948 +0.014947 +0.01503 +0.015161 +0.015143 +0.015169 +0.015051 +0.014951 +0.014948 +0.014994 +0.014907 +0.014839 +0.014695 +0.014606 +0.014579 +0.014641 +0.014561 +0.014524 +0.014402 +0.014329 +0.014331 +0.014411 +0.014354 +0.014329 +0.014227 +0.01417 +0.014178 +0.014264 +0.014222 +0.01421 +0.014112 +0.014051 +0.014073 +0.014162 +0.014127 +0.014136 +0.014051 +0.013995 +0.014053 +0.014164 +0.014126 +0.01418 +0.014125 +0.014085 +0.014166 +0.014312 +0.014289 +0.014347 +0.001303 +0.014297 +0.014275 +0.014361 +0.014496 +0.01448 +0.014534 +0.014497 +0.014458 +0.014551 +0.014683 +0.01468 +0.014736 +0.014694 +0.014657 +0.014728 +0.014862 +0.014861 +0.014914 +0.014889 +0.014858 +0.014966 +0.015132 +0.015116 +0.015172 +0.015102 +0.014924 +0.014785 +0.014834 +0.014724 +0.014687 +0.014552 +0.014461 +0.014339 +0.014318 +0.014232 +0.01422 +0.014106 +0.014042 +0.013961 +0.013978 +0.013916 +0.013921 +0.013824 +0.013776 +0.013727 +0.013777 +0.013695 +0.013726 +0.013626 +0.013561 +0.013514 +0.01358 +0.013536 +0.013541 +0.013495 +0.013446 +0.0135 +0.013623 +0.013553 +0.013579 +0.013449 +0.013408 +0.013508 +0.013627 +0.013591 +0.013638 +0.013625 +0.013602 +0.01368 +0.013809 +0.001304 +0.013788 +0.013852 +0.01381 +0.013771 +0.013775 +0.013899 +0.013891 +0.013957 +0.013906 +0.013888 +0.01396 +0.014087 +0.014071 +0.014177 +0.014142 +0.014104 +0.014173 +0.014304 +0.014316 +0.014364 +0.014292 +0.01431 +0.014352 +0.014493 +0.014468 +0.014452 +0.014334 +0.014245 +0.014221 +0.014278 +0.014182 +0.014122 +0.014004 +0.013899 +0.013876 +0.01394 +0.013854 +0.013806 +0.013703 +0.013619 +0.013612 +0.013699 +0.013631 +0.013601 +0.013503 +0.013437 +0.013442 +0.013534 +0.013466 +0.013453 +0.013364 +0.013303 +0.013318 +0.01342 +0.013376 +0.013376 +0.013298 +0.013258 +0.013299 +0.013414 +0.013394 +0.013432 +0.013383 +0.013362 +0.013438 +0.013565 +0.013535 +0.013591 +0.013546 +0.001305 +0.013533 +0.013602 +0.013723 +0.01372 +0.013771 +0.01372 +0.013701 +0.013783 +0.0139 +0.013887 +0.013946 +0.013908 +0.013873 +0.013949 +0.014071 +0.014065 +0.01412 +0.014091 +0.014071 +0.014163 +0.014304 +0.014304 +0.014366 +0.014305 +0.014059 +0.014026 +0.014105 +0.013983 +0.013954 +0.013817 +0.013608 +0.013617 +0.013673 +0.013584 +0.013563 +0.013441 +0.013307 +0.013299 +0.013365 +0.013309 +0.013314 +0.013231 +0.013193 +0.013147 +0.0132 +0.013131 +0.013173 +0.013075 +0.013028 +0.013096 +0.013134 +0.013071 +0.01308 +0.013012 +0.012959 +0.012946 +0.013048 +0.013028 +0.013064 +0.013017 +0.012995 +0.013082 +0.013202 +0.013176 +0.013224 +0.013197 +0.013179 +0.013267 +0.013389 +0.001306 +0.013337 +0.013335 +0.0133 +0.013284 +0.01337 +0.013483 +0.013464 +0.013517 +0.01349 +0.013467 +0.01355 +0.013652 +0.013603 +0.013644 +0.013595 +0.013561 +0.013629 +0.013749 +0.013754 +0.013879 +0.01384 +0.013795 +0.013854 +0.013987 +0.013945 +0.014024 +0.013986 +0.013947 +0.013992 +0.014063 +0.013983 +0.01394 +0.013808 +0.013708 +0.013671 +0.013711 +0.013632 +0.013591 +0.013474 +0.013385 +0.01337 +0.013428 +0.013366 +0.013341 +0.013245 +0.013187 +0.013177 +0.013246 +0.013197 +0.013178 +0.013087 +0.013036 +0.013048 +0.013122 +0.013081 +0.013078 +0.012999 +0.012959 +0.01298 +0.013067 +0.013048 +0.013056 +0.013002 +0.012976 +0.01303 +0.013146 +0.013144 +0.013175 +0.013141 +0.013116 +0.013164 +0.013307 +0.001307 +0.013297 +0.013347 +0.0133 +0.013266 +0.013341 +0.013474 +0.013466 +0.013515 +0.013465 +0.013435 +0.013517 +0.013639 +0.01363 +0.013679 +0.01364 +0.013607 +0.013671 +0.013805 +0.013795 +0.013851 +0.013806 +0.0138 +0.013881 +0.014034 +0.01402 +0.01408 +0.014037 +0.013876 +0.013784 +0.013864 +0.013787 +0.013766 +0.013659 +0.013584 +0.01355 +0.013543 +0.013478 +0.013473 +0.013376 +0.01331 +0.013361 +0.013352 +0.013298 +0.013287 +0.013213 +0.013175 +0.01313 +0.013203 +0.01313 +0.013176 +0.013085 +0.013049 +0.013099 +0.01322 +0.013116 +0.01307 +0.013018 +0.012979 +0.013071 +0.013159 +0.013119 +0.013162 +0.013073 +0.013062 +0.013132 +0.013229 +0.01322 +0.013275 +0.013219 +0.0132 +0.001308 +0.013309 +0.01343 +0.0134 +0.013435 +0.013423 +0.0134 +0.013471 +0.01355 +0.013528 +0.013575 +0.013545 +0.013502 +0.013581 +0.013689 +0.013669 +0.013702 +0.013662 +0.01365 +0.013797 +0.013926 +0.013897 +0.013934 +0.013878 +0.013827 +0.013923 +0.014073 +0.01407 +0.014079 +0.013989 +0.013922 +0.01392 +0.013971 +0.0139 +0.013847 +0.013717 +0.013631 +0.013635 +0.01368 +0.013616 +0.013578 +0.013467 +0.0134 +0.01342 +0.013481 +0.013445 +0.013411 +0.013322 +0.013264 +0.013293 +0.013361 +0.013326 +0.01331 +0.013218 +0.013171 +0.013207 +0.013282 +0.01326 +0.013257 +0.013174 +0.013137 +0.013189 +0.013282 +0.01327 +0.013297 +0.013232 +0.013211 +0.013288 +0.013394 +0.013395 +0.013431 +0.013386 +0.001309 +0.013377 +0.013449 +0.013563 +0.013561 +0.013605 +0.013553 +0.013538 +0.01362 +0.013746 +0.013727 +0.013784 +0.013744 +0.013713 +0.013789 +0.013906 +0.013892 +0.013952 +0.013903 +0.013899 +0.013984 +0.01412 +0.014115 +0.01417 +0.014143 +0.014123 +0.014223 +0.014223 +0.014112 +0.014121 +0.014026 +0.013896 +0.013807 +0.013865 +0.013794 +0.013781 +0.013677 +0.013598 +0.013538 +0.013542 +0.013446 +0.013456 +0.01337 +0.013277 +0.013226 +0.013272 +0.01322 +0.013214 +0.013136 +0.013082 +0.0131 +0.013103 +0.013052 +0.013054 +0.01301 +0.012929 +0.012904 +0.012994 +0.012943 +0.012992 +0.012936 +0.012899 +0.012992 +0.013102 +0.013065 +0.013131 +0.013087 +0.013038 +0.013032 +0.013161 +0.013138 +0.01319 +0.00131 +0.013168 +0.013159 +0.013237 +0.013366 +0.013344 +0.013407 +0.01337 +0.013348 +0.013435 +0.013561 +0.013541 +0.013579 +0.01353 +0.013501 +0.013559 +0.013663 +0.013617 +0.013653 +0.013601 +0.013583 +0.013733 +0.013886 +0.01384 +0.013888 +0.013826 +0.013782 +0.013861 +0.013939 +0.013842 +0.013832 +0.013694 +0.013597 +0.013612 +0.013653 +0.013561 +0.013523 +0.013381 +0.013286 +0.01328 +0.013323 +0.013243 +0.013216 +0.013101 +0.013016 +0.013027 +0.013082 +0.013015 +0.013013 +0.012905 +0.012837 +0.01287 +0.012936 +0.012884 +0.012898 +0.012816 +0.012746 +0.012802 +0.012883 +0.012846 +0.012883 +0.012815 +0.012777 +0.012843 +0.012962 +0.012945 +0.012993 +0.012943 +0.01292 +0.012983 +0.013114 +0.001311 +0.01311 +0.013153 +0.013099 +0.013071 +0.013153 +0.013273 +0.013271 +0.013303 +0.01327 +0.013239 +0.013329 +0.013444 +0.013436 +0.013472 +0.013444 +0.013402 +0.013489 +0.013602 +0.013601 +0.013652 +0.013599 +0.013575 +0.013669 +0.013799 +0.013787 +0.013846 +0.013812 +0.013789 +0.013903 +0.014035 +0.013919 +0.013924 +0.013845 +0.01374 +0.013726 +0.01379 +0.01373 +0.013712 +0.013631 +0.013538 +0.013459 +0.013525 +0.013458 +0.013447 +0.013393 +0.013326 +0.013393 +0.013483 +0.013366 +0.013329 +0.013255 +0.013215 +0.013206 +0.013293 +0.013248 +0.013276 +0.013208 +0.013172 +0.013234 +0.013354 +0.013258 +0.013248 +0.013195 +0.013143 +0.013192 +0.013276 +0.013251 +0.013323 +0.013278 +0.013251 +0.013358 +0.013467 +0.013451 +0.013522 +0.001312 +0.013454 +0.013438 +0.013552 +0.013667 +0.01364 +0.013672 +0.013614 +0.013569 +0.013642 +0.01375 +0.013738 +0.013757 +0.013725 +0.013689 +0.013771 +0.013886 +0.013908 +0.01401 +0.013969 +0.013926 +0.013998 +0.01411 +0.014082 +0.014151 +0.014127 +0.014075 +0.014125 +0.014176 +0.014091 +0.014033 +0.013903 +0.013771 +0.013749 +0.013765 +0.013674 +0.013617 +0.013483 +0.013377 +0.013369 +0.01342 +0.013351 +0.013322 +0.013222 +0.013135 +0.013152 +0.013203 +0.013147 +0.013132 +0.013029 +0.012954 +0.012975 +0.013038 +0.012992 +0.012991 +0.01291 +0.012839 +0.012888 +0.012952 +0.012929 +0.012947 +0.012894 +0.012836 +0.012907 +0.013014 +0.013001 +0.013046 +0.013011 +0.012968 +0.013046 +0.013156 +0.01318 +0.001313 +0.013208 +0.013151 +0.01313 +0.013198 +0.013331 +0.013328 +0.013369 +0.013321 +0.013289 +0.01337 +0.013498 +0.013481 +0.013513 +0.013483 +0.013447 +0.013546 +0.013662 +0.013666 +0.013724 +0.013683 +0.013667 +0.013719 +0.013796 +0.013562 +0.013463 +0.013345 +0.013185 +0.013133 +0.013182 +0.013101 +0.013069 +0.012988 +0.012804 +0.012763 +0.012828 +0.012772 +0.012755 +0.012694 +0.012633 +0.012637 +0.012665 +0.012576 +0.012619 +0.012531 +0.012498 +0.012458 +0.012529 +0.012476 +0.012499 +0.012453 +0.012406 +0.01246 +0.012574 +0.012519 +0.012477 +0.012429 +0.012393 +0.012454 +0.012575 +0.01255 +0.012589 +0.012563 +0.01255 +0.012618 +0.012737 +0.01272 +0.001314 +0.012769 +0.012717 +0.012646 +0.012701 +0.012829 +0.012794 +0.012852 +0.012809 +0.012796 +0.012894 +0.012998 +0.012988 +0.013025 +0.01298 +0.012952 +0.013018 +0.013133 +0.01315 +0.013207 +0.013164 +0.013132 +0.013193 +0.013308 +0.013322 +0.01337 +0.013314 +0.013286 +0.01337 +0.013472 +0.013435 +0.013428 +0.01331 +0.013229 +0.013224 +0.013253 +0.013182 +0.013139 +0.013005 +0.012929 +0.012919 +0.012957 +0.012898 +0.012869 +0.01276 +0.012701 +0.012716 +0.012775 +0.012736 +0.012729 +0.012639 +0.012591 +0.012623 +0.012685 +0.012653 +0.012665 +0.012584 +0.012547 +0.012591 +0.012664 +0.012646 +0.012671 +0.012607 +0.012575 +0.012635 +0.012741 +0.012738 +0.012773 +0.012722 +0.012708 +0.012765 +0.012897 +0.001315 +0.012882 +0.012936 +0.012877 +0.012865 +0.012915 +0.013049 +0.01304 +0.013093 +0.013041 +0.01302 +0.013083 +0.013218 +0.013201 +0.013259 +0.013205 +0.013188 +0.013246 +0.013392 +0.013368 +0.013432 +0.013388 +0.013379 +0.013454 +0.013596 +0.013583 +0.013636 +0.013468 +0.013422 +0.013475 +0.013551 +0.013466 +0.013448 +0.013266 +0.013197 +0.013175 +0.013226 +0.013129 +0.013124 +0.013043 +0.012914 +0.012839 +0.012938 +0.012865 +0.012868 +0.012796 +0.012733 +0.012796 +0.012877 +0.012775 +0.012701 +0.012649 +0.01259 +0.012603 +0.012668 +0.012598 +0.012647 +0.012563 +0.012555 +0.012597 +0.012711 +0.012662 +0.012614 +0.012555 +0.012577 +0.012629 +0.012753 +0.012725 +0.012775 +0.012731 +0.012745 +0.012817 +0.001316 +0.012922 +0.012894 +0.012955 +0.012913 +0.012839 +0.012865 +0.012992 +0.012976 +0.013031 +0.012991 +0.012968 +0.013038 +0.013183 +0.013211 +0.013254 +0.013191 +0.013161 +0.013224 +0.013363 +0.013365 +0.013397 +0.013358 +0.01334 +0.013414 +0.013519 +0.013514 +0.013496 +0.013387 +0.013322 +0.013318 +0.013348 +0.013284 +0.013241 +0.01312 +0.013021 +0.01301 +0.013051 +0.01299 +0.012955 +0.012837 +0.012771 +0.012775 +0.012824 +0.01279 +0.01278 +0.012682 +0.012635 +0.012653 +0.01272 +0.012686 +0.012687 +0.012599 +0.012566 +0.012598 +0.012671 +0.01264 +0.012664 +0.012589 +0.012563 +0.012617 +0.012715 +0.012707 +0.012747 +0.012691 +0.012677 +0.012732 +0.012859 +0.012855 +0.001317 +0.0129 +0.012846 +0.012827 +0.012891 +0.013017 +0.013018 +0.013062 +0.013015 +0.012986 +0.013046 +0.013182 +0.013178 +0.013225 +0.013176 +0.013147 +0.013224 +0.013331 +0.013318 +0.013385 +0.013329 +0.013318 +0.013404 +0.013532 +0.013521 +0.013582 +0.013544 +0.013533 +0.01352 +0.013528 +0.013452 +0.013452 +0.013358 +0.013263 +0.013261 +0.013225 +0.013132 +0.013116 +0.012987 +0.012865 +0.012835 +0.012892 +0.012837 +0.012814 +0.01272 +0.012576 +0.012568 +0.01266 +0.012577 +0.012603 +0.012499 +0.012451 +0.012387 +0.012457 +0.012398 +0.012408 +0.012342 +0.012275 +0.012353 +0.012404 +0.012316 +0.012353 +0.01227 +0.012218 +0.012257 +0.012344 +0.012315 +0.012377 +0.012331 +0.012305 +0.01239 +0.012525 +0.012501 +0.012536 +0.012492 +0.012485 +0.001318 +0.012574 +0.012698 +0.012648 +0.012694 +0.012635 +0.012591 +0.012636 +0.01274 +0.012707 +0.012749 +0.012713 +0.012698 +0.012786 +0.012956 +0.012944 +0.012978 +0.012935 +0.012908 +0.012966 +0.013104 +0.013098 +0.013148 +0.013077 +0.01308 +0.013143 +0.013244 +0.013209 +0.013184 +0.01306 +0.012976 +0.012952 +0.012984 +0.012911 +0.012839 +0.012716 +0.012634 +0.012615 +0.012655 +0.012588 +0.01255 +0.012432 +0.012368 +0.012366 +0.012421 +0.012377 +0.012376 +0.012261 +0.012205 +0.012223 +0.012291 +0.012251 +0.012262 +0.012174 +0.012121 +0.012135 +0.012229 +0.012199 +0.012215 +0.012164 +0.012116 +0.012165 +0.01228 +0.012274 +0.012308 +0.012269 +0.012241 +0.012294 +0.012412 +0.012418 +0.012459 +0.001319 +0.012408 +0.01238 +0.012445 +0.012561 +0.012556 +0.012607 +0.012555 +0.012528 +0.012588 +0.012723 +0.012707 +0.012757 +0.012708 +0.01268 +0.012741 +0.012858 +0.012847 +0.0129 +0.01285 +0.012846 +0.01291 +0.013042 +0.013037 +0.013094 +0.013047 +0.01305 +0.013128 +0.013132 +0.013021 +0.01303 +0.012918 +0.012797 +0.012698 +0.012773 +0.012691 +0.012702 +0.012592 +0.012556 +0.01253 +0.012544 +0.012464 +0.012471 +0.012393 +0.012275 +0.012279 +0.01235 +0.012308 +0.012313 +0.012256 +0.012189 +0.012239 +0.01226 +0.012215 +0.012223 +0.012098 +0.012075 +0.012115 +0.01223 +0.012171 +0.0122 +0.012116 +0.012071 +0.012091 +0.012222 +0.012182 +0.012224 +0.012198 +0.012175 +0.012241 +0.012378 +0.012348 +0.012388 +0.012363 +0.00132 +0.01234 +0.012406 +0.012531 +0.012515 +0.012525 +0.012454 +0.012432 +0.012517 +0.012635 +0.012603 +0.012631 +0.012589 +0.012563 +0.012626 +0.012738 +0.012714 +0.012754 +0.012769 +0.012762 +0.01282 +0.012942 +0.012918 +0.012962 +0.012931 +0.012902 +0.012981 +0.013078 +0.013018 +0.01301 +0.012875 +0.012786 +0.01278 +0.012805 +0.012724 +0.012683 +0.012547 +0.012466 +0.012467 +0.012511 +0.012441 +0.012427 +0.012307 +0.01224 +0.01227 +0.012319 +0.012273 +0.012284 +0.012187 +0.01211 +0.012163 +0.01223 +0.012175 +0.01221 +0.012125 +0.012058 +0.012111 +0.012194 +0.012164 +0.012204 +0.01214 +0.012088 +0.012148 +0.012264 +0.012246 +0.012294 +0.01224 +0.012208 +0.012286 +0.0124 +0.01239 +0.001321 +0.012435 +0.012383 +0.012363 +0.012428 +0.012552 +0.01254 +0.012582 +0.012534 +0.012511 +0.012594 +0.012696 +0.012686 +0.012736 +0.012686 +0.012657 +0.012719 +0.012845 +0.012851 +0.012882 +0.012868 +0.01283 +0.012925 +0.013052 +0.013034 +0.013104 +0.013063 +0.012921 +0.012943 +0.013046 +0.012975 +0.012969 +0.012869 +0.012789 +0.012808 +0.012772 +0.012661 +0.012672 +0.012567 +0.012506 +0.01244 +0.012485 +0.012435 +0.01244 +0.012349 +0.012312 +0.012336 +0.012399 +0.012292 +0.012321 +0.012223 +0.012161 +0.012151 +0.012248 +0.012194 +0.012233 +0.012149 +0.012117 +0.012191 +0.012279 +0.012245 +0.01218 +0.012142 +0.012125 +0.012192 +0.012312 +0.012283 +0.012326 +0.012284 +0.012275 +0.012344 +0.012462 +0.001322 +0.012445 +0.012489 +0.012438 +0.012423 +0.012461 +0.012551 +0.012519 +0.012571 +0.012535 +0.012526 +0.012606 +0.012719 +0.01268 +0.012725 +0.012682 +0.012662 +0.012718 +0.012879 +0.012877 +0.012912 +0.012855 +0.012848 +0.012918 +0.013038 +0.013033 +0.013071 +0.013025 +0.012996 +0.013013 +0.013065 +0.012977 +0.012925 +0.012799 +0.012707 +0.012684 +0.012725 +0.012658 +0.01262 +0.012513 +0.012449 +0.012443 +0.0125 +0.012444 +0.012428 +0.012329 +0.012279 +0.012307 +0.012378 +0.01232 +0.012324 +0.012243 +0.012194 +0.012226 +0.012311 +0.012259 +0.012266 +0.012206 +0.012165 +0.012208 +0.012314 +0.012276 +0.012301 +0.012257 +0.012236 +0.012297 +0.012412 +0.012391 +0.01242 +0.0124 +0.012368 +0.001323 +0.01245 +0.012551 +0.012536 +0.012583 +0.012542 +0.012523 +0.012593 +0.012707 +0.012694 +0.012744 +0.012701 +0.012664 +0.012735 +0.012856 +0.012854 +0.012896 +0.012837 +0.012826 +0.012908 +0.013022 +0.013023 +0.013058 +0.01303 +0.013022 +0.013107 +0.013233 +0.013204 +0.01312 +0.013065 +0.013031 +0.013067 +0.013123 +0.013035 +0.013019 +0.01281 +0.012731 +0.012731 +0.012758 +0.01269 +0.012696 +0.012602 +0.012473 +0.012448 +0.012501 +0.012465 +0.01245 +0.012409 +0.012339 +0.012409 +0.01248 +0.012391 +0.01234 +0.012274 +0.012235 +0.012215 +0.012304 +0.012251 +0.012272 +0.012241 +0.0122 +0.012258 +0.01237 +0.012322 +0.012367 +0.012326 +0.012228 +0.012282 +0.012414 +0.012364 +0.012424 +0.012401 +0.012385 +0.001324 +0.012452 +0.012577 +0.01256 +0.012602 +0.012568 +0.012552 +0.012634 +0.012752 +0.012726 +0.012767 +0.012732 +0.012691 +0.01275 +0.012844 +0.012802 +0.012837 +0.012797 +0.012767 +0.012837 +0.01302 +0.013038 +0.013072 +0.013006 +0.012983 +0.013029 +0.013169 +0.013159 +0.013135 +0.013014 +0.012896 +0.012895 +0.012957 +0.012856 +0.012822 +0.01271 +0.012625 +0.012608 +0.012672 +0.012601 +0.012569 +0.012464 +0.012395 +0.012403 +0.012472 +0.012418 +0.012404 +0.012311 +0.012244 +0.012262 +0.012333 +0.012285 +0.012282 +0.012197 +0.012135 +0.01217 +0.012262 +0.012225 +0.012242 +0.012184 +0.012135 +0.012192 +0.012309 +0.012286 +0.012328 +0.012293 +0.012246 +0.012328 +0.012447 +0.012434 +0.012474 +0.001325 +0.012428 +0.012393 +0.012484 +0.012595 +0.012583 +0.012624 +0.012584 +0.012547 +0.012625 +0.012749 +0.012738 +0.012785 +0.012732 +0.012703 +0.012766 +0.012892 +0.012894 +0.012933 +0.012893 +0.012882 +0.012961 +0.013089 +0.013083 +0.013123 +0.01309 +0.013092 +0.013036 +0.013092 +0.013033 +0.01305 +0.01295 +0.012868 +0.012895 +0.012966 +0.012796 +0.012717 +0.012637 +0.012572 +0.012525 +0.012581 +0.012517 +0.012522 +0.012453 +0.012336 +0.012286 +0.01238 +0.012324 +0.012348 +0.012264 +0.012223 +0.012268 +0.012339 +0.012235 +0.012217 +0.012151 +0.012088 +0.01216 +0.012224 +0.012182 +0.012223 +0.01211 +0.012073 +0.012127 +0.012223 +0.012195 +0.012248 +0.012191 +0.012178 +0.012263 +0.012377 +0.012331 +0.012383 +0.012345 +0.001326 +0.012302 +0.012325 +0.012449 +0.012426 +0.012489 +0.012443 +0.012433 +0.012507 +0.012637 +0.012606 +0.012659 +0.012599 +0.012579 +0.012631 +0.012758 +0.012723 +0.01277 +0.012761 +0.012761 +0.012816 +0.012934 +0.012917 +0.012975 +0.01292 +0.012897 +0.012963 +0.013089 +0.013021 +0.013016 +0.012907 +0.01283 +0.012819 +0.012877 +0.012776 +0.012745 +0.012632 +0.012555 +0.012554 +0.012616 +0.012528 +0.012513 +0.012411 +0.012349 +0.01236 +0.012437 +0.012364 +0.01237 +0.012278 +0.012219 +0.012251 +0.012345 +0.012273 +0.012282 +0.012215 +0.012169 +0.012201 +0.012315 +0.012259 +0.012289 +0.012223 +0.012201 +0.012256 +0.012386 +0.012353 +0.012398 +0.012343 +0.012335 +0.012413 +0.012521 +0.001327 +0.012506 +0.012533 +0.012494 +0.012489 +0.01256 +0.012669 +0.012648 +0.012691 +0.012652 +0.012638 +0.01271 +0.012824 +0.012812 +0.012859 +0.012809 +0.012776 +0.012854 +0.012965 +0.012958 +0.013009 +0.012965 +0.012956 +0.013029 +0.013163 +0.013154 +0.013201 +0.013161 +0.013158 +0.013174 +0.01317 +0.01311 +0.013124 +0.01303 +0.012956 +0.012995 +0.013059 +0.012887 +0.012857 +0.012776 +0.012667 +0.012623 +0.012712 +0.012635 +0.012625 +0.012569 +0.012486 +0.012504 +0.012511 +0.012455 +0.012459 +0.012392 +0.012344 +0.012403 +0.012447 +0.012375 +0.01237 +0.012313 +0.012235 +0.012237 +0.012349 +0.012307 +0.01233 +0.012293 +0.012271 +0.012343 +0.012453 +0.012434 +0.012466 +0.012426 +0.012414 +0.012435 +0.012514 +0.012488 +0.001328 +0.012541 +0.012516 +0.012502 +0.012575 +0.012697 +0.012677 +0.012734 +0.012697 +0.012681 +0.012762 +0.012867 +0.012847 +0.012873 +0.012829 +0.012795 +0.012859 +0.012959 +0.01293 +0.012981 +0.012995 +0.012979 +0.013034 +0.013156 +0.013152 +0.013181 +0.013108 +0.013024 +0.01302 +0.013069 +0.012965 +0.01293 +0.012796 +0.012677 +0.012678 +0.012729 +0.012651 +0.012624 +0.012519 +0.012416 +0.012436 +0.012503 +0.012434 +0.012433 +0.012342 +0.012264 +0.012288 +0.012373 +0.012315 +0.012314 +0.012242 +0.012173 +0.012203 +0.012296 +0.012245 +0.012265 +0.012203 +0.012151 +0.012191 +0.012306 +0.012274 +0.012304 +0.012265 +0.012233 +0.012293 +0.012427 +0.012397 +0.01245 +0.012397 +0.012378 +0.001329 +0.012439 +0.012564 +0.012563 +0.01259 +0.012555 +0.012521 +0.012597 +0.01271 +0.012724 +0.012736 +0.012708 +0.01267 +0.012738 +0.012859 +0.012861 +0.012897 +0.012867 +0.012839 +0.012937 +0.013045 +0.013051 +0.01309 +0.013065 +0.013044 +0.013047 +0.013071 +0.013021 +0.013022 +0.012936 +0.012848 +0.012883 +0.012915 +0.012753 +0.012725 +0.012616 +0.0125 +0.012494 +0.012544 +0.012485 +0.012486 +0.012404 +0.012328 +0.012268 +0.012343 +0.012293 +0.012315 +0.012239 +0.012197 +0.012237 +0.012351 +0.0123 +0.012255 +0.01214 +0.012084 +0.012181 +0.012259 +0.012207 +0.012244 +0.01219 +0.012116 +0.012147 +0.012235 +0.012213 +0.012267 +0.012233 +0.012192 +0.012306 +0.012412 +0.012401 +0.012423 +0.0124 +0.00133 +0.012386 +0.012464 +0.012576 +0.01255 +0.012607 +0.012569 +0.012556 +0.012629 +0.012726 +0.012679 +0.012714 +0.012665 +0.012636 +0.012697 +0.012799 +0.01276 +0.012797 +0.012762 +0.012734 +0.012881 +0.013034 +0.012999 +0.013031 +0.012982 +0.012948 +0.012997 +0.013121 +0.013092 +0.013061 +0.012937 +0.01284 +0.012847 +0.01289 +0.012804 +0.012761 +0.012639 +0.012549 +0.01254 +0.012595 +0.012518 +0.012504 +0.012408 +0.012342 +0.012361 +0.012429 +0.012379 +0.01237 +0.012291 +0.012239 +0.012267 +0.012345 +0.012295 +0.012302 +0.012234 +0.012183 +0.012227 +0.012323 +0.012287 +0.012301 +0.012245 +0.012216 +0.012276 +0.012384 +0.012363 +0.012409 +0.012369 +0.012337 +0.012403 +0.012515 +0.001331 +0.012509 +0.012565 +0.012513 +0.012482 +0.012555 +0.012673 +0.012656 +0.012709 +0.012665 +0.012638 +0.012703 +0.012818 +0.012821 +0.012868 +0.01282 +0.012796 +0.012867 +0.01297 +0.012962 +0.013005 +0.012972 +0.012953 +0.013031 +0.01316 +0.013152 +0.013196 +0.013177 +0.013131 +0.013096 +0.013101 +0.013022 +0.01301 +0.012912 +0.012825 +0.01275 +0.012752 +0.012696 +0.012684 +0.012591 +0.01252 +0.012526 +0.012509 +0.012455 +0.012444 +0.012384 +0.012317 +0.012287 +0.012341 +0.0123 +0.0123 +0.012262 +0.012186 +0.012267 +0.012353 +0.012291 +0.012231 +0.012142 +0.012126 +0.012189 +0.012266 +0.012232 +0.012258 +0.012211 +0.01218 +0.012161 +0.012247 +0.012255 +0.012303 +0.012266 +0.012262 +0.01234 +0.012448 +0.012433 +0.012488 +0.001332 +0.012454 +0.012424 +0.012504 +0.012626 +0.012616 +0.012654 +0.012624 +0.012595 +0.012678 +0.012776 +0.012733 +0.012755 +0.012708 +0.01266 +0.012723 +0.01282 +0.0128 +0.01285 +0.012874 +0.012864 +0.012945 +0.013033 +0.013037 +0.013073 +0.013007 +0.012937 +0.012939 +0.012982 +0.0129 +0.012844 +0.012719 +0.012629 +0.012629 +0.01267 +0.012622 +0.012579 +0.01247 +0.012401 +0.012415 +0.012467 +0.012427 +0.01241 +0.01231 +0.012254 +0.01229 +0.012348 +0.012314 +0.012307 +0.012221 +0.012166 +0.012205 +0.012279 +0.012264 +0.012263 +0.012192 +0.012151 +0.012209 +0.012302 +0.012295 +0.012309 +0.012262 +0.012232 +0.012309 +0.012418 +0.012414 +0.012441 +0.012405 +0.001333 +0.012372 +0.012461 +0.012569 +0.012549 +0.012603 +0.01255 +0.012525 +0.012613 +0.012723 +0.012709 +0.012752 +0.012704 +0.01269 +0.012769 +0.012887 +0.012875 +0.012895 +0.012851 +0.012836 +0.012903 +0.013033 +0.013015 +0.013073 +0.013027 +0.013007 +0.013102 +0.013232 +0.013222 +0.013268 +0.013203 +0.013008 +0.012983 +0.013054 +0.012964 +0.01294 +0.012849 +0.012686 +0.012623 +0.012709 +0.012634 +0.012623 +0.012542 +0.012482 +0.01245 +0.012489 +0.012393 +0.01244 +0.012357 +0.01231 +0.012307 +0.01236 +0.012308 +0.012332 +0.012256 +0.012217 +0.012195 +0.012287 +0.012223 +0.012262 +0.012206 +0.012159 +0.012237 +0.012326 +0.012264 +0.012263 +0.012214 +0.012175 +0.012261 +0.012388 +0.012354 +0.012394 +0.012371 +0.012357 +0.01243 +0.001334 +0.012541 +0.012519 +0.012583 +0.012518 +0.012489 +0.012486 +0.012614 +0.012591 +0.012655 +0.01261 +0.012601 +0.012661 +0.012784 +0.012758 +0.012838 +0.012805 +0.01278 +0.012837 +0.012977 +0.01296 +0.013005 +0.012947 +0.012952 +0.013008 +0.013141 +0.013113 +0.013175 +0.01308 +0.013017 +0.013039 +0.013094 +0.012992 +0.012974 +0.012832 +0.012745 +0.012735 +0.012779 +0.012694 +0.012677 +0.012531 +0.012469 +0.012476 +0.012529 +0.012458 +0.012461 +0.012346 +0.012293 +0.012319 +0.012391 +0.012325 +0.012348 +0.012239 +0.012191 +0.012229 +0.01231 +0.012254 +0.012273 +0.012191 +0.012153 +0.012196 +0.012292 +0.012249 +0.012296 +0.012221 +0.012198 +0.012269 +0.012383 +0.012353 +0.012407 +0.012354 +0.012349 +0.012408 +0.001335 +0.012528 +0.012502 +0.012561 +0.012508 +0.012488 +0.01257 +0.012679 +0.012661 +0.012712 +0.012668 +0.012635 +0.012723 +0.012824 +0.012815 +0.012866 +0.012821 +0.012786 +0.012858 +0.012986 +0.012966 +0.013021 +0.012968 +0.012961 +0.013047 +0.013167 +0.013159 +0.01321 +0.01318 +0.013164 +0.013169 +0.013118 +0.013024 +0.013005 +0.012883 +0.012788 +0.012685 +0.0127 +0.01262 +0.012603 +0.012512 +0.012433 +0.012402 +0.012362 +0.012294 +0.012282 +0.012219 +0.012135 +0.012146 +0.01216 +0.01208 +0.012099 +0.012017 +0.011953 +0.011909 +0.011944 +0.011907 +0.011907 +0.011852 +0.011806 +0.011844 +0.011948 +0.011858 +0.011807 +0.011764 +0.011734 +0.011779 +0.011879 +0.011839 +0.011879 +0.011843 +0.011839 +0.011857 +0.011939 +0.011912 +0.011966 +0.011948 +0.011937 +0.011998 +0.012114 +0.001336 +0.012095 +0.012145 +0.012106 +0.012098 +0.012166 +0.012286 +0.012258 +0.012309 +0.012248 +0.012231 +0.012287 +0.01239 +0.012344 +0.01238 +0.012329 +0.012302 +0.012362 +0.012493 +0.012536 +0.012599 +0.01253 +0.012506 +0.012568 +0.012675 +0.012652 +0.012719 +0.012633 +0.012583 +0.01257 +0.012627 +0.01255 +0.012508 +0.012377 +0.012297 +0.012271 +0.012313 +0.012243 +0.012219 +0.012099 +0.012047 +0.012044 +0.012104 +0.012048 +0.012053 +0.011956 +0.011908 +0.011931 +0.012005 +0.011953 +0.011962 +0.01187 +0.011835 +0.011866 +0.011943 +0.011897 +0.011901 +0.011836 +0.011812 +0.011846 +0.011944 +0.011912 +0.011946 +0.011886 +0.01188 +0.011931 +0.012052 +0.012024 +0.012058 +0.012026 +0.012004 +0.001337 +0.012087 +0.01218 +0.012158 +0.012208 +0.012172 +0.01215 +0.012213 +0.012327 +0.012318 +0.012371 +0.012316 +0.012293 +0.012367 +0.01248 +0.012462 +0.012507 +0.012463 +0.012448 +0.012501 +0.012628 +0.012614 +0.012658 +0.012615 +0.01261 +0.012688 +0.012807 +0.012793 +0.012846 +0.012817 +0.012783 +0.012669 +0.012708 +0.012642 +0.012645 +0.012545 +0.012464 +0.012485 +0.012476 +0.012324 +0.012339 +0.012191 +0.012088 +0.012089 +0.012132 +0.012059 +0.012076 +0.011999 +0.011893 +0.011847 +0.011933 +0.011875 +0.011889 +0.011815 +0.011776 +0.011814 +0.011892 +0.011817 +0.01174 +0.011706 +0.011657 +0.011711 +0.011805 +0.011743 +0.011781 +0.011709 +0.011666 +0.011708 +0.011817 +0.011783 +0.011829 +0.011807 +0.011795 +0.011857 +0.011965 +0.011959 +0.012 +0.001338 +0.011964 +0.011944 +0.012017 +0.012133 +0.012109 +0.012149 +0.012113 +0.012084 +0.012087 +0.01218 +0.012157 +0.012205 +0.012161 +0.012144 +0.012221 +0.012387 +0.012387 +0.012409 +0.012363 +0.012341 +0.0124 +0.012517 +0.012519 +0.012568 +0.012512 +0.012496 +0.012538 +0.012618 +0.012557 +0.012528 +0.012396 +0.012309 +0.012287 +0.012307 +0.012235 +0.01219 +0.012065 +0.011995 +0.011992 +0.012025 +0.01197 +0.011956 +0.011852 +0.011771 +0.011795 +0.011857 +0.01182 +0.011815 +0.011732 +0.011675 +0.011707 +0.011771 +0.011749 +0.011761 +0.011684 +0.011637 +0.011664 +0.011756 +0.011744 +0.011762 +0.011705 +0.011674 +0.011723 +0.011829 +0.011821 +0.011864 +0.011823 +0.011803 +0.011846 +0.011964 +0.001339 +0.011929 +0.012008 +0.011974 +0.011927 +0.012001 +0.01209 +0.012077 +0.012109 +0.0121 +0.012066 +0.012138 +0.012244 +0.012249 +0.012282 +0.012242 +0.012206 +0.012273 +0.012376 +0.012375 +0.012406 +0.012379 +0.012353 +0.01243 +0.012544 +0.012546 +0.012582 +0.012553 +0.012542 +0.012634 +0.012753 +0.012641 +0.01256 +0.012484 +0.012405 +0.012385 +0.012388 +0.012304 +0.012293 +0.012226 +0.012075 +0.012038 +0.012096 +0.012043 +0.012017 +0.011948 +0.011888 +0.011889 +0.011909 +0.01183 +0.011848 +0.011766 +0.011726 +0.011749 +0.01179 +0.011709 +0.011733 +0.011658 +0.011592 +0.011595 +0.011631 +0.011609 +0.01162 +0.011564 +0.011535 +0.011597 +0.011686 +0.011671 +0.011689 +0.011654 +0.011615 +0.011627 +0.011702 +0.011688 +0.011735 +0.011714 +0.01169 +0.011772 +0.011882 +0.00134 +0.011876 +0.011915 +0.011876 +0.011853 +0.011927 +0.012043 +0.012023 +0.012067 +0.012023 +0.012009 +0.012055 +0.01216 +0.012122 +0.012149 +0.012105 +0.012074 +0.012133 +0.012242 +0.012259 +0.012341 +0.012297 +0.012265 +0.012337 +0.012418 +0.012414 +0.012447 +0.012414 +0.012365 +0.01236 +0.012411 +0.01234 +0.012288 +0.012169 +0.012081 +0.012055 +0.012083 +0.01202 +0.011985 +0.011872 +0.011811 +0.01181 +0.01185 +0.011801 +0.011792 +0.011699 +0.01165 +0.011679 +0.011745 +0.011697 +0.011701 +0.011633 +0.011582 +0.011619 +0.011692 +0.011657 +0.011663 +0.011602 +0.011568 +0.011613 +0.011703 +0.011684 +0.011712 +0.011666 +0.011647 +0.011706 +0.01182 +0.011794 +0.011826 +0.011804 +0.011772 +0.001341 +0.011849 +0.01194 +0.01194 +0.011976 +0.011939 +0.011912 +0.011991 +0.012094 +0.012077 +0.012115 +0.012087 +0.012054 +0.012131 +0.012231 +0.01222 +0.012261 +0.012221 +0.012192 +0.012271 +0.012382 +0.012376 +0.01241 +0.012387 +0.012359 +0.012438 +0.012568 +0.012558 +0.012598 +0.012569 +0.012456 +0.012424 +0.012489 +0.012424 +0.012389 +0.012302 +0.012218 +0.012199 +0.01215 +0.012066 +0.012059 +0.011989 +0.0119 +0.011824 +0.011867 +0.011813 +0.011803 +0.011752 +0.011679 +0.01172 +0.011729 +0.01167 +0.011702 +0.01161 +0.011522 +0.011529 +0.011599 +0.011573 +0.011574 +0.011543 +0.011493 +0.011539 +0.011639 +0.011596 +0.011569 +0.011503 +0.011461 +0.011525 +0.011624 +0.011609 +0.01164 +0.011613 +0.011601 +0.011677 +0.011763 +0.011748 +0.011795 +0.001342 +0.011777 +0.011739 +0.01177 +0.011848 +0.011838 +0.011867 +0.01185 +0.011823 +0.011912 +0.012017 +0.012004 +0.012034 +0.011999 +0.011955 +0.012026 +0.012128 +0.012112 +0.012149 +0.012153 +0.012134 +0.012198 +0.012299 +0.012287 +0.01233 +0.012296 +0.01228 +0.012338 +0.012428 +0.0124 +0.012355 +0.01225 +0.012147 +0.012131 +0.012143 +0.012071 +0.012005 +0.011886 +0.011803 +0.011801 +0.011822 +0.011769 +0.011727 +0.01163 +0.011566 +0.011579 +0.011629 +0.011595 +0.011578 +0.011498 +0.011446 +0.011474 +0.011536 +0.01151 +0.011508 +0.011434 +0.011379 +0.011423 +0.011502 +0.011481 +0.011489 +0.011437 +0.011393 +0.011453 +0.011546 +0.011546 +0.011568 +0.011539 +0.011498 +0.011557 +0.011681 +0.011673 +0.011714 +0.001343 +0.011657 +0.011637 +0.011693 +0.011802 +0.011807 +0.011847 +0.011794 +0.011771 +0.011828 +0.011947 +0.01194 +0.011978 +0.011929 +0.011902 +0.011975 +0.012076 +0.012066 +0.012124 +0.012073 +0.012065 +0.012132 +0.012262 +0.01224 +0.012288 +0.012257 +0.012256 +0.012294 +0.012298 +0.012234 +0.01226 +0.012163 +0.0121 +0.012118 +0.012157 +0.011994 +0.011971 +0.011858 +0.011757 +0.011738 +0.011774 +0.01171 +0.011714 +0.011622 +0.011587 +0.011572 +0.011584 +0.01151 +0.011536 +0.01147 +0.011436 +0.01148 +0.011568 +0.011466 +0.011457 +0.011381 +0.011354 +0.011351 +0.011417 +0.011388 +0.01141 +0.011358 +0.011346 +0.011398 +0.01149 +0.011471 +0.011507 +0.011463 +0.011442 +0.011533 +0.011588 +0.011548 +0.011585 +0.011567 +0.001344 +0.011556 +0.011623 +0.011725 +0.011696 +0.011749 +0.011715 +0.011661 +0.011683 +0.011786 +0.011772 +0.011826 +0.011793 +0.011777 +0.011845 +0.011941 +0.011926 +0.011973 +0.011948 +0.011947 +0.012005 +0.01211 +0.012105 +0.012149 +0.012113 +0.012082 +0.012129 +0.012265 +0.012248 +0.012253 +0.012165 +0.012096 +0.012086 +0.012129 +0.012054 +0.012011 +0.011891 +0.011821 +0.011806 +0.011855 +0.011798 +0.011779 +0.011692 +0.011607 +0.011626 +0.011694 +0.011651 +0.011651 +0.011577 +0.011516 +0.011529 +0.011616 +0.011578 +0.011573 +0.011509 +0.011456 +0.011478 +0.011559 +0.01153 +0.011548 +0.011488 +0.011446 +0.011476 +0.011565 +0.011566 +0.011596 +0.011557 +0.011533 +0.011579 +0.011681 +0.011659 +0.011721 +0.011695 +0.011658 +0.001345 +0.011726 +0.011813 +0.011793 +0.011823 +0.011818 +0.011788 +0.011857 +0.011947 +0.011946 +0.011991 +0.011958 +0.011917 +0.011992 +0.012076 +0.012086 +0.012125 +0.012084 +0.012062 +0.012129 +0.012243 +0.012236 +0.012287 +0.012246 +0.012223 +0.012319 +0.012439 +0.012434 +0.012384 +0.012254 +0.012199 +0.012241 +0.01228 +0.012199 +0.012148 +0.011983 +0.011893 +0.011896 +0.011933 +0.011861 +0.01184 +0.011771 +0.011656 +0.011614 +0.011696 +0.011635 +0.01164 +0.011579 +0.011518 +0.011574 +0.011667 +0.011604 +0.011524 +0.011445 +0.011424 +0.01148 +0.011563 +0.01153 +0.011526 +0.011452 +0.011418 +0.011424 +0.01151 +0.011495 +0.011514 +0.011487 +0.011475 +0.011549 +0.011645 +0.011644 +0.01167 +0.011636 +0.011615 +0.011707 +0.001346 +0.011815 +0.011767 +0.01183 +0.011789 +0.011766 +0.011762 +0.011855 +0.011834 +0.011886 +0.01186 +0.011823 +0.011895 +0.012001 +0.011984 +0.012059 +0.012038 +0.012011 +0.012065 +0.01217 +0.012166 +0.012227 +0.012175 +0.012139 +0.012214 +0.012329 +0.012324 +0.012355 +0.012291 +0.012238 +0.012241 +0.012285 +0.012215 +0.012173 +0.012055 +0.011981 +0.011956 +0.012005 +0.011949 +0.01193 +0.01183 +0.011751 +0.011758 +0.011821 +0.011769 +0.01177 +0.011691 +0.011628 +0.011636 +0.011718 +0.011683 +0.011688 +0.011617 +0.011564 +0.011589 +0.011677 +0.011648 +0.011667 +0.011615 +0.011574 +0.011602 +0.011697 +0.011699 +0.011733 +0.011699 +0.011677 +0.011715 +0.01182 +0.011785 +0.01186 +0.001347 +0.01184 +0.011809 +0.011865 +0.011964 +0.011924 +0.011968 +0.011938 +0.011932 +0.012002 +0.012095 +0.012084 +0.012133 +0.012096 +0.012066 +0.012133 +0.012239 +0.012234 +0.012278 +0.012234 +0.0122 +0.012273 +0.012379 +0.012371 +0.012417 +0.012379 +0.012358 +0.012441 +0.012563 +0.012559 +0.012605 +0.01257 +0.01245 +0.012368 +0.012419 +0.012339 +0.012317 +0.012223 +0.012134 +0.012053 +0.012045 +0.011991 +0.011985 +0.01188 +0.011821 +0.011789 +0.011802 +0.011758 +0.011746 +0.011686 +0.011592 +0.011602 +0.011651 +0.011619 +0.011621 +0.011568 +0.011496 +0.011545 +0.011581 +0.011528 +0.01156 +0.011464 +0.011416 +0.011426 +0.011506 +0.011484 +0.011513 +0.011456 +0.011434 +0.011507 +0.011606 +0.011585 +0.011641 +0.011589 +0.011556 +0.01157 +0.011687 +0.011661 +0.001348 +0.011707 +0.011666 +0.011647 +0.01173 +0.011844 +0.011825 +0.01187 +0.01183 +0.011817 +0.011901 +0.012001 +0.011975 +0.012001 +0.011946 +0.011916 +0.011976 +0.012078 +0.012048 +0.012072 +0.012042 +0.012063 +0.012166 +0.012272 +0.012237 +0.012271 +0.012223 +0.012215 +0.012279 +0.012381 +0.012318 +0.012288 +0.01219 +0.012101 +0.01209 +0.012134 +0.012034 +0.011992 +0.011883 +0.011811 +0.011815 +0.011868 +0.01179 +0.011773 +0.011688 +0.011618 +0.01165 +0.011729 +0.01167 +0.011663 +0.011596 +0.011543 +0.011579 +0.011668 +0.011622 +0.011618 +0.011558 +0.011517 +0.011563 +0.011669 +0.011626 +0.01164 +0.011592 +0.011575 +0.01163 +0.011749 +0.011722 +0.011749 +0.011707 +0.011683 +0.011767 +0.011878 +0.001349 +0.011862 +0.011886 +0.011847 +0.011809 +0.011875 +0.012013 +0.012002 +0.01203 +0.011984 +0.011955 +0.012022 +0.012148 +0.012138 +0.01217 +0.012123 +0.012103 +0.012171 +0.01227 +0.012262 +0.012311 +0.01227 +0.012258 +0.012333 +0.012445 +0.012448 +0.012485 +0.012463 +0.012453 +0.012501 +0.012485 +0.012403 +0.012408 +0.012313 +0.012219 +0.012131 +0.012168 +0.012103 +0.0121 +0.012008 +0.011926 +0.011867 +0.011902 +0.011838 +0.011851 +0.011759 +0.01172 +0.011694 +0.011738 +0.011666 +0.011718 +0.011616 +0.011565 +0.011523 +0.011603 +0.011581 +0.011592 +0.011532 +0.011505 +0.011541 +0.011634 +0.011616 +0.011567 +0.011484 +0.011457 +0.011538 +0.011641 +0.011614 +0.011666 +0.011637 +0.011609 +0.011674 +0.011785 +0.011778 +0.011822 +0.00135 +0.011779 +0.011758 +0.011838 +0.01195 +0.011923 +0.011928 +0.011858 +0.01185 +0.011927 +0.012033 +0.012005 +0.012059 +0.012014 +0.011986 +0.012048 +0.012148 +0.012124 +0.012161 +0.01212 +0.012086 +0.012191 +0.012338 +0.012321 +0.012354 +0.012293 +0.012272 +0.012326 +0.01248 +0.012443 +0.012438 +0.01234 +0.01225 +0.012247 +0.012297 +0.012183 +0.012152 +0.01204 +0.011953 +0.011961 +0.012012 +0.011929 +0.011908 +0.011806 +0.011732 +0.011754 +0.01182 +0.011744 +0.011746 +0.011667 +0.011602 +0.011638 +0.011712 +0.011661 +0.011657 +0.011582 +0.011537 +0.011577 +0.011671 +0.011628 +0.011636 +0.011578 +0.011554 +0.011603 +0.01172 +0.011696 +0.011726 +0.01168 +0.011658 +0.011735 +0.011849 +0.011827 +0.011868 +0.001351 +0.011804 +0.011785 +0.011858 +0.011986 +0.011961 +0.012006 +0.01195 +0.011938 +0.011999 +0.01212 +0.012101 +0.012146 +0.012098 +0.012072 +0.012137 +0.01226 +0.01224 +0.012284 +0.012243 +0.012222 +0.012295 +0.012408 +0.012402 +0.012463 +0.012403 +0.012407 +0.012488 +0.012624 +0.012478 +0.012471 +0.012387 +0.012259 +0.012199 +0.012243 +0.012151 +0.012137 +0.01205 +0.011907 +0.011848 +0.011911 +0.011854 +0.011842 +0.011766 +0.011705 +0.011724 +0.011725 +0.011648 +0.011667 +0.011607 +0.011561 +0.011546 +0.011577 +0.011532 +0.011556 +0.011494 +0.011465 +0.011473 +0.011546 +0.011471 +0.011507 +0.01147 +0.011393 +0.011388 +0.011496 +0.011465 +0.011511 +0.011477 +0.011469 +0.011522 +0.011636 +0.011623 +0.011671 +0.01162 +0.011618 +0.011686 +0.001352 +0.011789 +0.011765 +0.011809 +0.011788 +0.011768 +0.011813 +0.011874 +0.01184 +0.011895 +0.011855 +0.011829 +0.011891 +0.011992 +0.011968 +0.012011 +0.011972 +0.011963 +0.012069 +0.012186 +0.012157 +0.012195 +0.012154 +0.012112 +0.012192 +0.012317 +0.012309 +0.012314 +0.012228 +0.012163 +0.012145 +0.012186 +0.012096 +0.012049 +0.011921 +0.011847 +0.011846 +0.011892 +0.011839 +0.011808 +0.011702 +0.011644 +0.011656 +0.011715 +0.011671 +0.011664 +0.011567 +0.011524 +0.011553 +0.011622 +0.011587 +0.011583 +0.011501 +0.011454 +0.011491 +0.011573 +0.011552 +0.011563 +0.011491 +0.011453 +0.011505 +0.011609 +0.011597 +0.01162 +0.011573 +0.011543 +0.011605 +0.011728 +0.01172 +0.011749 +0.011717 +0.001353 +0.011677 +0.011726 +0.011849 +0.011849 +0.011897 +0.011844 +0.011811 +0.011866 +0.011983 +0.011989 +0.012028 +0.011979 +0.011957 +0.01201 +0.012121 +0.012119 +0.012167 +0.012121 +0.012088 +0.012171 +0.012284 +0.012274 +0.012328 +0.012287 +0.012272 +0.012355 +0.012495 +0.012382 +0.012347 +0.012272 +0.012181 +0.012123 +0.01217 +0.012075 +0.012069 +0.011974 +0.011898 +0.011818 +0.011855 +0.011781 +0.011799 +0.011707 +0.011673 +0.011697 +0.011773 +0.011678 +0.011617 +0.011545 +0.011517 +0.011527 +0.011606 +0.011535 +0.011557 +0.011521 +0.011435 +0.011422 +0.01149 +0.011455 +0.0115 +0.011457 +0.011423 +0.011492 +0.011588 +0.011554 +0.0116 +0.01158 +0.01155 +0.01162 +0.011719 +0.011658 +0.011697 +0.001354 +0.011662 +0.011627 +0.011664 +0.011778 +0.011756 +0.011799 +0.011766 +0.011749 +0.011827 +0.011936 +0.011911 +0.011955 +0.011912 +0.011885 +0.011945 +0.012044 +0.012021 +0.012064 +0.012033 +0.012045 +0.012122 +0.012223 +0.012198 +0.012237 +0.012194 +0.012164 +0.012258 +0.012364 +0.012321 +0.012336 +0.012225 +0.012136 +0.012142 +0.012173 +0.012079 +0.012048 +0.011925 +0.011843 +0.01185 +0.01189 +0.011819 +0.011806 +0.011701 +0.01164 +0.011661 +0.011712 +0.011659 +0.011667 +0.011582 +0.011519 +0.011555 +0.011624 +0.011565 +0.011579 +0.011505 +0.01145 +0.011506 +0.011586 +0.011536 +0.01156 +0.011504 +0.011469 +0.011537 +0.01163 +0.011598 +0.011641 +0.011595 +0.011581 +0.01165 +0.011745 +0.011742 +0.011761 +0.001355 +0.011734 +0.011717 +0.011777 +0.011896 +0.011872 +0.011914 +0.011865 +0.011857 +0.011916 +0.012038 +0.012011 +0.012065 +0.01201 +0.011986 +0.012046 +0.012172 +0.012153 +0.012197 +0.012154 +0.012141 +0.0122 +0.01234 +0.012316 +0.012364 +0.012332 +0.012325 +0.012385 +0.012355 +0.012265 +0.012273 +0.012159 +0.012071 +0.011956 +0.011984 +0.011914 +0.011906 +0.011797 +0.011747 +0.011722 +0.01172 +0.011664 +0.011674 +0.01159 +0.011516 +0.01148 +0.011574 +0.011509 +0.011548 +0.01146 +0.01143 +0.01147 +0.011559 +0.011516 +0.011428 +0.011361 +0.011331 +0.011377 +0.011489 +0.011447 +0.011476 +0.011435 +0.011415 +0.011476 +0.011575 +0.011537 +0.011555 +0.011512 +0.011491 +0.011545 +0.01167 +0.011641 +0.001356 +0.011682 +0.011632 +0.011639 +0.011687 +0.0118 +0.011765 +0.011814 +0.01178 +0.01177 +0.011823 +0.011939 +0.01189 +0.011927 +0.011874 +0.011848 +0.011906 +0.012006 +0.011982 +0.012036 +0.012022 +0.012038 +0.012105 +0.012207 +0.012183 +0.012218 +0.012177 +0.012143 +0.012155 +0.012228 +0.012143 +0.012114 +0.011994 +0.011917 +0.011886 +0.011939 +0.011858 +0.011827 +0.011716 +0.011652 +0.011644 +0.011716 +0.011655 +0.011641 +0.01155 +0.011489 +0.011508 +0.011595 +0.011533 +0.01154 +0.011466 +0.011408 +0.01143 +0.011521 +0.011474 +0.011491 +0.01142 +0.011374 +0.011402 +0.011519 +0.011487 +0.011515 +0.011469 +0.011436 +0.011474 +0.011611 +0.011592 +0.011643 +0.011587 +0.011557 +0.011616 +0.001357 +0.011718 +0.011724 +0.011783 +0.011721 +0.011696 +0.011751 +0.011852 +0.011846 +0.011901 +0.011867 +0.01184 +0.011906 +0.011999 +0.011985 +0.012018 +0.01198 +0.011955 +0.012022 +0.012141 +0.012125 +0.012169 +0.012136 +0.012115 +0.012195 +0.012316 +0.012302 +0.012342 +0.012275 +0.012096 +0.012087 +0.012145 +0.012063 +0.012026 +0.011928 +0.011771 +0.011733 +0.011796 +0.011726 +0.011713 +0.011646 +0.011586 +0.011537 +0.011556 +0.011485 +0.011506 +0.011455 +0.011383 +0.011453 +0.011512 +0.011467 +0.01143 +0.011329 +0.011297 +0.011342 +0.011432 +0.011365 +0.011393 +0.011345 +0.011266 +0.011274 +0.011382 +0.011343 +0.011378 +0.01137 +0.011327 +0.011395 +0.011513 +0.011493 +0.011522 +0.011507 +0.011481 +0.011547 +0.001358 +0.011669 +0.011629 +0.011669 +0.011629 +0.011566 +0.0116 +0.011706 +0.011688 +0.011732 +0.01171 +0.011688 +0.01176 +0.011866 +0.01184 +0.011884 +0.011841 +0.011838 +0.011914 +0.012019 +0.012002 +0.012041 +0.012005 +0.011986 +0.012059 +0.01215 +0.01216 +0.012184 +0.012117 +0.01206 +0.012069 +0.012115 +0.012044 +0.012009 +0.011887 +0.011811 +0.011804 +0.011838 +0.011772 +0.011747 +0.01163 +0.011563 +0.011571 +0.011614 +0.011555 +0.011542 +0.011449 +0.011401 +0.011426 +0.011494 +0.011442 +0.011439 +0.011367 +0.011327 +0.011357 +0.011436 +0.011398 +0.011405 +0.011344 +0.011319 +0.011368 +0.011457 +0.011437 +0.011454 +0.01141 +0.011407 +0.011458 +0.011568 +0.011556 +0.011582 +0.011537 +0.001359 +0.011525 +0.011589 +0.01171 +0.011684 +0.011719 +0.011676 +0.011643 +0.011724 +0.011841 +0.011822 +0.011857 +0.011811 +0.011794 +0.011866 +0.011973 +0.01196 +0.011998 +0.011942 +0.011931 +0.011992 +0.012106 +0.012088 +0.012143 +0.012103 +0.01208 +0.012163 +0.01228 +0.012271 +0.012314 +0.012156 +0.012045 +0.012064 +0.012107 +0.012 +0.011887 +0.011783 +0.011705 +0.011656 +0.01172 +0.011612 +0.011604 +0.011546 +0.011455 +0.011401 +0.011415 +0.011379 +0.011376 +0.011326 +0.011267 +0.011316 +0.011387 +0.011337 +0.011343 +0.011244 +0.01115 +0.011165 +0.011235 +0.011204 +0.011213 +0.011163 +0.011149 +0.011202 +0.011277 +0.011246 +0.011276 +0.011189 +0.011154 +0.011202 +0.011296 +0.011261 +0.01131 +0.011292 +0.01127 +0.01134 +0.011461 +0.00136 +0.011412 +0.011471 +0.011424 +0.011431 +0.011492 +0.011596 +0.011572 +0.011614 +0.011581 +0.011573 +0.011638 +0.011737 +0.011679 +0.011713 +0.011658 +0.011634 +0.011687 +0.011784 +0.011738 +0.011793 +0.011751 +0.011795 +0.011889 +0.011995 +0.011959 +0.011988 +0.011933 +0.011881 +0.011871 +0.011963 +0.011866 +0.011823 +0.011705 +0.011616 +0.011589 +0.011628 +0.011545 +0.011517 +0.01141 +0.011342 +0.011333 +0.011398 +0.011322 +0.011318 +0.011227 +0.011171 +0.01119 +0.011272 +0.011204 +0.011213 +0.011141 +0.011087 +0.011117 +0.011209 +0.01115 +0.011163 +0.011102 +0.011068 +0.011105 +0.011207 +0.011172 +0.011202 +0.011147 +0.011126 +0.011174 +0.011299 +0.011264 +0.011321 +0.011248 +0.01124 +0.011315 +0.001361 +0.011411 +0.011401 +0.011435 +0.011394 +0.011378 +0.01144 +0.011547 +0.011528 +0.011575 +0.011535 +0.011503 +0.011565 +0.011679 +0.011676 +0.011709 +0.011671 +0.011643 +0.011699 +0.011806 +0.011793 +0.011818 +0.01179 +0.011764 +0.01184 +0.011944 +0.011938 +0.011985 +0.011947 +0.011937 +0.012025 +0.012133 +0.012075 +0.011925 +0.011812 +0.011748 +0.01177 +0.011807 +0.01168 +0.011597 +0.011519 +0.011454 +0.011397 +0.011443 +0.011383 +0.011377 +0.011318 +0.011245 +0.011276 +0.011278 +0.011231 +0.011232 +0.011186 +0.011079 +0.011101 +0.011156 +0.011133 +0.011152 +0.01109 +0.011063 +0.011099 +0.011188 +0.011148 +0.011093 +0.011045 +0.011019 +0.011074 +0.01117 +0.011159 +0.011181 +0.011155 +0.011138 +0.011204 +0.011306 +0.011291 +0.011329 +0.011272 +0.001362 +0.011284 +0.01127 +0.011369 +0.011343 +0.011403 +0.011372 +0.011348 +0.011416 +0.011519 +0.011508 +0.01155 +0.01151 +0.011483 +0.011538 +0.011641 +0.011618 +0.011656 +0.011619 +0.011626 +0.01169 +0.011795 +0.011773 +0.01181 +0.011783 +0.011756 +0.01183 +0.011929 +0.011923 +0.011943 +0.011849 +0.01177 +0.011761 +0.011793 +0.011709 +0.011663 +0.011538 +0.011461 +0.011449 +0.011485 +0.011432 +0.011407 +0.011302 +0.011242 +0.011251 +0.011302 +0.011257 +0.011248 +0.011169 +0.011121 +0.011144 +0.011215 +0.011183 +0.011184 +0.011112 +0.011083 +0.011113 +0.011186 +0.011165 +0.011179 +0.011117 +0.011095 +0.011146 +0.011232 +0.011212 +0.011244 +0.011194 +0.011184 +0.011234 +0.011342 +0.011328 +0.011364 +0.001363 +0.011329 +0.011302 +0.011367 +0.011469 +0.011464 +0.0115 +0.011454 +0.011436 +0.011507 +0.01161 +0.011589 +0.011628 +0.011589 +0.011574 +0.011637 +0.01174 +0.011719 +0.01177 +0.011734 +0.011693 +0.011766 +0.011872 +0.011857 +0.011898 +0.011854 +0.011844 +0.011926 +0.012035 +0.012022 +0.012073 +0.012041 +0.012013 +0.011962 +0.011958 +0.011873 +0.011863 +0.011777 +0.011692 +0.011662 +0.011625 +0.01153 +0.01155 +0.011457 +0.011379 +0.01134 +0.011366 +0.011302 +0.011316 +0.011243 +0.011201 +0.011253 +0.011304 +0.011242 +0.011193 +0.011143 +0.011098 +0.011109 +0.011177 +0.011117 +0.01115 +0.011102 +0.011061 +0.011127 +0.011213 +0.011156 +0.011167 +0.011084 +0.01106 +0.011129 +0.011231 +0.011178 +0.011219 +0.011207 +0.011185 +0.011248 +0.011361 +0.011322 +0.011359 +0.001364 +0.011333 +0.011321 +0.011392 +0.01149 +0.011461 +0.011507 +0.011455 +0.011413 +0.011449 +0.011544 +0.011514 +0.011559 +0.011531 +0.011497 +0.011571 +0.011723 +0.011726 +0.011756 +0.011705 +0.011679 +0.011745 +0.01186 +0.011856 +0.011892 +0.011848 +0.011829 +0.011889 +0.011978 +0.011915 +0.011892 +0.011769 +0.011667 +0.011643 +0.011673 +0.011584 +0.011545 +0.011445 +0.011369 +0.011375 +0.011431 +0.011365 +0.011356 +0.011268 +0.011202 +0.011218 +0.011288 +0.011237 +0.011238 +0.011168 +0.0111 +0.011132 +0.01121 +0.01117 +0.01117 +0.011108 +0.011047 +0.011086 +0.011171 +0.011145 +0.011158 +0.011106 +0.01106 +0.011093 +0.011205 +0.011189 +0.011217 +0.011188 +0.011148 +0.0112 +0.0113 +0.011295 +0.011361 +0.011298 +0.001365 +0.011291 +0.011327 +0.011437 +0.0114 +0.01147 +0.011424 +0.011407 +0.011456 +0.011564 +0.011554 +0.011609 +0.011559 +0.011539 +0.01159 +0.011703 +0.011684 +0.011717 +0.011672 +0.011663 +0.011723 +0.011837 +0.011823 +0.011874 +0.011828 +0.011816 +0.011898 +0.012019 +0.011983 +0.011926 +0.0118 +0.011737 +0.01176 +0.011796 +0.01167 +0.0116 +0.011498 +0.01144 +0.011388 +0.011417 +0.011357 +0.011355 +0.011265 +0.011223 +0.011177 +0.011226 +0.011142 +0.011194 +0.011096 +0.011078 +0.011084 +0.011168 +0.011098 +0.011106 +0.011011 +0.010964 +0.011027 +0.011101 +0.011052 +0.011087 +0.01098 +0.010954 +0.011018 +0.011113 +0.011065 +0.011132 +0.01107 +0.011052 +0.011124 +0.011234 +0.011195 +0.011241 +0.0112 +0.011173 +0.001366 +0.011195 +0.011288 +0.01128 +0.011324 +0.011295 +0.011273 +0.011341 +0.011448 +0.011431 +0.01147 +0.01143 +0.011407 +0.011462 +0.011558 +0.011541 +0.011572 +0.011543 +0.011548 +0.011624 +0.011713 +0.011693 +0.011736 +0.011697 +0.011683 +0.011746 +0.01185 +0.011827 +0.011853 +0.011749 +0.011645 +0.011648 +0.011674 +0.011576 +0.011532 +0.011402 +0.011308 +0.011314 +0.011343 +0.011276 +0.011253 +0.011146 +0.011069 +0.011091 +0.011132 +0.011076 +0.011084 +0.010999 +0.010929 +0.010958 +0.011041 +0.010992 +0.011001 +0.01093 +0.010877 +0.010921 +0.010995 +0.010965 +0.010994 +0.01094 +0.010897 +0.010927 +0.01102 +0.011018 +0.011064 +0.011026 +0.010975 +0.011044 +0.011126 +0.011106 +0.011157 +0.01113 +0.001367 +0.011102 +0.011166 +0.011249 +0.011258 +0.011296 +0.011267 +0.011227 +0.011289 +0.011379 +0.011368 +0.011402 +0.011381 +0.011354 +0.011421 +0.011511 +0.011507 +0.01154 +0.011516 +0.011473 +0.011555 +0.011642 +0.011645 +0.01167 +0.011661 +0.011631 +0.011708 +0.011808 +0.011807 +0.011846 +0.011764 +0.011624 +0.011655 +0.011698 +0.011612 +0.011584 +0.011434 +0.011321 +0.011313 +0.011342 +0.011269 +0.01128 +0.011188 +0.011062 +0.01105 +0.011094 +0.011065 +0.01105 +0.011022 +0.010943 +0.011019 +0.011074 +0.011022 +0.010962 +0.010908 +0.010876 +0.010915 +0.011 +0.010951 +0.010978 +0.010942 +0.010835 +0.010865 +0.010957 +0.010931 +0.010966 +0.010942 +0.010907 +0.01098 +0.011075 +0.011062 +0.011093 +0.011078 +0.011057 +0.011117 +0.011207 +0.001368 +0.011205 +0.011227 +0.011205 +0.011182 +0.011219 +0.011267 +0.011258 +0.011302 +0.011282 +0.011256 +0.011324 +0.011413 +0.011396 +0.011422 +0.011396 +0.011365 +0.011455 +0.011574 +0.011573 +0.011583 +0.011549 +0.011528 +0.011607 +0.011699 +0.01169 +0.011728 +0.011693 +0.011632 +0.011675 +0.011714 +0.011634 +0.011584 +0.011465 +0.01135 +0.011338 +0.011355 +0.011286 +0.011252 +0.011159 +0.011063 +0.011084 +0.011113 +0.011067 +0.011051 +0.010972 +0.010899 +0.010934 +0.010991 +0.010951 +0.010954 +0.010898 +0.010835 +0.010873 +0.01094 +0.010913 +0.010923 +0.010875 +0.010829 +0.010885 +0.010956 +0.010942 +0.010973 +0.010933 +0.010906 +0.010973 +0.011058 +0.011036 +0.011092 +0.011049 +0.011033 +0.001369 +0.01109 +0.01119 +0.01116 +0.011197 +0.01118 +0.011153 +0.011211 +0.011304 +0.011303 +0.011339 +0.011304 +0.011273 +0.011335 +0.011436 +0.011433 +0.011472 +0.011427 +0.011394 +0.011471 +0.011567 +0.011553 +0.011594 +0.011557 +0.011526 +0.011615 +0.011715 +0.011709 +0.011746 +0.011725 +0.011711 +0.011734 +0.01172 +0.011669 +0.01166 +0.011571 +0.011484 +0.011511 +0.011445 +0.011355 +0.011309 +0.011246 +0.011167 +0.011098 +0.011146 +0.011089 +0.011076 +0.011021 +0.01095 +0.01101 +0.011057 +0.010981 +0.010969 +0.010886 +0.010858 +0.010858 +0.01093 +0.010874 +0.010887 +0.010849 +0.010799 +0.010867 +0.010955 +0.010886 +0.010853 +0.010821 +0.010784 +0.010856 +0.010937 +0.010926 +0.010936 +0.010912 +0.010901 +0.010981 +0.011065 +0.011036 +0.011075 +0.011045 +0.00137 +0.010991 +0.011032 +0.011117 +0.011101 +0.011144 +0.011123 +0.011101 +0.01117 +0.011267 +0.011258 +0.011287 +0.01126 +0.011231 +0.011294 +0.011389 +0.011379 +0.011417 +0.011397 +0.011363 +0.011434 +0.011535 +0.011524 +0.011561 +0.01152 +0.011497 +0.011559 +0.011666 +0.011668 +0.011694 +0.011638 +0.0116 +0.011624 +0.011659 +0.011603 +0.011568 +0.011448 +0.011349 +0.011344 +0.011363 +0.011317 +0.011283 +0.011191 +0.011114 +0.011136 +0.011189 +0.011161 +0.011142 +0.011064 +0.011007 +0.011042 +0.0111 +0.011087 +0.011092 +0.011037 +0.010988 +0.011022 +0.011098 +0.011099 +0.011112 +0.01106 +0.011021 +0.011071 +0.011162 +0.011165 +0.011193 +0.011162 +0.011134 +0.011189 +0.011278 +0.001371 +0.011277 +0.011326 +0.011304 +0.01126 +0.011327 +0.011419 +0.011385 +0.011417 +0.011392 +0.011391 +0.01145 +0.011545 +0.011528 +0.011572 +0.011537 +0.01151 +0.011577 +0.011674 +0.011652 +0.011698 +0.011648 +0.011635 +0.011693 +0.011813 +0.011802 +0.011842 +0.011812 +0.011795 +0.011876 +0.011973 +0.01189 +0.011803 +0.011614 +0.011528 +0.011551 +0.011544 +0.011441 +0.011432 +0.011316 +0.011227 +0.011221 +0.011275 +0.011203 +0.01122 +0.01114 +0.0111 +0.011148 +0.011188 +0.011122 +0.011115 +0.01107 +0.010981 +0.010985 +0.011049 +0.011013 +0.01101 +0.010949 +0.010924 +0.010968 +0.011069 +0.01102 +0.011007 +0.01091 +0.010897 +0.010953 +0.011041 +0.011017 +0.01104 +0.010996 +0.010984 +0.011077 +0.011175 +0.011141 +0.011172 +0.011136 +0.011114 +0.001372 +0.011135 +0.01123 +0.011216 +0.011249 +0.011219 +0.011211 +0.011274 +0.011382 +0.011373 +0.011393 +0.011358 +0.01134 +0.011397 +0.011495 +0.011477 +0.011512 +0.011481 +0.011486 +0.011533 +0.011642 +0.011622 +0.011666 +0.011624 +0.011602 +0.011678 +0.011776 +0.011765 +0.011805 +0.011761 +0.011713 +0.011735 +0.011794 +0.011707 +0.011673 +0.011557 +0.011452 +0.011449 +0.01149 +0.011417 +0.011401 +0.011308 +0.011213 +0.011223 +0.011295 +0.011227 +0.011225 +0.011159 +0.011094 +0.011118 +0.011204 +0.011159 +0.011167 +0.011108 +0.011054 +0.011084 +0.011175 +0.011141 +0.011155 +0.011113 +0.011068 +0.011107 +0.011209 +0.011187 +0.011209 +0.011179 +0.011147 +0.011209 +0.011298 +0.011297 +0.011338 +0.011297 +0.001373 +0.011276 +0.011326 +0.011429 +0.011414 +0.011476 +0.01142 +0.011399 +0.011463 +0.011564 +0.011544 +0.011585 +0.011552 +0.011531 +0.011587 +0.011693 +0.011686 +0.011728 +0.011681 +0.011666 +0.011726 +0.011827 +0.011807 +0.011858 +0.011812 +0.011802 +0.011869 +0.011986 +0.011977 +0.012021 +0.011991 +0.01198 +0.011971 +0.012003 +0.011952 +0.01196 +0.011874 +0.011793 +0.011809 +0.011874 +0.011694 +0.011643 +0.011555 +0.011474 +0.01143 +0.011467 +0.011403 +0.011401 +0.011312 +0.011274 +0.011289 +0.011294 +0.011202 +0.011227 +0.011145 +0.011128 +0.011133 +0.011173 +0.011114 +0.01111 +0.011074 +0.011032 +0.011059 +0.011096 +0.011037 +0.011084 +0.011027 +0.011007 +0.011082 +0.011172 +0.011138 +0.01118 +0.011142 +0.011122 +0.011193 +0.011294 +0.011262 +0.011279 +0.011227 +0.001374 +0.011216 +0.011267 +0.01137 +0.01132 +0.011382 +0.011339 +0.01134 +0.011395 +0.011509 +0.011479 +0.011528 +0.011482 +0.011464 +0.011516 +0.01162 +0.011585 +0.011631 +0.011578 +0.011579 +0.011663 +0.011783 +0.011747 +0.011789 +0.011739 +0.011738 +0.011789 +0.01191 +0.011886 +0.01193 +0.011834 +0.011747 +0.011742 +0.011766 +0.011658 +0.011628 +0.011483 +0.011397 +0.011393 +0.011431 +0.011354 +0.011343 +0.011222 +0.011157 +0.011168 +0.011225 +0.011153 +0.01116 +0.01106 +0.011001 +0.011039 +0.01111 +0.011055 +0.011063 +0.010975 +0.010936 +0.010968 +0.011049 +0.011 +0.01103 +0.010949 +0.010909 +0.010964 +0.011057 +0.011022 +0.011061 +0.011 +0.010972 +0.011039 +0.011144 +0.011126 +0.011172 +0.011116 +0.011094 +0.011143 +0.001375 +0.011277 +0.011252 +0.011296 +0.011257 +0.011227 +0.011262 +0.011373 +0.011372 +0.011425 +0.011381 +0.011349 +0.011408 +0.011509 +0.011494 +0.011527 +0.011488 +0.011474 +0.01154 +0.011637 +0.01164 +0.011668 +0.011643 +0.011622 +0.011692 +0.011811 +0.011799 +0.01185 +0.011821 +0.011739 +0.011681 +0.011752 +0.011691 +0.011677 +0.011584 +0.011499 +0.011514 +0.011499 +0.01133 +0.011331 +0.011242 +0.011103 +0.011082 +0.011144 +0.011052 +0.011075 +0.010989 +0.010937 +0.010858 +0.010934 +0.010869 +0.010901 +0.010833 +0.010808 +0.010835 +0.010914 +0.010866 +0.010875 +0.010759 +0.01071 +0.010764 +0.010839 +0.010794 +0.010833 +0.0108 +0.010779 +0.01085 +0.010944 +0.010899 +0.010932 +0.010918 +0.010878 +0.01089 +0.010973 +0.010974 +0.001376 +0.011011 +0.010989 +0.010967 +0.011042 +0.011137 +0.011131 +0.011166 +0.011136 +0.011113 +0.011183 +0.01128 +0.011271 +0.011301 +0.011264 +0.011234 +0.011296 +0.011387 +0.011362 +0.011385 +0.011352 +0.011311 +0.011376 +0.011464 +0.011479 +0.011552 +0.011524 +0.011478 +0.01154 +0.011633 +0.01162 +0.011639 +0.011608 +0.011539 +0.011532 +0.011572 +0.01149 +0.011433 +0.011329 +0.011234 +0.011216 +0.011253 +0.011187 +0.011149 +0.011065 +0.010992 +0.011003 +0.011051 +0.011004 +0.010987 +0.01092 +0.010849 +0.010888 +0.010954 +0.010914 +0.010909 +0.010853 +0.010797 +0.010833 +0.010912 +0.010882 +0.010884 +0.010841 +0.010798 +0.010852 +0.010943 +0.010925 +0.010941 +0.010917 +0.010883 +0.010947 +0.01105 +0.011031 +0.01107 +0.011027 +0.001377 +0.011 +0.011071 +0.011167 +0.011155 +0.011195 +0.011155 +0.011122 +0.011192 +0.011294 +0.011291 +0.01132 +0.011287 +0.01125 +0.011322 +0.011419 +0.011419 +0.011446 +0.011415 +0.011379 +0.011448 +0.011548 +0.01153 +0.011576 +0.011541 +0.011524 +0.011595 +0.011698 +0.011702 +0.011739 +0.011717 +0.011701 +0.011733 +0.011719 +0.01166 +0.011673 +0.011598 +0.011527 +0.011559 +0.011608 +0.011461 +0.011423 +0.011353 +0.011264 +0.011235 +0.011293 +0.011237 +0.011226 +0.011191 +0.011112 +0.011162 +0.011147 +0.011114 +0.01111 +0.011082 +0.011032 +0.011072 +0.011097 +0.011057 +0.011085 +0.011046 +0.011017 +0.011069 +0.011098 +0.011083 +0.011107 +0.011071 +0.011059 +0.011083 +0.011148 +0.011129 +0.011174 +0.011147 +0.011121 +0.011208 +0.0113 +0.011284 +0.001378 +0.011313 +0.011293 +0.011281 +0.011344 +0.01145 +0.011413 +0.011468 +0.01144 +0.011426 +0.011464 +0.011528 +0.011489 +0.011543 +0.011507 +0.011484 +0.011541 +0.011641 +0.011614 +0.011653 +0.011617 +0.011607 +0.011708 +0.011823 +0.011804 +0.011834 +0.011789 +0.011765 +0.011824 +0.011961 +0.011925 +0.011929 +0.01183 +0.011748 +0.011729 +0.011758 +0.011658 +0.011614 +0.011494 +0.011406 +0.011406 +0.01144 +0.011374 +0.011352 +0.011256 +0.011182 +0.011199 +0.011256 +0.011198 +0.011201 +0.011128 +0.011065 +0.011108 +0.01118 +0.011135 +0.011144 +0.011082 +0.011035 +0.011085 +0.011161 +0.01112 +0.011145 +0.011093 +0.011055 +0.011112 +0.011208 +0.011182 +0.011215 +0.011184 +0.011152 +0.011222 +0.011321 +0.011305 +0.011344 +0.001379 +0.011303 +0.011285 +0.01135 +0.011458 +0.011425 +0.011481 +0.011428 +0.011424 +0.011474 +0.011586 +0.011573 +0.011617 +0.011567 +0.01155 +0.011602 +0.011718 +0.011698 +0.011754 +0.011695 +0.011676 +0.011748 +0.011851 +0.011841 +0.011886 +0.011847 +0.011848 +0.011911 +0.01204 +0.012021 +0.012048 +0.011865 +0.011803 +0.011825 +0.011869 +0.011742 +0.011634 +0.011522 +0.011447 +0.0114 +0.011436 +0.011351 +0.011369 +0.011271 +0.011163 +0.011114 +0.011168 +0.011129 +0.011127 +0.01106 +0.011 +0.011044 +0.011122 +0.011028 +0.010987 +0.010902 +0.010886 +0.010909 +0.010997 +0.010954 +0.010963 +0.010857 +0.010829 +0.010869 +0.010964 +0.010942 +0.010973 +0.010923 +0.010921 +0.010948 +0.01103 +0.011003 +0.011063 +0.011025 +0.01099 +0.011069 +0.011183 +0.00138 +0.011135 +0.011186 +0.011153 +0.01115 +0.01121 +0.011316 +0.011275 +0.011326 +0.011296 +0.01125 +0.011252 +0.011359 +0.011333 +0.011381 +0.011339 +0.011329 +0.011386 +0.011517 +0.011524 +0.011573 +0.011517 +0.011503 +0.011539 +0.01166 +0.011644 +0.0117 +0.011657 +0.011629 +0.011682 +0.011797 +0.01177 +0.011773 +0.01166 +0.01159 +0.011558 +0.011586 +0.011507 +0.011469 +0.01134 +0.011282 +0.011235 +0.011281 +0.01122 +0.011201 +0.011094 +0.011038 +0.011035 +0.011088 +0.01103 +0.011041 +0.010949 +0.010904 +0.01092 +0.010983 +0.01093 +0.010943 +0.010864 +0.010831 +0.01085 +0.010928 +0.01088 +0.010903 +0.010838 +0.010819 +0.010852 +0.010945 +0.010906 +0.010941 +0.010894 +0.01089 +0.010933 +0.011046 +0.011017 +0.011051 +0.011013 +0.010993 +0.011072 +0.001381 +0.011165 +0.01115 +0.011171 +0.011125 +0.01111 +0.011188 +0.011294 +0.011271 +0.011305 +0.011253 +0.011237 +0.011306 +0.011412 +0.0114 +0.011425 +0.011388 +0.011363 +0.01143 +0.011527 +0.011524 +0.011552 +0.011522 +0.011493 +0.011562 +0.011657 +0.011651 +0.011684 +0.011646 +0.011639 +0.011716 +0.011825 +0.01181 +0.011861 +0.011817 +0.011696 +0.011615 +0.011653 +0.01158 +0.011539 +0.011425 +0.01127 +0.011167 +0.011212 +0.011136 +0.011101 +0.011027 +0.010937 +0.010826 +0.010872 +0.010789 +0.010804 +0.01071 +0.010666 +0.01063 +0.010673 +0.010595 +0.010631 +0.010518 +0.010439 +0.010415 +0.010482 +0.010427 +0.010435 +0.010396 +0.010316 +0.010287 +0.010325 +0.010272 +0.010306 +0.010261 +0.010218 +0.010261 +0.010349 +0.010321 +0.010353 +0.010323 +0.010299 +0.010307 +0.01038 +0.010359 +0.010408 +0.010381 +0.010356 +0.010424 +0.010511 +0.010494 +0.010542 +0.001382 +0.010503 +0.010498 +0.010542 +0.010655 +0.010623 +0.010676 +0.010635 +0.010624 +0.010683 +0.010777 +0.010735 +0.010781 +0.010727 +0.010716 +0.010765 +0.010848 +0.010808 +0.010839 +0.0108 +0.010787 +0.010838 +0.010943 +0.010901 +0.010951 +0.010906 +0.010916 +0.010988 +0.011095 +0.011068 +0.011102 +0.011058 +0.011038 +0.0111 +0.011215 +0.011201 +0.011231 +0.011186 +0.011173 +0.011229 +0.011338 +0.01132 +0.011366 +0.01132 +0.011298 +0.011351 +0.01146 +0.011453 +0.011491 +0.011425 +0.011404 +0.011436 +0.011539 +0.011521 +0.011551 +0.011484 +0.011471 +0.011507 +0.011616 +0.0116 +0.01164 +0.011587 +0.011562 +0.011591 +0.0117 +0.011706 +0.011754 +0.011701 +0.011686 +0.011725 +0.011836 +0.011801 +0.011877 +0.011829 +0.011819 +0.011861 +0.011969 +0.01197 +0.012021 +0.011968 +0.011946 +0.011999 +0.012117 +0.01211 +0.01216 +0.012108 +0.012086 +0.012144 +0.012254 +0.012229 +0.012288 +0.012238 +0.012217 +0.012281 +0.012399 +0.012381 +0.012431 +0.012383 +0.01237 +0.012432 +0.012552 +0.01252 +0.012569 +0.01251 +0.012499 +0.01255 +0.012671 +0.012631 +0.012678 +0.012628 +0.012614 +0.012675 +0.012798 +0.012772 +0.012828 +0.012778 +0.012775 +0.012838 +0.012965 +0.012941 +0.012991 +0.012941 +0.012925 +0.012989 +0.013117 +0.01309 +0.013138 +0.013084 +0.013064 +0.013132 +0.013255 +0.013225 +0.013275 +0.013217 +0.013203 +0.013271 +0.013401 +0.01337 +0.013423 +0.013369 +0.013362 +0.013417 +0.013549 +0.013527 +0.013578 +0.013521 +0.013507 +0.013575 +0.013706 +0.013678 +0.013729 +0.013673 +0.013658 +0.013733 +0.013862 +0.013832 +0.013888 +0.013835 +0.013823 +0.013892 +0.014026 +0.013994 +0.014051 +0.013992 +0.013977 +0.014051 +0.014183 +0.014152 +0.014202 +0.014148 +0.01413 +0.01421 +0.014336 +0.014307 +0.014361 +0.014303 +0.014289 +0.014367 +0.0145 +0.014479 +0.014531 +0.014477 +0.014461 +0.01454 +0.014686 +0.014655 +0.014714 +0.014656 +0.014646 +0.014729 +0.014872 +0.014836 +0.014903 +0.014849 +0.014837 +0.014915 +0.015065 +0.015022 +0.015094 +0.015029 +0.015017 +0.015102 +0.015247 +0.015201 +0.015268 +0.015211 +0.015188 +0.015274 +0.015423 +0.015383 +0.015445 +0.01539 +0.015372 +0.015467 +0.015608 +0.015574 +0.015638 +0.015584 +0.015565 +0.015661 +0.015812 +0.015777 +0.015843 +0.015788 +0.015775 +0.015867 +0.016022 +0.015989 +0.016054 +0.015998 +0.015988 +0.016081 +0.016239 +0.016195 +0.016264 +0.016202 +0.01619 +0.016277 +0.016442 +0.01639 +0.01646 +0.016397 +0.01639 +0.016476 +0.016642 +0.0166 +0.01668 +0.016616 +0.016603 +0.0167 +0.016864 +0.016833 +0.016907 +0.016838 +0.016829 +0.016923 +0.017089 +0.01705 +0.017118 +0.017058 +0.017039 +0.017135 +0.017292 +0.017253 +0.017332 +0.01727 +0.017257 +0.017355 +0.017517 +0.017493 +0.017574 +0.017501 +0.017487 +0.017579 +0.017751 +0.017748 +0.017832 +0.017763 +0.017744 +0.017839 +0.018005 +0.017979 +0.018053 +0.017983 +0.017989 +0.018087 +0.018266 +0.018264 +0.018323 +0.01826 +0.018267 +0.018352 +0.018542 +0.018547 +0.018619 +0.018543 +0.018526 +0.018648 +0.018834 +0.018816 +0.018926 +0.018876 +0.018892 +0.018994 +0.019073 +0.01874 +0.018143 +0.01782 +0.017412 +0.017002 +0.016884 +0.016476 +0.016068 +0.01569 +0.015278 +0.015004 +0.01487 +0.014561 +0.014225 +0.013978 +0.01363 +0.013476 +0.013425 +0.013198 +0.012968 +0.012785 +0.012607 +0.012461 +0.012469 +0.012364 +0.012319 +0.012171 +0.012034 +0.012012 +0.012078 +0.012026 +0.012058 +0.012002 +0.011991 +0.012031 +0.012105 +0.01205 +0.012117 +0.012086 +0.01208 +0.01214 +0.012256 +0.01223 +0.012287 +0.012243 +0.01222 +0.001383 +0.012278 +0.012389 +0.012371 +0.012397 +0.012363 +0.012347 +0.012451 +0.012563 +0.012534 +0.012579 +0.012534 +0.012518 +0.012596 +0.012697 +0.012648 +0.012621 +0.012464 +0.012334 +0.012294 +0.012258 +0.012123 +0.012025 +0.011851 +0.011717 +0.011669 +0.011677 +0.011553 +0.011495 +0.011332 +0.011214 +0.011181 +0.011182 +0.011081 +0.011029 +0.010893 +0.010792 +0.010777 +0.010787 +0.010707 +0.010672 +0.010557 +0.010468 +0.01047 +0.010499 +0.010429 +0.010422 +0.010336 +0.010258 +0.010298 +0.010353 +0.010315 +0.010339 +0.010288 +0.010261 +0.010327 +0.010409 +0.01041 +0.010422 +0.010396 +0.010376 +0.010436 +0.010539 +0.010518 +0.010546 +0.010504 +0.010469 +0.001384 +0.010541 +0.010634 +0.010637 +0.010669 +0.010628 +0.010593 +0.010669 +0.010755 +0.010749 +0.010784 +0.010757 +0.010734 +0.010814 +0.010894 +0.010897 +0.010894 +0.010792 +0.010731 +0.010764 +0.010771 +0.010684 +0.010552 +0.010419 +0.010316 +0.010238 +0.010209 +0.010103 +0.010059 +0.00989 +0.009777 +0.009732 +0.009748 +0.009648 +0.009642 +0.009506 +0.009398 +0.009393 +0.009407 +0.009355 +0.009329 +0.009279 +0.009201 +0.00916 +0.009176 +0.009131 +0.009125 +0.009079 +0.009034 +0.009062 +0.009132 +0.009038 +0.009024 +0.008992 +0.008946 +0.008992 +0.009041 +0.009015 +0.009052 +0.009036 +0.009001 +0.009062 +0.009136 +0.009128 +0.009154 +0.009127 +0.009106 +0.009178 +0.009229 +0.009227 +0.009259 +0.001385 +0.009221 +0.009202 +0.009248 +0.009327 +0.009308 +0.009318 +0.009293 +0.009273 +0.00932 +0.009419 +0.009419 +0.009451 +0.009408 +0.00938 +0.00944 +0.009521 +0.009509 +0.009534 +0.009468 +0.009414 +0.009413 +0.009434 +0.009362 +0.009325 +0.009212 +0.009135 +0.009094 +0.009108 +0.009039 +0.009005 +0.008898 +0.008823 +0.008815 +0.00883 +0.008772 +0.008748 +0.008668 +0.008591 +0.008605 +0.008637 +0.008588 +0.008584 +0.008521 +0.008456 +0.008478 +0.008527 +0.008486 +0.0085 +0.008438 +0.008402 +0.008431 +0.008486 +0.008464 +0.00848 +0.00844 +0.008421 +0.008468 +0.008537 +0.00853 +0.008551 +0.008524 +0.008498 +0.008546 +0.008621 +0.008616 +0.008638 +0.008602 +0.008583 +0.008634 +0.001386 +0.008708 +0.008701 +0.008719 +0.008705 +0.00866 +0.008723 +0.008793 +0.00879 +0.008804 +0.008774 +0.008753 +0.008805 +0.008871 +0.008876 +0.008893 +0.008877 +0.008847 +0.008909 +0.00898 +0.008974 +0.008998 +0.008986 +0.008962 +0.009008 +0.008992 +0.00891 +0.008878 +0.008811 +0.008683 +0.008664 +0.008682 +0.008617 +0.008584 +0.008478 +0.008398 +0.008378 +0.008405 +0.008367 +0.008324 +0.008232 +0.008177 +0.008162 +0.008196 +0.008135 +0.008148 +0.0081 +0.008062 +0.008051 +0.008064 +0.008031 +0.008027 +0.008003 +0.007964 +0.008004 +0.008065 +0.008035 +0.008042 +0.008014 +0.007955 +0.007991 +0.008062 +0.008045 +0.008057 +0.00805 +0.008027 +0.008073 +0.00814 +0.008139 +0.008156 +0.008139 +0.008117 +0.008159 +0.008223 +0.008223 +0.001387 +0.008238 +0.008219 +0.008194 +0.008249 +0.008313 +0.008304 +0.008316 +0.008291 +0.00826 +0.008312 +0.008376 +0.00836 +0.008373 +0.008351 +0.008322 +0.008376 +0.008452 +0.008471 +0.008484 +0.008458 +0.008429 +0.00848 +0.008531 +0.008526 +0.008531 +0.008479 +0.008417 +0.008417 +0.008421 +0.008386 +0.00835 +0.008268 +0.008205 +0.008197 +0.008215 +0.008174 +0.008142 +0.008082 +0.008025 +0.008036 +0.008069 +0.00804 +0.008021 +0.007968 +0.007924 +0.007942 +0.007985 +0.007975 +0.007969 +0.007929 +0.007893 +0.007918 +0.007968 +0.007972 +0.007979 +0.007947 +0.007923 +0.007962 +0.008024 +0.008018 +0.008027 +0.00801 +0.00799 +0.008042 +0.008103 +0.008094 +0.00812 +0.008085 +0.00806 +0.001388 +0.008119 +0.008189 +0.008176 +0.00819 +0.008165 +0.008139 +0.008185 +0.00826 +0.008264 +0.00827 +0.008251 +0.008225 +0.00827 +0.008338 +0.008333 +0.008351 +0.008327 +0.008295 +0.008357 +0.008416 +0.008418 +0.008441 +0.00842 +0.008397 +0.008455 +0.008535 +0.008521 +0.008538 +0.008447 +0.008363 +0.008381 +0.008425 +0.008373 +0.008313 +0.008233 +0.008164 +0.008159 +0.008179 +0.008133 +0.00812 +0.008033 +0.007969 +0.007962 +0.007999 +0.007978 +0.007957 +0.007929 +0.007871 +0.007875 +0.007903 +0.007882 +0.007886 +0.007866 +0.00782 +0.007875 +0.007922 +0.007916 +0.007918 +0.0079 +0.007876 +0.007902 +0.007952 +0.007924 +0.007955 +0.007935 +0.00791 +0.007971 +0.00803 +0.008018 +0.008035 +0.008023 +0.007995 +0.008056 +0.001389 +0.008114 +0.008091 +0.008125 +0.008093 +0.008075 +0.008126 +0.008201 +0.008183 +0.008206 +0.008177 +0.00816 +0.008205 +0.008275 +0.008245 +0.008265 +0.008229 +0.008207 +0.008254 +0.008324 +0.008303 +0.008318 +0.008293 +0.00828 +0.008327 +0.008431 +0.008418 +0.008445 +0.008399 +0.008358 +0.008378 +0.008419 +0.008366 +0.008363 +0.008278 +0.008206 +0.00821 +0.008238 +0.008184 +0.008169 +0.008096 +0.008036 +0.008049 +0.008086 +0.008045 +0.008039 +0.007975 +0.007925 +0.007946 +0.007985 +0.007949 +0.007958 +0.007903 +0.007866 +0.007892 +0.007943 +0.007916 +0.007931 +0.007885 +0.007856 +0.007891 +0.007955 +0.007932 +0.007957 +0.007921 +0.007903 +0.007948 +0.008012 +0.008 +0.008033 +0.007991 +0.007986 +0.00801 +0.008091 +0.008086 +0.00139 +0.0081 +0.00808 +0.008051 +0.008097 +0.008168 +0.008168 +0.00818 +0.008158 +0.008132 +0.008181 +0.008246 +0.008242 +0.008265 +0.008236 +0.008214 +0.008267 +0.008328 +0.008319 +0.008341 +0.008316 +0.008289 +0.008349 +0.008415 +0.008416 +0.008434 +0.00841 +0.00839 +0.008457 +0.008534 +0.008503 +0.008434 +0.008393 +0.008327 +0.008362 +0.008399 +0.008348 +0.008286 +0.0082 +0.008139 +0.008154 +0.008175 +0.008134 +0.008112 +0.008041 +0.007975 +0.007983 +0.008014 +0.007988 +0.007978 +0.007942 +0.007901 +0.007926 +0.007952 +0.007919 +0.007931 +0.0079 +0.007875 +0.007902 +0.007938 +0.007925 +0.007926 +0.007918 +0.007894 +0.007951 +0.008019 +0.007997 +0.008015 +0.008003 +0.007974 +0.008026 +0.008099 +0.008098 +0.008093 +0.001391 +0.008078 +0.008058 +0.008079 +0.008132 +0.00811 +0.008148 +0.008113 +0.008104 +0.008147 +0.008221 +0.008209 +0.008231 +0.008207 +0.008193 +0.008222 +0.008301 +0.008299 +0.008331 +0.008302 +0.008283 +0.008318 +0.008397 +0.008381 +0.008399 +0.008365 +0.008363 +0.008402 +0.008482 +0.008461 +0.008476 +0.008438 +0.008394 +0.008397 +0.008437 +0.008384 +0.008358 +0.008281 +0.008225 +0.008216 +0.00826 +0.008186 +0.00818 +0.00812 +0.008064 +0.008068 +0.008123 +0.008074 +0.00807 +0.008014 +0.007966 +0.007977 +0.008033 +0.008009 +0.008007 +0.007965 +0.007926 +0.007941 +0.008006 +0.007982 +0.007999 +0.007963 +0.007931 +0.007957 +0.008028 +0.008003 +0.008032 +0.008012 +0.007989 +0.008026 +0.008102 +0.008078 +0.008109 +0.008085 +0.008064 +0.008101 +0.008184 +0.001392 +0.008159 +0.008188 +0.008153 +0.008146 +0.008184 +0.008262 +0.00824 +0.008278 +0.008224 +0.008226 +0.008253 +0.008337 +0.008322 +0.008356 +0.008311 +0.008301 +0.008336 +0.00842 +0.008395 +0.008436 +0.008392 +0.00839 +0.008433 +0.008516 +0.008497 +0.008535 +0.008501 +0.008496 +0.00853 +0.008535 +0.008452 +0.008455 +0.008396 +0.008326 +0.00827 +0.008306 +0.008235 +0.008237 +0.008173 +0.008099 +0.008061 +0.008119 +0.008059 +0.008071 +0.008029 +0.007959 +0.007941 +0.007988 +0.007943 +0.007963 +0.007924 +0.007896 +0.007934 +0.007993 +0.007965 +0.007979 +0.007948 +0.007925 +0.007924 +0.007992 +0.007948 +0.007996 +0.007958 +0.007943 +0.007992 +0.008062 +0.008032 +0.008071 +0.00804 +0.008032 +0.008073 +0.008166 +0.008119 +0.008159 +0.001393 +0.008126 +0.008109 +0.008159 +0.008244 +0.008203 +0.00823 +0.008183 +0.008165 +0.00821 +0.00828 +0.008251 +0.008275 +0.008244 +0.008224 +0.008272 +0.008347 +0.008324 +0.008348 +0.008338 +0.008342 +0.008388 +0.008459 +0.008449 +0.008463 +0.008428 +0.008402 +0.008418 +0.008473 +0.00843 +0.00842 +0.008345 +0.008278 +0.008266 +0.00831 +0.008254 +0.008226 +0.008157 +0.00811 +0.008101 +0.008143 +0.008119 +0.008094 +0.008042 +0.007999 +0.008002 +0.008053 +0.008021 +0.00803 +0.007976 +0.007948 +0.007964 +0.008027 +0.008003 +0.008007 +0.007973 +0.007953 +0.007982 +0.008047 +0.008036 +0.008043 +0.008027 +0.008007 +0.008043 +0.00812 +0.008102 +0.008134 +0.008098 +0.008085 +0.008117 +0.008199 +0.001394 +0.008176 +0.008216 +0.008172 +0.008165 +0.008202 +0.008281 +0.008258 +0.008294 +0.008252 +0.008246 +0.00828 +0.00836 +0.008339 +0.008376 +0.008338 +0.008327 +0.008361 +0.008444 +0.008427 +0.008452 +0.008412 +0.008409 +0.008443 +0.008536 +0.008509 +0.008551 +0.008522 +0.008498 +0.008556 +0.008647 +0.008601 +0.008558 +0.008483 +0.008445 +0.008461 +0.008509 +0.008435 +0.008404 +0.008276 +0.008227 +0.008227 +0.008265 +0.00819 +0.008188 +0.008084 +0.008039 +0.008021 +0.008082 +0.008028 +0.008019 +0.007982 +0.007912 +0.007914 +0.007962 +0.007921 +0.007938 +0.0079 +0.00788 +0.007905 +0.007984 +0.007929 +0.007966 +0.007924 +0.007902 +0.007911 +0.00796 +0.007928 +0.007973 +0.007936 +0.007925 +0.007966 +0.008053 +0.008028 +0.008063 +0.00803 +0.008024 +0.00806 +0.008153 +0.008107 +0.001395 +0.008142 +0.008117 +0.008102 +0.008148 +0.008227 +0.008212 +0.008236 +0.008202 +0.008188 +0.00823 +0.008306 +0.00828 +0.008304 +0.008271 +0.008254 +0.008294 +0.008365 +0.008327 +0.008346 +0.008318 +0.008303 +0.008338 +0.008413 +0.008404 +0.008432 +0.008435 +0.008414 +0.008442 +0.008497 +0.00844 +0.008415 +0.008341 +0.008276 +0.008275 +0.008307 +0.008242 +0.008221 +0.008154 +0.008095 +0.008084 +0.008125 +0.008085 +0.008072 +0.008012 +0.007965 +0.007967 +0.008012 +0.007984 +0.007971 +0.00793 +0.007897 +0.007911 +0.00797 +0.00794 +0.007961 +0.007913 +0.007894 +0.007917 +0.007985 +0.007965 +0.007981 +0.007962 +0.007945 +0.007982 +0.00806 +0.008038 +0.008069 +0.008029 +0.008004 +0.008044 +0.008121 +0.001396 +0.008103 +0.008147 +0.008106 +0.008099 +0.008134 +0.008206 +0.008188 +0.008215 +0.008183 +0.008171 +0.00821 +0.008292 +0.00827 +0.008299 +0.008265 +0.008249 +0.008285 +0.008365 +0.008341 +0.008382 +0.008338 +0.008327 +0.00836 +0.008443 +0.008433 +0.008463 +0.008431 +0.00842 +0.008461 +0.008551 +0.008531 +0.008571 +0.008535 +0.00849 +0.008425 +0.008468 +0.008396 +0.008403 +0.008332 +0.008289 +0.008276 +0.008247 +0.008174 +0.008176 +0.008106 +0.008084 +0.008084 +0.008107 +0.008053 +0.008054 +0.007993 +0.007963 +0.007947 +0.008013 +0.007972 +0.007988 +0.007956 +0.007925 +0.007969 +0.008027 +0.007998 +0.008021 +0.007967 +0.00795 +0.00796 +0.00803 +0.008008 +0.008039 +0.008003 +0.008002 +0.008037 +0.008115 +0.008093 +0.008133 +0.008097 +0.008099 +0.00811 +0.008202 +0.001397 +0.00819 +0.008211 +0.008185 +0.008166 +0.008213 +0.008287 +0.008272 +0.008295 +0.008267 +0.008252 +0.008301 +0.008381 +0.00834 +0.008362 +0.008329 +0.008307 +0.008348 +0.008416 +0.008396 +0.008415 +0.008384 +0.00836 +0.008407 +0.008478 +0.008503 +0.008538 +0.008504 +0.008472 +0.00848 +0.00853 +0.008456 +0.008426 +0.008357 +0.008313 +0.008292 +0.008321 +0.008271 +0.008255 +0.008187 +0.008135 +0.008137 +0.008185 +0.008154 +0.008152 +0.008097 +0.008056 +0.008067 +0.008115 +0.008094 +0.008098 +0.008061 +0.008033 +0.008051 +0.008107 +0.008093 +0.008099 +0.008073 +0.00806 +0.008089 +0.008155 +0.008139 +0.008157 +0.008128 +0.008117 +0.008157 +0.008239 +0.00822 +0.008245 +0.008205 +0.008184 +0.001398 +0.008234 +0.008307 +0.008303 +0.008313 +0.008297 +0.008276 +0.008323 +0.008387 +0.00838 +0.008396 +0.00837 +0.00835 +0.008401 +0.00847 +0.008466 +0.008479 +0.008456 +0.008425 +0.008485 +0.008548 +0.008543 +0.008564 +0.008535 +0.00852 +0.008567 +0.008649 +0.008639 +0.008659 +0.008647 +0.008627 +0.008689 +0.008748 +0.008631 +0.008606 +0.008552 +0.008472 +0.008445 +0.008451 +0.008387 +0.008376 +0.008294 +0.008209 +0.008214 +0.008264 +0.008209 +0.00821 +0.008137 +0.008061 +0.008094 +0.008115 +0.0081 +0.008082 +0.008067 +0.008025 +0.008074 +0.00813 +0.008095 +0.008072 +0.008031 +0.008017 +0.00806 +0.008118 +0.00811 +0.008114 +0.008111 +0.008085 +0.008137 +0.008207 +0.008188 +0.008197 +0.008196 +0.00814 +0.008172 +0.008242 +0.001399 +0.008228 +0.008257 +0.008229 +0.00821 +0.008259 +0.008334 +0.00832 +0.00835 +0.008321 +0.00831 +0.008344 +0.008429 +0.008405 +0.008432 +0.008401 +0.008382 +0.008425 +0.008499 +0.008474 +0.008498 +0.008463 +0.008451 +0.008477 +0.008565 +0.008559 +0.008603 +0.008575 +0.008557 +0.00859 +0.008673 +0.00865 +0.008659 +0.008611 +0.008574 +0.008567 +0.008584 +0.008521 +0.008489 +0.008405 +0.008334 +0.008316 +0.008346 +0.00829 +0.00827 +0.008205 +0.00815 +0.008155 +0.008183 +0.00815 +0.00814 +0.00809 +0.008051 +0.008055 +0.008117 +0.008087 +0.008093 +0.008051 +0.00802 +0.008044 +0.008106 +0.008087 +0.008097 +0.008068 +0.008042 +0.008078 +0.008151 +0.00814 +0.008159 +0.008136 +0.008112 +0.008159 +0.008225 +0.008209 +0.008243 +0.008211 +0.0014 +0.00819 +0.008242 +0.008302 +0.008304 +0.008313 +0.008291 +0.008265 +0.008317 +0.008391 +0.008377 +0.008396 +0.008377 +0.008352 +0.008406 +0.008473 +0.008464 +0.008478 +0.008456 +0.008434 +0.008478 +0.00855 +0.008548 +0.008561 +0.008544 +0.008516 +0.008579 +0.00865 +0.008645 +0.00866 +0.008651 +0.008636 +0.008639 +0.008635 +0.008583 +0.00856 +0.008506 +0.008438 +0.00846 +0.008432 +0.008315 +0.008285 +0.008238 +0.008167 +0.008137 +0.00817 +0.008118 +0.008116 +0.00806 +0.007968 +0.007985 +0.008 +0.007978 +0.007968 +0.007936 +0.007895 +0.007933 +0.007989 +0.007937 +0.007911 +0.00787 +0.007844 +0.007894 +0.00794 +0.007933 +0.007944 +0.007916 +0.007903 +0.007953 +0.007994 +0.007979 +0.008003 +0.007979 +0.007974 +0.008007 +0.008077 +0.008061 +0.008074 +0.001401 +0.008056 +0.008039 +0.00807 +0.008131 +0.008111 +0.008132 +0.008114 +0.008092 +0.008153 +0.008218 +0.008203 +0.008222 +0.008199 +0.008173 +0.008226 +0.00829 +0.008273 +0.00829 +0.008271 +0.008233 +0.008289 +0.008354 +0.008364 +0.008396 +0.008376 +0.008341 +0.008394 +0.008456 +0.008452 +0.008457 +0.008434 +0.008401 +0.00842 +0.008457 +0.008401 +0.008367 +0.0083 +0.008216 +0.008208 +0.008224 +0.008174 +0.008142 +0.008088 +0.008017 +0.00802 +0.008059 +0.008019 +0.008005 +0.007955 +0.007901 +0.007917 +0.007962 +0.007938 +0.007939 +0.007906 +0.007867 +0.007894 +0.00795 +0.00793 +0.007936 +0.007919 +0.007887 +0.007922 +0.007987 +0.007978 +0.007989 +0.007976 +0.00795 +0.007999 +0.008068 +0.008052 +0.00808 +0.008034 +0.008024 +0.001402 +0.008067 +0.008139 +0.008134 +0.008143 +0.008131 +0.008108 +0.008156 +0.008218 +0.00821 +0.008226 +0.008202 +0.008178 +0.008231 +0.008299 +0.008296 +0.008305 +0.008284 +0.008258 +0.008312 +0.00838 +0.008371 +0.008386 +0.008368 +0.008336 +0.0084 +0.008461 +0.008467 +0.008479 +0.00846 +0.008444 +0.008509 +0.008579 +0.008544 +0.008463 +0.008402 +0.008347 +0.008368 +0.008404 +0.008346 +0.008246 +0.008165 +0.008113 +0.008145 +0.00817 +0.008113 +0.008116 +0.00801 +0.007966 +0.007988 +0.008022 +0.007993 +0.007973 +0.007957 +0.007903 +0.007934 +0.007945 +0.007935 +0.007933 +0.007915 +0.007881 +0.007926 +0.007979 +0.00795 +0.007971 +0.007946 +0.00791 +0.007931 +0.007977 +0.007954 +0.007988 +0.00797 +0.007943 +0.008 +0.008065 +0.008062 +0.008077 +0.008062 +0.008038 +0.008102 +0.008147 +0.001403 +0.008144 +0.008169 +0.008142 +0.008125 +0.00817 +0.008246 +0.008232 +0.008257 +0.008227 +0.008205 +0.008248 +0.008321 +0.008296 +0.00832 +0.008287 +0.008271 +0.008297 +0.008375 +0.008348 +0.008375 +0.008346 +0.008332 +0.008389 +0.008479 +0.008462 +0.008488 +0.008439 +0.008411 +0.008421 +0.008471 +0.008411 +0.008397 +0.008312 +0.008253 +0.008253 +0.008271 +0.008219 +0.008212 +0.008137 +0.008079 +0.008102 +0.008137 +0.008101 +0.008097 +0.008038 +0.007999 +0.008018 +0.008065 +0.008028 +0.008041 +0.007993 +0.007953 +0.007998 +0.008043 +0.00803 +0.008049 +0.008009 +0.007987 +0.008034 +0.008103 +0.008085 +0.008113 +0.00808 +0.008059 +0.008108 +0.008176 +0.008174 +0.008185 +0.008152 +0.001404 +0.008147 +0.008182 +0.008272 +0.00823 +0.008273 +0.008235 +0.008227 +0.008261 +0.008343 +0.008323 +0.008355 +0.008314 +0.008307 +0.008343 +0.008425 +0.008405 +0.008433 +0.008395 +0.008384 +0.008421 +0.008498 +0.00849 +0.008517 +0.008484 +0.008469 +0.00852 +0.008605 +0.008579 +0.008619 +0.008581 +0.00857 +0.008587 +0.008572 +0.008497 +0.008492 +0.008406 +0.008348 +0.008319 +0.008355 +0.008297 +0.008298 +0.008229 +0.008187 +0.008179 +0.008197 +0.008133 +0.008152 +0.008087 +0.008069 +0.008054 +0.008104 +0.008052 +0.008072 +0.008022 +0.008014 +0.008023 +0.008088 +0.008039 +0.008073 +0.008012 +0.008014 +0.00805 +0.008115 +0.008091 +0.008111 +0.008055 +0.008067 +0.008087 +0.008161 +0.008139 +0.008168 +0.008131 +0.008135 +0.00819 +0.008225 +0.001405 +0.008218 +0.008257 +0.008217 +0.008212 +0.008249 +0.008331 +0.008305 +0.008343 +0.008304 +0.008298 +0.008338 +0.008419 +0.008384 +0.008413 +0.008372 +0.00836 +0.008393 +0.008464 +0.008436 +0.008465 +0.008431 +0.008415 +0.008447 +0.008538 +0.008534 +0.008588 +0.008551 +0.008533 +0.008554 +0.008613 +0.008566 +0.008554 +0.008471 +0.008443 +0.008419 +0.008459 +0.008404 +0.008397 +0.008321 +0.00828 +0.008264 +0.008315 +0.008276 +0.008279 +0.008211 +0.008182 +0.008166 +0.00823 +0.008191 +0.008205 +0.008144 +0.008124 +0.008129 +0.008197 +0.008168 +0.008191 +0.00814 +0.008129 +0.008139 +0.008211 +0.008197 +0.008233 +0.008187 +0.008186 +0.008212 +0.008291 +0.008269 +0.008295 +0.008267 +0.00824 +0.008287 +0.008374 +0.001406 +0.008355 +0.008381 +0.008341 +0.008327 +0.00837 +0.008449 +0.008431 +0.008467 +0.00843 +0.008417 +0.008456 +0.008534 +0.008515 +0.008547 +0.008505 +0.008501 +0.008533 +0.008615 +0.008602 +0.008633 +0.008601 +0.008589 +0.008642 +0.008728 +0.008701 +0.008744 +0.008715 +0.008675 +0.008618 +0.008676 +0.008618 +0.008622 +0.008554 +0.008513 +0.008527 +0.008565 +0.008435 +0.008431 +0.008353 +0.008321 +0.008328 +0.008352 +0.008302 +0.00831 +0.008253 +0.008219 +0.008201 +0.008257 +0.008209 +0.008227 +0.008192 +0.008163 +0.008205 +0.008274 +0.008233 +0.008269 +0.008224 +0.008207 +0.008245 +0.008287 +0.008263 +0.008281 +0.008263 +0.008249 +0.008287 +0.008374 +0.008357 +0.008359 +0.008348 +0.008338 +0.008378 +0.001407 +0.008469 +0.008432 +0.00846 +0.008434 +0.008429 +0.008443 +0.008516 +0.008469 +0.008514 +0.00848 +0.00847 +0.008521 +0.008597 +0.008562 +0.008599 +0.008562 +0.008548 +0.008591 +0.008695 +0.008685 +0.008716 +0.008668 +0.008658 +0.008684 +0.008779 +0.008754 +0.008764 +0.00869 +0.008637 +0.008624 +0.008652 +0.008591 +0.008573 +0.008488 +0.008437 +0.008428 +0.008477 +0.008423 +0.008424 +0.008361 +0.008326 +0.008326 +0.008386 +0.008347 +0.008353 +0.008298 +0.008265 +0.008273 +0.00834 +0.008311 +0.008326 +0.008277 +0.008256 +0.008265 +0.008344 +0.008319 +0.008344 +0.008307 +0.008295 +0.008319 +0.008417 +0.008373 +0.008417 +0.008387 +0.008374 +0.008406 +0.00848 +0.008472 +0.001408 +0.008498 +0.008478 +0.008441 +0.008491 +0.008563 +0.008557 +0.008585 +0.008551 +0.008534 +0.008575 +0.008655 +0.008636 +0.008666 +0.008635 +0.008611 +0.008658 +0.008749 +0.008721 +0.008761 +0.008733 +0.008719 +0.008767 +0.008854 +0.008842 +0.008866 +0.008849 +0.008782 +0.008741 +0.008786 +0.008728 +0.008716 +0.008649 +0.008602 +0.0086 +0.008569 +0.008485 +0.008464 +0.008413 +0.008364 +0.008329 +0.008351 +0.0083 +0.008299 +0.008253 +0.008205 +0.008213 +0.008238 +0.008186 +0.008203 +0.008149 +0.00814 +0.00816 +0.008209 +0.008176 +0.008183 +0.008139 +0.008132 +0.00814 +0.008211 +0.00818 +0.008202 +0.00818 +0.008172 +0.008209 +0.008286 +0.008268 +0.008292 +0.008262 +0.008258 +0.008309 +0.008389 +0.008345 +0.001409 +0.008384 +0.008363 +0.008338 +0.008393 +0.008461 +0.008448 +0.008453 +0.00842 +0.008393 +0.008451 +0.008513 +0.008494 +0.008508 +0.008484 +0.008453 +0.008505 +0.008571 +0.008568 +0.008581 +0.008576 +0.00857 +0.00863 +0.008694 +0.008688 +0.008694 +0.008662 +0.008621 +0.008633 +0.008676 +0.008629 +0.008576 +0.008503 +0.008432 +0.008425 +0.008445 +0.008406 +0.008372 +0.008313 +0.008257 +0.008268 +0.008306 +0.008284 +0.008253 +0.00821 +0.008162 +0.008182 +0.00823 +0.008203 +0.008198 +0.008159 +0.008124 +0.008149 +0.008204 +0.008189 +0.008188 +0.008153 +0.008124 +0.008166 +0.008227 +0.008224 +0.008227 +0.008211 +0.008183 +0.008233 +0.008303 +0.008297 +0.008316 +0.008289 +0.008269 +0.008304 +0.00141 +0.008387 +0.008384 +0.00839 +0.008368 +0.008347 +0.008392 +0.00847 +0.00846 +0.008483 +0.008453 +0.00843 +0.008476 +0.008554 +0.008539 +0.008561 +0.008525 +0.008514 +0.008558 +0.00863 +0.008625 +0.008654 +0.008628 +0.008614 +0.00866 +0.008745 +0.00874 +0.008753 +0.008732 +0.008642 +0.00861 +0.008648 +0.008585 +0.008576 +0.008492 +0.00841 +0.008325 +0.008368 +0.008312 +0.00829 +0.008229 +0.008198 +0.008189 +0.008185 +0.008144 +0.00813 +0.008074 +0.008014 +0.008017 +0.008061 +0.008011 +0.00803 +0.007983 +0.007959 +0.008 +0.008055 +0.008027 +0.008001 +0.007964 +0.007931 +0.007975 +0.008055 +0.008018 +0.008049 +0.00802 +0.008001 +0.008022 +0.008093 +0.008064 +0.008088 +0.008071 +0.008067 +0.008101 +0.008189 +0.008149 +0.008173 +0.001411 +0.008165 +0.008136 +0.008192 +0.008263 +0.008249 +0.008269 +0.008251 +0.008222 +0.008279 +0.008345 +0.008324 +0.00834 +0.008315 +0.008285 +0.00833 +0.008395 +0.008377 +0.008393 +0.008376 +0.00835 +0.008391 +0.008491 +0.008497 +0.008519 +0.008485 +0.00844 +0.008472 +0.0085 +0.008455 +0.008437 +0.008364 +0.008286 +0.008292 +0.008292 +0.008252 +0.008226 +0.008157 +0.008086 +0.008099 +0.008125 +0.008094 +0.008085 +0.008033 +0.007982 +0.008024 +0.008046 +0.008032 +0.008037 +0.007996 +0.007956 +0.007998 +0.008042 +0.008026 +0.008037 +0.008 +0.007967 +0.008016 +0.008069 +0.008059 +0.008088 +0.008055 +0.008033 +0.008079 +0.008142 +0.008138 +0.00816 +0.008122 +0.008109 +0.008165 +0.001412 +0.008222 +0.008229 +0.008226 +0.008208 +0.008183 +0.008237 +0.008302 +0.008298 +0.008317 +0.008297 +0.008268 +0.008316 +0.008384 +0.008378 +0.008393 +0.008374 +0.008345 +0.008396 +0.008464 +0.008464 +0.008476 +0.00846 +0.008432 +0.008503 +0.008567 +0.008563 +0.008583 +0.008569 +0.008548 +0.008598 +0.008578 +0.008527 +0.008494 +0.008457 +0.008392 +0.008382 +0.008356 +0.00829 +0.008262 +0.008234 +0.008164 +0.008155 +0.008183 +0.008124 +0.008105 +0.008056 +0.007984 +0.007999 +0.008021 +0.00799 +0.00798 +0.007953 +0.007902 +0.007958 +0.008001 +0.007973 +0.007946 +0.007898 +0.007885 +0.007922 +0.007982 +0.007967 +0.007969 +0.007958 +0.007931 +0.007981 +0.008049 +0.008036 +0.008027 +0.008005 +0.00798 +0.008037 +0.008095 +0.008084 +0.00811 +0.008098 +0.001413 +0.008076 +0.008101 +0.008181 +0.008175 +0.00819 +0.008172 +0.00815 +0.008205 +0.008269 +0.008253 +0.008266 +0.008249 +0.008217 +0.008255 +0.008312 +0.008289 +0.008304 +0.008286 +0.008258 +0.008309 +0.008384 +0.008401 +0.008435 +0.008419 +0.008391 +0.008428 +0.008493 +0.008483 +0.008476 +0.008418 +0.008359 +0.008362 +0.008384 +0.008338 +0.008298 +0.008217 +0.008156 +0.008155 +0.00816 +0.008128 +0.008105 +0.008037 +0.007987 +0.008001 +0.008025 +0.008 +0.007987 +0.007935 +0.007889 +0.007916 +0.007943 +0.007944 +0.007941 +0.007906 +0.007874 +0.007901 +0.007949 +0.007938 +0.007934 +0.007914 +0.007897 +0.007938 +0.007996 +0.00799 +0.008 +0.007972 +0.007947 +0.007995 +0.008058 +0.00805 +0.008075 +0.008065 +0.00803 +0.001414 +0.008073 +0.008149 +0.008129 +0.008155 +0.00812 +0.0081 +0.008142 +0.00822 +0.008209 +0.008235 +0.008204 +0.008186 +0.008229 +0.0083 +0.008291 +0.008314 +0.008274 +0.008259 +0.008312 +0.008389 +0.008367 +0.008397 +0.008373 +0.008354 +0.008408 +0.008492 +0.008479 +0.008507 +0.008462 +0.008355 +0.008358 +0.008394 +0.008346 +0.008343 +0.008289 +0.008186 +0.008152 +0.008182 +0.008125 +0.008133 +0.008072 +0.008018 +0.008057 +0.008029 +0.007971 +0.007975 +0.007918 +0.007889 +0.007862 +0.007917 +0.007861 +0.007884 +0.007842 +0.007823 +0.007857 +0.007911 +0.007888 +0.00789 +0.007863 +0.007833 +0.007831 +0.007884 +0.007854 +0.007871 +0.007861 +0.007837 +0.007879 +0.007957 +0.007934 +0.007959 +0.007937 +0.007923 +0.007962 +0.008036 +0.008038 +0.008032 +0.008014 +0.001415 +0.008003 +0.008047 +0.008121 +0.008103 +0.008138 +0.008102 +0.008093 +0.00813 +0.008211 +0.008179 +0.008209 +0.008168 +0.008156 +0.008178 +0.008246 +0.008212 +0.008244 +0.008207 +0.008194 +0.008226 +0.008315 +0.00831 +0.008365 +0.008329 +0.008318 +0.008328 +0.008396 +0.008332 +0.008321 +0.008253 +0.008205 +0.008172 +0.008205 +0.008143 +0.008127 +0.008048 +0.007999 +0.007978 +0.008019 +0.00796 +0.007965 +0.007893 +0.007855 +0.007853 +0.0079 +0.007852 +0.007855 +0.007802 +0.007775 +0.007778 +0.007844 +0.007811 +0.007826 +0.007776 +0.007754 +0.007768 +0.007838 +0.007816 +0.007842 +0.007804 +0.007793 +0.007812 +0.007892 +0.007871 +0.007901 +0.007871 +0.007859 +0.007896 +0.007967 +0.007959 +0.00797 +0.001416 +0.007939 +0.007933 +0.007965 +0.008052 +0.008029 +0.008054 +0.008013 +0.008004 +0.008041 +0.008121 +0.008103 +0.00813 +0.008098 +0.008088 +0.008124 +0.008199 +0.008181 +0.008216 +0.00817 +0.008166 +0.008202 +0.008284 +0.008265 +0.008304 +0.008266 +0.00827 +0.008315 +0.008401 +0.008363 +0.008319 +0.008266 +0.008237 +0.008247 +0.00831 +0.008232 +0.008235 +0.008133 +0.008028 +0.008024 +0.008072 +0.008011 +0.008002 +0.00795 +0.00789 +0.007842 +0.00789 +0.007834 +0.007861 +0.007806 +0.007769 +0.007802 +0.007847 +0.007808 +0.007791 +0.007734 +0.007732 +0.007751 +0.007826 +0.007769 +0.007804 +0.007759 +0.00775 +0.007796 +0.007864 +0.007844 +0.007875 +0.007833 +0.007834 +0.007852 +0.007914 +0.007887 +0.007925 +0.007892 +0.001417 +0.007897 +0.007925 +0.007994 +0.007975 +0.007995 +0.007974 +0.007952 +0.008011 +0.008083 +0.008062 +0.008086 +0.008057 +0.008039 +0.008087 +0.008151 +0.008121 +0.008142 +0.008105 +0.008089 +0.008131 +0.008203 +0.008173 +0.008206 +0.008166 +0.008155 +0.008211 +0.008306 +0.008301 +0.008308 +0.008263 +0.008216 +0.008214 +0.008244 +0.008188 +0.008172 +0.008099 +0.008031 +0.008026 +0.008069 +0.008013 +0.008005 +0.007948 +0.007892 +0.007899 +0.007952 +0.007925 +0.007928 +0.007873 +0.007847 +0.00785 +0.007913 +0.007879 +0.007882 +0.007852 +0.007833 +0.007861 +0.007925 +0.007905 +0.007908 +0.007876 +0.007854 +0.007888 +0.00795 +0.007935 +0.00797 +0.007951 +0.007929 +0.007969 +0.008042 +0.008022 +0.008051 +0.001418 +0.008004 +0.007984 +0.008039 +0.0081 +0.008105 +0.008124 +0.008097 +0.008073 +0.00812 +0.008176 +0.008182 +0.008202 +0.008182 +0.008154 +0.008206 +0.00827 +0.008259 +0.008273 +0.008257 +0.008226 +0.008277 +0.008352 +0.008342 +0.008367 +0.008342 +0.008324 +0.008378 +0.008449 +0.008447 +0.008473 +0.008413 +0.008325 +0.008354 +0.00839 +0.008343 +0.008317 +0.008275 +0.008163 +0.008136 +0.008162 +0.008111 +0.008098 +0.00806 +0.008004 +0.008039 +0.008046 +0.007986 +0.007989 +0.007924 +0.007884 +0.007889 +0.007934 +0.007893 +0.007909 +0.007868 +0.007848 +0.007889 +0.007945 +0.007919 +0.007892 +0.007867 +0.007835 +0.007879 +0.007947 +0.007921 +0.007945 +0.007932 +0.007892 +0.007952 +0.008001 +0.007983 +0.008003 +0.007988 +0.007982 +0.008002 +0.008082 +0.008071 +0.001419 +0.008089 +0.008067 +0.008042 +0.0081 +0.00817 +0.008154 +0.00817 +0.008151 +0.008126 +0.008162 +0.008215 +0.008196 +0.008214 +0.008195 +0.008168 +0.00822 +0.008278 +0.008274 +0.008292 +0.008272 +0.008268 +0.008332 +0.008394 +0.008388 +0.008398 +0.008374 +0.008341 +0.008385 +0.008445 +0.008416 +0.008397 +0.008328 +0.008262 +0.008273 +0.008299 +0.00825 +0.008234 +0.008163 +0.008103 +0.008131 +0.00815 +0.008124 +0.008116 +0.008062 +0.008012 +0.008046 +0.008088 +0.00806 +0.008058 +0.008015 +0.007977 +0.008025 +0.008062 +0.008051 +0.00806 +0.008025 +0.00799 +0.008041 +0.008099 +0.008094 +0.008113 +0.008081 +0.00805 +0.008105 +0.008166 +0.008168 +0.008194 +0.008148 +0.008131 +0.008179 +0.00142 +0.008248 +0.008251 +0.008262 +0.008238 +0.008214 +0.008257 +0.00833 +0.008321 +0.008343 +0.008322 +0.008298 +0.008345 +0.008413 +0.008402 +0.008418 +0.008396 +0.008371 +0.008423 +0.008492 +0.008501 +0.008493 +0.00849 +0.008455 +0.008528 +0.008594 +0.008586 +0.008617 +0.008599 +0.008566 +0.008545 +0.008553 +0.008511 +0.00849 +0.008445 +0.008379 +0.008416 +0.008404 +0.008307 +0.008275 +0.008247 +0.008171 +0.008165 +0.008204 +0.008148 +0.008165 +0.008114 +0.008067 +0.008061 +0.008085 +0.008045 +0.008057 +0.008024 +0.007991 +0.008035 +0.008084 +0.008059 +0.008062 +0.008037 +0.008002 +0.008001 +0.008061 +0.008035 +0.008046 +0.008045 +0.008012 +0.008065 +0.008135 +0.008118 +0.008137 +0.008128 +0.008098 +0.008152 +0.008218 +0.008225 +0.008218 +0.001421 +0.0082 +0.008184 +0.008238 +0.008313 +0.008294 +0.008319 +0.008294 +0.008266 +0.008323 +0.008398 +0.008371 +0.008392 +0.008348 +0.008322 +0.008359 +0.008426 +0.0084 +0.008425 +0.008401 +0.008379 +0.008417 +0.008504 +0.008519 +0.008556 +0.008524 +0.008504 +0.008523 +0.00858 +0.008532 +0.008504 +0.008421 +0.008371 +0.008356 +0.008386 +0.008324 +0.008314 +0.008248 +0.008185 +0.008186 +0.00822 +0.008187 +0.008184 +0.008137 +0.008092 +0.008097 +0.008145 +0.008114 +0.008115 +0.008075 +0.008053 +0.008075 +0.008129 +0.008112 +0.008116 +0.008073 +0.008052 +0.008084 +0.008156 +0.008141 +0.008158 +0.008128 +0.008119 +0.008152 +0.008229 +0.008215 +0.008232 +0.008212 +0.008171 +0.008233 +0.001422 +0.008304 +0.008294 +0.00832 +0.008279 +0.008275 +0.008303 +0.00839 +0.008367 +0.008407 +0.008364 +0.00836 +0.008389 +0.008473 +0.008449 +0.008483 +0.00844 +0.008432 +0.008471 +0.008549 +0.008536 +0.008567 +0.008525 +0.008524 +0.008568 +0.008652 +0.008637 +0.008673 +0.008633 +0.008637 +0.008664 +0.008683 +0.00859 +0.008597 +0.008537 +0.008493 +0.008425 +0.00846 +0.008378 +0.00838 +0.008331 +0.008275 +0.008232 +0.008274 +0.008203 +0.008215 +0.008168 +0.008128 +0.008134 +0.008135 +0.008099 +0.008103 +0.008071 +0.008051 +0.008083 +0.008155 +0.008105 +0.008132 +0.008082 +0.008076 +0.008076 +0.008133 +0.008108 +0.008136 +0.008109 +0.008095 +0.008131 +0.008229 +0.008181 +0.008222 +0.0082 +0.008187 +0.008221 +0.008326 +0.008297 +0.001423 +0.008282 +0.008277 +0.008269 +0.008318 +0.008393 +0.008372 +0.008397 +0.008367 +0.008354 +0.008399 +0.008478 +0.008445 +0.008473 +0.008434 +0.008409 +0.008444 +0.008519 +0.008481 +0.008511 +0.008476 +0.008461 +0.008505 +0.008582 +0.008605 +0.008641 +0.008596 +0.008555 +0.008561 +0.008583 +0.008517 +0.008484 +0.008413 +0.008356 +0.008342 +0.00836 +0.008307 +0.008296 +0.00822 +0.008164 +0.008157 +0.008189 +0.008154 +0.008162 +0.008095 +0.008053 +0.008061 +0.008103 +0.008072 +0.008073 +0.00804 +0.008018 +0.008045 +0.008097 +0.008068 +0.008076 +0.00803 +0.008004 +0.008042 +0.00811 +0.008095 +0.008123 +0.00809 +0.008076 +0.008119 +0.008184 +0.008179 +0.008196 +0.008159 +0.008134 +0.00819 +0.001424 +0.008253 +0.008256 +0.008275 +0.008252 +0.008226 +0.008273 +0.008343 +0.008333 +0.008349 +0.008324 +0.008303 +0.008356 +0.008426 +0.008418 +0.008434 +0.008412 +0.008384 +0.008438 +0.008506 +0.008493 +0.008514 +0.008487 +0.008468 +0.008524 +0.008606 +0.0086 +0.00861 +0.0086 +0.008582 +0.008633 +0.008654 +0.008568 +0.008554 +0.008486 +0.008402 +0.008395 +0.008422 +0.008367 +0.008347 +0.008306 +0.008215 +0.008216 +0.008249 +0.008224 +0.0082 +0.008185 +0.008104 +0.0081 +0.00814 +0.008094 +0.00811 +0.008074 +0.008041 +0.008093 +0.008144 +0.008125 +0.008126 +0.008111 +0.008063 +0.008137 +0.008192 +0.008161 +0.008139 +0.008108 +0.008097 +0.008143 +0.008208 +0.008201 +0.00822 +0.008212 +0.008179 +0.008234 +0.008312 +0.008283 +0.008318 +0.001425 +0.008291 +0.008274 +0.008329 +0.008393 +0.008377 +0.0084 +0.008376 +0.008356 +0.008405 +0.008483 +0.008456 +0.008478 +0.008446 +0.008425 +0.008463 +0.008534 +0.008502 +0.008525 +0.008493 +0.008475 +0.008515 +0.008601 +0.008572 +0.008634 +0.008625 +0.008607 +0.008638 +0.008703 +0.00866 +0.008636 +0.008563 +0.008483 +0.008475 +0.008517 +0.008447 +0.008415 +0.008344 +0.008272 +0.00827 +0.008295 +0.008253 +0.008243 +0.008191 +0.008146 +0.008136 +0.008192 +0.008156 +0.008159 +0.00812 +0.00808 +0.008106 +0.008154 +0.008132 +0.008143 +0.008117 +0.008083 +0.008107 +0.008174 +0.008146 +0.008161 +0.008144 +0.008121 +0.008158 +0.008239 +0.008219 +0.008233 +0.008207 +0.008182 +0.008227 +0.008292 +0.008298 +0.008324 +0.001426 +0.008296 +0.008271 +0.008308 +0.008393 +0.008365 +0.008402 +0.008361 +0.008355 +0.008391 +0.008476 +0.008454 +0.008483 +0.008444 +0.008437 +0.008479 +0.008556 +0.008538 +0.008572 +0.008526 +0.008525 +0.008559 +0.008658 +0.008629 +0.00867 +0.008636 +0.008634 +0.008679 +0.008756 +0.00863 +0.008595 +0.008524 +0.008477 +0.008453 +0.008472 +0.008398 +0.008396 +0.00832 +0.008285 +0.008242 +0.00827 +0.008215 +0.008229 +0.008167 +0.008138 +0.008142 +0.008185 +0.008103 +0.008133 +0.008081 +0.008062 +0.00808 +0.00812 +0.008088 +0.0081 +0.008067 +0.00805 +0.008083 +0.008168 +0.008131 +0.008162 +0.008131 +0.008117 +0.008143 +0.008198 +0.008161 +0.008206 +0.008169 +0.008164 +0.00821 +0.008307 +0.008272 +0.008266 +0.001427 +0.008271 +0.008253 +0.008297 +0.008371 +0.008358 +0.008382 +0.008358 +0.008328 +0.008383 +0.008459 +0.008431 +0.008452 +0.008424 +0.008403 +0.008444 +0.008508 +0.008476 +0.008502 +0.008464 +0.008449 +0.008493 +0.008576 +0.008561 +0.008617 +0.008594 +0.008582 +0.008623 +0.008685 +0.008645 +0.008627 +0.008554 +0.008481 +0.008476 +0.008519 +0.008455 +0.008431 +0.008349 +0.008289 +0.008281 +0.008312 +0.008264 +0.008256 +0.008192 +0.008138 +0.008144 +0.008185 +0.008143 +0.008155 +0.008089 +0.008054 +0.008075 +0.00813 +0.008099 +0.008115 +0.008076 +0.008046 +0.008073 +0.008133 +0.008105 +0.008128 +0.0081 +0.008076 +0.008114 +0.008188 +0.008165 +0.008193 +0.008156 +0.008133 +0.008182 +0.008252 +0.00825 +0.008276 +0.008244 +0.001428 +0.008215 +0.00827 +0.008336 +0.008334 +0.008343 +0.008324 +0.008302 +0.008357 +0.008417 +0.008415 +0.008427 +0.008405 +0.008383 +0.008437 +0.008499 +0.008492 +0.008514 +0.008487 +0.008459 +0.008519 +0.008587 +0.008589 +0.008614 +0.008585 +0.008565 +0.008623 +0.008699 +0.008678 +0.00868 +0.008573 +0.008465 +0.00847 +0.008508 +0.008457 +0.008414 +0.008315 +0.008253 +0.008274 +0.008296 +0.008244 +0.008242 +0.008202 +0.008125 +0.00812 +0.008152 +0.008127 +0.008116 +0.008095 +0.008047 +0.008099 +0.008153 +0.008128 +0.008138 +0.008105 +0.008086 +0.008125 +0.008174 +0.008131 +0.008145 +0.008135 +0.008099 +0.008145 +0.008195 +0.00817 +0.008203 +0.008179 +0.008154 +0.008217 +0.008275 +0.008269 +0.00829 +0.008291 +0.008247 +0.001429 +0.008292 +0.008375 +0.008356 +0.008386 +0.008358 +0.008339 +0.008388 +0.008472 +0.008433 +0.008468 +0.008437 +0.008418 +0.008458 +0.008525 +0.008494 +0.008517 +0.008482 +0.008457 +0.008512 +0.008582 +0.008562 +0.008604 +0.008595 +0.00858 +0.00862 +0.008672 +0.008619 +0.008604 +0.008536 +0.008458 +0.008482 +0.008524 +0.008466 +0.008441 +0.008362 +0.008308 +0.008311 +0.008338 +0.008289 +0.008285 +0.008221 +0.00817 +0.008192 +0.008242 +0.008203 +0.008213 +0.008157 +0.008119 +0.008159 +0.008219 +0.0082 +0.008217 +0.008176 +0.008139 +0.008174 +0.008238 +0.00823 +0.008264 +0.008226 +0.008208 +0.008254 +0.008316 +0.008303 +0.008322 +0.008289 +0.008262 +0.008313 +0.00143 +0.008401 +0.008387 +0.008417 +0.008379 +0.008365 +0.0084 +0.008481 +0.008456 +0.008493 +0.008462 +0.008451 +0.008486 +0.008572 +0.008551 +0.008575 +0.008544 +0.008527 +0.008563 +0.008653 +0.008633 +0.008673 +0.008629 +0.008634 +0.008674 +0.008761 +0.008743 +0.008782 +0.008724 +0.008614 +0.008626 +0.008668 +0.008601 +0.008595 +0.008517 +0.00839 +0.008376 +0.008417 +0.008344 +0.008353 +0.008283 +0.008227 +0.008187 +0.00822 +0.008162 +0.008186 +0.008117 +0.008095 +0.008088 +0.008139 +0.008076 +0.008101 +0.008058 +0.008037 +0.00805 +0.008096 +0.008062 +0.008079 +0.008044 +0.008029 +0.008059 +0.008148 +0.008112 +0.008147 +0.008119 +0.008103 +0.008118 +0.008198 +0.008154 +0.00819 +0.008158 +0.008173 +0.008183 +0.008275 +0.00826 +0.001431 +0.008285 +0.008256 +0.008236 +0.008285 +0.008355 +0.008336 +0.008365 +0.008339 +0.008323 +0.008377 +0.00845 +0.008427 +0.008439 +0.008406 +0.008381 +0.008422 +0.008489 +0.008465 +0.008489 +0.008457 +0.008435 +0.008485 +0.008557 +0.008577 +0.008624 +0.008594 +0.008561 +0.008593 +0.008639 +0.008587 +0.008569 +0.008484 +0.00843 +0.008454 +0.00849 +0.008427 +0.008416 +0.008344 +0.008285 +0.0083 +0.00834 +0.008297 +0.008301 +0.008243 +0.008196 +0.008217 +0.008269 +0.00824 +0.008251 +0.008202 +0.008165 +0.008196 +0.008255 +0.008239 +0.008264 +0.008222 +0.008194 +0.008237 +0.008304 +0.008285 +0.008321 +0.008289 +0.008274 +0.008304 +0.008379 +0.008384 +0.008397 +0.001432 +0.008366 +0.008354 +0.008389 +0.008472 +0.008444 +0.008483 +0.008452 +0.008441 +0.008471 +0.008554 +0.008533 +0.008566 +0.00853 +0.008519 +0.008558 +0.008639 +0.008618 +0.008654 +0.008615 +0.008607 +0.008645 +0.008726 +0.008712 +0.008745 +0.008713 +0.008704 +0.008751 +0.008848 +0.00882 +0.008857 +0.008787 +0.008701 +0.008698 +0.008749 +0.008689 +0.008686 +0.00861 +0.00851 +0.008449 +0.008494 +0.008444 +0.008439 +0.008365 +0.008344 +0.008338 +0.008401 +0.008316 +0.008283 +0.008229 +0.008186 +0.00821 +0.008247 +0.008212 +0.008222 +0.008178 +0.008162 +0.008187 +0.008259 +0.008213 +0.008238 +0.008191 +0.008163 +0.00819 +0.008271 +0.008226 +0.008267 +0.008242 +0.008231 +0.00826 +0.008351 +0.008327 +0.008359 +0.008351 +0.008304 +0.008359 +0.001433 +0.00844 +0.008417 +0.008457 +0.008418 +0.008408 +0.008449 +0.008535 +0.008505 +0.008544 +0.008505 +0.008473 +0.008481 +0.008553 +0.00852 +0.008561 +0.008525 +0.00852 +0.008561 +0.008663 +0.008669 +0.0087 +0.008659 +0.008649 +0.008675 +0.008771 +0.008733 +0.008752 +0.008702 +0.008657 +0.008653 +0.008707 +0.008638 +0.008608 +0.008521 +0.008461 +0.008439 +0.00848 +0.008417 +0.008398 +0.008324 +0.008271 +0.00827 +0.008322 +0.008265 +0.008267 +0.008204 +0.008163 +0.008168 +0.008236 +0.0082 +0.008209 +0.008156 +0.008121 +0.008141 +0.008217 +0.008186 +0.008204 +0.008157 +0.008135 +0.00817 +0.008255 +0.00823 +0.008258 +0.008222 +0.008205 +0.008244 +0.00832 +0.008312 +0.008347 +0.008298 +0.008285 +0.001434 +0.008327 +0.008395 +0.008391 +0.008422 +0.00839 +0.008367 +0.00841 +0.008484 +0.008466 +0.008496 +0.008469 +0.008446 +0.008491 +0.008566 +0.008556 +0.008583 +0.00855 +0.008527 +0.008581 +0.008653 +0.008645 +0.008668 +0.008647 +0.00863 +0.008682 +0.008768 +0.00875 +0.008776 +0.008744 +0.008638 +0.008618 +0.008652 +0.008604 +0.008596 +0.008524 +0.008457 +0.008382 +0.008416 +0.008358 +0.008354 +0.008305 +0.008256 +0.008277 +0.008354 +0.008265 +0.008226 +0.008164 +0.008133 +0.00816 +0.008232 +0.008175 +0.008209 +0.008153 +0.00812 +0.008126 +0.008171 +0.008149 +0.008175 +0.008142 +0.008126 +0.008165 +0.008236 +0.008227 +0.008246 +0.008216 +0.008205 +0.008249 +0.008319 +0.008323 +0.008322 +0.008299 +0.008289 +0.001435 +0.008334 +0.008417 +0.008383 +0.008423 +0.00839 +0.008378 +0.008377 +0.008446 +0.008414 +0.008458 +0.008424 +0.008418 +0.008461 +0.008544 +0.008508 +0.008545 +0.00851 +0.008498 +0.008544 +0.008644 +0.008626 +0.008658 +0.008611 +0.0086 +0.008638 +0.008718 +0.008697 +0.008735 +0.0087 +0.008675 +0.008678 +0.00874 +0.008685 +0.008657 +0.008578 +0.008515 +0.008497 +0.008539 +0.008471 +0.008456 +0.008381 +0.008334 +0.00833 +0.008388 +0.008343 +0.008339 +0.008278 +0.008238 +0.008243 +0.008315 +0.008275 +0.008285 +0.008236 +0.008211 +0.008222 +0.008303 +0.008273 +0.008295 +0.008257 +0.008241 +0.008267 +0.008356 +0.008335 +0.008357 +0.008323 +0.008308 +0.008341 +0.008428 +0.008411 +0.008451 +0.008409 +0.001436 +0.008388 +0.008431 +0.00851 +0.008498 +0.008521 +0.008489 +0.008476 +0.008517 +0.008593 +0.00858 +0.00861 +0.008577 +0.008559 +0.008602 +0.008679 +0.008659 +0.008695 +0.008656 +0.008637 +0.008693 +0.008765 +0.008757 +0.008782 +0.008759 +0.008739 +0.008798 +0.008882 +0.008872 +0.008891 +0.008853 +0.008745 +0.008751 +0.008794 +0.008744 +0.008735 +0.008671 +0.008616 +0.008545 +0.008552 +0.008507 +0.008499 +0.008446 +0.008401 +0.00842 +0.008486 +0.008433 +0.00843 +0.008328 +0.008281 +0.008313 +0.008372 +0.008326 +0.008347 +0.008295 +0.008282 +0.008315 +0.008366 +0.00834 +0.008352 +0.008318 +0.008275 +0.008291 +0.008376 +0.008339 +0.008369 +0.008354 +0.00833 +0.008377 +0.008459 +0.008437 +0.008465 +0.008443 +0.008443 +0.00846 +0.008547 +0.001437 +0.008538 +0.008557 +0.008535 +0.008514 +0.008568 +0.008642 +0.008627 +0.008643 +0.008623 +0.008586 +0.008606 +0.008658 +0.008644 +0.008664 +0.008647 +0.008625 +0.008679 +0.008777 +0.008795 +0.008807 +0.008782 +0.008746 +0.008803 +0.008871 +0.008852 +0.008858 +0.008809 +0.008754 +0.008773 +0.008785 +0.008735 +0.008703 +0.008621 +0.008546 +0.008547 +0.008566 +0.008523 +0.008511 +0.008442 +0.008377 +0.00839 +0.00843 +0.008397 +0.008389 +0.008336 +0.008275 +0.008306 +0.008351 +0.008334 +0.008341 +0.0083 +0.008254 +0.008296 +0.008344 +0.008325 +0.008347 +0.008317 +0.008284 +0.008337 +0.008401 +0.008391 +0.008411 +0.008379 +0.008355 +0.00841 +0.008476 +0.008478 +0.008499 +0.008466 +0.001438 +0.00844 +0.008489 +0.008565 +0.008557 +0.008574 +0.008552 +0.008527 +0.008578 +0.008646 +0.008642 +0.008667 +0.008639 +0.008614 +0.00867 +0.008735 +0.008726 +0.008751 +0.008722 +0.008693 +0.008754 +0.008819 +0.008837 +0.008839 +0.008821 +0.008803 +0.008871 +0.008938 +0.00892 +0.008844 +0.008762 +0.008698 +0.008727 +0.008749 +0.008671 +0.008587 +0.008509 +0.008458 +0.008489 +0.008499 +0.008438 +0.008444 +0.008341 +0.008296 +0.008303 +0.008341 +0.008301 +0.008295 +0.008255 +0.00822 +0.008259 +0.008311 +0.008268 +0.008256 +0.008212 +0.00818 +0.008214 +0.008262 +0.008238 +0.00825 +0.008222 +0.008203 +0.008256 +0.008315 +0.008303 +0.008326 +0.0083 +0.008273 +0.008337 +0.008394 +0.008369 +0.008411 +0.008373 +0.001439 +0.008343 +0.008373 +0.008429 +0.008421 +0.008443 +0.008424 +0.008401 +0.008457 +0.008528 +0.008518 +0.008543 +0.008519 +0.008496 +0.008545 +0.008611 +0.008611 +0.008614 +0.008612 +0.00859 +0.008647 +0.008715 +0.008704 +0.008724 +0.008691 +0.008656 +0.008716 +0.008786 +0.008794 +0.008805 +0.008762 +0.008711 +0.00872 +0.008735 +0.008697 +0.008664 +0.00858 +0.008502 +0.008501 +0.008519 +0.00848 +0.008455 +0.008386 +0.008329 +0.008341 +0.008374 +0.008356 +0.008345 +0.00829 +0.008248 +0.008266 +0.008311 +0.008307 +0.008307 +0.008277 +0.008238 +0.008274 +0.008323 +0.008314 +0.00832 +0.0083 +0.008283 +0.008329 +0.008388 +0.008389 +0.008398 +0.008372 +0.008348 +0.008401 +0.008477 +0.008469 +0.008485 +0.00144 +0.008448 +0.008441 +0.008484 +0.008557 +0.008551 +0.008569 +0.008538 +0.00852 +0.008563 +0.008644 +0.008633 +0.008657 +0.008625 +0.008607 +0.00865 +0.008725 +0.008708 +0.008739 +0.008705 +0.008686 +0.008745 +0.008815 +0.008815 +0.008843 +0.008807 +0.008795 +0.008855 +0.008939 +0.008903 +0.00885 +0.008733 +0.00868 +0.008701 +0.008744 +0.008654 +0.008603 +0.008522 +0.008472 +0.008474 +0.008516 +0.008456 +0.008448 +0.008374 +0.00831 +0.008311 +0.008366 +0.008307 +0.008334 +0.008278 +0.008254 +0.008292 +0.008349 +0.008314 +0.008305 +0.008251 +0.00822 +0.008266 +0.008332 +0.008284 +0.00832 +0.008288 +0.00827 +0.00832 +0.008373 +0.008344 +0.008384 +0.008351 +0.008328 +0.008393 +0.008455 +0.00843 +0.00846 +0.008443 +0.001441 +0.008407 +0.008451 +0.008508 +0.008487 +0.00852 +0.008498 +0.008472 +0.008531 +0.008597 +0.008583 +0.008607 +0.008582 +0.008555 +0.008609 +0.008672 +0.008659 +0.008675 +0.008652 +0.00865 +0.008718 +0.008786 +0.008776 +0.008782 +0.008763 +0.008717 +0.008767 +0.008822 +0.00878 +0.00876 +0.008682 +0.008602 +0.008617 +0.008637 +0.008574 +0.008541 +0.008481 +0.008416 +0.00843 +0.008465 +0.008422 +0.008409 +0.008359 +0.008301 +0.008326 +0.008369 +0.008335 +0.008336 +0.008298 +0.008256 +0.008302 +0.008351 +0.00833 +0.008335 +0.008298 +0.008257 +0.008313 +0.008383 +0.008369 +0.008389 +0.008356 +0.008324 +0.008381 +0.008448 +0.008447 +0.008474 +0.008429 +0.008413 +0.008464 +0.001442 +0.008532 +0.008533 +0.008543 +0.008526 +0.008494 +0.008549 +0.008616 +0.008616 +0.008627 +0.008611 +0.008584 +0.008631 +0.008703 +0.008696 +0.008715 +0.008689 +0.00867 +0.008721 +0.008785 +0.008791 +0.008799 +0.008779 +0.008755 +0.008824 +0.008896 +0.008888 +0.008914 +0.008893 +0.008856 +0.008887 +0.008838 +0.008783 +0.008766 +0.008703 +0.008593 +0.008566 +0.008581 +0.008544 +0.008531 +0.008462 +0.008418 +0.008443 +0.008423 +0.008381 +0.008374 +0.008329 +0.008277 +0.008261 +0.008298 +0.008264 +0.008275 +0.008247 +0.008195 +0.008252 +0.008294 +0.008271 +0.008286 +0.008249 +0.008191 +0.008212 +0.008261 +0.008254 +0.008272 +0.008246 +0.008233 +0.008282 +0.008347 +0.008347 +0.00836 +0.00834 +0.008319 +0.008392 +0.00843 +0.008421 +0.001443 +0.008456 +0.008432 +0.008405 +0.008458 +0.008536 +0.008515 +0.008551 +0.008515 +0.008498 +0.008507 +0.008568 +0.008543 +0.008574 +0.008543 +0.008526 +0.00857 +0.008647 +0.008634 +0.008681 +0.008668 +0.008657 +0.008692 +0.008763 +0.008755 +0.008765 +0.008733 +0.00871 +0.008737 +0.00878 +0.008726 +0.008695 +0.008615 +0.008547 +0.008528 +0.008555 +0.008489 +0.008467 +0.008393 +0.00833 +0.008318 +0.008364 +0.008322 +0.008317 +0.008247 +0.008211 +0.008216 +0.008271 +0.008227 +0.008231 +0.008193 +0.008167 +0.008188 +0.008252 +0.008228 +0.008231 +0.00819 +0.00817 +0.008209 +0.008288 +0.008275 +0.008289 +0.008262 +0.008245 +0.008286 +0.008364 +0.008345 +0.008378 +0.008339 +0.008328 +0.001444 +0.008374 +0.008444 +0.008435 +0.008447 +0.008428 +0.008397 +0.008453 +0.008519 +0.008515 +0.008533 +0.008514 +0.008487 +0.008538 +0.008607 +0.0086 +0.008617 +0.008587 +0.008561 +0.008627 +0.008688 +0.008686 +0.008711 +0.008679 +0.00866 +0.008722 +0.008788 +0.008794 +0.008816 +0.008802 +0.008754 +0.008726 +0.008712 +0.008655 +0.008637 +0.008591 +0.008524 +0.008516 +0.008464 +0.008408 +0.008391 +0.008348 +0.00827 +0.008311 +0.008337 +0.008256 +0.008219 +0.008167 +0.008133 +0.008146 +0.008188 +0.008147 +0.008145 +0.008112 +0.008047 +0.008084 +0.008119 +0.008108 +0.008113 +0.008078 +0.008062 +0.008099 +0.008158 +0.008154 +0.008154 +0.008146 +0.008124 +0.008145 +0.008199 +0.008181 +0.008198 +0.008181 +0.008167 +0.008224 +0.008284 +0.008275 +0.008294 +0.001445 +0.008278 +0.008251 +0.008324 +0.008372 +0.008353 +0.008386 +0.008363 +0.008355 +0.008376 +0.008433 +0.008407 +0.008435 +0.008402 +0.008384 +0.008425 +0.008498 +0.008477 +0.008507 +0.008481 +0.008477 +0.008546 +0.00862 +0.008602 +0.008624 +0.008583 +0.008561 +0.008585 +0.008629 +0.008597 +0.008585 +0.008486 +0.008437 +0.008423 +0.008452 +0.008397 +0.008382 +0.008299 +0.008251 +0.008249 +0.008289 +0.00825 +0.008245 +0.008181 +0.008145 +0.008148 +0.008195 +0.008167 +0.008172 +0.008119 +0.008093 +0.008119 +0.008182 +0.008153 +0.008165 +0.008123 +0.008111 +0.008155 +0.008215 +0.008208 +0.008228 +0.008192 +0.00818 +0.008217 +0.008297 +0.008283 +0.008306 +0.008276 +0.001446 +0.008257 +0.008305 +0.008378 +0.008368 +0.008382 +0.008359 +0.008338 +0.008389 +0.008454 +0.008452 +0.008466 +0.008444 +0.008422 +0.008469 +0.008534 +0.00853 +0.008548 +0.00852 +0.008504 +0.008556 +0.008629 +0.008624 +0.008653 +0.008628 +0.008607 +0.008672 +0.008739 +0.008719 +0.008626 +0.008546 +0.008483 +0.008523 +0.008563 +0.008483 +0.008401 +0.008334 +0.008274 +0.008305 +0.00835 +0.008291 +0.008295 +0.008194 +0.008134 +0.008153 +0.008178 +0.00816 +0.008131 +0.008122 +0.008067 +0.008109 +0.00812 +0.008107 +0.008094 +0.008078 +0.008047 +0.008062 +0.008121 +0.008092 +0.008092 +0.00809 +0.008049 +0.008116 +0.00817 +0.00815 +0.008175 +0.008144 +0.008107 +0.008156 +0.008217 +0.008199 +0.008222 +0.008208 +0.008183 +0.008245 +0.001447 +0.008297 +0.00828 +0.008315 +0.008288 +0.00827 +0.008318 +0.008392 +0.008377 +0.008403 +0.008371 +0.008351 +0.008397 +0.008459 +0.008436 +0.008457 +0.008424 +0.008412 +0.008455 +0.008527 +0.008512 +0.008567 +0.008537 +0.008525 +0.00856 +0.008623 +0.008594 +0.008587 +0.008517 +0.00847 +0.008468 +0.008499 +0.008439 +0.008416 +0.008346 +0.008286 +0.008267 +0.008301 +0.008258 +0.008241 +0.008179 +0.008142 +0.008145 +0.008189 +0.008151 +0.008141 +0.008091 +0.008062 +0.008074 +0.008132 +0.008109 +0.008115 +0.00807 +0.008051 +0.008072 +0.008144 +0.008128 +0.008146 +0.008117 +0.008104 +0.008126 +0.008208 +0.008195 +0.008217 +0.008193 +0.008171 +0.008222 +0.008281 +0.001448 +0.008273 +0.008302 +0.008268 +0.008266 +0.008281 +0.008372 +0.008354 +0.008383 +0.00835 +0.008338 +0.008376 +0.008457 +0.008435 +0.008465 +0.008423 +0.008418 +0.008446 +0.008535 +0.008508 +0.008549 +0.008507 +0.0085 +0.008533 +0.008619 +0.008609 +0.008648 +0.008606 +0.008601 +0.008642 +0.008738 +0.008702 +0.008713 +0.008567 +0.00852 +0.008511 +0.008557 +0.008496 +0.008441 +0.008355 +0.008319 +0.008325 +0.008374 +0.008327 +0.008316 +0.008217 +0.00818 +0.008157 +0.008226 +0.008164 +0.00818 +0.008116 +0.008099 +0.008081 +0.008128 +0.008082 +0.008109 +0.00806 +0.008036 +0.00807 +0.008138 +0.008099 +0.008136 +0.008075 +0.008045 +0.008058 +0.00813 +0.008111 +0.008144 +0.008108 +0.008107 +0.008144 +0.008221 +0.008195 +0.008238 +0.0082 +0.008202 +0.008217 +0.008309 +0.001449 +0.008295 +0.00832 +0.008288 +0.008273 +0.008315 +0.008394 +0.008376 +0.008407 +0.008375 +0.008358 +0.008399 +0.008475 +0.008428 +0.008452 +0.008422 +0.008403 +0.008448 +0.008516 +0.00849 +0.008527 +0.008476 +0.008473 +0.00854 +0.008633 +0.008605 +0.008606 +0.008545 +0.008488 +0.008473 +0.008525 +0.008464 +0.008437 +0.008359 +0.008297 +0.0083 +0.008326 +0.008276 +0.008259 +0.008195 +0.008143 +0.008162 +0.008208 +0.008159 +0.008149 +0.008098 +0.008051 +0.008081 +0.008147 +0.008119 +0.008126 +0.008087 +0.008054 +0.008081 +0.008149 +0.008133 +0.008156 +0.008127 +0.008096 +0.008137 +0.008217 +0.008194 +0.008228 +0.008196 +0.008179 +0.008217 +0.008283 +0.008282 +0.00145 +0.008313 +0.008271 +0.008267 +0.008293 +0.008372 +0.008355 +0.008385 +0.008348 +0.008346 +0.008377 +0.008464 +0.008441 +0.00847 +0.00843 +0.008418 +0.008458 +0.00854 +0.008513 +0.008555 +0.00851 +0.008494 +0.008541 +0.008625 +0.008612 +0.008649 +0.00861 +0.008602 +0.00865 +0.008735 +0.008694 +0.008698 +0.008562 +0.008499 +0.008487 +0.008526 +0.008475 +0.008425 +0.008334 +0.008293 +0.008282 +0.008341 +0.008268 +0.008274 +0.008177 +0.008134 +0.008139 +0.008182 +0.00814 +0.008141 +0.008091 +0.008065 +0.008072 +0.008125 +0.008071 +0.008099 +0.008053 +0.008038 +0.008062 +0.008134 +0.008103 +0.008097 +0.008045 +0.008036 +0.008064 +0.00815 +0.008107 +0.008144 +0.008117 +0.008095 +0.008134 +0.00821 +0.008162 +0.008208 +0.008179 +0.008183 +0.008195 +0.008281 +0.008263 +0.001451 +0.008293 +0.008257 +0.008256 +0.008287 +0.008368 +0.008343 +0.008369 +0.008341 +0.008323 +0.00837 +0.008439 +0.008409 +0.008428 +0.008395 +0.008377 +0.008411 +0.008489 +0.008478 +0.008502 +0.00848 +0.008488 +0.008532 +0.008613 +0.008586 +0.008594 +0.008549 +0.008486 +0.008491 +0.008537 +0.008466 +0.008441 +0.008365 +0.008299 +0.008293 +0.00833 +0.008274 +0.008255 +0.008191 +0.008146 +0.008149 +0.008198 +0.008154 +0.008145 +0.008092 +0.008046 +0.008069 +0.008132 +0.008103 +0.008111 +0.008069 +0.008038 +0.008061 +0.008136 +0.008116 +0.008132 +0.008101 +0.008069 +0.008106 +0.008184 +0.008169 +0.008198 +0.008168 +0.008141 +0.00819 +0.008257 +0.008254 +0.008267 +0.001452 +0.008255 +0.008218 +0.008266 +0.008338 +0.008329 +0.008351 +0.008333 +0.008303 +0.00835 +0.008415 +0.008412 +0.008437 +0.008411 +0.008383 +0.008434 +0.008497 +0.008494 +0.008512 +0.008489 +0.008459 +0.008517 +0.008583 +0.008578 +0.008603 +0.008575 +0.00855 +0.008625 +0.008676 +0.008682 +0.0087 +0.008687 +0.008652 +0.008657 +0.008622 +0.008561 +0.008556 +0.008509 +0.008438 +0.008392 +0.008391 +0.008349 +0.008331 +0.008293 +0.008246 +0.008275 +0.008332 +0.008299 +0.008273 +0.008185 +0.008123 +0.008185 +0.008221 +0.008204 +0.008204 +0.008168 +0.008143 +0.008167 +0.008222 +0.008184 +0.008201 +0.00818 +0.00814 +0.008211 +0.008262 +0.008246 +0.008264 +0.00824 +0.008222 +0.008236 +0.008289 +0.008283 +0.008297 +0.008278 +0.008267 +0.00832 +0.008378 +0.008384 +0.00842 +0.001453 +0.008356 +0.008349 +0.008411 +0.008479 +0.008471 +0.00849 +0.008465 +0.008444 +0.008494 +0.008563 +0.008555 +0.008571 +0.008538 +0.008515 +0.008563 +0.008634 +0.008625 +0.00863 +0.008612 +0.0086 +0.00866 +0.008732 +0.008725 +0.008709 +0.008672 +0.00861 +0.008615 +0.008655 +0.008605 +0.00857 +0.008504 +0.008437 +0.00844 +0.008466 +0.008417 +0.008396 +0.008342 +0.008289 +0.0083 +0.008341 +0.008309 +0.008295 +0.008251 +0.008204 +0.008228 +0.008278 +0.008267 +0.008262 +0.00823 +0.008196 +0.008223 +0.008284 +0.008268 +0.008287 +0.008257 +0.008227 +0.008268 +0.00834 +0.008333 +0.008339 +0.008328 +0.008302 +0.008351 +0.008414 +0.008406 +0.00844 +0.008398 +0.001454 +0.00838 +0.008433 +0.008497 +0.008491 +0.008514 +0.008489 +0.008465 +0.008515 +0.008583 +0.00858 +0.008596 +0.00857 +0.008541 +0.008595 +0.008664 +0.008665 +0.008671 +0.008659 +0.008629 +0.00868 +0.008754 +0.008747 +0.008775 +0.008744 +0.008721 +0.008789 +0.008866 +0.008862 +0.00887 +0.008828 +0.008699 +0.008674 +0.00869 +0.00864 +0.008625 +0.008502 +0.00841 +0.008395 +0.008415 +0.008368 +0.008352 +0.008297 +0.008255 +0.008239 +0.008207 +0.008178 +0.008156 +0.008122 +0.008067 +0.008111 +0.008142 +0.008124 +0.008116 +0.008065 +0.007993 +0.008016 +0.008081 +0.008046 +0.008053 +0.008034 +0.007997 +0.008049 +0.008115 +0.008094 +0.00811 +0.008099 +0.008066 +0.008108 +0.008154 +0.008132 +0.008151 +0.008149 +0.008124 +0.008178 +0.008257 +0.008217 +0.008239 +0.001455 +0.008226 +0.008201 +0.008254 +0.008327 +0.008317 +0.008332 +0.00831 +0.00828 +0.008336 +0.008404 +0.008376 +0.008394 +0.008367 +0.008343 +0.00839 +0.008451 +0.008434 +0.00845 +0.008423 +0.008404 +0.00846 +0.008562 +0.008557 +0.008557 +0.008505 +0.008434 +0.008433 +0.008439 +0.008388 +0.008362 +0.008283 +0.008205 +0.008203 +0.00822 +0.008173 +0.008135 +0.008069 +0.008006 +0.008007 +0.008029 +0.007993 +0.007973 +0.007913 +0.007858 +0.007887 +0.007925 +0.0079 +0.007904 +0.007864 +0.007828 +0.007863 +0.007914 +0.007905 +0.007918 +0.007886 +0.007855 +0.007905 +0.007971 +0.00796 +0.007986 +0.007956 +0.007932 +0.007979 +0.008036 +0.008042 +0.008049 +0.008032 +0.001456 +0.008007 +0.008055 +0.008125 +0.008108 +0.008138 +0.008105 +0.008088 +0.008128 +0.008204 +0.008192 +0.008214 +0.008184 +0.008168 +0.00821 +0.008282 +0.008268 +0.008294 +0.008264 +0.008252 +0.008278 +0.008364 +0.00835 +0.00837 +0.008347 +0.008324 +0.008379 +0.008457 +0.008449 +0.00847 +0.008448 +0.008432 +0.00849 +0.008556 +0.008459 +0.00841 +0.00835 +0.008294 +0.008276 +0.008287 +0.008219 +0.008197 +0.00815 +0.008057 +0.008037 +0.008101 +0.008056 +0.008054 +0.007998 +0.007916 +0.007921 +0.007954 +0.007922 +0.007923 +0.007891 +0.007852 +0.007889 +0.007954 +0.00791 +0.007935 +0.007886 +0.007854 +0.007853 +0.007904 +0.007888 +0.007912 +0.007877 +0.007871 +0.00791 +0.007976 +0.007973 +0.007986 +0.007962 +0.007948 +0.007994 +0.008066 +0.008061 +0.008066 +0.008047 +0.001457 +0.008037 +0.008075 +0.008156 +0.008126 +0.008165 +0.008128 +0.00812 +0.008142 +0.008203 +0.008164 +0.0082 +0.008169 +0.008165 +0.008187 +0.008267 +0.008239 +0.008269 +0.008234 +0.008225 +0.008277 +0.00838 +0.008361 +0.00838 +0.008342 +0.008326 +0.008374 +0.008442 +0.008417 +0.008432 +0.008355 +0.008311 +0.008282 +0.008327 +0.008264 +0.00825 +0.008158 +0.008109 +0.008104 +0.00814 +0.008083 +0.008102 +0.008011 +0.007975 +0.007986 +0.008038 +0.007997 +0.008008 +0.007945 +0.007919 +0.007941 +0.008003 +0.007969 +0.00799 +0.007939 +0.007924 +0.007952 +0.008023 +0.007992 +0.008021 +0.007976 +0.007969 +0.008006 +0.008085 +0.008058 +0.008091 +0.008046 +0.008044 +0.008077 +0.008148 +0.008137 +0.001458 +0.008172 +0.008128 +0.008124 +0.008146 +0.008232 +0.00822 +0.008248 +0.008212 +0.008196 +0.008231 +0.008316 +0.008297 +0.008335 +0.008292 +0.008283 +0.008317 +0.0084 +0.00838 +0.008416 +0.008355 +0.008361 +0.008397 +0.008487 +0.008461 +0.008507 +0.008465 +0.008456 +0.008512 +0.008594 +0.008568 +0.008572 +0.008462 +0.008438 +0.008445 +0.008496 +0.008421 +0.008358 +0.008278 +0.008234 +0.008242 +0.00827 +0.008192 +0.008199 +0.008115 +0.008063 +0.008044 +0.008108 +0.008043 +0.008057 +0.007997 +0.007962 +0.007962 +0.007979 +0.007948 +0.007966 +0.007929 +0.007909 +0.007936 +0.008011 +0.007963 +0.007996 +0.007965 +0.007948 +0.007978 +0.008029 +0.007988 +0.008029 +0.007995 +0.007984 +0.008023 +0.00811 +0.008081 +0.008114 +0.008083 +0.008082 +0.00811 +0.001459 +0.008206 +0.00815 +0.008191 +0.008169 +0.008163 +0.008196 +0.008277 +0.008255 +0.008277 +0.008245 +0.008224 +0.008265 +0.008332 +0.008299 +0.008324 +0.008291 +0.008271 +0.008321 +0.008372 +0.008361 +0.0084 +0.008378 +0.008382 +0.008433 +0.008503 +0.008483 +0.008501 +0.00845 +0.008409 +0.008433 +0.00846 +0.008411 +0.008394 +0.008308 +0.008261 +0.008249 +0.008277 +0.008229 +0.008222 +0.008147 +0.008101 +0.008125 +0.008154 +0.00812 +0.008118 +0.008061 +0.008023 +0.008053 +0.00809 +0.008066 +0.008079 +0.008029 +0.008001 +0.008036 +0.008096 +0.008078 +0.008095 +0.008051 +0.008037 +0.008081 +0.008152 +0.008137 +0.008158 +0.008125 +0.00811 +0.008146 +0.008224 +0.008223 +0.008225 +0.00146 +0.008207 +0.008189 +0.00823 +0.008295 +0.008295 +0.008308 +0.008284 +0.00827 +0.008316 +0.008386 +0.008377 +0.00839 +0.008366 +0.008339 +0.008392 +0.008459 +0.008458 +0.008477 +0.008448 +0.008419 +0.008481 +0.008542 +0.008543 +0.008559 +0.008545 +0.008521 +0.008581 +0.008659 +0.008646 +0.008676 +0.008636 +0.008557 +0.008522 +0.008558 +0.008514 +0.008501 +0.008445 +0.008395 +0.008364 +0.008358 +0.008307 +0.008294 +0.00826 +0.00821 +0.008247 +0.008272 +0.00821 +0.008203 +0.008143 +0.00811 +0.008108 +0.008165 +0.008126 +0.008138 +0.008114 +0.008072 +0.008132 +0.008181 +0.008152 +0.008172 +0.008143 +0.008123 +0.008179 +0.008221 +0.008192 +0.008214 +0.008185 +0.008167 +0.008195 +0.008247 +0.008237 +0.008268 +0.008245 +0.008223 +0.008285 +0.008341 +0.008336 +0.008369 +0.001461 +0.00833 +0.008311 +0.008367 +0.008442 +0.008429 +0.008442 +0.008421 +0.008393 +0.008455 +0.008521 +0.008509 +0.008519 +0.008488 +0.00846 +0.008508 +0.008576 +0.008557 +0.008575 +0.008555 +0.008521 +0.008575 +0.008677 +0.008678 +0.008684 +0.008637 +0.008574 +0.008584 +0.008605 +0.008569 +0.008545 +0.008477 +0.00839 +0.008391 +0.008423 +0.00837 +0.008342 +0.008281 +0.008218 +0.008224 +0.008263 +0.008226 +0.008213 +0.008166 +0.00811 +0.008136 +0.008185 +0.008165 +0.008163 +0.008129 +0.008087 +0.008118 +0.008177 +0.008167 +0.008173 +0.008149 +0.008106 +0.008155 +0.008221 +0.008215 +0.008232 +0.008212 +0.00818 +0.008234 +0.008292 +0.008298 +0.008311 +0.008295 +0.001462 +0.008258 +0.008308 +0.008379 +0.008372 +0.008402 +0.008363 +0.00835 +0.00838 +0.008461 +0.008456 +0.008482 +0.008449 +0.008433 +0.008472 +0.008545 +0.008533 +0.008556 +0.008522 +0.008515 +0.008556 +0.008631 +0.008619 +0.008648 +0.008616 +0.008608 +0.008661 +0.008736 +0.008728 +0.008743 +0.0087 +0.008576 +0.008539 +0.008578 +0.008514 +0.008511 +0.008408 +0.008292 +0.008287 +0.008348 +0.008278 +0.00827 +0.008236 +0.00814 +0.008128 +0.008157 +0.008118 +0.00812 +0.008075 +0.008037 +0.008066 +0.008118 +0.008084 +0.008094 +0.00801 +0.00799 +0.008011 +0.008079 +0.008052 +0.008062 +0.00804 +0.008018 +0.008056 +0.008131 +0.008097 +0.008126 +0.008105 +0.008082 +0.008099 +0.008159 +0.008133 +0.008164 +0.008146 +0.008127 +0.008186 +0.008252 +0.008225 +0.008267 +0.001463 +0.008231 +0.008224 +0.008264 +0.008345 +0.008319 +0.008356 +0.008316 +0.008305 +0.008345 +0.008428 +0.008399 +0.008427 +0.008387 +0.008372 +0.008409 +0.008486 +0.008458 +0.008491 +0.008457 +0.008457 +0.008509 +0.00859 +0.008551 +0.008565 +0.008489 +0.008438 +0.008438 +0.008467 +0.0084 +0.008384 +0.008292 +0.008241 +0.008234 +0.00828 +0.008217 +0.008223 +0.008148 +0.008114 +0.008125 +0.008175 +0.008132 +0.008137 +0.008075 +0.008049 +0.008068 +0.008129 +0.008094 +0.008118 +0.008057 +0.008044 +0.00807 +0.008133 +0.008109 +0.008126 +0.008084 +0.008074 +0.008111 +0.008186 +0.008165 +0.008198 +0.008139 +0.00814 +0.00818 +0.008264 +0.008249 +0.00826 +0.008227 +0.001464 +0.008227 +0.008257 +0.008341 +0.008323 +0.008351 +0.008311 +0.008296 +0.008332 +0.008419 +0.008404 +0.008437 +0.008395 +0.008383 +0.008417 +0.008504 +0.008484 +0.008512 +0.008478 +0.008469 +0.008516 +0.008597 +0.008582 +0.008613 +0.008577 +0.008577 +0.008621 +0.008632 +0.008555 +0.008559 +0.008494 +0.008456 +0.008432 +0.008446 +0.008362 +0.008364 +0.008303 +0.008267 +0.008224 +0.008276 +0.008221 +0.008231 +0.008184 +0.008148 +0.008153 +0.008172 +0.008138 +0.008143 +0.008107 +0.008092 +0.008119 +0.008203 +0.008157 +0.008176 +0.008137 +0.008122 +0.008155 +0.008252 +0.008185 +0.008185 +0.008146 +0.008131 +0.008184 +0.008254 +0.008226 +0.008267 +0.008221 +0.008228 +0.008264 +0.008345 +0.008324 +0.008358 +0.008328 +0.001465 +0.008301 +0.008355 +0.008431 +0.008417 +0.00844 +0.008408 +0.008391 +0.008421 +0.008481 +0.008458 +0.008483 +0.008455 +0.008427 +0.008469 +0.008541 +0.008525 +0.008556 +0.008549 +0.00855 +0.008586 +0.008664 +0.008632 +0.008635 +0.008584 +0.008527 +0.008522 +0.008562 +0.008499 +0.008479 +0.008413 +0.008346 +0.008343 +0.008392 +0.008343 +0.00832 +0.008268 +0.008224 +0.008226 +0.00828 +0.008242 +0.008236 +0.008188 +0.008147 +0.00817 +0.00823 +0.008203 +0.008212 +0.008179 +0.008147 +0.008171 +0.00824 +0.00822 +0.008238 +0.008214 +0.008188 +0.008233 +0.008301 +0.00829 +0.008314 +0.008283 +0.008261 +0.008318 +0.008376 +0.008367 +0.001466 +0.008399 +0.008357 +0.008353 +0.008389 +0.008472 +0.008448 +0.008478 +0.008441 +0.008431 +0.008466 +0.008553 +0.008532 +0.008562 +0.008526 +0.008514 +0.008556 +0.008633 +0.008636 +0.008643 +0.008616 +0.008607 +0.008658 +0.008741 +0.00873 +0.008762 +0.008726 +0.00871 +0.00866 +0.008699 +0.008626 +0.008636 +0.008572 +0.008524 +0.008551 +0.008573 +0.008452 +0.008451 +0.008411 +0.00837 +0.008386 +0.008426 +0.008359 +0.008385 +0.008299 +0.008279 +0.008264 +0.008331 +0.008268 +0.008301 +0.008244 +0.008239 +0.008262 +0.008337 +0.008287 +0.008277 +0.008244 +0.008225 +0.008272 +0.008344 +0.008313 +0.008336 +0.00831 +0.008299 +0.008331 +0.00841 +0.008371 +0.00842 +0.008382 +0.00839 +0.008416 +0.008488 +0.001467 +0.008475 +0.008495 +0.008465 +0.008457 +0.008489 +0.008556 +0.008511 +0.00855 +0.008519 +0.008507 +0.00856 +0.008633 +0.008613 +0.008639 +0.008603 +0.008583 +0.008626 +0.008737 +0.008726 +0.008758 +0.008712 +0.008691 +0.008718 +0.008772 +0.008745 +0.008732 +0.008647 +0.008595 +0.008596 +0.008613 +0.008574 +0.008552 +0.008476 +0.008425 +0.00843 +0.008455 +0.008422 +0.008413 +0.00834 +0.008301 +0.00831 +0.008354 +0.008321 +0.008323 +0.008269 +0.008233 +0.008259 +0.008306 +0.008292 +0.008302 +0.008254 +0.008229 +0.008255 +0.00832 +0.008314 +0.008335 +0.008298 +0.008285 +0.00832 +0.008392 +0.00838 +0.008396 +0.008378 +0.00836 +0.008408 +0.008477 +0.001468 +0.008468 +0.008487 +0.008451 +0.008438 +0.008473 +0.008558 +0.008545 +0.008576 +0.008541 +0.008522 +0.008565 +0.00865 +0.008619 +0.00865 +0.008616 +0.0086 +0.008652 +0.008727 +0.008711 +0.008746 +0.008717 +0.008701 +0.008752 +0.008833 +0.008819 +0.008856 +0.008826 +0.008793 +0.008742 +0.008749 +0.008679 +0.00868 +0.008629 +0.008567 +0.008542 +0.008516 +0.008454 +0.008456 +0.008403 +0.008365 +0.008386 +0.008427 +0.00835 +0.008306 +0.008256 +0.008217 +0.008255 +0.008293 +0.008257 +0.00824 +0.008195 +0.008161 +0.008188 +0.008264 +0.008212 +0.008228 +0.008204 +0.008179 +0.008215 +0.008281 +0.008239 +0.008272 +0.008242 +0.00822 +0.00827 +0.008324 +0.008298 +0.008339 +0.008309 +0.008288 +0.008346 +0.008416 +0.008403 +0.001469 +0.008415 +0.008385 +0.008385 +0.008422 +0.008508 +0.00848 +0.008515 +0.008481 +0.00847 +0.008479 +0.008551 +0.00852 +0.008544 +0.008516 +0.0085 +0.008535 +0.008631 +0.008609 +0.008674 +0.008641 +0.008631 +0.008662 +0.008746 +0.008713 +0.008742 +0.008681 +0.008655 +0.008652 +0.008683 +0.008606 +0.008598 +0.008517 +0.008454 +0.008442 +0.00848 +0.008424 +0.008428 +0.008358 +0.008308 +0.008318 +0.00837 +0.00832 +0.00834 +0.00828 +0.008247 +0.008264 +0.008323 +0.008279 +0.008301 +0.008259 +0.008247 +0.008274 +0.008347 +0.008308 +0.008336 +0.008283 +0.008264 +0.008302 +0.008381 +0.008364 +0.008411 +0.008371 +0.008355 +0.008389 +0.008469 +0.008453 +0.00147 +0.008475 +0.008449 +0.008445 +0.008476 +0.008563 +0.008543 +0.008562 +0.008527 +0.00851 +0.00855 +0.008635 +0.0086 +0.008651 +0.008613 +0.008611 +0.00865 +0.008732 +0.008721 +0.008753 +0.008707 +0.008714 +0.008753 +0.008861 +0.008833 +0.008806 +0.00875 +0.00874 +0.008778 +0.008862 +0.008798 +0.008804 +0.008734 +0.008688 +0.008678 +0.008673 +0.008572 +0.008562 +0.008493 +0.008452 +0.008435 +0.008456 +0.008403 +0.008402 +0.008311 +0.008266 +0.008245 +0.008306 +0.008233 +0.008252 +0.008197 +0.008169 +0.008209 +0.008231 +0.008187 +0.008196 +0.008139 +0.008133 +0.008118 +0.008188 +0.008143 +0.00817 +0.008141 +0.008129 +0.008165 +0.008252 +0.008217 +0.008259 +0.008212 +0.008205 +0.008251 +0.008343 +0.008323 +0.008328 +0.008316 +0.001471 +0.008304 +0.00832 +0.008388 +0.008355 +0.008391 +0.008355 +0.008345 +0.008389 +0.008471 +0.008447 +0.008476 +0.008432 +0.008422 +0.008455 +0.008536 +0.008514 +0.008548 +0.00851 +0.008529 +0.008569 +0.008649 +0.008619 +0.008648 +0.008589 +0.008569 +0.008573 +0.008611 +0.008541 +0.00853 +0.008416 +0.00837 +0.008344 +0.008374 +0.00832 +0.008312 +0.008212 +0.008182 +0.008173 +0.008207 +0.008167 +0.008169 +0.008103 +0.00807 +0.008071 +0.008125 +0.008095 +0.008113 +0.008056 +0.00804 +0.008059 +0.008121 +0.008097 +0.008124 +0.008076 +0.008062 +0.008094 +0.008166 +0.008148 +0.008174 +0.008132 +0.008128 +0.008162 +0.008246 +0.008231 +0.00824 +0.008208 +0.001472 +0.008214 +0.008238 +0.008331 +0.008306 +0.008332 +0.008298 +0.00828 +0.00831 +0.008392 +0.008369 +0.008407 +0.008376 +0.008368 +0.008403 +0.008482 +0.008464 +0.008496 +0.008453 +0.008447 +0.008492 +0.008574 +0.008565 +0.008593 +0.008562 +0.008556 +0.008607 +0.008684 +0.008614 +0.008623 +0.008563 +0.008538 +0.008534 +0.008564 +0.008505 +0.00848 +0.008375 +0.008328 +0.008314 +0.008345 +0.008279 +0.008282 +0.00823 +0.008175 +0.008152 +0.00819 +0.008129 +0.008148 +0.008082 +0.00806 +0.008083 +0.008132 +0.008092 +0.008082 +0.008042 +0.008016 +0.008033 +0.008109 +0.008058 +0.008086 +0.008053 +0.00803 +0.008072 +0.008154 +0.008112 +0.008157 +0.008116 +0.008088 +0.008111 +0.00818 +0.008147 +0.008197 +0.008161 +0.008149 +0.008213 +0.008259 +0.008248 +0.001473 +0.008281 +0.008248 +0.008246 +0.008281 +0.008366 +0.008336 +0.008372 +0.008334 +0.008325 +0.00836 +0.008446 +0.008414 +0.008442 +0.0084 +0.008385 +0.008415 +0.008502 +0.008474 +0.008504 +0.00849 +0.008485 +0.008529 +0.008597 +0.008555 +0.008564 +0.008485 +0.008437 +0.008435 +0.008467 +0.008392 +0.008396 +0.008297 +0.008245 +0.008244 +0.00829 +0.008213 +0.008223 +0.008151 +0.008113 +0.008115 +0.008163 +0.008118 +0.008132 +0.008064 +0.008027 +0.008047 +0.008108 +0.008078 +0.008099 +0.008044 +0.008022 +0.008046 +0.008108 +0.00809 +0.008122 +0.00808 +0.008062 +0.008097 +0.008172 +0.008148 +0.008188 +0.008133 +0.008137 +0.00818 +0.008245 +0.008227 +0.008258 +0.001474 +0.008219 +0.008214 +0.00825 +0.008331 +0.008308 +0.00834 +0.008298 +0.00829 +0.008329 +0.008413 +0.00839 +0.008422 +0.008377 +0.008371 +0.008407 +0.008489 +0.008466 +0.008506 +0.008463 +0.008453 +0.008498 +0.008584 +0.008564 +0.008619 +0.00856 +0.008561 +0.008608 +0.008687 +0.008571 +0.008552 +0.00849 +0.00845 +0.00841 +0.008448 +0.008388 +0.008387 +0.008314 +0.008284 +0.008241 +0.008267 +0.008225 +0.008235 +0.008181 +0.008147 +0.008155 +0.008191 +0.008122 +0.008147 +0.00809 +0.00809 +0.008095 +0.008154 +0.008097 +0.008126 +0.008083 +0.008068 +0.008101 +0.008177 +0.008149 +0.008184 +0.008141 +0.00814 +0.008169 +0.008255 +0.008221 +0.008255 +0.008226 +0.008189 +0.008209 +0.001475 +0.008292 +0.008261 +0.008288 +0.008277 +0.008248 +0.008296 +0.008372 +0.008362 +0.00839 +0.008361 +0.008344 +0.008395 +0.00846 +0.008453 +0.008473 +0.008441 +0.008422 +0.00846 +0.008534 +0.008524 +0.008563 +0.008536 +0.008515 +0.008549 +0.008627 +0.008613 +0.008643 +0.00861 +0.008572 +0.008579 +0.008626 +0.008571 +0.008547 +0.008465 +0.008396 +0.008384 +0.00842 +0.008355 +0.008343 +0.008277 +0.008219 +0.008208 +0.008263 +0.008222 +0.008218 +0.008167 +0.008127 +0.008125 +0.008194 +0.008145 +0.008159 +0.008124 +0.008094 +0.008115 +0.008184 +0.008156 +0.008168 +0.008133 +0.008118 +0.008156 +0.008234 +0.00821 +0.008232 +0.008203 +0.008177 +0.008226 +0.008295 +0.008286 +0.008317 +0.00828 +0.001476 +0.008255 +0.008321 +0.008371 +0.008368 +0.008389 +0.008362 +0.00834 +0.008392 +0.008457 +0.008453 +0.008465 +0.008445 +0.008421 +0.008474 +0.008544 +0.008543 +0.008555 +0.008529 +0.008509 +0.00856 +0.008629 +0.00863 +0.008647 +0.008632 +0.008618 +0.008682 +0.008742 +0.008688 +0.008694 +0.008647 +0.008602 +0.008612 +0.008643 +0.008598 +0.008533 +0.008463 +0.008392 +0.00839 +0.008411 +0.008365 +0.008354 +0.008295 +0.008228 +0.008205 +0.008249 +0.008207 +0.008203 +0.008168 +0.00811 +0.008123 +0.008167 +0.008127 +0.008144 +0.008084 +0.008045 +0.008061 +0.008105 +0.008095 +0.008095 +0.008077 +0.008044 +0.00809 +0.008154 +0.008145 +0.008143 +0.00814 +0.008105 +0.008143 +0.008186 +0.008164 +0.00819 +0.00818 +0.008148 +0.008205 +0.008276 +0.008269 +0.008277 +0.001477 +0.008259 +0.008242 +0.008305 +0.008353 +0.008346 +0.008377 +0.008343 +0.008323 +0.00837 +0.008439 +0.008418 +0.008441 +0.008402 +0.008384 +0.008426 +0.008503 +0.00848 +0.008518 +0.008508 +0.00849 +0.008533 +0.008601 +0.008571 +0.008569 +0.008506 +0.008447 +0.008457 +0.008483 +0.008421 +0.008405 +0.008333 +0.008269 +0.008273 +0.008304 +0.008255 +0.00826 +0.008186 +0.008142 +0.00816 +0.008207 +0.008167 +0.00817 +0.008124 +0.008078 +0.008106 +0.00816 +0.008138 +0.008155 +0.008121 +0.008076 +0.008116 +0.008179 +0.008158 +0.008178 +0.008154 +0.00814 +0.008184 +0.008256 +0.008238 +0.008264 +0.008225 +0.008217 +0.008236 +0.008314 +0.001478 +0.0083 +0.008335 +0.008314 +0.008288 +0.008336 +0.008405 +0.008395 +0.008408 +0.008389 +0.008365 +0.008426 +0.00849 +0.008483 +0.008497 +0.008472 +0.008447 +0.008498 +0.008561 +0.008565 +0.008574 +0.008565 +0.008538 +0.008609 +0.008677 +0.008665 +0.008682 +0.008635 +0.008515 +0.008523 +0.008558 +0.008518 +0.008497 +0.008408 +0.008302 +0.008299 +0.008339 +0.008301 +0.008281 +0.008231 +0.008175 +0.008135 +0.008155 +0.008129 +0.008117 +0.008091 +0.008016 +0.008062 +0.008105 +0.008062 +0.008039 +0.007995 +0.007952 +0.007991 +0.00806 +0.008019 +0.00804 +0.008004 +0.007971 +0.008031 +0.008081 +0.008072 +0.008055 +0.008028 +0.008008 +0.008055 +0.00812 +0.00811 +0.008124 +0.008104 +0.008094 +0.008147 +0.008211 +0.008201 +0.008211 +0.001479 +0.008182 +0.008174 +0.008219 +0.008295 +0.00827 +0.008294 +0.008266 +0.008255 +0.008301 +0.008369 +0.008341 +0.008351 +0.008322 +0.008294 +0.008338 +0.008409 +0.008394 +0.008421 +0.008388 +0.008372 +0.008444 +0.008531 +0.008521 +0.008535 +0.008483 +0.008448 +0.008452 +0.00848 +0.008428 +0.008421 +0.008338 +0.008281 +0.008281 +0.008316 +0.008252 +0.008244 +0.008173 +0.008126 +0.008142 +0.008166 +0.008141 +0.008131 +0.00807 +0.00803 +0.008047 +0.008104 +0.008064 +0.008084 +0.008033 +0.008007 +0.008029 +0.008088 +0.008077 +0.008096 +0.008057 +0.008034 +0.008069 +0.008139 +0.008136 +0.008159 +0.008125 +0.008114 +0.008145 +0.008224 +0.008195 +0.00823 +0.0082 +0.00148 +0.008191 +0.008227 +0.008298 +0.008294 +0.008311 +0.008272 +0.008257 +0.008304 +0.008383 +0.008368 +0.008391 +0.008359 +0.008341 +0.008389 +0.00846 +0.008445 +0.008472 +0.008443 +0.008421 +0.008469 +0.008547 +0.00854 +0.00856 +0.008534 +0.00852 +0.008584 +0.00866 +0.008644 +0.008676 +0.008566 +0.008497 +0.008502 +0.008547 +0.008497 +0.008456 +0.008344 +0.008284 +0.008272 +0.008293 +0.008242 +0.008237 +0.008172 +0.008106 +0.00807 +0.008106 +0.00807 +0.008063 +0.008011 +0.007962 +0.008 +0.008047 +0.007991 +0.007989 +0.007933 +0.007917 +0.007938 +0.007996 +0.007968 +0.00798 +0.00795 +0.007932 +0.007969 +0.008053 +0.008023 +0.008015 +0.007999 +0.007953 +0.008012 +0.00809 +0.00806 +0.008087 +0.008069 +0.008052 +0.008094 +0.008172 +0.008171 +0.008164 +0.001481 +0.008142 +0.008134 +0.008177 +0.008261 +0.008231 +0.008264 +0.008224 +0.00822 +0.008251 +0.008333 +0.008297 +0.008323 +0.008282 +0.008267 +0.008301 +0.008379 +0.008345 +0.008381 +0.008346 +0.008332 +0.008364 +0.008475 +0.008475 +0.008509 +0.008464 +0.00843 +0.00844 +0.00849 +0.008421 +0.008398 +0.008321 +0.008282 +0.008275 +0.008318 +0.00825 +0.008245 +0.008174 +0.008133 +0.008138 +0.00819 +0.008146 +0.008155 +0.0081 +0.008062 +0.008076 +0.008134 +0.008103 +0.008126 +0.008073 +0.00805 +0.008069 +0.00815 +0.008099 +0.008138 +0.0081 +0.008082 +0.008115 +0.008194 +0.008172 +0.008206 +0.008168 +0.008154 +0.008193 +0.008276 +0.008258 +0.008277 +0.001482 +0.008247 +0.008235 +0.00827 +0.008354 +0.008323 +0.008364 +0.008324 +0.00832 +0.008351 +0.008435 +0.008412 +0.008447 +0.008405 +0.008393 +0.008436 +0.008515 +0.008494 +0.008524 +0.00849 +0.008476 +0.00851 +0.008598 +0.008579 +0.008615 +0.008575 +0.008574 +0.00861 +0.008703 +0.008687 +0.008722 +0.008682 +0.008672 +0.008666 +0.008661 +0.008578 +0.008582 +0.008517 +0.008455 +0.008388 +0.008405 +0.008329 +0.008332 +0.008272 +0.008216 +0.008232 +0.008229 +0.008171 +0.008169 +0.008091 +0.008046 +0.008028 +0.008088 +0.008036 +0.008046 +0.008009 +0.007979 +0.008009 +0.008073 +0.008012 +0.008021 +0.007952 +0.007942 +0.007986 +0.008048 +0.008016 +0.00805 +0.008004 +0.007995 +0.008009 +0.008077 +0.008049 +0.008088 +0.008049 +0.008049 +0.008091 +0.008165 +0.008157 +0.00816 +0.008143 +0.001483 +0.008134 +0.008166 +0.008249 +0.00823 +0.008266 +0.008229 +0.008216 +0.008255 +0.008338 +0.008311 +0.008349 +0.008296 +0.008287 +0.008319 +0.008398 +0.008365 +0.008398 +0.008357 +0.008351 +0.008372 +0.008461 +0.008464 +0.008506 +0.008466 +0.008454 +0.008468 +0.008537 +0.008486 +0.008474 +0.008407 +0.008359 +0.008338 +0.008382 +0.008329 +0.00832 +0.008243 +0.008203 +0.008196 +0.00825 +0.008209 +0.008218 +0.008159 +0.008128 +0.00813 +0.008188 +0.008156 +0.008167 +0.008121 +0.0081 +0.008116 +0.008184 +0.008162 +0.008173 +0.008137 +0.008132 +0.008159 +0.008233 +0.008209 +0.00824 +0.008212 +0.008208 +0.00823 +0.008324 +0.008305 +0.008315 +0.008278 +0.001484 +0.008273 +0.008302 +0.008387 +0.008369 +0.008407 +0.008373 +0.008357 +0.008389 +0.008471 +0.008447 +0.008481 +0.008446 +0.008441 +0.008482 +0.008556 +0.008535 +0.008569 +0.008527 +0.008515 +0.008564 +0.008647 +0.008618 +0.008661 +0.008614 +0.008616 +0.008659 +0.008757 +0.008736 +0.00877 +0.008725 +0.00865 +0.00865 +0.00869 +0.00864 +0.008652 +0.008582 +0.008548 +0.008543 +0.008507 +0.00843 +0.008447 +0.008371 +0.00833 +0.008339 +0.008343 +0.008292 +0.008291 +0.008246 +0.008203 +0.008201 +0.008233 +0.008203 +0.00822 +0.008182 +0.008166 +0.008175 +0.008266 +0.008213 +0.008235 +0.008204 +0.008165 +0.008182 +0.008245 +0.008208 +0.008257 +0.008213 +0.008202 +0.008254 +0.008329 +0.008306 +0.008342 +0.0083 +0.008303 +0.00836 +0.008403 +0.008391 +0.001485 +0.008431 +0.008392 +0.008383 +0.008429 +0.008521 +0.008488 +0.008514 +0.008451 +0.00844 +0.008475 +0.008564 +0.008522 +0.008558 +0.008515 +0.008503 +0.008535 +0.008618 +0.008597 +0.008639 +0.008622 +0.008625 +0.008659 +0.008736 +0.008717 +0.008744 +0.008716 +0.008697 +0.008708 +0.00877 +0.008699 +0.008683 +0.008594 +0.008537 +0.008515 +0.00855 +0.008489 +0.00847 +0.008396 +0.008345 +0.008338 +0.008391 +0.008341 +0.008339 +0.008274 +0.008233 +0.00824 +0.008305 +0.008248 +0.008269 +0.008221 +0.008194 +0.008214 +0.008288 +0.008253 +0.008278 +0.008239 +0.008226 +0.008249 +0.008334 +0.008305 +0.008337 +0.008305 +0.008293 +0.008331 +0.008414 +0.008378 +0.008427 +0.008378 +0.001486 +0.008375 +0.008416 +0.008498 +0.008474 +0.008499 +0.008457 +0.008447 +0.00849 +0.008567 +0.008555 +0.008587 +0.008554 +0.008531 +0.008576 +0.008661 +0.00863 +0.008665 +0.008636 +0.008614 +0.008655 +0.00874 +0.008727 +0.008754 +0.008726 +0.008719 +0.008761 +0.008848 +0.008838 +0.008858 +0.008829 +0.008802 +0.008768 +0.008748 +0.008692 +0.008676 +0.008626 +0.008566 +0.008498 +0.008527 +0.008456 +0.008451 +0.008403 +0.008353 +0.00838 +0.008414 +0.008314 +0.00832 +0.008252 +0.008214 +0.00822 +0.008277 +0.008223 +0.008258 +0.008204 +0.008181 +0.008216 +0.008283 +0.00825 +0.008232 +0.008203 +0.008163 +0.008214 +0.008291 +0.008254 +0.008287 +0.008256 +0.008237 +0.008273 +0.008334 +0.008301 +0.008335 +0.008314 +0.008296 +0.008354 +0.008414 +0.008403 +0.001487 +0.008431 +0.008395 +0.008385 +0.008429 +0.008516 +0.008484 +0.008522 +0.008482 +0.00847 +0.008518 +0.008599 +0.008561 +0.008587 +0.008547 +0.00853 +0.008563 +0.008645 +0.008614 +0.008651 +0.008608 +0.008594 +0.008647 +0.008755 +0.008749 +0.008767 +0.008704 +0.008668 +0.008658 +0.008689 +0.008623 +0.008621 +0.008518 +0.008457 +0.008443 +0.008482 +0.008419 +0.008418 +0.008338 +0.008297 +0.008296 +0.008347 +0.008303 +0.008308 +0.008235 +0.008208 +0.00822 +0.008276 +0.008239 +0.008262 +0.008201 +0.008185 +0.008208 +0.008274 +0.008251 +0.008275 +0.00823 +0.008223 +0.008248 +0.008327 +0.008315 +0.008341 +0.0083 +0.008301 +0.008325 +0.008417 +0.008393 +0.008416 +0.001488 +0.008388 +0.008377 +0.008415 +0.008491 +0.00848 +0.008502 +0.008467 +0.008451 +0.008497 +0.008579 +0.008562 +0.008586 +0.008556 +0.008536 +0.008581 +0.008658 +0.00864 +0.008668 +0.008642 +0.008619 +0.008665 +0.008754 +0.008736 +0.008771 +0.008738 +0.008722 +0.008781 +0.008871 +0.008848 +0.008866 +0.008754 +0.008673 +0.008664 +0.0087 +0.00865 +0.00858 +0.008489 +0.008434 +0.008426 +0.008447 +0.008401 +0.008388 +0.008328 +0.008254 +0.008232 +0.008276 +0.008226 +0.008232 +0.008177 +0.00815 +0.008173 +0.008248 +0.008198 +0.008222 +0.008147 +0.008093 +0.008127 +0.008182 +0.008157 +0.008177 +0.008141 +0.008132 +0.008169 +0.008242 +0.00822 +0.008243 +0.008214 +0.008212 +0.008234 +0.008286 +0.008263 +0.008289 +0.008263 +0.008271 +0.008284 +0.001489 +0.008364 +0.008362 +0.008377 +0.008361 +0.008326 +0.008385 +0.008454 +0.008444 +0.008462 +0.008442 +0.008414 +0.008472 +0.008534 +0.008521 +0.00853 +0.00851 +0.008466 +0.008528 +0.008594 +0.008586 +0.008603 +0.008605 +0.00858 +0.008638 +0.008699 +0.008676 +0.008681 +0.008626 +0.008556 +0.008565 +0.008579 +0.008524 +0.008495 +0.008414 +0.008342 +0.008358 +0.008378 +0.008328 +0.008323 +0.008269 +0.008196 +0.008225 +0.00826 +0.008226 +0.008217 +0.008169 +0.00812 +0.008153 +0.008198 +0.008173 +0.008181 +0.008143 +0.008107 +0.008153 +0.008207 +0.008186 +0.008199 +0.008172 +0.00815 +0.008203 +0.008266 +0.008257 +0.008277 +0.008244 +0.008224 +0.008266 +0.008341 +0.008324 +0.008349 +0.00149 +0.008332 +0.008309 +0.008354 +0.008418 +0.008415 +0.008429 +0.008405 +0.008372 +0.008429 +0.008502 +0.008498 +0.008514 +0.008491 +0.008461 +0.008516 +0.00858 +0.00858 +0.008594 +0.008564 +0.008547 +0.008595 +0.008671 +0.008666 +0.008691 +0.008671 +0.008634 +0.008707 +0.008787 +0.008767 +0.008776 +0.008711 +0.008577 +0.008569 +0.008595 +0.008555 +0.008534 +0.008419 +0.008329 +0.008347 +0.00836 +0.008324 +0.008314 +0.008271 +0.008212 +0.008183 +0.008188 +0.008155 +0.008143 +0.008124 +0.008066 +0.008117 +0.008154 +0.008137 +0.008133 +0.008103 +0.008079 +0.008114 +0.008156 +0.008105 +0.00812 +0.008102 +0.008065 +0.008101 +0.008149 +0.008122 +0.008149 +0.008136 +0.008107 +0.008157 +0.008237 +0.008224 +0.008243 +0.008222 +0.008205 +0.008264 +0.008313 +0.001491 +0.008302 +0.008331 +0.008305 +0.008292 +0.008335 +0.008411 +0.008394 +0.008419 +0.008387 +0.008368 +0.008421 +0.00849 +0.008467 +0.008485 +0.008454 +0.008433 +0.008474 +0.008547 +0.008512 +0.008533 +0.008504 +0.008492 +0.008525 +0.008615 +0.008625 +0.008661 +0.008614 +0.008566 +0.008568 +0.008598 +0.008523 +0.008507 +0.008438 +0.008369 +0.008358 +0.008381 +0.008333 +0.008324 +0.008256 +0.008198 +0.008211 +0.008249 +0.008204 +0.008214 +0.00814 +0.008103 +0.008122 +0.008177 +0.008131 +0.008148 +0.008107 +0.008082 +0.008114 +0.008181 +0.008141 +0.008162 +0.008123 +0.008094 +0.008149 +0.008223 +0.0082 +0.008227 +0.008193 +0.008167 +0.008217 +0.008281 +0.008272 +0.008305 +0.00827 +0.001492 +0.008254 +0.008308 +0.008364 +0.008365 +0.00838 +0.008353 +0.008322 +0.008374 +0.008438 +0.008451 +0.008459 +0.00844 +0.008412 +0.008464 +0.008531 +0.008533 +0.008535 +0.008513 +0.008487 +0.008543 +0.008603 +0.008618 +0.008617 +0.00861 +0.008578 +0.008645 +0.008718 +0.008713 +0.008722 +0.008709 +0.008672 +0.008649 +0.008635 +0.008578 +0.008557 +0.008509 +0.008449 +0.008433 +0.008399 +0.008338 +0.008317 +0.008283 +0.008217 +0.008248 +0.008245 +0.008187 +0.008171 +0.00813 +0.008079 +0.008069 +0.008119 +0.008069 +0.008084 +0.008041 +0.008018 +0.008049 +0.008112 +0.008084 +0.008082 +0.008066 +0.008025 +0.008078 +0.008109 +0.008085 +0.008107 +0.008087 +0.00806 +0.008128 +0.008185 +0.008161 +0.008193 +0.008177 +0.008136 +0.008179 +0.008239 +0.008213 +0.008234 +0.001493 +0.008214 +0.008209 +0.008235 +0.008323 +0.008312 +0.008331 +0.008315 +0.008281 +0.008337 +0.0084 +0.008394 +0.008409 +0.008386 +0.008359 +0.008411 +0.008479 +0.008469 +0.008483 +0.008477 +0.00845 +0.008512 +0.008579 +0.008566 +0.008587 +0.008552 +0.008524 +0.008576 +0.008635 +0.008619 +0.008596 +0.008536 +0.008464 +0.008462 +0.00848 +0.00844 +0.0084 +0.008326 +0.008273 +0.008275 +0.008296 +0.008265 +0.008247 +0.008187 +0.008131 +0.008148 +0.008182 +0.008162 +0.008149 +0.008099 +0.008063 +0.008093 +0.008141 +0.008127 +0.008129 +0.008092 +0.008064 +0.008109 +0.008146 +0.008149 +0.008164 +0.008132 +0.008114 +0.008157 +0.008216 +0.008217 +0.008226 +0.008206 +0.008191 +0.008232 +0.008296 +0.008296 +0.001494 +0.008308 +0.008286 +0.00826 +0.008304 +0.008379 +0.008376 +0.008395 +0.008367 +0.008342 +0.008389 +0.008459 +0.008455 +0.008475 +0.00845 +0.008423 +0.00848 +0.008548 +0.008533 +0.008562 +0.008528 +0.008507 +0.008562 +0.008642 +0.008637 +0.008653 +0.008638 +0.008618 +0.008674 +0.008666 +0.008584 +0.008571 +0.008524 +0.008418 +0.008402 +0.008427 +0.00837 +0.008358 +0.008301 +0.008204 +0.008198 +0.008252 +0.008206 +0.008206 +0.008136 +0.008061 +0.008082 +0.008117 +0.00809 +0.008094 +0.008061 +0.008026 +0.008061 +0.008127 +0.008085 +0.008098 +0.008035 +0.008004 +0.008053 +0.008104 +0.008086 +0.008101 +0.008072 +0.00806 +0.008107 +0.00817 +0.008164 +0.008176 +0.008146 +0.008121 +0.008164 +0.008207 +0.008194 +0.008227 +0.008205 +0.001495 +0.008187 +0.008229 +0.008305 +0.008292 +0.00832 +0.008291 +0.008275 +0.008322 +0.008392 +0.008375 +0.008403 +0.008371 +0.008349 +0.008393 +0.008465 +0.008447 +0.00847 +0.008436 +0.008419 +0.00848 +0.008558 +0.008551 +0.00856 +0.00853 +0.008519 +0.008557 +0.008635 +0.0086 +0.008592 +0.008523 +0.008467 +0.008453 +0.008477 +0.008423 +0.008387 +0.008313 +0.008259 +0.008258 +0.008311 +0.008264 +0.008234 +0.008196 +0.008147 +0.00816 +0.008209 +0.008167 +0.008165 +0.008117 +0.008079 +0.0081 +0.008166 +0.008142 +0.008147 +0.008108 +0.008079 +0.008106 +0.008176 +0.008163 +0.008175 +0.008144 +0.008127 +0.008157 +0.008236 +0.008223 +0.008247 +0.00822 +0.008195 +0.008249 +0.008308 +0.008303 +0.001496 +0.008332 +0.008294 +0.008286 +0.008317 +0.008396 +0.008381 +0.008418 +0.008376 +0.008367 +0.008399 +0.00849 +0.008453 +0.008492 +0.008456 +0.008448 +0.008486 +0.008565 +0.00855 +0.00858 +0.008537 +0.008537 +0.008572 +0.008663 +0.008643 +0.008675 +0.008646 +0.008647 +0.008696 +0.008737 +0.008634 +0.00863 +0.008563 +0.008502 +0.008453 +0.008481 +0.008412 +0.008416 +0.008338 +0.008266 +0.008226 +0.008266 +0.008214 +0.008222 +0.008184 +0.008116 +0.008089 +0.008126 +0.00809 +0.008103 +0.008063 +0.008033 +0.008064 +0.008129 +0.008088 +0.00811 +0.008059 +0.00805 +0.008033 +0.008096 +0.008065 +0.008095 +0.008069 +0.008052 +0.008092 +0.008175 +0.008145 +0.008174 +0.008149 +0.008139 +0.008169 +0.008265 +0.008251 +0.008246 +0.008229 +0.001497 +0.008233 +0.008263 +0.008353 +0.008318 +0.008342 +0.008286 +0.008274 +0.008313 +0.008396 +0.008362 +0.008397 +0.008361 +0.008348 +0.008382 +0.008461 +0.00843 +0.008464 +0.008426 +0.008427 +0.008459 +0.008567 +0.008545 +0.00858 +0.00853 +0.00853 +0.008559 +0.008636 +0.008594 +0.008597 +0.008518 +0.008473 +0.008455 +0.008491 +0.008431 +0.008411 +0.008327 +0.008287 +0.008277 +0.008321 +0.008277 +0.008277 +0.008205 +0.00818 +0.008188 +0.008252 +0.008213 +0.008213 +0.008157 +0.008139 +0.008159 +0.00823 +0.008206 +0.008213 +0.008165 +0.008149 +0.008162 +0.008245 +0.008233 +0.008253 +0.008207 +0.008197 +0.008225 +0.008308 +0.008291 +0.008326 +0.00829 +0.008272 +0.00832 +0.008374 +0.001498 +0.008374 +0.008407 +0.008367 +0.008356 +0.008387 +0.008468 +0.00845 +0.008491 +0.008454 +0.008438 +0.008473 +0.008557 +0.008533 +0.008569 +0.008528 +0.008511 +0.008549 +0.008636 +0.008612 +0.008651 +0.008615 +0.008606 +0.008652 +0.00874 +0.008719 +0.008757 +0.008719 +0.00871 +0.008727 +0.008701 +0.008623 +0.008619 +0.008551 +0.008469 +0.008422 +0.008451 +0.008386 +0.008394 +0.008324 +0.008272 +0.008274 +0.008289 +0.008206 +0.008232 +0.008171 +0.008143 +0.008113 +0.008155 +0.008103 +0.008122 +0.00809 +0.008064 +0.008096 +0.008174 +0.008118 +0.008145 +0.008102 +0.008088 +0.008137 +0.008188 +0.008155 +0.008182 +0.008139 +0.008142 +0.008156 +0.008233 +0.008203 +0.008238 +0.00821 +0.00821 +0.008244 +0.008319 +0.008316 +0.001499 +0.008314 +0.008298 +0.008287 +0.008333 +0.008427 +0.008385 +0.008415 +0.008382 +0.008374 +0.008415 +0.008498 +0.008461 +0.008492 +0.008447 +0.008429 +0.008458 +0.008537 +0.008506 +0.008548 +0.008502 +0.008493 +0.008531 +0.008638 +0.008641 +0.00867 +0.008609 +0.008568 +0.00857 +0.008605 +0.00853 +0.008522 +0.008449 +0.008403 +0.008395 +0.008438 +0.008389 +0.008387 +0.00831 +0.008275 +0.008278 +0.008329 +0.008286 +0.008312 +0.008222 +0.0082 +0.008205 +0.008259 +0.008224 +0.008254 +0.008205 +0.008189 +0.008205 +0.008264 +0.008234 +0.008249 +0.008195 +0.008188 +0.00822 +0.008305 +0.008283 +0.008311 +0.008267 +0.008269 +0.008302 +0.00838 +0.008362 +0.008394 +0.008357 +0.008337 +0.0015 +0.008385 +0.008465 +0.008448 +0.008468 +0.008436 +0.008417 +0.008468 +0.008545 +0.00853 +0.008554 +0.008525 +0.008499 +0.008553 +0.008629 +0.008611 +0.008636 +0.008607 +0.008582 +0.008639 +0.008714 +0.008706 +0.00873 +0.008712 +0.00869 +0.008743 +0.008825 +0.0088 +0.00882 +0.008692 +0.008619 +0.00864 +0.008679 +0.008607 +0.008543 +0.008466 +0.008409 +0.008434 +0.008459 +0.008398 +0.008387 +0.008301 +0.008258 +0.008263 +0.008289 +0.00825 +0.008245 +0.008211 +0.008172 +0.008204 +0.008237 +0.008197 +0.008208 +0.008169 +0.008145 +0.008151 +0.008225 +0.008186 +0.008211 +0.008189 +0.008166 +0.008215 +0.008284 +0.00826 +0.00829 +0.008257 +0.008254 +0.008275 +0.00833 +0.008313 +0.008335 +0.008313 +0.001501 +0.008307 +0.008336 +0.008426 +0.008399 +0.008441 +0.008402 +0.008393 +0.008429 +0.008515 +0.008489 +0.008522 +0.008486 +0.008477 +0.008516 +0.008594 +0.008557 +0.008588 +0.008543 +0.008536 +0.008566 +0.008655 +0.008627 +0.008654 +0.00864 +0.008638 +0.008687 +0.008758 +0.008724 +0.008737 +0.00866 +0.008608 +0.008604 +0.008642 +0.008573 +0.008562 +0.008468 +0.00842 +0.008415 +0.008452 +0.008401 +0.008402 +0.008317 +0.008285 +0.008295 +0.00834 +0.00829 +0.008303 +0.008236 +0.008204 +0.00822 +0.008282 +0.008252 +0.00827 +0.008218 +0.008189 +0.008215 +0.008284 +0.008265 +0.008288 +0.008235 +0.00822 +0.008255 +0.008335 +0.008311 +0.008352 +0.008306 +0.008298 +0.008327 +0.00842 +0.008394 +0.008427 +0.001502 +0.008391 +0.008382 +0.008409 +0.008489 +0.008483 +0.008508 +0.008473 +0.008455 +0.008501 +0.008577 +0.008566 +0.008589 +0.00856 +0.008543 +0.008582 +0.008649 +0.008646 +0.008671 +0.008637 +0.008626 +0.00867 +0.008759 +0.008744 +0.00877 +0.008745 +0.008733 +0.008784 +0.008873 +0.008838 +0.008777 +0.008671 +0.008614 +0.008634 +0.008675 +0.008574 +0.00853 +0.008462 +0.008406 +0.0084 +0.008433 +0.008384 +0.008377 +0.008298 +0.008234 +0.008233 +0.008287 +0.008231 +0.00825 +0.008192 +0.008176 +0.008192 +0.008256 +0.008208 +0.008217 +0.008162 +0.008142 +0.008178 +0.008232 +0.008219 +0.008235 +0.008206 +0.008195 +0.008231 +0.008298 +0.008275 +0.008289 +0.008271 +0.008259 +0.008317 +0.008367 +0.008355 +0.008395 +0.001503 +0.00835 +0.008345 +0.008343 +0.008432 +0.008402 +0.008436 +0.008406 +0.008394 +0.008436 +0.008521 +0.008497 +0.008533 +0.008496 +0.008484 +0.00852 +0.008598 +0.008575 +0.008616 +0.008592 +0.008586 +0.008617 +0.008701 +0.008679 +0.008699 +0.008665 +0.00866 +0.00871 +0.008777 +0.008734 +0.008743 +0.008665 +0.00861 +0.008601 +0.008628 +0.008562 +0.008561 +0.008475 +0.008415 +0.008411 +0.008457 +0.008403 +0.008406 +0.00833 +0.008293 +0.0083 +0.008344 +0.008292 +0.008297 +0.008235 +0.00821 +0.008234 +0.008294 +0.00825 +0.008265 +0.008211 +0.008182 +0.00822 +0.008289 +0.00825 +0.008274 +0.008229 +0.008218 +0.008259 +0.008339 +0.008314 +0.008347 +0.0083 +0.008286 +0.008319 +0.0084 +0.008382 +0.008421 +0.008397 +0.001504 +0.008367 +0.008403 +0.008494 +0.008466 +0.0085 +0.00846 +0.008455 +0.008494 +0.00858 +0.008553 +0.008586 +0.008545 +0.00853 +0.008569 +0.008659 +0.008632 +0.008666 +0.008628 +0.008614 +0.008666 +0.008744 +0.008732 +0.00877 +0.008732 +0.00872 +0.008772 +0.008859 +0.008811 +0.0088 +0.00865 +0.0086 +0.008604 +0.00864 +0.008568 +0.008529 +0.00844 +0.008386 +0.008382 +0.008434 +0.008362 +0.008323 +0.008255 +0.008207 +0.008201 +0.008254 +0.00819 +0.008209 +0.008141 +0.008119 +0.008119 +0.008158 +0.008125 +0.008131 +0.008102 +0.008071 +0.008097 +0.008179 +0.008136 +0.008175 +0.008133 +0.008112 +0.008151 +0.008202 +0.008163 +0.008203 +0.008165 +0.008154 +0.008206 +0.008283 +0.008252 +0.008285 +0.00826 +0.008248 +0.008305 +0.001505 +0.00835 +0.008342 +0.008372 +0.008346 +0.008331 +0.008375 +0.008459 +0.00842 +0.008455 +0.008405 +0.008393 +0.008412 +0.00849 +0.008449 +0.008484 +0.008452 +0.008442 +0.008481 +0.008594 +0.008589 +0.008618 +0.008581 +0.00856 +0.008598 +0.008676 +0.008636 +0.008656 +0.008584 +0.008525 +0.008514 +0.008553 +0.008497 +0.008481 +0.00841 +0.008361 +0.00836 +0.008408 +0.008358 +0.008372 +0.008305 +0.008263 +0.008275 +0.008338 +0.008281 +0.008289 +0.008228 +0.008202 +0.00822 +0.008286 +0.008247 +0.008268 +0.008207 +0.008182 +0.008219 +0.008296 +0.00826 +0.00829 +0.008247 +0.008233 +0.008273 +0.008352 +0.008329 +0.008363 +0.008314 +0.008315 +0.008362 +0.008424 +0.00841 +0.001506 +0.00845 +0.008387 +0.008394 +0.008431 +0.008514 +0.008492 +0.008534 +0.008474 +0.008475 +0.008515 +0.008601 +0.008578 +0.008615 +0.00856 +0.008552 +0.008594 +0.008672 +0.008653 +0.008692 +0.008651 +0.008644 +0.008683 +0.008767 +0.008748 +0.008792 +0.008755 +0.00875 +0.008794 +0.008887 +0.008833 +0.008757 +0.008655 +0.008602 +0.008624 +0.008649 +0.008548 +0.008528 +0.008418 +0.008365 +0.008383 +0.008423 +0.008343 +0.008348 +0.008234 +0.008207 +0.008208 +0.008273 +0.008208 +0.008236 +0.00814 +0.008126 +0.008122 +0.008193 +0.008154 +0.00817 +0.008133 +0.0081 +0.008146 +0.008213 +0.008183 +0.00822 +0.008173 +0.008164 +0.008204 +0.008269 +0.008229 +0.008271 +0.008223 +0.00821 +0.008252 +0.008299 +0.008267 +0.008313 +0.008294 +0.001507 +0.00827 +0.008314 +0.008397 +0.008379 +0.008415 +0.00838 +0.008364 +0.008408 +0.008487 +0.008466 +0.008501 +0.008461 +0.008449 +0.008491 +0.00857 +0.008536 +0.008564 +0.008532 +0.008509 +0.008545 +0.008626 +0.008603 +0.008652 +0.008624 +0.008625 +0.00865 +0.00873 +0.008691 +0.008693 +0.008628 +0.008591 +0.008557 +0.008603 +0.008544 +0.008528 +0.008444 +0.008396 +0.008377 +0.008424 +0.008373 +0.008375 +0.008306 +0.008267 +0.008269 +0.008327 +0.008282 +0.008287 +0.008227 +0.008203 +0.008213 +0.008283 +0.008245 +0.008256 +0.008214 +0.008201 +0.008224 +0.008294 +0.008267 +0.008285 +0.008244 +0.008237 +0.008274 +0.00836 +0.008337 +0.008362 +0.008327 +0.008307 +0.008344 +0.008419 +0.00841 +0.001508 +0.008439 +0.008413 +0.008392 +0.008428 +0.00851 +0.008495 +0.008514 +0.008484 +0.008484 +0.008511 +0.008597 +0.008581 +0.008612 +0.008566 +0.008552 +0.008595 +0.008675 +0.00866 +0.00868 +0.00865 +0.008634 +0.008683 +0.008761 +0.008761 +0.008785 +0.008756 +0.008744 +0.008795 +0.008865 +0.008816 +0.008713 +0.008629 +0.008579 +0.008576 +0.008589 +0.0085 +0.008488 +0.008416 +0.008318 +0.008319 +0.008366 +0.008308 +0.008323 +0.008257 +0.008181 +0.008169 +0.00822 +0.008177 +0.00819 +0.008145 +0.008121 +0.008151 +0.008227 +0.008187 +0.008207 +0.008166 +0.008141 +0.008181 +0.008203 +0.008192 +0.008202 +0.008172 +0.008167 +0.008208 +0.008275 +0.008263 +0.008279 +0.008249 +0.008244 +0.008288 +0.008363 +0.008355 +0.008358 +0.008331 +0.001509 +0.008319 +0.008343 +0.008414 +0.008382 +0.008417 +0.008386 +0.008374 +0.00842 +0.008494 +0.008474 +0.008509 +0.008471 +0.008458 +0.008493 +0.008575 +0.008562 +0.008613 +0.008577 +0.008564 +0.0086 +0.008678 +0.008653 +0.008682 +0.008643 +0.008628 +0.008656 +0.008729 +0.008664 +0.00865 +0.00857 +0.008527 +0.008514 +0.008557 +0.008488 +0.008483 +0.008408 +0.008353 +0.008358 +0.008409 +0.008351 +0.008361 +0.008295 +0.008257 +0.008263 +0.008323 +0.008276 +0.008297 +0.008244 +0.008212 +0.008229 +0.008299 +0.00826 +0.008285 +0.008246 +0.008228 +0.008249 +0.008335 +0.008294 +0.008327 +0.008294 +0.008286 +0.008323 +0.008406 +0.008378 +0.008421 +0.008361 +0.008355 +0.008394 +0.00151 +0.00848 +0.008465 +0.008484 +0.00846 +0.008445 +0.008487 +0.008563 +0.008546 +0.008571 +0.008537 +0.008521 +0.008566 +0.008648 +0.008636 +0.008659 +0.008625 +0.008602 +0.008657 +0.008733 +0.008717 +0.008752 +0.00872 +0.008704 +0.008765 +0.008852 +0.00882 +0.008863 +0.008817 +0.008715 +0.008723 +0.00876 +0.00871 +0.008707 +0.008652 +0.008585 +0.00851 +0.008538 +0.008466 +0.008481 +0.008425 +0.008376 +0.008392 +0.008448 +0.00839 +0.008341 +0.008252 +0.00822 +0.008241 +0.008308 +0.008247 +0.008275 +0.00823 +0.008207 +0.008223 +0.008251 +0.008217 +0.008236 +0.008208 +0.008188 +0.008226 +0.008296 +0.008281 +0.008298 +0.008281 +0.008267 +0.008298 +0.008366 +0.008329 +0.008375 +0.008319 +0.008327 +0.008373 +0.008436 +0.001511 +0.008427 +0.00844 +0.008424 +0.008393 +0.008441 +0.008505 +0.008484 +0.008507 +0.008484 +0.00846 +0.008517 +0.008586 +0.008572 +0.00859 +0.008564 +0.008535 +0.008582 +0.008651 +0.008643 +0.008665 +0.008672 +0.008649 +0.008694 +0.008764 +0.008756 +0.008756 +0.008729 +0.008686 +0.008699 +0.008732 +0.008671 +0.00864 +0.008572 +0.008503 +0.008497 +0.008523 +0.008481 +0.008457 +0.008402 +0.008348 +0.008362 +0.008402 +0.00837 +0.008356 +0.008312 +0.008265 +0.00829 +0.008339 +0.008317 +0.00832 +0.008293 +0.008252 +0.008287 +0.008351 +0.008335 +0.008344 +0.008326 +0.008294 +0.008335 +0.008403 +0.0084 +0.008409 +0.008395 +0.008367 +0.008421 +0.008497 +0.008469 +0.008489 +0.001512 +0.008471 +0.008449 +0.008505 +0.00857 +0.008561 +0.008581 +0.008552 +0.008524 +0.008581 +0.008655 +0.008646 +0.008665 +0.008639 +0.008613 +0.008671 +0.00874 +0.008743 +0.008752 +0.008731 +0.0087 +0.008762 +0.008827 +0.008825 +0.008848 +0.008842 +0.008818 +0.008876 +0.008954 +0.008881 +0.008896 +0.008853 +0.008786 +0.008779 +0.008812 +0.008756 +0.008735 +0.008627 +0.00853 +0.00855 +0.008595 +0.008531 +0.008522 +0.008455 +0.008363 +0.00838 +0.008415 +0.00839 +0.008379 +0.00834 +0.008271 +0.008282 +0.008309 +0.008299 +0.008299 +0.008273 +0.008231 +0.008272 +0.008335 +0.008305 +0.008331 +0.008299 +0.008277 +0.008322 +0.008347 +0.008337 +0.008352 +0.008328 +0.008316 +0.008369 +0.008437 +0.008433 +0.008446 +0.00842 +0.008404 +0.008462 +0.001513 +0.008525 +0.008519 +0.008532 +0.008504 +0.008494 +0.008544 +0.008611 +0.008578 +0.008598 +0.008575 +0.008553 +0.008604 +0.008677 +0.008641 +0.008659 +0.008626 +0.008606 +0.008657 +0.008733 +0.008722 +0.00878 +0.008759 +0.008741 +0.008775 +0.008831 +0.008799 +0.008785 +0.008711 +0.008663 +0.008653 +0.008671 +0.008611 +0.008598 +0.008515 +0.00846 +0.008453 +0.008491 +0.008442 +0.008446 +0.008384 +0.008342 +0.008348 +0.008388 +0.00835 +0.008342 +0.008291 +0.008277 +0.008301 +0.008356 +0.008328 +0.008335 +0.008287 +0.008261 +0.008292 +0.00836 +0.008346 +0.008365 +0.008332 +0.008318 +0.008359 +0.00843 +0.008416 +0.008435 +0.008404 +0.008381 +0.008407 +0.0085 +0.008471 +0.001514 +0.008518 +0.008488 +0.008479 +0.00852 +0.0086 +0.008576 +0.008602 +0.008559 +0.008547 +0.008584 +0.008674 +0.008638 +0.00868 +0.008637 +0.008638 +0.008679 +0.00877 +0.008742 +0.008778 +0.008738 +0.008729 +0.008777 +0.008871 +0.008848 +0.008882 +0.008853 +0.008847 +0.008814 +0.008841 +0.008781 +0.00879 +0.008715 +0.008669 +0.008684 +0.008716 +0.008575 +0.008555 +0.008489 +0.008442 +0.008416 +0.008445 +0.00839 +0.008393 +0.008333 +0.008283 +0.008233 +0.008292 +0.008227 +0.008256 +0.008192 +0.00818 +0.008198 +0.00827 +0.008225 +0.008243 +0.008202 +0.008183 +0.008198 +0.008249 +0.008194 +0.00823 +0.008203 +0.008186 +0.008228 +0.008316 +0.008279 +0.008311 +0.008285 +0.008279 +0.008317 +0.008396 +0.008396 +0.008387 +0.008368 +0.001515 +0.008356 +0.008401 +0.008492 +0.008453 +0.008488 +0.008448 +0.008424 +0.008435 +0.008518 +0.008486 +0.008526 +0.008492 +0.008486 +0.008519 +0.008601 +0.00858 +0.008622 +0.008606 +0.008604 +0.008637 +0.008717 +0.008698 +0.008724 +0.008677 +0.008668 +0.008699 +0.008784 +0.008765 +0.008768 +0.008685 +0.008639 +0.008616 +0.008646 +0.008583 +0.008563 +0.008473 +0.008427 +0.008416 +0.008464 +0.00841 +0.008414 +0.008351 +0.008323 +0.008316 +0.008372 +0.008329 +0.008338 +0.008284 +0.00826 +0.008267 +0.008333 +0.008301 +0.008326 +0.008268 +0.008263 +0.008282 +0.008355 +0.008324 +0.008345 +0.008309 +0.00831 +0.008344 +0.008426 +0.008401 +0.008425 +0.00839 +0.008376 +0.008417 +0.008478 +0.001516 +0.008468 +0.008513 +0.008478 +0.008459 +0.008499 +0.008583 +0.008555 +0.008591 +0.008549 +0.008549 +0.008584 +0.00867 +0.008651 +0.008673 +0.008638 +0.00863 +0.008661 +0.008749 +0.008727 +0.008767 +0.008706 +0.00871 +0.008745 +0.008836 +0.008813 +0.008861 +0.008813 +0.008807 +0.00886 +0.008949 +0.008919 +0.008951 +0.008866 +0.008757 +0.00874 +0.008772 +0.008702 +0.008688 +0.008536 +0.008488 +0.008472 +0.008492 +0.008434 +0.008439 +0.008362 +0.008307 +0.008253 +0.008313 +0.008243 +0.008264 +0.008197 +0.008169 +0.008189 +0.008258 +0.008216 +0.008186 +0.008131 +0.008104 +0.008142 +0.008219 +0.008171 +0.008205 +0.00816 +0.008147 +0.008193 +0.00826 +0.008222 +0.008257 +0.008202 +0.008196 +0.008232 +0.008307 +0.008279 +0.008321 +0.008287 +0.008277 +0.008333 +0.001517 +0.008386 +0.008366 +0.008404 +0.008356 +0.008357 +0.008406 +0.008489 +0.008455 +0.008484 +0.008447 +0.008433 +0.008481 +0.008555 +0.008522 +0.008553 +0.008511 +0.008497 +0.008528 +0.008606 +0.00858 +0.008622 +0.008576 +0.008579 +0.008641 +0.008735 +0.008707 +0.008735 +0.008668 +0.008634 +0.008635 +0.008666 +0.008608 +0.008597 +0.008497 +0.008442 +0.008433 +0.008476 +0.008414 +0.00842 +0.008336 +0.008302 +0.008314 +0.008363 +0.008319 +0.008331 +0.008266 +0.008231 +0.008245 +0.008311 +0.008275 +0.008301 +0.008242 +0.008224 +0.008255 +0.008328 +0.008297 +0.008324 +0.008283 +0.008271 +0.008312 +0.008391 +0.008367 +0.008398 +0.008363 +0.008344 +0.008376 +0.008471 +0.00845 +0.001518 +0.008483 +0.008439 +0.008433 +0.008464 +0.008546 +0.008538 +0.008566 +0.008528 +0.008512 +0.008545 +0.008633 +0.00862 +0.008652 +0.008615 +0.008597 +0.008636 +0.00872 +0.008697 +0.008738 +0.008688 +0.008677 +0.008719 +0.008797 +0.00879 +0.008819 +0.008785 +0.008784 +0.008822 +0.008914 +0.008892 +0.008922 +0.008871 +0.008789 +0.008724 +0.008762 +0.008689 +0.008695 +0.008578 +0.008474 +0.008472 +0.00852 +0.008462 +0.008464 +0.008406 +0.008365 +0.008313 +0.008367 +0.008306 +0.008336 +0.008271 +0.00824 +0.008266 +0.008327 +0.008291 +0.008303 +0.008228 +0.008193 +0.008224 +0.008297 +0.008261 +0.008294 +0.008248 +0.008247 +0.008276 +0.008376 +0.008327 +0.008363 +0.008338 +0.008321 +0.008345 +0.008415 +0.008381 +0.008419 +0.008409 +0.001519 +0.008355 +0.008417 +0.008505 +0.008476 +0.00851 +0.008478 +0.008469 +0.008509 +0.008594 +0.008565 +0.008596 +0.008558 +0.008545 +0.008587 +0.008673 +0.008638 +0.008669 +0.008629 +0.008611 +0.008643 +0.008733 +0.008711 +0.008766 +0.008737 +0.00872 +0.008743 +0.008806 +0.008759 +0.008757 +0.008679 +0.008621 +0.008597 +0.008639 +0.008573 +0.008564 +0.00848 +0.008438 +0.008429 +0.008476 +0.008423 +0.008429 +0.008363 +0.008327 +0.008321 +0.008381 +0.008328 +0.008341 +0.00829 +0.008269 +0.008264 +0.008338 +0.008306 +0.008327 +0.008287 +0.008262 +0.008277 +0.008351 +0.008322 +0.008359 +0.008322 +0.008315 +0.008336 +0.008424 +0.008398 +0.008423 +0.008397 +0.00837 +0.008411 +0.008494 +0.008483 +0.00152 +0.008508 +0.008474 +0.008468 +0.0085 +0.008582 +0.008562 +0.008595 +0.008552 +0.008553 +0.008579 +0.008671 +0.00865 +0.00868 +0.008645 +0.008629 +0.008663 +0.008751 +0.008733 +0.008758 +0.008729 +0.008713 +0.00877 +0.008851 +0.008825 +0.00887 +0.008843 +0.008833 +0.008855 +0.008856 +0.008786 +0.008789 +0.008713 +0.008672 +0.008678 +0.008646 +0.00855 +0.008549 +0.008485 +0.008405 +0.008394 +0.008446 +0.008376 +0.008399 +0.008334 +0.008316 +0.008266 +0.008323 +0.008261 +0.00829 +0.008242 +0.008224 +0.008257 +0.008324 +0.008296 +0.008309 +0.008281 +0.008258 +0.008299 +0.008378 +0.008339 +0.008374 +0.008293 +0.008291 +0.008341 +0.008405 +0.008385 +0.008419 +0.008376 +0.008382 +0.008435 +0.008494 +0.001521 +0.008467 +0.008515 +0.008471 +0.008459 +0.008508 +0.008594 +0.008558 +0.008593 +0.008556 +0.008546 +0.008562 +0.008641 +0.008598 +0.008637 +0.008601 +0.00858 +0.008617 +0.008709 +0.008694 +0.008754 +0.008733 +0.008719 +0.008738 +0.008823 +0.008787 +0.00881 +0.00874 +0.008696 +0.008685 +0.00871 +0.008643 +0.008646 +0.008557 +0.008502 +0.008507 +0.008544 +0.008483 +0.008495 +0.00843 +0.008393 +0.008399 +0.008449 +0.0084 +0.008414 +0.008354 +0.008342 +0.008336 +0.008405 +0.008364 +0.00839 +0.008345 +0.008323 +0.00835 +0.008415 +0.008379 +0.008403 +0.00837 +0.008367 +0.008409 +0.008489 +0.008461 +0.00849 +0.008442 +0.008433 +0.008473 +0.008535 +0.008516 +0.001522 +0.008557 +0.008526 +0.008528 +0.008564 +0.008646 +0.008621 +0.008652 +0.008613 +0.008595 +0.008631 +0.008711 +0.008692 +0.008727 +0.008697 +0.008694 +0.008736 +0.008817 +0.008793 +0.008826 +0.008793 +0.008771 +0.008835 +0.008911 +0.008898 +0.008934 +0.0089 +0.008889 +0.008866 +0.008916 +0.008859 +0.008875 +0.008807 +0.008745 +0.008759 +0.008815 +0.008739 +0.008621 +0.00852 +0.008472 +0.008495 +0.008547 +0.008484 +0.00849 +0.008423 +0.008336 +0.008308 +0.008372 +0.008305 +0.008336 +0.008266 +0.008246 +0.00827 +0.008348 +0.008297 +0.008313 +0.008276 +0.008235 +0.008238 +0.008302 +0.00826 +0.008301 +0.008262 +0.008249 +0.008298 +0.008378 +0.008344 +0.00839 +0.00835 +0.00834 +0.008389 +0.008487 +0.008431 +0.008467 +0.001523 +0.008445 +0.008435 +0.008468 +0.008552 +0.008537 +0.008563 +0.00853 +0.008512 +0.00856 +0.008614 +0.008586 +0.008615 +0.008587 +0.00857 +0.008608 +0.008682 +0.008655 +0.008677 +0.008642 +0.008631 +0.008669 +0.008752 +0.008775 +0.008806 +0.008774 +0.00874 +0.008758 +0.008819 +0.008759 +0.00873 +0.008672 +0.00861 +0.008598 +0.008635 +0.008577 +0.008566 +0.008504 +0.008456 +0.00846 +0.008514 +0.008472 +0.008476 +0.008433 +0.008374 +0.0084 +0.008457 +0.00842 +0.008423 +0.008392 +0.008344 +0.008377 +0.008445 +0.008414 +0.008419 +0.008384 +0.008349 +0.008393 +0.008471 +0.008451 +0.008467 +0.008446 +0.008429 +0.008467 +0.008548 +0.008529 +0.008556 +0.00851 +0.008502 +0.008558 +0.001524 +0.008628 +0.008624 +0.008636 +0.008605 +0.008581 +0.008629 +0.008698 +0.008697 +0.008724 +0.008699 +0.008671 +0.008721 +0.00879 +0.00879 +0.008807 +0.008783 +0.008744 +0.008812 +0.008871 +0.008877 +0.008893 +0.008882 +0.008855 +0.008913 +0.008996 +0.008982 +0.008997 +0.008929 +0.00881 +0.008825 +0.008859 +0.008802 +0.008783 +0.008663 +0.008592 +0.008605 +0.008634 +0.008601 +0.008583 +0.008544 +0.008449 +0.008439 +0.008494 +0.008446 +0.008452 +0.008402 +0.008364 +0.008395 +0.008466 +0.008427 +0.008426 +0.008354 +0.00831 +0.008358 +0.008423 +0.008403 +0.008408 +0.008396 +0.008352 +0.008415 +0.008484 +0.008459 +0.008481 +0.008432 +0.008413 +0.008467 +0.008522 +0.008517 +0.008536 +0.008517 +0.008489 +0.001525 +0.008548 +0.008618 +0.008604 +0.008628 +0.008608 +0.008585 +0.008639 +0.008705 +0.008695 +0.008706 +0.008688 +0.008662 +0.008717 +0.008783 +0.008763 +0.008769 +0.008751 +0.008707 +0.008774 +0.008838 +0.00883 +0.008881 +0.008868 +0.008836 +0.008887 +0.008929 +0.008891 +0.008872 +0.008802 +0.00874 +0.00875 +0.008764 +0.008702 +0.008692 +0.00863 +0.008563 +0.008581 +0.008608 +0.008574 +0.008578 +0.008528 +0.008477 +0.00851 +0.008553 +0.008516 +0.008514 +0.008467 +0.008433 +0.008482 +0.008534 +0.008508 +0.008517 +0.008467 +0.008429 +0.008471 +0.00853 +0.008527 +0.008565 +0.008525 +0.008501 +0.008551 +0.008614 +0.008614 +0.008637 +0.008598 +0.008583 +0.008638 +0.001526 +0.008705 +0.008704 +0.008712 +0.008689 +0.008663 +0.008717 +0.008788 +0.008783 +0.008802 +0.008785 +0.008761 +0.008818 +0.008888 +0.008877 +0.008894 +0.00887 +0.008847 +0.008899 +0.008975 +0.008964 +0.008989 +0.008964 +0.008957 +0.009017 +0.009095 +0.009078 +0.00902 +0.008968 +0.008914 +0.008945 +0.00899 +0.008936 +0.008895 +0.008775 +0.008702 +0.008709 +0.008728 +0.008685 +0.008666 +0.008586 +0.008508 +0.008499 +0.008535 +0.008504 +0.008471 +0.008443 +0.008381 +0.008384 +0.00842 +0.008376 +0.008392 +0.008349 +0.008318 +0.008351 +0.008416 +0.008391 +0.008389 +0.008378 +0.008309 +0.008325 +0.008397 +0.00838 +0.008395 +0.008389 +0.008359 +0.008412 +0.008489 +0.008477 +0.008494 +0.00848 +0.008454 +0.00851 +0.008578 +0.008558 +0.001527 +0.008594 +0.008561 +0.008546 +0.008595 +0.008676 +0.008654 +0.008677 +0.00865 +0.008631 +0.00868 +0.008758 +0.00872 +0.008741 +0.008701 +0.008678 +0.008724 +0.008793 +0.008774 +0.008789 +0.008764 +0.008753 +0.008816 +0.008905 +0.008876 +0.008856 +0.008777 +0.008712 +0.008696 +0.008749 +0.008697 +0.008678 +0.008606 +0.008547 +0.008562 +0.008623 +0.008582 +0.008574 +0.008524 +0.008486 +0.008505 +0.008567 +0.008519 +0.008528 +0.008482 +0.008448 +0.008473 +0.008544 +0.008518 +0.008528 +0.008487 +0.008457 +0.008494 +0.008569 +0.008547 +0.008566 +0.008537 +0.008512 +0.008547 +0.008628 +0.008619 +0.008641 +0.008613 +0.008585 +0.008638 +0.008716 +0.001528 +0.0087 +0.008727 +0.008693 +0.00868 +0.008717 +0.008807 +0.008785 +0.008817 +0.008778 +0.00877 +0.008805 +0.008893 +0.008869 +0.008905 +0.008863 +0.008849 +0.008893 +0.00898 +0.008961 +0.009009 +0.008957 +0.008963 +0.009003 +0.009093 +0.009075 +0.009113 +0.009068 +0.008959 +0.008917 +0.008963 +0.008901 +0.008911 +0.008826 +0.008763 +0.008684 +0.008711 +0.008656 +0.008664 +0.008587 +0.008554 +0.008568 +0.008617 +0.008515 +0.008495 +0.008445 +0.008397 +0.008411 +0.008446 +0.008416 +0.008425 +0.008378 +0.008351 +0.008378 +0.008459 +0.008401 +0.008443 +0.00839 +0.008342 +0.008361 +0.008422 +0.008391 +0.008438 +0.008397 +0.008388 +0.008436 +0.008505 +0.008492 +0.008532 +0.008488 +0.00848 +0.008543 +0.008598 +0.008571 +0.001529 +0.008618 +0.008582 +0.008569 +0.008612 +0.008694 +0.008671 +0.008707 +0.008665 +0.008658 +0.0087 +0.008779 +0.008738 +0.008762 +0.00872 +0.008711 +0.008746 +0.008827 +0.008786 +0.008828 +0.008781 +0.008781 +0.008844 +0.008934 +0.0089 +0.008886 +0.008794 +0.008738 +0.008707 +0.008757 +0.008709 +0.008687 +0.008592 +0.008558 +0.008543 +0.008602 +0.008558 +0.008551 +0.00848 +0.008458 +0.008462 +0.008525 +0.008479 +0.00848 +0.008415 +0.008397 +0.008412 +0.008478 +0.008444 +0.008456 +0.008394 +0.008378 +0.008402 +0.008473 +0.008451 +0.008469 +0.008417 +0.008412 +0.008442 +0.008527 +0.00851 +0.008539 +0.008497 +0.008484 +0.008521 +0.008614 +0.008598 +0.008615 +0.00153 +0.008581 +0.008568 +0.008611 +0.008694 +0.008674 +0.008705 +0.008669 +0.008655 +0.008697 +0.008781 +0.008758 +0.008796 +0.008752 +0.008741 +0.00878 +0.008873 +0.00885 +0.008884 +0.008843 +0.008839 +0.008879 +0.00898 +0.008955 +0.008996 +0.008961 +0.008938 +0.008915 +0.008893 +0.008815 +0.008821 +0.008755 +0.008688 +0.008606 +0.008639 +0.008574 +0.008572 +0.0085 +0.008469 +0.008473 +0.008533 +0.008446 +0.008389 +0.008335 +0.008291 +0.008318 +0.008376 +0.008337 +0.008344 +0.008311 +0.008255 +0.00826 +0.008314 +0.008281 +0.008311 +0.008267 +0.008254 +0.008282 +0.008369 +0.008338 +0.00837 +0.008344 +0.008326 +0.008377 +0.008452 +0.008417 +0.008479 +0.008418 +0.008411 +0.001531 +0.008452 +0.008502 +0.008473 +0.008495 +0.008483 +0.008461 +0.008511 +0.00858 +0.008566 +0.008595 +0.008563 +0.008556 +0.008587 +0.008671 +0.008648 +0.008666 +0.008635 +0.008615 +0.008646 +0.008736 +0.008712 +0.00874 +0.00873 +0.008721 +0.008767 +0.008842 +0.008824 +0.008829 +0.008772 +0.008731 +0.008729 +0.008751 +0.008695 +0.008673 +0.008581 +0.008538 +0.008526 +0.008563 +0.008509 +0.008491 +0.008427 +0.008387 +0.008389 +0.008436 +0.008395 +0.008387 +0.008331 +0.008299 +0.008312 +0.008369 +0.008348 +0.008353 +0.008309 +0.008281 +0.0083 +0.008361 +0.008346 +0.008363 +0.008321 +0.008305 +0.008329 +0.008403 +0.008391 +0.008416 +0.008389 +0.008375 +0.008397 +0.008486 +0.008464 +0.008506 +0.008468 +0.001532 +0.008446 +0.008489 +0.008564 +0.008555 +0.008571 +0.008546 +0.008529 +0.008582 +0.008652 +0.008642 +0.008656 +0.008632 +0.008603 +0.008663 +0.008731 +0.008723 +0.008738 +0.008717 +0.008691 +0.008745 +0.008821 +0.008818 +0.00884 +0.008819 +0.008795 +0.00886 +0.008931 +0.008923 +0.00893 +0.008821 +0.008715 +0.008722 +0.008751 +0.008707 +0.008624 +0.008547 +0.008483 +0.008509 +0.008522 +0.008477 +0.008473 +0.008429 +0.008352 +0.008334 +0.008389 +0.008338 +0.008352 +0.008298 +0.008274 +0.008307 +0.008375 +0.008343 +0.008349 +0.008321 +0.008269 +0.008284 +0.008309 +0.008302 +0.008308 +0.008291 +0.008274 +0.008309 +0.008387 +0.00838 +0.00838 +0.008378 +0.008345 +0.008397 +0.008476 +0.00847 +0.008468 +0.008461 +0.008439 +0.001533 +0.008487 +0.008571 +0.00855 +0.008576 +0.008539 +0.008504 +0.008522 +0.008596 +0.008569 +0.008603 +0.008579 +0.008562 +0.008598 +0.00868 +0.008666 +0.008709 +0.008691 +0.008674 +0.008719 +0.008794 +0.008771 +0.0088 +0.008765 +0.008763 +0.008798 +0.008853 +0.008809 +0.008788 +0.008708 +0.008644 +0.008624 +0.008638 +0.008574 +0.008557 +0.008476 +0.008412 +0.008417 +0.008454 +0.008415 +0.008408 +0.008347 +0.008312 +0.008318 +0.008359 +0.008319 +0.00832 +0.008273 +0.008251 +0.008274 +0.008328 +0.008305 +0.008315 +0.008269 +0.008265 +0.008294 +0.008361 +0.008346 +0.008364 +0.008326 +0.008317 +0.008361 +0.008438 +0.008431 +0.008446 +0.00841 +0.008387 +0.001534 +0.008447 +0.008493 +0.008509 +0.008523 +0.008503 +0.008478 +0.008526 +0.008592 +0.008586 +0.008606 +0.008585 +0.008561 +0.008622 +0.008676 +0.008674 +0.008689 +0.008663 +0.008632 +0.0087 +0.008765 +0.008761 +0.008786 +0.008752 +0.008737 +0.008789 +0.008874 +0.008869 +0.008888 +0.008875 +0.008851 +0.008844 +0.008831 +0.008784 +0.008773 +0.008724 +0.00866 +0.008686 +0.008682 +0.008568 +0.008547 +0.008503 +0.008434 +0.008443 +0.00847 +0.008411 +0.00842 +0.008335 +0.008293 +0.008292 +0.008346 +0.008306 +0.008315 +0.008289 +0.008239 +0.008269 +0.008295 +0.00827 +0.008286 +0.008264 +0.008226 +0.008285 +0.008341 +0.008329 +0.008345 +0.008318 +0.008297 +0.008338 +0.008382 +0.008365 +0.008387 +0.008371 +0.008338 +0.008425 +0.00846 +0.008449 +0.001535 +0.008478 +0.008458 +0.008434 +0.008484 +0.008564 +0.008545 +0.008574 +0.008539 +0.008522 +0.008579 +0.008649 +0.008628 +0.008655 +0.008628 +0.008599 +0.008649 +0.008712 +0.008679 +0.008703 +0.008674 +0.008653 +0.008688 +0.008776 +0.008754 +0.008812 +0.008794 +0.008771 +0.008797 +0.008836 +0.008783 +0.008759 +0.008673 +0.008625 +0.008629 +0.008659 +0.008602 +0.008598 +0.008537 +0.008488 +0.008507 +0.008545 +0.00851 +0.008528 +0.008473 +0.00844 +0.008464 +0.008516 +0.008482 +0.008491 +0.008435 +0.008422 +0.008458 +0.008517 +0.008484 +0.008497 +0.008443 +0.008418 +0.008472 +0.008541 +0.008524 +0.008546 +0.008507 +0.008488 +0.008531 +0.0086 +0.008593 +0.00862 +0.008597 +0.008575 +0.001536 +0.008635 +0.008686 +0.008685 +0.008706 +0.008675 +0.008645 +0.008701 +0.008775 +0.00877 +0.008784 +0.008766 +0.008747 +0.008801 +0.00887 +0.008868 +0.008872 +0.008868 +0.008821 +0.008884 +0.008966 +0.008945 +0.00898 +0.008958 +0.008935 +0.009012 +0.009073 +0.00901 +0.009021 +0.008967 +0.008905 +0.008906 +0.00892 +0.008856 +0.008823 +0.008693 +0.008634 +0.008628 +0.008638 +0.008571 +0.008573 +0.008517 +0.00841 +0.008406 +0.008428 +0.008397 +0.008375 +0.008345 +0.008292 +0.008333 +0.008353 +0.008305 +0.008323 +0.008279 +0.008255 +0.008274 +0.008307 +0.008291 +0.008294 +0.008276 +0.008249 +0.008307 +0.008366 +0.008358 +0.00837 +0.008347 +0.008328 +0.008376 +0.008446 +0.008444 +0.008469 +0.008389 +0.008385 +0.001537 +0.00843 +0.008491 +0.008472 +0.008493 +0.008482 +0.008459 +0.008518 +0.008583 +0.008574 +0.008591 +0.008569 +0.008546 +0.008599 +0.008664 +0.008659 +0.008666 +0.008642 +0.008615 +0.008664 +0.00875 +0.008757 +0.008775 +0.008745 +0.008718 +0.008775 +0.008838 +0.008831 +0.008833 +0.008783 +0.008729 +0.008731 +0.00875 +0.008711 +0.008682 +0.008609 +0.008553 +0.008554 +0.008581 +0.008553 +0.008539 +0.008486 +0.008426 +0.008452 +0.008489 +0.008462 +0.008445 +0.008403 +0.008365 +0.008392 +0.008433 +0.008418 +0.008422 +0.008384 +0.008355 +0.008387 +0.008441 +0.008433 +0.008438 +0.008415 +0.008396 +0.008439 +0.008504 +0.008506 +0.008514 +0.008493 +0.008464 +0.008513 +0.008588 +0.008588 +0.001538 +0.0086 +0.008576 +0.008553 +0.008597 +0.008684 +0.008659 +0.008685 +0.008653 +0.008636 +0.008685 +0.008769 +0.008749 +0.008773 +0.008744 +0.008715 +0.008768 +0.008845 +0.008838 +0.008859 +0.008834 +0.008805 +0.008871 +0.008944 +0.008946 +0.008971 +0.008937 +0.008923 +0.008966 +0.008971 +0.008887 +0.008872 +0.008804 +0.008691 +0.008661 +0.008688 +0.008614 +0.008615 +0.008514 +0.008435 +0.008421 +0.00847 +0.008415 +0.008413 +0.008366 +0.008266 +0.008277 +0.008318 +0.008292 +0.008301 +0.008267 +0.008228 +0.008256 +0.008333 +0.00829 +0.008318 +0.008285 +0.008228 +0.008245 +0.0083 +0.008275 +0.008312 +0.008282 +0.008266 +0.008319 +0.008386 +0.008367 +0.008404 +0.008372 +0.008351 +0.008418 +0.008472 +0.008458 +0.001539 +0.008489 +0.008459 +0.008448 +0.008485 +0.00857 +0.008545 +0.008583 +0.008549 +0.008537 +0.008579 +0.008661 +0.008629 +0.008666 +0.008601 +0.008581 +0.008612 +0.008691 +0.008654 +0.00869 +0.008652 +0.008646 +0.008688 +0.008798 +0.008801 +0.00883 +0.008782 +0.008767 +0.008756 +0.008815 +0.00875 +0.008734 +0.008656 +0.008607 +0.008587 +0.008624 +0.008571 +0.008563 +0.008477 +0.008437 +0.008436 +0.008495 +0.008439 +0.00844 +0.008373 +0.008344 +0.008347 +0.008409 +0.008372 +0.008385 +0.008329 +0.00831 +0.008325 +0.008401 +0.008377 +0.008398 +0.00834 +0.008333 +0.008359 +0.008443 +0.008424 +0.008449 +0.008413 +0.008401 +0.008429 +0.008531 +0.0085 +0.00853 +0.008491 +0.00154 +0.008486 +0.008515 +0.008605 +0.008583 +0.008619 +0.008575 +0.008565 +0.008605 +0.008689 +0.008669 +0.008707 +0.008665 +0.008655 +0.008687 +0.008775 +0.008759 +0.008784 +0.008744 +0.008734 +0.008773 +0.00886 +0.008847 +0.00889 +0.008835 +0.00884 +0.008886 +0.008975 +0.008956 +0.008983 +0.008929 +0.008836 +0.008776 +0.008796 +0.008731 +0.008738 +0.008623 +0.008515 +0.008479 +0.008514 +0.008458 +0.008469 +0.008393 +0.008363 +0.008364 +0.008336 +0.008285 +0.008279 +0.008241 +0.008213 +0.008227 +0.0083 +0.008244 +0.00824 +0.008187 +0.008152 +0.008198 +0.008263 +0.008217 +0.008262 +0.008204 +0.008198 +0.008227 +0.008283 +0.00824 +0.008288 +0.00825 +0.008238 +0.00829 +0.008367 +0.008333 +0.008381 +0.008342 +0.008344 +0.008364 +0.001541 +0.008458 +0.008427 +0.008448 +0.008433 +0.008408 +0.008463 +0.008537 +0.008508 +0.008524 +0.008487 +0.008469 +0.008519 +0.008596 +0.008569 +0.008586 +0.008558 +0.008536 +0.008564 +0.008655 +0.00864 +0.008664 +0.00866 +0.008655 +0.008697 +0.008771 +0.008753 +0.008751 +0.008709 +0.008648 +0.008651 +0.008675 +0.008621 +0.0086 +0.008522 +0.008453 +0.008456 +0.008503 +0.008458 +0.008446 +0.008393 +0.008338 +0.008348 +0.008402 +0.008364 +0.008364 +0.008312 +0.008269 +0.008285 +0.008346 +0.008328 +0.008335 +0.008302 +0.008277 +0.0083 +0.008371 +0.008343 +0.008356 +0.008335 +0.008321 +0.008364 +0.008446 +0.008427 +0.008446 +0.008427 +0.008387 +0.008428 +0.008507 +0.001542 +0.00849 +0.008517 +0.008492 +0.008485 +0.00852 +0.008601 +0.008584 +0.008613 +0.008571 +0.008563 +0.008595 +0.00869 +0.008665 +0.008698 +0.008655 +0.008647 +0.008693 +0.008776 +0.008753 +0.008788 +0.008748 +0.008736 +0.008786 +0.00887 +0.00885 +0.008897 +0.00886 +0.008852 +0.008898 +0.008907 +0.008817 +0.008814 +0.008745 +0.008683 +0.008619 +0.008614 +0.008545 +0.008537 +0.008464 +0.00841 +0.008396 +0.008405 +0.008362 +0.008356 +0.008296 +0.008221 +0.008222 +0.008277 +0.008233 +0.008238 +0.008203 +0.00817 +0.00821 +0.008267 +0.008223 +0.008221 +0.008159 +0.008153 +0.008184 +0.008259 +0.008234 +0.008267 +0.008222 +0.008228 +0.008252 +0.008335 +0.008313 +0.008346 +0.008326 +0.008287 +0.008342 +0.008403 +0.001543 +0.008357 +0.008405 +0.008366 +0.008359 +0.008397 +0.008488 +0.008459 +0.00849 +0.008453 +0.008443 +0.008493 +0.008574 +0.008543 +0.008576 +0.00854 +0.008539 +0.008557 +0.00864 +0.008601 +0.00863 +0.008593 +0.008598 +0.00861 +0.008697 +0.008686 +0.008726 +0.008717 +0.008705 +0.008733 +0.008802 +0.008747 +0.00873 +0.008646 +0.008576 +0.008578 +0.008627 +0.008556 +0.00854 +0.008474 +0.008429 +0.008429 +0.008489 +0.008431 +0.008445 +0.008384 +0.008346 +0.008354 +0.008417 +0.00837 +0.008388 +0.008338 +0.008306 +0.008329 +0.0084 +0.00837 +0.008392 +0.008344 +0.00832 +0.008356 +0.008434 +0.008407 +0.008442 +0.008408 +0.008394 +0.008436 +0.008513 +0.008489 +0.00852 +0.008481 +0.008472 +0.001544 +0.008508 +0.00859 +0.008582 +0.008601 +0.008567 +0.008547 +0.008601 +0.008674 +0.008664 +0.008684 +0.008655 +0.00864 +0.008687 +0.00876 +0.008748 +0.008772 +0.008744 +0.00872 +0.008768 +0.008845 +0.008836 +0.008862 +0.008841 +0.008816 +0.008879 +0.008961 +0.008936 +0.008969 +0.008946 +0.008878 +0.008828 +0.008862 +0.008805 +0.008785 +0.00873 +0.008685 +0.008586 +0.0086 +0.008546 +0.008554 +0.008487 +0.00846 +0.008484 +0.008532 +0.008491 +0.008417 +0.008367 +0.008322 +0.00836 +0.008407 +0.008377 +0.008386 +0.008346 +0.008319 +0.008361 +0.008411 +0.008365 +0.008396 +0.008354 +0.008353 +0.008362 +0.008422 +0.008405 +0.008419 +0.008407 +0.008389 +0.008434 +0.008521 +0.008497 +0.008523 +0.008502 +0.008487 +0.008526 +0.001545 +0.008613 +0.008586 +0.008619 +0.008583 +0.008569 +0.008615 +0.008708 +0.008676 +0.008699 +0.008649 +0.008639 +0.00866 +0.008745 +0.008709 +0.008739 +0.0087 +0.008693 +0.008731 +0.008813 +0.008811 +0.008878 +0.008833 +0.008827 +0.00885 +0.008937 +0.008897 +0.008905 +0.008835 +0.008795 +0.008781 +0.008817 +0.008751 +0.008742 +0.008656 +0.008611 +0.008592 +0.008647 +0.008595 +0.008596 +0.008529 +0.008493 +0.008491 +0.008551 +0.008507 +0.008509 +0.008452 +0.008424 +0.008431 +0.008501 +0.008464 +0.008487 +0.008437 +0.008416 +0.008429 +0.008502 +0.00848 +0.00851 +0.008472 +0.00846 +0.008484 +0.008574 +0.008549 +0.008573 +0.008552 +0.008525 +0.008577 +0.008651 +0.008637 +0.001546 +0.008659 +0.00863 +0.008622 +0.008658 +0.008744 +0.008724 +0.008751 +0.008709 +0.008699 +0.008745 +0.008829 +0.008811 +0.00884 +0.008805 +0.00879 +0.008828 +0.00891 +0.008889 +0.008921 +0.008885 +0.008874 +0.008932 +0.009016 +0.008993 +0.009034 +0.009003 +0.008987 +0.009011 +0.008983 +0.008901 +0.008892 +0.0088 +0.008688 +0.008641 +0.008669 +0.008593 +0.008585 +0.008521 +0.008459 +0.008444 +0.008466 +0.008422 +0.008429 +0.008374 +0.008334 +0.008336 +0.008368 +0.008332 +0.008343 +0.008301 +0.008281 +0.00831 +0.008393 +0.008337 +0.008372 +0.008306 +0.008279 +0.008307 +0.008377 +0.008337 +0.008389 +0.008332 +0.00833 +0.008376 +0.008452 +0.00842 +0.008466 +0.008426 +0.008429 +0.008459 +0.008547 +0.008522 +0.001547 +0.008546 +0.008527 +0.008513 +0.008554 +0.008621 +0.0086 +0.008628 +0.008589 +0.008569 +0.00859 +0.008669 +0.008649 +0.008682 +0.008643 +0.008622 +0.00867 +0.008747 +0.008729 +0.008769 +0.008759 +0.008751 +0.008791 +0.008864 +0.008848 +0.008878 +0.008829 +0.008821 +0.008845 +0.008886 +0.008831 +0.008802 +0.008726 +0.008666 +0.008647 +0.008668 +0.008627 +0.008605 +0.008532 +0.008488 +0.00849 +0.008523 +0.008482 +0.008477 +0.008414 +0.008378 +0.008386 +0.008426 +0.008399 +0.008404 +0.00835 +0.008327 +0.00835 +0.008411 +0.008386 +0.008396 +0.008349 +0.008339 +0.008373 +0.00844 +0.008429 +0.008444 +0.00841 +0.008399 +0.008437 +0.008519 +0.008503 +0.008528 +0.008494 +0.008479 +0.001548 +0.008533 +0.008606 +0.008592 +0.00861 +0.008588 +0.008554 +0.008601 +0.008667 +0.008669 +0.008701 +0.008675 +0.008649 +0.008699 +0.008769 +0.008761 +0.008772 +0.008752 +0.008728 +0.00878 +0.008851 +0.008847 +0.008864 +0.00885 +0.008817 +0.008885 +0.008966 +0.008955 +0.008977 +0.00895 +0.008903 +0.008868 +0.008861 +0.008809 +0.008777 +0.00873 +0.008622 +0.008585 +0.008601 +0.008551 +0.008538 +0.008489 +0.008439 +0.00848 +0.008516 +0.008443 +0.008388 +0.008352 +0.008302 +0.008349 +0.008376 +0.008362 +0.00835 +0.008322 +0.008288 +0.008298 +0.008355 +0.008317 +0.00834 +0.008316 +0.008279 +0.008344 +0.008406 +0.008387 +0.00842 +0.008385 +0.008371 +0.008429 +0.008489 +0.008491 +0.008497 +0.008474 +0.001549 +0.008466 +0.008519 +0.008573 +0.008536 +0.008575 +0.008539 +0.008522 +0.008555 +0.008627 +0.008604 +0.008632 +0.008602 +0.008588 +0.008636 +0.008711 +0.008694 +0.008725 +0.008679 +0.008666 +0.008709 +0.008787 +0.00878 +0.00883 +0.008803 +0.00877 +0.008816 +0.008888 +0.008877 +0.008904 +0.008854 +0.008808 +0.008802 +0.008831 +0.008764 +0.008744 +0.008658 +0.008585 +0.008576 +0.008616 +0.008569 +0.008565 +0.008494 +0.008454 +0.008458 +0.008501 +0.008462 +0.008461 +0.008419 +0.008375 +0.008394 +0.008439 +0.008425 +0.008417 +0.008387 +0.008365 +0.008386 +0.008448 +0.008422 +0.008434 +0.008411 +0.008401 +0.008439 +0.008512 +0.008506 +0.008507 +0.008486 +0.008462 +0.008501 +0.00858 +0.008564 +0.008584 +0.00155 +0.008576 +0.008548 +0.008601 +0.008674 +0.008654 +0.008685 +0.008642 +0.008629 +0.008663 +0.008749 +0.00874 +0.008773 +0.008731 +0.008722 +0.008758 +0.008843 +0.008818 +0.008858 +0.008812 +0.008799 +0.00885 +0.008926 +0.008917 +0.008949 +0.008913 +0.008908 +0.008952 +0.00905 +0.009031 +0.009062 +0.008992 +0.008876 +0.008871 +0.008912 +0.008844 +0.008843 +0.008697 +0.008611 +0.008593 +0.008648 +0.00857 +0.008577 +0.008512 +0.008472 +0.008444 +0.008457 +0.008409 +0.008418 +0.00837 +0.00833 +0.008358 +0.008415 +0.008373 +0.008385 +0.008312 +0.008281 +0.008293 +0.008378 +0.008326 +0.008355 +0.008321 +0.008302 +0.008348 +0.008425 +0.008391 +0.008434 +0.008397 +0.008379 +0.008413 +0.008484 +0.008447 +0.008488 +0.008468 +0.008438 +0.001551 +0.008484 +0.008567 +0.008544 +0.008577 +0.008539 +0.008528 +0.008572 +0.008661 +0.008627 +0.008662 +0.008622 +0.008617 +0.008639 +0.008713 +0.008673 +0.008703 +0.008667 +0.00865 +0.008691 +0.00878 +0.008763 +0.00882 +0.008795 +0.008791 +0.008821 +0.008899 +0.008872 +0.008879 +0.008798 +0.008756 +0.008744 +0.008778 +0.008704 +0.008682 +0.008593 +0.008547 +0.008529 +0.008564 +0.008511 +0.008509 +0.008438 +0.008414 +0.008408 +0.008452 +0.00841 +0.008421 +0.008362 +0.00834 +0.008346 +0.008412 +0.00837 +0.008387 +0.008335 +0.008328 +0.00835 +0.008416 +0.008389 +0.008408 +0.00837 +0.00837 +0.008401 +0.008486 +0.008454 +0.008485 +0.008447 +0.008433 +0.008466 +0.008545 +0.008516 +0.001552 +0.008564 +0.008531 +0.008524 +0.008569 +0.008651 +0.008613 +0.008651 +0.00861 +0.008592 +0.008632 +0.008718 +0.008684 +0.00873 +0.008699 +0.008691 +0.008731 +0.008815 +0.008789 +0.008828 +0.008788 +0.008777 +0.008833 +0.008905 +0.008893 +0.008927 +0.00889 +0.008894 +0.0089 +0.008934 +0.008871 +0.008881 +0.008812 +0.008758 +0.008763 +0.008819 +0.008702 +0.008616 +0.008537 +0.008481 +0.008511 +0.008564 +0.008478 +0.008456 +0.008366 +0.008337 +0.008339 +0.008399 +0.008334 +0.008359 +0.008287 +0.008275 +0.008264 +0.008333 +0.008281 +0.008314 +0.008268 +0.008237 +0.008285 +0.008345 +0.008321 +0.008354 +0.008308 +0.00831 +0.00834 +0.008391 +0.008365 +0.008386 +0.008354 +0.008356 +0.008398 +0.008475 +0.008458 +0.008487 +0.001553 +0.008447 +0.008438 +0.008507 +0.008555 +0.008536 +0.00857 +0.008522 +0.008505 +0.008531 +0.008616 +0.008582 +0.008621 +0.008583 +0.008576 +0.00861 +0.008697 +0.008659 +0.008696 +0.00867 +0.008675 +0.00873 +0.00881 +0.008788 +0.008807 +0.008774 +0.008755 +0.008778 +0.008859 +0.008807 +0.008791 +0.008709 +0.008646 +0.008627 +0.008656 +0.008584 +0.008574 +0.00849 +0.008425 +0.008417 +0.00847 +0.008399 +0.0084 +0.008332 +0.008291 +0.008275 +0.008336 +0.008284 +0.008282 +0.008232 +0.008208 +0.008214 +0.008287 +0.008246 +0.008255 +0.008214 +0.008194 +0.008218 +0.008302 +0.008269 +0.008287 +0.008257 +0.008242 +0.008279 +0.008373 +0.008337 +0.008366 +0.008327 +0.008316 +0.008373 +0.00844 +0.001554 +0.008423 +0.008457 +0.00841 +0.008403 +0.008436 +0.008514 +0.00849 +0.008528 +0.008495 +0.008491 +0.008524 +0.008606 +0.008582 +0.008613 +0.008575 +0.008563 +0.0086 +0.008679 +0.008664 +0.008695 +0.00865 +0.00865 +0.008692 +0.008782 +0.008762 +0.008802 +0.008761 +0.008759 +0.008809 +0.008903 +0.008842 +0.008778 +0.00867 +0.008622 +0.008613 +0.008643 +0.008523 +0.008518 +0.008428 +0.008362 +0.008352 +0.008411 +0.008348 +0.008361 +0.008255 +0.008195 +0.008199 +0.008242 +0.008192 +0.008197 +0.008148 +0.008107 +0.008149 +0.008204 +0.008178 +0.008133 +0.008092 +0.008061 +0.008088 +0.008178 +0.008125 +0.008164 +0.008127 +0.008111 +0.008149 +0.008237 +0.008193 +0.008231 +0.008199 +0.008167 +0.008182 +0.008272 +0.008239 +0.008274 +0.008239 +0.001555 +0.008239 +0.008293 +0.008339 +0.008332 +0.008372 +0.008329 +0.008327 +0.008363 +0.008454 +0.008418 +0.008455 +0.008417 +0.008409 +0.008443 +0.008524 +0.008493 +0.008523 +0.008481 +0.008465 +0.008504 +0.008586 +0.008563 +0.008605 +0.008588 +0.00858 +0.008616 +0.008687 +0.008668 +0.008686 +0.008614 +0.00859 +0.008585 +0.008625 +0.008558 +0.008542 +0.008455 +0.008413 +0.008388 +0.008422 +0.008367 +0.008367 +0.008291 +0.008264 +0.008262 +0.008316 +0.008281 +0.008271 +0.008211 +0.008195 +0.008205 +0.008264 +0.008233 +0.008257 +0.008191 +0.008193 +0.008207 +0.008279 +0.00825 +0.008273 +0.008233 +0.008237 +0.008262 +0.008347 +0.008327 +0.00835 +0.008319 +0.008294 +0.008332 +0.008407 +0.001556 +0.008393 +0.008424 +0.008398 +0.008385 +0.008415 +0.008503 +0.008481 +0.008508 +0.00847 +0.008461 +0.008503 +0.008587 +0.008564 +0.008593 +0.00855 +0.008538 +0.008578 +0.008669 +0.008643 +0.008675 +0.008638 +0.008622 +0.008664 +0.008747 +0.008739 +0.008777 +0.008737 +0.008734 +0.008779 +0.008861 +0.008821 +0.008817 +0.008662 +0.008607 +0.008574 +0.008611 +0.008558 +0.00851 +0.008412 +0.008369 +0.008362 +0.008414 +0.008361 +0.008327 +0.008238 +0.00819 +0.008214 +0.008267 +0.008205 +0.008198 +0.008135 +0.008091 +0.008106 +0.008161 +0.008117 +0.008128 +0.008085 +0.008071 +0.008082 +0.00817 +0.008134 +0.008147 +0.008121 +0.008068 +0.00808 +0.008163 +0.008129 +0.008162 +0.008134 +0.008131 +0.008155 +0.008243 +0.008227 +0.008261 +0.008224 +0.008211 +0.008267 +0.008322 +0.001557 +0.008313 +0.008344 +0.008306 +0.008306 +0.008332 +0.008423 +0.008399 +0.008428 +0.008388 +0.00839 +0.008414 +0.008499 +0.008464 +0.00849 +0.008445 +0.008434 +0.008471 +0.008548 +0.008517 +0.008542 +0.008515 +0.008501 +0.008564 +0.008659 +0.008625 +0.008641 +0.008562 +0.008511 +0.008505 +0.008542 +0.008474 +0.008463 +0.008371 +0.008316 +0.008314 +0.008348 +0.008287 +0.008291 +0.008215 +0.008176 +0.008182 +0.008227 +0.008173 +0.008188 +0.008114 +0.008083 +0.008101 +0.008158 +0.008125 +0.008142 +0.008088 +0.008069 +0.008097 +0.008171 +0.008134 +0.008171 +0.008124 +0.008117 +0.008152 +0.008231 +0.00821 +0.008244 +0.008198 +0.008185 +0.008217 +0.008314 +0.008279 +0.001558 +0.008327 +0.008278 +0.008272 +0.008306 +0.008384 +0.008366 +0.0084 +0.008363 +0.008353 +0.008389 +0.008474 +0.008449 +0.008481 +0.00844 +0.00843 +0.008467 +0.00855 +0.008531 +0.008565 +0.008525 +0.008511 +0.008558 +0.008637 +0.008623 +0.008656 +0.008623 +0.008609 +0.008652 +0.008743 +0.008725 +0.00875 +0.008679 +0.008554 +0.008552 +0.008597 +0.008544 +0.008548 +0.008435 +0.008351 +0.008337 +0.008363 +0.008307 +0.008314 +0.008238 +0.008136 +0.008127 +0.008168 +0.00813 +0.00813 +0.008081 +0.008041 +0.008042 +0.008077 +0.008028 +0.008055 +0.008004 +0.007994 +0.008012 +0.008088 +0.00805 +0.008063 +0.008033 +0.008017 +0.008009 +0.008093 +0.008062 +0.008096 +0.008057 +0.008059 +0.008087 +0.008167 +0.00815 +0.008179 +0.00815 +0.008138 +0.008198 +0.008257 +0.001559 +0.00823 +0.008269 +0.008231 +0.008224 +0.008269 +0.00835 +0.008321 +0.008362 +0.008306 +0.008304 +0.008348 +0.008429 +0.008394 +0.00842 +0.008375 +0.008366 +0.008396 +0.008473 +0.008441 +0.008472 +0.008437 +0.008425 +0.008449 +0.00854 +0.008539 +0.008593 +0.008544 +0.008499 +0.0085 +0.008536 +0.008451 +0.008433 +0.008358 +0.008291 +0.008266 +0.008295 +0.008222 +0.008221 +0.008145 +0.008092 +0.00809 +0.008126 +0.008067 +0.00807 +0.008008 +0.007968 +0.007967 +0.008016 +0.007971 +0.007995 +0.007939 +0.007918 +0.007943 +0.008011 +0.007975 +0.007997 +0.007948 +0.007925 +0.007968 +0.008047 +0.008022 +0.00806 +0.008018 +0.008006 +0.008041 +0.008113 +0.008094 +0.008129 +0.008091 +0.008084 +0.00156 +0.008125 +0.008196 +0.008184 +0.008208 +0.008171 +0.008154 +0.008188 +0.008264 +0.008248 +0.008273 +0.008251 +0.008239 +0.008287 +0.008354 +0.008343 +0.008366 +0.008329 +0.008309 +0.008362 +0.008432 +0.008414 +0.008444 +0.008412 +0.008401 +0.00845 +0.008523 +0.008518 +0.008543 +0.008515 +0.008501 +0.008497 +0.008508 +0.008454 +0.008446 +0.008388 +0.008343 +0.008361 +0.008375 +0.008268 +0.008241 +0.00818 +0.008128 +0.00813 +0.00814 +0.008088 +0.008099 +0.008043 +0.008015 +0.007992 +0.00802 +0.007965 +0.007986 +0.007939 +0.007918 +0.007953 +0.008011 +0.007988 +0.007988 +0.007963 +0.007941 +0.007977 +0.008047 +0.008008 +0.008006 +0.007988 +0.007976 +0.008015 +0.008079 +0.008058 +0.008084 +0.008053 +0.008044 +0.008095 +0.00817 +0.008141 +0.008177 +0.008144 +0.001561 +0.00812 +0.008181 +0.008243 +0.008227 +0.008245 +0.008232 +0.008205 +0.008252 +0.008302 +0.008286 +0.008305 +0.008284 +0.008257 +0.008314 +0.008367 +0.008353 +0.008371 +0.008347 +0.008321 +0.008376 +0.008439 +0.008461 +0.00849 +0.00846 +0.008431 +0.008479 +0.008537 +0.008515 +0.008506 +0.00845 +0.008381 +0.008383 +0.008401 +0.008357 +0.008341 +0.008274 +0.008219 +0.008235 +0.00826 +0.008227 +0.008221 +0.008178 +0.008138 +0.008162 +0.008199 +0.008171 +0.008172 +0.008124 +0.008097 +0.008136 +0.008185 +0.008166 +0.008176 +0.008136 +0.008112 +0.008166 +0.008221 +0.008218 +0.008227 +0.008203 +0.00819 +0.008236 +0.008307 +0.008299 +0.008318 +0.008282 +0.001562 +0.008244 +0.008304 +0.00837 +0.008378 +0.008392 +0.008372 +0.00834 +0.008394 +0.008457 +0.008451 +0.00847 +0.00845 +0.008427 +0.008479 +0.008544 +0.008536 +0.008552 +0.008524 +0.008502 +0.008557 +0.008628 +0.008622 +0.008641 +0.008625 +0.00858 +0.008656 +0.008723 +0.00872 +0.008752 +0.008726 +0.00871 +0.00872 +0.008698 +0.008632 +0.008617 +0.008577 +0.008485 +0.008449 +0.008464 +0.008406 +0.00838 +0.008352 +0.008275 +0.008301 +0.008334 +0.008245 +0.008221 +0.008174 +0.008114 +0.008125 +0.008138 +0.008109 +0.008098 +0.008079 +0.008036 +0.008087 +0.008127 +0.008103 +0.008094 +0.008051 +0.008005 +0.008027 +0.008098 +0.008068 +0.008086 +0.00807 +0.008041 +0.008093 +0.008162 +0.008142 +0.008162 +0.00815 +0.008122 +0.008176 +0.008253 +0.008248 +0.008236 +0.001563 +0.00822 +0.008208 +0.008264 +0.008338 +0.008312 +0.008326 +0.008286 +0.008266 +0.008305 +0.008374 +0.008354 +0.008383 +0.00835 +0.008328 +0.008375 +0.008442 +0.008431 +0.008454 +0.008432 +0.008431 +0.008486 +0.008561 +0.008542 +0.008564 +0.008537 +0.008513 +0.008544 +0.008622 +0.008591 +0.008579 +0.008513 +0.008435 +0.008433 +0.008462 +0.008394 +0.008369 +0.008292 +0.008224 +0.008227 +0.008262 +0.008209 +0.008192 +0.008142 +0.008076 +0.008084 +0.00813 +0.008087 +0.00808 +0.00803 +0.00799 +0.00801 +0.008076 +0.008043 +0.008042 +0.008006 +0.007979 +0.008006 +0.008075 +0.008044 +0.008055 +0.008026 +0.008005 +0.008038 +0.008115 +0.0081 +0.008107 +0.008087 +0.00807 +0.008117 +0.008188 +0.008175 +0.008202 +0.008156 +0.008135 +0.001564 +0.008201 +0.008263 +0.008265 +0.008267 +0.008251 +0.008218 +0.008268 +0.008338 +0.008337 +0.008356 +0.00833 +0.0083 +0.008355 +0.008423 +0.008413 +0.008426 +0.008408 +0.008381 +0.008445 +0.008494 +0.008503 +0.008519 +0.008495 +0.008481 +0.008543 +0.008612 +0.008581 +0.008574 +0.008472 +0.008351 +0.008361 +0.008398 +0.008362 +0.00831 +0.008218 +0.008153 +0.008162 +0.008186 +0.008146 +0.008126 +0.008036 +0.007999 +0.00799 +0.008035 +0.007998 +0.007995 +0.007959 +0.007913 +0.007945 +0.00799 +0.007951 +0.007973 +0.007928 +0.007905 +0.007921 +0.007968 +0.007958 +0.007966 +0.007954 +0.007934 +0.00798 +0.008053 +0.008036 +0.008046 +0.00803 +0.008016 +0.008058 +0.008146 +0.008104 +0.008139 +0.001565 +0.008115 +0.008093 +0.008151 +0.008218 +0.008192 +0.008198 +0.008164 +0.00815 +0.008198 +0.008265 +0.008242 +0.008262 +0.008244 +0.008216 +0.008272 +0.008333 +0.008315 +0.008326 +0.008308 +0.008284 +0.00834 +0.008412 +0.008434 +0.008447 +0.00842 +0.008383 +0.008416 +0.008474 +0.008437 +0.008415 +0.008351 +0.008275 +0.008279 +0.008303 +0.008245 +0.008212 +0.008149 +0.008079 +0.00809 +0.008121 +0.008083 +0.008061 +0.008016 +0.007956 +0.00798 +0.008014 +0.007982 +0.00797 +0.007932 +0.007887 +0.007919 +0.007972 +0.007949 +0.007954 +0.007925 +0.007881 +0.007929 +0.007986 +0.00797 +0.00799 +0.00797 +0.007941 +0.007987 +0.008052 +0.00804 +0.008056 +0.008039 +0.007999 +0.008054 +0.008127 +0.001566 +0.008117 +0.00814 +0.008106 +0.008096 +0.008135 +0.008206 +0.008193 +0.008219 +0.008186 +0.008172 +0.008217 +0.00829 +0.008274 +0.008295 +0.008263 +0.008246 +0.008297 +0.00837 +0.008356 +0.008385 +0.008352 +0.00833 +0.008384 +0.00845 +0.008446 +0.008475 +0.008455 +0.008437 +0.008486 +0.008554 +0.008459 +0.008423 +0.00836 +0.008306 +0.008283 +0.008287 +0.008237 +0.008236 +0.00817 +0.008114 +0.008098 +0.008115 +0.008051 +0.008054 +0.00802 +0.007974 +0.007995 +0.007995 +0.007962 +0.007955 +0.007921 +0.007894 +0.007927 +0.008005 +0.007962 +0.007974 +0.007912 +0.007897 +0.007933 +0.007992 +0.007981 +0.007994 +0.007977 +0.007962 +0.007984 +0.008052 +0.00802 +0.00804 +0.008025 +0.008018 +0.008046 +0.008145 +0.0081 +0.00813 +0.001567 +0.008112 +0.008092 +0.008149 +0.008202 +0.008193 +0.008215 +0.0082 +0.008174 +0.008219 +0.008287 +0.008273 +0.008296 +0.00828 +0.008257 +0.008309 +0.008356 +0.008324 +0.008331 +0.008308 +0.008285 +0.008347 +0.008408 +0.008401 +0.008421 +0.008415 +0.008406 +0.008458 +0.008505 +0.008473 +0.008446 +0.008372 +0.008298 +0.00829 +0.008323 +0.008281 +0.008248 +0.008185 +0.008128 +0.008157 +0.008168 +0.008138 +0.008122 +0.008062 +0.008014 +0.008048 +0.008078 +0.008045 +0.00804 +0.007987 +0.00794 +0.007978 +0.00803 +0.008018 +0.008026 +0.007982 +0.007944 +0.007982 +0.008037 +0.008035 +0.008052 +0.008017 +0.007988 +0.008036 +0.008091 +0.008092 +0.008114 +0.008085 +0.008065 +0.008109 +0.008179 +0.008162 +0.001568 +0.008196 +0.008165 +0.008144 +0.008187 +0.008256 +0.008248 +0.008264 +0.008239 +0.008225 +0.00827 +0.008341 +0.008329 +0.008352 +0.008318 +0.008305 +0.008347 +0.008419 +0.008406 +0.008435 +0.008396 +0.008387 +0.008427 +0.008513 +0.008497 +0.008525 +0.008504 +0.008492 +0.008544 +0.0086 +0.008506 +0.008508 +0.008432 +0.008376 +0.008352 +0.008378 +0.008323 +0.00832 +0.008259 +0.008186 +0.008146 +0.008189 +0.008129 +0.008137 +0.008092 +0.008042 +0.008043 +0.008039 +0.007995 +0.008003 +0.007956 +0.00794 +0.007964 +0.008034 +0.007991 +0.008003 +0.007972 +0.007941 +0.007968 +0.008016 +0.007968 +0.00801 +0.007979 +0.007961 +0.00802 +0.008077 +0.008055 +0.008082 +0.00805 +0.008046 +0.008089 +0.008161 +0.00815 +0.008154 +0.001569 +0.008135 +0.008117 +0.008158 +0.008229 +0.008196 +0.008226 +0.008195 +0.008186 +0.008229 +0.008307 +0.008273 +0.00831 +0.008273 +0.008264 +0.008304 +0.008382 +0.008341 +0.008372 +0.00833 +0.008319 +0.008363 +0.00844 +0.008416 +0.00845 +0.008436 +0.008434 +0.008462 +0.008538 +0.008492 +0.008481 +0.008403 +0.008362 +0.008353 +0.008396 +0.008338 +0.008322 +0.008251 +0.00822 +0.008216 +0.00827 +0.008224 +0.008226 +0.008164 +0.008137 +0.008143 +0.0082 +0.008159 +0.00817 +0.008111 +0.008086 +0.008093 +0.008161 +0.008136 +0.008159 +0.008114 +0.008091 +0.008109 +0.008188 +0.008162 +0.008196 +0.008158 +0.008151 +0.008172 +0.008259 +0.008234 +0.008256 +0.008229 +0.008197 +0.008249 +0.008337 +0.00157 +0.008313 +0.00834 +0.008304 +0.008294 +0.008329 +0.008416 +0.008396 +0.008424 +0.00838 +0.008374 +0.008411 +0.008505 +0.008471 +0.008507 +0.008465 +0.00845 +0.008491 +0.008575 +0.008548 +0.008584 +0.008549 +0.008535 +0.008589 +0.008667 +0.00865 +0.008684 +0.008647 +0.008639 +0.008693 +0.008783 +0.008744 +0.008728 +0.008608 +0.008561 +0.008568 +0.008636 +0.008526 +0.008481 +0.008411 +0.008344 +0.008331 +0.008376 +0.008294 +0.008315 +0.008249 +0.008211 +0.008176 +0.008215 +0.008161 +0.008182 +0.008129 +0.008114 +0.008136 +0.008215 +0.008174 +0.008189 +0.008163 +0.008135 +0.008173 +0.008259 +0.008213 +0.008224 +0.00817 +0.008154 +0.008208 +0.008287 +0.008248 +0.008286 +0.008255 +0.008242 +0.008286 +0.008375 +0.008339 +0.008386 +0.001571 +0.008349 +0.00832 +0.008379 +0.008447 +0.008436 +0.00846 +0.008424 +0.008404 +0.008437 +0.008507 +0.008476 +0.008512 +0.008476 +0.008462 +0.00851 +0.008578 +0.008555 +0.008577 +0.008549 +0.008543 +0.008608 +0.00869 +0.008681 +0.008702 +0.008641 +0.008629 +0.008655 +0.0087 +0.008639 +0.00861 +0.008525 +0.008466 +0.008457 +0.008487 +0.008426 +0.00842 +0.008344 +0.008298 +0.008292 +0.00834 +0.008311 +0.008294 +0.008233 +0.008194 +0.008206 +0.008257 +0.008226 +0.008218 +0.008175 +0.008152 +0.00818 +0.008242 +0.008216 +0.008223 +0.008172 +0.008158 +0.008191 +0.008263 +0.008251 +0.008267 +0.008222 +0.008211 +0.008241 +0.008318 +0.008316 +0.008337 +0.008311 +0.008285 +0.008332 +0.008391 +0.001572 +0.008391 +0.008422 +0.008381 +0.008373 +0.008404 +0.008487 +0.008468 +0.008506 +0.008466 +0.008455 +0.008491 +0.008575 +0.008549 +0.008581 +0.008539 +0.008528 +0.008566 +0.008647 +0.008635 +0.008668 +0.008632 +0.008618 +0.008665 +0.00875 +0.00873 +0.008771 +0.008734 +0.008706 +0.008724 +0.008733 +0.008618 +0.008603 +0.008525 +0.008444 +0.008411 +0.008462 +0.008395 +0.008385 +0.008288 +0.008231 +0.00821 +0.008262 +0.00822 +0.008199 +0.008125 +0.008075 +0.008092 +0.008157 +0.008101 +0.00813 +0.008068 +0.008027 +0.00804 +0.008095 +0.008061 +0.008087 +0.008038 +0.008037 +0.008067 +0.008138 +0.008116 +0.008149 +0.008108 +0.008102 +0.008147 +0.008219 +0.00819 +0.008247 +0.008161 +0.008145 +0.001573 +0.008185 +0.008255 +0.008231 +0.008256 +0.008236 +0.008231 +0.008262 +0.008338 +0.008325 +0.00835 +0.008324 +0.008306 +0.008353 +0.008426 +0.008415 +0.008434 +0.008405 +0.008384 +0.008425 +0.008495 +0.008477 +0.0085 +0.008468 +0.008459 +0.008506 +0.008597 +0.008577 +0.008602 +0.008555 +0.008519 +0.008543 +0.008576 +0.008517 +0.008501 +0.008415 +0.008353 +0.008355 +0.008383 +0.008338 +0.00833 +0.008251 +0.008202 +0.008226 +0.008259 +0.008219 +0.008225 +0.008166 +0.008123 +0.008142 +0.008189 +0.008157 +0.008173 +0.008116 +0.008093 +0.008132 +0.008177 +0.008157 +0.008171 +0.008131 +0.008114 +0.008157 +0.008226 +0.008207 +0.008234 +0.008193 +0.008177 +0.008217 +0.008286 +0.008282 +0.008313 +0.008281 +0.008249 +0.001574 +0.008311 +0.008364 +0.008359 +0.008379 +0.008352 +0.008334 +0.008382 +0.008457 +0.008447 +0.00846 +0.008439 +0.008414 +0.008463 +0.008527 +0.008519 +0.008542 +0.008515 +0.008487 +0.00855 +0.00861 +0.008622 +0.008632 +0.008615 +0.008596 +0.008652 +0.008725 +0.008707 +0.00871 +0.008631 +0.008496 +0.008504 +0.008535 +0.008482 +0.00846 +0.008351 +0.00828 +0.008286 +0.008298 +0.008247 +0.008244 +0.008149 +0.008072 +0.008081 +0.008108 +0.008069 +0.008049 +0.008017 +0.007975 +0.007996 +0.008027 +0.007986 +0.007993 +0.007965 +0.007923 +0.007986 +0.008038 +0.008008 +0.008033 +0.008013 +0.007977 +0.008006 +0.008052 +0.008031 +0.008062 +0.008041 +0.008016 +0.008077 +0.00814 +0.008129 +0.008152 +0.008138 +0.008104 +0.001575 +0.008167 +0.008225 +0.008219 +0.008244 +0.008208 +0.0082 +0.008243 +0.008316 +0.008299 +0.008328 +0.008291 +0.008284 +0.008326 +0.008401 +0.008381 +0.008399 +0.008361 +0.008342 +0.008376 +0.008457 +0.008432 +0.008449 +0.00843 +0.00839 +0.008441 +0.008531 +0.008531 +0.008537 +0.008459 +0.008394 +0.008386 +0.008401 +0.008358 +0.008339 +0.008252 +0.008185 +0.00819 +0.008223 +0.008171 +0.008163 +0.008099 +0.00804 +0.008052 +0.008091 +0.00805 +0.008051 +0.007994 +0.007946 +0.007968 +0.008015 +0.007986 +0.008006 +0.007958 +0.007934 +0.007959 +0.008014 +0.007993 +0.008008 +0.007978 +0.007961 +0.008001 +0.008069 +0.008055 +0.008074 +0.008038 +0.008026 +0.008059 +0.008131 +0.008112 +0.00814 +0.008118 +0.001576 +0.00811 +0.008145 +0.008213 +0.008204 +0.008216 +0.008198 +0.008166 +0.008216 +0.008285 +0.008284 +0.008302 +0.008279 +0.008251 +0.008309 +0.00836 +0.008361 +0.008379 +0.008353 +0.008335 +0.008386 +0.008451 +0.008448 +0.008463 +0.008444 +0.008419 +0.008478 +0.008544 +0.008544 +0.008568 +0.008553 +0.008527 +0.008557 +0.008534 +0.008483 +0.008468 +0.008417 +0.008367 +0.008331 +0.008329 +0.00827 +0.008251 +0.008214 +0.008158 +0.008133 +0.008149 +0.008099 +0.008102 +0.008072 +0.008004 +0.008007 +0.008031 +0.008008 +0.008008 +0.007981 +0.007959 +0.007991 +0.00806 +0.008023 +0.008044 +0.008018 +0.007978 +0.008044 +0.008107 +0.008078 +0.008067 +0.008032 +0.008019 +0.008069 +0.008129 +0.008129 +0.008138 +0.008118 +0.008105 +0.008159 +0.008221 +0.008226 +0.001577 +0.008234 +0.008201 +0.008187 +0.008246 +0.008318 +0.008293 +0.008318 +0.008296 +0.008279 +0.008324 +0.008393 +0.008369 +0.008395 +0.008367 +0.008338 +0.008358 +0.008424 +0.008393 +0.008418 +0.008397 +0.008384 +0.00843 +0.00854 +0.008533 +0.008561 +0.008521 +0.008498 +0.008535 +0.008584 +0.008553 +0.008555 +0.008478 +0.008416 +0.008418 +0.008443 +0.008392 +0.00838 +0.008304 +0.008256 +0.008259 +0.008299 +0.008273 +0.008263 +0.008202 +0.008167 +0.008181 +0.008223 +0.008195 +0.008196 +0.008145 +0.008115 +0.008134 +0.008188 +0.00817 +0.008178 +0.008137 +0.008116 +0.008147 +0.008207 +0.0082 +0.008222 +0.008187 +0.008172 +0.008209 +0.008282 +0.008274 +0.00829 +0.008272 +0.008241 +0.008289 +0.001578 +0.008372 +0.008338 +0.008379 +0.008343 +0.008336 +0.008365 +0.008447 +0.008424 +0.00846 +0.008416 +0.00841 +0.008448 +0.008531 +0.008508 +0.008547 +0.008501 +0.008489 +0.00853 +0.008614 +0.008593 +0.00863 +0.008593 +0.008581 +0.008641 +0.008724 +0.008699 +0.008721 +0.008616 +0.008566 +0.008552 +0.008599 +0.008541 +0.008515 +0.008397 +0.00833 +0.008315 +0.008359 +0.00829 +0.00828 +0.008224 +0.008132 +0.008104 +0.008165 +0.008105 +0.008124 +0.008066 +0.008019 +0.007998 +0.008035 +0.007987 +0.00802 +0.007971 +0.00796 +0.007991 +0.008055 +0.008024 +0.008041 +0.008004 +0.008004 +0.008035 +0.008126 +0.008072 +0.008085 +0.00803 +0.00802 +0.008069 +0.00814 +0.00812 +0.008157 +0.008118 +0.008107 +0.008146 +0.001579 +0.008244 +0.008192 +0.008233 +0.008203 +0.008188 +0.008233 +0.008315 +0.008287 +0.008316 +0.008282 +0.008263 +0.008309 +0.008382 +0.008361 +0.008379 +0.008347 +0.008331 +0.008386 +0.00847 +0.008459 +0.008479 +0.00844 +0.008422 +0.008457 +0.008515 +0.008486 +0.008475 +0.008404 +0.008354 +0.008355 +0.008388 +0.008337 +0.008316 +0.008242 +0.008186 +0.008182 +0.008218 +0.008183 +0.008156 +0.008087 +0.008047 +0.008048 +0.008088 +0.008052 +0.008048 +0.007987 +0.007948 +0.007962 +0.008011 +0.007993 +0.007997 +0.007948 +0.007921 +0.007947 +0.008002 +0.00799 +0.008006 +0.007965 +0.007952 +0.007984 +0.008053 +0.008045 +0.008067 +0.008038 +0.008018 +0.008057 +0.008136 +0.00812 +0.008139 +0.00158 +0.008104 +0.008099 +0.008136 +0.008217 +0.008188 +0.008223 +0.008183 +0.008178 +0.008212 +0.008295 +0.008272 +0.008303 +0.008258 +0.008247 +0.008289 +0.008376 +0.008352 +0.008391 +0.008344 +0.008341 +0.008374 +0.008465 +0.00844 +0.008485 +0.008449 +0.008438 +0.008494 +0.008572 +0.008486 +0.008486 +0.00839 +0.008365 +0.008352 +0.008362 +0.008298 +0.008303 +0.008223 +0.008142 +0.008123 +0.008155 +0.008103 +0.008109 +0.008036 +0.00801 +0.007968 +0.007983 +0.007933 +0.007934 +0.007895 +0.007865 +0.007879 +0.007947 +0.007902 +0.007925 +0.007867 +0.007836 +0.007821 +0.007908 +0.007864 +0.007895 +0.007861 +0.007841 +0.007887 +0.007959 +0.007938 +0.00797 +0.007927 +0.007924 +0.007967 +0.008033 +0.008023 +0.008032 +0.008017 +0.001581 +0.008004 +0.008037 +0.008126 +0.008088 +0.008122 +0.008086 +0.00808 +0.008108 +0.008175 +0.00814 +0.008176 +0.008135 +0.008131 +0.008164 +0.008249 +0.008209 +0.008246 +0.008208 +0.008194 +0.008231 +0.008309 +0.008287 +0.008334 +0.008315 +0.008307 +0.008335 +0.008417 +0.008393 +0.008407 +0.008366 +0.008342 +0.008341 +0.008393 +0.008321 +0.00831 +0.008239 +0.008194 +0.00818 +0.008223 +0.008165 +0.008163 +0.008105 +0.008059 +0.008059 +0.008115 +0.008058 +0.008063 +0.008006 +0.007971 +0.007973 +0.008033 +0.007993 +0.008015 +0.007966 +0.007949 +0.007966 +0.008036 +0.007993 +0.008007 +0.007964 +0.007954 +0.007986 +0.008074 +0.008043 +0.008067 +0.008026 +0.008012 +0.008043 +0.008123 +0.008091 +0.008126 +0.008082 +0.008086 +0.00812 +0.008209 +0.001582 +0.008187 +0.008213 +0.00819 +0.008149 +0.008196 +0.008272 +0.008257 +0.008278 +0.008249 +0.008237 +0.008285 +0.008359 +0.008345 +0.008372 +0.008337 +0.008312 +0.008365 +0.008433 +0.008416 +0.008447 +0.008411 +0.008399 +0.008443 +0.008523 +0.008512 +0.008532 +0.008516 +0.0085 +0.008557 +0.00863 +0.008546 +0.00851 +0.008445 +0.008394 +0.008385 +0.008389 +0.008324 +0.008314 +0.008223 +0.00816 +0.008145 +0.008181 +0.00814 +0.008133 +0.008078 +0.007994 +0.007984 +0.008036 +0.00799 +0.008005 +0.007955 +0.007939 +0.007952 +0.008025 +0.007983 +0.008008 +0.00796 +0.00794 +0.007935 +0.00798 +0.007962 +0.007992 +0.007961 +0.007954 +0.007993 +0.008063 +0.00805 +0.00807 +0.008041 +0.00803 +0.008076 +0.008165 +0.008118 +0.008157 +0.001583 +0.008142 +0.008113 +0.008163 +0.008229 +0.008217 +0.008243 +0.008225 +0.008197 +0.008252 +0.008302 +0.00828 +0.008293 +0.008276 +0.008251 +0.008293 +0.00835 +0.008329 +0.008345 +0.008326 +0.008293 +0.008353 +0.008414 +0.008419 +0.008465 +0.008449 +0.008415 +0.008455 +0.008501 +0.00845 +0.008439 +0.008361 +0.008306 +0.008312 +0.008321 +0.008273 +0.008258 +0.008202 +0.008133 +0.008153 +0.008181 +0.008139 +0.008136 +0.008088 +0.008043 +0.008073 +0.008102 +0.008066 +0.008062 +0.008015 +0.007972 +0.008025 +0.008083 +0.008065 +0.008072 +0.008034 +0.007997 +0.008044 +0.008098 +0.008098 +0.008111 +0.00809 +0.008066 +0.008117 +0.008181 +0.008176 +0.008198 +0.008147 +0.008132 +0.001584 +0.008177 +0.00825 +0.008244 +0.008266 +0.008246 +0.008219 +0.008269 +0.008338 +0.008331 +0.008339 +0.008316 +0.008295 +0.008348 +0.008417 +0.008411 +0.008424 +0.008403 +0.008375 +0.008431 +0.008492 +0.008486 +0.008514 +0.008484 +0.008453 +0.00851 +0.008583 +0.008571 +0.008598 +0.008579 +0.008548 +0.008618 +0.008693 +0.008676 +0.008677 +0.008566 +0.008474 +0.008481 +0.008519 +0.008449 +0.008358 +0.00831 +0.008239 +0.008209 +0.008229 +0.008186 +0.008161 +0.008135 +0.008083 +0.008097 +0.008091 +0.00803 +0.008042 +0.008 +0.007975 +0.008 +0.00806 +0.008027 +0.008032 +0.007975 +0.007948 +0.007986 +0.008038 +0.008026 +0.008033 +0.008025 +0.008 +0.008053 +0.008125 +0.008103 +0.008114 +0.008099 +0.00809 +0.008092 +0.00817 +0.008152 +0.001585 +0.00817 +0.008153 +0.008138 +0.008188 +0.00825 +0.008238 +0.008254 +0.008245 +0.008215 +0.008272 +0.008336 +0.008322 +0.008341 +0.008318 +0.008298 +0.008354 +0.008403 +0.008395 +0.0084 +0.008377 +0.00835 +0.008401 +0.008471 +0.008462 +0.008468 +0.008455 +0.008449 +0.008526 +0.008578 +0.00856 +0.008553 +0.008485 +0.008411 +0.00841 +0.008416 +0.00837 +0.00837 +0.008303 +0.008241 +0.008255 +0.008279 +0.008239 +0.00823 +0.008182 +0.00814 +0.008166 +0.008199 +0.008163 +0.008157 +0.008103 +0.008056 +0.008099 +0.008156 +0.008136 +0.008143 +0.008098 +0.008061 +0.008106 +0.008166 +0.008149 +0.008165 +0.008134 +0.008106 +0.008163 +0.008222 +0.008212 +0.008231 +0.008201 +0.008189 +0.008218 +0.008299 +0.008302 +0.001586 +0.008299 +0.008279 +0.008267 +0.008311 +0.00839 +0.00837 +0.00839 +0.008365 +0.008332 +0.008385 +0.008457 +0.00845 +0.008472 +0.008451 +0.008429 +0.008483 +0.008549 +0.008544 +0.008558 +0.008537 +0.00851 +0.008556 +0.008631 +0.008614 +0.008643 +0.008622 +0.008603 +0.008668 +0.008738 +0.008725 +0.008748 +0.008682 +0.008612 +0.008619 +0.008648 +0.008608 +0.008568 +0.008486 +0.008354 +0.00836 +0.008411 +0.008351 +0.008331 +0.008293 +0.008231 +0.00824 +0.008241 +0.008219 +0.00821 +0.008185 +0.008132 +0.008178 +0.008219 +0.008201 +0.008172 +0.00813 +0.008112 +0.008152 +0.008214 +0.008185 +0.008199 +0.008178 +0.008155 +0.008208 +0.008292 +0.008259 +0.008267 +0.008251 +0.00822 +0.008246 +0.008319 +0.008303 +0.008329 +0.008308 +0.001587 +0.00829 +0.00835 +0.008395 +0.008394 +0.008423 +0.008394 +0.008374 +0.008431 +0.008506 +0.008485 +0.008516 +0.008473 +0.00846 +0.008516 +0.008589 +0.008564 +0.008577 +0.008549 +0.008524 +0.008572 +0.008649 +0.008622 +0.008642 +0.008607 +0.008584 +0.008636 +0.008726 +0.008721 +0.008719 +0.008644 +0.008576 +0.00856 +0.00859 +0.008535 +0.008512 +0.008438 +0.008384 +0.008384 +0.008421 +0.008385 +0.008381 +0.008305 +0.008279 +0.008292 +0.008337 +0.008295 +0.008299 +0.008236 +0.008213 +0.008237 +0.008292 +0.008268 +0.008281 +0.008234 +0.008215 +0.008245 +0.008306 +0.008291 +0.008307 +0.008269 +0.008247 +0.008295 +0.008368 +0.008358 +0.008374 +0.008344 +0.008322 +0.008363 +0.008456 +0.008423 +0.001588 +0.008454 +0.00843 +0.008407 +0.008462 +0.008524 +0.008519 +0.008538 +0.008516 +0.008478 +0.008539 +0.008609 +0.008605 +0.008619 +0.008593 +0.008566 +0.008623 +0.008692 +0.008692 +0.008702 +0.008672 +0.008651 +0.0087 +0.008778 +0.00877 +0.008799 +0.008777 +0.008747 +0.008818 +0.008889 +0.008873 +0.008878 +0.008812 +0.008665 +0.008669 +0.008694 +0.008646 +0.008605 +0.008493 +0.008408 +0.008434 +0.008448 +0.008395 +0.008396 +0.008341 +0.008239 +0.00825 +0.008274 +0.008248 +0.008229 +0.008205 +0.008144 +0.008188 +0.008246 +0.008204 +0.008208 +0.008139 +0.008087 +0.008132 +0.008181 +0.008157 +0.008168 +0.008151 +0.008113 +0.008182 +0.008234 +0.008216 +0.008243 +0.008211 +0.008163 +0.008207 +0.008279 +0.008256 +0.008274 +0.008269 +0.008241 +0.008305 +0.008357 +0.001589 +0.008345 +0.008379 +0.008349 +0.00833 +0.008382 +0.008458 +0.00844 +0.008466 +0.008437 +0.008423 +0.008475 +0.008545 +0.008522 +0.008543 +0.008505 +0.008487 +0.008527 +0.008601 +0.008576 +0.008601 +0.00856 +0.008545 +0.008594 +0.0087 +0.008681 +0.008678 +0.00861 +0.008535 +0.008519 +0.008546 +0.008497 +0.008458 +0.008383 +0.008322 +0.008321 +0.008358 +0.008303 +0.008298 +0.008246 +0.00819 +0.008203 +0.008252 +0.008205 +0.008208 +0.008158 +0.008121 +0.008141 +0.008205 +0.008176 +0.008194 +0.008148 +0.008127 +0.008163 +0.008232 +0.008209 +0.008223 +0.008199 +0.008179 +0.008223 +0.008302 +0.008281 +0.00831 +0.00827 +0.008256 +0.00829 +0.008363 +0.00159 +0.008367 +0.008383 +0.008361 +0.008336 +0.008379 +0.008454 +0.008446 +0.008463 +0.008441 +0.008417 +0.008472 +0.008533 +0.00853 +0.008546 +0.008523 +0.008497 +0.008556 +0.00861 +0.008614 +0.00863 +0.008601 +0.00858 +0.008638 +0.008704 +0.008702 +0.008733 +0.008707 +0.008681 +0.008748 +0.008822 +0.008801 +0.008741 +0.008634 +0.008571 +0.008583 +0.008609 +0.008517 +0.008479 +0.008403 +0.008346 +0.008343 +0.008376 +0.008345 +0.008341 +0.0083 +0.008232 +0.00822 +0.008241 +0.008208 +0.008228 +0.008188 +0.008158 +0.008199 +0.008246 +0.008225 +0.008227 +0.008221 +0.008185 +0.008201 +0.008243 +0.008216 +0.008233 +0.008221 +0.00819 +0.008244 +0.008317 +0.008303 +0.008313 +0.008305 +0.00828 +0.008329 +0.008399 +0.008398 +0.008405 +0.008384 +0.001591 +0.008372 +0.008414 +0.008492 +0.008475 +0.008503 +0.008473 +0.008454 +0.008509 +0.008583 +0.008562 +0.008557 +0.008518 +0.008498 +0.008546 +0.00862 +0.008594 +0.008616 +0.008588 +0.008567 +0.008613 +0.008691 +0.008697 +0.008745 +0.008711 +0.008694 +0.008723 +0.008796 +0.008754 +0.008735 +0.008659 +0.008604 +0.008594 +0.008611 +0.008553 +0.008528 +0.008458 +0.008399 +0.008394 +0.008438 +0.008392 +0.00838 +0.008329 +0.008282 +0.008287 +0.008336 +0.00829 +0.00829 +0.008249 +0.008218 +0.008238 +0.008303 +0.008273 +0.008278 +0.008242 +0.008219 +0.008248 +0.008334 +0.008298 +0.008314 +0.008288 +0.008277 +0.008314 +0.008396 +0.008378 +0.008394 +0.008366 +0.008342 +0.008393 +0.008473 +0.001592 +0.008461 +0.008481 +0.008443 +0.008435 +0.008469 +0.008556 +0.008537 +0.008567 +0.008526 +0.008522 +0.008562 +0.008645 +0.008621 +0.008653 +0.008609 +0.008602 +0.008638 +0.008718 +0.0087 +0.008736 +0.00869 +0.008687 +0.008722 +0.008815 +0.008788 +0.008829 +0.008799 +0.008793 +0.008841 +0.008927 +0.008866 +0.008781 +0.00869 +0.008631 +0.008643 +0.008646 +0.008541 +0.008531 +0.008419 +0.008377 +0.008361 +0.008398 +0.008342 +0.008331 +0.008236 +0.008179 +0.008195 +0.008243 +0.0082 +0.008195 +0.008163 +0.0081 +0.008104 +0.008163 +0.008119 +0.008152 +0.0081 +0.008088 +0.008117 +0.00819 +0.008169 +0.008196 +0.008161 +0.008158 +0.008192 +0.008266 +0.008247 +0.008284 +0.008222 +0.008203 +0.008226 +0.001593 +0.008295 +0.008266 +0.008307 +0.008274 +0.00826 +0.008303 +0.00838 +0.008368 +0.008401 +0.008372 +0.008352 +0.008399 +0.008467 +0.00846 +0.008486 +0.008456 +0.008437 +0.008484 +0.008557 +0.008543 +0.008569 +0.008524 +0.008513 +0.008555 +0.008639 +0.008623 +0.00866 +0.008617 +0.008607 +0.008643 +0.008726 +0.008699 +0.008696 +0.008637 +0.008581 +0.008574 +0.008603 +0.008548 +0.008529 +0.008452 +0.008389 +0.008383 +0.008434 +0.008379 +0.008373 +0.008304 +0.008264 +0.008264 +0.008318 +0.008274 +0.008271 +0.008231 +0.008187 +0.008207 +0.008271 +0.008245 +0.008258 +0.008227 +0.008198 +0.008224 +0.008295 +0.008272 +0.008299 +0.008261 +0.008249 +0.008285 +0.008365 +0.008344 +0.008365 +0.008333 +0.008312 +0.008362 +0.008441 +0.001594 +0.008425 +0.008448 +0.008417 +0.008407 +0.00844 +0.008532 +0.008503 +0.008532 +0.008493 +0.008481 +0.008526 +0.008611 +0.008588 +0.008622 +0.008577 +0.008569 +0.008601 +0.008685 +0.008666 +0.008705 +0.008653 +0.008652 +0.00869 +0.008779 +0.00876 +0.008801 +0.008762 +0.008751 +0.008809 +0.0089 +0.008863 +0.008886 +0.008741 +0.008683 +0.008675 +0.008727 +0.008638 +0.008585 +0.008498 +0.008444 +0.008424 +0.008461 +0.008388 +0.008405 +0.008349 +0.00827 +0.008246 +0.008278 +0.008242 +0.008255 +0.008201 +0.008172 +0.008195 +0.00827 +0.008215 +0.008256 +0.008199 +0.008179 +0.008214 +0.008255 +0.008211 +0.008256 +0.008217 +0.008204 +0.008253 +0.008332 +0.00829 +0.008328 +0.008302 +0.008289 +0.008304 +0.008382 +0.008373 +0.008367 +0.001595 +0.008351 +0.00834 +0.008386 +0.008465 +0.008439 +0.008473 +0.008444 +0.008434 +0.008472 +0.008552 +0.008534 +0.008567 +0.008529 +0.008513 +0.008558 +0.008639 +0.00861 +0.008638 +0.008601 +0.008586 +0.008622 +0.008703 +0.008671 +0.008699 +0.008667 +0.008657 +0.008708 +0.008809 +0.008786 +0.008797 +0.008745 +0.008703 +0.008686 +0.008726 +0.008656 +0.008628 +0.008536 +0.008484 +0.008456 +0.008506 +0.008448 +0.008438 +0.008362 +0.008324 +0.008321 +0.00837 +0.008318 +0.008315 +0.008256 +0.008218 +0.008225 +0.008293 +0.008257 +0.008269 +0.008222 +0.008203 +0.008213 +0.008294 +0.008264 +0.008282 +0.008247 +0.008222 +0.008258 +0.00834 +0.008323 +0.008345 +0.008308 +0.008293 +0.008321 +0.008411 +0.008393 +0.008439 +0.008382 +0.001596 +0.008374 +0.00841 +0.00849 +0.008486 +0.008498 +0.008473 +0.00846 +0.008492 +0.008576 +0.008564 +0.008588 +0.008555 +0.008537 +0.008583 +0.008658 +0.00865 +0.008673 +0.008633 +0.008619 +0.008666 +0.008734 +0.008735 +0.008754 +0.008732 +0.00871 +0.008763 +0.008851 +0.008838 +0.008865 +0.008841 +0.00881 +0.008778 +0.008766 +0.008698 +0.008693 +0.008633 +0.008573 +0.008537 +0.008499 +0.008446 +0.008431 +0.008375 +0.008335 +0.008349 +0.008406 +0.008323 +0.008256 +0.008223 +0.008171 +0.008214 +0.008254 +0.008217 +0.008222 +0.008176 +0.008134 +0.008146 +0.008217 +0.008174 +0.008189 +0.008166 +0.008142 +0.008191 +0.008267 +0.00824 +0.008267 +0.008245 +0.00822 +0.00827 +0.008351 +0.008331 +0.008368 +0.00831 +0.008315 +0.001597 +0.008321 +0.008367 +0.008349 +0.00838 +0.008365 +0.008343 +0.008396 +0.008466 +0.008459 +0.008479 +0.008459 +0.008433 +0.008489 +0.008564 +0.008562 +0.008574 +0.00855 +0.008522 +0.008575 +0.008635 +0.008645 +0.008659 +0.008636 +0.008609 +0.008668 +0.008729 +0.008728 +0.008743 +0.008716 +0.00868 +0.008698 +0.008724 +0.00868 +0.008648 +0.008571 +0.008504 +0.008505 +0.008529 +0.008486 +0.008466 +0.008412 +0.008361 +0.008364 +0.008411 +0.008385 +0.008371 +0.008319 +0.00828 +0.0083 +0.008348 +0.008325 +0.008321 +0.008287 +0.00826 +0.008293 +0.008347 +0.008333 +0.00833 +0.0083 +0.008281 +0.008326 +0.008389 +0.008383 +0.008391 +0.008365 +0.008339 +0.008391 +0.008458 +0.008454 +0.008485 +0.008441 +0.008423 +0.001598 +0.008474 +0.008551 +0.008541 +0.008554 +0.008532 +0.008503 +0.008553 +0.008626 +0.008625 +0.008641 +0.008616 +0.008588 +0.008641 +0.00871 +0.008709 +0.008725 +0.008693 +0.008671 +0.008724 +0.008789 +0.008793 +0.008815 +0.008791 +0.008774 +0.008834 +0.008905 +0.008896 +0.008913 +0.008869 +0.008746 +0.00871 +0.008725 +0.008672 +0.008672 +0.008555 +0.008472 +0.008465 +0.008499 +0.008461 +0.008452 +0.008422 +0.008361 +0.008373 +0.008358 +0.008333 +0.008319 +0.008303 +0.008248 +0.008301 +0.008347 +0.00832 +0.008336 +0.008295 +0.008253 +0.008256 +0.008321 +0.008297 +0.008309 +0.0083 +0.00826 +0.008319 +0.008384 +0.008371 +0.008397 +0.008373 +0.008342 +0.008415 +0.008476 +0.008461 +0.008492 +0.008463 +0.001599 +0.00845 +0.008491 +0.008549 +0.008523 +0.008545 +0.008524 +0.008511 +0.008536 +0.008602 +0.008572 +0.008604 +0.008583 +0.008566 +0.008615 +0.008685 +0.008665 +0.00869 +0.008659 +0.008641 +0.008708 +0.008789 +0.008783 +0.008801 +0.008768 +0.008744 +0.008797 +0.008872 +0.008848 +0.008852 +0.008777 +0.008711 +0.008699 +0.008729 +0.008658 +0.00864 +0.008552 +0.008486 +0.008496 +0.008521 +0.008472 +0.008469 +0.0084 +0.008355 +0.008366 +0.008413 +0.008371 +0.008384 +0.008329 +0.008284 +0.008318 +0.008375 +0.008346 +0.008369 +0.008323 +0.008288 +0.008331 +0.008374 +0.008362 +0.008393 +0.008354 +0.008323 +0.008369 +0.008436 +0.008416 +0.008448 +0.008414 +0.008403 +0.008447 +0.008514 +0.008498 +0.008534 +0.0016 +0.0085 +0.008487 +0.008517 +0.008611 +0.008586 +0.008614 +0.008579 +0.008571 +0.008613 +0.0087 +0.008666 +0.008704 +0.00866 +0.00865 +0.008691 +0.008777 +0.008753 +0.00879 +0.008749 +0.008729 +0.008776 +0.008855 +0.008842 +0.008878 +0.008847 +0.008835 +0.00888 +0.008966 +0.00895 +0.008986 +0.00893 +0.008864 +0.008773 +0.008806 +0.008718 +0.008734 +0.008645 +0.008522 +0.008494 +0.008543 +0.008473 +0.008493 +0.008429 +0.008391 +0.008423 +0.008444 +0.008383 +0.008369 +0.008323 +0.008293 +0.008283 +0.00836 +0.0083 +0.008339 +0.008282 +0.008285 +0.008297 +0.008378 +0.008352 +0.008372 +0.00834 +0.008329 +0.008355 +0.00845 +0.008402 +0.008391 +0.008364 +0.008346 +0.00839 +0.008478 +0.008443 +0.008483 +0.008457 +0.008445 +0.00848 +0.008574 +0.001601 +0.008552 +0.008569 +0.008538 +0.008535 +0.008578 +0.008661 +0.008629 +0.008669 +0.008626 +0.008618 +0.008656 +0.008734 +0.008693 +0.008721 +0.008677 +0.008666 +0.008696 +0.008788 +0.008758 +0.008782 +0.008757 +0.008777 +0.008819 +0.008908 +0.008859 +0.008865 +0.008781 +0.008725 +0.0087 +0.008762 +0.008697 +0.008678 +0.008587 +0.008533 +0.008543 +0.00859 +0.008537 +0.008537 +0.008466 +0.008424 +0.008436 +0.008499 +0.008453 +0.008464 +0.008395 +0.008365 +0.008394 +0.008475 +0.008429 +0.008459 +0.008406 +0.008376 +0.008402 +0.008478 +0.008458 +0.008495 +0.008453 +0.008437 +0.00847 +0.008554 +0.008524 +0.008558 +0.008519 +0.008505 +0.008541 +0.00864 +0.001602 +0.008615 +0.008656 +0.008605 +0.008596 +0.008633 +0.008711 +0.008693 +0.008731 +0.008693 +0.008685 +0.008716 +0.008804 +0.008782 +0.008826 +0.008772 +0.008761 +0.008806 +0.00889 +0.008866 +0.008905 +0.008865 +0.008858 +0.008897 +0.008989 +0.008969 +0.009015 +0.008982 +0.008971 +0.009018 +0.009082 +0.008971 +0.008966 +0.008892 +0.008812 +0.008764 +0.008797 +0.008725 +0.008734 +0.008647 +0.008558 +0.008552 +0.008598 +0.008547 +0.008557 +0.008492 +0.008455 +0.008406 +0.008467 +0.008414 +0.008443 +0.00838 +0.008364 +0.008398 +0.008466 +0.008429 +0.008459 +0.008406 +0.008391 +0.008442 +0.008513 +0.008483 +0.008481 +0.008411 +0.008401 +0.008454 +0.008531 +0.008503 +0.008539 +0.008501 +0.008494 +0.008544 +0.008625 +0.008608 +0.008617 +0.008602 +0.001603 +0.008584 +0.008628 +0.008726 +0.008689 +0.008722 +0.008683 +0.008675 +0.008701 +0.008766 +0.008736 +0.00877 +0.008733 +0.008716 +0.008756 +0.008834 +0.008813 +0.008846 +0.008817 +0.008825 +0.008874 +0.00897 +0.008934 +0.008966 +0.00891 +0.008882 +0.008885 +0.008933 +0.008864 +0.008847 +0.008746 +0.008679 +0.008676 +0.008709 +0.00865 +0.008661 +0.008566 +0.008526 +0.008532 +0.008589 +0.008543 +0.008553 +0.008484 +0.008438 +0.008453 +0.008513 +0.008474 +0.008502 +0.008432 +0.008409 +0.008436 +0.008501 +0.008466 +0.0085 +0.00845 +0.008433 +0.008468 +0.008546 +0.00852 +0.008558 +0.008504 +0.008498 +0.008541 +0.008622 +0.008606 +0.008631 +0.008608 +0.001604 +0.008573 +0.008631 +0.008702 +0.008692 +0.00872 +0.008687 +0.008663 +0.008708 +0.00879 +0.008779 +0.008807 +0.008774 +0.008755 +0.008795 +0.008873 +0.00886 +0.00889 +0.008864 +0.008836 +0.008892 +0.00897 +0.00896 +0.008984 +0.008954 +0.00894 +0.008991 +0.009083 +0.009073 +0.0091 +0.009024 +0.008912 +0.008916 +0.008948 +0.008887 +0.008875 +0.008719 +0.00864 +0.00864 +0.008672 +0.008608 +0.008614 +0.008543 +0.008506 +0.008454 +0.008495 +0.008445 +0.008457 +0.008405 +0.008376 +0.008385 +0.008458 +0.008418 +0.008428 +0.008402 +0.00833 +0.008338 +0.008407 +0.008364 +0.008401 +0.008374 +0.008346 +0.00839 +0.008465 +0.008441 +0.008459 +0.00844 +0.008417 +0.008467 +0.008552 +0.00854 +0.008548 +0.008524 +0.008511 +0.001605 +0.0085 +0.008584 +0.008553 +0.008591 +0.008557 +0.008552 +0.008596 +0.008679 +0.008655 +0.008691 +0.008655 +0.008647 +0.008684 +0.008771 +0.008744 +0.008773 +0.008735 +0.008724 +0.008763 +0.008862 +0.008844 +0.008874 +0.008831 +0.008825 +0.008856 +0.008948 +0.008925 +0.008952 +0.008893 +0.008844 +0.008841 +0.008894 +0.008809 +0.008801 +0.008709 +0.008654 +0.00865 +0.008705 +0.008648 +0.008651 +0.008582 +0.008543 +0.008553 +0.008614 +0.008569 +0.008583 +0.008516 +0.008485 +0.008498 +0.008575 +0.008534 +0.008565 +0.008516 +0.008491 +0.008514 +0.008597 +0.008569 +0.008608 +0.008564 +0.008549 +0.008581 +0.00867 +0.008641 +0.008686 +0.00865 +0.008622 +0.008672 +0.001606 +0.008747 +0.008733 +0.008763 +0.008739 +0.008717 +0.008754 +0.008836 +0.008818 +0.008843 +0.008815 +0.0088 +0.008842 +0.008935 +0.008901 +0.008937 +0.008907 +0.008883 +0.008932 +0.009006 +0.009006 +0.009025 +0.008992 +0.008978 +0.009023 +0.009107 +0.009101 +0.00913 +0.009104 +0.009089 +0.009141 +0.009198 +0.009083 +0.009009 +0.008934 +0.008855 +0.008808 +0.008825 +0.00875 +0.008739 +0.008674 +0.00862 +0.008629 +0.008647 +0.008575 +0.008579 +0.008487 +0.008446 +0.008431 +0.008485 +0.008428 +0.008448 +0.008398 +0.008373 +0.008408 +0.008465 +0.008427 +0.008407 +0.008365 +0.008346 +0.008369 +0.008441 +0.0084 +0.008422 +0.008402 +0.00838 +0.008426 +0.008515 +0.008477 +0.00851 +0.008482 +0.008462 +0.00851 +0.0086 +0.00858 +0.008577 +0.001607 +0.008566 +0.008562 +0.008599 +0.008674 +0.008641 +0.008685 +0.008635 +0.008616 +0.00864 +0.008719 +0.008689 +0.008732 +0.008699 +0.008684 +0.00872 +0.008805 +0.008783 +0.008813 +0.008788 +0.0088 +0.008832 +0.008921 +0.008897 +0.008928 +0.008881 +0.008872 +0.008915 +0.008977 +0.008918 +0.008914 +0.008819 +0.008764 +0.008745 +0.008784 +0.008724 +0.008723 +0.008649 +0.008601 +0.008619 +0.008674 +0.008629 +0.008643 +0.008573 +0.008536 +0.008553 +0.008615 +0.008565 +0.008579 +0.008516 +0.008496 +0.008526 +0.008596 +0.008561 +0.008581 +0.008532 +0.008506 +0.008536 +0.00862 +0.008601 +0.008639 +0.008594 +0.008578 +0.008619 +0.008695 +0.008681 +0.008707 +0.008672 +0.008648 +0.001608 +0.008705 +0.008785 +0.008776 +0.008794 +0.008761 +0.008739 +0.008783 +0.00886 +0.008852 +0.008886 +0.008854 +0.008828 +0.008871 +0.008952 +0.008938 +0.008966 +0.008929 +0.008909 +0.008964 +0.009038 +0.009033 +0.009056 +0.009036 +0.009019 +0.009069 +0.009155 +0.009141 +0.009143 +0.009075 +0.00898 +0.00891 +0.008927 +0.008874 +0.008869 +0.008728 +0.008669 +0.008666 +0.008707 +0.008664 +0.008661 +0.00859 +0.008506 +0.008481 +0.008538 +0.008486 +0.0085 +0.008425 +0.008401 +0.008426 +0.0085 +0.008458 +0.008481 +0.008381 +0.008353 +0.008374 +0.008445 +0.00842 +0.008429 +0.008404 +0.008374 +0.008418 +0.0085 +0.008469 +0.008505 +0.008475 +0.008447 +0.008486 +0.008546 +0.008519 +0.008554 +0.008533 +0.008511 +0.001609 +0.008556 +0.008629 +0.008619 +0.008656 +0.008616 +0.008607 +0.008647 +0.008728 +0.008705 +0.008745 +0.008697 +0.008696 +0.008726 +0.008815 +0.00878 +0.008809 +0.008769 +0.008758 +0.008789 +0.008872 +0.008865 +0.00892 +0.008877 +0.008864 +0.008896 +0.008966 +0.008929 +0.008935 +0.008849 +0.008792 +0.008768 +0.008794 +0.008728 +0.008709 +0.008615 +0.008564 +0.008553 +0.008595 +0.008538 +0.008536 +0.008459 +0.008417 +0.008416 +0.008465 +0.008422 +0.008426 +0.008359 +0.008337 +0.008353 +0.008421 +0.008391 +0.008402 +0.008345 +0.008335 +0.008362 +0.008438 +0.00842 +0.008448 +0.008401 +0.008393 +0.00842 +0.008499 +0.008482 +0.008508 +0.008471 +0.00848 +0.008495 +0.008588 +0.00161 +0.008564 +0.008595 +0.008557 +0.008544 +0.008589 +0.008669 +0.008646 +0.008681 +0.008648 +0.008629 +0.008672 +0.008749 +0.008742 +0.008762 +0.00873 +0.008708 +0.008761 +0.008833 +0.00882 +0.008853 +0.00882 +0.008807 +0.008856 +0.008947 +0.008925 +0.008958 +0.008937 +0.008923 +0.008985 +0.009007 +0.008925 +0.00892 +0.008856 +0.008802 +0.008758 +0.008776 +0.008685 +0.008681 +0.008598 +0.008507 +0.008492 +0.008548 +0.008491 +0.008477 +0.008416 +0.00832 +0.008337 +0.008368 +0.008323 +0.008319 +0.008292 +0.008247 +0.008292 +0.00834 +0.008299 +0.008313 +0.008234 +0.008225 +0.008245 +0.008309 +0.008287 +0.008299 +0.008283 +0.008271 +0.00831 +0.008397 +0.008362 +0.008386 +0.008369 +0.008346 +0.008408 +0.008472 +0.008451 +0.001611 +0.008463 +0.008422 +0.008418 +0.008454 +0.008536 +0.0085 +0.008537 +0.008507 +0.008495 +0.008535 +0.008617 +0.008583 +0.008615 +0.008572 +0.008561 +0.0086 +0.008685 +0.008647 +0.00869 +0.00866 +0.008674 +0.008709 +0.008798 +0.008768 +0.008802 +0.008748 +0.008715 +0.008734 +0.008785 +0.008713 +0.008705 +0.008614 +0.008555 +0.008549 +0.008585 +0.008517 +0.00851 +0.00843 +0.008386 +0.008389 +0.008436 +0.008379 +0.008384 +0.008312 +0.008269 +0.008284 +0.008342 +0.008299 +0.008319 +0.008259 +0.008231 +0.008249 +0.008321 +0.008292 +0.008317 +0.00827 +0.008246 +0.008281 +0.008358 +0.008336 +0.008376 +0.008328 +0.008321 +0.008355 +0.00843 +0.00842 +0.008457 +0.008411 +0.001612 +0.008398 +0.008436 +0.008517 +0.008511 +0.008519 +0.008498 +0.008477 +0.008524 +0.008599 +0.008588 +0.008613 +0.008581 +0.008559 +0.008606 +0.008682 +0.008679 +0.008686 +0.00866 +0.008649 +0.008694 +0.008778 +0.008761 +0.008795 +0.008765 +0.00875 +0.008804 +0.008884 +0.008853 +0.008815 +0.008693 +0.008624 +0.008642 +0.008673 +0.008588 +0.008555 +0.00847 +0.008409 +0.008419 +0.008463 +0.008401 +0.008409 +0.00837 +0.008267 +0.00829 +0.00832 +0.00829 +0.008282 +0.008254 +0.008211 +0.008261 +0.008316 +0.008283 +0.008297 +0.008246 +0.00823 +0.008274 +0.008342 +0.00831 +0.008283 +0.008252 +0.008245 +0.008282 +0.008371 +0.008344 +0.008373 +0.008332 +0.008328 +0.008373 +0.008452 +0.008434 +0.008472 +0.008414 +0.001613 +0.008417 +0.008463 +0.00851 +0.00849 +0.008515 +0.008489 +0.008471 +0.008531 +0.008603 +0.008582 +0.008598 +0.008582 +0.008559 +0.00861 +0.008674 +0.008657 +0.008665 +0.008643 +0.008615 +0.008672 +0.008736 +0.008725 +0.008763 +0.008755 +0.008739 +0.008781 +0.00884 +0.008812 +0.008784 +0.008721 +0.008666 +0.008679 +0.008709 +0.008665 +0.008633 +0.008576 +0.008524 +0.00853 +0.008563 +0.008532 +0.008526 +0.008479 +0.008427 +0.008445 +0.008489 +0.00847 +0.008452 +0.008417 +0.008384 +0.008408 +0.008464 +0.008454 +0.008438 +0.008413 +0.008385 +0.008425 +0.008484 +0.008474 +0.008481 +0.008465 +0.008447 +0.008489 +0.008562 +0.008549 +0.00856 +0.008544 +0.008512 +0.008576 +0.001614 +0.008651 +0.008639 +0.00866 +0.008623 +0.008599 +0.008643 +0.008721 +0.008708 +0.008742 +0.008714 +0.008694 +0.008737 +0.008808 +0.008802 +0.008828 +0.008789 +0.008773 +0.008829 +0.008896 +0.008895 +0.008916 +0.008895 +0.008875 +0.008933 +0.009026 +0.008999 +0.009028 +0.008992 +0.008876 +0.00889 +0.008933 +0.008895 +0.008893 +0.008827 +0.00877 +0.008702 +0.008718 +0.008655 +0.008667 +0.008602 +0.008557 +0.008595 +0.008594 +0.00853 +0.008518 +0.008477 +0.008423 +0.008423 +0.008457 +0.008435 +0.008434 +0.008402 +0.008367 +0.008397 +0.008481 +0.008433 +0.008461 +0.008432 +0.008402 +0.008465 +0.008515 +0.008473 +0.008506 +0.008473 +0.008453 +0.008494 +0.008555 +0.008526 +0.008571 +0.008534 +0.008515 +0.00857 +0.008672 +0.001615 +0.008612 +0.008651 +0.008627 +0.008611 +0.008664 +0.008733 +0.008724 +0.008745 +0.008723 +0.008697 +0.00875 +0.008815 +0.008797 +0.00881 +0.00879 +0.008766 +0.008812 +0.008894 +0.008901 +0.008925 +0.008889 +0.008851 +0.008888 +0.008913 +0.008873 +0.008847 +0.008769 +0.008701 +0.00871 +0.008725 +0.008672 +0.00866 +0.008586 +0.008522 +0.00854 +0.008572 +0.008527 +0.008515 +0.008453 +0.008402 +0.008425 +0.008453 +0.008424 +0.008428 +0.008383 +0.008343 +0.008377 +0.008424 +0.008406 +0.008416 +0.008381 +0.008347 +0.008391 +0.008443 +0.008436 +0.008458 +0.008428 +0.008402 +0.008455 +0.008515 +0.008518 +0.008528 +0.008523 +0.008473 +0.008535 +0.001616 +0.008603 +0.008594 +0.008618 +0.008584 +0.008569 +0.008619 +0.008683 +0.008676 +0.008703 +0.008671 +0.008655 +0.008703 +0.008786 +0.00876 +0.008787 +0.008755 +0.008739 +0.008782 +0.008868 +0.008858 +0.008882 +0.008859 +0.008847 +0.008901 +0.008976 +0.008954 +0.008926 +0.008816 +0.008756 +0.008775 +0.008806 +0.008737 +0.00868 +0.008595 +0.008537 +0.008516 +0.008561 +0.008488 +0.00848 +0.008414 +0.008307 +0.008333 +0.008347 +0.008318 +0.008305 +0.008263 +0.008219 +0.008264 +0.008305 +0.00824 +0.008257 +0.008188 +0.00816 +0.008197 +0.008248 +0.008214 +0.008241 +0.0082 +0.008188 +0.008238 +0.008301 +0.00829 +0.008314 +0.008268 +0.008248 +0.008271 +0.008333 +0.008325 +0.008351 +0.008322 +0.008327 +0.008346 +0.001617 +0.008429 +0.008421 +0.008447 +0.008422 +0.008396 +0.008448 +0.008517 +0.008514 +0.00853 +0.008509 +0.008482 +0.008533 +0.008598 +0.008586 +0.008601 +0.008581 +0.008544 +0.008594 +0.008674 +0.00868 +0.008703 +0.00867 +0.008636 +0.008679 +0.008714 +0.008677 +0.00865 +0.008578 +0.00851 +0.008512 +0.008526 +0.008476 +0.008451 +0.008382 +0.008319 +0.008329 +0.008356 +0.008318 +0.008305 +0.008241 +0.008192 +0.00821 +0.008246 +0.008216 +0.00821 +0.008171 +0.008133 +0.008166 +0.008213 +0.008202 +0.008202 +0.008173 +0.008143 +0.008187 +0.00824 +0.008237 +0.008257 +0.008229 +0.008209 +0.008252 +0.008314 +0.008317 +0.008313 +0.008285 +0.008331 +0.008408 +0.001618 +0.008383 +0.00842 +0.008382 +0.008368 +0.008405 +0.008491 +0.008473 +0.008494 +0.008462 +0.008454 +0.008489 +0.008576 +0.008554 +0.008585 +0.008542 +0.008534 +0.008574 +0.008653 +0.00864 +0.008673 +0.008639 +0.008631 +0.00868 +0.008768 +0.008741 +0.008777 +0.008735 +0.00864 +0.008621 +0.00867 +0.008612 +0.008624 +0.008551 +0.008503 +0.008451 +0.008464 +0.008403 +0.008411 +0.008353 +0.008314 +0.008334 +0.008379 +0.008277 +0.008283 +0.008206 +0.008183 +0.008176 +0.008231 +0.008188 +0.008205 +0.008159 +0.008124 +0.008164 +0.008229 +0.008187 +0.008221 +0.008171 +0.00815 +0.008169 +0.00821 +0.008179 +0.008216 +0.008177 +0.00818 +0.008219 +0.008294 +0.008282 +0.008305 +0.008264 +0.00827 +0.008301 +0.008395 +0.008358 +0.001619 +0.008396 +0.008352 +0.008342 +0.008398 +0.008474 +0.008448 +0.008475 +0.008405 +0.008395 +0.008447 +0.008515 +0.008492 +0.008514 +0.008482 +0.008463 +0.008501 +0.008579 +0.008571 +0.008618 +0.008599 +0.008584 +0.008628 +0.008692 +0.008659 +0.008663 +0.008572 +0.008517 +0.00852 +0.008534 +0.00846 +0.008442 +0.008346 +0.008288 +0.008283 +0.008301 +0.008236 +0.008216 +0.00815 +0.008099 +0.008099 +0.008126 +0.008071 +0.008067 +0.00801 +0.007972 +0.00799 +0.008033 +0.007998 +0.00801 +0.007984 +0.007938 +0.00798 +0.008037 +0.008001 +0.008021 +0.007977 +0.007966 +0.007999 +0.008082 +0.008068 +0.008093 +0.008054 +0.008041 +0.008071 +0.008144 +0.008121 +0.008161 +0.00812 +0.008116 +0.00162 +0.008173 +0.008231 +0.008227 +0.008238 +0.00821 +0.008185 +0.008232 +0.008295 +0.00829 +0.008303 +0.008278 +0.00825 +0.008323 +0.008376 +0.008375 +0.008401 +0.008372 +0.008353 +0.008405 +0.008485 +0.008474 +0.008496 +0.008482 +0.008461 +0.008487 +0.008472 +0.008418 +0.008407 +0.008364 +0.008309 +0.0083 +0.008273 +0.008221 +0.008209 +0.008151 +0.008095 +0.008097 +0.008086 +0.008041 +0.008042 +0.007974 +0.007905 +0.007897 +0.007945 +0.007901 +0.007908 +0.00787 +0.00783 +0.007872 +0.007893 +0.007866 +0.007869 +0.007831 +0.007807 +0.00782 +0.007862 +0.007863 +0.007873 +0.007853 +0.00784 +0.007883 +0.007948 +0.007939 +0.007949 +0.007943 +0.007917 +0.007965 +0.008055 +0.008 +0.008029 +0.001621 +0.008013 +0.007991 +0.008045 +0.0081 +0.008081 +0.008102 +0.008082 +0.008056 +0.008094 +0.008153 +0.00814 +0.008157 +0.008142 +0.008108 +0.008163 +0.008222 +0.008206 +0.008223 +0.008202 +0.00819 +0.008257 +0.008336 +0.008329 +0.008336 +0.008303 +0.008283 +0.008311 +0.008353 +0.008319 +0.008297 +0.008228 +0.008163 +0.008167 +0.008181 +0.008151 +0.008102 +0.008059 +0.00799 +0.007992 +0.008024 +0.007995 +0.007977 +0.007921 +0.007879 +0.007895 +0.007929 +0.007908 +0.007891 +0.007847 +0.007814 +0.007854 +0.00791 +0.007906 +0.007903 +0.007871 +0.007846 +0.007887 +0.007924 +0.00793 +0.007946 +0.007932 +0.007915 +0.007955 +0.008027 +0.008015 +0.008036 +0.007992 +0.001622 +0.007974 +0.008023 +0.008087 +0.008094 +0.008111 +0.008088 +0.008057 +0.008106 +0.008172 +0.008161 +0.008176 +0.008154 +0.008126 +0.00818 +0.008244 +0.008245 +0.008261 +0.008236 +0.008214 +0.008275 +0.008334 +0.008337 +0.008349 +0.008336 +0.008303 +0.008376 +0.008457 +0.008436 +0.008391 +0.008339 +0.008287 +0.008325 +0.008355 +0.008304 +0.008295 +0.008236 +0.008116 +0.008088 +0.008119 +0.008068 +0.008052 +0.008007 +0.00794 +0.00797 +0.007962 +0.007899 +0.007888 +0.007844 +0.007809 +0.007802 +0.007822 +0.007795 +0.007788 +0.007767 +0.007717 +0.007774 +0.007823 +0.007795 +0.007808 +0.007775 +0.007759 +0.007811 +0.007852 +0.007846 +0.007836 +0.007823 +0.0078 +0.00785 +0.007915 +0.007909 +0.007917 +0.007899 +0.007882 +0.007935 +0.007979 +0.001623 +0.007985 +0.007981 +0.007969 +0.007961 +0.007994 +0.008064 +0.00804 +0.008068 +0.008029 +0.00802 +0.008071 +0.008141 +0.008116 +0.008137 +0.008097 +0.008082 +0.008115 +0.008183 +0.00817 +0.008195 +0.008171 +0.008154 +0.008214 +0.008299 +0.008285 +0.008295 +0.008251 +0.008214 +0.008205 +0.008241 +0.008184 +0.008175 +0.008104 +0.008055 +0.008051 +0.008087 +0.008053 +0.008047 +0.00797 +0.007927 +0.00793 +0.007987 +0.007948 +0.007949 +0.007892 +0.00786 +0.007868 +0.007927 +0.007896 +0.007902 +0.007868 +0.007849 +0.007875 +0.007938 +0.007918 +0.007923 +0.007893 +0.007872 +0.007908 +0.00799 +0.007979 +0.007999 +0.007974 +0.00795 +0.007993 +0.008061 +0.008047 +0.008067 +0.001624 +0.008034 +0.008031 +0.00807 +0.008149 +0.008126 +0.008152 +0.008114 +0.0081 +0.008132 +0.008215 +0.008197 +0.008233 +0.008193 +0.008184 +0.008217 +0.008299 +0.008275 +0.008314 +0.008266 +0.008263 +0.008299 +0.008381 +0.008366 +0.0084 +0.008366 +0.008367 +0.00841 +0.008491 +0.008454 +0.008413 +0.00831 +0.008263 +0.008271 +0.008316 +0.008204 +0.008174 +0.008081 +0.008031 +0.007993 +0.008027 +0.007958 +0.007955 +0.007898 +0.00781 +0.007783 +0.007846 +0.007776 +0.007797 +0.007729 +0.007716 +0.007724 +0.007783 +0.007741 +0.007737 +0.00769 +0.007679 +0.007678 +0.00776 +0.00772 +0.007745 +0.007721 +0.007705 +0.007745 +0.00783 +0.007797 +0.007829 +0.007802 +0.007793 +0.007827 +0.007915 +0.007895 +0.007887 +0.001625 +0.007872 +0.007871 +0.007904 +0.00796 +0.007924 +0.007967 +0.007934 +0.00792 +0.007959 +0.00803 +0.008002 +0.008037 +0.008003 +0.008 +0.008036 +0.008113 +0.008078 +0.008106 +0.008068 +0.008058 +0.008089 +0.008161 +0.008135 +0.008172 +0.008143 +0.008159 +0.008191 +0.008268 +0.008234 +0.008228 +0.008161 +0.008111 +0.008102 +0.008151 +0.008091 +0.008078 +0.008003 +0.007957 +0.007948 +0.008001 +0.00795 +0.007937 +0.007867 +0.007838 +0.007841 +0.007895 +0.007859 +0.007859 +0.007803 +0.00778 +0.007788 +0.007855 +0.007833 +0.007857 +0.00781 +0.007795 +0.007814 +0.007889 +0.007862 +0.007892 +0.007859 +0.007851 +0.007879 +0.007964 +0.007938 +0.007979 +0.007929 +0.007919 +0.00795 +0.001626 +0.008023 +0.008015 +0.008042 +0.008013 +0.007991 +0.008033 +0.008104 +0.008094 +0.008115 +0.008085 +0.008067 +0.008117 +0.008178 +0.008175 +0.008197 +0.008167 +0.008142 +0.008192 +0.008263 +0.008248 +0.008269 +0.008243 +0.008219 +0.008278 +0.008346 +0.008348 +0.00837 +0.008341 +0.008325 +0.008376 +0.008414 +0.008318 +0.008313 +0.008244 +0.008163 +0.00814 +0.008178 +0.008115 +0.008115 +0.008024 +0.007946 +0.00796 +0.007992 +0.00795 +0.007955 +0.007898 +0.007813 +0.007805 +0.007864 +0.007811 +0.007833 +0.007787 +0.007756 +0.007794 +0.007854 +0.007809 +0.00783 +0.007795 +0.007772 +0.007767 +0.007826 +0.007805 +0.007825 +0.007806 +0.007783 +0.007834 +0.0079 +0.00788 +0.007914 +0.007879 +0.007864 +0.007914 +0.008003 +0.007952 +0.007983 +0.001627 +0.007969 +0.007942 +0.007993 +0.008058 +0.008053 +0.00807 +0.008047 +0.008017 +0.008075 +0.008138 +0.008123 +0.00814 +0.008124 +0.008084 +0.008112 +0.008168 +0.008152 +0.008172 +0.00815 +0.008123 +0.008175 +0.008255 +0.008277 +0.008304 +0.008277 +0.008249 +0.008283 +0.008329 +0.00829 +0.008274 +0.0082 +0.008118 +0.008146 +0.008174 +0.008122 +0.008101 +0.008036 +0.007978 +0.00799 +0.008026 +0.007995 +0.00799 +0.007932 +0.007881 +0.007914 +0.007947 +0.007923 +0.007916 +0.007868 +0.007829 +0.007871 +0.007925 +0.00791 +0.007917 +0.007888 +0.007841 +0.007897 +0.007959 +0.007956 +0.007976 +0.007949 +0.007923 +0.00797 +0.008029 +0.008029 +0.008046 +0.008009 +0.001628 +0.007986 +0.008046 +0.008111 +0.008105 +0.008124 +0.008097 +0.008075 +0.008116 +0.008182 +0.008181 +0.008202 +0.008174 +0.00815 +0.008197 +0.008272 +0.008262 +0.00828 +0.008259 +0.008222 +0.008282 +0.008342 +0.008333 +0.008357 +0.008332 +0.00832 +0.008376 +0.008444 +0.008448 +0.008456 +0.008437 +0.008418 +0.00843 +0.008417 +0.008378 +0.008353 +0.008303 +0.008243 +0.008265 +0.008221 +0.008152 +0.00813 +0.008095 +0.008011 +0.007991 +0.008031 +0.007978 +0.00799 +0.007922 +0.007841 +0.007845 +0.007892 +0.007851 +0.007852 +0.007818 +0.007771 +0.007823 +0.00786 +0.007847 +0.007847 +0.007787 +0.007765 +0.007796 +0.007839 +0.007838 +0.007851 +0.00783 +0.007814 +0.007862 +0.007917 +0.007909 +0.007927 +0.007906 +0.007903 +0.007928 +0.007975 +0.007962 +0.001629 +0.007976 +0.007961 +0.007939 +0.007987 +0.008053 +0.008043 +0.008062 +0.008046 +0.008021 +0.008073 +0.008137 +0.008125 +0.008137 +0.008119 +0.008089 +0.008146 +0.008203 +0.008191 +0.008206 +0.00818 +0.008153 +0.008207 +0.008264 +0.008281 +0.008314 +0.008291 +0.008263 +0.008297 +0.008365 +0.00833 +0.008322 +0.008266 +0.008203 +0.008215 +0.008242 +0.00819 +0.00814 +0.008099 +0.008018 +0.008034 +0.008069 +0.008029 +0.008005 +0.00795 +0.007913 +0.007934 +0.007982 +0.007947 +0.007931 +0.007891 +0.007846 +0.007877 +0.007943 +0.007928 +0.007929 +0.007904 +0.007867 +0.0079 +0.007961 +0.007955 +0.007943 +0.007942 +0.007918 +0.007963 +0.008036 +0.008034 +0.008035 +0.008019 +0.007985 +0.008044 +0.00809 +0.00163 +0.008082 +0.008113 +0.008076 +0.008073 +0.008114 +0.008185 +0.00817 +0.008196 +0.008163 +0.008147 +0.008187 +0.008258 +0.008253 +0.008274 +0.008252 +0.008213 +0.00827 +0.008343 +0.008331 +0.008361 +0.008318 +0.008312 +0.008359 +0.00844 +0.008423 +0.008456 +0.008429 +0.008411 +0.008432 +0.008416 +0.008347 +0.008336 +0.008282 +0.008224 +0.008166 +0.008182 +0.008121 +0.008105 +0.008051 +0.007999 +0.007961 +0.007983 +0.007934 +0.007943 +0.00789 +0.007826 +0.007812 +0.007853 +0.007804 +0.007826 +0.007775 +0.007761 +0.007781 +0.007851 +0.007823 +0.007826 +0.0078 +0.007773 +0.007809 +0.007894 +0.007848 +0.007847 +0.007824 +0.007799 +0.007842 +0.007921 +0.00789 +0.007912 +0.007896 +0.007885 +0.007928 +0.007999 +0.00798 +0.008027 +0.007964 +0.001631 +0.007953 +0.008009 +0.008075 +0.008068 +0.008085 +0.008066 +0.008039 +0.008092 +0.008155 +0.008143 +0.008155 +0.008137 +0.00811 +0.008157 +0.008213 +0.008193 +0.008203 +0.008181 +0.008164 +0.008204 +0.008276 +0.008286 +0.008327 +0.008295 +0.008253 +0.00828 +0.008308 +0.008253 +0.008214 +0.008135 +0.008074 +0.0081 +0.008118 +0.00807 +0.008055 +0.008002 +0.007947 +0.007968 +0.008004 +0.007978 +0.007971 +0.00792 +0.007868 +0.007896 +0.007935 +0.007909 +0.007913 +0.00787 +0.007837 +0.007873 +0.007922 +0.007906 +0.007916 +0.007882 +0.007851 +0.0079 +0.007953 +0.007948 +0.007963 +0.007938 +0.007917 +0.00797 +0.008025 +0.008029 +0.008044 +0.008006 +0.00799 +0.001632 +0.008048 +0.008107 +0.0081 +0.008116 +0.008094 +0.008068 +0.008118 +0.008185 +0.008181 +0.008197 +0.008171 +0.008142 +0.008198 +0.008255 +0.008259 +0.008274 +0.008247 +0.008233 +0.008274 +0.008348 +0.008342 +0.008364 +0.008337 +0.008322 +0.008387 +0.008458 +0.008443 +0.008434 +0.008324 +0.008252 +0.008259 +0.008295 +0.008243 +0.008154 +0.0081 +0.008042 +0.008024 +0.008044 +0.007993 +0.007987 +0.007934 +0.007889 +0.007865 +0.007863 +0.007825 +0.007815 +0.007793 +0.00774 +0.007769 +0.007824 +0.007787 +0.007795 +0.007751 +0.007687 +0.007727 +0.00777 +0.007751 +0.00777 +0.007746 +0.007722 +0.007781 +0.007834 +0.007825 +0.007845 +0.00782 +0.0078 +0.007856 +0.007913 +0.007922 +0.007917 +0.007905 +0.001633 +0.007884 +0.007935 +0.008013 +0.007982 +0.007994 +0.007941 +0.007934 +0.007982 +0.00805 +0.008025 +0.008048 +0.008023 +0.008004 +0.008058 +0.008119 +0.008101 +0.008124 +0.008095 +0.008071 +0.008112 +0.008182 +0.008168 +0.008205 +0.008189 +0.008174 +0.008214 +0.00829 +0.008266 +0.008286 +0.008233 +0.008193 +0.008192 +0.008226 +0.008169 +0.008155 +0.008088 +0.008016 +0.008024 +0.008057 +0.008008 +0.007997 +0.007931 +0.007891 +0.007893 +0.007937 +0.007892 +0.007893 +0.007835 +0.007795 +0.007801 +0.007862 +0.007831 +0.007841 +0.007798 +0.007768 +0.007807 +0.007852 +0.00784 +0.007857 +0.007824 +0.007805 +0.007845 +0.007914 +0.007899 +0.007931 +0.007895 +0.007878 +0.007912 +0.007991 +0.015972 +0.007962 +0.001634 +0.007958 +0.007988 +0.008072 +0.008045 +0.008079 +0.008042 +0.008031 +0.008068 +0.008146 +0.008129 +0.008154 +0.008114 +0.008107 +0.008142 +0.008226 +0.008204 +0.008231 +0.008198 +0.008187 +0.00822 +0.008309 +0.008285 +0.008322 +0.00829 +0.008279 +0.008323 +0.008415 +0.008387 +0.008396 +0.008258 +0.008201 +0.008203 +0.008247 +0.008177 +0.008112 +0.008029 +0.007988 +0.007986 +0.008014 +0.007942 +0.007953 +0.007849 +0.007812 +0.007783 +0.007842 +0.007777 +0.007795 +0.007738 +0.007723 +0.007705 +0.007744 +0.007709 +0.007722 +0.00769 +0.007671 +0.0077 +0.007774 +0.007728 +0.007759 +0.007727 +0.007722 +0.007761 +0.007845 +0.007806 +0.007842 +0.007806 +0.007796 +0.007793 +0.007858 +0.007836 +0.001635 +0.007868 +0.007853 +0.007834 +0.007876 +0.007938 +0.00793 +0.007953 +0.007932 +0.007914 +0.007954 +0.008029 +0.008018 +0.00804 +0.008008 +0.007993 +0.008034 +0.008112 +0.008087 +0.008116 +0.008081 +0.008063 +0.008097 +0.008165 +0.008147 +0.008173 +0.008149 +0.008144 +0.008199 +0.008261 +0.008251 +0.008263 +0.008228 +0.008198 +0.008217 +0.008277 +0.008212 +0.00819 +0.008125 +0.008063 +0.008068 +0.008104 +0.008054 +0.008025 +0.007971 +0.007925 +0.007942 +0.007988 +0.007955 +0.007951 +0.007904 +0.007864 +0.00788 +0.007943 +0.007902 +0.007911 +0.007868 +0.007847 +0.007876 +0.007946 +0.007921 +0.007935 +0.007904 +0.007875 +0.007917 +0.007998 +0.00798 +0.008009 +0.007975 +0.007954 +0.007997 +0.008065 +0.008054 +0.008057 +0.001636 +0.008051 +0.008027 +0.008082 +0.008147 +0.008136 +0.008147 +0.008129 +0.008101 +0.008147 +0.008213 +0.008215 +0.008221 +0.008203 +0.00818 +0.008228 +0.008293 +0.008295 +0.008309 +0.008283 +0.008264 +0.008313 +0.00838 +0.008378 +0.008401 +0.008378 +0.008362 +0.008426 +0.008492 +0.008467 +0.008394 +0.008312 +0.008244 +0.008277 +0.008308 +0.008224 +0.008155 +0.008091 +0.008041 +0.008038 +0.008057 +0.008003 +0.008001 +0.007913 +0.007855 +0.007855 +0.007888 +0.007853 +0.007848 +0.00781 +0.007767 +0.00776 +0.007801 +0.00777 +0.007775 +0.00776 +0.007722 +0.00776 +0.007823 +0.007796 +0.007813 +0.007803 +0.007775 +0.007832 +0.007899 +0.007878 +0.007862 +0.007844 +0.007814 +0.007884 +0.007932 +0.007935 +0.00794 +0.001637 +0.007921 +0.007909 +0.007951 +0.008016 +0.007996 +0.008023 +0.008003 +0.00799 +0.00803 +0.008101 +0.008076 +0.0081 +0.00807 +0.008057 +0.008104 +0.008172 +0.008147 +0.008163 +0.00813 +0.008112 +0.008155 +0.008226 +0.0082 +0.008217 +0.008197 +0.008171 +0.008232 +0.008331 +0.008322 +0.008335 +0.008275 +0.008239 +0.008238 +0.008268 +0.008212 +0.008198 +0.008123 +0.008071 +0.008064 +0.0081 +0.008053 +0.008044 +0.007987 +0.007942 +0.007948 +0.008004 +0.007974 +0.007971 +0.007919 +0.007882 +0.007899 +0.007961 +0.007934 +0.007943 +0.007903 +0.007881 +0.007907 +0.007976 +0.007962 +0.007973 +0.007944 +0.007927 +0.007956 +0.008037 +0.008023 +0.008041 +0.00802 +0.007992 +0.008049 +0.008105 +0.008097 +0.001638 +0.008124 +0.008091 +0.008076 +0.008111 +0.008196 +0.008176 +0.008204 +0.008161 +0.008157 +0.008191 +0.008273 +0.008254 +0.008284 +0.008245 +0.008235 +0.008267 +0.008349 +0.008335 +0.008362 +0.008323 +0.008315 +0.008353 +0.008436 +0.008424 +0.008454 +0.008422 +0.00842 +0.008463 +0.008539 +0.008489 +0.008423 +0.008324 +0.008279 +0.008261 +0.00829 +0.008207 +0.008159 +0.008085 +0.008037 +0.008001 +0.008049 +0.007989 +0.007992 +0.007903 +0.007831 +0.007833 +0.007871 +0.007827 +0.007828 +0.007778 +0.007752 +0.007771 +0.007845 +0.00779 +0.007777 +0.007726 +0.007697 +0.007742 +0.007807 +0.007762 +0.007809 +0.007767 +0.007753 +0.0078 +0.007874 +0.00784 +0.007883 +0.007841 +0.007826 +0.007858 +0.007917 +0.007899 +0.007926 +0.001639 +0.007871 +0.007882 +0.007915 +0.007996 +0.007974 +0.008007 +0.007968 +0.007967 +0.007985 +0.008074 +0.008053 +0.008085 +0.008052 +0.008039 +0.008061 +0.008148 +0.00812 +0.008149 +0.008108 +0.008102 +0.00812 +0.008218 +0.00822 +0.008244 +0.008206 +0.008195 +0.008206 +0.008281 +0.008236 +0.008225 +0.008145 +0.008091 +0.008068 +0.008107 +0.008043 +0.008022 +0.007951 +0.007901 +0.007888 +0.007935 +0.007883 +0.007877 +0.007812 +0.007775 +0.007773 +0.007834 +0.007784 +0.00779 +0.007741 +0.007717 +0.007723 +0.007798 +0.007766 +0.007784 +0.007746 +0.007732 +0.007747 +0.007828 +0.007798 +0.007823 +0.007794 +0.007784 +0.007811 +0.0079 +0.007868 +0.007901 +0.007866 +0.007845 +0.007881 +0.00164 +0.007969 +0.007944 +0.007976 +0.007938 +0.007929 +0.007961 +0.008039 +0.008019 +0.00805 +0.008013 +0.008003 +0.008039 +0.008116 +0.008096 +0.008127 +0.008092 +0.008082 +0.008118 +0.008202 +0.008174 +0.00821 +0.008169 +0.008168 +0.008209 +0.008303 +0.008277 +0.00831 +0.00826 +0.008173 +0.008121 +0.008151 +0.008094 +0.008095 +0.008029 +0.008003 +0.007922 +0.007928 +0.007856 +0.007869 +0.007804 +0.007772 +0.007787 +0.007837 +0.007756 +0.007687 +0.007654 +0.007616 +0.007639 +0.007699 +0.007644 +0.007672 +0.007621 +0.007606 +0.007632 +0.007673 +0.007647 +0.007659 +0.007618 +0.007619 +0.007647 +0.007731 +0.007684 +0.007715 +0.007699 +0.007669 +0.007677 +0.007755 +0.007727 +0.007756 +0.007735 +0.007723 +0.007775 +0.007819 +0.007816 +0.007846 +0.001641 +0.00781 +0.007809 +0.007842 +0.007919 +0.007893 +0.00793 +0.007892 +0.007882 +0.007916 +0.007997 +0.007973 +0.008004 +0.007962 +0.007948 +0.007982 +0.008059 +0.008033 +0.008064 +0.008029 +0.008014 +0.008068 +0.008149 +0.00813 +0.008142 +0.008095 +0.008068 +0.008067 +0.008115 +0.008047 +0.00803 +0.007947 +0.007903 +0.007894 +0.007933 +0.00787 +0.007857 +0.007797 +0.007756 +0.007758 +0.007808 +0.00776 +0.007756 +0.007695 +0.007673 +0.007679 +0.007746 +0.007708 +0.007718 +0.007674 +0.00765 +0.007669 +0.007749 +0.007733 +0.007748 +0.007714 +0.007695 +0.007716 +0.007806 +0.007788 +0.007818 +0.007787 +0.007768 +0.007805 +0.007882 +0.007856 +0.007874 +0.001642 +0.007847 +0.007823 +0.007871 +0.00795 +0.007938 +0.007958 +0.007928 +0.00791 +0.007945 +0.008017 +0.008011 +0.008029 +0.008004 +0.007983 +0.008026 +0.008093 +0.008087 +0.008116 +0.008067 +0.008063 +0.008107 +0.008177 +0.008168 +0.008197 +0.008164 +0.008161 +0.008208 +0.008283 +0.00826 +0.008253 +0.008127 +0.008069 +0.008077 +0.008115 +0.008049 +0.00799 +0.007921 +0.007864 +0.007853 +0.007887 +0.007825 +0.007838 +0.007775 +0.007715 +0.007689 +0.00774 +0.007694 +0.007708 +0.007659 +0.007633 +0.007657 +0.007705 +0.007686 +0.007687 +0.007648 +0.007598 +0.007617 +0.007685 +0.007656 +0.007688 +0.007658 +0.007646 +0.007695 +0.007754 +0.007744 +0.007764 +0.007736 +0.00773 +0.00779 +0.007832 +0.007815 +0.007857 +0.001643 +0.007815 +0.007804 +0.007854 +0.007929 +0.007893 +0.007938 +0.007905 +0.007889 +0.007886 +0.007947 +0.007925 +0.007956 +0.007926 +0.00792 +0.007953 +0.008034 +0.008011 +0.00805 +0.008015 +0.008022 +0.008054 +0.008137 +0.008113 +0.008145 +0.008102 +0.008091 +0.008121 +0.0082 +0.008181 +0.008201 +0.008138 +0.008081 +0.008064 +0.008102 +0.008042 +0.008032 +0.007951 +0.0079 +0.007897 +0.007934 +0.007884 +0.007879 +0.007814 +0.007776 +0.007782 +0.007831 +0.007785 +0.007792 +0.007732 +0.007695 +0.007714 +0.007774 +0.007733 +0.007757 +0.007708 +0.007684 +0.007716 +0.007779 +0.00775 +0.007778 +0.007737 +0.007729 +0.00776 +0.007838 +0.007815 +0.007852 +0.007806 +0.007805 +0.007819 +0.00791 +0.007881 +0.007914 +0.001644 +0.007882 +0.007872 +0.007914 +0.007973 +0.007963 +0.007992 +0.00796 +0.007943 +0.00799 +0.00805 +0.008041 +0.008065 +0.008032 +0.008021 +0.008061 +0.008134 +0.008126 +0.008146 +0.008112 +0.0081 +0.008136 +0.008214 +0.008207 +0.008227 +0.0082 +0.008204 +0.008254 +0.008327 +0.008274 +0.008223 +0.008164 +0.008109 +0.008128 +0.008175 +0.008112 +0.008027 +0.007956 +0.007897 +0.007929 +0.007974 +0.007907 +0.007886 +0.007807 +0.007774 +0.007785 +0.007821 +0.00779 +0.007781 +0.00775 +0.007705 +0.00773 +0.00778 +0.007746 +0.007774 +0.007734 +0.007714 +0.007728 +0.007781 +0.007757 +0.007778 +0.007766 +0.007737 +0.007787 +0.007859 +0.007832 +0.007865 +0.007835 +0.007817 +0.007867 +0.007951 +0.007909 +0.001645 +0.007931 +0.007927 +0.007898 +0.00795 +0.008019 +0.008006 +0.008021 +0.007991 +0.007945 +0.00799 +0.008042 +0.008032 +0.008057 +0.008033 +0.00801 +0.008049 +0.008119 +0.008115 +0.008144 +0.00814 +0.008113 +0.008164 +0.008225 +0.008216 +0.008231 +0.008208 +0.008183 +0.008226 +0.008267 +0.008226 +0.008203 +0.008132 +0.008076 +0.008084 +0.008101 +0.008056 +0.008034 +0.007971 +0.007917 +0.007935 +0.00796 +0.00792 +0.007907 +0.007857 +0.007803 +0.00783 +0.007863 +0.007845 +0.007824 +0.007788 +0.007746 +0.007792 +0.007839 +0.007838 +0.007832 +0.007804 +0.007772 +0.007821 +0.007876 +0.007877 +0.007891 +0.007865 +0.007843 +0.007886 +0.007945 +0.007946 +0.007963 +0.007936 +0.007915 +0.001646 +0.007961 +0.008029 +0.008021 +0.008038 +0.008024 +0.007981 +0.008036 +0.008099 +0.008099 +0.008114 +0.008091 +0.008064 +0.008116 +0.008181 +0.008178 +0.008194 +0.008172 +0.008145 +0.008195 +0.008262 +0.008258 +0.008278 +0.008256 +0.008243 +0.008306 +0.008368 +0.008359 +0.008359 +0.008254 +0.008196 +0.008203 +0.008239 +0.00819 +0.008106 +0.008048 +0.007977 +0.007976 +0.007997 +0.007953 +0.007923 +0.007896 +0.007831 +0.007805 +0.007831 +0.007788 +0.007797 +0.007757 +0.007706 +0.007746 +0.007777 +0.00777 +0.007736 +0.007701 +0.007665 +0.007705 +0.007771 +0.007736 +0.007752 +0.007735 +0.007703 +0.007777 +0.007824 +0.007818 +0.007837 +0.007809 +0.007782 +0.007802 +0.007849 +0.007847 +0.007868 +0.007852 +0.001647 +0.007847 +0.007876 +0.007938 +0.007935 +0.007952 +0.007936 +0.007914 +0.007962 +0.008024 +0.008018 +0.008038 +0.008012 +0.00799 +0.008041 +0.008103 +0.008096 +0.008111 +0.008079 +0.008054 +0.008097 +0.008171 +0.00818 +0.008196 +0.008179 +0.008141 +0.008187 +0.008248 +0.008249 +0.008257 +0.008206 +0.008144 +0.008151 +0.008166 +0.008133 +0.008118 +0.008049 +0.007987 +0.007992 +0.008026 +0.007996 +0.007982 +0.007933 +0.007876 +0.007903 +0.007942 +0.007918 +0.007918 +0.007875 +0.007834 +0.007867 +0.007908 +0.007894 +0.007908 +0.007874 +0.007847 +0.007888 +0.007938 +0.007929 +0.007938 +0.007909 +0.007895 +0.007955 +0.008002 +0.008007 +0.008016 +0.008003 +0.007968 +0.008008 +0.008075 +0.001648 +0.008066 +0.008084 +0.00805 +0.00805 +0.008087 +0.008164 +0.008147 +0.008174 +0.00814 +0.008119 +0.008162 +0.008234 +0.008217 +0.008241 +0.008208 +0.008199 +0.008242 +0.008322 +0.008311 +0.008336 +0.008312 +0.008294 +0.008342 +0.008435 +0.008406 +0.008439 +0.008386 +0.008305 +0.008329 +0.008371 +0.008311 +0.008292 +0.008239 +0.008173 +0.008112 +0.008112 +0.008044 +0.008028 +0.007989 +0.007926 +0.007927 +0.007934 +0.00787 +0.007861 +0.007785 +0.007747 +0.007723 +0.007776 +0.007717 +0.007719 +0.007693 +0.007655 +0.0077 +0.007749 +0.007713 +0.007733 +0.007693 +0.007671 +0.007727 +0.007766 +0.007738 +0.007767 +0.007731 +0.007723 +0.007752 +0.007806 +0.007783 +0.007818 +0.007798 +0.00777 +0.00782 +0.007907 +0.00786 +0.007892 +0.007872 +0.001649 +0.007856 +0.007905 +0.007968 +0.00796 +0.007972 +0.007958 +0.007933 +0.007983 +0.008046 +0.008041 +0.008047 +0.00803 +0.008 +0.008048 +0.008107 +0.008091 +0.0081 +0.008088 +0.008059 +0.008104 +0.008174 +0.008174 +0.008209 +0.008181 +0.008136 +0.00817 +0.008179 +0.008128 +0.008104 +0.008036 +0.007966 +0.007974 +0.007989 +0.007938 +0.00793 +0.007877 +0.007808 +0.007829 +0.007858 +0.007825 +0.007821 +0.007773 +0.007726 +0.007753 +0.007787 +0.007772 +0.007754 +0.007724 +0.00768 +0.007734 +0.007791 +0.007775 +0.007786 +0.007748 +0.007716 +0.007762 +0.007817 +0.007819 +0.007843 +0.007818 +0.007791 +0.007841 +0.007895 +0.007898 +0.007901 +0.007881 +0.00165 +0.007867 +0.007911 +0.007982 +0.007966 +0.007983 +0.00796 +0.007938 +0.007978 +0.008049 +0.008042 +0.008066 +0.008036 +0.008014 +0.008055 +0.008125 +0.008121 +0.008142 +0.008109 +0.008104 +0.00814 +0.008213 +0.008208 +0.008223 +0.00821 +0.008178 +0.008238 +0.008323 +0.008319 +0.008291 +0.008196 +0.00814 +0.008155 +0.008191 +0.008141 +0.008148 +0.008032 +0.007947 +0.007955 +0.007982 +0.007922 +0.007932 +0.007875 +0.007825 +0.00785 +0.007835 +0.007792 +0.007784 +0.007748 +0.007704 +0.007727 +0.007754 +0.007729 +0.007737 +0.007704 +0.007692 +0.007712 +0.007779 +0.007732 +0.007752 +0.00773 +0.007714 +0.007753 +0.007828 +0.007803 +0.007829 +0.007805 +0.007767 +0.007802 +0.007863 +0.007847 +0.007863 +0.007849 +0.007829 +0.00788 +0.001651 +0.007948 +0.007928 +0.007959 +0.007926 +0.007922 +0.007957 +0.008033 +0.008013 +0.008046 +0.008005 +0.007997 +0.008031 +0.008109 +0.008082 +0.008111 +0.008065 +0.008061 +0.008089 +0.008158 +0.00815 +0.008192 +0.008169 +0.00815 +0.008164 +0.008232 +0.008186 +0.00818 +0.00811 +0.00806 +0.008046 +0.008084 +0.008029 +0.008021 +0.007947 +0.007905 +0.007897 +0.007953 +0.007894 +0.007891 +0.007836 +0.007806 +0.007806 +0.007866 +0.007819 +0.007832 +0.007779 +0.007757 +0.007757 +0.007833 +0.007808 +0.007832 +0.007793 +0.007774 +0.007792 +0.007873 +0.007847 +0.00788 +0.007855 +0.007838 +0.007867 +0.007947 +0.007922 +0.007961 +0.007914 +0.007901 +0.001652 +0.007953 +0.008013 +0.008006 +0.008029 +0.007992 +0.007974 +0.008022 +0.008098 +0.00808 +0.0081 +0.008075 +0.008055 +0.008096 +0.008168 +0.008156 +0.008179 +0.008151 +0.008131 +0.008172 +0.008251 +0.008235 +0.008264 +0.008229 +0.008221 +0.008268 +0.008343 +0.008337 +0.008369 +0.008329 +0.008289 +0.008231 +0.008243 +0.008189 +0.008174 +0.008125 +0.00807 +0.00802 +0.008015 +0.007958 +0.007941 +0.007906 +0.007854 +0.007876 +0.007925 +0.007876 +0.00781 +0.00774 +0.007717 +0.007737 +0.007784 +0.007755 +0.007759 +0.007727 +0.007707 +0.007707 +0.007761 +0.007721 +0.007733 +0.007715 +0.00768 +0.007723 +0.007791 +0.007773 +0.007787 +0.007769 +0.007752 +0.007794 +0.007861 +0.007843 +0.00786 +0.007857 +0.007814 +0.007861 +0.007924 +0.001653 +0.007903 +0.007924 +0.00789 +0.007886 +0.007929 +0.00801 +0.007968 +0.007998 +0.007967 +0.007967 +0.008009 +0.008087 +0.008053 +0.008082 +0.008043 +0.008029 +0.008056 +0.00813 +0.008096 +0.008121 +0.008089 +0.008077 +0.008112 +0.008199 +0.008173 +0.008236 +0.008199 +0.008173 +0.008173 +0.008216 +0.008148 +0.008128 +0.008063 +0.008012 +0.007998 +0.008036 +0.007975 +0.007972 +0.007915 +0.007874 +0.007874 +0.007934 +0.007882 +0.007888 +0.007837 +0.007804 +0.007809 +0.007871 +0.007826 +0.007834 +0.007788 +0.007775 +0.007794 +0.007867 +0.007838 +0.007852 +0.007815 +0.007793 +0.007815 +0.007897 +0.007884 +0.007915 +0.007886 +0.007866 +0.007907 +0.007977 +0.007966 +0.007975 +0.007941 +0.001654 +0.007926 +0.007972 +0.008051 +0.008031 +0.008069 +0.008026 +0.008017 +0.008044 +0.008117 +0.008106 +0.008139 +0.008102 +0.008096 +0.008126 +0.008207 +0.008183 +0.008216 +0.008182 +0.008171 +0.008206 +0.008288 +0.008264 +0.0083 +0.008269 +0.008258 +0.008303 +0.008396 +0.008372 +0.008398 +0.008332 +0.008229 +0.008219 +0.008258 +0.008195 +0.008198 +0.008101 +0.007993 +0.007969 +0.008022 +0.007949 +0.007964 +0.007886 +0.007859 +0.007802 +0.007828 +0.007763 +0.007789 +0.00772 +0.007694 +0.007707 +0.007759 +0.007724 +0.007721 +0.007636 +0.007627 +0.007641 +0.00771 +0.007679 +0.007694 +0.007664 +0.007657 +0.007688 +0.007768 +0.007737 +0.007761 +0.007738 +0.007709 +0.007717 +0.007794 +0.007763 +0.007801 +0.007772 +0.007759 +0.007798 +0.007879 +0.007854 +0.001655 +0.007889 +0.00785 +0.007857 +0.007871 +0.007956 +0.007944 +0.007969 +0.007935 +0.00792 +0.007962 +0.008035 +0.008019 +0.008041 +0.008013 +0.007981 +0.008028 +0.008093 +0.008072 +0.008096 +0.00807 +0.008054 +0.008106 +0.008182 +0.008165 +0.008174 +0.008121 +0.008054 +0.008062 +0.008101 +0.008048 +0.008034 +0.007962 +0.007919 +0.007915 +0.007948 +0.007911 +0.007906 +0.007843 +0.007796 +0.007814 +0.007847 +0.007811 +0.007813 +0.007758 +0.007717 +0.007747 +0.007786 +0.00775 +0.007776 +0.007735 +0.007706 +0.007747 +0.007789 +0.007775 +0.007801 +0.007764 +0.007748 +0.007794 +0.007855 +0.007852 +0.007864 +0.007834 +0.007823 +0.007854 +0.007928 +0.00791 +0.00794 +0.001656 +0.007909 +0.007897 +0.007935 +0.008011 +0.00799 +0.008017 +0.007982 +0.007965 +0.007996 +0.008075 +0.008065 +0.008096 +0.008059 +0.008054 +0.008089 +0.008163 +0.008137 +0.008175 +0.008135 +0.008122 +0.008169 +0.008255 +0.008229 +0.008269 +0.008238 +0.008228 +0.00825 +0.00825 +0.008176 +0.008175 +0.008112 +0.008079 +0.008058 +0.008053 +0.007965 +0.007968 +0.007903 +0.007866 +0.007834 +0.007877 +0.007805 +0.007824 +0.007734 +0.007683 +0.007671 +0.007722 +0.007668 +0.007681 +0.007623 +0.007613 +0.007633 +0.007681 +0.007632 +0.007639 +0.007611 +0.007583 +0.007598 +0.007678 +0.00763 +0.00766 +0.007636 +0.007621 +0.007658 +0.007741 +0.007701 +0.007733 +0.007705 +0.007695 +0.007711 +0.007787 +0.00775 +0.00778 +0.007754 +0.001657 +0.007762 +0.007779 +0.007842 +0.007835 +0.007863 +0.007836 +0.007819 +0.007863 +0.00793 +0.007918 +0.007943 +0.007911 +0.007893 +0.007936 +0.008004 +0.007991 +0.008004 +0.007977 +0.007958 +0.007993 +0.008066 +0.00805 +0.008075 +0.008053 +0.00805 +0.008091 +0.008157 +0.008133 +0.008138 +0.00807 +0.008028 +0.00802 +0.008042 +0.007989 +0.007966 +0.007883 +0.007843 +0.007841 +0.007868 +0.007824 +0.007808 +0.007747 +0.007713 +0.007723 +0.007759 +0.00773 +0.007725 +0.007669 +0.007639 +0.007653 +0.007701 +0.007691 +0.007697 +0.007655 +0.007639 +0.007662 +0.007721 +0.007713 +0.007732 +0.007697 +0.007686 +0.007726 +0.007786 +0.007784 +0.007798 +0.007779 +0.007745 +0.007783 +0.007857 +0.007847 +0.001658 +0.007876 +0.007845 +0.007834 +0.007856 +0.00794 +0.00792 +0.007951 +0.007908 +0.007903 +0.007936 +0.008016 +0.007998 +0.008025 +0.007986 +0.007979 +0.008014 +0.008092 +0.008073 +0.008107 +0.008063 +0.008052 +0.008087 +0.00817 +0.008151 +0.008178 +0.008144 +0.008142 +0.008175 +0.008264 +0.008234 +0.008269 +0.008231 +0.00822 +0.008279 +0.008344 +0.008331 +0.008296 +0.008266 +0.00824 +0.0083 +0.008368 +0.008349 +0.008381 +0.008349 +0.008335 +0.008379 +0.008461 +0.008442 +0.008481 +0.00843 +0.008439 +0.008462 +0.008554 +0.008528 +0.00856 +0.008519 +0.008511 +0.008562 +0.008637 +0.008613 +0.008651 +0.008606 +0.008613 +0.008655 +0.008733 +0.008699 +0.008693 +0.008651 +0.008653 +0.00869 +0.008775 +0.008751 +0.008789 +0.008736 +0.00874 +0.008784 +0.008869 +0.008833 +0.008871 +0.008839 +0.008829 +0.008865 +0.008954 +0.008924 +0.008963 +0.008929 +0.008916 +0.008964 +0.009048 +0.009015 +0.009045 +0.009015 +0.009002 +0.00903 +0.009104 +0.009066 +0.009107 +0.009071 +0.009056 +0.009101 +0.009187 +0.009162 +0.009199 +0.009161 +0.009152 +0.009197 +0.009285 +0.009258 +0.009295 +0.009254 +0.009248 +0.009294 +0.009388 +0.009356 +0.009394 +0.009355 +0.009344 +0.009394 +0.009477 +0.009434 +0.009469 +0.00942 +0.009409 +0.009448 +0.009533 +0.009497 +0.009538 +0.009499 +0.009491 +0.00954 +0.009633 +0.009602 +0.009648 +0.009608 +0.009598 +0.00965 +0.009737 +0.009717 +0.009756 +0.009714 +0.009707 +0.00976 +0.009855 +0.009819 +0.009843 +0.009775 +0.009763 +0.009821 +0.009912 +0.009881 +0.009921 +0.009885 +0.009878 +0.009933 +0.010036 +0.009998 +0.01004 +0.010003 +0.009993 +0.010026 +0.010101 +0.010065 +0.010111 +0.010076 +0.010066 +0.010122 +0.010221 +0.010192 +0.010239 +0.010194 +0.010186 +0.010248 +0.010341 +0.010306 +0.010349 +0.010309 +0.010292 +0.010304 +0.010382 +0.010356 +0.01041 +0.010368 +0.010364 +0.010419 +0.010524 +0.010503 +0.010545 +0.010506 +0.0105 +0.010555 +0.010662 +0.010634 +0.010682 +0.010644 +0.010635 +0.010677 +0.010723 +0.010689 +0.010742 +0.0107 +0.010698 +0.010755 +0.010855 +0.010826 +0.010875 +0.010833 +0.010826 +0.010883 +0.010989 +0.010958 +0.010999 +0.010962 +0.010939 +0.010933 +0.01103 +0.011004 +0.01106 +0.011021 +0.011015 +0.011072 +0.011188 +0.011164 +0.011215 +0.011167 +0.01116 +0.011223 +0.011339 +0.011312 +0.01136 +0.011313 +0.011313 +0.011378 +0.011456 +0.011385 +0.011431 +0.011392 +0.011387 +0.011442 +0.011548 +0.011518 +0.011558 +0.011521 +0.011508 +0.011562 +0.01166 +0.011618 +0.01167 +0.011636 +0.01162 +0.011693 +0.011801 +0.01177 +0.011818 +0.011776 +0.01176 +0.011771 +0.011875 +0.011844 +0.011907 +0.011858 +0.011858 +0.011917 +0.012045 +0.012019 +0.012072 +0.012027 +0.012018 +0.012092 +0.012212 +0.012185 +0.012244 +0.012148 +0.012115 +0.012142 +0.012268 +0.012239 +0.012291 +0.012249 +0.012248 +0.012319 +0.01244 +0.012419 +0.012466 +0.012429 +0.012417 +0.012491 +0.012616 +0.012581 +0.012631 +0.01256 +0.012513 +0.012563 +0.012685 +0.012651 +0.012712 +0.012668 +0.012661 +0.012738 +0.012863 +0.01283 +0.012888 +0.012848 +0.012836 +0.012905 +0.013041 +0.012996 +0.013054 +0.013006 +0.012945 +0.01297 +0.013093 +0.013076 +0.013136 +0.013097 +0.01309 +0.013169 +0.013299 +0.013277 +0.01334 +0.013295 +0.013281 +0.013363 +0.013501 +0.013462 +0.013523 +0.013477 +0.013424 +0.013415 +0.013545 +0.01352 +0.01359 +0.013551 +0.013559 +0.013631 +0.013772 +0.013764 +0.013821 +0.013764 +0.013755 +0.01384 +0.014001 +0.013963 +0.013903 +0.013842 +0.013848 +0.013882 +0.014007 +0.013913 +0.013929 +0.013844 +0.013711 +0.013603 +0.013701 +0.013617 +0.013643 +0.013548 +0.013482 +0.01353 +0.013613 +0.013455 +0.013449 +0.013355 +0.013304 +0.013303 +0.013409 +0.013356 +0.013395 +0.013334 +0.013311 +0.013382 +0.013528 +0.013466 +0.013484 +0.013425 +0.013402 +0.013487 +0.013609 +0.001659 +0.013581 +0.01364 +0.013592 +0.013575 +0.013664 +0.013789 +0.013766 +0.013818 +0.013775 +0.013749 +0.013815 +0.013944 +0.013968 +0.014038 +0.013987 +0.013955 +0.014026 +0.014152 +0.014124 +0.014179 +0.014158 +0.014132 +0.014209 +0.01433 +0.014319 +0.014376 +0.014324 +0.014306 +0.01439 +0.014516 +0.014501 +0.014561 +0.014512 +0.014489 +0.014576 +0.014706 +0.0147 +0.014759 +0.014705 +0.014676 +0.014761 +0.014901 +0.014898 +0.014945 +0.014892 +0.014868 +0.014956 +0.015093 +0.015083 +0.015137 +0.01508 +0.015067 +0.015154 +0.015289 +0.015287 +0.015351 +0.0153 +0.01528 +0.015357 +0.015512 +0.0155 +0.015538 +0.015456 +0.015372 +0.015386 +0.015473 +0.015386 +0.015355 +0.015232 +0.015133 +0.015129 +0.015201 +0.015106 +0.015078 +0.01496 +0.014868 +0.01488 +0.01496 +0.014885 +0.014864 +0.014758 +0.014662 +0.014679 +0.01475 +0.014672 +0.014661 +0.01454 +0.014464 +0.014478 +0.014563 +0.014496 +0.01447 +0.014377 +0.014305 +0.014322 +0.014423 +0.014367 +0.014359 +0.014284 +0.014232 +0.014277 +0.014396 +0.014377 +0.014415 +0.014364 +0.014341 +0.014424 +0.014548 +0.014554 +0.014586 +0.00166 +0.014553 +0.01454 +0.014612 +0.014747 +0.014737 +0.014791 +0.014746 +0.014733 +0.014829 +0.014976 +0.014949 +0.014975 +0.014912 +0.014883 +0.014972 +0.015107 +0.015123 +0.015174 +0.015112 +0.015089 +0.015174 +0.015316 +0.015312 +0.015362 +0.01531 +0.015288 +0.015379 +0.015517 +0.015496 +0.015558 +0.015515 +0.015475 +0.01558 +0.01573 +0.015727 +0.01578 +0.015759 +0.015743 +0.015856 +0.016026 +0.01597 +0.015852 +0.015639 +0.015552 +0.01552 +0.01554 +0.015444 +0.015428 +0.015222 +0.015146 +0.015145 +0.015199 +0.015127 +0.015134 +0.015024 +0.014864 +0.014861 +0.014937 +0.014883 +0.014877 +0.014795 +0.01473 +0.014744 +0.014752 +0.014641 +0.014684 +0.014561 +0.0145 +0.014428 +0.014515 +0.01446 +0.014452 +0.01441 +0.014356 +0.014412 +0.014546 +0.014456 +0.014399 +0.014375 +0.014337 +0.014434 +0.014561 +0.014544 +0.014598 +0.014568 +0.014549 +0.01464 +0.001661 +0.014782 +0.014734 +0.014795 +0.014751 +0.014702 +0.014728 +0.014865 +0.014841 +0.014897 +0.01486 +0.014845 +0.014946 +0.015128 +0.01512 +0.015166 +0.015116 +0.015094 +0.015162 +0.015305 +0.015289 +0.015339 +0.015283 +0.015251 +0.015337 +0.015465 +0.015477 +0.015544 +0.01549 +0.015452 +0.015548 +0.015707 +0.015707 +0.01575 +0.015703 +0.01569 +0.015766 +0.015872 +0.015814 +0.015802 +0.015674 +0.015587 +0.015606 +0.015686 +0.015619 +0.015609 +0.015494 +0.015419 +0.015449 +0.015546 +0.015488 +0.015501 +0.015406 +0.015341 +0.01539 +0.0155 +0.01546 +0.015475 +0.015385 +0.015335 +0.01538 +0.015486 +0.015442 +0.01546 +0.015376 +0.015322 +0.015377 +0.015487 +0.015452 +0.015474 +0.015395 +0.001662 +0.01535 +0.015412 +0.015531 +0.015502 +0.015542 +0.015473 +0.015448 +0.01553 +0.01567 +0.015666 +0.015716 +0.015655 +0.015672 +0.01572 +0.015896 +0.015893 +0.015937 +0.015888 +0.015886 +0.015961 +0.01612 +0.016132 +0.016166 +0.016124 +0.0161 +0.016207 +0.016349 +0.016354 +0.016412 +0.01635 +0.016321 +0.016405 +0.016587 +0.016555 +0.01663 +0.016606 +0.016595 +0.016709 +0.016872 +0.01687 +0.016892 +0.016567 +0.016283 +0.016249 +0.016201 +0.016035 +0.015991 +0.015766 +0.015591 +0.015549 +0.01562 +0.015497 +0.015489 +0.015382 +0.015133 +0.015152 +0.015227 +0.015144 +0.015115 +0.015032 +0.014852 +0.014797 +0.014857 +0.014809 +0.014795 +0.014717 +0.01465 +0.0147 +0.014759 +0.014596 +0.014642 +0.014558 +0.014419 +0.014459 +0.014564 +0.014525 +0.014594 +0.014546 +0.014523 +0.014611 +0.014772 +0.01474 +0.014787 +0.014756 +0.014762 +0.014829 +0.001663 +0.014921 +0.014875 +0.014948 +0.014915 +0.014902 +0.014995 +0.015106 +0.015056 +0.01511 +0.015057 +0.015021 +0.015098 +0.015232 +0.015209 +0.015351 +0.015328 +0.015289 +0.015377 +0.015517 +0.015519 +0.015586 +0.015529 +0.015513 +0.015562 +0.015643 +0.015574 +0.015531 +0.015394 +0.015297 +0.015287 +0.015349 +0.015279 +0.015274 +0.015137 +0.015086 +0.015107 +0.015178 +0.015144 +0.015144 +0.015042 +0.014992 +0.015014 +0.015115 +0.015075 +0.015077 +0.014985 +0.014941 +0.014972 +0.01507 +0.015035 +0.015042 +0.014956 +0.014916 +0.014941 +0.015065 +0.01504 +0.015055 +0.014971 +0.014946 +0.014986 +0.01512 +0.0151 +0.001664 +0.015142 +0.01508 +0.015083 +0.015145 +0.015287 +0.015289 +0.015343 +0.015297 +0.015268 +0.015371 +0.015503 +0.015507 +0.015553 +0.015508 +0.015493 +0.015582 +0.01572 +0.015727 +0.015776 +0.015726 +0.015701 +0.015786 +0.015927 +0.015939 +0.015988 +0.015949 +0.015927 +0.016052 +0.016208 +0.016202 +0.016291 +0.016246 +0.016195 +0.016023 +0.016048 +0.015949 +0.015906 +0.015754 +0.015641 +0.015515 +0.015524 +0.015441 +0.015421 +0.015312 +0.015234 +0.015277 +0.015223 +0.015151 +0.015164 +0.015067 +0.015017 +0.01495 +0.015038 +0.014954 +0.014976 +0.014901 +0.014845 +0.014921 +0.015016 +0.014927 +0.014878 +0.014803 +0.014779 +0.014809 +0.014905 +0.014882 +0.014916 +0.014862 +0.014847 +0.014938 +0.015075 +0.015048 +0.01511 +0.001665 +0.015027 +0.014964 +0.015071 +0.015205 +0.015176 +0.015234 +0.01522 +0.015189 +0.015293 +0.015451 +0.015421 +0.015462 +0.015419 +0.015401 +0.015486 +0.015618 +0.015567 +0.015611 +0.015553 +0.015524 +0.015606 +0.015748 +0.015781 +0.01591 +0.015848 +0.015802 +0.015888 +0.016014 +0.016032 +0.016104 +0.016035 +0.015936 +0.015972 +0.016048 +0.015968 +0.015922 +0.015814 +0.01572 +0.015713 +0.015797 +0.015727 +0.01571 +0.015619 +0.015552 +0.015567 +0.015687 +0.015631 +0.015626 +0.015557 +0.015491 +0.015518 +0.015635 +0.01559 +0.015594 +0.015525 +0.015455 +0.015496 +0.015616 +0.015572 +0.015583 +0.015516 +0.01547 +0.015513 +0.01565 +0.015623 +0.001666 +0.015647 +0.0156 +0.015554 +0.015622 +0.015783 +0.01577 +0.01582 +0.015788 +0.015756 +0.015836 +0.015992 +0.015997 +0.016049 +0.016008 +0.01598 +0.016073 +0.016228 +0.01623 +0.016281 +0.016239 +0.01623 +0.016302 +0.016476 +0.016474 +0.01653 +0.016476 +0.016453 +0.016553 +0.016705 +0.016696 +0.016753 +0.016717 +0.016694 +0.016827 +0.016998 +0.01699 +0.017072 +0.017037 +0.016998 +0.016881 +0.016842 +0.016754 +0.016745 +0.016612 +0.016541 +0.016581 +0.016564 +0.016472 +0.016472 +0.016377 +0.016223 +0.016193 +0.016293 +0.016239 +0.016258 +0.016157 +0.016118 +0.016171 +0.016229 +0.016081 +0.016132 +0.016032 +0.015918 +0.015892 +0.016054 +0.015976 +0.016033 +0.015965 +0.015926 +0.016027 +0.016142 +0.016122 +0.016151 +0.016031 +0.015993 +0.016039 +0.001667 +0.016206 +0.016182 +0.016244 +0.016214 +0.016213 +0.016321 +0.016476 +0.016451 +0.016533 +0.016493 +0.016463 +0.016564 +0.016686 +0.016629 +0.016678 +0.016622 +0.016602 +0.016695 +0.016845 +0.016819 +0.016877 +0.016849 +0.016896 +0.016986 +0.01714 +0.017134 +0.017209 +0.017144 +0.017146 +0.017233 +0.017357 +0.017303 +0.017271 +0.017132 +0.017051 +0.017051 +0.017139 +0.017081 +0.017026 +0.0169 +0.016842 +0.016839 +0.016947 +0.016895 +0.016873 +0.016759 +0.016702 +0.016725 +0.016828 +0.016786 +0.016769 +0.016658 +0.016602 +0.016625 +0.016731 +0.016692 +0.016682 +0.016569 +0.016526 +0.01656 +0.016678 +0.016657 +0.016669 +0.01659 +0.016563 +0.016617 +0.01677 +0.01676 +0.001668 +0.0168 +0.016744 +0.016746 +0.016832 +0.017002 +0.016996 +0.017048 +0.01701 +0.017004 +0.017086 +0.017268 +0.017271 +0.017313 +0.017273 +0.017266 +0.017361 +0.017542 +0.017543 +0.017594 +0.017547 +0.01754 +0.017643 +0.017778 +0.017802 +0.017872 +0.017823 +0.017819 +0.017954 +0.018141 +0.01815 +0.0182 +0.018055 +0.017744 +0.017717 +0.017744 +0.017582 +0.017545 +0.017281 +0.01716 +0.017119 +0.017179 +0.017072 +0.017045 +0.016881 +0.016707 +0.016666 +0.016777 +0.016667 +0.016641 +0.016565 +0.016302 +0.016297 +0.016377 +0.016298 +0.016291 +0.016185 +0.016103 +0.016056 +0.016067 +0.016026 +0.016041 +0.015975 +0.015938 +0.016003 +0.016166 +0.016104 +0.016149 +0.016032 +0.015998 +0.016124 +0.016268 +0.016228 +0.016313 +0.001669 +0.016272 +0.016249 +0.016358 +0.016538 +0.016499 +0.016559 +0.016504 +0.016472 +0.016578 +0.01671 +0.016654 +0.016698 +0.016643 +0.01661 +0.016698 +0.016906 +0.01699 +0.017025 +0.016968 +0.016921 +0.017008 +0.017214 +0.017202 +0.017209 +0.017109 +0.01702 +0.017005 +0.017095 +0.017003 +0.016951 +0.016821 +0.01671 +0.016701 +0.016795 +0.016698 +0.016665 +0.016548 +0.016456 +0.016459 +0.016567 +0.016497 +0.01647 +0.016363 +0.01628 +0.016283 +0.016384 +0.016315 +0.016291 +0.016184 +0.01611 +0.016116 +0.016232 +0.016171 +0.016162 +0.016064 +0.016005 +0.016029 +0.016155 +0.016117 +0.016135 +0.016067 +0.016045 +0.016095 +0.016263 +0.016262 +0.016307 +0.016266 +0.00167 +0.016251 +0.016343 +0.016496 +0.01651 +0.016548 +0.016506 +0.016499 +0.016584 +0.016748 +0.016748 +0.016801 +0.016752 +0.016733 +0.016835 +0.016989 +0.017009 +0.017071 +0.017041 +0.01703 +0.017155 +0.017342 +0.017325 +0.017261 +0.017026 +0.016926 +0.016918 +0.016904 +0.016766 +0.016697 +0.01645 +0.016337 +0.016304 +0.016327 +0.016203 +0.016184 +0.015986 +0.015857 +0.015848 +0.0159 +0.015822 +0.015835 +0.015711 +0.015662 +0.015539 +0.015612 +0.015521 +0.015561 +0.015451 +0.015412 +0.015463 +0.015542 +0.015428 +0.015425 +0.015343 +0.015282 +0.015316 +0.015436 +0.015394 +0.015474 +0.015415 +0.015388 +0.015516 +0.015655 +0.015615 +0.01569 +0.015648 +0.001671 +0.015622 +0.015703 +0.015827 +0.015796 +0.015851 +0.015805 +0.015804 +0.01589 +0.016025 +0.015982 +0.01604 +0.015981 +0.015943 +0.016026 +0.016174 +0.016186 +0.016327 +0.016274 +0.016227 +0.016291 +0.016447 +0.016468 +0.016479 +0.016353 +0.016247 +0.016241 +0.016316 +0.01622 +0.016179 +0.016067 +0.015947 +0.01595 +0.01604 +0.015957 +0.015933 +0.015823 +0.015741 +0.015733 +0.015846 +0.015786 +0.015758 +0.015661 +0.015595 +0.015591 +0.01571 +0.015648 +0.015632 +0.01554 +0.015472 +0.015489 +0.015608 +0.015553 +0.015563 +0.015489 +0.015431 +0.015471 +0.015604 +0.015569 +0.015594 +0.015531 +0.015491 +0.015555 +0.015708 +0.015694 +0.015742 +0.001672 +0.015702 +0.01568 +0.015775 +0.015914 +0.015929 +0.01597 +0.015921 +0.015922 +0.015994 +0.016151 +0.016158 +0.016201 +0.016156 +0.016147 +0.016232 +0.016378 +0.016367 +0.016437 +0.016394 +0.016363 +0.016487 +0.016648 +0.016649 +0.016725 +0.01668 +0.016685 +0.016727 +0.016647 +0.016531 +0.01653 +0.01639 +0.016179 +0.016136 +0.016244 +0.016125 +0.016093 +0.015971 +0.015806 +0.015704 +0.0158 +0.015705 +0.015727 +0.015632 +0.015535 +0.015603 +0.015636 +0.015453 +0.015474 +0.015332 +0.015231 +0.015182 +0.015316 +0.015226 +0.015245 +0.015163 +0.015105 +0.015179 +0.015196 +0.015161 +0.015182 +0.01513 +0.01511 +0.015141 +0.015274 +0.015239 +0.01528 +0.015269 +0.015255 +0.015344 +0.015501 +0.001673 +0.015473 +0.015536 +0.015486 +0.015482 +0.015575 +0.015711 +0.01565 +0.015697 +0.015653 +0.015606 +0.015682 +0.015817 +0.01577 +0.01583 +0.01582 +0.015892 +0.015956 +0.016101 +0.016076 +0.016106 +0.016102 +0.016075 +0.016143 +0.016279 +0.0162 +0.016195 +0.016088 +0.015991 +0.015996 +0.016088 +0.015996 +0.015966 +0.015844 +0.015747 +0.015749 +0.015827 +0.015742 +0.015727 +0.015615 +0.015534 +0.015547 +0.015648 +0.015566 +0.01555 +0.015456 +0.015376 +0.015393 +0.015495 +0.015418 +0.015412 +0.015323 +0.015255 +0.015281 +0.015397 +0.015335 +0.015342 +0.015265 +0.015221 +0.015262 +0.015403 +0.015366 +0.015399 +0.015355 +0.015339 +0.015424 +0.015574 +0.015565 +0.001674 +0.015625 +0.01556 +0.015562 +0.015642 +0.015785 +0.015789 +0.015844 +0.015789 +0.015782 +0.015871 +0.016023 +0.016024 +0.016071 +0.016023 +0.015994 +0.016091 +0.01623 +0.016243 +0.016317 +0.016284 +0.016242 +0.016382 +0.016559 +0.016537 +0.016617 +0.016411 +0.016272 +0.016325 +0.016398 +0.016262 +0.016113 +0.015988 +0.015896 +0.015797 +0.015834 +0.015733 +0.015715 +0.01561 +0.01542 +0.01532 +0.015411 +0.015338 +0.015329 +0.015214 +0.015171 +0.015165 +0.015122 +0.015039 +0.015052 +0.014966 +0.014906 +0.014904 +0.014945 +0.014847 +0.014898 +0.014809 +0.014762 +0.014846 +0.014904 +0.014845 +0.014899 +0.014851 +0.01481 +0.014807 +0.014941 +0.014935 +0.015 +0.014967 +0.014949 +0.015049 +0.001675 +0.0152 +0.015195 +0.01525 +0.015204 +0.015185 +0.015294 +0.015434 +0.015389 +0.015428 +0.015375 +0.015324 +0.015396 +0.015513 +0.015472 +0.015528 +0.015537 +0.015588 +0.015669 +0.015798 +0.015774 +0.015815 +0.015789 +0.015783 +0.015838 +0.015927 +0.015866 +0.015838 +0.0157 +0.015593 +0.015598 +0.015644 +0.015561 +0.015531 +0.015397 +0.015306 +0.015315 +0.015391 +0.01532 +0.015317 +0.015205 +0.015127 +0.01516 +0.015249 +0.015185 +0.015192 +0.015082 +0.015017 +0.01505 +0.015137 +0.015086 +0.015084 +0.014993 +0.014934 +0.014979 +0.015078 +0.015041 +0.015067 +0.014988 +0.014947 +0.015016 +0.015135 +0.015122 +0.01517 +0.015113 +0.015108 +0.015193 +0.001676 +0.015327 +0.01534 +0.015381 +0.015338 +0.015312 +0.015411 +0.01555 +0.015554 +0.015599 +0.015558 +0.015547 +0.015627 +0.015777 +0.015776 +0.015828 +0.015773 +0.015763 +0.015847 +0.015992 +0.015991 +0.016052 +0.016015 +0.016004 +0.016097 +0.016284 +0.016283 +0.016344 +0.016265 +0.016005 +0.015941 +0.016024 +0.015876 +0.015839 +0.01569 +0.015452 +0.015431 +0.015495 +0.015379 +0.015372 +0.015283 +0.015117 +0.015008 +0.015088 +0.015033 +0.015029 +0.014907 +0.014863 +0.014892 +0.014919 +0.014753 +0.014793 +0.014675 +0.014565 +0.014565 +0.014673 +0.014641 +0.014645 +0.014591 +0.014558 +0.014638 +0.014775 +0.014702 +0.01469 +0.014639 +0.014615 +0.014704 +0.01486 +0.014814 +0.014881 +0.01486 +0.001677 +0.014828 +0.014908 +0.01507 +0.015028 +0.01508 +0.015021 +0.014984 +0.015031 +0.015157 +0.015131 +0.015201 +0.015149 +0.015129 +0.015228 +0.015389 +0.015422 +0.015463 +0.015404 +0.015376 +0.015476 +0.01563 +0.015612 +0.015684 +0.015625 +0.015611 +0.015686 +0.015789 +0.015713 +0.015668 +0.015545 +0.01543 +0.015388 +0.015433 +0.015321 +0.01526 +0.015118 +0.015007 +0.01498 +0.015046 +0.014961 +0.01492 +0.014813 +0.01473 +0.014728 +0.014814 +0.014741 +0.014721 +0.014627 +0.014556 +0.014566 +0.014661 +0.014608 +0.014599 +0.01451 +0.014452 +0.014474 +0.014576 +0.014534 +0.014538 +0.014471 +0.014425 +0.014465 +0.014583 +0.014569 +0.014584 +0.014536 +0.014523 +0.014584 +0.014732 +0.014728 +0.014762 +0.001678 +0.014725 +0.014703 +0.014792 +0.014919 +0.014931 +0.014974 +0.014913 +0.014918 +0.01498 +0.015127 +0.015137 +0.015187 +0.015133 +0.015095 +0.015183 +0.015329 +0.015326 +0.0154 +0.015361 +0.015345 +0.015452 +0.015621 +0.015562 +0.015483 +0.015115 +0.014992 +0.014898 +0.014856 +0.014719 +0.014691 +0.014481 +0.014308 +0.014289 +0.014324 +0.01424 +0.014185 +0.013997 +0.013912 +0.013955 +0.014 +0.013943 +0.013851 +0.013752 +0.013661 +0.013709 +0.013772 +0.013695 +0.013638 +0.013528 +0.013513 +0.013554 +0.013651 +0.013606 +0.013595 +0.013499 +0.013453 +0.013524 +0.013643 +0.01359 +0.013667 +0.013615 +0.013586 +0.013623 +0.013724 +0.013712 +0.013771 +0.013735 +0.001679 +0.013726 +0.013816 +0.013945 +0.013921 +0.013974 +0.013947 +0.013924 +0.014006 +0.014121 +0.014074 +0.014098 +0.014054 +0.014022 +0.014095 +0.014221 +0.014286 +0.014353 +0.014286 +0.014244 +0.014291 +0.014375 +0.014292 +0.014245 +0.014115 +0.013981 +0.013967 +0.013993 +0.013894 +0.013855 +0.013718 +0.01363 +0.013617 +0.013674 +0.013602 +0.013582 +0.013474 +0.013406 +0.013422 +0.013485 +0.013432 +0.013425 +0.013322 +0.013265 +0.013294 +0.013368 +0.013327 +0.013328 +0.013241 +0.013197 +0.013238 +0.013319 +0.013298 +0.013313 +0.013236 +0.013203 +0.013257 +0.013356 +0.01334 +0.013383 +0.013328 +0.013309 +0.013385 +0.013495 +0.013491 +0.00168 +0.013538 +0.013497 +0.013469 +0.013551 +0.013663 +0.013671 +0.013707 +0.013661 +0.013649 +0.013719 +0.013852 +0.013841 +0.013906 +0.013838 +0.013816 +0.013904 +0.014038 +0.014017 +0.014063 +0.014021 +0.014004 +0.014088 +0.014232 +0.01423 +0.014286 +0.01424 +0.014236 +0.014344 +0.014444 +0.014272 +0.014258 +0.014114 +0.013959 +0.013924 +0.013993 +0.01389 +0.013882 +0.013771 +0.013574 +0.013559 +0.013643 +0.013544 +0.013539 +0.013466 +0.013395 +0.013379 +0.01339 +0.013334 +0.013356 +0.013278 +0.013225 +0.013297 +0.013363 +0.013275 +0.013261 +0.013201 +0.013122 +0.013153 +0.013248 +0.013201 +0.013256 +0.013192 +0.013176 +0.013263 +0.013361 +0.013348 +0.013388 +0.013343 +0.01332 +0.013312 +0.013417 +0.001681 +0.013413 +0.013479 +0.013447 +0.013422 +0.013519 +0.013653 +0.013625 +0.013686 +0.013656 +0.013634 +0.013716 +0.013838 +0.013813 +0.013834 +0.013789 +0.013751 +0.013816 +0.01393 +0.013911 +0.014008 +0.013981 +0.013954 +0.01402 +0.01416 +0.014118 +0.014105 +0.014 +0.013917 +0.013887 +0.013951 +0.01385 +0.013798 +0.01368 +0.013584 +0.013562 +0.013623 +0.013539 +0.013497 +0.013389 +0.013313 +0.013309 +0.013389 +0.013328 +0.013309 +0.013214 +0.01315 +0.013156 +0.013246 +0.013191 +0.013182 +0.013099 +0.013045 +0.013059 +0.013153 +0.013111 +0.013111 +0.013038 +0.012991 +0.013021 +0.013128 +0.013106 +0.013124 +0.01308 +0.013047 +0.013114 +0.01324 +0.013229 +0.013274 +0.013233 +0.013205 +0.001682 +0.013292 +0.013408 +0.013384 +0.013437 +0.0134 +0.013375 +0.013446 +0.013571 +0.013568 +0.013611 +0.013566 +0.01355 +0.01363 +0.013749 +0.013721 +0.013776 +0.01373 +0.013709 +0.013798 +0.013926 +0.01392 +0.013983 +0.013949 +0.013939 +0.014031 +0.014147 +0.013991 +0.013864 +0.01375 +0.01362 +0.013519 +0.013559 +0.013473 +0.013444 +0.013347 +0.013263 +0.013144 +0.013159 +0.013071 +0.013079 +0.012996 +0.012913 +0.012968 +0.013051 +0.012903 +0.012894 +0.012785 +0.012734 +0.012696 +0.012796 +0.012725 +0.012765 +0.012684 +0.01266 +0.012717 +0.012808 +0.012785 +0.01278 +0.012678 +0.012663 +0.012733 +0.012863 +0.012822 +0.012858 +0.012849 +0.012823 +0.012897 +0.013016 +0.001683 +0.012988 +0.013027 +0.012996 +0.012989 +0.013055 +0.013169 +0.01312 +0.013175 +0.013145 +0.013121 +0.013181 +0.013278 +0.013229 +0.013274 +0.013232 +0.013207 +0.013291 +0.013493 +0.013497 +0.013509 +0.013469 +0.013422 +0.013489 +0.013608 +0.013538 +0.013502 +0.013391 +0.013293 +0.013283 +0.01333 +0.013238 +0.013196 +0.013091 +0.013 +0.012999 +0.013054 +0.012976 +0.012951 +0.012857 +0.012791 +0.012813 +0.012876 +0.012832 +0.012822 +0.012735 +0.012677 +0.012706 +0.012787 +0.012741 +0.012742 +0.012665 +0.01261 +0.012652 +0.012742 +0.0127 +0.012714 +0.012645 +0.012606 +0.012664 +0.012767 +0.012737 +0.012777 +0.012729 +0.0127 +0.012779 +0.012896 +0.012871 +0.012929 +0.001684 +0.012876 +0.012868 +0.012929 +0.013046 +0.013047 +0.013083 +0.013043 +0.013012 +0.013097 +0.013213 +0.013207 +0.013254 +0.013208 +0.013181 +0.013255 +0.013388 +0.01336 +0.01341 +0.013373 +0.013347 +0.013427 +0.013551 +0.013552 +0.013594 +0.013567 +0.013558 +0.013658 +0.013792 +0.013653 +0.013651 +0.013536 +0.013367 +0.013319 +0.013365 +0.01326 +0.01324 +0.013101 +0.012932 +0.012908 +0.012968 +0.01288 +0.012871 +0.012772 +0.012667 +0.012605 +0.012654 +0.012611 +0.012607 +0.012545 +0.012478 +0.012548 +0.012616 +0.012579 +0.012571 +0.012465 +0.012349 +0.012401 +0.012499 +0.012434 +0.012474 +0.012429 +0.0124 +0.012483 +0.012595 +0.012547 +0.012586 +0.012528 +0.012499 +0.012539 +0.012653 +0.012627 +0.012671 +0.001685 +0.012643 +0.01264 +0.012712 +0.012834 +0.012805 +0.012859 +0.012829 +0.012807 +0.012878 +0.012989 +0.012957 +0.012989 +0.01295 +0.012914 +0.012978 +0.013142 +0.013152 +0.013182 +0.013131 +0.013105 +0.013154 +0.013295 +0.0133 +0.013303 +0.013198 +0.013113 +0.013141 +0.013203 +0.013113 +0.013095 +0.012976 +0.012887 +0.012901 +0.01295 +0.012877 +0.012853 +0.012749 +0.012679 +0.012702 +0.012764 +0.012708 +0.0127 +0.012611 +0.012552 +0.012585 +0.012662 +0.012611 +0.012614 +0.012529 +0.012486 +0.012529 +0.012617 +0.012576 +0.012591 +0.012521 +0.012481 +0.012539 +0.012643 +0.012616 +0.012655 +0.012603 +0.012576 +0.012654 +0.012767 +0.01275 +0.012798 +0.001686 +0.012749 +0.012741 +0.012796 +0.012929 +0.012911 +0.012947 +0.012916 +0.012893 +0.01297 +0.013094 +0.013061 +0.013119 +0.013076 +0.013047 +0.013128 +0.013241 +0.01322 +0.013272 +0.013224 +0.013225 +0.013306 +0.013422 +0.013416 +0.013476 +0.013456 +0.013418 +0.01347 +0.013403 +0.013268 +0.013265 +0.013053 +0.012922 +0.012893 +0.012937 +0.012852 +0.01278 +0.012616 +0.012535 +0.012579 +0.012613 +0.012534 +0.012463 +0.012369 +0.012311 +0.012321 +0.012392 +0.012328 +0.012344 +0.01225 +0.012159 +0.012183 +0.012255 +0.012237 +0.012249 +0.012201 +0.012164 +0.012217 +0.012342 +0.012261 +0.012267 +0.012205 +0.01217 +0.012267 +0.012375 +0.012332 +0.012395 +0.012355 +0.012332 +0.012412 +0.001687 +0.012541 +0.012507 +0.012542 +0.012509 +0.012475 +0.012484 +0.012604 +0.012588 +0.012637 +0.012604 +0.012582 +0.012656 +0.012768 +0.012751 +0.012808 +0.012794 +0.012772 +0.012829 +0.012952 +0.012955 +0.012996 +0.012939 +0.012929 +0.013001 +0.01312 +0.013095 +0.013114 +0.013014 +0.012935 +0.012917 +0.012965 +0.012866 +0.012817 +0.0127 +0.012602 +0.012584 +0.012633 +0.01255 +0.012521 +0.012421 +0.012343 +0.012355 +0.012408 +0.012349 +0.012345 +0.012256 +0.012198 +0.012227 +0.01229 +0.012242 +0.01225 +0.012175 +0.012128 +0.012178 +0.01226 +0.012217 +0.012246 +0.012193 +0.012157 +0.012226 +0.012333 +0.012303 +0.012343 +0.012307 +0.012278 +0.012355 +0.012459 +0.001688 +0.012447 +0.012493 +0.012453 +0.012424 +0.0125 +0.012612 +0.012599 +0.012635 +0.012602 +0.012576 +0.012651 +0.012772 +0.012748 +0.012801 +0.01276 +0.012736 +0.012804 +0.012913 +0.012895 +0.012951 +0.012909 +0.012902 +0.012976 +0.013107 +0.013091 +0.013143 +0.013117 +0.013107 +0.013091 +0.01307 +0.012978 +0.012958 +0.012843 +0.012665 +0.012543 +0.012573 +0.012497 +0.012466 +0.012384 +0.012267 +0.01217 +0.012225 +0.012159 +0.01218 +0.012074 +0.012024 +0.012032 +0.012059 +0.011998 +0.012009 +0.011944 +0.011816 +0.011844 +0.011908 +0.011884 +0.011902 +0.011833 +0.011812 +0.011848 +0.01195 +0.011898 +0.011873 +0.011835 +0.011808 +0.011869 +0.011977 +0.011964 +0.012009 +0.011974 +0.011961 +0.012028 +0.01214 +0.001689 +0.012117 +0.012176 +0.012137 +0.012113 +0.012146 +0.012231 +0.012222 +0.012268 +0.01223 +0.012203 +0.012279 +0.012399 +0.012376 +0.012415 +0.012359 +0.012335 +0.012398 +0.012513 +0.012484 +0.012524 +0.012522 +0.012519 +0.012579 +0.012693 +0.012677 +0.012715 +0.01269 +0.012658 +0.012698 +0.012777 +0.012697 +0.012651 +0.01253 +0.012433 +0.012404 +0.012451 +0.012372 +0.012325 +0.012228 +0.012154 +0.012144 +0.012207 +0.012147 +0.012119 +0.012033 +0.011974 +0.011986 +0.012055 +0.012006 +0.012003 +0.011922 +0.011864 +0.011883 +0.011979 +0.011935 +0.011948 +0.011869 +0.01181 +0.011855 +0.011973 +0.011928 +0.011963 +0.011914 +0.011873 +0.011937 +0.012056 +0.012047 +0.012082 +0.012041 +0.012005 +0.012071 +0.00169 +0.012194 +0.012185 +0.012232 +0.01217 +0.012153 +0.012223 +0.012345 +0.012328 +0.012372 +0.012327 +0.0123 +0.012374 +0.012495 +0.012479 +0.012529 +0.012474 +0.012451 +0.012513 +0.012634 +0.012608 +0.012674 +0.012622 +0.012615 +0.012681 +0.01281 +0.012802 +0.012854 +0.012818 +0.012799 +0.012747 +0.012728 +0.012625 +0.012614 +0.012516 +0.012351 +0.012262 +0.012326 +0.012256 +0.012267 +0.012163 +0.012099 +0.012067 +0.012082 +0.012015 +0.012054 +0.011955 +0.011931 +0.011919 +0.011991 +0.011922 +0.011965 +0.011865 +0.011792 +0.011777 +0.011892 +0.011833 +0.011869 +0.011808 +0.011772 +0.01184 +0.011931 +0.011883 +0.011888 +0.0118 +0.011782 +0.01186 +0.011961 +0.011931 +0.012002 +0.011951 +0.011934 +0.011996 +0.012133 +0.001691 +0.012098 +0.012147 +0.012109 +0.01209 +0.012177 +0.012284 +0.012248 +0.012255 +0.0122 +0.012184 +0.012254 +0.012364 +0.012333 +0.012357 +0.012327 +0.012299 +0.012363 +0.012473 +0.012479 +0.012577 +0.012525 +0.012507 +0.012557 +0.012668 +0.012637 +0.012701 +0.012651 +0.012588 +0.0126 +0.012658 +0.012597 +0.012598 +0.012527 +0.012452 +0.012444 +0.012469 +0.0124 +0.012369 +0.012272 +0.0122 +0.012207 +0.012256 +0.012203 +0.012205 +0.012107 +0.012048 +0.012077 +0.012145 +0.012105 +0.012113 +0.01203 +0.011987 +0.012026 +0.0121 +0.01207 +0.012091 +0.012021 +0.011992 +0.012046 +0.012137 +0.012111 +0.012156 +0.012097 +0.012076 +0.012151 +0.012249 +0.012236 +0.012276 +0.001692 +0.012241 +0.012224 +0.012286 +0.012389 +0.012385 +0.012438 +0.01238 +0.012372 +0.012433 +0.012552 +0.012533 +0.01259 +0.012536 +0.012518 +0.012584 +0.012701 +0.012676 +0.012739 +0.01268 +0.01266 +0.012736 +0.012859 +0.012853 +0.012903 +0.012864 +0.012854 +0.012932 +0.013076 +0.013047 +0.013009 +0.012823 +0.012754 +0.012751 +0.012771 +0.012652 +0.012593 +0.012457 +0.012406 +0.012362 +0.012412 +0.012311 +0.01232 +0.01224 +0.012183 +0.012149 +0.01217 +0.012071 +0.012103 +0.012013 +0.011965 +0.012005 +0.012016 +0.011946 +0.011963 +0.011883 +0.011803 +0.011785 +0.011895 +0.011842 +0.011883 +0.011824 +0.011801 +0.011873 +0.011985 +0.011945 +0.011997 +0.011957 +0.011945 +0.011996 +0.012074 +0.012018 +0.012063 +0.001693 +0.012033 +0.012025 +0.012106 +0.012217 +0.012187 +0.012231 +0.012192 +0.012182 +0.012262 +0.012366 +0.012346 +0.012379 +0.012332 +0.012299 +0.012361 +0.012465 +0.012423 +0.012468 +0.012419 +0.012401 +0.012524 +0.012673 +0.012631 +0.012662 +0.012616 +0.012585 +0.012639 +0.012709 +0.012626 +0.01259 +0.012469 +0.012394 +0.012369 +0.012413 +0.012339 +0.012298 +0.012193 +0.012127 +0.012122 +0.012169 +0.012116 +0.012092 +0.011999 +0.011952 +0.011969 +0.012029 +0.011984 +0.011976 +0.011894 +0.011861 +0.011888 +0.011964 +0.011927 +0.011927 +0.011858 +0.011835 +0.01187 +0.011966 +0.011934 +0.011956 +0.011911 +0.011893 +0.011955 +0.012067 +0.012048 +0.012079 +0.012056 +0.012026 +0.001694 +0.012097 +0.012205 +0.012187 +0.012239 +0.012194 +0.01217 +0.012243 +0.012351 +0.012338 +0.012385 +0.012342 +0.012313 +0.012394 +0.01249 +0.012478 +0.012525 +0.012478 +0.012462 +0.012546 +0.012659 +0.01266 +0.012691 +0.012661 +0.01266 +0.012744 +0.012872 +0.012713 +0.012661 +0.012554 +0.012408 +0.012355 +0.012398 +0.012307 +0.012282 +0.012197 +0.012122 +0.012038 +0.012028 +0.011938 +0.011953 +0.011878 +0.011807 +0.011845 +0.011913 +0.011789 +0.011721 +0.011635 +0.011603 +0.01158 +0.011631 +0.011568 +0.011598 +0.011539 +0.011518 +0.011558 +0.01163 +0.011559 +0.011576 +0.011496 +0.011487 +0.011512 +0.011596 +0.01158 +0.011618 +0.011593 +0.011592 +0.011651 +0.011756 +0.011735 +0.011788 +0.011748 +0.001695 +0.011733 +0.011807 +0.011901 +0.011886 +0.011934 +0.011897 +0.011886 +0.011953 +0.01206 +0.012016 +0.012042 +0.011974 +0.011952 +0.012006 +0.012101 +0.012062 +0.012121 +0.012074 +0.012091 +0.012208 +0.01232 +0.012294 +0.01233 +0.012271 +0.01225 +0.012296 +0.012414 +0.012372 +0.012336 +0.012205 +0.012135 +0.01212 +0.012151 +0.012093 +0.012056 +0.011933 +0.011874 +0.011877 +0.01192 +0.011859 +0.011839 +0.01173 +0.011677 +0.0117 +0.01174 +0.011714 +0.011704 +0.011613 +0.011564 +0.011588 +0.011655 +0.011626 +0.011619 +0.011529 +0.011493 +0.011526 +0.011601 +0.011585 +0.011594 +0.011521 +0.011493 +0.011548 +0.011645 +0.01164 +0.011673 +0.011626 +0.011601 +0.01166 +0.011785 +0.011765 +0.011812 +0.001696 +0.011756 +0.011729 +0.01181 +0.011918 +0.011906 +0.011944 +0.011903 +0.011871 +0.011942 +0.012053 +0.012054 +0.012085 +0.012029 +0.01202 +0.012078 +0.01219 +0.012187 +0.012222 +0.012199 +0.012179 +0.012254 +0.012371 +0.012365 +0.012416 +0.012333 +0.012214 +0.012243 +0.01231 +0.012225 +0.012214 +0.012073 +0.011917 +0.011916 +0.011982 +0.011897 +0.011886 +0.011769 +0.011664 +0.011636 +0.011724 +0.011651 +0.011656 +0.011577 +0.011514 +0.011489 +0.011549 +0.011507 +0.011516 +0.011458 +0.011398 +0.011463 +0.011556 +0.011467 +0.011448 +0.011368 +0.011355 +0.0114 +0.011515 +0.011479 +0.011506 +0.011473 +0.011443 +0.01145 +0.011568 +0.011552 +0.011592 +0.011548 +0.011534 +0.011611 +0.011723 +0.001697 +0.011698 +0.01175 +0.011697 +0.011685 +0.011751 +0.011873 +0.011847 +0.011903 +0.011838 +0.011833 +0.011895 +0.011998 +0.011948 +0.011986 +0.011928 +0.011908 +0.01195 +0.012063 +0.01203 +0.012099 +0.012096 +0.012095 +0.012141 +0.012256 +0.012224 +0.012283 +0.012219 +0.01217 +0.012175 +0.012244 +0.01215 +0.012132 +0.012027 +0.011952 +0.011939 +0.011997 +0.011918 +0.011897 +0.011794 +0.011726 +0.011718 +0.01179 +0.011724 +0.011717 +0.011629 +0.011583 +0.011576 +0.011666 +0.011614 +0.011624 +0.011553 +0.011503 +0.011522 +0.011616 +0.011572 +0.011593 +0.011542 +0.011501 +0.011536 +0.011651 +0.011623 +0.01166 +0.011623 +0.0116 +0.011649 +0.011761 +0.011744 +0.01181 +0.011753 +0.001698 +0.011737 +0.011795 +0.011888 +0.011871 +0.011919 +0.011885 +0.01187 +0.011924 +0.01203 +0.012022 +0.012071 +0.012027 +0.012002 +0.012066 +0.012172 +0.012148 +0.01219 +0.012161 +0.012137 +0.012206 +0.012327 +0.01231 +0.012363 +0.012322 +0.012315 +0.01238 +0.012522 +0.012502 +0.012519 +0.012343 +0.012284 +0.012314 +0.012359 +0.012245 +0.012131 +0.012009 +0.011954 +0.011949 +0.011972 +0.011884 +0.011901 +0.011807 +0.011726 +0.011664 +0.011715 +0.011681 +0.011673 +0.011619 +0.011567 +0.01162 +0.011696 +0.011651 +0.011659 +0.011544 +0.01145 +0.011491 +0.011563 +0.011535 +0.011531 +0.011494 +0.01147 +0.01153 +0.011647 +0.011586 +0.011618 +0.0116 +0.01153 +0.011551 +0.011659 +0.011642 +0.011684 +0.011653 +0.011649 +0.011721 +0.001699 +0.011827 +0.011811 +0.011856 +0.011809 +0.011806 +0.011872 +0.011984 +0.011964 +0.012003 +0.011969 +0.011946 +0.012012 +0.012108 +0.012065 +0.0121 +0.012047 +0.012018 +0.012073 +0.012176 +0.01216 +0.012258 +0.012245 +0.012188 +0.012257 +0.012361 +0.012364 +0.012394 +0.012307 +0.012237 +0.012247 +0.012284 +0.012221 +0.012188 +0.012065 +0.011989 +0.011981 +0.012028 +0.011973 +0.01195 +0.011842 +0.011787 +0.011788 +0.01185 +0.011816 +0.011813 +0.01173 +0.011686 +0.011712 +0.011785 +0.011753 +0.011768 +0.011698 +0.01165 +0.011678 +0.01177 +0.011751 +0.011768 +0.011706 +0.011674 +0.011716 +0.011809 +0.011807 +0.011848 +0.01179 +0.011776 +0.011821 +0.011932 +0.011922 +0.0017 +0.01198 +0.011936 +0.011918 +0.011961 +0.01207 +0.012045 +0.012099 +0.012076 +0.01204 +0.012105 +0.012211 +0.012218 +0.012246 +0.012211 +0.01218 +0.012247 +0.012362 +0.012358 +0.012394 +0.012348 +0.012333 +0.012394 +0.012523 +0.012501 +0.012564 +0.01252 +0.012504 +0.012586 +0.012719 +0.012709 +0.012649 +0.012539 +0.012493 +0.012533 +0.012572 +0.012484 +0.012459 +0.012247 +0.012168 +0.012191 +0.012261 +0.01217 +0.012171 +0.012051 +0.011956 +0.011945 +0.012031 +0.011951 +0.011981 +0.011904 +0.011869 +0.011863 +0.011885 +0.011839 +0.011851 +0.0118 +0.011766 +0.011803 +0.011893 +0.01182 +0.011838 +0.011771 +0.011728 +0.011783 +0.011869 +0.011837 +0.011909 +0.011866 +0.011846 +0.011925 +0.012037 +0.012013 +0.012061 +0.012027 +0.001701 +0.012007 +0.012085 +0.012189 +0.012173 +0.012217 +0.012185 +0.01216 +0.012193 +0.012265 +0.01224 +0.01228 +0.012248 +0.012213 +0.012286 +0.012396 +0.012387 +0.012466 +0.012446 +0.012402 +0.012478 +0.012583 +0.012588 +0.012616 +0.012587 +0.012556 +0.012629 +0.012727 +0.012683 +0.012674 +0.012598 +0.012496 +0.012504 +0.012555 +0.012486 +0.012448 +0.012367 +0.01228 +0.012286 +0.012337 +0.012282 +0.012253 +0.012175 +0.012099 +0.012121 +0.012189 +0.012138 +0.012127 +0.012064 +0.011993 +0.012024 +0.012093 +0.012054 +0.012047 +0.011991 +0.011928 +0.011975 +0.01206 +0.012033 +0.012038 +0.011997 +0.011953 +0.012009 +0.012111 +0.012094 +0.012124 +0.012098 +0.012067 +0.012136 +0.012241 +0.012236 +0.001702 +0.012274 +0.012239 +0.012205 +0.012284 +0.01239 +0.01238 +0.01242 +0.012378 +0.012363 +0.012437 +0.012532 +0.012527 +0.01257 +0.012524 +0.012507 +0.012567 +0.012681 +0.012679 +0.012717 +0.012689 +0.012657 +0.012753 +0.012873 +0.012859 +0.012907 +0.012875 +0.012871 +0.01287 +0.012849 +0.012752 +0.012735 +0.012627 +0.012527 +0.012423 +0.012434 +0.012353 +0.012344 +0.012266 +0.012181 +0.012185 +0.012195 +0.012097 +0.012106 +0.012014 +0.011901 +0.011908 +0.01198 +0.011941 +0.011943 +0.011865 +0.011821 +0.011833 +0.011874 +0.011806 +0.01185 +0.011767 +0.011736 +0.011788 +0.011853 +0.011827 +0.011855 +0.011784 +0.011773 +0.01181 +0.011925 +0.011907 +0.011934 +0.011901 +0.011896 +0.011954 +0.012072 +0.012062 +0.001703 +0.012094 +0.012045 +0.012033 +0.012116 +0.012239 +0.012194 +0.012244 +0.012197 +0.012188 +0.012227 +0.012317 +0.012262 +0.012312 +0.012258 +0.012245 +0.012305 +0.012447 +0.01249 +0.012538 +0.012472 +0.012453 +0.012499 +0.012614 +0.01258 +0.012622 +0.012507 +0.012403 +0.012397 +0.012445 +0.012339 +0.012305 +0.012178 +0.012083 +0.012069 +0.012126 +0.012044 +0.012033 +0.011933 +0.011869 +0.011875 +0.011953 +0.011895 +0.011902 +0.01181 +0.011761 +0.01178 +0.011857 +0.011806 +0.011818 +0.011738 +0.011688 +0.011712 +0.011798 +0.011759 +0.011788 +0.011717 +0.011677 +0.011725 +0.011833 +0.011798 +0.011855 +0.011806 +0.011773 +0.011835 +0.011946 +0.011941 +0.011988 +0.011935 +0.001704 +0.011913 +0.011975 +0.012086 +0.012084 +0.012125 +0.012074 +0.012054 +0.012123 +0.012234 +0.012223 +0.012269 +0.012221 +0.012196 +0.012267 +0.012372 +0.012366 +0.012405 +0.012359 +0.012331 +0.012405 +0.012516 +0.012516 +0.012562 +0.012518 +0.012508 +0.012588 +0.012716 +0.012708 +0.012728 +0.012576 +0.012401 +0.012401 +0.012443 +0.012314 +0.012211 +0.012098 +0.012018 +0.011959 +0.012018 +0.01193 +0.011912 +0.011854 +0.01177 +0.011763 +0.011754 +0.011699 +0.011702 +0.011646 +0.011586 +0.011654 +0.011697 +0.011619 +0.011597 +0.011508 +0.011484 +0.011476 +0.011542 +0.0115 +0.011528 +0.0115 +0.011466 +0.011528 +0.011635 +0.011591 +0.011637 +0.011624 +0.011591 +0.011595 +0.011682 +0.011641 +0.011703 +0.011679 +0.001705 +0.011663 +0.01173 +0.011834 +0.011827 +0.01187 +0.011829 +0.011808 +0.011891 +0.011999 +0.011974 +0.012018 +0.011979 +0.011955 +0.012008 +0.012112 +0.012079 +0.012112 +0.012061 +0.012029 +0.012087 +0.012189 +0.012205 +0.012293 +0.012246 +0.012217 +0.01227 +0.012379 +0.012342 +0.012378 +0.012298 +0.0122 +0.0122 +0.012233 +0.012146 +0.012122 +0.012004 +0.011931 +0.011933 +0.011989 +0.011916 +0.011904 +0.011812 +0.011746 +0.011763 +0.011829 +0.011777 +0.011787 +0.011709 +0.011656 +0.011683 +0.011765 +0.011717 +0.011729 +0.011657 +0.011598 +0.011641 +0.011719 +0.011682 +0.011701 +0.011639 +0.0116 +0.011653 +0.011754 +0.011734 +0.011775 +0.011733 +0.011703 +0.011775 +0.011879 +0.011873 +0.011906 +0.001706 +0.011861 +0.01185 +0.011913 +0.012012 +0.012009 +0.012052 +0.012006 +0.011988 +0.012053 +0.012163 +0.012147 +0.012193 +0.012153 +0.012129 +0.012194 +0.012302 +0.012296 +0.012329 +0.012281 +0.012277 +0.012328 +0.012461 +0.012448 +0.012492 +0.012463 +0.012452 +0.012535 +0.012663 +0.01264 +0.012531 +0.01241 +0.012343 +0.012356 +0.012365 +0.012237 +0.012143 +0.012059 +0.011976 +0.011942 +0.011975 +0.011912 +0.011909 +0.011822 +0.011704 +0.011654 +0.011733 +0.011673 +0.011696 +0.011616 +0.011586 +0.011603 +0.011705 +0.011587 +0.011593 +0.011497 +0.011478 +0.011497 +0.011571 +0.011552 +0.011576 +0.011541 +0.011524 +0.011575 +0.011693 +0.011665 +0.011697 +0.01168 +0.011628 +0.011634 +0.011754 +0.011741 +0.001707 +0.011776 +0.011754 +0.011733 +0.011808 +0.01191 +0.011903 +0.011949 +0.011913 +0.01188 +0.011974 +0.012051 +0.012044 +0.012076 +0.012041 +0.011989 +0.012064 +0.012159 +0.012138 +0.012168 +0.012161 +0.012163 +0.012234 +0.012319 +0.012319 +0.01234 +0.012317 +0.012272 +0.012291 +0.012342 +0.012265 +0.012198 +0.012081 +0.011981 +0.011965 +0.012002 +0.011943 +0.011902 +0.011806 +0.011727 +0.011734 +0.011781 +0.011734 +0.011699 +0.01162 +0.011546 +0.01157 +0.011625 +0.011599 +0.011576 +0.011525 +0.011458 +0.011502 +0.011566 +0.011547 +0.011545 +0.011501 +0.011442 +0.01148 +0.011573 +0.011556 +0.011568 +0.011543 +0.011492 +0.011549 +0.011657 +0.011654 +0.011679 +0.011662 +0.011625 +0.011689 +0.001708 +0.011777 +0.011781 +0.011829 +0.011798 +0.011761 +0.011824 +0.01192 +0.0119 +0.011945 +0.011926 +0.011901 +0.01196 +0.012064 +0.012056 +0.012107 +0.012063 +0.012036 +0.012095 +0.012208 +0.012188 +0.012231 +0.012189 +0.012172 +0.012239 +0.012367 +0.012357 +0.012398 +0.012365 +0.01236 +0.012431 +0.012465 +0.012308 +0.012283 +0.012132 +0.012003 +0.011952 +0.011992 +0.011929 +0.011908 +0.011814 +0.011733 +0.011666 +0.01169 +0.011629 +0.011639 +0.011542 +0.011499 +0.011525 +0.011624 +0.011544 +0.011476 +0.011374 +0.011329 +0.011389 +0.01145 +0.011428 +0.011429 +0.011368 +0.011282 +0.011291 +0.011384 +0.01137 +0.011395 +0.011359 +0.011341 +0.011397 +0.011522 +0.011499 +0.011528 +0.011504 +0.011477 +0.011546 +0.011672 +0.001709 +0.011645 +0.01166 +0.011592 +0.011577 +0.011633 +0.011723 +0.011697 +0.011738 +0.011706 +0.011692 +0.011759 +0.011861 +0.011836 +0.01187 +0.01183 +0.011809 +0.011874 +0.012024 +0.012006 +0.012041 +0.012004 +0.011969 +0.012047 +0.012158 +0.012137 +0.012191 +0.012135 +0.012111 +0.01214 +0.012194 +0.012133 +0.012099 +0.011974 +0.011891 +0.011876 +0.011911 +0.011851 +0.011829 +0.011719 +0.011658 +0.011667 +0.011717 +0.011677 +0.011678 +0.01157 +0.011522 +0.011552 +0.011615 +0.011579 +0.011591 +0.011509 +0.011459 +0.011493 +0.011561 +0.011544 +0.011562 +0.011497 +0.011456 +0.011495 +0.011585 +0.011581 +0.011608 +0.011558 +0.011538 +0.011586 +0.011689 +0.011695 +0.011732 +0.01169 +0.00171 +0.011663 +0.011719 +0.011822 +0.01183 +0.011866 +0.011829 +0.011801 +0.011856 +0.011958 +0.011956 +0.01201 +0.011967 +0.011937 +0.012003 +0.012103 +0.012097 +0.012146 +0.012104 +0.012072 +0.012144 +0.012259 +0.012235 +0.012294 +0.012233 +0.012236 +0.012316 +0.012427 +0.012408 +0.012467 +0.01244 +0.012287 +0.012301 +0.012376 +0.012296 +0.012282 +0.012188 +0.012088 +0.012082 +0.012001 +0.011904 +0.011919 +0.011826 +0.011756 +0.011811 +0.011815 +0.011708 +0.011725 +0.011599 +0.011552 +0.011526 +0.011603 +0.011534 +0.011559 +0.011478 +0.011449 +0.011497 +0.011562 +0.011484 +0.011461 +0.011414 +0.011368 +0.011372 +0.011469 +0.011428 +0.011459 +0.011434 +0.011411 +0.011478 +0.011598 +0.011565 +0.011598 +0.011577 +0.011559 +0.011628 +0.011739 +0.001711 +0.011717 +0.011753 +0.011713 +0.011676 +0.011676 +0.011778 +0.011764 +0.01181 +0.011778 +0.011762 +0.011825 +0.011936 +0.011923 +0.01196 +0.011948 +0.011931 +0.011984 +0.012092 +0.012088 +0.01213 +0.012081 +0.01206 +0.012139 +0.012246 +0.012225 +0.012281 +0.012231 +0.012202 +0.012261 +0.012336 +0.012255 +0.012251 +0.012133 +0.01204 +0.012028 +0.012065 +0.011987 +0.011971 +0.01185 +0.01178 +0.011792 +0.011836 +0.011787 +0.011775 +0.011677 +0.011619 +0.011649 +0.011707 +0.01167 +0.011683 +0.011595 +0.011537 +0.011582 +0.011647 +0.011614 +0.011646 +0.011566 +0.011517 +0.011564 +0.01166 +0.011628 +0.011668 +0.011617 +0.011576 +0.011634 +0.011736 +0.01173 +0.011782 +0.011728 +0.011709 +0.011755 +0.001712 +0.011859 +0.011863 +0.011916 +0.011866 +0.011851 +0.011897 +0.011997 +0.011978 +0.012033 +0.012007 +0.011977 +0.012033 +0.012153 +0.012149 +0.012183 +0.012143 +0.012112 +0.012174 +0.012285 +0.01227 +0.012307 +0.012272 +0.01225 +0.012325 +0.012447 +0.012431 +0.012477 +0.012446 +0.01244 +0.012518 +0.012618 +0.012461 +0.012425 +0.012305 +0.012169 +0.012139 +0.01218 +0.012097 +0.012094 +0.011995 +0.011923 +0.011834 +0.011874 +0.01182 +0.011825 +0.011733 +0.011682 +0.01172 +0.011797 +0.011679 +0.011676 +0.011584 +0.011553 +0.011534 +0.01163 +0.01157 +0.011593 +0.011537 +0.01148 +0.011532 +0.011582 +0.011543 +0.011583 +0.01152 +0.011494 +0.011563 +0.011646 +0.011611 +0.011657 +0.011619 +0.011606 +0.011657 +0.011785 +0.011761 +0.011799 +0.001713 +0.011741 +0.011731 +0.011802 +0.011927 +0.011881 +0.011935 +0.01188 +0.011854 +0.011873 +0.011989 +0.011965 +0.012015 +0.011967 +0.01195 +0.012013 +0.01213 +0.012127 +0.01221 +0.012163 +0.012137 +0.012189 +0.012309 +0.012277 +0.012352 +0.012297 +0.012285 +0.01233 +0.012439 +0.012384 +0.012371 +0.012242 +0.012157 +0.012126 +0.012173 +0.012087 +0.012061 +0.011942 +0.011884 +0.011855 +0.011927 +0.011866 +0.011866 +0.01176 +0.011722 +0.011731 +0.011814 +0.01177 +0.011782 +0.011712 +0.01167 +0.011688 +0.011782 +0.011737 +0.011762 +0.011697 +0.011658 +0.011685 +0.011791 +0.011757 +0.011787 +0.011737 +0.011701 +0.011745 +0.011861 +0.011836 +0.011878 +0.011844 +0.011819 +0.011856 +0.001714 +0.011984 +0.01197 +0.012026 +0.01197 +0.011955 +0.012007 +0.012129 +0.012111 +0.012167 +0.012115 +0.012097 +0.012156 +0.012274 +0.012256 +0.012308 +0.012262 +0.012246 +0.012295 +0.012411 +0.012398 +0.01244 +0.012384 +0.012378 +0.012451 +0.012572 +0.012551 +0.012615 +0.012576 +0.012571 +0.012652 +0.012731 +0.012576 +0.012573 +0.012441 +0.0123 +0.012239 +0.012281 +0.012181 +0.01216 +0.012057 +0.011921 +0.011874 +0.011953 +0.011879 +0.011856 +0.011789 +0.011708 +0.011685 +0.011707 +0.011664 +0.011663 +0.011598 +0.011557 +0.011599 +0.011706 +0.011634 +0.011639 +0.011491 +0.011452 +0.011529 +0.011616 +0.011568 +0.011607 +0.011549 +0.01152 +0.011553 +0.011634 +0.011593 +0.011648 +0.011609 +0.011596 +0.011661 +0.011789 +0.011759 +0.011794 +0.001715 +0.011751 +0.011743 +0.011819 +0.011931 +0.011906 +0.011948 +0.011904 +0.011897 +0.011981 +0.012065 +0.012016 +0.012051 +0.012 +0.011971 +0.012033 +0.012136 +0.012095 +0.012137 +0.012088 +0.01208 +0.0122 +0.012343 +0.012322 +0.012338 +0.012295 +0.012265 +0.012317 +0.012438 +0.012375 +0.012334 +0.012229 +0.012132 +0.012106 +0.012149 +0.012068 +0.01202 +0.011917 +0.011844 +0.011834 +0.011899 +0.011837 +0.011814 +0.011727 +0.011664 +0.011678 +0.011749 +0.011703 +0.011701 +0.011626 +0.011578 +0.011601 +0.011684 +0.011652 +0.011653 +0.011591 +0.011537 +0.011577 +0.011676 +0.01165 +0.011674 +0.01162 +0.011577 +0.011627 +0.011743 +0.011733 +0.011764 +0.011727 +0.011686 +0.011749 +0.011864 +0.001716 +0.011867 +0.011909 +0.011861 +0.011832 +0.011888 +0.011993 +0.011985 +0.012047 +0.012001 +0.011978 +0.012025 +0.012137 +0.012127 +0.012185 +0.012139 +0.01212 +0.012175 +0.012281 +0.01227 +0.012311 +0.012259 +0.012249 +0.012312 +0.012437 +0.012429 +0.012477 +0.012432 +0.012427 +0.012506 +0.012648 +0.012582 +0.012472 +0.012329 +0.012264 +0.012271 +0.012271 +0.012147 +0.012111 +0.01198 +0.011909 +0.011859 +0.011915 +0.011831 +0.011813 +0.011744 +0.011665 +0.011646 +0.011651 +0.011602 +0.011609 +0.011538 +0.011485 +0.011542 +0.011618 +0.011573 +0.011497 +0.0114 +0.011391 +0.011428 +0.011532 +0.011491 +0.011506 +0.011461 +0.011444 +0.011423 +0.011527 +0.011495 +0.011542 +0.011503 +0.011502 +0.011564 +0.011676 +0.011665 +0.011704 +0.011659 +0.001717 +0.011637 +0.011724 +0.011834 +0.011811 +0.011846 +0.01181 +0.0118 +0.011875 +0.01199 +0.011949 +0.011934 +0.01187 +0.011853 +0.011917 +0.012017 +0.011989 +0.012026 +0.011996 +0.012007 +0.012116 +0.012232 +0.012204 +0.012228 +0.01219 +0.01215 +0.012216 +0.012338 +0.012316 +0.012304 +0.012188 +0.012112 +0.012107 +0.01213 +0.012058 +0.012017 +0.011887 +0.011814 +0.011821 +0.01185 +0.011798 +0.011775 +0.011671 +0.011613 +0.011632 +0.011687 +0.011649 +0.011651 +0.011565 +0.011515 +0.01154 +0.011612 +0.011575 +0.011587 +0.011505 +0.011454 +0.011491 +0.011566 +0.011545 +0.011556 +0.011493 +0.011455 +0.011502 +0.011593 +0.011585 +0.011622 +0.011568 +0.011552 +0.011598 +0.011695 +0.011712 +0.01175 +0.011706 +0.001718 +0.011677 +0.011742 +0.011826 +0.01182 +0.011879 +0.011851 +0.011808 +0.011875 +0.011968 +0.01196 +0.012008 +0.011972 +0.011941 +0.012005 +0.012116 +0.012106 +0.012136 +0.01211 +0.012075 +0.012173 +0.012264 +0.012277 +0.012309 +0.012285 +0.012262 +0.012363 +0.012449 +0.012347 +0.01235 +0.012298 +0.012141 +0.012096 +0.012133 +0.012054 +0.012028 +0.01188 +0.011757 +0.011746 +0.011792 +0.01173 +0.011697 +0.01163 +0.011486 +0.011469 +0.011549 +0.011486 +0.011501 +0.011426 +0.011374 +0.011429 +0.011522 +0.011431 +0.011389 +0.011315 +0.01129 +0.011345 +0.011427 +0.011399 +0.01137 +0.011325 +0.011269 +0.011347 +0.011448 +0.011414 +0.01144 +0.011417 +0.01139 +0.011452 +0.011532 +0.011518 +0.011553 +0.011508 +0.011493 +0.001719 +0.011581 +0.011673 +0.011659 +0.011704 +0.011667 +0.011652 +0.011725 +0.011831 +0.011802 +0.011828 +0.011747 +0.011728 +0.011777 +0.011876 +0.011852 +0.011892 +0.011858 +0.011879 +0.011987 +0.012097 +0.012062 +0.012103 +0.012043 +0.012021 +0.012071 +0.012201 +0.012148 +0.012114 +0.012005 +0.011926 +0.011924 +0.011964 +0.011882 +0.011848 +0.011746 +0.011678 +0.01168 +0.011735 +0.011674 +0.011654 +0.011569 +0.01151 +0.011527 +0.011607 +0.011548 +0.011548 +0.011477 +0.011436 +0.01145 +0.011542 +0.011496 +0.011496 +0.011434 +0.01139 +0.011427 +0.011526 +0.011488 +0.0115 +0.011454 +0.011424 +0.011479 +0.011592 +0.011568 +0.011602 +0.011569 +0.011533 +0.011608 +0.011716 +0.0117 +0.00172 +0.011738 +0.011694 +0.011677 +0.011736 +0.011853 +0.011837 +0.01188 +0.01183 +0.011808 +0.011869 +0.01199 +0.011976 +0.012023 +0.011963 +0.011947 +0.012002 +0.012128 +0.012099 +0.012162 +0.012106 +0.012116 +0.012174 +0.012297 +0.012283 +0.012343 +0.012306 +0.012159 +0.012118 +0.012191 +0.012112 +0.012099 +0.011993 +0.01191 +0.011793 +0.011802 +0.011723 +0.011727 +0.011627 +0.01158 +0.011586 +0.01161 +0.011499 +0.011511 +0.011427 +0.011333 +0.011338 +0.011411 +0.011356 +0.01138 +0.011304 +0.011292 +0.011319 +0.011414 +0.011336 +0.011286 +0.011244 +0.011216 +0.011239 +0.011337 +0.011279 +0.011317 +0.011302 +0.011278 +0.011333 +0.011451 +0.011404 +0.011451 +0.011445 +0.011407 +0.011403 +0.0115 +0.001721 +0.01148 +0.011533 +0.011495 +0.011485 +0.011554 +0.011671 +0.011646 +0.011695 +0.011652 +0.01165 +0.011701 +0.011816 +0.01179 +0.011828 +0.011777 +0.011753 +0.011806 +0.011917 +0.011884 +0.011925 +0.011891 +0.011911 +0.011967 +0.012085 +0.012045 +0.012093 +0.012044 +0.012028 +0.012053 +0.01211 +0.012045 +0.012014 +0.011889 +0.011826 +0.011801 +0.011842 +0.011774 +0.011752 +0.011632 +0.011576 +0.011568 +0.011621 +0.011566 +0.01156 +0.011459 +0.011419 +0.011429 +0.011497 +0.01145 +0.011456 +0.011374 +0.011343 +0.011364 +0.011439 +0.011405 +0.011421 +0.011343 +0.011327 +0.011358 +0.011447 +0.011428 +0.011457 +0.011389 +0.011387 +0.011439 +0.011539 +0.01153 +0.01157 +0.011526 +0.011507 +0.001722 +0.011564 +0.011676 +0.011665 +0.011701 +0.011669 +0.011632 +0.011702 +0.011808 +0.011803 +0.011838 +0.011799 +0.011774 +0.011837 +0.011947 +0.011945 +0.011976 +0.011931 +0.011908 +0.011983 +0.012079 +0.012072 +0.012104 +0.012077 +0.012056 +0.012144 +0.012262 +0.012242 +0.012288 +0.012261 +0.012198 +0.012143 +0.012206 +0.012141 +0.012115 +0.012021 +0.011944 +0.011969 +0.011942 +0.011778 +0.011767 +0.011711 +0.011592 +0.011522 +0.011588 +0.011513 +0.011517 +0.011451 +0.011387 +0.011441 +0.011431 +0.011382 +0.011378 +0.011303 +0.011212 +0.01123 +0.011284 +0.011248 +0.011268 +0.011217 +0.011192 +0.011232 +0.011322 +0.011269 +0.011273 +0.011191 +0.011171 +0.011226 +0.011321 +0.011299 +0.011336 +0.011315 +0.01129 +0.011372 +0.011468 +0.011436 +0.011479 +0.001723 +0.011442 +0.011434 +0.011503 +0.011578 +0.011546 +0.011582 +0.011554 +0.011532 +0.011617 +0.011707 +0.011684 +0.011703 +0.011671 +0.011634 +0.011697 +0.011787 +0.011761 +0.011796 +0.011765 +0.011786 +0.011882 +0.011991 +0.011948 +0.011985 +0.011941 +0.011906 +0.011965 +0.012031 +0.011966 +0.011917 +0.011804 +0.011717 +0.011702 +0.011721 +0.011661 +0.011611 +0.011512 +0.011423 +0.011426 +0.011458 +0.011416 +0.011379 +0.011291 +0.011237 +0.011252 +0.0113 +0.01127 +0.01125 +0.011182 +0.011127 +0.011157 +0.01121 +0.011183 +0.011177 +0.011115 +0.011077 +0.011118 +0.011176 +0.011166 +0.011172 +0.011124 +0.011102 +0.011154 +0.011237 +0.01123 +0.011257 +0.011225 +0.011204 +0.011265 +0.011364 +0.011356 +0.001724 +0.011393 +0.011347 +0.011332 +0.011389 +0.011495 +0.011488 +0.011525 +0.011482 +0.011461 +0.011525 +0.011632 +0.011623 +0.011658 +0.011612 +0.01159 +0.011657 +0.011763 +0.011743 +0.011781 +0.011746 +0.011726 +0.011799 +0.011914 +0.011893 +0.011945 +0.011909 +0.011895 +0.011982 +0.012102 +0.012048 +0.011959 +0.011857 +0.011799 +0.011815 +0.011827 +0.011695 +0.011631 +0.011507 +0.011424 +0.011402 +0.011431 +0.011347 +0.011331 +0.011253 +0.011134 +0.011102 +0.011153 +0.011097 +0.011099 +0.011019 +0.010977 +0.011013 +0.011108 +0.010997 +0.010952 +0.010892 +0.010843 +0.010907 +0.010982 +0.010944 +0.01091 +0.010832 +0.010819 +0.010872 +0.010961 +0.010943 +0.010976 +0.010912 +0.010911 +0.010952 +0.011032 +0.011008 +0.011058 +0.011017 +0.010996 +0.011072 +0.011169 +0.001725 +0.011144 +0.011184 +0.011161 +0.011136 +0.011209 +0.011305 +0.01128 +0.011314 +0.011291 +0.01125 +0.011317 +0.011388 +0.01136 +0.011383 +0.011342 +0.011314 +0.011375 +0.011477 +0.011482 +0.01157 +0.011545 +0.011504 +0.011561 +0.011656 +0.011637 +0.011661 +0.011641 +0.011587 +0.011593 +0.011625 +0.011558 +0.011528 +0.011423 +0.011316 +0.011322 +0.011353 +0.011281 +0.011252 +0.011165 +0.011074 +0.011091 +0.011142 +0.011093 +0.011083 +0.011022 +0.010938 +0.010975 +0.011042 +0.011003 +0.011008 +0.010951 +0.010881 +0.010925 +0.010996 +0.010972 +0.010984 +0.010939 +0.010881 +0.010919 +0.011014 +0.011 +0.011017 +0.010988 +0.010941 +0.010993 +0.011097 +0.011091 +0.011129 +0.0111 +0.011059 +0.011117 +0.001726 +0.011213 +0.011218 +0.011258 +0.011218 +0.011194 +0.011243 +0.01134 +0.011338 +0.011388 +0.011347 +0.011327 +0.011369 +0.011473 +0.011464 +0.011513 +0.011473 +0.011455 +0.011495 +0.011614 +0.011594 +0.011635 +0.011595 +0.011582 +0.011649 +0.011761 +0.011757 +0.011797 +0.01177 +0.011761 +0.011813 +0.011801 +0.011729 +0.011733 +0.011648 +0.011573 +0.011549 +0.011501 +0.011414 +0.011397 +0.011305 +0.011186 +0.011145 +0.011181 +0.011125 +0.011119 +0.011043 +0.010998 +0.011004 +0.011021 +0.010929 +0.010969 +0.010898 +0.010869 +0.010915 +0.01095 +0.010907 +0.010909 +0.010848 +0.010786 +0.010798 +0.010884 +0.010838 +0.010867 +0.010842 +0.010816 +0.010876 +0.01098 +0.010951 +0.010976 +0.010957 +0.01095 +0.011007 +0.011117 +0.011085 +0.001727 +0.011114 +0.01106 +0.011018 +0.011061 +0.011152 +0.011137 +0.01117 +0.011146 +0.011126 +0.011201 +0.011295 +0.011282 +0.011307 +0.011277 +0.011251 +0.011343 +0.011443 +0.011426 +0.011455 +0.011429 +0.011412 +0.011474 +0.011565 +0.011572 +0.011602 +0.011553 +0.011515 +0.011547 +0.01159 +0.011541 +0.011508 +0.0114 +0.011324 +0.011326 +0.011349 +0.011296 +0.011261 +0.01116 +0.011091 +0.011099 +0.011135 +0.0111 +0.011081 +0.011004 +0.01095 +0.010985 +0.011032 +0.011015 +0.011009 +0.010939 +0.01089 +0.01093 +0.010993 +0.010981 +0.010986 +0.010924 +0.010881 +0.010934 +0.011014 +0.011007 +0.011029 +0.010988 +0.010957 +0.011023 +0.011111 +0.011123 +0.011147 +0.011109 +0.011071 +0.001728 +0.011147 +0.011231 +0.011249 +0.011273 +0.011232 +0.011206 +0.011268 +0.011365 +0.011373 +0.011401 +0.011364 +0.011334 +0.011398 +0.011492 +0.011498 +0.01153 +0.011491 +0.011458 +0.011543 +0.01163 +0.011638 +0.011661 +0.011644 +0.011621 +0.011699 +0.011809 +0.0118 +0.011834 +0.011694 +0.011609 +0.011637 +0.011688 +0.0116 +0.011481 +0.011378 +0.011299 +0.011275 +0.011304 +0.011233 +0.011213 +0.011124 +0.01098 +0.010973 +0.011026 +0.01098 +0.01096 +0.010914 +0.01078 +0.010789 +0.01083 +0.010813 +0.010807 +0.010769 +0.010698 +0.010763 +0.010825 +0.0108 +0.010725 +0.010662 +0.010628 +0.01069 +0.010765 +0.010761 +0.010783 +0.010752 +0.010735 +0.010795 +0.010878 +0.010882 +0.010922 +0.01088 +0.010854 +0.010945 +0.001729 +0.011022 +0.011 +0.010986 +0.01095 +0.010924 +0.011 +0.011091 +0.011072 +0.011111 +0.011085 +0.011058 +0.011129 +0.011223 +0.011206 +0.011226 +0.011196 +0.011163 +0.011228 +0.011313 +0.011301 +0.011339 +0.011342 +0.011319 +0.011384 +0.011469 +0.011457 +0.011492 +0.011459 +0.011429 +0.011453 +0.011483 +0.011433 +0.011378 +0.011269 +0.011184 +0.01118 +0.01119 +0.011141 +0.011101 +0.010997 +0.010925 +0.010931 +0.010958 +0.010918 +0.010899 +0.010817 +0.010744 +0.010772 +0.010822 +0.010791 +0.010795 +0.010718 +0.010662 +0.010696 +0.010757 +0.01074 +0.01075 +0.010695 +0.010648 +0.010686 +0.010756 +0.010757 +0.010781 +0.010738 +0.010703 +0.010758 +0.010824 +0.010816 +0.010863 +0.01083 +0.010818 +0.010862 +0.00173 +0.010957 +0.01093 +0.010977 +0.010943 +0.010934 +0.010984 +0.011079 +0.011061 +0.011105 +0.011074 +0.011043 +0.011104 +0.011205 +0.011194 +0.011238 +0.011194 +0.011169 +0.011228 +0.011323 +0.01132 +0.011352 +0.011313 +0.011299 +0.01136 +0.011474 +0.011457 +0.011499 +0.011469 +0.011461 +0.011541 +0.011653 +0.011558 +0.011467 +0.011384 +0.011308 +0.01125 +0.011265 +0.011169 +0.011144 +0.011015 +0.010893 +0.010864 +0.010914 +0.010845 +0.010825 +0.01074 +0.010622 +0.010583 +0.01064 +0.010595 +0.01058 +0.010519 +0.010471 +0.010509 +0.010578 +0.010475 +0.010475 +0.010415 +0.010365 +0.010354 +0.010441 +0.010399 +0.010415 +0.010389 +0.010349 +0.01041 +0.010519 +0.010483 +0.010516 +0.010491 +0.010461 +0.010526 +0.010638 +0.010613 +0.010639 +0.010601 +0.001731 +0.010577 +0.010583 +0.010681 +0.010645 +0.010699 +0.010658 +0.010646 +0.010714 +0.010813 +0.010797 +0.010841 +0.010789 +0.010778 +0.010825 +0.010928 +0.0109 +0.010954 +0.010923 +0.010911 +0.010957 +0.011062 +0.011042 +0.011094 +0.011042 +0.011039 +0.011078 +0.011188 +0.011185 +0.011214 +0.011154 +0.011129 +0.011136 +0.011194 +0.011129 +0.011105 +0.010992 +0.010925 +0.010907 +0.010951 +0.010868 +0.010859 +0.010747 +0.010698 +0.010695 +0.010738 +0.010683 +0.010679 +0.010592 +0.010555 +0.010567 +0.010634 +0.010589 +0.010599 +0.010522 +0.010496 +0.010516 +0.01059 +0.010561 +0.010579 +0.010516 +0.010502 +0.010536 +0.010634 +0.010611 +0.01065 +0.010595 +0.010592 +0.010633 +0.010737 +0.010717 +0.01076 +0.010721 +0.001732 +0.010697 +0.010753 +0.010851 +0.010839 +0.01088 +0.01084 +0.01081 +0.010874 +0.010972 +0.01097 +0.011 +0.010958 +0.010937 +0.011001 +0.011092 +0.011083 +0.01112 +0.011086 +0.011064 +0.011142 +0.011243 +0.011233 +0.011272 +0.011239 +0.011222 +0.011314 +0.011383 +0.011289 +0.011312 +0.011255 +0.011186 +0.011146 +0.011172 +0.01109 +0.011081 +0.010982 +0.010852 +0.010814 +0.010852 +0.010784 +0.010768 +0.010697 +0.010617 +0.010628 +0.010611 +0.010541 +0.010545 +0.010471 +0.01043 +0.010464 +0.01053 +0.01045 +0.010443 +0.010381 +0.010324 +0.01038 +0.010429 +0.010398 +0.010429 +0.010368 +0.010353 +0.010421 +0.010496 +0.01049 +0.010484 +0.010428 +0.010417 +0.010481 +0.010572 +0.010554 +0.010586 +0.010545 +0.010528 +0.001733 +0.01061 +0.010699 +0.010675 +0.010704 +0.010679 +0.010652 +0.01073 +0.010826 +0.010796 +0.010823 +0.010773 +0.010735 +0.010802 +0.010869 +0.010854 +0.010877 +0.01085 +0.010822 +0.010892 +0.01101 +0.011042 +0.011064 +0.011029 +0.011003 +0.011055 +0.011139 +0.011126 +0.011162 +0.01114 +0.011104 +0.011128 +0.011172 +0.011129 +0.011094 +0.010998 +0.010919 +0.01092 +0.010939 +0.010893 +0.010865 +0.01078 +0.010702 +0.010722 +0.010755 +0.010707 +0.010696 +0.010617 +0.010557 +0.010589 +0.010639 +0.010607 +0.010595 +0.010534 +0.010485 +0.010525 +0.010578 +0.010555 +0.01056 +0.010503 +0.010465 +0.010515 +0.010584 +0.010568 +0.010579 +0.010537 +0.010514 +0.010569 +0.010649 +0.010652 +0.010671 +0.01064 +0.010637 +0.01066 +0.010772 +0.001734 +0.010761 +0.010796 +0.01076 +0.010731 +0.010797 +0.010893 +0.010886 +0.010919 +0.010884 +0.01085 +0.010912 +0.011008 +0.011011 +0.011041 +0.011008 +0.010971 +0.011043 +0.011132 +0.011131 +0.011162 +0.01113 +0.011103 +0.011187 +0.011288 +0.011278 +0.011314 +0.01129 +0.011244 +0.01117 +0.011192 +0.011132 +0.011107 +0.011039 +0.010958 +0.010972 +0.010927 +0.010836 +0.010817 +0.01076 +0.010627 +0.010599 +0.010651 +0.010601 +0.010597 +0.010548 +0.010474 +0.010454 +0.010474 +0.010447 +0.010457 +0.010419 +0.010374 +0.010411 +0.010488 +0.010445 +0.010462 +0.010396 +0.010303 +0.010366 +0.010433 +0.0104 +0.01044 +0.010409 +0.010368 +0.010463 +0.01053 +0.010498 +0.010552 +0.010516 +0.010483 +0.01051 +0.010597 +0.010573 +0.001735 +0.010607 +0.010581 +0.010571 +0.010635 +0.010732 +0.01071 +0.010747 +0.01072 +0.010698 +0.010767 +0.010859 +0.010835 +0.010868 +0.010827 +0.010797 +0.010855 +0.010943 +0.010916 +0.010953 +0.010917 +0.010943 +0.011003 +0.011092 +0.011073 +0.011112 +0.011067 +0.011058 +0.01111 +0.011203 +0.011162 +0.011142 +0.011041 +0.01098 +0.010974 +0.011015 +0.010952 +0.010919 +0.010815 +0.010754 +0.010765 +0.010815 +0.010766 +0.010754 +0.010662 +0.01061 +0.010637 +0.010691 +0.010661 +0.010661 +0.010583 +0.010546 +0.010576 +0.010643 +0.010625 +0.010633 +0.010566 +0.010525 +0.010568 +0.010651 +0.010644 +0.010664 +0.010612 +0.010587 +0.010633 +0.010728 +0.010744 +0.010778 +0.010714 +0.010698 +0.010751 +0.001736 +0.010837 +0.010827 +0.010867 +0.010849 +0.010809 +0.010874 +0.010957 +0.010969 +0.010995 +0.01096 +0.010928 +0.010995 +0.011088 +0.011091 +0.011115 +0.011084 +0.011052 +0.011118 +0.011205 +0.01121 +0.011232 +0.011217 +0.011181 +0.011278 +0.011358 +0.011346 +0.011393 +0.011378 +0.011343 +0.011316 +0.01134 +0.011289 +0.011275 +0.011206 +0.011114 +0.011139 +0.011179 +0.011032 +0.010997 +0.010912 +0.010819 +0.010822 +0.010846 +0.010783 +0.010793 +0.010729 +0.010663 +0.010637 +0.010657 +0.010623 +0.010629 +0.010591 +0.010525 +0.010594 +0.010635 +0.010617 +0.010602 +0.010506 +0.010458 +0.010513 +0.010594 +0.010548 +0.010586 +0.010555 +0.010523 +0.01058 +0.010615 +0.010597 +0.010651 +0.010623 +0.010594 +0.010673 +0.010759 +0.01074 +0.010782 +0.001737 +0.010742 +0.01074 +0.010801 +0.010893 +0.010874 +0.010908 +0.010879 +0.010868 +0.010933 +0.011033 +0.010993 +0.010993 +0.010939 +0.010919 +0.010976 +0.011066 +0.011039 +0.011075 +0.011045 +0.011062 +0.011148 +0.011251 +0.01123 +0.011261 +0.01122 +0.011194 +0.01125 +0.011356 +0.011346 +0.011345 +0.011242 +0.011166 +0.011154 +0.011191 +0.011127 +0.011084 +0.010974 +0.0109 +0.010893 +0.010933 +0.010892 +0.010868 +0.010773 +0.010724 +0.010729 +0.010782 +0.01075 +0.010747 +0.010669 +0.010622 +0.010639 +0.010701 +0.010675 +0.010681 +0.010609 +0.010578 +0.010597 +0.010673 +0.010656 +0.010674 +0.01062 +0.010593 +0.010628 +0.010714 +0.010716 +0.010743 +0.010698 +0.010688 +0.01073 +0.01083 +0.010817 +0.010856 +0.001738 +0.010818 +0.010805 +0.010847 +0.010957 +0.010925 +0.010965 +0.010933 +0.010929 +0.010976 +0.011081 +0.01105 +0.011091 +0.011058 +0.011046 +0.011099 +0.011203 +0.011173 +0.011217 +0.011173 +0.011159 +0.011225 +0.011326 +0.011318 +0.011364 +0.011318 +0.011311 +0.011382 +0.011509 +0.011473 +0.011479 +0.011292 +0.01124 +0.011252 +0.011298 +0.011201 +0.011132 +0.011017 +0.010959 +0.01093 +0.010976 +0.010897 +0.010891 +0.010803 +0.010767 +0.0107 +0.010733 +0.01066 +0.010684 +0.010611 +0.010576 +0.010618 +0.010701 +0.010641 +0.010662 +0.010593 +0.010508 +0.010496 +0.010592 +0.010542 +0.010573 +0.010526 +0.0105 +0.010555 +0.01067 +0.010621 +0.010667 +0.010622 +0.010613 +0.010663 +0.010787 +0.010751 +0.010776 +0.010704 +0.001739 +0.010701 +0.010723 +0.010814 +0.010789 +0.010834 +0.0108 +0.010797 +0.010852 +0.010965 +0.010938 +0.010989 +0.010936 +0.010928 +0.010978 +0.011076 +0.01105 +0.011082 +0.011035 +0.011021 +0.011076 +0.011212 +0.0112 +0.011234 +0.011182 +0.011176 +0.011234 +0.011333 +0.01132 +0.011369 +0.01129 +0.011238 +0.011241 +0.011291 +0.011227 +0.011202 +0.011084 +0.011009 +0.010995 +0.011037 +0.010974 +0.010959 +0.010854 +0.010803 +0.010796 +0.010852 +0.010808 +0.010805 +0.010716 +0.010685 +0.010698 +0.010768 +0.010725 +0.010741 +0.010667 +0.010642 +0.010665 +0.010739 +0.010708 +0.010739 +0.01067 +0.010655 +0.010696 +0.010793 +0.010756 +0.010805 +0.010753 +0.010752 +0.010786 +0.010891 +0.010882 +0.010908 +0.00174 +0.010878 +0.010854 +0.010918 +0.011013 +0.010995 +0.01104 +0.010992 +0.01098 +0.011034 +0.011142 +0.011118 +0.011167 +0.011117 +0.011105 +0.011156 +0.011264 +0.011247 +0.011289 +0.011238 +0.01123 +0.011276 +0.0114 +0.011374 +0.011432 +0.011374 +0.011371 +0.011446 +0.011559 +0.011531 +0.011583 +0.011518 +0.011353 +0.011341 +0.011407 +0.011316 +0.011309 +0.011192 +0.011028 +0.011021 +0.011073 +0.011004 +0.010986 +0.010902 +0.01079 +0.01073 +0.010809 +0.010743 +0.010735 +0.010672 +0.010612 +0.010655 +0.010686 +0.010624 +0.010618 +0.010536 +0.01048 +0.010518 +0.010585 +0.010553 +0.010571 +0.010517 +0.010465 +0.010459 +0.010565 +0.010532 +0.010569 +0.010538 +0.01051 +0.010564 +0.010677 +0.010661 +0.010701 +0.010655 +0.010639 +0.010708 +0.010804 +0.001741 +0.010784 +0.010826 +0.010782 +0.010775 +0.010823 +0.010945 +0.010912 +0.010936 +0.010843 +0.010841 +0.0109 +0.010999 +0.010968 +0.011008 +0.010957 +0.010955 +0.010982 +0.011099 +0.011076 +0.011159 +0.011132 +0.011111 +0.011156 +0.011258 +0.011241 +0.011292 +0.011252 +0.011219 +0.011273 +0.011338 +0.011268 +0.011265 +0.011141 +0.011072 +0.011053 +0.011085 +0.011006 +0.010985 +0.010876 +0.010814 +0.010807 +0.010862 +0.010796 +0.010797 +0.010705 +0.01066 +0.01068 +0.010753 +0.010703 +0.010728 +0.01065 +0.010611 +0.010639 +0.010722 +0.010677 +0.010714 +0.01064 +0.010604 +0.010648 +0.010737 +0.010703 +0.010745 +0.010686 +0.010656 +0.010711 +0.010812 +0.010784 +0.010838 +0.010787 +0.010765 +0.010824 +0.001742 +0.010922 +0.010912 +0.010955 +0.010906 +0.010892 +0.010934 +0.011049 +0.011036 +0.011076 +0.011025 +0.011013 +0.011065 +0.011172 +0.011157 +0.011202 +0.011155 +0.011137 +0.011187 +0.011287 +0.011277 +0.011323 +0.011273 +0.011275 +0.011325 +0.011446 +0.011428 +0.011468 +0.011434 +0.011433 +0.011505 +0.011599 +0.011465 +0.011472 +0.011388 +0.011283 +0.011211 +0.011262 +0.011168 +0.011158 +0.011056 +0.010956 +0.010882 +0.010943 +0.010844 +0.010845 +0.010769 +0.010713 +0.010651 +0.010679 +0.010597 +0.010624 +0.010541 +0.010515 +0.010549 +0.01061 +0.010556 +0.010556 +0.010438 +0.010415 +0.010409 +0.010504 +0.010433 +0.010474 +0.010425 +0.010405 +0.010475 +0.010565 +0.010518 +0.010574 +0.010527 +0.010515 +0.010575 +0.010642 +0.010599 +0.010626 +0.010607 +0.001743 +0.010606 +0.010659 +0.010757 +0.010728 +0.010764 +0.010729 +0.010737 +0.010784 +0.010891 +0.010855 +0.010905 +0.01086 +0.010834 +0.010831 +0.010923 +0.01089 +0.010941 +0.010902 +0.010907 +0.011007 +0.011132 +0.011102 +0.011133 +0.011082 +0.011067 +0.011113 +0.011217 +0.011227 +0.011257 +0.011209 +0.011161 +0.011166 +0.011233 +0.011155 +0.011131 +0.011007 +0.010928 +0.010895 +0.010937 +0.010853 +0.010825 +0.01072 +0.010654 +0.010633 +0.010686 +0.010622 +0.010604 +0.010525 +0.010472 +0.010482 +0.010554 +0.010489 +0.010503 +0.010439 +0.010399 +0.010416 +0.0105 +0.010456 +0.010473 +0.01041 +0.010388 +0.010425 +0.010516 +0.010478 +0.010499 +0.010464 +0.010451 +0.010496 +0.010604 +0.01057 +0.010604 +0.010563 +0.010549 +0.010618 +0.001744 +0.010702 +0.010698 +0.010714 +0.010688 +0.010664 +0.010725 +0.010817 +0.010804 +0.010842 +0.010804 +0.010789 +0.010839 +0.010938 +0.010928 +0.010967 +0.010922 +0.010904 +0.010962 +0.01106 +0.011029 +0.011078 +0.011033 +0.011017 +0.011075 +0.011182 +0.011169 +0.011216 +0.011177 +0.011156 +0.011232 +0.011347 +0.011329 +0.011336 +0.011157 +0.011066 +0.011045 +0.011079 +0.010964 +0.010878 +0.010761 +0.010677 +0.010673 +0.010688 +0.010606 +0.010587 +0.010481 +0.010375 +0.010359 +0.01044 +0.010354 +0.010376 +0.010275 +0.010259 +0.010252 +0.010284 +0.010212 +0.010237 +0.010147 +0.010128 +0.010174 +0.010257 +0.010209 +0.010182 +0.010104 +0.010067 +0.010119 +0.010239 +0.010178 +0.010205 +0.01018 +0.010157 +0.010188 +0.010272 +0.010254 +0.010287 +0.010249 +0.010236 +0.010302 +0.010384 +0.010365 +0.001745 +0.010418 +0.010362 +0.01036 +0.010415 +0.01052 +0.010494 +0.010536 +0.010499 +0.010482 +0.010544 +0.010637 +0.010585 +0.010633 +0.010568 +0.010553 +0.010601 +0.010695 +0.010653 +0.010693 +0.01065 +0.010644 +0.01068 +0.010837 +0.010842 +0.010879 +0.01082 +0.0108 +0.01085 +0.010947 +0.010927 +0.010979 +0.010893 +0.010824 +0.010825 +0.01088 +0.010802 +0.010786 +0.010659 +0.010583 +0.01057 +0.010609 +0.010534 +0.010529 +0.010419 +0.010363 +0.010363 +0.010411 +0.010358 +0.010365 +0.01028 +0.010245 +0.010255 +0.010323 +0.010275 +0.010314 +0.010245 +0.0102 +0.010226 +0.0103 +0.010275 +0.010318 +0.010258 +0.010234 +0.010276 +0.010367 +0.010335 +0.010403 +0.010354 +0.010335 +0.010381 +0.01047 +0.010456 +0.001746 +0.01048 +0.010461 +0.010445 +0.010494 +0.010587 +0.01057 +0.010617 +0.010571 +0.010549 +0.010601 +0.010705 +0.010695 +0.010733 +0.010685 +0.010669 +0.010718 +0.010822 +0.010808 +0.010846 +0.010803 +0.010788 +0.010836 +0.010929 +0.010918 +0.010958 +0.010907 +0.0109 +0.010951 +0.011062 +0.011052 +0.011095 +0.011054 +0.011046 +0.011111 +0.01123 +0.011194 +0.011178 +0.011009 +0.010937 +0.010915 +0.01095 +0.010845 +0.010806 +0.010655 +0.010608 +0.010611 +0.010639 +0.010571 +0.01056 +0.010455 +0.010365 +0.010346 +0.010434 +0.010352 +0.010383 +0.010285 +0.010274 +0.010282 +0.010316 +0.010258 +0.010268 +0.010219 +0.010177 +0.010216 +0.010282 +0.010208 +0.010243 +0.010187 +0.010132 +0.010133 +0.010226 +0.010191 +0.010223 +0.010174 +0.010172 +0.01023 +0.010324 +0.010297 +0.010343 +0.010303 +0.010288 +0.010355 +0.010447 +0.010424 +0.001747 +0.010464 +0.010419 +0.010406 +0.010418 +0.010501 +0.010472 +0.010519 +0.010477 +0.010468 +0.010527 +0.010629 +0.010604 +0.010642 +0.010597 +0.010579 +0.010626 +0.010729 +0.010724 +0.010783 +0.010734 +0.010707 +0.010754 +0.010858 +0.010856 +0.010896 +0.010842 +0.010831 +0.01088 +0.010985 +0.010932 +0.010938 +0.010832 +0.010773 +0.01075 +0.010776 +0.010704 +0.010665 +0.010554 +0.010488 +0.01047 +0.01051 +0.010458 +0.010449 +0.010349 +0.010318 +0.010319 +0.010388 +0.010341 +0.010346 +0.010262 +0.01025 +0.010267 +0.010339 +0.010304 +0.01032 +0.010244 +0.010233 +0.010261 +0.010344 +0.010314 +0.010338 +0.01028 +0.010283 +0.010318 +0.010415 +0.010403 +0.010434 +0.01039 +0.010382 +0.010422 +0.010533 +0.001748 +0.010504 +0.010558 +0.010507 +0.010487 +0.010544 +0.010638 +0.010624 +0.010672 +0.010628 +0.010607 +0.010648 +0.010754 +0.010744 +0.01079 +0.010738 +0.010722 +0.010774 +0.010878 +0.01085 +0.010887 +0.010836 +0.010832 +0.010877 +0.010987 +0.010967 +0.011014 +0.010962 +0.010966 +0.011025 +0.011133 +0.011114 +0.011158 +0.011108 +0.011075 +0.011008 +0.010963 +0.010854 +0.010843 +0.010731 +0.010581 +0.010538 +0.010578 +0.010513 +0.010511 +0.010418 +0.010285 +0.010262 +0.010316 +0.010256 +0.010262 +0.010175 +0.010131 +0.010068 +0.010144 +0.010075 +0.01011 +0.010015 +0.009999 +0.010014 +0.010118 +0.010015 +0.010003 +0.00995 +0.009921 +0.009959 +0.010051 +0.01 +0.010039 +0.009994 +0.009953 +0.009966 +0.010075 +0.010043 +0.010091 +0.010042 +0.010035 +0.010093 +0.010193 +0.010173 +0.010206 +0.010173 +0.001749 +0.010153 +0.010208 +0.010308 +0.010283 +0.010328 +0.01029 +0.010273 +0.010327 +0.010428 +0.010396 +0.010437 +0.010392 +0.010375 +0.010417 +0.010509 +0.010459 +0.010497 +0.010456 +0.010435 +0.010488 +0.010582 +0.010591 +0.010669 +0.010635 +0.010608 +0.01065 +0.010744 +0.01072 +0.010753 +0.010698 +0.010691 +0.010707 +0.010758 +0.010665 +0.010644 +0.010532 +0.010452 +0.010416 +0.010452 +0.010381 +0.010354 +0.010249 +0.010197 +0.010184 +0.010229 +0.010179 +0.010169 +0.010081 +0.010037 +0.010048 +0.010103 +0.010065 +0.01008 +0.01001 +0.009976 +0.009984 +0.010058 +0.010029 +0.010049 +0.009988 +0.009963 +0.009983 +0.010068 +0.01005 +0.010086 +0.010034 +0.010025 +0.010061 +0.010156 +0.010132 +0.010175 +0.010159 +0.010105 +0.01017 +0.00175 +0.010263 +0.010242 +0.010284 +0.010248 +0.010232 +0.010271 +0.010379 +0.010358 +0.0104 +0.010357 +0.010343 +0.010391 +0.01049 +0.010473 +0.010512 +0.01047 +0.010456 +0.010503 +0.0106 +0.010577 +0.010626 +0.010575 +0.010561 +0.010621 +0.010715 +0.010694 +0.010736 +0.010698 +0.01068 +0.010754 +0.010858 +0.010827 +0.010882 +0.01084 +0.010853 +0.010857 +0.010835 +0.010749 +0.010756 +0.010656 +0.010597 +0.010546 +0.010516 +0.010427 +0.010427 +0.010358 +0.010281 +0.010222 +0.010268 +0.010182 +0.010202 +0.010127 +0.010064 +0.01004 +0.010058 +0.010017 +0.010029 +0.009974 +0.00993 +0.009943 +0.010029 +0.009959 +0.009928 +0.00985 +0.009814 +0.009863 +0.009929 +0.009881 +0.009927 +0.009872 +0.009846 +0.00984 +0.009921 +0.00988 +0.009922 +0.009888 +0.00989 +0.009928 +0.010021 +0.009996 +0.010051 +0.01001 +0.009999 +0.010049 +0.010147 +0.001751 +0.01011 +0.010156 +0.010121 +0.010114 +0.010163 +0.01024 +0.010197 +0.010243 +0.010204 +0.010195 +0.01023 +0.010309 +0.010266 +0.01031 +0.010272 +0.010247 +0.010298 +0.010401 +0.010421 +0.010479 +0.010436 +0.010415 +0.010461 +0.010555 +0.010523 +0.01057 +0.010509 +0.010519 +0.010573 +0.010678 +0.010615 +0.010621 +0.010547 +0.01047 +0.010449 +0.010501 +0.010414 +0.010387 +0.010284 +0.010216 +0.010196 +0.010241 +0.01018 +0.010166 +0.01008 +0.010027 +0.010029 +0.010087 +0.010019 +0.01003 +0.009959 +0.009925 +0.009933 +0.010008 +0.009953 +0.009967 +0.009903 +0.009869 +0.009892 +0.009977 +0.009922 +0.009932 +0.009892 +0.00987 +0.009908 +0.009999 +0.009968 +0.009988 +0.009947 +0.009943 +0.009989 +0.010096 +0.010062 +0.010121 +0.010037 +0.010034 +0.001752 +0.010085 +0.010186 +0.010176 +0.010206 +0.01017 +0.010139 +0.010202 +0.010296 +0.010283 +0.010315 +0.010279 +0.010254 +0.010312 +0.010402 +0.010393 +0.01042 +0.010379 +0.010365 +0.010417 +0.010505 +0.010499 +0.010525 +0.010492 +0.010461 +0.010527 +0.01062 +0.01061 +0.010647 +0.01061 +0.010592 +0.010655 +0.010761 +0.010755 +0.010793 +0.010741 +0.01071 +0.010647 +0.010634 +0.010563 +0.010562 +0.010467 +0.010385 +0.010278 +0.010289 +0.010244 +0.010233 +0.010158 +0.010103 +0.010117 +0.010142 +0.010059 +0.010028 +0.00996 +0.009898 +0.009923 +0.009966 +0.009932 +0.009941 +0.009905 +0.009857 +0.009874 +0.009902 +0.009876 +0.0099 +0.009872 +0.009837 +0.009899 +0.009984 +0.009957 +0.009998 +0.009959 +0.009932 +0.010007 +0.010088 +0.010043 +0.010091 +0.010055 +0.001753 +0.01002 +0.010038 +0.010144 +0.010114 +0.010161 +0.010116 +0.010105 +0.01016 +0.010262 +0.010242 +0.010283 +0.010242 +0.010225 +0.010266 +0.010364 +0.010338 +0.01038 +0.010339 +0.010339 +0.010389 +0.010489 +0.010461 +0.010504 +0.010464 +0.010447 +0.010498 +0.0106 +0.010583 +0.010624 +0.010573 +0.010553 +0.010589 +0.010649 +0.010569 +0.010558 +0.010433 +0.010357 +0.010334 +0.010353 +0.010269 +0.010249 +0.010134 +0.010065 +0.010059 +0.010088 +0.010013 +0.010003 +0.0099 +0.009843 +0.009853 +0.009907 +0.009841 +0.009855 +0.009772 +0.00973 +0.009748 +0.009818 +0.009754 +0.00978 +0.009705 +0.009664 +0.009694 +0.009775 +0.009737 +0.009771 +0.009714 +0.009691 +0.009733 +0.009827 +0.009803 +0.009849 +0.009798 +0.009787 +0.009822 +0.009929 +0.009911 +0.009943 +0.001754 +0.009902 +0.009888 +0.009932 +0.01003 +0.010015 +0.01005 +0.010006 +0.009995 +0.010039 +0.010139 +0.010114 +0.010158 +0.010111 +0.010095 +0.010138 +0.01024 +0.010221 +0.010261 +0.010218 +0.010207 +0.010251 +0.010364 +0.010328 +0.010385 +0.010335 +0.010334 +0.010397 +0.0105 +0.010461 +0.010515 +0.010417 +0.010374 +0.010387 +0.010445 +0.010347 +0.010332 +0.010186 +0.010072 +0.010031 +0.010072 +0.009986 +0.009972 +0.009896 +0.009839 +0.00977 +0.009794 +0.009711 +0.009728 +0.009657 +0.00961 +0.009635 +0.009654 +0.009585 +0.009601 +0.009546 +0.009469 +0.00948 +0.009543 +0.009494 +0.009534 +0.009476 +0.009474 +0.009507 +0.009588 +0.00955 +0.009579 +0.009564 +0.009527 +0.009513 +0.00961 +0.009574 +0.009617 +0.009587 +0.009583 +0.00963 +0.009722 +0.009705 +0.009761 +0.001755 +0.009718 +0.009713 +0.009762 +0.009845 +0.009837 +0.009866 +0.009837 +0.009822 +0.009882 +0.009974 +0.009955 +0.00997 +0.009934 +0.009917 +0.009943 +0.010011 +0.009972 +0.010003 +0.009973 +0.009947 +0.010006 +0.010103 +0.010125 +0.010174 +0.010136 +0.010099 +0.010158 +0.010234 +0.010215 +0.010247 +0.01019 +0.010129 +0.010127 +0.01016 +0.010098 +0.010076 +0.00997 +0.009895 +0.009893 +0.009921 +0.009864 +0.009861 +0.009756 +0.009691 +0.009698 +0.009735 +0.009688 +0.009687 +0.009612 +0.009554 +0.009575 +0.009628 +0.009589 +0.009601 +0.00954 +0.009492 +0.009516 +0.009575 +0.009552 +0.00958 +0.009514 +0.009488 +0.009526 +0.009595 +0.009585 +0.009619 +0.009579 +0.009561 +0.009601 +0.00968 +0.00968 +0.009723 +0.009661 +0.009651 +0.009707 +0.001756 +0.009786 +0.009777 +0.009805 +0.009785 +0.00975 +0.009804 +0.009884 +0.009886 +0.009913 +0.009882 +0.009855 +0.009913 +0.009988 +0.009989 +0.010015 +0.009985 +0.009957 +0.010012 +0.010097 +0.01009 +0.010112 +0.010075 +0.010054 +0.010118 +0.010191 +0.010194 +0.010217 +0.010192 +0.010163 +0.010241 +0.010316 +0.010318 +0.010351 +0.010321 +0.010303 +0.010384 +0.010426 +0.010329 +0.010306 +0.010242 +0.01016 +0.010103 +0.0101 +0.010033 +0.009996 +0.00994 +0.009866 +0.009828 +0.009831 +0.009783 +0.00976 +0.00972 +0.009657 +0.009664 +0.00965 +0.009595 +0.009603 +0.009558 +0.00951 +0.009562 +0.009571 +0.009541 +0.009542 +0.009496 +0.009434 +0.009448 +0.00952 +0.009485 +0.009513 +0.009492 +0.009462 +0.009533 +0.009609 +0.00959 +0.00962 +0.009599 +0.009558 +0.009637 +0.00973 +0.009688 +0.009717 +0.001757 +0.009707 +0.009679 +0.009746 +0.009828 +0.009798 +0.009793 +0.009757 +0.009733 +0.0098 +0.00988 +0.009864 +0.009892 +0.009862 +0.009843 +0.009905 +0.009985 +0.009955 +0.009983 +0.009955 +0.009926 +0.009984 +0.010065 +0.010054 +0.010113 +0.010091 +0.010062 +0.010114 +0.010194 +0.010187 +0.010203 +0.010191 +0.01016 +0.010217 +0.010272 +0.010228 +0.010222 +0.010138 +0.010052 +0.010063 +0.010079 +0.010016 +0.010002 +0.009917 +0.009832 +0.009858 +0.00989 +0.009843 +0.009826 +0.009763 +0.009697 +0.009732 +0.009776 +0.009744 +0.009759 +0.009713 +0.009661 +0.00971 +0.009743 +0.00972 +0.009744 +0.009701 +0.009654 +0.009704 +0.009762 +0.009734 +0.009749 +0.009729 +0.009697 +0.009762 +0.00983 +0.009814 +0.009837 +0.009796 +0.00977 +0.009843 +0.009932 +0.009914 +0.001758 +0.009938 +0.00991 +0.009884 +0.009947 +0.010032 +0.010024 +0.010041 +0.01001 +0.009978 +0.010054 +0.010138 +0.010128 +0.010147 +0.010122 +0.010096 +0.010166 +0.010242 +0.010233 +0.010256 +0.010231 +0.010195 +0.010256 +0.01035 +0.010332 +0.010373 +0.010334 +0.010313 +0.010389 +0.010468 +0.010467 +0.010503 +0.010471 +0.010457 +0.010493 +0.010469 +0.010401 +0.010391 +0.010321 +0.010241 +0.010256 +0.010195 +0.010118 +0.010095 +0.01002 +0.009963 +0.009937 +0.009947 +0.009905 +0.009885 +0.009838 +0.009767 +0.009783 +0.009792 +0.009762 +0.009749 +0.009721 +0.009649 +0.009693 +0.009726 +0.009685 +0.009706 +0.009665 +0.009598 +0.00962 +0.009679 +0.009681 +0.009696 +0.00967 +0.009647 +0.009703 +0.009782 +0.009774 +0.009807 +0.00978 +0.009761 +0.009818 +0.00989 +0.009882 +0.001759 +0.009916 +0.009882 +0.009862 +0.009927 +0.010018 +0.009977 +0.01 +0.009951 +0.009938 +0.009999 +0.010077 +0.01005 +0.010076 +0.010043 +0.010019 +0.010072 +0.010165 +0.010138 +0.01017 +0.010134 +0.01012 +0.010207 +0.010308 +0.010288 +0.010319 +0.010272 +0.010252 +0.010301 +0.010401 +0.010387 +0.010412 +0.010337 +0.010261 +0.010263 +0.010304 +0.010231 +0.010203 +0.0101 +0.010018 +0.010018 +0.010047 +0.009985 +0.009973 +0.009889 +0.009816 +0.009828 +0.00987 +0.009821 +0.009822 +0.009755 +0.009699 +0.009731 +0.009791 +0.009742 +0.009754 +0.009693 +0.009652 +0.009683 +0.009756 +0.009717 +0.009737 +0.009684 +0.00966 +0.009707 +0.009787 +0.009764 +0.009798 +0.009755 +0.009732 +0.009794 +0.009877 +0.009859 +0.009893 +0.00985 +0.009837 +0.00176 +0.009891 +0.009979 +0.009967 +0.009995 +0.009977 +0.009928 +0.009993 +0.010082 +0.010082 +0.010103 +0.010077 +0.010046 +0.010099 +0.010185 +0.010183 +0.010213 +0.010184 +0.010144 +0.010216 +0.010296 +0.010279 +0.010309 +0.010279 +0.010242 +0.01032 +0.01039 +0.010398 +0.010412 +0.010392 +0.010367 +0.010435 +0.010522 +0.010526 +0.010554 +0.01053 +0.010496 +0.010545 +0.010512 +0.010383 +0.01035 +0.010231 +0.010112 +0.010082 +0.010093 +0.010026 +0.010012 +0.009933 +0.009874 +0.009827 +0.009831 +0.009789 +0.00978 +0.009718 +0.009657 +0.009707 +0.009752 +0.009735 +0.009663 +0.009598 +0.00954 +0.009581 +0.00966 +0.009619 +0.009624 +0.009565 +0.009491 +0.009534 +0.009597 +0.009573 +0.009607 +0.009575 +0.009541 +0.009601 +0.009692 +0.009674 +0.009696 +0.009674 +0.009656 +0.009716 +0.009794 +0.009762 +0.001761 +0.009802 +0.009761 +0.009726 +0.009764 +0.009846 +0.009819 +0.009865 +0.009836 +0.009822 +0.00988 +0.009963 +0.009951 +0.009987 +0.009944 +0.009929 +0.009986 +0.010073 +0.010046 +0.010079 +0.010037 +0.010016 +0.010068 +0.010155 +0.010145 +0.010175 +0.010165 +0.01014 +0.010188 +0.010284 +0.01027 +0.010311 +0.010266 +0.010244 +0.010283 +0.010333 +0.010272 +0.010245 +0.010135 +0.010061 +0.01004 +0.010058 +0.009989 +0.009964 +0.009871 +0.009791 +0.009803 +0.009833 +0.00978 +0.009776 +0.009683 +0.009637 +0.009652 +0.00971 +0.009682 +0.00968 +0.009623 +0.009585 +0.00961 +0.009671 +0.009652 +0.009663 +0.009605 +0.009575 +0.009607 +0.00968 +0.009675 +0.009694 +0.009651 +0.009627 +0.009668 +0.009752 +0.009753 +0.009778 +0.00974 +0.009725 +0.009767 +0.009851 +0.001762 +0.009852 +0.00988 +0.009844 +0.009821 +0.00988 +0.009955 +0.009956 +0.009986 +0.009962 +0.009916 +0.009982 +0.010068 +0.010063 +0.01009 +0.01006 +0.010029 +0.010086 +0.010169 +0.010166 +0.010196 +0.010159 +0.010129 +0.010195 +0.010277 +0.010273 +0.010299 +0.010264 +0.010242 +0.010307 +0.010392 +0.010393 +0.010426 +0.010404 +0.010378 +0.010457 +0.010541 +0.010465 +0.010341 +0.010272 +0.010177 +0.010169 +0.010124 +0.010032 +0.01003 +0.009924 +0.009824 +0.009818 +0.00985 +0.009807 +0.009796 +0.009734 +0.009606 +0.009624 +0.009657 +0.009636 +0.009626 +0.009585 +0.009521 +0.009528 +0.009557 +0.009522 +0.009543 +0.009495 +0.009451 +0.009434 +0.009473 +0.009461 +0.009483 +0.009449 +0.009428 +0.009474 +0.009545 +0.009536 +0.009555 +0.009529 +0.009513 +0.009583 +0.009657 +0.009632 +0.009635 +0.009596 +0.009565 +0.001763 +0.009628 +0.009721 +0.009695 +0.009722 +0.009695 +0.009678 +0.00974 +0.009826 +0.009809 +0.009847 +0.009797 +0.009785 +0.009846 +0.009927 +0.009903 +0.009929 +0.009889 +0.009867 +0.009916 +0.010003 +0.009974 +0.010001 +0.009971 +0.00995 +0.010034 +0.010131 +0.010124 +0.010147 +0.01011 +0.01009 +0.010134 +0.010241 +0.010213 +0.010222 +0.010145 +0.010059 +0.01004 +0.010075 +0.009995 +0.009958 +0.009849 +0.009778 +0.009764 +0.009812 +0.009757 +0.009733 +0.009662 +0.009598 +0.009607 +0.009664 +0.009613 +0.009616 +0.009562 +0.00951 +0.009529 +0.009601 +0.009567 +0.009569 +0.009524 +0.00948 +0.009505 +0.009581 +0.009542 +0.009558 +0.00952 +0.009487 +0.009528 +0.009607 +0.009588 +0.009611 +0.009587 +0.009561 +0.009603 +0.009696 +0.009684 +0.009731 +0.009666 +0.009655 +0.001764 +0.009713 +0.009801 +0.009786 +0.009813 +0.009791 +0.009758 +0.009816 +0.009899 +0.009896 +0.009916 +0.009892 +0.009862 +0.009922 +0.010004 +0.01 +0.010022 +0.00999 +0.009966 +0.010027 +0.010095 +0.010101 +0.010116 +0.010091 +0.010062 +0.01013 +0.010209 +0.010212 +0.010238 +0.010205 +0.010187 +0.010268 +0.010354 +0.010345 +0.010374 +0.010287 +0.010148 +0.010158 +0.010196 +0.010121 +0.010048 +0.009893 +0.009826 +0.009842 +0.009868 +0.009812 +0.009775 +0.009691 +0.009615 +0.009635 +0.009661 +0.009621 +0.009601 +0.009582 +0.009518 +0.009527 +0.009545 +0.0095 +0.009526 +0.00947 +0.009441 +0.009489 +0.009539 +0.00951 +0.009477 +0.009424 +0.009391 +0.009464 +0.009529 +0.009499 +0.009528 +0.00951 +0.009476 +0.009549 +0.009634 +0.009605 +0.009628 +0.00961 +0.009585 +0.009646 +0.001765 +0.009713 +0.009704 +0.009726 +0.009705 +0.00966 +0.009706 +0.009782 +0.009766 +0.009792 +0.009768 +0.009747 +0.009809 +0.009888 +0.009883 +0.009904 +0.009875 +0.009848 +0.009907 +0.009984 +0.009975 +0.009996 +0.009982 +0.009966 +0.010028 +0.01011 +0.010098 +0.010115 +0.010095 +0.010067 +0.010138 +0.010208 +0.010213 +0.010234 +0.0102 +0.010146 +0.010164 +0.010206 +0.010142 +0.010094 +0.01001 +0.009919 +0.009913 +0.009939 +0.00989 +0.009855 +0.009787 +0.009715 +0.009726 +0.009766 +0.009724 +0.009702 +0.009642 +0.009585 +0.009611 +0.009668 +0.009638 +0.009636 +0.009587 +0.009542 +0.009569 +0.009633 +0.009608 +0.009598 +0.009567 +0.009525 +0.009563 +0.009635 +0.009615 +0.009616 +0.009594 +0.00957 +0.009629 +0.009698 +0.009693 +0.009704 +0.009679 +0.00964 +0.009715 +0.009801 +0.009786 +0.001766 +0.009807 +0.009786 +0.009755 +0.009817 +0.009897 +0.009892 +0.009915 +0.00989 +0.009861 +0.009915 +0.009999 +0.010002 +0.010022 +0.009992 +0.009964 +0.010024 +0.010106 +0.010093 +0.010123 +0.010098 +0.010066 +0.010125 +0.010215 +0.010197 +0.01023 +0.010201 +0.010172 +0.010251 +0.010331 +0.010332 +0.010352 +0.010337 +0.010321 +0.010382 +0.010356 +0.01028 +0.010264 +0.010193 +0.01008 +0.010021 +0.010037 +0.009976 +0.009971 +0.009897 +0.00983 +0.009866 +0.009877 +0.009775 +0.00977 +0.009712 +0.009613 +0.009635 +0.00968 +0.009651 +0.009646 +0.009608 +0.009548 +0.009611 +0.009669 +0.009636 +0.009593 +0.009527 +0.00951 +0.009562 +0.009621 +0.009618 +0.009626 +0.009602 +0.009584 +0.009638 +0.009724 +0.009709 +0.009707 +0.009675 +0.009664 +0.009701 +0.009788 +0.009767 +0.001767 +0.009802 +0.00977 +0.009749 +0.009811 +0.009906 +0.009881 +0.009916 +0.009878 +0.009865 +0.009921 +0.010009 +0.009984 +0.010011 +0.009984 +0.009959 +0.009999 +0.010074 +0.010032 +0.010062 +0.010035 +0.010016 +0.010068 +0.010159 +0.010184 +0.010233 +0.010195 +0.010171 +0.010221 +0.010303 +0.010289 +0.010305 +0.010278 +0.010255 +0.010268 +0.010312 +0.010226 +0.010203 +0.010096 +0.009999 +0.009982 +0.010015 +0.00995 +0.009919 +0.009842 +0.009766 +0.00977 +0.009815 +0.009765 +0.009757 +0.00969 +0.009637 +0.009654 +0.009718 +0.009674 +0.009678 +0.009627 +0.009586 +0.00961 +0.009682 +0.009648 +0.009657 +0.009622 +0.009577 +0.009618 +0.009699 +0.009674 +0.009688 +0.009666 +0.009642 +0.009689 +0.009786 +0.009758 +0.009785 +0.009754 +0.009721 +0.009789 +0.001768 +0.009881 +0.009864 +0.009889 +0.009846 +0.009837 +0.009882 +0.009982 +0.009964 +0.009998 +0.009956 +0.009946 +0.009991 +0.010083 +0.010067 +0.010112 +0.010065 +0.010051 +0.010095 +0.010198 +0.010167 +0.010203 +0.010158 +0.010145 +0.010192 +0.010293 +0.010267 +0.010317 +0.010265 +0.010265 +0.010318 +0.010421 +0.010401 +0.010448 +0.010407 +0.010404 +0.010454 +0.010455 +0.010348 +0.010334 +0.010238 +0.010136 +0.010058 +0.010089 +0.010003 +0.009995 +0.009918 +0.009856 +0.009866 +0.009857 +0.009777 +0.00979 +0.009713 +0.009678 +0.009655 +0.009703 +0.009639 +0.009656 +0.009598 +0.009563 +0.009609 +0.009674 +0.009618 +0.009585 +0.009523 +0.009526 +0.009545 +0.009617 +0.009583 +0.009611 +0.009564 +0.009562 +0.009611 +0.009675 +0.009631 +0.009685 +0.00964 +0.009634 +0.009683 +0.009789 +0.009756 +0.00979 +0.001769 +0.009754 +0.009736 +0.009803 +0.009892 +0.00987 +0.009898 +0.009872 +0.009852 +0.009895 +0.009968 +0.009936 +0.009971 +0.009941 +0.009921 +0.009972 +0.010052 +0.010029 +0.010058 +0.010025 +0.010005 +0.010046 +0.010146 +0.010152 +0.010209 +0.010179 +0.01014 +0.010191 +0.010282 +0.010262 +0.010285 +0.010263 +0.010245 +0.010264 +0.010308 +0.010239 +0.010197 +0.010099 +0.010025 +0.009996 +0.010025 +0.009967 +0.009929 +0.009845 +0.009785 +0.009776 +0.009823 +0.009763 +0.009755 +0.00968 +0.009623 +0.009639 +0.009699 +0.009655 +0.009653 +0.009598 +0.009563 +0.009583 +0.009648 +0.009619 +0.009623 +0.009574 +0.009547 +0.009579 +0.009653 +0.009626 +0.00964 +0.009604 +0.009595 +0.00964 +0.009726 +0.009709 +0.00973 +0.009696 +0.009673 +0.009728 +0.009829 +0.00177 +0.009806 +0.009835 +0.009801 +0.009783 +0.009836 +0.009931 +0.009905 +0.009942 +0.009904 +0.009895 +0.009938 +0.010044 +0.010009 +0.010053 +0.010011 +0.009996 +0.010043 +0.010145 +0.010115 +0.010148 +0.010115 +0.010099 +0.010145 +0.010251 +0.010222 +0.010267 +0.010228 +0.01021 +0.01027 +0.01038 +0.010358 +0.010403 +0.010363 +0.010351 +0.010312 +0.010298 +0.010216 +0.010219 +0.010125 +0.010066 +0.009958 +0.00998 +0.009902 +0.009917 +0.009841 +0.0098 +0.009818 +0.009884 +0.009802 +0.009748 +0.009635 +0.009616 +0.009626 +0.009709 +0.009624 +0.009654 +0.009582 +0.009517 +0.009528 +0.009584 +0.009552 +0.009569 +0.009513 +0.009507 +0.009552 +0.00963 +0.009609 +0.009636 +0.00959 +0.009594 +0.009606 +0.009663 +0.009636 +0.009687 +0.009635 +0.009643 +0.009693 +0.009779 +0.001771 +0.009756 +0.009796 +0.009766 +0.009751 +0.009802 +0.009905 +0.009869 +0.009912 +0.009876 +0.00986 +0.009918 +0.010011 +0.009977 +0.010007 +0.009968 +0.009942 +0.009959 +0.01004 +0.010012 +0.010047 +0.010012 +0.00999 +0.010057 +0.010189 +0.010186 +0.010209 +0.010165 +0.010149 +0.01019 +0.010279 +0.010272 +0.010313 +0.010262 +0.010198 +0.010202 +0.010226 +0.010167 +0.010132 +0.01003 +0.009942 +0.009945 +0.009969 +0.009915 +0.0099 +0.009818 +0.009749 +0.009764 +0.009807 +0.009765 +0.009771 +0.009702 +0.009645 +0.009672 +0.009736 +0.009707 +0.009729 +0.009668 +0.009627 +0.009646 +0.009717 +0.009693 +0.009715 +0.009662 +0.00962 +0.009663 +0.009725 +0.009706 +0.00975 +0.009708 +0.009678 +0.009729 +0.009809 +0.009784 +0.009823 +0.009785 +0.009784 +0.009824 +0.001772 +0.009924 +0.009889 +0.009925 +0.009881 +0.009882 +0.009934 +0.010027 +0.009996 +0.010032 +0.009988 +0.009979 +0.01003 +0.01013 +0.010107 +0.010138 +0.010102 +0.010089 +0.010141 +0.010239 +0.010211 +0.010243 +0.0102 +0.010188 +0.010233 +0.01033 +0.010314 +0.010344 +0.010308 +0.010289 +0.010349 +0.010453 +0.010432 +0.01048 +0.010437 +0.010429 +0.010495 +0.010604 +0.010554 +0.01051 +0.010349 +0.010284 +0.010281 +0.010281 +0.010182 +0.010187 +0.010047 +0.00997 +0.009971 +0.010011 +0.009941 +0.009966 +0.009871 +0.00984 +0.009794 +0.009855 +0.009792 +0.00983 +0.00974 +0.00973 +0.009749 +0.009842 +0.009791 +0.009801 +0.009701 +0.009651 +0.009693 +0.00977 +0.009714 +0.009759 +0.009693 +0.009667 +0.009713 +0.009768 +0.009721 +0.009758 +0.009715 +0.009693 +0.009742 +0.009843 +0.00981 +0.00985 +0.009805 +0.00979 +0.009792 +0.009893 +0.009865 +0.009909 +0.001773 +0.009875 +0.009866 +0.009921 +0.010009 +0.009993 +0.010023 +0.009991 +0.009971 +0.010027 +0.010116 +0.010105 +0.010122 +0.010094 +0.010073 +0.010141 +0.010238 +0.010225 +0.010254 +0.01022 +0.0102 +0.010263 +0.010339 +0.010333 +0.01036 +0.010318 +0.010295 +0.010365 +0.010441 +0.010441 +0.010469 +0.010442 +0.010408 +0.010469 +0.010563 +0.010553 +0.010589 +0.010553 +0.010529 +0.010583 +0.010682 +0.010673 +0.010711 +0.010672 +0.010646 +0.010705 +0.010802 +0.010796 +0.01083 +0.010786 +0.010765 +0.010827 +0.010925 +0.010914 +0.010953 +0.010906 +0.010882 +0.010941 +0.011042 +0.011042 +0.011072 +0.011032 +0.011007 +0.011063 +0.011167 +0.011157 +0.011195 +0.011153 +0.01113 +0.011188 +0.011286 +0.011276 +0.011315 +0.011275 +0.011247 +0.011303 +0.01141 +0.011406 +0.011438 +0.011397 +0.011374 +0.011438 +0.011534 +0.011519 +0.011563 +0.011522 +0.0115 +0.011558 +0.011663 +0.011653 +0.011691 +0.011651 +0.011629 +0.011688 +0.011791 +0.011784 +0.011828 +0.011779 +0.011753 +0.011818 +0.011922 +0.011913 +0.011954 +0.011906 +0.011882 +0.011947 +0.012049 +0.012045 +0.01208 +0.012041 +0.01202 +0.012078 +0.012179 +0.012165 +0.012227 +0.012185 +0.012156 +0.012219 +0.012316 +0.012291 +0.012328 +0.012293 +0.012281 +0.012349 +0.012448 +0.01244 +0.012491 +0.012442 +0.012421 +0.012475 +0.012587 +0.012568 +0.012618 +0.012581 +0.012552 +0.012614 +0.012725 +0.01272 +0.012766 +0.01272 +0.012698 +0.012765 +0.012869 +0.012849 +0.012892 +0.012869 +0.012847 +0.012913 +0.01302 +0.012997 +0.013042 +0.012977 +0.01296 +0.013049 +0.01316 +0.013151 +0.013197 +0.013148 +0.013126 +0.01319 +0.013301 +0.013307 +0.013346 +0.013295 +0.013267 +0.013341 +0.013457 +0.013459 +0.013494 +0.013449 +0.013426 +0.013496 +0.013613 +0.013605 +0.013655 +0.013605 +0.013575 +0.013654 +0.013772 +0.013772 +0.013809 +0.013764 +0.013738 +0.013817 +0.013934 +0.013929 +0.013974 +0.013925 +0.013901 +0.013971 +0.014099 +0.014091 +0.014139 +0.014093 +0.014068 +0.014141 +0.014265 +0.014255 +0.014311 +0.014258 +0.014232 +0.014306 +0.014437 +0.014438 +0.01448 +0.014432 +0.014408 +0.01448 +0.014612 +0.014613 +0.014658 +0.014601 +0.014582 +0.014659 +0.014788 +0.014786 +0.014833 +0.014783 +0.014765 +0.014832 +0.014968 +0.014967 +0.015015 +0.014962 +0.01494 +0.015022 +0.015152 +0.015148 +0.015204 +0.01515 +0.015118 +0.015204 +0.015342 +0.015348 +0.015397 +0.015334 +0.015298 +0.015394 +0.015537 +0.015534 +0.015581 +0.015535 +0.015507 +0.015604 +0.015731 +0.015702 +0.015799 +0.015751 +0.015715 +0.015785 +0.01592 +0.015903 +0.015952 +0.015914 +0.015909 +0.015996 +0.016143 +0.016113 +0.016167 +0.016126 +0.016112 +0.016198 +0.016343 +0.016324 +0.016398 +0.016347 +0.016314 +0.01641 +0.016562 +0.016563 +0.016613 +0.01657 +0.01654 +0.016636 +0.016786 +0.016801 +0.016838 +0.016791 +0.016769 +0.01686 +0.017019 +0.017039 +0.017067 +0.017017 +0.017 +0.017097 +0.017253 +0.01726 +0.017305 +0.017265 +0.017237 +0.017333 +0.017491 +0.017491 +0.017553 +0.017505 +0.017479 +0.017576 +0.017737 +0.017745 +0.017801 +0.01775 +0.017731 +0.017822 +0.017996 +0.018011 +0.018057 +0.018006 +0.017975 +0.018092 +0.018255 +0.018265 +0.018326 +0.018268 +0.018247 +0.018358 +0.018525 +0.018542 +0.018593 +0.018545 +0.018526 +0.01863 +0.018797 +0.018814 +0.018876 +0.018821 +0.018801 +0.018907 +0.019093 +0.0191 +0.019161 +0.019111 +0.01909 +0.019194 +0.019391 +0.019401 +0.019458 +0.019411 +0.019386 +0.019498 +0.019688 +0.019704 +0.019759 +0.019717 +0.019695 +0.019805 +0.019997 +0.020016 +0.020084 +0.020023 +0.020007 +0.02013 +0.020323 +0.020343 +0.020401 +0.020356 +0.020337 +0.020456 +0.020663 +0.02068 +0.02074 +0.0207 +0.020681 +0.020797 +0.021018 +0.021031 +0.021096 +0.021054 +0.021031 +0.02116 +0.021374 +0.021389 +0.021462 +0.021421 +0.021401 +0.021524 +0.021755 +0.02177 +0.021844 +0.021795 +0.02178 +0.021908 +0.022141 +0.022154 +0.022229 +0.022195 +0.022164 +0.022311 +0.022537 +0.022557 +0.022633 +0.022602 +0.022578 +0.02272 +0.022955 +0.022978 +0.023059 +0.023023 +0.023009 +0.023147 +0.023395 +0.02342 +0.023503 +0.023469 +0.023462 +0.023582 +0.023854 +0.023884 +0.023963 +0.023924 +0.023916 +0.024064 +0.024328 +0.024356 +0.024448 +0.024404 +0.0244 +0.024549 +0.024818 +0.024851 +0.024932 +0.024909 +0.024892 +0.025048 +0.025331 +0.025357 +0.025459 +0.025432 +0.025407 +0.025589 +0.025868 +0.025907 +0.025998 +0.025981 +0.025959 +0.026138 +0.026439 +0.026467 +0.026578 +0.026561 +0.026542 +0.02674 +0.02704 +0.027076 +0.027195 +0.027179 +0.027165 +0.027364 +0.027672 +0.027707 +0.027852 +0.027828 +0.02781 +0.028027 +0.028345 +0.028389 +0.028542 +0.028506 +0.028513 +0.028723 +0.029061 +0.029101 +0.029254 +0.029242 +0.029235 +0.02946 +0.029814 +0.029863 +0.030018 +0.030004 +0.030007 +0.030246 +0.030602 +0.030669 +0.03082 +0.030821 +0.030825 +0.031063 +0.031449 +0.031506 +0.031692 +0.031677 +0.031699 +0.031943 +0.032357 +0.032419 +0.03263 +0.032608 +0.032633 +0.032917 +0.033333 +0.033402 +0.033624 +0.033613 +0.033653 +0.033939 +0.03438 +0.034456 +0.034694 +0.034698 +0.034743 +0.03506 +0.035529 +0.035628 +0.035886 +0.035889 +0.035965 +0.036281 +0.036777 +0.036885 +0.037155 +0.037183 +0.037266 +0.037604 +0.038141 +0.038268 +0.038567 +0.038608 +0.0387 +0.039069 +0.039635 +0.039783 +0.040101 +0.040156 +0.040277 +0.040682 +0.041283 +0.041449 +0.041805 +0.04189 +0.042042 +0.042487 +0.043149 +0.043353 +0.043739 +0.043866 +0.044044 +0.044538 +0.045256 +0.045492 +0.04594 +0.046103 +0.046325 +0.046871 +0.047662 +0.047974 +0.048479 +0.048691 +0.048949 +0.049568 +0.050457 +0.050809 +0.0514 +0.051652 +0.051999 +0.052723 +0.053732 +0.054176 +0.054868 +0.055225 +0.055661 +0.056491 +0.057681 +0.058216 +0.059047 +0.059524 +0.060083 +0.061131 +0.062503 +0.063209 +0.064266 +0.064933 +0.065745 +0.067031 +0.06873 +0.069725 +0.071125 +0.07213 +0.073235 +0.074925 +0.077147 +0.078644 +0.080534 +0.08211 +0.083851 +0.086295 +0.08947 +0.091876 +0.094896 +0.097779 +0.101029 +0.105254 +0.110713 +0.115556 +0.121719 +0.128541 +0.136379 +0.1467 +0.161612 +0.178818 +0.204237 +0.247271 +0.336884 diff --git a/rollup.config.js b/rollup.config.js index c083573d9c..71d326d5ff 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,9 +1,13 @@ +/* + Open Rowing Monitor, https://github.com/JaapvanEkris/openrowingmonitor +*/ + // Import rollup plugins -import html from '@web/rollup-plugin-html' +import { rollupPluginHTML as html } from "@web/rollup-plugin-html" import resolve from '@rollup/plugin-node-resolve' import commonjs from '@rollup/plugin-commonjs' import { babel } from '@rollup/plugin-babel' -import { terser } from 'rollup-plugin-terser' +import terser from '@rollup/plugin-terser' import summary from 'rollup-plugin-summary' // Configure an instance of @web/rollup-plugin-html diff --git a/snowpack.config.js b/snowpack.config.js deleted file mode 100644 index 83b32bb376..0000000000 --- a/snowpack.config.js +++ /dev/null @@ -1,63 +0,0 @@ -// Snowpack Configuration File -// See all supported options: https://www.snowpack.dev/reference/configuration -import proxy from 'http2-proxy' -import { nodeResolve } from '@rollup/plugin-node-resolve' - -export default { - mount: { - // the web frontend is located in this directory - './app/client': { url: '/' } - }, - plugins: ['@snowpack/plugin-babel'], - mode: 'development', - packageOptions: { - rollup: { - plugins: [ - // todo: related to the lit documentation this should enable development mode - // unfortunately this currently does not seem to work - nodeResolve({ - exportConditions: ['development'], - dedupe: true - }) - ] - } - }, - devOptions: { - open: 'none', - output: 'stream' - }, - buildOptions: { - out: 'build' - }, - optimize: { - bundle: true, - treeshake: true, - minify: false, - target: 'es2020', - sourcemap: false - }, - // add a proxy for websocket requests for the dev setting - routes: [ - { - src: '/websocket', - upgrade: (req, socket, head) => { - const defaultWSHandler = (err, req, socket, head) => { - if (err) { - socket.destroy() - } - } - - proxy.ws( - req, - socket, - head, - { - hostname: 'localhost', - port: 80 - }, - defaultWSHandler - ) - } - } - ] -}