diff --git a/CLAUDE.md b/CLAUDE.md index a4658b3..534984e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -109,6 +109,7 @@ src/ │ ├── megasquirt.rs # MegaSquirt (MS1/MS2/MS3) TunerStudio CSV parser │ ├── mhd.rs # MHD Tuning CSV parser (BMW N54/N55/S55/B58) │ ├── motorsport_electronics.rs # Motorsport Electronics ME221/ME442 (ME Tuner) CSV parser +│ ├── racechrono.rs # RaceChrono CSV v3 session export parser (GPS + sensors + OBD/CAN) │ ├── bluedriver.rs # BlueDriver OBD-II scan tool CSV parser │ └── dynamicefi.rs # DynamicEFI EBL WhatsUp (GM TBI) CSV parser └── ui/ @@ -291,6 +292,7 @@ The parser system uses a trait-based design for supporting multiple ECU formats: - **`parsers/megasquirt.rs`** - MegaSquirt (MS1/MS2/MS3/MS3Pro) TunerStudio CSV parser - **`parsers/mhd.rs`** - MHD Tuning CSV parser (BMW N54/N55/S55/B58 flashed with MHD) - **`parsers/motorsport_electronics.rs`** - Motorsport Electronics ME221/ME442 (ME Tuner) CSV parser +- **`parsers/racechrono.rs`** - RaceChrono CSV v3 session export parser (lap-timing app; GPS + phone sensors + OBD/CAN merged on a unix-time base) - **`parsers/bluedriver.rs`** - BlueDriver OBD-II scan tool CSV parser (UTF-16 with BOM) - **`parsers/dynamicefi.rs`** - DynamicEFI EBL WhatsUp CSV parser (modified GM TBI systems) @@ -309,6 +311,7 @@ Note: `EcuType` also reserves `Aem`, `MaxxEcu`, and `MotEc` variants for formats - MegaSquirt MS1/MS2/MS3 (TunerStudio CSV export) - MHD Tuning (CSV export — BMW N54/N55/S55/B58) - Motorsport Electronics ME221/ME442 (ME Tuner CSV export) +- RaceChrono / RaceChrono Pro (CSV v3 session export — lap-timing app) - Woolich Racing Tuned (WRT CSV export — motorcycle ECUs) - BlueDriver (OBD-II scan tool CSV export) - DynamicEFI EBL WhatsUp (modified GM TBI CSV export) @@ -346,6 +349,12 @@ because it also leads with a `Time` column, and only matches a first column of e **Load-bearing invariant:** a parser whose own fingerprint lives inside that comment preamble must run its `detect()` against the **raw** text, before the strip. `Mhd::detect` is the current case, which is why it is dispatched ahead of `dispatch_text_content` rather than inside the chain. Anything added to the chain itself sees comment-stripped content. +**RaceChrono parser load-bearing behaviors** (`src/parsers/racechrono.rs`): + +- **Time base is the unix `timestamp` column, never `elapsed_time`** - `elapsed_time` resets to zero at every fragment boundary (a fragment is one recording segment; sessions paused/resumed at the track have several), so re-basing `timestamp` to the first record is the only way to get a monotonic time axis. Monotonic times are required because computed-channel time-shift lookups binary-search the `times` vector. +- **Duplicate column names are disambiguated by source, unique names stay raw** - RaceChrono exports the same column name once per source (`speed` from GPS and calc, `device_update_rate` from every sensor). Duplicates get the sources-row label appended (`speed (gps)`); unique names — including `latitude`/`longitude` — must stay exactly as exported because `find_gps_channels` in `src/ui/widgets/track_map.rs` matches those names *exactly* (lowercased), and a suffix would silently disable the GPS Track Map for RaceChrono logs. When the short labels themselves collide (two location devices both labeled `gps`), the first occurrence keeps its bare name — so `latitude` still survives — and later ones carry the full source tag (`latitude (101: gps)`). +- **Detection accepts any `Format,N` version; `parse` rejects non-v3** - so a v1/v2 export surfaces a clear "re-export as CSV v3" error instead of falling through to the Haltech default parser and failing cryptically. + **Haltech parser load-bearing behaviors** (`src/parsers/haltech.rs`, added for wall-clock-timestamped exports): - **Last-known-value substitution** - Unparseable/blank fields are filled with the last successfully parsed value for that column (`0.0` before the first valid sample), matching the approach used in `parsers/ecumaster.rs`. This preserves column alignment instead of shifting subsequent columns when a field fails to parse. @@ -408,7 +417,7 @@ The Track Map widget can draw map tile backgrounds. Tiles are **opt-in** (off by ## Key Features -- **Multi-ECU Support** - Haltech, ECUMaster, RomRaider, Speeduino, rusEFI, AiM, Link, Emerald, MegaSquirt, MHD Tuning, Motorsport Electronics, Woolich Racing Tuned, BlueDriver, DynamicEFI, and Locomotive log formats +- **Multi-ECU Support** - Haltech, ECUMaster, RomRaider, Speeduino, rusEFI, AiM, Link, Emerald, MegaSquirt, MHD Tuning, Motorsport Electronics, RaceChrono, Woolich Racing Tuned, BlueDriver, DynamicEFI, and Locomotive log formats - **Computed Channels** - Create virtual channels from mathematical formulas with time-shifting (e.g., `RPM[-1]`, `Boost@-0.5s`) - **Analysis Algorithms** - AFR/Lambda drift and zone detection, derived metrics (VE, injector duty cycle), signal filters, and descriptive statistics (`src/analysis/`) - **GPS Track Map** - Right-side data panel with a track map: lap detection, channel-colored polyline (Viridis/Turbo with editable range), hover-scrub/click-seek cursor sync, and opt-in Esri/OSM tile backgrounds (`src/ui/widgets/track_map.rs`, `src/tiles.rs`, `src/laps.rs`). GPS coordinate encodings are auto-detected and normalized to decimal degrees (`GpsCoordSpec` in `src/laps.rs`): NMEA `DDMM.mmmm`, milli/micro/1e-7-scaled integer degrees, and 0-360 longitude. Detection is conservative - values already in valid degree ranges are never transformed, and radians are deliberately not detected (ambiguous with genuine near-equator degree tracks). @@ -491,6 +500,7 @@ Example log files are in `exampleLogs/` organized by ECU type: - `exampleLogs/megasquirt/` - MegaSquirt TunerStudio CSV exports, plus a `_gps.mlg` fixture with synthetic GPS channels (generated by `examples/inject_fake_gps_mlg.rs`; the coordinates are a fake closed loop, not a real location) - `exampleLogs/mhd/` - MHD Tuning CSV exports (VIN redacted) - `exampleLogs/motorsportElectronics/` - Motorsport Electronics ME Tuner CSV exports +- `exampleLogs/racechrono/` - RaceChrono CSV v3 session excerpt (user-contributed track session, trimmed; covers blank-heavy pit-lane rows, the genuine fragment 0->1 boundary where `elapsed_time` resets, and fully-populated on-track rows) - `exampleLogs/bluedriver/` - BlueDriver OBD-II CSV exports - `exampleLogs/obdlink/` - OBDLink (iOS) OBD-II CSV exports (parsed by the RomRaider chain) - `exampleLogs/dynamicEFI/` - DynamicEFI EBL WhatsUp CSV exports diff --git a/Cargo.lock b/Cargo.lock index 201a658..ea003e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4578,7 +4578,7 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "ultralog" -version = "2.13.0" +version = "2.13.1" dependencies = [ "anyhow", "arboard", diff --git a/Cargo.toml b/Cargo.toml index 31331f6..080e4dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ultralog" -version = "2.13.0" +version = "2.13.1" edition = "2024" # egui/eframe 0.36 is the binding constraint on the minimum supported Rust # version; edition 2024 itself only needs 1.85. diff --git a/README.md b/README.md index 81992c4..f63e448 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A high-performance, cross-platform ECU log viewer written in Rust. ![CI](https://github.com/ClassicMiniDIY/UltraLog/actions/workflows/ci.yml/badge.svg) ![License](https://img.shields.io/badge/license-AGPL--3.0-blue.svg) -![Version](https://img.shields.io/badge/version-2.10.1-green.svg) +![Version](https://img.shields.io/badge/version-2.13.1-green.svg) --- @@ -165,6 +165,32 @@ Configurable units for 8 measurement categories: - **Supported devices:** BMW N54, N55, S55, B58 and other platforms flashed with MHD - **Supported data:** Boost and boost target, wastegate duty, RPM, coolant and intake temps, per-cylinder timing correction, lambda/AFR per bank, fuel rail pressure, load, gear, torque, and all logged channels +### Motorsport Electronics - Full Support + +- **File type:** CSV exports from the ME Tuner software (ME221/ME442 ECUs) +- **Features:** Unit inference from channel names, seconds-based `Time` column detected ahead of RomRaider's millisecond convention so timestamps scale correctly +- **Supported devices:** ME221 and ME442 — common on turbo/supercharged MX-5s, Ford Focus ST150, Honda S2000, Toyota Starlet, and Mitsubishi Evo builds +- **Supported data:** RPM, MAP, TPS, sync status, and all channels logged by ME Tuner + +### DynamicEFI EBL WhatsUp - Full Support + +- **File type:** CSV exports from DynamicEFI's EBL WhatsUp software (modified GM TBI systems) +- **Features:** `HH:MM:SS` RUNTIME timestamp handling at 1-second resolution, Y/N flag and P/N gear-indicator mapping to numeric values, trailing-comma handling +- **Supported data:** BLM, BPC, INT, and the other GM TBI channel abbreviations, plus all logged channels + +### Locomotive Datalogger - Full Support + +- **File type:** CSV exports with a `TimeStamp:` / `Customer:` / `UnitNumber:` metadata header +- **Features:** Wall-clock timestamp parsing from day-of-week-prefixed data rows, metadata capture (customer, unit number, software part number and version) +- **Supported data:** All channels recorded by the datalogger + +### RaceChrono - Full Support + +- **File type:** CSV v3 session exports from the RaceChrono / RaceChrono Pro lap-timing app (Android/iOS) +- **Features:** GPS, phone-sensor, and OBD/CAN channels merged on a unix-time base; duplicate column names disambiguated by source (`speed (gps)` vs `speed (calc)`); paused-and-resumed multi-fragment sessions; `.C` temperature notation normalized to °C; GPS Track Map works out of the box (lap detection, channel-colored track polyline) +- **Supported data:** Latitude, longitude, altitude, speed, bearing, and fix quality from GPS; accelerometer, gyroscope, and magnetometer axes; lap and fragment numbers; and any OBD/CAN channels the session logged (RPM, oil temp, throttle, and more) +- **Note:** Export the session as **CSV v3** from RaceChrono — the other RaceChrono export formats (`.vbo`, `.rcz`, CSV v1/v2) are not supported + ### Coming Soon - AEM - MaxxECU diff --git a/docs/index.html b/docs/index.html index c798134..af2b9a5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -9,9 +9,9 @@ UltraLog - Free ECU Log Viewer & Analyzer | Haltech, ECUMaster, Speeduino, AiM & More + content="UltraLog is a free, open-source ECU datalog viewer built with Rust. Analyze logs from Haltech, ECUMaster, RomRaider, Speeduino, rusEFI, AiM, Link, Emerald, BlueDriver, MegaSquirt, MHD, Woolich, and RaceChrono lap-timing sessions. Features include stacked plot areas, histogram heatmaps, scatter plots, computed channels, MCP server for AI integration, and professional analysis tools. Download for Windows, macOS, and Linux."> + content="ECU log viewer, datalog analyzer, Haltech NSP, ECUMaster EMU Pro, RomRaider, Speeduino MLG, rusEFI, AiM XRK DRK, Link ECU LLG, Emerald K6 M3D, automotive tuning software, engine tuning, AFR analysis, boost log, free tuning software, open source ECU, car data logger, dyno analysis, motorsport data, fuel map analysis, ignition timing, lambda analysis, volumetric efficiency, injector duty cycle, Butterworth filter, scatter plot, histogram heatmap, computed channels, Rust application, stacked plots, MCP server, Model Context Protocol, Claude Desktop, BlueDriver OBD-II, AI log analysis, RaceChrono CSV, lap timing analysis, track day data, GPS track map"> @@ -107,13 +107,13 @@ "@type": "SoftwareApplication", "name": "UltraLog", "alternateName": ["UltraLog ECU Viewer", "UltraLog Datalog Analyzer"], - "description": "A high-performance, cross-platform ECU log viewer and analyzer built with Rust. Supports Haltech, ECUMaster, RomRaider, Speeduino, rusEFI, AiM, Link, and Emerald ECU formats with advanced analysis tools.", + "description": "A high-performance, cross-platform ECU log viewer and analyzer built with Rust. Supports Haltech, ECUMaster, RomRaider, Speeduino, rusEFI, AiM, Link, Emerald, MegaSquirt, MHD, Motorsport Electronics, RaceChrono, Woolich, BlueDriver, DynamicEFI, and Locomotive log formats with advanced analysis tools.", "url": "https://ultralog.co/", "applicationCategory": "UtilitiesApplication", "applicationSubCategory": "Automotive Software", "operatingSystem": ["Windows 10", "Windows 11", "macOS", "Linux"], - "softwareVersion": "2.13.0", - "releaseNotes": "https://github.com/ClassicMiniDIY/UltraLog/releases/tag/v2.10.1", + "softwareVersion": "2.13.1", + "releaseNotes": "https://github.com/ClassicMiniDIY/UltraLog/releases/tag/v2.13.1", "downloadUrl": "https://github.com/ClassicMiniDIY/UltraLog/releases/latest", "installUrl": "https://github.com/ClassicMiniDIY/UltraLog/releases/latest", "screenshot": [ @@ -1427,7 +1427,7 @@

Unlock Your Performanc
New - v2.13.0 + v2.13.1 Open Source @@ -1530,8 +1530,15 @@

Computed Math Channels

What's New

-

GPS track maps with satellite imagery, stacked plots, AI-powered analysis via MCP, and more

+

RaceChrono lap-timing imports, GPS track maps with satellite imagery, stacked plots, AI-powered analysis via MCP, and more

+
+
+
+

RaceChrono Imports

+
+

Open RaceChrono and RaceChrono Pro CSV v3 session exports directly — GPS, phone sensors, and OBD/CAN channels on one timeline, with lap numbers and the track map ready out of the box. Analyze your track days on a big screen instead of your phone.

+
@@ -1740,7 +1747,13 @@

Supported ECUs

Link ECU (LLG) Emerald K6/M3D MegaSquirt - BlueDriver OBD-II + BlueDriver OBD-II + Woolich Racing Tuned + MHD Tuning + Motorsport Electronics + DynamicEFI + Locomotive + RaceChrono
diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 0cf8e00..311a95d 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -3,7 +3,7 @@ xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"> https://ultralog.co/ - 2026-08-18 + 2026-08-19 weekly 1.0 diff --git a/exampleLogs/racechrono/session_massa_finalese_v3_excerpt.csv b/exampleLogs/racechrono/session_massa_finalese_v3_excerpt.csv new file mode 100644 index 0000000..7914d5e --- /dev/null +++ b/exampleLogs/racechrono/session_massa_finalese_v3_excerpt.csv @@ -0,0 +1,412 @@ +This file is created using RaceChrono Pro v10.1.3 ( http://racechrono.com/ ). +Format,3 +Session title,"Copia di Massa Finalese" +Session type,Lap timing +Track name,"Copia di Massa Finalese" +Driver name, +Created,04/08/2026,13:14 +Note, + +timestamp,fragment_id,lap_number,elapsed_time,distance_traveled,accuracy,altitude,bearing,device_update_rate,fix_type,latitude,longitude,satellites,speed,combined_acc,device_update_rate,lateral_acc,lean_angle,longitudinal_acc,speed,engine_oil_temp,percent_1,rpm,device_update_rate,x_acc,y_acc,z_acc,device_update_rate,x_rate_of_rotation,y_rate_of_rotation,z_rate_of_rotation,device_update_rate,x_magnetic_field,y_magnetic_field,z_magnetic_field +unix time,,,s,m,m,m,deg,Hz,,deg,deg,sats,m/s,G,Hz,G,deg,G,m/s,.C,%,rpm,Hz,G,G,G,Hz,deg/s,deg/s,deg/s,Hz,uT,uT,uT +,,,,,100: gps,100: gps,100: gps,100: gps,100: gps,100: gps,100: gps,100: gps,100: gps,calc,calc,calc,calc,calc,calc,300: canbus,300: canbus,300: canbus,200: acc,200: acc,200: acc,200: acc,201: gyro,201: gyro,201: gyro,201: gyro,202: magn,202: magn,202: magn,202: magn +1785849363.002,0,,0.002,0.00037,5.3984,-2.3996,0.0,,1.0,44.831825,11.224415,4.012,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.02025,0.50517,0.0154,0.89562,41.0149,-0.005,0.236,-0.007,40.94392,-141.465,-37.8,-201.3 +1785849363.007,0,,0.007,0.0013,5.3944,-2.3986,0.0,,1.0,44.831825,11.224415,4.042,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.0351,0.50503,0.0154,0.89562,41.02434,-0.02,0.16074,-0.007,40.95089,-141.48,-37.8,-201.3 +1785849363.021,0,,0.021,0.00389,5.3832,-2.3958,0.0,,1.0,44.831825,11.224415,4.126,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.07667,0.50466,0.0154,0.89562,41.05075,-0.062,-0.05,-0.007,41.00015,-141.31333,-38.07333,-201.3 +1785849363.028,0,,0.028,0.00518,5.3776,-2.3944,0.0,,1.0,44.831825,11.224415,4.168,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.11047,0.50491,0.01547,0.89562,41.0785,-0.04205,-0.09025,0.01295,41.02478,-141.23,-38.21,-201.3 +1785849363.041,0,,0.041,0.00759,5.3672,-2.3918,0.0,,1.0,44.8318249,11.224415,4.246,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.17324,0.50537,0.0156,0.89562,41.13002,-0.005,-0.165,0.05,41.09519,-141.15056,-38.12333,-201.38667 +1785849363.046,0,,0.046,0.00851,5.3632,-2.3908,0.0,,1.0,44.8318249,11.224415,4.276,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.20669,0.50525,0.01526,0.89533,41.1606,-0.01857,-0.15143,0.03643,41.12227,-141.12,-38.09,-201.42 +1785849363.05,0,,0.05,0.00925,5.36,-2.39,0.0,,1.0,44.8318249,11.224415,4.3,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.23344,0.50515,0.01499,0.89509,41.18507,-0.02943,-0.14057,0.02557,41.15087,-141.012,-38.15,-201.372 +1785849363.062,0,,0.062,0.01147,5.3504,-2.3876,0.0,,1.0,44.8318249,11.224415,4.372,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.3137,0.50486,0.01417,0.89439,41.25849,-0.062,-0.108,-0.007,41.23667,-140.688,-38.33,-201.228 +1785849363.066,0,,0.066,0.01221,5.3472,-2.3868,0.0,,1.0,44.8318249,11.224415,4.396,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.34714,0.50486,0.01417,0.89444,41.29074,-0.062,-0.108,-0.007,41.26528,-140.58,-38.39,-201.18 +1785849363.074,0,,0.074,0.01369,5.3408,-2.3852,0.0,,1.0,44.8318249,11.224415,4.444,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.41401,0.50486,0.01417,0.89452,41.35525,-0.062,-0.108,-0.007,41.33598,-140.436,-38.514,-201.108 +1785849363.081,0,,0.081,0.01499,5.3352,-2.3838,0.0,,1.0,44.8318249,11.224415,4.486,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.47252,0.50486,0.01417,0.8946,41.4117,-0.062,-0.108,-0.007,41.39785,-140.31,-38.6225,-201.045 +1785849363.086,0,,0.086,0.01591,5.3312,-2.3828,0.0,,1.0,44.8318249,11.224415,4.516,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.51993,0.5052,0.01383,0.89434,41.45841,-0.04617,-0.09189,0.02494,41.44204,-140.22,-38.7,-201.0 +1785849363.099,0,,0.099,0.01832,5.3208,-2.3802,0.0,,1.0,44.8318248,11.224415,4.594,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.6432,0.50609,0.01295,0.89368,41.57986,-0.005,-0.05,0.108,41.57369,-140.29429,-38.66286,-201.0 +1785849363.1,0,,0.1,0.0185,5.32,-2.38,0.0,,1.0,44.8318248,11.224415,4.6,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.65406,0.50603,0.01288,0.89372,41.5908,0.00043,-0.04181,0.10252,41.58382,-140.3,-38.66,-201.0 +1785849363.107,0,,0.107,0.0198,5.3144,-2.3786,0.0,,1.0,44.8318248,11.224415,4.642,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.73005,0.50562,0.01241,0.89403,41.66739,0.03843,0.01552,0.06419,41.65471,-140.34,-38.64,-201.0 +1785849363.12,0,,0.12,0.0222,5.304,-2.376,0.0,,1.0,44.8318248,11.224415,4.72,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.87117,0.50486,0.01152,0.8946,41.80962,0.109,0.122,-0.007,41.80471,-140.1775,-38.64,-201.078 +1785849363.127,0,,0.127,0.0235,5.2984,-2.3746,0.0,,1.0,44.8318248,11.224415,4.762,0.0,,20.0,,,,0.0,0.0,33.0,0.0,42.9554,0.50524,0.01133,0.89478,41.89618,0.067,0.07963,-0.028,41.88548,-140.09,-38.64,-201.12 +1785849363.139,0,,0.139,0.02572,5.2888,-2.3722,0.0,,1.0,44.8318248,11.224415,4.834,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.09979,0.50588,0.01101,0.89511,42.04457,-0.005,0.007,-0.064,42.03692,-140.24789,-38.67789,-201.00632 +1785849363.146,0,,0.146,0.02701,5.2832,-2.3708,0.0,,1.0,44.8318248,11.224415,4.876,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.19179,0.5057,0.01126,0.89571,42.14003,-0.02495,0.007,-0.04405,42.12526,-140.34,-38.7,-200.94 +1785849363.15,0,,0.15,0.02775,5.28,-2.37,0.0,,1.0,44.8318248,11.224415,4.9,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.24436,0.5056,0.01141,0.89606,42.19457,-0.03635,0.007,-0.03265,42.1805,-140.376,-38.724,-200.976 +1785849363.159,0,,0.159,0.02942,5.2728,-2.3682,0.0,,1.0,44.8318247,11.224415,4.954,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.36265,0.50537,0.01173,0.89684,42.3173,-0.062,0.007,-0.007,42.30479,-140.457,-38.778,-201.057 +1785849363.165,0,,0.165,0.03053,5.268,-2.367,0.0,,1.0,44.8318247,11.224415,4.99,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.44652,0.50531,0.01195,0.8969,42.40568,-0.062,-0.02932,-0.04332,42.38765,-140.511,-38.814,-201.111 +1785849363.166,0,,0.166,0.03071,5.2672,-2.3668,0.0,,1.0,44.8318247,11.224415,4.996,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.4605,0.5053,0.01199,0.89692,42.42041,-0.062,-0.03537,-0.04937,42.40146,-140.52,-38.82,-201.12 +1785849363.178,0,,0.178,0.03293,5.2576,-2.3644,0.0,,1.0,44.8318247,11.224415,5.068,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.62825,0.50517,0.01244,0.89704,42.59719,-0.062,-0.108,-0.122,42.57722,-140.442,-38.886,-201.048 +1785849363.186,0,,0.186,0.03441,5.2512,-2.3628,0.0,,1.0,44.8318247,11.224415,5.116,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.74618,0.50439,0.01264,0.89615,42.72209,-0.0392,-0.0848,-0.0532,42.6944,-140.39,-38.93,-201.0 +1785849363.198,0,,0.198,0.03663,5.2416,-2.3604,0.0,,1.0,44.8318247,11.224415,5.188,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.92308,0.50323,0.01295,0.8948,42.90945,-0.005,-0.05,0.05,42.87879,-140.52043,-39.06043,-201.0 +1785849363.2,0,,0.2,0.037,5.24,-2.36,0.0,,1.0,44.8318247,11.224415,5.2,0.0,,20.0,,,,0.0,0.0,33.0,0.0,43.95367,0.50347,0.01307,0.8948,42.94214,0.0007,-0.0443,0.0386,42.90952,-140.54217,-39.08217,-201.0 +1785849363.209,0,,0.209,0.03867,5.2328,-2.3582,0.0,,1.0,44.8318247,11.224415,5.254,0.0,,20.0,,,,0.0,0.0,33.0,0.0,44.09133,0.50458,0.01362,0.8948,43.08927,0.02635,-0.01865,-0.0127,43.04781,-140.64,-39.18,-201.0 +1785849363.218,0,,0.218,0.04033,5.2256,-2.3564,0.0,,1.0,44.8318246,11.224415,5.308,0.0,,20.0,,,,0.0,0.0,33.0,0.0,44.22899,0.50568,0.01417,0.8948,43.23639,0.052,0.007,-0.064,43.19156,-140.79882,-39.24353,-200.80941 +1785849363.226,0,,0.226,0.04181,5.2192,-2.3548,0.0,,1.0,44.8318246,11.224415,5.356,0.0,,20.0,,,,0.0,0.0,33.0,0.0,44.35487,0.50512,0.0138,0.89473,43.37229,0.01055,0.02773,-0.064,43.31934,-140.94,-39.3,-200.64 +1785849363.24,0,,0.24,0.0444,5.208,-2.352,0.0,,1.0,44.8318246,11.224415,5.44,0.0,,20.0,,,,0.0,0.0,33.0,0.0,44.57516,0.50415,0.01315,0.8946,43.61012,-0.062,0.064,-0.064,43.5472,-141.066,-39.377,-200.43 +1785849363.246,0,,0.246,0.04551,5.2032,-2.3508,0.0,,1.0,44.8318246,11.224415,5.476,0.0,,20.0,,,,0.0,0.0,33.0,0.0,44.6709,0.5044,0.01377,0.89528,43.714,-0.04188,0.04388,-0.04388,43.64485,-141.12,-39.41,-200.34 +1785849363.25,0,,0.25,0.04625,5.2,-2.35,0.0,,1.0,44.8318246,11.224415,5.5,0.0,,20.0,,,,0.0,0.0,33.0,0.0,44.73474,0.50457,0.01417,0.89574,43.78325,-0.02847,0.03047,-0.03047,43.71063,-141.07,-39.424,-200.292 +1785849363.257,0,,0.257,0.04755,5.1944,-2.3486,0.0,,1.0,44.8318246,11.224415,5.542,0.0,,20.0,,,,0.0,0.0,33.0,0.0,44.84644,0.50486,0.01489,0.89653,43.90444,-0.005,0.007,-0.007,43.82574,-140.9825,-39.4485,-200.208 +1785849363.266,0,,0.266,0.04921,5.1872,-2.3468,0.0,,1.0,44.8318246,11.224415,5.596,0.0,,20.0,,,,0.0,0.0,33.0,0.0,44.99112,0.50521,0.01511,0.89579,44.06262,-0.02943,-0.01743,-0.007,43.97373,-140.87,-39.48,-200.1 +1785849363.27,0,,0.27,0.04995,5.184,-2.346,0.0,,1.0,44.8318246,11.224415,5.62,0.0,,20.0,,,,0.0,0.0,33.0,0.0,45.05543,0.50537,0.0152,0.89546,44.13292,-0.04029,-0.02829,-0.007,44.04036,-140.836,-39.48,-200.124 +1785849363.278,0,,0.278,0.05143,5.1776,-2.3444,0.0,,1.0,44.8318245,11.224415,5.668,0.0,,20.0,,,,0.0,0.0,33.0,0.0,45.18403,0.50568,0.0154,0.8948,44.27351,-0.062,-0.05,-0.007,44.17361,-140.768,-39.48,-200.172 +1785849363.286,0,,0.286,0.05291,5.1712,-2.3428,0.0,,1.0,44.8318245,11.224415,5.716,0.0,,20.0,,,,0.0,0.0,33.0,0.0,45.31213,0.50586,0.01508,0.89439,44.41455,-0.03667,-0.07578,0.01833,44.30686,-140.7,-39.48,-200.22 +1785849363.296,0,,0.296,0.05476,5.1632,-2.3408,0.0,,1.0,44.8318245,11.224415,5.776,0.0,,20.0,,,,0.0,0.0,33.0,0.0,45.47225,0.50609,0.01468,0.89388,44.59084,-0.005,-0.108,0.05,44.47205,-140.64286,-39.48,-200.13429 +1785849363.3,0,,0.3,0.0555,5.16,-2.34,0.0,,1.0,44.8318245,11.224415,5.8,0.0,,20.0,,,,0.0,0.0,33.0,0.0,45.53568,0.50595,0.01463,0.89416,44.66115,0.01671,-0.04248,0.06105,44.53813,-140.62,-39.48,-200.1 +1785849363.307,0,,0.307,0.0568,5.1544,-2.3386,0.0,,1.0,44.8318245,11.224415,5.842,0.0,,20.0,,,,0.0,0.0,33.0,0.0,45.64669,0.50571,0.01452,0.89463,44.78419,0.05471,0.07219,0.08038,44.65376,-140.58,-39.48,-200.04 +1785849363.317,0,,0.317,0.05865,5.1464,-2.3366,0.0,,1.0,44.8318245,11.224415,5.902,0.0,,20.0,,,,0.0,0.0,33.0,0.0,45.80528,0.50537,0.01438,0.89531,44.95997,0.109,0.236,0.108,44.81589,-140.64316,-39.38526,-200.04 +1785849363.326,0,,0.326,0.06031,5.1392,-2.3348,0.0,,1.0,44.8318245,11.224415,5.956,0.0,,20.0,,,,0.0,0.0,33.0,0.0,45.94478,0.50445,0.01438,0.89546,45.11589,0.055,0.12753,0.08053,44.96181,-140.7,-39.3,-200.04 +1785849363.336,0,,0.336,0.06216,5.1312,-2.3328,0.0,,1.0,44.8318244,11.224415,6.016,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.09978,0.50343,0.01438,0.89562,45.28913,-0.005,0.007,0.05,45.12112,-140.7,-39.35238,-200.06857 +1785849363.347,0,,0.347,0.06419,5.1224,-2.3306,0.0,,1.0,44.8318244,11.224415,6.082,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.26583,0.50451,0.01452,0.89596,45.47583,-0.06,0.007,0.05,45.29636,-140.7,-39.41,-200.1 +1785849363.35,0,,0.35,0.06475,5.12,-2.33,0.0,,1.0,44.8318244,11.224415,6.1,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.31111,0.5048,0.01456,0.89605,45.52675,-0.075,0.007,0.05,45.34288,-140.7,-39.3935,-200.136 +1785849363.359,0,,0.359,0.06642,5.1128,-2.3282,0.0,,1.0,44.8318244,11.224415,6.154,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.44697,0.50568,0.01468,0.89633,45.6795,-0.12,0.007,0.05,45.48245,-140.7,-39.344,-200.244 +1785849363.367,0,,0.367,0.0679,5.1064,-2.3266,0.0,,1.0,44.8318244,11.224415,6.202,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.56258,0.50649,0.01372,0.89557,45.81072,-0.0625,0.0355,0.021,45.60651,-140.7,-39.3,-200.34 +1785849363.374,0,,0.374,0.06919,5.1008,-2.3252,0.0,,1.0,44.8318244,11.224415,6.244,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.66374,0.50721,0.01287,0.8949,45.92555,-0.01219,0.06044,-0.00438,45.70989,-140.65579,-39.34053,-200.42842 +1785849363.375,0,,0.375,0.06937,5.1,-2.325,0.0,,1.0,44.8318244,11.224415,6.25,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.67819,0.50731,0.01275,0.8948,45.94195,-0.005,0.064,-0.008,45.72466,-140.64947,-39.34632,-200.44105 +1785849363.386,0,,0.386,0.07141,5.0912,-2.3228,0.0,,1.0,44.8318244,11.224415,6.316,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.83097,0.50645,0.01259,0.8948,46.11657,-0.005,0.064,-0.03786,45.88711,-140.58,-39.41,-200.58 +1785849363.396,0,,0.396,0.07326,5.0832,-2.3208,0.0,,1.0,44.8318243,11.224415,6.376,0.0,,20.0,,,,0.0,0.0,33.0,0.0,46.96986,0.50568,0.01244,0.8948,46.27531,-0.005,0.064,-0.065,46.02926,-140.55,-39.32,-200.64 +1785849363.4,0,,0.4,0.074,5.08,-2.32,0.0,,1.0,44.8318243,11.224415,6.4,0.0,,20.0,,,,0.0,0.0,33.0,0.0,47.02206,0.50557,0.01266,0.89487,46.33552,-0.005,0.064,-0.065,46.08612,-140.538,-39.284,-200.664 +1785849363.406,0,,0.406,0.07511,5.0752,-2.3188,0.0,,1.0,44.8318243,11.224415,6.436,0.0,,20.0,,,,0.0,0.0,33.0,0.0,47.10037,0.50541,0.01298,0.89496,46.42584,-0.005,0.064,-0.065,46.17141,-140.52,-39.23,-200.7 +1785849363.415,0,,0.415,0.07678,5.068,-2.317,0.0,,1.0,44.8318243,11.224415,6.49,0.0,,20.0,,,,0.0,0.0,33.0,0.0,47.21784,0.50517,0.01346,0.89511,46.56131,-0.005,0.064,-0.065,46.29128,-140.64429,-39.18286,-200.77286 +1785849363.427,0,,0.427,0.079,5.0584,-2.3146,0.0,,1.0,44.8318243,11.224415,6.562,0.0,,20.0,,,,0.0,0.0,33.0,0.0,47.36538,0.5056,0.01328,0.89468,46.73331,-0.005,0.0298,-0.0308,46.45112,-140.81,-39.12,-200.87 +1785849363.435,0,,0.435,0.08048,5.052,-2.313,0.0,,1.0,44.8318243,11.224415,6.61,0.0,,20.0,,,,0.0,0.0,33.0,0.0,47.46373,0.50588,0.01315,0.89439,46.84799,-0.005,0.007,-0.008,46.55084,-140.834,-39.164,-200.85 +1785849363.447,0,,0.447,0.0827,5.0424,-2.3106,0.0,,1.0,44.8318243,11.224415,6.682,0.0,,20.0,,,,0.0,0.0,33.0,0.0,47.60093,0.50527,0.01334,0.89378,47.00968,-0.005,0.007,-0.0422,46.70042,-140.87,-39.23,-200.82 +1785849363.45,0,,0.45,0.08325,5.04,-2.31,0.0,,1.0,44.8318243,11.224415,6.7,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,33.0,0.0,47.63523,0.50512,0.01338,0.89363,47.0501,-0.005,0.007,-0.05075,46.73491,-140.89053,-39.23,-200.82 +1785849363.455,0,,0.455,0.08418,5.036,-2.309,0.0,,1.0,44.8318242,11.224415,6.73,0.0,0.00006,20.0,-0.00001,0.00051,0.00006,0.0,0.0,33.0,0.0,47.6924,0.50486,0.01346,0.89337,47.11747,-0.005,0.007,-0.065,46.79239,-140.92474,-39.23,-200.82 +1785849363.464,0,,0.464,0.08584,5.0288,-2.3072,0.0,,1.0,44.8318242,11.224415,6.784,0.0,0.00017,20.0,-0.00002,0.00142,0.00016,0.0,0.0,33.0,0.0,47.7852,0.50477,0.01378,0.89383,47.22838,-0.05675,0.007,-0.03935,46.89587,-140.98632,-39.23,-200.82 +1785849363.466,0,,0.466,0.08621,5.0272,-2.3068,0.0,,1.0,44.8318242,11.224415,6.796,0.0,0.00019,20.0,-0.00003,0.00162,0.00019,0.0,0.0,33.0,0.0,47.80582,0.50475,0.01385,0.89393,47.25302,-0.06825,0.007,-0.03365,46.91886,-141.0,-39.23,-200.82 +1785849363.475,0,,0.475,0.08788,5.02,-2.305,0.0,,1.0,44.8318242,11.224415,6.85,0.0,0.0003,20.0,-0.00004,0.00253,0.00029,0.0,0.0,33.0,0.0,47.89862,0.50466,0.01417,0.89439,47.36393,-0.12,0.007,-0.008,47.01269,-140.9145,-39.23,-200.739 +1785849363.486,0,,0.486,0.08991,5.0112,-2.3028,0.0,,1.0,44.8318242,11.224415,6.916,0.0,0.00043,20.0,-0.00006,0.00364,0.00042,0.0,0.0,33.0,0.0,48.00114,0.50453,0.01449,0.89483,47.48833,-0.04972,-0.06328,-0.008,47.12736,-140.81,-39.23,-200.64 +1785849363.493,0,,0.493,0.09121,5.0056,-2.3014,0.0,,1.0,44.8318242,11.224415,6.958,0.0,0.00051,20.0,-0.00008,0.00435,0.0005,0.0,0.0,33.0,0.0,48.06638,0.50445,0.01468,0.89511,47.5675,-0.005,-0.108,-0.008,47.1924,-140.83,-39.25333,-200.59667 +1785849363.5,0,,0.5,0.0925,5.0,-2.3,0.0,,1.0,44.8318242,11.224415,7.0,0.0,0.00059,20.0,-0.00009,0.00505,0.00058,0.0,0.0,33.0,0.0,48.12397,0.50476,0.01451,0.89446,47.63867,0.014,-0.05067,0.01133,47.25743,-140.85,-39.27667,-200.55333 +1785849363.507,0,,0.507,0.0938,4.9944,-2.2986,0.0,,1.0,44.8318242,11.224415,7.042,0.0,0.00066,20.0,-0.0001,0.00564,0.00065,0.0,0.0,33.0,0.0,48.18155,0.50507,0.01434,0.89382,47.70984,0.033,0.00667,0.03067,47.32246,-140.87,-39.3,-200.51 +1785849363.514,0,,0.514,0.09509,4.9888,-2.2972,0.0,,1.0,44.8318241,11.224415,7.084,0.0,0.00073,20.0,-0.00011,0.00622,0.00072,0.0,0.0,33.0,0.0,48.23913,0.50537,0.01417,0.89317,47.78102,0.052,0.064,0.05,47.37933,-140.80737,-39.3,-200.35895 +1785849363.526,0,,0.526,0.09731,4.9792,-2.2948,0.0,,1.0,44.8318241,11.224415,7.156,0.0,0.00085,20.0,-0.00013,0.00723,0.00084,0.0,0.0,33.0,0.0,48.32453,0.50492,0.0145,0.89484,47.88918,-0.02063,0.064,-0.02263,47.47683,-140.7,-39.3,-200.1 +1785849363.533,0,,0.533,0.09861,4.9736,-2.2934,0.0,,1.0,44.8318241,11.224415,7.198,0.0,0.00091,20.0,-0.00014,0.00781,0.0009,0.0,0.0,33.0,0.0,48.37435,0.50466,0.01468,0.89582,47.95227,-0.063,0.064,-0.065,47.52529,-140.64,-39.26,-200.04 +1785849363.547,0,,0.547,0.1012,4.9624,-2.2906,0.0,,1.0,44.8318241,11.224415,7.282,0.0,0.00105,20.0,-0.00016,0.00898,0.00104,0.0,0.0,33.0,0.0,48.45776,0.50478,0.0145,0.8957,48.06094,-0.0977,0.0293,0.005,47.6222,-140.52,-39.18,-199.92 +1785849363.55,0,,0.55,0.10175,4.96,-2.29,0.0,,1.0,44.8318241,11.224415,7.3,0.0,0.00108,20.0,-0.00016,0.00923,0.00107,0.0,0.0,33.0,0.0,48.47564,0.50481,0.01446,0.89567,48.08422,-0.10513,0.02187,0.02,47.63989,-140.53895,-39.21632,-199.90105 +1785849363.556,0,,0.556,0.10286,4.9552,-2.2888,0.0,,1.0,44.8318241,11.224415,7.336,0.0,0.00113,20.0,-0.00017,0.00967,0.00112,0.0,0.0,33.0,0.0,48.51138,0.50486,0.01438,0.89562,48.13079,-0.12,0.007,0.05,47.67526,-140.57684,-39.28895,-199.86316 +1785849363.566,0,,0.566,0.10471,4.9472,-2.2868,0.0,,1.0,44.8318241,11.224415,7.396,0.0,0.00122,20.0,-0.00018,0.01038,0.0012,0.0,0.0,33.0,0.0,48.55987,0.50514,0.01398,0.89584,48.19665,-0.05611,-0.08856,-0.01389,47.73421,-140.64,-39.41,-199.8 +1785849363.57,0,,0.57,0.10545,4.944,-2.286,0.0,,1.0,44.8318241,11.224415,7.42,0.0,0.00125,20.0,-0.00019,0.01067,0.00123,0.0,0.0,33.0,0.0,48.57926,0.50526,0.01382,0.89593,48.22299,-0.03056,-0.12678,-0.03944,47.75349,-140.628,-39.446,-199.836 +1785849363.574,0,,0.574,0.10619,4.9408,-2.2852,0.0,,1.0,44.831824,11.224415,7.444,0.0,0.00128,20.0,-0.00019,0.01096,0.00127,0.0,0.0,33.0,0.0,48.59866,0.50537,0.01366,0.89602,48.24933,-0.005,-0.165,-0.065,47.77278,-140.616,-39.482,-199.872 +1785849363.586,0,,0.586,0.10841,4.9312,-2.2828,0.0,,1.0,44.831824,11.224415,7.516,0.0,0.00138,20.0,-0.00021,0.01182,0.00137,0.0,0.0,33.0,0.0,48.64471,0.50492,0.01212,0.89654,48.31539,0.031,-0.165,-0.029,47.83063,-140.58,-39.59,-199.98 +1785849363.593,0,,0.593,0.10971,4.9256,-2.2814,0.0,,1.0,44.831824,11.224415,7.558,0.0,0.00144,20.0,-0.00021,0.01232,0.00143,0.0,0.0,33.0,0.0,48.67158,0.50466,0.01122,0.89684,48.35392,0.052,-0.165,-0.008,47.85833,-140.56,-39.65333,-199.98 +1785849363.6,0,,0.6,0.111,4.92,-2.28,0.0,,1.0,44.831824,11.224415,7.6,0.0,0.0015,20.0,-0.00022,0.01282,0.00148,0.0,0.0,33.0,0.0,48.69563,0.50537,0.01212,0.89568,48.38658,0.031,-0.10163,-0.008,47.88603,-140.54,-39.71667,-199.98 +1785849363.607,0,,0.607,0.11229,4.9144,-2.2786,0.0,,1.0,44.831824,11.224415,7.642,0.0,0.00155,20.0,-0.00023,0.01327,0.00154,0.0,0.0,33.0,0.0,48.71969,0.50609,0.01302,0.89451,48.41924,0.01,-0.03826,-0.008,47.91374,-140.52,-39.78,-199.98 +1785849363.612,0,,0.612,0.11322,4.9104,-2.2776,0.0,,1.0,44.831824,11.224415,7.672,0.0,0.00159,20.0,-0.00024,0.01359,0.00157,0.0,0.0,33.0,0.0,48.73687,0.5066,0.01366,0.89368,48.44256,-0.005,0.007,-0.008,47.92747,-140.53579,-39.78,-199.99579 +1785849363.626,0,,0.626,0.11581,4.8992,-2.2748,0.0,,1.0,44.831824,11.224415,7.756,0.0,0.0017,20.0,-0.00025,0.01449,0.00168,0.0,0.0,33.0,0.0,48.7583,0.50624,0.01452,0.89396,48.48562,-0.0855,0.007,0.0326,47.96594,-140.58,-39.78,-200.04 +1785849363.632,0,,0.632,0.11692,4.8944,-2.2736,0.0,,1.0,44.8318239,11.224415,7.792,0.0,0.00174,20.0,-0.00026,0.01487,0.00172,0.0,0.0,33.0,0.0,48.76749,0.50609,0.01489,0.89409,48.50407,-0.12,0.007,0.05,47.97591,-140.58,-39.759,-200.022 +1785849363.646,0,,0.646,0.11951,4.8832,-2.2708,0.0,,1.0,44.8318239,11.224415,7.876,0.0,0.00185,20.0,-0.00028,0.01577,0.00183,0.0,0.0,33.0,0.0,48.77843,0.50578,0.01346,0.89551,48.53536,0.00674,0.091,0.00726,47.99918,-140.58,-39.71,-199.98 +1785849363.65,0,,0.65,0.12025,4.88,-2.27,0.0,,1.0,44.8318239,11.224415,7.9,0.0,0.00188,20.0,-0.00028,0.01603,0.00186,0.0,0.0,33.0,0.0,48.78156,0.5057,0.01305,0.89592,48.54431,0.04295,0.115,-0.00495,48.00129,-140.652,-39.604,-199.98 +1785849363.651,0,,0.651,0.12044,4.8792,-2.2698,0.0,,1.0,44.8318239,11.224415,7.906,0.0,0.00188,20.0,-0.00028,0.01609,0.00186,0.0,0.0,33.0,0.0,48.78234,0.50568,0.01295,0.89602,48.54654,0.052,0.121,-0.008,48.00182,-140.67,-39.5775,-199.98 +1785849363.666,0,,0.666,0.12321,4.8672,-2.2668,0.0,,1.0,44.8318239,11.224415,7.996,0.0,0.00199,20.0,-0.0003,0.01702,0.00197,0.0,0.0,33.0,0.0,48.7782,0.5048,0.01346,0.89661,48.56269,-0.03014,0.03957,-0.008,48.00975,-140.94,-39.18,-199.98 +1785849363.672,0,,0.672,0.12432,4.8624,-2.2656,0.0,,1.0,44.8318239,11.224415,8.032,0.0,0.00204,20.0,-0.0003,0.01739,0.00201,0.0,0.0,33.0,0.0,48.77655,0.50445,0.01366,0.89684,48.56915,-0.063,0.007,-0.008,48.00671,-140.994,-39.105,-199.998 +1785849363.674,0,,0.674,0.12469,4.8608,-2.2652,0.0,,1.0,44.8318239,11.224415,8.044,0.0,0.00205,20.0,-0.00031,0.01752,0.00203,0.0,0.0,33.0,0.0,48.77423,0.5044,0.01361,0.89675,48.5693,-0.05656,0.007,-0.01433,48.0057,-141.012,-39.08,-200.004 +1785849363.686,0,,0.686,0.12691,4.8512,-2.2628,0.0,,1.0,44.8318239,11.224415,8.116,0.0,0.00214,20.0,-0.00032,0.01826,0.00211,0.0,0.0,33.0,0.0,48.7603,0.50406,0.01327,0.89621,48.57024,-0.01789,0.007,-0.05233,47.99962,-141.12,-38.93,-200.04 +1785849363.69,0,,0.69,0.12765,4.848,-2.262,0.0,,1.0,44.8318239,11.224415,8.14,0.0,0.00217,20.0,-0.00032,0.01851,0.00214,0.0,0.0,33.0,0.0,48.75566,0.50394,0.01315,0.89602,48.57056,-0.005,0.007,-0.065,47.99392,-141.156,-38.968,-200.112 +1785849363.7,0,,0.7,0.1295,4.84,-2.26,0.0,,1.0,44.8318238,11.224415,8.2,0.0,0.00224,20.0,-0.00033,0.01913,0.00221,0.0,0.0,33.0,0.0,48.73462,0.50419,0.0134,0.89534,48.56086,-0.005,-0.02062,-0.01024,47.97968,-141.246,-39.063,-200.292 +1785849363.706,0,,0.706,0.13061,4.8352,-2.2588,0.0,,1.0,44.8318238,11.224415,8.236,0.0,0.00228,20.0,-0.00034,0.01951,0.00226,0.0,0.0,33.0,0.0,48.722,0.50433,0.01354,0.89494,48.55504,-0.005,-0.03719,0.02262,47.97114,-141.3,-39.12,-200.4 +1785849363.711,0,,0.711,0.13153,4.8312,-2.2578,0.0,,1.0,44.8318238,11.224415,8.266,0.0,0.00232,20.0,-0.00035,0.01982,0.00229,0.0,0.0,33.0,0.0,48.71148,0.50445,0.01366,0.8946,48.55019,-0.005,-0.051,0.05,47.95979,-141.28158,-39.07,-200.46316 +1785849363.725,0,,0.725,0.13413,4.82,-2.255,0.0,,1.0,44.8318238,11.224415,8.35,0.0,0.00242,20.0,-0.00036,0.0207,0.0024,0.0,0.0,33.0,0.0,48.67142,0.50588,0.01389,0.89587,48.52468,-0.005,0.03374,0.05,47.92801,-141.23,-38.93,-200.64 +1785849363.73,0,,0.73,0.13505,4.816,-2.254,0.0,,1.0,44.8318238,11.224415,8.38,0.0,0.00246,20.0,-0.00037,0.02101,0.00243,0.0,0.0,33.0,0.0,48.65711,0.50639,0.01397,0.89633,48.51556,-0.005,0.064,0.05,47.91281,-141.24667,-38.87524,-200.62571 +1785849363.746,0,,0.746,0.13801,4.8032,-2.2508,0.0,,1.0,44.8318238,11.224415,8.476,0.0,0.00258,20.0,-0.00038,0.02202,0.00255,0.0,0.0,33.0,0.0,48.5996,0.505,0.01495,0.89478,48.47222,-0.04919,0.064,0.00581,47.86415,-141.3,-38.7,-200.58 +1785849363.75,0,,0.75,0.13875,4.8,-2.25,0.0,,1.0,44.8318238,11.224415,8.5,0.0,0.00261,20.0,-0.00039,0.02227,0.00258,0.0,0.0,33.0,0.0,48.58522,0.50466,0.01519,0.89439,48.46139,-0.06024,0.064,-0.00524,47.84929,-141.346,-38.616,-200.566 +1785849363.751,0,,0.751,0.13894,4.7992,-2.2498,0.0,,1.0,44.8318237,11.224415,8.506,0.0,0.00261,20.0,-0.00039,0.02234,0.00259,0.0,0.0,33.0,0.0,48.58103,0.50469,0.01519,0.89438,48.45868,-0.063,0.064,-0.008,47.84557,-141.3575,-38.595,-200.5625 +1785849363.764,0,,0.764,0.14134,4.7888,-2.2472,0.0,,1.0,44.8318237,11.224415,8.584,0.0,0.00272,20.0,-0.0004,0.0232,0.00268,0.0,0.0,33.0,0.0,48.52662,0.50516,0.01519,0.89418,48.41518,-0.063,0.025,-0.008,47.79728,-141.507,-38.322,-200.517 +1785850132.4,0,12,769.4,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.62517,0.53972,0.01047,0.88316,50.60956,-0.50158,-0.909,-0.095,49.87366,-12.6385,-0.9595,-10.959 +1785850132.407,0,12,769.407,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.624,0.53987,0.01343,0.88188,50.60862,-0.33284,-0.951,-0.074,49.87232,-12.6,-0.9,-10.98 +1785850132.415,0,12,769.415,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.62265,0.54004,0.01683,0.88042,50.60755,-0.14,-0.999,-0.05,49.87049,-12.644,-0.776,-11.004 +1785850132.427,0,12,769.427,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.61807,0.53993,0.01921,0.8824,50.60341,0.08914,-0.50814,0.04829,49.86774,-12.71,-0.59,-11.04 +1785850132.436,0,12,769.436,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.61464,0.53984,0.02101,0.88389,50.6003,0.261,-0.14,0.122,49.86446,-12.74,-0.41429,-11.11286 +1785850132.448,0,12,769.448,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.60803,0.5418,0.02158,0.88312,50.59414,0.307,-0.0712,0.122,49.8601,-12.78,-0.18,-11.21 +1785850132.45,0,12,769.45,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.60693,0.54212,0.02167,0.88299,50.59311,0.31467,-0.05973,0.122,49.85903,-12.77333,-0.18,-11.20056 +1785850132.466,0,12,769.466,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.59812,0.54473,0.02243,0.88195,50.58491,0.376,0.032,0.122,49.85045,-12.72,-0.18,-11.125 +1785850132.484,0,12,769.484,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,0.54718,0.01662,0.87951,50.57638,0.09,0.089,0.122,49.8408,-12.66,-0.18,-11.04 +1785850132.491,0,12,769.491,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,-12.48,-0.18,-11.04 +1785850132.5,0,12,769.5,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.55,0,12,769.55,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.6,0,12,769.6,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.65,0,12,769.65,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.7,0,12,769.7,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.75,0,12,769.75,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.8,0,12,769.8,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.85,0,12,769.85,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.9,0,12,769.9,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850132.95,0,12,769.95,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.0,0,12,770.0,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.05,0,12,770.05,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.1,0,12,770.1,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.15,0,12,770.15,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.2,0,12,770.2,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.25,0,12,770.25,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.3,0,12,770.3,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.35,0,12,770.35,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.4,0,12,770.4,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.45,0,12,770.45,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.5,0,12,770.5,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.55,0,12,770.55,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.6,0,12,770.6,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.65,0,12,770.65,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.7,0,12,770.7,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.75,0,12,770.75,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.8,0,12,770.8,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.85,0,12,770.85,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.9,0,12,770.9,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850133.95,0,12,770.95,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.0,0,12,771.0,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.05,0,12,771.05,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.1,0,12,771.1,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.15,0,12,771.15,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.2,0,12,771.2,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.25,0,12,771.25,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.3,0,12,771.3,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.35,0,12,771.35,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.4,0,12,771.4,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785850134.45,0,12,771.45,8495.492,,,,1.0,,44.8318883,11.224395,,,0.0,20.0,0.0,0.0,0.0,0.0,0.0,34.0,5220.0,50.58889,,,,50.57638,0.09,0.089,0.122,49.83739,,, +1785851075.002,1,,0.002,0.00459,8.3984,-2.6948,297.44,,1.0,44.83179,11.2243317,8.006,0.68867,,20.0,,,,0.68867,0.0,37.0,0.0,51.43469,0.5069,-0.0051,0.89633,50.2803,-0.075,0.055,0.065,49.87213,16.56042,-17.31958,-18.27208 +1785851075.009,1,,0.009,0.02065,8.3928,-2.6766,297.44,,1.0,44.8317902,11.2243318,8.027,0.68753,,20.0,,,,0.68753,0.0,37.0,0.0,51.44265,0.50697,-0.0052,0.89623,50.27268,-0.094,0.074,0.065,49.86884,16.61,-17.34,-18.24 +1785851075.023,1,,0.023,0.05276,8.3816,-2.6402,297.44,,1.0,44.8317904,11.224332,8.069,0.68525,,20.0,,,,0.68525,0.0,37.0,0.0,51.45857,0.5071,-0.0054,0.89602,50.25744,-0.132,0.112,0.065,49.86267,16.659,-17.291,-18.443 +1785851075.029,1,,0.029,0.06653,8.3768,-2.6246,297.44,,1.0,44.8317905,11.2243321,8.087,0.68427,,20.0,,,,0.68427,0.0,37.0,0.0,51.46417,0.50704,-0.00586,0.89696,50.25144,-0.05968,0.02137,0.011,49.86002,16.68,-17.27,-18.53 +1785851075.042,1,,0.042,0.09635,8.3664,-2.5908,297.44,,1.0,44.8317908,11.2243322,8.126,0.68215,,20.0,,,,0.68215,0.0,37.0,0.0,51.47631,0.5069,-0.00683,0.89898,50.23845,0.097,-0.175,-0.106,49.85517,16.524,-17.3155,-18.647 +1785851075.049,1,,0.049,0.11241,8.3608,-2.5726,297.44,,1.0,44.8317909,11.2243323,8.147,0.68101,,20.0,,,,0.68101,0.0,37.0,0.0,51.48269,0.5074,-0.00648,0.89873,50.23216,0.07705,-0.175,-0.1263,49.85255,16.44,-17.34,-18.71 +1785851075.05,1,,0.05,0.1147,8.36,-2.57,297.44,,1.0,44.8317909,11.2243323,8.15,0.68085,,20.0,,,,0.68085,0.0,37.0,0.0,51.4836,0.50747,-0.00642,0.8987,50.23127,0.0742,-0.175,-0.1292,49.85219,16.44,-17.328,-18.71 +1785851075.062,1,,0.062,0.14223,8.3504,-2.5388,297.44,,1.0,44.8317911,11.2243325,8.186,0.67889,,20.0,,,,0.67889,0.0,37.0,0.0,51.49453,0.50833,-0.00581,0.89827,50.22049,0.04,-0.175,-0.164,49.84783,16.44,-17.184,-18.71 +1785851075.069,1,,0.069,0.15829,8.3448,-2.5206,297.44,,1.0,44.8317913,11.2243326,8.207,0.67775,,20.0,,,,0.67775,0.0,37.0,0.0,51.49992,0.50814,-0.00457,0.89808,50.21482,0.05995,-0.07455,-0.1437,49.84529,16.44,-17.1,-18.71 +1785851075.081,1,,0.081,0.18581,8.3352,-2.4894,297.44,,1.0,44.8317915,11.2243327,8.243,0.6758,,20.0,,,,0.6758,0.0,37.0,0.0,51.50916,0.50782,-0.00245,0.89776,50.20511,0.09415,0.09765,-0.1089,49.84096,16.44,-17.13789,-18.79211 +1785851075.082,1,,0.082,0.18811,8.3344,-2.4868,297.44,,1.0,44.8317915,11.2243328,8.246,0.67563,,20.0,,,,0.67563,0.0,37.0,0.0,51.50969,0.50776,-0.00209,0.8977,50.2043,0.097,0.112,-0.106,49.8406,16.44,-17.14105,-18.79895 +1785851075.088,1,,0.088,0.20187,8.3296,-2.4712,297.44,,1.0,44.8317916,11.2243328,8.264,0.67466,,20.0,,,,0.67466,0.0,37.0,0.0,51.51291,0.50741,0.00007,0.89735,50.19977,0.0454,0.0775,-0.1234,49.83844,16.44,-17.16,-18.84 +1785851075.1,1,,0.1,0.2294,8.32,-2.44,297.44,,1.0,44.8317918,11.224333,8.3,0.6727,,20.0,,,,0.6727,0.0,37.0,0.0,51.51934,0.50671,0.00438,0.89665,50.19071,-0.0578,0.0085,-0.1582,49.83449,16.4,-17.22286,-18.8 +1785851075.102,1,,0.102,0.23399,8.3184,-2.4348,297.44,,1.0,44.8317919,11.224333,8.306,0.67237,,20.0,,,,0.67237,0.0,37.0,0.0,51.52041,0.5066,0.0051,0.89653,50.1892,-0.075,-0.003,-0.164,49.83383,16.39333,-17.23333,-18.79333 +1785851075.105,1,,0.105,0.24087,8.316,-2.427,297.44,,1.0,44.8317919,11.2243331,8.315,0.67189,,20.0,,,,0.67189,0.0,37.0,0.0,51.52151,0.50679,0.00537,0.8965,50.18734,-0.05684,-0.012,-0.15484,49.83285,16.38333,-17.24905,-18.78333 +1785851075.109,1,,0.109,0.25005,8.3128,-2.4166,297.44,,1.0,44.831792,11.2243331,8.327,0.67123,,20.0,,,,0.67123,0.0,37.0,0.0,51.52298,0.50705,0.00574,0.89646,50.18487,-0.03263,-0.024,-0.14263,49.83153,16.37,-17.27,-18.77 +1785851075.121,1,,0.121,0.27757,8.3032,-2.3854,297.44,,1.0,44.8317922,11.2243333,8.363,0.66928,,20.0,,,,0.66928,0.0,37.0,0.0,51.52737,0.50782,0.00683,0.89633,50.17746,0.04,-0.06,-0.106,49.8282,16.556,-17.27,-18.734 +1785851075.129,1,,0.129,0.29593,8.2968,-2.3646,297.44,,1.0,44.8317924,11.2243334,8.387,0.66797,,20.0,,,,0.66797,0.0,37.0,0.0,51.52891,0.50782,0.00663,0.89682,50.17345,-0.006,-0.014,-0.0376,49.82598,16.68,-17.27,-18.71 +1785851075.141,1,,0.141,0.32345,8.2872,-2.3334,297.44,,1.0,44.8317926,11.2243335,8.423,0.66602,,20.0,,,,0.66602,0.0,37.0,0.0,51.53121,0.50782,0.00632,0.89755,50.16744,-0.075,0.055,0.065,49.82327,16.68,-17.348,-18.572 +1785851075.149,1,,0.149,0.34181,8.2808,-2.3126,297.44,,1.0,44.8317927,11.2243337,8.447,0.66471,,20.0,,,,0.66471,0.0,37.0,0.0,51.5314,0.5073,0.00624,0.89734,50.16441,-0.00258,0.055,0.065,49.82146,16.68,-17.4,-18.48 +1785851075.15,1,,0.15,0.3441,8.28,-2.31,297.44,,1.0,44.8317928,11.2243337,8.45,0.66455,,20.0,,,,0.66455,0.0,37.0,0.0,51.53143,0.50724,0.00623,0.89731,50.16404,0.00647,0.055,0.065,49.82129,16.683,-17.4025,-18.4825 +1785851075.16,1,,0.16,0.36704,8.272,-2.284,297.44,,1.0,44.8317929,11.2243338,8.48,0.66292,,20.0,,,,0.66292,0.0,37.0,0.0,51.53167,0.5066,0.00612,0.89704,50.16025,0.097,0.055,0.065,49.81955,16.713,-17.4275,-18.5075 +1785851075.169,1,,0.169,0.38769,8.2648,-2.2606,297.44,,1.0,44.8317931,11.2243339,8.507,0.66145,,20.0,,,,0.66145,0.0,37.0,0.0,51.53026,0.5066,0.00634,0.89696,50.1581,-0.00114,-0.01871,0.04057,49.81798,16.74,-17.45,-18.53 +1785851075.181,1,,0.181,0.41521,8.2552,-2.2294,297.44,,1.0,44.8317933,11.2243341,8.543,0.6595,,20.0,,,,0.6595,0.0,37.0,0.0,51.52838,0.5066,0.00663,0.89684,50.15523,-0.132,-0.117,0.008,49.81641,16.74,-17.636,-18.422 +1785851075.189,1,,0.189,0.43357,8.2488,-2.2086,297.44,,1.0,44.8317935,11.2243342,8.567,0.65819,,20.0,,,,0.65819,0.0,37.0,0.0,51.52577,0.50702,0.00611,0.89633,50.15428,-0.108,-0.069,0.10442,49.81537,16.74,-17.76,-18.35 +1785851075.195,1,,0.195,0.44733,8.244,-2.193,297.44,,1.0,44.8317936,11.2243343,8.585,0.65722,,20.0,,,,0.65722,0.0,37.0,0.0,51.52381,0.50735,0.00573,0.89594,50.15358,-0.09,-0.033,0.17674,49.81496,16.755,-17.739,-18.35 +1785851075.2,1,,0.2,0.4588,8.24,-2.18,297.44,,1.0,44.8317937,11.2243343,8.6,0.6564,,20.0,,,,0.6564,0.0,37.0,0.0,51.52218,0.50761,0.0054,0.89562,50.15299,-0.075,-0.003,0.237,49.81461,16.7675,-17.7215,-18.35 +1785851075.209,1,,0.209,0.47945,8.2328,-2.1566,297.44,,1.0,44.8317938,11.2243345,8.627,0.65493,,20.0,,,,0.65493,0.0,37.0,0.0,51.51759,0.50739,0.00265,0.89649,50.15349,-0.09943,0.04629,0.18814,49.81398,16.79,-17.69,-18.35 +1785851075.22,1,,0.22,0.50468,8.224,-2.128,297.44,,1.0,44.831794,11.2243346,8.66,0.65314,,20.0,,,,0.65314,0.0,37.0,0.0,51.51199,0.5071,-0.00071,0.89755,50.15411,-0.12929,0.10652,0.12843,49.81371,16.8615,-17.8275,-18.3885 +1785851075.221,1,,0.221,0.50697,8.2232,-2.1254,297.44,,1.0,44.8317941,11.2243346,8.663,0.65298,,20.0,,,,0.65298,0.0,37.0,0.0,51.51132,0.50713,-0.00093,0.8976,50.15416,-0.132,0.112,0.123,49.81369,16.868,-17.84,-18.392 +1785851075.229,1,,0.229,0.52533,8.2168,-2.1046,297.44,,1.0,44.8317942,11.2243347,8.687,0.65167,,20.0,,,,0.65167,0.0,37.0,0.0,51.506,0.50735,-0.00269,0.89799,50.15556,-0.05556,0.06089,0.14833,49.81349,16.92,-17.94,-18.42 +1785851075.239,1,,0.239,0.54827,8.2088,-2.0786,297.44,,1.0,44.8317944,11.2243349,8.717,0.65004,,20.0,,,,0.65004,0.0,37.0,0.0,51.49935,0.50761,-0.00489,0.89847,50.15731,0.04,-0.003,0.18,49.81383,16.92,-17.90818,-18.33818 +1785851075.25,1,,0.25,0.5735,8.2,-2.05,297.44,,1.0,44.8317946,11.224335,8.75,0.64825,,20.0,,,,0.64825,0.0,37.0,0.0,51.4904,0.50745,-0.00557,0.89847,50.16034,0.00865,0.0289,0.0854,49.81422,16.92,-17.87318,-18.24818 +1785851075.251,1,,0.251,0.57579,8.1992,-2.0474,297.44,,1.0,44.8317946,11.224335,8.753,0.64809,,20.0,,,,0.64809,0.0,37.0,0.0,51.48958,0.50743,-0.00563,0.89847,50.16061,0.0058,0.0318,0.0768,49.81425,16.92,-17.87,-18.24 +1785851075.259,1,,0.259,0.59415,8.1928,-2.0266,297.44,,1.0,44.8317947,11.2243351,8.777,0.64678,,20.0,,,,0.64678,0.0,37.0,0.0,51.48307,0.50731,-0.00612,0.89847,50.16281,-0.017,0.055,0.008,49.81479,17.0,-17.74111,-18.21333 +1785851075.269,1,,0.269,0.61709,8.1848,-2.0006,297.44,,1.0,44.8317949,11.2243353,8.807,0.64515,,20.0,,,,0.64515,0.0,37.0,0.0,51.47326,0.5072,-0.00521,0.89761,50.16694,-0.04753,0.02447,-0.022,49.81547,17.1,-17.58,-18.18 +1785851075.278,1,,0.278,0.63773,8.1776,-1.9772,297.44,,1.0,44.8317951,11.2243354,8.834,0.64369,,20.0,,,,0.64369,0.0,37.0,0.0,51.46443,0.5071,-0.00438,0.89684,50.17065,-0.075,-0.003,-0.049,49.81653,17.1495,-17.499,-18.18 +1785851075.289,1,,0.289,0.66297,8.1688,-1.9486,297.44,,1.0,44.8317953,11.2243355,8.867,0.64189,,20.0,,,,0.64189,0.0,37.0,0.0,51.4519,0.50685,-0.00525,0.89684,50.17659,0.011,0.0545,0.008,49.81782,17.21,-17.4,-18.18 +1785851075.3,1,,0.3,0.6882,8.16,-1.92,297.44,,1.0,44.8317955,11.2243357,8.9,0.6401,,20.0,,,,0.6401,0.0,37.0,0.0,51.43937,0.5066,-0.00612,0.89684,50.18253,0.097,0.112,0.065,49.81965,16.979,-17.3285,-18.213 +1785851075.3,1,,0.3,0.6882,8.16,-1.92,297.44,,1.0,44.8317955,11.2243357,8.9,0.6401,,20.0,,,,0.6401,0.0,37.0,0.0,51.43937,0.5066,-0.00612,0.89684,50.18253,0.097,0.112,0.065,49.81965,16.979,-17.3285,-18.213 +1785851075.309,1,,0.309,0.70885,8.1528,-1.8966,297.44,,1.0,44.8317957,11.2243358,8.927,0.63863,,20.0,,,,0.63863,0.0,37.0,0.0,51.42791,0.5066,-0.00525,0.89781,50.1882,0.0685,0.026,0.008,49.82114,16.79,-17.27,-18.24 +1785851075.318,1,,0.318,0.72949,8.1456,-1.8732,297.44,,1.0,44.8317958,11.2243359,8.954,0.63717,,20.0,,,,0.63717,0.0,37.0,0.0,51.41645,0.5066,-0.00438,0.89878,50.19387,0.04,-0.06,-0.049,49.8229,16.709,-17.162,-18.213 +1785851075.329,1,,0.329,0.75473,8.1368,-1.8446,297.44,,1.0,44.831796,11.2243361,8.987,0.63537,,20.0,,,,0.63537,0.0,37.0,0.0,51.40136,0.5074,-0.00219,0.89888,50.20203,0.10024,0.00024,-0.10924,49.82505,16.61,-17.03,-18.18 +1785851075.339,1,,0.339,0.77767,8.1288,-1.8186,297.44,,1.0,44.8317962,11.2243362,9.017,0.63374,,20.0,,,,0.63374,0.0,37.0,0.0,51.38764,0.50812,-0.0002,0.89898,50.20946,0.155,0.055,-0.164,49.8274,16.61,-16.91,-18.21 +1785851075.349,1,,0.349,0.80061,8.1208,-1.7926,297.44,,1.0,44.8317964,11.2243363,9.047,0.63211,,20.0,,,,0.63211,0.0,37.0,0.0,51.37295,0.50784,0.00223,0.89655,50.2178,0.02722,0.02278,-0.13233,49.82976,16.61,-16.79,-18.24 +1785851075.35,1,,0.35,0.8029,8.12,-1.79,297.44,,1.0,44.8317964,11.2243363,9.05,0.63195,,20.0,,,,0.63195,0.0,37.0,0.0,51.37148,0.50781,0.00248,0.8963,50.21863,0.01444,0.01956,-0.12917,49.83003,16.6135,-16.793,-18.225 +1785851075.357,1,,0.357,0.81896,8.1144,-1.7718,297.44,,1.0,44.8317965,11.2243364,9.071,0.63081,,20.0,,,,0.63081,0.0,37.0,0.0,51.3612,0.50761,0.00418,0.8946,50.22447,-0.075,-0.003,-0.107,49.83193,16.638,-16.814,-18.12 +1785851075.369,1,,0.369,0.84649,8.1048,-1.7406,297.44,,1.0,44.8317968,11.2243366,9.107,0.62885,,20.0,,,,0.62885,0.0,37.0,0.0,51.34255,0.50723,0.00602,0.89593,50.23536,-0.04336,-0.03409,-0.04482,49.8352,16.68,-16.85,-17.94 +1785851075.379,1,,0.379,0.86943,8.0968,-1.7146,297.44,,1.0,44.8317969,11.2243367,9.137,0.62722,,20.0,,,,0.62722,0.0,37.0,0.0,51.32702,0.5069,0.00755,0.89704,50.24443,-0.017,-0.06,0.007,49.83821,16.645,-16.765,-17.88 +1785851075.389,1,,0.389,0.89237,8.0888,-1.6886,297.44,,1.0,44.8317971,11.2243369,9.167,0.62559,,20.0,,,,0.62559,0.0,37.0,0.0,51.31075,0.50701,0.00743,0.89761,50.25408,-0.017,0.00333,0.007,49.84123,16.61,-16.68,-17.82 +1785853456.67,2,29,672.67,5555.99541,2.667,0.365,132.2,1.0,1.0,44.830427,11.2237343,19.0,7.26131,0.30703,20.0,-0.25888,14.34452,-0.16505,7.26131,0.0,39.0,6420.0,50.69628,0.79752,-0.06179,0.16754,50.6946,-34.24,12.98,-18.856,50.04008,22.71,-28.62,-3.5525 +1785853456.675,2,29,672.675,5556.03803,2.6675,0.3625,132.2,1.0,1.0,44.8304266,11.2237341,19.0,7.25278,0.3081,20.0,-0.2601,14.4106,-0.16513,7.25278,0.0,39.0,6420.0,50.69707,0.81857,-0.08122,0.17062,50.69525,-31.40238,-6.75976,-21.61171,50.04075,22.74,-28.56,-3.6 +1785853456.691,2,29,672.691,5556.17439,2.6691,0.3545,132.2,1.0,1.0,44.8304255,11.2237335,19.0,7.22546,0.31152,20.0,-0.26398,14.62206,-0.1654,7.22546,0.0,39.0,6420.0,50.69961,0.88593,-0.14337,0.18049,50.69733,-22.322,-69.927,-30.43,50.04238,22.884,-28.792,-3.84 +1785853456.695,2,29,672.695,5556.20849,2.6695,0.3525,132.2,1.0,1.0,44.8304252,11.2237334,19.0,7.21863,0.31238,20.0,-0.26495,14.67492,-0.16546,7.21863,0.0,39.0,6420.0,50.70021,0.86146,-0.12844,0.16952,50.6978,-24.48644,-51.21033,-25.71889,50.04278,22.92,-28.85,-3.9 +1785853456.7,2,29,672.7,5556.2511,2.67,0.35,132.2,1.0,1.0,44.8304248,11.2237332,19.0,7.2101,0.31345,20.0,-0.26617,14.741,-0.16555,7.2101,0.0,39.0,6420.0,50.70096,0.83086,-0.10977,0.15581,50.69838,-27.192,-27.8145,-19.83,50.04314,23.04,-28.8675,-3.825 +1785853456.709,2,29,672.709,5556.32781,2.6709,0.3455,132.2,1.0,1.0,44.8304242,11.2237328,19.0,7.19474,0.31533,20.0,-0.2683,14.85691,-0.16565,7.19474,0.0,39.0,6420.0,50.70231,0.7758,-0.07617,0.13114,50.69944,-32.062,14.298,-9.23,50.04378,23.256,-28.899,-3.69 +1785853456.715,2,29,672.715,5556.37895,2.6715,0.3425,132.2,1.0,1.0,44.8304238,11.2237326,19.0,7.18449,0.31658,20.0,-0.26972,14.93418,-0.16572,7.18449,0.0,39.0,6420.0,50.70318,0.81598,-0.06082,0.07193,50.70012,-29.91771,-8.76771,-13.78114,50.04421,23.4,-28.92,-3.6 +1785853456.73,2,29,672.73,5556.50679,2.673,0.335,132.2,1.0,1.0,44.8304227,11.223732,19.0,7.15889,0.3197,20.0,-0.27328,15.12735,-0.1659,7.15889,0.0,39.0,6420.0,50.70536,0.91642,-0.02243,-0.07607,50.70183,-24.557,-66.432,-25.159,50.04498,23.4,-28.65,-3.645 +1785853456.735,2,29,672.735,5556.54941,2.6735,0.3325,132.2,1.0,1.0,44.8304223,11.2237318,19.0,7.15035,0.32075,20.0,-0.27446,15.19174,-0.16595,7.15035,0.0,39.0,6420.0,50.70601,0.91301,-0.01138,-0.05895,50.70234,-27.84384,-49.40911,-19.45953,50.04523,23.4,-28.56,-3.66 +1785853456.749,2,29,672.749,5556.66873,2.6749,0.3255,132.2,1.0,1.0,44.8304213,11.2237313,19.0,7.12646,0.32367,20.0,-0.27778,15.37204,-0.16612,7.12646,0.0,39.0,6420.0,50.70781,0.90347,0.01958,-0.01101,50.70376,-37.047,-1.745,-3.501,50.04545,23.68,-28.6,-3.85333 +1785853456.75,2,29,672.75,5556.67725,2.675,0.325,132.2,1.0,1.0,44.8304213,11.2237313,19.0,7.12475,0.32387,20.0,-0.27802,15.38492,-0.16613,7.12475,0.0,39.0,6420.0,50.70792,0.89586,0.00932,-0.00494,50.70385,-36.68414,-2.65081,-4.09852,50.04547,23.7,-28.60286,-3.86714 +1785853456.756,2,29,672.756,5556.72839,2.6756,0.322,132.2,1.0,1.0,44.8304208,11.223731,19.0,7.11451,0.32507,20.0,-0.27939,15.45947,-0.16616,7.11451,0.0,39.0,6420.0,50.7086,0.85022,-0.05223,0.03149,50.7044,-34.507,-8.08567,-7.68367,50.04556,23.82,-28.62,-3.95 +1785853456.769,2,29,672.769,5556.83919,2.6769,0.3155,132.2,1.0,1.0,44.8304199,11.2237305,19.0,7.09232,0.32768,20.0,-0.28237,15.621,-0.16623,7.09232,0.0,39.0,6420.0,50.71008,0.75133,-0.18559,0.11044,50.70559,-29.78986,-19.86119,-15.45148,50.04551,24.02526,-28.57895,-4.36737 +1785853456.77,2,29,672.77,5556.84771,2.677,0.315,132.2,1.0,1.0,44.8304198,11.2237305,19.0,7.09061,0.32788,20.0,-0.2826,15.63342,-0.16623,7.09061,0.0,39.0,6420.0,50.7102,0.75788,-0.17615,0.10903,50.70568,-29.427,-20.767,-16.049,50.04551,24.04105,-28.57579,-4.39947 +1785853456.775,2,29,672.775,5556.89032,2.6775,0.3125,132.2,1.0,1.0,44.8304195,11.2237303,19.0,7.08208,0.32888,20.0,-0.28375,15.69555,-0.16626,7.08208,0.0,39.0,6420.0,50.71082,0.79067,-0.12896,0.10199,50.70616,-27.36425,-22.5145,-13.58525,50.04549,24.12,-28.56,-4.56 +1785853456.789,2,29,672.789,5557.00965,2.6789,0.3055,132.2,1.0,1.0,44.8304185,11.2237298,19.0,7.05818,0.33168,20.0,-0.28695,15.8695,-0.16633,7.05818,0.0,39.0,6420.0,50.71255,0.88246,0.00316,0.08229,50.70751,-21.58855,-27.4075,-6.68675,50.04515,24.414,-28.518,-5.022 +1785853456.79,2,29,672.79,5557.01817,2.679,0.305,132.2,1.0,1.0,44.8304184,11.2237297,19.0,7.05647,0.33188,20.0,-0.28718,15.88193,-0.16633,7.05647,0.0,39.0,6420.0,50.71264,0.88133,0.00449,0.08436,50.7076,-21.176,-27.757,-6.194,50.04513,24.435,-28.515,-5.055 +1785853456.795,2,29,672.795,5557.06079,2.6795,0.3025,132.2,1.0,1.0,44.830418,11.2237295,19.0,7.04794,0.33288,20.0,-0.28833,15.94405,-0.16636,7.04794,0.0,39.0,6420.0,50.71308,0.87564,0.01111,0.09468,50.70796,-23.88995,-19.20779,-8.27453,50.04501,24.54,-28.5,-5.22 +1785853456.8,2,29,672.8,5557.1034,2.68,0.3,132.2,1.0,1.0,44.8304177,11.2237293,19.0,7.0394,0.33388,20.0,-0.28947,16.00618,-0.16638,7.0394,0.0,39.0,6420.0,50.71353,0.86996,0.01774,0.10501,50.70832,-26.60389,-10.65858,-10.35505,50.04468,24.67636,-28.55455,-5.28818 +1785853456.809,2,29,672.809,5557.18011,2.6809,0.2955,132.2,1.0,1.0,44.830417,11.223729,19.0,7.02404,0.33558,20.0,-0.29144,16.1128,-0.16635,7.02404,0.0,39.0,6420.0,50.71433,0.85972,0.02967,0.12359,50.70896,-31.489,4.73,-14.1,50.04409,24.92182,-28.65273,-5.41091 +1785853456.817,2,29,672.817,5557.24829,2.6817,0.2915,132.2,1.0,1.0,44.8304164,11.2237287,19.0,7.01038,0.3371,20.0,-0.29319,16.20758,-0.16632,7.01038,0.0,39.0,6420.0,50.71505,0.8723,0.03371,0.215,50.70947,-34.553,-18.86368,-12.82126,50.04356,25.14,-28.74,-5.52 +1785853456.828,2,29,672.828,5557.34204,2.6828,0.286,132.2,1.0,1.0,44.8304157,11.2237283,19.0,6.9916,0.33917,20.0,-0.2956,16.3379,-0.16629,6.9916,0.0,39.0,6420.0,50.71605,0.8896,0.03926,0.34069,50.71018,-38.766,-51.305,-11.063,50.04271,25.41789,-28.91368,-5.62421 +1785853456.836,2,29,672.836,5557.41023,2.6836,0.282,132.2,1.0,1.0,44.8304151,11.223728,19.0,6.97795,0.34069,20.0,-0.29735,16.43268,-0.16626,6.97795,0.0,39.0,6420.0,50.7166,0.9252,0.07805,0.25347,50.71059,-43.93291,-17.24027,-10.20882,50.0421,25.62,-29.04,-5.7 +1785853456.85,2,29,672.85,5557.52955,2.685,0.275,132.2,1.0,1.0,44.8304141,11.2237274,19.0,6.95405,0.34333,20.0,-0.30042,16.59855,-0.16621,6.95405,0.0,39.0,6420.0,50.71757,0.98749,0.14592,0.10085,50.7113,-52.975,42.373,-8.714,50.04078,25.88727,-29.04,-6.04364 +1785853456.858,2,29,672.858,5557.59773,2.6858,0.271,132.2,1.0,1.0,44.8304135,11.2237271,19.0,6.94039,0.34473,20.0,-0.30207,16.68775,-0.1661,6.94039,0.0,39.0,6420.0,50.71818,0.90141,0.05486,0.06393,50.71176,-39.22384,-7.20258,-11.46432,50.04002,26.04,-29.04,-6.24 +1785853456.869,2,29,672.869,5557.69149,2.6869,0.2655,132.2,1.0,1.0,44.8304127,11.2237267,19.0,6.92162,0.34666,20.0,-0.30434,16.81042,-0.16596,6.92162,0.0,39.0,6420.0,50.71903,0.78304,-0.07036,0.01315,50.71238,-20.316,-75.369,-15.246,50.03889,26.24842,-29.06895,-6.61632 +1785853456.877,2,29,672.877,5557.75967,2.6877,0.2615,132.2,1.0,1.0,44.8304121,11.2237264,19.0,6.90796,0.34806,20.0,-0.306,16.89962,-0.16585,6.90796,0.0,39.0,6420.0,50.71946,0.74991,-0.05532,0.056,50.71271,-23.4847,-41.9283,-10.28357,50.03806,26.4,-29.09,-6.89 +1785853456.892,2,29,672.892,5557.88752,2.6892,0.254,132.2,1.0,1.0,44.8304111,11.2237258,19.0,6.88236,0.35069,20.0,-0.3091,17.06689,-0.16564,6.88236,0.0,39.0,6420.0,50.72026,0.6878,-0.02712,0.13634,50.71332,-29.426,20.773,-0.979,50.03578,27.05,-29.29833,-7.64833 +1785853456.895,2,29,672.895,5557.91309,2.6895,0.2525,132.2,1.0,1.0,44.8304109,11.2237257,19.0,6.87724,0.35121,20.0,-0.30972,17.10034,-0.1656,6.87724,0.0,39.0,6420.0,50.72038,0.71307,-0.02299,0.14406,50.71342,-28.23369,7.91369,-3.75081,50.03532,27.18,-29.34,-7.8 +1785853456.9,2,29,672.9,5557.9557,2.69,0.25,132.2,1.0,1.0,44.8304105,11.2237255,19.0,6.8687,0.35209,20.0,-0.31075,17.15609,-0.16553,6.8687,0.0,39.0,6420.0,50.72058,0.7552,-0.01611,0.15693,50.71359,-26.2465,-13.5185,-8.3705,50.03469,27.465,-29.37,-8.0075 +1785853456.908,2,29,672.908,5558.02388,2.6908,0.246,132.2,1.0,1.0,44.8304099,11.2237252,19.0,6.85504,0.35336,20.0,-0.31229,17.23894,-0.16533,6.85504,0.0,39.0,6420.0,50.72089,0.82261,-0.0051,0.17753,50.71385,-23.067,-47.81,-15.762,50.03368,27.921,-29.418,-8.3395 +1785853456.915,2,29,672.915,5558.08354,2.6915,0.2425,132.2,1.0,1.0,44.8304094,11.2237249,19.0,6.8431,0.35448,20.0,-0.31364,17.31142,-0.16516,6.8431,0.0,39.0,6420.0,50.72112,0.78356,0.02613,0.06593,50.71402,-30.78765,-13.8796,-10.42765,50.0328,28.32,-29.46,-8.63 +1785853456.928,2,29,672.928,5558.19434,2.6928,0.236,132.2,1.0,1.0,44.8304085,11.2237244,19.0,6.8209,0.35655,20.0,-0.31615,17.44604,-0.16483,6.8209,0.0,39.0,6420.0,50.72154,0.71105,0.08413,-0.14133,50.71435,-45.126,49.134,-0.521,50.03065,29.178,-29.4925,-9.098 +1785853456.935,2,29,672.935,5558.25401,2.6935,0.2325,132.2,1.0,1.0,44.830408,11.2237242,19.0,6.80896,0.35766,20.0,-0.31749,17.51852,-0.16465,6.80896,0.0,39.0,6420.0,50.72169,0.72643,0.03821,-0.11425,50.71446,-26.09728,1.31778,-4.91039,50.0295,29.64,-29.51,-9.35 +1785853456.946,2,29,672.946,5558.34776,2.6946,0.227,132.2,1.0,1.0,44.8304072,11.2237237,19.0,6.79018,0.35941,20.0,-0.31961,17.63243,-0.16438,6.79018,0.0,39.0,6420.0,50.72192,0.75061,-0.03396,-0.07169,50.71464,3.805,-73.822,-11.808,50.02779,30.234,-29.6475,-10.1145 +1785853456.95,2,29,672.95,5558.38185,2.695,0.225,132.2,1.0,1.0,44.8304069,11.2237236,19.0,6.78335,0.36005,20.0,-0.32038,17.67385,-0.16428,6.78335,0.0,39.0,6420.0,50.72201,0.73057,-0.03036,-0.00848,50.71471,2.44081,-58.94695,-9.2979,50.02717,30.45,-29.6975,-10.3925 +1785853456.955,2,29,672.955,5558.42447,2.6955,0.2225,132.2,1.0,1.0,44.8304066,11.2237234,19.0,6.77481,0.36075,20.0,-0.32127,17.72131,-0.16409,6.77481,0.0,39.0,6420.0,50.72213,0.70551,-0.02587,0.07052,50.71481,0.73557,-40.35314,-6.16029,50.0264,30.72,-29.76,-10.74 +1785853456.967,2,29,672.967,5558.52674,2.6967,0.2165,132.2,1.0,1.0,44.8304057,11.2237229,19.0,6.75433,0.36245,20.0,-0.3234,17.83521,-0.16363,6.75433,0.0,39.0,6420.0,50.7224,0.64538,-0.01509,0.26013,50.71503,-3.357,4.272,1.37,50.02431,31.656,-29.862,-11.346 +1785853456.975,2,29,672.975,5558.59493,2.6975,0.2125,132.2,1.0,1.0,44.8304051,11.2237226,19.0,6.74067,0.36359,20.0,-0.32482,17.91115,-0.16333,6.74067,0.0,39.0,6420.0,50.72268,0.68399,-0.01477,0.29661,50.71529,3.82433,-15.056,-4.43622,50.02292,32.28,-29.93,-11.75 +1785853456.985,2,29,672.985,5558.68016,2.6985,0.2075,132.2,1.0,1.0,44.8304044,11.2237222,19.0,6.7236,0.365,20.0,-0.3266,18.00607,-0.16295,6.7236,0.0,39.0,6420.0,50.72302,0.73226,-0.01438,0.34222,50.71562,12.801,-39.216,-11.694,50.02112,33.175,-29.93,-12.325 +1785853456.995,2,29,672.995,5558.76539,2.6995,0.2025,132.2,1.0,1.0,44.8304037,11.2237219,19.0,6.70653,0.36642,20.0,-0.32837,18.10099,-0.16258,6.70653,0.0,39.0,6420.0,50.72306,0.7561,0.06094,0.12604,50.71564,1.9691,-11.55029,-5.4459,50.01933,34.07,-29.93,-12.9 +1785853457.0,2,29,673.0,5558.808,2.7,0.2,161.0,1.0,1.0,44.8304033,11.2237217,19.0,6.698,0.36713,20.0,-0.32926,18.14845,-0.16239,6.698,0.0,39.0,6420.0,50.72307,0.76802,0.09859,0.01795,50.71566,-3.44686,2.28257,-2.32186,50.0184,34.5225,-29.9625,-13.08 +1785853457.006,2,29,673.006,5558.87193,2.7012,0.2,161.0,1.0,1.0,44.830403,11.223721,19.0,6.69445,0.36787,20.0,-0.33023,18.20008,-0.16208,6.69445,0.0,39.0,6420.0,50.72309,0.78233,0.14378,-0.11176,50.71567,-9.946,18.882,1.427,50.01728,35.0655,-30.0015,-13.296 +1785853457.015,2,29,673.015,5558.96783,2.703,0.2,161.0,1.0,1.0,44.8304026,11.2237199,19.0,6.68914,0.36898,20.0,-0.33169,18.27753,-0.16163,6.68914,0.0,39.0,6420.0,50.72311,0.73431,0.04954,0.08014,50.71569,-3.73079,8.81289,-7.01358,50.01561,35.88,-30.06,-13.62 +1785853457.025,2,29,673.025,5559.07438,2.705,0.2,161.0,1.0,1.0,44.8304021,11.2237188,19.0,6.68323,0.37022,20.0,-0.33331,18.36359,-0.16112,6.68323,0.0,39.0,6420.0,50.72312,0.68097,-0.05517,0.29337,50.7157,3.175,-2.375,-16.392,50.01374,36.63,-30.205,-13.98 +1785853457.035,2,29,673.035,5559.18093,2.707,0.2,161.0,1.0,1.0,44.8304016,11.2237176,19.0,6.67732,0.37145,20.0,-0.33493,18.44965,-0.16061,6.67732,0.0,39.0,6420.0,50.72318,0.73618,0.01086,0.18941,50.71578,-1.9815,-2.4605,-11.4645,50.01188,37.38,-30.35,-14.34 +1785853457.045,2,29,673.045,5559.28747,2.709,0.2,161.0,1.0,1.0,44.8304012,11.2237164,19.0,6.67141,0.37269,20.0,-0.33655,18.5357,-0.1601,6.67141,0.0,39.0,6420.0,50.72323,0.7914,0.07689,0.08545,50.71586,-7.138,-2.546,-6.537,50.00992,38.15143,-30.44048,-14.65429 +1785853457.05,2,29,673.05,5559.34075,2.71,0.2,161.0,1.0,1.0,44.8304009,11.2237158,19.0,6.66845,0.37331,20.0,-0.33736,18.57873,-0.15985,6.66845,0.0,39.0,6420.0,50.72325,0.74224,0.10662,0.37409,50.71589,-2.79563,-2.04863,-8.15042,50.00894,38.53714,-30.48571,-14.81143 +1785853457.056,2,29,673.056,5559.40468,2.7112,0.2,161.0,1.0,1.0,44.8304006,11.2237151,19.0,6.6649,0.37395,20.0,-0.33824,18.62519,-0.15947,6.6649,0.0,39.0,6420.0,50.72329,0.68325,0.1423,0.72045,50.71593,2.41521,-1.45179,-10.08653,50.00776,39.0,-30.54,-15.0 +1785853457.064,2,29,673.064,5559.48992,2.7128,0.2,161.0,1.0,1.0,44.8304002,11.2237142,19.0,6.66018,0.3748,20.0,-0.33941,18.68713,-0.15896,6.66018,0.0,39.0,6420.0,50.72333,0.60459,0.18987,1.18226,50.71599,9.363,-0.656,-12.668,50.0063,39.60211,-30.59053,-15.25263 +1785853457.075,2,29,673.075,5559.60713,2.715,0.2,161.0,1.0,1.0,44.8303997,11.2237129,19.0,6.65367,0.37597,20.0,-0.34102,18.7723,-0.15827,6.65367,0.0,39.0,6420.0,50.72343,0.61642,0.1087,0.74266,50.71612,1.33396,-9.97252,-13.65417,50.00429,40.43,-30.66,-15.6 +1785853457.086,2,29,673.086,5559.72433,2.7172,0.2,161.0,1.0,1.0,44.8303992,11.2237116,19.0,6.64717,0.37714,20.0,-0.34264,18.85746,-0.15757,6.64717,0.0,39.0,6420.0,50.72354,0.62825,0.02753,0.30306,50.71626,-6.69509,-19.28904,-14.64035,50.00224,41.1945,-30.759,-15.798 +1785853457.087,2,29,673.087,5559.73499,2.7174,0.2,161.0,1.0,1.0,44.8303991,11.2237115,19.0,6.64658,0.37725,20.0,-0.34279,18.86521,-0.15751,6.64658,0.0,39.0,6420.0,50.72354,0.64005,0.04079,0.28798,50.71627,-7.425,-20.136,-14.73,50.00205,41.264,-30.768,-15.816 +1785853457.095,2,29,673.095,5559.82023,2.719,0.2,161.0,1.0,1.0,44.8303987,11.2237106,19.0,6.64185,0.3781,20.0,-0.34396,18.92715,-0.157,6.64185,0.0,39.0,6420.0,50.72355,0.7345,0.14684,0.16739,50.71628,-6.04994,-19.86635,-15.78176,50.00056,41.82,-30.84,-15.96 +1785853457.1,2,29,673.1,5559.8735,2.72,0.2,161.0,1.0,1.0,44.8303985,11.22371,19.0,6.6389,0.37863,20.0,-0.34469,18.96586,-0.15668,6.6389,0.0,39.0,6420.0,50.72356,0.79353,0.21312,0.09201,50.71629,-5.19053,-19.69782,-16.43912,49.99966,42.0425,-30.855,-15.9275 +1785853457.104,2,29,673.104,5559.91612,2.7208,0.2,161.0,1.0,1.0,44.8303983,11.2237095,19.0,6.63654,0.379,20.0,-0.34522,18.99365,-0.15638,6.63654,0.0,39.0,6420.0,50.72357,0.84076,0.26615,0.03171,50.71629,-4.503,-19.563,-16.965,49.99894,42.2205,-30.867,-15.9015 +1785853457.115,2,29,673.115,5560.03333,2.723,0.2,161.0,1.0,1.0,44.8303978,11.2237083,19.0,6.63003,0.38,20.0,-0.34668,19.07006,-0.15556,6.63003,0.0,39.0,6420.0,50.72364,0.88248,0.35829,-0.09823,50.71641,-11.43575,-29.17425,-15.48385,49.99696,42.71,-30.9,-15.83 +1785853457.124,2,29,673.124,5560.12922,2.7248,0.2,161.0,1.0,1.0,44.8303973,11.2237072,19.0,6.62472,0.38081,20.0,-0.34788,19.13258,-0.15488,6.62472,0.0,39.0,6420.0,50.7237,0.91662,0.43369,-0.20456,50.7165,-17.108,-37.038,-14.272,49.99522,42.7955,-30.9,-15.8615 +1785853457.135,2,29,673.135,5560.24643,2.727,0.2,161.0,1.0,1.0,44.8303968,11.2237059,19.0,6.61822,0.38181,20.0,-0.34934,19.20899,-0.15406,6.61822,0.0,39.0,6420.0,50.72371,0.96486,0.44642,0.17811,50.71657,-20.44815,-7.47935,-11.81405,49.9931,42.9,-30.9,-15.9 +1785853457.144,2,29,673.144,5560.34232,2.7288,0.2,161.0,1.0,1.0,44.8303964,11.2237049,19.0,6.6129,0.38263,20.0,-0.35053,19.27151,-0.15339,6.6129,0.0,39.0,6420.0,50.72372,1.00432,0.45683,0.4912,50.71662,-23.181,16.705,-9.803,49.99144,42.95143,-30.82286,-15.92571 +1785853457.15,2,29,673.15,5560.40625,2.73,0.2,161.0,1.0,1.0,44.8303961,11.2237042,19.0,6.60935,0.38317,20.0,-0.35133,19.3132,-0.15294,6.60935,0.0,39.0,6420.0,50.72375,1.06412,0.38812,0.51625,50.71665,-25.2609,0.943,-7.9982,49.99034,42.98571,-30.77143,-15.94286 +1785853457.156,2,29,673.156,5560.47018,2.7312,0.2,161.0,1.0,1.0,44.8303958,11.2237035,19.0,6.6058,0.38364,20.0,-0.35205,19.3507,-0.15243,6.6058,0.0,39.0,6420.0,50.72378,1.12393,0.31942,0.54131,50.71667,-27.3408,-14.819,-6.1934,49.98923,43.02,-30.72,-15.96 +1785853457.164,2,29,673.164,5560.55542,2.7328,0.2,161.0,1.0,1.0,44.8303954,11.2237025,19.0,6.60108,0.38426,20.0,-0.35302,19.4007,-0.15174,6.60108,0.0,39.0,6420.0,50.72381,1.20367,0.2278,0.57471,50.7167,-30.114,-35.835,-3.787,49.98773,43.04526,-30.56421,-15.98526 +1785853457.175,2,29,673.175,5560.67262,2.735,0.2,161.0,1.0,1.0,44.8303949,11.2237013,19.0,6.59458,0.38511,20.0,-0.35434,19.46945,-0.15081,6.59458,0.0,39.0,6420.0,50.72375,1.17759,0.17649,0.51078,50.71672,-35.8494,-11.3182,-5.77195,49.98565,43.08,-30.35,-16.02 +1785853457.184,2,29,673.184,5560.76852,2.7368,0.2,161.0,1.0,1.0,44.8303944,11.2237002,19.0,6.58926,0.38581,20.0,-0.35543,19.5257,-0.15004,6.58926,0.0,39.0,6420.0,50.72369,1.15626,0.1345,0.45846,50.71674,-40.542,8.741,-7.396,49.98394,42.9135,-30.1925,-16.128 +1785853457.195,2,29,673.195,5560.88573,2.739,0.2,161.0,1.0,1.0,44.8303939,11.2236989,19.0,6.58275,0.38666,20.0,-0.35675,19.59446,-0.14911,6.58275,0.0,39.0,6420.0,50.72368,1.1817,0.08048,0.42393,50.71687,-41.7707,-15.90175,-2.9531,49.98184,42.71,-30.0,-16.26 +1785853457.2,2,29,673.2,5560.939,2.74,0.2,161.0,1.0,1.0,44.8303937,11.2236983,19.0,6.5798,0.38705,20.0,-0.35736,19.62571,-0.14868,6.5798,0.0,39.0,6420.0,50.72367,1.19327,0.05593,0.40823,50.71693,-42.3292,-27.103,-0.9336,49.98105,42.51909,-30.0,-16.16227 +1785853457.203,2,29,673.203,5560.97096,2.7406,0.2,161.0,1.0,1.0,44.8303935,11.223698,19.0,6.57803,0.38725,20.0,-0.35769,19.64273,-0.1484,6.57803,0.0,39.0,6420.0,50.72367,1.20021,0.0412,0.39881,50.71696,-42.6643,-33.82375,0.2781,49.98057,42.40455,-30.0,-16.10364 +1785853457.204,2,29,673.204,5560.98162,2.7408,0.2,161.0,1.0,1.0,44.8303935,11.2236979,19.0,6.57744,0.38732,20.0,-0.3578,19.6484,-0.14831,6.57744,0.0,39.0,6420.0,50.72368,1.19309,0.04056,0.39604,50.71697,-42.776,-36.064,0.682,49.98041,42.36636,-30.0,-16.08409 +1785853457.217,2,29,673.217,5561.12014,2.7434,0.2,161.0,1.0,1.0,44.8303928,11.2236963,19.0,6.56975,0.38819,20.0,-0.35923,19.72214,-0.14709,6.56975,0.0,39.0,6420.0,50.72387,1.10055,0.03222,0.36006,50.71713,-48.77225,-3.291,0.2725,49.97836,41.87,-30.0,-15.83 +1785853457.224,2,29,673.224,5561.19472,2.7448,0.2,161.0,1.0,1.0,44.8303925,11.2236955,19.0,6.56562,0.38866,20.0,-0.36001,19.76185,-0.14643,6.56562,0.0,39.0,6420.0,50.72397,1.05072,0.02774,0.34069,50.71722,-52.001,14.356,0.052,49.97712,41.28667,-29.86,-15.71722 +1785853457.235,2,29,673.235,5561.31193,2.747,0.2,161.0,1.0,1.0,44.830392,11.2236943,19.0,6.55911,0.3894,20.0,-0.36122,19.82425,-0.14541,6.55911,0.0,39.0,6420.0,50.72402,1.07651,-0.06772,0.46654,50.71737,-54.45895,-11.10625,1.7537,49.97519,40.37,-29.64,-15.54 +1785853457.244,2,29,673.244,5561.40782,2.7488,0.2,161.0,1.0,1.0,44.8303915,11.2236932,19.0,6.5538,0.39,20.0,-0.36221,19.8753,-0.14456,6.5538,0.0,39.0,6420.0,50.72405,1.09762,-0.14582,0.56951,50.71749,-56.47,-31.939,3.146,49.97364,39.71652,-29.47565,-15.54 +1785853457.25,2,29,673.25,5561.47175,2.75,0.2,161.0,1.0,1.0,44.8303913,11.2236925,19.0,6.55025,0.3904,20.0,-0.36287,19.90933,-0.144,6.55025,0.0,39.0,6420.0,50.72407,0.9912,-0.12043,0.66148,50.71756,-49.14965,-28.94606,0.53741,49.97261,39.28087,-29.36609,-15.54 +1785853457.258,2,29,673.258,5561.55699,2.7516,0.2,161.0,1.0,1.0,44.8303909,11.2236916,19.0,6.54552,0.39088,20.0,-0.36369,19.95109,-0.1432,6.54552,0.0,39.0,6420.0,50.72411,0.84931,-0.08657,0.7841,50.71764,-39.38918,-24.95547,-2.94071,49.97123,38.7,-29.22,-15.54 +1785853457.26,2,29,673.26,5561.5783,2.752,0.2,161.0,1.0,1.0,44.8303908,11.2236913,19.0,6.54434,0.391,20.0,-0.3639,19.96153,-0.143,6.54434,0.0,39.0,6420.0,50.72412,0.81384,-0.07811,0.81475,50.71766,-36.94906,-23.95782,-3.81024,49.9709,38.54471,-29.20471,-15.51882 +1785853457.261,2,29,673.261,5561.58895,2.7522,0.2,161.0,1.0,1.0,44.8303907,11.2236912,19.0,6.54375,0.39106,20.0,-0.364,19.96674,-0.1429,6.54375,0.0,39.0,6420.0,50.72411,0.80587,-0.06961,0.78815,50.71767,-35.729,-23.459,-4.245,49.97074,38.46706,-29.19706,-15.50824 +1785853457.275,2,29,673.275,5561.73813,2.755,0.2,161.0,1.0,1.0,44.83039,11.2236896,19.0,6.53548,0.39189,20.0,-0.36543,20.03982,-0.1415,6.53548,0.0,39.0,6420.0,50.72407,0.6944,0.04938,0.41573,50.71778,-12.68564,-21.30809,0.31264,49.96846,37.38,-29.09,-15.36 +1785853457.283,2,29,673.283,5561.82337,2.7566,0.2,161.0,1.0,1.0,44.8303897,11.2236887,19.0,6.53075,0.39236,20.0,-0.36625,20.08157,-0.1407,6.53075,0.0,39.0,6420.0,50.72405,0.63069,0.11737,0.20292,50.71784,0.482,-20.079,2.917,49.96742,37.064,-29.07,-15.332 +1785853457.295,2,29,673.295,5561.95123,2.759,0.2,161.0,1.0,1.0,44.8303891,11.2236873,19.0,6.52366,0.39307,20.0,-0.36748,20.1442,-0.13949,6.52366,0.0,39.0,6420.0,50.72429,0.6569,0.13551,0.51949,50.71818,-6.83871,-2.32394,2.79559,49.96585,36.59,-29.04,-15.29 +1785853457.3,2,29,673.3,5562.0045,2.76,0.2,161.0,1.0,1.0,44.8303888,11.2236867,19.0,6.5207,0.39337,20.0,-0.36799,20.1703,-0.13899,6.5207,0.0,39.0,6420.0,50.7244,0.66781,0.14307,0.65139,50.71833,-9.889,5.074,2.745,49.96516,36.5175,-29.04,-15.3225 +1785853457.3,2,29,673.3,5562.0045,2.76,0.2,161.0,1.0,1.0,44.8303888,11.2236867,19.0,6.5207,0.39337,20.0,-0.36799,20.1703,-0.13899,6.5207,0.0,39.0,6420.0,50.7244,0.66781,0.14307,0.65139,50.71833,-9.889,5.074,2.745,49.96516,36.5175,-29.04,-15.3225 +1785853457.315,2,29,673.315,5562.16433,2.763,0.2,161.0,1.0,1.0,44.8303881,11.2236849,19.0,6.51183,0.39418,20.0,-0.36944,20.24352,-0.13742,6.51183,0.0,39.0,6420.0,50.72459,0.77488,0.12442,0.58645,50.71863,-24.73092,-7.48735,3.43904,49.9631,36.3,-29.04,-15.42 +1785853457.326,2,29,673.326,5562.28153,2.7652,0.2,161.0,1.0,1.0,44.8303876,11.2236836,19.0,6.50533,0.39478,20.0,-0.3705,20.29722,-0.13626,6.50533,0.0,39.0,6420.0,50.72473,0.8534,0.11074,0.53882,50.71886,-35.615,-16.699,3.948,49.96176,36.10619,-29.06619,-15.73429 +1785853457.336,2,29,673.336,5562.38808,2.7672,0.2,161.0,1.0,1.0,44.8303871,11.2236825,19.0,6.49942,0.39532,20.0,-0.37147,20.34603,-0.13521,6.49942,0.0,39.0,6420.0,50.72482,0.78559,0.06369,0.5512,50.71906,-16.38,-19.52257,2.06514,49.96054,35.93,-29.09,-16.02 +1785853457.34,2,29,673.34,5562.4307,2.768,0.2,161.0,1.0,1.0,44.8303869,11.223682,19.0,6.49706,0.39554,20.0,-0.37185,20.36556,-0.13479,6.49706,0.0,39.0,6420.0,50.72486,0.75846,0.04487,0.55615,50.71914,-8.686,-20.652,1.312,49.96007,36.03,-29.09,-16.10727 +1785853457.35,2,29,673.35,5562.53725,2.77,0.2,161.0,1.0,1.0,44.8303864,11.2236808,19.0,6.49115,0.39608,20.0,-0.37282,20.41437,-0.13374,6.49115,0.0,39.0,6420.0,50.72494,0.74502,0.07027,0.51249,50.71932,-9.96191,-1.17155,0.81745,49.95889,36.28,-29.09,-16.32545 +1785853457.358,2,29,673.358,5562.62249,2.7716,0.2,161.0,1.0,1.0,44.830386,11.2236799,19.0,6.48642,0.39649,20.0,-0.37356,20.45151,-0.13287,6.48642,0.0,39.0,6420.0,50.725,0.73427,0.09059,0.47756,50.71945,-10.98264,14.41282,0.42182,49.95795,36.48,-29.09,-16.5 +1785853457.362,2,29,673.362,5562.66511,2.7724,0.2,161.0,1.0,1.0,44.8303858,11.2236794,19.0,6.48406,0.39669,20.0,-0.37392,20.47008,-0.13243,6.48406,0.0,39.0,6420.0,50.72503,0.72889,0.10075,0.4601,50.71952,-11.493,22.205,0.224,49.95754,36.64941,-29.05,-16.69765 +1785853457.375,2,29,673.375,5562.80363,2.775,0.2,161.0,1.0,1.0,44.8303852,11.2236779,19.0,6.47638,0.39736,20.0,-0.37512,20.53044,-0.13102,6.47638,0.0,39.0,6420.0,50.72511,0.85288,0.08001,0.47281,50.71978,-3.29994,-32.95706,-2.27353,49.95618,37.2,-28.92,-17.34 +1785853457.379,2,29,673.379,5562.84625,2.7758,0.2,161.0,1.0,1.0,44.830385,11.2236775,19.0,6.47401,0.39757,20.0,-0.37549,20.54901,-0.13059,6.47401,0.0,39.0,6420.0,50.72513,0.89103,0.07362,0.47672,50.71985,-0.779,-49.93,-3.042,49.95586,37.488,-28.954,-17.4 +1785853457.395,2,29,673.395,5563.01672,2.779,0.2,161.0,1.0,1.0,44.8303842,11.2236756,19.0,6.46456,0.39839,20.0,-0.37697,20.62329,-0.12885,6.46456,0.0,39.0,6420.0,50.72545,1.01278,0.05377,0.56156,50.72039,-16.287,2.13267,-3.768,49.95454,38.64,-29.09,-17.64 +1785853457.4,2,29,673.4,5563.07,2.78,0.2,161.0,1.0,1.0,44.830384,11.223675,19.0,6.4616,0.39864,20.0,-0.37743,20.6465,-0.12831,6.4616,0.0,39.0,6420.0,50.72555,1.05083,0.04757,0.58807,50.72056,-21.13325,18.40225,-3.99488,49.95425,38.9525,-29.1675,-17.7575 +1785853457.403,2,29,673.403,5563.10197,2.7806,0.2,161.0,1.0,1.0,44.8303839,11.2236747,19.0,6.45983,0.39879,20.0,-0.3777,20.65995,-0.12797,6.45983,0.0,39.0,6420.0,50.72561,1.07366,0.04385,0.60398,50.72066,-24.041,28.164,-4.131,49.95407,39.14,-29.214,-17.828 +1785853457.415,2,29,673.415,5563.22982,2.783,0.2,161.0,1.0,1.0,44.8303833,11.2236733,19.0,6.45274,0.3994,20.0,-0.37877,20.71376,-0.12664,6.45274,0.0,39.0,6420.0,50.72581,0.91412,-0.05955,0.79028,50.72103,-5.30525,-29.76225,-3.615,49.95336,39.89,-29.4,-18.11 +1785853457.419,2,29,673.419,5563.27245,2.7838,0.2,161.0,1.0,1.0,44.8303831,11.2236728,19.0,6.45037,0.3996,20.0,-0.37913,20.73169,-0.1262,6.45037,0.0,39.0,6420.0,50.72587,0.86095,-0.09402,0.85238,50.72115,0.94,-49.071,-3.443,49.95318,40.16619,-29.35429,-18.30619 +1785853457.436,2,29,673.436,5563.45358,2.7872,0.2,161.0,1.0,1.0,44.8303823,11.2236708,19.0,6.44032,0.40045,20.0,-0.38065,20.80791,-0.12431,6.44032,0.0,39.0,6420.0,50.72619,0.79492,-0.09914,0.78556,50.72177,-15.26409,18.84555,-9.72991,49.95239,41.34,-29.16,-19.14 +1785853457.441,2,29,673.441,5563.50686,2.7882,0.2,161.0,1.0,1.0,44.830382,11.2236702,19.0,6.43737,0.4007,20.0,-0.3811,20.83032,-0.12376,6.43737,0.0,39.0,6420.0,50.72628,0.77549,-0.10065,0.76591,50.72195,-20.03,38.821,-11.579,49.95233,41.53091,-29.07818,-19.24682 +1785853457.45,2,29,673.45,5563.60275,2.79,0.2,161.0,1.0,1.0,44.8303816,11.2236692,19.0,6.43205,0.40115,20.0,-0.3819,20.87067,-0.12276,6.43205,0.0,39.0,6420.0,50.72639,0.80896,-0.05757,0.83404,50.72219,-15.05565,-3.55418,-9.27394,49.95221,41.87455,-28.93091,-19.43909 +1785853457.458,2,29,673.458,5563.68799,2.7916,0.2,161.0,1.0,1.0,44.8303812,11.2236682,19.0,6.42732,0.40155,20.0,-0.38261,20.90575,-0.12186,6.42732,0.0,39.0,6420.0,50.72649,0.83872,-0.01927,0.8946,50.7224,-10.634,-41.221,-7.225,49.95211,42.18,-28.8,-19.61 +1785853457.475,2,29,673.475,5563.86913,2.795,0.2,161.0,1.0,1.0,44.8303804,11.2236663,19.0,6.41727,0.40241,20.0,-0.3841,20.98029,-0.11995,6.41727,0.0,39.0,6420.0,50.72666,1.07176,-0.03623,0.81568,50.72295,-12.45448,-2.25996,-8.6227,49.95181,42.42,-28.5,-20.16 +1785853457.481,2,29,673.481,5563.93305,2.7962,0.2,161.0,1.0,1.0,44.8303801,11.2236656,19.0,6.41373,0.40271,20.0,-0.38462,21.0066,-0.11928,6.41373,0.0,39.0,6420.0,50.72673,1.15401,-0.04222,0.78783,50.72314,-13.097,11.491,-9.116,49.95193,42.46909,-28.41818,-20.09455 +1785853457.497,2,29,673.497,5564.10353,2.7994,0.2,161.0,1.0,1.0,44.8303793,11.2236637,19.0,6.40427,0.40351,20.0,-0.38603,21.07676,-0.11748,6.40427,0.0,39.0,6420.0,50.72678,0.93847,-0.10367,0.66909,50.72357,-25.01522,-36.07789,-12.83333,49.95227,42.6,-28.2,-19.92 +1785853457.499,2,29,673.499,5564.12485,2.7998,0.2,161.0,1.0,1.0,44.8303792,11.2236635,19.0,6.40309,0.40361,20.0,-0.3862,21.08553,-0.11725,6.40309,0.0,39.0,6420.0,50.72678,0.91152,-0.11135,0.65425,50.72362,-26.505,-42.024,-13.298,49.95235,42.59368,-28.2,-19.96421 +1785853457.5,2,29,673.5,5564.1355,2.8,0.2,161.0,1.0,1.0,44.8303792,11.2236633,19.0,6.4025,0.40366,20.0,-0.38629,21.08991,-0.11714,6.4025,0.0,39.0,6420.0,50.72681,0.90622,-0.10891,0.65711,50.72367,-26.119,-40.84789,-12.75821,49.9524,42.59053,-28.2,-19.98632 +1785853457.516,2,29,673.516,5564.30598,2.8032,0.2,161.0,1.0,1.0,44.8303784,11.2236615,19.0,6.39304,0.40448,20.0,-0.38768,21.15917,-0.11533,6.39304,0.0,39.0,6420.0,50.72717,0.82129,-0.06984,0.70279,50.72443,-19.943,-22.03021,-4.12158,49.95307,42.54,-28.2,-20.34 +1785853457.518,2,29,673.518,5564.32729,2.8036,0.2,161.0,1.0,1.0,44.8303783,11.2236612,19.0,6.39186,0.40459,20.0,-0.38785,21.16782,-0.1151,6.39186,0.0,39.0,6420.0,50.72722,0.81067,-0.06496,0.7085,50.72453,-19.171,-19.678,-3.042,49.95321,42.54,-28.17333,-20.34667 +1785853457.534,2,29,673.534,5564.49777,2.8068,0.2,161.0,1.0,1.0,44.8303775,11.2236594,19.0,6.38241,0.40541,20.0,-0.38924,21.23708,-0.11329,6.38241,0.0,39.0,6420.0,50.72746,1.15303,0.16337,0.81709,50.72529,-27.32511,-2.83926,-11.87147,49.95434,42.54,-27.96,-20.4 +1785853457.536,2,29,673.536,5564.51908,2.8072,0.2,161.0,1.0,1.0,44.8303774,11.2236591,19.0,6.38122,0.40551,20.0,-0.38942,21.24573,-0.11306,6.38122,0.0,39.0,6420.0,50.7275,1.19582,0.19191,0.83066,50.72539,-28.34437,-0.73442,-12.97516,49.95454,42.50769,-27.90923,-20.45077 +1785853457.537,2,29,673.537,5564.52974,2.8074,0.2,161.0,1.0,1.0,44.8303774,11.223659,19.0,6.38063,0.40556,20.0,-0.3895,21.25006,-0.11295,6.38063,0.0,39.0,6420.0,50.72751,1.18257,0.18968,0.84479,50.72543,-28.854,0.318,-13.527,49.95464,42.49154,-27.88385,-20.47615 +1785853457.55,2,29,673.55,5564.66825,2.81,0.2,161.0,1.0,1.0,44.8303768,11.2236575,19.0,6.37295,0.40623,20.0,-0.39063,21.30633,-0.11147,6.37295,0.0,39.0,6420.0,50.72769,1.01035,0.16068,1.0285,50.72603,-22.70879,-15.97533,-8.68558,49.95591,42.28154,-27.55385,-20.80615 +1785853457.56,2,29,673.56,5564.7748,2.812,0.2,161.0,1.0,1.0,44.8303763,11.2236563,19.0,6.36704,0.40676,20.0,-0.3915,21.34934,-0.11033,6.36704,0.0,39.0,6420.0,50.72784,0.87787,0.13838,1.16982,50.72649,-17.98171,-28.50867,-4.96142,49.95689,42.12,-27.3,-21.06 +1785853457.561,2,29,673.561,5564.78546,2.8122,0.2,161.0,1.0,1.0,44.8303762,11.2236562,19.0,6.36645,0.40681,20.0,-0.39158,21.35365,-0.11022,6.36645,0.0,39.0,6420.0,50.72785,0.88469,0.13498,1.1127,50.72654,-17.509,-29.762,-4.589,49.95702,42.12,-27.284,-21.064 +1785853457.575,2,29,673.575,5564.93463,2.815,0.2,161.0,1.0,1.0,44.8303755,11.2236546,19.0,6.35817,0.40755,20.0,-0.39279,21.41386,-0.10863,6.35817,0.0,39.0,6420.0,50.72805,0.98016,0.08752,0.31307,50.72719,-37.081,-15.91227,-6.6218,49.95886,42.12,-27.06,-21.12 +1785853457.576,2,29,673.576,5564.94528,2.8152,0.2,161.0,1.0,1.0,44.8303755,11.2236545,19.0,6.35758,0.4076,20.0,-0.39288,21.41817,-0.10851,6.35758,0.0,39.0,6420.0,50.72806,0.98698,0.08413,0.25595,50.72723,-38.479,-14.923,-6.767,49.95901,42.099,-27.0535,-21.117 +1785853457.595,2,29,673.595,5565.14773,2.819,0.2,161.0,1.0,1.0,44.8303746,11.2236523,19.0,6.34635,0.40861,20.0,-0.39452,21.49989,-0.10635,6.34635,0.0,39.0,6420.0,50.7282,0.77589,0.07867,0.62424,50.72797,-31.37961,-14.25965,-2.64896,49.96188,41.7,-26.93,-21.06 +1785853457.598,2,29,673.598,5565.17969,2.8196,0.2,161.0,1.0,1.0,44.8303744,11.2236519,19.0,6.34458,0.40877,20.0,-0.39478,21.5128,-0.10601,6.34458,0.0,39.0,6420.0,50.72822,0.74256,0.0778,0.68239,50.72809,-30.25865,-14.15491,-1.99874,49.96236,41.74286,-26.89714,-21.11143 +1785853457.599,2,29,673.599,5565.19035,2.8198,0.2,161.0,1.0,1.0,44.8303744,11.2236518,19.0,6.34399,0.40882,20.0,-0.39487,21.5171,-0.10589,6.34399,0.0,39.0,6420.0,50.72822,0.75478,0.07656,0.69993,50.72813,-29.885,-14.12,-1.782,49.96252,41.75714,-26.88619,-21.12857 +1785853457.6,2,29,673.6,5565.201,2.82,0.2,161.0,1.0,1.0,44.8303743,11.2236517,19.0,6.3434,0.40888,20.0,-0.39496,21.5214,-0.10578,6.3434,0.0,39.0,6420.0,50.72823,0.76701,0.07531,0.71747,50.72817,-29.26488,-12.88647,-1.81906,49.96268,41.77143,-26.87524,-21.14571 +1785853457.615,2,29,673.615,5565.36083,2.823,0.2,161.0,1.0,1.0,44.8303736,11.2236499,19.0,6.33453,0.40971,20.0,-0.39626,21.5861,-0.10407,6.33453,0.0,39.0,6420.0,50.72825,0.95038,0.05659,0.98056,50.72874,-19.96312,5.61647,-2.37494,49.96509,41.98571,-26.71095,-21.40286 +1785853457.616,2,29,673.616,5565.37148,2.8232,0.2,161.0,1.0,1.0,44.8303736,11.2236498,19.0,6.33394,0.40976,20.0,-0.39634,21.59041,-0.10396,6.33394,0.0,39.0,6420.0,50.72825,0.94676,0.05699,0.98341,50.72878,-19.343,6.85,-2.412,49.96526,42.0,-26.7,-21.42 +1785853457.64,2,29,673.64,5565.6272,2.828,0.2,161.0,1.0,1.0,44.8303724,11.223647,19.0,6.31976,0.41109,20.0,-0.39843,21.69393,-0.10122,6.31976,0.0,39.0,6420.0,50.72807,0.86003,0.06659,1.05184,50.7297,-28.109,-4.953,2.63,49.96981,42.0,-26.7,-21.42 +1785853457.65,2,29,673.65,5565.73375,2.83,0.2,161.0,1.0,1.0,44.8303719,11.2236458,19.0,6.31385,0.41165,20.0,-0.3993,21.73706,-0.10008,6.31385,0.0,39.0,6420.0,50.72817,0.97494,0.08475,0.75988,50.72993,-26.17525,-14.83675,1.09,49.97192,42.15,-26.58125,-21.6075 +1785853457.656,2,29,673.656,5565.79768,2.8312,0.2,161.0,1.0,1.0,44.8303716,11.2236451,19.0,6.3103,0.412,20.0,-0.39982,21.76305,-0.0994,6.3103,0.0,39.0,6420.0,50.72822,1.04388,0.09565,0.58471,50.73007,-25.015,-20.767,0.166,49.97319,42.24,-26.51,-21.72 +1785853457.677,2,29,673.677,5566.02144,2.8354,0.2,161.0,1.0,1.0,44.8303706,11.2236427,19.0,6.29789,0.41322,20.0,-0.40166,21.85401,-0.097,6.29789,0.0,39.0,6420.0,50.72779,0.94354,0.0673,0.47621,50.73034,-36.245,9.715,2.286,49.978,42.68864,-26.405,-22.00636 +1785853457.678,2,29,673.678,5566.03209,2.8356,0.2,161.0,1.0,1.0,44.8303706,11.2236426,19.0,6.2973,0.41327,20.0,-0.40174,21.85834,-0.09689,6.2973,0.0,39.0,6420.0,50.72777,0.94076,0.062,0.49382,50.73034,-35.69111,9.6545,2.25739,49.97823,42.71,-26.4,-22.02 +1785853457.695,2,29,673.695,5566.21323,2.839,0.2,161.0,1.0,1.0,44.8303697,11.2236406,19.0,6.28725,0.41426,20.0,-0.40323,21.93197,-0.09495,6.28725,0.0,39.0,6420.0,50.7274,0.89348,-0.02804,0.79324,50.7305,-26.275,8.626,1.771,49.98233,43.02,-26.22,-22.32 +1785853457.7,2,29,673.7,5566.2665,2.84,0.2,161.0,1.0,1.0,44.8303695,11.22364,19.0,6.2843,0.41455,20.0,-0.40366,21.95362,-0.09438,6.2843,0.0,39.0,6420.0,50.72722,0.88432,0.01122,0.7455,50.7305,-25.98864,7.15464,1.836,49.98358,43.17652,-26.22,-22.35913 +1785853457.717,2,29,673.717,5566.44763,2.8434,0.2,161.0,1.0,1.0,44.8303687,11.223638,19.0,6.27425,0.41558,20.0,-0.40516,22.02768,-0.09244,6.27425,0.0,39.0,6420.0,50.72664,0.8532,0.1447,0.58318,50.73049,-25.015,2.152,2.057,49.98782,43.7087,-26.22,-22.49217 +1785853457.718,2,29,673.718,5566.45829,2.8436,0.2,161.0,1.0,1.0,44.8303686,11.2236379,19.0,6.27366,0.41565,20.0,-0.40525,22.03204,-0.09232,6.27366,0.0,39.0,6420.0,50.72661,0.85288,0.15105,0.58254,50.7305,-25.276,1.86867,2.22572,49.98807,43.74,-26.22,-22.5 +1785853457.735,2,29,673.735,5566.63943,2.847,0.2,161.0,1.0,1.0,44.8303678,11.2236359,19.0,6.26361,0.41668,20.0,-0.40675,22.1061,-0.09038,6.26361,0.0,39.0,6420.0,50.72611,0.84759,0.25901,0.57175,50.73056,-29.713,-2.948,5.094,49.99266,44.25,-26.05,-22.83056 +1785853457.736,2,29,673.736,5566.65008,2.8472,0.2,161.0,1.0,1.0,44.8303678,11.2236358,19.0,6.26302,0.41674,20.0,-0.40684,22.11045,-0.09027,6.26302,0.0,39.0,6420.0,50.72607,0.84473,0.24585,0.57263,50.73055,-29.79895,-2.91936,5.18255,49.99293,44.28,-26.04,-22.85 +1785853457.75,2,29,673.75,5566.79925,2.85,0.2,161.0,1.0,1.0,44.8303671,11.2236342,19.0,6.25475,0.41759,20.0,-0.40807,22.17145,-0.08867,6.25475,0.0,39.0,6420.0,50.72549,0.80476,0.06162,0.5849,50.73041,-31.00232,-2.51845,6.42218,49.99673,44.85273,-26.04,-23.16182 +1785853457.757,2,29,673.757,5566.87383,2.8514,0.2,161.0,1.0,1.0,44.8303667,11.2236334,19.0,6.25061,0.41804,20.0,-0.40869,22.20218,-0.08787,6.25061,0.0,39.0,6420.0,50.72521,0.78477,-0.03049,0.59103,50.73035,-31.604,-2.318,7.042,49.99863,45.13909,-26.04,-23.31773 +1785853457.758,2,29,673.758,5566.88449,2.8516,0.2,161.0,1.0,1.0,44.8303667,11.2236332,19.0,6.25002,0.4181,20.0,-0.40878,22.20657,-0.08775,6.25002,0.0,39.0,6420.0,50.72516,0.78706,-0.02681,0.59498,50.73033,-30.84844,-2.71188,6.87725,49.9989,45.18,-26.04,-23.34 +1785853457.773,2,29,673.773,5567.04432,2.8546,0.2,161.0,1.0,1.0,44.830366,11.2236315,19.0,6.24116,0.41906,20.0,-0.41012,22.27242,-0.08604,6.24116,0.0,39.0,6420.0,50.72443,0.82138,0.02845,0.65425,50.73004,-19.515,-8.62,4.406,50.00308,45.79875,-26.08688,-23.62125 +1785853457.774,2,29,673.774,5567.05497,2.8548,0.2,161.0,1.0,1.0,44.8303659,11.2236314,19.0,6.24057,0.41912,20.0,-0.41021,22.27681,-0.08592,6.24057,0.0,39.0,6420.0,50.72438,0.82198,0.03436,0.65575,50.73002,-19.68687,-7.60361,4.30635,50.00336,45.84,-26.09,-23.64 +1785853457.796,2,29,673.796,5567.28938,2.8592,0.2,161.0,1.0,1.0,44.8303649,11.2236288,19.0,6.22756,0.42053,20.0,-0.41217,22.3734,-0.08341,6.22756,0.0,39.0,6420.0,50.72335,0.83505,0.16448,0.68872,50.72952,-23.468,14.757,2.114,50.00948,46.64348,-26.15696,-24.09913 +1785853457.797,2,29,673.797,5567.30004,2.8594,0.2,161.0,1.0,1.0,44.8303648,11.2236287,19.0,6.22697,0.42059,20.0,-0.41226,22.37779,-0.08329,6.22697,0.0,39.0,6420.0,50.72329,0.82597,0.16049,0.69587,50.72948,-23.30618,14.04588,2.63647,50.00975,46.68,-26.16,-24.12 +1785853457.8,2,29,673.8,5567.332,2.86,0.2,161.0,1.0,1.0,44.8303647,11.2236283,19.0,6.2252,0.42078,20.0,-0.41253,22.39096,-0.08295,6.2252,0.0,39.0,6420.0,50.72311,0.79874,0.14852,0.71734,50.72936,-22.82071,11.91253,4.20388,50.01059,46.79,-26.14,-24.15833 +1785853457.813,2,29,673.813,5567.47052,2.8626,0.2,161.0,1.0,1.0,44.830364,11.2236268,19.0,6.21752,0.42166,20.0,-0.4137,22.4486,-0.08146,6.21752,0.0,39.0,6420.0,50.72234,0.68076,0.09667,0.81037,50.72887,-20.717,2.668,10.996,50.01419,47.26667,-26.05333,-24.32444 +1785853457.815,2,29,673.815,5567.49183,2.863,0.2,161.0,1.0,1.0,44.8303639,11.2236266,19.0,6.21633,0.42179,20.0,-0.41389,22.45747,-0.08123,6.21633,0.0,39.0,6420.0,50.72222,0.67154,0.08225,0.78382,50.72877,-21.15543,4.31209,10.20878,50.01474,47.34,-26.04,-24.35 +1785853457.836,2,29,673.836,5567.71558,2.8672,0.2,161.0,1.0,1.0,44.8303629,11.2236241,19.0,6.20392,0.4232,20.0,-0.41578,22.55057,-0.07882,6.20392,0.0,39.0,6420.0,50.72086,0.57471,-0.06914,0.50507,50.72773,-25.759,21.575,1.943,50.02042,48.3,-25.92,-25.14 +1785853457.85,2,29,673.85,5567.86475,2.87,0.2,161.0,1.0,1.0,44.8303623,11.2236225,19.0,6.19565,0.42414,20.0,-0.41705,22.61264,-0.07722,6.19565,0.0,39.0,6420.0,50.71991,0.76369,-0.04861,0.47107,50.72711,-20.44512,-3.6425,1.14062,50.02408,48.846,-26.004,-25.434 +1785853457.852,2,29,673.852,5567.88606,2.8704,0.2,161.0,1.0,1.0,44.8303622,11.2236223,19.0,6.19447,0.42428,20.0,-0.41724,22.62161,-0.07699,6.19447,0.0,39.0,6420.0,50.71977,0.79069,-0.04568,0.46621,50.72702,-19.686,-7.245,1.026,50.02461,48.924,-26.016,-25.476 +1785853457.856,2,29,673.856,5567.92868,2.8712,0.2,161.0,1.0,1.0,44.830362,11.2236218,19.0,6.1921,0.42456,20.0,-0.4176,22.63956,-0.07653,6.1921,0.0,39.0,6420.0,50.71942,0.76091,-0.03774,0.5732,50.7267,-17.53365,-9.06848,1.92287,50.02566,49.08,-26.04,-25.56 +1785853457.875,2,29,673.875,5568.13113,2.875,0.2,161.0,1.0,1.0,44.830361,11.2236196,19.0,6.18088,0.4259,20.0,-0.41935,22.72478,-0.07434,6.18088,0.0,39.0,6420.0,50.71779,0.61948,0.0,1.08141,50.7252,-7.31,-17.73,6.183,50.03041,49.62,-25.8,-26.16 +1785853457.892,2,29,673.892,5568.31226,2.8784,0.2,161.0,1.0,1.0,44.8303602,11.2236176,19.0,6.17083,0.4271,20.0,-0.42092,22.80104,-0.07239,6.17083,0.0,39.0,6420.0,50.71645,0.47682,0.03192,0.7449,50.72384,-23.41,37.217,3.662,50.03437,49.722,-25.8,-26.4575 +1785853457.895,2,29,673.895,5568.34423,2.879,0.2,161.0,1.0,1.0,44.8303601,11.2236173,19.0,6.16906,0.42731,20.0,-0.42119,22.8145,-0.07204,6.16906,0.0,39.0,6420.0,50.71621,0.52617,0.03068,0.72798,50.72357,-22.64432,29.57586,2.70091,50.03507,49.74,-25.8,-26.51 +1785853457.9,2,29,673.9,5568.3975,2.88,0.2,161.0,1.0,1.0,44.8303598,11.2236167,19.0,6.1661,0.42767,20.0,-0.42165,22.83693,-0.07147,6.1661,0.0,39.0,6420.0,50.71581,0.60842,0.02862,0.69978,50.72313,-21.36818,16.84064,1.09909,50.03616,49.755,-25.7075,-26.5575 +1785853457.914,2,29,673.914,5568.54667,2.8828,0.2,161.0,1.0,1.0,44.8303592,11.223615,19.0,6.15783,0.42871,20.0,-0.42297,22.90056,-0.06986,6.15783,0.0,39.0,6420.0,50.71467,0.83872,0.02284,0.6208,50.72188,-17.795,-18.818,-3.386,50.0392,49.797,-25.4485,-26.6905 +1785853457.915,2,29,673.915,5568.55733,2.883,0.2,161.0,1.0,1.0,44.8303591,11.2236149,19.0,6.15724,0.42878,20.0,-0.42306,22.9051,-0.06974,6.15724,0.0,39.0,6420.0,50.71459,0.83849,0.01928,0.63057,50.72178,-17.37371,-18.75059,-3.28488,50.03942,49.8,-25.43,-26.7 +1785853457.931,2,29,673.931,5568.72781,2.8862,0.2,161.0,1.0,1.0,44.8303583,11.2236131,19.0,6.14778,0.42997,20.0,-0.42456,22.97783,-0.0679,6.14778,0.0,39.0,6420.0,50.71319,0.83484,-0.03763,0.78692,50.72018,-10.633,-17.672,-1.667,50.04243,49.512,-25.094,-26.988 +1785853457.935,2,29,673.935,5568.77042,2.887,0.2,161.0,1.0,1.0,44.8303581,11.2236126,19.0,6.14542,0.43027,20.0,-0.42494,22.99601,-0.06743,6.14542,0.0,39.0,6420.0,50.7128,0.74702,-0.04556,0.70651,50.7197,-10.82064,-11.98418,-1.59409,50.04318,49.44,-25.01,-27.06 +1785853457.95,2,29,673.95,5568.93025,2.89,0.2,161.0,1.0,1.0,44.8303574,11.2236108,19.0,6.13655,0.43138,20.0,-0.42635,23.06419,-0.06571,6.13655,0.0,39.0,6420.0,50.71133,0.41767,-0.07532,0.40497,50.71789,-11.52427,9.34514,-1.32068,50.0457,49.17,-24.5675,-27.195 +1785853457.953,2,29,673.953,5568.96222,2.8906,0.2,161.0,1.0,1.0,44.8303573,11.2236105,19.0,6.13478,0.43161,20.0,-0.42663,23.07802,-0.06536,6.13478,0.0,39.0,6420.0,50.71103,0.3518,-0.08127,0.34466,50.71753,-11.665,13.611,-1.266,50.0462,49.116,-24.479,-27.222 +1785853457.955,2,29,673.955,5568.98353,2.891,0.2,161.0,1.0,1.0,44.8303572,11.2236103,19.0,6.13359,0.43177,20.0,-0.42683,23.08724,-0.06513,6.13359,0.0,39.0,6420.0,50.71085,0.38185,-0.05865,0.39112,50.7173,-12.11665,13.41547,-1.53553,50.04654,49.08,-24.42,-27.24 +1785853457.97,2,29,673.97,5569.14335,2.894,0.2,161.0,1.0,1.0,44.8303565,11.2236085,19.0,6.12473,0.43294,20.0,-0.42826,23.15638,-0.06339,6.12473,0.0,39.0,6420.0,50.70951,0.60724,0.11105,0.7395,50.7156,-15.504,11.949,-3.557,50.04862,48.8025,-24.0525,-27.285 +1785853457.975,2,29,673.975,5569.19663,2.895,0.2,161.0,1.0,1.0,44.8303562,11.2236079,19.0,6.12177,0.43333,20.0,-0.42874,23.17943,-0.06281,6.12177,0.0,39.0,6420.0,50.70897,0.5798,0.08442,0.72343,50.7149,-14.74422,5.48465,-3.2083,50.04932,48.71,-23.93,-27.3 +1785853457.993,2,29,673.993,5569.38842,2.8986,0.2,161.0,1.0,1.0,44.8303553,11.2236058,19.0,6.11114,0.43474,20.0,-0.43047,23.26241,-0.06073,6.11114,0.0,39.0,6420.0,50.70703,0.481,-0.01142,0.66557,50.71238,-12.009,-17.787,-1.953,50.05122,48.179,-23.183,-27.138 +1785853457.995,2,29,673.995,5569.40972,2.899,0.2,161.0,1.0,1.0,44.8303552,11.2236056,19.0,6.10995,0.43489,20.0,-0.43066,23.27163,-0.0605,6.10995,0.0,39.0,6420.0,50.70679,0.47344,-0.01286,0.65921,50.7121,-11.48994,-15.88618,-1.30594,50.05143,48.12,-23.1,-27.12 +1785853458.0,2,29,674.0,5569.463,2.9,0.2,200.5,1.0,1.0,44.830355,11.223605,19.0,6.107,0.43528,20.0,-0.43114,23.29468,-0.05992,6.107,0.0,39.0,6420.0,50.70618,0.45455,-0.01646,0.64331,50.71139,-10.19229,-11.13412,0.31171,50.05184,47.99143,-22.9,-27.10571 +1785853458.01,2,29,674.01,5569.61682,2.901,0.197,200.5,1.0,1.0,44.830355,11.2236031,19.0,6.11265,0.4361,20.0,-0.43212,23.34144,-0.05876,6.11265,0.0,39.0,6420.0,50.70496,0.41676,-0.02366,0.61152,50.70996,-7.597,-1.63,3.547,50.05266,47.73429,-22.5,-27.07714 +1785853458.016,2,29,674.016,5569.70911,2.9016,0.1952,200.5,1.0,1.0,44.8303551,11.2236019,19.0,6.11604,0.43659,20.0,-0.4327,23.36949,-0.05807,6.11604,0.0,39.0,6420.0,50.70434,0.47416,-0.00796,0.71373,50.70907,-9.58483,0.62704,2.29143,50.05315,47.58,-22.26,-27.06 +1785853458.033,2,29,674.033,5569.97061,2.9033,0.1901,200.5,1.0,1.0,44.8303551,11.2235986,19.0,6.12565,0.43798,20.0,-0.43437,23.44899,-0.05609,6.12565,0.0,39.0,6420.0,50.70257,0.63681,0.03651,1.0033,50.70655,-15.217,7.022,-1.266,50.05406,47.15053,-22.31368,-26.79158 +1785853458.035,2,29,674.035,5570.00137,2.9035,0.1895,200.5,1.0,1.0,44.8303551,11.2235982,19.0,6.12677,0.43815,20.0,-0.43456,23.45834,-0.05586,6.12677,0.0,39.0,6420.0,50.70238,0.57289,0.03002,0.92242,50.70627,-16.28412,7.2655,-1.223,50.05417,47.1,-22.32,-26.76 +1785853458.049,2,29,674.049,5570.21672,2.9049,0.1853,200.5,1.0,1.0,44.8303552,11.2235954,19.0,6.13468,0.43929,20.0,-0.43593,23.52381,-0.05424,6.13468,0.0,39.0,6420.0,50.70104,0.12543,-0.0154,0.35629,50.70428,-23.754,8.97,-0.922,50.05452,46.764,-21.858,-26.802 +1785853458.05,2,29,674.05,5570.2321,2.905,0.185,200.5,1.0,1.0,44.8303552,11.2235953,19.0,6.13525,0.43937,20.0,-0.43603,23.52848,-0.05412,6.13525,0.0,39.0,6420.0,50.70095,0.14035,-0.01446,0.37128,50.70415,-23.34337,8.64054,-0.93392,50.05454,46.74,-21.825,-26.805 +1785853458.055,2,29,674.055,5570.30901,2.9055,0.1835,200.5,1.0,1.0,44.8303552,11.2235943,19.0,6.13807,0.4398,20.0,-0.43653,23.55219,-0.05354,6.13807,0.0,39.0,6420.0,50.70049,0.21498,-0.00976,0.44623,50.70346,-21.29025,6.99325,-0.9935,50.05466,46.62,-21.66,-26.82 +1785853458.073,2,29,674.073,5570.58589,2.9073,0.1781,200.5,1.0,1.0,44.8303552,11.2235908,19.0,6.14824,0.44134,20.0,-0.43832,23.63752,-0.05144,6.14824,0.0,39.0,6420.0,50.69883,0.48365,0.00714,0.71604,50.701,-13.899,1.063,-1.208,50.05462,46.242,-21.336,-26.766 +1785853458.075,2,29,674.075,5570.61665,2.9075,0.1775,200.5,1.0,1.0,44.8303553,11.2235904,19.0,6.14938,0.44152,20.0,-0.43852,23.647,-0.05121,6.14938,0.0,39.0,6420.0,50.69869,0.4365,0.00208,0.70309,50.70075,-14.55288,1.61571,-1.208,50.05461,46.2,-21.3,-26.76 +1785853458.09,2,29,674.09,5570.84738,2.909,0.173,200.5,1.0,1.0,44.8303553,11.2235875,19.0,6.15785,0.4428,20.0,-0.44002,23.71811,-0.04947,6.15785,0.0,39.0,6420.0,50.69764,0.0829,-0.03589,0.60592,50.69887,-19.457,5.761,-1.208,50.05417,46.15263,-20.87368,-26.66526 +1785853458.094,2,29,674.094,5570.90891,2.9094,0.1718,200.5,1.0,1.0,44.8303553,11.2235867,19.0,6.16011,0.44314,20.0,-0.44042,23.73707,-0.049,6.16011,0.0,39.0,6420.0,50.69728,0.04057,-0.00729,0.66657,50.69829,-19.477,5.50204,-1.08852,50.05405,46.14,-20.76,-26.64 +1785853458.1,2,29,674.1,5571.0012,2.91,0.17,200.5,1.0,1.0,44.8303553,11.2235855,19.0,6.1635,0.44366,20.0,-0.44102,23.76552,-0.0483,6.1635,0.0,39.0,6420.0,50.69675,-0.02293,0.03562,0.75754,50.69742,-19.507,5.11361,-0.9093,50.05371,46.05429,-20.64,-26.55429 +1785853458.113,2,29,674.113,5571.20117,2.9113,0.1661,200.5,1.0,1.0,44.8303554,11.223583,19.0,6.17085,0.44481,20.0,-0.44234,23.82792,-0.04678,6.17085,0.0,39.0,6420.0,50.6956,-0.1605,0.12859,0.95466,50.69554,-19.572,4.272,-0.521,50.05297,45.86857,-20.38,-26.36857 +1785853458.115,2,29,674.115,5571.23193,2.9115,0.1655,200.5,1.0,1.0,44.8303554,11.2235826,19.0,6.17198,0.44499,20.0,-0.44254,23.83752,-0.04655,6.17198,0.0,39.0,6420.0,50.69542,-0.19334,0.11865,0.94329,50.69524,-19.69329,5.76835,-0.31876,50.05285,45.84,-20.34,-26.34 +1785853458.13,2,29,674.13,5571.46266,2.913,0.161,200.5,1.0,1.0,44.8303554,11.2235797,19.0,6.18045,0.44633,20.0,-0.44407,23.90952,-0.0448,6.18045,0.0,39.0,6420.0,50.69408,-0.4396,0.04415,0.85799,50.69306,-20.603,16.991,1.198,50.05167,45.66,-20.205,-26.61 +1785853458.135,2,29,674.135,5571.53957,2.9135,0.1595,200.5,1.0,1.0,44.8303555,11.2235787,19.0,6.18327,0.44678,20.0,-0.44457,23.93353,-0.04422,6.18327,0.0,39.0,6420.0,50.6937,-0.25001,0.07013,1.03702,50.69239,-22.77205,14.22171,1.86657,50.05128,45.6,-20.16,-26.7 +1785853458.15,2,29,674.15,5571.7703,2.915,0.155,200.5,1.0,1.0,44.8303555,11.2235758,19.0,6.19175,0.44811,20.0,-0.4461,24.00553,-0.04246,6.19175,0.0,39.0,6420.0,50.69257,0.31878,0.14807,1.57412,50.69038,-29.27919,5.91386,3.87229,50.04963,45.47143,-20.06714,-26.7 +1785853458.151,2,29,674.151,5571.78568,2.9151,0.1547,200.5,1.0,1.0,44.8303555,11.2235756,19.0,6.19231,0.44821,20.0,-0.4462,24.01038,-0.04235,6.19231,0.0,39.0,6420.0,50.6925,0.3567,0.15326,1.60993,50.69025,-29.713,5.36,4.006,50.04952,45.46286,-20.06095,-26.7 +1785853458.156,2,29,674.156,5571.86259,2.9156,0.1532,200.5,1.0,1.0,44.8303555,11.2235746,19.0,6.19514,0.44867,20.0,-0.44672,24.03464,-0.04176,6.19514,0.0,39.0,6420.0,50.69224,0.32689,0.14682,1.20963,50.6897,-29.54447,5.37706,4.94953,50.04896,45.42,-20.03,-26.7 +1785853458.168,2,29,674.168,5572.04718,2.9168,0.1496,200.5,1.0,1.0,44.8303556,11.2235722,19.0,6.20192,0.44978,20.0,-0.44796,24.09287,-0.04036,6.20192,0.0,39.0,6420.0,50.69161,0.25534,0.13134,0.24891,50.68836,-29.14,5.418,7.214,50.04745,44.73789,-19.73316,-26.77579 +1785853458.175,2,29,674.175,5572.15485,2.9175,0.1475,200.5,1.0,1.0,44.8303556,11.2235709,19.0,6.20587,0.45043,20.0,-0.44868,24.12684,-0.03954,6.20587,0.0,39.0,6420.0,50.69117,0.27663,0.09824,0.35994,50.68753,-28.62648,3.0436,6.70076,50.04656,44.34,-19.56,-26.82 +1785853458.192,2,29,674.192,5572.41634,2.9192,0.1424,200.5,1.0,1.0,44.8303556,11.2235676,19.0,6.21548,0.452,20.0,-0.45043,24.20933,-0.03755,6.21548,0.0,39.0,6420.0,50.69011,0.32835,0.01785,0.62957,50.6855,-27.37936,-2.7228,5.45432,50.04425,43.371,-18.795,-26.973 +1785853458.193,2,29,674.193,5572.43173,2.9193,0.1421,200.5,1.0,1.0,44.8303556,11.2235674,19.0,6.21604,0.45209,20.0,-0.45053,24.21418,-0.03743,6.21604,0.0,39.0,6420.0,50.69005,0.32708,0.02727,0.69073,50.68538,-27.306,-3.062,5.381,50.04412,43.314,-18.75,-26.982 +1785853458.195,2,29,674.195,5572.46249,2.9195,0.1415,200.5,1.0,1.0,44.8303557,11.223567,19.0,6.21718,0.45228,20.0,-0.45074,24.22388,-0.0372,6.21718,0.0,39.0,6420.0,50.68993,0.32453,0.04611,0.81304,50.68516,-26.61029,-2.088,5.48743,50.04385,43.2,-18.66,-27.0 +1785853458.2,2,29,674.2,5572.5394,2.92,0.14,200.5,1.0,1.0,44.8303557,11.223566,19.0,6.22,0.45274,20.0,-0.45126,24.24815,-0.03661,6.22,0.0,39.0,6420.0,50.68964,0.31818,0.09322,1.11882,50.68461,-24.871,0.347,5.7535,50.0431,42.91364,-18.51,-26.85 +1785853458.207,2,29,674.207,5572.64707,2.9207,0.1379,200.5,1.0,1.0,44.8303557,11.2235646,19.0,6.22395,0.45341,20.0,-0.45199,24.28241,-0.03579,6.22395,0.0,39.0,6420.0,50.68923,0.30928,0.15918,1.54691,50.68384,-22.436,3.756,6.126,50.04206,42.51273,-18.3,-26.64 +1785853458.217,2,29,674.217,5572.80089,2.9217,0.1349,200.5,1.0,1.0,44.8303557,11.2235627,19.0,6.2296,0.45436,20.0,-0.45303,24.33137,-0.03462,6.2296,0.0,39.0,6420.0,50.68874,0.05556,0.19904,1.26329,50.68282,-20.17055,9.95464,8.10509,50.04057,41.94,-18.0,-26.34 +1785853458.229,2,29,674.229,5572.98548,2.9229,0.1313,200.5,1.0,1.0,44.8303558,11.2235603,19.0,6.23639,0.45551,20.0,-0.45429,24.39012,-0.03321,6.23639,0.0,39.0,6420.0,50.68817,-0.24891,0.24687,0.92295,50.68161,-17.452,17.393,10.48,50.03854,40.89333,-17.4,-26.01333 +1785853458.235,2,29,674.235,5573.07777,2.9235,0.1295,200.5,1.0,1.0,44.8303558,11.2235592,19.0,6.23978,0.45608,20.0,-0.45491,24.41949,-0.03251,6.23978,0.0,39.0,6420.0,50.68796,-0.00921,0.09524,0.84089,50.68111,-18.94167,22.54933,9.98333,50.03753,40.37,-17.1,-25.85 +1785853458.247,2,29,674.247,5573.26235,2.9247,0.1259,200.5,1.0,1.0,44.8303558,11.2235568,19.0,6.24655,0.45723,20.0,-0.45617,24.47824,-0.0311,6.24655,0.0,39.0,6420.0,50.68755,0.47019,-0.20802,0.67679,50.6801,-21.921,32.862,8.99,50.03553,39.23,-16.74,-25.65909 +1785853458.25,2,29,674.25,5573.3085,2.925,0.125,200.5,1.0,1.0,44.8303558,11.2235563,19.0,6.24825,0.45752,20.0,-0.45648,24.49292,-0.03075,6.24825,0.0,39.0,6420.0,50.68747,0.49357,-0.16744,0.77471,50.67988,-22.332,31.45709,8.36222,50.03503,38.945,-16.65,-25.61136 +1785853458.257,2,29,674.257,5573.41617,2.9257,0.1229,200.5,1.0,1.0,44.8303559,11.2235549,19.0,6.2522,0.4582,20.0,-0.45722,24.52743,-0.02993,6.2522,0.0,39.0,6420.0,50.68727,0.54813,-0.07275,1.00318,50.67937,-23.291,28.17896,6.89739,50.03386,38.28,-16.44,-25.5 +1785853458.27,2,29,674.27,5573.61614,2.927,0.119,200.5,1.0,1.0,44.8303559,11.2235524,19.0,6.25955,0.45948,20.0,-0.45859,24.59151,-0.0284,6.25955,0.0,39.0,6420.0,50.6869,0.64946,0.10309,1.4275,50.67843,-25.072,22.091,4.177,50.03153,36.98,-16.13667,-25.28333 +1785853458.275,2,29,674.275,5573.69305,2.9275,0.1175,200.5,1.0,1.0,44.8303559,11.2235514,19.0,6.26237,0.45997,20.0,-0.45912,24.61616,-0.02781,6.26237,0.0,39.0,6420.0,50.6867,0.55415,0.10475,1.38002,50.67813,-23.38887,12.31475,5.37669,50.03063,36.48,-16.02,-25.2 +1785853458.286,2,29,674.286,5573.86225,2.9286,0.1142,200.5,1.0,1.0,44.830356,11.2235492,19.0,6.26859,0.46105,20.0,-0.46028,24.67039,-0.02652,6.26859,0.0,39.0,6420.0,50.68627,0.34446,0.1084,1.27556,50.67746,-19.686,-9.193,8.016,50.02855,35.391,-15.426,-24.837 +1785853458.295,2,29,674.295,5574.00069,2.9295,0.1115,200.5,1.0,1.0,44.830356,11.2235475,19.0,6.27367,0.46194,20.0,-0.46123,24.71475,-0.02546,6.27367,0.0,39.0,6420.0,50.68613,0.11131,0.00493,0.90735,50.677,-22.57813,-3.43104,7.29874,50.02685,34.5,-14.94,-24.54 +1785853458.3,2,29,674.3,5574.0776,2.93,0.11,200.5,1.0,1.0,44.830356,11.2235465,19.0,6.2765,0.46243,20.0,-0.46176,24.7394,-0.02487,6.2765,0.0,39.0,6420.0,50.68605,-0.01821,-0.05255,0.70278,50.67675,-24.18487,-0.22996,6.90026,50.02604,34.08,-14.865,-24.435 +1785853458.309,2,29,674.309,5574.21604,2.9309,0.1073,200.5,1.0,1.0,44.830356,11.2235447,19.0,6.28158,0.46333,20.0,-0.46271,24.78399,-0.02382,6.28158,0.0,39.0,6420.0,50.68591,-0.25136,-0.15602,0.33457,50.6763,-27.077,5.532,6.183,50.02458,33.324,-14.73,-24.246 diff --git a/src/app.rs b/src/app.rs index 09e7de9..986fc07 100644 --- a/src/app.rs +++ b/src/app.rs @@ -22,7 +22,7 @@ use crate::ipc::IpcServer; use crate::mcp::{DEFAULT_MCP_PORT, McpServerHandle, start_mcp_server}; use crate::parsers::{ Aim, BlueDriver, DynamicEfi, EcuMaster, EcuType, Emerald, Haltech, Link, Locomotive, - MegaSquirt, Mhd, MotorsportElectronics, Parseable, RomRaider, Speeduino, Woolich, + MegaSquirt, Mhd, MotorsportElectronics, Parseable, RaceChrono, RomRaider, Speeduino, Woolich, }; use crate::settings::UserSettings; use crate::state::{ @@ -630,7 +630,17 @@ impl UltraLogApp { /// Run the text format detection chain against normalized content. fn dispatch_text_content(contents: &str) -> Result<(crate::parsers::Log, EcuType), LoadResult> { - if MegaSquirt::detect(contents) { + if RaceChrono::detect(contents) { + // RaceChrono CSV session export detected (banner + Format marker) + let parser = RaceChrono; + match parser.parse(contents) { + Ok(l) => Ok((l, EcuType::RaceChrono)), + Err(e) => Err(LoadResult::Error(format!( + "Failed to parse RaceChrono file: {}", + e + ))), + } + } else if MegaSquirt::detect(contents) { // MegaSquirt TunerStudio datalog detected let parser = MegaSquirt; match parser.parse(contents) { diff --git a/src/bin/test_parser.rs b/src/bin/test_parser.rs index 8794ab5..0d3709f 100644 --- a/src/bin/test_parser.rs +++ b/src/bin/test_parser.rs @@ -5,7 +5,7 @@ use std::path::Path; // Import from the library use ultralog::parsers::{ BlueDriver, EcuMaster, EcuType, Emerald, Haltech, Link, Locomotive, MegaSquirt, Mhd, Parseable, - Speeduino, Woolich, strip_leading_comment_lines, + RaceChrono, Speeduino, Woolich, strip_leading_comment_lines, }; use encoding_rs::{UTF_16BE, UTF_16LE}; @@ -103,6 +103,17 @@ fn main() { std::process::exit(1); } } + } else if RaceChrono::detect(&contents) { + println!("\nDetected: RaceChrono CSV format"); + println!("Parsing RaceChrono session export..."); + let parser = RaceChrono; + match parser.parse(&contents) { + Ok(log) => (EcuType::RaceChrono, log), + Err(e) => { + eprintln!("Parse error: {}", e); + std::process::exit(1); + } + } } else if MegaSquirt::detect(&contents) { println!("\nDetected: MegaSquirt format"); println!("Parsing MegaSquirt log..."); diff --git a/src/parsers/mod.rs b/src/parsers/mod.rs index d374203..0e5281c 100644 --- a/src/parsers/mod.rs +++ b/src/parsers/mod.rs @@ -9,6 +9,7 @@ pub mod locomotive; pub mod megasquirt; pub mod mhd; pub mod motorsport_electronics; +pub mod racechrono; pub mod romraider; pub mod speeduino; pub mod types; @@ -25,6 +26,7 @@ pub use locomotive::Locomotive; pub use megasquirt::MegaSquirt; pub use mhd::Mhd; pub use motorsport_electronics::MotorsportElectronics; +pub use racechrono::RaceChrono; pub use romraider::RomRaider; pub use speeduino::Speeduino; pub use types::{Channel, EcuType, Log, Parseable, Value}; diff --git a/src/parsers/racechrono.rs b/src/parsers/racechrono.rs new file mode 100644 index 0000000..dbd493d --- /dev/null +++ b/src/parsers/racechrono.rs @@ -0,0 +1,899 @@ +//! RaceChrono CSV v3 session export parser. +//! +//! Parses session exports from the RaceChrono / RaceChrono Pro lap-timing +//! app (Android/iOS), which merges GPS, phone-sensor, and OBD/CAN channels +//! into one table. +//! +//! Format characteristics (CSV v3, "Format,3"): +//! - A banner line: `This file is created using RaceChrono Pro vX.Y.Z ...` +//! - A `Key,Value` metadata preamble (`Format`, `Session title`, `Track name`, +//! `Created`, ...) terminated by a blank line. Values may be double-quoted. +//! - A comma-delimited header row whose first column is `timestamp` +//! - A units row (`unix time,,,s,m,...`) — temperatures use `.C` for °C +//! - A sources row tagging each column with its producer +//! (`100: gps`, `calc`, `300: canbus`, `200: acc`, `201: gyro`, `202: magn`) +//! - Data rows keyed by unix-time `timestamp`. Channels update at different +//! rates, so fields are blank between updates of their source. +//! +//! Column names repeat across sources (`speed` from GPS and calc, +//! `device_update_rate` from every sensor), so duplicated names are +//! disambiguated with the source label: `speed (gps)`, `speed (calc)`. +//! When the short labels themselves collide (two location devices both +//! labeled `gps`), the first occurrence keeps its bare name — `latitude` / +//! `longitude` must survive exactly for the GPS Track Map — and later ones +//! carry the full source tag: `latitude (101: gps)`. Unique names are kept +//! exactly as exported. +//! +//! `elapsed_time` resets to zero at every fragment boundary (a fragment is +//! one recording segment; sessions paused and resumed at the track have +//! several), so the unix `timestamp` column is the only valid time base. +//! Times are re-based to seconds since the first record. +//! +//! The parser also survives a spreadsheet round-trip: Excel/Numbers/Sheets +//! pad every preamble line with trailing commas out to the widest row, so +//! metadata values are stripped of that padding before use. +//! +//! Reference: + +use serde::Serialize; +use std::collections::HashMap; +use std::error::Error; + +use super::types::{Channel, Log, Meta, Parseable, Value}; + +/// Number of leading lines inspected when fingerprinting a file. +/// The banner and `Format` marker sit inside the metadata preamble. +const DETECT_SCAN_LINES: usize = 12; + +/// The only CSV export version this parser understands. +const SUPPORTED_FORMAT_VERSION: u32 = 3; + +/// Upper bound on continuation lines joined into one quoted metadata value +/// (e.g. a multi-line `Note`). Stops an unterminated quote from swallowing +/// the rest of the file. +const MAX_QUOTED_VALUE_LINES: usize = 100; + +/// RaceChrono session metadata, taken from the `Key,Value` preamble. +#[derive(Clone, Debug, Default, Serialize)] +pub struct RaceChronoMeta { + /// The full banner line, e.g. + /// `"This file is created using RaceChrono Pro v10.1.3 ( http://racechrono.com/ )."` + pub creator: String, + /// `Format` value (3 for CSV v3) + pub format_version: u32, + /// `Session title` value + pub session_title: String, + /// `Session type` value (e.g. "Lap timing") + pub session_type: String, + /// `Track name` value + pub track_name: String, + /// `Driver name` value — often blank + pub driver_name: String, + /// `Created` value, date and time as exported (e.g. "04/08/2026,13:14") + pub created: String, + /// `Note` value + pub note: String, + /// Number of channels in the log + pub channel_count: usize, + /// Number of data points + pub data_points: usize, +} + +/// RaceChrono channel definition +#[derive(Clone, Debug, Default, Serialize)] +pub struct RaceChronoChannel { + /// Display name; source-suffixed only when the raw column name repeats + /// (e.g. "speed (gps)") + pub name: String, + /// Display unit from the units row, normalized (`.C` -> "°C") + pub unit: String, + /// Raw source tag from the sources row (e.g. "100: gps", "calc") + pub source: String, +} + +/// RaceChrono CSV v3 session export parser +pub struct RaceChrono; + +impl RaceChrono { + /// Detect a RaceChrono CSV session export. + /// + /// Requires both the "created using RaceChrono" banner and a `Format,N` + /// metadata line, so a stray CSV that merely mentions RaceChrono in a + /// comment is not claimed. Any format version is detected — `parse` + /// reports unsupported versions with a clear error instead of letting + /// the file fall through to an unrelated parser. + pub fn detect(contents: &str) -> bool { + let contents = contents.trim_start_matches('\u{FEFF}'); + let mut lines = contents.lines().take(DETECT_SCAN_LINES); + + let Some(banner) = lines.find(|line| !line.trim().is_empty()) else { + return false; + }; + if !banner.contains("RaceChrono") { + return false; + } + + lines.any(|line| line.trim_start().starts_with("Format,")) + } + + /// Trim whitespace and the trailing-comma padding a spreadsheet + /// round-trip adds to preamble lines (`Format,3,,,,` -> `3`). + fn strip_padding(value: &str) -> &str { + value.trim().trim_end_matches(',').trim_end() + } + + /// Whether a line is blank for structural purposes. A spreadsheet + /// round-trip pads the preamble-terminating blank line out to `,,,,,`, + /// which must still read as blank. + fn is_blank_line(line: &str) -> bool { + line.chars().all(|c| c == ',' || c.is_whitespace()) + } + + /// Strip one pair of surrounding double quotes from a metadata value. + fn unquote(value: &str) -> &str { + let value = value.trim(); + value + .strip_prefix('"') + .and_then(|v| v.strip_suffix('"')) + .unwrap_or(value) + } + + /// Whether a padded metadata value opens a quote it does not close, so + /// the value continues on following lines (a multi-line `Note`). + fn is_unterminated_quote(value: &str) -> bool { + value.starts_with('"') && (value.len() == 1 || !value.ends_with('"')) + } + + /// Translate RaceChrono unit notation into the symbols the rest of the + /// app uses. The CSV export writes `.C` where the app shows °C. + fn normalize_unit(unit: &str) -> String { + match unit { + ".C" => "°C".to_string(), + ".F" => "°F".to_string(), + _ => unit.to_string(), + } + } + + /// Whether a field looks like a numbered device tag from the sources + /// row, e.g. "100: gps" or "300: canbus". + fn looks_like_device_tag(field: &str) -> bool { + match field.split_once(':') { + Some((id, label)) => { + let id = id.trim(); + !id.is_empty() && id.chars().all(|c| c.is_ascii_digit()) && !label.trim().is_empty() + } + None => false, + } + } + + /// Reduce a sources-row tag to its label: "100: gps" -> "gps", + /// "calc" -> "calc". The numeric prefix is RaceChrono's device id. + fn source_label(source: &str) -> &str { + match source.split_once(':') { + Some((id, label)) if id.trim().chars().all(|c| c.is_ascii_digit()) => label.trim(), + _ => source.trim(), + } + } + + /// Build unique display names for columns `1..` of the header. + /// + /// - unique column names stay exactly as exported + /// - duplicated names get the source label appended when the labels + /// differ: `speed (gps)`, `speed (calc)` + /// - when the labels collide too (two location devices both labeled + /// `gps`), the first occurrence keeps the bare name — the GPS Track + /// Map matches `latitude`/`longitude` exactly — and later ones carry + /// the full source tag: `latitude (101: gps)` + /// - anything still colliding after that gets an ordinal suffix + fn build_channel_names(header_fields: &[&str], sources: &[String]) -> Vec { + let column_count = header_fields.len(); + + let mut groups: HashMap> = HashMap::new(); + for (idx, field) in header_fields.iter().enumerate().skip(1) { + groups.entry(field.to_lowercase()).or_default().push(idx); + } + + let mut names: Vec = vec![String::new(); column_count]; + for group in groups.values() { + if group.len() == 1 { + let idx = group[0]; + names[idx] = header_fields[idx].to_string(); + continue; + } + + let labels: Vec<&str> = group + .iter() + .map(|&idx| Self::source_label(&sources[idx])) + .collect(); + let mut seen_labels: HashMap = HashMap::new(); + let labels_distinct = labels + .iter() + .all(|l| !l.is_empty() && seen_labels.insert(l.to_lowercase(), ()).is_none()); + + if labels_distinct { + for (pos, &idx) in group.iter().enumerate() { + names[idx] = format!("{} ({})", header_fields[idx], labels[pos]); + } + } else { + names[group[0]] = header_fields[group[0]].to_string(); + for &idx in &group[1..] { + let tag = sources[idx].trim(); + names[idx] = if tag.is_empty() { + header_fields[idx].to_string() + } else { + format!("{} ({})", header_fields[idx], tag) + }; + } + } + } + + // Residual collisions get an ordinal so every channel stays + // individually addressable. + let mut seen: HashMap = HashMap::new(); + for name in names.iter_mut().skip(1) { + let count = seen.entry(name.to_lowercase()).or_insert(0); + *count += 1; + if *count > 1 { + *name = format!("{} #{}", name, count); + } + } + + names + } +} + +impl Parseable for RaceChrono { + fn parse(&self, file_contents: &str) -> Result> { + let file_contents = file_contents.trim_start_matches('\u{FEFF}'); + let mut meta = RaceChronoMeta::default(); + let mut lines = file_contents.lines().peekable(); + + // Phase 1: metadata preamble, terminated by the first blank line + // (possibly comma-padded by a spreadsheet round-trip). + let mut saw_format_line = false; + while let Some(line) = lines.next() { + let trimmed = line.trim(); + if Self::is_blank_line(trimmed) { + break; + } + + let Some((key, value)) = trimmed.split_once(',') else { + // The banner line has no comma. + if meta.creator.is_empty() { + meta.creator = trimmed.to_string(); + } + continue; + }; + + let mut value = Self::strip_padding(value).to_string(); + + // A quoted value can span lines (a multi-line Note). Join the + // continuation lines until the quote closes, bounded so an + // unterminated quote cannot swallow the rest of the file. + if Self::is_unterminated_quote(&value) { + for continuation in lines.by_ref().take(MAX_QUOTED_VALUE_LINES) { + value.push('\n'); + value.push_str(Self::strip_padding(continuation)); + if value.ends_with('"') { + break; + } + } + } + + let value = Self::unquote(&value); + match key.trim() { + "Format" => { + saw_format_line = true; + meta.format_version = value.parse().map_err(|_| { + format!("Invalid RaceChrono format: unparseable version '{}'", value) + })? + } + "Session title" => meta.session_title = value.to_string(), + "Session type" => meta.session_type = value.to_string(), + "Track name" => meta.track_name = value.to_string(), + "Driver name" => meta.driver_name = value.to_string(), + "Created" => meta.created = value.to_string(), + "Note" => meta.note = value.to_string(), + _ => {} + } + } + + // A missing Format line gets its own message — reporting it as + // "version 0 is not supported" would mislead on corrupted or + // truncated exports. + if !saw_format_line { + return Err( + "Invalid RaceChrono format: no 'Format' metadata line found in the preamble".into(), + ); + } + if meta.format_version != SUPPORTED_FORMAT_VERSION { + return Err(format!( + "RaceChrono CSV format version {} is not supported — re-export the session as CSV v3", + meta.format_version + ) + .into()); + } + + // Phase 2: header row. + let header = loop { + let line = lines + .next() + .ok_or("Invalid RaceChrono format: no header row found")?; + let trimmed = line.trim(); + if !Self::is_blank_line(trimmed) { + break trimmed; + } + }; + + let mut header_fields: Vec<&str> = header.split(',').map(str::trim).collect(); + // Drop the trailing empty columns a spreadsheet round-trip appends + // so padding never becomes ghost channels. + while header_fields.len() > 1 && header_fields.last().is_some_and(|f| f.is_empty()) { + header_fields.pop(); + } + let time_header = header_fields.first().copied().unwrap_or(""); + if !time_header.eq_ignore_ascii_case("timestamp") { + return Err(format!( + "Invalid RaceChrono format: expected 'timestamp' as the first column, found '{}'", + time_header + ) + .into()); + } + if header_fields.len() < 2 { + return Err("Invalid RaceChrono format: header row has no channel columns".into()); + } + + // Phase 3: units and sources rows. Both sit between the header and + // the data (recognized by a non-numeric first field) and a file + // missing either one still parses. The sources row is identified by + // its numbered device tags ("100: gps"), so a lone sources row is + // not mistaken for units; two untagged rows keep the exported + // units-then-sources order. Any further annotation row is left for + // the data loop, which skips rows without a usable timestamp. + let mut units_row: Option> = None; + let mut sources_row: Option> = None; + while let Some(&next) = lines.peek() { + let trimmed = next.trim(); + if Self::is_blank_line(trimmed) { + lines.next(); + continue; + } + let first_field = trimmed.split(',').next().unwrap_or("").trim(); + if first_field.parse::().is_ok() { + break; + } + + let row: Vec = next.split(',').map(|f| f.trim().to_string()).collect(); + let has_device_tags = row + .iter() + .skip(1) + .any(|field| Self::looks_like_device_tag(field)); + match (units_row.is_some(), sources_row.is_some()) { + (false, false) => { + if has_device_tags { + sources_row = Some(row); + } else { + units_row = Some(row); + } + } + (true, false) => sources_row = Some(row), + (false, true) => units_row = Some(row), + (true, true) => break, + } + lines.next(); + } + + // Phase 4: build channels for every column after `timestamp`. + let field_at = |row: &Option>, idx: usize| -> String { + row.as_ref() + .and_then(|r| r.get(idx)) + .cloned() + .unwrap_or_default() + }; + + let sources: Vec = (0..header_fields.len()) + .map(|idx| field_at(&sources_row, idx)) + .collect(); + let names = Self::build_channel_names(&header_fields, &sources); + + let channels: Vec = (1..header_fields.len()) + .map(|idx| { + Channel::RaceChrono(RaceChronoChannel { + name: names[idx].clone(), + unit: Self::normalize_unit(&field_at(&units_row, idx)), + source: sources[idx].clone(), + }) + }) + .collect(); + + let channel_count = channels.len(); + + // Phase 5: parse data rows. Channels update at different rates, so + // blank fields carry the last known value for that column (0.0 + // before the first valid sample), matching the Haltech, ECUMaster, + // and MHD parsers. Times are re-based to the first record because + // the raw timestamps are unix time. + let estimated_rows = file_contents + .as_bytes() + .iter() + .filter(|&&b| b == b'\n') + .count(); + let mut times: Vec = Vec::with_capacity(estimated_rows); + let mut data: Vec> = Vec::with_capacity(estimated_rows); + let mut last_values: Vec = vec![Value::Float(0.0); channel_count]; + let mut first_time: Option = None; + let mut out_of_order_rows = 0usize; + let mut malformed_rows = 0usize; + + for line in lines { + let line = line.trim(); + if Self::is_blank_line(line) { + continue; + } + + // Cheap column count so a short row is rejected before any + // last-known-value state is touched. Data rows are unquoted, + // so every comma is a field separator. + let field_count = 1 + line.as_bytes().iter().filter(|&&b| b == b',').count(); + if field_count < header_fields.len() { + malformed_rows += 1; + continue; + } + + let mut fields = line.split(','); + let time: f64 = match fields.next().unwrap_or("").trim().parse() { + Ok(t) => t, + Err(_) => { + // Row without a usable timestamp. + malformed_rows += 1; + continue; + } + }; + + let base = *first_time.get_or_insert(time); + let relative_time = time - base; + + // `times` must stay sorted: computed-channel time-shift lookups + // binary-search it. Drop any row that steps backwards. + if times.last().is_some_and(|last| relative_time < *last) { + out_of_order_rows += 1; + continue; + } + + let mut row: Vec = Vec::with_capacity(channel_count); + for (idx, field) in fields.take(channel_count).enumerate() { + row.push(match field.trim().parse::() { + Ok(v) => { + let value = Value::Float(v); + last_values[idx] = value; + value + } + Err(_) => last_values[idx], + }); + } + + times.push(relative_time); + data.push(row); + } + + if out_of_order_rows > 0 { + tracing::warn!( + "RaceChrono log contained {} out-of-order timestamps; those rows were dropped", + out_of_order_rows + ); + } + if malformed_rows > 0 { + tracing::warn!( + "RaceChrono log contained {} malformed rows (short or missing timestamp); those rows were skipped", + malformed_rows + ); + } + + if times.is_empty() { + return Err("No data rows found in RaceChrono log".into()); + } + + meta.channel_count = channel_count; + meta.data_points = times.len(); + + tracing::info!( + "RaceChrono parse complete: {} channels, {} data points", + channel_count, + meta.data_points + ); + + Ok(Log { + meta: Meta::RaceChrono(meta), + channels, + times, + data, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const SAMPLE: &str = "This file is created using RaceChrono Pro v10.1.3 ( http://racechrono.com/ ).\n\ + Format,3\n\ + Session title,\"Test Session\"\n\ + Session type,Lap timing\n\ + Track name,\"Test Track\"\n\ + Driver name,\n\ + Created,04/08/2026,13:14\n\ + Note,\n\ + \n\ + timestamp,fragment_id,lap_number,elapsed_time,latitude,longitude,speed,speed,engine_oil_temp,rpm\n\ + unix time,,,s,deg,deg,m/s,m/s,.C,rpm\n\ + ,,,,100: gps,100: gps,100: gps,calc,300: canbus,300: canbus\n\ + 1785849363.002,0,,0.002,44.831825,11.224415,0.0,,90.0,850.0\n\ + 1785849363.052,0,,0.052,44.831826,11.224416,1.5,1.4,,900.0\n\ + 1785849363.102,0,1,0.102,44.831827,11.224417,3.0,2.9,91.0,\n"; + + #[test] + fn detects_racechrono_export() { + assert!(RaceChrono::detect(SAMPLE)); + } + + #[test] + fn detects_racechrono_export_with_bom() { + assert!(RaceChrono::detect(&format!("\u{FEFF}{}", SAMPLE))); + } + + #[test] + fn detects_non_pro_banner() { + let contents = "This file is created using RaceChrono v10.1.3 ( http://racechrono.com/ ).\n\ + Format,3\n"; + assert!(RaceChrono::detect(contents)); + } + + #[test] + fn rejects_other_csv_formats() { + // RomRaider-style + assert!(!RaceChrono::detect("Time,RPM,Load\n0,1000,50\n")); + // Haltech + assert!(!RaceChrono::detect("%DataLog%\nDataLogVersion : 1.1\n")); + // A CSV that merely mentions RaceChrono without the Format marker + assert!(!RaceChrono::detect( + "Exported from RaceChrono for analysis\nTime,RPM\n0,1000\n" + )); + // Format marker without the banner + assert!(!RaceChrono::detect("Format,3\ntimestamp,speed\n0,1\n")); + assert!(!RaceChrono::detect("")); + } + + #[test] + fn rejects_unsupported_format_versions() { + let v2 = "This file is created using RaceChrono Pro v10.1.3 ( http://racechrono.com/ ).\n\ + Format,2\n\ + \n\ + timestamp,speed\n"; + // Detection still claims the file so the user gets a clear error + // instead of a fall-through to an unrelated parser. + assert!(RaceChrono::detect(v2)); + let err = RaceChrono.parse(v2).unwrap_err().to_string(); + assert!(err.contains("version 2"), "unexpected error: {}", err); + assert!(err.contains("CSV v3"), "unexpected error: {}", err); + } + + #[test] + fn errors_clearly_on_missing_format_line() { + // A truncated preamble must not be reported as "version 0 is not + // supported". + let contents = "This file is created using RaceChrono Pro v10.1.3\n\ + Session title,\"Test\"\n\ + \n\ + timestamp,speed\n\ + 100.0,1.0\n"; + + let err = RaceChrono.parse(contents).unwrap_err().to_string(); + assert!( + err.contains("no 'Format' metadata line"), + "unexpected error: {}", + err + ); + assert!(!err.contains("version 0"), "unexpected error: {}", err); + } + + #[test] + fn parses_sample_metadata() { + let log = RaceChrono.parse(SAMPLE).expect("parse failed"); + + match log.meta { + Meta::RaceChrono(meta) => { + assert!(meta.creator.contains("RaceChrono Pro v10.1.3")); + assert_eq!(meta.format_version, 3); + assert_eq!(meta.session_title, "Test Session"); + assert_eq!(meta.session_type, "Lap timing"); + assert_eq!(meta.track_name, "Test Track"); + assert_eq!(meta.driver_name, ""); + assert_eq!(meta.created, "04/08/2026,13:14"); + assert_eq!(meta.channel_count, 9); + assert_eq!(meta.data_points, 3); + } + other => panic!("expected RaceChrono metadata, got {:?}", other), + } + } + + #[test] + fn survives_spreadsheet_round_trip_padding() { + // Excel/Numbers/Sheets pad every preamble line with trailing commas + // out to the widest row when a user opens and re-saves the CSV. + let contents = "This file is created using RaceChrono Pro v10.1.3,,,,,,\n\ + Format,3,,,,,\n\ + Session title,\"Padded Session\",,,,,\n\ + Created,04/08/2026,13:14,,,,\n\ + ,,,,,,\n\ + timestamp,speed,rpm,,,,\n\ + unix time,m/s,rpm,,,,\n\ + ,calc,300: canbus,,,,\n\ + 100.0,1.0,1000,,,,\n\ + 100.1,2.0,1100,,,,\n"; + + // A padded blank line is no longer blank, so detection and the + // preamble terminator both need the padding handled. + let log = RaceChrono.parse(contents).expect("parse failed"); + match &log.meta { + Meta::RaceChrono(meta) => { + assert_eq!(meta.format_version, 3); + assert_eq!(meta.session_title, "Padded Session"); + assert_eq!(meta.created, "04/08/2026,13:14"); + } + other => panic!("expected RaceChrono metadata, got {:?}", other), + } + // Trailing padding columns must not become ghost channels + let names: Vec = log.channels.iter().map(|c| c.name()).collect(); + assert_eq!(names, vec!["speed", "rpm"]); + assert_eq!(log.data.len(), 2); + assert_eq!(log.data[1][1].as_f64(), 1100.0); + } + + #[test] + fn joins_multiline_quoted_note() { + let contents = "RaceChrono banner\n\ + Format,3\n\ + Note,\"first line\nsecond line\"\n\ + \n\ + timestamp,speed\n\ + 100.0,1.0\n"; + + let log = RaceChrono.parse(contents).expect("parse failed"); + match &log.meta { + Meta::RaceChrono(meta) => { + assert_eq!(meta.note, "first line\nsecond line"); + } + other => panic!("expected RaceChrono metadata, got {:?}", other), + } + assert_eq!(log.data.len(), 1); + } + + #[test] + fn disambiguates_duplicate_names_with_source_labels() { + let log = RaceChrono.parse(SAMPLE).expect("parse failed"); + + let names: Vec = log.channels.iter().map(|c| c.name()).collect(); + assert_eq!( + names, + vec![ + "fragment_id", + "lap_number", + "elapsed_time", + "latitude", + "longitude", + "speed (gps)", + "speed (calc)", + "engine_oil_temp", + "rpm", + ] + ); + } + + #[test] + fn keeps_gps_channel_names_unsuffixed() { + // The GPS Track Map matches "latitude"/"longitude" exactly; unique + // column names must never grow a source suffix. + let log = RaceChrono.parse(SAMPLE).expect("parse failed"); + assert!(log.channels.iter().any(|c| c.name() == "latitude")); + assert!(log.channels.iter().any(|c| c.name() == "longitude")); + } + + #[test] + fn dual_location_devices_keep_bare_latitude_longitude() { + // Two location devices (phone GPS + external receiver) export the + // same columns with the same short label. The first occurrence must + // keep its bare name for the GPS Track Map; the second carries the + // full source tag. + let contents = "RaceChrono banner\n\ + Format,3\n\ + \n\ + timestamp,latitude,longitude,latitude,longitude\n\ + unix time,deg,deg,deg,deg\n\ + ,100: gps,100: gps,101: gps,101: gps\n\ + 100.0,44.8,11.2,44.9,11.3\n\ + 100.1,44.8,11.2,44.9,11.3\n"; + + let log = RaceChrono.parse(contents).expect("parse failed"); + let names: Vec = log.channels.iter().map(|c| c.name()).collect(); + assert_eq!( + names, + vec![ + "latitude", + "longitude", + "latitude (101: gps)", + "longitude (101: gps)", + ] + ); + } + + #[test] + fn normalizes_units() { + let log = RaceChrono.parse(SAMPLE).expect("parse failed"); + + let unit_of = |name: &str| { + log.channels + .iter() + .find(|c| c.name() == name) + .unwrap_or_else(|| panic!("Missing channel '{}'", name)) + .unit() + .to_string() + }; + + assert_eq!(unit_of("latitude"), "deg"); + assert_eq!(unit_of("speed (gps)"), "m/s"); + // RaceChrono writes '.C' for °C + assert_eq!(unit_of("engine_oil_temp"), "°C"); + assert_eq!(unit_of("rpm"), "rpm"); + assert_eq!(unit_of("fragment_id"), ""); + } + + #[test] + fn rebases_unix_timestamps_to_session_start() { + let log = RaceChrono.parse(SAMPLE).expect("parse failed"); + + assert_eq!(log.times.len(), 3); + assert!(log.times[0].abs() < 1e-9); + assert!((log.times[1] - 0.05).abs() < 1e-6); + assert!((log.times[2] - 0.1).abs() < 1e-6); + } + + #[test] + fn carries_last_known_value_over_blank_fields() { + let log = RaceChrono.parse(SAMPLE).expect("parse failed"); + + let index_of = |name: &str| { + log.channels + .iter() + .position(|c| c.name() == name) + .unwrap_or_else(|| panic!("Missing channel '{}'", name)) + }; + + // speed (calc) is blank on the first row -> 0.0 before first sample + assert_eq!(log.data[0][index_of("speed (calc)")].as_f64(), 0.0); + // engine_oil_temp is blank on the second row -> carries 90.0 + assert_eq!(log.data[1][index_of("engine_oil_temp")].as_f64(), 90.0); + // rpm is blank on the third row -> carries 900.0 + assert_eq!(log.data[2][index_of("rpm")].as_f64(), 900.0); + // lap_number is blank until the first lap -> 0.0, then 1.0 + assert_eq!(log.data[0][index_of("lap_number")].as_f64(), 0.0); + assert_eq!(log.data[2][index_of("lap_number")].as_f64(), 1.0); + } + + #[test] + fn handles_crlf_line_endings() { + let crlf = SAMPLE.replace('\n', "\r\n"); + assert!(RaceChrono::detect(&crlf)); + let log = RaceChrono.parse(&crlf).expect("parse failed"); + assert_eq!(log.channels.len(), 9); + assert_eq!(log.data.len(), 3); + assert_eq!(log.data[2][8].as_f64(), 900.0); + } + + #[test] + fn drops_out_of_order_and_short_rows() { + let contents = "RaceChrono banner\n\ + Format,3\n\ + \n\ + timestamp,speed,rpm\n\ + unix time,m/s,rpm\n\ + ,calc,300: canbus\n\ + 100.0,1.0,1000\n\ + 100.2,2.0,1100\n\ + 100.1,9.9,9999\n\ + 100.3,3.0\n\ + 100.4,4.0,1400\n"; + + let log = RaceChrono.parse(contents).expect("parse failed"); + assert_eq!(log.times.len(), 3); + assert!(log.times.windows(2).all(|w| w[0] <= w[1])); + assert_eq!(log.data[2][0].as_f64(), 4.0); + assert_eq!(log.data[2][1].as_f64(), 1400.0); + } + + #[test] + fn skips_rows_with_unusable_timestamps() { + // A blank or garbage timestamp discards that row only, never the + // whole file — including a garbage row sitting where the data + // should start. + let contents = "RaceChrono banner\n\ + Format,3\n\ + \n\ + timestamp,speed,rpm\n\ + unix time,m/s,rpm\n\ + ,calc,300: canbus\n\ + ,5.0,1500\n\ + 100.0,1.0,1000\n\ + garbage,9.9,9999\n\ + 100.1,2.0,1100\n"; + + let log = RaceChrono.parse(contents).expect("parse failed"); + assert_eq!(log.times.len(), 2); + assert_eq!(log.data[0][1].as_f64(), 1000.0); + assert_eq!(log.data[1][1].as_f64(), 1100.0); + } + + #[test] + fn parses_without_units_and_sources_rows() { + // Defensive: recognize the data start by its numeric first field + // even if the units/sources rows are absent. + let contents = "RaceChrono banner\n\ + Format,3\n\ + \n\ + timestamp,speed,rpm\n\ + 100.0,1.0,1000\n\ + 100.1,2.0,1100\n"; + + let log = RaceChrono.parse(contents).expect("parse failed"); + assert_eq!(log.channels.len(), 2); + assert_eq!(log.channels[0].name(), "speed"); + assert_eq!(log.channels[0].unit(), ""); + assert_eq!(log.data.len(), 2); + } + + #[test] + fn sources_row_without_units_row_is_not_mistaken_for_units() { + // The sources row is recognized by its numbered device tags, so a + // file missing the units row still gets source-labeled duplicate + // names and empty units — not source tags as units. + let contents = "RaceChrono banner\n\ + Format,3\n\ + \n\ + timestamp,speed,speed,rpm\n\ + ,100: gps,calc,300: canbus\n\ + 100.0,1.0,0.9,1000\n\ + 100.1,2.0,1.9,1100\n"; + + let log = RaceChrono.parse(contents).expect("parse failed"); + let names: Vec = log.channels.iter().map(|c| c.name()).collect(); + assert_eq!(names, vec!["speed (gps)", "speed (calc)", "rpm"]); + assert!(log.channels.iter().all(|c| c.unit().is_empty())); + } + + #[test] + fn errors_on_zero_data_rows() { + let contents = "RaceChrono banner\n\ + Format,3\n\ + \n\ + timestamp,speed\n\ + unix time,m/s\n"; + + let err = RaceChrono.parse(contents).unwrap_err().to_string(); + assert!(err.contains("No data rows"), "unexpected error: {}", err); + } + + #[test] + fn source_label_extraction() { + assert_eq!(RaceChrono::source_label("100: gps"), "gps"); + assert_eq!(RaceChrono::source_label("300: canbus"), "canbus"); + assert_eq!(RaceChrono::source_label("calc"), "calc"); + assert_eq!(RaceChrono::source_label(""), ""); + // A colon without a numeric device id is not a source prefix + assert_eq!(RaceChrono::source_label("a: b"), "a: b"); + } + + #[test] + fn rejects_header_without_timestamp_column() { + let contents = "RaceChrono banner\nFormat,3\n\nTime,RPM\n0,1000\n"; + assert!(RaceChrono.parse(contents).is_err()); + } +} diff --git a/src/parsers/types.rs b/src/parsers/types.rs index 297a2a2..4bac068 100644 --- a/src/parsers/types.rs +++ b/src/parsers/types.rs @@ -12,6 +12,7 @@ use super::locomotive::{LocomotiveChannel, LocomotiveMeta}; use super::megasquirt::{MegaSquirtChannel, MegaSquirtMeta}; use super::mhd::{MhdChannel, MhdMeta}; use super::motorsport_electronics::{MotorsportElectronicsChannel, MotorsportElectronicsMeta}; +use super::racechrono::{RaceChronoChannel, RaceChronoMeta}; use super::romraider::{RomRaiderChannel, RomRaiderMeta}; use super::speeduino::{SpeeduinoChannel, SpeeduinoMeta}; use super::woolich::{WoolichChannel, WoolichMeta}; @@ -31,6 +32,7 @@ pub enum Meta { MegaSquirt(MegaSquirtMeta), Mhd(MhdMeta), MotorsportElectronics(MotorsportElectronicsMeta), + RaceChrono(RaceChronoMeta), RomRaider(RomRaiderMeta), Speeduino(SpeeduinoMeta), Woolich(WoolichMeta), @@ -63,6 +65,7 @@ pub enum Channel { MegaSquirt(MegaSquirtChannel), Mhd(MhdChannel), MotorsportElectronics(MotorsportElectronicsChannel), + RaceChrono(RaceChronoChannel), RomRaider(RomRaiderChannel), Speeduino(SpeeduinoChannel), Woolich(WoolichChannel), @@ -87,6 +90,7 @@ impl Serialize for Channel { Channel::MegaSquirt(m) => m.serialize(serializer), Channel::Mhd(m) => m.serialize(serializer), Channel::MotorsportElectronics(m) => m.serialize(serializer), + Channel::RaceChrono(r) => r.serialize(serializer), Channel::RomRaider(r) => r.serialize(serializer), Channel::Speeduino(s) => s.serialize(serializer), Channel::Woolich(w) => w.serialize(serializer), @@ -109,6 +113,7 @@ impl Channel { Channel::MegaSquirt(m) => m.name.clone(), Channel::Mhd(m) => m.name.clone(), Channel::MotorsportElectronics(m) => m.name.clone(), + Channel::RaceChrono(r) => r.name.clone(), Channel::RomRaider(r) => r.name.clone(), Channel::Speeduino(s) => s.name.clone(), Channel::Woolich(w) => w.name.clone(), @@ -130,6 +135,7 @@ impl Channel { Channel::MegaSquirt(m) => m.name.clone(), Channel::Mhd(m) => m.name.clone(), Channel::MotorsportElectronics(m) => m.name.clone(), + Channel::RaceChrono(r) => r.name.clone(), Channel::RomRaider(r) => r.name.clone(), Channel::Speeduino(s) => s.name.clone(), Channel::Woolich(w) => w.name.clone(), @@ -150,6 +156,7 @@ impl Channel { Channel::MegaSquirt(_) => "MegaSquirt".to_string(), Channel::Mhd(_) => "MHD".to_string(), Channel::MotorsportElectronics(_) => "Motorsport Electronics".to_string(), + Channel::RaceChrono(_) => "RaceChrono".to_string(), Channel::RomRaider(_) => "RomRaider".to_string(), Channel::Speeduino(_) => "Speeduino/rusEFI".to_string(), Channel::Woolich(_) => "Woolich".to_string(), @@ -173,6 +180,7 @@ impl Channel { Channel::MegaSquirt(_) => None, Channel::Mhd(_) => None, Channel::MotorsportElectronics(_) => None, + Channel::RaceChrono(_) => None, Channel::RomRaider(_) => None, Channel::Speeduino(_) => None, Channel::Woolich(_) => None, @@ -199,6 +207,7 @@ impl Channel { Channel::MegaSquirt(_) => None, Channel::Mhd(_) => None, Channel::MotorsportElectronics(_) => None, + Channel::RaceChrono(_) => None, Channel::RomRaider(_) => None, Channel::Speeduino(_) => None, Channel::Woolich(_) => None, @@ -237,6 +246,7 @@ impl Channel { Channel::MegaSquirt(m) => m.unit(), Channel::Mhd(m) => &m.unit, Channel::MotorsportElectronics(m) => m.unit(), + Channel::RaceChrono(r) => &r.unit, Channel::RomRaider(r) => r.unit(), Channel::Speeduino(s) => s.unit(), Channel::Woolich(w) => w.unit(), @@ -331,6 +341,7 @@ pub enum EcuType { MegaSquirt, Mhd, MotorsportElectronics, + RaceChrono, Aem, MaxxEcu, MotEc, @@ -354,6 +365,7 @@ impl EcuType { EcuType::MegaSquirt => "MegaSquirt", EcuType::Mhd => "MHD", EcuType::MotorsportElectronics => "Motorsport Electronics", + EcuType::RaceChrono => "RaceChrono", EcuType::Aem => "AEM", EcuType::MaxxEcu => "MaxxECU", EcuType::MotEc => "MoTeC", diff --git a/src/units.rs b/src/units.rs index 17d88e2..6a41b84 100644 --- a/src/units.rs +++ b/src/units.rs @@ -30,6 +30,24 @@ impl TemperatureUnit { TemperatureUnit::Fahrenheit => (kelvin - 273.15) * 9.0 / 5.0 + 32.0, } } + + /// Convert from Celsius to the selected unit + pub fn convert_from_celsius(&self, celsius: f64) -> f64 { + match self { + TemperatureUnit::Kelvin => celsius + 273.15, + TemperatureUnit::Celsius => celsius, + TemperatureUnit::Fahrenheit => celsius * 9.0 / 5.0 + 32.0, + } + } + + /// Convert from Fahrenheit to the selected unit + pub fn convert_from_fahrenheit(&self, fahrenheit: f64) -> f64 { + match self { + TemperatureUnit::Kelvin => (fahrenheit - 32.0) * 5.0 / 9.0 + 273.15, + TemperatureUnit::Celsius => (fahrenheit - 32.0) * 5.0 / 9.0, + TemperatureUnit::Fahrenheit => fahrenheit, + } + } } /// Pressure unit preference @@ -83,6 +101,11 @@ impl SpeedUnit { SpeedUnit::Mph => kmh * 0.621371, } } + + /// Convert from m/s (GPS loggers such as RaceChrono) to the selected unit + pub fn convert_from_mps(&self, mps: f64) -> f64 { + self.convert_from_kmh(mps * 3.6) + } } /// Distance unit preference @@ -108,6 +131,26 @@ impl DistanceUnit { DistanceUnit::Miles => km * 0.621371, } } + + /// Convert a short distance in meters for display. The imperial + /// counterpart of the meter is the foot — channels logged in meters + /// (GPS altitude, accuracy, distance traveled) would read as 0.00x mi + /// if forced through the km -> mi conversion. + pub fn convert_from_meters(&self, meters: f64) -> f64 { + match self { + DistanceUnit::Kilometers => meters, + DistanceUnit::Miles => meters * 3.28084, + } + } + + /// Display symbol for short distances (the meter-sourced counterpart + /// of `symbol()`) + pub fn short_symbol(&self) -> &'static str { + match self { + DistanceUnit::Kilometers => "m", + DistanceUnit::Miles => "ft", + } + } } /// Fuel economy unit preference @@ -290,6 +333,16 @@ impl UnitPreferences { self.temperature.convert_from_kelvin(value), self.temperature.symbol(), ), + // Temperature (source is Celsius — most CSV parsers emit °C) + "°C" => ( + self.temperature.convert_from_celsius(value), + self.temperature.symbol(), + ), + // Temperature (source is Fahrenheit) + "°F" => ( + self.temperature.convert_from_fahrenheit(value), + self.temperature.symbol(), + ), // Pressure (source is kPa) "kPa" => ( self.pressure.convert_from_kpa(value), @@ -297,8 +350,17 @@ impl UnitPreferences { ), // Speed (source is km/h) "km/h" => (self.speed.convert_from_kmh(value), self.speed.symbol()), + // Speed (source is m/s — GPS loggers such as RaceChrono) + "m/s" => (self.speed.convert_from_mps(value), self.speed.symbol()), // Distance (source is km) "km" => (self.distance.convert_from_km(value), self.distance.symbol()), + // Short distance (source is meters). Metric keeps meters, + // imperial shows feet — altitude or GPS accuracy in miles + // would display as 0.00x mi. + "m" => ( + self.distance.convert_from_meters(value), + self.distance.short_symbol(), + ), // Fuel economy (source is L/100km) "L/100km" => ( self.fuel_economy.convert_from_l_per_100km(value), @@ -369,6 +431,31 @@ mod tests { assert!((unit.convert_from_kelvin(233.15) - (-40.0)).abs() < 0.001); } + #[test] + fn test_temperature_from_celsius() { + // Identity + assert_eq!(TemperatureUnit::Celsius.convert_from_celsius(90.0), 90.0); + // 100°C = 212°F + assert!((TemperatureUnit::Fahrenheit.convert_from_celsius(100.0) - 212.0).abs() < 0.001); + // -40°C = -40°F + assert!((TemperatureUnit::Fahrenheit.convert_from_celsius(-40.0) - (-40.0)).abs() < 0.001); + // 0°C = 273.15K + assert!((TemperatureUnit::Kelvin.convert_from_celsius(0.0) - 273.15).abs() < 0.001); + } + + #[test] + fn test_temperature_from_fahrenheit() { + // Identity + assert_eq!( + TemperatureUnit::Fahrenheit.convert_from_fahrenheit(212.0), + 212.0 + ); + // 212°F = 100°C + assert!((TemperatureUnit::Celsius.convert_from_fahrenheit(212.0) - 100.0).abs() < 0.001); + // 32°F = 273.15K + assert!((TemperatureUnit::Kelvin.convert_from_fahrenheit(32.0) - 273.15).abs() < 0.001); + } + #[test] fn test_temperature_symbols() { assert_eq!(TemperatureUnit::Kelvin.symbol(), "K"); @@ -437,6 +524,15 @@ mod tests { assert!((unit.convert_from_kmh(160.0) - 99.4194).abs() < 0.01); } + #[test] + fn test_speed_from_mps() { + // 10 m/s = 36 km/h + assert!((SpeedUnit::KmH.convert_from_mps(10.0) - 36.0).abs() < 0.001); + // 10 m/s ≈ 22.37 mph + assert!((SpeedUnit::Mph.convert_from_mps(10.0) - 22.3694).abs() < 0.001); + assert_eq!(SpeedUnit::KmH.convert_from_mps(0.0), 0.0); + } + #[test] fn test_speed_symbols() { assert_eq!(SpeedUnit::KmH.symbol(), "km/h"); @@ -463,10 +559,20 @@ mod tests { assert!((unit.convert_from_km(1.60934) - 1.0).abs() < 0.001); } + #[test] + fn test_distance_from_meters() { + // Metric keeps meters untouched + assert_eq!(DistanceUnit::Kilometers.convert_from_meters(100.0), 100.0); + // Imperial shows feet: 100 m ≈ 328.084 ft + assert!((DistanceUnit::Miles.convert_from_meters(100.0) - 328.084).abs() < 0.001); + } + #[test] fn test_distance_symbols() { assert_eq!(DistanceUnit::Kilometers.symbol(), "km"); assert_eq!(DistanceUnit::Miles.symbol(), "mi"); + assert_eq!(DistanceUnit::Kilometers.short_symbol(), "m"); + assert_eq!(DistanceUnit::Miles.short_symbol(), "ft"); } // ============================================ @@ -638,6 +744,60 @@ mod tests { assert_eq!(unit, "PSI"); } + #[test] + fn test_unit_preferences_convert_celsius_and_fahrenheit_sources() { + let mut prefs = UnitPreferences::default(); + + // °C source with the default Celsius preference is untouched + let (value, unit) = prefs.convert_value(90.0, "°C"); + assert_eq!(value, 90.0); + assert_eq!(unit, "°C"); + + // Switch to Fahrenheit: parsers that emit °C now honor it + prefs.temperature = TemperatureUnit::Fahrenheit; + let (value, unit) = prefs.convert_value(100.0, "°C"); + assert!((value - 212.0).abs() < 0.001); + assert_eq!(unit, "°F"); + + // °F source with a Celsius preference converts down + prefs.temperature = TemperatureUnit::Celsius; + let (value, unit) = prefs.convert_value(212.0, "°F"); + assert!((value - 100.0).abs() < 0.001); + assert_eq!(unit, "°C"); + } + + #[test] + fn test_unit_preferences_convert_mps_source() { + let mut prefs = UnitPreferences::default(); + + // Default km/h preference: 10 m/s displays as 36 km/h + let (value, unit) = prefs.convert_value(10.0, "m/s"); + assert!((value - 36.0).abs() < 0.001); + assert_eq!(unit, "km/h"); + + // mph preference + prefs.speed = SpeedUnit::Mph; + let (value, unit) = prefs.convert_value(10.0, "m/s"); + assert!((value - 22.3694).abs() < 0.001); + assert_eq!(unit, "mph"); + } + + #[test] + fn test_unit_preferences_convert_meters_source() { + let mut prefs = UnitPreferences::default(); + + // Metric preference keeps meters as meters (altitude, GPS accuracy) + let (value, unit) = prefs.convert_value(100.0, "m"); + assert_eq!(value, 100.0); + assert_eq!(unit, "m"); + + // Imperial preference shows feet, never 0.00x mi + prefs.distance = DistanceUnit::Miles; + let (value, unit) = prefs.convert_value(100.0, "m"); + assert!((value - 328.084).abs() < 0.001); + assert_eq!(unit, "ft"); + } + #[test] fn test_unit_preferences_unknown_unit_passthrough() { let prefs = UnitPreferences::default(); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4f299d6..91cbf2d 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -71,7 +71,10 @@ pub mod example_files { pub const LINK_STANDARD: &str = "exampleLogs/link/linklog.llg"; // RomRaider example files - pub const ROMRAIDER_EUROPEAN: &str = "exampleLogs/romraider/romraiderlog_20251031_170713.csv"; + // Note the directory's capital R: macOS resolves either casing, but + // Linux CI is case-sensitive and a lowercase path silently skips every + // guarded test that uses it. + pub const ROMRAIDER_EUROPEAN: &str = "exampleLogs/RomRaider/romraiderlog_20251031_170713.csv"; /// OBDLink (iOS) export from issue #80. Declares `Time (sec)`, unlike /// RomRaider's own `Time (msec)`, and carries a UTF-8 BOM plus a leading @@ -87,6 +90,14 @@ pub mod example_files { // MHD Tuning example files pub const MHD_N55_PULL: &str = "exampleLogs/mhd/mhd-n55-pull.csv"; + /// RaceChrono CSV v3 session excerpt (user-contributed track session, + /// trimmed to 100 pit-lane rows, 100 rows straddling the genuine + /// fragment 0 -> 1 boundary where `elapsed_time` resets to zero, and + /// 200 mid-session rows on lap 29, so the fixture covers blank-heavy + /// records, fully-populated records, and the fragment reset). + pub const RACECHRONO_V3_EXCERPT: &str = + "exampleLogs/racechrono/session_massa_finalese_v3_excerpt.csv"; + // Woolich Racing Tuned example files pub const WOOLICH_STANDARD: &str = "exampleLogs/woolich/Woolich.csv"; } diff --git a/tests/parsers/mod.rs b/tests/parsers/mod.rs index 5b79a67..edae0d7 100644 --- a/tests/parsers/mod.rs +++ b/tests/parsers/mod.rs @@ -14,6 +14,7 @@ pub mod haltech_tests; pub mod link_tests; pub mod mhd_tests; pub mod motorsport_electronics_tests; +pub mod racechrono_tests; pub mod romraider_tests; pub mod speeduino_tests; pub mod woolich_tests; diff --git a/tests/parsers/racechrono_tests.rs b/tests/parsers/racechrono_tests.rs new file mode 100644 index 0000000..a71b17b --- /dev/null +++ b/tests/parsers/racechrono_tests.rs @@ -0,0 +1,253 @@ +//! RaceChrono CSV v3 parser integration tests +//! +//! Covers detection, parsing of the example session excerpt, duplicate +//! column-name disambiguation, and the unix-timestamp time base. + +#[path = "../common/mod.rs"] +mod common; + +use common::example_files::*; +use common::read_example_file; +use ultralog::parsers::racechrono::RaceChrono; +use ultralog::parsers::types::Meta; +use ultralog::parsers::{EcuMaster, Mhd, Parseable, RomRaider}; + +#[test] +fn test_detect_racechrono_example_file() { + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + assert!( + RaceChrono::detect(&contents), + "Should detect the RaceChrono example export" + ); +} + +#[test] +fn test_parse_racechrono_example_file() { + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + let log = RaceChrono + .parse(&contents) + .expect("Failed to parse RaceChrono example"); + + // Header row is `timestamp` plus 34 channel columns + assert_eq!(log.channels.len(), 34, "Expected 34 channels"); + assert_eq!(log.data.len(), 400, "Expected 400 data rows"); + assert_eq!(log.times.len(), log.data.len()); + + // Every row is aligned with the channel list + for row in &log.data { + assert_eq!(row.len(), log.channels.len()); + } + + // Times are relative to the first sample and monotonically increasing. + // The excerpt splices three slices of the session (pit lane, the + // fragment 0 -> 1 boundary, lap 29), so the span covers the gaps + // between them. + assert_eq!(log.times[0], 0.0); + assert!(log.times.windows(2).all(|w| w[0] <= w[1])); + assert!((log.times.last().unwrap() - 4095.307).abs() < 0.001); +} + +#[test] +fn test_racechrono_fragment_boundary_uses_timestamp_not_elapsed_time() { + // The fixture contains the session's genuine fragment 0 -> 1 boundary: + // elapsed_time resets to ~0 there while the unix timestamps keep + // climbing. This is exactly why the parser must build its time axis + // from `timestamp` — an elapsed_time-based axis would jump backwards. + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + let log = RaceChrono + .parse(&contents) + .expect("Failed to parse RaceChrono example"); + + let index_of = |name: &str| { + log.channels + .iter() + .position(|c| c.name() == name) + .unwrap_or_else(|| panic!("Missing channel '{}'", name)) + }; + + let fragment = index_of("fragment_id"); + let elapsed = index_of("elapsed_time"); + + // Rows 149/150 straddle the boundary + assert_eq!(log.data[149][fragment].as_f64(), 0.0); + assert_eq!(log.data[150][fragment].as_f64(), 1.0); + assert!((log.data[149][elapsed].as_f64() - 771.45).abs() < 1e-6); + assert!((log.data[150][elapsed].as_f64() - 0.002).abs() < 1e-6); + + // elapsed_time drops across the boundary, the time axis must not + assert!(log.data[150][elapsed].as_f64() < log.data[149][elapsed].as_f64()); + assert!(log.times[150] > log.times[149]); +} + +#[test] +fn test_racechrono_metadata() { + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + let log = RaceChrono + .parse(&contents) + .expect("Failed to parse RaceChrono example"); + + match log.meta { + Meta::RaceChrono(meta) => { + assert_eq!(meta.format_version, 3); + assert_eq!(meta.session_title, "Copia di Massa Finalese"); + assert_eq!(meta.session_type, "Lap timing"); + assert_eq!(meta.track_name, "Copia di Massa Finalese"); + assert!(meta.creator.contains("RaceChrono")); + assert_eq!(meta.channel_count, 34); + assert_eq!(meta.data_points, 400); + } + other => panic!("expected RaceChrono metadata, got {:?}", other), + } +} + +#[test] +fn test_racechrono_duplicate_names_disambiguated_by_source() { + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + let log = RaceChrono + .parse(&contents) + .expect("Failed to parse RaceChrono example"); + + let names: Vec = log.channels.iter().map(|c| c.name()).collect(); + + // `speed` comes from both GPS and the calc pipeline + for expected in ["speed (gps)", "speed (calc)"] { + assert!( + names.iter().any(|n| n == expected), + "Expected channel '{}' in {:?}", + expected, + names + ); + } + + // `device_update_rate` is exported once per sensor source + for expected in [ + "device_update_rate (gps)", + "device_update_rate (calc)", + "device_update_rate (acc)", + "device_update_rate (gyro)", + "device_update_rate (magn)", + ] { + assert!( + names.iter().any(|n| n == expected), + "Expected channel '{}' in {:?}", + expected, + names + ); + } + + // No two channels may share a display name + let mut sorted = names.clone(); + sorted.sort(); + sorted.dedup(); + assert_eq!(sorted.len(), names.len(), "channel names must be unique"); +} + +#[test] +fn test_racechrono_gps_channels_keep_plain_names() { + // The GPS Track Map matches these names exactly — a source suffix on + // either would silently disable the track map for RaceChrono logs. + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + let log = RaceChrono + .parse(&contents) + .expect("Failed to parse RaceChrono example"); + + let names: Vec = log.channels.iter().map(|c| c.name()).collect(); + assert!(names.iter().any(|n| n == "latitude")); + assert!(names.iter().any(|n| n == "longitude")); +} + +#[test] +fn test_racechrono_units_normalized() { + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + let log = RaceChrono + .parse(&contents) + .expect("Failed to parse RaceChrono example"); + + let unit_of = |name: &str| { + log.channels + .iter() + .find(|c| c.name() == name) + .unwrap_or_else(|| panic!("Missing channel '{}'", name)) + .unit() + .to_string() + }; + + assert_eq!(unit_of("latitude"), "deg"); + assert_eq!(unit_of("speed (gps)"), "m/s"); + assert_eq!(unit_of("rpm"), "rpm"); + // RaceChrono's CSV export writes '.C' where the app shows °C + assert_eq!(unit_of("engine_oil_temp"), "°C"); +} + +#[test] +fn test_racechrono_values_align_with_channels() { + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + let log = RaceChrono + .parse(&contents) + .expect("Failed to parse RaceChrono example"); + + let index_of = |name: &str| { + log.channels + .iter() + .position(|c| c.name() == name) + .unwrap_or_else(|| panic!("Missing channel '{}'", name)) + }; + + // First data row: parked in the pit lane before the session starts + assert_eq!(log.data[0][index_of("fragment_id")].as_f64(), 0.0); + assert_eq!(log.data[0][index_of("lap_number")].as_f64(), 0.0); + assert!((log.data[0][index_of("latitude")].as_f64() - 44.831825).abs() < 1e-6); + assert!((log.data[0][index_of("longitude")].as_f64() - 11.224415).abs() < 1e-6); + assert_eq!(log.data[0][index_of("speed (gps)")].as_f64(), 0.0); + + // Row 200 is the first spliced mid-session record: fragment 2, lap 29, + // on track at 6420 rpm. + assert_eq!(log.data[200][index_of("fragment_id")].as_f64(), 2.0); + assert_eq!(log.data[200][index_of("lap_number")].as_f64(), 29.0); + assert_eq!(log.data[200][index_of("rpm")].as_f64(), 6420.0); + assert!((log.data[200][index_of("speed (gps)")].as_f64() - 7.26131).abs() < 1e-6); +} + +#[test] +fn test_racechrono_not_confused_with_other_formats() { + let contents = read_example_file(RACECHRONO_V3_EXCERPT); + + assert!( + !Mhd::detect(&contents), + "RaceChrono should not be detected as MHD" + ); + assert!( + !EcuMaster::detect(&contents), + "RaceChrono should not be detected as ECUMaster" + ); + assert!( + !RomRaider::detect(&contents), + "RaceChrono should not be detected as RomRaider" + ); + + // And the reverse: other formats keep their identity + assert!(!RaceChrono::detect("Time,RPM,Load\n0,1000,50\n")); + assert!(!RaceChrono::detect("%DataLog%\nDataLogVersion : 1.1\n")); + assert!(!RaceChrono::detect("TIME;engine/rpm\n0.0;1000\n")); +} + +#[test] +fn test_racechrono_detect_rejects_example_corpus() { + // RaceChrono::detect runs first in the text dispatch chain, so a false + // positive against any other supported format would shadow its parser. + for example in [ + HALTECH_SMALL, + ECUMASTER_STANDARD, + ROMRAIDER_EUROPEAN, + OBDLINK_SECONDS, + MHD_N55_PULL, + WOOLICH_STANDARD, + ] { + let contents = read_example_file(example); + assert!( + !RaceChrono::detect(&contents), + "RaceChrono::detect must not claim {}", + example + ); + } +}