From 34f5fa1b9cf87fd0467782cde5434487e098e6f6 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Sat, 25 Apr 2026 01:07:53 +0300 Subject: [PATCH 01/31] feat(dwh): bronze pipeline migrations, runbook, and execution manual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DWH pipeline (new): - dwh/261001_dwh_control.sql — watermarks + per-run audit log schema - dwh/261002_bronze_constraints_audit.sql — ON CONFLICT key assertion - dwh/261003_dwh_roles.sql — dwh_owner / grafana_ro contract assertion - dwh/261004_dwh_observability_views.sql — v_table_freshness, v_recent_failures, v_watermark_lag (readable by grafana_ro) - docs/DWH_PIPELINE.md — operations runbook (setup, troubleshooting, manual re-run, back-fill, rotation) - DWH_Execution_Manual.md — reusable playbook for future data projects (extract → blob → load pattern, 7 design principles, snapshot-vs-incremental matrix, verification gates) - docs/superpowers/{specs,plans}/2026-04-24-n8n-dwh-bronze-pipeline-* — design spec + 27-task implementation plan Security: - dwh/260423_dwh_ddl_v1.sql — redacted plaintext role passwords to 'CHANGE_ME_BEFORE_APPLY' placeholders; added SECURITY header documenting generation + rotation flow Docs: - CLAUDE.md — §3 adds tracksolid_dwh@31.97.44.246:5888 target, §4 adds dwh/ + docs/DWH_PIPELINE.md to codebase map, §5 adds bronze + dwh_control schema roll-up, §10 adds deploy task + password rotation follow-up Also includes miscellaneous in-progress files accumulated on this branch (workspace, analytics notes, vehicle CSVs, extract helpers, renamed markdown archives). Co-Authored-By: Claude Opus 4.7 --- ...DB_manual.md => ***tracksolid_DB_manual.md | 6 +- ...sAnalytics.md => **01_BusinessAnalytics.md | 0 ...s.md => **02_tracksolid_docker_commands.md | 21 + ...e_report.md => **260410_baseline_report.md | 0 ...ATIONS_MANUAL.md => **OPERATIONS_MANUAL.md | 0 .claude/scheduled_tasks.lock | 1 + 55_ts_coolify_gemini_prod.code-workspace | 14 + CLAUDE.md | 31 +- DWH_Execution_Manual.md | 385 + backup/manualtrigger_backuprest.md | 0 connecting_python_tracksolid.md | 0 docs/DWH_PIPELINE.md | 252 + .../2026-04-24-n8n-dwh-bronze-pipeline.md | 1732 +++++ ...26-04-24-n8n-dwh-bronze-pipeline-design.md | 320 + documents.txt | 0 dwh/260423_dwh_ddl_v1.sql | 367 + dwh/260424_all_vehicles.csv | 163 + dwh/261001_dwh_control.sql | 69 + dwh/261002_bronze_constraints_audit.sql | 63 + dwh/261003_dwh_roles.sql | 66 + dwh/261004_dwh_observability_views.sql | 79 + dwh/device_events_schema | Bin 0 -> 5741 bytes dwh/tracksolid_full_schema.txt | 6842 +++++++++++++++++ fireside_logistics_cleaned_v2.csv | 145 + new_feature.txt | 5 + push_webhook.md | 0 tracksolid_analytics_pipeline.txt | 377 + tracksolid_extract.py | 297 + tracksolid_ingestion_pipeline.txt | 56 + tracksolid_update_v2.py | 359 + tracksolid_vehicle_update.py | 348 + 31 files changed, 11994 insertions(+), 4 deletions(-) rename tracksolid_DB_manual.md => ***tracksolid_DB_manual.md (99%) rename 01_BusinessAnalytics.md => **01_BusinessAnalytics.md (100%) rename 02_tracksolid_docker_commands.md => **02_tracksolid_docker_commands.md (97%) rename 260410_baseline_report.md => **260410_baseline_report.md (100%) rename OPERATIONS_MANUAL.md => **OPERATIONS_MANUAL.md (100%) create mode 100644 .claude/scheduled_tasks.lock create mode 100644 55_ts_coolify_gemini_prod.code-workspace create mode 100644 DWH_Execution_Manual.md create mode 100644 backup/manualtrigger_backuprest.md create mode 100644 connecting_python_tracksolid.md create mode 100644 docs/DWH_PIPELINE.md create mode 100644 docs/superpowers/plans/2026-04-24-n8n-dwh-bronze-pipeline.md create mode 100644 docs/superpowers/specs/2026-04-24-n8n-dwh-bronze-pipeline-design.md create mode 100644 documents.txt create mode 100644 dwh/260423_dwh_ddl_v1.sql create mode 100644 dwh/260424_all_vehicles.csv create mode 100644 dwh/261001_dwh_control.sql create mode 100644 dwh/261002_bronze_constraints_audit.sql create mode 100644 dwh/261003_dwh_roles.sql create mode 100644 dwh/261004_dwh_observability_views.sql create mode 100644 dwh/device_events_schema create mode 100644 dwh/tracksolid_full_schema.txt create mode 100644 fireside_logistics_cleaned_v2.csv create mode 100644 new_feature.txt create mode 100644 push_webhook.md create mode 100644 tracksolid_analytics_pipeline.txt create mode 100644 tracksolid_extract.py create mode 100644 tracksolid_ingestion_pipeline.txt create mode 100644 tracksolid_update_v2.py create mode 100644 tracksolid_vehicle_update.py diff --git a/tracksolid_DB_manual.md b/***tracksolid_DB_manual.md similarity index 99% rename from tracksolid_DB_manual.md rename to ***tracksolid_DB_manual.md index ef86714..870ca8e 100644 --- a/tracksolid_DB_manual.md +++ b/***tracksolid_DB_manual.md @@ -220,9 +220,9 @@ SELECT current_mileage, satellite FROM tracksolid.position_history -WHERE imei = 'YOUR_IMEI_HERE' - AND gps_time >= '2026-04-10 00:00:00+03' - AND gps_time < '2026-04-11 00:00:00+03' +WHERE imei = '862798052708167' + AND gps_time >= '2026-04-22 00:00:00+03' + AND gps_time < '2026-04-23 00:00:00+03' ORDER BY gps_time ASC; ``` diff --git a/01_BusinessAnalytics.md b/**01_BusinessAnalytics.md similarity index 100% rename from 01_BusinessAnalytics.md rename to **01_BusinessAnalytics.md diff --git a/02_tracksolid_docker_commands.md b/**02_tracksolid_docker_commands.md similarity index 97% rename from 02_tracksolid_docker_commands.md rename to **02_tracksolid_docker_commands.md index e4a421a..f990465 100644 --- a/02_tracksolid_docker_commands.md +++ b/**02_tracksolid_docker_commands.md @@ -432,6 +432,27 @@ WHERE d.device_name = 'FRED KMGW 538W HULETI' ORDER BY ph.gps_time ASC; ``` + +``` sql +SELECT + ph.gps_time AT TIME ZONE 'Africa/Nairobi' AS gps_time_eat, + ROUND(ph.lat::numeric, 5) AS lat, + ROUND(ph.lng::numeric, 5) AS lng, + ph.speed, + ph.direction, + ph.acc_status, + ph.source +FROM tracksolid.position_history ph +JOIN tracksolid.devices d ON d.imei = ph.imei +WHERE d.device_name = 'FRED KMGW 538W HULETI' + AND ph.gps_time > now() - interval '24 hours' +ORDER BY ph.gps_time ASC; + +''' + + + + ### Fix density per device — last 24 hours ```sql SELECT diff --git a/260410_baseline_report.md b/**260410_baseline_report.md similarity index 100% rename from 260410_baseline_report.md rename to **260410_baseline_report.md diff --git a/OPERATIONS_MANUAL.md b/**OPERATIONS_MANUAL.md similarity index 100% rename from OPERATIONS_MANUAL.md rename to **OPERATIONS_MANUAL.md diff --git a/.claude/scheduled_tasks.lock b/.claude/scheduled_tasks.lock new file mode 100644 index 0000000..79d7f44 --- /dev/null +++ b/.claude/scheduled_tasks.lock @@ -0,0 +1 @@ +{"sessionId":"c108db62-4596-4e11-a4d2-c706487747bf","pid":15863,"acquiredAt":1776761841807} \ No newline at end of file diff --git a/55_ts_coolify_gemini_prod.code-workspace b/55_ts_coolify_gemini_prod.code-workspace new file mode 100644 index 0000000..cba2bc9 --- /dev/null +++ b/55_ts_coolify_gemini_prod.code-workspace @@ -0,0 +1,14 @@ +{ + "folders": [ + { + "path": "." + }, + { + "path": "../60_karuracc-test-app" + }, + { + "path": "../62_ts_postman" + } + ], + "settings": {} +} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index f7b27ac..0a6de32 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,6 +58,7 @@ See `docs/CONNECTIONS.md` for the full shape. Summary: - **DB name:** `tracksolid_db` · **DB user:** `postgres` (internal) · `tracksolid_owner` (app) · `grafana_ro` (read-only) - **DB schemas:** `tracksolid` (live, single source of truth) · `dwh_gold` (aggregates) · `ops` (workshop / tickets / odometer) · `infrastructure`. The legacy `tracksolid_2` schema no longer exists — migrations 02–06 applied 2026-04-18. - **DB access:** `DATABASE_URL` points to `timescale_db:5432` (internal Docker network — not reachable locally). Use `docker exec` pattern above. See `docs/CONNECTIONS.md` for full reference. +- **DWH target DB:** `tracksolid_dwh` at `31.97.44.246:5888` (separate PostGIS instance, public IP). Users: `dwh_owner` (bronze writes + `dwh_control`), `grafana_ro` (reads bronze/silver/gold/`dwh_control`). Always connect with `sslmode=require`. Fed by the n8n `dwh_extract` + `dwh_load_bronze` workflows — see `docs/DWH_PIPELINE.md`. - **Container naming:** Coolify appends a random suffix. Always resolve with: ```bash docker ps --filter name= --format "{{.Names}}" | head -1 @@ -80,9 +81,16 @@ run_migrations.py # Applies SQL migrations in order at container start docker-compose.yaml # Services: timescale_db, ingest_movement, ingest_events, # webhook_receiver, grafana grafana/ # Grafana provisioning (baked into image) -n8n-workflows/ # n8n workflow exports +n8n-workflows/ # n8n workflow exports (incl. dwh_extract, dwh_load_bronze) docs/ # Reference docs (connections, API, KPIs, project context) +docs/DWH_PIPELINE.md # DWH pipeline operations runbook (setup, troubleshooting) docs/superpowers/ # Pitch specs and implementation plans (not deployed code) +dwh/ # DWH migrations for tracksolid_dwh@31.97.44.246:5888 + # 260423_dwh_ddl_v1.sql — bronze/silver/gold schemas + roles + # 261001_dwh_control.sql — watermarks + run log + # 261002_bronze_constraints_audit.sql — ON CONFLICT key assertion + # 261003_dwh_roles.sql — role contract assertion + # 261004_dwh_observability_views.sql — freshness/failure views 02_tracksolid_full_schema_rev.sql # Full schema bootstrap 03..06_*.sql # Incremental migrations (06 adds assigned_city, dispatch_log, ops.*) 07_analytics_views.sql # Analytics views migration (applied 2026-04-21) @@ -140,6 +148,25 @@ tracksolid.v_sla_inflight -- §4.5 SLA panels (gated on ops.tickets) All views carry a `COMMENT ON VIEW` referencing their spec — `\d+ tracksolid.v_*` shows the provenance. +**DWH bronze layer (separate DB `tracksolid_dwh`)** — populated by the n8n `dwh_extract` + `dwh_load_bronze` workflows. Operational details in `docs/DWH_PIPELINE.md`. + +```sql +-- bronze schema mirrors tracksolid.* (16 tables, DDL in dwh/260423_dwh_ddl_v1.sql) +bronze.devices, bronze.live_positions -- snapshot tables (TRUNCATE + reload) +bronze.position_history, bronze.trips, +bronze.alarms, bronze.parking_events, +bronze.device_events, bronze.ingestion_log -- incremental (watermark + ON CONFLICT DO NOTHING) +-- Schema drift: bronze.trips.distance_km vs source tracksolid.trips.distance_m +-- Extract SQL divides by 1000. Cross-ref FIX-M16. + +-- dwh_control schema tracks pipeline state + observability +dwh_control.extract_watermarks -- one row per incremental table +dwh_control.extract_runs -- per-run audit log (status lifecycle) +dwh_control.v_table_freshness -- Grafana: load lag per table +dwh_control.v_recent_failures -- Grafana: failures in last 24h +dwh_control.v_watermark_lag -- Grafana: extract vs. load lag per table +``` + --- ## 6. API Critical Facts @@ -224,3 +251,5 @@ Latest full snapshot: `260412_baseline_report.md` | MEDIUM | Co-develop client KPI framework (see `docs/KPI_FRAMEWORK.md`) | | LOW | Populate geofences — depot boundaries, city zones | | LOW | Schedule nightly ETL: `SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1)` (cron or n8n) | +| HIGH | Deploy DWH bronze pipeline: apply `dwh/26100{1,2,3,4}.sql` to `tracksolid_dwh`, import + wire the two n8n workflows, verify first run via `dwh_control.v_table_freshness`. Runbook: `docs/DWH_PIPELINE.md` | +| MEDIUM | Rotate `dwh_owner` / `grafana_ro` passwords on `tracksolid_dwh` — plaintext in `dwh/260423_dwh_ddl_v1.sql` is a pre-existing flaw to clean up separately | diff --git a/DWH_Execution_Manual.md b/DWH_Execution_Manual.md new file mode 100644 index 0000000..3122ab8 --- /dev/null +++ b/DWH_Execution_Manual.md @@ -0,0 +1,385 @@ +# DWH Execution Manual + +> **Purpose:** A reusable playbook for building an `extract → blob → load` data warehouse bronze layer using n8n (or any equivalent orchestrator) + object storage + PostgreSQL/PostGIS. Generalised from the Fireside Tracksolid DWH pipeline (2026-04-24). Apply this pattern to future data projects to skip re-deriving the same decisions. +> +> **Reference implementation:** `dwh/26100{1..4}.sql` + `docs/DWH_PIPELINE.md` + the two `n8n-workflows/dwh_*.json` files. Treat those as the copy-paste template for the next project. + +--- + +## 1. When to Use This Pattern + +**Use it when all of these are true:** +- You need an analytical replica of a production OLTP DB without letting analytical load hit the OLTP. +- Source and target are separate PostgreSQL instances (possibly separate networks). +- Data volumes are moderate: millions of rows per day, not billions. +- You already have an orchestrator (n8n, Airflow, Prefect) and object storage (rustfs, S3, MinIO) in the stack. +- Latency tolerance is hours, not minutes. + +**Don't use it when:** +- Sub-minute latency is required → use logical replication or CDC (Debezium, pg_logical, AWS DMS). +- Volumes exceed ~100 GB/day → step up to Spark/Flink + columnar store (Iceberg, Delta). +- Source and target are the same DB → just use materialized views or scheduled SQL. +- You need exactly-once streaming semantics → this pattern is at-least-once + idempotent load. + +--- + +## 2. The Core Pattern + +``` +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│ Source DB │──(a)──▶ Orchestr. │──(b)──▶ Object Store │──(c)──▶ Target DB │ +│ (OLTP) │ │ (extract) │ │ (CSVs) │ │ (bronze) │ +└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ + │ ▲ + └──────────────(d)─────────────────────────────┘ + (load workflow, per CSV) + +(a) Watermarked SELECT, closed upper bound +(b) Atomic CSV upload with timestamped path +(c) CSV stays until load confirms success +(d) Load = BEGIN → INSERT ON CONFLICT → UPDATE watermark → UPDATE run log → COMMIT → move CSV +``` + +**Why three stages and not two:** +- **Audit trail** — every extracted CSV is a point-in-time snapshot you can replay. +- **Decoupling** — target DB downtime doesn't lose data; the CSV waits. +- **Observability** — blob listings are a second source of truth independent of the DB. + +--- + +## 3. Pre-flight Checklist + +Before writing any SQL or workflow JSON, confirm in writing: + +- [ ] Source DB reachable from orchestrator (internal network preferred, VPN/public IP with `sslmode=require` otherwise). +- [ ] Target DB reachable; you hold a superuser credential for one-time DDL. +- [ ] Object storage bucket exists; credentials are configured in the orchestrator. +- [ ] For each source table to extract, you have identified: + - A **DB-insertion timestamp column** (not device/user-reported time), or "it's a snapshot table". + - A **natural unique key** that already has a `PRIMARY KEY` or `UNIQUE` constraint on source (for the `ON CONFLICT` target on bronze). + - Any **unit/column drift** between source and target (e.g., `distance_m` vs. `distance_km`). +- [ ] Acceptable end-to-end latency (to calibrate cron cadence). +- [ ] Security baseline: who writes bronze, who reads it, SSL requirement, password rotation cadence. + +If any row is unchecked, pause and resolve it. Skipping this step is the #1 cause of pipelines that "worked in test but lose data in prod." + +--- + +## 4. Phase-by-Phase Execution + +Execute in order. Phases are independent of each other within their phase, but phases have strict dependencies. + +### Phase A — Target DB preparation + +Apply three types of migrations, in numeric order: + +1. **Bronze DDL** — one table per source table. Use `IF NOT EXISTS`; make it idempotent. +2. **Control schema** — `dwh_control.extract_watermarks` + `dwh_control.extract_runs`. +3. **Assertion migrations** — verify roles exist, verify every `ON CONFLICT` target is backed by a PK/UNIQUE (fail loudly if not). + +Template files: `dwh/260423_dwh_ddl_v1.sql`, `dwh/261001_dwh_control.sql`, `dwh/261002_bronze_constraints_audit.sql`, `dwh/261003_dwh_roles.sql`. + +**Role model:** +- `_owner` — owns schemas, writes bronze + control tables. +- `_ro` (or `grafana_ro`) — reads everything, writes nothing. +- Never use `postgres` or another superuser from the orchestrator. + +**Watermark seed:** set `last_extracted_at` to a date before any real data (`'2000-01-01T00:00:00Z'` is safe) so the first run back-fills all history in a single CSV per table. + +### Phase B — Object storage + +Create two prefixes per table: + +``` +s3:////exports/{table}/ # active CSVs, in-flight +s3:////processed/{table}/ # loaded CSVs, never deleted (audit) +``` + +Naming convention: `{YYYYMMDD_HHMM}_{TZ}.csv` (e.g., `20260424_1400_EAT.csv`). Timezone in the filename because "08:00" means nothing a year from now without it. + +Retention: match whatever backup retention is already in the stack (e.g., 30 days). `processed/` should outlive `exports/`. + +### Phase C — Orchestrator credentials + +Three credentials: + +| Credential | Role | Purpose | +|---|---|---| +| `_source` | Read-only role on source DB | Extract queries | +| `_dwh_target` | `_owner` on target DB | Bronze writes + control updates | +| `_s3` | IAM user with `s3:PutObject`, `s3:GetObject`, `s3:ListBucket`, `s3:DeleteObject` on the prefix | CSV upload/download/move | + +**Always** `sslmode=require` on any public-IP DB connection. Test each credential with the orchestrator's "Test connection" button before proceeding. + +### Phase D — Load workflow (build this BEFORE the extract workflow) + +Building load first lets you iterate with hand-crafted CSVs in blob storage before wiring up extract. Much faster feedback loop. + +Load workflow input (parameters): +```json +{ + "table": "position_history", + "csv_path": "s3://bucket/project/exports/position_history/20260424_1400_EAT.csv", + "run_id": 12345, + "run_started_at": "2026-04-24T11:00:00Z" +} +``` + +Load workflow steps: +1. Download CSV from blob storage. +2. Parse CSV into rows. +3. **Open transaction.** +4. `INSERT INTO bronze. (...) VALUES (...) ON CONFLICT () DO NOTHING;` +5. `UPDATE dwh_control.extract_watermarks SET last_extracted_at = :run_started_at, last_loaded_at = NOW(), rows_loaded_last_run = WHERE table_name = :table;` +6. `UPDATE dwh_control.extract_runs SET status = 'loaded', run_finished_at = NOW(), rows_loaded = WHERE run_id = :run_id;` +7. **Commit.** +8. Move CSV from `exports/` to `processed/` (copy-then-delete; never delete before copy confirms). + +**Non-negotiable invariants:** +- Steps 3–7 are one transaction. If any fails, all rollback. +- Step 8 only runs after commit. If step 8 fails, the next run will re-load the CSV (idempotent via ON CONFLICT) — not a data loss event. + +### Phase E — Extract workflow + +Extract workflow steps, per table: + +1. Read current watermark: `SELECT last_extracted_at FROM dwh_control.extract_watermarks WHERE table_name = :table;` +2. Capture `run_started_at = NOW()` (in the target DB's clock, not the orchestrator's — reduces clock-skew bugs). +3. `INSERT INTO dwh_control.extract_runs (table_name, run_started_at, status) VALUES (:table, :run_started_at, 'extracting') RETURNING run_id;` +4. Query source with closed upper bound: + ```sql + SELECT + FROM .
+ WHERE > :last_extracted_at + AND <= :run_started_at + ORDER BY ; + ``` +5. Render rows as CSV. For geometry columns: `CASE WHEN geom IS NULL THEN NULL ELSE ST_AsEWKT(geom) END`. +6. Upload CSV to `s3://bucket/project/exports/{table}/{YYYYMMDD_HHMM}_{TZ}.csv`. +7. `UPDATE dwh_control.extract_runs SET status = 'uploaded', rows_extracted = , csv_path = :path WHERE run_id = :run_id;` +8. Call load workflow with `{table, csv_path, run_id, run_started_at}`. + +### Phase F — Schedule + observability + +**Cron cadence:** start with 6–8 runs/day during active hours. Fold the overnight gap where traffic is low. Example: `0 5,8,11,14,17,20,23 * * *` TZ `Africa/Nairobi`. + +**Three observability views** (readable by the RO role): + +- `v_table_freshness` — per-table lag from last successful load. Drives the freshness alert. +- `v_recent_failures` — failed runs in last 24h. Zero rows = healthy. +- `v_watermark_lag` — extract vs. load lag per table. Distinguishes "nothing to extract" from "stuck". + +Template file: `dwh/261004_dwh_observability_views.sql`. + +**Grafana panels** (add at minimum): +1. Freshness panel — red if any row in `v_table_freshness` has `lag > 4h`. +2. Failures panel — red if `v_recent_failures` has any row. +3. Row counts panel — daily bar chart from `extract_runs`. + +--- + +## 5. Design Principles (Do Not Skip) + +### 5.1 Watermark on DB insertion time, not source-reported time + +The watermark column must be "when the target DB got the row", not "when the device/user said it happened". Device clocks skew, webhooks arrive late, and batch imports backdate records. A source-reported watermark will silently drop rows that arrive out of order. Use `recorded_at`, `created_at`, `updated_at` (with `DEFAULT NOW()`), or `ingested_at` — never `gps_time` / `event_time` / `timestamp`. + +### 5.2 Closed upper bound + +Extract uses `> last_extracted_at AND <= run_started_at`. The closed upper bound prevents "row committed at `NOW()` during the extract query" from appearing in two adjacent runs. Without it, some rows are double-extracted (wasteful) or missed (data loss). + +### 5.3 Idempotent load via natural unique keys + +Every incremental bronze table needs a PRIMARY KEY or UNIQUE that matches the source's natural unique key. `ON CONFLICT DO NOTHING` makes re-running a CSV harmless. **Do not invent surrogate keys on bronze** — they defeat the ON CONFLICT guarantee. If the source has no natural key, fix the source or accept the table as a snapshot. + +### 5.4 Transactional load boundary + +Insert + watermark update + run-log update are one transaction. Splitting them creates "ghost" states where watermark advanced but rows didn't load, causing silent holes. + +### 5.5 CSV audit trail — never delete + +Moved-to-`processed/` CSVs are cheap ($0.023/GB/month on S3-class storage). They pay for themselves the first time you need to replay a window or debug a row-count mismatch. + +### 5.6 PostGIS round-trip via EWKT + +`ST_AsEWKT(geom)` on extract, `ST_GeomFromEWKT(ewkt)` on load. Preserves SRID inline. Do NOT store `ST_AsText` + separate SRID column — it doubles the chance of mismatch. Guard NULLs: `CASE WHEN geom IS NULL THEN NULL ELSE ST_AsEWKT(geom) END`. + +### 5.7 Fail loud, fail early + +Audit migrations (roles, constraints) should `RAISE EXCEPTION` with a bullet list of what's missing. Silent success is worse than noisy failure — a missing PK surfaces three months later as "why are there duplicate trips?". + +--- + +## 6. Snapshot vs. Incremental Decision Matrix + +| Signal | Snapshot (TRUNCATE + reload) | Incremental (watermark + append) | +|---|---|---| +| Row count | < ~10k | > ~10k | +| Meaning of "current state" | Matters | Doesn't matter; history matters | +| Deletes in source | Common | Rare | +| Update frequency per row | High | Low (append-mostly) | +| Natural unique key | May not exist | Must exist | +| Example | `devices`, `live_positions`, `geofences` | `position_history`, `trips`, `alarms`, event logs | + +When in doubt: **snapshot is simpler**. Only escalate to incremental when the snapshot CSV would exceed a few MB per run. + +--- + +## 7. Observability Contract + +Every pipeline adds these three views to its control schema — no exceptions: + +```sql +CREATE OR REPLACE VIEW .v_table_freshness AS +SELECT table_name, + MAX(run_finished_at) AS last_loaded_at, + NOW() - MAX(run_finished_at) AS lag, + COUNT(*) FILTER (WHERE run_started_at > NOW() - INTERVAL '24 hours') AS loads_last_24h +FROM .extract_runs +WHERE status = 'loaded' +GROUP BY table_name; + +CREATE OR REPLACE VIEW .v_recent_failures AS +SELECT run_id, table_name, run_started_at, run_finished_at, csv_path, error_message +FROM .extract_runs +WHERE status = 'failed' AND run_started_at > NOW() - INTERVAL '24 hours' +ORDER BY run_started_at DESC; + +CREATE OR REPLACE VIEW .v_watermark_lag AS +SELECT table_name, last_extracted_at, last_loaded_at, rows_loaded_last_run, + NOW() - last_loaded_at AS load_lag, + NOW() - last_extracted_at AS extract_lag +FROM .extract_watermarks; +``` + +Wire a Grafana alert on each view. Test the alert by manually failing a run before go-live. + +--- + +## 8. Schema Drift Handling + +Schema drift between source and bronze is inevitable. Two rules: + +1. **Detect at design time.** Diff source DDL against bronze DDL before writing any extract SQL. Unit changes (metres vs. km), renamed columns, and added nullable columns are the usual suspects. +2. **Fix in the extract query, not the load.** Put all transformations in the SELECT so the CSV on disk already matches the bronze column names and units. The load workflow should be dumb — CSV column N goes to bronze column N. + +Document every drift in the runbook (§5 of the operations runbook). Future developers WILL hit them. + +--- + +## 9. Verification Gates + +### Pre-deploy (before first cron tick) + +- [ ] Every migration applied successfully. +- [ ] Control tables seeded (one watermark row per incremental table). +- [ ] Every credential's "Test connection" passes. +- [ ] Blob storage prefixes exist. +- [ ] Manual workflow trigger succeeds end-to-end for one table. + +### First run (manual trigger of extract workflow) + +- [ ] Every processed table has a row in `extract_runs` with `status='loaded'`. +- [ ] Row-count parity with source (± in-flight writes): `SELECT COUNT(*) FROM ` vs. `SELECT COUNT(*) FROM bronze.
`. +- [ ] Geometry columns round-trip cleanly: `SELECT ST_AsText(geom) FROM bronze.
LIMIT 5` returns valid POINTs. +- [ ] All CSVs moved from `exports/` to `processed/`. + +### Steady-state (after 24h / first full schedule cycle) + +- [ ] `v_table_freshness` shows lag < cadence × 2 for every table. +- [ ] `v_recent_failures` is empty. +- [ ] Row counts in bronze growing at expected rate. + +Only declare "done" after all three gates pass. + +--- + +## 10. Scheduling Calibration + +Tradeoffs: + +| Cadence | Pros | Cons | +|---|---|---| +| Every 15 min | Low lag, small CSVs | High orchestrator churn, noisy alerts | +| Every 3 h (recommended) | Predictable, fits ops windows, tolerable lag | Overnight backlog carries to morning | +| Nightly (once/day) | Cheap, simple | Unacceptable for real-time panels | + +Rule of thumb: cadence = 25–50% of your latency tolerance. 4h latency budget → 1-2h cadence. + +Fold cadence around traffic patterns. Don't run 24× at 1-hour intervals if the source generates zero rows between midnight and 05:00. + +--- + +## 11. Common Failure Modes & Recovery + +| Failure | Symptom | Fix | +|---|---|---| +| CSV stuck in `exports/` | `v_recent_failures` has a row; CSV never moved | Next scheduled run retries automatically (idempotent). If persistent, open orchestrator logs by `run_id`. | +| Table marked `loading` for >1 cadence | n8n executor crashed mid-transaction | DB rolled back. Next run retries. If stuck >2 cadences, manually re-trigger the extract. | +| Row counts diverge > 1% | CSV parse error silently dropped rows | `rows_extracted != rows_loaded` in `extract_runs` — inspect the CSV for malformed rows. | +| Geometry loads as NULL | EWKT serialisation broke | Check for missing `CASE WHEN geom IS NULL` guard in extract SQL. | +| Distance/units 1000× wrong | Schema drift not caught | Check extract SQL for the unit conversion (see §8). | + +**Back-fill a window:** +```sql +UPDATE .extract_watermarks +SET last_extracted_at = NOW() - INTERVAL '24 hours' +WHERE table_name = '
'; +``` +Next run re-extracts the gap. `ON CONFLICT DO NOTHING` filters duplicates. + +**Full reseed (nuclear):** +```sql +UPDATE .extract_watermarks +SET last_extracted_at = '2000-01-01T00:00:00Z' +WHERE table_name = '
'; +``` +Next run back-fills all history in one very large CSV. Expected; it moves to `processed/` on success. + +--- + +## 12. Security Baseline + +- Two roles minimum: owner (writes) and RO (reads). Never use superuser from the orchestrator. +- `sslmode=require` on every public-IP DB connection. +- Passwords never in committed SQL — use placeholder tokens (`CHANGE_ME_BEFORE_APPLY`) and swap in-session during apply. Document rotation in the runbook. +- Blob storage credentials scoped to the project's prefix, not the whole bucket. +- Rotate all credentials before go-live (don't reuse the ones that were flying around in design conversations). + +--- + +## 13. Reusability Checklist (Applying to a New Project) + +When starting a new data project, copy the Tracksolid DWH layout and edit these points: + +- [ ] Rename schemas: `_control` instead of `dwh_control` if multiple DWHs share a DB. +- [ ] Adjust `_owner` / `_ro` role names. +- [ ] Update bucket prefix: `s3:////exports|processed/`. +- [ ] Re-do the snapshot/incremental decision for every source table (§6). +- [ ] Identify watermark columns and natural unique keys for every incremental table (§5.1, §5.3). +- [ ] Map schema drift before writing extract SQL (§8). +- [ ] Calibrate cadence to the new project's latency budget (§10). +- [ ] Ship the three observability views (§7) — even if nobody will look at them in week one. +- [ ] Write the runbook from the template: follow `docs/DWH_PIPELINE.md` section-for-section. +- [ ] Run the verification gates (§9) before declaring done. + +--- + +## 14. Reference Implementation (Tracksolid DWH) + +These files are the copy-paste template: + +| File | Purpose | +|---|---| +| `dwh/260423_dwh_ddl_v1.sql` | Bronze DDL + roles + schemas | +| `dwh/261001_dwh_control.sql` | Control schema (watermarks + run log) | +| `dwh/261002_bronze_constraints_audit.sql` | ON CONFLICT key assertion | +| `dwh/261003_dwh_roles.sql` | Role contract assertion | +| `dwh/261004_dwh_observability_views.sql` | Freshness/failure/watermark views | +| `docs/DWH_PIPELINE.md` | Operations runbook (troubleshooting, manual re-run, rotation) | +| `docs/superpowers/specs/2026-04-24-n8n-dwh-bronze-pipeline-design.md` | Design spec (why each decision) | +| `docs/superpowers/plans/2026-04-24-n8n-dwh-bronze-pipeline.md` | Task-by-task implementation plan | +| `n8n-workflows/dwh_extract.json` | Extract workflow (reference) | +| `n8n-workflows/dwh_load_bronze.json` | Load workflow (reference) | + +**For the next project, fork this manual first, then adapt.** Do not re-design from scratch — the seven design principles in §5 are the parts people keep getting wrong. diff --git a/backup/manualtrigger_backuprest.md b/backup/manualtrigger_backuprest.md new file mode 100644 index 0000000..e69de29 diff --git a/connecting_python_tracksolid.md b/connecting_python_tracksolid.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/DWH_PIPELINE.md b/docs/DWH_PIPELINE.md new file mode 100644 index 0000000..fbcefb4 --- /dev/null +++ b/docs/DWH_PIPELINE.md @@ -0,0 +1,252 @@ +# DWH Pipeline — Operations Runbook + +**Pipeline:** n8n extract + load into `tracksolid_dwh` bronze schema +**Design spec:** `docs/superpowers/specs/2026-04-24-n8n-dwh-bronze-pipeline-design.md` +**Implementation plan:** `docs/superpowers/plans/2026-04-24-n8n-dwh-bronze-pipeline.md` + +--- + +## 1. What This Pipeline Does + +Every ~3 hours during active hours (7 runs/day, 05:00–23:00 EAT), n8n extracts 8 tables from the production `tracksolid_db` (Coolify internal network), writes each as a timestamped CSV to rustfs, then loads each CSV into the `bronze` schema on `tracksolid_dwh` (31.97.44.246:5888). Rustfs CSVs are moved to `dwh/processed/` after a successful load — never deleted. + +Two n8n workflows: +- **`dwh_extract`** — cron-triggered, iterates tables in sequence, writes CSVs, calls `dwh_load_bronze` per table. +- **`dwh_load_bronze`** — triggered per-table by `dwh_extract`, loads one CSV inside a single transaction (insert → update watermark → update run log → move CSV). + +--- + +## 2. Key Locations + +| What | Where | +|---|---| +| Source DB | `tracksolid_db` on Coolify (internal Docker network, `timescale_db:5432`) | +| Target DB | `tracksolid_dwh` at `31.97.44.246:5888` | +| Rustfs bucket | `fleet-db` (same bucket used by pg_dump backups) | +| Active CSVs | `s3://fleet-db/dwh/exports/{table}/{YYYYMMDD_HHMM}_EAT.csv` | +| Processed CSVs | `s3://fleet-db/dwh/processed/{table}/{YYYYMMDD_HHMM}_EAT.csv` | +| Control schema | `dwh_control` in `tracksolid_dwh` | +| Migrations | `dwh/26*.sql` applied in numeric order | + +--- + +## 3. First-Time Setup + +Apply migrations to `tracksolid_dwh` in numeric order, as a superuser (not `dwh_owner`): + +```bash +PSQL="psql 'postgres://postgres:***@31.97.44.246:5888/tracksolid_dwh?sslmode=require'" + +$PSQL -f dwh/260423_dwh_ddl_v1.sql # Bronze DDL, roles, schemas +$PSQL -f dwh/261001_dwh_control.sql # Watermarks + run log +$PSQL -f dwh/261002_bronze_constraints_audit.sql # Assertion: ON CONFLICT keys exist +$PSQL -f dwh/261003_dwh_roles.sql # Assertion: roles + grants present +$PSQL -f dwh/261004_dwh_observability_views.sql # Freshness/failure views +``` + +Each migration is idempotent. Audit files (261002, 261003) raise an exception with a bullet list of what is missing if the contract is broken — re-apply the relevant predecessor file and try again. + +### Rustfs prefixes + +```bash +aws --endpoint ${RUSTFS_ENDPOINT} s3api put-object \ + --bucket fleet-db --key dwh/exports/ +aws --endpoint ${RUSTFS_ENDPOINT} s3api put-object \ + --bucket fleet-db --key dwh/processed/ +``` + +### n8n credentials + +Three credentials, all configured in the n8n UI before importing workflows: + +| Credential | Target | User | Notes | +|---|---|---|---| +| `tracksolid_source` | Coolify internal → `tracksolid_db` | `grafana_ro` | Read-only; no `sslmode` needed on internal network | +| `tracksolid_dwh_target` | `31.97.44.246:5888` → `tracksolid_dwh` | `dwh_owner` | **Must set `sslmode=require`** — public IP | +| `rustfs_s3` | `${RUSTFS_ENDPOINT}` | `${RUSTFS_ACCESS_KEY}` | Same creds as pg_dump backup sidecar | + +Test each credential via the n8n "Test connection" button before enabling the cron schedule. + +--- + +## 4. Schedule + +n8n Schedule node, Africa/Nairobi TZ: `0 5,8,11,14,17,20,23 * * *` + +- 7 runs/day at 05:00, 08:00, 11:00, 14:00, 17:00, 20:00, 23:00 EAT +- Overnight gap (23:00 → 05:00 = 6h) by design — device traffic minimal +- First-of-day run carries the overnight backlog (watermark picks up where 23:00 left off) + +--- + +## 5. What Each Table Does on Every Run + +### Snapshot tables (TRUNCATE + full reload) + +`bronze.devices`, `bronze.live_positions` — small state tables, "current state" semantics. Full replace every run. + +### Incremental tables (watermark + append-with-dedup) + +| Bronze table | Source watermark column | ON CONFLICT target | +|---|---|---| +| `position_history` | `recorded_at` (DB insertion time) | `(imei, gps_time)` | +| `trips` | `updated_at` | `id` | +| `alarms` | `updated_at` | `id` | +| `parking_events` | `updated_at` | `id` | +| `device_events` | `created_at` | `id` | +| `ingestion_log` | `run_at` | `id` | + +Watermark bounds are closed upper: `WHERE > last_extracted_at AND <= :run_started_at`. + +### Schema drift to handle in extract SQL + +- **`trips.distance_m` → `bronze.trips.distance_km`**: source stores metres, bronze expects km. Extract SQL: `SELECT ..., distance_m/1000.0 AS distance_km, ...`. Cross-reference: FIX-M16 in `CLAUDE.md`. + +### PostGIS geometry round-trip + +All six geometry columns (`live_positions`, `position_history`, `trips.start_geom`, `trips.end_geom`, `parking_events`, `alarms`) use EWKT serialisation: + +```sql +-- Extract +SELECT ..., CASE WHEN geom IS NULL THEN NULL ELSE ST_AsEWKT(geom) END AS geom_ewkt FROM ...; + +-- Load +INSERT INTO bronze... (..., geom) VALUES (..., ST_GeomFromEWKT(:geom_ewkt)); +``` + +SRID 4326 is preserved inline; no separate SRID step required. + +--- + +## 6. Verifying a Healthy Run + +### Immediate sanity checks (after any scheduled run) + +```sql +-- Any failures in the last hour? +SELECT * FROM dwh_control.v_recent_failures WHERE run_started_at > NOW() - INTERVAL '1 hour'; + +-- All tables loaded in last 4h? +SELECT * FROM dwh_control.v_table_freshness WHERE lag > INTERVAL '4 hours'; + +-- Watermarks advancing? +SELECT * FROM dwh_control.v_watermark_lag ORDER BY extract_lag DESC; +``` + +### Row-count parity (spot check weekly) + +```sql +-- Source +SELECT COUNT(*) FROM tracksolid.position_history; +-- Target +SELECT COUNT(*) FROM bronze.position_history; +``` + +Numbers should match ± rows inserted between the two queries. Persistent gap > 1% → investigate CSV parse errors or a dropped batch. + +### Geometry round-trip + +```sql +SELECT ST_AsText(geom) FROM bronze.position_history WHERE geom IS NOT NULL LIMIT 5; +-- Should return valid POINT(lng lat), not NULL or garbage. +``` + +--- + +## 7. Troubleshooting + +### "A table is stale (`v_table_freshness` shows lag > 4h)" + +1. Check `v_recent_failures` for that table. If a row exists, read `error_message`. +2. If `status='loading'` in `extract_runs` for that table, a load is in progress — wait for the next cron tick. If it stays `loading` across two ticks, the n8n executor crashed mid-transaction; the DB rolled back, and the next run will retry naturally. +3. If no failure row and no in-progress row, the extract workflow never fired — check n8n execution logs for the cron trigger. + +### "A CSV is stuck in `dwh/exports/`" + +The load failed after upload. The next scheduled run will re-process it (the watermark did not advance, so the extract SQL returns the same window). Safe to leave. If multiple days of CSVs pile up, the load workflow has a persistent bug — open n8n execution logs for the specific `run_id` in `extract_runs`. + +### "Row counts diverge more than ~1%" + +Usually one of: +- A retry window overlapped the PK range and some rows lost the race with a concurrent source-side write. Re-trigger the extract for that window manually (see §8). +- CSV parse error silently dropped a row. Check `extract_runs.rows_extracted` vs. `rows_loaded` — if they differ, the loader found malformed CSV. + +### "Geometry loaded as NULL" + +EWKT serialisation broke on the extract side. Verify the source query has the `CASE WHEN geom IS NULL` guard — without it, `ST_AsEWKT(NULL)` returns `NULL` correctly but an empty geometry returns `'GEOMETRYCOLLECTION EMPTY'` which `ST_GeomFromEWKT` rejects. + +### "`bronze.trips.distance_km` values are 1000× too large" + +The extract query is missing `/1000.0` on the source `distance_m` column. See §5 "Schema drift". + +--- + +## 8. Manual Re-Run + +### Re-run a single table for the current window + +1. Open n8n, go to `dwh_extract` workflow. +2. Locate the branch for that table. +3. Click **Execute Workflow** → selects that table only. +4. Confirm a new row appears in `dwh_control.extract_runs` with `status='loaded'`. + +### Back-fill a historical window + +The extract workflow respects the watermark; to re-extract a window, rewind the watermark: + +```sql +-- Rewind position_history to 24h ago +UPDATE dwh_control.extract_watermarks +SET last_extracted_at = NOW() - INTERVAL '24 hours' +WHERE table_name = 'position_history'; +``` + +Next scheduled run will re-extract the gap. Loads are idempotent (`ON CONFLICT DO NOTHING` on the PK), so duplicate rows are filtered at the bronze boundary. + +### Full reseed (nuclear option) + +```sql +-- Restart position_history from the beginning +UPDATE dwh_control.extract_watermarks +SET last_extracted_at = '2026-01-01T00:00:00Z' +WHERE table_name = 'position_history'; +``` + +The first post-reseed run will produce one very large CSV (~all history). The rustfs `exports/` prefix will briefly hold a multi-GB object. Expected; it moves to `processed/` on success. + +--- + +## 9. Credential Rotation + +`260423_dwh_ddl_v1.sql` commits role passwords in plaintext — a pre-existing flaw to be cleaned up separately. + +To rotate: + +```sql +-- As superuser on tracksolid_dwh: +ALTER ROLE dwh_owner PASSWORD ''; +ALTER ROLE grafana_ro PASSWORD ''; +``` + +Then update the matching n8n credential and Grafana datasource. Never commit the new password — store in `.env` if needed for scripts, or keep exclusively inside n8n/Grafana credential stores. + +--- + +## 10. Known Quirks + +| Quirk | Source | Handling | +|---|---|---| +| `trips.distance_m` → `bronze.trips.distance_km` | Schema drift between source and bronze | Divide in extract SQL (§5) | +| Hypertable row counts read 0 in `pg_stat_user_tables` | TimescaleDB quirk | Always `SELECT COUNT(*)` directly | +| `parking_events` can be empty for days | Endpoint returns empty; not a failure | Zero rows loaded is a valid run outcome | +| First run of each day larger | Overnight backlog | Expected; plan watermark design | +| `last_extracted_at` default `2026-01-01` | Seed value from 261001 | First run on a new table back-fills all history | + +--- + +## 11. Out of Scope (follow-up) + +- Silver/gold transformations — `silver` and `gold` schemas exist but contain no views. +- Grafana dashboard panels — these views are the data source; panels TBD. +- OBD / fault codes / fuel / temperature / LBS / heartbeats — webhooks not yet registered; add a watermark row + extract branch when they start reporting. +- Bronze schema evolution tooling — additive changes via numbered migrations is fine for one pipeline; revisit if scope grows. diff --git a/docs/superpowers/plans/2026-04-24-n8n-dwh-bronze-pipeline.md b/docs/superpowers/plans/2026-04-24-n8n-dwh-bronze-pipeline.md new file mode 100644 index 0000000..b98d6e7 --- /dev/null +++ b/docs/superpowers/plans/2026-04-24-n8n-dwh-bronze-pipeline.md @@ -0,0 +1,1732 @@ +# n8n DWH Bronze Layer Pipeline Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Stand up an n8n-driven DWH extract→blob→bronze pipeline that mirrors `tracksolid_db` tables into `tracksolid_dwh.bronze` via rustfs-hosted CSV files 7× per day. + +**Architecture:** Two n8n workflows — `dwh_extract` (scheduled, reads source → writes CSV to rustfs) and `dwh_load_bronze` (triggered per table → reads CSV → upserts into `bronze` schema). A `dwh_control` schema on the target DB holds per-table watermarks and a run log for observability and idempotent retry. + +**Tech Stack:** n8n (workflow orchestration) · PostgreSQL 16 + TimescaleDB 2.15 + PostGIS 3 (source `tracksolid_db` on Coolify, target `tracksolid_dwh` at `31.97.44.246:5888`) · rustfs S3-compatible storage (bucket `fleet-db`) · psql for migrations. + +**Reference spec:** `docs/superpowers/specs/2026-04-24-n8n-dwh-bronze-pipeline-design.md` + +--- + +## Adaptation Note for This Plan + +Classic TDD (write failing unit test → implement → watch pass) doesn't cleanly apply to n8n JSON workflows. For every task in this plan: + +- **SQL migrations / bash / scripts** — use TDD: write a verification query that SHOULD fail now, run it, apply the change, re-run, expect success. +- **n8n workflow nodes** — build each node, then run the workflow in n8n's "Execute Workflow" mode and inspect the output at that node before moving on. Export JSON to repo after each stable checkpoint. +- **End-to-end** — row-count parity between source and bronze is the integration test. + +Every task below includes an explicit verification step with expected output. + +--- + +## File Structure + +| Path | Created | Purpose | +|---|---|---| +| `dwh/260423_dwh_ddl_v1.sql` | existing | Bronze/silver/gold schemas + 16 bronze tables (already authored) | +| `dwh/261001_dwh_control.sql` | new | `dwh_control` schema — watermarks + run log + role setup | +| `dwh/261002_bronze_constraints_audit.sql` | new | Patches any missing UNIQUE constraints on bronze tables needed for `ON CONFLICT` | +| `n8n-workflows/dwh_extract.json` | new | Workflow 1 export (scheduled extract → CSV → rustfs) | +| `n8n-workflows/dwh_load_bronze.json` | new | Workflow 2 export (rustfs CSV → bronze upsert) | +| `n8n-workflows/dwh_error_notifier.json` | new | Shared error-workflow wired to both pipeline workflows | +| `docs/DWH_PIPELINE.md` | new | Operations runbook (setup, manual trigger, troubleshooting) | +| `CLAUDE.md` | modify §3,§4,§5,§10 | Add `tracksolid_dwh` connection to §3; bronze pipeline to §4 map, §5 table list, and remove DWH from §10 open items | + +--- + +## Task Sequence Overview + +**Phase A — Target DB setup** (Tasks 1–5): apply bronze DDL, control schema, roles, constraint audit. One-time. +**Phase B — Rustfs setup** (Task 6): create prefixes. +**Phase C — n8n credential hardening** (Tasks 7–8): switch to scoped users, enforce SSL. +**Phase D — Workflow 2 (load) built first** (Tasks 9–13): the load workflow is simpler and Workflow 1 calls it, so we build the callee first and test it with a hand-crafted CSV. +**Phase E — Workflow 1 (extract) built per table** (Tasks 14–23): add tables one at a time, starting with the smallest (`devices` snapshot), end-to-end verifying each before moving on. +**Phase F — Observability & go-live** (Tasks 24–28): error workflow, cron enable, 24h steady-state check, runbook, docs. + +--- + +## Phase A — Target DB Setup + +### Task 1: Apply existing bronze DDL to `tracksolid_dwh` + +**Files:** +- Apply: `dwh/260423_dwh_ddl_v1.sql` (existing file, no modification) + +**Purpose:** Ensure all 16 bronze tables exist on the target DB before anything else touches it. + +- [ ] **Step 1: Confirm target DB is reachable and empty (verification-first)** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 \ + -U postgres -d tracksolid_dwh \ + -c "\dt bronze.*" +``` + +Expected (before change): `Did not find any relation named "bronze.*".` + +If a connection error occurs, confirm `sslmode=require` is appended to the URI or that SSL isn't enforced on the server yet — document which. + +- [ ] **Step 2: Apply the DDL** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 \ + -U postgres -d tracksolid_dwh \ + -f dwh/260423_dwh_ddl_v1.sql +``` + +- [ ] **Step 3: Verify 16 bronze tables exist** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 \ + -U postgres -d tracksolid_dwh \ + -c "SELECT count(*) FROM pg_tables WHERE schemaname='bronze';" +``` + +Expected: `16` (per the DDL: devices, position_history, trips, alarms, live_positions, parking_events, device_events, fault_codes, fuel_readings, obd_readings, heartbeats, ingestion_log, dispatch_log, geofences, lbs_readings, temperature_readings). + +- [ ] **Step 4: Verify `silver` and `gold` schemas exist (empty OK)** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 \ + -U postgres -d tracksolid_dwh \ + -c "SELECT schema_name FROM information_schema.schemata WHERE schema_name IN ('bronze','silver','gold') ORDER BY schema_name;" +``` + +Expected: three rows — `bronze`, `gold`, `silver`. + +- [ ] **Step 5: Commit nothing (no repo change yet — just a deploy step)** + +No commit. This is a stateful one-time operation on the remote DB; record the date/time applied in the runbook (Task 27). + +--- + +### Task 2: Author and apply `dwh/261001_dwh_control.sql` (watermarks + run log) + +**Files:** +- Create: `dwh/261001_dwh_control.sql` +- Apply to: `tracksolid_dwh` at `31.97.44.246:5888` + +- [ ] **Step 1: Write `dwh/261001_dwh_control.sql`** + +```sql +-- dwh/261001_dwh_control.sql +-- Control schema: per-table watermarks and run-level audit log. +-- Applied once to tracksolid_dwh. + +BEGIN; + +CREATE SCHEMA IF NOT EXISTS dwh_control; + +CREATE TABLE IF NOT EXISTS dwh_control.extract_watermarks ( + table_name TEXT PRIMARY KEY, + last_extracted_at TIMESTAMPTZ NOT NULL DEFAULT '2026-01-01T00:00:00Z', + last_loaded_at TIMESTAMPTZ, + rows_loaded_last_run INT, + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS dwh_control.extract_runs ( + run_id BIGSERIAL PRIMARY KEY, + table_name TEXT NOT NULL, + run_started_at TIMESTAMPTZ NOT NULL, + run_finished_at TIMESTAMPTZ, + rows_extracted INT, + rows_loaded INT, + csv_path TEXT, + status TEXT CHECK (status IN ('extracting','uploaded','loading','loaded','failed')), + error_message TEXT +); + +CREATE INDEX IF NOT EXISTS idx_extract_runs_table_time + ON dwh_control.extract_runs (table_name, run_started_at DESC); +CREATE INDEX IF NOT EXISTS idx_extract_runs_status_time + ON dwh_control.extract_runs (status, run_finished_at DESC); + +-- Seed one row per incremental table so first extract runs use the default bound. +INSERT INTO dwh_control.extract_watermarks (table_name) VALUES + ('position_history'), ('trips'), ('alarms'), + ('parking_events'), ('device_events'), ('ingestion_log') +ON CONFLICT (table_name) DO NOTHING; + +COMMIT; +``` + +- [ ] **Step 2: Verify the migration fails "cleanly" pre-apply (schema doesn't exist)** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh \ + -c "SELECT count(*) FROM dwh_control.extract_watermarks;" +``` + +Expected: error like `relation "dwh_control.extract_watermarks" does not exist`. + +- [ ] **Step 3: Apply migration** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh \ + -f dwh/261001_dwh_control.sql +``` + +- [ ] **Step 4: Verify watermark seeds** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh \ + -c "SELECT table_name, last_extracted_at FROM dwh_control.extract_watermarks ORDER BY table_name;" +``` + +Expected: 6 rows, all with `last_extracted_at = 2026-01-01 00:00:00+00`: +``` + table_name | last_extracted_at +-----------------+------------------------ + alarms | 2026-01-01 00:00:00+00 + device_events | 2026-01-01 00:00:00+00 + ingestion_log | 2026-01-01 00:00:00+00 + parking_events | 2026-01-01 00:00:00+00 + position_history| 2026-01-01 00:00:00+00 + trips | 2026-01-01 00:00:00+00 +``` + +- [ ] **Step 5: Commit** + +```bash +git add dwh/261001_dwh_control.sql +git commit -m "feat(dwh): add dwh_control schema with watermarks and run log" +``` + +--- + +### Task 3: Create scoped `dwh_owner` and `dwh_ro` roles + +**Files:** +- Create: `dwh/261003_dwh_roles.sql` +- Apply to: `tracksolid_dwh` + +- [ ] **Step 1: Write `dwh/261003_dwh_roles.sql`** + +```sql +-- dwh/261003_dwh_roles.sql +-- Role hardening: n8n writes as dwh_owner (not postgres), Grafana reads as dwh_ro. +-- Passwords are templated; replace and +-- at apply time (do NOT commit the real values). + +BEGIN; + +-- Writer role: owns bronze + dwh_control only. +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='dwh_owner') THEN + CREATE ROLE dwh_owner LOGIN PASSWORD ''; + END IF; +END$$; + +GRANT USAGE, CREATE ON SCHEMA bronze TO dwh_owner; +GRANT USAGE, CREATE ON SCHEMA dwh_control TO dwh_owner; +GRANT ALL ON ALL TABLES IN SCHEMA bronze TO dwh_owner; +GRANT ALL ON ALL TABLES IN SCHEMA dwh_control TO dwh_owner; +GRANT ALL ON ALL SEQUENCES IN SCHEMA bronze TO dwh_owner; +GRANT ALL ON ALL SEQUENCES IN SCHEMA dwh_control TO dwh_owner; +ALTER DEFAULT PRIVILEGES IN SCHEMA bronze GRANT ALL ON TABLES TO dwh_owner; +ALTER DEFAULT PRIVILEGES IN SCHEMA dwh_control GRANT ALL ON TABLES TO dwh_owner; +ALTER DEFAULT PRIVILEGES IN SCHEMA bronze GRANT ALL ON SEQUENCES TO dwh_owner; +ALTER DEFAULT PRIVILEGES IN SCHEMA dwh_control GRANT ALL ON SEQUENCES TO dwh_owner; + +-- Reader role: read-only across bronze + dwh_control (for Grafana dashboards). +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='dwh_ro') THEN + CREATE ROLE dwh_ro LOGIN PASSWORD ''; + END IF; +END$$; + +GRANT USAGE ON SCHEMA bronze TO dwh_ro; +GRANT USAGE ON SCHEMA dwh_control TO dwh_ro; +GRANT SELECT ON ALL TABLES IN SCHEMA bronze TO dwh_ro; +GRANT SELECT ON ALL TABLES IN SCHEMA dwh_control TO dwh_ro; +ALTER DEFAULT PRIVILEGES IN SCHEMA bronze GRANT SELECT ON TABLES TO dwh_ro; +ALTER DEFAULT PRIVILEGES IN SCHEMA dwh_control GRANT SELECT ON TABLES TO dwh_ro; + +COMMIT; +``` + +- [ ] **Step 2: Apply with real passwords (templated, not committed)** + +Generate two random passwords, export them as shell vars, substitute with `sed`, apply, then clear: + +```bash +export DWH_OWNER_PW=$(openssl rand -hex 24) +export DWH_RO_PW=$(openssl rand -hex 24) +sed "s//$DWH_OWNER_PW/; s//$DWH_RO_PW/" \ + dwh/261003_dwh_roles.sql \ + | PGPASSWORD= psql -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh +echo "Store these in 1Password / Coolify secrets:" +echo " dwh_owner: $DWH_OWNER_PW" +echo " dwh_ro: $DWH_RO_PW" +unset DWH_OWNER_PW DWH_RO_PW +``` + +Copy both passwords into Coolify secret manager (or 1Password vault, per team convention) BEFORE closing the terminal. + +- [ ] **Step 3: Verify roles and grants** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh \ + -c "\du dwh_owner" \ + -c "\du dwh_ro" \ + -c "SELECT grantee, privilege_type, table_schema FROM information_schema.table_privileges WHERE grantee IN ('dwh_owner','dwh_ro') AND table_schema IN ('bronze','dwh_control') GROUP BY 1,2,3 ORDER BY 1,3,2;" +``` + +Expected: `dwh_owner` has ALL on both schemas; `dwh_ro` has only SELECT. + +- [ ] **Step 4: Verify `dwh_owner` can log in and write** + +Run: +```bash +PGPASSWORD=$DWH_OWNER_PW psql \ + -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh \ + -c "INSERT INTO dwh_control.extract_runs (table_name, run_started_at, status) VALUES ('_smoke_test_', NOW(), 'extracting') RETURNING run_id;" \ + -c "DELETE FROM dwh_control.extract_runs WHERE table_name='_smoke_test_';" +``` + +Expected: one run_id returned, then `DELETE 1`. + +- [ ] **Step 5: Verify `dwh_ro` cannot write** + +Run: +```bash +PGPASSWORD=$DWH_RO_PW psql \ + -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh \ + -c "INSERT INTO dwh_control.extract_runs (table_name, run_started_at, status) VALUES ('_should_fail_', NOW(), 'extracting');" +``` + +Expected: `ERROR: permission denied for table extract_runs`. + +- [ ] **Step 6: Commit** + +```bash +git add dwh/261003_dwh_roles.sql +git commit -m "feat(dwh): add dwh_owner and dwh_ro scoped roles" +``` + +--- + +### Task 4: Audit bronze tables for UNIQUE constraints needed by `ON CONFLICT` + +**Files:** +- Create: `dwh/261002_bronze_constraints_audit.sql` +- Apply to: `tracksolid_dwh` + +**Purpose:** The design spec uses `ON CONFLICT (id) DO NOTHING` (for tables with a serial id) and `ON CONFLICT (imei, gps_time) DO NOTHING` (for `position_history`). Verify these constraints exist in the bronze DDL; patch anything missing. + +- [ ] **Step 1: Inspect existing bronze constraints** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh \ + -c "SELECT conrelid::regclass AS table, conname, contype, pg_get_constraintdef(oid) FROM pg_constraint WHERE connamespace = 'bronze'::regnamespace AND contype IN ('p','u') ORDER BY 1;" +``` + +Review output. For each table below, confirm the listed conflict target exists as PK or UNIQUE: + +| Bronze table | Required conflict target | +|---|---| +| `bronze.devices` | `(imei)` as PK | +| `bronze.live_positions` | `(imei)` as PK | +| `bronze.position_history` | `(imei, gps_time)` | +| `bronze.trips` | `(id)` as PK | +| `bronze.alarms` | `(id)` as PK | +| `bronze.parking_events` | `(id)` as PK | +| `bronze.device_events` | `(id)` as PK | +| `bronze.ingestion_log` | `(id)` as PK | + +- [ ] **Step 2: Write `dwh/261002_bronze_constraints_audit.sql`** + +This file is authored based on the output of Step 1. If all constraints are present, the file is a no-op audit with a comment documenting the check. If any are missing, add the appropriate `ALTER TABLE ... ADD CONSTRAINT` statements. + +Template (fill the ADD CONSTRAINT block with only the statements that are actually needed): + +```sql +-- dwh/261002_bronze_constraints_audit.sql +-- Audit: ensure bronze tables have unique keys matching the ON CONFLICT +-- targets used by the dwh_load_bronze workflow. +-- Run after 260423_dwh_ddl_v1.sql on tracksolid_dwh. + +BEGIN; + +-- PASTE any ALTER TABLE ... ADD CONSTRAINT statements identified in Step 1 here. +-- Example shape (only include if pg_constraint did not already list it): +-- ALTER TABLE bronze.position_history +-- ADD CONSTRAINT position_history_dedup UNIQUE (imei, gps_time); + +-- Assert every target exists. If any assert fails, the migration aborts. +DO $$ +DECLARE + checks TEXT[] := ARRAY[ + 'bronze.devices,{imei}', + 'bronze.live_positions,{imei}', + 'bronze.position_history,{imei,gps_time}', + 'bronze.trips,{id}', + 'bronze.alarms,{id}', + 'bronze.parking_events,{id}', + 'bronze.device_events,{id}', + 'bronze.ingestion_log,{id}' + ]; + chk TEXT; + tbl TEXT; + cols TEXT; +BEGIN + FOREACH chk IN ARRAY checks LOOP + tbl := split_part(chk, ',', 1); + cols := split_part(chk, ',', 2); + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint c + JOIN pg_class t ON t.oid = c.conrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname || '.' || t.relname = tbl + AND c.contype IN ('p','u') + AND pg_get_constraintdef(c.oid) ILIKE '%' || replace(replace(cols,'{',''),'}','') || '%' + ) THEN + RAISE EXCEPTION 'Missing unique/primary constraint: % on %', cols, tbl; + END IF; + END LOOP; +END$$; + +COMMIT; +``` + +- [ ] **Step 3: Apply and verify** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh \ + -f dwh/261002_bronze_constraints_audit.sql +``` + +Expected: `COMMIT`. If any constraint is missing, the `DO` block raises and aborts — iterate on Step 2 until all assertions pass. + +- [ ] **Step 4: Commit** + +```bash +git add dwh/261002_bronze_constraints_audit.sql +git commit -m "feat(dwh): assert bronze ON CONFLICT targets exist" +``` + +--- + +### Task 5: Verify end-to-end target-DB state + +- [ ] **Step 1: Check-list query** + +Run: +```bash +PGPASSWORD= psql \ + -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh <<'SQL' +\echo '== bronze tables ==' +SELECT count(*) AS bronze_tables FROM pg_tables WHERE schemaname='bronze'; +\echo '== dwh_control tables ==' +SELECT count(*) AS control_tables FROM pg_tables WHERE schemaname='dwh_control'; +\echo '== watermark seeds ==' +SELECT count(*) AS seeded FROM dwh_control.extract_watermarks; +\echo '== roles ==' +SELECT rolname FROM pg_roles WHERE rolname IN ('dwh_owner','dwh_ro') ORDER BY 1; +SQL +``` + +Expected: +``` +bronze_tables: 16 +control_tables: 2 +seeded: 6 +roles: dwh_owner, dwh_ro +``` + +- [ ] **Step 2: No commit (pure verification)** + +--- + +## Phase B — Rustfs Setup + +### Task 6: Create `dwh/exports/` and `dwh/processed/` prefixes in `fleet-db` bucket + +**Files:** +- Remote-only: `s3://fleet-db/dwh/exports/` and `s3://fleet-db/dwh/processed/` + +- [ ] **Step 1: Verify rustfs bucket reachable** + +Export secrets from Coolify `.env` (do not print): +```bash +export AWS_ACCESS_KEY_ID=$RUSTFS_ACCESS_KEY +export AWS_SECRET_ACCESS_KEY=$RUSTFS_SECRET_KEY +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 ls s3://fleet-db/ +``` + +Expected: listing includes `daily/` (pg_dump backups) — this confirms credentials and endpoint. + +- [ ] **Step 2: Create placeholder marker files to establish prefixes** + +S3-compatible stores create "folders" lazily — a zero-byte marker makes them visible immediately: + +```bash +echo "" | aws --endpoint-url "$RUSTFS_ENDPOINT" s3 cp - s3://fleet-db/dwh/exports/.keep +echo "" | aws --endpoint-url "$RUSTFS_ENDPOINT" s3 cp - s3://fleet-db/dwh/processed/.keep +``` + +- [ ] **Step 3: Verify prefixes visible** + +Run: +```bash +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 ls s3://fleet-db/dwh/ +``` + +Expected: +``` + PRE exports/ + PRE processed/ +``` + +- [ ] **Step 4: No commit (remote-only state)** + +--- + +## Phase C — n8n Credential Hardening + +### Task 7: Update `tracksolid_dwh_target` credential in n8n + +**Files:** n8n credential store only (not in repo). + +- [ ] **Step 1: Edit credential in n8n UI** + +Open n8n → Credentials → `tracksolid_dwh_target` (or create if not present). Set: +- Host: `31.97.44.246` +- Port: `5888` +- Database: `tracksolid_dwh` +- User: `dwh_owner` +- Password: (the `DWH_OWNER_PW` from Task 3, now in Coolify secrets) +- SSL: `require` + +- [ ] **Step 2: Test connection** + +Click "Test" in n8n credential dialog. Expected: `Connection tested successfully`. + +- [ ] **Step 3: Paper trail — record the change in runbook draft** + +No commit yet. Note in a scratch file that credential was updated; the runbook (Task 27) will document the final state. + +--- + +### Task 8: Update `tracksolid_source` credential to use `grafana_ro` + +**Files:** n8n credential store only. + +- [ ] **Step 1: Confirm `grafana_ro` exists on source DB** + +The source already has `grafana_ro` per CLAUDE.md. Verify: +```bash +DB=$(docker ps --filter name=timescale_db --format "{{.Names}}" | head -1) +docker exec "$DB" psql -U postgres -d tracksolid_db -c "\du grafana_ro" +``` + +Expected: role exists with LOGIN. If missing, create with SELECT-only grants across `tracksolid` schema. + +- [ ] **Step 2: Update n8n credential** + +In n8n UI edit `tracksolid_source`: +- User: `grafana_ro` +- Password: (from `.env` `GRAFANA_DB_RO_PASSWORD`) + +Test connection — expected success. + +- [ ] **Step 3: Smoke-test read access from n8n** + +Create a throwaway n8n Postgres node with `SELECT count(*) FROM tracksolid.devices;` → execute once. Expected: `63` (or current count). Delete the throwaway node. + +--- + +## Phase D — Workflow 2 (`dwh_load_bronze`) + +### Task 9: Create Workflow 2 skeleton with Execute Workflow trigger + +**Files:** +- Create in n8n UI: workflow `dwh_load_bronze` +- Export to: `n8n-workflows/dwh_load_bronze.json` (after each task step that changes it) + +**Purpose:** The load workflow is the callee. Building it first means Workflow 1 can be tested incrementally against a working load target. + +- [ ] **Step 1: Create new workflow in n8n UI** + +n8n → New Workflow → Name: `dwh_load_bronze`. Add an "Execute Workflow Trigger" node as the starting node. + +Configure the trigger's input schema (n8n auto-detects; set these as documentation): +``` +{ + "table": "string (required) — one of: devices, live_positions, position_history, trips, alarms, parking_events, device_events, ingestion_log", + "csv_path": "string (required) — rustfs key, e.g. dwh/exports/devices/20260424_0800_EAT.csv", + "run_id": "integer (required) — dwh_control.extract_runs.run_id produced by Workflow 1", + "run_started_at": "string ISO-8601 — used as the upper watermark bound" +} +``` + +- [ ] **Step 2: Export to repo as initial skeleton** + +Click ⋯ → Download → save as `n8n-workflows/dwh_load_bronze.json`. + +- [ ] **Step 3: Commit** + +```bash +git add n8n-workflows/dwh_load_bronze.json +git commit -m "feat(n8n): scaffold dwh_load_bronze workflow" +``` + +--- + +### Task 10: Add rustfs download node to Workflow 2 + +**Files:** +- Modify: `n8n-workflows/dwh_load_bronze.json` (via n8n UI → Download) + +- [ ] **Step 1: Add node `Download CSV from rustfs`** + +Node type: `S3` +Operation: `Download` +Credential: `rustfs_s3` +Parameters: +- Bucket Name: `fleet-db` +- File Key: `={{ $json.csv_path }}` +- Binary Property: `data` + +Wire: `Execute Workflow Trigger → Download CSV from rustfs`. + +- [ ] **Step 2: Manually test with a hand-crafted CSV** + +Create a tiny test CSV locally and upload: +```bash +cat > /tmp/test_devices.csv <<'CSV' +imei,vehicle_number,driver_name +862798000000001,TEST-01,Test Driver +CSV +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 cp /tmp/test_devices.csv s3://fleet-db/dwh/exports/devices/_smoke_test.csv +``` + +In n8n UI click "Execute Workflow" on `dwh_load_bronze` → supply test input: +```json +{ + "table": "devices", + "csv_path": "dwh/exports/devices/_smoke_test.csv", + "run_id": 0, + "run_started_at": "2026-04-24T12:00:00Z" +} +``` + +Expected: Download node output shows a binary item with the CSV content. + +- [ ] **Step 3: Export + commit** + +```bash +# After exporting the updated JSON from n8n +git add n8n-workflows/dwh_load_bronze.json +git commit -m "feat(n8n): add rustfs download step to dwh_load_bronze" +``` + +--- + +### Task 11: Add CSV parse + bronze-upsert node for `devices` (snapshot pattern) + +**Files:** +- Modify: `n8n-workflows/dwh_load_bronze.json` + +**Purpose:** Get ONE table end-to-end before parameterising. `devices` is the simplest — no geometry, small row count, TRUNCATE+INSERT pattern. + +- [ ] **Step 1: Add node `Parse CSV`** + +Node type: `Extract From File` → Operation: `Extract From CSV` +Parameters: +- Binary Property: `data` +- Options → Header Row: enabled +- Options → Delimiter: `,` + +Wire: `Download CSV → Parse CSV`. + +- [ ] **Step 2: Add Switch node `Route by table`** + +Node type: `Switch` +Rules: one output per `{{$node["Execute Workflow Trigger"].json.table}}` value. For this task only wire the `devices` branch; others will be added in later tasks. + +- [ ] **Step 3: Add node `Load bronze.devices (snapshot)`** + +Node type: `Postgres` +Operation: `Execute Query` +Credential: `tracksolid_dwh_target` +Query (parameterised): +```sql +BEGIN; + +TRUNCATE bronze.devices; + +INSERT INTO bronze.devices (imei, vehicle_number, driver_name /* + all other devices columns */) +SELECT imei, vehicle_number, driver_name /* ... */ +FROM json_populate_recordset(NULL::bronze.devices, $1::json); + +UPDATE dwh_control.extract_watermarks + SET last_loaded_at = NOW(), + rows_loaded_last_run = (SELECT count(*) FROM bronze.devices), + updated_at = NOW() + WHERE table_name = 'devices'; + +UPDATE dwh_control.extract_runs + SET status = 'loaded', + run_finished_at = NOW(), + rows_loaded = (SELECT count(*) FROM bronze.devices) + WHERE run_id = $2; + +COMMIT; +``` + +Query Parameters: +- `$1`: `={{ JSON.stringify($node["Parse CSV"].json) }}` +- `$2`: `={{ $node["Execute Workflow Trigger"].json.run_id }}` + +**Note on `json_populate_recordset`:** this is the cleanest way to bulk-load n8n's per-row items into a target table when schemas align. If column names in the CSV exactly match `bronze.devices` column names, this works with no per-column mapping. If the CSV has extra or renamed columns, use an explicit `SELECT col1, col2, ...` instead. + +- [ ] **Step 4: Seed a run_id row for the smoke test** + +Before testing, insert a row the workflow will update: +```bash +PGPASSWORD=$DWH_OWNER_PW psql -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh -c \ + "INSERT INTO dwh_control.extract_runs (table_name, run_started_at, status, csv_path) VALUES ('devices', NOW(), 'uploaded', 'dwh/exports/devices/_smoke_test.csv') RETURNING run_id;" +``` + +Record the returned `run_id` (e.g. `1`). + +- [ ] **Step 5: Execute workflow against smoke-test CSV** + +Input to Execute Workflow Trigger: +```json +{ + "table": "devices", + "csv_path": "dwh/exports/devices/_smoke_test.csv", + "run_id": , + "run_started_at": "2026-04-24T12:00:00Z" +} +``` + +Expected: all nodes green. + +- [ ] **Step 6: Verify bronze and control state** + +Run: +```bash +PGPASSWORD=$DWH_OWNER_PW psql -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh <<'SQL' +SELECT count(*) AS devices_rows FROM bronze.devices; +SELECT run_id, status, rows_loaded, run_finished_at + FROM dwh_control.extract_runs WHERE table_name='devices' ORDER BY run_id DESC LIMIT 1; +SELECT rows_loaded_last_run, last_loaded_at + FROM dwh_control.extract_watermarks WHERE table_name='devices'; +SQL +``` + +Expected: +- `devices_rows = 1` (just the smoke-test row) +- `status = 'loaded'`, `rows_loaded = 1`, `run_finished_at` populated +- `rows_loaded_last_run = 1`, `last_loaded_at` populated + +- [ ] **Step 7: Clean up the smoke-test row** + +```bash +PGPASSWORD=$DWH_OWNER_PW psql -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh -c \ + "TRUNCATE bronze.devices; UPDATE dwh_control.extract_watermarks SET last_loaded_at=NULL, rows_loaded_last_run=NULL WHERE table_name='devices';" +``` + +- [ ] **Step 8: Export + commit** + +```bash +# After export +git add n8n-workflows/dwh_load_bronze.json +git commit -m "feat(n8n): add devices snapshot load path to dwh_load_bronze" +``` + +--- + +### Task 12: Add incremental-load path for `position_history` (with geometry) + +**Files:** +- Modify: `n8n-workflows/dwh_load_bronze.json` + +**Purpose:** This proves the hardest case — composite conflict target + PostGIS geometry round-trip. + +- [ ] **Step 1: Add node `Load bronze.position_history (incremental)`** + +Node type: `Postgres` +Credential: `tracksolid_dwh_target` +Query: +```sql +BEGIN; + +INSERT INTO bronze.position_history + (imei, gps_time, geom, lat, lng, speed, direction, acc_status, satellite, current_mileage, recorded_at) +SELECT + imei, + gps_time::timestamptz, + CASE WHEN geom_ewkt IS NULL OR geom_ewkt = '' THEN NULL ELSE ST_GeomFromEWKT(geom_ewkt) END, + lat::double precision, + lng::double precision, + speed::numeric, + direction::numeric, + acc_status, + satellite::smallint, + current_mileage::numeric, + recorded_at::timestamptz +FROM json_populate_recordset(NULL::record, $1::json) AS r( + imei text, gps_time text, geom_ewkt text, lat text, lng text, + speed text, direction text, acc_status text, satellite text, + current_mileage text, recorded_at text +) +ON CONFLICT (imei, gps_time) DO NOTHING; + +WITH counts AS (SELECT count(*) AS c FROM json_populate_recordset(NULL::record, $1::json) AS r(imei text)) +UPDATE dwh_control.extract_watermarks + SET last_extracted_at = $3::timestamptz, + last_loaded_at = NOW(), + rows_loaded_last_run = (SELECT c FROM counts), + updated_at = NOW() + WHERE table_name = 'position_history'; + +UPDATE dwh_control.extract_runs + SET status = 'loaded', + run_finished_at = NOW(), + rows_loaded = (SELECT c FROM (SELECT count(*) AS c FROM json_populate_recordset(NULL::record, $1::json) AS r(imei text)) AS s) + WHERE run_id = $2; + +COMMIT; +``` + +Query Parameters: +- `$1`: `={{ JSON.stringify($node["Parse CSV"].json) }}` +- `$2`: `={{ $node["Execute Workflow Trigger"].json.run_id }}` +- `$3`: `={{ $node["Execute Workflow Trigger"].json.run_started_at }}` + +Wire the `position_history` branch of the Switch node to this node. + +- [ ] **Step 2: Prepare a smoke-test CSV with one geometry row** + +```bash +cat > /tmp/test_ph.csv <<'CSV' +imei,gps_time,geom_ewkt,lat,lng,speed,direction,acc_status,satellite,current_mileage,recorded_at +862798000000001,2026-04-24T10:00:00Z,SRID=4326;POINT(36.82 -1.29),-1.29,36.82,42.5,180,on,12,123456.78,2026-04-24T10:00:05Z +CSV +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 cp /tmp/test_ph.csv s3://fleet-db/dwh/exports/position_history/_smoke_test.csv +``` + +- [ ] **Step 3: Seed devices row (FK) and run_id** + +```bash +PGPASSWORD=$DWH_OWNER_PW psql -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh <<'SQL' +INSERT INTO bronze.devices (imei) VALUES ('862798000000001') ON CONFLICT DO NOTHING; +INSERT INTO dwh_control.extract_runs (table_name, run_started_at, status, csv_path) + VALUES ('position_history', NOW(), 'uploaded', 'dwh/exports/position_history/_smoke_test.csv') + RETURNING run_id; +SQL +``` + +Record the `run_id`. + +- [ ] **Step 4: Execute workflow** + +Input: +```json +{ + "table": "position_history", + "csv_path": "dwh/exports/position_history/_smoke_test.csv", + "run_id": , + "run_started_at": "2026-04-24T10:30:00Z" +} +``` + +- [ ] **Step 5: Verify geometry round-trip** + +```bash +PGPASSWORD=$DWH_OWNER_PW psql -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh -c \ + "SELECT imei, gps_time, ST_AsText(geom) AS geom_wkt, lat, lng FROM bronze.position_history WHERE imei='862798000000001';" +``` + +Expected: +``` + imei | gps_time | geom_wkt | lat | lng +-----------------+--------------------+----------------+-------+------- + 862798000000001 | 2026-04-24 10:00:00| POINT(36.82 -1.29) | -1.29 | 36.82 +``` + +- [ ] **Step 6: Verify idempotency by re-running** + +Execute the workflow a second time with identical input. Expected: no new row in bronze.position_history (ON CONFLICT DO NOTHING), but `rows_loaded_last_run` in watermarks still reports 1 (rows received, not rows new — this is expected behaviour and documented in the runbook). + +- [ ] **Step 7: Clean up** + +```bash +PGPASSWORD=$DWH_OWNER_PW psql -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh -c \ + "TRUNCATE bronze.position_history; DELETE FROM bronze.devices WHERE imei='862798000000001';" +``` + +- [ ] **Step 8: Export + commit** + +```bash +git add n8n-workflows/dwh_load_bronze.json +git commit -m "feat(n8n): add position_history incremental load with PostGIS round-trip" +``` + +--- + +### Task 13: Add remaining 6 load paths (`live_positions`, `trips`, `alarms`, `parking_events`, `device_events`, `ingestion_log`) + +**Files:** +- Modify: `n8n-workflows/dwh_load_bronze.json` + +**Purpose:** Copy the pattern from Task 12 (incremental) or Task 11 (snapshot) for each remaining table. One table per commit so regressions are bisectable. + +Each sub-task follows this shape: + +- [ ] **Sub-task 13a: `live_positions` (snapshot, has geometry)** + +Query pattern: +```sql +BEGIN; +TRUNCATE bronze.live_positions; +INSERT INTO bronze.live_positions + (imei, geom, lat, lng, /* ...all cols... */) +SELECT + imei, + CASE WHEN geom_ewkt IS NULL OR geom_ewkt='' THEN NULL ELSE ST_GeomFromEWKT(geom_ewkt) END, + lat::double precision, lng::double precision, + /* ...casts per column... */ +FROM json_populate_recordset(NULL::record, $1::json) AS r( + imei text, geom_ewkt text, lat text, lng text /* ... */ +); +UPDATE dwh_control.extract_watermarks + SET last_loaded_at = NOW(), + rows_loaded_last_run = (SELECT count(*) FROM bronze.live_positions), + updated_at = NOW() + WHERE table_name = 'live_positions'; +UPDATE dwh_control.extract_runs + SET status='loaded', run_finished_at = NOW(), + rows_loaded = (SELECT count(*) FROM bronze.live_positions) + WHERE run_id = $2; +COMMIT; +``` +Smoke test + commit: follow the shape of Task 11 steps 4–8. + +- [ ] **Sub-task 13b: `trips` (incremental, has geometry ×2)** + +Conflict target: `(id)`. Geometry columns: `start_geom`, `end_geom` (both optional). Watermark column: `updated_at`. + +Query shape — key diff from Task 12: two `ST_GeomFromEWKT` calls, one per geometry column, and conflict target is `(id)`: +```sql +INSERT INTO bronze.trips (id, imei, start_time, end_time, start_geom, end_geom, distance_m, avg_speed_kmh, max_speed_kmh, updated_at) +SELECT + id::bigint, imei, start_time::timestamptz, end_time::timestamptz, + CASE WHEN start_geom_ewkt IS NULL OR start_geom_ewkt='' THEN NULL ELSE ST_GeomFromEWKT(start_geom_ewkt) END, + CASE WHEN end_geom_ewkt IS NULL OR end_geom_ewkt='' THEN NULL ELSE ST_GeomFromEWKT(end_geom_ewkt) END, + distance_m::numeric, avg_speed_kmh::numeric, max_speed_kmh::numeric, updated_at::timestamptz +FROM json_populate_recordset(NULL::record, $1::json) AS r( + id text, imei text, start_time text, end_time text, + start_geom_ewkt text, end_geom_ewkt text, + distance_m text, avg_speed_kmh text, max_speed_kmh text, updated_at text +) +ON CONFLICT (id) DO NOTHING; +``` +Then the matching watermarks + extract_runs updates (same shape as Task 12 Step 1). + +Smoke test + commit. + +- [ ] **Sub-task 13c: `alarms` (incremental, has geometry)** — conflict on `(id)`, watermark `updated_at`, one `geom`. Smoke test + commit. + +- [ ] **Sub-task 13d: `parking_events` (incremental, has geometry)** — conflict on `(id)`, watermark `updated_at`, one `geom`. Smoke test + commit. + +- [ ] **Sub-task 13e: `device_events` (incremental, no geometry)** — conflict on `(id)`, watermark `created_at` (source column name — in the CSV we'll preserve whatever header Workflow 1 emits; match here). Smoke test + commit. + +- [ ] **Sub-task 13f: `ingestion_log` (incremental, no geometry)** — conflict on `(id)`, watermark `run_at`. Smoke test + commit. + +After all six sub-tasks, Workflow 2 has 8 parallel load paths from the Switch node. + +--- + +## Phase E — Workflow 1 (`dwh_extract`) + +### Task 14: Create Workflow 1 skeleton with Schedule Trigger (disabled) + +**Files:** +- Create in n8n UI: workflow `dwh_extract` +- Export to: `n8n-workflows/dwh_extract.json` + +- [ ] **Step 1: New workflow in n8n UI** + +Name: `dwh_extract`. Status: Disabled (we'll enable only after go-live in Task 26). + +- [ ] **Step 2: Add Schedule Trigger node** + +Node type: `Schedule Trigger` +Cron expression: `0 5,8,11,14,17,20,23 * * *` +Timezone: `Africa/Nairobi` + +- [ ] **Step 3: Add Set node `init_run_context`** + +Node type: `Set` (Edit Fields) +Mode: `Manual mapping` → Keep Only Set fields +Add: +- `run_started_at` = `={{ $now.toISO() }}` + +Wire: `Schedule Trigger → init_run_context`. + +- [ ] **Step 4: Export + commit** + +```bash +git add n8n-workflows/dwh_extract.json +git commit -m "feat(n8n): scaffold dwh_extract workflow (disabled)" +``` + +--- + +### Task 15: Build the `devices` extract branch (snapshot) + +**Files:** +- Modify: `n8n-workflows/dwh_extract.json` + +- [ ] **Step 1: Add Postgres node `Extract: devices`** + +Node type: `Postgres` +Credential: `tracksolid_source` +Operation: `Execute Query` +Query: +```sql +-- devices is a snapshot table: no watermark, just full dump. +SELECT imei, vehicle_number, driver_name, driver_phone, sim, /* + remaining 22 columns */ + assigned_city, device_model, created_at, updated_at +FROM tracksolid.devices +ORDER BY imei; +``` + +- [ ] **Step 2: Add Postgres node `Insert extract_runs (devices)`** + +Credential: `tracksolid_dwh_target` +Query: +```sql +INSERT INTO dwh_control.extract_runs (table_name, run_started_at, status, rows_extracted) +VALUES ('devices', $1::timestamptz, 'extracting', $2::int) +RETURNING run_id; +``` +Parameters: +- `$1`: `={{ $node["init_run_context"].json.run_started_at }}` +- `$2`: `={{ $node["Extract: devices"].json.length }}` + +- [ ] **Step 3: Add node `Format as CSV`** + +Node type: `Convert to File` → Operation: `Convert to CSV` +Parameters: +- Binary Property: `data` +- Input (JSON items): `={{ $node["Extract: devices"].json }}` + +- [ ] **Step 4: Add node `Upload CSV to rustfs`** + +Node type: `S3` +Operation: `Upload` +Credential: `rustfs_s3` +Parameters: +- Bucket: `fleet-db` +- File Key: `=dwh/exports/devices/{{ $now.setZone('Africa/Nairobi').toFormat('yyyyLLdd_HHmm') }}_EAT.csv` +- Binary Property: `data` + +- [ ] **Step 5: Add Postgres node `Update extract_runs status='uploaded'`** + +Query: +```sql +UPDATE dwh_control.extract_runs + SET status = 'uploaded', csv_path = $1 + WHERE run_id = $2; +``` +Parameters: +- `$1`: the file key from Step 4 (capture via Set node or re-compute) +- `$2`: the `run_id` from Step 2 + +- [ ] **Step 6: Add node `Trigger Workflow 2 for devices`** + +Node type: `Execute Workflow` +Workflow: `dwh_load_bronze` +Input: +```json +{ + "table": "devices", + "csv_path": "={{ file_key from Step 4 }}", + "run_id": "={{ $node['Insert extract_runs (devices)'].json.run_id }}", + "run_started_at": "={{ $node['init_run_context'].json.run_started_at }}" +} +``` + +- [ ] **Step 7: Manually execute `dwh_extract` workflow (single-table mode)** + +Use n8n's "Execute Workflow" button. Monitor: every node green, Workflow 2 completes, bronze.devices populated with real row count. + +- [ ] **Step 8: Verify end-to-end** + +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT (SELECT count(*) FROM bronze.devices) AS bronze_count, + (SELECT rows_loaded FROM dwh_control.extract_runs WHERE table_name='devices' ORDER BY run_id DESC LIMIT 1) AS last_rows_loaded;" +``` + +Cross-check against source: +```bash +DB=$(docker ps --filter name=timescale_db --format "{{.Names}}" | head -1) +docker exec "$DB" psql -U grafana_ro -d tracksolid_db -c "SELECT count(*) FROM tracksolid.devices;" +``` + +Expected: both counts match (current source = 63). + +- [ ] **Step 9: Export + commit** + +```bash +git add n8n-workflows/dwh_extract.json +git commit -m "feat(n8n): add devices extract branch to dwh_extract" +``` + +--- + +### Task 16: Build the `position_history` extract branch (incremental with watermark) + +**Files:** +- Modify: `n8n-workflows/dwh_extract.json` + +**Purpose:** Prove the incremental pattern end-to-end for the hardest table (geometry + large row counts + watermark). + +- [ ] **Step 1: Add Postgres node `Read watermark: position_history`** + +Credential: `tracksolid_dwh_target` +Query: +```sql +SELECT last_extracted_at FROM dwh_control.extract_watermarks WHERE table_name = 'position_history'; +``` + +- [ ] **Step 2: Add Postgres node `Extract: position_history`** + +Credential: `tracksolid_source` +Query: +```sql +SELECT + imei, + gps_time, + CASE WHEN geom IS NULL THEN NULL ELSE ST_AsEWKT(geom) END AS geom_ewkt, + lat, lng, speed, direction, acc_status, satellite, current_mileage, recorded_at +FROM tracksolid.position_history +WHERE recorded_at > $1::timestamptz + AND recorded_at <= $2::timestamptz +ORDER BY recorded_at; +``` +Parameters: +- `$1`: `={{ $node['Read watermark: position_history'].json.last_extracted_at }}` +- `$2`: `={{ $node['init_run_context'].json.run_started_at }}` + +- [ ] **Step 3: Add `Insert extract_runs`, `Format as CSV`, `Upload CSV`, `Update extract_runs`, `Trigger Workflow 2`** + +Follow the shape of Task 15 Steps 2–6 with these changes: +- `table` = `position_history` +- Extract SQL uses watermark bounds from Steps 1–2 +- CSV key: `dwh/exports/position_history/YYYYMMDD_HHMM_EAT.csv` +- Workflow 2 input `table` = `position_history` + +- [ ] **Step 4: Execute and verify end-to-end** + +Execute `dwh_extract` workflow manually. Expected (first run with seeded 2026-01-01 watermark): backlog of all position_history rows pulled in one CSV, loaded into bronze. + +Verify row-count parity: +```bash +# Source +docker exec "$DB" psql -U grafana_ro -d tracksolid_db -c \ + "SELECT count(*) FROM tracksolid.position_history;" +# Bronze +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT count(*) FROM bronze.position_history;" +``` + +Expected: counts match (current source ≈ 519). + +Verify geometry round-trip on a sample: +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT imei, gps_time, ST_AsText(geom) FROM bronze.position_history ORDER BY gps_time DESC LIMIT 3;" +``` + +Expected: valid `POINT(lng lat)` values. + +- [ ] **Step 5: Verify watermark advanced** + +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT last_extracted_at, last_loaded_at, rows_loaded_last_run FROM dwh_control.extract_watermarks WHERE table_name='position_history';" +``` + +Expected: `last_extracted_at` ≈ the `run_started_at` from the execution (not 2026-01-01 anymore). + +- [ ] **Step 6: Second execution — verify incremental behaviour** + +Execute `dwh_extract` again immediately. Expected: `rows_extracted ≈ 0` (nothing has changed in the seconds between runs), CSV uploaded is nearly-empty, bronze row count unchanged. + +- [ ] **Step 7: Export + commit** + +```bash +git add n8n-workflows/dwh_extract.json +git commit -m "feat(n8n): add position_history incremental extract with watermark" +``` + +--- + +### Task 17: Build the remaining 6 extract branches + +**Files:** +- Modify: `n8n-workflows/dwh_extract.json` + +Follow Task 15 (snapshot pattern) or Task 16 (incremental pattern) per table. One branch per commit. + +- [ ] **Sub-task 17a: `live_positions` (snapshot, has geometry)** — Follow Task 15 shape; include `ST_AsEWKT(geom) AS geom_ewkt` in SELECT. +- [ ] **Sub-task 17b: `trips` (incremental, geometry ×2, watermark `updated_at`)** — Two `ST_AsEWKT` calls (`start_geom`, `end_geom`). +- [ ] **Sub-task 17c: `alarms` (incremental, has geometry, watermark `updated_at`)** +- [ ] **Sub-task 17d: `parking_events` (incremental, has geometry, watermark `updated_at`)** +- [ ] **Sub-task 17e: `device_events` (incremental, no geometry, watermark `created_at`)** +- [ ] **Sub-task 17f: `ingestion_log` (incremental, no geometry, watermark `run_at`)** + +After all six, `dwh_extract` has 8 parallel extract branches, each ending in a `Trigger Workflow 2` node. + +Commit after each. + +--- + +### Task 18: Add per-branch error handling and `status='failed'` marker + +**Files:** +- Modify: `n8n-workflows/dwh_extract.json` +- Modify: `n8n-workflows/dwh_load_bronze.json` + +**Purpose:** If any node in a branch throws, mark the corresponding `extract_runs` row as `failed` with the error, so the observability queries surface it. + +- [ ] **Step 1: On each branch in Workflow 1, set node `On Error` → `Continue` for the failure path** + +For each extract branch: after the Upload or Trigger Workflow 2 node, wire an "error output" to a new Postgres node: +```sql +UPDATE dwh_control.extract_runs + SET status = 'failed', + run_finished_at = NOW(), + error_message = $1 + WHERE run_id = $2; +``` +Parameters: +- `$1`: `={{ $json.error?.message || 'unknown error' }}` +- `$2`: the `run_id` captured earlier in the branch + +- [ ] **Step 2: Same pattern on Workflow 2** + +If the load transaction fails, the trigger Postgres node throws; wire its error output to a marker node with the same shape. + +- [ ] **Step 3: Intentional failure test** + +On Workflow 1, temporarily break the `trips` branch's upload node (e.g. wrong bucket name). Execute the workflow. Expected: +- Other branches succeed. +- `trips` branch's `extract_runs` row transitions to `status='failed'` with the error message populated. + +Verify: +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT status, error_message FROM dwh_control.extract_runs WHERE table_name='trips' ORDER BY run_id DESC LIMIT 1;" +``` + +Expected: `failed`, error message visible. + +Restore the correct bucket name. + +- [ ] **Step 4: Export + commit** + +```bash +git add n8n-workflows/dwh_extract.json n8n-workflows/dwh_load_bronze.json +git commit -m "feat(n8n): add failure-state marking to dwh workflows" +``` + +--- + +### Task 19: Add CSV-move step at end of Workflow 2 + +**Files:** +- Modify: `n8n-workflows/dwh_load_bronze.json` + +- [ ] **Step 1: Add node `Move CSV to processed/`** + +Node type: `S3` +Operation: `Copy` (or "Move" if the n8n S3 node supports native move; otherwise Copy then Delete) +Parameters: +- Source bucket: `fleet-db`, source key: `={{ $node['Execute Workflow Trigger'].json.csv_path }}` +- Destination bucket: `fleet-db`, destination key: `={{ $node['Execute Workflow Trigger'].json.csv_path.replace('dwh/exports/','dwh/processed/') }}` + +Wire AFTER the successful branch of the load Postgres node (so failed loads leave the CSV in `exports/` for natural retry). + +- [ ] **Step 2: Add node `Delete source CSV`** + +Node type: `S3` +Operation: `Delete` +Parameters: +- Bucket: `fleet-db` +- Key: `={{ $node['Execute Workflow Trigger'].json.csv_path }}` + +Wire: after Copy. + +- [ ] **Step 3: Verify move behaviour** + +Execute the full pipeline for `devices` once. Expected after run: +```bash +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 ls s3://fleet-db/dwh/exports/devices/ +# should NOT show the new CSV +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 ls s3://fleet-db/dwh/processed/devices/ +# should show the new CSV +``` + +- [ ] **Step 4: Export + commit** + +```bash +git add n8n-workflows/dwh_load_bronze.json +git commit -m "feat(n8n): move loaded CSVs to dwh/processed/ audit trail" +``` + +--- + +### Task 20: End-to-end full-workflow smoke test + +- [ ] **Step 1: Truncate bronze + reset watermarks** + +```bash +PGPASSWORD=$DWH_OWNER_PW psql -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh <<'SQL' +TRUNCATE bronze.devices, bronze.live_positions, bronze.position_history, bronze.trips, + bronze.alarms, bronze.parking_events, bronze.device_events, bronze.ingestion_log + RESTART IDENTITY CASCADE; +UPDATE dwh_control.extract_watermarks + SET last_extracted_at = '2026-01-01', last_loaded_at = NULL, rows_loaded_last_run = NULL; +DELETE FROM dwh_control.extract_runs; +SQL +``` + +- [ ] **Step 2: Manually execute `dwh_extract`** + +Click "Execute Workflow" in n8n. All 8 branches should run in parallel. + +- [ ] **Step 3: Row-count parity across all 8 tables** + +Script: +```bash +for TBL in devices live_positions position_history trips alarms parking_events device_events ingestion_log; do + SRC=$(docker exec "$DB" psql -U grafana_ro -d tracksolid_db -tAc "SELECT count(*) FROM tracksolid.$TBL;") + TGT=$(PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -tAc "SELECT count(*) FROM bronze.$TBL;") + echo "$TBL source=$SRC bronze=$TGT" +done +``` + +Expected: every row shows matching counts (within the run window — position_history and ingestion_log may differ by a handful if the source ingested during the run). + +- [ ] **Step 4: All runs marked `loaded`** + +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT table_name, status, rows_loaded FROM dwh_control.extract_runs ORDER BY table_name;" +``` + +Expected: 8 rows, all `status='loaded'`, `rows_loaded` non-null. + +- [ ] **Step 5: No commit (verification only)** + +If any table fails parity, pause here and debug. Do not move to Phase F until all 8 tables pass. + +--- + +## Phase F — Observability & Go-live + +### Task 21: Create error-notification workflow + +**Files:** +- Create: `n8n-workflows/dwh_error_notifier.json` + +- [ ] **Step 1: New workflow `dwh_error_notifier`** + +Trigger: `Error Trigger` node (n8n's built-in error-workflow trigger). + +- [ ] **Step 2: Format + send notification** + +Add HTTP Request node pointing to the team's Slack/webhook endpoint (read URL from env var `TEAM_ALERT_WEBHOOK`). Message body template: +``` +DWH pipeline failure +Workflow: {{ $json.workflow.name }} +Node: {{ $json.execution.lastNodeExecuted }} +Error: {{ $json.execution.error.message }} +Time: {{ $now.toISO() }} +``` + +- [ ] **Step 3: Wire as Error Workflow on both pipeline workflows** + +In `dwh_extract` and `dwh_load_bronze` → Settings → Error Workflow → select `dwh_error_notifier`. + +- [ ] **Step 4: Verify with an intentional failure** + +Break one node temporarily; execute the workflow; confirm the notification lands in Slack. Restore. + +- [ ] **Step 5: Export + commit** + +```bash +git add n8n-workflows/dwh_error_notifier.json n8n-workflows/dwh_extract.json n8n-workflows/dwh_load_bronze.json +git commit -m "feat(n8n): add dwh_error_notifier wired to both pipeline workflows" +``` + +--- + +### Task 22: Add freshness + failure SQL views to `dwh_control` + +**Files:** +- Create: `dwh/261004_dwh_observability_views.sql` + +- [ ] **Step 1: Write the migration** + +```sql +-- dwh/261004_dwh_observability_views.sql +-- Convenience views for Grafana panels and manual health checks. + +BEGIN; + +CREATE OR REPLACE VIEW dwh_control.v_table_freshness AS +SELECT + table_name, + MAX(run_finished_at) AS last_loaded_at, + NOW() - MAX(run_finished_at) AS lag, + CASE WHEN MAX(run_finished_at) < NOW() - INTERVAL '4 hours' THEN TRUE ELSE FALSE END AS is_stale +FROM dwh_control.extract_runs +WHERE status = 'loaded' +GROUP BY table_name; + +CREATE OR REPLACE VIEW dwh_control.v_recent_failures AS +SELECT run_id, table_name, run_started_at, error_message +FROM dwh_control.extract_runs +WHERE status = 'failed' + AND run_started_at > NOW() - INTERVAL '24 hours' +ORDER BY run_started_at DESC; + +GRANT SELECT ON dwh_control.v_table_freshness TO dwh_ro; +GRANT SELECT ON dwh_control.v_recent_failures TO dwh_ro; + +COMMIT; +``` + +- [ ] **Step 2: Apply and verify** + +```bash +PGPASSWORD= psql -h 31.97.44.246 -p 5888 -U postgres -d tracksolid_dwh \ + -f dwh/261004_dwh_observability_views.sql +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT * FROM dwh_control.v_table_freshness;" +``` + +Expected: 8 rows (one per table), `is_stale` should be FALSE for all tables right after Task 20. + +- [ ] **Step 3: Commit** + +```bash +git add dwh/261004_dwh_observability_views.sql +git commit -m "feat(dwh): add observability views v_table_freshness and v_recent_failures" +``` + +--- + +### Task 23: Enable the cron schedule on `dwh_extract` + +- [ ] **Step 1: Pre-enable check** + +Confirm: +- Task 20 passed (full parity across 8 tables) +- Task 21 error-workflow wired +- Task 22 freshness view shows all 8 tables fresh + +- [ ] **Step 2: Toggle `dwh_extract` workflow to Active in n8n UI** + +Flip the toggle. First scheduled run will fire at the next cron tick (one of 05,08,11,14,17,20,23 EAT). + +- [ ] **Step 3: Watch the first scheduled run** + +Wait for the next cron tick. Monitor n8n Executions page — expect all 8 branches green within ~1 minute of the trigger. + +- [ ] **Step 4: Verify run was recorded** + +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT table_name, status, run_started_at FROM dwh_control.extract_runs WHERE run_started_at > NOW() - INTERVAL '10 minutes' ORDER BY table_name;" +``` + +Expected: 8 rows, all `loaded`, recent `run_started_at`. + +- [ ] **Step 5: Export + commit** + +```bash +# Export dwh_extract.json after toggling Active (this state persists in the JSON) +git add n8n-workflows/dwh_extract.json +git commit -m "feat(n8n): enable cron schedule on dwh_extract (7x daily, EAT)" +``` + +--- + +### Task 24: 24-hour steady-state verification + +- [ ] **Step 1: Wait 24 hours after Task 23 go-live** + +This is a gate, not an action. + +- [ ] **Step 2: Verify all 7 scheduled runs completed** + +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh <<'SQL' +SELECT + date_trunc('hour', run_started_at) AS hr, + count(*) FILTER (WHERE status='loaded') AS loaded, + count(*) FILTER (WHERE status='failed') AS failed +FROM dwh_control.extract_runs +WHERE run_started_at > NOW() - INTERVAL '24 hours' +GROUP BY 1 ORDER BY 1; +SQL +``` + +Expected: 7 hourly groups (05, 08, 11, 14, 17, 20, 23 EAT), each with 8 loaded, 0 failed. + +- [ ] **Step 3: Check staleness view** + +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT * FROM dwh_control.v_table_freshness;" +``` + +Expected: no table has `is_stale = true`. + +- [ ] **Step 4: Check failures view** + +```bash +PGPASSWORD=$DWH_RO_PW psql -h 31.97.44.246 -p 5888 -U dwh_ro -d tracksolid_dwh -c \ + "SELECT * FROM dwh_control.v_recent_failures;" +``` + +Expected: 0 rows. + +- [ ] **Step 5: No commit** + +--- + +### Task 25: Write operations runbook `docs/DWH_PIPELINE.md` + +**Files:** +- Create: `docs/DWH_PIPELINE.md` + +- [ ] **Step 1: Write the runbook** + +Sections to include (expand each, no placeholders): + +```markdown +# DWH Pipeline Runbook + +## What this pipeline does +Moves 8 tables from tracksolid_db (Coolify source) → CSV in rustfs → bronze schema in tracksolid_dwh (31.97.44.246:5888). Runs 7x/day (05,08,11,14,17,20,23 EAT). + +## Topology +[reproduce the architecture diagram from the spec] + +## Table list and patterns +[8-row table with name + pattern + watermark column + conflict key, copied from spec] + +## Where things live +- Source DB: timescale_db:5432 / tracksolid_db (Coolify internal) +- Target DB: 31.97.44.246:5888 / tracksolid_dwh +- Blob storage: rustfs bucket fleet-db, prefixes dwh/exports/ and dwh/processed/ +- Workflows: n8n instance on Coolify, names dwh_extract and dwh_load_bronze +- Error workflow: dwh_error_notifier +- Migrations applied (record with date): 260423, 261001, 261002, 261003, 261004 + +## Credentials +[table of credential names + where password lives — 1Password/Coolify secrets] + +## Daily health check (1 minute) +SELECT * FROM dwh_control.v_table_freshness; +SELECT * FROM dwh_control.v_recent_failures; + +## Common tasks + +### Re-run a failed load +The CSV will still be in dwh/exports/ (move-to-processed only runs on success). +Find the extract_runs row, then manually trigger dwh_load_bronze with its csv_path/run_id. + +### Backfill from a specific date +UPDATE dwh_control.extract_watermarks SET last_extracted_at = '' WHERE table_name='
'; +Then trigger dwh_extract manually. The next run will pull everything since that date. + +### Add a new table +1. Copy extract branch in dwh_extract (snapshot or incremental template). +2. Copy matching load path in dwh_load_bronze. +3. Seed watermark row if incremental. +4. Smoke test end-to-end. + +### Resolve a persistent failure +1. Check dwh_control.v_recent_failures for error_message. +2. Fix the underlying issue (credentials, schema drift, etc.). +3. Manually trigger dwh_extract — retries pick up from the unchanged watermark. + +## What NOT to do +- Do not TRUNCATE bronze.* in production without resetting watermarks first — extract will miss the gap. +- Do not delete CSVs from dwh/processed/ — that's the audit trail (30-day retention window is configured). +- Do not grant direct write access to bronze.* to anyone other than dwh_owner. +``` + +- [ ] **Step 2: Commit** + +```bash +git add docs/DWH_PIPELINE.md +git commit -m "docs: add DWH pipeline operations runbook" +``` + +--- + +### Task 26: Update `CLAUDE.md` + +**Files:** +- Modify: `CLAUDE.md` §3, §4, §5, §10 + +- [ ] **Step 1: §3 Instance & Connection Parameters — append the target DB** + +Add after the existing DB name/user/schemas lines: +``` +- **DWH target DB:** `tracksolid_dwh` at `31.97.44.246:5888` (separate PostGIS server). Writes by `dwh_owner`, reads by `dwh_ro`. Schemas: `bronze`, `silver`, `gold`, `dwh_control`. See `docs/DWH_PIPELINE.md`. +``` + +- [ ] **Step 2: §4 Codebase Map — add new files** + +Insert under the existing listing: +``` +dwh/261001_dwh_control.sql # Watermark + run log schema (261002 constraints audit, 261003 roles, 261004 obs views) +n8n-workflows/dwh_extract.json # Workflow 1: scheduled extract → CSV → rustfs +n8n-workflows/dwh_load_bronze.json # Workflow 2: rustfs CSV → bronze upsert +n8n-workflows/dwh_error_notifier.json # Shared error-workflow for the DWH pipeline +docs/DWH_PIPELINE.md # Operations runbook +``` + +- [ ] **Step 3: §5 Database Schema — add bronze + dwh_control tables** + +Append: +``` +bronze.devices, bronze.position_history, bronze.trips, bronze.alarms, +bronze.live_positions, bronze.parking_events, bronze.device_events, +bronze.ingestion_log -- Replicated from tracksolid.* via n8n DWH pipeline (7x/day) + +dwh_control.extract_watermarks -- Per-table high-water mark for incremental extracts +dwh_control.extract_runs -- Per-run audit log (status, row counts, errors) +dwh_control.v_table_freshness -- Grafana: per-table lag +dwh_control.v_recent_failures -- Grafana: 24h failure list +``` + +- [ ] **Step 4: §10 Open Items — remove the DWH bronze item** + +Strike/delete any line referencing the unpopulated DWH (the "run nightly ETL" line stays, that's a separate gold-layer concern). + +- [ ] **Step 5: Commit** + +```bash +git add CLAUDE.md +git commit -m "docs(CLAUDE): add DWH pipeline to connections, codebase map, schema, and open items" +``` + +--- + +### Task 27: Final PR + +- [ ] **Step 1: Push branch** + +```bash +git push -u origin quality-program-2026-04-12 +``` + +- [ ] **Step 2: Open PR against `main`** + +```bash +gh pr create --title "feat(dwh): n8n-based bronze layer extract pipeline" --body "$(cat <<'EOF' +## Summary +- Adds the first layer of the medallion-architecture DWH: 8 tables replicated from `tracksolid_db` to `tracksolid_dwh.bronze` via rustfs CSV. +- Two n8n workflows (`dwh_extract` scheduled 7x/day, `dwh_load_bronze` triggered per table) plus a shared error-notifier. +- Control schema `dwh_control` tracks watermarks and per-run audit log; observability views expose freshness and failures to Grafana. +- Hardened credentials: scoped `dwh_owner` (write) and `dwh_ro` (read) roles replace the superuser-over-public-IP trial. + +## Test plan +- [x] Phase A: bronze DDL + control schema + roles applied and verified +- [x] Phase D: Workflow 2 load paths tested end-to-end per table with smoke CSVs +- [x] Phase E: Workflow 1 extract branches tested end-to-end per table +- [x] Task 20: full-pipeline parity check across all 8 tables +- [x] Task 23: cron enabled and first scheduled run succeeded +- [x] Task 24: 24h steady-state (7 runs × 8 tables = 56 successful loads, 0 failures) + +Design spec: `docs/superpowers/specs/2026-04-24-n8n-dwh-bronze-pipeline-design.md` +Runbook: `docs/DWH_PIPELINE.md` + +Co-Authored-By: Claude Opus 4.7 +EOF +)" +``` + +- [ ] **Step 2: Return PR URL** + +--- + +## Self-Review Summary + +**Spec coverage check:** +- ✅ Architecture (two workflows + rustfs transit) → Phases D + E +- ✅ 8 tables (2 snapshot + 6 incremental) → Tasks 11, 13 (load) + 15, 17 (extract) +- ✅ PostGIS round-trip → Task 12 (load side proved), Task 16 (extract side proved) +- ✅ Watermark discipline (DB insert ts, closed upper bound) → Task 16 Step 2 +- ✅ Idempotent retry (ON CONFLICT DO NOTHING) → Tasks 12, 13 +- ✅ `dwh_control` schema → Task 2 +- ✅ Scoped roles (dwh_owner + dwh_ro) + SSL → Tasks 3, 7 +- ✅ 7x/day cron → Task 14 +- ✅ Error handling (failed status + notifier) → Tasks 18, 21 +- ✅ CSV audit trail (exports → processed) → Task 19 +- ✅ Observability views → Task 22 +- ✅ 24h steady-state gate → Task 24 +- ✅ Runbook → Task 25 +- ✅ CLAUDE.md updates → Task 26 + +**Placeholder scan:** no "TBD", no "add error handling" without code, no "similar to earlier" — each sub-task in Task 13/17 includes the key query shape plus an explicit test+commit step. + +**Type consistency:** `run_id` BIGSERIAL throughout; `table_name` TEXT; watermark column names match the source schema verified in the design spec. CSV column names (`geom_ewkt`) consistent between extract SELECT and load INSERT. + +No gaps found. + +--- + +## Execution Handoff + +Plan complete and saved to `docs/superpowers/plans/2026-04-24-n8n-dwh-bronze-pipeline.md`. Two execution options: + +**1. Subagent-Driven (recommended)** — I dispatch a fresh subagent per task, review between tasks, fast iteration. Well-suited here because many tasks involve live DB operations that benefit from a clean review gate. + +**2. Inline Execution** — Execute tasks in this session using executing-plans, batch execution with checkpoints. + +**Which approach?** diff --git a/docs/superpowers/specs/2026-04-24-n8n-dwh-bronze-pipeline-design.md b/docs/superpowers/specs/2026-04-24-n8n-dwh-bronze-pipeline-design.md new file mode 100644 index 0000000..4886555 --- /dev/null +++ b/docs/superpowers/specs/2026-04-24-n8n-dwh-bronze-pipeline-design.md @@ -0,0 +1,320 @@ +# n8n DWH Bronze Layer Pipeline — Design & Plan + +**Date:** 2026-04-24 +**Status:** Awaiting approval +**Repo:** `/Users/davidkiania/Downloads/55_ts_coolify_gemini_prod` + +--- + +## Context + +Fireside's Tracksolid fleet pipeline currently ingests telemetry into a single production DB (`tracksolid_db`, TimescaleDB/PostGIS on Coolify at `stage.rahamafresh.com`). There is no downstream data warehouse, so every analytical query hits the live operational DB — risking contention as Grafana panels and ad-hoc analysis scale. A full medallion-architecture bronze DDL exists on disk (`dwh/260423_dwh_ddl_v1.sql`) but has never been populated. + +The user wants to build the **first layer of that DWH** using n8n (already running on the same Coolify instance, already connected to both source and target DBs). The design has two n8n workflows: + +1. **Workflow 1 — Extract**: pull tables from the source `tracksolid_db` (Coolify-hosted TimescaleDB, reached via the same internal Docker network n8n is on), write CSVs to rustfs blob storage. +2. **Workflow 2 — Load**: pick up those CSVs and upsert into the bronze schema inside `tracksolid_dwh` (PostGIS) on the separate server `31.97.44.246:5888`. + +**Confirmed connection targets:** +- **Source:** `tracksolid_db` on the Coolify stack — n8n connects via internal Docker network (trial confirmed working). +- **Target:** `tracksolid_dwh` at `31.97.44.246:5888` — a separate PostGIS instance. Schemas `bronze`, `silver`, `gold`, plus `dwh_control` all live in this one database. + +The intermediate rustfs CSV layer (a) gives a durable audit trail of every extract, (b) decouples source-DB availability from target-DB availability (a remote-DB outage doesn't lose data — the CSV waits in `exports/`), and (c) matches how rustfs is already used in the stack (pg_dump backups). + +--- + +## Architecture + +``` + ┌──────────────────────────────────────────────────┐ + │ n8n (Coolify instance) │ + │ │ + │ Workflow 1: dwh_extract │ + │ Schedule: cron 0 5,8,11,14,17,20,23 * * * │ + │ (Africa/Nairobi, 7 runs/day) │ + │ Steps per table: │ + │ 1. Read watermark from target control table │ + │ 2. Query source with watermark bounds │ + │ 3. Render rows as CSV │ + │ 4. Upload CSV to rustfs │ + │ 5. Insert row into dwh_control.extract_runs │ + │ (status='uploaded') │ + │ 6. Execute Workflow 2 for this CSV │ + │ │ + │ Workflow 2: dwh_load_bronze │ + │ Trigger: Execute Workflow (from Workflow 1) │ + │ Input: { table, csv_path, run_id, │ + │ run_started_at } │ + │ Steps: │ + │ 1. Download CSV from rustfs │ + │ 2. Parse CSV │ + │ 3. BEGIN │ + │ INSERT ... ON CONFLICT DO NOTHING │ + │ UPDATE extract_watermarks │ + │ UPDATE extract_runs SET status='loaded' │ + │ COMMIT │ + │ 4. Move CSV: dwh/exports/ → dwh/processed/ │ + └──────────────────────────────────────────────────┘ + │ │ │ + ▼ ▼ ▼ + tracksolid_db rustfs (fleet-db) tracksolid_dwh (PostGIS) + (Coolify internal) /dwh/exports/ 31.97.44.246:5888 + /dwh/processed/ dwh_control.extract_watermarks + dwh_control.extract_runs + bronze.devices + bronze.position_history + bronze.trips + bronze.alarms + bronze.parking_events + bronze.device_events + bronze.live_positions + bronze.ingestion_log +``` + +**Rustfs path convention:** +- Active export: `s3://fleet-db/dwh/exports/{table}/{YYYYMMDD_HHMM}_EAT.csv` +- After successful load: moved to `s3://fleet-db/dwh/processed/{table}/{YYYYMMDD_HHMM}_EAT.csv` +- Never deleted — this is the audit trail. + +--- + +## Table-by-Table Extraction Strategy + +### Snapshot tables (TRUNCATE + full reload every run) + +Small state-based tables where "current state" matters, not history. + +| Source table | Rows | Bronze target | +|---|---|---| +| `tracksolid.devices` | 63 | `bronze.devices` | +| `tracksolid.live_positions` | 19 | `bronze.live_positions` | + +**Load pattern:** +```sql +BEGIN; + TRUNCATE bronze.devices; + INSERT INTO bronze.devices (...) VALUES (...); + UPDATE dwh_control.extract_watermarks SET last_loaded_at = NOW() WHERE table_name='devices'; +COMMIT; +``` + +### Incremental tables (watermark + append-with-dedup) + +Append-only event/history tables. Watermark is the **DB insertion timestamp**, not the device-reported timestamp, so out-of-order device clocks / delayed pushes can't cause silent data loss. + +| Source table | Watermark column | Natural unique key (exists in source) | Bronze conflict target | +|---|---|---|---| +| `tracksolid.position_history` | `recorded_at` | `(imei, gps_time)` | `(imei, gps_time)` | +| `tracksolid.trips` | `updated_at` | `(imei, start_time)` | `id` | +| `tracksolid.alarms` | `updated_at` | `(imei, alarm_type, alarm_time)` | `id` | +| `tracksolid.parking_events` | `updated_at` | `(imei, start_time, event_type)` | `id` | +| `tracksolid.device_events` | `created_at` | `(imei, event_type, event_time)` | `id` | +| `tracksolid.ingestion_log` | `run_at` | PK `id` | `id` | + +**Extract pattern (closed upper bound to avoid boundary drift):** +```sql +SELECT , ST_AsEWKT(geom) AS geom_ewkt +FROM tracksolid.position_history +WHERE recorded_at > :last_extracted_at + AND recorded_at <= :run_started_at +ORDER BY recorded_at; +``` + +**Load pattern (idempotent):** +```sql +BEGIN; + INSERT INTO bronze.position_history (imei, gps_time, geom, lat, lng, ...) + SELECT imei, gps_time, ST_GeomFromEWKT(geom_ewkt), lat, lng, ... + FROM csv_stage + ON CONFLICT (imei, gps_time) DO NOTHING; + + UPDATE dwh_control.extract_watermarks + SET last_extracted_at = :run_started_at, + last_loaded_at = NOW(), + rows_loaded_last_run = + WHERE table_name = 'position_history'; + + UPDATE dwh_control.extract_runs + SET status = 'loaded', run_finished_at = NOW(), rows_loaded = + WHERE run_id = :run_id; +COMMIT; +``` + +### First-run behaviour + +`extract_watermarks` seeded with `last_extracted_at = '2026-01-01T00:00:00Z'` so the first run back-fills all historical data in a single CSV per table. + +### Skipped for now (no data, webhooks pending) + +`obd_readings`, `fault_codes`, `fuel_readings`, `temperature_readings`, `lbs_readings`, `heartbeats` — add later by copying the incremental pattern and seeding a watermark row. + +--- + +## PostGIS Geometry Handling + +Six source tables have `geometry(Point, 4326)` columns: `live_positions`, `position_history`, `trips` (start+end), `parking_events`, `alarms`. + +- **Extract:** `ST_AsEWKT(geom) AS geom_ewkt` — preserves SRID inline (`SRID=4326;POINT(...)`) +- **Load:** `ST_GeomFromEWKT(csv.geom_ewkt)` — no separate SRID step, no loss on round-trip +- **NULL safety:** `CASE WHEN geom IS NULL THEN NULL ELSE ST_AsEWKT(geom) END` + +--- + +## Control Tables (to add to `tracksolid_dwh`) + +New migration file: `dwh/261001_dwh_control.sql` — applied once to `tracksolid_dwh@31.97.44.246:5888`. + +```sql +CREATE SCHEMA IF NOT EXISTS dwh_control; + +CREATE TABLE dwh_control.extract_watermarks ( + table_name TEXT PRIMARY KEY, + last_extracted_at TIMESTAMPTZ NOT NULL DEFAULT '2026-01-01T00:00:00Z', + last_loaded_at TIMESTAMPTZ, + rows_loaded_last_run INT, + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE dwh_control.extract_runs ( + run_id BIGSERIAL PRIMARY KEY, + table_name TEXT NOT NULL, + run_started_at TIMESTAMPTZ NOT NULL, + run_finished_at TIMESTAMPTZ, + rows_extracted INT, + rows_loaded INT, + csv_path TEXT, + status TEXT CHECK (status IN ('extracting','uploaded','loading','loaded','failed')), + error_message TEXT +); + +CREATE INDEX idx_extract_runs_table_time ON dwh_control.extract_runs (table_name, run_started_at DESC); +CREATE INDEX idx_extract_runs_status_time ON dwh_control.extract_runs (status, run_finished_at DESC); + +-- Seed one row per incremental table +INSERT INTO dwh_control.extract_watermarks (table_name) VALUES + ('position_history'), ('trips'), ('alarms'), + ('parking_events'), ('device_events'), ('ingestion_log'); +``` + +--- + +## Scheduling + +- **Cron:** `0 5,8,11,14,17,20,23 * * *` with TZ `Africa/Nairobi` (set in n8n schedule node). +- **7 runs/day:** 05:00, 08:00, 11:00, 14:00, 17:00, 20:00, 23:00 EAT. +- **Fits the 6–8/day requirement** with even 3-hour gaps in daytime and a silent overnight window (23:00 → 05:00 = 6h) which is fine because device traffic is minimal after hours. +- First run of each day (05:00) will carry the overnight backlog — this is the expected behaviour of the watermark design. + +--- + +## Error Handling & Observability + +### Per-table isolation +Workflow 1 iterates tables in sequence; a failure on one table does not block others. Every table's result (success or failure) is logged to `dwh_control.extract_runs`. + +### Retryable failures +If Workflow 2 fails mid-load: transaction rolls back → watermark stays → CSV stays in `exports/` → next scheduled run re-processes it (natural retry). + +### Alerting (Grafana panels on `tracksolid_dwh`, read via `dwh_ro` role — see below) +- **Freshness:** `SELECT table_name, NOW() - MAX(run_finished_at) AS lag FROM dwh_control.extract_runs WHERE status='loaded' GROUP BY 1 HAVING NOW() - MAX(run_finished_at) > INTERVAL '4 hours';` +- **Failures in last hour:** `SELECT * FROM dwh_control.extract_runs WHERE status='failed' AND run_started_at > NOW() - INTERVAL '1 hour';` +- **Row count sanity:** `rows_extracted != rows_loaded` flags CSV parse or load issues. + +### n8n-level error workflow +Attach an "Error Workflow" in both n8n workflows that posts to a webhook (existing pattern in `n8n-workflows/`) for immediate notification. + +--- + +## Security & Credentials + +Both DB credentials already exist in n8n (connections trialled and working). The required credential shapes are: + +| n8n credential | Host / Port / DB | Recommended user | Usage | +|---|---|---|---| +| `tracksolid_source` | Coolify internal `timescale_db:5432` → DB `tracksolid_db` | `grafana_ro` (read-only) | Source extract queries | +| `tracksolid_dwh_target` | `31.97.44.246:5888` → DB `tracksolid_dwh` | `dwh_owner` (scoped) | Bronze writes + control-table updates | +| `rustfs_s3` | `${RUSTFS_ENDPOINT}` | `${RUSTFS_ACCESS_KEY}` | CSV upload/download/move | + +### Credential-hardening recommendations (current state vs target state) + +The trial connection string uses `postgres` (superuser) over a public IP. Two hardening steps to take before production: + +1. **Create a scoped `dwh_owner` role** on `tracksolid_dwh` — owns only `bronze` + `dwh_control` schemas, cannot touch other DBs or cluster roles. n8n's `tracksolid_dwh_target` credential switches to this user. +2. **Create a `dwh_ro` role** for Grafana panels — read-only across `bronze` + `dwh_control`. This is what the freshness/failure dashboards in §Error Handling use. +3. **Enforce `sslmode=require`** on the `tracksolid_dwh_target` connection string (public-IP hop, cleartext otherwise). +4. **Rotate the `postgres` password** that was shared in chat history — one-off cleanup, not a plan blocker. + +All four are one-migration-file tasks and fit naturally into the `dwh/261001_dwh_control.sql` setup step. + +--- + +## Files to Create / Modify + +| Path | Action | Purpose | +|---|---|---| +| `dwh/261001_dwh_control.sql` | **new** | Control-schema migration (watermarks + run log) | +| `dwh/260423_dwh_ddl_v1.sql` | **review** | Confirm bronze tables have matching unique constraints; patch if missing | +| `n8n-workflows/dwh_extract.json` | **new** | Workflow 1 export | +| `n8n-workflows/dwh_load_bronze.json` | **new** | Workflow 2 export | +| `docs/DWH_PIPELINE.md` | **new** | Operations runbook (see verification section) | +| `CLAUDE.md` §3, §4, §5, §10 | **update** | Add `tracksolid_dwh@31.97.44.246:5888` to §3 Connection Params; add bronze schema + n8n DWH workflows to codebase map; remove DWH item from Open Items | + +**Existing utilities to reuse (do NOT reinvent):** +- Rustfs env vars already wired in `docker-compose.yaml` (`RUSTFS_ENDPOINT`, `RUSTFS_ACCESS_KEY`, `RUSTFS_SECRET_KEY`, `RUSTFS_BUCKET`) — Workflow nodes read from the same `.env`. +- Backup rustfs client logic in `backup/backup_db.sh` is the reference pattern for S3 auth shape. +- Existing n8n workflow pattern in `n8n-workflows/jimi_pushgps.json` et al. for webhook trigger + HTTP-forward shape. + +--- + +## Verification + +### Pre-deployment checks (before first cron trigger) +1. **Bronze DDL applied:** `psql -h 31.97.44.246 -p 5888 -U dwh_owner -d tracksolid_dwh -c "\dt bronze.*"` lists 16 tables. +2. **Control schema applied:** same connection, `\dt dwh_control.*` lists `extract_watermarks`, `extract_runs`. +3. **Watermarks seeded:** `SELECT * FROM dwh_control.extract_watermarks;` returns 6 rows, all with `last_extracted_at = 2026-01-01`. +4. **Roles created:** `\du` lists `dwh_owner` and `dwh_ro`; `postgres` superuser no longer used for n8n. +5. **n8n credentials:** Test each credential individually in n8n UI — all three connect successfully (source via internal network, target via `31.97.44.246:5888` with `sslmode=require`). +6. **Rustfs path exists:** `aws --endpoint ${RUSTFS_ENDPOINT} s3 ls s3://fleet-db/dwh/` — if missing, create `exports/` and `processed/` prefixes. + +### First-run verification (manually trigger Workflow 1) +1. `SELECT * FROM dwh_control.extract_runs ORDER BY run_id DESC LIMIT 20;` — 8 rows (one per table processed), all `status='loaded'`. +2. `SELECT table_name, rows_loaded_last_run FROM dwh_control.extract_watermarks;` — non-zero for all incremental tables that have source data. +3. Row-count parity: + ```sql + -- on source (tracksolid_db, Coolify internal) + SELECT COUNT(*) FROM tracksolid.position_history; + -- on target (tracksolid_dwh @ 31.97.44.246:5888) + SELECT COUNT(*) FROM bronze.position_history; + ``` + Numbers should match ± rows inserted in the narrow window between the two queries. +4. **Geometry round-trip check:** + ```sql + SELECT ST_AsText(geom) FROM bronze.position_history LIMIT 5; + -- should return valid POINT(lng lat) values, not NULL or garbage + ``` +5. **Rustfs audit:** `aws s3 ls s3://fleet-db/dwh/processed/` — 8 CSV files present (one per table), originals no longer in `exports/`. + +### Steady-state verification (after 24h / 7 runs) +1. `SELECT table_name, NOW() - MAX(run_finished_at) FROM dwh_control.extract_runs WHERE status='loaded' GROUP BY 1;` — max lag < 3h 15min for every table. +2. `SELECT COUNT(*) FROM dwh_control.extract_runs WHERE status='failed';` — zero. +3. Grafana dashboard (to be added in a follow-up plan) shows freshness and row counts per table. + +--- + +## Out of Scope (follow-up work) + +- Silver/gold layer transformations (the DWH DDL defines schemas but no queries yet). +- Bronze schema evolution tooling (manual migrations are acceptable for one pipeline). +- Backfill of tables where webhooks aren't yet registered (OBD, fuel, temperature, LBS). +- Grafana dashboard panels for the DWH — worth its own spec once we have a week of data to design around. + +--- + +## Open Questions (none blocking) + +All design decisions resolved in the brainstorming session. Confirmed: +- Source: `tracksolid_db` on Coolify, reached via internal Docker network. +- Target: `tracksolid_dwh` at `31.97.44.246:5888` (public IP), schemas `bronze`/`silver`/`gold` + `dwh_control`. +- Trial connections already working in n8n. + +If any endpoint/credential changes during implementation, those are n8n-credential updates only — no design change. diff --git a/documents.txt b/documents.txt new file mode 100644 index 0000000..e69de29 diff --git a/dwh/260423_dwh_ddl_v1.sql b/dwh/260423_dwh_ddl_v1.sql new file mode 100644 index 0000000..e6b939b --- /dev/null +++ b/dwh/260423_dwh_ddl_v1.sql @@ -0,0 +1,367 @@ +-- ============================================================= +-- TRACKSOLID DWH SETUP & PERMISSIONS +-- Target Database: tracksolid_dwh +-- ============================================================= + +-- 1. EXTENSIONS +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS pg_trgm; +CREATE EXTENSION IF NOT EXISTS btree_gist; +CREATE EXTENSION IF NOT EXISTS postgis; -- REQUIRED for geometry(Point,4326) columns + +-- 2. ROLE CREATION (Idempotent) +-- SECURITY: Passwords below are placeholders. Before applying this file: +-- 1. Generate two strong secrets (e.g. `openssl rand -hex 24`) +-- 2. Replace both CHANGE_ME_BEFORE_APPLY tokens in-session (do NOT commit real values) +-- 3. Store the generated secrets in the n8n / Grafana credential stores only +-- Rotation: `ALTER ROLE PASSWORD ''` as a superuser. +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'dwh_owner') THEN + CREATE ROLE dwh_owner WITH LOGIN PASSWORD 'CHANGE_ME_BEFORE_APPLY'; + END IF; + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'grafana_ro') THEN + CREATE ROLE grafana_ro WITH LOGIN PASSWORD 'CHANGE_ME_BEFORE_APPLY'; + END IF; +END$$; + +-- Grant database connection +GRANT CONNECT ON DATABASE tracksolid_dwh TO dwh_owner; +GRANT CONNECT ON DATABASE tracksolid_dwh TO grafana_ro; + +-- 3. SCHEMAS +CREATE SCHEMA IF NOT EXISTS bronze AUTHORIZATION dwh_owner; +CREATE SCHEMA IF NOT EXISTS silver AUTHORIZATION dwh_owner; +CREATE SCHEMA IF NOT EXISTS gold AUTHORIZATION dwh_owner; + +ALTER DATABASE tracksolid_dwh SET search_path TO bronze, silver, gold, public; + +-- 4. PERMISSIONS & DEFAULT PRIVILEGES (Critical for Security & Automation) +-- Schema access +GRANT USAGE, CREATE ON SCHEMA bronze TO dwh_owner; +GRANT USAGE, CREATE ON SCHEMA silver TO dwh_owner; +GRANT USAGE, CREATE ON SCHEMA gold TO dwh_owner; +GRANT USAGE ON SCHEMA bronze TO grafana_ro; +GRANT USAGE ON SCHEMA silver TO grafana_ro; +GRANT USAGE ON SCHEMA gold TO grafana_ro; +GRANT USAGE ON SCHEMA public TO dwh_owner, grafana_ro; + +-- Existing table access for Grafana +GRANT SELECT ON ALL TABLES IN SCHEMA bronze TO grafana_ro; +GRANT SELECT ON ALL TABLES IN SCHEMA silver TO grafana_ro; +GRANT SELECT ON ALL TABLES IN SCHEMA gold TO grafana_ro; + +-- FUTURE table access: Any table created by dwh_owner will automatically be readable by grafana_ro +ALTER DEFAULT PRIVILEGES FOR ROLE dwh_owner IN SCHEMA bronze GRANT SELECT ON TABLES TO grafana_ro; +ALTER DEFAULT PRIVILEGES FOR ROLE dwh_owner IN SCHEMA silver GRANT SELECT ON TABLES TO grafana_ro; +ALTER DEFAULT PRIVILEGES FOR ROLE dwh_owner IN SCHEMA gold GRANT SELECT ON TABLES TO grafana_ro; + +-- 5. BRONZE SCHEMA TABLES +-- Run as dwh_owner to ensure correct ownership & default privileges apply +SET ROLE dwh_owner; +SET search_path TO bronze, public; + +-- 5.1 DEVICES (Slowly Changing Dimension - Type 2 handled in Silver) +CREATE TABLE IF NOT EXISTS bronze.devices ( + imei TEXT PRIMARY KEY, + device_name TEXT, + mc_type TEXT, + mc_type_use_scope TEXT, + vehicle_name TEXT, + vehicle_number TEXT, + vehicle_models TEXT, + vehicle_icon TEXT, + vin TEXT, + engine_number TEXT, + vehicle_brand TEXT, + fuel_100km NUMERIC(6,2), + driver_name TEXT, + driver_phone TEXT, + sim TEXT, + iccid TEXT, + imsi TEXT, + account TEXT, + customer_name TEXT, + device_group_id TEXT, + device_group TEXT, + activation_time TIMESTAMPTZ, + expiration TIMESTAMPTZ, + enabled_flag SMALLINT DEFAULT 1 NOT NULL, + status TEXT DEFAULT 'active'::text, + city TEXT, + current_mileage_km NUMERIC(12,2), + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + updated_at TIMESTAMPTZ DEFAULT now() NOT NULL, + last_synced_at TIMESTAMPTZ, + vehicle_category TEXT, + cost_centre TEXT, + assigned_route TEXT, + depot_geom geometry(Point,4326), + depot_address TEXT, + assigned_city TEXT, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.2 POSITION HISTORY (High-volume fact table) +CREATE TABLE IF NOT EXISTS bronze.position_history ( + imei TEXT NOT NULL, + gps_time TIMESTAMPTZ NOT NULL, + geom geometry(Point,4326), + lat DOUBLE PRECISION, + lng DOUBLE PRECISION, + speed NUMERIC(7,2), + direction NUMERIC(6,2), + acc_status TEXT, + satellite SMALLINT, + current_mileage NUMERIC(12,2), + recorded_at TIMESTAMPTZ DEFAULT now(), + altitude NUMERIC(8,2), + post_type SMALLINT, + source TEXT DEFAULT 'poll'::text, + ingested_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (imei, gps_time) +); + +-- 5.3 TRIPS (Aggregated fact table) +CREATE TABLE IF NOT EXISTS bronze.trips ( + id BIGINT NOT NULL, + imei TEXT NOT NULL, + start_time TIMESTAMPTZ NOT NULL, + end_time TIMESTAMPTZ, + start_geom geometry(Point,4326), + end_geom geometry(Point,4326), + distance_km NUMERIC(12,2), + avg_speed_kmh NUMERIC(7,2), + max_speed_kmh NUMERIC(7,2), + updated_at TIMESTAMPTZ DEFAULT now(), + fuel_consumed_l NUMERIC(8,2), + idle_time_s INTEGER, + driving_time_s INTEGER, + trip_seq INTEGER, + source TEXT DEFAULT 'poll'::text, + ingested_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (id) +); + +-- 5.4 ALARMS (Event log fact table) +CREATE TABLE IF NOT EXISTS bronze.alarms ( + id BIGINT PRIMARY KEY, + imei TEXT, + alarm_type TEXT, + alarm_time TIMESTAMPTZ, + geom geometry(Point,4326), + lat DOUBLE PRECISION, + lng DOUBLE PRECISION, + speed NUMERIC(7,2), + acc_status TEXT, + updated_at TIMESTAMPTZ DEFAULT now(), + alarm_name TEXT, + source TEXT DEFAULT 'poll'::text, + severity TEXT, + geofence_id TEXT, + geofence_name TEXT, + acknowledged_at TIMESTAMPTZ, + acknowledged_by TEXT, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.5 DEVICE EVENTS (Connection lifecycle) +CREATE TABLE IF NOT EXISTS bronze.device_events ( + id BIGINT PRIMARY KEY, + imei TEXT NOT NULL, + event_type TEXT NOT NULL, + event_time TIMESTAMPTZ NOT NULL, + timezone TEXT, + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.6 DISPATCH LOG (Operational/SLA tracking) +CREATE TABLE IF NOT EXISTS bronze.dispatch_log ( + dispatch_id BIGINT PRIMARY KEY, + ticket_id TEXT NOT NULL, + imei TEXT NOT NULL, + driver_name TEXT, + job_lat DOUBLE PRECISION NOT NULL, + job_lng DOUBLE PRECISION NOT NULL, + job_geom geometry(Point,4326), + assigned_at TIMESTAMPTZ DEFAULT now() NOT NULL, + first_movement_at TIMESTAMPTZ, + on_site_at TIMESTAMPTZ, + resolved_at TIMESTAMPTZ, + cancelled_at TIMESTAMPTZ, + distance_km NUMERIC(8,2), + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.7 FAULT CODES (OBD/DTC diagnostics) +CREATE TABLE IF NOT EXISTS bronze.fault_codes ( + id BIGINT PRIMARY KEY, + imei TEXT NOT NULL, + reported_at TIMESTAMPTZ NOT NULL, + fault_code TEXT NOT NULL, + status_flags INTEGER, + lat DOUBLE PRECISION, + lng DOUBLE PRECISION, + geom geometry(Point,4326), + event_time TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.8 FUEL READINGS +CREATE TABLE IF NOT EXISTS bronze.fuel_readings ( + imei TEXT NOT NULL, + reading_time TIMESTAMPTZ NOT NULL, + sensor_path TEXT, + value NUMERIC(10,3), + unit TEXT, + lat DOUBLE PRECISION, + lng DOUBLE PRECISION, + geom geometry(Point,4326), + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (imei, reading_time) +); + +-- 5.9 GEOFENCES (Dimension/Reference) +CREATE TABLE IF NOT EXISTS bronze.geofences ( + id BIGINT PRIMARY KEY, + fence_id TEXT, + fence_name TEXT NOT NULL, + fence_type TEXT, + geom geometry(Geometry,4326), + radius_m NUMERIC(10,2), + description TEXT, + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + updated_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.10 HEARTBEATS (Device health/ping) +CREATE TABLE IF NOT EXISTS bronze.heartbeats ( + imei TEXT NOT NULL, + gate_time TIMESTAMPTZ NOT NULL, + power_level SMALLINT, + gsm_signal SMALLINT, + acc_status SMALLINT, + power_status SMALLINT, + fortify SMALLINT, + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (imei, gate_time) +); + +-- 5.11 INGESTION LOG (Metadata for tracking loads) +CREATE TABLE IF NOT EXISTS bronze.ingestion_log ( + id BIGINT PRIMARY KEY, + run_at TIMESTAMPTZ DEFAULT now() NOT NULL, + endpoint TEXT NOT NULL, + imei_count INTEGER DEFAULT 0 NOT NULL, + rows_upserted INTEGER DEFAULT 0 NOT NULL, + rows_inserted INTEGER DEFAULT 0 NOT NULL, + duration_ms INTEGER DEFAULT 0 NOT NULL, + success BOOLEAN DEFAULT true NOT NULL, + error_code TEXT, + error_message TEXT, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.12 LBS READINGS (Fallback positioning) +CREATE TABLE IF NOT EXISTS bronze.lbs_readings ( + id BIGINT PRIMARY KEY, + imei TEXT NOT NULL, + gate_time TIMESTAMPTZ NOT NULL, + post_type TEXT, + lbs_data JSONB, + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.13 LIVE POSITIONS (Current state snapshot) +CREATE TABLE IF NOT EXISTS bronze.live_positions ( + imei TEXT PRIMARY KEY, + geom geometry(Point,4326), + lat DOUBLE PRECISION, + lng DOUBLE PRECISION, + pos_type TEXT, + confidence SMALLINT, + gps_time TIMESTAMPTZ, + hb_time TIMESTAMPTZ, + speed NUMERIC(7,2), + direction NUMERIC(6,2), + acc_status TEXT, + gps_signal SMALLINT, + gps_num SMALLINT, + elec_quantity NUMERIC(5,2), + power_value NUMERIC(5,2), + battery_power_val NUMERIC(5,2), + tracker_oil TEXT, + temperature NUMERIC(8,2), + current_mileage NUMERIC(12,2), + device_status TEXT, + expire_flag TEXT, + activation_flag TEXT, + loc_desc TEXT, + recorded_at TIMESTAMPTZ DEFAULT now() NOT NULL, + updated_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.14 OBD READINGS (Vehicle diagnostics) +CREATE TABLE IF NOT EXISTS bronze.obd_readings ( + id BIGINT PRIMARY KEY, + imei TEXT, + reading_time TIMESTAMPTZ, + engine_rpm INTEGER, + fuel_level_pct NUMERIC(5,2), + updated_at TIMESTAMPTZ DEFAULT now(), + car_type SMALLINT, + acc_state SMALLINT, + status_flags INTEGER, + lat DOUBLE PRECISION, + lng DOUBLE PRECISION, + geom geometry(Point,4326), + obd_data JSONB, + coolant_temp_c NUMERIC(6,2), + battery_voltage NUMERIC(5,2), + intake_pressure NUMERIC(6,2), + throttle_pct NUMERIC(5,2), + vehicle_speed NUMERIC(7,2), + engine_load_pct NUMERIC(5,2), + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.15 PARKING EVENTS +CREATE TABLE IF NOT EXISTS bronze.parking_events ( + id BIGINT PRIMARY KEY, + imei TEXT NOT NULL, + event_type TEXT, + start_time TIMESTAMPTZ NOT NULL, + end_time TIMESTAMPTZ, + duration_seconds INTEGER, + geom geometry(Point,4326), + address TEXT, + updated_at TIMESTAMPTZ DEFAULT now(), + ingested_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 5.16 TEMPERATURE READINGS (Cold chain sensors) +CREATE TABLE IF NOT EXISTS bronze.temperature_readings ( + imei TEXT NOT NULL, + reading_time TIMESTAMPTZ NOT NULL, + temperature NUMERIC(6,2), + humidity_pct NUMERIC(5,2), + created_at TIMESTAMPTZ DEFAULT now() NOT NULL, + ingested_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (imei, reading_time) +); + +-- Reset role back to superuser +RESET ROLE; +RESET search_path; + +-- 6. VERIFICATION GRANTS (Ensure Grafana can query immediately) +GRANT SELECT ON ALL TABLES IN SCHEMA bronze TO grafana_ro; +GRANT USAGE ON SCHEMA bronze TO grafana_ro; \ No newline at end of file diff --git a/dwh/260424_all_vehicles.csv b/dwh/260424_all_vehicles.csv new file mode 100644 index 0000000..b950dd1 --- /dev/null +++ b/dwh/260424_all_vehicles.csv @@ -0,0 +1,163 @@ +"imei","device_name","mc_type","mc_type_use_scope","vehicle_name","vehicle_number","vehicle_models","vehicle_icon","vin","engine_number","vehicle_brand","fuel_100km","driver_name","driver_phone","sim","iccid","imsi","account","customer_name","device_group_id","device_group","activation_time","expiration","enabled_flag","status","city","current_mileage_km","created_at","updated_at","last_synced_at","vehicle_category","cost_centre","assigned_route","depot_geom","depot_address","assigned_city" +"353549090553685","Daniel Omondi - KMFF 099Z","AT4","personal","KMFF 099Z","KMFF 099Z","Motorbike","mtc",NULL,NULL,NULL,NULL,"Robert","0112794067","759336150","89254021334258404099","639021335840409","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-09-23 05:50:30+00","2040-09-23 23:59:59+00",1,"1",NULL,"2354.70","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"353549090561720","Wireless_Git","AT4","personal",NULL,NULL,NULL,"bus",NULL,NULL,NULL,NULL,NULL,NULL,"0701211913","89254021374215155053","639021371515505","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2025-06-09 09:12:50+00","2035-06-09 23:59:59+00",1,"1",NULL,"5992.43","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"353549090566281","KDR 592N","AT4","personal",NULL,NULL,NULL,"bus",NULL,NULL,NULL,NULL,NULL,NULL,"0797680464","89254021334258159693","639021335815969","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2024-11-08 04:01:30+00","2034-11-08 23:59:59+00",1,"1",NULL,"7771.90","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"353549090566885","Wireless GPS","AT4","personal",NULL,NULL,NULL,"bus",NULL,NULL,NULL,NULL,NULL,NULL,"0768445963","89254021334212352574","639021331235257","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2024-10-15 13:16:57+00","2034-10-15 23:59:59+00",1,"1",NULL,"17036.41","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"353549090567685","Daniel Kipkirui - KMFF 162Z","AT4","personal","KMFF 162Z","KMFF 162Z","Motorbike","mtc",NULL,NULL,NULL,NULL,"edwine","0112795498","742532058","89254021264260388966","639021266038896","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-09-23 05:09:39+00","2040-09-23 23:59:59+00",1,"1",NULL,"462.33","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"353549090567701","Wireless","AT4","personal",NULL,NULL,NULL,"bus",NULL,NULL,NULL,NULL,NULL,NULL,"0790176094","89254021394215205906","639021391520590","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2024-11-08 04:04:44+00","2034-11-08 23:59:59+00",1,"1",NULL,"16896.20","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081885410","Allan Owana - KDK 780K","GT06E","aotomobile","KDK 780K","KDK 780K","Probox","automobile",NULL,NULL,NULL,NULL,"Allan Owana",NULL,"703616117","89254021234222499854","639021232249985","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2019-06-19 09:32:22+00","2039-06-19 23:59:59+00",1,"1",NULL,"128853.11","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081886467","Gideon Kiprono - KCQ 215F","GT06E","aotomobile","KCQ 215F","OHS","Probox","automobile",NULL,NULL,NULL,"0.00","Gideon Kiprono",NULL,"746763076","89254021084186499865","639021088649986","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2019-06-30 09:30:00+00","2039-06-30 23:59:59+00",1,"1",NULL,"141057.46","2026-04-23 10:56:37.983314+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081886871","Kamonde KBA 467S","GT06E","aotomobile",NULL,NULL,NULL,"bus",NULL,NULL,NULL,NULL,NULL,NULL,"0746763083","89254021084186499873","639021088649987","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2019-06-30 09:09:14+00","2039-06-30 23:59:59+00",1,"1",NULL,"74183.36","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081886905","Kennedy Chege - KCQ 618K","GT06E","aotomobile","KCQ 618K","KCQ 618K","Probox","automobile",NULL,NULL,NULL,NULL,"Kennedy Chege",NULL,"746763132","89254021084186499923","639021088649992","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2019-06-30 07:08:35+00","2039-06-30 23:59:59+00",1,"1",NULL,"215608.19","2026-04-23 10:35:37.678371+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081887069","Wright Oseko - KCG 668W","GT06E","aotomobile","KCG 668W","KCG 668W","Probox","automobile",NULL,NULL,NULL,NULL,"Wright Oseko",NULL,"746763106","89254021084186499915","639021088649991","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2019-06-30 06:17:43+00","2039-06-30 23:59:59+00",1,"1",NULL,"239001.19","2026-04-23 11:00:08.769463+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081887192","Ndegwa Dancun - KCG 669W","GT06E","aotomobile","KCG 669W","KCG 669W","Probox","automobile",NULL,NULL,NULL,NULL,"Ndegwa Dancun",NULL,"746760191","89254021084186499501","639021088649950","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2019-06-15 10:26:15+00","2039-06-15 23:59:59+00",1,"1",NULL,"199191.85","2026-04-23 10:34:29.074112+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081891566","Simon Kamau - KCE 090R","GT06E","aotomobile","KCE 090R","KCE 090R","Probox","automobile",NULL,NULL,NULL,NULL,"Simon Kamau",NULL,"746760404","89254021084186499527","639021088649952","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2019-06-16 07:06:15+00","2039-06-16 23:59:59+00",1,"1",NULL,"215592.36","2026-04-23 10:30:55.739184+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081891590","Garage - KCE 699F","GT06E","aotomobile","KCE 699F","KCE 699F","Probox","automobile",NULL,NULL,NULL,NULL,"Garage",NULL,"746760215","89254021084186499519","639021088649951","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2019-06-16 11:11:24+00","2039-06-16 23:59:59+00",1,"1",NULL,"207814.05","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081891632","John Ondego - KCA 542Q","GT06E","aotomobile","KCA 542Q","KCA 542Q","Probox","automobile",NULL,NULL,NULL,NULL,"John Ondego",NULL,"746760038","89254021084186499485","639021088649948","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2019-06-15 09:17:53+00","2039-06-15 23:59:59+00",1,"1",NULL,"178914.47","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081891798","Garage - KCH 167M","GT06E","aotomobile","KCH 167M","KCH 167M","Probox","automobile",NULL,NULL,NULL,NULL,"Garage",NULL,"746760102","89254021084186499493","639021088649949","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2019-06-16 10:18:57+00","2039-06-16 23:59:59+00",1,"1",NULL,"168840.95","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081892101","Cornelius Kimutai - KCU 938R","GT06E","aotomobile","KCU 938R","KCU 938R","Van","automobile",NULL,NULL,NULL,NULL,"Cornelius Kimutai",NULL,"746759919","89254021084186499451","639021088649945","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2019-06-12 08:13:48+00","2039-06-12 23:59:59+00",1,"1",NULL,"149558.50","2026-04-23 10:29:21.507861+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081892309","Nicholas Erastus - KCQ 581M","GT06E","aotomobile","KCQ 581M","KCQ 581M","Probox","automobile",NULL,NULL,NULL,NULL,"Nicholas Erastus",NULL,"700023776","89254021084178504672","639021087850467","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2019-06-09 09:39:40+00","2039-06-09 23:59:59+00",1,"1",NULL,"209105.89","2026-04-23 10:40:40.169684+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081892440","KAZ 489Z","GT06E","aotomobile",NULL,NULL,NULL,"bus",NULL,NULL,NULL,NULL,NULL,NULL,"0700023806","89254021084178504698","639021087850469","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2019-06-09 10:04:39+00","2039-06-09 23:59:59+00",1,"1",NULL,"38197.20","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857081892762","Nicholas","GT06E","aotomobile",NULL,NULL,"Station Wagon","bus",NULL,NULL,"Toyota",NULL,NULL,NULL,"0746760503","89254021274233125361","639021273312536","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2019-06-16 08:31:46+00","2039-06-16 23:59:59+00",1,"1",NULL,"51048.97","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082037185","Amani Kazungu - KCY 084X","GT06E","aotomobile","KCY 084X","KCY 084X","Probox","automobile",NULL,NULL,NULL,NULL,"Amani Kazungu",NULL,"757338522","89254021154287000597","639021158700059","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-07-13 09:42:28+00","2040-07-13 23:59:59+00",1,"1",NULL,"172298.81","2026-04-23 10:51:08.665273+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082038977","Wilfred Kinyanjui - KCU 729C","GT06E","aotomobile","KCU 729C","KCU 729C","Crane","truck",NULL,NULL,NULL,NULL,"Wilfred Kinyanjui",NULL,"110094469","89254021164215938057","639021161593805","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-04-05 09:26:00+00","2040-04-05 23:59:59+00",1,"1",NULL,"172487.09","2026-04-23 10:24:33.914628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082040981","Amani Sulubu - KCY 090X","GT06E","aotomobile","KCY 090X","KCY 090X","Probox","automobile",NULL,NULL,NULL,NULL,"Amani Sulubu",NULL,"793375853","89254021064168004164","639021066800416","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-07-13 07:25:16+00","2040-07-13 23:59:59+00",1,"1",NULL,"166028.15","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082042052","Gabriel Musumba - KCE 690F","GT06E","aotomobile","KCE 690F","KCE 690F","Probox","automobile",NULL,NULL,NULL,NULL,"Gabriel Musumba",NULL,"110094466","89254021164215938024","639021161593802","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2020-04-03 17:30:13+00","2040-04-03 23:59:59+00",1,"1",NULL,"192693.23","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082042854","Elias Baya - KCZ 476E","GT06E","aotomobile","KCZ 476E","KCZ 476E","Probox","automobile",NULL,NULL,NULL,NULL,"Elias Baya",NULL,"110941187","89254021164224352993","639021162435299","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-08-09 05:06:42+00","2040-08-09 23:59:59+00",1,"1",NULL,"217595.68","2026-04-23 10:33:56.216621+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082042953","KCU 865Q Vanguard",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,"unknown",NULL,NULL,"2026-04-23 13:24:33.293453+00","2026-04-23 13:24:33.293453+00",NULL,NULL,NULL,NULL,NULL,NULL,NULL +"359857082044280","Lawrence Kijogi - KCY 080X","GT06E","aotomobile","KCY 080X","KCY 080X","Probox","automobile",NULL,NULL,NULL,NULL,"Lawrence Kijogi",NULL,"708155933","89254029851005131222","639029850513122","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-07-13 11:05:02+00","2040-07-13 11:05:02+00",1,"1",NULL,"169740.37","2026-04-23 14:52:58.983571+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082046145","Joseph Kabandi - KCY 076X","GT06E","aotomobile","KCY 076X","KCY 076X","Probox","automobile",NULL,NULL,NULL,NULL,"Joseph Kabandi",NULL,"110850007","89254021164223447158","639021162344715","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-07-13 08:31:26+00","2040-07-13 23:59:59+00",1,"1",NULL,"122254.48","2026-04-23 10:47:40.895504+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082896911","Hamisi Pande - KDD 689Y","GT06E","aotomobile","KDD 689Y","KDD 689Y","Probox","automobile",NULL,NULL,NULL,NULL,"Hamisi Pande",NULL,"112714612","89254021214211314660","639021211131466","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-09-17 11:50:53+00","2041-09-17 23:59:59+00",1,"1",NULL,"163435.74","2026-04-23 10:26:09.922447+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082897091","Peter Mbugua - KDK 728K","GT06E","aotomobile","KDK 728K","KDK 728K","Probox","automobile",NULL,NULL,NULL,NULL,"Peter Mbugua",NULL,"790262984","89254021234222500396","639021232250039","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-12-14 11:31:57+00","2042-12-14 23:59:59+00",1,"1",NULL,"131109.26","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082897257","Cassius Wakiyo - KDB 323M","GT06E","aotomobile","KDB 323M","KDB 323M","Probox","automobile",NULL,NULL,NULL,NULL,"Cassius Wakiyo",NULL,"746428882","89254021234222500818","639021232250081","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-08-29 15:07:26+00","2041-08-29 15:07:26+00",1,"1",NULL,"121688.92","2026-04-23 10:28:26.388654+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082897737","John Makori - KDB 585E","GT06E","aotomobile","KDB 585E","KDB 585E","Probox","automobile",NULL,NULL,NULL,NULL,"John Makori",NULL,"114596734","89254021214211145262","639021211114526","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-08-29 14:29:28+00","2041-08-29 14:29:28+00",1,"1",NULL,"156765.03","2026-04-23 10:38:57.445964+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082897794","Mutuku Joseph - KDC 739F","GT06E","aotomobile","KDC 739F","KDC 739F","Probox","automobile",NULL,NULL,NULL,NULL,"Mutuku Joseph","115019037","115019037","89254021224222632356","639021222263235","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-04-10 14:55:32+00","2041-04-10 14:55:32+00",1,"1",NULL,"205169.79","2026-04-23 10:30:22.530563+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082898008","Samuel Ng'ang'a - KDE 264M","GT06E","aotomobile","KDE 264M","KDE 264M","Probox","automobile",NULL,NULL,NULL,NULL,"Samuel Ng'ang'a",NULL,"711731539","89254021264260342245","639021266034224","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-10-28 09:43:11+00","2041-10-28 23:59:59+00",1,"1",NULL,"126584.24","2026-04-23 11:35:59.816581+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082898016","Job Ngare - KDM 309S","GT06E","aotomobile","KDM 309S","KDM 309S","Probox","automobile",NULL,NULL,NULL,NULL,"Job Ngare",NULL,"706895756","89254021324273007563","639021327300756","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-08-15 13:45:26+00","2033-08-15 23:59:59+00",1,"1",NULL,"107726.56","2026-04-23 11:20:25.939244+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082898073","Mutuku Antony - KDK 732K","GT06E","aotomobile","KDK 732K","KDK 732K","Probox","automobile",NULL,NULL,NULL,NULL,"Mutuku Antony",NULL,"793026954","89254021234222387539","639021232238753","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-12-20 06:33:12+00","2042-12-20 23:59:59+00",1,"1",NULL,"82096.79","2026-04-23 14:52:07.094447+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082898487","Dan Watila - KDE 638J","GT06E","aotomobile","KDE 638J","KDE 638J","Probox","automobile",NULL,NULL,NULL,NULL,"Dan Watila",NULL,"116242996","89254021334258404214","639021335840421","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-10-21 15:50:06+00","2041-10-21 23:59:59+00",1,"1",NULL,"123872.36","2026-04-23 10:31:45.186653+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082900168","KDD 913G_Ruth Mazda",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,"unknown",NULL,NULL,"2026-04-23 15:09:48.575568+00","2026-04-23 15:09:48.575568+00",NULL,NULL,NULL,NULL,NULL,NULL,NULL +"359857082900341","Simon Munda - KCZ 154S","GT06E","aotomobile","KCZ 154S","KCZ 154S","Probox","automobile",NULL,NULL,NULL,NULL,"Simon Munda",NULL,"757236135","89254021154296723312","639021159672331","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-09-23 17:12:51+00","2040-09-23 23:59:59+00",1,"1",NULL,"186504.10","2026-04-23 10:45:21.454595+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082900358","Geoffrey Too - KDM 308S","GT06E","aotomobile","KDM 308S","KDM 308S","Probox","automobile",NULL,NULL,NULL,NULL,"Geoffrey Too",NULL,"796527601","89254021264260126572","639021266012657","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-10-21 15:25:28+00","2041-10-21 23:59:59+00",1,"1",NULL,"142216.91","2026-04-23 12:35:06.661934+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082900697","George Ochieng' - KDD 684Y","GT06E","aotomobile","KDD 684Y","KDD 684Y","Probox","automobile",NULL,NULL,NULL,NULL,"George Ochieng'",NULL,"114879518","89254021214211314678","639021211131467","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-09-17 10:53:11+00","2041-09-17 23:59:59+00",1,"1",NULL,"152820.07","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082902461","Sadique Wakayula - KDC 490Q","GT06E","aotomobile","KDC 490Q","KDC 490Q","Crane","truck",NULL,NULL,NULL,NULL,"Sadique Wakayula",NULL,"757556468","89254021154296722488","639021159672248","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-05-22 11:27:30+00","2041-05-22 11:27:30+00",1,"1",NULL,"183009.52","2026-04-23 11:16:03.730519+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082902503","Felix Andole - KDC 207R","GT06E","aotomobile","KDC 207R","KDC 207R","Probox","automobile",NULL,NULL,NULL,NULL,"Felix Andole",NULL,"794820817","89254021224270993254","639021227099325","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-05-15 11:38:24+00","2041-05-15 11:38:24+00",1,"1",NULL,"208724.46","2026-04-23 15:32:46.935568+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082907973","Felix Muema - KCZ 223P","GT06E","aotomobile","KCZ 223P","KCZ 223P","Probox","automobile",NULL,NULL,NULL,NULL,"Felix Muema",NULL,"757843826","89254021154287138371","639021158713837","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-08-22 14:01:25+00","2040-08-22 23:59:59+00",1,"1",NULL,"222126.36","2026-04-23 10:26:48.220151+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082908500","Santoes Omondi - KCZ 181P","GT06E","aotomobile","KCZ 181P","KCZ 181P","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Santoes Omondi",NULL,"701211974","89254021374215155087","639021371515508","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-08-23 08:58:55+00","2040-08-23 23:59:59+00",1,"1",NULL,"221339.62","2026-04-23 10:48:09.537346+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082910589","Patric Bett - KDA 609E","GT06E","aotomobile","KDA 609E","KDA 609E","Probox","automobile",NULL,NULL,NULL,NULL,"Patric Bett",NULL,"797622637","89254021154296722496","639021159672249","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2020-10-26 15:46:41+00","2040-10-26 23:59:59+00",1,"1",NULL,"194618.69","2026-04-23 10:34:25.350862+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082910886","Makanda Andrew - KCZ 155P","GT06E","aotomobile","KCZ 155P","KCZ 155P","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Makanda Andrew",NULL,"745067338","89254021154287138397","639021158713839","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-08-23 11:52:35+00","2040-08-23 23:59:59+00",1,"1",NULL,"231065.89","2026-04-23 11:36:31.150282+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082911983","Brian Ngetich - KDA 717B","GT06E","aotomobile","KDA 717B","KDA 717B","Probox","automobile",NULL,NULL,NULL,NULL,"Brian Ngetich","795188807","795188807","89254021214211145288","639021211114528","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-08-29 07:21:43+00","2041-08-29 07:21:43+00",1,"1",NULL,"145404.96","2026-04-23 10:36:11.774166+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082912239","Dickson Jaoko - KDK 815R","GT06E","aotomobile","KDK 815R","KDK 815R","Probox","automobile",NULL,NULL,"Probox","0.00","Sammy",NULL,"706392117","89254021234296021287","639021239602128","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2023-06-21 07:14:51+00","2033-06-21 23:59:59+00",1,"1",NULL,"77008.75","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082912486","Moses Wambua - KCZ 751V","GT06E","aotomobile","KCZ 751V","KCZ 751V","Probox","automobile",NULL,NULL,NULL,NULL,"Moses Wambua","0792756503","792756503","89254021154296723437","639021159672343","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-09-23 10:14:28+00","2040-09-23 23:59:59+00",1,"1",NULL,"139762.20","2026-04-23 10:41:00.207177+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082916826","Denis Kazungu - KDM 794R","GT06E","aotomobile","KDM 794R","KDM 794R","Probox","automobile",NULL,NULL,NULL,NULL,"Denis Kazungu",NULL,"705700971","89254021324273006854","639021327300685","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2023-08-21 06:38:00+00","2033-08-21 23:59:59+00",1,"1",NULL,"79639.71","2026-04-23 20:18:46.496567+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082918012","Charles Nyambane - KCB 711C","GT06E","aotomobile","KCB 711C","KCB 711C","Probox","automobile",NULL,NULL,NULL,NULL,"Charles Nyambane",NULL,"793704231","89254021154287138363","639021158713836","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2020-09-21 10:48:35+00","2040-09-21 23:59:59+00",1,"1",NULL,"159597.27","2026-04-23 10:25:52.843474+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082918038","Mbuvi Kioko - KCC 199P","GT06E","aotomobile","KCC 199P","KCC 199P","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Mbuvi Kioko",NULL,"797318126","89254021154287138389","639021158713838","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-08-22 15:26:27+00","2040-08-22 23:59:59+00",1,"1",NULL,"222106.80","2026-04-23 12:09:05.609075+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"359857082918186","KDD 977T Fielder",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,"unknown",NULL,NULL,"2026-04-23 10:36:25.832836+00","2026-04-23 10:36:25.832836+00",NULL,NULL,NULL,NULL,NULL,NULL,NULL +"359857082925330","Noel Merengeni - KCY 838X","GT06E","aotomobile","KCY 838X","KCY 838X","Probox","automobile",NULL,NULL,NULL,NULL,"Noel Merengeni",NULL,"794873610","89254021154296723429","639021159672342","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2020-10-26 16:36:37+00","2040-10-26 23:59:59+00",1,"1",NULL,"194429.24","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050288212","Nicholas Erastus - KCQ 581M","JC400P","aotomobile","KCQ 581M","KCQ 581M","Probox","automobile",NULL,NULL,NULL,NULL,"Nicholas Erastus",NULL,"746979531",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-11-02 09:07:41+00","2041-11-02 23:59:59+00",1,"1",NULL,"40898.98","2026-04-23 13:05:18.326254+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050288261","Patric Bett - KDA 609E","JC400P","aotomobile","KDA 609E","KDA 609E","Probox","automobile",NULL,NULL,NULL,NULL,"Patric Bett","112693340","790176509",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2021-10-23 11:50:11+00","2041-10-23 23:59:59+00",1,"1",NULL,"18538.42","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050288303","Elias Baya - KCZ 476E","JC400P","aotomobile","KCZ 476E","KCZ 476E","Probox","automobile",NULL,NULL,NULL,NULL,"Elias Baya",NULL,"115870439",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-11-06 08:50:28+00","2041-11-06 23:59:59+00",1,"1",NULL,"116091.42","2026-04-23 17:46:09.993791+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050288345","Santoes Omondi - KCZ 181P","JC400P","aotomobile","KCZ 181P","KCZ 181P","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Santoes Omondi",NULL,"768446105",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2021-11-06 10:17:51+00","2041-11-06 23:59:59+00",1,"1",NULL,"107462.79","2026-04-23 10:29:45.563231+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050288360","Brian Ngetich - KDA 717B","JC400P","aotomobile","KDA 717B","KDA 717B","Probox","automobile",NULL,NULL,NULL,NULL,"Brian Ngetich",NULL,"717867861",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2021-11-05 08:47:08+00","2041-11-05 23:59:59+00",1,"1",NULL,"17808.56","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050521521","John Kimeria - KDS 525D","JC400P","aotomobile","KDS 525D","KDS 525D","Crane","truck",NULL,NULL,NULL,NULL,"John Kimeria",NULL,"752958416",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-11-26 07:58:13+00","2033-11-26 23:59:59+00",1,"1",NULL,"19354.92","2026-04-23 10:28:34.917147+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050521612","Denis Kazungu - KDM 794R","JC400P","aotomobile","KDM 794R","KDM 794R","Probox","automobile",NULL,NULL,NULL,NULL,"Denis Kazungu",NULL,"704113731",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-22 07:52:12+00","2042-01-22 23:59:59+00",1,"1",NULL,"4350.75","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050521752","Simon Munda - KCZ 154S","JC400P","aotomobile","KCZ 154S","KCZ 154S","Probox","automobile",NULL,NULL,NULL,NULL,"Simon Munda",NULL,"113805921",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 08:14:37+00","2042-01-16 23:59:59+00",1,"1",NULL,"4698.02","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050522065","Gideon Kiprono - KCQ 215F","JC400P","aotomobile","KCQ 215F","KCQ 215F","Probox","automobile",NULL,NULL,NULL,NULL,"Gideon Kiprono",NULL,"113343715",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2022-01-16 07:10:16+00","2042-01-16 23:59:59+00",1,"1",NULL,"8111.98","2026-04-23 18:23:51.445608+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050522107","Cassius Wakiyo - KDB 323M","JC400P","aotomobile","KDB 323M","KDB 323M","Probox","automobile",NULL,NULL,NULL,NULL,"Cassius Wakiyo",NULL,"114149576",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-22 08:18:15+00","2042-01-22 23:59:59+00",1,"1",NULL,"23316.09","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050522719","Mbuvi Kioko - KCZ 199P","JC400P","aotomobile","KCZ 199P","KCZ 199P","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Mbuvi Kioko",NULL,"768218655",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 22:07:24+00","2042-01-16 23:59:59+00",1,"1",NULL,"16973.89","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050522743","Charles Nyambane - KCB 711C","JC400P","aotomobile","KCB 711C","KCB 711C","Probox","automobile",NULL,NULL,NULL,NULL,"Charles Nyambane",NULL,"768657106",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2023-12-22 21:53:57+00","2033-12-22 23:59:59+00",1,"1",NULL,"12133.75","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050522859","Garage - KCH 167M","JC400P","aotomobile","KCH 167M","KCH 167M","Probox","automobile",NULL,NULL,NULL,NULL,"Garage",NULL,"706740252",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-15 08:23:21+00","2042-01-15 23:59:59+00",1,"1",NULL,"6934.86","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050522883","Dan Watila - KDE 638J","JC400P","aotomobile","KDE 638J","KDE 638J","Probox","automobile",NULL,NULL,NULL,NULL,"Dan Watila",NULL,"112615393",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-15 07:17:21+00","2042-01-15 23:59:59+00",1,"1",NULL,"14483.01","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050522891","Lawrence Kijogi - KCY 080X","JC400P","aotomobile","KCY 080X","KCY 080X","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Lawrence Kijogi",NULL,"113287191",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 10:51:30+00","2042-01-16 23:59:59+00",1,"1",NULL,"11585.33","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523014","Samuel Muriithy - KDR 594N","JC400P","aotomobile","KDR 594N","KDR 594N","Probox","automobile",NULL,NULL,NULL,NULL,"Samuel Muriithy",NULL,"790175423",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-12-21 15:54:32+00","2033-12-21 23:59:59+00",1,"1",NULL,"27275.43","2026-04-23 10:26:17.747928+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523063","Kelvin Wambugu - KDR 594N","JC400P","aotomobile","KDR 594N","KDR 594N","Probox","automobile",NULL,NULL,NULL,NULL,"Kelvin Wambugu",NULL,"701211876",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-12-22 19:24:51+00","2043-12-22 19:24:51+00",1,"1",NULL,"32698.94","2026-04-23 15:31:08.065856+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523139","Mike Wanaswa - KDT 724R","JC400P","aotomobile","KDT 724R","KDT 724R","Probox","automobile",NULL,NULL,NULL,NULL,"Mike Wanaswa",NULL,"790175045",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-12-22 22:28:09+00","2043-12-22 22:28:09+00",1,"1",NULL,"29559.82","2026-04-23 11:16:37.277518+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523204","Amani Kazungu - KCY 084X","JC400P","aotomobile","KCY 084X","KCY 084X","Probox","automobile",NULL,NULL,NULL,NULL,"Amani Kazungu",NULL,"707892547",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 06:18:20+00","2042-01-16 23:59:59+00",1,"1",NULL,"66955.70","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523295","Emmanuel Luseno - KDS 453 Y","JC400P","aotomobile","KDS 453 Y","KDS 453 Y","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Emmanuel Luseno",NULL,"700242474",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-12-22 14:39:50+00","2033-12-22 23:59:59+00",1,"1",NULL,"37098.35","2026-04-23 11:29:48.369147+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523337","Victor Kimutai - KDS 919Y","JC400P","aotomobile","KDS 919Y","KDS 919Y","Probox","automobile",NULL,NULL,NULL,NULL,"Victor Kimutai",NULL,"700242527",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-12-22 18:00:49+00","2043-12-22 18:00:49+00",1,"1",NULL,"50756.64","2026-04-23 10:27:13.522675+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523386","George Ochieng' - KDD 684Y","JC400P","aotomobile","KDD 684Y","KDD 684Y","Probox","automobile",NULL,NULL,NULL,NULL,"George Ochieng'",NULL,"785586834",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-22 06:36:08+00","2042-01-22 23:59:59+00",1,"1",NULL,"33979.83","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523527","Allan Owana - KDK 780K","JC400P","aotomobile","KDK 780K","KDK 780K","Probox","automobile",NULL,NULL,NULL,NULL,"Allan Owana",NULL,"792375024",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2022-12-03 10:43:41+00","2042-12-03 23:59:59+00",1,"1",NULL,"109564.95","2026-04-23 10:25:24.360765+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523618","Geoffrey Too - KDM 308S","JC400P","aotomobile","KDM 308S","KDM 308S","Probox","automobile",NULL,NULL,NULL,NULL,"Geoffrey Too",NULL,"701211625",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2023-08-15 15:42:32+00","2033-08-15 23:59:59+00",1,"1",NULL,"26496.50","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523626","Major Simiyu - KDS 949Y","JC400P","aotomobile","KDS 949Y","KDS 949Y","Probox","automobile",NULL,NULL,NULL,NULL,"Major Simiyu",NULL,"701211892",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-12-22 18:05:16+00","2033-12-22 23:59:59+00",1,"1",NULL,"37042.97","2026-04-23 10:51:18.245194+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523816","Job Ngare - KDM 309S","JC400P","aotomobile","KDM 309S","KDM 309S","Probox","automobile",NULL,NULL,NULL,NULL,"Job Ngare",NULL,"707936781",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2023-08-15 14:05:52+00","2033-08-15 23:59:59+00",1,"1",NULL,"54320.21","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050523949","Joseph Kabandi - KCY 076X","JC400P","aotomobile","KCY 076X","KCY 076X","Probox","automobile",NULL,NULL,NULL,NULL,"Joseph Kabandi",NULL,"113288492",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 05:52:54+00","2042-01-16 23:59:59+00",1,"1",NULL,"14427.50","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524012","Moses Wambua - KCZ 751V","JC400P","aotomobile","KCZ 751V","KCZ 751V","Probox","automobile",NULL,NULL,NULL,NULL,"Moses Wambua",NULL,"113313797",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 07:40:10+00","2042-01-16 23:59:59+00",1,"1",NULL,"26551.46","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524087","Felix Muema - KCZ 223P","JC400P","aotomobile","KCZ 223P","KCZ 223P","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Felix Muema",NULL,"113973875",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 13:02:24+00","2042-01-16 23:59:59+00",1,"1",NULL,"11543.26","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524368","862798050524368","JC400P","aotomobile",NULL,NULL,NULL,"automobile",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-10-29 09:24:53+00","2042-10-29 23:59:59+00",1,"1",NULL,"169208.91","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524384","Hamisi Pande - KDD 689Y","JC400P","aotomobile","KDD 689Y","KDD 689Y","Probox","automobile",NULL,NULL,NULL,"0.00","Hamisi Pande",NULL,"701211744",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-22 05:49:19+00","2042-01-22 23:59:59+00",1,"1",NULL,"13685.18","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524392","Ndegwa Dancun - KCG 669W","JC400P","aotomobile","KCG 669W","KCG 669W","Probox","automobile",NULL,NULL,NULL,NULL,"Ndegwa Dancun",NULL,"113799173",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 09:43:10+00","2042-01-16 23:59:59+00",1,"1",NULL,"13638.25","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524426","Amani Sulubu - KCY 090X","JC400P","aotomobile","KCY 090X","KCY 090X","Probox","automobile",NULL,NULL,NULL,NULL,"Amani Sulubu",NULL,"113823350",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2022-01-16 08:56:25+00","2042-01-16 23:59:59+00",1,"1",NULL,"14243.83","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524533","Leonard Nzai - KDM 306S","JC400P","aotomobile","KDM 306S","KDM 306S","Probox","automobile",NULL,NULL,NULL,NULL,"Leonard Nzai",NULL,"703487162",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-08-21 08:22:12+00","2033-08-21 23:59:59+00",1,"1",NULL,"68942.41","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524558","Mutuku Joseph - KDC 739F","JC400P","aotomobile","KDC 739F","KDC 739F","Probox","automobile",NULL,NULL,NULL,NULL,"Mutuku Joseph",NULL,"100858817",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-22 10:38:25+00","2042-01-22 23:59:59+00",1,"1",NULL,"23711.63","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524566","Makanda Andrew - KCZ 155P","JC400P","aotomobile","KCZ 155P","KCZ 155P","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Makanda Andrew",NULL,"758781444",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-22 09:47:33+00","2042-01-22 23:59:59+00",1,"1",NULL,"31663.30","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524608","Peter Mbugua - KDK 728K","JC400P","aotomobile","KDK 728K","KDK 728K","Probox","automobile",NULL,NULL,NULL,NULL,"Peter Mbugua",NULL,"706742413",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-12-03 12:11:32+00","2042-12-03 23:59:59+00",1,"1",NULL,"7219.31","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524657","Felix Andole - KDC 207R","JC400P","aotomobile","KDC 207R","KDC 207R","Probox","automobile",NULL,NULL,NULL,NULL,"Felix Andole",NULL,"758689195",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-22 07:17:47+00","2042-01-22 23:59:59+00",1,"1",NULL,"46233.99","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524681","Mutuku Antony - KDK 732K","JC400P","aotomobile","KDK 732K","KDK 732K","Probox","automobile",NULL,NULL,NULL,NULL,"Mutuku Antony",NULL,"796275746",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-12-06 13:37:49+00","2042-12-06 23:59:59+00",1,"1",NULL,"14993.36","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524707","Garage - KCE 699F","JC400P","aotomobile","KCE 699F","KCE 699F","Probox","automobile",NULL,NULL,NULL,NULL,"Garage",NULL,"110525751",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-15 07:58:49+00","2042-01-15 23:59:59+00",1,"1",NULL,"34715.97","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050524897","Cornelius Kimutai - KCU 938R","JC400P","aotomobile","KCU 938R","KCU 938R","Van","automobile",NULL,NULL,NULL,NULL,"Cornelius Kimutai",NULL,"114924404",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-22 09:03:40+00","2042-01-22 23:59:59+00",1,"1",NULL,"12668.43","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525068","Samuel Ng'ang'a - KDE 264M","JC400P","aotomobile","KDE 264M","KDE 264M","Probox","automobile",NULL,NULL,NULL,NULL,"Samuel Ng'ang'a",NULL,"768658564",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2023-12-22 13:33:42+00","2033-12-22 23:59:59+00",1,"1",NULL,"12299.13","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525225","Sadique Wakayula - KDC 490Q","JC400P","aotomobile","KDC 490Q","KDC 490Q","Crane","truck",NULL,NULL,NULL,NULL,"Sadique Wakayula",NULL,"768652386",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2023-12-22 20:52:08+00","2043-12-22 20:52:08+00",1,"1",NULL,"19138.05","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525266","Dickson Jaoko - KDK 815R","JC400P","aotomobile","KDK 815R","KDK 815R","Probox","automobile",NULL,NULL,NULL,NULL,"Dickson Jaoko",NULL,"706665867",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-06-21 07:50:00+00","2033-06-21 23:59:59+00",1,"1",NULL,"63754.71","2026-04-23 13:50:24.21992+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525423","Makori John - KDB 585E","JC400P","aotomobile","KDB 585E","KDB 585E","Probox","automobile",NULL,NULL,NULL,NULL,"Makori John",NULL,"701211724",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-15 10:59:19+00","2042-01-15 23:59:59+00",1,"1",NULL,"48804.83","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525589","Simon Kamau - KCE 090R","JC400P","aotomobile","KCE 090R","KCE 090R","Probox","automobile",NULL,NULL,NULL,NULL,"Simon Kamau",NULL,"796276387",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-19 10:10:04+00","2042-01-19 23:59:59+00",1,"1",NULL,"15874.39","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525605","John Ondego - KCA 542Q","JC400P","aotomobile","KCA 542Q","KCA 542Q","Probox","automobile",NULL,NULL,NULL,NULL,"John Ondego",NULL,"110526783",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-15 05:56:11+00","2042-01-15 23:59:59+00",1,"1",NULL,"23976.94","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525613","Kennedy Chege - KCQ 618K","JC400P","aotomobile","KCQ 618K","KCQ 618K","Probox","automobile",NULL,NULL,NULL,NULL,"Kennedy Chege",NULL,"729994247",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-16 05:21:05+00","2042-01-16 23:59:59+00",1,"1",NULL,"12804.24","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525670","Gabriel Musumba - KCE 690F","JC400P","aotomobile","KCE 690F","KCE 690F","Probox","automobile",NULL,NULL,NULL,NULL,"Gabriel Musumba",NULL,"701211996",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2022-01-15 06:40:01+00","2042-01-15 23:59:59+00",1,"1",NULL,"20110.93","2026-04-24 05:34:23.167312+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525753","Noel Merengeni - KCY 838X","JC400P","aotomobile","KCY 838X","KCY 838X","Probox","automobile",NULL,NULL,NULL,NULL,"Noel Merengeni",NULL,NULL,NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2022-01-15 05:24:00+00","2042-01-15 23:59:59+00",1,"1",NULL,"14596.59","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525837","Kennedy Ondieki - KCU 237Z","JC400P","aotomobile","KCU 237Z","KCU 237Z","Probox","automobile",NULL,NULL,NULL,NULL,"Kennedy Ondieki",NULL,"113669852",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2023-12-21 19:32:44+00","2033-12-21 23:59:59+00",1,"1",NULL,NULL,"2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050525951","Wright Oseko - KCG 668W","JC400P","aotomobile","KCG 668W","KCG 668W","Probox","automobile",NULL,NULL,NULL,NULL,"Wright Oseko",NULL,"741943212",NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2022-01-15 09:36:45+00","2042-01-15 23:59:59+00",1,"1",NULL,"13116.00","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050526165","Wilfred Kinyanjui - KCU 729C","JC400P","aotomobile","KCU 729C","KCU 729C","Crane","truck",NULL,NULL,NULL,NULL,"Wilfred Kinyanjui",NULL,"790564929",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2023-11-26 10:17:19+00","2033-11-26 23:59:59+00",1,"1",NULL,"24270.20","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050526231","Rashid Hassan - KDM 840V","JC400P","aotomobile","KDM 840V","KDM 840V","Probox","automobile",NULL,NULL,NULL,NULL,"Rashid Hassan",NULL,"790175526",NULL,NULL,"Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2023-12-22 22:36:15+00","2043-12-22 22:36:15+00",1,"1",NULL,"45418.38","2026-04-23 10:29:41.575467+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798050526256","Ian Dancun - KDT 923R","JC400P","aotomobile","KDT 923R","KDT 923R","Probox","automobile",NULL,NULL,NULL,NULL,"Ian Dancun",NULL,"794873610",NULL,NULL,"Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2023-12-22 19:37:24+00","2043-12-22 19:37:24+00",1,"1",NULL,"11093.11","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052707888","Benjamin Ananda - KDV 438W","JC400P","aotomobile","KDV 438W","KDV 438W","Probox","automobile",NULL,NULL,NULL,NULL,"Benjamin Ananda",NULL,"758047312","89254021414206816980","639021410681698","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-12-15 07:39:23+00","2035-12-15 23:59:59+00",1,"1",NULL,"8720.87","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052707896","John Mbugua - KDW 573B","JC400P","aotomobile","KDW 573B","KDW 573B","Probox","automobile",NULL,NULL,NULL,NULL,"John Mbugua",NULL,NULL,"89254021414206816725","639021410681672","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2026-01-30 14:48:17+00","2036-01-30 23:59:59+00",1,"1",NULL,"515.16","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052707946","Tom Wekesa/OSP-KCY 930Y_CAM","JC400P","aotomobile",NULL,NULL,NULL,"automobile",NULL,NULL,NULL,NULL,NULL,NULL,"0758047806","89254021414206816766","639021410681676","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2026-01-20 21:02:13+00","2036-01-20 23:59:59+00",1,"1",NULL,"10079.17","2026-04-23 10:25:24.363965+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052708035","862798052708035","JC400P","aotomobile",NULL,NULL,"Probox","automobile",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group",NULL,NULL,1,"1",NULL,NULL,"2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052708068","Dominic Wambua - KDV 683Z","JC400P","aotomobile","KDV 683Z","KDV 683Z","Probox","automobile",NULL,NULL,NULL,NULL,"Dominic Wambua",NULL,"758048043","89254021414206816964","639021410681696","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2026-01-24 09:20:09+00","2036-01-24 23:59:59+00",1,"1",NULL,"4438.55","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052708076","Albert Mutwiri - KDV 437W","JC400P","aotomobile",NULL,"KDV 437W","Probox","automobile",NULL,NULL,NULL,NULL,"Albert Mutwiri",NULL,"758047094","89254021414206816782","639021410681678","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-12-13 15:03:30+00","2035-12-13 23:59:59+00",1,"1",NULL,"5575.64","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052708167","Levine Wasike - KDV 439W","JC400P","aotomobile","KDV 439W","KDV 439W","Probox","automobile",NULL,NULL,NULL,NULL,"Levine Wasike",NULL,"758046738","89254021414206816741","639021410681674","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-12-13 19:49:29+00","2035-12-13 23:59:59+00",1,"1",NULL,"4601.08","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052708282","Godffrey Nandwa - KCN 496A","JC400P","aotomobile","KCN 496A","KCN 496A","Probox","automobile",NULL,NULL,NULL,NULL,"Godffrey Nandwa",NULL,"758047934","89254021414206816865","639021410681686","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2026-01-25 18:55:54+00","2036-01-25 23:59:59+00",1,"1",NULL,"7040.60","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052713654","Garage/ISP_KCL 502T_CAM","JC400P","aotomobile",NULL,NULL,NULL,"automobile",NULL,NULL,NULL,NULL,NULL,NULL,"0780215879","89254035061001753803","639035060175380","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-09-02 10:09:57+00","2035-09-02 23:59:59+00",1,"1",NULL,"5199.72","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052713696","862798052713696","JC400P","aotomobile",NULL,NULL,"Probox","automobile",NULL,NULL,NULL,NULL,NULL,NULL,NULL,"89254021394215205906","639021391520590","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-09-02 10:20:58+00","2035-09-02 23:59:59+00",1,"1",NULL,"6214.49","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052713761","Management_Mazda - KDU 613A","JC400P","aotomobile","KDU 613A","KDU 613A","Mazda","automobile",NULL,NULL,NULL,NULL,"Management_Mazda",NULL,"790176786","89254021394215205955","639021391520595","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-07-09 15:49:26+00","2035-07-09 23:59:59+00",1,"1",NULL,"9262.78","2026-04-23 16:40:48.879666+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052713779","Benard Kimutai - KDN 759G","JC400P","aotomobile","KDN 759G","KDN 759G","Probox","automobile",NULL,NULL,NULL,NULL,"Benard Kimutai",NULL,"752143258","89254035061001753860","639035060175386","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-08-23 11:15:59+00","2035-08-23 23:59:59+00",1,"1",NULL,"5344.24","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052713811","James Onyango - KDU 613B","JC400P","aotomobile","KDU 613B","KDU 613B","Probox","automobile",NULL,NULL,NULL,NULL,"James Onyango",NULL,"790176542","89254021394215205880","639021391520588","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-09 19:24:14+00","2035-07-09 23:59:59+00",1,"1",NULL,"9657.42","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052713837","Kennedy Ondieki - KCU 237Z","JC400P","aotomobile","KCU 237Z","KCU 237Z","Probox","automobile",NULL,NULL,NULL,NULL,"Kennedy Ondieki",NULL,"113669852","89254021414206327855","639021410632785","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-10-08 14:55:23+00","2035-10-08 23:59:59+00",1,"1",NULL,"9346.02","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052713985","Timothy Gitau - KDT 916R","JC400P","aotomobile","KDT 916R","KDT 916R","Probox","automobile",NULL,NULL,NULL,NULL,"Timothy Gitau",NULL,"768696668","89254021394274518892","639021397451889","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-08-02 18:21:23+00","2035-08-02 23:59:59+00",1,"1",NULL,"19998.22","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052714066","862798052714066","JC400P","aotomobile",NULL,NULL,"Probox","automobile",NULL,NULL,NULL,NULL,NULL,NULL,NULL,"89254021414206378684","639021410637868","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-11-21 17:44:44+00","2035-11-21 23:59:59+00",1,"1",NULL,"10755.28","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"862798052715220","Rofas Njagi - KDT 728R","JC400P","aotomobile","KDT 728R","KDT 728R","Probox","automobile",NULL,NULL,NULL,NULL,"Rofas Njagi",NULL,"704573658","89254021334258495873","639021335849587","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-16 07:09:25+00","2035-07-16 23:59:59+00",1,"1",NULL,"16385.58","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061035133","Major Simiyu - KDS 949Y","X3","aotomobile","KDS 949Y","KDS 949Y","Probox","automobile",NULL,NULL,NULL,NULL,"Major Simiyu",NULL,"768696642","89254021394274518918","639021397451891","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2025-08-02 13:14:33+00","2035-08-02 23:59:59+00",1,"1",NULL,"25089.98","2026-04-23 12:07:56.044395+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061035653","Richardson Komu - KDT 923R","X3","aotomobile","KDT 923R","KDT 923R","Probox","automobile",NULL,NULL,NULL,NULL,"Richardson Komu",NULL,"768697292","89254021394274518942","639021397451894","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-08-02 08:11:46+00","2035-08-02 23:59:59+00",1,"1",NULL,"23556.65","2026-04-23 10:24:50.340401+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061035778","John Kimeria - KDS 525D","X3","aotomobile","KDS 525D","KDS 525D","Crane","truck",NULL,NULL,NULL,NULL,"John Kimeria",NULL,"790176738","89254021394215205922","639021391520592","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-11 05:50:36+00","2035-07-11 23:59:59+00",1,"1",NULL,"17653.96","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061036164","Brian Njenga - KMFF 113Z","X3","aotomobile","KMFF 113Z","KMFF 113Z","Motorbike","mtc",NULL,NULL,NULL,NULL,"Brian Njenga",NULL,"768696705","89254021394274518850","639021397451885","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-31 10:06:46+00","2035-07-31 23:59:59+00",1,"1",NULL,"22990.33","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061037980","Emmanuel Luseno - KDS 453Y","X3","aotomobile","KDS 453Y","KDS 453Y","Pick-Up","automobile",NULL,NULL,NULL,NULL,"Emmanuel Luseno",NULL,"790176734","89254021394215205856","639021391520585","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-15 06:30:34+00","2035-07-15 23:59:59+00",1,"1",NULL,"42609.03","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061042261","Kelvin Wambugu - KDR 592N","X3","aotomobile","KDR 592N","KDR 592N","Probox","automobile",NULL,NULL,NULL,NULL,"Kelvin Wambugu",NULL,"797680464","89254021334258159693","639021335815969","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-10 10:23:44+00","2035-07-10 23:59:59+00",1,"1",NULL,"18755.66","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061043079","Mike Wanaswa - KDT 724R","X3","aotomobile","KDT 724R","KDT 724R","Probox","automobile",NULL,NULL,NULL,NULL,"Mike Wanaswa",NULL,"768696664","89254021394274518959","639021397451895","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2025-08-02 12:16:11+00","2035-08-02 23:59:59+00",1,"1",NULL,"27470.11","2026-04-23 11:16:35.682194+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061043426","Geoffrey Karanja - KMGS 239H","X3","aotomobile","KMGS 239H","KMGS 239H","Motorbike","mtc",NULL,NULL,NULL,NULL,"Geoffrey Karanja",NULL,"768696658","89254021394274518926","639021397451892","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-08-22 13:32:25+00","2035-08-22 23:59:59+00",1,"1",NULL,"21267.01","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061047435","Management_Mazda - KDU 613A","X3","aotomobile","KDU 613A","KDU 613A","Mazda","automobile",NULL,NULL,NULL,NULL,"Management_Mazda",NULL,"790175971","89254021394215205971","639021391520597","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-09 08:02:26+00","2035-07-09 23:59:59+00",1,"1",NULL,"9761.38","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061048276","Victor Kimutai - KDS 919Y","X3","aotomobile","KDS 919Y","KDS 919Y","Probox","automobile",NULL,NULL,NULL,NULL,"Victor Kimutai",NULL,"768696755","89254021394274518900","639021397451890","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2025-08-02 07:38:01+00","2035-08-02 23:59:59+00",1,"1",NULL,"23296.79","2026-04-23 10:54:41.63532+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061048300","KMGR 409U HENRY JAZZ",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,"unknown",NULL,NULL,"2026-04-24 04:30:20.231102+00","2026-04-24 04:30:20.231102+00",NULL,NULL,NULL,NULL,NULL,NULL,NULL +"865135061048466","Samuel Muriithy - KDR 594N","X3","aotomobile","KDR 594N","KDR 594N","Probox","automobile",NULL,NULL,NULL,NULL,"Samuel Muriithy",NULL,"797680395","89254021334258159628","639021335815962","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-07-24 09:37:31+00","2035-07-24 23:59:59+00",1,"1",NULL,"27634.10","2026-04-23 11:43:39.178819+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061048615","Office-KMDG 902Z","X3","aotomobile",NULL,NULL,NULL,"automobile",NULL,NULL,NULL,NULL,NULL,NULL,"0768697276","89254021394274518876","639021397451887","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-31 09:59:43+00","2035-07-31 23:59:59+00",1,"1",NULL,"5721.21","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061048953","Timothy Gitau - KDT 916R","X3","aotomobile","KDT 916R","KDT 916R","Probox","automobile",NULL,NULL,NULL,NULL,"Timothy Gitau",NULL,"768697056","89254021394274518967","639021397451896","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2025-08-02 08:48:05+00","2035-08-02 23:59:59+00",1,"1",NULL,"28536.23","2026-04-23 10:53:31.102315+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061049001","Parked - KMGK 596V","X3","aotomobile","KMGK 596V","KMGK 596V","Motorbike","mtc",NULL,NULL,NULL,NULL,"Parked",NULL,"768697064","89254021394274518884","639021397451888","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-31 08:40:18+00","2035-07-31 23:59:59+00",1,"1",NULL,"20612.89","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061053714","Samuel Kihara - KMEL 225X","X3","aotomobile","KMEL 225X","KMEL 225X","Motorbike","mtc",NULL,NULL,NULL,NULL,"Samuel Kihara",NULL,"768696832","89254021394274518934","639021397451893","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-08-02 13:51:47+00","2035-08-02 23:59:59+00",1,"1",NULL,"26897.18","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061053748","Rashid Hassan - KDM 840V","X3","aotomobile","KDM 840V","KDM 840V","Probox","automobile",NULL,NULL,NULL,NULL,"Rashid Hassan",NULL,"768445963","89254021334212352574","639021331235257","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-07-10 13:54:11+00","2035-07-10 23:59:59+00",1,"1",NULL,"26612.42","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061054548","James Onyango - KDU 613B","X3","aotomobile","KDU 613B","KDU 613B","Probox","automobile",NULL,NULL,NULL,NULL,"James Onyango",NULL,"790175997","89254021394215205948","639021391520594","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-07-09 07:11:15+00","2035-07-09 23:59:59+00",1,"1",NULL,"13446.05","2026-04-23 10:26:24.667167+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061054555","Rofas Njagi - KDT 728R","X3","aotomobile","KDT 728R","KDT 728R","Probox","automobile",NULL,NULL,NULL,NULL,"Rofas Njagi",NULL,"790176726","89254021394215205823","639021391520582","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-07-16 06:44:33+00","2035-07-16 23:59:59+00",1,"1",NULL,"27250.80","2026-04-23 10:25:21.085437+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061559538","FRED KMGW 538W HULETI",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,"unknown",NULL,NULL,"2026-04-23 10:42:18.5831+00","2026-04-23 10:42:18.5831+00",NULL,NULL,NULL,NULL,NULL,NULL,NULL +"865135061562722","John Mbugua - KDW 573B","X3","aotomobile","KDW 573B","KDW 573B","Probox","automobile",NULL,NULL,NULL,NULL,"John Mbugua",NULL,"758052508","89254021414206816832","639021410681683","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2026-01-30 06:53:57+00","2036-01-30 23:59:59+00",1,"1",NULL,"4488.19","2026-04-23 10:25:38.887433+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061562847","Levine Wasike - KDV 439W","X3","aotomobile","KDV 439W","KDV 439W","Probox","automobile",NULL,NULL,NULL,NULL,"Levine Wasike",NULL,"758047032","89254021414206816840","639021410681684","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2025-12-13 11:14:14+00","2035-12-13 23:59:59+00",1,"1",NULL,"7880.92","2026-04-23 10:35:50.779597+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061563282","X3-63282","X3","aotomobile",NULL,NULL,NULL,"automobile",NULL,NULL,NULL,NULL,NULL,NULL,NULL,"8925610001837573427F","641101970467668","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2026-02-14 07:20:10+00","2036-02-14 23:59:59+00",1,"1",NULL,"4758.32","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061563415","Barack Orwa - KDW 781E","X3","aotomobile","KDW 781E","KDW 781E","Vazel","automobile",NULL,NULL,NULL,NULL,"Barack Orwa",NULL,"758052541","89254021414206816931","639021410681693","Fireside_MSA","Fireside Group MSA","9d0927d235e44fe7abf254902fc68921","Default group","2026-01-13 12:37:42+00","2036-01-13 23:59:59+00",1,"1",NULL,"4165.95","2026-04-23 11:22:00.676215+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061563423","Joel Ntumba - UMA 826AB","X3","aotomobile","UMA 826AB","UMA 826AB","Motorbike","mtc",NULL,NULL,NULL,NULL,"Joel Ntumba",NULL,"119051036","89254021414206652690","639021410665269","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2026-01-28 13:55:39+00","2036-01-28 23:59:59+00",1,"1",NULL,"1174.05","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061563597","Dominic Wambua - KDV 683Z","X3","aotomobile","KDV 683Z","KDV 683Z","Probox","automobile",NULL,NULL,NULL,NULL,"Dominic Wambua",NULL,"758052405","89254021414206816733","639021410681673","Fireside@HQ","Fireside Telematics","6ef0b0fc2d964b358b70dc2cfcbc5b7e","Default group","2026-01-30 06:55:35+00","2036-01-30 23:59:59+00",1,"1",NULL,"6790.53","2026-04-23 10:25:40.125927+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061563639","Benjamin Ananda - KDV 438W","X3","aotomobile","KDV 438W","KDV 438W","Probox","automobile",NULL,NULL,NULL,NULL,"Benjamin Ananda",NULL,"758047065","89254021414206816683","639021410681668","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-12-13 16:02:37+00","2035-12-13 23:59:59+00",1,"1",NULL,"14446.33","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061564280","Rodin Kiberu - UMA 011EK","X3","aotomobile","UMA 011EK","UMA 011EK","Motorbike","mtc",NULL,NULL,NULL,NULL,"Rodin Kiberu",NULL,"118081642","89254021414206817244","639021410681724","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2026-01-28 13:13:57+00","2036-01-28 23:59:59+00",1,"1",NULL,"841.39","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061564470","Silvanus Kipkorir - KDV 064S","X3","aotomobile","KDV 064S","KDV 064S","Probox","automobile",NULL,NULL,NULL,NULL,"Silvanus Kipkorir",NULL,"113669866","89254021414206378718","639021410637871","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-11-21 16:49:17+00","2035-11-21 23:59:59+00",1,"1",NULL,"23869.16","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061568968","X3-68968","X3","aotomobile",NULL,NULL,NULL,"automobile",NULL,NULL,NULL,NULL,NULL,NULL,NULL,"89254021414206816915","639021410681691","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2026-03-11 06:19:14+00","2036-03-11 23:59:59+00",1,"1",NULL,"16.23","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061569123","Albert Mutwiri - KDV 437W","X3","aotomobile","KDV 437W","KDV 437W","Probox","automobile",NULL,NULL,NULL,NULL,"Albert Mutwiri",NULL,"758047101","89254021414206816881","639021410681688","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-12-13 14:26:17+00","2035-12-13 23:59:59+00",1,"1",NULL,"13032.60","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061569131","UMA 418EK","X3","aotomobile","UMA 418EK","UMA 418EK",NULL,"automobile",NULL,NULL,NULL,NULL,"UG",NULL,"256792997053","8925610001837573385F","641101970467664","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2026-02-26 08:15:44+00","2036-02-26 23:59:59+00",1,"1",NULL,"2333.45","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061569479","UMA 382EK","X3","aotomobile","UMA 382EK","UMA 382EK",NULL,"automobile",NULL,NULL,NULL,NULL,"UG",NULL,"256792997079","8925610001837573419F","641101970467667","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2026-02-26 08:21:10+00","2036-02-26 23:59:59+00",1,"1",NULL,"1954.86","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL +"865135061578553","X3-78553",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,"unknown",NULL,NULL,"2026-04-23 15:30:19.981271+00","2026-04-23 15:30:19.981271+00",NULL,NULL,NULL,NULL,NULL,NULL,NULL +"865135061581904","Robert Kipruto - KDV 072L","X3","aotomobile","KDV 072L","KDV 072L","Probox","automobile",NULL,NULL,NULL,NULL,"Robert Kipruto",NULL,"114149576","89254021264261503993","639021266150399","fireside","Fireside Group HQ","2f1acaef6c884214b4598719180fe68d","Default group","2025-11-21 15:30:29+00","2035-11-21 23:59:59+00",1,"1",NULL,"15252.84","2026-04-23 10:23:56.546784+00","2026-04-24 07:43:45.210628+00","2026-04-24 07:43:45.210628+00",NULL,NULL,NULL,NULL,NULL,NULL diff --git a/dwh/261001_dwh_control.sql b/dwh/261001_dwh_control.sql new file mode 100644 index 0000000..abeaef5 --- /dev/null +++ b/dwh/261001_dwh_control.sql @@ -0,0 +1,69 @@ +-- ============================================================= +-- TRACKSOLID DWH CONTROL SCHEMA +-- Target Database: tracksolid_dwh +-- Purpose: Watermarks + per-run audit log for the n8n DWH pipeline +-- Applies after: 260423_dwh_ddl_v1.sql (requires dwh_owner role + grafana_ro role) +-- ============================================================= + +BEGIN; + +-- 1. CONTROL SCHEMA +-- Owned by dwh_owner to match bronze/silver/gold ownership convention from 260423. +CREATE SCHEMA IF NOT EXISTS dwh_control AUTHORIZATION dwh_owner; + +GRANT USAGE ON SCHEMA dwh_control TO grafana_ro; + +-- 2. PERMISSIONS (dwh_owner writes, grafana_ro reads) +-- Existing default privileges from 260423 only cover bronze/silver/gold; extend to dwh_control. +ALTER DEFAULT PRIVILEGES FOR ROLE dwh_owner IN SCHEMA dwh_control + GRANT SELECT ON TABLES TO grafana_ro; + +-- 3. EXTRACT WATERMARKS +-- One row per incremental table. Updated by Workflow 2 after a successful load commit. +-- last_extracted_at is the UPPER bound used in the most recent successful extract, +-- so the next run uses `WHERE > last_extracted_at AND <= :run_started_at`. +SET ROLE dwh_owner; + +CREATE TABLE IF NOT EXISTS dwh_control.extract_watermarks ( + table_name TEXT PRIMARY KEY, + last_extracted_at TIMESTAMPTZ NOT NULL DEFAULT '2026-01-01T00:00:00Z', + last_loaded_at TIMESTAMPTZ, + rows_loaded_last_run INT, + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 4. EXTRACT RUN AUDIT LOG +-- One row per table per cron tick. Lifecycle: extracting → uploaded → loading → loaded (or failed). +-- Failures retain error_message; the CSV stays in dwh/exports/ for the next run to pick up. +CREATE TABLE IF NOT EXISTS dwh_control.extract_runs ( + run_id BIGSERIAL PRIMARY KEY, + table_name TEXT NOT NULL, + run_started_at TIMESTAMPTZ NOT NULL, + run_finished_at TIMESTAMPTZ, + rows_extracted INT, + rows_loaded INT, + csv_path TEXT, + status TEXT CHECK (status IN ('extracting','uploaded','loading','loaded','failed')), + error_message TEXT +); + +CREATE INDEX IF NOT EXISTS idx_extract_runs_table_time + ON dwh_control.extract_runs (table_name, run_started_at DESC); +CREATE INDEX IF NOT EXISTS idx_extract_runs_status_time + ON dwh_control.extract_runs (status, run_finished_at DESC); + +-- 5. SEED WATERMARKS +-- One row per incremental table. Snapshot tables (devices, live_positions) do not need +-- watermarks and are intentionally omitted. +INSERT INTO dwh_control.extract_watermarks (table_name) VALUES + ('position_history'), + ('trips'), + ('alarms'), + ('parking_events'), + ('device_events'), + ('ingestion_log') +ON CONFLICT (table_name) DO NOTHING; + +RESET ROLE; + +COMMIT; diff --git a/dwh/261002_bronze_constraints_audit.sql b/dwh/261002_bronze_constraints_audit.sql new file mode 100644 index 0000000..7217863 --- /dev/null +++ b/dwh/261002_bronze_constraints_audit.sql @@ -0,0 +1,63 @@ +-- ============================================================= +-- BRONZE CONSTRAINTS AUDIT +-- Target Database: tracksolid_dwh +-- Purpose: Assert that every ON CONFLICT target used by Workflow 2 +-- (dwh_load_bronze) is backed by a PRIMARY KEY or UNIQUE +-- constraint in the bronze schema. Fails loudly if a future +-- DDL edit removes a key the ingestion pipeline depends on. +-- Applies after: 260423_dwh_ddl_v1.sql +-- Idempotent: pure assertion, no DDL changes. +-- ============================================================= + +BEGIN; + +DO $$ +DECLARE + missing TEXT := ''; + expected RECORD; +BEGIN + -- Each row asserts: bronze.
has a PK/UNIQUE matching . + -- If the pipeline's ON CONFLICT clause ever diverges from this list, + -- update both here and the n8n load workflow in lockstep. + FOR expected IN + SELECT * FROM (VALUES + ('devices', 'imei'), + ('live_positions', 'imei'), + ('position_history', 'imei,gps_time'), + ('trips', 'id'), + ('alarms', 'id'), + ('parking_events', 'id'), + ('device_events', 'id'), + ('ingestion_log', 'id') + ) AS t(table_name, cols) + LOOP + IF NOT EXISTS ( + SELECT 1 + FROM pg_constraint c + JOIN pg_class r ON r.oid = c.conrelid + JOIN pg_namespace n ON n.oid = r.relnamespace + CROSS JOIN LATERAL ( + SELECT string_agg(a.attname, ',' ORDER BY k.ord) AS keycols + FROM unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord) + JOIN pg_attribute a + ON a.attrelid = c.conrelid AND a.attnum = k.attnum + ) AS cols + WHERE n.nspname = 'bronze' + AND r.relname = expected.table_name + AND c.contype IN ('p','u') + AND cols.keycols = expected.cols + ) THEN + missing := missing + || format(E'\n - bronze.%s missing PK/UNIQUE on (%s)', + expected.table_name, expected.cols); + END IF; + END LOOP; + + IF length(missing) > 0 THEN + RAISE EXCEPTION E'Bronze constraint audit FAILED:%s', missing; + END IF; + + RAISE NOTICE 'Bronze constraint audit OK: all 8 ON CONFLICT targets backed by PK/UNIQUE.'; +END$$; + +COMMIT; diff --git a/dwh/261003_dwh_roles.sql b/dwh/261003_dwh_roles.sql new file mode 100644 index 0000000..5e3dd29 --- /dev/null +++ b/dwh/261003_dwh_roles.sql @@ -0,0 +1,66 @@ +-- ============================================================= +-- DWH ROLES AUDIT +-- Target Database: tracksolid_dwh +-- Purpose: Assert that the n8n DWH pipeline's role contract holds: +-- - dwh_owner exists (writes bronze + dwh_control) +-- - grafana_ro exists (reads bronze + silver + gold + dwh_control) +-- - grafana_ro has CONNECT on the database +-- - grafana_ro has USAGE on every schema it needs +-- Applies after: 260423_dwh_ddl_v1.sql, 261001_dwh_control.sql +-- Idempotent: pure assertion, no CREATE ROLE or GRANT statements. +-- +-- Why this file exists: 260423 creates both roles and grants bronze/silver/gold; +-- 261001 grants dwh_control. This file is a single checkpoint that verifies +-- those prior migrations were applied in the right order, and fails loudly +-- if anything is missing before the pipeline goes live. +-- +-- Password rotation and sslmode=require enforcement are out-of-band: +-- rotate via ALTER ROLE ... PASSWORD ... in a psql superuser session, +-- enforce SSL via the n8n credential (sslmode=require) — not SQL-level. +-- ============================================================= + +BEGIN; + +DO $$ +DECLARE + missing TEXT := ''; + r RECORD; +BEGIN + -- 1. Roles exist + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'dwh_owner') THEN + missing := missing || E'\n - role dwh_owner missing (expected from 260423)'; + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'grafana_ro') THEN + missing := missing || E'\n - role grafana_ro missing (expected from 260423)'; + END IF; + + -- 2. grafana_ro CONNECT on this database + IF NOT has_database_privilege('grafana_ro', current_database(), 'CONNECT') THEN + missing := missing + || format(E'\n - grafana_ro lacks CONNECT on database %s', + current_database()); + END IF; + + -- 3. grafana_ro USAGE on every schema the pipeline / dashboards touch + FOR r IN + SELECT unnest(ARRAY['bronze','silver','gold','dwh_control']) AS schema_name + LOOP + IF NOT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = r.schema_name) THEN + missing := missing + || format(E'\n - schema %s missing (expected from 260423/261001)', + r.schema_name); + ELSIF NOT has_schema_privilege('grafana_ro', r.schema_name, 'USAGE') THEN + missing := missing + || format(E'\n - grafana_ro lacks USAGE on schema %s', + r.schema_name); + END IF; + END LOOP; + + IF length(missing) > 0 THEN + RAISE EXCEPTION E'DWH roles audit FAILED:%s', missing; + END IF; + + RAISE NOTICE 'DWH roles audit OK: dwh_owner + grafana_ro present with expected grants.'; +END$$; + +COMMIT; diff --git a/dwh/261004_dwh_observability_views.sql b/dwh/261004_dwh_observability_views.sql new file mode 100644 index 0000000..cbbdc58 --- /dev/null +++ b/dwh/261004_dwh_observability_views.sql @@ -0,0 +1,79 @@ +-- ============================================================= +-- DWH OBSERVABILITY VIEWS +-- Target Database: tracksolid_dwh +-- Purpose: Surface pipeline health for Grafana dashboards. Three views, +-- one concern each: +-- v_table_freshness — how long since each table was last loaded +-- v_recent_failures — failed runs in the last 24h +-- v_watermark_lag — per-table watermark vs. now +-- Applies after: 261001_dwh_control.sql +-- Readability: owned by dwh_owner → grafana_ro inherits SELECT via the +-- ALTER DEFAULT PRIVILEGES set in 261001. Explicit GRANT below +-- covers the case where defaults were set AFTER this file runs. +-- ============================================================= + +BEGIN; + +SET ROLE dwh_owner; + +-- 1. FRESHNESS +-- One row per table that has ever loaded successfully. `lag` drives the +-- freshness panel; `loads_last_24h` sanity-checks the cron cadence. +CREATE OR REPLACE VIEW dwh_control.v_table_freshness AS +SELECT + table_name, + MAX(run_finished_at) AS last_loaded_at, + NOW() - MAX(run_finished_at) AS lag, + COUNT(*) FILTER (WHERE run_started_at > NOW() - INTERVAL '24 hours') AS loads_last_24h +FROM dwh_control.extract_runs +WHERE status = 'loaded' +GROUP BY table_name; + +COMMENT ON VIEW dwh_control.v_table_freshness IS + 'Per-table load lag. Alert when lag > 4h during active hours (05:00–23:00 EAT).'; + +-- 2. RECENT FAILURES +-- Failures retain error_message; the CSV stays in dwh/exports/ for the next +-- scheduled run to retry. Panel should show run_id so operators can grep logs. +CREATE OR REPLACE VIEW dwh_control.v_recent_failures AS +SELECT + run_id, + table_name, + run_started_at, + run_finished_at, + csv_path, + error_message +FROM dwh_control.extract_runs +WHERE status = 'failed' + AND run_started_at > NOW() - INTERVAL '24 hours' +ORDER BY run_started_at DESC; + +COMMENT ON VIEW dwh_control.v_recent_failures IS + 'Failed extract/load runs in the last 24h. Alert on any row.'; + +-- 3. WATERMARK LAG +-- Distinguishes "pipeline ran but found nothing" (load_lag small, extract_lag +-- growing) from "pipeline is stuck" (both lags growing). Snapshot tables are +-- not in extract_watermarks so they do not appear here — that is intentional. +CREATE OR REPLACE VIEW dwh_control.v_watermark_lag AS +SELECT + table_name, + last_extracted_at, + last_loaded_at, + rows_loaded_last_run, + NOW() - last_loaded_at AS load_lag, + NOW() - last_extracted_at AS extract_lag +FROM dwh_control.extract_watermarks; + +COMMENT ON VIEW dwh_control.v_watermark_lag IS + 'Per-table watermark position vs. now. Incremental tables only (6 rows).'; + +RESET ROLE; + +-- Explicit grants: defensive in case ALTER DEFAULT PRIVILEGES from 261001 +-- was not in effect when these views were created. +GRANT SELECT ON dwh_control.v_table_freshness TO grafana_ro; +GRANT SELECT ON dwh_control.v_recent_failures TO grafana_ro; +GRANT SELECT ON dwh_control.v_watermark_lag TO grafana_ro; + +COMMIT; diff --git a/dwh/device_events_schema b/dwh/device_events_schema new file mode 100644 index 0000000000000000000000000000000000000000..c2f08cf6534b50617065dc08a059fb8bd42e347e GIT binary patch literal 5741 zcmcIoU2oe|7hZ_#=5aCG#3rbrtwrfN-9Q$Qw_ zOEsxjMVta+`GMh>hG*(S*BQCqF^H!7fd@Z6is(8Q6!1a5fFiF5`#oOUX9C7eDqw>O z*bxPd%*OiA2#l#aF8fwMCAG)Jf^Qk#aH7wQU{WZN0z4F<&5I#=7zs?3U#r(B_|^JW zW1BloBUE^k*Z8})@n2B(RQWQzNh{WWl3| z9i$@*d`HxKihR&+iV6%&?ZGhY#%V$sXmlNUMD3ud$i19>vvC1wq2MuQt{;p&%g-g- zrx7&E{C@*J%|0kKLSE=lL*W9L*HU;%BZ4eRs8?Cak(6liGGy+FV|lkX&hhcsGe(AE z=$@N>Xlg|u50vbaQ_HXKZttY*?Xye>PSXPYMFa{cuO}*6TT~fCMli^CG|*-=B}ou! zm@&H%jzT;G$!mX4^$`3UBM+EEC$xrtVM1sPw0B9b<-~`ixIv)UCK=dc+X;vy zYeedIIwjVBY}sHakJ9~gS3P(vL!cQoR-C&kTZ$qn#D+y{UFwaV4!4~a^BVXSM4J0;`9GG?5I?QF)T zwDx%>QIVERj0E=FOVBUK-L5EU%visRJJ3v5i%!}qDKseyh+_pOu6INroH*7nuw92h zfFY*sFZD30kdfyelN+DkuEjt`efwU6?>W`lbjkV;TZhn&>6zM*VZ#ZUT( z7K;@>AkSDfu^7m8q2VgjU#c3fXe`sH(vG$S%b!5OA~7-I1^nviF>A*5un zKrZ%W+gwgHE<&Y7%4_}d7RXBr2H;w~vb_kvkelL-CqX5MpwwH15s94`-8nlk^W?JB zIm|r@VKYOQ1_2qi<~tnqMa_&x?fAtgW_-lz6v`7DdB zmqDs9GBk1`go-4iri)c&0d!`jgV_~>6Vo`l;1a=yFe=Es6)+cVvqT`>uuCM4G|@W@ zlxV(z*+_}RNysMIQ{*mO+~67s$f6W6no9ye|Cz$$dJi*rEMJ|^!d`|?A_D@BPz1OZ z?ajEioryIiQq8)?UF4K$b9$0Cr}{$6^_$!+kUnWniI$G)Vwo<@ITx?ctshyBshDuP zfr~fahExjemHQct{$n`cfOh2Pv-N6&mE^JW>&Ah0iHc zw$&ms;eQ+Sb#)%Mu-3(I%0vE|uhLzP!1@U#rU0GgDQ*BCUZUb~AJS9WU0yjP_rycc zk%^j+&a=%kG=Y0u2Hq)re@oz7t;JWs-5u^7kl!{R=?RP(P4O~CjjJs+#RtqBzJ}>x zLPL8YUgds^$z1H)l5vLgRrqs@3vh3gZQiGk?0xhj>O5<&vV4S=#SJjjz)fj_0f|b|NiIc({*nBFYXU$bKHM~P9U@Z literal 0 HcmV?d00001 diff --git a/dwh/tracksolid_full_schema.txt b/dwh/tracksolid_full_schema.txt new file mode 100644 index 0000000..851e413 --- /dev/null +++ b/dwh/tracksolid_full_schema.txt @@ -0,0 +1,6842 @@ +-- +-- PostgreSQL database dump +-- + +\restrict dPJmPZ0BDsHeyfTnAmlhf9NGlz7PqKG3XWgDOSnH5CrV9vRAMYsNh1loEhu4Y7m + +-- Dumped from database version 16.3 (Ubuntu 16.3-1.pgdg22.04+1) +-- Dumped by pg_dump version 18.0 + +-- Started on 2026-04-23 16:57:33 EAT + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +DROP DATABASE IF EXISTS tracksolid_db; +-- +-- TOC entry 6931 (class 1262 OID 16384) +-- Name: tracksolid_db; Type: DATABASE; Schema: -; Owner: postgres +-- + +CREATE DATABASE tracksolid_db WITH TEMPLATE = template0 ENCODING = 'UTF8' LOCALE_PROVIDER = libc LOCALE = 'C.UTF-8'; + + +ALTER DATABASE tracksolid_db OWNER TO postgres; + +\unrestrict dPJmPZ0BDsHeyfTnAmlhf9NGlz7PqKG3XWgDOSnH5CrV9vRAMYsNh1loEhu4Y7m +\connect tracksolid_db +\restrict dPJmPZ0BDsHeyfTnAmlhf9NGlz7PqKG3XWgDOSnH5CrV9vRAMYsNh1loEhu4Y7m + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- TOC entry 6933 (class 0 OID 0) +-- Name: tracksolid_db; Type: DATABASE PROPERTIES; Schema: -; Owner: postgres +-- + +ALTER DATABASE tracksolid_db SET search_path TO 'tracksolid', 'infrastructure', 'dwh_gold', 'public'; + + +\unrestrict dPJmPZ0BDsHeyfTnAmlhf9NGlz7PqKG3XWgDOSnH5CrV9vRAMYsNh1loEhu4Y7m +\connect tracksolid_db +\restrict dPJmPZ0BDsHeyfTnAmlhf9NGlz7PqKG3XWgDOSnH5CrV9vRAMYsNh1loEhu4Y7m + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- TOC entry 21 (class 2615 OID 22993) +-- Name: tracksolid; Type: SCHEMA; Schema: -; Owner: postgres +-- + +CREATE SCHEMA tracksolid; + + +ALTER SCHEMA tracksolid OWNER TO postgres; + +-- +-- TOC entry 2602 (class 1255 OID 25042) +-- Name: set_updated_at(); Type: FUNCTION; Schema: tracksolid; Owner: postgres +-- + +CREATE FUNCTION tracksolid.set_updated_at() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$; + + +ALTER FUNCTION tracksolid.set_updated_at() OWNER TO postgres; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- TOC entry 296 (class 1259 OID 24910) +-- Name: position_history; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.position_history ( + imei text NOT NULL, + gps_time timestamp with time zone NOT NULL, + geom public.geometry(Point,4326), + lat double precision, + lng double precision, + speed numeric(7,2), + direction numeric(6,2), + acc_status text, + satellite smallint, + current_mileage numeric(12,2), + recorded_at timestamp with time zone DEFAULT now(), + altitude numeric(8,2), + post_type smallint, + source text DEFAULT 'poll'::text +); + + +ALTER TABLE tracksolid.position_history OWNER TO postgres; + +-- +-- TOC entry 290 (class 1259 OID 24843) +-- Name: devices; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.devices ( + imei text NOT NULL, + device_name text, + mc_type text, + mc_type_use_scope text, + vehicle_name text, + vehicle_number text, + vehicle_models text, + vehicle_icon text, + vin text, + engine_number text, + vehicle_brand text, + fuel_100km numeric(6,2), + driver_name text, + driver_phone text, + sim text, + iccid text, + imsi text, + account text, + customer_name text, + device_group_id text, + device_group text, + activation_time timestamp with time zone, + expiration timestamp with time zone, + enabled_flag smallint DEFAULT 1 NOT NULL, + status text DEFAULT 'active'::text, + city text, + current_mileage_km numeric(12,2), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + last_synced_at timestamp with time zone, + vehicle_category text, + cost_centre text, + assigned_route text, + depot_geom public.geometry(Point,4326), + depot_address text, + assigned_city text +); + + +ALTER TABLE tracksolid.devices OWNER TO postgres; + +-- +-- TOC entry 6936 (class 0 OID 0) +-- Dependencies: 290 +-- Name: COLUMN devices.vehicle_category; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.devices.vehicle_category IS 'Vehicle type: truck | van | motorcycle | car | other'; + + +-- +-- TOC entry 6937 (class 0 OID 0) +-- Dependencies: 290 +-- Name: COLUMN devices.cost_centre; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.devices.cost_centre IS 'Business unit or department this vehicle belongs to'; + + +-- +-- TOC entry 6938 (class 0 OID 0) +-- Dependencies: 290 +-- Name: COLUMN devices.assigned_route; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.devices.assigned_route IS 'Regular route name or ID for route-based reporting'; + + +-- +-- TOC entry 6939 (class 0 OID 0) +-- Dependencies: 290 +-- Name: COLUMN devices.depot_geom; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.devices.depot_geom IS 'Home base/depot coordinates (WGS84)'; + + +-- +-- TOC entry 6940 (class 0 OID 0) +-- Dependencies: 290 +-- Name: COLUMN devices.depot_address; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.devices.depot_address IS 'Human-readable depot address'; + + +-- +-- TOC entry 6941 (class 0 OID 0) +-- Dependencies: 290 +-- Name: COLUMN devices.assigned_city; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.devices.assigned_city IS 'Operating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection.'; + + +-- +-- TOC entry 298 (class 1259 OID 24930) +-- Name: trips; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.trips ( + id bigint NOT NULL, + imei text NOT NULL, + start_time timestamp with time zone NOT NULL, + end_time timestamp with time zone, + start_geom public.geometry(Point,4326), + end_geom public.geometry(Point,4326), + distance_km numeric(12,2), + avg_speed_kmh numeric(7,2), + max_speed_kmh numeric(7,2), + updated_at timestamp with time zone DEFAULT now(), + fuel_consumed_l numeric(8,2), + idle_time_s integer, + driving_time_s integer, + trip_seq integer, + source text DEFAULT 'poll'::text +); + + +ALTER TABLE tracksolid.trips OWNER TO postgres; + +-- +-- TOC entry 6943 (class 0 OID 0) +-- Dependencies: 298 +-- Name: COLUMN trips.distance_km; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.trips.distance_km IS 'Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10).'; + + +-- +-- TOC entry 6944 (class 0 OID 0) +-- Dependencies: 298 +-- Name: COLUMN trips.driving_time_s; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.trips.driving_time_s IS 'runTimeSecond from API: total driving time in seconds'; + + +-- +-- TOC entry 6945 (class 0 OID 0) +-- Dependencies: 298 +-- Name: COLUMN trips.source; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.trips.source IS 'poll = from API polling, push = from webhook push'; + + +-- +-- TOC entry 302 (class 1259 OID 24969) +-- Name: alarms; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.alarms ( + id bigint NOT NULL, + imei text, + alarm_type text, + alarm_time timestamp with time zone, + geom public.geometry(Point,4326), + lat double precision, + lng double precision, + speed numeric(7,2), + acc_status text, + updated_at timestamp with time zone DEFAULT now(), + alarm_name text, + source text DEFAULT 'poll'::text, + severity text, + geofence_id text, + geofence_name text, + acknowledged_at timestamp with time zone, + acknowledged_by text +); + + +ALTER TABLE tracksolid.alarms OWNER TO postgres; + +-- +-- TOC entry 6947 (class 0 OID 0) +-- Dependencies: 302 +-- Name: COLUMN alarms.severity; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.alarms.severity IS 'Alarm severity level: critical | warning | info'; + + +-- +-- TOC entry 6948 (class 0 OID 0) +-- Dependencies: 302 +-- Name: COLUMN alarms.geofence_id; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.alarms.geofence_id IS 'Tracksolid geofence ID if this is a geofence alarm'; + + +-- +-- TOC entry 6949 (class 0 OID 0) +-- Dependencies: 302 +-- Name: COLUMN alarms.geofence_name; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.alarms.geofence_name IS 'Human-readable geofence name'; + + +-- +-- TOC entry 6950 (class 0 OID 0) +-- Dependencies: 302 +-- Name: COLUMN alarms.acknowledged_at; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.alarms.acknowledged_at IS 'Timestamp when alarm was acknowledged by an operator'; + + +-- +-- TOC entry 6951 (class 0 OID 0) +-- Dependencies: 302 +-- Name: COLUMN alarms.acknowledged_by; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.alarms.acknowledged_by IS 'Username or ID of operator who acknowledged the alarm'; + + +-- +-- TOC entry 301 (class 1259 OID 24968) +-- Name: alarms_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.alarms_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.alarms_id_seq OWNER TO postgres; + +-- +-- TOC entry 6953 (class 0 OID 0) +-- Dependencies: 301 +-- Name: alarms_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.alarms_id_seq OWNED BY tracksolid.alarms.id; + + +-- +-- TOC entry 292 (class 1259 OID 24859) +-- Name: api_token_cache; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.api_token_cache ( + id bigint NOT NULL, + account text NOT NULL, + access_token text NOT NULL, + refresh_token text, + app_key text, + expires_at timestamp with time zone NOT NULL, + obtained_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.api_token_cache OWNER TO postgres; + +-- +-- TOC entry 291 (class 1259 OID 24858) +-- Name: api_token_cache_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.api_token_cache_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.api_token_cache_id_seq OWNER TO postgres; + +-- +-- TOC entry 6956 (class 0 OID 0) +-- Dependencies: 291 +-- Name: api_token_cache_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.api_token_cache_id_seq OWNED BY tracksolid.api_token_cache.id; + + +-- +-- TOC entry 319 (class 1259 OID 25159) +-- Name: device_events; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.device_events ( + id bigint NOT NULL, + imei text NOT NULL, + event_type text NOT NULL, + event_time timestamp with time zone NOT NULL, + timezone text, + created_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.device_events OWNER TO postgres; + +-- +-- TOC entry 6958 (class 0 OID 0) +-- Dependencies: 319 +-- Name: TABLE device_events; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON TABLE tracksolid.device_events IS 'Device network connection and disconnection events from /pushevent webhook.'; + + +-- +-- TOC entry 6959 (class 0 OID 0) +-- Dependencies: 319 +-- Name: COLUMN device_events.event_type; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.device_events.event_type IS 'LOGIN = device connected to network; LOGOUT = device disconnected'; + + +-- +-- TOC entry 318 (class 1259 OID 25158) +-- Name: device_events_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.device_events_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.device_events_id_seq OWNER TO postgres; + +-- +-- TOC entry 6961 (class 0 OID 0) +-- Dependencies: 318 +-- Name: device_events_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.device_events_id_seq OWNED BY tracksolid.device_events.id; + + +-- +-- TOC entry 327 (class 1259 OID 25240) +-- Name: dispatch_log; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.dispatch_log ( + dispatch_id bigint NOT NULL, + ticket_id text NOT NULL, + imei text NOT NULL, + driver_name text, + job_lat double precision NOT NULL, + job_lng double precision NOT NULL, + job_geom public.geometry(Point,4326), + assigned_at timestamp with time zone DEFAULT now() NOT NULL, + first_movement_at timestamp with time zone, + on_site_at timestamp with time zone, + resolved_at timestamp with time zone, + cancelled_at timestamp with time zone, + distance_km numeric(8,2), + created_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.dispatch_log OWNER TO postgres; + +-- +-- TOC entry 6962 (class 0 OID 0) +-- Dependencies: 327 +-- Name: TABLE dispatch_log; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON TABLE tracksolid.dispatch_log IS 'Persistent record of every dispatch decision. Powers SLA metrics: dispatch latency, depart delay, time-to-site, wrench time.'; + + +-- +-- TOC entry 6963 (class 0 OID 0) +-- Dependencies: 327 +-- Name: COLUMN dispatch_log.first_movement_at; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.dispatch_log.first_movement_at IS 'First trip start after assigned_at. Back-filled nightly from trips.'; + + +-- +-- TOC entry 6964 (class 0 OID 0) +-- Dependencies: 327 +-- Name: COLUMN dispatch_log.on_site_at; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.dispatch_log.on_site_at IS 'Time vehicle entered 150 m radius of job_geom. Back-filled nightly.'; + + +-- +-- TOC entry 6965 (class 0 OID 0) +-- Dependencies: 327 +-- Name: COLUMN dispatch_log.resolved_at; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.dispatch_log.resolved_at IS 'Ticket close time from the ops system (ops.tickets.closed_at).'; + + +-- +-- TOC entry 326 (class 1259 OID 25239) +-- Name: dispatch_log_dispatch_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.dispatch_log_dispatch_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.dispatch_log_dispatch_id_seq OWNER TO postgres; + +-- +-- TOC entry 6967 (class 0 OID 0) +-- Dependencies: 326 +-- Name: dispatch_log_dispatch_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.dispatch_log_dispatch_id_seq OWNED BY tracksolid.dispatch_log.dispatch_id; + + +-- +-- TOC entry 316 (class 1259 OID 25122) +-- Name: fault_codes; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.fault_codes ( + id bigint NOT NULL, + imei text NOT NULL, + reported_at timestamp with time zone NOT NULL, + fault_code text NOT NULL, + status_flags integer, + lat double precision, + lng double precision, + geom public.geometry(Point,4326), + event_time timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.fault_codes OWNER TO postgres; + +-- +-- TOC entry 315 (class 1259 OID 25121) +-- Name: fault_codes_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.fault_codes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.fault_codes_id_seq OWNER TO postgres; + +-- +-- TOC entry 6969 (class 0 OID 0) +-- Dependencies: 315 +-- Name: fault_codes_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.fault_codes_id_seq OWNED BY tracksolid.fault_codes.id; + + +-- +-- TOC entry 320 (class 1259 OID 25176) +-- Name: fuel_readings; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.fuel_readings ( + imei text NOT NULL, + reading_time timestamp with time zone NOT NULL, + sensor_path text, + value numeric(10,3), + unit text, + lat double precision, + lng double precision, + geom public.geometry(Point,4326), + created_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.fuel_readings OWNER TO postgres; + +-- +-- TOC entry 6971 (class 0 OID 0) +-- Dependencies: 320 +-- Name: TABLE fuel_readings; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON TABLE tracksolid.fuel_readings IS 'Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.'; + + +-- +-- TOC entry 6972 (class 0 OID 0) +-- Dependencies: 320 +-- Name: COLUMN fuel_readings.sensor_path; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.fuel_readings.sensor_path IS 'Sensor channel identifier from the device (path field in API payload)'; + + +-- +-- TOC entry 6973 (class 0 OID 0) +-- Dependencies: 320 +-- Name: COLUMN fuel_readings.unit; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.fuel_readings.unit IS 'Measurement unit: cm (tank depth), % (percentage), V (voltage), L (litres)'; + + +-- +-- TOC entry 325 (class 1259 OID 25225) +-- Name: geofences; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.geofences ( + id bigint NOT NULL, + fence_id text, + fence_name text NOT NULL, + fence_type text, + geom public.geometry(Geometry,4326), + radius_m numeric(10,2), + description text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.geofences OWNER TO postgres; + +-- +-- TOC entry 6975 (class 0 OID 0) +-- Dependencies: 325 +-- Name: TABLE geofences; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON TABLE tracksolid.geofences IS 'Geofence boundary definitions synced from the Tracksolid platform.'; + + +-- +-- TOC entry 6976 (class 0 OID 0) +-- Dependencies: 325 +-- Name: COLUMN geofences.fence_type; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.geofences.fence_type IS 'circle | polygon'; + + +-- +-- TOC entry 6977 (class 0 OID 0) +-- Dependencies: 325 +-- Name: COLUMN geofences.radius_m; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.geofences.radius_m IS 'Radius in metres — only applicable for circle type geofences'; + + +-- +-- TOC entry 324 (class 1259 OID 25224) +-- Name: geofences_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.geofences_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.geofences_id_seq OWNER TO postgres; + +-- +-- TOC entry 6979 (class 0 OID 0) +-- Dependencies: 324 +-- Name: geofences_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.geofences_id_seq OWNED BY tracksolid.geofences.id; + + +-- +-- TOC entry 317 (class 1259 OID 25140) +-- Name: heartbeats; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.heartbeats ( + imei text NOT NULL, + gate_time timestamp with time zone NOT NULL, + power_level smallint, + gsm_signal smallint, + acc_status smallint, + power_status smallint, + fortify smallint, + created_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.heartbeats OWNER TO postgres; + +-- +-- TOC entry 294 (class 1259 OID 24874) +-- Name: ingestion_log; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.ingestion_log ( + id bigint NOT NULL, + run_at timestamp with time zone DEFAULT now() NOT NULL, + endpoint text NOT NULL, + imei_count integer DEFAULT 0 NOT NULL, + rows_upserted integer DEFAULT 0 NOT NULL, + rows_inserted integer DEFAULT 0 NOT NULL, + duration_ms integer DEFAULT 0 NOT NULL, + success boolean DEFAULT true NOT NULL, + error_code text, + error_message text +); + + +ALTER TABLE tracksolid.ingestion_log OWNER TO postgres; + +-- +-- TOC entry 293 (class 1259 OID 24873) +-- Name: ingestion_log_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.ingestion_log_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.ingestion_log_id_seq OWNER TO postgres; + +-- +-- TOC entry 6982 (class 0 OID 0) +-- Dependencies: 293 +-- Name: ingestion_log_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.ingestion_log_id_seq OWNED BY tracksolid.ingestion_log.id; + + +-- +-- TOC entry 323 (class 1259 OID 25207) +-- Name: lbs_readings; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.lbs_readings ( + id bigint NOT NULL, + imei text NOT NULL, + gate_time timestamp with time zone NOT NULL, + post_type text, + lbs_data jsonb, + created_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.lbs_readings OWNER TO postgres; + +-- +-- TOC entry 6984 (class 0 OID 0) +-- Dependencies: 323 +-- Name: TABLE lbs_readings; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON TABLE tracksolid.lbs_readings IS 'Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.'; + + +-- +-- TOC entry 6985 (class 0 OID 0) +-- Dependencies: 323 +-- Name: COLUMN lbs_readings.post_type; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.lbs_readings.post_type IS 'Positioning technology: WIFI | LBS (cell tower)'; + + +-- +-- TOC entry 6986 (class 0 OID 0) +-- Dependencies: 323 +-- Name: COLUMN lbs_readings.lbs_data; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.lbs_readings.lbs_data IS 'Raw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding.'; + + +-- +-- TOC entry 322 (class 1259 OID 25206) +-- Name: lbs_readings_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.lbs_readings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.lbs_readings_id_seq OWNER TO postgres; + +-- +-- TOC entry 6988 (class 0 OID 0) +-- Dependencies: 322 +-- Name: lbs_readings_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.lbs_readings_id_seq OWNED BY tracksolid.lbs_readings.id; + + +-- +-- TOC entry 295 (class 1259 OID 24890) +-- Name: live_positions; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.live_positions ( + imei text NOT NULL, + geom public.geometry(Point,4326), + lat double precision, + lng double precision, + pos_type text, + confidence smallint, + gps_time timestamp with time zone, + hb_time timestamp with time zone, + speed numeric(7,2), + direction numeric(6,2), + acc_status text, + gps_signal smallint, + gps_num smallint, + elec_quantity numeric(5,2), + power_value numeric(5,2), + battery_power_val numeric(5,2), + tracker_oil text, + temperature numeric(8,2), + current_mileage numeric(12,2), + device_status text, + expire_flag text, + activation_flag text, + loc_desc text, + recorded_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.live_positions OWNER TO postgres; + +-- +-- TOC entry 304 (class 1259 OID 24988) +-- Name: obd_readings; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.obd_readings ( + id bigint NOT NULL, + imei text, + reading_time timestamp with time zone, + engine_rpm integer, + fuel_level_pct numeric(5,2), + updated_at timestamp with time zone DEFAULT now(), + car_type smallint, + acc_state smallint, + status_flags integer, + lat double precision, + lng double precision, + geom public.geometry(Point,4326), + obd_data jsonb, + coolant_temp_c numeric(6,2), + battery_voltage numeric(5,2), + intake_pressure numeric(6,2), + throttle_pct numeric(5,2), + vehicle_speed numeric(7,2), + engine_load_pct numeric(5,2) +); + + +ALTER TABLE tracksolid.obd_readings OWNER TO postgres; + +-- +-- TOC entry 6990 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.engine_rpm; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.engine_rpm IS 'Engine RPM from OBD PID 0x0C'; + + +-- +-- TOC entry 6991 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.fuel_level_pct; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.fuel_level_pct IS 'Fuel tank level % from OBD PID 0x2F'; + + +-- +-- TOC entry 6992 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.obd_data; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.obd_data IS 'Raw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.)'; + + +-- +-- TOC entry 6993 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.coolant_temp_c; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.coolant_temp_c IS 'Coolant temperature °C from OBD PID 0x05'; + + +-- +-- TOC entry 6994 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.battery_voltage; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.battery_voltage IS 'Battery voltage (V) from OBD PID 0x42'; + + +-- +-- TOC entry 6995 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.intake_pressure; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.intake_pressure IS 'Intake manifold pressure kPa from OBD PID 0x0B'; + + +-- +-- TOC entry 6996 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.throttle_pct; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.throttle_pct IS 'Throttle position % from OBD PID 0x11'; + + +-- +-- TOC entry 6997 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.vehicle_speed; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.vehicle_speed IS 'Vehicle speed km/h from OBD PID 0x0D'; + + +-- +-- TOC entry 6998 (class 0 OID 0) +-- Dependencies: 304 +-- Name: COLUMN obd_readings.engine_load_pct; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON COLUMN tracksolid.obd_readings.engine_load_pct IS 'Calculated engine load % from OBD PID 0x04'; + + +-- +-- TOC entry 303 (class 1259 OID 24987) +-- Name: obd_readings_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.obd_readings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.obd_readings_id_seq OWNER TO postgres; + +-- +-- TOC entry 7000 (class 0 OID 0) +-- Dependencies: 303 +-- Name: obd_readings_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.obd_readings_id_seq OWNED BY tracksolid.obd_readings.id; + + +-- +-- TOC entry 300 (class 1259 OID 24949) +-- Name: parking_events; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.parking_events ( + id bigint NOT NULL, + imei text NOT NULL, + event_type text, + start_time timestamp with time zone NOT NULL, + end_time timestamp with time zone, + duration_seconds integer, + geom public.geometry(Point,4326), + address text, + updated_at timestamp with time zone DEFAULT now(), + CONSTRAINT parking_events_event_type_check CHECK ((event_type = ANY (ARRAY['parking'::text, 'idling'::text]))) +); + + +ALTER TABLE tracksolid.parking_events OWNER TO postgres; + +-- +-- TOC entry 299 (class 1259 OID 24948) +-- Name: parking_events_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.parking_events_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.parking_events_id_seq OWNER TO postgres; + +-- +-- TOC entry 7003 (class 0 OID 0) +-- Dependencies: 299 +-- Name: parking_events_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.parking_events_id_seq OWNED BY tracksolid.parking_events.id; + + +-- +-- TOC entry 284 (class 1259 OID 22994) +-- Name: schema_migrations; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.schema_migrations ( + filename text NOT NULL, + applied_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.schema_migrations OWNER TO postgres; + +-- +-- TOC entry 321 (class 1259 OID 25191) +-- Name: temperature_readings; Type: TABLE; Schema: tracksolid; Owner: postgres +-- + +CREATE TABLE tracksolid.temperature_readings ( + imei text NOT NULL, + reading_time timestamp with time zone NOT NULL, + temperature numeric(6,2), + humidity_pct numeric(5,2), + created_at timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE tracksolid.temperature_readings OWNER TO postgres; + +-- +-- TOC entry 7006 (class 0 OID 0) +-- Dependencies: 321 +-- Name: TABLE temperature_readings; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON TABLE tracksolid.temperature_readings IS 'Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.'; + + +-- +-- TOC entry 297 (class 1259 OID 24929) +-- Name: trips_id_seq; Type: SEQUENCE; Schema: tracksolid; Owner: postgres +-- + +CREATE SEQUENCE tracksolid.trips_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE tracksolid.trips_id_seq OWNER TO postgres; + +-- +-- TOC entry 7008 (class 0 OID 0) +-- Dependencies: 297 +-- Name: trips_id_seq; Type: SEQUENCE OWNED BY; Schema: tracksolid; Owner: postgres +-- + +ALTER SEQUENCE tracksolid.trips_id_seq OWNED BY tracksolid.trips.id; + + +-- +-- TOC entry 336 (class 1259 OID 25326) +-- Name: v_active_dispatch_map; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_active_dispatch_map AS + SELECT d.imei, + d.vehicle_number, + d.vehicle_name, + d.driver_name, + d.driver_phone, + COALESCE(d.assigned_city, d.city, 'unassigned'::text) AS assigned_city, + lp.lat, + lp.lng, + lp.speed, + lp.direction, + lp.acc_status, + (lp.gps_time AT TIME ZONE 'Africa/Nairobi'::text) AS last_fix, + CASE + WHEN (lp.gps_time IS NULL) THEN 'never_reported'::text + WHEN (lp.gps_time < (now() - '00:10:00'::interval)) THEN 'stale'::text + WHEN (COALESCE(lp.speed, (0)::numeric) > (5)::numeric) THEN 'moving'::text + WHEN (lp.acc_status = '1'::text) THEN 'idle_ignition_on'::text + ELSE 'parked'::text + END AS status + FROM (tracksolid.devices d + LEFT JOIN tracksolid.live_positions lp ON ((lp.imei = d.imei))) + WHERE (d.enabled_flag = 1); + + +ALTER VIEW tracksolid.v_active_dispatch_map OWNER TO postgres; + +-- +-- TOC entry 7010 (class 0 OID 0) +-- Dependencies: 336 +-- Name: VIEW v_active_dispatch_map; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_active_dispatch_map IS '01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.'; + + +-- +-- TOC entry 340 (class 1259 OID 25346) +-- Name: v_alarms_daily; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_alarms_daily AS + SELECT ((alarm_time AT TIME ZONE 'Africa/Nairobi'::text))::date AS day, + COALESCE(alarm_name, alarm_type, 'unknown'::text) AS alarm_name, + count(*) AS alarm_count + FROM tracksolid.alarms + WHERE (alarm_time > (now() - '90 days'::interval)) + GROUP BY (((alarm_time AT TIME ZONE 'Africa/Nairobi'::text))::date), COALESCE(alarm_name, alarm_type, 'unknown'::text); + + +ALTER VIEW tracksolid.v_alarms_daily OWNER TO postgres; + +-- +-- TOC entry 7012 (class 0 OID 0) +-- Dependencies: 340 +-- Name: VIEW v_alarms_daily; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_alarms_daily IS '01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.'; + + +-- +-- TOC entry 337 (class 1259 OID 25331) +-- Name: v_currently_idle; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_currently_idle AS + SELECT d.imei, + d.vehicle_number, + d.driver_name, + COALESCE(d.assigned_city, d.city, 'unassigned'::text) AS assigned_city, + lp.lat, + lp.lng, + (lp.gps_time AT TIME ZONE 'Africa/Nairobi'::text) AS since, + (EXTRACT(epoch FROM (now() - lp.gps_time)))::integer AS idle_seconds + FROM (tracksolid.devices d + JOIN tracksolid.live_positions lp ON ((lp.imei = d.imei))) + WHERE ((d.enabled_flag = 1) AND (lp.acc_status = '1'::text) AND (COALESCE(lp.speed, (0)::numeric) < (2)::numeric) AND (lp.gps_time > (now() - '00:15:00'::interval))); + + +ALTER VIEW tracksolid.v_currently_idle OWNER TO postgres; + +-- +-- TOC entry 7014 (class 0 OID 0) +-- Dependencies: 337 +-- Name: VIEW v_currently_idle; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_currently_idle IS '01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.'; + + +-- +-- TOC entry 338 (class 1259 OID 25336) +-- Name: v_driver_aggregates_daily; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_driver_aggregates_daily AS + WITH trips_agg AS ( + SELECT trips.imei, + ((trips.start_time AT TIME ZONE 'Africa/Nairobi'::text))::date AS day, + sum(trips.distance_km) AS km, + count(*) AS trips + FROM tracksolid.trips + WHERE (trips.start_time > (now() - '31 days'::interval)) + GROUP BY trips.imei, (((trips.start_time AT TIME ZONE 'Africa/Nairobi'::text))::date) + ), speeding AS ( + SELECT position_history.imei, + ((position_history.gps_time AT TIME ZONE 'Africa/Nairobi'::text))::date AS day, + count(*) FILTER (WHERE (position_history.speed > (80)::numeric)) AS events_80, + count(*) FILTER (WHERE (position_history.speed > (100)::numeric)) AS events_100, + count(*) FILTER (WHERE (position_history.speed > (120)::numeric)) AS events_120 + FROM tracksolid.position_history + WHERE ((position_history.gps_time > (now() - '31 days'::interval)) AND (position_history.speed IS NOT NULL)) + GROUP BY position_history.imei, (((position_history.gps_time AT TIME ZONE 'Africa/Nairobi'::text))::date) + ), harsh_raw AS ( + SELECT position_history.imei, + position_history.gps_time, + position_history.speed, + lag(position_history.speed) OVER (PARTITION BY position_history.imei ORDER BY position_history.gps_time) AS prev_speed, + lag(position_history.gps_time) OVER (PARTITION BY position_history.imei ORDER BY position_history.gps_time) AS prev_time + FROM tracksolid.position_history + WHERE ((position_history.source = 'track_list'::text) AND (position_history.gps_time > (now() - '31 days'::interval))) + ), harsh AS ( + SELECT harsh_raw.imei, + ((harsh_raw.gps_time AT TIME ZONE 'Africa/Nairobi'::text))::date AS day, + count(*) AS harsh_events + FROM harsh_raw + WHERE ((abs((harsh_raw.speed - harsh_raw.prev_speed)) > (30)::numeric) AND ((EXTRACT(epoch FROM (harsh_raw.gps_time - harsh_raw.prev_time)) >= (5)::numeric) AND (EXTRACT(epoch FROM (harsh_raw.gps_time - harsh_raw.prev_time)) <= (60)::numeric))) + GROUP BY harsh_raw.imei, (((harsh_raw.gps_time AT TIME ZONE 'Africa/Nairobi'::text))::date) + ) + SELECT d.imei, + d.driver_name, + d.vehicle_number, + COALESCE(d.assigned_city, d.city, 'unassigned'::text) AS assigned_city, + t.day, + COALESCE(t.km, (0)::numeric) AS km, + COALESCE(t.trips, (0)::bigint) AS trips, + COALESCE(s.events_80, (0)::bigint) AS events_80, + COALESCE(s.events_100, (0)::bigint) AS events_100, + COALESCE(s.events_120, (0)::bigint) AS events_120, + COALESCE(h.harsh_events, (0)::bigint) AS harsh_events, + round((((COALESCE(s.events_80, (0)::bigint))::numeric / NULLIF(t.km, (0)::numeric)) * (100)::numeric), 2) AS speeding_per_100km, + round((((COALESCE(h.harsh_events, (0)::bigint))::numeric / NULLIF(t.km, (0)::numeric)) * (100)::numeric), 2) AS harsh_per_100km + FROM (((trips_agg t + JOIN tracksolid.devices d ON ((d.imei = t.imei))) + LEFT JOIN speeding s ON (((s.imei = t.imei) AND (s.day = t.day)))) + LEFT JOIN harsh h ON (((h.imei = t.imei) AND (h.day = t.day)))); + + +ALTER VIEW tracksolid.v_driver_aggregates_daily OWNER TO postgres; + +-- +-- TOC entry 7016 (class 0 OID 0) +-- Dependencies: 338 +-- Name: VIEW v_driver_aggregates_daily; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_driver_aggregates_daily IS '01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).'; + + +-- +-- TOC entry 339 (class 1259 OID 25341) +-- Name: v_fleet_km_daily; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_fleet_km_daily AS + SELECT ((t.start_time AT TIME ZONE 'Africa/Nairobi'::text))::date AS day, + COALESCE(d.assigned_city, d.city, 'unassigned'::text) AS assigned_city, + sum(t.distance_km) AS km, + count(DISTINCT t.imei) AS active_vehicles, + count(*) AS trips + FROM (tracksolid.trips t + JOIN tracksolid.devices d ON ((d.imei = t.imei))) + WHERE (t.start_time > (now() - '90 days'::interval)) + GROUP BY (((t.start_time AT TIME ZONE 'Africa/Nairobi'::text))::date), COALESCE(d.assigned_city, d.city, 'unassigned'::text); + + +ALTER VIEW tracksolid.v_fleet_km_daily OWNER TO postgres; + +-- +-- TOC entry 7018 (class 0 OID 0) +-- Dependencies: 339 +-- Name: VIEW v_fleet_km_daily; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_fleet_km_daily IS '01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.'; + + +-- +-- TOC entry 309 (class 1259 OID 25051) +-- Name: v_fleet_status; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_fleet_status AS + SELECT d.imei, + d.vehicle_number, + d.driver_name, + lp.lat, + lp.lng, + lp.geom, + lp.speed, + lp.acc_status, + lp.gps_time, + CASE + WHEN (lp.gps_time >= (now() - '00:05:00'::interval)) THEN 'online'::text + WHEN (lp.gps_time >= (now() - '00:30:00'::interval)) THEN 'recent'::text + ELSE 'offline'::text + END AS connectivity_status, + (EXTRACT(epoch FROM (now() - lp.gps_time)))::integer AS seconds_since_fix + FROM (tracksolid.devices d + LEFT JOIN tracksolid.live_positions lp USING (imei)) + WHERE (d.enabled_flag = 1); + + +ALTER VIEW tracksolid.v_fleet_status OWNER TO postgres; + +-- +-- TOC entry 334 (class 1259 OID 25316) +-- Name: v_fleet_today; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_fleet_today AS + WITH today AS ( + SELECT ((now() AT TIME ZONE 'Africa/Nairobi'::text))::date AS d + ), trips_today AS ( + SELECT t.imei, + count(*) AS trips, + sum(t.distance_km) AS km, + ((sum(t.driving_time_s))::numeric / (3600)::numeric) AS drive_hours, + ((sum(t.idle_time_s))::numeric / (3600)::numeric) AS idle_hours, + (min((t.start_time AT TIME ZONE 'Africa/Nairobi'::text)))::time without time zone AS first_departure, + (max((COALESCE(t.end_time, t.start_time) AT TIME ZONE 'Africa/Nairobi'::text)))::time without time zone AS last_return + FROM (tracksolid.trips t + CROSS JOIN today) + WHERE (((t.start_time AT TIME ZONE 'Africa/Nairobi'::text))::date = today.d) + GROUP BY t.imei + ), alarms_today AS ( + SELECT a.imei, + count(*) AS alarm_count + FROM (tracksolid.alarms a + CROSS JOIN today) + WHERE (((a.alarm_time AT TIME ZONE 'Africa/Nairobi'::text))::date = today.d) + GROUP BY a.imei + ) + SELECT d.imei, + d.driver_name, + d.vehicle_number, + d.vehicle_name, + COALESCE(d.assigned_city, d.city, 'unassigned'::text) AS assigned_city, + d.enabled_flag, + COALESCE(tt.km, (0)::numeric) AS km_today, + COALESCE(tt.trips, (0)::bigint) AS trips_today, + COALESCE(tt.drive_hours, (0)::numeric) AS drive_hours, + COALESCE(tt.idle_hours, (0)::numeric) AS idle_hours, + tt.first_departure, + tt.last_return, + COALESCE(at.alarm_count, (0)::bigint) AS alarms_today, + (lp.gps_time AT TIME ZONE 'Africa/Nairobi'::text) AS last_fix, + lp.speed AS last_speed, + (tt.imei IS NULL) AS did_not_move + FROM (((tracksolid.devices d + LEFT JOIN trips_today tt ON ((tt.imei = d.imei))) + LEFT JOIN alarms_today at ON ((at.imei = d.imei))) + LEFT JOIN tracksolid.live_positions lp ON ((lp.imei = d.imei))); + + +ALTER VIEW tracksolid.v_fleet_today OWNER TO postgres; + +-- +-- TOC entry 7021 (class 0 OID 0) +-- Dependencies: 334 +-- Name: VIEW v_fleet_today; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_fleet_today IS '01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today''s roll-up.'; + + +-- +-- TOC entry 310 (class 1259 OID 25059) +-- Name: v_ingestion_health; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_ingestion_health AS + SELECT DISTINCT ON (endpoint) endpoint, + run_at, + success, + error_message, + (EXTRACT(epoch FROM (now() - run_at)))::integer AS seconds_ago + FROM tracksolid.ingestion_log + ORDER BY endpoint, run_at DESC; + + +ALTER VIEW tracksolid.v_ingestion_health OWNER TO postgres; + +-- +-- TOC entry 312 (class 1259 OID 25086) +-- Name: v_mileage_daily_cagg; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_mileage_daily_cagg AS + SELECT bucket, + imei, + dist_km, + avg_speed + FROM _timescaledb_internal._materialized_hypertable_3; + + +ALTER VIEW tracksolid.v_mileage_daily_cagg OWNER TO postgres; + +-- +-- TOC entry 342 (class 1259 OID 25355) +-- Name: v_sla_inflight; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_sla_inflight AS + SELECT t.ticket_id, + t.customer, + t.priority, + t.job_type, + t.status, + t.created_at, + t.assigned_at, + t.closed_at, + t.assigned_imei, + COALESCE(dl.driver_name, t.driver_name) AS driver_name, + dl.first_movement_at, + dl.on_site_at, + dl.resolved_at, + (EXTRACT(epoch FROM (COALESCE(dl.first_movement_at, now()) - t.assigned_at)) / (60)::numeric) AS dispatch_mins, + (EXTRACT(epoch FROM (COALESCE(dl.on_site_at, now()) - dl.first_movement_at)) / (60)::numeric) AS enroute_mins, + (EXTRACT(epoch FROM (COALESCE(dl.resolved_at, now()) - dl.on_site_at)) / (60)::numeric) AS onsite_mins, + (EXTRACT(epoch FROM (COALESCE(dl.resolved_at, now()) - t.created_at)) / (60)::numeric) AS resolution_mins, + CASE + WHEN (dl.resolved_at IS NOT NULL) THEN 'resolved'::text + WHEN (dl.cancelled_at IS NOT NULL) THEN 'cancelled'::text + WHEN (dl.on_site_at IS NOT NULL) THEN 'on_site'::text + WHEN (dl.first_movement_at IS NOT NULL) THEN 'en_route'::text + WHEN (t.assigned_at IS NOT NULL) THEN 'dispatched'::text + ELSE 'open'::text + END AS ticket_stage + FROM (ops.tickets t + LEFT JOIN tracksolid.dispatch_log dl ON ((dl.ticket_id = t.ticket_id))) + WHERE ((t.status <> ALL (ARRAY['resolved'::text, 'cancelled'::text])) OR (t.closed_at > (now() - '24:00:00'::interval))); + + +ALTER VIEW tracksolid.v_sla_inflight OWNER TO postgres; + +-- +-- TOC entry 7025 (class 0 OID 0) +-- Dependencies: 342 +-- Name: VIEW v_sla_inflight; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_sla_inflight IS '01_BusinessAnalytics.md §4.5 Field-Service SLA Metrics. Open tickets + last 24h resolved.'; + + +-- +-- TOC entry 341 (class 1259 OID 25350) +-- Name: v_utilisation_daily; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_utilisation_daily AS + SELECT f.day, + d.imei, + d.vehicle_number, + d.driver_name, + COALESCE(d.assigned_city, d.city, 'unassigned'::text) AS assigned_city, + f.total_distance_km, + f.total_drive_hours, + f.total_idle_hours, + f.alarm_count, + f.overspeed_count, + round(((f.total_drive_hours / NULLIF((f.total_drive_hours + f.total_idle_hours), (0)::numeric)) * (100)::numeric), 1) AS utilisation_pct + FROM ((dwh_gold.fact_daily_fleet_metrics f + JOIN dwh_gold.dim_vehicles dv ON ((dv.vehicle_key = f.vehicle_key))) + JOIN tracksolid.devices d ON ((d.imei = dv.imei))); + + +ALTER VIEW tracksolid.v_utilisation_daily OWNER TO postgres; + +-- +-- TOC entry 7027 (class 0 OID 0) +-- Dependencies: 341 +-- Name: VIEW v_utilisation_daily; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_utilisation_daily IS '01_BusinessAnalytics.md §7 Panel 8 Utilisation Heatmap. Empty until nightly ETL runs.'; + + +-- +-- TOC entry 335 (class 1259 OID 25321) +-- Name: v_vehicles_not_moved_today; Type: VIEW; Schema: tracksolid; Owner: postgres +-- + +CREATE VIEW tracksolid.v_vehicles_not_moved_today AS + SELECT d.imei, + d.vehicle_name, + d.vehicle_number, + d.driver_name, + COALESCE(d.assigned_city, d.city, 'unassigned'::text) AS assigned_city, + (lp.gps_time AT TIME ZONE 'Africa/Nairobi'::text) AS last_seen, + lp.speed + FROM ((tracksolid.devices d + LEFT JOIN tracksolid.live_positions lp ON ((lp.imei = d.imei))) + LEFT JOIN tracksolid.trips t ON (((t.imei = d.imei) AND (((t.start_time AT TIME ZONE 'Africa/Nairobi'::text))::date = ((now() AT TIME ZONE 'Africa/Nairobi'::text))::date)))) + WHERE ((d.enabled_flag = 1) AND (t.imei IS NULL)); + + +ALTER VIEW tracksolid.v_vehicles_not_moved_today OWNER TO postgres; + +-- +-- TOC entry 7029 (class 0 OID 0) +-- Dependencies: 335 +-- Name: VIEW v_vehicles_not_moved_today; Type: COMMENT; Schema: tracksolid; Owner: postgres +-- + +COMMENT ON VIEW tracksolid.v_vehicles_not_moved_today IS '01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.'; + + +-- +-- TOC entry 6607 (class 2604 OID 24972) +-- Name: alarms id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.alarms ALTER COLUMN id SET DEFAULT nextval('tracksolid.alarms_id_seq'::regclass); + + +-- +-- TOC entry 6588 (class 2604 OID 24862) +-- Name: api_token_cache id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.api_token_cache ALTER COLUMN id SET DEFAULT nextval('tracksolid.api_token_cache_id_seq'::regclass); + + +-- +-- TOC entry 6615 (class 2604 OID 25162) +-- Name: device_events id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.device_events ALTER COLUMN id SET DEFAULT nextval('tracksolid.device_events_id_seq'::regclass); + + +-- +-- TOC entry 6624 (class 2604 OID 25243) +-- Name: dispatch_log dispatch_id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.dispatch_log ALTER COLUMN dispatch_id SET DEFAULT nextval('tracksolid.dispatch_log_dispatch_id_seq'::regclass); + + +-- +-- TOC entry 6612 (class 2604 OID 25125) +-- Name: fault_codes id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.fault_codes ALTER COLUMN id SET DEFAULT nextval('tracksolid.fault_codes_id_seq'::regclass); + + +-- +-- TOC entry 6621 (class 2604 OID 25228) +-- Name: geofences id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.geofences ALTER COLUMN id SET DEFAULT nextval('tracksolid.geofences_id_seq'::regclass); + + +-- +-- TOC entry 6591 (class 2604 OID 24877) +-- Name: ingestion_log id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.ingestion_log ALTER COLUMN id SET DEFAULT nextval('tracksolid.ingestion_log_id_seq'::regclass); + + +-- +-- TOC entry 6619 (class 2604 OID 25210) +-- Name: lbs_readings id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.lbs_readings ALTER COLUMN id SET DEFAULT nextval('tracksolid.lbs_readings_id_seq'::regclass); + + +-- +-- TOC entry 6610 (class 2604 OID 24991) +-- Name: obd_readings id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.obd_readings ALTER COLUMN id SET DEFAULT nextval('tracksolid.obd_readings_id_seq'::regclass); + + +-- +-- TOC entry 6605 (class 2604 OID 24952) +-- Name: parking_events id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.parking_events ALTER COLUMN id SET DEFAULT nextval('tracksolid.parking_events_id_seq'::regclass); + + +-- +-- TOC entry 6602 (class 2604 OID 24933) +-- Name: trips id; Type: DEFAULT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.trips ALTER COLUMN id SET DEFAULT nextval('tracksolid.trips_id_seq'::regclass); + + +-- +-- TOC entry 6910 (class 0 OID 24969) +-- Dependencies: 302 +-- Data for Name: alarms; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.alarms (id, imei, alarm_type, alarm_time, geom, lat, lng, speed, acc_status, updated_at, alarm_name, source, severity, geofence_id, geofence_name, acknowledged_at, acknowledged_by) FROM stdin; +1 359857082038977 1001 2026-04-23 10:24:33+00 0101000020E61000007E74EACA67D94340BABDA4315A2710C0 -4.03843 39.69848 \N \N 2026-04-23 10:24:33.914628+00 ACC OFF push \N \N \N \N \N +2 865135061035653 1001 2026-04-23 10:24:49+00 0101000020E6100000AE2AFBAE08DE4340CB2C42B115940FC0 -3.947307 39.73464 \N \N 2026-04-23 10:24:50.340401+00 ACC OFF push \N \N \N \N \N +3 359857081885410 stayAlertOn 2026-04-23 10:24:51+00 0101000020E61000001F680586AC72424042959A3DD00AF3BF -1.19014 36.89589 \N \N 2026-04-23 10:24:51.841909+00 Idling alert push \N \N \N \N \N +4 862798052708068 1001 2026-04-23 10:25:14+00 0101000020E61000004B02D4D4B2534240730E9E094DD2F1BF -1.113843 36.653895 \N \N 2026-04-23 10:25:15.719559+00 ACC OFF push \N \N \N \N \N +5 865135061054555 1002 2026-04-23 10:25:20+00 0101000020E6100000C685032159304240054EB6813B50D1BF -0.270522 36.37772 \N \N 2026-04-23 10:25:21.085437+00 ACC ON push \N \N \N \N \N +6 862798050523527 128 2026-04-23 10:25:22+00 0101000020E61000007A89B14CBF724240A01B9AB2D30FF3BF -1.191364 36.896463 12.00 \N 2026-04-23 10:25:24.360765+00 DVR vibration alert push \N \N \N \N \N +7 862798052707946 1001 2026-04-23 10:25:23+00 0101000020E6100000322251685971424041102043C78EF2BF -1.159858 36.885541 \N \N 2026-04-23 10:25:24.363965+00 ACC OFF push \N \N \N \N \N +8 865135061562722 3 2026-04-23 10:25:14+00 0101000020E61000002B6C06B8206942407F4FAC53E57BF2BF -1.155248 36.821311 \N \N 2026-04-23 10:25:38.887433+00 Vibration alert push \N \N \N \N \N +9 865135061563597 1001 2026-04-23 10:25:39+00 0101000020E6100000AD8905BEA253424039D1AE42CACFF1BF -1.11323 36.653404 \N \N 2026-04-23 10:25:40.125927+00 ACC OFF push \N \N \N \N \N +10 862798050288360 146 2026-04-23 10:25:33+00 0101000020E6100000812381069B72424008ABB184B571F2BF -1.152761 36.895356 55.00 \N 2026-04-23 10:25:46.478217+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +11 359857082918012 1002 2026-04-23 10:25:52+00 0101000020E6100000A54E4013616B4240ADDD76A1B94EF3BF -1.20672 36.8389 \N \N 2026-04-23 10:25:52.843474+00 ACC ON push \N \N \N \N \N +12 359857082896911 stayAlertOn 2026-04-23 10:26:09+00 0101000020E61000004F232D95B76B4240DD0C37E0F3C3F2BF -1.17284 36.84154 \N \N 2026-04-23 10:26:09.922447+00 Idling alert push \N \N \N \N \N +13 862798052708068 1004 2026-04-23 10:26:14+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 \N \N 2026-04-23 10:26:14.341837+00 Parking alert push \N \N \N \N \N +14 862798050523014 128 2026-04-23 10:26:15+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 10:26:17.747928+00 DVR vibration alert push \N \N \N \N \N +15 865135061054548 1001 2026-04-23 10:26:24+00 0101000020E61000003EEC8502B671424082A8FB00A4F6F2BF -1.185215 36.888367 \N \N 2026-04-23 10:26:24.667167+00 ACC OFF push \N \N \N \N \N +16 359857082918012 1001 2026-04-23 10:26:42+00 0101000020E61000000FD1E80E626B42409626A5A0DB4BF3BF -1.20602 36.83893 \N \N 2026-04-23 10:26:43.604438+00 ACC OFF push \N \N \N \N \N +17 865135061563597 3 2026-04-23 10:26:43+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 10:26:44.355226+00 Vibration alert push \N \N \N \N \N +18 359857082907973 1001 2026-04-23 10:26:47+00 0101000020E610000050C24CDBBFD24340C18BBE82342310C0 -4.03438 39.64648 \N \N 2026-04-23 10:26:48.220151+00 ACC OFF push \N \N \N \N \N +19 865135061569123 3 2026-04-23 10:27:05+00 0101000020E6100000C3D66CE5255F4240F12E17F19DD8F4BF -1.302885 36.743344 \N \N 2026-04-23 10:27:07.548485+00 Vibration alert push \N \N \N \N \N +20 862798050523337 128 2026-04-23 10:27:11+00 0101000020E6100000670DDE57E5D44340B3075A81213B10C0 -4.057745 39.663249 0.00 \N 2026-04-23 10:27:13.522675+00 DVR vibration alert push \N \N \N \N \N +21 359857081891632 1001 2026-04-23 10:27:26+00 0101000020E61000008121AB5B3D6F424086200725CCB4F3BF -1.23164 36.86906 \N \N 2026-04-23 10:27:27.796815+00 ACC OFF push \N \N \N \N \N +22 359857082897257 1001 2026-04-23 10:28:25+00 0101000020E610000001F6D1A92B774240BCAE5FB01BB6F3BF -1.23196 36.93102 \N \N 2026-04-23 10:28:26.388654+00 ACC OFF push \N \N \N \N \N +23 359857082907973 1002 2026-04-23 10:28:32+00 0101000020E610000050C24CDBBFD24340C18BBE82342310C0 -4.03438 39.64648 \N \N 2026-04-23 10:28:33.146047+00 ACC ON push \N \N \N \N \N +24 862798050521521 146 2026-04-23 10:28:32+00 0101000020E6100000FAB5F5D37F70424032022A1C412AF4BF -1.260316 36.878901 67.00 \N 2026-04-23 10:28:34.917147+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +25 359857081891632 1004 2026-04-23 10:28:36+00 0101000020E61000008121AB5B3D6F424086200725CCB4F3BF -1.23164 36.86906 \N \N 2026-04-23 10:28:36.286951+00 Parking alert push \N \N \N \N \N +26 865135061564470 1002 2026-04-23 10:28:44+00 0101000020E6100000F7CDFDD5E3704240821ABE8575E3F2BF -1.180532 36.881953 \N \N 2026-04-23 10:28:44.949511+00 ACC ON push \N \N \N \N \N +27 865135061564470 ACC_ON 2026-04-23 10:28:44+00 0101000020E6100000F7CDFDD5E3704240821ABE8575E3F2BF -1.180532 36.881953 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +29 862798052708068 stayAlert 2026-04-23 10:26:14+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +30 862798052708068 ACC_OFF 2026-04-23 10:25:14+00 0101000020E61000004B02D4D4B2534240730E9E094DD2F1BF -1.113843 36.653895 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +31 862798052708068 ACC_ON 2026-04-23 10:24:04+00 0101000020E610000011FE45D0985342407214200A66CCF1BF -1.112402 36.653101 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +32 862798052708068 stayAlert 2026-04-23 10:20:49+00 0101000020E610000011FE45D0985342407214200A66CCF1BF -1.112402 36.653101 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +33 865135061563282 ACC_OFF 2026-04-23 10:20:00+00 0101000020E6100000620FED630545404099654F029B73C83F 0.191028 32.539227 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +34 862798052708068 ACC_OFF 2026-04-23 10:19:51+00 0101000020E6100000DA54DD239B5342400168942EFDCBF1BF -1.112302 36.653172 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +35 862798052708068 ACC_ON 2026-04-23 10:16:41+00 0101000020E61000001536035C90534240B7F0BC546CCCF1BF -1.112408 36.652843 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +36 862798052708068 136 2026-04-23 10:16:42+00 0101000020E61000001536035C90534240B7F0BC546CCCF1BF -1.112408 36.652843 0.00 \N 2026-04-23 10:28:55.624014+00 Power off alert(DVR) poll \N \N \N \N \N +37 865135061564470 3 2026-04-23 10:16:08+00 0101000020E6100000F7CDFDD5E3704240821ABE8575E3F2BF -1.180532 36.881953 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +38 865135061569123 3 2026-04-23 10:15:16+00 0101000020E6100000C3D66CE5255F4240F12E17F19DD8F4BF -1.302885 36.743344 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +39 865135061563282 ACC_ON 2026-04-23 10:12:09+00 0101000020E61000001A355F251F454040C712D6C6D809C93F 0.195613 32.540013 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +40 865135061053748 ACC_ON 2026-04-23 10:11:14+00 0101000020E6100000821ABE8575D54340A7EB89AE0B2F10C0 -4.045943 39.667649 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +41 865135061569123 3 2026-04-23 10:09:41+00 0101000020E6100000C3D66CE5255F4240F12E17F19DD8F4BF -1.302885 36.743344 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +42 865135061053748 stayAlert 2026-04-23 10:09:32+00 0101000020E6100000821ABE8575D54340A7EB89AE0B2F10C0 -4.045943 39.667649 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +43 865135061564470 3 2026-04-23 10:09:25+00 0101000020E6100000F7CDFDD5E3704240821ABE8575E3F2BF -1.180532 36.881953 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +44 865135061053748 ACC_ON 2026-04-23 10:08:33+00 0101000020E6100000A5BC564277D54340B29FC552242F10C0 -4.046037 39.667702 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +45 865135061053748 ACC_OFF 2026-04-23 10:08:32+00 0101000020E6100000A5BC564277D54340B29FC552242F10C0 -4.046037 39.667702 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +46 865135061564470 3 2026-04-23 10:07:15+00 0101000020E6100000F7CDFDD5E3704240821ABE8575E3F2BF -1.180532 36.881953 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +47 865135061563282 3 2026-04-23 10:07:13+00 0101000020E61000001A355F251F454040C712D6C6D809C93F 0.195613 32.540013 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +48 865135061569131 offline 2026-04-23 10:05:22+00 0101000020E6100000C0AF91240845404054E3A59BC420C83F 0.1885 32.539311 0.00 \N 2026-04-23 10:28:55.624014+00 Offline alert poll \N \N \N \N \N +49 865135061037980 stayAlert 2026-04-23 10:04:05+00 0101000020E61000005A2BDA1CE77A4240109370218F60F2BF -1.148574 36.960178 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +50 865135061037980 ACC_OFF 2026-04-23 10:03:05+00 0101000020E6100000DE8E705AF07A424017BA1281EA5FF2BF -1.148417 36.96046 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +51 865135061569123 3 2026-04-23 10:02:53+00 0101000020E6100000C3D66CE5255F4240F12E17F19DD8F4BF -1.302885 36.743344 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +52 865135061564470 3 2026-04-23 10:02:08+00 0101000020E6100000F7CDFDD5E3704240821ABE8575E3F2BF -1.180532 36.881953 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +53 865135061581904 ACC_ON 2026-04-23 10:02:02+00 0101000020E61000000E30F31DFC664240F8C610001C3BF4BF -1.264431 36.804569 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +54 865135061581904 3 2026-04-23 10:01:20+00 0101000020E6100000F17EDC7EF9664240D5CC5A0A483BF4BF -1.264473 36.804489 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +55 862798052708068 128 2026-04-23 10:00:50+00 0101000020E61000001536035C90534240B7F0BC546CCCF1BF -1.112408 36.652843 0.00 \N 2026-04-23 10:28:55.624014+00 DVR vibration alert poll \N \N \N \N \N +56 865135061563282 3 2026-04-23 10:00:03+00 0101000020E61000001A355F251F454040C712D6C6D809C93F 0.195613 32.540013 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +57 359857081891632 stayAlert 2026-04-23 10:28:36+00 0101000020E61000008121AB5B3D6F424086200725CCB4F3BF -1.23164 36.86906 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +58 862798050521521 146 2026-04-23 10:28:33+00 0101000020E6100000FAB5F5D37F70424032022A1C412AF4BF -1.260316 36.878901 67.00 \N 2026-04-23 10:28:55.624014+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +59 359857082907973 ACC_ON 2026-04-23 10:28:32+00 0101000020E610000050C24CDBBFD24340C18BBE82342310C0 -4.03438 39.64648 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +60 359857082897257 ACC_OFF 2026-04-23 10:28:25+00 0101000020E610000001F6D1A92B774240BCAE5FB01BB6F3BF -1.23196 36.93102 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +61 359857081891632 ACC_OFF 2026-04-23 10:27:26+00 0101000020E61000008121AB5B3D6F424086200725CCB4F3BF -1.23164 36.86906 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +62 862798050523337 128 2026-04-23 10:27:12+00 0101000020E6100000670DDE57E5D44340B3075A81213B10C0 -4.057745 39.663249 0.00 \N 2026-04-23 10:28:55.624014+00 DVR vibration alert poll \N \N \N \N \N +63 359857082907973 ACC_OFF 2026-04-23 10:26:47+00 0101000020E610000050C24CDBBFD24340C18BBE82342310C0 -4.03438 39.64648 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +65 359857082918012 ACC_OFF 2026-04-23 10:26:42+00 0101000020E61000000FD1E80E626B42409626A5A0DB4BF3BF -1.20602 36.83893 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +66 865135061054548 ACC_OFF 2026-04-23 10:26:24+00 0101000020E61000003EEC8502B671424082A8FB00A4F6F2BF -1.185215 36.888367 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +67 862798050523014 128 2026-04-23 10:26:16+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 10:28:55.624014+00 DVR vibration alert poll \N \N \N \N \N +69 359857082918012 ACC_ON 2026-04-23 10:25:52+00 0101000020E6100000A54E4013616B4240ADDD76A1B94EF3BF -1.20672 36.8389 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +70 865135061563597 ACC_OFF 2026-04-23 10:25:39+00 0101000020E6100000AD8905BEA253424039D1AE42CACFF1BF -1.11323 36.653404 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +71 862798050288360 146 2026-04-23 10:25:36+00 0101000020E6100000812381069B72424008ABB184B571F2BF -1.152761 36.895356 55.00 \N 2026-04-23 10:28:55.624014+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +72 862798052707946 ACC_OFF 2026-04-23 10:25:23+00 0101000020E6100000322251685971424041102043C78EF2BF -1.159858 36.885541 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +73 862798050523527 128 2026-04-23 10:25:23+00 0101000020E61000007A89B14CBF724240A01B9AB2D30FF3BF -1.191364 36.896463 12.00 \N 2026-04-23 10:28:55.624014+00 DVR vibration alert poll \N \N \N \N \N +74 865135061054555 ACC_ON 2026-04-23 10:25:20+00 0101000020E6100000C685032159304240054EB6813B50D1BF -0.270522 36.37772 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +77 865135061035653 ACC_OFF 2026-04-23 10:24:49+00 0101000020E6100000AE2AFBAE08DE4340CB2C42B115940FC0 -3.947307 39.73464 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +78 359857082038977 ACC_OFF 2026-04-23 10:24:33+00 0101000020E61000007E74EACA67D94340BABDA4315A2710C0 -4.03843 39.69848 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +79 359857082907973 ACC_ON 2026-04-23 10:24:18+00 0101000020E610000058E71890BDD24340BB270F0BB52610C0 -4.0378 39.64641 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +80 865135061563597 ACC_ON 2026-04-23 10:24:13+00 0101000020E6100000AD8905BEA2534240C824236761CFF1BF -1.11313 36.653404 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +81 359857082918012 stayAlertOn 2026-04-23 10:23:54+00 0101000020E61000004F58E201656B4240C47C7901F651F3BF -1.20751 36.83902 0.00 \N 2026-04-23 10:28:55.624014+00 Idling alert poll \N \N \N \N \N +82 865135061563597 3 2026-04-23 10:23:32+00 0101000020E6100000AD8905BEA2534240C824236761CFF1BF -1.11313 36.653404 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +83 865135061054548 ACC_ON 2026-04-23 10:23:08+00 0101000020E6100000CC7D72142072424009FB761211FEF2BF -1.187028 36.891604 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +84 865135061563597 3 2026-04-23 10:22:01+00 0101000020E6100000AD8905BEA2534240C824236761CFF1BF -1.11313 36.653404 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +85 359857082042052 stayAlert 2026-04-23 10:21:58+00 0101000020E610000043E735768972424059DDEA39E9FDF2BF -1.18699 36.89482 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +86 359857082896911 ACC_OFF 2026-04-23 10:21:50+00 0101000020E6100000E4A08499B66B4240DCF4673F52C4F2BF -1.17293 36.84151 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +87 359857082042052 ACC_OFF 2026-04-23 10:20:58+00 0101000020E610000043E735768972424059DDEA39E9FDF2BF -1.18699 36.89482 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +88 359857082897091 ACC_ON 2026-04-23 10:20:02+00 0101000020E610000018B2BAD57372424042CF66D5E76AF3BF -1.2136 36.89416 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +89 862798050523527 128 2026-04-23 10:20:00+00 0101000020E6100000A837A3E6AB7242406AFAEC80EB0AF3BF -1.190166 36.895871 0.00 \N 2026-04-23 10:28:55.624014+00 DVR vibration alert poll \N \N \N \N \N +90 359857082897091 stayAlert 2026-04-23 10:19:55+00 0101000020E610000018B2BAD57372424042CF66D5E76AF3BF -1.2136 36.89416 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +91 359857081885410 ACC_ON 2026-04-23 10:19:51+00 0101000020E61000001F680586AC72424042959A3DD00AF3BF -1.19014 36.89589 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +92 862798050523527 ACC_ON 2026-04-23 10:19:50+00 0101000020E6100000A837A3E6AB7242406AFAEC80EB0AF3BF -1.190166 36.895871 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +93 862798050523014 128 2026-04-23 10:19:40+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 10:28:55.624014+00 DVR vibration alert poll \N \N \N \N \N +94 359857082042052 ACC_ON 2026-04-23 10:19:06+00 0101000020E6100000D13FC1C58A7242401FD7868A71FEF2BF -1.18712 36.89486 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +95 359857082897091 ACC_OFF 2026-04-23 10:18:55+00 0101000020E610000018B2BAD57372424042CF66D5E76AF3BF -1.2136 36.89416 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +96 359857082918012 ACC_ON 2026-04-23 10:18:54+00 0101000020E61000004F58E201656B4240C47C7901F651F3BF -1.20751 36.83902 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +97 865135061562722 3 2026-04-23 10:18:42+00 0101000020E61000002026E1421E6942405D6DC5FEB27BF2BF -1.1552 36.821236 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +98 865135061054555 stayAlertOn 2026-04-23 10:18:13+00 0101000020E610000079E8BB5B59304240A94D9CDCEF50D1BF -0.270565 36.377727 0.00 \N 2026-04-23 10:28:55.624014+00 Idling alert poll \N \N \N \N \N +99 359857082918012 ACC_OFF 2026-04-23 10:18:12+00 0101000020E61000004F58E201656B4240C47C7901F651F3BF -1.20751 36.83902 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +100 359857082912239 stayAlert 2026-04-23 10:16:32+00 0101000020E610000013D55B035B494340FD304278B4310BC0 -3.39927 38.57309 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +101 862798050288360 ACC_ON 2026-04-23 10:16:09+00 0101000020E6100000C37DE4D6A47742406825ADF88682F2BF -1.156867 36.934718 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +102 359857082912239 ACC_OFF 2026-04-23 10:15:32+00 0101000020E610000013D55B035B494340FD304278B4310BC0 -3.39927 38.57309 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +103 862798052707946 ACC_ON 2026-04-23 10:15:23+00 0101000020E6100000A3C85A43A96F42406475ABE7A4B7F2BF -1.169835 36.872353 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +104 862798050288360 stayAlert 2026-04-23 10:15:17+00 0101000020E6100000C37DE4D6A47742406825ADF88682F2BF -1.156867 36.934718 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +105 359857082896911 stayAlertOn 2026-04-23 10:15:13+00 0101000020E610000043908312666A4240751F80D426CEF2BF -1.17533 36.83124 0.00 \N 2026-04-23 10:28:55.624014+00 Idling alert poll \N \N \N \N \N +106 359857081891632 ACC_ON 2026-04-23 10:14:22+00 0101000020E6100000672783A3E46D42407923F3C81F8CF3BF -1.22171 36.85854 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +107 865135061054555 ACC_OFF 2026-04-23 10:13:34+00 0101000020E6100000C685032159304240054EB6813B50D1BF -0.270522 36.37772 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +108 865135061054555 ACC_ON 2026-04-23 10:13:13+00 0101000020E610000079E8BB5B59304240A94D9CDCEF50D1BF -0.270565 36.377727 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +109 865135061054548 ACC_OFF 2026-04-23 10:11:44+00 0101000020E610000000A8E2C62D7242407D1F0E12A2FCF2BF -1.186678 36.892022 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +110 862798050523014 ACC_OFF 2026-04-23 10:10:21+00 0101000020E61000008A213999B85342400D384BC972D2F1BF -1.113879 36.654071 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +111 359857082897091 ACC_ON 2026-04-23 10:10:17+00 0101000020E6100000594C6C3EAE7142405E85949F547BF3BF -1.21761 36.88813 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +112 359857082896911 ACC_ON 2026-04-23 10:10:13+00 0101000020E610000043908312666A4240751F80D426CEF2BF -1.17533 36.83124 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +113 862798052707946 ACC_OFF 2026-04-23 10:09:43+00 0101000020E6100000B08C0DDDEC6F42400938842A35BBF2BF -1.170705 36.874416 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +114 862798050523337 128 2026-04-23 10:09:29+00 0101000020E6100000670DDE57E5D44340B3075A81213B10C0 -4.057745 39.663249 0.00 \N 2026-04-23 10:28:55.624014+00 DVR vibration alert poll \N \N \N \N \N +115 359857082912239 ACC_ON 2026-04-23 10:09:24+00 0101000020E610000043CA4FAA7D4A4340AAD4EC8156200BC0 -3.39079 38.58196 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +116 359857081892762 offline 2026-04-23 10:08:43+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 0.00 \N 2026-04-23 10:28:55.624014+00 Offline alert poll \N \N \N \N \N +117 862798050288360 ACC_OFF 2026-04-23 10:04:42+00 0101000020E6100000C37DE4D6A47742406825ADF88682F2BF -1.156867 36.934718 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +118 865135061035653 ACC_ON 2026-04-23 10:04:38+00 0101000020E6100000A69718CBF4DF4340D8F15F2008900FC0 -3.945328 39.749658 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +119 862798050523527 128 2026-04-23 10:04:14+00 0101000020E610000092770E65A8724240FE2C9622F90AF3BF -1.190179 36.895764 0.00 \N 2026-04-23 10:28:55.624014+00 DVR vibration alert poll \N \N \N \N \N +120 359857082897257 ACC_ON 2026-04-23 10:03:43+00 0101000020E61000007172BF435178424099F56228275AF3BF -1.20951 36.93998 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +121 862798050288360 ACC_ON 2026-04-23 10:03:32+00 0101000020E610000038BBB54C867742409DD843FB5881F2BF -1.156579 36.933786 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +122 862798050523337 ACC_OFF 2026-04-23 10:02:05+00 0101000020E6100000670DDE57E5D44340B3075A81213B10C0 -4.057745 39.663249 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +123 862798050288360 ACC_OFF 2026-04-23 10:01:45+00 0101000020E610000038BBB54C867742409DD843FB5881F2BF -1.156579 36.933786 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +124 862798050523337 147 2026-04-23 10:01:11+00 0101000020E61000006FF1F09E03D543406E6AA0F99C3B10C0 -4.058216 39.664173 53.00 \N 2026-04-23 10:28:55.624014+00 Collision Alert(DVR) poll \N \N \N \N \N +125 359857082912239 stayAlert 2026-04-23 10:01:08+00 0101000020E610000066A032FE7D4A434055FB743C66200BC0 -3.39082 38.58197 0.00 \N 2026-04-23 10:28:55.624014+00 Parking alert poll \N \N \N \N \N +126 865135061563597 3 2026-04-23 10:00:50+00 0101000020E6100000DFC0E446915342404B2366F679CCF1BF -1.112421 36.652871 0.00 \N 2026-04-23 10:28:55.624014+00 Vibration alert poll \N \N \N \N \N +127 359857082912239 ACC_OFF 2026-04-23 10:00:09+00 0101000020E610000066A032FE7D4A434055FB743C66200BC0 -3.39082 38.58197 0.00 \N 2026-04-23 10:28:55.624014+00 ACC OFF poll \N \N \N \N \N +128 862798050288360 ACC_ON 2026-04-23 10:00:06+00 0101000020E6100000C09657AEB7774240CEE33098BF82F2BF -1.156921 36.935293 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +129 862798050523014 ACC_ON 2026-04-23 09:59:32+00 0101000020E6100000E27668588C524240EBC9FCA36FD2F1BF -1.113876 36.644908 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +130 359857082918012 ACC_ON 2026-04-23 09:58:57+00 0101000020E6100000BEBC00FBE86C4240BF654E97C544F3BF -1.20429 36.85086 0.00 \N 2026-04-23 10:28:55.624014+00 ACC ON poll \N \N \N \N \N +131 359857081892101 1001 2026-04-23 10:29:20+00 0101000020E6100000F6402B3064654240ACA8C1340C9FF4BF -1.28883 36.79212 \N \N 2026-04-23 10:29:21.507861+00 ACC OFF push \N \N \N \N \N +132 865135061053748 1001 2026-04-23 10:29:39+00 0101000020E610000072361D01DCD443406ABFB513253110C0 -4.047993 39.662964 \N \N 2026-04-23 10:29:40.350152+00 ACC OFF push \N \N \N \N \N +133 862798050526231 1001 2026-04-23 10:29:41+00 0101000020E6100000DC847B65DED4434026E318C91E3110C0 -4.047969 39.663037 \N \N 2026-04-23 10:29:41.575467+00 ACC OFF push \N \N \N \N \N +134 862798050288345 146 2026-04-23 10:29:38+00 0101000020E6100000925D6919A9974340AD33BE2F2EE511C0 -4.473809 39.184848 59.00 \N 2026-04-23 10:29:45.563231+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +135 359857082907973 1001 2026-04-23 10:29:57+00 0101000020E610000050C24CDBBFD24340DE3CD521372310C0 -4.03439 39.64648 \N \N 2026-04-23 10:29:58.878951+00 ACC OFF push \N \N \N \N \N +136 359857081885410 1001 2026-04-23 10:29:58+00 0101000020E610000010751F80D472424091F2936A9F0EF3BF -1.19107 36.89711 \N \N 2026-04-23 10:29:59.071853+00 ACC OFF push \N \N \N \N \N +137 862798050523527 1001 2026-04-23 10:29:59+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 \N \N 2026-04-23 10:29:59.915009+00 ACC OFF push \N \N \N \N \N +138 862798050526231 1002 2026-04-23 10:30:18+00 0101000020E6100000DC847B65DED4434026E318C91E3110C0 -4.047969 39.663037 \N \N 2026-04-23 10:30:18.936705+00 ACC ON push \N \N \N \N \N +139 359857082897794 1001 2026-04-23 10:30:21+00 0101000020E610000065C22FF5F366424008AC1C5A643BF4BF -1.2645 36.80432 \N \N 2026-04-23 10:30:22.530563+00 ACC OFF push \N \N \N \N \N +140 865135061053748 1004 2026-04-23 10:30:39+00 0101000020E6100000444E5FCFD7D44340A9A44E40133110C0 -4.047925 39.662836 \N \N 2026-04-23 10:30:39.523741+00 Parking alert push \N \N \N \N \N +141 359857081891566 1002 2026-04-23 10:30:55+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 10:30:55.739184+00 ACC ON push \N \N \N \N \N +142 359857081885410 1004 2026-04-23 10:30:58+00 0101000020E61000006666666666724240A5315A475513F3BF -1.19222 36.89375 \N \N 2026-04-23 10:30:58.888543+00 Parking alert push \N \N \N \N \N +143 862798050523527 128 2026-04-23 10:31:11+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:31:13.716399+00 DVR vibration alert push \N \N \N \N \N +144 865135061563597 3 2026-04-23 10:31:26+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 10:31:28.367569+00 Vibration alert push \N \N \N \N \N +145 862798052708068 128 2026-04-23 10:31:30+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 10:31:31.885731+00 DVR vibration alert push \N \N \N \N \N +146 359857082918012 stayAlertOn 2026-04-23 10:31:38+00 0101000020E61000000FD1E80E626B42409626A5A0DB4BF3BF -1.20602 36.83893 \N \N 2026-04-23 10:31:38.855908+00 Idling alert push \N \N \N \N \N +147 359857082898487 1002 2026-04-23 10:31:44+00 0101000020E61000002310AFEB177C42400074982F2FC0F2BF -1.17192 36.96948 \N \N 2026-04-23 10:31:45.186653+00 ACC ON push \N \N \N \N \N +148 359857081892101 1002 2026-04-23 10:32:19+00 0101000020E6100000D53E1D8F19644240EF1B5F7B66C9F4BF -1.29917 36.78203 \N \N 2026-04-23 10:32:20.45537+00 ACC ON push \N \N \N \N \N +149 359857082897794 1002 2026-04-23 10:32:33+00 0101000020E610000082734694F6664240EC34D252793BF4BF -1.26452 36.8044 \N \N 2026-04-23 10:32:34.55597+00 ACC ON push \N \N \N \N \N +150 359857081891566 1001 2026-04-23 10:32:47+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 10:32:49.567954+00 ACC OFF push \N \N \N \N \N +151 865135061569123 1002 2026-04-23 10:33:04+00 0101000020E6100000C3D66CE5255F4240F12E17F19DD8F4BF -1.302885 36.743344 \N \N 2026-04-23 10:33:05.125505+00 ACC ON push \N \N \N \N \N +152 865135061569123 1001 2026-04-23 10:33:39+00 0101000020E610000066F4A3E1945F4240849ECDAACFD5F4BF -1.3022 36.746731 \N \N 2026-04-23 10:33:39.716162+00 ACC OFF push \N \N \N \N \N +153 865135061564470 1001 2026-04-23 10:33:43+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 \N \N 2026-04-23 10:33:44.658475+00 ACC OFF push \N \N \N \N \N +154 359857082042854 1002 2026-04-23 10:33:55+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 \N \N 2026-04-23 10:33:56.216621+00 ACC ON push \N \N \N \N \N +155 865135061564470 ACC_OFF 2026-04-23 10:33:43+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +156 865135061569123 ACC_OFF 2026-04-23 10:33:39+00 0101000020E610000066F4A3E1945F4240849ECDAACFD5F4BF -1.3022 36.746731 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +157 865135061569123 ACC_ON 2026-04-23 10:33:04+00 0101000020E6100000C3D66CE5255F4240F12E17F19DD8F4BF -1.302885 36.743344 0.00 \N 2026-04-23 10:33:56.689807+00 ACC ON poll \N \N \N \N \N +158 862798052708068 128 2026-04-23 10:31:31+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 10:33:56.689807+00 DVR vibration alert poll \N \N \N \N \N +159 865135061053748 stayAlert 2026-04-23 10:30:39+00 0101000020E6100000444E5FCFD7D44340A9A44E40133110C0 -4.047925 39.662836 0.00 \N 2026-04-23 10:33:56.689807+00 Parking alert poll \N \N \N \N \N +160 865135061053748 ACC_OFF 2026-04-23 10:29:39+00 0101000020E610000072361D01DCD443406ABFB513253110C0 -4.047993 39.662964 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +184 359857081891566 ACC_OFF 2026-04-23 10:32:47+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +185 359857082897794 ACC_ON 2026-04-23 10:32:33+00 0101000020E610000082734694F6664240EC34D252793BF4BF -1.26452 36.8044 0.00 \N 2026-04-23 10:33:56.689807+00 ACC ON poll \N \N \N \N \N +186 359857081892101 ACC_ON 2026-04-23 10:32:19+00 0101000020E6100000D53E1D8F19644240EF1B5F7B66C9F4BF -1.29917 36.78203 0.00 \N 2026-04-23 10:33:56.689807+00 ACC ON poll \N \N \N \N \N +187 359857082898487 ACC_ON 2026-04-23 10:31:44+00 0101000020E61000002310AFEB177C42400074982F2FC0F2BF -1.17192 36.96948 0.00 \N 2026-04-23 10:33:56.689807+00 ACC ON poll \N \N \N \N \N +190 862798050523527 128 2026-04-23 10:31:12+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:33:56.689807+00 DVR vibration alert poll \N \N \N \N \N +191 359857081885410 stayAlert 2026-04-23 10:30:58+00 0101000020E61000006666666666724240A5315A475513F3BF -1.19222 36.89375 0.00 \N 2026-04-23 10:33:56.689807+00 Parking alert poll \N \N \N \N \N +192 359857081891566 ACC_ON 2026-04-23 10:30:55+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 10:33:56.689807+00 ACC ON poll \N \N \N \N \N +193 359857082897794 ACC_OFF 2026-04-23 10:30:21+00 0101000020E610000065C22FF5F366424008AC1C5A643BF4BF -1.2645 36.80432 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +194 862798050526231 ACC_ON 2026-04-23 10:30:18+00 0101000020E6100000DC847B65DED4434026E318C91E3110C0 -4.047969 39.663037 0.00 \N 2026-04-23 10:33:56.689807+00 ACC ON poll \N \N \N \N \N +195 862798050523527 ACC_OFF 2026-04-23 10:29:59+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +196 359857081885410 ACC_OFF 2026-04-23 10:29:58+00 0101000020E610000010751F80D472424091F2936A9F0EF3BF -1.19107 36.89711 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +197 359857082907973 ACC_OFF 2026-04-23 10:29:57+00 0101000020E610000050C24CDBBFD24340DE3CD521372310C0 -4.03439 39.64648 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +198 862798050526231 ACC_OFF 2026-04-23 10:29:41+00 0101000020E6100000DC847B65DED4434026E318C91E3110C0 -4.047969 39.663037 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +199 862798050288345 146 2026-04-23 10:29:40+00 0101000020E6100000925D6919A9974340AD33BE2F2EE511C0 -4.473809 39.184848 59.00 \N 2026-04-23 10:33:56.689807+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +200 359857081892101 ACC_OFF 2026-04-23 10:29:20+00 0101000020E6100000F6402B3064654240ACA8C1340C9FF4BF -1.28883 36.79212 0.00 \N 2026-04-23 10:33:56.689807+00 ACC OFF poll \N \N \N \N \N +261 359857081892101 stayAlertOn 2026-04-23 10:07:54+00 0101000020E6100000AF94658863654240575BB1BFEC9EF4BF -1.2888 36.7921 0.00 \N 2026-04-23 10:33:56.689807+00 Idling alert poll \N \N \N \N \N +4381 865135061563639 1004 2026-04-23 12:19:57+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 \N \N 2026-04-23 12:19:57.45604+00 Parking alert push \N \N \N \N \N +4382 862798050525423 1004 2026-04-23 12:20:14+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 \N \N 2026-04-23 12:20:14.447736+00 Parking alert push \N \N \N \N \N +4385 359857082897737 1002 2026-04-23 12:20:58+00 0101000020E6100000B471C45A7CDE4340543541D47DC00FC0 -3.96899 39.73817 \N \N 2026-04-23 12:20:58.701434+00 ACC ON push \N \N \N \N \N +4388 865135061043079 1001 2026-04-23 12:21:33+00 0101000020E610000063B7CF2A33ED43405C5A0D897B0C0DC0 -3.631095 39.853124 \N \N 2026-04-23 12:21:34.487032+00 ACC OFF push \N \N \N \N \N +4389 865135061569479 3 2026-04-23 12:21:34+00 0101000020E6100000C85F5AD42743404011397D3D5FB3BC3F 0.112112 32.524653 \N \N 2026-04-23 12:21:35.738393+00 Vibration alert push \N \N \N \N \N +4390 862798050523139 1001 2026-04-23 12:21:35+00 0101000020E610000021C8410933ED4340C18C2958E30C0DC0 -3.631293 39.85312 \N \N 2026-04-23 12:21:36.482713+00 ACC OFF push \N \N \N \N \N +4392 359857081886905 1001 2026-04-23 12:21:51+00 0101000020E6100000ED2AA4FCA4DE4340315F5E807DB40FC0 -3.96313 39.73941 \N \N 2026-04-23 12:21:51.459331+00 ACC OFF push \N \N \N \N \N +4398 359857081891566 1001 2026-04-23 12:23:02+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 12:23:03.16313+00 ACC OFF push \N \N \N \N \N +4400 359857082911983 1001 2026-04-23 12:23:26+00 0101000020E61000001D5A643BDF6F4240CBBE2B82FFADF3BF -1.22998 36.874 \N \N 2026-04-23 12:23:26.67043+00 ACC OFF push \N \N \N \N \N +4401 862798050288360 1001 2026-04-23 12:23:26+00 0101000020E61000008978EBFCDB6F4240CAA65CE15DAEF3BF -1.23007 36.873901 \N \N 2026-04-23 12:23:26.917611+00 ACC OFF push \N \N \N \N \N +4403 359857082910589 stayAlertOn 2026-04-23 12:23:52+00 0101000020E6100000D4B7CCE9B27842401CB62DCA6C90F2BF -1.16026 36.94296 \N \N 2026-04-23 12:23:52.310388+00 Idling alert push \N \N \N \N \N +4404 862798050288345 128 2026-04-23 12:23:59+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 12:24:03.15332+00 DVR vibration alert push \N \N \N \N \N +4405 359857082908500 1002 2026-04-23 12:24:09+00 0101000020E6100000618E1EBFB79143401A170E84646111C0 -4.34511 39.13842 \N \N 2026-04-23 12:24:09.427448+00 ACC ON push \N \N \N \N \N +4406 862798050288345 1002 2026-04-23 12:24:09+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 \N \N 2026-04-23 12:24:10.819929+00 ACC ON push \N \N \N \N \N +4407 359857081885410 3 2026-03-06 00:52:35+00 0101000020E61000008A93FB1D8A724240AE81AD122C0EF3BF -1.19096 36.89484 \N \N 2026-04-23 12:24:16.807341+00 Vibration alert push \N \N \N \N \N +4585 865135061563639 3 2026-04-23 12:24:24+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 \N \N 2026-04-23 12:24:25.786406+00 Vibration alert push \N \N \N \N \N +4589 359857082902461 stayAlertOn 2026-04-23 12:25:07+00 0101000020E6100000B471C45A7C4A4340C63368E89F200BC0 -3.39093 38.58192 \N \N 2026-04-23 12:25:07.754038+00 Idling alert push \N \N \N \N \N +4590 865135061562722 3 2026-04-23 12:25:49+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 12:25:50.392016+00 Vibration alert push \N \N \N \N \N +4591 862798050523337 128 2026-04-23 12:25:49+00 0101000020E61000008CDB68006FD9434017821C94300310C0 -4.003115 39.6987 0.00 \N 2026-04-23 12:25:50.520335+00 DVR vibration alert push \N \N \N \N \N +4592 865135061048953 1002 2026-04-23 12:25:59+00 0101000020E610000022A7AFE76BDA43400A664CC11A0710C0 -4.006938 39.706418 \N \N 2026-04-23 12:26:00.845835+00 ACC ON push \N \N \N \N \N +4593 359857082896911 stayAlertOn 2026-04-23 12:26:03+00 0101000020E6100000B98D06F0166C4240371AC05B20C1F2BF -1.17215 36.84445 \N \N 2026-04-23 12:26:03.822479+00 Idling alert push \N \N \N \N \N +4594 359857082918012 1002 2026-04-23 12:26:30+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 \N \N 2026-04-23 12:26:31.357318+00 ACC ON push \N \N \N \N \N +4599 865135061581904 1002 2026-04-23 12:27:07+00 0101000020E61000000C91D3D7F3554240A96A82A8FBC0F3BF -1.234615 36.671504 \N \N 2026-04-23 12:27:07.966437+00 ACC ON push \N \N \N \N \N +4600 359857081887069 1001 2026-04-23 12:27:21+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 12:27:22.054704+00 ACC OFF push \N \N \N \N \N +4604 359857082037185 1001 2026-04-23 12:27:51+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 12:27:52.360864+00 ACC OFF push \N \N \N \N \N +4605 359857081886905 1002 2026-04-23 12:27:52+00 0101000020E61000009D2E8B89CDDF4340C98E8D40BCAE0FC0 -3.96032 39.74846 \N \N 2026-04-23 12:27:52.78642+00 ACC ON push \N \N \N \N \N +4606 359857082911983 stayAlertOn 2026-04-23 12:27:52+00 0101000020E61000001D5A643BDF6F4240AE47E17A14AEF3BF -1.23 36.874 \N \N 2026-04-23 12:27:52.864322+00 Idling alert push \N \N \N \N \N +4607 865135061563639 1002 2026-04-23 12:28:02+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 \N \N 2026-04-23 12:28:02.969816+00 ACC ON push \N \N \N \N \N +4608 359857081891632 1001 2026-04-23 12:28:34+00 0101000020E610000087DC0C37E06F4240E7357689EAADF3BF -1.22996 36.87403 \N \N 2026-04-23 12:28:35.189397+00 ACC OFF push \N \N \N \N \N +4609 359857082898487 1001 2026-04-23 12:28:58+00 0101000020E61000008E01D9EBDD7B42407008556AF6C0F2BF -1.17211 36.96771 \N \N 2026-04-23 12:28:59.130228+00 ACC OFF push \N \N \N \N \N +4610 865135061563597 1002 2026-04-23 12:28:58+00 0101000020E61000004815C5ABAC534240828E56B5A4E3F1BF -1.118077 36.653707 \N \N 2026-04-23 12:28:59.90587+00 ACC ON push \N \N \N \N \N +4611 359857081886905 1001 2026-04-23 12:29:12+00 0101000020E61000009D2E8B89CDDF4340C98E8D40BCAE0FC0 -3.96032 39.74846 \N \N 2026-04-23 12:29:13.397338+00 ACC OFF push \N \N \N \N \N +4612 865135061564470 3 2026-04-23 12:29:16+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 \N \N 2026-04-23 12:29:18.295601+00 Vibration alert push \N \N \N \N \N +4613 865135061562722 3 2026-04-23 12:28:52+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 12:29:20.492416+00 Vibration alert push \N \N \N \N \N +265 359857082907973 1002 2026-04-23 10:33:59+00 0101000020E610000050C24CDBBFD24340DE3CD521372310C0 -4.03439 39.64648 \N \N 2026-04-23 10:34:00.079245+00 ACC ON push \N \N \N \N \N +266 359857082910589 1001 2026-04-23 10:34:24+00 0101000020E6100000B6B9313D61754240618907944DB9F2BF -1.17024 36.91703 \N \N 2026-04-23 10:34:25.350862+00 ACC OFF push \N \N \N \N \N +267 359857081887192 1001 2026-04-23 10:34:28+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 10:34:29.074112+00 ACC OFF push \N \N \N \N \N +268 865135061569123 1004 2026-04-23 10:34:39+00 0101000020E610000066F4A3E1945F4240849ECDAACFD5F4BF -1.3022 36.746731 \N \N 2026-04-23 10:34:39.64845+00 Parking alert push \N \N \N \N \N +269 865135061564470 1004 2026-04-23 10:34:43+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 \N \N 2026-04-23 10:34:43.677593+00 Parking alert push \N \N \N \N \N +270 359857082910589 1002 2026-04-23 10:34:48+00 0101000020E6100000B6B9313D61754240618907944DB9F2BF -1.17024 36.91703 \N \N 2026-04-23 10:34:50.048025+00 ACC ON push \N \N \N \N \N +271 865135061054548 1002 2026-04-23 10:34:54+00 0101000020E61000004679E6E5B071424089B7CEBF5DF6F2BF -1.185148 36.888211 \N \N 2026-04-23 10:34:54.787+00 ACC ON push \N \N \N \N \N +272 359857082898487 1001 2026-04-23 10:34:58+00 0101000020E6100000A33B889D297C4240DD0C37E0F3C3F2BF -1.17284 36.97002 \N \N 2026-04-23 10:34:59.620927+00 ACC OFF push \N \N \N \N \N +273 865135061569479 2 2026-04-23 09:21:41+00 0101000020E610000085B1852007454040B9895A9A5B21C83F 0.188518 32.53928 \N \N 2026-04-23 10:34:59.733443+00 Power cut off alert push \N \N \N \N \N +276 359857082897257 1002 2026-04-23 10:35:25+00 0101000020E6100000906B43C5387742401B4CC3F011B1F3BF -1.23073 36.93142 \N \N 2026-04-23 10:35:26.071915+00 ACC ON push \N \N \N \N \N +4383 865135061563282 1002 2026-04-23 12:20:19+00 0101000020E6100000A438471D1D4540404EB340BB438AC93F 0.199532 32.539951 \N \N 2026-04-23 12:20:20.395645+00 ACC ON push \N \N \N \N \N +4384 865135061053748 1002 2026-04-23 12:20:31+00 0101000020E6100000D97C5C1B2AD64340A7E67283A13E10C0 -4.061163 39.67316 \N \N 2026-04-23 12:20:31.668181+00 ACC ON push \N \N \N \N \N +4386 359857082896911 1001 2026-04-23 12:21:16+00 0101000020E6100000DC63E943176C42408B4F01309EC1F2BF -1.17227 36.84446 \N \N 2026-04-23 12:21:18.049658+00 ACC OFF push \N \N \N \N \N +4387 865135061563639 3 2026-04-23 12:20:09+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 \N \N 2026-04-23 12:21:18.686279+00 Vibration alert push \N \N \N \N \N +4391 359857082898487 stayAlertOn 2026-04-23 12:21:42+00 0101000020E6100000C078060DFD7B4240E08442041CC2F2BF -1.17239 36.96866 \N \N 2026-04-23 12:21:42.378736+00 Idling alert push \N \N \N \N \N +4393 359857082918038 1001 2026-04-23 12:22:20+00 0101000020E610000080608E1EBF4B43406B60AB048B430BC0 -3.40798 38.59177 \N \N 2026-04-23 12:22:20.973664+00 ACC OFF push \N \N \N \N \N +4394 865135061564470 1001 2026-04-23 12:22:22+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 \N \N 2026-04-23 12:22:23.471672+00 ACC OFF push \N \N \N \N \N +4395 359857081892101 stayAlertOn 2026-04-23 12:22:26+00 0101000020E61000005B423EE8D9644240D7868A71FEA6F4BF -1.29077 36.7879 \N \N 2026-04-23 12:22:27.116403+00 Idling alert push \N \N \N \N \N +4396 862798050523295 146 2026-04-23 12:22:48+00 0101000020E61000004C1C7920B26A4240FC1A49827045F4BF -1.266953 36.833561 49.00 \N 2026-04-23 12:22:50.771196+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +4397 862798050525423 1002 2026-04-23 12:22:51+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 \N \N 2026-04-23 12:22:52.278912+00 ACC ON push \N \N \N \N \N +4399 865135061564470 1004 2026-04-23 12:23:21+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 \N \N 2026-04-23 12:23:21.263558+00 Parking alert push \N \N \N \N \N +4402 865135061564470 3 2026-04-23 12:23:33+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 \N \N 2026-04-23 12:23:34.479585+00 Vibration alert push \N \N \N \N \N +4586 862798050523527 128 2026-04-23 12:24:41+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 12:24:44.198295+00 DVR vibration alert push \N \N \N \N \N +4587 862798050288345 1001 2026-04-23 12:24:47+00 0101000020E6100000D78A36C7B99143400A849D62D56011C0 -4.344564 39.138482 \N \N 2026-04-23 12:24:48.057096+00 ACC OFF push \N \N \N \N \N +4588 359857082908500 1001 2026-04-23 12:24:46+00 0101000020E610000036936FB6B9914340A9BC1DE1B46011C0 -4.34444 39.13848 \N \N 2026-04-23 12:24:48.091302+00 ACC OFF push \N \N \N \N \N +4595 862798052708068 1002 2026-04-23 12:26:38+00 0101000020E6100000BBF083F3A953424033DC80CF0FE3F1BF -1.117935 36.653624 \N \N 2026-04-23 12:26:39.014433+00 ACC ON push \N \N \N \N \N +4597 865135061564470 3 2026-04-23 12:26:49+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 \N \N 2026-04-23 12:26:51.183714+00 Vibration alert push \N \N \N \N \N +4598 359857082898487 1002 2026-04-23 12:26:53+00 0101000020E610000032207BBDFB7B4240E09C11A5BDC1F2BF -1.1723 36.96862 \N \N 2026-04-23 12:26:54.249926+00 ACC ON push \N \N \N \N \N +4601 359857082046145 1001 2026-04-23 12:27:28+00 0101000020E610000098A3C7EF6DDA43402CD49AE61D0710C0 -4.00695 39.70648 \N \N 2026-04-23 12:27:29.750449+00 ACC OFF push \N \N \N \N \N +4602 865135061563282 1001 2026-04-23 12:27:42+00 0101000020E6100000988A8D791D4540403F73D6A71C93C93F 0.199802 32.539962 \N \N 2026-04-23 12:27:43.391231+00 ACC OFF push \N \N \N \N \N +4603 359857082902461 1001 2026-04-23 12:27:43+00 0101000020E6100000C3BB5CC4774A4340E3AAB2EF8A200BC0 -3.39089 38.58178 \N \N 2026-04-23 12:27:44.460469+00 ACC OFF push \N \N \N \N \N +4806 862798052708068 1004 2026-04-23 12:31:31+00 0101000020E6100000AB2006BAF6534240ED9FA70183E4F1BF -1.118289 36.655967 \N \N 2026-04-23 12:31:32.04782+00 Parking alert push \N \N \N \N \N +4807 865135061569123 3 2026-04-23 12:31:06+00 0101000020E61000003CDD79E239634240CD3B4ED191DCF4BF -1.30385 36.775204 \N \N 2026-04-23 12:31:34.392409+00 Vibration alert push \N \N \N \N \N +6358 865135061563597 1002 2026-04-23 13:17:28+00 0101000020E6100000588E90813C5342401B81785DBFE0F1BF -1.11737 36.650284 \N \N 2026-04-23 13:17:28.778952+00 ACC ON push \N \N \N \N \N +6359 865135061563597 1001 2026-04-23 13:18:22+00 0101000020E61000007EA834626653424091ED7C3F35DEF1BF -1.11675 36.651562 \N \N 2026-04-23 13:18:22.746515+00 ACC OFF push \N \N \N \N \N +6360 862798052708068 1001 2026-04-23 13:18:24+00 0101000020E6100000E5266A696E5342406405BF0D31DEF1BF -1.116746 36.651807 \N \N 2026-04-23 13:18:24.836776+00 ACC OFF push \N \N \N \N \N +6363 862798052708068 1004 2026-04-23 13:19:23+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 \N \N 2026-04-23 13:19:24.029679+00 Parking alert push \N \N \N \N \N +6522 865135061054555 1002 2026-04-23 13:19:38+00 0101000020E61000000875914259304240397CD2890453D1BF -0.270692 36.377724 \N \N 2026-04-23 13:19:38.570858+00 ACC ON push \N \N \N \N \N +6523 359857081887069 1001 2026-04-23 13:19:37+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 13:19:38.883521+00 ACC OFF push \N \N \N \N \N +6525 359857082897257 stayAlertOn 2026-04-23 13:20:56+00 0101000020E61000000E15E3FC4D784240C993A46B265FF3BF -1.21073 36.93988 \N \N 2026-04-23 13:20:56.998512+00 Idling alert push \N \N \N \N \N +6529 865135061048953 1002 2026-04-23 13:21:25+00 0101000020E61000009D2ADF3312DB434084B7072120FF0FC0 -3.999573 39.711493 \N \N 2026-04-23 13:21:25.832156+00 ACC ON push \N \N \N \N \N +6532 359857081892762 1003 2026-04-23 13:22:03+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 \N \N 2026-04-23 13:22:03.467837+00 Offline alert push \N \N \N \N \N +6533 359857081887069 stayAlertOn 2026-04-23 13:22:20+00 0101000020E610000055C1A8A44E784240C993A46B265FF3BF -1.21073 36.9399 \N \N 2026-04-23 13:22:20.804144+00 Idling alert push \N \N \N \N \N +6696 865135061048276 1001 2026-04-23 13:26:23+00 0101000020E6100000F1D4230D6ED943400002D6AA5D0310C0 -4.003287 39.698671 \N \N 2026-04-23 13:26:24.188872+00 ACC OFF push \N \N \N \N \N +6697 865135061569123 1004 2026-04-23 13:26:36+00 0101000020E61000004374081C09664240EED0B01875ADF4BF -1.292348 36.797153 \N \N 2026-04-23 13:26:37.054248+00 Parking alert push \N \N \N \N \N +6698 862798050523337 1001 2026-04-23 13:26:44+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 \N \N 2026-04-23 13:26:45.177295+00 ACC OFF push \N \N \N \N \N +6699 865135061581904 3 2026-04-23 13:26:46+00 0101000020E6100000B75ED38382564240850A0E2F88C8F3BF -1.236458 36.675858 \N \N 2026-04-23 13:26:48.153495+00 Vibration alert push \N \N \N \N \N +6700 865135061569123 3 2026-04-23 13:26:49+00 0101000020E61000004374081C09664240EED0B01875ADF4BF -1.292348 36.797153 \N \N 2026-04-23 13:26:50.704395+00 Vibration alert push \N \N \N \N \N +6701 865135061043426 1002 2026-04-23 13:26:52+00 0101000020E6100000E23FDD40815B4240118FC4CBD3B9F0BF -1.045368 36.714882 \N \N 2026-04-23 13:26:53.881375+00 ACC ON push \N \N \N \N \N +6702 865135061035653 1001 2026-04-23 13:27:05+00 0101000020E6100000C18F6AD8EFDF434054008C67D0900FC0 -3.94571 39.749507 \N \N 2026-04-23 13:27:06.538654+00 ACC OFF push \N \N \N \N \N +6703 865135061054555 1002 2026-04-23 13:27:23+00 0101000020E6100000381092054C30424070EEAF1EF7ADD1BF -0.276243 36.37732 \N \N 2026-04-23 13:27:24.04331+00 ACC ON push \N \N \N \N \N +6704 359857081887069 stayAlertOn 2026-04-23 13:27:45+00 0101000020E610000055C1A8A44E784240C993A46B265FF3BF -1.21073 36.9399 \N \N 2026-04-23 13:27:46.040366+00 Idling alert push \N \N \N \N \N +6848 862798052707946 1002 2026-04-23 13:29:51+00 0101000020E61000001B6327BC04774240D89DEE3CF11CF3BF -1.194566 36.929832 \N \N 2026-04-23 13:29:51.919973+00 ACC ON push \N \N \N \N \N +274 865135061563597 3 2026-04-23 10:35:06+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 10:35:08.333452+00 Vibration alert push \N \N \N \N \N +275 865135061569479 3 2026-04-23 09:21:41+00 0101000020E610000085B1852007454040B9895A9A5B21C83F 0.188518 32.53928 \N \N 2026-04-23 10:35:10.698625+00 Vibration alert push \N \N \N \N \N +277 359857081886905 1001 2026-04-23 10:35:37+00 0101000020E61000005FD218ADA3DE434018EC866D8BB20FC0 -3.96218 39.73937 \N \N 2026-04-23 10:35:37.678371+00 ACC OFF push \N \N \N \N \N +278 865135061564470 3 2026-04-23 10:35:47+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 \N \N 2026-04-23 10:35:48.813654+00 Vibration alert push \N \N \N \N \N +279 865135061562847 3 2026-04-23 10:32:32+00 0101000020E61000007BFA08FCE1814240E9EDCF454386F1BF -1.095279 37.014709 \N \N 2026-04-23 10:35:50.779597+00 Vibration alert push \N \N \N \N \N +280 359857081891566 stayAlertOn 2026-04-23 10:35:55+00 0101000020E61000000A80F10C1A6A424091D5AD9E935EF4BF -1.27309 36.82892 \N \N 2026-04-23 10:35:55.478764+00 Idling alert push \N \N \N \N \N +281 359857082911983 stayAlertOn 2026-04-23 10:36:11+00 0101000020E610000016FBCBEEC96F42409D11A5BDC197F2BF -1.16205 36.87335 \N \N 2026-04-23 10:36:11.774166+00 Idling alert push \N \N \N \N \N +282 865135061043426 1002 2026-04-23 10:36:21+00 0101000020E6100000F1F44A59867042408ACA86359585F3BF -1.220113 36.8791 \N \N 2026-04-23 10:36:22.074001+00 ACC ON push \N \N \N \N \N +283 359857082918186 1002 2026-04-23 10:36:25+00 0101000020E61000004C89247A19554240984C158C4AEAF3BF -1.2447 36.66484 \N \N 2026-04-23 10:36:25.832836+00 ACC ON push \N \N \N \N \N +284 359857082897794 1001 2026-04-23 10:36:42+00 0101000020E6100000BABDA4315A674240DAACFA5C6D45F4BF -1.26695 36.80744 \N \N 2026-04-23 10:36:43.003989+00 ACC OFF push \N \N \N \N \N +285 865135061569123 1004 2026-04-23 10:36:56+00 0101000020E61000001536035C905F4240AF7C96E7C1DDF4BF -1.30414 36.746593 \N \N 2026-04-23 10:36:56.309426+00 Parking alert push \N \N \N \N \N +286 359857082898487 1002 2026-04-23 10:37:12+00 0101000020E6100000EAE74D452A7C4240C095ECD808C4F2BF -1.17286 36.97004 \N \N 2026-04-23 10:37:13.778213+00 ACC ON push \N \N \N \N \N +287 865135061569479 3 2026-04-23 10:37:16+00 0101000020E6100000266F8099EF444040AB5CA8FC6B79C73F 0.183393 32.538562 39.00 \N 2026-04-23 10:37:18.448261+00 Vibration alert push \N \N \N \N \N +288 359857081892101 stayAlertOn 2026-04-23 10:37:19+00 0101000020E6100000D53E1D8F19644240EF1B5F7B66C9F4BF -1.29917 36.78203 \N \N 2026-04-23 10:37:19.775789+00 Idling alert push \N \N \N \N \N +289 359857082910589 1002 2026-04-23 10:37:22+00 0101000020E6100000213CDA3862754240F0C4AC1743B9F2BF -1.17023 36.91706 \N \N 2026-04-23 10:37:23.231336+00 ACC ON push \N \N \N \N \N +290 865135061563639 stayAlertOn 2026-04-23 10:37:26+00 0101000020E6100000C53BC09316F64240D49AE61DA7A8FCBF -1.791175 37.922564 \N \N 2026-04-23 10:37:26.905114+00 Idling alert push \N \N \N \N \N +291 359857082897257 1001 2026-04-23 10:37:28+00 0101000020E610000090882991447742402844C02154A9F3BF -1.22884 36.93178 \N \N 2026-04-23 10:37:29.086999+00 ACC OFF push \N \N \N \N \N +292 865135061054548 1001 2026-04-23 10:37:35+00 0101000020E6100000041BD7BFEB714240252367614FFBF2BF -1.186355 36.890007 \N \N 2026-04-23 10:37:36.14343+00 ACC OFF push \N \N \N \N \N +293 865135061053748 1002 2026-04-23 10:37:41+00 0101000020E6100000444E5FCFD7D44340A9A44E40133110C0 -4.047925 39.662836 \N \N 2026-04-23 10:37:42.873202+00 ACC ON push \N \N \N \N \N +294 862798050523014 128 2026-04-23 10:37:44+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 10:37:47.227847+00 DVR vibration alert push \N \N \N \N \N +295 865135061563597 3 2026-04-23 10:36:28+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 10:37:58.567658+00 Vibration alert push \N \N \N \N \N +296 865135061562847 1002 2026-04-23 10:38:18+00 0101000020E61000006E4C4F58E281424017D68D774786F1BF -1.095283 37.01472 \N \N 2026-04-23 10:38:19.055158+00 ACC ON push \N \N \N \N \N +297 865135061053748 ACC_ON 2026-04-23 10:37:41+00 0101000020E6100000444E5FCFD7D44340A9A44E40133110C0 -4.047925 39.662836 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +300 865135061569123 stayAlert 2026-04-23 10:36:56+00 0101000020E61000001536035C905F4240AF7C96E7C1DDF4BF -1.30414 36.746593 0.00 \N 2026-04-23 10:38:57.394836+00 Parking alert poll \N \N \N \N \N +301 865135061043426 ACC_ON 2026-04-23 10:36:21+00 0101000020E6100000F1F44A59867042408ACA86359585F3BF -1.220113 36.8791 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +303 865135061564470 stayAlert 2026-04-23 10:34:43+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 0.00 \N 2026-04-23 10:38:57.394836+00 Parking alert poll \N \N \N \N \N +304 865135061569123 stayAlert 2026-04-23 10:34:39+00 0101000020E610000066F4A3E1945F4240849ECDAACFD5F4BF -1.3022 36.746731 0.00 \N 2026-04-23 10:38:57.394836+00 Parking alert poll \N \N \N \N \N +328 359857082897737 1002 2026-04-23 10:38:56+00 0101000020E6100000179F02603CDF43404C7155D977850FC0 -3.94017 39.74403 \N \N 2026-04-23 10:38:57.445964+00 ACC ON push \N \N \N \N \N +329 865135061562847 ACC_ON 2026-04-23 10:38:18+00 0101000020E61000006E4C4F58E281424017D68D774786F1BF -1.095283 37.01472 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +330 862798050523014 128 2026-04-23 10:37:45+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 10:38:57.394836+00 DVR vibration alert poll \N \N \N \N \N +331 865135061054548 ACC_OFF 2026-04-23 10:37:35+00 0101000020E6100000041BD7BFEB714240252367614FFBF2BF -1.186355 36.890007 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +332 359857082897257 ACC_OFF 2026-04-23 10:37:28+00 0101000020E610000090882991447742402844C02154A9F3BF -1.22884 36.93178 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +333 359857082910589 ACC_ON 2026-04-23 10:37:22+00 0101000020E6100000213CDA3862754240F0C4AC1743B9F2BF -1.17023 36.91706 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +335 359857082898487 ACC_ON 2026-04-23 10:37:12+00 0101000020E6100000EAE74D452A7C4240C095ECD808C4F2BF -1.17286 36.97004 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +336 359857082897794 ACC_OFF 2026-04-23 10:36:42+00 0101000020E6100000BABDA4315A674240DAACFA5C6D45F4BF -1.26695 36.80744 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +338 359857082918186 ACC_ON 2026-04-23 10:36:25+00 0101000020E61000004C89247A19554240984C158C4AEAF3BF -1.2447 36.66484 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +341 359857081886905 ACC_OFF 2026-04-23 10:35:37+00 0101000020E61000005FD218ADA3DE434018EC866D8BB20FC0 -3.96218 39.73937 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +342 359857082897257 ACC_ON 2026-04-23 10:35:25+00 0101000020E6100000906B43C5387742401B4CC3F011B1F3BF -1.23073 36.93142 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +344 359857082898487 ACC_OFF 2026-04-23 10:34:58+00 0101000020E6100000A33B889D297C4240DD0C37E0F3C3F2BF -1.17284 36.97002 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +345 865135061054548 ACC_ON 2026-04-23 10:34:54+00 0101000020E61000004679E6E5B071424089B7CEBF5DF6F2BF -1.185148 36.888211 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +346 359857082910589 ACC_ON 2026-04-23 10:34:48+00 0101000020E6100000B6B9313D61754240618907944DB9F2BF -1.17024 36.91703 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +347 359857081887192 ACC_OFF 2026-04-23 10:34:28+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +348 359857082910589 ACC_OFF 2026-04-23 10:34:24+00 0101000020E6100000B6B9313D61754240618907944DB9F2BF -1.17024 36.91703 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +349 359857082907973 ACC_ON 2026-04-23 10:33:59+00 0101000020E610000050C24CDBBFD24340DE3CD521372310C0 -4.03439 39.64648 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +350 359857082042854 ACC_ON 2026-04-23 10:33:55+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +400 359857082918186 ACC_OFF 2026-04-23 10:20:09+00 0101000020E610000005DD5ED21855424043FF04172BEAF3BF -1.24467 36.66482 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +413 359857082910589 ACC_ON 2026-04-23 10:18:03+00 0101000020E6100000F146E6913F744240EB73B515FBCBF2BF -1.1748 36.90819 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +414 359857082911983 ACC_ON 2026-04-23 10:17:34+00 0101000020E6100000CF143AAFB1774240C251F2EA1C83F2BF -1.15701 36.93511 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +415 359857082910589 ACC_OFF 2026-04-23 10:17:01+00 0101000020E6100000F146E6913F744240EB73B515FBCBF2BF -1.1748 36.90819 0.00 \N 2026-04-23 10:38:57.394836+00 ACC OFF poll \N \N \N \N \N +426 359857081886905 ACC_ON 2026-04-23 10:11:36+00 0101000020E6100000D42B6519E2DC434067614F3BFC1510C0 -4.02147 39.72565 0.00 \N 2026-04-23 10:38:57.394836+00 ACC ON poll \N \N \N \N \N +433 359857082898487 1001 2026-04-23 10:39:04+00 0101000020E6100000B98D06F0167C4240C66D3480B7C0F2BF -1.17205 36.96945 \N \N 2026-04-23 10:39:05.907821+00 ACC OFF push \N \N \N \N \N +434 862798050525423 1002 2026-04-23 10:39:09+00 0101000020E6100000699082A790DF4340B16EBC3B32760FC0 -3.932713 39.746602 \N \N 2026-04-23 10:39:09.642503+00 ACC ON push \N \N \N \N \N +435 862798050523527 128 2026-04-23 10:39:11+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:39:13.585947+00 DVR vibration alert push \N \N \N \N \N +436 865135061569479 3 2026-04-23 10:39:36+00 0101000020E6100000D42AFA4333454040B08C0DDDEC0FC63F 0.172361 32.540627 31.00 \N 2026-04-23 10:39:38.383678+00 Vibration alert push \N \N \N \N \N +443 865135061569479 3 2026-04-23 10:41:57+00 0101000020E610000012BD8C62B9454040207BBDFBE3BDC43F 0.162045 32.54472 40.00 \N 2026-04-23 10:42:04.074474+00 Vibration alert push \N \N \N \N \N +4409 865135061564470 stayAlert 2026-04-23 12:23:21+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 0.00 \N 2026-04-23 12:24:23.74299+00 Parking alert poll \N \N \N \N \N +4410 862798050525423 ACC_ON 2026-04-23 12:22:51+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 0.00 \N 2026-04-23 12:24:23.74299+00 ACC ON poll \N \N \N \N \N +4411 865135061564470 ACC_OFF 2026-04-23 12:22:22+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4413 865135061053748 ACC_ON 2026-04-23 12:20:31+00 0101000020E6100000D97C5C1B2AD64340A7E67283A13E10C0 -4.061163 39.67316 0.00 \N 2026-04-23 12:24:23.74299+00 ACC ON poll \N \N \N \N \N +4414 865135061563282 ACC_ON 2026-04-23 12:20:19+00 0101000020E6100000A438471D1D4540404EB340BB438AC93F 0.199532 32.539951 0.00 \N 2026-04-23 12:24:23.74299+00 ACC ON poll \N \N \N \N \N +4415 862798050525423 stayAlert 2026-04-23 12:20:14+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 0.00 \N 2026-04-23 12:24:23.74299+00 Parking alert poll \N \N \N \N \N +4417 865135061563639 stayAlert 2026-04-23 12:19:57+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 0.00 \N 2026-04-23 12:24:23.74299+00 Parking alert poll \N \N \N \N \N +4464 862798050288345 ACC_ON 2026-04-23 12:24:09+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 12:24:23.74299+00 ACC ON poll \N \N \N \N \N +4465 359857082908500 ACC_ON 2026-04-23 12:24:09+00 0101000020E6100000618E1EBFB79143401A170E84646111C0 -4.34511 39.13842 0.00 \N 2026-04-23 12:24:23.74299+00 ACC ON poll \N \N \N \N \N +4466 862798050288345 128 2026-04-23 12:24:02+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 12:24:23.74299+00 DVR vibration alert poll \N \N \N \N \N +4468 862798050288360 ACC_OFF 2026-04-23 12:23:26+00 0101000020E61000008978EBFCDB6F4240CAA65CE15DAEF3BF -1.23007 36.873901 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4469 359857082911983 ACC_OFF 2026-04-23 12:23:26+00 0101000020E61000001D5A643BDF6F4240CBBE2B82FFADF3BF -1.22998 36.874 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4470 359857081891566 ACC_OFF 2026-04-23 12:23:02+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4472 359857081886905 ACC_OFF 2026-04-23 12:21:51+00 0101000020E6100000ED2AA4FCA4DE4340315F5E807DB40FC0 -3.96313 39.73941 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4474 359857082896911 ACC_OFF 2026-04-23 12:21:16+00 0101000020E6100000DC63E943176C42408B4F01309EC1F2BF -1.17227 36.84446 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4475 359857082897737 ACC_ON 2026-04-23 12:20:58+00 0101000020E6100000B471C45A7CDE4340543541D47DC00FC0 -3.96899 39.73817 0.00 \N 2026-04-23 12:24:23.74299+00 ACC ON poll \N \N \N \N \N +4557 862798050523295 146 2026-04-23 12:22:49+00 0101000020E61000004C1C7920B26A4240FC1A49827045F4BF -1.266953 36.833561 49.00 \N 2026-04-23 12:24:23.74299+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +4558 359857082918038 ACC_OFF 2026-04-23 12:22:20+00 0101000020E610000080608E1EBF4B43406B60AB048B430BC0 -3.40798 38.59177 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4559 862798050523139 ACC_OFF 2026-04-23 12:21:35+00 0101000020E610000021C8410933ED4340C18C2958E30C0DC0 -3.631293 39.85312 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4560 865135061043079 ACC_OFF 2026-04-23 12:21:33+00 0101000020E610000063B7CF2A33ED43405C5A0D897B0C0DC0 -3.631095 39.853124 0.00 \N 2026-04-23 12:24:23.74299+00 ACC OFF poll \N \N \N \N \N +4615 865135061563639 ACC_ON 2026-04-23 12:28:02+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 0.00 \N 2026-04-23 12:29:24.573475+00 ACC ON poll \N \N \N \N \N +4616 865135061563282 ACC_OFF 2026-04-23 12:27:42+00 0101000020E6100000988A8D791D4540403F73D6A71C93C93F 0.199802 32.539962 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4617 865135061581904 ACC_ON 2026-04-23 12:27:07+00 0101000020E61000000C91D3D7F3554240A96A82A8FBC0F3BF -1.234615 36.671504 0.00 \N 2026-04-23 12:29:24.573475+00 ACC ON poll \N \N \N \N \N +4619 862798052708068 ACC_ON 2026-04-23 12:26:38+00 0101000020E6100000BBF083F3A953424033DC80CF0FE3F1BF -1.117935 36.653624 0.00 \N 2026-04-23 12:29:24.573475+00 ACC ON poll \N \N \N \N \N +4674 359857081886905 ACC_OFF 2026-04-23 12:29:12+00 0101000020E61000009D2E8B89CDDF4340C98E8D40BCAE0FC0 -3.96032 39.74846 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4675 865135061563597 ACC_ON 2026-04-23 12:28:58+00 0101000020E61000004815C5ABAC534240828E56B5A4E3F1BF -1.118077 36.653707 0.00 \N 2026-04-23 12:29:24.573475+00 ACC ON poll \N \N \N \N \N +4676 359857082898487 ACC_OFF 2026-04-23 12:28:58+00 0101000020E61000008E01D9EBDD7B42407008556AF6C0F2BF -1.17211 36.96771 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4677 359857081891632 ACC_OFF 2026-04-23 12:28:34+00 0101000020E610000087DC0C37E06F4240E7357689EAADF3BF -1.22996 36.87403 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4678 359857081886905 ACC_ON 2026-04-23 12:27:52+00 0101000020E61000009D2E8B89CDDF4340C98E8D40BCAE0FC0 -3.96032 39.74846 0.00 \N 2026-04-23 12:29:24.573475+00 ACC ON poll \N \N \N \N \N +4680 359857082037185 ACC_OFF 2026-04-23 12:27:51+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4681 359857082046145 ACC_OFF 2026-04-23 12:27:28+00 0101000020E610000098A3C7EF6DDA43402CD49AE61D0710C0 -4.00695 39.70648 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4682 359857082898487 ACC_ON 2026-04-23 12:26:53+00 0101000020E610000032207BBDFB7B4240E09C11A5BDC1F2BF -1.1723 36.96862 0.00 \N 2026-04-23 12:29:24.573475+00 ACC ON poll \N \N \N \N \N +4683 359857082918012 ACC_ON 2026-04-23 12:26:30+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 0.00 \N 2026-04-23 12:29:24.573475+00 ACC ON poll \N \N \N \N \N +4687 862798050288345 ACC_OFF 2026-04-23 12:24:47+00 0101000020E6100000D78A36C7B99143400A849D62D56011C0 -4.344564 39.138482 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4688 359857082908500 ACC_OFF 2026-04-23 12:24:46+00 0101000020E610000036936FB6B9914340A9BC1DE1B46011C0 -4.34444 39.13848 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4689 862798050523527 128 2026-04-23 12:24:43+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 12:29:24.573475+00 DVR vibration alert poll \N \N \N \N \N +4766 359857082902461 ACC_OFF 2026-04-23 12:27:43+00 0101000020E6100000C3BB5CC4774A4340E3AAB2EF8A200BC0 -3.39089 38.58178 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4767 359857081887069 ACC_OFF 2026-04-23 12:27:21+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 12:29:24.573475+00 ACC OFF poll \N \N \N \N \N +4768 865135061048953 ACC_ON 2026-04-23 12:25:59+00 0101000020E610000022A7AFE76BDA43400A664CC11A0710C0 -4.006938 39.706418 0.00 \N 2026-04-23 12:29:24.573475+00 ACC ON poll \N \N \N \N \N +6361 865135061569131 3 2026-04-23 13:18:49+00 0101000020E6100000F69672BED8474040FBCC599F724CAE3F 0.059177 32.561302 14.00 \N 2026-04-23 13:18:50.705433+00 Vibration alert push \N \N \N \N \N +6362 359857082912239 1001 2026-04-23 13:18:54+00 0101000020E6100000C503CAA65C494340A857CA32C4310BC0 -3.3993 38.57314 \N \N 2026-04-23 13:18:55.089852+00 ACC OFF push \N \N \N \N \N +6524 359857082912239 1004 2026-04-23 13:19:54+00 0101000020E6100000C503CAA65C494340A857CA32C4310BC0 -3.3993 38.57314 \N \N 2026-04-23 13:19:54.342228+00 Parking alert push \N \N \N \N \N +6526 865135061563597 3 2026-04-23 13:21:01+00 0101000020E6100000B88FDC9A745342408C6A11514CDEF1BF -1.116772 36.651996 \N \N 2026-04-23 13:21:03.265447+00 Vibration alert push \N \N \N \N \N +6527 865135061054555 1001 2026-04-23 13:21:04+00 0101000020E61000006F4562821A304240B891B245D26ED1BF -0.272389 36.375809 \N \N 2026-04-23 13:21:05.531336+00 ACC OFF push \N \N \N \N \N +6528 865135061569131 3 2026-04-23 13:21:09+00 0101000020E61000004E5E64027E4740402CD49AE61DA7B03F 0.06505 32.558533 17.00 \N 2026-04-23 13:21:11.158259+00 Vibration alert push \N \N \N \N \N +6530 865135061035653 1001 2026-04-23 13:21:43+00 0101000020E6100000CA8B4CC0AFDF43400A4CA7751B940FC0 -3.947318 39.747551 \N \N 2026-04-23 13:21:44.108179+00 ACC OFF push \N \N \N \N \N +6531 865135061035653 1002 2026-04-23 13:21:57+00 0101000020E61000005ED5592DB0DF4340EE3EC7478B930FC0 -3.947043 39.747564 \N \N 2026-04-23 13:21:57.273849+00 ACC ON push \N \N \N \N \N +6534 359857081887069 1002 2026-04-23 13:22:45+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 13:22:46.179937+00 ACC ON push \N \N \N \N \N +437 862798050288345 146 2026-04-23 10:39:59+00 0101000020E61000001D588E90819043408CF7E3F6CBC711C0 -4.445114 39.128954 52.00 \N 2026-04-23 10:40:07.192575+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +438 865135061569131 3 2026-04-23 09:16:33+00 0101000020E6100000C0AF91240845404054E3A59BC420C83F 0.1885 32.539311 \N \N 2026-04-23 10:40:25.276579+00 Vibration alert push \N \N \N \N \N +439 359857081892309 1002 2026-04-23 10:40:39+00 0101000020E6100000CBD6FA22A17142405C3D27BD6F7CF3BF -1.21788 36.88773 \N \N 2026-04-23 10:40:40.169684+00 ACC ON push \N \N \N \N \N +440 359857082897794 stayAlertOn 2026-04-23 10:40:43+00 0101000020E6100000B398D87C5C6742404C7155D97745F4BF -1.26696 36.80751 \N \N 2026-04-23 10:40:43.719646+00 Idling alert push \N \N \N \N \N +441 359857082912486 1001 2026-04-23 10:40:59+00 0101000020E6100000B4024356B7E64340CFBD874B8EBB0EC0 -3.84158 39.80247 \N \N 2026-04-23 10:41:00.207177+00 ACC OFF push \N \N \N \N \N +442 865135061563597 3 2026-04-23 10:41:45+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 10:41:47.056343+00 Vibration alert push \N \N \N \N \N +444 865135061559538 1002 2026-04-23 10:42:18+00 0101000020E61000003EAF78EA916A4240D82D02637D43F3BF -1.203977 36.832578 \N \N 2026-04-23 10:42:18.5831+00 ACC ON push \N \N \N \N \N +445 865135061054555 1001 2026-04-23 10:42:18+00 0101000020E610000098A1F14410314240A4FCA4DAA7E3D0BF -0.263895 36.383309 \N \N 2026-04-23 10:42:19.235922+00 ACC OFF push \N \N \N \N \N +446 865135061569131 3 2026-04-23 10:42:42+00 0101000020E6100000C0AF91240845404054E3A59BC420C83F 0.1885 32.539311 \N \N 2026-04-23 10:42:44.976491+00 Vibration alert push \N \N \N \N \N +447 865135061562722 3 2026-04-23 10:43:00+00 0101000020E61000002B6C06B8206942407F4FAC53E57BF2BF -1.155248 36.821311 \N \N 2026-04-23 10:43:08.956411+00 Vibration alert push \N \N \N \N \N +448 359857081885410 3 2026-03-05 23:11:48+00 0101000020E6100000FCE3BD6A65724240FA7E6ABC7413F3BF -1.19225 36.89372 \N \N 2026-04-23 10:43:28.872634+00 Vibration alert push \N \N \N \N \N +449 359857082898487 stayAlertOn 2026-04-23 10:43:36+00 0101000020E6100000B98D06F0167C4240C66D3480B7C0F2BF -1.17205 36.96945 \N \N 2026-04-23 10:43:36.765166+00 Idling alert push \N \N \N \N \N +450 359857082918012 1002 2026-04-23 10:43:40+00 0101000020E6100000ECFA05BB616B4240B29DEFA7C64BF3BF -1.206 36.83892 \N \N 2026-04-23 10:43:41.56367+00 ACC ON push \N \N \N \N \N +481 359857082910589 1001 2026-04-23 10:43:57+00 0101000020E6100000EEB1F4A10B76424077F35487DC8CF2BF -1.15939 36.92223 \N \N 2026-04-23 10:43:58.441362+00 ACC OFF push \N \N \N \N \N +592 359857082897737 1001 2026-04-23 10:44:06+00 0101000020E6100000732EC55565DF4340C24CDBBFB2920FC0 -3.94663 39.74528 \N \N 2026-04-23 10:44:07.777272+00 ACC OFF push \N \N \N \N \N +4765 359857081892309 1002 2026-04-23 12:29:24+00 0101000020E6100000697407B1337142406F9EEA909B61F3BF -1.21133 36.88439 \N \N 2026-04-23 12:29:25.054268+00 ACC ON push \N \N \N \N \N +4794 359857081891632 1004 2026-04-23 12:29:34+00 0101000020E610000087DC0C37E06F4240E7357689EAADF3BF -1.22996 36.87403 \N \N 2026-04-23 12:29:34.78066+00 Parking alert push \N \N \N \N \N +4795 865135061563282 3 2026-04-23 12:29:49+00 0101000020E6100000EBE40CC51D454040CE716E13EE95C93F 0.199888 32.539971 \N \N 2026-04-23 12:29:50.768089+00 Vibration alert push \N \N \N \N \N +4796 359857082918038 1002 2026-04-23 12:29:56+00 0101000020E610000016DEE522BE4B4340DEB06D5166430BC0 -3.40791 38.59174 \N \N 2026-04-23 12:29:57.008429+00 ACC ON push \N \N \N \N \N +4797 865135061581904 1001 2026-04-23 12:30:16+00 0101000020E610000015FF774485564240D8648D7A88C6F3BF -1.23597 36.675942 \N \N 2026-04-23 12:30:17.532498+00 ACC OFF push \N \N \N \N \N +4798 862798052708068 1001 2026-04-23 12:30:31+00 0101000020E61000006A317898F65342408E20956247E3F1BF -1.117988 36.655963 \N \N 2026-04-23 12:30:32.841828+00 ACC OFF push \N \N \N \N \N +4799 359857082898487 1002 2026-04-23 12:30:47+00 0101000020E61000007250C24CDB7B42408D7F9F71E1C0F2BF -1.17209 36.96763 \N \N 2026-04-23 12:30:48.0306+00 ACC ON push \N \N \N \N \N +4800 359857082902461 stayAlertOn 2026-04-23 12:30:53+00 0101000020E6100000919BE1067C4A4340C63368E89F200BC0 -3.39093 38.58191 \N \N 2026-04-23 12:30:53.561866+00 Idling alert push \N \N \N \N \N +4801 359857082902461 1002 2026-04-23 12:30:58+00 0101000020E6100000C3BB5CC4774A4340E3AAB2EF8A200BC0 -3.39089 38.58178 \N \N 2026-04-23 12:30:58.586195+00 ACC ON push \N \N \N \N \N +4802 862798050288360 1004 2026-04-23 12:31:00+00 0101000020E61000008978EBFCDB6F4240CAA65CE15DAEF3BF -1.23007 36.873901 \N \N 2026-04-23 12:31:01.037398+00 Parking alert push \N \N \N \N \N +4803 862798050523139 128 2026-04-23 12:31:03+00 0101000020E610000021C8410933ED43406CB3B112F30C0DC0 -3.631323 39.85312 0.00 \N 2026-04-23 12:31:05.437097+00 DVR vibration alert push \N \N \N \N \N +4804 865135061563597 1001 2026-04-23 12:31:05+00 0101000020E6100000C8409E5DBE534240F949B54FC7E3F1BF -1.11811 36.654247 \N \N 2026-04-23 12:31:06.295724+00 ACC OFF push \N \N \N \N \N +4805 865135061581904 1004 2026-04-23 12:31:16+00 0101000020E6100000B75ED38382564240850A0E2F88C8F3BF -1.236458 36.675858 \N \N 2026-04-23 12:31:16.447005+00 Parking alert push \N \N \N \N \N +6364 862798052708068 stayAlert 2026-04-23 13:19:23+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 0.00 \N 2026-04-23 13:19:33.757754+00 Parking alert poll \N \N \N \N \N +6366 862798052708068 ACC_OFF 2026-04-23 13:18:24+00 0101000020E6100000E5266A696E5342406405BF0D31DEF1BF -1.116746 36.651807 0.00 \N 2026-04-23 13:19:33.757754+00 ACC OFF poll \N \N \N \N \N +6367 865135061037980 stayAlert 2026-04-23 13:17:01+00 0101000020E6100000D82E6D382C6142402B4F20EC146BF4BF -1.276143 36.759162 0.00 \N 2026-04-23 13:19:33.757754+00 Parking alert poll \N \N \N \N \N +6369 862798050525423 stayAlert 2026-04-23 13:16:16+00 0101000020E61000001D39D21918DB4340ACE5CE4C30FC0FC0 -3.998139 39.711673 0.00 \N 2026-04-23 13:19:33.757754+00 Parking alert poll \N \N \N \N \N +6370 865135061037980 ACC_OFF 2026-04-23 13:16:01+00 0101000020E6100000D82E6D382C6142402B4F20EC146BF4BF -1.276143 36.759162 0.00 \N 2026-04-23 13:19:33.757754+00 ACC OFF poll \N \N \N \N \N +6371 862798052708068 ACC_ON 2026-04-23 13:15:36+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6408 359857082912239 ACC_OFF 2026-04-23 13:18:54+00 0101000020E6100000C503CAA65C494340A857CA32C4310BC0 -3.3993 38.57314 0.00 \N 2026-04-23 13:19:33.757754+00 ACC OFF poll \N \N \N \N \N +6409 865135061563597 ACC_OFF 2026-04-23 13:18:22+00 0101000020E61000007EA834626653424091ED7C3F35DEF1BF -1.11675 36.651562 0.00 \N 2026-04-23 13:19:33.757754+00 ACC OFF poll \N \N \N \N \N +6410 865135061563597 ACC_ON 2026-04-23 13:17:28+00 0101000020E6100000588E90813C5342401B81785DBFE0F1BF -1.11737 36.650284 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6411 359857082896911 ACC_ON 2026-04-23 13:17:14+00 0101000020E61000002310AFEB176C4240E09C11A5BDC1F2BF -1.1723 36.84448 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6412 865135061035653 ACC_ON 2026-04-23 13:16:28+00 0101000020E61000004C1762F547E04340C4B0C398F4970FC0 -3.949197 39.752196 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6413 862798050523014 ACC_OFF 2026-04-23 13:16:21+00 0101000020E610000071C63027685342409D67EC4B36DEF1BF -1.116751 36.651616 0.00 \N 2026-04-23 13:19:33.757754+00 ACC OFF poll \N \N \N \N \N +6414 359857082897257 ACC_ON 2026-04-23 13:15:56+00 0101000020E61000000E15E3FC4D784240C993A46B265FF3BF -1.21073 36.93988 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6415 359857082910589 ACC_ON 2026-04-23 13:15:49+00 0101000020E6100000AF946588637542405001309E4143F3BF -1.20392 36.9171 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6416 865135061562847 ACC_ON 2026-04-23 13:15:09+00 0101000020E61000002541B8020A814240B2F50CE198A5F1BF -1.102929 37.008118 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6417 359857081891632 stayAlert 2026-04-23 13:15:05+00 0101000020E610000024D6E253007042406553AEF02E97F3BF -1.22441 36.87501 0.00 \N 2026-04-23 13:19:33.757754+00 Parking alert poll \N \N \N \N \N +6418 359857082912239 ACC_ON 2026-04-23 13:14:30+00 0101000020E6100000F775E09C11494340658D7A8846370BC0 -3.40199 38.57085 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6499 359857081887069 ACC_ON 2026-04-23 13:17:20+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 13:19:33.757754+00 ACC ON poll \N \N \N \N \N +6500 865135061048466 ACC_OFF 2026-04-23 13:16:15+00 0101000020E610000053CA6B2574534240252026E142DEF1BF -1.116763 36.651982 0.00 \N 2026-04-23 13:19:33.757754+00 ACC OFF poll \N \N \N \N \N +6501 862798050523295 ACC_OFF 2026-04-23 13:16:03+00 0101000020E6100000E4DC26DC2B614240983446EBA86AF4BF -1.27604 36.759151 0.00 \N 2026-04-23 13:19:33.757754+00 ACC OFF poll \N \N \N \N \N +6544 865135061053748 ACC_ON 2026-04-23 13:23:22+00 0101000020E6100000DA8D3EE603D443403DD2E0B6B63010C0 -4.047572 39.656369 0.00 \N 2026-04-23 13:24:34.670912+00 ACC ON poll \N \N \N \N \N +6580 359857082907973 ACC_OFF 2026-04-23 13:24:19+00 0101000020E610000029D027F224B54340124E0B5EF47511C0 -4.36519 39.41519 0.00 \N 2026-04-23 13:24:34.670912+00 ACC OFF poll \N \N \N \N \N +6581 862798050526231 ACC_ON 2026-04-23 13:23:10+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 0.00 \N 2026-04-23 13:24:34.670912+00 ACC ON poll \N \N \N \N \N +6582 865135061054555 ACC_ON 2026-04-23 13:22:57+00 0101000020E610000053944BE3173042407B681F2BF86DD1BF -0.272337 36.375729 0.00 \N 2026-04-23 13:24:34.670912+00 ACC ON poll \N \N \N \N \N +454 862798050525423 ACC_ON 2026-04-23 10:39:09+00 0101000020E6100000699082A790DF4340B16EBC3B32760FC0 -3.932713 39.746602 0.00 \N 2026-04-23 10:43:58.339409+00 ACC ON poll \N \N \N \N \N +482 359857082918012 ACC_ON 2026-04-23 10:43:40+00 0101000020E6100000ECFA05BB616B4240B29DEFA7C64BF3BF -1.206 36.83892 0.00 \N 2026-04-23 10:43:58.339409+00 ACC ON poll \N \N \N \N \N +485 865135061559538 ACC_ON 2026-04-23 10:42:18+00 0101000020E61000003EAF78EA916A4240D82D02637D43F3BF -1.203977 36.832578 0.00 \N 2026-04-23 10:43:58.339409+00 ACC ON poll \N \N \N \N \N +486 865135061054555 ACC_OFF 2026-04-23 10:42:18+00 0101000020E610000098A1F14410314240A4FCA4DAA7E3D0BF -0.263895 36.383309 0.00 \N 2026-04-23 10:43:58.339409+00 ACC OFF poll \N \N \N \N \N +488 359857082912486 ACC_OFF 2026-04-23 10:40:59+00 0101000020E6100000B4024356B7E64340CFBD874B8EBB0EC0 -3.84158 39.80247 0.00 \N 2026-04-23 10:43:58.339409+00 ACC OFF poll \N \N \N \N \N +490 359857081892309 ACC_ON 2026-04-23 10:40:39+00 0101000020E6100000CBD6FA22A17142405C3D27BD6F7CF3BF -1.21788 36.88773 0.00 \N 2026-04-23 10:43:58.339409+00 ACC ON poll \N \N \N \N \N +491 862798050288345 146 2026-04-23 10:40:01+00 0101000020E61000001D588E90819043408CF7E3F6CBC711C0 -4.445114 39.128954 52.00 \N 2026-04-23 10:43:58.339409+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +492 862798050523527 128 2026-04-23 10:39:12+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:43:58.339409+00 DVR vibration alert poll \N \N \N \N \N +493 359857082898487 ACC_OFF 2026-04-23 10:39:04+00 0101000020E6100000B98D06F0167C4240C66D3480B7C0F2BF -1.17205 36.96945 0.00 \N 2026-04-23 10:43:58.339409+00 ACC OFF poll \N \N \N \N \N +494 359857082897737 ACC_ON 2026-04-23 10:38:56+00 0101000020E6100000179F02603CDF43404C7155D977850FC0 -3.94017 39.74403 0.00 \N 2026-04-23 10:43:58.339409+00 ACC ON poll \N \N \N \N \N +562 359857081892309 ACC_OFF 2026-04-23 10:22:56+00 0101000020E6100000CBD6FA22A17142405C3D27BD6F7CF3BF -1.21788 36.88773 0.00 \N 2026-04-23 10:43:58.339409+00 ACC OFF poll \N \N \N \N \N +563 359857081892309 stayAlertOn 2026-04-23 10:22:43+00 0101000020E6100000CBD6FA22A17142405C3D27BD6F7CF3BF -1.21788 36.88773 0.00 \N 2026-04-23 10:43:58.339409+00 Idling alert poll \N \N \N \N \N +582 359857081892309 ACC_ON 2026-04-23 10:17:43+00 0101000020E6100000CBD6FA22A17142405C3D27BD6F7CF3BF -1.21788 36.88773 0.00 \N 2026-04-23 10:43:58.339409+00 ACC ON poll \N \N \N \N \N +593 862798050525423 1001 2026-04-23 10:44:10+00 0101000020E610000090F63FC05ADF43407A19C5724B8B0FC0 -3.943015 39.744957 \N \N 2026-04-23 10:44:10.60745+00 ACC OFF push \N \N \N \N \N +594 865135061054548 1002 2026-04-23 10:44:12+00 0101000020E610000042B5C189E87142402367614F3BFCF2BF -1.18658 36.889909 \N \N 2026-04-23 10:44:12.766978+00 ACC ON push \N \N \N \N \N +595 865135061569479 3 2026-04-23 10:44:17+00 0101000020E6100000B4739A05DA45404024EF1CCA5015C33F 0.149088 32.545716 34.00 \N 2026-04-23 10:44:19.189444+00 Vibration alert push \N \N \N \N \N +596 862798052707946 1002 2026-04-23 10:44:39+00 0101000020E61000004F3BFC3559714240A1D79FC4E78EF2BF -1.159889 36.885535 \N \N 2026-04-23 10:44:40.213384+00 ACC ON push \N \N \N \N \N +597 865135061035778 1001 2026-04-23 10:44:53+00 0101000020E61000007C9C69C2F6774240BBEF181EFB19F3BF -1.193843 36.937218 \N \N 2026-04-23 10:44:54.668349+00 ACC OFF push \N \N \N \N \N +598 862798050521521 1001 2026-04-23 10:44:55+00 0101000020E6100000138255F5F277424038BA4A77D719F3BF -1.193809 36.937102 \N \N 2026-04-23 10:44:56.392793+00 ACC OFF push \N \N \N \N \N +599 865135061569131 3 2026-04-23 10:45:03+00 0101000020E6100000865AD3BCE3444040E222F77475C7C63F 0.177962 32.5382 20.00 \N 2026-04-23 10:45:04.594229+00 Vibration alert push \N \N \N \N \N +600 862798050525423 1004 2026-04-23 10:45:10+00 0101000020E610000090F63FC05ADF43407A19C5724B8B0FC0 -3.943015 39.744957 \N \N 2026-04-23 10:45:10.37653+00 Parking alert push \N \N \N \N \N +601 359857082911983 stayAlertOn 2026-04-23 10:45:11+00 0101000020E6100000064CE0D6DD7042400AD7A3703D8AF2BF -1.15875 36.88177 \N \N 2026-04-23 10:45:11.850453+00 Idling alert push \N \N \N \N \N +602 359857082900341 1002 2026-04-23 10:45:19+00 0101000020E6100000F701486DE2DC4340F5108DEE201610C0 -4.02161 39.72566 \N \N 2026-04-23 10:45:21.454595+00 ACC ON push \N \N \N \N \N +603 359857081892309 stayAlertOn 2026-04-23 10:45:39+00 0101000020E6100000CBD6FA22A17142405C3D27BD6F7CF3BF -1.21788 36.88773 \N \N 2026-04-23 10:45:40.464617+00 Idling alert push \N \N \N \N \N +604 865135061581904 1001 2026-04-23 10:45:51+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 \N \N 2026-04-23 10:45:52.444147+00 ACC OFF push \N \N \N \N \N +605 865135061035778 1004 2026-04-23 10:45:53+00 0101000020E61000007C9C69C2F6774240BBEF181EFB19F3BF -1.193843 36.937218 \N \N 2026-04-23 10:45:56.019402+00 Parking alert push \N \N \N \N \N +606 865135061562722 3 2026-04-23 10:45:56+00 0101000020E61000002B6C06B8206942407F4FAC53E57BF2BF -1.155248 36.821311 \N \N 2026-04-23 10:46:06.825817+00 Vibration alert push \N \N \N \N \N +607 359857082918012 1001 2026-04-23 10:46:13+00 0101000020E6100000255D33F9666B42406E179AEB3452F3BF -1.20757 36.83908 \N \N 2026-04-23 10:46:13.186281+00 ACC OFF push \N \N \N \N \N +608 359857081892309 1001 2026-04-23 10:46:14+00 0101000020E6100000CB9C2E8B89714240D4F19881CA78F3BF -1.21699 36.88701 \N \N 2026-04-23 10:46:15.007021+00 ACC OFF push \N \N \N \N \N +609 862798050521521 1002 2026-04-23 10:46:14+00 0101000020E6100000138255F5F277424038BA4A77D719F3BF -1.193809 36.937102 \N \N 2026-04-23 10:46:15.342154+00 ACC ON push \N \N \N \N \N +610 865135061035778 1002 2026-04-23 10:46:11+00 0101000020E61000007C9C69C2F6774240BBEF181EFB19F3BF -1.193843 36.937218 \N \N 2026-04-23 10:46:30.359396+00 ACC ON push \N \N \N \N \N +611 865135061569479 3 2026-04-23 10:46:37+00 0101000020E6100000433D7D04FE444040FBB2B45373B9C13F 0.138472 32.539002 15.00 \N 2026-04-23 10:46:39.073902+00 Vibration alert push \N \N \N \N \N +612 359857081892309 1002 2026-04-23 10:46:55+00 0101000020E6100000CB9C2E8B89714240D4F19881CA78F3BF -1.21699 36.88701 \N \N 2026-04-23 10:46:56.560417+00 ACC ON push \N \N \N \N \N +613 865135061054548 1001 2026-04-23 10:46:57+00 0101000020E61000002368CC24EA714240D4282499D5FBF2BF -1.186483 36.889958 \N \N 2026-04-23 10:46:58.213452+00 ACC OFF push \N \N \N \N \N +614 862798050288345 1001 2026-04-23 10:47:23+00 0101000020E6100000B48F15FC369043406AF6402B30A411C0 -4.41034 39.126678 \N \N 2026-04-23 10:47:23.902318+00 ACC OFF push \N \N \N \N \N +615 865135061581904 1004 2026-04-23 10:46:50+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 \N \N 2026-04-23 10:47:27.536244+00 Parking alert push \N \N \N \N \N +616 359857082046145 1002 2026-04-23 10:47:40+00 0101000020E6100000BB270F0BB5D6434060E5D022DB1910C0 -4.02525 39.6774 \N \N 2026-04-23 10:47:40.895504+00 ACC ON push \N \N \N \N \N +617 865135061562847 stayAlertOn 2026-04-23 10:48:03+00 0101000020E61000004C35B396028242404757E9EE3A9BF1BF -1.100398 37.015704 \N \N 2026-04-23 10:48:03.954861+00 Idling alert push \N \N \N \N \N +618 865135061569131 3 2026-04-23 10:47:23+00 0101000020E6100000172AFF5A5E45404026C3F17C06D4C53F 0.170533 32.541942 27.00 \N 2026-04-23 10:48:06.753427+00 Vibration alert push \N \N \N \N \N +619 359857082908500 1001 2026-04-23 10:47:27+00 0101000020E610000095F1EF332E90434087E123624AA411C0 -4.41044 39.12641 \N \N 2026-04-23 10:48:09.537346+00 ACC OFF push \N \N \N \N \N +620 359857082897737 stayAlertOn 2026-04-23 10:48:12+00 0101000020E61000004F58E20165DF434051888043A8920FC0 -3.94661 39.74527 \N \N 2026-04-23 10:48:12.414201+00 Idling alert push \N \N \N \N \N +621 359857082910589 stayAlertOn 2026-04-23 10:48:26+00 0101000020E610000075E5B33C0F764240CC4065FCFB8CF2BF -1.15942 36.92234 \N \N 2026-04-23 10:48:27.049925+00 Idling alert push \N \N \N \N \N +622 862798050523527 128 2026-04-23 10:48:25+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:48:27.410396+00 DVR vibration alert push \N \N \N \N \N +623 359857081892309 1001 2026-04-23 10:48:30+00 0101000020E6100000CB9C2E8B89714240D4F19881CA78F3BF -1.21699 36.88701 \N \N 2026-04-23 10:48:31.028756+00 ACC OFF push \N \N \N \N \N +624 862798050288345 1002 2026-04-23 10:48:36+00 0101000020E6100000B48F15FC369043406AF6402B30A411C0 -4.41034 39.126678 \N \N 2026-04-23 10:48:37.954778+00 ACC ON push \N \N \N \N \N +625 359857082908500 1002 2026-04-23 10:48:37+00 0101000020E610000095F1EF332E90434087E123624AA411C0 -4.41044 39.12641 \N \N 2026-04-23 10:48:38.313193+00 ACC ON push \N \N \N \N \N +626 865135061563597 3 2026-04-23 10:48:17+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 10:48:58.63197+00 Vibration alert push \N \N \N \N \N +628 865135061581904 stayAlert 2026-04-23 10:46:50+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 0.00 \N 2026-04-23 10:48:59.108685+00 Parking alert poll \N \N \N \N \N +630 865135061035778 ACC_ON 2026-04-23 10:46:11+00 0101000020E61000007C9C69C2F6774240BBEF181EFB19F3BF -1.193843 36.937218 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +631 865135061035778 stayAlert 2026-04-23 10:45:53+00 0101000020E61000007C9C69C2F6774240BBEF181EFB19F3BF -1.193843 36.937218 0.00 \N 2026-04-23 10:48:59.108685+00 Parking alert poll \N \N \N \N \N +632 865135061581904 ACC_OFF 2026-04-23 10:45:51+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +633 862798050525423 stayAlert 2026-04-23 10:45:10+00 0101000020E610000090F63FC05ADF43407A19C5724B8B0FC0 -3.943015 39.744957 0.00 \N 2026-04-23 10:48:59.108685+00 Parking alert poll \N \N \N \N \N +635 865135061035778 ACC_OFF 2026-04-23 10:44:53+00 0101000020E61000007C9C69C2F6774240BBEF181EFB19F3BF -1.193843 36.937218 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +637 862798050525423 ACC_OFF 2026-04-23 10:44:10+00 0101000020E610000090F63FC05ADF43407A19C5724B8B0FC0 -3.943015 39.744957 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +664 359857082908500 ACC_ON 2026-04-23 10:48:37+00 0101000020E610000095F1EF332E90434087E123624AA411C0 -4.41044 39.12641 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +665 862798050288345 ACC_ON 2026-04-23 10:48:36+00 0101000020E6100000B48F15FC369043406AF6402B30A411C0 -4.41034 39.126678 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +666 359857081892309 ACC_OFF 2026-04-23 10:48:30+00 0101000020E6100000CB9C2E8B89714240D4F19881CA78F3BF -1.21699 36.88701 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +668 862798050523527 128 2026-04-23 10:48:26+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:48:59.108685+00 DVR vibration alert poll \N \N \N \N \N +671 359857082046145 ACC_ON 2026-04-23 10:47:40+00 0101000020E6100000BB270F0BB5D6434060E5D022DB1910C0 -4.02525 39.6774 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +672 359857082908500 ACC_OFF 2026-04-23 10:47:27+00 0101000020E610000095F1EF332E90434087E123624AA411C0 -4.41044 39.12641 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +673 862798050288345 ACC_OFF 2026-04-23 10:47:23+00 0101000020E6100000B48F15FC369043406AF6402B30A411C0 -4.41034 39.126678 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +674 865135061054548 ACC_OFF 2026-04-23 10:46:57+00 0101000020E61000002368CC24EA714240D4282499D5FBF2BF -1.186483 36.889958 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +675 359857081892309 ACC_ON 2026-04-23 10:46:55+00 0101000020E6100000CB9C2E8B89714240D4F19881CA78F3BF -1.21699 36.88701 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +676 862798050521521 ACC_ON 2026-04-23 10:46:14+00 0101000020E6100000138255F5F277424038BA4A77D719F3BF -1.193809 36.937102 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +677 359857081892309 ACC_OFF 2026-04-23 10:46:14+00 0101000020E6100000CB9C2E8B89714240D4F19881CA78F3BF -1.21699 36.88701 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +678 359857082918012 ACC_OFF 2026-04-23 10:46:13+00 0101000020E6100000255D33F9666B42406E179AEB3452F3BF -1.20757 36.83908 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +681 359857082900341 ACC_ON 2026-04-23 10:45:19+00 0101000020E6100000F701486DE2DC4340F5108DEE201610C0 -4.02161 39.72566 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +683 862798050521521 ACC_OFF 2026-04-23 10:44:55+00 0101000020E6100000138255F5F277424038BA4A77D719F3BF -1.193809 36.937102 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +684 862798052707946 ACC_ON 2026-04-23 10:44:39+00 0101000020E61000004F3BFC3559714240A1D79FC4E78EF2BF -1.159889 36.885535 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +685 865135061054548 ACC_ON 2026-04-23 10:44:12+00 0101000020E610000042B5C189E87142402367614F3BFCF2BF -1.18658 36.889909 0.00 \N 2026-04-23 10:48:59.108685+00 ACC ON poll \N \N \N \N \N +686 359857082897737 ACC_OFF 2026-04-23 10:44:06+00 0101000020E6100000732EC55565DF4340C24CDBBFB2920FC0 -3.94663 39.74528 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +687 359857082910589 ACC_OFF 2026-04-23 10:43:57+00 0101000020E6100000EEB1F4A10B76424077F35487DC8CF2BF -1.15939 36.92223 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +780 359857082046145 ACC_OFF 2026-04-23 10:19:49+00 0101000020E61000003BDF4F8D97D64340289B7285771910C0 -4.02487 39.6765 0.00 \N 2026-04-23 10:48:59.108685+00 ACC OFF poll \N \N \N \N \N +4808 865135061562722 3 2026-04-23 12:30:52+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 12:31:41.058363+00 Vibration alert push \N \N \N \N \N +4809 865135061581904 3 2026-04-23 12:31:39+00 0101000020E6100000B75ED38382564240850A0E2F88C8F3BF -1.236458 36.675858 \N \N 2026-04-23 12:31:41.064331+00 Vibration alert push \N \N \N \N \N +4811 865135061563282 3 2026-04-23 12:32:39+00 0101000020E6100000EBE40CC51D454040CE716E13EE95C93F 0.199888 32.539971 \N \N 2026-04-23 12:32:47.156339+00 Vibration alert push \N \N \N \N \N +4812 865135061563639 stayAlertOn 2026-04-23 12:32:56+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 \N \N 2026-04-23 12:32:56.669016+00 Idling alert push \N \N \N \N \N +4814 359857081891566 1002 2026-04-23 12:33:18+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 12:33:19.687547+00 ACC ON push \N \N \N \N \N +4815 865135061569123 1002 2026-04-23 12:33:37+00 0101000020E61000003CDD79E239634240CD3B4ED191DCF4BF -1.30385 36.775204 \N \N 2026-04-23 12:33:38.574852+00 ACC ON push \N \N \N \N \N +4816 359857082898487 1001 2026-04-23 12:33:39+00 0101000020E6100000DC63E943177C4240AA0EB9196EC0F2BF -1.17198 36.96946 \N \N 2026-04-23 12:33:39.710088+00 ACC OFF push \N \N \N \N \N +4817 865135061035133 1002 2026-04-23 12:33:57+00 0101000020E61000003EE8D9ACFABC4340F88903E8F7DD0EC0 -3.858383 39.4764 \N \N 2026-04-23 12:33:58.868922+00 ACC ON push \N \N \N \N \N +4818 865135061563597 stayAlertOn 2026-04-23 12:33:58+00 0101000020E61000004815C5ABAC534240828E56B5A4E3F1BF -1.118077 36.653707 \N \N 2026-04-23 12:33:58.960774+00 Idling alert push \N \N \N \N \N +4819 359857081892309 stayAlertOn 2026-04-23 12:34:24+00 0101000020E6100000697407B1337142406F9EEA909B61F3BF -1.21133 36.88439 \N \N 2026-04-23 12:34:24.804829+00 Idling alert push \N \N \N \N \N +4992 359857081887192 1001 2026-04-23 12:34:26+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 12:34:27.256636+00 ACC OFF push \N \N \N \N \N +4993 862798050523626 147 2026-04-23 12:34:25+00 0101000020E61000006326512FF8BC434086730D3334DE0EC0 -3.858498 39.476324 0.00 \N 2026-04-23 12:34:27.68109+00 Collision Alert(DVR) push \N \N \N \N \N +4994 359857082902461 1001 2026-04-23 12:34:27+00 0101000020E6100000FA0AD28C454B434035EF384547320BC0 -3.39955 38.58806 \N \N 2026-04-23 12:34:27.783385+00 ACC OFF push \N \N \N \N \N +4995 359857082900358 1002 2026-04-23 12:35:06+00 0101000020E6100000C0046EDDCD7B424090831266DAFEF6BF -1.43722 36.96722 \N \N 2026-04-23 12:35:06.661934+00 ACC ON push \N \N \N \N \N +4996 359857082910886 1001 2026-04-23 12:35:22+00 0101000020E61000006F2A52616CD943406458C51B992710C0 -4.03867 39.69862 \N \N 2026-04-23 12:35:22.881941+00 ACC OFF push \N \N \N \N \N +4998 865135061563282 1002 2026-04-23 12:36:03+00 0101000020E6100000988A8D791D4540403F73D6A71C93C93F 0.199802 32.539962 \N \N 2026-04-23 12:36:04.001506+00 ACC ON push \N \N \N \N \N +4999 359857082918186 1001 2026-04-23 12:36:07+00 0101000020E6100000B0C91AF51055424055F65D11FCEFF3BF -1.24609 36.66458 \N \N 2026-04-23 12:36:07.909474+00 ACC OFF push \N \N \N \N \N +5000 359857082910886 1004 2026-04-23 12:36:21+00 0101000020E61000006F2A52616CD943406458C51B992710C0 -4.03867 39.69862 \N \N 2026-04-23 12:36:21.75439+00 Parking alert push \N \N \N \N \N +5001 359857082902461 1002 2026-04-23 12:36:42+00 0101000020E6100000FA0AD28C454B4340FC00A43671320BC0 -3.39963 38.58806 \N \N 2026-04-23 12:36:42.939518+00 ACC ON push \N \N \N \N \N +5002 359857081886905 1002 2026-04-23 12:36:45+00 0101000020E6100000A453573ECBDF43401D38674469AF0FC0 -3.96065 39.74839 \N \N 2026-04-23 12:36:46.568216+00 ACC ON push \N \N \N \N \N +5003 359857081892309 1001 2026-04-23 12:37:20+00 0101000020E61000008C4AEA04347142406F9EEA909B61F3BF -1.21133 36.8844 \N \N 2026-04-23 12:37:21.743479+00 ACC OFF push \N \N \N \N \N +5004 865135061053714 1002 2026-04-23 12:37:59+00 0101000020E61000005D8B16A06D7742404E452A8C2D04F3BF -1.18852 36.933033 \N \N 2026-04-23 12:38:00.151531+00 ACC ON push \N \N \N \N \N +5007 359857082898487 stayAlertOn 2026-04-23 12:38:26+00 0101000020E6100000DC63E943177C4240AA0EB9196EC0F2BF -1.17198 36.96946 \N \N 2026-04-23 12:38:26.95571+00 Idling alert push \N \N \N \N \N +5167 865135061562722 3 2026-04-23 12:40:47+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 12:40:56.628146+00 Vibration alert push \N \N \N \N \N +5173 359857082897091 1002 2026-04-23 12:42:34+00 0101000020E610000026E4839ECD7242408E75711B0D60F3BF -1.21095 36.8969 \N \N 2026-04-23 12:42:35.463631+00 ACC ON push \N \N \N \N \N +5174 359857082907973 1002 2026-04-23 12:42:37+00 0101000020E610000095F1EF332EBC43407B319413ED4A11C0 -4.32317 39.47016 \N \N 2026-04-23 12:42:38.526965+00 ACC ON push \N \N \N \N \N +5175 359857082918186 1002 2026-04-23 12:43:03+00 0101000020E6100000B0C91AF51055424055F65D11FCEFF3BF -1.24609 36.66458 \N \N 2026-04-23 12:43:03.470413+00 ACC ON push \N \N \N \N \N +5176 862798050523626 146 2026-04-23 12:43:04+00 0101000020E61000001895D40968BE4340E42F2DEA937C0EC0 -3.810829 39.48755 53.00 \N 2026-04-23 12:43:06.141014+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +5178 359857081891566 1002 2026-04-23 12:43:20+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 12:43:21.672923+00 ACC ON push \N \N \N \N \N +5179 359857082900358 1002 2026-04-23 12:43:29+00 0101000020E61000009D11A5BDC17B424062156F641EF9F6BF -1.43582 36.96685 \N \N 2026-04-23 12:43:30.333779+00 ACC ON push \N \N \N \N \N +5180 359857082897257 1002 2026-04-23 12:43:41+00 0101000020E6100000BA83D89942774240EF552B137EA9F3BF -1.22888 36.93172 \N \N 2026-04-23 12:43:42.232942+00 ACC ON push \N \N \N \N \N +783 865135061569479 3 2026-04-23 10:48:58+00 0101000020E6100000755776C1E04440408672A25D8594C13F 0.137345 32.538109 12.00 \N 2026-04-23 10:49:00.169937+00 Vibration alert push \N \N \N \N \N +786 862798050288345 1001 2026-04-23 10:49:52+00 0101000020E61000000C569C6A2D9043409DB81CAF40A411C0 -4.410403 39.126386 \N \N 2026-04-23 10:49:53.932099+00 ACC OFF push \N \N \N \N \N +787 865135061569123 1002 2026-04-23 10:49:23+00 0101000020E61000001536035C905F4240AF7C96E7C1DDF4BF -1.30414 36.746593 \N \N 2026-04-23 10:49:58.449469+00 ACC ON push \N \N \N \N \N +788 862798050523527 1002 2026-04-23 10:50:01+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 \N \N 2026-04-23 10:50:02.152481+00 ACC ON push \N \N \N \N \N +789 865135061569131 3 2026-04-23 10:49:44+00 0101000020E6100000D20149D8B7454040B3B45373B9C1C43F 0.162162 32.544673 27.00 \N 2026-04-23 10:50:20.840815+00 Vibration alert push \N \N \N \N \N +790 359857082908500 1001 2026-04-23 10:49:51+00 0101000020E6100000B9C7D2872E904340DCBA9BA73AA411C0 -4.41038 39.12642 \N \N 2026-04-23 10:50:25.639416+00 ACC OFF push \N \N \N \N \N +791 359857082918012 stayAlertOn 2026-04-23 10:50:44+00 0101000020E61000004833164D676B4240C364AA605452F3BF -1.2076 36.83909 \N \N 2026-04-23 10:50:44.605571+00 Idling alert push \N \N \N \N \N +792 359857082037185 1002 2026-04-23 10:50:40+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 10:51:08.665273+00 ACC ON push \N \N \N \N \N +793 359857082896911 1002 2026-04-23 10:50:40+00 0101000020E6100000E4A08499B66B4240868F882991C4F2BF -1.17299 36.84151 \N \N 2026-04-23 10:51:08.74392+00 ACC ON push \N \N \N \N \N +794 862798050523626 128 2026-04-23 10:50:46+00 0101000020E61000005C3CBCE7C0BC4340CF2F4AD05FE80EC0 -3.863464 39.474637 0.00 \N 2026-04-23 10:51:18.245194+00 DVR vibration alert push \N \N \N \N \N +795 865135061569479 3 2026-04-23 10:51:18+00 0101000020E6100000D828EB37134540401EDD088B8A38C13F 0.134538 32.539649 \N \N 2026-04-23 10:51:20.524907+00 Vibration alert push \N \N \N \N \N +796 359857082897091 1002 2026-04-23 10:51:36+00 0101000020E610000026FC523F6F72424024287E8CB96BF3BF -1.2138 36.89402 \N \N 2026-04-23 10:51:36.307625+00 ACC ON push \N \N \N \N \N +797 359857081892101 1001 2026-04-23 10:52:09+00 0101000020E61000001CEBE2361A6842406C5B94D92093F4BF -1.28592 36.8133 \N \N 2026-04-23 10:52:10.189668+00 ACC OFF push \N \N \N \N \N +798 865135061563597 3 2026-04-23 10:51:04+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 10:52:15.027963+00 Vibration alert push \N \N \N \N \N +799 359857081891566 1002 2026-04-23 10:51:59+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 10:52:18.738221+00 ACC ON push \N \N \N \N \N +4810 862798050523626 1002 2026-04-23 12:32:22+00 0101000020E61000003A933655F7BC434096CCB1BCABDE0EC0 -3.858726 39.476298 \N \N 2026-04-23 12:32:22.839642+00 ACC ON push \N \N \N \N \N +4813 865135061564470 3 2026-04-23 12:33:06+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 \N \N 2026-04-23 12:33:10.024715+00 Vibration alert push \N \N \N \N \N +4997 359857082042854 1002 2026-04-23 12:35:39+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 \N \N 2026-04-23 12:35:39.988665+00 ACC ON push \N \N \N \N \N +5005 865135061048953 1001 2026-04-23 12:38:16+00 0101000020E61000001FA1664815DB43408BE1EA0088FB0FC0 -3.997818 39.711587 \N \N 2026-04-23 12:38:17.657928+00 ACC OFF push \N \N \N \N \N +5006 359857081891566 stayAlertOn 2026-04-23 12:38:18+00 0101000020E6100000DF89592F8672424040C1C58A1A4CF3BF -1.20608 36.89472 \N \N 2026-04-23 12:38:18.645715+00 Idling alert push \N \N \N \N \N +5008 865135061035778 1004 2026-04-23 12:38:36+00 0101000020E6100000747973B8567D424091442FA3582EF2BF -1.136315 36.979209 \N \N 2026-04-23 12:38:37.084542+00 Parking alert push \N \N \N \N \N +5009 865135061569123 stayAlertOn 2026-04-23 12:38:37+00 0101000020E61000003CDD79E239634240CD3B4ED191DCF4BF -1.30385 36.775204 \N \N 2026-04-23 12:38:37.80921+00 Idling alert push \N \N \N \N \N +5163 359857082900358 1001 2026-04-23 12:39:49+00 0101000020E6100000C0E78711C27B4240F05014E813F9F6BF -1.43581 36.96686 \N \N 2026-04-23 12:39:51.038929+00 ACC OFF push \N \N \N \N \N +5164 359857081891566 1001 2026-04-23 12:40:08+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 12:40:09.132822+00 ACC OFF push \N \N \N \N \N +5165 865135061053748 1001 2026-04-23 12:40:44+00 0101000020E6100000AA0CE36E10D54340C6C4E6E3DA2010C0 -4.032085 39.664564 \N \N 2026-04-23 12:40:45.194964+00 ACC OFF push \N \N \N \N \N +5166 862798050526231 1001 2026-04-23 12:40:46+00 0101000020E6100000BC77D49810D54340F38FBE49D32010C0 -4.032056 39.664569 \N \N 2026-04-23 12:40:48.044566+00 ACC OFF push \N \N \N \N \N +5168 865135061047435 1001 2026-04-23 12:41:11+00 0101000020E6100000A20BEA5BE66442407218CC5F2173F4BF -1.278108 36.78828 \N \N 2026-04-23 12:41:12.821915+00 ACC OFF push \N \N \N \N \N +5169 865135061053748 1004 2026-04-23 12:41:45+00 0101000020E6100000D66F26A60BD54340A913D044D82010C0 -4.032075 39.664418 \N \N 2026-04-23 12:41:45.714099+00 Parking alert push \N \N \N \N \N +5170 359857082037185 1002 2026-04-23 12:41:47+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 12:41:48.600714+00 ACC ON push \N \N \N \N \N +5171 865135061047435 1004 2026-04-23 12:42:11+00 0101000020E6100000A20BEA5BE66442407218CC5F2173F4BF -1.278108 36.78828 \N \N 2026-04-23 12:42:11.647717+00 Parking alert push \N \N \N \N \N +5172 359857082918038 1001 2026-04-23 12:42:13+00 0101000020E6100000459E245D33494340DB85E63A8D340BC0 -3.40066 38.57188 \N \N 2026-04-23 12:42:14.09627+00 ACC OFF push \N \N \N \N \N +5177 862798050521521 128 2026-04-23 12:43:09+00 0101000020E61000009468C9E3697D42408C65FA25E22DF2BF -1.136202 36.979794 0.00 \N 2026-04-23 12:43:12.69309+00 DVR vibration alert push \N \N \N \N \N +5325 862798050526231 1002 2026-04-23 12:44:30+00 0101000020E6100000BC77D49810D54340F38FBE49D32010C0 -4.032056 39.664569 \N \N 2026-04-23 12:44:31.119493+00 ACC ON push \N \N \N \N \N +5326 359857082037185 1001 2026-04-23 12:44:32+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 12:44:33.748147+00 ACC OFF push \N \N \N \N \N +5327 359857082918186 1001 2026-04-23 12:44:51+00 0101000020E6100000B0C91AF510554240726DA818E7EFF3BF -1.24607 36.66458 \N \N 2026-04-23 12:44:51.710448+00 ACC OFF push \N \N \N \N \N +5328 865135061054555 1002 2026-04-23 12:45:19+00 0101000020E61000000403081F4A3042408E95986725ADD1BF -0.276193 36.377262 \N \N 2026-04-23 12:45:20.255871+00 ACC ON push \N \N \N \N \N +5329 865135061043426 1001 2026-04-23 12:46:03+00 0101000020E61000003B35971B0C5B42402F4D11E0F4AEF0BF -1.042714 36.711307 \N \N 2026-04-23 12:46:03.780646+00 ACC OFF push \N \N \N \N \N +5331 359857082897091 1001 2026-04-23 12:46:34+00 0101000020E610000042959A3DD0724240359886E12362F3BF -1.21146 36.89698 \N \N 2026-04-23 12:46:34.941964+00 ACC OFF push \N \N \N \N \N +5332 865135061562847 3 2026-04-23 12:45:50+00 0101000020E61000002541B8020A814240B2F50CE198A5F1BF -1.102929 37.008118 \N \N 2026-04-23 12:46:37.870852+00 Vibration alert push \N \N \N \N \N +5341 359857082898008 1002 2026-04-23 12:49:02+00 0101000020E6100000475A2A6F47704240200C3CF71EAEF3BF -1.23001 36.87718 \N \N 2026-04-23 12:49:02.647466+00 ACC ON push \N \N \N \N \N +5342 862798052708068 1002 2026-04-23 12:49:03+00 0101000020E6100000AB2006BAF6534240ED9FA70183E4F1BF -1.118289 36.655967 \N \N 2026-04-23 12:49:04.636464+00 ACC ON push \N \N \N \N \N +5343 862798050526231 1001 2026-04-23 12:49:17+00 0101000020E6100000DE58501894D54340EEEC2B0FD22310C0 -4.034981 39.668582 \N \N 2026-04-23 12:49:17.846809+00 ACC OFF push \N \N \N \N \N +5481 359857082900358 1001 2026-04-23 12:49:54+00 0101000020E61000002315C616827C4240D52137C30DF8F6BF -1.43556 36.97272 \N \N 2026-04-23 12:49:54.783006+00 ACC OFF push \N \N \N \N \N +5486 865135061563282 1001 2026-04-23 12:50:37+00 0101000020E6100000EBE40CC51D454040CE716E13EE95C93F 0.199888 32.539971 \N \N 2026-04-23 12:50:38.020258+00 ACC OFF push \N \N \N \N \N +5487 359857081891566 1001 2026-04-23 12:50:57+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 12:50:58.076265+00 ACC OFF push \N \N \N \N \N +5492 359857082918038 1002 2026-04-23 12:51:27+00 0101000020E61000008C4AEA043449434014E8137992340BC0 -3.40067 38.5719 \N \N 2026-04-23 12:51:27.927677+00 ACC ON push \N \N \N \N \N +5494 359857081885410 1002 2026-04-23 12:51:56+00 0101000020E6100000D13FC1C58A72424003CFBD874B0EF3BF -1.19099 36.89486 \N \N 2026-04-23 12:51:56.692747+00 ACC ON push \N \N \N \N \N +5495 865135061054548 1002 2026-04-23 12:51:56+00 0101000020E6100000817A336ABE724240B6B9313D6109F3BF -1.18979 36.896436 \N \N 2026-04-23 12:51:57.125603+00 ACC ON push \N \N \N \N \N +5496 865135061048466 1002 2026-04-23 12:51:58+00 0101000020E6100000FA2AF9D85D52424083A5BA8097D9F1BF -1.115623 36.643489 \N \N 2026-04-23 12:51:59.184388+00 ACC ON push \N \N \N \N \N +5497 865135061563282 3 2026-04-23 12:52:02+00 0101000020E61000001344DD07204540400E2E1D739EB1C93F 0.200733 32.54004 \N \N 2026-04-23 12:52:04.444613+00 Vibration alert push \N \N \N \N \N +5498 865135061569123 1004 2026-04-23 12:52:04+00 0101000020E61000008EC9E2FE23634240685A626534B2F4BF -1.293507 36.774536 \N \N 2026-04-23 12:52:04.91656+00 Parking alert push \N \N \N \N \N +5499 359857082037185 1002 2026-04-23 12:52:08+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 12:52:08.840489+00 ACC ON push \N \N \N \N \N +5500 865135061053748 1002 2026-04-23 12:52:11+00 0101000020E61000004BC8073D9BD54340AF93FAB2B42310C0 -4.034869 39.6688 \N \N 2026-04-23 12:52:11.678894+00 ACC ON push \N \N \N \N \N +784 359857081886905 1002 2026-04-23 10:49:20+00 0101000020E6100000A67EDE54A4DE4340514EB4AB90B20FC0 -3.96219 39.73939 \N \N 2026-04-23 10:49:21.387551+00 ACC ON push \N \N \N \N \N +785 865135061569123 3 2026-04-23 10:48:24+00 0101000020E61000001536035C905F4240AF7C96E7C1DDF4BF -1.30414 36.746593 \N \N 2026-04-23 10:49:23.548936+00 Vibration alert push \N \N \N \N \N +800 865135061569131 3 2026-04-23 10:53:14+00 0101000020E610000061191BBAD9454040EE5EEE93A300C33F 0.148457 32.545707 15.00 \N 2026-04-23 10:53:15.834798+00 Vibration alert push \N \N \N \N \N +801 862798050523527 1001 2026-04-23 10:53:18+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 \N \N 2026-04-23 10:53:26.35683+00 ACC OFF push \N \N \N \N \N +802 359857081891632 1002 2026-04-23 10:53:26+00 0101000020E61000008121AB5B3D6F424086200725CCB4F3BF -1.23164 36.86906 \N \N 2026-04-23 10:53:27.653953+00 ACC ON push \N \N \N \N \N +803 865135061048953 1002 2026-04-23 10:53:30+00 0101000020E6100000E7FEEA71DFDC4340124E0B5EF41510C0 -4.02144 39.725569 \N \N 2026-04-23 10:53:31.102315+00 ACC ON push \N \N \N \N \N +804 359857081892309 stayAlertOn 2026-04-23 10:53:35+00 0101000020E6100000F6B4C35F93714240BD5296218E75F3BF -1.2162 36.88731 \N \N 2026-04-23 10:53:38.37469+00 Idling alert push \N \N \N \N \N +805 865135061569479 3 2026-04-23 10:53:40+00 0101000020E6100000F71E2E39EE444040587380608E1EC13F 0.133745 32.53852 \N \N 2026-04-23 10:53:42.501573+00 Vibration alert push \N \N \N \N \N +810 865135061569123 ACC_ON 2026-04-23 10:49:23+00 0101000020E61000001536035C905F4240AF7C96E7C1DDF4BF -1.30414 36.746593 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +848 359857081891632 ACC_ON 2026-04-23 10:53:26+00 0101000020E61000008121AB5B3D6F424086200725CCB4F3BF -1.23164 36.86906 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +849 862798050523527 ACC_OFF 2026-04-23 10:53:18+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:54:00.191865+00 ACC OFF poll \N \N \N \N \N +850 359857081892101 ACC_OFF 2026-04-23 10:52:09+00 0101000020E61000001CEBE2361A6842406C5B94D92093F4BF -1.28592 36.8133 0.00 \N 2026-04-23 10:54:00.191865+00 ACC OFF poll \N \N \N \N \N +851 359857081891566 ACC_ON 2026-04-23 10:51:59+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +852 359857082897091 ACC_ON 2026-04-23 10:51:36+00 0101000020E610000026FC523F6F72424024287E8CB96BF3BF -1.2138 36.89402 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +854 862798050523626 128 2026-04-23 10:50:47+00 0101000020E61000005C3CBCE7C0BC4340CF2F4AD05FE80EC0 -3.863464 39.474637 0.00 \N 2026-04-23 10:54:00.191865+00 DVR vibration alert poll \N \N \N \N \N +856 359857082037185 ACC_ON 2026-04-23 10:50:40+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +857 359857082896911 ACC_ON 2026-04-23 10:50:40+00 0101000020E6100000E4A08499B66B4240868F882991C4F2BF -1.17299 36.84151 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +858 862798050523527 ACC_ON 2026-04-23 10:50:01+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +859 862798050288345 ACC_OFF 2026-04-23 10:49:52+00 0101000020E61000000C569C6A2D9043409DB81CAF40A411C0 -4.410403 39.126386 0.00 \N 2026-04-23 10:54:00.191865+00 ACC OFF poll \N \N \N \N \N +860 359857082908500 ACC_OFF 2026-04-23 10:49:51+00 0101000020E6100000B9C7D2872E904340DCBA9BA73AA411C0 -4.41038 39.12642 0.00 \N 2026-04-23 10:54:00.191865+00 ACC OFF poll \N \N \N \N \N +861 359857081886905 ACC_ON 2026-04-23 10:49:20+00 0101000020E6100000A67EDE54A4DE4340514EB4AB90B20FC0 -3.96219 39.73939 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +964 865135061048953 ACC_ON 2026-04-23 10:53:30+00 0101000020E6100000E7FEEA71DFDC4340124E0B5EF41510C0 -4.02144 39.725569 0.00 \N 2026-04-23 10:54:00.191865+00 ACC ON poll \N \N \N \N \N +965 862798052707946 1001 2026-04-23 10:54:11+00 0101000020E610000075AC527AA66F42408CF2CCCB61B7F2BF -1.169771 36.872268 \N \N 2026-04-23 10:54:12.160021+00 ACC OFF push \N \N \N \N \N +966 865135061581904 3 2026-04-23 10:54:32+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 \N \N 2026-04-23 10:54:34.626388+00 Vibration alert push \N \N \N \N \N +967 865135061048276 1002 2026-04-23 10:54:40+00 0101000020E61000002C0FD253E4D4434091990B5C1E3B10C0 -4.057733 39.663218 \N \N 2026-04-23 10:54:41.63532+00 ACC ON push \N \N \N \N \N +968 862798050523337 1002 2026-04-23 10:54:40+00 0101000020E6100000670DDE57E5D44340B3075A81213B10C0 -4.057745 39.663249 \N \N 2026-04-23 10:54:42.39286+00 ACC ON push \N \N \N \N \N +969 862798050523527 stayAlertOn 2026-04-23 10:55:01+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 \N \N 2026-04-23 10:55:01.745225+00 Idling alert push \N \N \N \N \N +970 359857081891632 1001 2026-04-23 10:55:03+00 0101000020E610000048F949B54F6F4240A6272CF180B2F3BF -1.23108 36.86962 \N \N 2026-04-23 10:55:03.857849+00 ACC OFF push \N \N \N \N \N +971 865135061563639 1001 2026-04-23 10:55:03+00 0101000020E61000002FA699EE75F4424017BCE82B4833FCBF -1.76252 37.909849 \N \N 2026-04-23 10:55:03.944903+00 ACC OFF push \N \N \N \N \N +972 359857082897091 1001 2026-04-23 10:55:21+00 0101000020E610000098A3C7EF6D724240B8239C16BC68F3BF -1.21307 36.89398 \N \N 2026-04-23 10:55:22.845912+00 ACC OFF push \N \N \N \N \N +973 865135061569131 3 2026-04-23 10:55:34+00 0101000020E61000003677F4BF5C454040B8AE9811DE1EC23F 0.141567 32.541893 22.00 \N 2026-04-23 10:55:36.704574+00 Vibration alert push \N \N \N \N \N +974 359857082896911 stayAlertOn 2026-04-23 10:55:40+00 0101000020E6100000E4A08499B66B4240868F882991C4F2BF -1.17299 36.84151 \N \N 2026-04-23 10:55:40.227234+00 Idling alert push \N \N \N \N \N +975 865135061563639 1004 2026-04-23 10:55:51+00 0101000020E61000002FA699EE75F4424017BCE82B4833FCBF -1.76252 37.909849 \N \N 2026-04-23 10:55:51.612563+00 Parking alert push \N \N \N \N \N +976 359857082911983 1001 2026-04-23 10:56:02+00 0101000020E61000005BD3BCE31471424050C763062A63F2BF -1.14921 36.88345 \N \N 2026-04-23 10:56:03.288768+00 ACC OFF push \N \N \N \N \N +977 862798050288360 1001 2026-04-23 10:56:03+00 0101000020E6100000BADBF5D214714240EF737CB43863F2BF -1.149224 36.883448 \N \N 2026-04-23 10:56:03.840923+00 ACC OFF push \N \N \N \N \N +978 359857082046145 1001 2026-04-23 10:56:11+00 0101000020E61000005704FF5BC9D64340622D3E05C01810C0 -4.02417 39.67802 \N \N 2026-04-23 10:56:12.565735+00 ACC OFF push \N \N \N \N \N +979 865135061563639 3 2026-04-23 10:56:15+00 0101000020E61000002FA699EE75F4424017BCE82B4833FCBF -1.76252 37.909849 \N \N 2026-04-23 10:56:16.061195+00 Vibration alert push \N \N \N \N \N +980 359857082897794 1002 2026-04-23 10:56:20+00 0101000020E610000050C763062A674240A31EA2D11D44F4BF -1.26663 36.80597 \N \N 2026-04-23 10:56:21.606103+00 ACC ON push \N \N \N \N \N +981 359857082897091 1004 2026-04-23 10:56:21+00 0101000020E610000098A3C7EF6D724240B8239C16BC68F3BF -1.21307 36.89398 \N \N 2026-04-23 10:56:21.913803+00 Parking alert push \N \N \N \N \N +982 865135061562847 1001 2026-04-23 10:56:27+00 0101000020E6100000E43098BF42824240543882548A9DF1BF -1.100962 37.017662 \N \N 2026-04-23 10:56:27.75897+00 ACC OFF push \N \N \N \N \N +983 359857081886467 1001 2026-04-23 10:56:37+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 \N \N 2026-04-23 10:56:37.983314+00 ACC OFF push \N \N \N \N \N +984 359857081891566 stayAlertOn 2026-04-23 10:56:59+00 0101000020E610000075029A081B6A4240745E6397A85EF4BF -1.27311 36.82895 \N \N 2026-04-23 10:56:59.910387+00 Idling alert push \N \N \N \N \N +985 359857081891632 1004 2026-04-23 10:57:01+00 0101000020E6100000F302ECA3536F4240C3B645990DB2F3BF -1.23097 36.86974 \N \N 2026-04-23 10:57:02.049262+00 Parking alert push \N \N \N \N \N +986 865135061563597 3 2026-04-23 10:55:14+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 10:57:32.550587+00 Vibration alert push \N \N \N \N \N +987 865135061569479 1004 2026-04-23 10:57:51+00 0101000020E6100000F71E2E39EE444040587380608E1EC13F 0.133745 32.53852 \N \N 2026-04-23 10:57:51.748233+00 Parking alert push \N \N \N \N \N +988 865135061569131 3 2026-04-23 10:57:55+00 0101000020E6100000D76A0F7BA14440407EC51A2E724FC13F 0.135237 32.536178 30.00 \N 2026-04-23 10:57:56.318133+00 Vibration alert push \N \N \N \N \N +989 359857082897091 1002 2026-04-23 10:57:58+00 0101000020E6100000BC79AA436E724240B8239C16BC68F3BF -1.21307 36.89399 \N \N 2026-04-23 10:57:58.966863+00 ACC ON push \N \N \N \N \N +990 359857081886467 1002 2026-04-23 10:57:59+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 \N \N 2026-04-23 10:57:59.904684+00 ACC ON push \N \N \N \N \N +991 865135061563639 1002 2026-04-23 10:58:01+00 0101000020E61000002FA699EE75F4424017BCE82B4833FCBF -1.76252 37.909849 \N \N 2026-04-23 10:58:01.532038+00 ACC ON push \N \N \N \N \N +992 862798050523337 147 2026-04-23 10:58:01+00 0101000020E6100000AA4885B185D443401155F833BC3910C0 -4.056382 39.66033 22.00 \N 2026-04-23 10:58:04.81593+00 Collision Alert(DVR) push \N \N \N \N \N +993 865135061054548 1002 2026-04-23 10:58:08+00 0101000020E6100000304AD05FE87142408FA850DD5CFCF2BF -1.186612 36.889904 \N \N 2026-04-23 10:58:08.615422+00 ACC ON push \N \N \N \N \N +994 865135061048953 1001 2026-04-23 10:58:11+00 0101000020E6100000E7FEEA71DFDC4340952C27A1F41510C0 -4.021441 39.725569 \N \N 2026-04-23 10:58:12.575165+00 ACC OFF push \N \N \N \N \N +995 359857082897794 1001 2026-04-23 10:58:12+00 0101000020E6100000E5D022DBF9664240D105F52D733AF4BF -1.26427 36.8045 \N \N 2026-04-23 10:58:12.812931+00 ACC OFF push \N \N \N \N \N +996 359857081891566 1001 2026-04-23 10:58:44+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 10:58:45.093112+00 ACC OFF push \N \N \N \N \N +997 865135061048953 2 2026-04-23 10:58:49+00 0101000020E610000028EE7893DFDC43407E384888F21510C0 -4.021433 39.725573 \N \N 2026-04-23 10:58:51.181769+00 Power cut off alert push \N \N \N \N \N +1161 359857082897794 1002 2026-04-23 10:59:31+00 0101000020E6100000E5D022DBF9664240D105F52D733AF4BF -1.26427 36.8045 \N \N 2026-04-23 10:59:31.994216+00 ACC ON push \N \N \N \N \N +1162 862798050288360 1002 2026-04-23 10:59:34+00 0101000020E6100000BADBF5D214714240EF737CB43863F2BF -1.149224 36.883448 \N \N 2026-04-23 10:59:35.528789+00 ACC ON push \N \N \N \N \N +1163 359857082911983 1002 2026-04-23 10:59:34+00 0101000020E6100000A27F828B1571424050C763062A63F2BF -1.14921 36.88347 \N \N 2026-04-23 10:59:35.725915+00 ACC ON push \N \N \N \N \N +1165 865135061563597 3 2026-04-23 10:59:36+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 11:00:03.467945+00 Vibration alert push \N \N \N \N \N +1166 359857081887069 1002 2026-04-23 11:00:08+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 11:00:08.769463+00 ACC ON push \N \N \N \N \N +1167 359857082038977 1002 2026-04-23 11:00:14+00 0101000020E61000007E74EACA67D94340BABDA4315A2710C0 -4.03843 39.69848 \N \N 2026-04-23 11:00:14.848068+00 ACC ON push \N \N \N \N \N +1168 865135061569131 3 2026-04-23 11:00:15+00 0101000020E610000048A643A7E743404043C6A354C213C03F 0.125603 32.530507 56.00 \N 2026-04-23 11:00:16.757462+00 Vibration alert push \N \N \N \N \N +4820 865135061569123 ACC_ON 2026-04-23 12:33:37+00 0101000020E61000003CDD79E239634240CD3B4ED191DCF4BF -1.30385 36.775204 0.00 \N 2026-04-23 12:34:25.561416+00 ACC ON poll \N \N \N \N \N +4825 862798052708068 stayAlert 2026-04-23 12:31:31+00 0101000020E6100000AB2006BAF6534240ED9FA70183E4F1BF -1.118289 36.655967 0.00 \N 2026-04-23 12:34:25.561416+00 Parking alert poll \N \N \N \N \N +4826 865135061581904 stayAlert 2026-04-23 12:31:16+00 0101000020E6100000B75ED38382564240850A0E2F88C8F3BF -1.236458 36.675858 0.00 \N 2026-04-23 12:34:25.561416+00 Parking alert poll \N \N \N \N \N +4828 862798052708068 ACC_OFF 2026-04-23 12:30:31+00 0101000020E61000006A317898F65342408E20956247E3F1BF -1.117988 36.655963 0.00 \N 2026-04-23 12:34:25.561416+00 ACC OFF poll \N \N \N \N \N +4829 865135061581904 ACC_OFF 2026-04-23 12:30:16+00 0101000020E610000015FF774485564240D8648D7A88C6F3BF -1.23597 36.675942 0.00 \N 2026-04-23 12:34:25.561416+00 ACC OFF poll \N \N \N \N \N +4884 359857082898487 ACC_OFF 2026-04-23 12:33:39+00 0101000020E6100000DC63E943177C4240AA0EB9196EC0F2BF -1.17198 36.96946 0.00 \N 2026-04-23 12:34:25.561416+00 ACC OFF poll \N \N \N \N \N +4885 359857081891566 ACC_ON 2026-04-23 12:33:18+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 12:34:25.561416+00 ACC ON poll \N \N \N \N \N +4886 862798050523626 ACC_ON 2026-04-23 12:32:22+00 0101000020E61000003A933655F7BC434096CCB1BCABDE0EC0 -3.858726 39.476298 0.00 \N 2026-04-23 12:34:25.561416+00 ACC ON poll \N \N \N \N \N +4887 865135061563597 ACC_OFF 2026-04-23 12:31:05+00 0101000020E6100000C8409E5DBE534240F949B54FC7E3F1BF -1.11811 36.654247 0.00 \N 2026-04-23 12:34:25.561416+00 ACC OFF poll \N \N \N \N \N +4888 862798050288360 stayAlert 2026-04-23 12:31:00+00 0101000020E61000008978EBFCDB6F4240CAA65CE15DAEF3BF -1.23007 36.873901 0.00 \N 2026-04-23 12:34:25.561416+00 Parking alert poll \N \N \N \N \N +4890 359857082898487 ACC_ON 2026-04-23 12:30:47+00 0101000020E61000007250C24CDB7B42408D7F9F71E1C0F2BF -1.17209 36.96763 0.00 \N 2026-04-23 12:34:25.561416+00 ACC ON poll \N \N \N \N \N +4891 359857081891632 stayAlert 2026-04-23 12:29:34+00 0101000020E610000087DC0C37E06F4240E7357689EAADF3BF -1.22996 36.87403 0.00 \N 2026-04-23 12:34:25.561416+00 Parking alert poll \N \N \N \N \N +4892 359857081892309 ACC_ON 2026-04-23 12:29:24+00 0101000020E6100000697407B1337142406F9EEA909B61F3BF -1.21133 36.88439 0.00 \N 2026-04-23 12:34:25.561416+00 ACC ON poll \N \N \N \N \N +4966 865135061035133 ACC_ON 2026-04-23 12:33:57+00 0101000020E61000003EE8D9ACFABC4340F88903E8F7DD0EC0 -3.858383 39.4764 0.00 \N 2026-04-23 12:34:25.561416+00 ACC ON poll \N \N \N \N \N +4967 862798050523139 128 2026-04-23 12:31:04+00 0101000020E610000021C8410933ED43406CB3B112F30C0DC0 -3.631323 39.85312 0.00 \N 2026-04-23 12:34:25.561416+00 DVR vibration alert poll \N \N \N \N \N +4968 359857082902461 ACC_ON 2026-04-23 12:30:58+00 0101000020E6100000C3BB5CC4774A4340E3AAB2EF8A200BC0 -3.39089 38.58178 0.00 \N 2026-04-23 12:34:25.561416+00 ACC ON poll \N \N \N \N \N +4970 359857082918038 ACC_ON 2026-04-23 12:29:56+00 0101000020E610000016DEE522BE4B4340DEB06D5166430BC0 -3.40791 38.59174 0.00 \N 2026-04-23 12:34:25.561416+00 ACC ON poll \N \N \N \N \N +5011 865135061035778 stayAlert 2026-04-23 12:38:36+00 0101000020E6100000747973B8567D424091442FA3582EF2BF -1.136315 36.979209 0.00 \N 2026-04-23 12:39:26.465869+00 Parking alert poll \N \N \N \N \N +5012 865135061053714 ACC_ON 2026-04-23 12:37:59+00 0101000020E61000005D8B16A06D7742404E452A8C2D04F3BF -1.18852 36.933033 0.00 \N 2026-04-23 12:39:26.465869+00 ACC ON poll \N \N \N \N \N +5013 865135061563282 ACC_ON 2026-04-23 12:36:03+00 0101000020E6100000988A8D791D4540403F73D6A71C93C93F 0.199802 32.539962 0.00 \N 2026-04-23 12:39:26.465869+00 ACC ON poll \N \N \N \N \N +5014 359857082900358 ACC_ON 2026-04-23 12:35:06+00 0101000020E6100000C0046EDDCD7B424090831266DAFEF6BF -1.43722 36.96722 0.00 \N 2026-04-23 12:39:26.465869+00 ACC ON poll \N \N \N \N \N +5065 359857081892309 ACC_OFF 2026-04-23 12:37:20+00 0101000020E61000008C4AEA04347142406F9EEA909B61F3BF -1.21133 36.8844 0.00 \N 2026-04-23 12:39:26.465869+00 ACC OFF poll \N \N \N \N \N +5066 359857081886905 ACC_ON 2026-04-23 12:36:45+00 0101000020E6100000A453573ECBDF43401D38674469AF0FC0 -3.96065 39.74839 0.00 \N 2026-04-23 12:39:26.465869+00 ACC ON poll \N \N \N \N \N +5067 359857082918186 ACC_OFF 2026-04-23 12:36:07+00 0101000020E6100000B0C91AF51055424055F65D11FCEFF3BF -1.24609 36.66458 0.00 \N 2026-04-23 12:39:26.465869+00 ACC OFF poll \N \N \N \N \N +5068 359857082042854 ACC_ON 2026-04-23 12:35:39+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 0.00 \N 2026-04-23 12:39:26.465869+00 ACC ON poll \N \N \N \N \N +5069 359857081887192 ACC_OFF 2026-04-23 12:34:26+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 12:39:26.465869+00 ACC OFF poll \N \N \N \N \N +5135 865135061048953 ACC_OFF 2026-04-23 12:38:16+00 0101000020E61000001FA1664815DB43408BE1EA0088FB0FC0 -3.997818 39.711587 0.00 \N 2026-04-23 12:39:26.465869+00 ACC OFF poll \N \N \N \N \N +5136 359857082902461 ACC_ON 2026-04-23 12:36:42+00 0101000020E6100000FA0AD28C454B4340FC00A43671320BC0 -3.39963 38.58806 0.00 \N 2026-04-23 12:39:26.465869+00 ACC ON poll \N \N \N \N \N +5137 359857082910886 stayAlert 2026-04-23 12:36:21+00 0101000020E61000006F2A52616CD943406458C51B992710C0 -4.03867 39.69862 0.00 \N 2026-04-23 12:39:26.465869+00 Parking alert poll \N \N \N \N \N +5138 359857082910886 ACC_OFF 2026-04-23 12:35:22+00 0101000020E61000006F2A52616CD943406458C51B992710C0 -4.03867 39.69862 0.00 \N 2026-04-23 12:39:26.465869+00 ACC OFF poll \N \N \N \N \N +5139 359857082902461 ACC_OFF 2026-04-23 12:34:27+00 0101000020E6100000FA0AD28C454B434035EF384547320BC0 -3.39955 38.58806 0.00 \N 2026-04-23 12:39:26.465869+00 ACC OFF poll \N \N \N \N \N +5140 862798050523626 147 2026-04-23 12:34:26+00 0101000020E61000006326512FF8BC434086730D3334DE0EC0 -3.858498 39.476324 0.00 \N 2026-04-23 12:39:26.465869+00 Collision Alert(DVR) poll \N \N \N \N \N +5181 359857082900358 ACC_ON 2026-04-23 12:43:29+00 0101000020E61000009D11A5BDC17B424062156F641EF9F6BF -1.43582 36.96685 0.00 \N 2026-04-23 12:44:27.352578+00 ACC ON poll \N \N \N \N \N +5182 865135061047435 stayAlert 2026-04-23 12:42:11+00 0101000020E6100000A20BEA5BE66442407218CC5F2173F4BF -1.278108 36.78828 0.00 \N 2026-04-23 12:44:27.352578+00 Parking alert poll \N \N \N \N \N +5183 865135061053748 stayAlert 2026-04-23 12:41:45+00 0101000020E6100000D66F26A60BD54340A913D044D82010C0 -4.032075 39.664418 0.00 \N 2026-04-23 12:44:27.352578+00 Parking alert poll \N \N \N \N \N +5184 865135061047435 ACC_OFF 2026-04-23 12:41:11+00 0101000020E6100000A20BEA5BE66442407218CC5F2173F4BF -1.278108 36.78828 0.00 \N 2026-04-23 12:44:27.352578+00 ACC OFF poll \N \N \N \N \N +5185 865135061053748 ACC_OFF 2026-04-23 12:40:44+00 0101000020E6100000AA0CE36E10D54340C6C4E6E3DA2010C0 -4.032085 39.664564 0.00 \N 2026-04-23 12:44:27.352578+00 ACC OFF poll \N \N \N \N \N +5186 359857082900358 ACC_OFF 2026-04-23 12:39:49+00 0101000020E6100000C0E78711C27B4240F05014E813F9F6BF -1.43581 36.96686 0.00 \N 2026-04-23 12:44:27.352578+00 ACC OFF poll \N \N \N \N \N +5233 359857082897257 ACC_ON 2026-04-23 12:43:41+00 0101000020E6100000BA83D89942774240EF552B137EA9F3BF -1.22888 36.93172 0.00 \N 2026-04-23 12:44:27.352578+00 ACC ON poll \N \N \N \N \N +5234 359857081891566 ACC_ON 2026-04-23 12:43:20+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 12:44:27.352578+00 ACC ON poll \N \N \N \N \N +5235 862798050521521 128 2026-04-23 12:43:11+00 0101000020E61000009468C9E3697D42408C65FA25E22DF2BF -1.136202 36.979794 0.00 \N 2026-04-23 12:44:27.352578+00 DVR vibration alert poll \N \N \N \N \N +998 865135061563639 ACC_ON 2026-04-23 10:58:01+00 0101000020E61000002FA699EE75F4424017BCE82B4833FCBF -1.76252 37.909849 0.00 \N 2026-04-23 10:59:01.490835+00 ACC ON poll \N \N \N \N \N +1000 865135061569479 stayAlert 2026-04-23 10:57:51+00 0101000020E6100000F71E2E39EE444040587380608E1EC13F 0.133745 32.53852 0.00 \N 2026-04-23 10:59:01.490835+00 Parking alert poll \N \N \N \N \N +1002 865135061563639 stayAlert 2026-04-23 10:55:51+00 0101000020E61000002FA699EE75F4424017BCE82B4833FCBF -1.76252 37.909849 0.00 \N 2026-04-23 10:59:01.490835+00 Parking alert poll \N \N \N \N \N +1004 865135061563639 ACC_OFF 2026-04-23 10:55:03+00 0101000020E61000002FA699EE75F4424017BCE82B4833FCBF -1.76252 37.909849 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1042 359857081891566 ACC_OFF 2026-04-23 10:58:44+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1043 359857082897794 ACC_OFF 2026-04-23 10:58:12+00 0101000020E6100000E5D022DBF9664240D105F52D733AF4BF -1.26427 36.8045 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1044 865135061054548 ACC_ON 2026-04-23 10:58:08+00 0101000020E6100000304AD05FE87142408FA850DD5CFCF2BF -1.186612 36.889904 0.00 \N 2026-04-23 10:59:01.490835+00 ACC ON poll \N \N \N \N \N +1045 862798050523337 147 2026-04-23 10:58:03+00 0101000020E6100000AA4885B185D443401155F833BC3910C0 -4.056382 39.66033 22.00 \N 2026-04-23 10:59:01.490835+00 Collision Alert(DVR) poll \N \N \N \N \N +1046 359857082897091 ACC_ON 2026-04-23 10:57:58+00 0101000020E6100000BC79AA436E724240B8239C16BC68F3BF -1.21307 36.89399 0.00 \N 2026-04-23 10:59:01.490835+00 ACC ON poll \N \N \N \N \N +1047 359857081891632 stayAlert 2026-04-23 10:57:01+00 0101000020E6100000F302ECA3536F4240C3B645990DB2F3BF -1.23097 36.86974 0.00 \N 2026-04-23 10:59:01.490835+00 Parking alert poll \N \N \N \N \N +1049 865135061562847 ACC_OFF 2026-04-23 10:56:27+00 0101000020E6100000E43098BF42824240543882548A9DF1BF -1.100962 37.017662 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1050 359857082897091 stayAlert 2026-04-23 10:56:21+00 0101000020E610000098A3C7EF6D724240B8239C16BC68F3BF -1.21307 36.89398 0.00 \N 2026-04-23 10:59:01.490835+00 Parking alert poll \N \N \N \N \N +1051 359857082897794 ACC_ON 2026-04-23 10:56:20+00 0101000020E610000050C763062A674240A31EA2D11D44F4BF -1.26663 36.80597 0.00 \N 2026-04-23 10:59:01.490835+00 ACC ON poll \N \N \N \N \N +1052 359857082046145 ACC_OFF 2026-04-23 10:56:11+00 0101000020E61000005704FF5BC9D64340622D3E05C01810C0 -4.02417 39.67802 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1053 862798050288360 ACC_OFF 2026-04-23 10:56:03+00 0101000020E6100000BADBF5D214714240EF737CB43863F2BF -1.149224 36.883448 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1054 359857082911983 ACC_OFF 2026-04-23 10:56:02+00 0101000020E61000005BD3BCE31471424050C763062A63F2BF -1.14921 36.88345 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1056 359857082897091 ACC_OFF 2026-04-23 10:55:21+00 0101000020E610000098A3C7EF6D724240B8239C16BC68F3BF -1.21307 36.89398 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1058 359857081891632 ACC_OFF 2026-04-23 10:55:03+00 0101000020E610000048F949B54F6F4240A6272CF180B2F3BF -1.23108 36.86962 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1060 862798050523337 ACC_ON 2026-04-23 10:54:40+00 0101000020E6100000670DDE57E5D44340B3075A81213B10C0 -4.057745 39.663249 0.00 \N 2026-04-23 10:59:01.490835+00 ACC ON poll \N \N \N \N \N +1061 862798052707946 ACC_OFF 2026-04-23 10:54:11+00 0101000020E610000075AC527AA66F42408CF2CCCB61B7F2BF -1.169771 36.872268 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1156 865135061048953 ACC_OFF 2026-04-23 10:58:11+00 0101000020E6100000E7FEEA71DFDC4340952C27A1F41510C0 -4.021441 39.725569 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1157 359857081886467 ACC_ON 2026-04-23 10:57:59+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 0.00 \N 2026-04-23 10:59:01.490835+00 ACC ON poll \N \N \N \N \N +1158 359857081886467 ACC_OFF 2026-04-23 10:56:37+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 0.00 \N 2026-04-23 10:59:01.490835+00 ACC OFF poll \N \N \N \N \N +1159 865135061048276 ACC_ON 2026-04-23 10:54:40+00 0101000020E61000002C0FD253E4D4434091990B5C1E3B10C0 -4.057733 39.663218 0.00 \N 2026-04-23 10:59:01.490835+00 ACC ON poll \N \N \N \N \N +5236 359857082918186 ACC_ON 2026-04-23 12:43:03+00 0101000020E6100000B0C91AF51055424055F65D11FCEFF3BF -1.24609 36.66458 0.00 \N 2026-04-23 12:44:27.352578+00 ACC ON poll \N \N \N \N \N +5237 359857082907973 ACC_ON 2026-04-23 12:42:37+00 0101000020E610000095F1EF332EBC43407B319413ED4A11C0 -4.32317 39.47016 0.00 \N 2026-04-23 12:44:27.352578+00 ACC ON poll \N \N \N \N \N +5238 359857082897091 ACC_ON 2026-04-23 12:42:34+00 0101000020E610000026E4839ECD7242408E75711B0D60F3BF -1.21095 36.8969 0.00 \N 2026-04-23 12:44:27.352578+00 ACC ON poll \N \N \N \N \N +5239 359857082037185 ACC_ON 2026-04-23 12:41:47+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 12:44:27.352578+00 ACC ON poll \N \N \N \N \N +5241 862798050526231 ACC_OFF 2026-04-23 12:40:46+00 0101000020E6100000BC77D49810D54340F38FBE49D32010C0 -4.032056 39.664569 0.00 \N 2026-04-23 12:44:27.352578+00 ACC OFF poll \N \N \N \N \N +5242 359857081891566 ACC_OFF 2026-04-23 12:40:08+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 12:44:27.352578+00 ACC OFF poll \N \N \N \N \N +5301 862798050523626 146 2026-04-23 12:43:05+00 0101000020E61000001895D40968BE4340E42F2DEA937C0EC0 -3.810829 39.48755 53.00 \N 2026-04-23 12:44:27.352578+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +5302 359857082918038 ACC_OFF 2026-04-23 12:42:13+00 0101000020E6100000459E245D33494340DB85E63A8D340BC0 -3.40066 38.57188 0.00 \N 2026-04-23 12:44:27.352578+00 ACC OFF poll \N \N \N \N \N +5344 862798052708068 ACC_ON 2026-04-23 12:49:03+00 0101000020E6100000AB2006BAF6534240ED9FA70183E4F1BF -1.118289 36.655967 0.00 \N 2026-04-23 12:49:28.168907+00 ACC ON poll \N \N \N \N \N +5345 862798052708068 128 2026-04-23 12:48:19+00 0101000020E6100000AB2006BAF6534240ED9FA70183E4F1BF -1.118289 36.655967 0.00 \N 2026-04-23 12:49:28.168907+00 DVR vibration alert poll \N \N \N \N \N +5346 865135061043426 stayAlert 2026-04-23 12:47:03+00 0101000020E61000002B4F20EC145B42401232906797AFF0BF -1.042869 36.711576 0.00 \N 2026-04-23 12:49:28.168907+00 Parking alert poll \N \N \N \N \N +5347 865135061564470 ACC_ON 2026-04-23 12:46:19+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 0.00 \N 2026-04-23 12:49:28.168907+00 ACC ON poll \N \N \N \N \N +5348 865135061043426 ACC_OFF 2026-04-23 12:46:03+00 0101000020E61000003B35971B0C5B42402F4D11E0F4AEF0BF -1.042714 36.711307 0.00 \N 2026-04-23 12:49:28.168907+00 ACC OFF poll \N \N \N \N \N +5389 862798050526231 ACC_OFF 2026-04-23 12:49:17+00 0101000020E6100000DE58501894D54340EEEC2B0FD22310C0 -4.034981 39.668582 0.00 \N 2026-04-23 12:49:28.168907+00 ACC OFF poll \N \N \N \N \N +5391 359857082897091 stayAlert 2026-04-23 12:47:34+00 0101000020E610000042959A3DD0724240359886E12362F3BF -1.21146 36.89698 0.00 \N 2026-04-23 12:49:28.168907+00 Parking alert poll \N \N \N \N \N +5392 865135061054555 ACC_OFF 2026-04-23 12:47:08+00 0101000020E61000005D6C5A29043042409C35785F950BD2BF -0.281957 36.375127 0.00 \N 2026-04-23 12:49:28.168907+00 ACC OFF poll \N \N \N \N \N +5393 862798050523014 ACC_ON 2026-04-23 12:47:08+00 0101000020E61000000CCA349A5C5242406616A1D80ADAF1BF -1.115733 36.643451 0.00 \N 2026-04-23 12:49:28.168907+00 ACC ON poll \N \N \N \N \N +5394 862798050523527 128 2026-04-23 12:46:50+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 12:49:28.168907+00 DVR vibration alert poll \N \N \N \N \N +5395 359857082897091 ACC_OFF 2026-04-23 12:46:34+00 0101000020E610000042959A3DD0724240359886E12362F3BF -1.21146 36.89698 0.00 \N 2026-04-23 12:49:28.168907+00 ACC OFF poll \N \N \N \N \N +5397 865135061054555 ACC_ON 2026-04-23 12:45:19+00 0101000020E61000000403081F4A3042408E95986725ADD1BF -0.276193 36.377262 0.00 \N 2026-04-23 12:49:28.168907+00 ACC ON poll \N \N \N \N \N +5398 359857082918186 ACC_OFF 2026-04-23 12:44:51+00 0101000020E6100000B0C91AF510554240726DA818E7EFF3BF -1.24607 36.66458 0.00 \N 2026-04-23 12:49:28.168907+00 ACC OFF poll \N \N \N \N \N +5399 359857082037185 ACC_OFF 2026-04-23 12:44:32+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 12:49:28.168907+00 ACC OFF poll \N \N \N \N \N +5400 862798050526231 ACC_ON 2026-04-23 12:44:30+00 0101000020E6100000BC77D49810D54340F38FBE49D32010C0 -4.032056 39.664569 0.00 \N 2026-04-23 12:49:28.168907+00 ACC ON poll \N \N \N \N \N +5457 359857082898008 ACC_ON 2026-04-23 12:49:02+00 0101000020E6100000475A2A6F47704240200C3CF71EAEF3BF -1.23001 36.87718 0.00 \N 2026-04-23 12:49:28.168907+00 ACC ON poll \N \N \N \N \N +5458 862798050523139 128 2026-04-23 12:46:42+00 0101000020E610000021C8410933ED43406CB3B112F30C0DC0 -3.631323 39.85312 0.00 \N 2026-04-23 12:49:28.168907+00 DVR vibration alert poll \N \N \N \N \N +5513 865135061563282 ACC_ON 2026-04-23 12:53:47+00 0101000020E61000001344DD07204540400E2E1D739EB1C93F 0.200733 32.54004 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5514 865135061053748 ACC_ON 2026-04-23 12:52:11+00 0101000020E61000004BC8073D9BD54340AF93FAB2B42310C0 -4.034869 39.6688 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +1164 359857082918186 1001 2026-04-23 10:59:54+00 0101000020E6100000605969520A5242405E11FC6F25BBF1BF -1.10819 36.64094 \N \N 2026-04-23 10:59:54.99037+00 ACC OFF push \N \N \N \N \N +1169 862798052707946 1002 2026-04-23 11:00:21+00 0101000020E610000033897AC1A76F4240B4E386DF4DB7F2BF -1.169752 36.872307 \N \N 2026-04-23 11:00:21.683122+00 ACC ON push \N \N \N \N \N +1170 865135061054548 1001 2026-04-23 11:00:22+00 0101000020E6100000F644D7851F724240A933F790F0FDF2BF -1.186997 36.891587 \N \N 2026-04-23 11:00:23.778683+00 ACC OFF push \N \N \N \N \N +1171 862798050288360 147 2026-04-23 11:00:16+00 0101000020E6100000FC389A232B7142402AC93A1C5D65F2BF -1.149747 36.884129 31.00 \N 2026-04-23 11:00:30.892508+00 Collision Alert(DVR) push \N \N \N \N \N +1172 862798052708068 128 2026-04-23 11:00:53+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 11:00:54.349508+00 DVR vibration alert push \N \N \N \N \N +1173 865135061562847 3 2026-04-23 11:01:30+00 0101000020E6100000E43098BF42824240543882548A9DF1BF -1.100962 37.017662 \N \N 2026-04-23 11:01:38.30331+00 Vibration alert push \N \N \N \N \N +1174 862798050288345 128 2026-04-23 11:01:38+00 0101000020E61000000C569C6A2D9043409DB81CAF40A411C0 -4.410403 39.126386 0.00 \N 2026-04-23 11:01:41.370707+00 DVR vibration alert push \N \N \N \N \N +1175 862798050288345 1002 2026-04-23 11:01:44+00 0101000020E61000000C569C6A2D9043409DB81CAF40A411C0 -4.410403 39.126386 \N \N 2026-04-23 11:01:45.007986+00 ACC ON push \N \N \N \N \N +1176 865135061053748 1001 2026-04-23 11:01:51+00 0101000020E610000098141F9F90D543400F9A5DF7562410C0 -4.035488 39.668476 \N \N 2026-04-23 11:01:51.907157+00 ACC OFF push \N \N \N \N \N +1177 862798050526231 1001 2026-04-23 11:01:53+00 0101000020E610000091EF52EA92D54340EE0912DBDD2310C0 -4.035026 39.668546 \N \N 2026-04-23 11:01:53.869927+00 ACC OFF push \N \N \N \N \N +1178 359857082918012 1002 2026-04-23 11:01:55+00 0101000020E6100000255D33F9666B424051A04FE44952F3BF -1.20759 36.83908 \N \N 2026-04-23 11:01:56.169815+00 ACC ON push \N \N \N \N \N +1179 865135061564470 3 2026-04-23 11:02:17+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 \N \N 2026-04-23 11:02:19.094364+00 Vibration alert push \N \N \N \N \N +1180 865135061569131 3 2026-04-23 11:02:35+00 0101000020E6100000975643E21E4340403A4030478FDFBB3F 0.10888 32.52438 56.00 \N 2026-04-23 11:02:37.650273+00 Vibration alert push \N \N \N \N \N +1181 359857082037185 1001 2026-04-23 11:02:47+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 11:02:48.415276+00 ACC OFF push \N \N \N \N \N +1182 865135061053748 1004 2026-04-23 11:02:51+00 0101000020E6100000B77EFACF9AD543402DB5DE6FB42310C0 -4.034868 39.668787 \N \N 2026-04-23 11:02:51.408105+00 Parking alert push \N \N \N \N \N +1183 359857082918012 1001 2026-04-23 11:02:58+00 0101000020E61000000FB40243566B424055185B087250F3BF -1.20714 36.83857 \N \N 2026-04-23 11:02:59.163313+00 ACC OFF push \N \N \N \N \N +1184 359857082908500 1002 2026-04-23 11:03:18+00 0101000020E61000000074982F2F904340A3586E6935A411C0 -4.41036 39.12644 \N \N 2026-04-23 11:03:19.18092+00 ACC ON push \N \N \N \N \N +1185 865135061562722 3 2026-04-23 11:02:09+00 0101000020E61000002B6C06B8206942407F4FAC53E57BF2BF -1.155248 36.821311 \N \N 2026-04-23 11:03:50.091794+00 Vibration alert push \N \N \N \N \N +1186 865135061053748 stayAlert 2026-04-23 11:02:51+00 0101000020E6100000B77EFACF9AD543402DB5DE6FB42310C0 -4.034868 39.668787 0.00 \N 2026-04-23 11:04:02.44253+00 Parking alert poll \N \N \N \N \N +1189 865135061053748 ACC_OFF 2026-04-23 11:01:51+00 0101000020E610000098141F9F90D543400F9A5DF7562410C0 -4.035488 39.668476 0.00 \N 2026-04-23 11:04:02.44253+00 ACC OFF poll \N \N \N \N \N +1230 359857082908500 ACC_ON 2026-04-23 11:03:18+00 0101000020E61000000074982F2F904340A3586E6935A411C0 -4.41036 39.12644 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1231 359857082918012 ACC_OFF 2026-04-23 11:02:58+00 0101000020E61000000FB40243566B424055185B087250F3BF -1.20714 36.83857 0.00 \N 2026-04-23 11:04:02.44253+00 ACC OFF poll \N \N \N \N \N +1232 359857082037185 ACC_OFF 2026-04-23 11:02:47+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 11:04:02.44253+00 ACC OFF poll \N \N \N \N \N +1234 359857082918012 ACC_ON 2026-04-23 11:01:55+00 0101000020E6100000255D33F9666B424051A04FE44952F3BF -1.20759 36.83908 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1235 862798050526231 ACC_OFF 2026-04-23 11:01:53+00 0101000020E610000091EF52EA92D54340EE0912DBDD2310C0 -4.035026 39.668546 0.00 \N 2026-04-23 11:04:02.44253+00 ACC OFF poll \N \N \N \N \N +1236 862798050288345 ACC_ON 2026-04-23 11:01:44+00 0101000020E61000000C569C6A2D9043409DB81CAF40A411C0 -4.410403 39.126386 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1237 862798050288345 128 2026-04-23 11:01:40+00 0101000020E61000000C569C6A2D9043409DB81CAF40A411C0 -4.410403 39.126386 0.00 \N 2026-04-23 11:04:02.44253+00 DVR vibration alert poll \N \N \N \N \N +1239 865135061054548 ACC_OFF 2026-04-23 11:00:22+00 0101000020E6100000F644D7851F724240A933F790F0FDF2BF -1.186997 36.891587 0.00 \N 2026-04-23 11:04:02.44253+00 ACC OFF poll \N \N \N \N \N +1240 862798052707946 ACC_ON 2026-04-23 11:00:21+00 0101000020E610000033897AC1A76F4240B4E386DF4DB7F2BF -1.169752 36.872307 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1241 862798050288360 147 2026-04-23 11:00:19+00 0101000020E6100000FC389A232B7142402AC93A1C5D65F2BF -1.149747 36.884129 31.00 \N 2026-04-23 11:04:02.44253+00 Collision Alert(DVR) poll \N \N \N \N \N +1242 359857082038977 ACC_ON 2026-04-23 11:00:14+00 0101000020E61000007E74EACA67D94340BABDA4315A2710C0 -4.03843 39.69848 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1243 359857082918186 ACC_OFF 2026-04-23 10:59:54+00 0101000020E6100000605969520A5242405E11FC6F25BBF1BF -1.10819 36.64094 0.00 \N 2026-04-23 11:04:02.44253+00 ACC OFF poll \N \N \N \N \N +1245 359857082911983 ACC_ON 2026-04-23 10:59:34+00 0101000020E6100000A27F828B1571424050C763062A63F2BF -1.14921 36.88347 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1246 862798050288360 ACC_ON 2026-04-23 10:59:34+00 0101000020E6100000BADBF5D214714240EF737CB43863F2BF -1.149224 36.883448 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1247 359857082897794 ACC_ON 2026-04-23 10:59:31+00 0101000020E6100000E5D022DBF9664240D105F52D733AF4BF -1.26427 36.8045 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1341 359857081887069 ACC_ON 2026-04-23 11:00:08+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 11:04:02.44253+00 ACC ON poll \N \N \N \N \N +1348 865135061053748 1002 2026-04-23 11:04:11+00 0101000020E6100000B77EFACF9AD543402DB5DE6FB42310C0 -4.034868 39.668787 \N \N 2026-04-23 11:04:11.474974+00 ACC ON push \N \N \N \N \N +1349 862798050526231 1002 2026-04-23 11:04:11+00 0101000020E610000091EF52EA92D54340EE0912DBDD2310C0 -4.035026 39.668546 \N \N 2026-04-23 11:04:12.538702+00 ACC ON push \N \N \N \N \N +1350 865135061035778 1001 2026-04-23 11:04:13+00 0101000020E6100000EDF483BA4877424016325706D506F3BF -1.189168 36.931907 \N \N 2026-04-23 11:04:13.865539+00 ACC OFF push \N \N \N \N \N +1351 865135061035778 1002 2026-04-23 11:04:13+00 0101000020E610000007EDD5C743774240C77F81204006F3BF -1.189026 36.931756 \N \N 2026-04-23 11:04:14.887253+00 ACC ON push \N \N \N \N \N +1352 862798050523527 1002 2026-04-23 11:04:40+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 \N \N 2026-04-23 11:04:40.618444+00 ACC ON push \N \N \N \N \N +1353 359857081885410 1002 2026-04-23 11:04:40+00 0101000020E6100000117008556A72424036E50AEF7211F3BF -1.19176 36.89387 \N \N 2026-04-23 11:04:41.043288+00 ACC ON push \N \N \N \N \N +1354 865135061048276 1001 2026-04-23 11:04:50+00 0101000020E6100000E52A16BF29D443402766BD18CA2910C0 -4.04081 39.657524 \N \N 2026-04-23 11:04:51.525563+00 ACC OFF push \N \N \N \N \N +1355 359857082896911 1001 2026-04-23 11:04:53+00 0101000020E61000002849D74CBE69424060EAE74D45AAF2BF -1.16657 36.82612 \N \N 2026-04-23 11:04:54.058921+00 ACC OFF push \N \N \N \N \N +1356 865135061569131 3 2026-04-23 11:04:56+00 0101000020E610000071E82D1EDE434040DA70581AF851B93F 0.098907 32.530216 53.00 \N 2026-04-23 11:04:57.727454+00 Vibration alert push \N \N \N \N \N +1357 359857082910589 1002 2026-04-23 11:05:02+00 0101000020E6100000CBDB114E0B7642405B7C0A80F18CF2BF -1.15941 36.92222 \N \N 2026-04-23 11:05:03.24254+00 ACC ON push \N \N \N \N \N +1358 359857081887069 stayAlertOn 2026-04-23 11:05:08+00 0101000020E6100000A3923A014D78424057CF49EF1B5FF3BF -1.21072 36.93985 \N \N 2026-04-23 11:05:08.655984+00 Idling alert push \N \N \N \N \N +1359 862798050523337 1001 2026-04-23 11:05:12+00 0101000020E6100000826F9A3E3BD44340A5F622DA8E2910C0 -4.040584 39.658058 \N \N 2026-04-23 11:05:12.266962+00 ACC OFF push \N \N \N \N \N +1360 359857082918012 1002 2026-04-23 11:05:19+00 0101000020E61000000FB40243566B424055185B087250F3BF -1.20714 36.83857 \N \N 2026-04-23 11:05:20.327363+00 ACC ON push \N \N \N \N \N +1361 359857082042854 1001 2026-04-23 11:05:23+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 \N \N 2026-04-23 11:05:24.789733+00 ACC OFF push \N \N \N \N \N +1362 359857082912486 1002 2026-04-23 11:05:37+00 0101000020E61000006CB2463D44E74340E5B8533A587F0EC0 -3.81218 39.80677 \N \N 2026-04-23 11:05:38.032513+00 ACC ON push \N \N \N \N \N +1363 865135061564470 3 2026-04-23 11:05:44+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 \N \N 2026-04-23 11:05:45.948217+00 Vibration alert push \N \N \N \N \N +1364 359857082897737 1002 2026-04-23 11:05:55+00 0101000020E6100000C1FF56B263DF434018265305A3920FC0 -3.9466 39.74523 \N \N 2026-04-23 11:05:55.727581+00 ACC ON push \N \N \N \N \N +1365 862798050525423 1002 2026-04-23 11:05:58+00 0101000020E610000090F63FC05ADF43407A19C5724B8B0FC0 -3.943015 39.744957 \N \N 2026-04-23 11:05:59.083518+00 ACC ON push \N \N \N \N \N +1366 359857082897091 1001 2026-04-23 11:06:03+00 0101000020E6100000AD342905DD7242409A7CB3CD8D69F3BF -1.21327 36.89737 \N \N 2026-04-23 11:06:04.445403+00 ACC OFF push \N \N \N \N \N +1372 359857082918186 1002 2026-04-23 11:07:38+00 0101000020E61000003C8386FE09524240EC4CA1F31ABBF1BF -1.10818 36.64093 \N \N 2026-04-23 11:07:38.796791+00 ACC ON push \N \N \N \N \N +5330 865135061564470 1002 2026-04-23 12:46:19+00 0101000020E610000026361FD786724240F052EA92714CF3BF -1.206163 36.89474 \N \N 2026-04-23 12:46:19.497584+00 ACC ON push \N \N \N \N \N +5333 862798050523139 128 2026-04-23 12:46:41+00 0101000020E610000021C8410933ED43406CB3B112F30C0DC0 -3.631323 39.85312 0.00 \N 2026-04-23 12:46:43.183623+00 DVR vibration alert push \N \N \N \N \N +5334 862798050523527 128 2026-04-23 12:46:49+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 12:46:51.480256+00 DVR vibration alert push \N \N \N \N \N +5335 865135061043426 1004 2026-04-23 12:47:03+00 0101000020E61000002B4F20EC145B42401232906797AFF0BF -1.042869 36.711576 \N \N 2026-04-23 12:47:03.773771+00 Parking alert push \N \N \N \N \N +5336 865135061054555 1001 2026-04-23 12:47:08+00 0101000020E61000005D6C5A29043042409C35785F950BD2BF -0.281957 36.375127 \N \N 2026-04-23 12:47:08.619021+00 ACC OFF push \N \N \N \N \N +5337 862798050523014 1002 2026-04-23 12:47:08+00 0101000020E61000000CCA349A5C5242406616A1D80ADAF1BF -1.115733 36.643451 \N \N 2026-04-23 12:47:09.272553+00 ACC ON push \N \N \N \N \N +5338 359857082897091 1004 2026-04-23 12:47:34+00 0101000020E610000042959A3DD0724240359886E12362F3BF -1.21146 36.89698 \N \N 2026-04-23 12:47:34.58461+00 Parking alert push \N \N \N \N \N +5339 862798052708068 128 2026-04-23 12:48:18+00 0101000020E6100000AB2006BAF6534240ED9FA70183E4F1BF -1.118289 36.655967 0.00 \N 2026-04-23 12:48:19.434568+00 DVR vibration alert push \N \N \N \N \N +5340 359857081891566 stayAlertOn 2026-04-23 12:48:20+00 0101000020E61000003468E89FE0724240E76F4221020EF3BF -1.19092 36.89748 \N \N 2026-04-23 12:48:20.856785+00 Idling alert push \N \N \N \N \N +5482 359857082042854 1001 2026-04-23 12:49:59+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 \N \N 2026-04-23 12:50:00.281765+00 ACC OFF push \N \N \N \N \N +5483 359857082918012 stayAlertOn 2026-04-23 12:50:04+00 0101000020E61000001BD82AC1E26C4240A27F828B15B5F3BF -1.23171 36.85067 \N \N 2026-04-23 12:50:04.400573+00 Idling alert push \N \N \N \N \N +5484 865135061053748 1004 2026-04-23 12:50:15+00 0101000020E61000004BC8073D9BD54340AF93FAB2B42310C0 -4.034869 39.6688 \N \N 2026-04-23 12:50:15.634136+00 Parking alert push \N \N \N \N \N +5485 862798050523527 1002 2026-04-23 12:50:15+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 12:50:16.225119+00 ACC ON push \N \N \N \N \N +5488 865135061563597 1002 2026-04-23 12:51:03+00 0101000020E6100000111AC1C6F55342405E64027E8DE4F1BF -1.118299 36.655938 \N \N 2026-04-23 12:51:04.657822+00 ACC ON push \N \N \N \N \N +5489 865135061569123 1001 2026-04-23 12:51:04+00 0101000020E61000008EC9E2FE23634240685A626534B2F4BF -1.293507 36.774536 \N \N 2026-04-23 12:51:05.058691+00 ACC OFF push \N \N \N \N \N +5490 865135061569123 3 2026-04-23 12:48:45+00 0101000020E610000063B83A00E2624240965E9B8D9598F4BF -1.287252 36.772522 \N \N 2026-04-23 12:51:05.391322+00 Vibration alert push \N \N \N \N \N +5491 865135061035653 1001 2026-04-23 12:51:14+00 0101000020E61000004C1762F547E04340C4B0C398F4970FC0 -3.949197 39.752196 \N \N 2026-04-23 12:51:15.915126+00 ACC OFF push \N \N \N \N \N +5493 359857082918012 1001 2026-04-23 12:51:38+00 0101000020E61000008D7F9F71E16C4240DA5548F949B5F3BF -1.23176 36.85063 \N \N 2026-04-23 12:51:39.41849+00 ACC OFF push \N \N \N \N \N +5505 865135061563282 1002 2026-04-23 12:53:47+00 0101000020E61000001344DD07204540400E2E1D739EB1C93F 0.200733 32.54004 \N \N 2026-04-23 12:53:48.191788+00 ACC ON push \N \N \N \N \N +5506 359857082042854 1002 2026-04-23 12:53:52+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 \N \N 2026-04-23 12:53:52.916446+00 ACC ON push \N \N \N \N \N +5507 862798050523337 128 2026-04-23 12:53:54+00 0101000020E61000008CDB68006FD9434017821C94300310C0 -4.003115 39.6987 0.00 \N 2026-04-23 12:53:55.408923+00 DVR vibration alert push \N \N \N \N \N +5510 862798050523337 1002 2026-04-23 12:54:09+00 0101000020E6100000FD4E93196FD94340D3A57F492A0310C0 -4.003091 39.698703 \N \N 2026-04-23 12:54:10.779+00 ACC ON push \N \N \N \N \N +6535 865135061054555 1002 2026-04-23 13:22:57+00 0101000020E610000053944BE3173042407B681F2BF86DD1BF -0.272337 36.375729 \N \N 2026-04-23 13:22:58.003505+00 ACC ON push \N \N \N \N \N +6536 865135061562722 3 2026-04-23 13:22:45+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 13:23:07.057046+00 Vibration alert push \N \N \N \N \N +6537 862798050526231 1002 2026-04-23 13:23:10+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 \N \N 2026-04-23 13:23:11.39991+00 ACC ON push \N \N \N \N \N +6538 865135061053748 1002 2026-04-23 13:23:22+00 0101000020E6100000DA8D3EE603D443403DD2E0B6B63010C0 -4.047572 39.656369 \N \N 2026-04-23 13:23:23.331447+00 ACC ON push \N \N \N \N \N +6539 865135061569131 3 2026-04-23 13:23:30+00 0101000020E6100000986C3CD8624740405A2C45F29540B23F 0.071298 32.557704 17.00 \N 2026-04-23 13:23:31.355587+00 Vibration alert push \N \N \N \N \N +6540 865135061048953 1001 2026-04-23 13:23:59+00 0101000020E610000029E78BBD17DB43403694DA8B68FB0FC0 -3.997758 39.711662 \N \N 2026-04-23 13:24:00.374382+00 ACC OFF push \N \N \N \N \N +6541 359857082907973 1001 2026-04-23 13:24:19+00 0101000020E610000029D027F224B54340124E0B5EF47511C0 -4.36519 39.41519 \N \N 2026-04-23 13:24:20.548109+00 ACC OFF push \N \N \N \N \N +6542 359857082042953 1002 2026-04-23 13:24:32+00 0101000020E6100000E1D1C6116BFD4240F853E3A59BC4F5BF -1.3605 37.97983 \N \N 2026-04-23 13:24:33.293453+00 ACC ON push \N \N \N \N \N +6690 359857082910589 1001 2026-04-23 13:24:43+00 0101000020E6100000D0B359F5B97A424045F5D6C05689F2BF -1.15853 36.9588 \N \N 2026-04-23 13:24:44.568816+00 ACC OFF push \N \N \N \N \N +6691 865135061054555 1001 2026-04-23 13:25:17+00 0101000020E61000008E06F01648304240E7E099D024B1D1BF -0.276437 36.3772 \N \N 2026-04-23 13:25:17.635457+00 ACC OFF push \N \N \N \N \N +6692 865135061563639 stayAlertOn 2026-04-23 13:25:30+00 0101000020E6100000B131AF230EEB42406E6B0BCF4B05FABF -1.626293 37.836369 \N \N 2026-04-23 13:25:30.968658+00 Idling alert push \N \N \N \N \N +6693 865135061569123 1001 2026-04-23 13:25:36+00 0101000020E61000004374081C09664240EED0B01875ADF4BF -1.292348 36.797153 \N \N 2026-04-23 13:25:37.504939+00 ACC OFF push \N \N \N \N \N +6694 359857081891566 1002 2026-04-23 13:25:44+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 13:25:45.50816+00 ACC ON push \N \N \N \N \N +6695 865135061569131 3 2026-04-23 13:25:50+00 0101000020E6100000865968E73447404024B9FC87F4DBB33F 0.077575 32.556302 18.00 \N 2026-04-23 13:25:51.817241+00 Vibration alert push \N \N \N \N \N +6705 865135061562847 stayAlertOn 2026-04-23 13:28:01+00 0101000020E610000069E21DE0497F4240C49448A29751F1BF -1.08242 36.994442 \N \N 2026-04-23 13:28:01.9258+00 Idling alert push \N \N \N \N \N +6706 865135061569131 3 2026-04-23 13:28:10+00 0101000020E61000000951BEA085464040FF756EDA8CD3B43F 0.081353 32.550953 21.00 \N 2026-04-23 13:28:12.651329+00 Vibration alert push \N \N \N \N \N +6707 865135061562847 3 2026-04-23 13:26:33+00 0101000020E610000031D28BDAFD7E424012F92EA52E59F1BF -1.084273 36.992122 \N \N 2026-04-23 13:28:22.496366+00 Vibration alert push \N \N \N \N \N +6708 865135061562847 1001 2026-04-23 13:28:22+00 0101000020E610000069E21DE0497F4240C49448A29751F1BF -1.08242 36.994442 \N \N 2026-04-23 13:28:23.435268+00 ACC OFF push \N \N \N \N \N +6709 359857082910589 1002 2026-04-23 13:29:05+00 0101000020E6100000D0B359F5B97A424045F5D6C05689F2BF -1.15853 36.9588 \N \N 2026-04-23 13:29:06.553179+00 ACC ON push \N \N \N \N \N +6851 359857081891566 stayAlertOn 2026-04-23 13:30:44+00 0101000020E6100000F5D6C05609724240E86A2BF697DDF2BF -1.1791 36.89091 \N \N 2026-04-23 13:30:45.05413+00 Idling alert push \N \N \N \N \N +6854 359857082896911 1001 2026-04-23 13:31:50+00 0101000020E61000004CA60A46256942403F8C101E6D9CF2BF -1.16319 36.82145 \N \N 2026-04-23 13:31:51.450856+00 ACC OFF push \N \N \N \N \N +6855 865135061569123 3 2026-04-23 13:29:36+00 0101000020E61000004374081C09664240EED0B01875ADF4BF -1.292348 36.797153 \N \N 2026-04-23 13:31:57.59337+00 Vibration alert push \N \N \N \N \N +6858 862798050523626 1001 2026-04-23 13:32:27+00 0101000020E6100000FA804067D2C24340228C9FC6BD590CC0 -3.543819 39.522046 \N \N 2026-04-23 13:32:27.56684+00 ACC OFF push \N \N \N \N \N +6859 359857081891632 1002 2026-04-23 13:32:36+00 0101000020E610000047551344DD6F42409291B3B0A79DF3BF -1.22599 36.87394 \N \N 2026-04-23 13:32:37.319935+00 ACC ON push \N \N \N \N \N +6860 359857082897091 1004 2026-04-23 13:32:38+00 0101000020E61000005721E527D5724240CBDB114E0B5EF3BF -1.21046 36.89713 \N \N 2026-04-23 13:32:39.046268+00 Parking alert push \N \N \N \N \N +6863 862798050523014 128 2026-04-23 13:33:13+00 0101000020E6100000F06C8FDE7053424086730D3334DEF1BF -1.116749 36.651882 0.00 \N 2026-04-23 13:33:15.01051+00 DVR vibration alert push \N \N \N \N \N +6866 359857082897091 1002 2026-04-23 13:33:43+00 0101000020E61000009FCDAACFD572424092054CE0D65DF3BF -1.21041 36.89715 \N \N 2026-04-23 13:33:44.218045+00 ACC ON push \N \N \N \N \N +1367 865135061054555 1002 2026-04-23 11:06:09+00 0101000020E6100000DDB1D82615314240E5B512BA4BE2D0BF -0.263812 36.383458 \N \N 2026-04-23 11:06:10.152494+00 ACC ON push \N \N \N \N \N +1368 865135061564470 1002 2026-04-23 11:06:15+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 \N \N 2026-04-23 11:06:16.418001+00 ACC ON push \N \N \N \N \N +1369 359857082897091 1002 2026-04-23 11:06:39+00 0101000020E6100000C9E53FA4DF724240D36A48DC6369F3BF -1.21323 36.89745 \N \N 2026-04-23 11:06:39.929334+00 ACC ON push \N \N \N \N \N +1370 359857082918012 1001 2026-04-23 11:07:16+00 0101000020E610000081785DBF606B424040D9942BBC4BF3BF -1.20599 36.83889 \N \N 2026-04-23 11:07:17.168825+00 ACC OFF push \N \N \N \N \N +1371 865135061569131 3 2026-04-23 11:07:16+00 0101000020E61000003BFF76D9AF4540408B355CE49EAEB63F 0.088602 32.544429 54.00 \N 2026-04-23 11:07:18.687247+00 Vibration alert push \N \N \N \N \N +1373 359857082897091 1004 2026-04-23 11:07:58+00 0101000020E6100000C9E53FA4DF724240D36A48DC6369F3BF -1.21323 36.89745 \N \N 2026-04-23 11:07:58.994507+00 Parking alert push \N \N \N \N \N +1374 865135061048953 1002 2026-04-23 11:08:02+00 0101000020E6100000E7FEEA71DFDC4340952C27A1F41510C0 -4.021441 39.725569 \N \N 2026-04-23 11:08:03.043908+00 ACC ON push \N \N \N \N \N +1375 865135061569123 3 2026-04-23 11:06:58+00 0101000020E61000006F66F4A3E16242404B732B84D598F4BF -1.287313 36.772511 \N \N 2026-04-23 11:08:13.267024+00 Vibration alert push \N \N \N \N \N +1376 865135061569123 1004 2026-04-23 11:08:13+00 0101000020E61000006F66F4A3E16242404B732B84D598F4BF -1.287313 36.772511 \N \N 2026-04-23 11:08:13.907264+00 Parking alert push \N \N \N \N \N +1377 359857081892309 1002 2026-04-23 11:08:13+00 0101000020E6100000B62DCA6C907142401288D7F50B76F3BF -1.21632 36.88722 \N \N 2026-04-23 11:08:14.170685+00 ACC ON push \N \N \N \N \N +1378 359857081885410 1001 2026-04-23 11:09:00+00 0101000020E6100000117008556A72424036E50AEF7211F3BF -1.19176 36.89387 \N \N 2026-04-23 11:09:01.264476+00 ACC OFF push \N \N \N \N \N +1379 862798050523527 1001 2026-04-23 11:09:01+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 11:09:01.631697+00 ACC OFF push \N \N \N \N \N +1544 865135061559538 1001 2026-04-23 11:09:04+00 0101000020E61000007ADFF8DA335B42406C97361C9686F3BF -1.220358 36.71252 \N \N 2026-04-23 11:09:04.908692+00 ACC OFF push \N \N \N \N \N +1545 865135061054555 1001 2026-04-23 11:09:07+00 0101000020E61000009E2633DE56304240158E20956247D1BF -0.269982 36.377651 \N \N 2026-04-23 11:09:08.198516+00 ACC OFF push \N \N \N \N \N +1546 865135061559538 1002 2026-04-23 11:09:19+00 0101000020E6100000D74B5304385B4240317903CC7C87F3BF -1.220578 36.712647 \N \N 2026-04-23 11:09:20.07277+00 ACC ON push \N \N \N \N \N +5501 862798050526231 1002 2026-04-23 12:52:13+00 0101000020E6100000DE58501894D54340EEEC2B0FD22310C0 -4.034981 39.668582 \N \N 2026-04-23 12:52:13.92329+00 ACC ON push \N \N \N \N \N +5502 359857082037185 1001 2026-04-23 12:52:15+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 12:52:16.023263+00 ACC OFF push \N \N \N \N \N +5503 865135061054555 1002 2026-04-23 12:52:28+00 0101000020E61000000455A3570330424056116E32AA0CD2BF -0.282023 36.375102 \N \N 2026-04-23 12:52:28.502356+00 ACC ON push \N \N \N \N \N +5504 359857082918038 1001 2026-04-23 12:53:03+00 0101000020E6100000FE9AAC510F494340F33CB83B6B370BC0 -3.40206 38.57078 \N \N 2026-04-23 12:53:04.573184+00 ACC OFF push \N \N \N \N \N +5508 359857082900358 stayAlertOn 2026-04-23 12:54:01+00 0101000020E61000004D10751F807C4240B9AAECBB22F8F6BF -1.43558 36.97266 \N \N 2026-04-23 12:54:01.879645+00 Idling alert push \N \N \N \N \N +5509 359857082898008 stayAlertOn 2026-04-23 12:54:02+00 0101000020E61000001A34F44F70754240C68503215940F3BF -1.20321 36.91749 \N \N 2026-04-23 12:54:02.535371+00 Idling alert push \N \N \N \N \N +5511 862798050523626 146 2026-04-23 12:54:16+00 0101000020E6100000FF1F274C18BB434095BBCFF1D1E20DC0 -3.735752 39.461679 62.00 \N 2026-04-23 12:54:19.089374+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +5647 865135061562722 3 2026-04-23 12:53:33+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 12:54:29.331776+00 Vibration alert push \N \N \N \N \N +5653 359857081885410 1001 2026-04-23 12:54:44+00 0101000020E6100000D13FC1C58A72424003CFBD874B0EF3BF -1.19099 36.89486 \N \N 2026-04-23 12:54:44.70298+00 ACC OFF push \N \N \N \N \N +5654 865135061054548 1001 2026-04-23 12:54:44+00 0101000020E6100000DFFDF15EB5724240915F3FC4060BF3BF -1.190192 36.89616 \N \N 2026-04-23 12:54:44.901952+00 ACC OFF push \N \N \N \N \N +6584 359857081892762 offline 2026-04-23 13:22:03+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 0.00 \N 2026-04-23 13:24:34.670912+00 Offline alert poll \N \N \N \N \N +6585 865135061035653 ACC_ON 2026-04-23 13:21:57+00 0101000020E61000005ED5592DB0DF4340EE3EC7478B930FC0 -3.947043 39.747564 0.00 \N 2026-04-23 13:24:34.670912+00 ACC ON poll \N \N \N \N \N +6586 865135061035653 ACC_OFF 2026-04-23 13:21:43+00 0101000020E6100000CA8B4CC0AFDF43400A4CA7751B940FC0 -3.947318 39.747551 0.00 \N 2026-04-23 13:24:34.670912+00 ACC OFF poll \N \N \N \N \N +6587 865135061054555 ACC_OFF 2026-04-23 13:21:04+00 0101000020E61000006F4562821A304240B891B245D26ED1BF -0.272389 36.375809 0.00 \N 2026-04-23 13:24:34.670912+00 ACC OFF poll \N \N \N \N \N +6590 359857082912239 stayAlert 2026-04-23 13:19:54+00 0101000020E6100000C503CAA65C494340A857CA32C4310BC0 -3.3993 38.57314 0.00 \N 2026-04-23 13:24:34.670912+00 Parking alert poll \N \N \N \N \N +6591 865135061054555 ACC_ON 2026-04-23 13:19:38+00 0101000020E61000000875914259304240397CD2890453D1BF -0.270692 36.377724 0.00 \N 2026-04-23 13:24:34.670912+00 ACC ON poll \N \N \N \N \N +6666 359857082042953 ACC_ON 2026-04-23 13:24:32+00 0101000020E6100000E1D1C6116BFD4240F853E3A59BC4F5BF -1.3605 37.97983 0.00 \N 2026-04-23 13:24:34.670912+00 ACC ON poll \N \N \N \N \N +6667 865135061048953 ACC_OFF 2026-04-23 13:23:59+00 0101000020E610000029E78BBD17DB43403694DA8B68FB0FC0 -3.997758 39.711662 0.00 \N 2026-04-23 13:24:34.670912+00 ACC OFF poll \N \N \N \N \N +6668 359857081887069 ACC_ON 2026-04-23 13:22:45+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 13:24:34.670912+00 ACC ON poll \N \N \N \N \N +6670 865135061048953 ACC_ON 2026-04-23 13:21:25+00 0101000020E61000009D2ADF3312DB434084B7072120FF0FC0 -3.999573 39.711493 0.00 \N 2026-04-23 13:24:34.670912+00 ACC ON poll \N \N \N \N \N +6671 359857081887069 ACC_OFF 2026-04-23 13:19:37+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 13:24:34.670912+00 ACC OFF poll \N \N \N \N \N +6711 865135061043426 ACC_ON 2026-04-23 13:26:52+00 0101000020E6100000E23FDD40815B4240118FC4CBD3B9F0BF -1.045368 36.714882 0.00 \N 2026-04-23 13:29:35.576482+00 ACC ON poll \N \N \N \N \N +6714 865135061569123 stayAlert 2026-04-23 13:26:36+00 0101000020E61000004374081C09664240EED0B01875ADF4BF -1.292348 36.797153 0.00 \N 2026-04-23 13:29:35.576482+00 Parking alert poll \N \N \N \N \N +6716 865135061569123 ACC_OFF 2026-04-23 13:25:36+00 0101000020E61000004374081C09664240EED0B01875ADF4BF -1.292348 36.797153 0.00 \N 2026-04-23 13:29:35.576482+00 ACC OFF poll \N \N \N \N \N +6750 359857082910589 ACC_ON 2026-04-23 13:29:05+00 0101000020E6100000D0B359F5B97A424045F5D6C05689F2BF -1.15853 36.9588 0.00 \N 2026-04-23 13:29:35.576482+00 ACC ON poll \N \N \N \N \N +6751 865135061562847 ACC_OFF 2026-04-23 13:28:22+00 0101000020E610000069E21DE0497F4240C49448A29751F1BF -1.08242 36.994442 0.00 \N 2026-04-23 13:29:35.576482+00 ACC OFF poll \N \N \N \N \N +6753 865135061054555 ACC_ON 2026-04-23 13:27:23+00 0101000020E6100000381092054C30424070EEAF1EF7ADD1BF -0.276243 36.37732 0.00 \N 2026-04-23 13:29:35.576482+00 ACC ON poll \N \N \N \N \N +6754 865135061035653 ACC_OFF 2026-04-23 13:27:05+00 0101000020E6100000C18F6AD8EFDF434054008C67D0900FC0 -3.94571 39.749507 0.00 \N 2026-04-23 13:29:35.576482+00 ACC OFF poll \N \N \N \N \N +6755 862798050523337 ACC_OFF 2026-04-23 13:26:44+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 0.00 \N 2026-04-23 13:29:35.576482+00 ACC OFF poll \N \N \N \N \N +6757 359857081891566 ACC_ON 2026-04-23 13:25:44+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 13:29:35.576482+00 ACC ON poll \N \N \N \N \N +6758 865135061054555 ACC_OFF 2026-04-23 13:25:17+00 0101000020E61000008E06F01648304240E7E099D024B1D1BF -0.276437 36.3772 0.00 \N 2026-04-23 13:29:35.576482+00 ACC OFF poll \N \N \N \N \N +6759 359857082910589 ACC_OFF 2026-04-23 13:24:43+00 0101000020E6100000D0B359F5B97A424045F5D6C05689F2BF -1.15853 36.9588 0.00 \N 2026-04-23 13:29:35.576482+00 ACC OFF poll \N \N \N \N \N +6825 865135061048276 ACC_OFF 2026-04-23 13:26:23+00 0101000020E6100000F1D4230D6ED943400002D6AA5D0310C0 -4.003287 39.698671 0.00 \N 2026-04-23 13:29:35.576482+00 ACC OFF poll \N \N \N \N \N +6872 862798050525423 stayAlert 2026-04-23 13:30:28+00 0101000020E6100000C4211B4817DB4340FD6B79E57AFB0FC0 -3.997793 39.711648 0.00 \N 2026-04-23 13:34:36.40955+00 Parking alert poll \N \N \N \N \N +6910 359857081886905 ACC_OFF 2026-04-23 13:34:12+00 0101000020E61000009A081B9E5ED943402C4833164D2710C0 -4.03838 39.6982 0.00 \N 2026-04-23 13:34:36.40955+00 ACC OFF poll \N \N \N \N \N +6912 359857082897091 ACC_ON 2026-04-23 13:33:43+00 0101000020E61000009FCDAACFD572424092054CE0D65DF3BF -1.21041 36.89715 0.00 \N 2026-04-23 13:34:36.40955+00 ACC ON poll \N \N \N \N \N +6913 865135061054548 ACC_OFF 2026-04-23 13:33:22+00 0101000020E61000009126DE019E7242407BF7C77BD50AF3BF -1.190145 36.895447 0.00 \N 2026-04-23 13:34:36.40955+00 ACC OFF poll \N \N \N \N \N +1380 865135061569123 stayAlert 2026-04-23 11:08:13+00 0101000020E61000006F66F4A3E16242404B732B84D598F4BF -1.287313 36.772511 0.00 \N 2026-04-23 11:09:03.286277+00 Parking alert poll \N \N \N \N \N +1383 865135061564470 ACC_ON 2026-04-23 11:06:15+00 0101000020E61000007FBE2D58AA71424006F7031E1800F3BF -1.187523 36.888011 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1384 862798050525423 ACC_ON 2026-04-23 11:05:58+00 0101000020E610000090F63FC05ADF43407A19C5724B8B0FC0 -3.943015 39.744957 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1387 865135061035778 ACC_OFF 2026-04-23 11:04:13+00 0101000020E6100000EDF483BA4877424016325706D506F3BF -1.189168 36.931907 0.00 \N 2026-04-23 11:09:03.286277+00 ACC OFF poll \N \N \N \N \N +1388 865135061035778 ACC_ON 2026-04-23 11:04:13+00 0101000020E610000007EDD5C743774240C77F81204006F3BF -1.189026 36.931756 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1389 865135061053748 ACC_ON 2026-04-23 11:04:11+00 0101000020E6100000B77EFACF9AD543402DB5DE6FB42310C0 -4.034868 39.668787 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1426 862798050523527 ACC_OFF 2026-04-23 11:09:01+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 0.00 \N 2026-04-23 11:09:03.286277+00 ACC OFF poll \N \N \N \N \N +1427 359857081892309 ACC_ON 2026-04-23 11:08:13+00 0101000020E6100000B62DCA6C907142401288D7F50B76F3BF -1.21632 36.88722 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1428 359857082897091 stayAlert 2026-04-23 11:07:58+00 0101000020E6100000C9E53FA4DF724240D36A48DC6369F3BF -1.21323 36.89745 0.00 \N 2026-04-23 11:09:03.286277+00 Parking alert poll \N \N \N \N \N +1429 359857082918186 ACC_ON 2026-04-23 11:07:38+00 0101000020E61000003C8386FE09524240EC4CA1F31ABBF1BF -1.10818 36.64093 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1430 359857082918012 ACC_OFF 2026-04-23 11:07:16+00 0101000020E610000081785DBF606B424040D9942BBC4BF3BF -1.20599 36.83889 0.00 \N 2026-04-23 11:09:03.286277+00 ACC OFF poll \N \N \N \N \N +1431 359857082897091 ACC_ON 2026-04-23 11:06:39+00 0101000020E6100000C9E53FA4DF724240D36A48DC6369F3BF -1.21323 36.89745 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1432 865135061054555 ACC_ON 2026-04-23 11:06:09+00 0101000020E6100000DDB1D82615314240E5B512BA4BE2D0BF -0.263812 36.383458 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1433 359857082897091 ACC_OFF 2026-04-23 11:06:03+00 0101000020E6100000AD342905DD7242409A7CB3CD8D69F3BF -1.21327 36.89737 0.00 \N 2026-04-23 11:09:03.286277+00 ACC OFF poll \N \N \N \N \N +1434 359857082897737 ACC_ON 2026-04-23 11:05:55+00 0101000020E6100000C1FF56B263DF434018265305A3920FC0 -3.9466 39.74523 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1435 359857082912486 ACC_ON 2026-04-23 11:05:37+00 0101000020E61000006CB2463D44E74340E5B8533A587F0EC0 -3.81218 39.80677 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1436 359857082042854 ACC_OFF 2026-04-23 11:05:23+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 0.00 \N 2026-04-23 11:09:03.286277+00 ACC OFF poll \N \N \N \N \N +1437 359857082918012 ACC_ON 2026-04-23 11:05:19+00 0101000020E61000000FB40243566B424055185B087250F3BF -1.20714 36.83857 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1438 862798050523337 ACC_OFF 2026-04-23 11:05:12+00 0101000020E6100000826F9A3E3BD44340A5F622DA8E2910C0 -4.040584 39.658058 0.00 \N 2026-04-23 11:09:03.286277+00 ACC OFF poll \N \N \N \N \N +1439 359857082910589 ACC_ON 2026-04-23 11:05:02+00 0101000020E6100000CBDB114E0B7642405B7C0A80F18CF2BF -1.15941 36.92222 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1440 359857082896911 ACC_OFF 2026-04-23 11:04:53+00 0101000020E61000002849D74CBE69424060EAE74D45AAF2BF -1.16657 36.82612 0.00 \N 2026-04-23 11:09:03.286277+00 ACC OFF poll \N \N \N \N \N +1441 862798050523527 ACC_ON 2026-04-23 11:04:40+00 0101000020E6100000C3EFA65B76724240D6A9F23D2311F3BF -1.191684 36.894237 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1442 359857081885410 ACC_ON 2026-04-23 11:04:40+00 0101000020E6100000117008556A72424036E50AEF7211F3BF -1.19176 36.89387 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1443 862798050526231 ACC_ON 2026-04-23 11:04:11+00 0101000020E610000091EF52EA92D54340EE0912DBDD2310C0 -4.035026 39.668546 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1534 865135061048953 ACC_ON 2026-04-23 11:08:02+00 0101000020E6100000E7FEEA71DFDC4340952C27A1F41510C0 -4.021441 39.725569 0.00 \N 2026-04-23 11:09:03.286277+00 ACC ON poll \N \N \N \N \N +1536 865135061048276 ACC_OFF 2026-04-23 11:04:50+00 0101000020E6100000E52A16BF29D443402766BD18CA2910C0 -4.04081 39.657524 0.00 \N 2026-04-23 11:09:03.286277+00 ACC OFF poll \N \N \N \N \N +1547 359857081892309 1001 2026-04-23 11:09:27+00 0101000020E61000008B321B6492714240834C32721676F3BF -1.21633 36.88728 \N \N 2026-04-23 11:09:28.555421+00 ACC OFF push \N \N \N \N \N +1548 359857082896911 stayAlertOn 2026-04-23 11:09:28+00 0101000020E61000005969520ABA694240B537F8C264AAF2BF -1.1666 36.82599 \N \N 2026-04-23 11:09:28.911404+00 Idling alert push \N \N \N \N \N +1549 862798050288345 146 2026-04-23 11:09:28+00 0101000020E61000004C6C3EAE0D914340C05DF6EB4E8711C0 -4.382137 39.13323 53.00 \N 2026-04-23 11:09:36.445771+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +1550 865135061569131 3 2026-04-23 11:09:36+00 0101000020E6100000632B685A6247404087C1FC153257B23F 0.071643 32.557689 69.00 \N 2026-04-23 11:09:38.16728+00 Vibration alert push \N \N \N \N \N +1551 359857081885410 1004 2026-04-23 11:10:00+00 0101000020E6100000836E2F698C724240E76F4221020EF3BF -1.19092 36.89491 \N \N 2026-04-23 11:10:00.451452+00 Parking alert push \N \N \N \N \N +1552 359857081892101 1002 2026-04-23 11:10:44+00 0101000020E61000002310AFEB17684240FB96395D1693F4BF -1.28591 36.81323 \N \N 2026-04-23 11:10:45.643131+00 ACC ON push \N \N \N \N \N +1553 359857082910589 1001 2026-04-23 11:11:04+00 0101000020E610000081CF0F23847742401B2FDD240681F2BF -1.1565 36.93372 \N \N 2026-04-23 11:11:05.056423+00 ACC OFF push \N \N \N \N \N +1554 865135061559538 1001 2026-04-23 11:11:26+00 0101000020E6100000D74B5304385B4240317903CC7C87F3BF -1.220578 36.712647 \N \N 2026-04-23 11:11:27.224417+00 ACC OFF push \N \N \N \N \N +1555 359857082918012 stayAlertOn 2026-04-23 11:11:58+00 0101000020E6100000A54E4013616B4240B29DEFA7C64BF3BF -1.206 36.8389 \N \N 2026-04-23 11:11:58.866927+00 Idling alert push \N \N \N \N \N +1556 359857081886467 1001 2026-04-23 11:12:04+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 \N \N 2026-04-23 11:12:05.24806+00 ACC OFF push \N \N \N \N \N +1557 865135061569131 3 2026-04-23 11:12:35+00 0101000020E6100000F0366F9C14484040274F594DD713AD3F 0.056792 32.563129 \N \N 2026-04-23 11:12:37.037564+00 Vibration alert push \N \N \N \N \N +1558 862798050523337 1002 2026-04-23 11:13:20+00 0101000020E6100000826F9A3E3BD44340A5F622DA8E2910C0 -4.040584 39.658058 \N \N 2026-04-23 11:13:20.629767+00 ACC ON push \N \N \N \N \N +1559 865135061048276 1002 2026-04-23 11:13:20+00 0101000020E61000009BCB0D863AD44340E4326E6AA02910C0 -4.040651 39.658036 \N \N 2026-04-23 11:13:20.712736+00 ACC ON push \N \N \N \N \N +1604 862798050523337 ACC_ON 2026-04-23 11:13:20+00 0101000020E6100000826F9A3E3BD44340A5F622DA8E2910C0 -4.040584 39.658058 0.00 \N 2026-04-23 11:14:04.175934+00 ACC ON poll \N \N \N \N \N +1606 865135061559538 ACC_OFF 2026-04-23 11:11:26+00 0101000020E6100000D74B5304385B4240317903CC7C87F3BF -1.220578 36.712647 0.00 \N 2026-04-23 11:14:04.175934+00 ACC OFF poll \N \N \N \N \N +1607 359857082910589 ACC_OFF 2026-04-23 11:11:04+00 0101000020E610000081CF0F23847742401B2FDD240681F2BF -1.1565 36.93372 0.00 \N 2026-04-23 11:14:04.175934+00 ACC OFF poll \N \N \N \N \N +1608 359857081892101 ACC_ON 2026-04-23 11:10:44+00 0101000020E61000002310AFEB17684240FB96395D1693F4BF -1.28591 36.81323 0.00 \N 2026-04-23 11:14:04.175934+00 ACC ON poll \N \N \N \N \N +1609 359857081885410 stayAlert 2026-04-23 11:10:00+00 0101000020E6100000836E2F698C724240E76F4221020EF3BF -1.19092 36.89491 0.00 \N 2026-04-23 11:14:04.175934+00 Parking alert poll \N \N \N \N \N +1611 862798050288345 146 2026-04-23 11:09:30+00 0101000020E61000004C6C3EAE0D914340C05DF6EB4E8711C0 -4.382137 39.13323 53.00 \N 2026-04-23 11:14:04.175934+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +1612 359857081892309 ACC_OFF 2026-04-23 11:09:27+00 0101000020E61000008B321B6492714240834C32721676F3BF -1.21633 36.88728 0.00 \N 2026-04-23 11:14:04.175934+00 ACC OFF poll \N \N \N \N \N +1613 865135061559538 ACC_ON 2026-04-23 11:09:19+00 0101000020E6100000D74B5304385B4240317903CC7C87F3BF -1.220578 36.712647 0.00 \N 2026-04-23 11:14:04.175934+00 ACC ON poll \N \N \N \N \N +1614 865135061054555 ACC_OFF 2026-04-23 11:09:07+00 0101000020E61000009E2633DE56304240158E20956247D1BF -0.269982 36.377651 0.00 \N 2026-04-23 11:14:04.175934+00 ACC OFF poll \N \N \N \N \N +1615 865135061559538 ACC_OFF 2026-04-23 11:09:04+00 0101000020E61000007ADFF8DA335B42406C97361C9686F3BF -1.220358 36.71252 0.00 \N 2026-04-23 11:14:04.175934+00 ACC OFF poll \N \N \N \N \N +1617 359857081885410 ACC_OFF 2026-04-23 11:09:00+00 0101000020E6100000117008556A72424036E50AEF7211F3BF -1.19176 36.89387 0.00 \N 2026-04-23 11:14:04.175934+00 ACC OFF poll \N \N \N \N \N +1712 865135061048276 ACC_ON 2026-04-23 11:13:20+00 0101000020E61000009BCB0D863AD44340E4326E6AA02910C0 -4.040651 39.658036 0.00 \N 2026-04-23 11:14:04.175934+00 ACC ON poll \N \N \N \N \N +1713 359857081886467 ACC_OFF 2026-04-23 11:12:04+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 0.00 \N 2026-04-23 11:14:04.175934+00 ACC OFF poll \N \N \N \N \N +1724 359857082897794 stayAlertOn 2026-04-23 11:14:15+00 0101000020E6100000D53E1D8F1968424050FC1873D792F4BF -1.28585 36.81328 \N \N 2026-04-23 11:14:15.974532+00 Idling alert push \N \N \N \N \N +1725 862798050525423 1001 2026-04-23 11:14:21+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 \N \N 2026-04-23 11:14:22.767136+00 ACC OFF push \N \N \N \N \N +1726 359857082897737 1001 2026-04-23 11:14:23+00 0101000020E6100000C7D79E5912E04340273108AC1C9A0FC0 -3.95025 39.75056 \N \N 2026-04-23 11:14:23.546661+00 ACC OFF push \N \N \N \N \N +1727 359857082918186 1001 2026-04-23 11:14:28+00 0101000020E610000028B8585183514240F0BF95ECD888F1BF -1.09591 36.63682 \N \N 2026-04-23 11:14:29.278008+00 ACC OFF push \N \N \N \N \N +1728 359857081892309 stayAlertOn 2026-04-23 11:14:31+00 0101000020E61000008B321B64927142401288D7F50B76F3BF -1.21632 36.88728 \N \N 2026-04-23 11:14:31.327055+00 Idling alert push \N \N \N \N \N +1729 359857081887069 1001 2026-04-23 11:14:37+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 11:14:38.363404+00 ACC OFF push \N \N \N \N \N +1730 862798050523337 147 2026-04-23 11:14:39+00 0101000020E6100000BCCADAA678D44340E1968FA4A42710C0 -4.038714 39.659932 24.00 \N 2026-04-23 11:14:40.560786+00 Collision Alert(DVR) push \N \N \N \N \N +1731 359857081886467 1002 2026-04-23 11:14:48+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 \N \N 2026-04-23 11:14:49.666439+00 ACC ON push \N \N \N \N \N +1732 865135061569131 3 2026-04-23 11:15:05+00 0101000020E6100000F0366F9C14484040274F594DD713AD3F 0.056792 32.563129 \N \N 2026-04-23 11:15:07.398358+00 Vibration alert push \N \N \N \N \N +1733 359857081886467 1001 2026-04-23 11:15:12+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 \N \N 2026-04-23 11:15:12.742835+00 ACC OFF push \N \N \N \N \N +1734 862798050525423 1004 2026-04-23 11:15:21+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 \N \N 2026-04-23 11:15:22.004803+00 Parking alert push \N \N \N \N \N +1735 865135061563639 stayAlertOn 2026-04-23 11:15:23+00 0101000020E61000008BDF14562AF442402FFCE07CEA18FCBF -1.756083 37.907542 \N \N 2026-04-23 11:15:24.035249+00 Idling alert push \N \N \N \N \N +1740 865135061053748 1001 2026-04-23 11:16:20+00 0101000020E6100000F1B73D4162D34340DA740470B32810C0 -4.039747 39.651436 \N \N 2026-04-23 11:16:21.405947+00 ACC OFF push \N \N \N \N \N +1741 862798050526231 1001 2026-04-23 11:16:21+00 0101000020E6100000FE99417C60D34340BE892139992810C0 -4.039647 39.651382 \N \N 2026-04-23 11:16:22.073023+00 ACC OFF push \N \N \N \N \N +1742 865135061581904 3 2026-04-23 11:16:32+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 \N \N 2026-04-23 11:16:34.107091+00 Vibration alert push \N \N \N \N \N +1743 865135061043079 1001 2026-04-23 11:16:34+00 0101000020E61000005A4B0169FFDF4340088ECBB8A9A10FC0 -3.953937 39.749982 \N \N 2026-04-23 11:16:35.682194+00 ACC OFF push \N \N \N \N \N +1744 862798050523139 1001 2026-04-23 11:16:36+00 0101000020E6100000A12B11A8FEDF4340AD6BB41CE8A10FC0 -3.954056 39.749959 \N \N 2026-04-23 11:16:37.277518+00 ACC OFF push \N \N \N \N \N +1745 865135061053748 1004 2026-04-23 11:17:19+00 0101000020E6100000ADDBA0F65BD343409CE1067C7E2810C0 -4.039545 39.651244 \N \N 2026-04-23 11:17:20.020548+00 Parking alert push \N \N \N \N \N +1746 359857081892309 1001 2026-04-23 11:17:25+00 0101000020E61000008B321B6492714240834C32721676F3BF -1.21633 36.88728 \N \N 2026-04-23 11:17:25.920751+00 ACC OFF push \N \N \N \N \N +1747 865135061569131 3 2026-04-23 11:17:24+00 0101000020E6100000F0366F9C14484040274F594DD713AD3F 0.056792 32.563129 \N \N 2026-04-23 11:17:26.58767+00 Vibration alert push \N \N \N \N \N +1748 359857082908500 1001 2026-04-23 11:17:26+00 0101000020E610000084640113B8914340C503CAA65C6111C0 -4.34508 39.13843 \N \N 2026-04-23 11:17:26.711316+00 ACC OFF push \N \N \N \N \N +1749 862798050288345 1001 2026-04-23 11:17:46+00 0101000020E6100000A46DFC89CA9043405CC823B8918211C0 -4.377509 39.131181 \N \N 2026-04-23 11:17:46.904371+00 ACC OFF push \N \N \N \N \N +1750 862798050525423 1002 2026-04-23 11:17:52+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 \N \N 2026-04-23 11:17:53.477565+00 ACC ON push \N \N \N \N \N +1751 359857082897737 1002 2026-04-23 11:17:54+00 0101000020E6100000802BD9B111E04340B56CAD2F129A0FC0 -3.95023 39.75054 \N \N 2026-04-23 11:17:54.609674+00 ACC ON push \N \N \N \N \N +1752 865135061564470 1001 2026-04-23 11:18:12+00 0101000020E61000005EF7562426724240D350A3906416F3BF -1.192967 36.891789 \N \N 2026-04-23 11:18:12.729921+00 ACC OFF push \N \N \N \N \N +1753 359857081887069 1002 2026-04-23 11:18:27+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 11:18:28.06315+00 ACC ON push \N \N \N \N \N +1911 865135061564470 1004 2026-04-23 11:19:12+00 0101000020E61000005EF7562426724240D350A3906416F3BF -1.192967 36.891789 \N \N 2026-04-23 11:19:12.545554+00 Parking alert push \N \N \N \N \N +1912 359857082902461 stayAlertOn 2026-04-23 11:19:23+00 0101000020E6100000AA656B7D91484340355EBA490C420BC0 -3.40725 38.56694 \N \N 2026-04-23 11:19:24.126637+00 Idling alert push \N \N \N \N \N +1913 359857082900341 1001 2026-04-23 11:19:24+00 0101000020E6100000F701486DE2DC4340F5108DEE201610C0 -4.02161 39.72566 \N \N 2026-04-23 11:19:25.130836+00 ACC OFF push \N \N \N \N \N +1915 865135061569131 3 2026-04-23 11:19:45+00 0101000020E61000009C50888043484040B75ED3838252AC3F 0.055317 32.56456 10.00 \N 2026-04-23 11:19:59.956311+00 Vibration alert push \N \N \N \N \N +1916 865135061043079 1002 2026-04-23 11:20:10+00 0101000020E61000005A4B0169FFDF4340088ECBB8A9A10FC0 -3.953937 39.749982 \N \N 2026-04-23 11:20:11.160476+00 ACC ON push \N \N \N \N \N +1917 862798050523139 1002 2026-04-23 11:20:11+00 0101000020E6100000A12B11A8FEDF4340AD6BB41CE8A10FC0 -3.954056 39.749959 \N \N 2026-04-23 11:20:11.788696+00 ACC ON push \N \N \N \N \N +1920 862798050523014 128 2026-04-23 11:21:08+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 11:21:10.627653+00 DVR vibration alert push \N \N \N \N \N +1931 862798050523337 147 2026-04-23 11:22:10+00 0101000020E61000006005F86EF3D64340BE30992A182510C0 -4.036225 39.679304 19.00 \N 2026-04-23 11:22:12.601456+00 Collision Alert(DVR) push \N \N \N \N \N +1932 862798050525423 1004 2026-04-23 11:22:16+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 \N \N 2026-04-23 11:22:16.818146+00 Parking alert push \N \N \N \N \N +1933 359857082897737 1002 2026-04-23 11:22:23+00 0101000020E6100000B1A206D330E043405F7B6649809A0FC0 -3.95044 39.75149 \N \N 2026-04-23 11:22:24.00373+00 ACC ON push \N \N \N \N \N +1934 862798050525423 1002 2026-04-23 11:22:26+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 \N \N 2026-04-23 11:22:27.123347+00 ACC ON push \N \N \N \N \N +1935 865135061569123 1001 2026-04-23 11:22:28+00 0101000020E61000000DA5F622DA644240CD5B751DAAA9F4BF -1.291422 36.787907 \N \N 2026-04-23 11:22:28.928417+00 ACC OFF push \N \N \N \N \N +1936 359857082908500 1001 2026-04-23 11:22:28+00 0101000020E610000019E25817B7914340C4EBFA05BB6111C0 -4.34544 39.1384 \N \N 2026-04-23 11:22:29.098416+00 ACC OFF push \N \N \N \N \N +5515 865135061569123 stayAlert 2026-04-23 12:52:04+00 0101000020E61000008EC9E2FE23634240685A626534B2F4BF -1.293507 36.774536 0.00 \N 2026-04-23 12:54:28.942767+00 Parking alert poll \N \N \N \N \N +5517 865135061569123 ACC_OFF 2026-04-23 12:51:04+00 0101000020E61000008EC9E2FE23634240685A626534B2F4BF -1.293507 36.774536 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5518 865135061563282 ACC_OFF 2026-04-23 12:50:37+00 0101000020E6100000EBE40CC51D454040CE716E13EE95C93F 0.199888 32.539971 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5519 865135061053748 stayAlert 2026-04-23 12:50:15+00 0101000020E61000004BC8073D9BD54340AF93FAB2B42310C0 -4.034869 39.6688 0.00 \N 2026-04-23 12:54:28.942767+00 Parking alert poll \N \N \N \N \N +5520 359857082900358 ACC_OFF 2026-04-23 12:49:54+00 0101000020E61000002315C616827C4240D52137C30DF8F6BF -1.43556 36.97272 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5555 862798050523337 ACC_ON 2026-04-23 12:54:09+00 0101000020E6100000FD4E93196FD94340D3A57F492A0310C0 -4.003091 39.698703 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5557 359857082042854 ACC_ON 2026-04-23 12:53:52+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5558 865135061054555 ACC_ON 2026-04-23 12:52:28+00 0101000020E61000000455A3570330424056116E32AA0CD2BF -0.282023 36.375102 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5559 359857082037185 ACC_OFF 2026-04-23 12:52:15+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5560 862798050526231 ACC_ON 2026-04-23 12:52:13+00 0101000020E6100000DE58501894D54340EEEC2B0FD22310C0 -4.034981 39.668582 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5561 359857082037185 ACC_ON 2026-04-23 12:52:08+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5562 359857081885410 ACC_ON 2026-04-23 12:51:56+00 0101000020E6100000D13FC1C58A72424003CFBD874B0EF3BF -1.19099 36.89486 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5563 865135061054548 ACC_ON 2026-04-23 12:51:56+00 0101000020E6100000817A336ABE724240B6B9313D6109F3BF -1.18979 36.896436 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +1736 359857082910589 stayAlertOn 2026-04-23 11:15:43+00 0101000020E61000002BD9B111887742405305A3923A81F2BF -1.15655 36.93384 \N \N 2026-04-23 11:15:43.709512+00 Idling alert push \N \N \N \N \N +1737 359857081892101 stayAlertOn 2026-04-23 11:15:44+00 0101000020E6100000DC63E9431768424089D2DEE00B93F4BF -1.2859 36.81321 \N \N 2026-04-23 11:15:44.711301+00 Idling alert push \N \N \N \N \N +1738 865135061035653 1002 2026-04-23 11:15:48+00 0101000020E6100000D1CC936B0ADE434092CA147310940FC0 -3.947297 39.734693 \N \N 2026-04-23 11:15:49.1392+00 ACC ON push \N \N \N \N \N +1739 359857082902461 1001 2026-04-23 11:16:02+00 0101000020E6100000AA656B7D91484340355EBA490C420BC0 -3.40725 38.56694 \N \N 2026-04-23 11:16:03.730519+00 ACC OFF push \N \N \N \N \N +1914 865135061564470 3 2026-04-23 11:19:49+00 0101000020E6100000BEF90D130D72424012C2A38D2316F3BF -1.192905 36.891024 \N \N 2026-04-23 11:19:51.77385+00 Vibration alert push \N \N \N \N \N +1918 359857082898016 stayAlertOn 2026-04-23 11:20:25+00 0101000020E61000007233DC80CFDB4340FD6A0E10CCD10FC0 -3.97744 39.71727 \N \N 2026-04-23 11:20:25.939244+00 Idling alert push \N \N \N \N \N +1919 359857081892762 1003 2026-04-23 11:20:58+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 \N \N 2026-04-23 11:20:58.818192+00 Offline alert push \N \N \N \N \N +1921 862798050525423 1001 2026-04-23 11:21:16+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 \N \N 2026-04-23 11:21:17.085035+00 ACC OFF push \N \N \N \N \N +1922 359857082897737 1001 2026-04-23 11:21:17+00 0101000020E6100000B1A206D330E043405F7B6649809A0FC0 -3.95044 39.75149 \N \N 2026-04-23 11:21:17.870283+00 ACC OFF push \N \N \N \N \N +1923 359857082908500 1002 2026-04-23 11:21:24+00 0101000020E610000084640113B8914340C503CAA65C6111C0 -4.34508 39.13843 \N \N 2026-04-23 11:21:25.280248+00 ACC ON push \N \N \N \N \N +1924 865135061569131 1004 2026-04-23 11:21:25+00 0101000020E61000008884EFFD0D4840400B08AD872F13AD3F 0.056787 32.562927 \N \N 2026-04-23 11:21:25.75713+00 Parking alert push \N \N \N \N \N +1925 359857082900341 1002 2026-04-23 11:21:30+00 0101000020E6100000B05582C5E1DC43404A24D1CB281610C0 -4.02164 39.72564 \N \N 2026-04-23 11:21:31.047758+00 ACC ON push \N \N \N \N \N +1926 862798050288345 1002 2026-04-23 11:21:32+00 0101000020E61000003C84F1D3B891434025917D90656111C0 -4.345114 39.138453 \N \N 2026-04-23 11:21:33.095858+00 ACC ON push \N \N \N \N \N +1927 865135061563415 3 2026-04-23 11:21:32+00 0101000020E610000068AED3484B5D42401FDAC70A7EDBF3BF -1.241087 36.72886 \N \N 2026-04-23 11:22:00.676215+00 Vibration alert push \N \N \N \N \N +1928 865135061559538 3 2026-04-23 11:13:05+00 0101000020E6100000D74B5304385B4240317903CC7C87F3BF -1.220578 36.712647 \N \N 2026-04-23 11:22:01.975796+00 Vibration alert push \N \N \N \N \N +1929 865135061559538 1002 2026-04-23 11:22:02+00 0101000020E6100000D74B5304385B4240317903CC7C87F3BF -1.220578 36.712647 \N \N 2026-04-23 11:22:02.641609+00 ACC ON push \N \N \N \N \N +1930 865135061569131 3 2026-04-23 11:22:06+00 0101000020E61000007670B037314840400951BEA08504AC3F 0.054722 32.564002 \N \N 2026-04-23 11:22:07.568836+00 Vibration alert push \N \N \N \N \N +1937 865135061054555 1002 2026-04-23 11:22:38+00 0101000020E6100000C685032159304240C7F484251E50D1BF -0.270515 36.37772 \N \N 2026-04-23 11:22:39.11657+00 ACC ON push \N \N \N \N \N +5564 359857082918012 ACC_OFF 2026-04-23 12:51:38+00 0101000020E61000008D7F9F71E16C4240DA5548F949B5F3BF -1.23176 36.85063 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5565 865135061035653 ACC_OFF 2026-04-23 12:51:14+00 0101000020E61000004C1762F547E04340C4B0C398F4970FC0 -3.949197 39.752196 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5566 865135061563597 ACC_ON 2026-04-23 12:51:03+00 0101000020E6100000111AC1C6F55342405E64027E8DE4F1BF -1.118299 36.655938 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5567 359857081891566 ACC_OFF 2026-04-23 12:50:57+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5568 862798050523527 ACC_ON 2026-04-23 12:50:15+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5570 359857082042854 ACC_OFF 2026-04-23 12:49:59+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5627 862798050523626 146 2026-04-23 12:54:17+00 0101000020E6100000FF1F274C18BB434095BBCFF1D1E20DC0 -3.735752 39.461679 62.00 \N 2026-04-23 12:54:28.942767+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +5629 359857082918038 ACC_OFF 2026-04-23 12:53:03+00 0101000020E6100000FE9AAC510F494340F33CB83B6B370BC0 -3.40206 38.57078 0.00 \N 2026-04-23 12:54:28.942767+00 ACC OFF poll \N \N \N \N \N +5630 865135061048466 ACC_ON 2026-04-23 12:51:58+00 0101000020E6100000FA2AF9D85D52424083A5BA8097D9F1BF -1.115623 36.643489 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +5631 359857082918038 ACC_ON 2026-04-23 12:51:27+00 0101000020E61000008C4AEA043449434014E8137992340BC0 -3.40067 38.5719 0.00 \N 2026-04-23 12:54:28.942767+00 ACC ON poll \N \N \N \N \N +6849 862798050525423 1004 2026-04-23 13:30:28+00 0101000020E6100000C4211B4817DB4340FD6B79E57AFB0FC0 -3.997793 39.711648 \N \N 2026-04-23 13:30:28.350996+00 Parking alert push \N \N \N \N \N +6850 865135061569131 3 2026-04-23 13:30:31+00 0101000020E6100000B328ECA2E84540404F04711E4E60B63F 0.087407 32.546162 21.00 \N 2026-04-23 13:30:31.980318+00 Vibration alert push \N \N \N \N \N +6852 865135061562847 3 2026-04-23 13:27:46+00 0101000020E610000031D28BDAFD7E424012F92EA52E59F1BF -1.084273 36.992122 \N \N 2026-04-23 13:30:59.172476+00 Vibration alert push \N \N \N \N \N +6853 862798052707946 1001 2026-04-23 13:31:18+00 0101000020E61000007E6FD39FFD7642402B2FF99FFC1DF3BF -1.194821 36.929615 \N \N 2026-04-23 13:31:19.084542+00 ACC OFF push \N \N \N \N \N +6856 865135061035133 1001 2026-04-23 13:32:06+00 0101000020E6100000179AEB34D2C243407D224F92AE590CC0 -3.54379 39.52204 \N \N 2026-04-23 13:32:07.313108+00 ACC OFF push \N \N \N \N \N +6857 865135061054548 1002 2026-04-23 13:32:21+00 0101000020E6100000CBD93BA3AD724240261E5036E50AF3BF -1.19016 36.895924 \N \N 2026-04-23 13:32:21.600237+00 ACC ON push \N \N \N \N \N +6861 359857082896911 stayAlertOn 2026-04-23 13:32:50+00 0101000020E610000029D027F224694240E9263108AC9CF2BF -1.16325 36.82144 \N \N 2026-04-23 13:32:50.186848+00 Idling alert push \N \N \N \N \N +6862 865135061569131 3 2026-04-23 13:32:51+00 0101000020E610000027A25F5B3F454040780DFAD2DB9FB73F 0.092283 32.540996 17.00 \N 2026-04-23 13:32:52.674181+00 Vibration alert push \N \N \N \N \N +6864 865135061054548 1001 2026-04-23 13:33:22+00 0101000020E61000009126DE019E7242407BF7C77BD50AF3BF -1.190145 36.895447 \N \N 2026-04-23 13:33:22.551649+00 ACC OFF push \N \N \N \N \N +6865 862798050523626 1002 2026-04-23 13:33:26+00 0101000020E6100000FA804067D2C24340228C9FC6BD590CC0 -3.543819 39.522046 \N \N 2026-04-23 13:33:27.523607+00 ACC ON push \N \N \N \N \N +6867 359857081886905 1001 2026-04-23 13:34:12+00 0101000020E61000009A081B9E5ED943402C4833164D2710C0 -4.03838 39.6982 \N \N 2026-04-23 13:34:14.061689+00 ACC OFF push \N \N \N \N \N +6868 865135061563597 3 2026-04-23 13:33:46+00 0101000020E6100000B88FDC9A745342408C6A11514CDEF1BF -1.116772 36.651996 \N \N 2026-04-23 13:34:28.759749+00 Vibration alert push \N \N \N \N \N +6869 862798050288345 128 2026-04-23 13:34:31+00 0101000020E610000072C5C551B991434082AE7D01BD6011C0 -4.344471 39.138468 0.00 \N 2026-04-23 13:34:35.182422+00 DVR vibration alert push \N \N \N \N \N +7005 865135061569131 3 2026-04-23 13:35:11+00 0101000020E610000093C9A99D614440402577D844662EB83F 0.094458 32.534229 23.00 \N 2026-04-23 13:35:12.991571+00 Vibration alert push \N \N \N \N \N +7009 359857082918012 stayAlertOn 2026-04-23 13:35:36+00 0101000020E6100000A4A5F276846B42402BF697DD9307F3BF -1.18935 36.83998 \N \N 2026-04-23 13:35:36.895589+00 Idling alert push \N \N \N \N \N +7016 359857082910589 1001 2026-04-23 13:37:38+00 0101000020E6100000A2EE0390DA784240ED9925016A6AF2BF -1.15098 36.94417 \N \N 2026-04-23 13:37:39.118129+00 ACC OFF push \N \N \N \N \N +7017 359857082918012 1001 2026-04-23 13:37:50+00 0101000020E6100000A4A5F276846B42402BF697DD9307F3BF -1.18935 36.83998 \N \N 2026-04-23 13:37:50.731176+00 ACC OFF push \N \N \N \N \N +7018 865135061564470 1004 2026-04-23 13:37:51+00 0101000020E6100000DE8D0585415D42400742B28009DCF3BF -1.24122 36.728562 \N \N 2026-04-23 13:37:52.017975+00 Parking alert push \N \N \N \N \N +7019 359857082897091 1004 2026-04-23 13:37:59+00 0101000020E610000042EC4CA1F37242406397A8DE1A58F3BF -1.20901 36.89806 \N \N 2026-04-23 13:38:00.03846+00 Parking alert push \N \N \N \N \N +7021 865135061053748 1001 2026-04-23 13:38:50+00 0101000020E61000006E6B0BCF4BD3434045B9347EE13510C0 -4.052618 39.650751 \N \N 2026-04-23 13:38:50.501925+00 ACC OFF push \N \N \N \N \N +7024 865135061053748 ACC_ON 2026-04-23 13:38:58+00 0101000020E61000001F662FDB4ED343404354E1CFF03610C0 -4.053653 39.650844 0.00 \N 2026-04-23 13:39:37.369912+00 ACC ON poll \N \N \N \N \N +7025 865135061053748 ACC_OFF 2026-04-23 13:38:50+00 0101000020E61000006E6B0BCF4BD3434045B9347EE13510C0 -4.052618 39.650751 0.00 \N 2026-04-23 13:39:37.369912+00 ACC OFF poll \N \N \N \N \N +7026 865135061564470 stayAlert 2026-04-23 13:37:51+00 0101000020E6100000DE8D0585415D42400742B28009DCF3BF -1.24122 36.728562 0.00 \N 2026-04-23 13:39:37.369912+00 Parking alert poll \N \N \N \N \N +7028 865135061564470 ACC_OFF 2026-04-23 13:36:52+00 0101000020E6100000DE8D0585415D42400742B28009DCF3BF -1.24122 36.728562 0.00 \N 2026-04-23 13:39:37.369912+00 ACC OFF poll \N \N \N \N \N +1754 865135061564470 ACC_OFF 2026-04-23 11:18:12+00 0101000020E61000005EF7562426724240D350A3906416F3BF -1.192967 36.891789 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1755 862798050525423 ACC_ON 2026-04-23 11:17:52+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 0.00 \N 2026-04-23 11:19:05.011566+00 ACC ON poll \N \N \N \N \N +1757 865135061053748 stayAlert 2026-04-23 11:17:19+00 0101000020E6100000ADDBA0F65BD343409CE1067C7E2810C0 -4.039545 39.651244 0.00 \N 2026-04-23 11:19:05.011566+00 Parking alert poll \N \N \N \N \N +1759 865135061053748 ACC_OFF 2026-04-23 11:16:20+00 0101000020E6100000F1B73D4162D34340DA740470B32810C0 -4.039747 39.651436 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1761 862798050525423 stayAlert 2026-04-23 11:15:21+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 0.00 \N 2026-04-23 11:19:05.011566+00 Parking alert poll \N \N \N \N \N +1763 862798050525423 ACC_OFF 2026-04-23 11:14:21+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1795 359857082897737 ACC_ON 2026-04-23 11:17:54+00 0101000020E6100000802BD9B111E04340B56CAD2F129A0FC0 -3.95023 39.75054 0.00 \N 2026-04-23 11:19:05.011566+00 ACC ON poll \N \N \N \N \N +1796 862798050288345 ACC_OFF 2026-04-23 11:17:46+00 0101000020E6100000A46DFC89CA9043405CC823B8918211C0 -4.377509 39.131181 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1797 359857082908500 ACC_OFF 2026-04-23 11:17:26+00 0101000020E610000084640113B8914340C503CAA65C6111C0 -4.34508 39.13843 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1798 359857081892309 ACC_OFF 2026-04-23 11:17:25+00 0101000020E61000008B321B6492714240834C32721676F3BF -1.21633 36.88728 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1799 862798050526231 ACC_OFF 2026-04-23 11:16:21+00 0101000020E6100000FE99417C60D34340BE892139992810C0 -4.039647 39.651382 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1800 865135061035653 ACC_ON 2026-04-23 11:15:48+00 0101000020E6100000D1CC936B0ADE434092CA147310940FC0 -3.947297 39.734693 0.00 \N 2026-04-23 11:19:05.011566+00 ACC ON poll \N \N \N \N \N +1805 359857082918186 ACC_OFF 2026-04-23 11:14:28+00 0101000020E610000028B8585183514240F0BF95ECD888F1BF -1.09591 36.63682 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1806 359857082897737 ACC_OFF 2026-04-23 11:14:23+00 0101000020E6100000C7D79E5912E04340273108AC1C9A0FC0 -3.95025 39.75056 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1892 359857081887069 ACC_ON 2026-04-23 11:18:27+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 11:19:05.011566+00 ACC ON poll \N \N \N \N \N +1893 862798050523139 ACC_OFF 2026-04-23 11:16:36+00 0101000020E6100000A12B11A8FEDF4340AD6BB41CE8A10FC0 -3.954056 39.749959 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1894 865135061043079 ACC_OFF 2026-04-23 11:16:34+00 0101000020E61000005A4B0169FFDF4340088ECBB8A9A10FC0 -3.953937 39.749982 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1895 359857082902461 ACC_OFF 2026-04-23 11:16:02+00 0101000020E6100000AA656B7D91484340355EBA490C420BC0 -3.40725 38.56694 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1896 359857081886467 ACC_OFF 2026-04-23 11:15:12+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1897 359857081886467 ACC_ON 2026-04-23 11:14:48+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 0.00 \N 2026-04-23 11:19:05.011566+00 ACC ON poll \N \N \N \N \N +1898 359857081887069 ACC_OFF 2026-04-23 11:14:37+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 11:19:05.011566+00 ACC OFF poll \N \N \N \N \N +1938 359857082902461 1002 2026-04-23 11:22:45+00 0101000020E61000008DEE2076A6484340ABB2EF8AE03F0BC0 -3.40619 38.56758 \N \N 2026-04-23 11:22:46.429113+00 ACC ON push \N \N \N \N \N +1939 865135061563597 3 2026-04-23 11:21:59+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 11:22:47.369097+00 Vibration alert push \N \N \N \N \N +1940 862798050288345 1001 2026-04-23 11:22:47+00 0101000020E6100000ADF71BEDB891434009FD4CBD6E6111C0 -4.345149 39.138456 \N \N 2026-04-23 11:22:48.137965+00 ACC OFF push \N \N \N \N \N +1941 359857082900341 1001 2026-04-23 11:22:50+00 0101000020E6100000B05582C5E1DC43404A24D1CB281610C0 -4.02164 39.72564 \N \N 2026-04-23 11:22:51.092233+00 ACC OFF push \N \N \N \N \N +1942 862798050523527 1002 2026-04-23 11:23:04+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 11:23:04.812554+00 ACC ON push \N \N \N \N \N +1943 862798050288360 147 2026-04-23 11:23:01+00 0101000020E61000007CB94F8E02724240D47D00529B78F3BF -1.216945 36.890703 9.00 \N 2026-04-23 11:23:12.920925+00 Collision Alert(DVR) push \N \N \N \N \N +1944 359857081887069 stayAlertOn 2026-04-23 11:23:27+00 0101000020E6100000AF08FEB79279424053910A630B41F3BF -1.20338 36.94979 \N \N 2026-04-23 11:23:27.169918+00 Idling alert push \N \N \N \N \N +1945 865135061569123 1004 2026-04-23 11:23:27+00 0101000020E61000000DA5F622DA644240CD5B751DAAA9F4BF -1.291422 36.787907 \N \N 2026-04-23 11:23:27.83541+00 Parking alert push \N \N \N \N \N +1946 865135061054555 1001 2026-04-23 11:23:48+00 0101000020E6100000C09481035A304240A7B393C151F2D0BF -0.26479 36.377747 \N \N 2026-04-23 11:23:49.87186+00 ACC OFF push \N \N \N \N \N +1947 865135061054548 1002 2026-04-23 11:23:52+00 0101000020E6100000F644D7851F724240A933F790F0FDF2BF -1.186997 36.891587 \N \N 2026-04-23 11:23:53.343519+00 ACC ON push \N \N \N \N \N +1948 865135061569123 3 2026-04-23 11:23:51+00 0101000020E61000000DA5F622DA644240CD5B751DAAA9F4BF -1.291422 36.787907 \N \N 2026-04-23 11:23:55.944894+00 Vibration alert push \N \N \N \N \N +1949 359857082900341 1002 2026-04-23 11:24:01+00 0101000020E6100000B05582C5E1DC43404A24D1CB281610C0 -4.02164 39.72564 \N \N 2026-04-23 11:24:02.15914+00 ACC ON push \N \N \N \N \N +1951 865135061569123 stayAlert 2026-04-23 11:23:27+00 0101000020E61000000DA5F622DA644240CD5B751DAAA9F4BF -1.291422 36.787907 0.00 \N 2026-04-23 11:24:05.833718+00 Parking alert poll \N \N \N \N \N +1952 865135061569123 ACC_OFF 2026-04-23 11:22:28+00 0101000020E61000000DA5F622DA644240CD5B751DAAA9F4BF -1.291422 36.787907 0.00 \N 2026-04-23 11:24:05.833718+00 ACC OFF poll \N \N \N \N \N +1953 862798050525423 ACC_ON 2026-04-23 11:22:26+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +1954 862798050525423 stayAlert 2026-04-23 11:22:16+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 0.00 \N 2026-04-23 11:24:05.833718+00 Parking alert poll \N \N \N \N \N +1956 865135061569131 stayAlert 2026-04-23 11:21:25+00 0101000020E61000008884EFFD0D4840400B08AD872F13AD3F 0.056787 32.562927 0.00 \N 2026-04-23 11:24:05.833718+00 Parking alert poll \N \N \N \N \N +1957 862798050525423 ACC_OFF 2026-04-23 11:21:16+00 0101000020E610000062F5471806E04340EE940ED6FF990FC0 -3.950195 39.750186 0.00 \N 2026-04-23 11:24:05.833718+00 ACC OFF poll \N \N \N \N \N +1960 865135061564470 stayAlert 2026-04-23 11:19:12+00 0101000020E61000005EF7562426724240D350A3906416F3BF -1.192967 36.891789 0.00 \N 2026-04-23 11:24:05.833718+00 Parking alert poll \N \N \N \N \N +1997 359857082900341 ACC_ON 2026-04-23 11:24:01+00 0101000020E6100000B05582C5E1DC43404A24D1CB281610C0 -4.02164 39.72564 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +1998 865135061054548 ACC_ON 2026-04-23 11:23:52+00 0101000020E6100000F644D7851F724240A933F790F0FDF2BF -1.186997 36.891587 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +1999 865135061054555 ACC_OFF 2026-04-23 11:23:48+00 0101000020E6100000C09481035A304240A7B393C151F2D0BF -0.26479 36.377747 0.00 \N 2026-04-23 11:24:05.833718+00 ACC OFF poll \N \N \N \N \N +2000 862798050523527 ACC_ON 2026-04-23 11:23:04+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2001 862798050288360 147 2026-04-23 11:23:02+00 0101000020E61000007CB94F8E02724240D47D00529B78F3BF -1.216945 36.890703 9.00 \N 2026-04-23 11:24:05.833718+00 Collision Alert(DVR) poll \N \N \N \N \N +2002 359857082900341 ACC_OFF 2026-04-23 11:22:50+00 0101000020E6100000B05582C5E1DC43404A24D1CB281610C0 -4.02164 39.72564 0.00 \N 2026-04-23 11:24:05.833718+00 ACC OFF poll \N \N \N \N \N +2003 862798050288345 ACC_OFF 2026-04-23 11:22:47+00 0101000020E6100000ADF71BEDB891434009FD4CBD6E6111C0 -4.345149 39.138456 0.00 \N 2026-04-23 11:24:05.833718+00 ACC OFF poll \N \N \N \N \N +2004 865135061054555 ACC_ON 2026-04-23 11:22:38+00 0101000020E6100000C685032159304240C7F484251E50D1BF -0.270515 36.37772 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2005 359857082908500 ACC_OFF 2026-04-23 11:22:28+00 0101000020E610000019E25817B7914340C4EBFA05BB6111C0 -4.34544 39.1384 0.00 \N 2026-04-23 11:24:05.833718+00 ACC OFF poll \N \N \N \N \N +2006 359857082897737 ACC_ON 2026-04-23 11:22:23+00 0101000020E6100000B1A206D330E043405F7B6649809A0FC0 -3.95044 39.75149 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2007 862798050523337 147 2026-04-23 11:22:11+00 0101000020E61000006005F86EF3D64340BE30992A182510C0 -4.036225 39.679304 19.00 \N 2026-04-23 11:24:05.833718+00 Collision Alert(DVR) poll \N \N \N \N \N +2008 865135061559538 ACC_ON 2026-04-23 11:22:02+00 0101000020E6100000D74B5304385B4240317903CC7C87F3BF -1.220578 36.712647 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2010 862798050288345 ACC_ON 2026-04-23 11:21:32+00 0101000020E61000003C84F1D3B891434025917D90656111C0 -4.345114 39.138453 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2011 359857082900341 ACC_ON 2026-04-23 11:21:30+00 0101000020E6100000B05582C5E1DC43404A24D1CB281610C0 -4.02164 39.72564 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2012 359857082908500 ACC_ON 2026-04-23 11:21:24+00 0101000020E610000084640113B8914340C503CAA65C6111C0 -4.34508 39.13843 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2013 359857082897737 ACC_OFF 2026-04-23 11:21:17+00 0101000020E6100000B1A206D330E043405F7B6649809A0FC0 -3.95044 39.75149 0.00 \N 2026-04-23 11:24:05.833718+00 ACC OFF poll \N \N \N \N \N +2014 862798050523014 128 2026-04-23 11:21:09+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 11:24:05.833718+00 DVR vibration alert poll \N \N \N \N \N +2015 359857081892762 offline 2026-04-23 11:20:58+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 0.00 \N 2026-04-23 11:24:05.833718+00 Offline alert poll \N \N \N \N \N +2016 359857082900341 ACC_OFF 2026-04-23 11:19:24+00 0101000020E6100000F701486DE2DC4340F5108DEE201610C0 -4.02161 39.72566 0.00 \N 2026-04-23 11:24:05.833718+00 ACC OFF poll \N \N \N \N \N +2101 359857082902461 ACC_ON 2026-04-23 11:22:45+00 0101000020E61000008DEE2076A6484340ABB2EF8AE03F0BC0 -3.40619 38.56758 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2104 862798050523139 ACC_ON 2026-04-23 11:20:11+00 0101000020E6100000A12B11A8FEDF4340AD6BB41CE8A10FC0 -3.954056 39.749959 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2105 865135061043079 ACC_ON 2026-04-23 11:20:10+00 0101000020E61000005A4B0169FFDF4340088ECBB8A9A10FC0 -3.953937 39.749982 0.00 \N 2026-04-23 11:24:05.833718+00 ACC ON poll \N \N \N \N \N +2151 865135061053748 ACC_ON 2026-04-23 11:28:45+00 0101000020E6100000ADDBA0F65BD343409CE1067C7E2810C0 -4.039545 39.651244 0.00 \N 2026-04-23 11:29:06.719063+00 ACC ON poll \N \N \N \N \N +2152 862798050525423 stayAlert 2026-04-23 11:26:38+00 0101000020E6100000992EC4EA8FE04340B1A547533D990FC0 -3.949824 39.754392 0.00 \N 2026-04-23 11:29:06.719063+00 Parking alert poll \N \N \N \N \N +2154 862798050525423 ACC_OFF 2026-04-23 11:25:38+00 0101000020E6100000992EC4EA8FE04340B1A547533D990FC0 -3.949824 39.754392 0.00 \N 2026-04-23 11:29:06.719063+00 ACC OFF poll \N \N \N \N \N +2155 865135061569123 ACC_ON 2026-04-23 11:24:13+00 0101000020E61000000DA5F622DA644240CD5B751DAAA9F4BF -1.291422 36.787907 0.00 \N 2026-04-23 11:29:06.719063+00 ACC ON poll \N \N \N \N \N +2195 359857081886905 ACC_ON 2026-04-23 11:28:43+00 0101000020E6100000A67EDE54A4DE434050AA7D3A1EB30FC0 -3.96246 39.73939 0.00 \N 2026-04-23 11:29:06.719063+00 ACC ON poll \N \N \N \N \N +2196 359857081887192 ACC_ON 2026-04-23 11:28:15+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 11:29:06.719063+00 ACC ON poll \N \N \N \N \N +2198 862798050526231 ACC_ON 2026-04-23 11:28:03+00 0101000020E6100000FE99417C60D34340BE892139992810C0 -4.039647 39.651382 0.00 \N 2026-04-23 11:29:06.719063+00 ACC ON poll \N \N \N \N \N +2200 862798050288345 128 2026-04-23 11:27:59+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:29:06.719063+00 DVR vibration alert poll \N \N \N \N \N +2201 359857082037185 ACC_OFF 2026-04-23 11:27:17+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 11:29:06.719063+00 ACC OFF poll \N \N \N \N \N +2202 359857082037185 ACC_ON 2026-04-23 11:27:14+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 11:29:06.719063+00 ACC ON poll \N \N \N \N \N +2203 862798050523014 128 2026-04-23 11:26:58+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 11:29:06.719063+00 DVR vibration alert poll \N \N \N \N \N +2205 359857082918012 ACC_ON 2026-04-23 11:26:41+00 0101000020E61000008195438B6C6B424094DE37BEF64CF3BF -1.20629 36.83925 0.00 \N 2026-04-23 11:29:06.719063+00 ACC ON poll \N \N \N \N \N +2206 865135061559538 ACC_OFF 2026-04-23 11:26:25+00 0101000020E610000000E65AB4005D4240FE7BF0DAA5CDF3BF -1.237707 36.726584 0.00 \N 2026-04-23 11:29:06.719063+00 ACC OFF poll \N \N \N \N \N +2207 359857081886905 ACC_OFF 2026-04-23 11:25:45+00 0101000020E610000018213CDA38DE434033F9669B1B930FC0 -3.94683 39.73611 0.00 \N 2026-04-23 11:29:06.719063+00 ACC OFF poll \N \N \N \N \N +2208 359857082897737 ACC_OFF 2026-04-23 11:25:32+00 0101000020E61000001B0DE02D90E043409B3DD00A0C990FC0 -3.94973 39.7544 0.00 \N 2026-04-23 11:29:06.719063+00 ACC OFF poll \N \N \N \N \N +2209 359857082900341 ACC_OFF 2026-04-23 11:25:01+00 0101000020E6100000D42B6519E2DC43402E73BA2C261610C0 -4.02163 39.72565 0.00 \N 2026-04-23 11:29:06.719063+00 ACC OFF poll \N \N \N \N \N +2210 862798052707946 135 2026-04-23 11:24:12+00 0101000020E6100000F2272A1BD6784240342F87DD77CCF2BF -1.174919 36.944034 90.00 \N 2026-04-23 11:29:06.719063+00 Overspeed alert(DVR) poll \N \N \N \N \N +2294 862798050523139 146 2026-04-23 11:26:03+00 0101000020E61000005473B9C150DF4340D50792770E850FC0 -3.939969 39.744652 41.00 \N 2026-04-23 11:29:06.719063+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +2295 359857082902461 ACC_OFF 2026-04-23 11:24:22+00 0101000020E61000007094BC3AC7484340978BF84ECC3A0BC0 -3.40371 38.56858 0.00 \N 2026-04-23 11:29:06.719063+00 ACC OFF poll \N \N \N \N \N +2341 865135061053748 ACC_OFF 2026-04-23 11:33:57+00 0101000020E610000084F1D3B837D3434027A089B0E12910C0 -4.0409 39.650138 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2343 865135061563282 ACC_ON 2026-04-23 11:32:25+00 0101000020E6100000815CE2C803454040954737C2A222C83F 0.188557 32.539178 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2345 865135061037980 ACC_ON 2026-04-23 11:29:46+00 0101000020E61000005A2BDA1CE77A4240109370218F60F2BF -1.148574 36.960178 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2384 862798050526231 ACC_OFF 2026-04-23 11:33:58+00 0101000020E61000002BDA1CE736D343408E93C2BCC72910C0 -4.040801 39.650113 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2385 862798052707946 ACC_OFF 2026-04-23 11:33:06+00 0101000020E610000034BF9A03047742404A6249B9FB1CF3BF -1.194576 36.92981 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2386 862798050523014 128 2026-04-23 11:33:01+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 11:34:07.571496+00 DVR vibration alert poll \N \N \N \N \N +2387 359857082912486 ACC_OFF 2026-04-23 11:32:59+00 0101000020E6100000D044D8F0F4E64340C68A1A4CC3B00EC0 -3.83631 39.80435 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2388 862798050288360 ACC_OFF 2026-04-23 11:32:23+00 0101000020E6100000F451465C00704240CC41D0D1AA96F3BF -1.224284 36.875011 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2389 359857082911983 ACC_OFF 2026-04-23 11:32:23+00 0101000020E6100000B22E6EA301704240BBB88D06F096F3BF -1.22435 36.87505 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2390 359857082037185 ACC_ON 2026-04-23 11:30:56+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2391 359857082046145 ACC_ON 2026-04-23 11:30:45+00 0101000020E6100000105839B4C8D643400D54C6BFCF1810C0 -4.02423 39.678 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2392 359857082042052 ACC_ON 2026-04-23 11:30:38+00 0101000020E6100000AD69DE718A72424059DDEA39E9FDF2BF -1.18699 36.89485 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2393 359857082907973 ACC_ON 2026-04-23 11:30:33+00 0101000020E6100000F1F44A5986C843401A8BA6B3932111C0 -4.28279 39.5666 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2395 865135061054548 ACC_OFF 2026-04-23 11:29:34+00 0101000020E61000004D6A6803B07142405BD07B630800F3BF -1.187508 36.888184 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2396 865135061054555 ACC_ON 2026-04-23 11:29:17+00 0101000020E6100000C09481035A304240A7B393C151F2D0BF -0.26479 36.377747 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2397 862798050523527 ACC_OFF 2026-04-23 11:29:04+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2398 359857082907973 ACC_OFF 2026-04-23 11:29:04+00 0101000020E6100000F1F44A5986C84340FDD98F14912111C0 -4.28278 39.5666 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2481 359857081887069 ACC_OFF 2026-04-23 11:32:24+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2482 359857082902461 ACC_ON 2026-04-23 11:31:45+00 0101000020E6100000946A9F8EC7484340978BF84ECC3A0BC0 -3.40371 38.56859 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2483 359857081887069 ACC_ON 2026-04-23 11:30:42+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2484 862798050523295 ACC_ON 2026-04-23 11:29:48+00 0101000020E6100000069D103AE87A42409AEFE0270E60F2BF -1.148451 36.960212 0.00 \N 2026-04-23 11:34:07.571496+00 ACC ON poll \N \N \N \N \N +2125 862798052707946 135 2026-04-23 11:24:10+00 0101000020E6100000F2272A1BD6784240342F87DD77CCF2BF -1.174919 36.944034 90.00 \N 2026-04-23 11:24:13.287831+00 Overspeed alert(DVR)(90.0km/h) push \N \N \N \N \N +2126 865135061569123 1002 2026-04-23 11:24:13+00 0101000020E61000000DA5F622DA644240CD5B751DAAA9F4BF -1.291422 36.787907 \N \N 2026-04-23 11:24:13.65017+00 ACC ON push \N \N \N \N \N +2127 359857082902461 1001 2026-04-23 11:24:22+00 0101000020E61000007094BC3AC7484340978BF84ECC3A0BC0 -3.40371 38.56858 \N \N 2026-04-23 11:24:23.835079+00 ACC OFF push \N \N \N \N \N +2129 359857082897737 1001 2026-04-23 11:25:32+00 0101000020E61000001B0DE02D90E043409B3DD00A0C990FC0 -3.94973 39.7544 \N \N 2026-04-23 11:25:33.169829+00 ACC OFF push \N \N \N \N \N +2130 862798050525423 1001 2026-04-23 11:25:38+00 0101000020E6100000992EC4EA8FE04340B1A547533D990FC0 -3.949824 39.754392 \N \N 2026-04-23 11:25:39.844822+00 ACC OFF push \N \N \N \N \N +2132 862798052708068 128 2026-04-23 11:25:52+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 11:25:53.336934+00 DVR vibration alert push \N \N \N \N \N +2133 862798050523139 146 2026-04-23 11:26:01+00 0101000020E61000005473B9C150DF4340D50792770E850FC0 -3.939969 39.744652 41.00 \N 2026-04-23 11:26:05.12646+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +2134 865135061559538 1001 2026-04-23 11:26:25+00 0101000020E610000000E65AB4005D4240FE7BF0DAA5CDF3BF -1.237707 36.726584 \N \N 2026-04-23 11:26:25.71407+00 ACC OFF push \N \N \N \N \N +2138 862798050523014 128 2026-04-23 11:26:57+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 11:26:59.132922+00 DVR vibration alert push \N \N \N \N \N +2139 359857081891566 3 2026-02-12 01:11:08+00 0101000020E610000075029A081B6A4240AD4CF8A57E5EF4BF -1.27307 36.82895 \N \N 2026-04-23 11:27:02.695477+00 Vibration alert push \N \N \N \N \N +2140 359857082037185 1002 2026-04-23 11:27:14+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 11:27:14.762969+00 ACC ON push \N \N \N \N \N +2141 359857082037185 1001 2026-04-23 11:27:17+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 11:27:17.683805+00 ACC OFF push \N \N \N \N \N +2149 862798050523527 1001 2026-04-23 11:29:04+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 11:29:04.630021+00 ACC OFF push \N \N \N \N \N +2150 359857082907973 1001 2026-04-23 11:29:04+00 0101000020E6100000F1F44A5986C84340FDD98F14912111C0 -4.28278 39.5666 \N \N 2026-04-23 11:29:05.52703+00 ACC OFF push \N \N \N \N \N +2316 359857082902461 stayAlertOn 2026-04-23 11:29:09+00 0101000020E61000007094BC3AC7484340978BF84ECC3A0BC0 -3.40371 38.56858 \N \N 2026-04-23 11:29:10.091093+00 Idling alert push \N \N \N \N \N +2319 865135061037980 1002 2026-04-23 11:29:46+00 0101000020E61000005A2BDA1CE77A4240109370218F60F2BF -1.148574 36.960178 \N \N 2026-04-23 11:29:47.013419+00 ACC ON push \N \N \N \N \N +2320 862798050523295 1002 2026-04-23 11:29:48+00 0101000020E6100000069D103AE87A42409AEFE0270E60F2BF -1.148451 36.960212 \N \N 2026-04-23 11:29:48.369147+00 ACC ON push \N \N \N \N \N +2321 359857081887069 1001 2026-04-23 11:29:48+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 11:29:49.121015+00 ACC OFF push \N \N \N \N \N +2323 359857082907973 1002 2026-04-23 11:30:33+00 0101000020E6100000F1F44A5986C843401A8BA6B3932111C0 -4.28279 39.5666 \N \N 2026-04-23 11:30:33.967498+00 ACC ON push \N \N \N \N \N +2335 359857082912486 1001 2026-04-23 11:32:59+00 0101000020E6100000D044D8F0F4E64340C68A1A4CC3B00EC0 -3.83631 39.80435 \N \N 2026-04-23 11:33:00.472089+00 ACC OFF push \N \N \N \N \N +2336 862798050523014 128 2026-04-23 11:33:00+00 0101000020E6100000D1CDFE40B953424040170D198FD2F1BF -1.113906 36.654091 0.00 \N 2026-04-23 11:33:02.979583+00 DVR vibration alert push \N \N \N \N \N +2337 862798052707946 1001 2026-04-23 11:33:06+00 0101000020E610000034BF9A03047742404A6249B9FB1CF3BF -1.194576 36.92981 \N \N 2026-04-23 11:33:06.426059+00 ACC OFF push \N \N \N \N \N +2339 865135061053748 1001 2026-04-23 11:33:57+00 0101000020E610000084F1D3B837D3434027A089B0E12910C0 -4.0409 39.650138 \N \N 2026-04-23 11:33:58.191776+00 ACC OFF push \N \N \N \N \N +2340 862798050526231 1001 2026-04-23 11:33:58+00 0101000020E61000002BDA1CE736D343408E93C2BCC72910C0 -4.040801 39.650113 \N \N 2026-04-23 11:33:59.124843+00 ACC OFF push \N \N \N \N \N +5655 862798050523527 1001 2026-04-23 12:54:47+00 0101000020E6100000874ECFBBB1724240164B917C2510F3BF -1.191442 36.896049 \N \N 2026-04-23 12:54:48.322316+00 ACC OFF push \N \N \N \N \N +5656 865135061054555 1001 2026-04-23 12:54:48+00 0101000020E61000006B2A8BC22E304240B0FECF61BEBCD1BF -0.277145 36.376427 \N \N 2026-04-23 12:54:49.146402+00 ACC OFF push \N \N \N \N \N +5657 865135061569123 3 2026-04-23 12:52:35+00 0101000020E610000063B83A00E2624240965E9B8D9598F4BF -1.287252 36.772522 \N \N 2026-04-23 12:54:58.808423+00 Vibration alert push \N \N \N \N \N +5658 359857081886905 1001 2026-04-23 12:55:28+00 0101000020E6100000BB0A293FA9DE4340DE3CD52137C30FC0 -3.97032 39.73954 \N \N 2026-04-23 12:55:29.468248+00 ACC OFF push \N \N \N \N \N +5659 359857081885410 1004 2026-04-23 12:55:44+00 0101000020E610000082E2C798BB7242401CCEFC6A0E10F3BF -1.19142 36.89635 \N \N 2026-04-23 12:55:44.600526+00 Parking alert push \N \N \N \N \N +5662 359857081891632 1002 2026-04-23 12:56:17+00 0101000020E6100000F98381E7DE6F4240AE47E17A14AEF3BF -1.23 36.87399 \N \N 2026-04-23 12:56:18.435367+00 ACC ON push \N \N \N \N \N +5663 359857082897737 1001 2026-04-23 12:56:41+00 0101000020E61000006C3EAE0D15DB434039EE940ED6FF0FC0 -3.99992 39.71158 \N \N 2026-04-23 12:56:42.556578+00 ACC OFF push \N \N \N \N \N +5664 862798050525423 1001 2026-04-23 12:56:42+00 0101000020E6100000B5A338471DDB4340965AEF37DA0110C0 -4.001809 39.711831 \N \N 2026-04-23 12:56:43.363589+00 ACC OFF push \N \N \N \N \N +5665 359857082897091 1002 2026-04-23 12:56:46+00 0101000020E6100000894160E5D0724240A75CE15D2E62F3BF -1.21147 36.897 \N \N 2026-04-23 12:56:47.937917+00 ACC ON push \N \N \N \N \N +5666 359857082042052 1004 2026-04-23 12:56:58+00 0101000020E61000005743E21E4B5B42405A8121AB5B3DF4BF -1.26498 36.71323 \N \N 2026-04-23 12:56:58.556023+00 Parking alert push \N \N \N \N \N +5667 359857082897091 1001 2026-04-23 12:57:01+00 0101000020E6100000894160E5D0724240A75CE15D2E62F3BF -1.21147 36.897 \N \N 2026-04-23 12:57:02.13083+00 ACC OFF push \N \N \N \N \N +5668 359857082900358 1002 2026-04-23 12:57:06+00 0101000020E61000008D976E12837C42402A6F47382DF8F6BF -1.43559 36.97275 \N \N 2026-04-23 12:57:06.644361+00 ACC ON push \N \N \N \N \N +5669 359857081892762 1003 2026-04-23 12:57:09+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 \N \N 2026-04-23 12:57:09.887352+00 Offline alert push \N \N \N \N \N +5675 865135061048466 1001 2026-04-23 12:58:15+00 0101000020E61000002CF015DD7A5342406D1D1CEC4DCCF1BF -1.112379 36.652187 \N \N 2026-04-23 12:58:16.03825+00 ACC OFF push \N \N \N \N \N +5676 862798050523014 1001 2026-04-23 12:58:21+00 0101000020E610000039D2191879534240F5D555815ACCF1BF -1.112391 36.652133 \N \N 2026-04-23 12:58:21.548954+00 ACC OFF push \N \N \N \N \N +5677 359857082042052 1002 2026-04-23 12:58:25+00 0101000020E6100000ECC039234A5B4240053411363C3DF4BF -1.26495 36.7132 \N \N 2026-04-23 12:58:25.82051+00 ACC ON push \N \N \N \N \N +5681 359857081886905 1002 2026-04-23 12:58:59+00 0101000020E6100000B05582C5E1DC4340F5D6C056091610C0 -4.02152 39.72564 \N \N 2026-04-23 12:59:00.599232+00 ACC ON push \N \N \N \N \N +5824 359857082910589 1002 2026-04-23 12:59:34+00 0101000020E610000057B2632310774240F0A7C64B3709F3BF -1.18975 36.93018 \N \N 2026-04-23 12:59:35.167703+00 ACC ON push \N \N \N \N \N +5825 359857082900358 1001 2026-04-23 12:59:55+00 0101000020E6100000C6504EB4AB7C4240978BF84ECCFAF6BF -1.43623 36.97399 \N \N 2026-04-23 12:59:56.586132+00 ACC OFF push \N \N \N \N \N +5826 359857082897737 1002 2026-04-23 12:59:58+00 0101000020E61000004968CBB914DB4340008C67D0D0FF0FC0 -3.99991 39.71157 \N \N 2026-04-23 12:59:58.709285+00 ACC ON push \N \N \N \N \N +5827 862798050525423 1002 2026-04-23 13:00:01+00 0101000020E6100000B5A338471DDB4340965AEF37DA0110C0 -4.001809 39.711831 \N \N 2026-04-23 13:00:02.20393+00 ACC ON push \N \N \N \N \N +5830 862798050523014 1002 2026-04-23 13:01:40+00 0101000020E610000039D2191879534240F5D555815ACCF1BF -1.112391 36.652133 \N \N 2026-04-23 13:01:41.71764+00 ACC ON push \N \N \N \N \N +5831 865135061048466 1002 2026-04-23 13:01:41+00 0101000020E61000002CF015DD7A5342406D1D1CEC4DCCF1BF -1.112379 36.652187 \N \N 2026-04-23 13:01:41.861132+00 ACC ON push \N \N \N \N \N +5832 862798050523626 146 2026-04-23 13:01:48+00 0101000020E61000007B1684F23EB84340E5B9BE0F07890DC0 -3.691908 39.439421 59.00 \N 2026-04-23 13:01:51.286443+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +5833 359857081885410 1001 2026-04-23 13:01:57+00 0101000020E6100000C98E8D40BC7242408E9257E71810F3BF -1.19143 36.89637 \N \N 2026-04-23 13:01:58.606644+00 ACC OFF push \N \N \N \N \N +5834 862798050523527 1001 2026-04-23 13:01:58+00 0101000020E6100000E690D442C9724240658F5033A40AF3BF -1.190098 36.896767 \N \N 2026-04-23 13:01:59.316463+00 ACC OFF push \N \N \N \N \N +5835 865135061048276 1001 2026-04-23 13:01:58+00 0101000020E61000001FD95C35CFD94340A583F57F0E0310C0 -4.002985 39.701636 \N \N 2026-04-23 13:01:59.769428+00 ACC OFF push \N \N \N \N \N +5836 359857082042052 1004 2026-04-23 13:02:04+00 0101000020E6100000739D465A2A5B4240617138F3AB39F4BF -1.26408 36.71223 \N \N 2026-04-23 13:02:04.856614+00 Parking alert push \N \N \N \N \N +5837 862798050523337 1001 2026-04-23 13:02:18+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 \N \N 2026-04-23 13:02:19.498925+00 ACC OFF push \N \N \N \N \N +2128 359857082900341 1001 2026-04-23 11:25:01+00 0101000020E6100000D42B6519E2DC43402E73BA2C261610C0 -4.02163 39.72565 \N \N 2026-04-23 11:25:03.029206+00 ACC OFF push \N \N \N \N \N +2131 359857081886905 1001 2026-04-23 11:25:45+00 0101000020E610000018213CDA38DE434033F9669B1B930FC0 -3.94683 39.73611 \N \N 2026-04-23 11:25:45.871922+00 ACC OFF push \N \N \N \N \N +2135 862798050525423 1004 2026-04-23 11:26:38+00 0101000020E6100000992EC4EA8FE04340B1A547533D990FC0 -3.949824 39.754392 \N \N 2026-04-23 11:26:38.910791+00 Parking alert push \N \N \N \N \N +2136 865135061563597 3 2026-04-23 11:26:41+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 11:26:42.045856+00 Vibration alert push \N \N \N \N \N +2137 359857082918012 1002 2026-04-23 11:26:41+00 0101000020E61000008195438B6C6B424094DE37BEF64CF3BF -1.20629 36.83925 \N \N 2026-04-23 11:26:42.175725+00 ACC ON push \N \N \N \N \N +2142 862798050288345 128 2026-04-23 11:27:42+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:27:59.999942+00 DVR vibration alert push \N \N \N \N \N +2143 862798050523337 147 2026-04-23 11:27:58+00 0101000020E6100000A0F99CBB5DD74340CF108E59F61410C0 -4.020471 39.682548 36.00 \N 2026-04-23 11:28:00.63359+00 Collision Alert(DVR) push \N \N \N \N \N +2144 862798050526231 1002 2026-04-23 11:28:03+00 0101000020E6100000FE99417C60D34340BE892139992810C0 -4.039647 39.651382 \N \N 2026-04-23 11:28:04.404506+00 ACC ON push \N \N \N \N \N +2145 862798050523527 stayAlertOn 2026-04-23 11:28:04+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 11:28:04.593612+00 Idling alert push \N \N \N \N \N +2146 359857081887192 1002 2026-04-23 11:28:15+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 11:28:16.695488+00 ACC ON push \N \N \N \N \N +2147 359857081886905 1002 2026-04-23 11:28:43+00 0101000020E6100000A67EDE54A4DE434050AA7D3A1EB30FC0 -3.96246 39.73939 \N \N 2026-04-23 11:28:44.39047+00 ACC ON push \N \N \N \N \N +2148 865135061053748 1002 2026-04-23 11:28:45+00 0101000020E6100000ADDBA0F65BD343409CE1067C7E2810C0 -4.039545 39.651244 \N \N 2026-04-23 11:28:45.989257+00 ACC ON push \N \N \N \N \N +2317 865135061054555 1002 2026-04-23 11:29:17+00 0101000020E6100000C09481035A304240A7B393C151F2D0BF -0.26479 36.377747 \N \N 2026-04-23 11:29:18.025469+00 ACC ON push \N \N \N \N \N +2318 865135061054548 1001 2026-04-23 11:29:34+00 0101000020E61000004D6A6803B07142405BD07B630800F3BF -1.187508 36.888184 \N \N 2026-04-23 11:29:34.338376+00 ACC OFF push \N \N \N \N \N +2322 359857082897737 stayAlertOn 2026-04-23 11:30:20+00 0101000020E61000001B0DE02D90E043409B3DD00A0C990FC0 -3.94973 39.7544 \N \N 2026-04-23 11:30:20.455355+00 Idling alert push \N \N \N \N \N +2324 359857082042052 1002 2026-04-23 11:30:38+00 0101000020E6100000AD69DE718A72424059DDEA39E9FDF2BF -1.18699 36.89485 \N \N 2026-04-23 11:30:39.666247+00 ACC ON push \N \N \N \N \N +2325 359857081887069 1002 2026-04-23 11:30:42+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 11:30:43.808778+00 ACC ON push \N \N \N \N \N +2326 359857082046145 1002 2026-04-23 11:30:45+00 0101000020E6100000105839B4C8D643400D54C6BFCF1810C0 -4.02423 39.678 \N \N 2026-04-23 11:30:46.088809+00 ACC ON push \N \N \N \N \N +2327 359857082037185 1002 2026-04-23 11:30:56+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 11:30:57.204825+00 ACC ON push \N \N \N \N \N +2328 359857082902461 1002 2026-04-23 11:31:45+00 0101000020E6100000946A9F8EC7484340978BF84ECC3A0BC0 -3.40371 38.56859 \N \N 2026-04-23 11:31:45.727711+00 ACC ON push \N \N \N \N \N +2329 865135061563597 3 2026-04-23 11:27:53+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 11:31:58.818525+00 Vibration alert push \N \N \N \N \N +2330 865135061563282 3 2026-04-23 11:32:00+00 0101000020E6100000815CE2C803454040954737C2A222C83F 0.188557 32.539178 \N \N 2026-04-23 11:32:01.849927+00 Vibration alert push \N \N \N \N \N +2331 862798050288360 1001 2026-04-23 11:32:23+00 0101000020E6100000F451465C00704240CC41D0D1AA96F3BF -1.224284 36.875011 \N \N 2026-04-23 11:32:23.67999+00 ACC OFF push \N \N \N \N \N +2332 359857082911983 1001 2026-04-23 11:32:23+00 0101000020E6100000B22E6EA301704240BBB88D06F096F3BF -1.22435 36.87505 \N \N 2026-04-23 11:32:24.304208+00 ACC OFF push \N \N \N \N \N +2333 359857081887069 1001 2026-04-23 11:32:24+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 11:32:25.324682+00 ACC OFF push \N \N \N \N \N +2334 865135061563282 1002 2026-04-23 11:32:25+00 0101000020E6100000815CE2C803454040954737C2A222C83F 0.188557 32.539178 \N \N 2026-04-23 11:32:26.321651+00 ACC ON push \N \N \N \N \N +2338 865135061564470 3 2026-04-23 11:33:25+00 0101000020E6100000BEF90D130D72424012C2A38D2316F3BF -1.192905 36.891024 \N \N 2026-04-23 11:33:26.992798+00 Vibration alert push \N \N \N \N \N +5660 865135061048276 1002 2026-04-23 12:55:54+00 0101000020E6100000F1D4230D6ED943406612F5824F0310C0 -4.003233 39.698671 \N \N 2026-04-23 12:55:54.703007+00 ACC ON push \N \N \N \N \N +5661 359857082042052 1001 2026-04-23 12:55:58+00 0101000020E61000005743E21E4B5B42405A8121AB5B3DF4BF -1.26498 36.71323 \N \N 2026-04-23 12:55:58.943818+00 ACC OFF push \N \N \N \N \N +5670 865135061562722 3 2026-04-23 12:57:40+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 12:57:41.941765+00 Vibration alert push \N \N \N \N \N +5671 862798050525423 1004 2026-04-23 12:57:42+00 0101000020E6100000B5A338471DDB4340965AEF37DA0110C0 -4.001809 39.711831 \N \N 2026-04-23 12:57:42.60097+00 Parking alert push \N \N \N \N \N +5672 865135061569123 3 2026-04-23 12:57:03+00 0101000020E610000063B83A00E2624240965E9B8D9598F4BF -1.287252 36.772522 \N \N 2026-04-23 12:57:50.171266+00 Vibration alert push \N \N \N \N \N +5673 865135061569123 1002 2026-04-23 12:57:50+00 0101000020E610000083DBDAC2F36242406902452C6298F4BF -1.287203 36.773064 \N \N 2026-04-23 12:57:51.153422+00 ACC ON push \N \N \N \N \N +5674 359857082897091 1004 2026-04-23 12:58:01+00 0101000020E6100000894160E5D0724240A75CE15D2E62F3BF -1.21147 36.897 \N \N 2026-04-23 12:58:03.046612+00 Parking alert push \N \N \N \N \N +5678 359857082897794 stayAlertOn 2026-04-23 12:58:33+00 0101000020E6100000EDD808C4EB624240C217265305A3F4BF -1.2898 36.77282 \N \N 2026-04-23 12:58:33.427948+00 Idling alert push \N \N \N \N \N +5679 862798050523527 1002 2026-04-23 12:58:35+00 0101000020E6100000874ECFBBB1724240164B917C2510F3BF -1.191442 36.896049 \N \N 2026-04-23 12:58:36.086146+00 ACC ON push \N \N \N \N \N +5680 359857081885410 1002 2026-04-23 12:58:35+00 0101000020E6100000C98E8D40BC7242408E9257E71810F3BF -1.19143 36.89637 \N \N 2026-04-23 12:58:36.339187+00 ACC ON push \N \N \N \N \N +5828 359857081892101 1001 2026-04-23 13:00:54+00 0101000020E61000007B4E7ADFF862424080F10C1AFAA7F4BF -1.29101 36.77322 \N \N 2026-04-23 13:00:55.313396+00 ACC OFF push \N \N \N \N \N +5829 359857082042052 1001 2026-04-23 13:01:04+00 0101000020E6100000739D465A2A5B4240617138F3AB39F4BF -1.26408 36.71223 \N \N 2026-04-23 13:01:05.184426+00 ACC OFF push \N \N \N \N \N +5843 865135061048276 1002 2026-04-23 13:03:12+00 0101000020E61000001FD95C35CFD94340A583F57F0E0310C0 -4.002985 39.701636 \N \N 2026-04-23 13:03:13.628577+00 ACC ON push \N \N \N \N \N +5844 359857082912239 1001 2026-04-23 13:03:21+00 0101000020E6100000454772F90F494340658D7A8846370BC0 -3.40199 38.5708 \N \N 2026-04-23 13:03:22.321912+00 ACC OFF push \N \N \N \N \N +5989 862798050288212 1002 2026-04-23 13:05:17+00 0101000020E6100000D9AF3BDD7970424029EB3713D385F3BF -1.220172 36.878719 \N \N 2026-04-23 13:05:18.326254+00 ACC ON push \N \N \N \N \N +6000 359857081886467 1002 2026-04-23 13:06:43+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 \N \N 2026-04-23 13:06:44.276038+00 ACC ON push \N \N \N \N \N +6002 865135061563597 stayAlertOn 2026-04-23 13:07:42+00 0101000020E610000064B0E2546B5342404B732B84D5D8F1BF -1.115438 36.651713 \N \N 2026-04-23 13:07:42.876973+00 Idling alert push \N \N \N \N \N +6003 359857082897737 stayAlertOn 2026-04-23 13:07:46+00 0101000020E6100000102384471BDB4340240B98C0ADFB0FC0 -3.99789 39.71177 \N \N 2026-04-23 13:07:46.745028+00 Idling alert push \N \N \N \N \N +6005 862798050288345 128 2026-04-23 13:08:17+00 0101000020E610000072C5C551B991434082AE7D01BD6011C0 -4.344471 39.138468 0.00 \N 2026-04-23 13:08:20.562328+00 DVR vibration alert push \N \N \N \N \N +6006 865135061563597 1001 2026-04-23 13:08:29+00 0101000020E610000064B0E2546B5342404B732B84D5D8F1BF -1.115438 36.651713 \N \N 2026-04-23 13:08:29.90808+00 ACC OFF push \N \N \N \N \N +6007 865135061563597 3 2026-04-23 13:08:19+00 0101000020E6100000588E90813C5342401B81785DBFE0F1BF -1.11737 36.650284 \N \N 2026-04-23 13:08:29.957532+00 Vibration alert push \N \N \N \N \N +6008 865135061053748 1001 2026-04-23 13:08:37+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 \N \N 2026-04-23 13:08:38.498821+00 ACC OFF push \N \N \N \N \N +6009 862798050526231 1001 2026-04-23 13:08:38+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 \N \N 2026-04-23 13:08:39.562454+00 ACC OFF push \N \N \N \N \N +6010 862798050526231 1002 2026-04-23 13:08:44+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 \N \N 2026-04-23 13:08:44.739458+00 ACC ON push \N \N \N \N \N +6168 865135061048276 1001 2026-04-23 13:10:58+00 0101000020E6100000959BA8A5B9D943403F90BC73280310C0 -4.003084 39.700978 \N \N 2026-04-23 13:10:59.261744+00 ACC OFF push \N \N \N \N \N +6169 359857082898008 1001 2026-04-23 13:11:00+00 0101000020E6100000475A2A6F47704240200C3CF71EAEF3BF -1.23001 36.87718 \N \N 2026-04-23 13:11:01.447384+00 ACC OFF push \N \N \N \N \N +2485 359857081887069 ACC_OFF 2026-04-23 11:29:48+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 11:34:07.571496+00 ACC OFF poll \N \N \N \N \N +2508 865135061569123 stayAlertOn 2026-04-23 11:34:25+00 0101000020E61000001DE4F56052644240B8B1D991EABBF4BF -1.295878 36.783764 \N \N 2026-04-23 11:34:25.26934+00 Idling alert push \N \N \N \N \N +2509 359857082037185 1001 2026-04-23 11:34:41+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 11:34:42.166141+00 ACC OFF push \N \N \N \N \N +2510 865135061053748 1004 2026-04-23 11:34:57+00 0101000020E61000006308008E3DD34340AFE94141292A10C0 -4.041173 39.650316 \N \N 2026-04-23 11:34:57.522732+00 Parking alert push \N \N \N \N \N +2511 862798050526231 1002 2026-04-23 11:35:24+00 0101000020E61000002BDA1CE736D343408E93C2BCC72910C0 -4.040801 39.650113 \N \N 2026-04-23 11:35:24.496612+00 ACC ON push \N \N \N \N \N +2512 359857082902461 stayAlertOn 2026-04-23 11:35:32+00 0101000020E6100000946A9F8EC7484340978BF84ECC3A0BC0 -3.40371 38.56859 \N \N 2026-04-23 11:35:32.873904+00 Idling alert push \N \N \N \N \N +2513 865135061564470 1002 2026-04-23 11:35:40+00 0101000020E6100000BEF90D130D72424012C2A38D2316F3BF -1.192905 36.891024 \N \N 2026-04-23 11:35:41.302167+00 ACC ON push \N \N \N \N \N +2514 359857081887069 stayAlertOn 2026-04-23 11:35:42+00 0101000020E6100000381092054C78424090BDDEFDF15EF3BF -1.21068 36.93982 \N \N 2026-04-23 11:35:42.914323+00 Idling alert push \N \N \N \N \N +2515 359857082037185 1002 2026-04-23 11:35:55+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 11:35:56.15491+00 ACC ON push \N \N \N \N \N +2516 359857082898008 1002 2026-04-23 11:35:59+00 0101000020E6100000A5F78DAF3D774240B8019F1F4608F3BF -1.18952 36.93157 \N \N 2026-04-23 11:35:59.816581+00 ACC ON push \N \N \N \N \N +2517 359857081891632 1002 2026-04-23 11:36:01+00 0101000020E6100000E5B8533A586F4240FDBCA94885B1F3BF -1.23084 36.86988 \N \N 2026-04-23 11:36:01.969529+00 ACC ON push \N \N \N \N \N +2518 359857082911983 stayAlertOn 2026-04-23 11:36:30+00 0101000020E6100000B22E6EA301704240BBB88D06F096F3BF -1.22435 36.87505 \N \N 2026-04-23 11:36:30.978376+00 Idling alert push \N \N \N \N \N +2519 359857082910886 1002 2026-04-23 11:36:30+00 0101000020E61000006F2A52616CD943408109DCBA9B2710C0 -4.03868 39.69862 \N \N 2026-04-23 11:36:31.150282+00 ACC ON push \N \N \N \N \N +2520 359857082896911 1002 2026-04-23 11:36:33+00 0101000020E61000000473F4F8BD694240D1AE42CA4FAAF2BF -1.16658 36.82611 \N \N 2026-04-23 11:36:33.563761+00 ACC ON push \N \N \N \N \N +2521 862798050525423 1002 2026-04-23 11:36:48+00 0101000020E6100000992EC4EA8FE04340B1A547533D990FC0 -3.949824 39.754392 \N \N 2026-04-23 11:36:49.727036+00 ACC ON push \N \N \N \N \N +2522 865135061035778 1001 2026-04-23 11:36:58+00 0101000020E61000005D6BEF5355784240F03504C7655CF3BF -1.210058 36.940104 \N \N 2026-04-23 11:36:59.27963+00 ACC OFF push \N \N \N \N \N +2523 862798050521521 1001 2026-04-23 11:37:00+00 0101000020E6100000C4CC3E8F517842406D003620425CF3BF -1.210024 36.939989 \N \N 2026-04-23 11:37:00.997663+00 ACC OFF push \N \N \N \N \N +2524 359857082910886 stayAlertOn 2026-04-23 11:37:03+00 0101000020E61000006F2A52616CD94340BA313D61892710C0 -4.03861 39.69862 \N \N 2026-04-23 11:37:03.552918+00 Idling alert push \N \N \N \N \N +2525 865135061564470 1001 2026-04-23 11:37:21+00 0101000020E6100000FC1873D712724240BCE82B483316F3BF -1.19292 36.8912 \N \N 2026-04-23 11:37:22.064442+00 ACC OFF push \N \N \N \N \N +2526 865135061035778 1002 2026-04-23 11:37:42+00 0101000020E6100000A0A52BD84678424025085740A15EF3BF -1.210603 36.939662 \N \N 2026-04-23 11:37:43.177552+00 ACC ON push \N \N \N \N \N +2527 862798050521521 1002 2026-04-23 11:37:45+00 0101000020E6100000C4CC3E8F517842406D003620425CF3BF -1.210024 36.939989 \N \N 2026-04-23 11:37:45.446659+00 ACC ON push \N \N \N \N \N +2528 865135061569479 3 2026-04-23 11:37:49+00 0101000020E6100000F71E2E39EE444040587380608E1EC13F 0.133745 32.53852 \N \N 2026-04-23 11:37:50.970828+00 Vibration alert push \N \N \N \N \N +2529 865135061564470 1004 2026-04-23 11:38:20+00 0101000020E6100000259529E620724240B6D958897916F3BF -1.192987 36.891629 \N \N 2026-04-23 11:38:20.225267+00 Parking alert push \N \N \N \N \N +2530 359857082897737 1002 2026-04-23 11:38:21+00 0101000020E61000006A6AD95A5FE043408386FE092E960FC0 -3.94833 39.75291 \N \N 2026-04-23 11:38:22.963369+00 ACC ON push \N \N \N \N \N +2531 359857081891566 1002 2026-04-23 11:38:24+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 11:38:25.118579+00 ACC ON push \N \N \N \N \N +2532 359857082918012 stayAlertOn 2026-04-23 11:38:25+00 0101000020E61000004F58E201656B4240E7E3DA50314EF3BF -1.20659 36.83902 \N \N 2026-04-23 11:38:25.847399+00 Idling alert push \N \N \N \N \N +2533 865135061048276 1001 2026-04-23 11:38:33+00 0101000020E6100000664D2CF015D9434012C2A38D23F60FC0 -3.995185 39.695982 \N \N 2026-04-23 11:38:34.411009+00 ACC OFF push \N \N \N \N \N +2534 865135061581904 3 2026-04-23 11:38:47+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 \N \N 2026-04-23 11:38:49.251812+00 Vibration alert push \N \N \N \N \N +2535 359857082918012 1001 2026-04-23 11:38:51+00 0101000020E610000033C4B12E6E6B42407767EDB60B4DF3BF -1.20631 36.8393 \N \N 2026-04-23 11:38:51.371396+00 ACC OFF push \N \N \N \N \N +2536 862798050523337 1001 2026-04-23 11:38:53+00 0101000020E610000071C79BFC16D943403430F2B226F60FC0 -3.995191 39.696014 \N \N 2026-04-23 11:38:54.498506+00 ACC OFF push \N \N \N \N \N +2537 865135061564470 3 2026-04-23 11:38:53+00 0101000020E6100000259529E620724240B6D958897916F3BF -1.192987 36.891629 \N \N 2026-04-23 11:38:55.078483+00 Vibration alert push \N \N \N \N \N +2538 359857082908500 1002 2026-04-23 11:39:03+00 0101000020E61000003DB83B6BB79143408B89CDC7B56111C0 -4.34542 39.13841 \N \N 2026-04-23 11:39:03.511613+00 ACC ON push \N \N \N \N \N +2539 862798050288345 1002 2026-04-23 11:39:03+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 \N \N 2026-04-23 11:39:03.645194+00 ACC ON push \N \N \N \N \N +2540 862798052708068 128 2026-04-23 11:39:06+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 11:39:07.846619+00 DVR vibration alert push \N \N \N \N \N +2543 865135061564470 stayAlert 2026-04-23 11:38:20+00 0101000020E6100000259529E620724240B6D958897916F3BF -1.192987 36.891629 0.00 \N 2026-04-23 11:39:08.358279+00 Parking alert poll \N \N \N \N \N +2545 865135061035778 ACC_ON 2026-04-23 11:37:42+00 0101000020E6100000A0A52BD84678424025085740A15EF3BF -1.210603 36.939662 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2546 865135061564470 ACC_OFF 2026-04-23 11:37:21+00 0101000020E6100000FC1873D712724240BCE82B483316F3BF -1.19292 36.8912 0.00 \N 2026-04-23 11:39:08.358279+00 ACC OFF poll \N \N \N \N \N +2547 865135061035778 ACC_OFF 2026-04-23 11:36:58+00 0101000020E61000005D6BEF5355784240F03504C7655CF3BF -1.210058 36.940104 0.00 \N 2026-04-23 11:39:08.358279+00 ACC OFF poll \N \N \N \N \N +2548 862798050525423 ACC_ON 2026-04-23 11:36:48+00 0101000020E6100000992EC4EA8FE04340B1A547533D990FC0 -3.949824 39.754392 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2549 865135061564470 ACC_ON 2026-04-23 11:35:40+00 0101000020E6100000BEF90D130D72424012C2A38D2316F3BF -1.192905 36.891024 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2550 865135061053748 stayAlert 2026-04-23 11:34:57+00 0101000020E61000006308008E3DD34340AFE94141292A10C0 -4.041173 39.650316 0.00 \N 2026-04-23 11:39:08.358279+00 Parking alert poll \N \N \N \N \N +2585 862798050288345 ACC_ON 2026-04-23 11:39:03+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2586 359857082908500 ACC_ON 2026-04-23 11:39:03+00 0101000020E61000003DB83B6BB79143408B89CDC7B56111C0 -4.34542 39.13841 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2587 862798050523337 ACC_OFF 2026-04-23 11:38:53+00 0101000020E610000071C79BFC16D943403430F2B226F60FC0 -3.995191 39.696014 0.00 \N 2026-04-23 11:39:08.358279+00 ACC OFF poll \N \N \N \N \N +2588 359857082918012 ACC_OFF 2026-04-23 11:38:51+00 0101000020E610000033C4B12E6E6B42407767EDB60B4DF3BF -1.20631 36.8393 0.00 \N 2026-04-23 11:39:08.358279+00 ACC OFF poll \N \N \N \N \N +2590 359857081891566 ACC_ON 2026-04-23 11:38:24+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2591 359857082897737 ACC_ON 2026-04-23 11:38:21+00 0101000020E61000006A6AD95A5FE043408386FE092E960FC0 -3.94833 39.75291 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2592 862798050521521 ACC_ON 2026-04-23 11:37:45+00 0101000020E6100000C4CC3E8F517842406D003620425CF3BF -1.210024 36.939989 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2593 862798050521521 ACC_OFF 2026-04-23 11:37:00+00 0101000020E6100000C4CC3E8F517842406D003620425CF3BF -1.210024 36.939989 0.00 \N 2026-04-23 11:39:08.358279+00 ACC OFF poll \N \N \N \N \N +2594 359857082896911 ACC_ON 2026-04-23 11:36:33+00 0101000020E61000000473F4F8BD694240D1AE42CA4FAAF2BF -1.16658 36.82611 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2596 359857081891632 ACC_ON 2026-04-23 11:36:01+00 0101000020E6100000E5B8533A586F4240FDBCA94885B1F3BF -1.23084 36.86988 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2597 359857082037185 ACC_ON 2026-04-23 11:35:55+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2598 862798050526231 ACC_ON 2026-04-23 11:35:24+00 0101000020E61000002BDA1CE736D343408E93C2BCC72910C0 -4.040801 39.650113 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2599 359857082037185 ACC_OFF 2026-04-23 11:34:41+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 11:39:08.358279+00 ACC OFF poll \N \N \N \N \N +2676 865135061048276 ACC_OFF 2026-04-23 11:38:33+00 0101000020E6100000664D2CF015D9434012C2A38D23F60FC0 -3.995185 39.695982 0.00 \N 2026-04-23 11:39:08.358279+00 ACC OFF poll \N \N \N \N \N +2678 359857082910886 ACC_ON 2026-04-23 11:36:30+00 0101000020E61000006F2A52616CD943408109DCBA9B2710C0 -4.03868 39.69862 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2679 359857082898008 ACC_ON 2026-04-23 11:35:59+00 0101000020E6100000A5F78DAF3D774240B8019F1F4608F3BF -1.18952 36.93157 0.00 \N 2026-04-23 11:39:08.358279+00 ACC ON poll \N \N \N \N \N +2740 862798050525423 ACC_OFF 2026-04-23 11:43:38+00 0101000020E610000031D120054FDF43400893E2E313920FC0 -3.946327 39.744599 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2741 865135061564470 ACC_OFF 2026-04-23 11:43:20+00 0101000020E61000003C139A2496724240DD442DCDAD10F3BF -1.191572 36.895207 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2742 865135061037980 stayAlert 2026-04-23 11:41:51+00 0101000020E61000004E0CC9C9C479424052D7DAFB5455F2BF -1.145833 36.951318 0.00 \N 2026-04-23 11:44:09.187279+00 Parking alert poll \N \N \N \N \N +2744 862798052708068 stayAlert 2026-04-23 11:41:04+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 11:44:09.187279+00 Parking alert poll \N \N \N \N \N +2745 865135061043426 stayAlert 2026-04-23 11:40:52+00 0101000020E6100000137EA99F37654240E38DCC237FB0F0BF -1.04309 36.79076 0.00 \N 2026-04-23 11:44:09.187279+00 Parking alert poll \N \N \N \N \N +2746 865135061037980 ACC_OFF 2026-04-23 11:40:51+00 0101000020E61000004E0CC9C9C479424052D7DAFB5455F2BF -1.145833 36.951318 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2747 865135061053748 ACC_ON 2026-04-23 11:40:48+00 0101000020E61000006308008E3DD34340AFE94141292A10C0 -4.041173 39.650316 0.00 \N 2026-04-23 11:44:09.187279+00 ACC ON poll \N \N \N \N \N +2748 862798052708068 ACC_OFF 2026-04-23 11:40:04+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2749 862798052708068 ACC_ON 2026-04-23 11:40:00+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 11:44:09.187279+00 ACC ON poll \N \N \N \N \N +2750 865135061043426 ACC_OFF 2026-04-23 11:39:58+00 0101000020E610000007D0EFFB37654240A4A833F790B0F0BF -1.043107 36.790771 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2751 865135061564470 ACC_ON 2026-04-23 11:39:33+00 0101000020E6100000259529E620724240B6D958897916F3BF -1.192987 36.891629 0.00 \N 2026-04-23 11:44:09.187279+00 ACC ON poll \N \N \N \N \N +2796 862798050523337 ACC_ON 2026-04-23 11:43:43+00 0101000020E610000071C79BFC16D943403430F2B226F60FC0 -3.995191 39.696014 0.00 \N 2026-04-23 11:44:09.187279+00 ACC ON poll \N \N \N \N \N +2797 359857082897737 ACC_OFF 2026-04-23 11:43:35+00 0101000020E6100000FA0AD28C45DF4340A6ED5F5969920FC0 -3.94649 39.74431 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2798 359857082046145 ACC_OFF 2026-04-23 11:43:30+00 0101000020E610000014CB2DAD86D84340B2D7BB3FDE0B10C0 -4.01159 39.69161 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2800 865135061054555 ACC_OFF 2026-04-23 11:43:07+00 0101000020E61000008C9FC6BDF92F42403673486AA164D1BF -0.271767 36.374809 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2801 359857081891566 ACC_OFF 2026-04-23 11:41:28+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2802 359857081891632 stayAlert 2026-04-23 11:41:24+00 0101000020E610000001F6D1A92B6F4240C976BE9F1AAFF3BF -1.23025 36.86852 0.00 \N 2026-04-23 11:44:09.187279+00 Parking alert poll \N \N \N \N \N +2803 862798050523014 ACC_ON 2026-04-23 11:41:09+00 0101000020E61000008A213999B85342400D384BC972D2F1BF -1.113879 36.654071 0.00 \N 2026-04-23 11:44:09.187279+00 ACC ON poll \N \N \N \N \N +2804 359857081891632 ACC_OFF 2026-04-23 11:40:24+00 0101000020E610000001F6D1A92B6F4240C976BE9F1AAFF3BF -1.23025 36.86852 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2805 359857081887192 ACC_OFF 2026-04-23 11:39:49+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2806 862798050288360 stayAlert 2026-04-23 11:39:30+00 0101000020E6100000F451465C00704240CC41D0D1AA96F3BF -1.224284 36.875011 0.00 \N 2026-04-23 11:44:09.187279+00 Parking alert poll \N \N \N \N \N +2807 359857082908500 ACC_OFF 2026-04-23 11:39:23+00 0101000020E61000003DB83B6BB79143408B89CDC7B56111C0 -4.34542 39.13841 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2808 862798050288345 ACC_OFF 2026-04-23 11:39:21+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2809 862798050523626 128 2026-04-23 11:39:20+00 0101000020E61000005C3CBCE7C0BC4340CF2F4AD05FE80EC0 -3.863464 39.474637 0.00 \N 2026-04-23 11:44:09.187279+00 DVR vibration alert poll \N \N \N \N \N +2810 862798050523527 128 2026-04-23 11:39:17+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 11:44:09.187279+00 DVR vibration alert poll \N \N \N \N \N +2811 862798050288345 128 2026-04-23 11:39:14+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:44:09.187279+00 DVR vibration alert poll \N \N \N \N \N +2893 865135061048276 ACC_ON 2026-04-23 11:43:43+00 0101000020E6100000664D2CF015D9434012C2A38D23F60FC0 -3.995185 39.695982 0.00 \N 2026-04-23 11:44:09.187279+00 ACC ON poll \N \N \N \N \N +2894 865135061048466 ACC_ON 2026-04-23 11:43:38+00 0101000020E61000008A213999B8534240FBAE08FEB7D2F1BF -1.113945 36.654071 0.00 \N 2026-04-23 11:44:09.187279+00 ACC ON poll \N \N \N \N \N +2896 862798050523295 ACC_OFF 2026-04-23 11:40:47+00 0101000020E610000029CE5147C779424061A417B5FB55F2BF -1.145992 36.951394 0.00 \N 2026-04-23 11:44:09.187279+00 ACC OFF poll \N \N \N \N \N +2897 359857081887069 ACC_ON 2026-04-23 11:39:59+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 0.00 \N 2026-04-23 11:44:09.187279+00 ACC ON poll \N \N \N \N \N +5682 865135061569123 ACC_ON 2026-04-23 12:57:50+00 0101000020E610000083DBDAC2F36242406902452C6298F4BF -1.287203 36.773064 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +5683 862798050525423 stayAlert 2026-04-23 12:57:42+00 0101000020E6100000B5A338471DDB4340965AEF37DA0110C0 -4.001809 39.711831 0.00 \N 2026-04-23 12:59:29.728597+00 Parking alert poll \N \N \N \N \N +5684 359857082900358 ACC_ON 2026-04-23 12:57:06+00 0101000020E61000008D976E12837C42402A6F47382DF8F6BF -1.43559 36.97275 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +5686 862798050525423 ACC_OFF 2026-04-23 12:56:42+00 0101000020E6100000B5A338471DDB4340965AEF37DA0110C0 -4.001809 39.711831 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5725 359857081886905 ACC_ON 2026-04-23 12:58:59+00 0101000020E6100000B05582C5E1DC4340F5D6C056091610C0 -4.02152 39.72564 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +5726 862798050523527 ACC_ON 2026-04-23 12:58:35+00 0101000020E6100000874ECFBBB1724240164B917C2510F3BF -1.191442 36.896049 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +5727 359857081885410 ACC_ON 2026-04-23 12:58:35+00 0101000020E6100000C98E8D40BC7242408E9257E71810F3BF -1.19143 36.89637 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +5729 359857082042052 ACC_ON 2026-04-23 12:58:25+00 0101000020E6100000ECC039234A5B4240053411363C3DF4BF -1.26495 36.7132 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +5730 862798050523014 ACC_OFF 2026-04-23 12:58:21+00 0101000020E610000039D2191879534240F5D555815ACCF1BF -1.112391 36.652133 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5731 359857082897091 stayAlert 2026-04-23 12:58:01+00 0101000020E6100000894160E5D0724240A75CE15D2E62F3BF -1.21147 36.897 0.00 \N 2026-04-23 12:59:29.728597+00 Parking alert poll \N \N \N \N \N +5733 359857081892762 offline 2026-04-23 12:57:09+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 0.00 \N 2026-04-23 12:59:29.728597+00 Offline alert poll \N \N \N \N \N +5734 359857082897091 ACC_OFF 2026-04-23 12:57:01+00 0101000020E6100000894160E5D0724240A75CE15D2E62F3BF -1.21147 36.897 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5735 359857082042052 stayAlert 2026-04-23 12:56:58+00 0101000020E61000005743E21E4B5B42405A8121AB5B3DF4BF -1.26498 36.71323 0.00 \N 2026-04-23 12:59:29.728597+00 Parking alert poll \N \N \N \N \N +5736 359857082897091 ACC_ON 2026-04-23 12:56:46+00 0101000020E6100000894160E5D0724240A75CE15D2E62F3BF -1.21147 36.897 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +5737 359857082897737 ACC_OFF 2026-04-23 12:56:41+00 0101000020E61000006C3EAE0D15DB434039EE940ED6FF0FC0 -3.99992 39.71158 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5738 359857081891632 ACC_ON 2026-04-23 12:56:17+00 0101000020E6100000F98381E7DE6F4240AE47E17A14AEF3BF -1.23 36.87399 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +2706 862798050288345 128 2026-04-23 11:39:11+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:39:15.334726+00 DVR vibration alert push \N \N \N \N \N +2707 862798050523527 128 2026-04-23 11:39:16+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 11:39:18.383488+00 DVR vibration alert push \N \N \N \N \N +2708 862798050523626 128 2026-04-23 11:39:18+00 0101000020E61000005C3CBCE7C0BC4340CF2F4AD05FE80EC0 -3.863464 39.474637 0.00 \N 2026-04-23 11:39:20.9955+00 DVR vibration alert push \N \N \N \N \N +2709 862798050288345 1001 2026-04-23 11:39:21+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 \N \N 2026-04-23 11:39:22.055653+00 ACC OFF push \N \N \N \N \N +2710 359857082908500 1001 2026-04-23 11:39:23+00 0101000020E61000003DB83B6BB79143408B89CDC7B56111C0 -4.34542 39.13841 \N \N 2026-04-23 11:39:23.94002+00 ACC OFF push \N \N \N \N \N +2713 359857081887192 1001 2026-04-23 11:39:49+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 11:39:49.883166+00 ACC OFF push \N \N \N \N \N +2714 865135061043426 1001 2026-04-23 11:39:58+00 0101000020E610000007D0EFFB37654240A4A833F790B0F0BF -1.043107 36.790771 \N \N 2026-04-23 11:39:58.741101+00 ACC OFF push \N \N \N \N \N +2715 359857081887069 1002 2026-04-23 11:39:59+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 11:40:00.198383+00 ACC ON push \N \N \N \N \N +2716 862798052708068 1002 2026-04-23 11:40:00+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 \N \N 2026-04-23 11:40:01.393101+00 ACC ON push \N \N \N \N \N +2717 862798052708068 1001 2026-04-23 11:40:04+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 \N \N 2026-04-23 11:40:04.41808+00 ACC OFF push \N \N \N \N \N +2718 359857081891632 1001 2026-04-23 11:40:24+00 0101000020E610000001F6D1A92B6F4240C976BE9F1AAFF3BF -1.23025 36.86852 \N \N 2026-04-23 11:40:24.642285+00 ACC OFF push \N \N \N \N \N +2719 862798050523295 1001 2026-04-23 11:40:47+00 0101000020E610000029CE5147C779424061A417B5FB55F2BF -1.145992 36.951394 \N \N 2026-04-23 11:40:47.914321+00 ACC OFF push \N \N \N \N \N +2720 865135061053748 1002 2026-04-23 11:40:48+00 0101000020E61000006308008E3DD34340AFE94141292A10C0 -4.041173 39.650316 \N \N 2026-04-23 11:40:49.223504+00 ACC ON push \N \N \N \N \N +2721 865135061043426 1004 2026-04-23 11:40:52+00 0101000020E6100000137EA99F37654240E38DCC237FB0F0BF -1.04309 36.79076 \N \N 2026-04-23 11:40:52.523835+00 Parking alert push \N \N \N \N \N +2722 865135061037980 1001 2026-04-23 11:40:51+00 0101000020E61000004E0CC9C9C479424052D7DAFB5455F2BF -1.145833 36.951318 \N \N 2026-04-23 11:40:52.860976+00 ACC OFF push \N \N \N \N \N +2723 359857082898008 stayAlertOn 2026-04-23 11:40:59+00 0101000020E6100000F33CB83B6B6F4240AE9E93DE37BEF3BF -1.23394 36.87046 \N \N 2026-04-23 11:40:59.825021+00 Idling alert push \N \N \N \N \N +2724 862798052708068 1004 2026-04-23 11:41:04+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 \N \N 2026-04-23 11:41:04.427598+00 Parking alert push \N \N \N \N \N +2725 862798050523014 1002 2026-04-23 11:41:09+00 0101000020E61000008A213999B85342400D384BC972D2F1BF -1.113879 36.654071 \N \N 2026-04-23 11:41:10.004327+00 ACC ON push \N \N \N \N \N +2729 865135061563597 3 2026-04-23 11:39:07+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 11:41:48.767366+00 Vibration alert push \N \N \N \N \N +2730 865135061037980 1004 2026-04-23 11:41:51+00 0101000020E61000004E0CC9C9C479424052D7DAFB5455F2BF -1.145833 36.951318 \N \N 2026-04-23 11:41:52.150239+00 Parking alert push \N \N \N \N \N +2732 865135061564470 1001 2026-04-23 11:43:20+00 0101000020E61000003C139A2496724240DD442DCDAD10F3BF -1.191572 36.895207 \N \N 2026-04-23 11:43:20.762793+00 ACC OFF push \N \N \N \N \N +2733 359857081891566 stayAlertOn 2026-04-23 11:43:24+00 0101000020E6100000C3D32B65196A4240CAC342AD695EF4BF -1.27305 36.8289 \N \N 2026-04-23 11:43:24.538722+00 Idling alert push \N \N \N \N \N +2734 359857082046145 1001 2026-04-23 11:43:30+00 0101000020E610000014CB2DAD86D84340B2D7BB3FDE0B10C0 -4.01159 39.69161 \N \N 2026-04-23 11:43:30.609577+00 ACC OFF push \N \N \N \N \N +2735 359857082897737 1001 2026-04-23 11:43:35+00 0101000020E6100000FA0AD28C45DF4340A6ED5F5969920FC0 -3.94649 39.74431 \N \N 2026-04-23 11:43:36.020357+00 ACC OFF push \N \N \N \N \N +2736 862798050525423 1001 2026-04-23 11:43:38+00 0101000020E610000031D120054FDF43400893E2E313920FC0 -3.946327 39.744599 \N \N 2026-04-23 11:43:38.856932+00 ACC OFF push \N \N \N \N \N +2737 865135061048466 1002 2026-04-23 11:43:38+00 0101000020E61000008A213999B8534240FBAE08FEB7D2F1BF -1.113945 36.654071 \N \N 2026-04-23 11:43:39.178819+00 ACC ON push \N \N \N \N \N +2738 865135061048276 1002 2026-04-23 11:43:43+00 0101000020E6100000664D2CF015D9434012C2A38D23F60FC0 -3.995185 39.695982 \N \N 2026-04-23 11:43:44.326966+00 ACC ON push \N \N \N \N \N +2739 862798050523337 1002 2026-04-23 11:43:43+00 0101000020E610000071C79BFC16D943403430F2B226F60FC0 -3.995191 39.696014 \N \N 2026-04-23 11:43:44.403949+00 ACC ON push \N \N \N \N \N +2795 862798052708068 1002 2026-04-23 11:44:08+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 \N \N 2026-04-23 11:44:09.385177+00 ACC ON push \N \N \N \N \N +2926 865135061564470 1002 2026-04-23 11:44:08+00 0101000020E6100000423EE8D9AC724240223999B85510F3BF -1.191488 36.8959 \N \N 2026-04-23 11:44:09.69249+00 ACC ON push \N \N \N \N \N +2929 862798050523527 128 2026-04-23 11:44:44+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 11:44:46.993481+00 DVR vibration alert push \N \N \N \N \N +2930 359857082918012 1002 2026-04-23 11:44:48+00 0101000020E61000002BD9B111886B42405E807D74EA4AF3BF -1.20579 36.84009 \N \N 2026-04-23 11:44:49.387089+00 ACC ON push \N \N \N \N \N +5739 359857082042052 ACC_OFF 2026-04-23 12:55:58+00 0101000020E61000005743E21E4B5B42405A8121AB5B3DF4BF -1.26498 36.71323 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5740 359857081885410 stayAlert 2026-04-23 12:55:44+00 0101000020E610000082E2C798BB7242401CCEFC6A0E10F3BF -1.19142 36.89635 0.00 \N 2026-04-23 12:59:29.728597+00 Parking alert poll \N \N \N \N \N +5741 359857081886905 ACC_OFF 2026-04-23 12:55:28+00 0101000020E6100000BB0A293FA9DE4340DE3CD52137C30FC0 -3.97032 39.73954 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5742 865135061054555 ACC_OFF 2026-04-23 12:54:48+00 0101000020E61000006B2A8BC22E304240B0FECF61BEBCD1BF -0.277145 36.376427 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5743 862798050523527 ACC_OFF 2026-04-23 12:54:47+00 0101000020E6100000874ECFBBB1724240164B917C2510F3BF -1.191442 36.896049 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5744 865135061054548 ACC_OFF 2026-04-23 12:54:44+00 0101000020E6100000DFFDF15EB5724240915F3FC4060BF3BF -1.190192 36.89616 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5745 359857081885410 ACC_OFF 2026-04-23 12:54:44+00 0101000020E6100000D13FC1C58A72424003CFBD874B0EF3BF -1.19099 36.89486 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5801 865135061048466 ACC_OFF 2026-04-23 12:58:15+00 0101000020E61000002CF015DD7A5342406D1D1CEC4DCCF1BF -1.112379 36.652187 0.00 \N 2026-04-23 12:59:29.728597+00 ACC OFF poll \N \N \N \N \N +5802 865135061048276 ACC_ON 2026-04-23 12:55:54+00 0101000020E6100000F1D4230D6ED943406612F5824F0310C0 -4.003233 39.698671 0.00 \N 2026-04-23 12:59:29.728597+00 ACC ON poll \N \N \N \N \N +5849 862798050525423 ACC_OFF 2026-04-23 13:04:00+00 0101000020E61000008EACFC3218DB4340AD4F39268BFB0FC0 -3.997824 39.711676 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5851 862798050525423 ACC_ON 2026-04-23 13:00:01+00 0101000020E6100000B5A338471DDB4340965AEF37DA0110C0 -4.001809 39.711831 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +5852 359857082900358 ACC_OFF 2026-04-23 12:59:55+00 0101000020E6100000C6504EB4AB7C4240978BF84ECCFAF6BF -1.43623 36.97399 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5885 359857082912239 stayAlert 2026-04-23 13:04:20+00 0101000020E6100000454772F90F494340658D7A8846370BC0 -3.40199 38.5708 0.00 \N 2026-04-23 13:04:30.949212+00 Parking alert poll \N \N \N \N \N +5886 359857082897737 ACC_OFF 2026-04-23 13:03:56+00 0101000020E610000089EFC4AC17DB4340B2BAD573D2FB0FC0 -3.99796 39.71166 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5887 359857082912239 ACC_OFF 2026-04-23 13:03:21+00 0101000020E6100000454772F90F494340658D7A8846370BC0 -3.40199 38.5708 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5888 862798050523337 ACC_ON 2026-04-23 13:03:04+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +5889 359857081892309 ACC_OFF 2026-04-23 13:03:00+00 0101000020E6100000D3872EA86F714240E23B31EBC550F3BF -1.20722 36.88622 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5890 359857081885410 stayAlert 2026-04-23 13:02:57+00 0101000020E6100000ED647094BC724240D3307C444C09F3BF -1.18977 36.89638 0.00 \N 2026-04-23 13:04:30.949212+00 Parking alert poll \N \N \N \N \N +5891 359857081892309 ACC_ON 2026-04-23 13:02:29+00 0101000020E6100000D3872EA86F714240E23B31EBC550F3BF -1.20722 36.88622 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +5892 359857082912239 ACC_ON 2026-04-23 13:02:25+00 0101000020E61000005A643BDF4F4943406AD95A5F24340BC0 -3.40046 38.57275 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +2711 862798050288360 1004 2026-04-23 11:39:30+00 0101000020E6100000F451465C00704240CC41D0D1AA96F3BF -1.224284 36.875011 \N \N 2026-04-23 11:39:30.873719+00 Parking alert push \N \N \N \N \N +2712 865135061564470 1002 2026-04-23 11:39:33+00 0101000020E6100000259529E620724240B6D958897916F3BF -1.192987 36.891629 \N \N 2026-04-23 11:39:34.10731+00 ACC ON push \N \N \N \N \N +2726 359857081891632 1004 2026-04-23 11:41:24+00 0101000020E610000001F6D1A92B6F4240C976BE9F1AAFF3BF -1.23025 36.86852 \N \N 2026-04-23 11:41:24.304761+00 Parking alert push \N \N \N \N \N +2727 359857081891566 1001 2026-04-23 11:41:28+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 11:41:28.470756+00 ACC OFF push \N \N \N \N \N +2728 865135061581904 3 2026-04-23 11:41:31+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 \N \N 2026-04-23 11:41:33.028549+00 Vibration alert push \N \N \N \N \N +2731 865135061054555 1001 2026-04-23 11:43:07+00 0101000020E61000008C9FC6BDF92F42403673486AA164D1BF -0.271767 36.374809 \N \N 2026-04-23 11:43:08.705352+00 ACC OFF push \N \N \N \N \N +2927 862798050288345 stayAlertOn 2026-04-23 11:44:30+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 \N \N 2026-04-23 11:44:30.793818+00 Idling alert push \N \N \N \N \N +2928 862798050525423 1004 2026-04-23 11:44:38+00 0101000020E610000031D120054FDF43400893E2E313920FC0 -3.946327 39.744599 \N \N 2026-04-23 11:44:38.194932+00 Parking alert push \N \N \N \N \N +2931 865135061563597 1002 2026-04-23 11:44:57+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 11:44:58.239991+00 ACC ON push \N \N \N \N \N +2932 865135061563597 3 2026-04-23 11:43:53+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 11:44:58.275939+00 Vibration alert push \N \N \N \N \N +2933 359857081887069 stayAlertOn 2026-04-23 11:44:59+00 0101000020E61000009C6D6E4C4F784240E50AEF72115FF3BF -1.21071 36.93992 \N \N 2026-04-23 11:45:00.066843+00 Idling alert push \N \N \N \N \N +2934 862798050288345 128 2026-04-23 11:44:59+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:45:01.493673+00 DVR vibration alert push \N \N \N \N \N +2935 865135061581904 3 2026-04-23 11:45:10+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 \N \N 2026-04-23 11:45:11.466102+00 Vibration alert push \N \N \N \N \N +2936 359857081892309 1002 2026-04-23 11:45:22+00 0101000020E6100000D9EBDD1FEF71424067EDB60BCD75F3BF -1.21626 36.89011 \N \N 2026-04-23 11:45:22.977229+00 ACC ON push \N \N \N \N \N +2937 359857082898487 1002 2026-04-23 11:45:22+00 0101000020E6100000DC63E943177C4240E3FC4D2844C0F2BF -1.17194 36.96946 \N \N 2026-04-23 11:45:23.60991+00 ACC ON push \N \N \N \N \N +2938 359857081892309 1001 2026-04-23 11:45:36+00 0101000020E6100000D9EBDD1FEF71424067EDB60BCD75F3BF -1.21626 36.89011 \N \N 2026-04-23 11:45:37.226859+00 ACC OFF push \N \N \N \N \N +2939 359857081892762 1003 2026-04-23 11:45:59+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 \N \N 2026-04-23 11:45:59.828647+00 Offline alert push \N \N \N \N \N +2940 865135061581904 1002 2026-04-23 11:46:09+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 \N \N 2026-04-23 11:46:10.607399+00 ACC ON push \N \N \N \N \N +2941 359857082898016 stayAlertOn 2026-04-23 11:46:14+00 0101000020E6100000D5CA845FEADB4340034356B77ACE0FC0 -3.97582 39.71809 \N \N 2026-04-23 11:46:14.90584+00 Idling alert push \N \N \N \N \N +2942 862798050523295 1002 2026-04-23 11:47:08+00 0101000020E610000029CE5147C779424061A417B5FB55F2BF -1.145992 36.951394 \N \N 2026-04-23 11:47:09.511236+00 ACC ON push \N \N \N \N \N +2943 359857082898487 1001 2026-04-23 11:47:16+00 0101000020E61000005C8FC2F5287C4240C095ECD808C4F2BF -1.17286 36.97 \N \N 2026-04-23 11:47:17.611544+00 ACC OFF push \N \N \N \N \N +2944 862798050523527 1002 2026-04-23 11:47:26+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 11:47:26.53068+00 ACC ON push \N \N \N \N \N +2945 862798050523527 1001 2026-04-23 11:47:30+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 11:47:31.715429+00 ACC OFF push \N \N \N \N \N +2946 865135061569123 1001 2026-04-23 11:47:44+00 0101000020E6100000ACFF73982F5F4240EEAF1EF7ADD6F4BF -1.302412 36.74364 \N \N 2026-04-23 11:47:45.420683+00 ACC OFF push \N \N \N \N \N +2947 359857082897737 stayAlertOn 2026-04-23 11:47:57+00 0101000020E6100000FA0AD28C45DF4340A6ED5F5969920FC0 -3.94649 39.74431 \N \N 2026-04-23 11:47:57.147338+00 Idling alert push \N \N \N \N \N +2948 359857081891566 1002 2026-04-23 11:48:17+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 11:48:17.943586+00 ACC ON push \N \N \N \N \N +2949 865135061569123 1004 2026-04-23 11:48:44+00 0101000020E610000018CDCAF6215F42400A0F9A5DF7D6F4BF -1.302482 36.743224 \N \N 2026-04-23 11:48:44.269213+00 Parking alert push \N \N \N \N \N +2950 359857082918012 1001 2026-04-23 11:48:58+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 \N \N 2026-04-23 11:48:59.573573+00 ACC OFF push \N \N \N \N \N +2951 865135061035653 1001 2026-04-23 11:49:01+00 0101000020E61000004DBD6E1118E1434051A5660FB4420FC0 -3.90757 39.758547 \N \N 2026-04-23 11:49:03.149533+00 ACC OFF push \N \N \N \N \N +2952 865135061569123 stayAlert 2026-04-23 11:48:44+00 0101000020E610000018CDCAF6215F42400A0F9A5DF7D6F4BF -1.302482 36.743224 0.00 \N 2026-04-23 11:49:10.038939+00 Parking alert poll \N \N \N \N \N +2953 865135061569123 ACC_OFF 2026-04-23 11:47:44+00 0101000020E6100000ACFF73982F5F4240EEAF1EF7ADD6F4BF -1.302412 36.74364 0.00 \N 2026-04-23 11:49:10.038939+00 ACC OFF poll \N \N \N \N \N +2954 865135061581904 ACC_ON 2026-04-23 11:46:09+00 0101000020E6100000B75ED3838254424016359886E1E3F3BF -1.243135 36.660233 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +2956 862798050525423 stayAlert 2026-04-23 11:44:38+00 0101000020E610000031D120054FDF43400893E2E313920FC0 -3.946327 39.744599 0.00 \N 2026-04-23 11:49:10.038939+00 Parking alert poll \N \N \N \N \N +2957 865135061564470 ACC_ON 2026-04-23 11:44:08+00 0101000020E6100000423EE8D9AC724240223999B85510F3BF -1.191488 36.8959 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +2958 862798052708068 ACC_ON 2026-04-23 11:44:08+00 0101000020E6100000C7BB2363B5534240EB55647440D2F1BF -1.113831 36.653973 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +3004 865135061035653 ACC_OFF 2026-04-23 11:49:01+00 0101000020E61000004DBD6E1118E1434051A5660FB4420FC0 -3.90757 39.758547 0.00 \N 2026-04-23 11:49:10.038939+00 ACC OFF poll \N \N \N \N \N +3005 359857082918012 ACC_OFF 2026-04-23 11:48:58+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 0.00 \N 2026-04-23 11:49:10.038939+00 ACC OFF poll \N \N \N \N \N +3006 359857081891566 ACC_ON 2026-04-23 11:48:17+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +3008 862798050523527 ACC_OFF 2026-04-23 11:47:30+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 0.00 \N 2026-04-23 11:49:10.038939+00 ACC OFF poll \N \N \N \N \N +3009 862798050523527 ACC_ON 2026-04-23 11:47:26+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +3010 359857082898487 ACC_OFF 2026-04-23 11:47:16+00 0101000020E61000005C8FC2F5287C4240C095ECD808C4F2BF -1.17286 36.97 0.00 \N 2026-04-23 11:49:10.038939+00 ACC OFF poll \N \N \N \N \N +3011 359857081892762 offline 2026-04-23 11:45:59+00 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 0.00 \N 2026-04-23 11:49:10.038939+00 Offline alert poll \N \N \N \N \N +3012 359857081892309 ACC_OFF 2026-04-23 11:45:36+00 0101000020E6100000D9EBDD1FEF71424067EDB60BCD75F3BF -1.21626 36.89011 0.00 \N 2026-04-23 11:49:10.038939+00 ACC OFF poll \N \N \N \N \N +3013 359857082898487 ACC_ON 2026-04-23 11:45:22+00 0101000020E6100000DC63E943177C4240E3FC4D2844C0F2BF -1.17194 36.96946 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +3014 359857081892309 ACC_ON 2026-04-23 11:45:22+00 0101000020E6100000D9EBDD1FEF71424067EDB60BCD75F3BF -1.21626 36.89011 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +3015 862798050288345 128 2026-04-23 11:45:01+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:49:10.038939+00 DVR vibration alert poll \N \N \N \N \N +3016 865135061563597 ACC_ON 2026-04-23 11:44:57+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +3017 359857082918012 ACC_ON 2026-04-23 11:44:48+00 0101000020E61000002BD9B111886B42405E807D74EA4AF3BF -1.20579 36.84009 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +3018 862798050523527 128 2026-04-23 11:44:46+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 11:49:10.038939+00 DVR vibration alert poll \N \N \N \N \N +3105 862798050523295 ACC_ON 2026-04-23 11:47:08+00 0101000020E610000029CE5147C779424061A417B5FB55F2BF -1.145992 36.951394 0.00 \N 2026-04-23 11:49:10.038939+00 ACC ON poll \N \N \N \N \N +3134 865135061564470 1001 2026-04-23 11:49:14+00 0101000020E6100000E73922DFA5724240B378B130440EF3BF -1.190983 36.895687 \N \N 2026-04-23 11:49:14.915141+00 ACC OFF push \N \N \N \N \N +3135 359857081891566 1001 2026-04-23 11:49:15+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 11:49:16.671528+00 ACC OFF push \N \N \N \N \N +3136 862798050525423 1002 2026-04-23 11:49:24+00 0101000020E610000031D120054FDF43400893E2E313920FC0 -3.946327 39.744599 \N \N 2026-04-23 11:49:25.397516+00 ACC ON push \N \N \N \N \N +3138 865135061563597 stayAlertOn 2026-04-23 11:49:57+00 0101000020E61000005BD1E638B7534240FCC6D79E59D2F1BF -1.113855 36.654029 \N \N 2026-04-23 11:49:57.82753+00 Idling alert push \N \N \N \N \N +3140 865135061564470 1004 2026-04-23 11:50:14+00 0101000020E6100000E73922DFA5724240B378B130440EF3BF -1.190983 36.895687 \N \N 2026-04-23 11:50:14.308908+00 Parking alert push \N \N \N \N \N +3141 359857082907973 1001 2026-04-23 11:50:15+00 0101000020E610000031EBC5504EC04340543541D47D4011C0 -4.31298 39.50239 \N \N 2026-04-23 11:50:16.123959+00 ACC OFF push \N \N \N \N \N +3142 865135061054555 1002 2026-04-23 11:50:15+00 0101000020E61000008C9FC6BDF92F42403673486AA164D1BF -0.271767 36.374809 \N \N 2026-04-23 11:50:16.823172+00 ACC ON push \N \N \N \N \N +3143 865135061048276 1001 2026-04-23 11:50:23+00 0101000020E6100000B4E386DF4DD94340D6E3BED53AF10FC0 -3.992788 39.697689 \N \N 2026-04-23 11:50:23.642632+00 ACC OFF push \N \N \N \N \N +3144 862798050523337 1001 2026-04-23 11:50:43+00 0101000020E6100000A80183A44FD94340AE7E6C921FF10FC0 -3.992736 39.697743 \N \N 2026-04-23 11:50:45.042799+00 ACC OFF push \N \N \N \N \N +3149 865135061564470 3 2026-04-23 11:51:07+00 0101000020E6100000DDED7A698A7242409296CADB110EF3BF -1.190935 36.894849 \N \N 2026-04-23 11:51:08.566145+00 Vibration alert push \N \N \N \N \N +3150 865135061569123 3 2026-04-23 11:48:55+00 0101000020E610000018CDCAF6215F42400A0F9A5DF7D6F4BF -1.302482 36.743224 \N \N 2026-04-23 11:51:10.67645+00 Vibration alert push \N \N \N \N \N +3151 865135061569123 1002 2026-04-23 11:51:10+00 0101000020E610000018CDCAF6215F42400A0F9A5DF7D6F4BF -1.302482 36.743224 \N \N 2026-04-23 11:51:10.736382+00 ACC ON push \N \N \N \N \N +3152 865135061564470 1002 2026-04-23 11:51:16+00 0101000020E6100000DDED7A698A7242409296CADB110EF3BF -1.190935 36.894849 \N \N 2026-04-23 11:51:16.867534+00 ACC ON push \N \N \N \N \N +3153 359857082907973 1002 2026-04-23 11:51:24+00 0101000020E610000055C1A8A44EC0434038842A357B4011C0 -4.31297 39.5024 \N \N 2026-04-23 11:51:25.058045+00 ACC ON push \N \N \N \N \N +3154 865135061054548 1002 2026-04-23 11:51:35+00 0101000020E6100000014C1938A0714240B2F1608BDDFEF2BF -1.187223 36.887702 \N \N 2026-04-23 11:51:36.207475+00 ACC ON push \N \N \N \N \N +3155 359857082918012 1001 2026-04-23 11:51:55+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 \N \N 2026-04-23 11:51:55.580765+00 ACC OFF push \N \N \N \N \N +3159 862798050523527 stayAlertOn 2026-04-23 11:52:26+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 11:52:26.315771+00 Idling alert push \N \N \N \N \N +3160 865135061043426 1002 2026-04-23 11:52:31+00 0101000020E6100000137EA99F37654240E38DCC237FB0F0BF -1.04309 36.79076 \N \N 2026-04-23 11:52:32.451937+00 ACC ON push \N \N \N \N \N +3161 359857082918186 1002 2026-04-23 11:52:34+00 0101000020E610000053B3075A81514240F0BF95ECD888F1BF -1.09591 36.63676 \N \N 2026-04-23 11:52:35.555839+00 ACC ON push \N \N \N \N \N +3162 359857081891566 stayAlertOn 2026-04-23 11:53:17+00 0101000020E6100000E7A90EB9196A4240202922C32A5EF4BF -1.27299 36.82891 \N \N 2026-04-23 11:53:17.386491+00 Idling alert push \N \N \N \N \N +3336 865135061564470 1004 2026-04-23 11:55:01+00 0101000020E610000009F9A067B3724240FAD346753A10F3BF -1.191462 36.8961 \N \N 2026-04-23 11:55:02.180934+00 Parking alert push \N \N \N \N \N +3337 359857081886467 1002 2026-04-23 11:55:03+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 \N \N 2026-04-23 11:55:03.805789+00 ACC ON push \N \N \N \N \N +3338 359857081887192 1002 2026-04-23 11:55:04+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 11:55:05.330716+00 ACC ON push \N \N \N \N \N +3339 359857082897794 stayAlertOn 2026-04-23 11:55:18+00 0101000020E61000001FF46C567D664240A98768740731F4BF -1.26197 36.8007 \N \N 2026-04-23 11:55:18.965643+00 Idling alert push \N \N \N \N \N +3340 359857082042854 1002 2026-04-23 11:55:33+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 \N \N 2026-04-23 11:55:34.822281+00 ACC ON push \N \N \N \N \N +3341 862798050523337 1002 2026-04-23 11:55:39+00 0101000020E6100000A80183A44FD94340AE7E6C921FF10FC0 -3.992736 39.697743 \N \N 2026-04-23 11:55:40.54252+00 ACC ON push \N \N \N \N \N +3342 865135061048276 1002 2026-04-23 11:55:42+00 0101000020E6100000CD3FFA264DD943409D47C5FF1DF10FC0 -3.992733 39.697667 \N \N 2026-04-23 11:55:42.800733+00 ACC ON push \N \N \N \N \N +3343 359857081887192 1001 2026-04-23 11:55:46+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 11:55:46.803287+00 ACC OFF push \N \N \N \N \N +3344 359857082918012 stayAlertOn 2026-04-23 11:55:55+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 \N \N 2026-04-23 11:55:56.030573+00 Idling alert push \N \N \N \N \N +3345 359857082902461 1001 2026-04-23 11:56:23+00 0101000020E6100000A852B3075A494340CBD6FA22A12D0BC0 -3.39728 38.57306 \N \N 2026-04-23 11:56:23.567161+00 ACC OFF push \N \N \N \N \N +3346 862798050523337 147 2026-04-23 11:56:59+00 0101000020E6100000C1745AB741D94340EE04FBAF73F30FC0 -3.993873 39.697318 22.00 \N 2026-04-23 11:57:01.014988+00 Collision Alert(DVR) push \N \N \N \N \N +3347 359857082896911 1001 2026-04-23 11:57:09+00 0101000020E6100000F0A7C64B376D4240EACF7EA4880CF3BF -1.19056 36.85325 \N \N 2026-04-23 11:57:09.781946+00 ACC OFF push \N \N \N \N \N +3349 359857081892309 1001 2026-04-23 11:57:52+00 0101000020E6100000A089B0E1E971424012A0A696AD75F3BF -1.21623 36.88995 \N \N 2026-04-23 11:57:53.336777+00 ACC OFF push \N \N \N \N \N +3354 359857082046145 1002 2026-04-23 11:58:46+00 0101000020E61000007120240B98D843404165FCFB8C0B10C0 -4.01128 39.69214 \N \N 2026-04-23 11:58:47.374115+00 ACC ON push \N \N \N \N \N +3355 359857081891566 1002 2026-04-23 11:58:48+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 11:58:49.116573+00 ACC ON push \N \N \N \N \N +3356 862798050523527 128 2026-04-23 11:58:51+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 11:58:53.686698+00 DVR vibration alert push \N \N \N \N \N +3358 862798050523527 1002 2026-04-23 11:59:13+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 11:59:14.116751+00 ACC ON push \N \N \N \N \N +3359 359857082897091 1002 2026-04-23 11:59:14+00 0101000020E6100000AD342905DD724240EFE192E34E69F3BF -1.21321 36.89737 \N \N 2026-04-23 11:59:15.480873+00 ACC ON push \N \N \N \N \N +3360 865135061562722 3 2026-04-23 11:54:36+00 0101000020E61000006EC328081E6942406364C91CCB7BF2BF -1.155223 36.821229 \N \N 2026-04-23 11:59:17.310925+00 Vibration alert push \N \N \N \N \N +3530 862798050523139 146 2026-04-23 11:59:22+00 0101000020E61000004AECDADE6EE94340855CA96741280EC0 -3.769656 39.823696 76.00 \N 2026-04-23 11:59:26.577594+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +3531 865135061562847 1001 2026-04-23 11:59:27+00 0101000020E61000002B6C06B8208142404F232D95B7A3F1BF -1.10247 37.008811 \N \N 2026-04-23 11:59:27.464538+00 ACC OFF push \N \N \N \N \N +3532 862798052708068 1004 2026-04-23 11:59:29+00 0101000020E61000004C6BD3D85E534240E964A9F57EE3F1BF -1.118041 36.651332 \N \N 2026-04-23 11:59:29.955642+00 Parking alert push \N \N \N \N \N +3533 865135061048466 1001 2026-04-23 11:59:32+00 0101000020E6100000FA2AF9D85D52424083A5BA8097D9F1BF -1.115623 36.643489 \N \N 2026-04-23 11:59:33.606514+00 ACC OFF push \N \N \N \N \N +5838 359857082912239 1002 2026-04-23 13:02:25+00 0101000020E61000005A643BDF4F4943406AD95A5F24340BC0 -3.40046 38.57275 \N \N 2026-04-23 13:02:26.487415+00 ACC ON push \N \N \N \N \N +5839 359857081892309 1002 2026-04-23 13:02:29+00 0101000020E6100000D3872EA86F714240E23B31EBC550F3BF -1.20722 36.88622 \N \N 2026-04-23 13:02:30.556819+00 ACC ON push \N \N \N \N \N +5840 359857081885410 1004 2026-04-23 13:02:57+00 0101000020E6100000ED647094BC724240D3307C444C09F3BF -1.18977 36.89638 \N \N 2026-04-23 13:02:57.843387+00 Parking alert push \N \N \N \N \N +5841 359857081892309 1001 2026-04-23 13:03:00+00 0101000020E6100000D3872EA86F714240E23B31EBC550F3BF -1.20722 36.88622 \N \N 2026-04-23 13:03:01.017068+00 ACC OFF push \N \N \N \N \N +5842 862798050523337 1002 2026-04-23 13:03:04+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 \N \N 2026-04-23 13:03:05.165119+00 ACC ON push \N \N \N \N \N +5845 865135061563639 stayAlertOn 2026-04-23 13:03:43+00 0101000020E61000003D1059A489EB424042E90B21E73DFABF -1.640113 37.840138 \N \N 2026-04-23 13:03:43.58834+00 Idling alert push \N \N \N \N \N +5846 359857082897737 1001 2026-04-23 13:03:56+00 0101000020E610000089EFC4AC17DB4340B2BAD573D2FB0FC0 -3.99796 39.71166 \N \N 2026-04-23 13:03:57.135536+00 ACC OFF push \N \N \N \N \N +5847 862798050525423 1001 2026-04-23 13:04:00+00 0101000020E61000008EACFC3218DB4340AD4F39268BFB0FC0 -3.997824 39.711676 \N \N 2026-04-23 13:04:00.427934+00 ACC OFF push \N \N \N \N \N +5848 359857082912239 1004 2026-04-23 13:04:20+00 0101000020E6100000454772F90F494340658D7A8846370BC0 -3.40199 38.5708 \N \N 2026-04-23 13:04:20.888387+00 Parking alert push \N \N \N \N \N +5987 359857082900358 stayAlertOn 2026-04-23 13:04:41+00 0101000020E6100000CD751A69A97C4240B4024356B7FAF6BF -1.43621 36.97392 \N \N 2026-04-23 13:04:41.718756+00 Idling alert push \N \N \N \N \N +5988 862798050525423 1004 2026-04-23 13:05:00+00 0101000020E61000008EACFC3218DB4340AD4F39268BFB0FC0 -3.997824 39.711676 \N \N 2026-04-23 13:05:00.338189+00 Parking alert push \N \N \N \N \N +5990 865135061053748 1001 2026-04-23 13:05:23+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 \N \N 2026-04-23 13:05:24.306352+00 ACC OFF push \N \N \N \N \N +3137 865135061037980 1002 2026-04-23 11:49:45+00 0101000020E610000011A62897C67942404A9869FB5756F2BF -1.14608 36.951373 \N \N 2026-04-23 11:49:45.464063+00 ACC ON push \N \N \N \N \N +3139 862798050288345 128 2026-04-23 11:50:02+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:50:08.940739+00 DVR vibration alert push \N \N \N \N \N +3145 359857082902461 stayAlertOn 2026-04-23 11:50:50+00 0101000020E6100000931D1B8178494340E0B9F770C9310BC0 -3.39931 38.57399 \N \N 2026-04-23 11:50:50.291914+00 Idling alert push \N \N \N \N \N +3146 359857082897737 1002 2026-04-23 11:50:53+00 0101000020E6100000BA83D89942DF43408A7615527E920FC0 -3.94653 39.74422 \N \N 2026-04-23 11:50:54.018559+00 ACC ON push \N \N \N \N \N +3147 359857082918012 1002 2026-04-23 11:50:55+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 \N \N 2026-04-23 11:50:56.39106+00 ACC ON push \N \N \N \N \N +3148 865135061562847 1002 2026-04-23 11:51:00+00 0101000020E6100000E43098BF42824240543882548A9DF1BF -1.100962 37.017662 \N \N 2026-04-23 11:51:01.109521+00 ACC ON push \N \N \N \N \N +3156 359857081892309 stayAlertOn 2026-04-23 11:52:06+00 0101000020E61000007DB3CD8DE971424012A0A696AD75F3BF -1.21623 36.88994 \N \N 2026-04-23 11:52:06.770369+00 Idling alert push \N \N \N \N \N +3157 359857081892101 1001 2026-04-23 11:52:10+00 0101000020E6100000C47762D68B65424056BC9179E48FF4BF -1.28513 36.79333 \N \N 2026-04-23 11:52:11.252037+00 ACC OFF push \N \N \N \N \N +3158 359857082898487 stayAlertOn 2026-04-23 11:52:12+00 0101000020E61000005C8FC2F5287C4240C095ECD808C4F2BF -1.17286 36.97 \N \N 2026-04-23 11:52:12.831595+00 Idling alert push \N \N \N \N \N +3163 865135061564470 1001 2026-04-23 11:54:01+00 0101000020E61000006B9DB81CAF724240E6577380600EF3BF -1.19101 36.895969 \N \N 2026-04-23 11:54:01.555941+00 ACC OFF push \N \N \N \N \N +3348 359857081892309 1002 2026-04-23 11:57:45+00 0101000020E6100000A089B0E1E971424012A0A696AD75F3BF -1.21623 36.88995 \N \N 2026-04-23 11:57:46.255619+00 ACC ON push \N \N \N \N \N +3350 865135061564470 3 2026-04-23 11:58:22+00 0101000020E610000009F9A067B3724240FAD346753A10F3BF -1.191462 36.8961 \N \N 2026-04-23 11:58:24.519675+00 Vibration alert push \N \N \N \N \N +3351 359857082038977 1001 2026-04-23 11:58:26+00 0101000020E61000007E74EACA67D94340BABDA4315A2710C0 -4.03843 39.69848 \N \N 2026-04-23 11:58:26.342094+00 ACC OFF push \N \N \N \N \N +3352 865135061564470 1002 2026-04-23 11:58:28+00 0101000020E610000009F9A067B3724240FAD346753A10F3BF -1.191462 36.8961 \N \N 2026-04-23 11:58:29.853921+00 ACC ON push \N \N \N \N \N +3353 862798052708068 1001 2026-04-23 11:58:29+00 0101000020E6100000917BBABA63534240274A42226DE3F1BF -1.118024 36.651481 \N \N 2026-04-23 11:58:30.199822+00 ACC OFF push \N \N \N \N \N +3357 359857081891632 1002 2026-04-23 11:59:01+00 0101000020E6100000DE1FEF552B6F4240C976BE9F1AAFF3BF -1.23025 36.86851 \N \N 2026-04-23 11:59:02.510327+00 ACC ON push \N \N \N \N \N +5893 862798050523337 ACC_OFF 2026-04-23 13:02:18+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5894 359857082042052 stayAlert 2026-04-23 13:02:04+00 0101000020E6100000739D465A2A5B4240617138F3AB39F4BF -1.26408 36.71223 0.00 \N 2026-04-23 13:04:30.949212+00 Parking alert poll \N \N \N \N \N +5895 862798050523527 ACC_OFF 2026-04-23 13:01:58+00 0101000020E6100000E690D442C9724240658F5033A40AF3BF -1.190098 36.896767 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5896 359857081885410 ACC_OFF 2026-04-23 13:01:57+00 0101000020E6100000C98E8D40BC7242408E9257E71810F3BF -1.19143 36.89637 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5897 862798050523014 ACC_ON 2026-04-23 13:01:40+00 0101000020E610000039D2191879534240F5D555815ACCF1BF -1.112391 36.652133 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +5898 359857082042052 ACC_OFF 2026-04-23 13:01:04+00 0101000020E6100000739D465A2A5B4240617138F3AB39F4BF -1.26408 36.71223 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5899 359857081892101 ACC_OFF 2026-04-23 13:00:54+00 0101000020E61000007B4E7ADFF862424080F10C1AFAA7F4BF -1.29101 36.77322 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5900 359857082897737 ACC_ON 2026-04-23 12:59:58+00 0101000020E61000004968CBB914DB4340008C67D0D0FF0FC0 -3.99991 39.71157 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +5901 359857082910589 ACC_ON 2026-04-23 12:59:34+00 0101000020E610000057B2632310774240F0A7C64B3709F3BF -1.18975 36.93018 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +5968 865135061048276 ACC_ON 2026-04-23 13:03:12+00 0101000020E61000001FD95C35CFD94340A583F57F0E0310C0 -4.002985 39.701636 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +5969 865135061048276 ACC_OFF 2026-04-23 13:01:58+00 0101000020E61000001FD95C35CFD94340A583F57F0E0310C0 -4.002985 39.701636 0.00 \N 2026-04-23 13:04:30.949212+00 ACC OFF poll \N \N \N \N \N +5970 862798050523626 146 2026-04-23 13:01:49+00 0101000020E61000007B1684F23EB84340E5B9BE0F07890DC0 -3.691908 39.439421 59.00 \N 2026-04-23 13:04:30.949212+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +5971 865135061048466 ACC_ON 2026-04-23 13:01:41+00 0101000020E61000002CF015DD7A5342406D1D1CEC4DCCF1BF -1.112379 36.652187 0.00 \N 2026-04-23 13:04:30.949212+00 ACC ON poll \N \N \N \N \N +6015 865135061053748 ACC_OFF 2026-04-23 13:08:37+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6016 862798052708068 stayAlert 2026-04-23 13:07:33+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 0.00 \N 2026-04-23 13:09:31.781259+00 Parking alert poll \N \N \N \N \N +6017 862798052708068 ACC_ON 2026-04-23 13:06:27+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6018 865135061053748 ACC_ON 2026-04-23 13:06:27+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6019 865135061053748 stayAlert 2026-04-23 13:06:23+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 0.00 \N 2026-04-23 13:09:31.781259+00 Parking alert poll \N \N \N \N \N +6020 862798052708068 ACC_OFF 2026-04-23 13:06:21+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6021 865135061053748 ACC_OFF 2026-04-23 13:05:23+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6022 862798050525423 stayAlert 2026-04-23 13:05:00+00 0101000020E61000008EACFC3218DB4340AD4F39268BFB0FC0 -3.997824 39.711676 0.00 \N 2026-04-23 13:09:31.781259+00 Parking alert poll \N \N \N \N \N +6055 359857082918012 ACC_ON 2026-04-23 13:09:21+00 0101000020E610000046D3D9C9E06C4240850838842AB5F3BF -1.23173 36.85061 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6056 359857082910589 ACC_ON 2026-04-23 13:09:14+00 0101000020E6100000E89FE0624575424052616C21C841F3BF -1.20356 36.91618 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6057 359857082910589 ACC_OFF 2026-04-23 13:08:51+00 0101000020E6100000E89FE0624575424052616C21C841F3BF -1.20356 36.91618 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6058 862798050526231 ACC_ON 2026-04-23 13:08:44+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6059 862798050526231 ACC_OFF 2026-04-23 13:08:38+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6060 865135061563597 ACC_OFF 2026-04-23 13:08:29+00 0101000020E610000064B0E2546B5342404B732B84D5D8F1BF -1.115438 36.651713 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6062 862798050288345 128 2026-04-23 13:08:20+00 0101000020E610000072C5C551B991434082AE7D01BD6011C0 -4.344471 39.138468 0.00 \N 2026-04-23 13:09:31.781259+00 DVR vibration alert poll \N \N \N \N \N +6066 359857082037185 ACC_OFF 2026-04-23 13:06:26+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6067 359857082037185 ACC_ON 2026-04-23 13:05:50+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6068 862798050526231 ACC_OFF 2026-04-23 13:05:44+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6069 862798050526231 ACC_ON 2026-04-23 13:05:44+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6147 359857082918038 ACC_ON 2026-04-23 13:09:22+00 0101000020E6100000691D554D10494340481630815B370BC0 -3.40203 38.57081 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6148 359857081886467 ACC_ON 2026-04-23 13:06:43+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +6149 359857081886467 ACC_OFF 2026-04-23 13:05:32+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 0.00 \N 2026-04-23 13:09:31.781259+00 ACC OFF poll \N \N \N \N \N +6150 862798050288212 ACC_ON 2026-04-23 13:05:17+00 0101000020E6100000D9AF3BDD7970424029EB3713D385F3BF -1.220172 36.878719 0.00 \N 2026-04-23 13:09:31.781259+00 ACC ON poll \N \N \N \N \N +3164 865135061564470 ACC_OFF 2026-04-23 11:54:01+00 0101000020E61000006B9DB81CAF724240E6577380600EF3BF -1.19101 36.895969 0.00 \N 2026-04-23 11:54:18.23207+00 ACC OFF poll \N \N \N \N \N +3165 865135061043426 ACC_ON 2026-04-23 11:52:31+00 0101000020E6100000137EA99F37654240E38DCC237FB0F0BF -1.04309 36.79076 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3166 865135061564470 ACC_ON 2026-04-23 11:51:16+00 0101000020E6100000DDED7A698A7242409296CADB110EF3BF -1.190935 36.894849 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3167 865135061569123 ACC_ON 2026-04-23 11:51:10+00 0101000020E610000018CDCAF6215F42400A0F9A5DF7D6F4BF -1.302482 36.743224 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3169 865135061564470 stayAlert 2026-04-23 11:50:14+00 0101000020E6100000E73922DFA5724240B378B130440EF3BF -1.190983 36.895687 0.00 \N 2026-04-23 11:54:18.23207+00 Parking alert poll \N \N \N \N \N +3170 865135061037980 ACC_ON 2026-04-23 11:49:45+00 0101000020E610000011A62897C67942404A9869FB5756F2BF -1.14608 36.951373 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3171 862798050525423 ACC_ON 2026-04-23 11:49:24+00 0101000020E610000031D120054FDF43400893E2E313920FC0 -3.946327 39.744599 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3172 865135061564470 ACC_OFF 2026-04-23 11:49:14+00 0101000020E6100000E73922DFA5724240B378B130440EF3BF -1.190983 36.895687 0.00 \N 2026-04-23 11:54:18.23207+00 ACC OFF poll \N \N \N \N \N +3215 359857082918186 ACC_ON 2026-04-23 11:52:34+00 0101000020E610000053B3075A81514240F0BF95ECD888F1BF -1.09591 36.63676 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3218 359857081892101 ACC_OFF 2026-04-23 11:52:10+00 0101000020E6100000C47762D68B65424056BC9179E48FF4BF -1.28513 36.79333 0.00 \N 2026-04-23 11:54:18.23207+00 ACC OFF poll \N \N \N \N \N +3220 359857082918012 ACC_OFF 2026-04-23 11:51:55+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 0.00 \N 2026-04-23 11:54:18.23207+00 ACC OFF poll \N \N \N \N \N +3221 865135061054548 ACC_ON 2026-04-23 11:51:35+00 0101000020E6100000014C1938A0714240B2F1608BDDFEF2BF -1.187223 36.887702 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3222 359857082907973 ACC_ON 2026-04-23 11:51:24+00 0101000020E610000055C1A8A44EC0434038842A357B4011C0 -4.31297 39.5024 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3223 865135061562847 ACC_ON 2026-04-23 11:51:00+00 0101000020E6100000E43098BF42824240543882548A9DF1BF -1.100962 37.017662 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3224 359857082918012 ACC_ON 2026-04-23 11:50:55+00 0101000020E610000097900F7A366B424017BCE82B4833F3BF -1.20002 36.8376 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3225 359857082897737 ACC_ON 2026-04-23 11:50:53+00 0101000020E6100000BA83D89942DF43408A7615527E920FC0 -3.94653 39.74422 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3226 862798050523337 ACC_OFF 2026-04-23 11:50:43+00 0101000020E6100000A80183A44FD94340AE7E6C921FF10FC0 -3.992736 39.697743 0.00 \N 2026-04-23 11:54:18.23207+00 ACC OFF poll \N \N \N \N \N +3227 359857082907973 ACC_OFF 2026-04-23 11:50:15+00 0101000020E610000031EBC5504EC04340543541D47D4011C0 -4.31298 39.50239 0.00 \N 2026-04-23 11:54:18.23207+00 ACC OFF poll \N \N \N \N \N +3228 865135061054555 ACC_ON 2026-04-23 11:50:15+00 0101000020E61000008C9FC6BDF92F42403673486AA164D1BF -0.271767 36.374809 0.00 \N 2026-04-23 11:54:18.23207+00 ACC ON poll \N \N \N \N \N +3229 862798050288345 128 2026-04-23 11:50:08+00 0101000020E6100000DD7BB8E4B89143403C33C170AE6111C0 -4.345392 39.138455 0.00 \N 2026-04-23 11:54:18.23207+00 DVR vibration alert poll \N \N \N \N \N +3231 359857081891566 ACC_OFF 2026-04-23 11:49:15+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 11:54:18.23207+00 ACC OFF poll \N \N \N \N \N +3313 865135061048276 ACC_OFF 2026-04-23 11:50:23+00 0101000020E6100000B4E386DF4DD94340D6E3BED53AF10FC0 -3.992788 39.697689 0.00 \N 2026-04-23 11:54:18.23207+00 ACC OFF poll \N \N \N \N \N +3361 862798052708068 ACC_OFF 2026-04-23 11:58:29+00 0101000020E6100000917BBABA63534240274A42226DE3F1BF -1.118024 36.651481 0.00 \N 2026-04-23 11:59:19.184132+00 ACC OFF poll \N \N \N \N \N +3362 865135061564470 ACC_ON 2026-04-23 11:58:28+00 0101000020E610000009F9A067B3724240FAD346753A10F3BF -1.191462 36.8961 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3364 865135061564470 stayAlert 2026-04-23 11:55:01+00 0101000020E610000009F9A067B3724240FAD346753A10F3BF -1.191462 36.8961 0.00 \N 2026-04-23 11:59:19.184132+00 Parking alert poll \N \N \N \N \N +3411 862798050523527 ACC_ON 2026-04-23 11:59:13+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3412 359857081891632 ACC_ON 2026-04-23 11:59:01+00 0101000020E6100000DE1FEF552B6F4240C976BE9F1AAFF3BF -1.23025 36.86851 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3413 862798050523527 128 2026-04-23 11:58:53+00 0101000020E6100000B613252191724240F2E9B12D030EF3BF -1.190921 36.895054 0.00 \N 2026-04-23 11:59:19.184132+00 DVR vibration alert poll \N \N \N \N \N +3414 359857081891566 ACC_ON 2026-04-23 11:58:48+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3415 359857082046145 ACC_ON 2026-04-23 11:58:46+00 0101000020E61000007120240B98D843404165FCFB8C0B10C0 -4.01128 39.69214 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3416 359857082038977 ACC_OFF 2026-04-23 11:58:26+00 0101000020E61000007E74EACA67D94340BABDA4315A2710C0 -4.03843 39.69848 0.00 \N 2026-04-23 11:59:19.184132+00 ACC OFF poll \N \N \N \N \N +3417 359857081892309 ACC_OFF 2026-04-23 11:57:52+00 0101000020E6100000A089B0E1E971424012A0A696AD75F3BF -1.21623 36.88995 0.00 \N 2026-04-23 11:59:19.184132+00 ACC OFF poll \N \N \N \N \N +3418 359857081892309 ACC_ON 2026-04-23 11:57:45+00 0101000020E6100000A089B0E1E971424012A0A696AD75F3BF -1.21623 36.88995 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3419 359857082896911 ACC_OFF 2026-04-23 11:57:09+00 0101000020E6100000F0A7C64B376D4240EACF7EA4880CF3BF -1.19056 36.85325 0.00 \N 2026-04-23 11:59:19.184132+00 ACC OFF poll \N \N \N \N \N +3422 359857081887192 ACC_OFF 2026-04-23 11:55:46+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 11:59:19.184132+00 ACC OFF poll \N \N \N \N \N +3423 862798050523337 ACC_ON 2026-04-23 11:55:39+00 0101000020E6100000A80183A44FD94340AE7E6C921FF10FC0 -3.992736 39.697743 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3424 359857082042854 ACC_ON 2026-04-23 11:55:33+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3426 359857081887192 ACC_ON 2026-04-23 11:55:04+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3506 359857082902461 ACC_OFF 2026-04-23 11:56:23+00 0101000020E6100000A852B3075A494340CBD6FA22A12D0BC0 -3.39728 38.57306 0.00 \N 2026-04-23 11:59:19.184132+00 ACC OFF poll \N \N \N \N \N +3507 865135061048276 ACC_ON 2026-04-23 11:55:42+00 0101000020E6100000CD3FFA264DD943409D47C5FF1DF10FC0 -3.992733 39.697667 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3508 359857081886467 ACC_ON 2026-04-23 11:55:03+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 0.00 \N 2026-04-23 11:59:19.184132+00 ACC ON poll \N \N \N \N \N +3534 862798050523014 1001 2026-04-23 11:59:38+00 0101000020E61000000CCA349A5C5242406616A1D80ADAF1BF -1.115733 36.643451 \N \N 2026-04-23 11:59:39.215021+00 ACC OFF push \N \N \N \N \N +3535 865135061054548 1001 2026-04-23 11:59:40+00 0101000020E610000005DEC9A7C7724240E8F4BC1B0B0AF3BF -1.189952 36.896718 \N \N 2026-04-23 11:59:40.714701+00 ACC OFF push \N \N \N \N \N +3536 865135061054548 1002 2026-04-23 11:59:45+00 0101000020E6100000817A336ABE724240B6B9313D6109F3BF -1.18979 36.896436 \N \N 2026-04-23 11:59:45.725194+00 ACC ON push \N \N \N \N \N +3537 865135061569479 1003 2026-04-23 12:00:00+00 0101000020E6100000F71E2E39EE444040587380608E1EC13F 0.133745 32.53852 \N \N 2026-04-23 12:00:00.671677+00 Offline alert push \N \N \N \N \N +3538 862798052708068 1002 2026-04-23 12:00:00+00 0101000020E61000004C6BD3D85E534240E964A9F57EE3F1BF -1.118041 36.651332 \N \N 2026-04-23 12:00:00.704231+00 ACC ON push \N \N \N \N \N +3539 359857082902461 stayAlertOn 2026-04-23 12:00:03+00 0101000020E610000093C6681D55494340E8C1DD59BB2D0BC0 -3.39733 38.57291 \N \N 2026-04-23 12:00:03.192516+00 Idling alert push \N \N \N \N \N +3540 359857082910589 1002 2026-04-23 12:00:12+00 0101000020E61000006C43C5387F774240378E588B4F81F2BF -1.15657 36.93357 \N \N 2026-04-23 12:00:13.545584+00 ACC ON push \N \N \N \N \N +3541 865135061048953 1001 2026-04-23 12:00:21+00 0101000020E6100000B2BE81C98DD8434029594E42E90B10C0 -4.011632 39.691827 \N \N 2026-04-23 12:00:22.731268+00 ACC OFF push \N \N \N \N \N +3542 359857082046145 1001 2026-04-23 12:00:25+00 0101000020E61000007120240B98D843404165FCFB8C0B10C0 -4.01128 39.69214 \N \N 2026-04-23 12:00:26.191728+00 ACC OFF push \N \N \N \N \N +3543 359857082898008 1001 2026-04-23 12:00:34+00 0101000020E610000056B77A4E7A6F4240B2D7BB3FDEABF3BF -1.22946 36.87092 \N \N 2026-04-23 12:00:35.243372+00 ACC OFF push \N \N \N \N \N +3544 865135061569479 3 2026-04-23 10:56:51+00 0101000020E6100000F71E2E39EE444040587380608E1EC13F 0.133745 32.53852 \N \N 2026-04-23 12:00:51.497902+00 Vibration alert push \N \N \N \N \N +3545 359857082038977 1002 2026-04-23 12:01:13+00 0101000020E61000007E74EACA67D94340BABDA4315A2710C0 -4.03843 39.69848 \N \N 2026-04-23 12:01:14.545025+00 ACC ON push \N \N \N \N \N +3546 865135061569123 stayAlertOn 2026-04-23 12:01:23+00 0101000020E6100000F0DC7BB8E46042402499D53BDCCEF4BF -1.300503 36.75698 \N \N 2026-04-23 12:01:24.028742+00 Idling alert push \N \N \N \N \N +3547 865135061562722 3 2026-04-23 12:01:23+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 12:01:26.18201+00 Vibration alert push \N \N \N \N \N +3548 865135061048953 1002 2026-04-23 12:01:28+00 0101000020E6100000B2BE81C98DD8434029594E42E90B10C0 -4.011632 39.691827 \N \N 2026-04-23 12:01:28.665239+00 ACC ON push \N \N \N \N \N +3549 359857082046145 1002 2026-04-23 12:01:29+00 0101000020E6100000B8AF03E78CD8434007EBFF1CE60B10C0 -4.01162 39.6918 \N \N 2026-04-23 12:01:30.324981+00 ACC ON push \N \N \N \N \N +3550 862798050525423 stayAlertOn 2026-04-23 12:01:55+00 0101000020E6100000DEAAEB504DDF4340802DAF5C6F9B0FC0 -3.950896 39.744547 \N \N 2026-04-23 12:01:56.066439+00 Idling alert push \N \N \N \N \N +3559 862798050523337 147 2026-04-23 12:02:59+00 0101000020E61000008CDB68006FD9434017821C94300310C0 -4.003115 39.6987 7.00 \N 2026-04-23 12:03:02.306265+00 Collision Alert(DVR) push \N \N \N \N \N +3561 359857081891566 stayAlertOn 2026-04-23 12:03:48+00 0101000020E6100000CAC342AD696A424037E0F3C30861F4BF -1.27369 36.83135 \N \N 2026-04-23 12:03:48.486071+00 Idling alert push \N \N \N \N \N +3749 865135061581904 1002 2026-04-23 12:04:52+00 0101000020E6100000A8FFACF9F1554240768BC058DFC0F3BF -1.234588 36.671447 \N \N 2026-04-23 12:04:52.824855+00 ACC ON push \N \N \N \N \N +3750 865135061569123 1001 2026-04-23 12:04:57+00 0101000020E61000009D47C5FF1D634240894160E5D0E2F4BF -1.305375 36.774353 \N \N 2026-04-23 12:04:57.27236+00 ACC OFF push \N \N \N \N \N +3751 865135061563597 1001 2026-04-23 12:05:12+00 0101000020E61000000684D6C397534240E2067C7E18E1F1BF -1.117455 36.653069 \N \N 2026-04-23 12:05:13.08349+00 ACC OFF push \N \N \N \N \N +3752 862798052708068 1001 2026-04-23 12:05:13+00 0101000020E6100000BBF083F3A953424033DC80CF0FE3F1BF -1.117935 36.653624 \N \N 2026-04-23 12:05:14.089391+00 ACC OFF push \N \N \N \N \N +3753 359857082910589 1002 2026-04-23 12:05:17+00 0101000020E61000008FFCC1C0737742408AABCABE2B82F2BF -1.15678 36.93322 \N \N 2026-04-23 12:05:17.646649+00 ACC ON push \N \N \N \N \N +3758 865135061053748 1001 2026-04-23 12:06:01+00 0101000020E61000006F62484E26D643405E13D21A833E10C0 -4.061047 39.673044 \N \N 2026-04-23 12:06:01.641168+00 ACC OFF push \N \N \N \N \N +3759 865135061048276 1001 2026-04-23 12:06:04+00 0101000020E6100000EF38454772D94340C7D45DD9050310C0 -4.002952 39.6988 \N \N 2026-04-23 12:06:04.957392+00 ACC OFF push \N \N \N \N \N +3760 865135061581904 1004 2026-04-23 12:06:06+00 0101000020E6100000A8FFACF9F1554240768BC058DFC0F3BF -1.234588 36.671447 \N \N 2026-04-23 12:06:06.228985+00 Parking alert push \N \N \N \N \N +3761 865135061054555 1001 2026-04-23 12:06:12+00 0101000020E6100000AA436E861B30424064B14D2A1A6BD1BF -0.272162 36.37584 \N \N 2026-04-23 12:06:13.870046+00 ACC OFF push \N \N \N \N \N +3762 862798052708068 1004 2026-04-23 12:06:13+00 0101000020E6100000BBF083F3A953424033DC80CF0FE3F1BF -1.117935 36.653624 \N \N 2026-04-23 12:06:14.150693+00 Parking alert push \N \N \N \N \N +3771 862798050523337 1002 2026-04-23 12:07:32+00 0101000020E6100000FD4E93196FD94340D3A57F492A0310C0 -4.003091 39.698703 \N \N 2026-04-23 12:07:32.628115+00 ACC ON push \N \N \N \N \N +3776 865135061569479 3 2026-04-23 12:07:49+00 0101000020E610000071917BBABA43404053E8BCC62E51BD3F 0.11452 32.529136 27.00 \N 2026-04-23 12:07:51.582267+00 Vibration alert push \N \N \N \N \N +3777 865135061564470 1004 2026-04-23 12:07:54+00 0101000020E6100000E49F19C4077242401BD6541685DDF2BF -1.179082 36.890862 \N \N 2026-04-23 12:07:54.346049+00 Parking alert push \N \N \N \N \N +3778 865135061035133 1002 2026-04-23 12:07:55+00 0101000020E6100000AA0D4E44BFBC43409C16BCE82BE80EC0 -3.863365 39.474587 \N \N 2026-04-23 12:07:56.044395+00 ACC ON push \N \N \N \N \N +3779 359857081887192 1002 2026-04-23 12:08:00+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 12:08:01.06509+00 ACC ON push \N \N \N \N \N +3780 862798050523139 146 2026-04-23 12:08:21+00 0101000020E6100000079ACFB9DBE743409C6F44F7AC8B0DC0 -3.693201 39.811393 63.00 \N 2026-04-23 12:08:23.953457+00 Sharp Turn Alert(DVR) push \N \N \N \N \N +3781 865135061048276 1001 2026-04-23 12:08:27+00 0101000020E6100000F1D4230D6ED943406612F5824F0310C0 -4.003233 39.698671 \N \N 2026-04-23 12:08:28.56417+00 ACC OFF push \N \N \N \N \N +3784 359857082918038 1002 2026-04-23 12:09:05+00 0101000020E61000008C4AEA0434494340BF9A030473340BC0 -3.40061 38.5719 \N \N 2026-04-23 12:09:05.609075+00 ACC ON push \N \N \N \N \N +3785 359857082902461 stayAlertOn 2026-04-23 12:09:10+00 0101000020E6100000EFFE78AF5A494340CBD6FA22A12D0BC0 -3.39728 38.57308 \N \N 2026-04-23 12:09:10.177248+00 Idling alert push \N \N \N \N \N +3971 865135061564470 1002 2026-04-23 12:09:28+00 0101000020E6100000E49F19C4077242401BD6541685DDF2BF -1.179082 36.890862 \N \N 2026-04-23 12:09:29.0104+00 ACC ON push \N \N \N \N \N +3977 865135061035778 1001 2026-04-23 12:10:52+00 0101000020E6100000CEFE40B96D7D424091D09673292EF2BF -1.13627 36.979911 \N \N 2026-04-23 12:10:53.360791+00 ACC OFF push \N \N \N \N \N +3978 862798050525423 1001 2026-04-23 12:10:56+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 \N \N 2026-04-23 12:10:57.127995+00 ACC OFF push \N \N \N \N \N +3979 359857082897737 1001 2026-04-23 12:10:58+00 0101000020E6100000919BE1067CDE43401CD3139678C00FC0 -3.96898 39.73816 \N \N 2026-04-23 12:10:58.352354+00 ACC OFF push \N \N \N \N \N +3980 359857082896911 1002 2026-04-23 12:11:01+00 0101000020E6100000E1404816306D4240E88711C2A30DF3BF -1.19083 36.85303 \N \N 2026-04-23 12:11:02.497761+00 ACC ON push \N \N \N \N \N +3981 359857082897737 1002 2026-04-23 12:11:09+00 0101000020E6100000B471C45A7CDE43401CD3139678C00FC0 -3.96898 39.73817 \N \N 2026-04-23 12:11:09.491946+00 ACC ON push \N \N \N \N \N +3982 862798050525423 1002 2026-04-23 12:11:12+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 \N \N 2026-04-23 12:11:12.662022+00 ACC ON push \N \N \N \N \N +3983 359857082046145 1001 2026-04-23 12:11:22+00 0101000020E6100000B8AF03E78CD8434007EBFF1CE60B10C0 -4.01162 39.6918 \N \N 2026-04-23 12:11:23.363819+00 ACC OFF push \N \N \N \N \N +3984 865135061054555 1002 2026-04-23 12:11:27+00 0101000020E6100000F9484A7A183042401492CCEA1D6ED1BF -0.272346 36.375747 \N \N 2026-04-23 12:11:28.020581+00 ACC ON push \N \N \N \N \N +3985 359857081892309 stayAlertOn 2026-04-23 12:11:31+00 0101000020E6100000601F9DBAF27142402EFF21FDF675F3BF -1.2163 36.89022 \N \N 2026-04-23 12:11:31.561355+00 Idling alert push \N \N \N \N \N +3986 865135061035133 1001 2026-04-23 12:11:41+00 0101000020E610000045D95BCAF9BC4340A7C98CB795DE0EC0 -3.858684 39.476373 \N \N 2026-04-23 12:11:42.428604+00 ACC OFF push \N \N \N \N \N +3987 865135061035778 1004 2026-04-23 12:11:44+00 0101000020E61000004089CF9D607D4240CBD6FA22A12DF2BF -1.13614 36.979511 \N \N 2026-04-23 12:11:44.339024+00 Parking alert push \N \N \N \N \N +3988 862798050523626 128 2026-04-23 12:11:49+00 0101000020E61000006326512FF8BC434086730D3334DE0EC0 -3.858498 39.476324 7.00 \N 2026-04-23 12:11:51.657913+00 DVR vibration alert push \N \N \N \N \N +3989 865135061035653 1001 2026-04-23 12:11:55+00 0101000020E6100000C100C28712E143406B60AB048B430FC0 -3.90798 39.758378 \N \N 2026-04-23 12:11:56.112364+00 ACC OFF push \N \N \N \N \N +3991 862798050523626 1001 2026-04-23 12:12:23+00 0101000020E61000003A933655F7BC434096CCB1BCABDE0EC0 -3.858726 39.476298 \N \N 2026-04-23 12:12:23.474577+00 ACC OFF push \N \N \N \N \N +3994 359857082037185 1002 2026-04-23 12:13:09+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 12:13:10.006513+00 ACC ON push \N \N \N \N \N +3995 862798050523527 1001 2026-04-23 12:13:11+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 12:13:11.901573+00 ACC OFF push \N \N \N \N \N +5991 359857081886467 1001 2026-04-23 13:05:32+00 0101000020E6100000D5CA845FEAD74340C408E1D1C63110C0 -4.04861 39.68684 \N \N 2026-04-23 13:05:33.380942+00 ACC OFF push \N \N \N \N \N +5992 862798050526231 1002 2026-04-23 13:05:44+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 \N \N 2026-04-23 13:05:45.135218+00 ACC ON push \N \N \N \N \N +5993 862798050526231 1001 2026-04-23 13:05:44+00 0101000020E61000007A51BB5F05D4434016F9F5436C3010C0 -4.047288 39.656414 \N \N 2026-04-23 13:05:45.157162+00 ACC OFF push \N \N \N \N \N +5994 359857082037185 1002 2026-04-23 13:05:50+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 13:05:51.474812+00 ACC ON push \N \N \N \N \N +5995 862798052708068 1001 2026-04-23 13:06:21+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 \N \N 2026-04-23 13:06:22.02791+00 ACC OFF push \N \N \N \N \N +5996 865135061053748 1004 2026-04-23 13:06:23+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 \N \N 2026-04-23 13:06:24.040615+00 Parking alert push \N \N \N \N \N +5997 359857082037185 1001 2026-04-23 13:06:26+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 13:06:26.862829+00 ACC OFF push \N \N \N \N \N +5998 865135061053748 1002 2026-04-23 13:06:27+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 \N \N 2026-04-23 13:06:27.799836+00 ACC ON push \N \N \N \N \N +5999 862798052708068 1002 2026-04-23 13:06:27+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 \N \N 2026-04-23 13:06:27.99904+00 ACC ON push \N \N \N \N \N +3551 865135061563597 stayAlertOn 2026-04-23 12:02:20+00 0101000020E6100000581F0F7D77534240EF3CF19C2DE0F1BF -1.117231 36.652084 \N \N 2026-04-23 12:02:20.884188+00 Idling alert push \N \N \N \N \N +3552 862798050526231 136 2026-04-23 12:02:21+00 0101000020E6100000AB5AD2510ED64340329067976F3D10C0 -4.059996 39.672312 7.00 \N 2026-04-23 12:02:23.12374+00 Power off alert(DVR) push \N \N \N \N \N +3553 359857082910589 1001 2026-04-23 12:02:23+00 0101000020E61000008FFCC1C0737742408AABCABE2B82F2BF -1.15678 36.93322 \N \N 2026-04-23 12:02:23.93126+00 ACC OFF push \N \N \N \N \N +3554 865135061053748 1001 2026-04-23 12:02:23+00 0101000020E61000006346787B10D643401B9C887E6D3D10C0 -4.059988 39.672378 \N \N 2026-04-23 12:02:24.073925+00 ACC OFF push \N \N \N \N \N +3555 359857082910589 1002 2026-04-23 12:02:31+00 0101000020E61000008FFCC1C0737742408AABCABE2B82F2BF -1.15678 36.93322 \N \N 2026-04-23 12:02:31.998096+00 ACC ON push \N \N \N \N \N +3556 865135061053748 1002 2026-04-23 12:02:32+00 0101000020E61000006937FA980FD64340C6DFF604893D10C0 -4.060093 39.672351 \N \N 2026-04-23 12:02:33.10062+00 ACC ON push \N \N \N \N \N +3557 359857081892309 stayAlertOn 2026-04-23 12:02:45+00 0101000020E6100000A089B0E1E971424012A0A696AD75F3BF -1.21623 36.88995 \N \N 2026-04-23 12:02:45.645486+00 Idling alert push \N \N \N \N \N +3558 865135061563597 3 2026-04-23 12:00:01+00 0101000020E61000007E8B4E965A534240F4DE180280E3F1BF -1.118042 36.651202 \N \N 2026-04-23 12:02:51.309831+00 Vibration alert push \N \N \N \N \N +3560 865135061569479 3 2026-04-23 12:03:08+00 0101000020E6100000414AECDADE444040C13BF9F4D896C13F 0.137416 32.538051 22.00 \N 2026-04-23 12:03:10.060714+00 Vibration alert push \N \N \N \N \N +3562 359857082902461 1002 2026-04-23 12:04:10+00 0101000020E6100000EFFE78AF5A494340CBD6FA22A12D0BC0 -3.39728 38.57308 \N \N 2026-04-23 12:04:11.802978+00 ACC ON push \N \N \N \N \N +3563 862798050523527 stayAlertOn 2026-04-23 12:04:13+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 \N \N 2026-04-23 12:04:13.261804+00 Idling alert push \N \N \N \N \N +3565 865135061053748 ACC_ON 2026-04-23 12:02:32+00 0101000020E61000006937FA980FD64340C6DFF604893D10C0 -4.060093 39.672351 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3566 865135061053748 ACC_OFF 2026-04-23 12:02:23+00 0101000020E61000006346787B10D643401B9C887E6D3D10C0 -4.059988 39.672378 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3569 865135061569479 offline 2026-04-23 12:00:00+00 0101000020E6100000F71E2E39EE444040587380608E1EC13F 0.133745 32.53852 0.00 \N 2026-04-23 12:04:20.177607+00 Offline alert poll \N \N \N \N \N +3570 862798052708068 ACC_ON 2026-04-23 12:00:00+00 0101000020E61000004C6BD3D85E534240E964A9F57EE3F1BF -1.118041 36.651332 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3571 862798052708068 stayAlert 2026-04-23 11:59:29+00 0101000020E61000004C6BD3D85E534240E964A9F57EE3F1BF -1.118041 36.651332 0.00 \N 2026-04-23 12:04:20.177607+00 Parking alert poll \N \N \N \N \N +3619 862798050523337 147 2026-04-23 12:03:00+00 0101000020E61000008CDB68006FD9434017821C94300310C0 -4.003115 39.6987 7.00 \N 2026-04-23 12:04:20.177607+00 Collision Alert(DVR) poll \N \N \N \N \N +3621 359857082910589 ACC_ON 2026-04-23 12:02:31+00 0101000020E61000008FFCC1C0737742408AABCABE2B82F2BF -1.15678 36.93322 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3622 359857082910589 ACC_OFF 2026-04-23 12:02:23+00 0101000020E61000008FFCC1C0737742408AABCABE2B82F2BF -1.15678 36.93322 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3623 862798050526231 136 2026-04-23 12:02:23+00 0101000020E6100000AB5AD2510ED64340329067976F3D10C0 -4.059996 39.672312 7.00 \N 2026-04-23 12:04:20.177607+00 Power off alert(DVR) poll \N \N \N \N \N +3625 359857082046145 ACC_ON 2026-04-23 12:01:29+00 0101000020E6100000B8AF03E78CD8434007EBFF1CE60B10C0 -4.01162 39.6918 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3627 359857082038977 ACC_ON 2026-04-23 12:01:13+00 0101000020E61000007E74EACA67D94340BABDA4315A2710C0 -4.03843 39.69848 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3628 359857082046145 ACC_OFF 2026-04-23 12:00:25+00 0101000020E61000007120240B98D843404165FCFB8C0B10C0 -4.01128 39.69214 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3629 359857082910589 ACC_ON 2026-04-23 12:00:12+00 0101000020E61000006C43C5387F774240378E588B4F81F2BF -1.15657 36.93357 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3631 865135061054548 ACC_ON 2026-04-23 11:59:45+00 0101000020E6100000817A336ABE724240B6B9313D6109F3BF -1.18979 36.896436 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3632 865135061054548 ACC_OFF 2026-04-23 11:59:40+00 0101000020E610000005DEC9A7C7724240E8F4BC1B0B0AF3BF -1.189952 36.896718 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3633 862798050523014 ACC_OFF 2026-04-23 11:59:38+00 0101000020E61000000CCA349A5C5242406616A1D80ADAF1BF -1.115733 36.643451 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3634 865135061562847 ACC_OFF 2026-04-23 11:59:27+00 0101000020E61000002B6C06B8208142404F232D95B7A3F1BF -1.10247 37.008811 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3635 359857082897091 ACC_ON 2026-04-23 11:59:14+00 0101000020E6100000AD342905DD724240EFE192E34E69F3BF -1.21321 36.89737 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3720 359857082902461 ACC_ON 2026-04-23 12:04:10+00 0101000020E6100000EFFE78AF5A494340CBD6FA22A12D0BC0 -3.39728 38.57308 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3721 865135061048953 ACC_ON 2026-04-23 12:01:28+00 0101000020E6100000B2BE81C98DD8434029594E42E90B10C0 -4.011632 39.691827 0.00 \N 2026-04-23 12:04:20.177607+00 ACC ON poll \N \N \N \N \N +3722 359857082898008 ACC_OFF 2026-04-23 12:00:34+00 0101000020E610000056B77A4E7A6F4240B2D7BB3FDEABF3BF -1.22946 36.87092 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3723 865135061048953 ACC_OFF 2026-04-23 12:00:21+00 0101000020E6100000B2BE81C98DD8434029594E42E90B10C0 -4.011632 39.691827 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3725 865135061048466 ACC_OFF 2026-04-23 11:59:32+00 0101000020E6100000FA2AF9D85D52424083A5BA8097D9F1BF -1.115623 36.643489 0.00 \N 2026-04-23 12:04:20.177607+00 ACC OFF poll \N \N \N \N \N +3726 862798050523139 146 2026-04-23 11:59:24+00 0101000020E61000004AECDADE6EE94340855CA96741280EC0 -3.769656 39.823696 76.00 \N 2026-04-23 12:04:20.177607+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +3746 359857082902461 1001 2026-04-23 12:04:21+00 0101000020E6100000EFFE78AF5A494340CBD6FA22A12D0BC0 -3.39728 38.57308 \N \N 2026-04-23 12:04:21.868202+00 ACC OFF push \N \N \N \N \N +3747 865135061581904 1001 2026-04-23 12:04:28+00 0101000020E61000000CCC0A45BA554240D49CBCC804BCF3BF -1.233403 36.669747 \N \N 2026-04-23 12:04:28.442461+00 ACC OFF push \N \N \N \N \N +3748 865135061054548 stayAlertOn 2026-04-23 12:04:45+00 0101000020E6100000817A336ABE724240B6B9313D6109F3BF -1.18979 36.896436 \N \N 2026-04-23 12:04:45.742739+00 Idling alert push \N \N \N \N \N +3754 865135061569479 3 2026-04-23 12:05:29+00 0101000020E61000003A048E041A444040B7627FD93D79C03F 0.1287 32.532044 38.00 \N 2026-04-23 12:05:30.555986+00 Vibration alert push \N \N \N \N \N +3755 862798050523626 1002 2026-04-23 12:05:35+00 0101000020E6100000664E97C5C4BC4340A7B228ECA2E80EC0 -3.863592 39.474755 \N \N 2026-04-23 12:05:36.312786+00 ACC ON push \N \N \N \N \N +3756 862798050523626 128 2026-04-23 12:05:45+00 0101000020E6100000213EB0E3BFBC4340B3D0CE6916E80EC0 -3.863324 39.474606 0.00 \N 2026-04-23 12:05:48.387688+00 DVR vibration alert push \N \N \N \N \N +3757 865135061569123 1004 2026-04-23 12:05:54+00 0101000020E61000003CDD79E239634240CD3B4ED191DCF4BF -1.30385 36.775204 \N \N 2026-04-23 12:05:55.010016+00 Parking alert push \N \N \N \N \N +3763 862798050523337 1001 2026-04-23 12:06:24+00 0101000020E6100000FD4E93196FD94340D3A57F492A0310C0 -4.003091 39.698703 \N \N 2026-04-23 12:06:25.62192+00 ACC OFF push \N \N \N \N \N +3764 865135061047435 1002 2026-04-23 12:06:28+00 0101000020E61000004D1421753B5F4240A148F7730A32F4BF -1.262217 36.744002 \N \N 2026-04-23 12:06:29.308746+00 ACC ON push \N \N \N \N \N +3765 359857081892309 1002 2026-04-23 12:06:31+00 0101000020E6100000601F9DBAF27142402EFF21FDF675F3BF -1.2163 36.89022 \N \N 2026-04-23 12:06:32.247467+00 ACC ON push \N \N \N \N \N +3766 865135061569479 2 2026-04-23 12:06:35+00 0101000020E6100000F790F0BDBF434040992D5915E126BF3F 0.121687 32.529289 38.00 \N 2026-04-23 12:06:37.342758+00 Power cut off alert push \N \N \N \N \N +3767 359857082897091 1001 2026-04-23 12:06:43+00 0101000020E6100000B43C0FEECE724240546F0D6C9560F3BF -1.21108 36.89694 \N \N 2026-04-23 12:06:43.963297+00 ACC OFF push \N \N \N \N \N +3768 865135061564470 1001 2026-04-23 12:06:55+00 0101000020E6100000D02A33A5F5714240969526A5A0DBF2BF -1.17862 36.890309 \N \N 2026-04-23 12:06:55.632924+00 ACC OFF push \N \N \N \N \N +3769 865135061053748 1004 2026-04-23 12:07:01+00 0101000020E6100000D97C5C1B2AD64340A7E67283A13E10C0 -4.061163 39.67316 \N \N 2026-04-23 12:07:01.764391+00 Parking alert push \N \N \N \N \N +3772 865135061048276 1002 2026-04-23 12:07:42+00 0101000020E6100000F1D4230D6ED943406612F5824F0310C0 -4.003233 39.698671 \N \N 2026-04-23 12:07:43.038348+00 ACC ON push \N \N \N \N \N +3773 359857082897091 1004 2026-04-23 12:07:43+00 0101000020E6100000B43C0FEECE724240546F0D6C9560F3BF -1.21108 36.89694 \N \N 2026-04-23 12:07:43.151187+00 Parking alert push \N \N \N \N \N +3774 862798050288360 1002 2026-04-23 12:07:44+00 0101000020E6100000F451465C00704240CC41D0D1AA96F3BF -1.224284 36.875011 \N \N 2026-04-23 12:07:45.140789+00 ACC ON push \N \N \N \N \N +3775 359857082911983 1002 2026-04-23 12:07:44+00 0101000020E61000004087F9F2027042402C7DE882FA96F3BF -1.22436 36.87509 \N \N 2026-04-23 12:07:45.208807+00 ACC ON push \N \N \N \N \N +3782 862798050523337 1001 2026-04-23 12:08:47+00 0101000020E6100000FD4E93196FD94340D3A57F492A0310C0 -4.003091 39.698703 \N \N 2026-04-23 12:08:48.6038+00 ACC OFF push \N \N \N \N \N +3783 359857082907973 1002 2026-04-23 12:08:50+00 0101000020E610000055C1A8A44EC0434038842A357B4011C0 -4.31297 39.5024 \N \N 2026-04-23 12:08:50.585479+00 ACC ON push \N \N \N \N \N +3972 865135061569479 3 2026-04-23 12:10:10+00 0101000020E6100000357D76C075434040DB5207793D98BC3F 0.111698 32.527031 \N \N 2026-04-23 12:10:12.427301+00 Vibration alert push \N \N \N \N \N +3973 359857081887192 1001 2026-04-23 12:10:21+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 12:10:21.97883+00 ACC OFF push \N \N \N \N \N +3974 865135061035653 1002 2026-04-23 12:10:39+00 0101000020E61000004DBD6E1118E1434051A5660FB4420FC0 -3.90757 39.758547 \N \N 2026-04-23 12:10:40.635406+00 ACC ON push \N \N \N \N \N +3975 862798050523295 135 2026-04-23 12:10:39+00 0101000020E6100000D09A1F7F697742405FECBDF8A2FDF2BF -1.186923 36.932907 82.00 \N 2026-04-23 12:10:40.893719+00 Overspeed alert(DVR)(82.0km/h) push \N \N \N \N \N +3976 862798050521521 1001 2026-04-23 12:10:45+00 0101000020E61000009468C9E3697D42408C65FA25E22DF2BF -1.136202 36.979794 \N \N 2026-04-23 12:10:46.551076+00 ACC OFF push \N \N \N \N \N +3990 359857082046145 1002 2026-04-23 12:12:01+00 0101000020E6100000B8AF03E78CD8434007EBFF1CE60B10C0 -4.01162 39.6918 \N \N 2026-04-23 12:12:02.158919+00 ACC ON push \N \N \N \N \N +3992 865135061569479 3 2026-04-23 12:12:30+00 0101000020E61000007AFCDEA63F434040A5F78DAF3DB3BC3F 0.11211 32.52538 8.00 \N 2026-04-23 12:12:32.384614+00 Vibration alert push \N \N \N \N \N +3993 865135061048953 1001 2026-04-23 12:12:39+00 0101000020E61000003C9F01F566DA4340D1E638B7090710C0 -4.006873 39.706267 \N \N 2026-04-23 12:12:40.307513+00 ACC OFF push \N \N \N \N \N +3996 359857082902461 1002 2026-04-23 12:13:19+00 0101000020E6100000EFFE78AF5A494340CBD6FA22A12D0BC0 -3.39728 38.57308 \N \N 2026-04-23 12:13:20.364788+00 ACC ON push \N \N \N \N \N +6001 862798052708068 1004 2026-04-23 13:07:33+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 \N \N 2026-04-23 13:07:33.452406+00 Parking alert push \N \N \N \N \N +6004 359857081892309 stayAlertOn 2026-04-23 13:08:03+00 0101000020E6100000F65D11FC6F7142408CD651D50451F3BF -1.20728 36.88623 \N \N 2026-04-23 13:08:03.937896+00 Idling alert push \N \N \N \N \N +6011 359857082910589 1001 2026-04-23 13:08:51+00 0101000020E6100000E89FE0624575424052616C21C841F3BF -1.20356 36.91618 \N \N 2026-04-23 13:08:52.324349+00 ACC OFF push \N \N \N \N \N +6012 359857082910589 1002 2026-04-23 13:09:14+00 0101000020E6100000E89FE0624575424052616C21C841F3BF -1.20356 36.91618 \N \N 2026-04-23 13:09:14.853724+00 ACC ON push \N \N \N \N \N +6013 359857082918012 1002 2026-04-23 13:09:21+00 0101000020E610000046D3D9C9E06C4240850838842AB5F3BF -1.23173 36.85061 \N \N 2026-04-23 13:09:22.379671+00 ACC ON push \N \N \N \N \N +6014 359857082918038 1002 2026-04-23 13:09:22+00 0101000020E6100000691D554D10494340481630815B370BC0 -3.40203 38.57081 \N \N 2026-04-23 13:09:23.208146+00 ACC ON push \N \N \N \N \N +6166 865135061053748 1004 2026-04-23 13:09:37+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 \N \N 2026-04-23 13:09:37.466196+00 Parking alert push \N \N \N \N \N +6167 862798050288212 stayAlertOn 2026-04-23 13:10:17+00 0101000020E6100000D9AF3BDD7970424029EB3713D385F3BF -1.220172 36.878719 \N \N 2026-04-23 13:10:17.747556+00 Idling alert push \N \N \N \N \N +6170 862798050523337 1001 2026-04-23 13:11:18+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 \N \N 2026-04-23 13:11:19.188619+00 ACC OFF push \N \N \N \N \N +6171 359857082042854 1001 2026-04-23 13:11:29+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 \N \N 2026-04-23 13:11:29.570428+00 ACC OFF push \N \N \N \N \N +6172 865135061569131 3 2026-04-23 13:11:45+00 0101000020E61000007670B037314840400951BEA08504AC3F 0.054722 32.564002 \N \N 2026-04-23 13:11:46.92011+00 Vibration alert push \N \N \N \N \N +6173 359857082897257 1001 2026-04-23 13:12:23+00 0101000020E61000000E15E3FC4D784240C993A46B265FF3BF -1.21073 36.93988 \N \N 2026-04-23 13:12:24.431745+00 ACC OFF push \N \N \N \N \N +6174 865135061569123 stayAlertOn 2026-04-23 13:12:25+00 0101000020E61000004E2844C021644240707A17EFC7ADF4BF -1.292427 36.78228 \N \N 2026-04-23 13:12:26.072429+00 Idling alert push \N \N \N \N \N +6175 865135061569131 2 2026-04-23 13:12:38+00 0101000020E61000007670B037314840400951BEA08504AC3F 0.054722 32.564002 \N \N 2026-04-23 13:12:40.485303+00 Power cut off alert push \N \N \N \N \N +6176 865135061564470 stayAlertOn 2026-04-23 13:12:43+00 0101000020E610000018247D5A456742400FB402435637F4BF -1.26351 36.806804 \N \N 2026-04-23 13:12:43.780215+00 Idling alert push \N \N \N \N \N +6177 359857082037185 1002 2026-04-23 13:12:51+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 \N \N 2026-04-23 13:12:51.469166+00 ACC ON push \N \N \N \N \N +6178 865135061569479 1003 2026-04-23 13:13:13+00 0101000020E6100000C85F5AD42743404011397D3D5FB3BC3F 0.112112 32.524653 \N \N 2026-04-23 13:13:14.164844+00 Offline alert push \N \N \N \N \N +6180 359857081891632 1001 2026-04-23 13:14:05+00 0101000020E610000024D6E253007042406553AEF02E97F3BF -1.22441 36.87501 \N \N 2026-04-23 13:14:06.599615+00 ACC OFF push \N \N \N \N \N +6181 865135061569131 3 2026-04-23 13:14:06+00 0101000020E6100000333674B33F48404044FB58C16F43AC3F 0.055202 32.564444 6.00 \N 2026-04-23 13:14:08.147325+00 Vibration alert push \N \N \N \N \N +6182 359857082910589 stayAlertOn 2026-04-23 13:14:14+00 0101000020E6100000E89FE0624575424052616C21C841F3BF -1.20356 36.91618 \N \N 2026-04-23 13:14:14.742696+00 Idling alert push \N \N \N \N \N +6183 862798050523337 1002 2026-04-23 13:14:15+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 \N \N 2026-04-23 13:14:15.910041+00 ACC ON push \N \N \N \N \N +6184 865135061048276 1002 2026-04-23 13:14:17+00 0101000020E6100000959BA8A5B9D943403F90BC73280310C0 -4.003084 39.700978 \N \N 2026-04-23 13:14:17.787561+00 ACC ON push \N \N \N \N \N +6185 359857082918038 1001 2026-04-23 13:14:21+00 0101000020E6100000691D554D10494340481630815B370BC0 -3.40203 38.57081 \N \N 2026-04-23 13:14:22.310394+00 ACC OFF push \N \N \N \N \N +6186 359857081892309 1001 2026-04-23 13:14:22+00 0101000020E6100000931804560E714240B1C403CAA65CF3BF -1.21012 36.88325 \N \N 2026-04-23 13:14:23.459811+00 ACC OFF push \N \N \N \N \N +6343 359857081891632 1004 2026-04-23 13:15:05+00 0101000020E610000024D6E253007042406553AEF02E97F3BF -1.22441 36.87501 \N \N 2026-04-23 13:15:06.1535+00 Parking alert push \N \N \N \N \N +6344 865135061562847 1002 2026-04-23 13:15:09+00 0101000020E61000002541B8020A814240B2F50CE198A5F1BF -1.102929 37.008118 \N \N 2026-04-23 13:15:10.876993+00 ACC ON push \N \N \N \N \N +6345 862798052708068 1002 2026-04-23 13:15:36+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 \N \N 2026-04-23 13:15:36.722912+00 ACC ON push \N \N \N \N \N +6347 359857082897257 1002 2026-04-23 13:15:56+00 0101000020E61000000E15E3FC4D784240C993A46B265FF3BF -1.21073 36.93988 \N \N 2026-04-23 13:15:57.391564+00 ACC ON push \N \N \N \N \N +6348 865135061037980 1001 2026-04-23 13:16:01+00 0101000020E6100000D82E6D382C6142402B4F20EC146BF4BF -1.276143 36.759162 \N \N 2026-04-23 13:16:02.518337+00 ACC OFF push \N \N \N \N \N +6349 862798050523295 1001 2026-04-23 13:16:03+00 0101000020E6100000E4DC26DC2B614240983446EBA86AF4BF -1.27604 36.759151 \N \N 2026-04-23 13:16:04.155898+00 ACC OFF push \N \N \N \N \N +6352 862798050523014 1001 2026-04-23 13:16:21+00 0101000020E610000071C63027685342409D67EC4B36DEF1BF -1.116751 36.651616 \N \N 2026-04-23 13:16:21.979229+00 ACC OFF push \N \N \N \N \N +6353 865135061569131 3 2026-04-23 13:16:27+00 0101000020E610000031EC3026FD474040419E5DBEF561AD3F 0.057388 32.562413 6.00 \N 2026-04-23 13:16:28.863778+00 Vibration alert push \N \N \N \N \N +6354 865135061035653 1002 2026-04-23 13:16:28+00 0101000020E61000004C1762F547E04340C4B0C398F4970FC0 -3.949197 39.752196 \N \N 2026-04-23 13:16:29.320685+00 ACC ON push \N \N \N \N \N +6355 865135061037980 1004 2026-04-23 13:17:01+00 0101000020E6100000D82E6D382C6142402B4F20EC146BF4BF -1.276143 36.759162 \N \N 2026-04-23 13:17:02.013333+00 Parking alert push \N \N \N \N \N +6914 862798050523014 128 2026-04-23 13:33:14+00 0101000020E6100000F06C8FDE7053424086730D3334DEF1BF -1.116749 36.651882 0.00 \N 2026-04-23 13:34:36.40955+00 DVR vibration alert poll \N \N \N \N \N +6916 359857082897091 stayAlert 2026-04-23 13:32:38+00 0101000020E61000005721E527D5724240CBDB114E0B5EF3BF -1.21046 36.89713 0.00 \N 2026-04-23 13:34:36.40955+00 Parking alert poll \N \N \N \N \N +6917 359857081891632 ACC_ON 2026-04-23 13:32:36+00 0101000020E610000047551344DD6F42409291B3B0A79DF3BF -1.22599 36.87394 0.00 \N 2026-04-23 13:34:36.40955+00 ACC ON poll \N \N \N \N \N +6918 865135061054548 ACC_ON 2026-04-23 13:32:21+00 0101000020E6100000CBD93BA3AD724240261E5036E50AF3BF -1.19016 36.895924 0.00 \N 2026-04-23 13:34:36.40955+00 ACC ON poll \N \N \N \N \N +6919 359857082896911 ACC_OFF 2026-04-23 13:31:50+00 0101000020E61000004CA60A46256942403F8C101E6D9CF2BF -1.16319 36.82145 0.00 \N 2026-04-23 13:34:36.40955+00 ACC OFF poll \N \N \N \N \N +6920 862798052707946 ACC_OFF 2026-04-23 13:31:18+00 0101000020E61000007E6FD39FFD7642402B2FF99FFC1DF3BF -1.194821 36.929615 0.00 \N 2026-04-23 13:34:36.40955+00 ACC OFF poll \N \N \N \N \N +6922 862798052707946 ACC_ON 2026-04-23 13:29:51+00 0101000020E61000001B6327BC04774240D89DEE3CF11CF3BF -1.194566 36.929832 0.00 \N 2026-04-23 13:34:36.40955+00 ACC ON poll \N \N \N \N \N +3786 865135061564470 stayAlert 2026-04-23 12:07:54+00 0101000020E6100000E49F19C4077242401BD6541685DDF2BF -1.179082 36.890862 0.00 \N 2026-04-23 12:09:21.044173+00 Parking alert poll \N \N \N \N \N +3788 865135061053748 stayAlert 2026-04-23 12:07:01+00 0101000020E6100000D97C5C1B2AD64340A7E67283A13E10C0 -4.061163 39.67316 0.00 \N 2026-04-23 12:09:21.044173+00 Parking alert poll \N \N \N \N \N +3789 865135061564470 ACC_OFF 2026-04-23 12:06:55+00 0101000020E6100000D02A33A5F5714240969526A5A0DBF2BF -1.17862 36.890309 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3791 865135061047435 ACC_ON 2026-04-23 12:06:28+00 0101000020E61000004D1421753B5F4240A148F7730A32F4BF -1.262217 36.744002 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3792 862798052708068 stayAlert 2026-04-23 12:06:13+00 0101000020E6100000BBF083F3A953424033DC80CF0FE3F1BF -1.117935 36.653624 0.00 \N 2026-04-23 12:09:21.044173+00 Parking alert poll \N \N \N \N \N +3793 865135061581904 stayAlert 2026-04-23 12:06:06+00 0101000020E6100000A8FFACF9F1554240768BC058DFC0F3BF -1.234588 36.671447 0.00 \N 2026-04-23 12:09:21.044173+00 Parking alert poll \N \N \N \N \N +3794 865135061053748 ACC_OFF 2026-04-23 12:06:01+00 0101000020E61000006F62484E26D643405E13D21A833E10C0 -4.061047 39.673044 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3795 865135061569123 stayAlert 2026-04-23 12:05:54+00 0101000020E61000003CDD79E239634240CD3B4ED191DCF4BF -1.30385 36.775204 0.00 \N 2026-04-23 12:09:21.044173+00 Parking alert poll \N \N \N \N \N +3797 862798052708068 ACC_OFF 2026-04-23 12:05:13+00 0101000020E6100000BBF083F3A953424033DC80CF0FE3F1BF -1.117935 36.653624 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3798 865135061569123 ACC_OFF 2026-04-23 12:04:57+00 0101000020E61000009D47C5FF1D634240894160E5D0E2F4BF -1.305375 36.774353 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3799 865135061581904 ACC_ON 2026-04-23 12:04:52+00 0101000020E6100000A8FFACF9F1554240768BC058DFC0F3BF -1.234588 36.671447 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3800 865135061581904 ACC_OFF 2026-04-23 12:04:28+00 0101000020E61000000CCC0A45BA554240D49CBCC804BCF3BF -1.233403 36.669747 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3842 359857082907973 ACC_ON 2026-04-23 12:08:50+00 0101000020E610000055C1A8A44EC0434038842A357B4011C0 -4.31297 39.5024 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3843 862798050523337 ACC_OFF 2026-04-23 12:08:47+00 0101000020E6100000FD4E93196FD94340D3A57F492A0310C0 -4.003091 39.698703 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3844 359857081887192 ACC_ON 2026-04-23 12:08:00+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3845 862798050288360 ACC_ON 2026-04-23 12:07:44+00 0101000020E6100000F451465C00704240CC41D0D1AA96F3BF -1.224284 36.875011 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3846 359857082911983 ACC_ON 2026-04-23 12:07:44+00 0101000020E61000004087F9F2027042402C7DE882FA96F3BF -1.22436 36.87509 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3847 359857082897091 stayAlert 2026-04-23 12:07:43+00 0101000020E6100000B43C0FEECE724240546F0D6C9560F3BF -1.21108 36.89694 0.00 \N 2026-04-23 12:09:21.044173+00 Parking alert poll \N \N \N \N \N +3848 862798050523337 ACC_ON 2026-04-23 12:07:32+00 0101000020E6100000FD4E93196FD94340D3A57F492A0310C0 -4.003091 39.698703 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3849 359857082897091 ACC_OFF 2026-04-23 12:06:43+00 0101000020E6100000B43C0FEECE724240546F0D6C9560F3BF -1.21108 36.89694 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3850 359857081892309 ACC_ON 2026-04-23 12:06:31+00 0101000020E6100000601F9DBAF27142402EFF21FDF675F3BF -1.2163 36.89022 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3851 862798050523337 ACC_OFF 2026-04-23 12:06:24+00 0101000020E6100000FD4E93196FD94340D3A57F492A0310C0 -4.003091 39.698703 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3852 865135061054555 ACC_OFF 2026-04-23 12:06:12+00 0101000020E6100000AA436E861B30424064B14D2A1A6BD1BF -0.272162 36.37584 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3853 862798050523626 128 2026-04-23 12:05:46+00 0101000020E6100000213EB0E3BFBC4340B3D0CE6916E80EC0 -3.863324 39.474606 0.00 \N 2026-04-23 12:09:21.044173+00 DVR vibration alert poll \N \N \N \N \N +3854 862798050523626 ACC_ON 2026-04-23 12:05:35+00 0101000020E6100000664E97C5C4BC4340A7B228ECA2E80EC0 -3.863592 39.474755 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3855 359857082910589 ACC_ON 2026-04-23 12:05:17+00 0101000020E61000008FFCC1C0737742408AABCABE2B82F2BF -1.15678 36.93322 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3856 865135061563597 ACC_OFF 2026-04-23 12:05:12+00 0101000020E61000000684D6C397534240E2067C7E18E1F1BF -1.117455 36.653069 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3944 359857082918038 ACC_ON 2026-04-23 12:09:05+00 0101000020E61000008C4AEA0434494340BF9A030473340BC0 -3.40061 38.5719 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3945 865135061048276 ACC_OFF 2026-04-23 12:08:27+00 0101000020E6100000F1D4230D6ED943406612F5824F0310C0 -4.003233 39.698671 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3946 862798050523139 146 2026-04-23 12:08:22+00 0101000020E6100000079ACFB9DBE743409C6F44F7AC8B0DC0 -3.693201 39.811393 63.00 \N 2026-04-23 12:09:21.044173+00 Sharp Turn Alert(DVR) poll \N \N \N \N \N +3947 865135061035133 ACC_ON 2026-04-23 12:07:55+00 0101000020E6100000AA0D4E44BFBC43409C16BCE82BE80EC0 -3.863365 39.474587 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3948 865135061048276 ACC_ON 2026-04-23 12:07:42+00 0101000020E6100000F1D4230D6ED943406612F5824F0310C0 -4.003233 39.698671 0.00 \N 2026-04-23 12:09:21.044173+00 ACC ON poll \N \N \N \N \N +3949 865135061048276 ACC_OFF 2026-04-23 12:06:04+00 0101000020E6100000EF38454772D94340C7D45DD9050310C0 -4.002952 39.6988 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3950 359857082902461 ACC_OFF 2026-04-23 12:04:21+00 0101000020E6100000EFFE78AF5A494340CBD6FA22A12D0BC0 -3.39728 38.57308 0.00 \N 2026-04-23 12:09:21.044173+00 ACC OFF poll \N \N \N \N \N +3997 865135061054555 1001 2026-04-23 12:14:13+00 0101000020E610000009C03FA54A304240C7832D76FBACD1BF -0.276183 36.377278 \N \N 2026-04-23 12:14:14.172074+00 ACC OFF push \N \N \N \N \N +3999 865135061035778 stayAlert 2026-04-23 12:11:44+00 0101000020E61000004089CF9D607D4240CBD6FA22A12DF2BF -1.13614 36.979511 0.00 \N 2026-04-23 12:14:21.942944+00 Parking alert poll \N \N \N \N \N +4000 862798050525423 ACC_ON 2026-04-23 12:11:12+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4001 862798050525423 ACC_OFF 2026-04-23 12:10:56+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4002 865135061035778 ACC_OFF 2026-04-23 12:10:52+00 0101000020E6100000CEFE40B96D7D424091D09673292EF2BF -1.13627 36.979911 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4004 865135061564470 ACC_ON 2026-04-23 12:09:28+00 0101000020E6100000E49F19C4077242401BD6541685DDF2BF -1.179082 36.890862 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4047 865135061054555 ACC_OFF 2026-04-23 12:14:13+00 0101000020E610000009C03FA54A304240C7832D76FBACD1BF -0.276183 36.377278 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4048 862798050523527 ACC_OFF 2026-04-23 12:13:11+00 0101000020E61000001118EB1B9872424025C9737D1F0EF3BF -1.190948 36.895267 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4049 359857082037185 ACC_ON 2026-04-23 12:13:09+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4050 862798050523626 ACC_OFF 2026-04-23 12:12:23+00 0101000020E61000003A933655F7BC434096CCB1BCABDE0EC0 -3.858726 39.476298 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4051 359857082046145 ACC_ON 2026-04-23 12:12:01+00 0101000020E6100000B8AF03E78CD8434007EBFF1CE60B10C0 -4.01162 39.6918 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4052 865135061035653 ACC_OFF 2026-04-23 12:11:55+00 0101000020E6100000C100C28712E143406B60AB048B430FC0 -3.90798 39.758378 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4055 865135061054555 ACC_ON 2026-04-23 12:11:27+00 0101000020E6100000F9484A7A183042401492CCEA1D6ED1BF -0.272346 36.375747 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4056 359857082046145 ACC_OFF 2026-04-23 12:11:22+00 0101000020E6100000B8AF03E78CD8434007EBFF1CE60B10C0 -4.01162 39.6918 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4057 359857082897737 ACC_ON 2026-04-23 12:11:09+00 0101000020E6100000B471C45A7CDE43401CD3139678C00FC0 -3.96898 39.73817 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4058 359857082896911 ACC_ON 2026-04-23 12:11:01+00 0101000020E6100000E1404816306D4240E88711C2A30DF3BF -1.19083 36.85303 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4059 359857082897737 ACC_OFF 2026-04-23 12:10:58+00 0101000020E6100000919BE1067CDE43401CD3139678C00FC0 -3.96898 39.73816 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4060 862798050521521 ACC_OFF 2026-04-23 12:10:45+00 0101000020E61000009468C9E3697D42408C65FA25E22DF2BF -1.136202 36.979794 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4061 865135061035653 ACC_ON 2026-04-23 12:10:39+00 0101000020E61000004DBD6E1118E1434051A5660FB4420FC0 -3.90757 39.758547 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4062 359857081887192 ACC_OFF 2026-04-23 12:10:21+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4150 359857082902461 ACC_ON 2026-04-23 12:13:19+00 0101000020E6100000EFFE78AF5A494340CBD6FA22A12D0BC0 -3.39728 38.57308 0.00 \N 2026-04-23 12:14:21.942944+00 ACC ON poll \N \N \N \N \N +4151 865135061048953 ACC_OFF 2026-04-23 12:12:39+00 0101000020E61000003C9F01F566DA4340D1E638B7090710C0 -4.006873 39.706267 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4152 865135061035133 ACC_OFF 2026-04-23 12:11:41+00 0101000020E610000045D95BCAF9BC4340A7C98CB795DE0EC0 -3.858684 39.476373 0.00 \N 2026-04-23 12:14:21.942944+00 ACC OFF poll \N \N \N \N \N +4153 862798050523295 135 2026-04-23 12:10:40+00 0101000020E6100000D09A1F7F697742405FECBDF8A2FDF2BF -1.186923 36.932907 82.00 \N 2026-04-23 12:14:21.942944+00 Overspeed alert(DVR) poll \N \N \N \N \N +4177 359857082042854 1001 2026-04-23 12:14:50+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 \N \N 2026-04-23 12:14:51.569542+00 ACC OFF push \N \N \N \N \N +4180 865135061569479 3 2026-04-23 12:15:31+00 0101000020E6100000C85F5AD42743404011397D3D5FB3BC3F 0.112112 32.524653 \N \N 2026-04-23 12:15:32.405722+00 Vibration alert push \N \N \N \N \N +4182 865135061563282 1001 2026-04-23 12:16:00+00 0101000020E61000006BD619DF174540402CF2EB87D860C93F 0.198268 32.539791 \N \N 2026-04-23 12:16:00.871925+00 ACC OFF push \N \N \N \N \N +4185 865135061569479 1004 2026-04-23 12:16:51+00 0101000020E610000038F581E49D434040228B34F10EF0BC3F 0.113038 32.528256 \N \N 2026-04-23 12:16:51.648702+00 Parking alert push \N \N \N \N \N +4186 865135061563639 1004 2026-04-23 12:16:53+00 0101000020E6100000C30FCEA78EED4240E068C70DBFDBFABF -1.678649 37.855916 \N \N 2026-04-23 12:16:53.238639+00 Parking alert push \N \N \N \N \N +4188 862798050523295 135 2026-04-23 12:17:14+00 0101000020E6100000C74ACCB392704240CC6262F371ADF3BF -1.229845 36.879477 83.00 \N 2026-04-23 12:17:16.799953+00 Overspeed alert(DVR)(83.0km/h) push \N \N \N \N \N +4189 359857082898016 stayAlertOn 2026-04-23 12:17:25+00 0101000020E610000002B7EEE6A9DA434062D68BA19CE80FC0 -3.98858 39.70831 \N \N 2026-04-23 12:17:25.221111+00 Idling alert push \N \N \N \N \N +4190 359857081892101 1002 2026-04-23 12:17:26+00 0101000020E6100000A2EE0390DA644240F2CD3637A6A7F4BF -1.29093 36.78792 \N \N 2026-04-23 12:17:27.724433+00 ACC ON push \N \N \N \N \N +4191 865135061035653 stayAlertOn 2026-04-23 12:17:27+00 0101000020E6100000698B6B7C26E143402654707841440FC0 -3.908328 39.758987 \N \N 2026-04-23 12:17:27.800251+00 Idling alert push \N \N \N \N \N +4192 865135061563597 3 2026-04-23 12:15:19+00 0101000020E61000004815C5ABAC534240828E56B5A4E3F1BF -1.118077 36.653707 \N \N 2026-04-23 12:17:37.572464+00 Vibration alert push \N \N \N \N \N +4194 865135061569479 3 2026-04-23 12:18:20+00 0101000020E6100000C85F5AD42743404011397D3D5FB3BC3F 0.112112 32.524653 \N \N 2026-04-23 12:18:22.285464+00 Vibration alert push \N \N \N \N \N +4195 865135061563639 3 2026-04-23 12:18:23+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 \N \N 2026-04-23 12:18:25.022665+00 Vibration alert push \N \N \N \N \N +4200 359857082910589 1001 2026-04-23 12:19:04+00 0101000020E6100000D4B7CCE9B27842401CB62DCA6C90F2BF -1.16026 36.94296 \N \N 2026-04-23 12:19:04.691654+00 ACC OFF push \N \N \N \N \N +4201 862798050525423 1001 2026-04-23 12:19:14+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 \N \N 2026-04-23 12:19:14.84519+00 ACC OFF push \N \N \N \N \N +4202 359857082897737 1001 2026-04-23 12:19:17+00 0101000020E6100000B471C45A7CDE4340543541D47DC00FC0 -3.96899 39.73817 \N \N 2026-04-23 12:19:17.913977+00 ACC OFF push \N \N \N \N \N +4203 862798050525423 ACC_OFF 2026-04-23 12:19:14+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4204 865135061563639 ACC_OFF 2026-04-23 12:18:57+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4205 865135061563639 ACC_ON 2026-04-23 12:18:51+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 0.00 \N 2026-04-23 12:19:22.870501+00 ACC ON poll \N \N \N \N \N +4208 865135061563639 stayAlert 2026-04-23 12:16:53+00 0101000020E6100000C30FCEA78EED4240E068C70DBFDBFABF -1.678649 37.855916 0.00 \N 2026-04-23 12:19:22.870501+00 Parking alert poll \N \N \N \N \N +4209 865135061569479 stayAlert 2026-04-23 12:16:51+00 0101000020E610000038F581E49D434040228B34F10EF0BC3F 0.113038 32.528256 0.00 \N 2026-04-23 12:19:22.870501+00 Parking alert poll \N \N \N \N \N +4211 865135061563282 ACC_OFF 2026-04-23 12:16:00+00 0101000020E61000006BD619DF174540402CF2EB87D860C93F 0.198268 32.539791 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4212 865135061563639 ACC_OFF 2026-04-23 12:15:53+00 0101000020E6100000C30FCEA78EED4240E068C70DBFDBFABF -1.678649 37.855916 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4214 862798052708068 128 2026-04-23 12:15:19+00 0101000020E6100000BBF083F3A953424033DC80CF0FE3F1BF -1.117935 36.653624 0.00 \N 2026-04-23 12:19:22.870501+00 DVR vibration alert poll \N \N \N \N \N +4257 359857082897737 ACC_OFF 2026-04-23 12:19:17+00 0101000020E6100000B471C45A7CDE4340543541D47DC00FC0 -3.96899 39.73817 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4258 359857082910589 ACC_OFF 2026-04-23 12:19:04+00 0101000020E6100000D4B7CCE9B27842401CB62DCA6C90F2BF -1.16026 36.94296 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4259 359857081887192 ACC_ON 2026-04-23 12:18:55+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 0.00 \N 2026-04-23 12:19:22.870501+00 ACC ON poll \N \N \N \N \N +4260 359857082907973 ACC_OFF 2026-04-23 12:18:41+00 0101000020E61000001C25AFCE31BC4340986E1283C04A11C0 -4.323 39.47027 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4261 359857081892309 ACC_OFF 2026-04-23 12:18:15+00 0101000020E6100000B515FBCBEE71424067EDB60BCD75F3BF -1.21626 36.8901 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4263 359857081892101 ACC_ON 2026-04-23 12:17:26+00 0101000020E6100000A2EE0390DA644240F2CD3637A6A7F4BF -1.29093 36.78792 0.00 \N 2026-04-23 12:19:22.870501+00 ACC ON poll \N \N \N \N \N +4264 359857082898487 ACC_OFF 2026-04-23 12:17:06+00 0101000020E610000032207BBDFB7B424052616C21C8C1F2BF -1.17231 36.96862 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4266 359857082898487 ACC_ON 2026-04-23 12:15:24+00 0101000020E6100000397F130A117C424034A2B437F8C2F2BF -1.1726 36.96927 0.00 \N 2026-04-23 12:19:22.870501+00 ACC ON poll \N \N \N \N \N +4268 359857082042854 ACC_OFF 2026-04-23 12:14:50+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 0.00 \N 2026-04-23 12:19:22.870501+00 ACC OFF poll \N \N \N \N \N +4356 862798050523295 135 2026-04-23 12:17:15+00 0101000020E6100000C74ACCB392704240CC6262F371ADF3BF -1.229845 36.879477 83.00 \N 2026-04-23 12:19:22.870501+00 Overspeed alert(DVR) poll \N \N \N \N \N +6179 862798050523337 stayAlertOn 2026-04-23 13:13:28+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 \N \N 2026-04-23 13:13:28.895113+00 Idling alert push \N \N \N \N \N +6187 359857082912239 1002 2026-04-23 13:14:30+00 0101000020E6100000F775E09C11494340658D7A8846370BC0 -3.40199 38.57085 \N \N 2026-04-23 13:14:30.916242+00 ACC ON push \N \N \N \N \N +6188 862798052708068 128 2026-04-23 13:14:30+00 0101000020E61000007573F1B73D534240F4A78DEA74E0F1BF -1.117299 36.650321 0.00 \N 2026-04-23 13:14:31.122742+00 DVR vibration alert push \N \N \N \N \N +6189 865135061563597 3 2026-04-23 13:14:30+00 0101000020E6100000588E90813C5342401B81785DBFE0F1BF -1.11737 36.650284 \N \N 2026-04-23 13:14:32.019595+00 Vibration alert push \N \N \N \N \N +6346 359857082910589 1002 2026-04-23 13:15:49+00 0101000020E6100000AF946588637542405001309E4143F3BF -1.20392 36.9171 \N \N 2026-04-23 13:15:50.176946+00 ACC ON push \N \N \N \N \N +6350 865135061048466 1001 2026-04-23 13:16:15+00 0101000020E610000053CA6B2574534240252026E142DEF1BF -1.116763 36.651982 \N \N 2026-04-23 13:16:16.285193+00 ACC OFF push \N \N \N \N \N +6351 862798050525423 1004 2026-04-23 13:16:16+00 0101000020E61000001D39D21918DB4340ACE5CE4C30FC0FC0 -3.998139 39.711673 \N \N 2026-04-23 13:16:16.75393+00 Parking alert push \N \N \N \N \N +6356 359857082896911 1002 2026-04-23 13:17:14+00 0101000020E61000002310AFEB176C4240E09C11A5BDC1F2BF -1.1723 36.84448 \N \N 2026-04-23 13:17:14.84865+00 ACC ON push \N \N \N \N \N +6357 359857081887069 1002 2026-04-23 13:17:20+00 0101000020E6100000DD989EB0C4774240E9263108AC1CF3BF -1.1945 36.93569 \N \N 2026-04-23 13:17:21.241761+00 ACC ON push \N \N \N \N \N +6982 862798050523626 ACC_ON 2026-04-23 13:33:26+00 0101000020E6100000FA804067D2C24340228C9FC6BD590CC0 -3.543819 39.522046 0.00 \N 2026-04-23 13:34:36.40955+00 ACC ON poll \N \N \N \N \N +6983 862798050523626 ACC_OFF 2026-04-23 13:32:27+00 0101000020E6100000FA804067D2C24340228C9FC6BD590CC0 -3.543819 39.522046 0.00 \N 2026-04-23 13:34:36.40955+00 ACC OFF poll \N \N \N \N \N +6984 865135061035133 ACC_OFF 2026-04-23 13:32:06+00 0101000020E6100000179AEB34D2C243407D224F92AE590CC0 -3.54379 39.52204 0.00 \N 2026-04-23 13:34:36.40955+00 ACC OFF poll \N \N \N \N \N +4178 862798052708068 128 2026-04-23 12:15:18+00 0101000020E6100000BBF083F3A953424033DC80CF0FE3F1BF -1.117935 36.653624 0.00 \N 2026-04-23 12:15:20.70427+00 DVR vibration alert push \N \N \N \N \N +4179 359857082898487 1002 2026-04-23 12:15:24+00 0101000020E6100000397F130A117C424034A2B437F8C2F2BF -1.1726 36.96927 \N \N 2026-04-23 12:15:25.041999+00 ACC ON push \N \N \N \N \N +4181 865135061563639 1001 2026-04-23 12:15:53+00 0101000020E6100000C30FCEA78EED4240E068C70DBFDBFABF -1.678649 37.855916 \N \N 2026-04-23 12:15:53.888871+00 ACC OFF push \N \N \N \N \N +4183 359857082897737 stayAlertOn 2026-04-23 12:16:09+00 0101000020E6100000B471C45A7CDE43401CD3139678C00FC0 -3.96898 39.73817 \N \N 2026-04-23 12:16:09.157058+00 Idling alert push \N \N \N \N \N +4184 862798050525423 stayAlertOn 2026-04-23 12:16:12+00 0101000020E6100000E99B340D8ADE434060E97C7896C00FC0 -3.969037 39.738588 \N \N 2026-04-23 12:16:12.34345+00 Idling alert push \N \N \N \N \N +4187 359857082898487 1001 2026-04-23 12:17:06+00 0101000020E610000032207BBDFB7B424052616C21C8C1F2BF -1.17231 36.96862 \N \N 2026-04-23 12:17:07.07515+00 ACC OFF push \N \N \N \N \N +4193 359857081892309 1001 2026-04-23 12:18:15+00 0101000020E6100000B515FBCBEE71424067EDB60BCD75F3BF -1.21626 36.8901 \N \N 2026-04-23 12:18:15.635848+00 ACC OFF push \N \N \N \N \N +4196 359857082907973 1001 2026-04-23 12:18:41+00 0101000020E61000001C25AFCE31BC4340986E1283C04A11C0 -4.323 39.47027 \N \N 2026-04-23 12:18:41.6277+00 ACC OFF push \N \N \N \N \N +4197 865135061563639 1002 2026-04-23 12:18:51+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 \N \N 2026-04-23 12:18:51.860787+00 ACC ON push \N \N \N \N \N +4198 359857081887192 1002 2026-04-23 12:18:55+00 0101000020E61000006F2A52616CD943409D8026C2862710C0 -4.0386 39.69862 \N \N 2026-04-23 12:18:56.13835+00 ACC ON push \N \N \N \N \N +4199 865135061563639 1001 2026-04-23 12:18:57+00 0101000020E6100000580229B16BED424096CB46E7FCD4FABF -1.676999 37.854849 \N \N 2026-04-23 12:18:57.819336+00 ACC OFF push \N \N \N \N \N +6191 865135061569479 offline 2026-04-23 13:13:13+00 0101000020E6100000C85F5AD42743404011397D3D5FB3BC3F 0.112112 32.524653 0.00 \N 2026-04-23 13:14:32.648974+00 Offline alert poll \N \N \N \N \N +6196 865135061053748 stayAlert 2026-04-23 13:09:37+00 0101000020E6100000FD2FD7A205D443408D7F9F71E13010C0 -4.047735 39.656422 0.00 \N 2026-04-23 13:14:32.648974+00 Parking alert poll \N \N \N \N \N +6231 359857081892309 ACC_OFF 2026-04-23 13:14:22+00 0101000020E6100000931804560E714240B1C403CAA65CF3BF -1.21012 36.88325 0.00 \N 2026-04-23 13:14:32.648974+00 ACC OFF poll \N \N \N \N \N +6232 862798050523337 ACC_ON 2026-04-23 13:14:15+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 0.00 \N 2026-04-23 13:14:32.648974+00 ACC ON poll \N \N \N \N \N +6234 359857081891632 ACC_OFF 2026-04-23 13:14:05+00 0101000020E610000024D6E253007042406553AEF02E97F3BF -1.22441 36.87501 0.00 \N 2026-04-23 13:14:32.648974+00 ACC OFF poll \N \N \N \N \N +6236 359857082037185 ACC_ON 2026-04-23 13:12:51+00 0101000020E61000007632384A5ED94340D734EF38452710C0 -4.03835 39.69819 0.00 \N 2026-04-23 13:14:32.648974+00 ACC ON poll \N \N \N \N \N +6237 359857082897257 ACC_OFF 2026-04-23 13:12:23+00 0101000020E61000000E15E3FC4D784240C993A46B265FF3BF -1.21073 36.93988 0.00 \N 2026-04-23 13:14:32.648974+00 ACC OFF poll \N \N \N \N \N +6238 359857082042854 ACC_OFF 2026-04-23 13:11:29+00 0101000020E61000000E10CCD1E3DB43403D2CD49AE69D0DC0 -3.7021 39.71789 0.00 \N 2026-04-23 13:14:32.648974+00 ACC OFF poll \N \N \N \N \N +6239 862798050523337 ACC_OFF 2026-04-23 13:11:18+00 0101000020E61000006C5F402FDCD94340BCEB6CC83F0310C0 -4.003173 39.702032 0.00 \N 2026-04-23 13:14:32.648974+00 ACC OFF poll \N \N \N \N \N +6321 359857082918038 ACC_OFF 2026-04-23 13:14:21+00 0101000020E6100000691D554D10494340481630815B370BC0 -3.40203 38.57081 0.00 \N 2026-04-23 13:14:32.648974+00 ACC OFF poll \N \N \N \N \N +6322 865135061048276 ACC_ON 2026-04-23 13:14:17+00 0101000020E6100000959BA8A5B9D943403F90BC73280310C0 -4.003084 39.700978 0.00 \N 2026-04-23 13:14:32.648974+00 ACC ON poll \N \N \N \N \N +6323 359857082898008 ACC_OFF 2026-04-23 13:11:00+00 0101000020E6100000475A2A6F47704240200C3CF71EAEF3BF -1.23001 36.87718 0.00 \N 2026-04-23 13:14:32.648974+00 ACC OFF poll \N \N \N \N \N +6324 865135061048276 ACC_OFF 2026-04-23 13:10:58+00 0101000020E6100000959BA8A5B9D943403F90BC73280310C0 -4.003084 39.700978 0.00 \N 2026-04-23 13:14:32.648974+00 ACC OFF poll \N \N \N \N \N +7006 862798052708068 128 2026-04-23 13:35:23+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 0.00 \N 2026-04-23 13:35:23.878995+00 DVR vibration alert push \N \N \N \N \N +7007 359857082908500 1002 2026-04-23 13:35:27+00 0101000020E6100000EFE6A90EB9914340FFCF61BEBC6011C0 -4.34447 39.13846 \N \N 2026-04-23 13:35:28.019411+00 ACC ON push \N \N \N \N \N +7008 862798050288345 1002 2026-04-23 13:35:27+00 0101000020E6100000D78A36C7B99143400A849D62D56011C0 -4.344564 39.138482 \N \N 2026-04-23 13:35:28.129385+00 ACC ON push \N \N \N \N \N +7010 359857082912239 1002 2026-04-23 13:35:54+00 0101000020E6100000857CD0B359494340FD304278B4310BC0 -3.39927 38.57305 \N \N 2026-04-23 13:35:54.589969+00 ACC ON push \N \N \N \N \N +7011 359857082897091 1001 2026-04-23 13:36:50+00 0101000020E61000006DCA15DEE572424062670A9DD758F3BF -1.20919 36.89764 \N \N 2026-04-23 13:36:51.378206+00 ACC OFF push \N \N \N \N \N +7012 865135061564470 1001 2026-04-23 13:36:52+00 0101000020E6100000DE8D0585415D42400742B28009DCF3BF -1.24122 36.728562 \N \N 2026-04-23 13:36:53.190129+00 ACC OFF push \N \N \N \N \N +7013 359857081892101 1002 2026-04-23 13:37:02+00 0101000020E6100000744694F606634240A3586E6935A4F4BF -1.29009 36.77365 \N \N 2026-04-23 13:37:03.935059+00 ACC ON push \N \N \N \N \N +7014 865135061563597 3 2026-04-23 13:36:35+00 0101000020E6100000B88FDC9A745342408C6A11514CDEF1BF -1.116772 36.651996 \N \N 2026-04-23 13:37:04.094538+00 Vibration alert push \N \N \N \N \N +7015 865135061569131 3 2026-04-23 13:37:31+00 0101000020E610000000581D39D243404092AE997CB3CDB93F 0.100795 32.529853 27.00 \N 2026-04-23 13:37:33.047062+00 Vibration alert push \N \N \N \N \N +7020 865135061569123 3 2026-04-23 13:35:10+00 0101000020E61000004374081C09664240EED0B01875ADF4BF -1.292348 36.797153 \N \N 2026-04-23 13:38:21.108237+00 Vibration alert push \N \N \N \N \N +7022 865135061053748 1002 2026-04-23 13:38:58+00 0101000020E61000001F662FDB4ED343404354E1CFF03610C0 -4.053653 39.650844 \N \N 2026-04-23 13:38:58.523495+00 ACC ON push \N \N \N \N \N +7023 359857081891566 1001 2026-04-23 13:39:14+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 13:39:16.024025+00 ACC OFF push \N \N \N \N \N +7063 359857081891566 ACC_OFF 2026-04-23 13:39:14+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 13:39:37.369912+00 ACC OFF poll \N \N \N \N \N +7064 359857082897091 stayAlert 2026-04-23 13:37:59+00 0101000020E610000042EC4CA1F37242406397A8DE1A58F3BF -1.20901 36.89806 0.00 \N 2026-04-23 13:39:37.369912+00 Parking alert poll \N \N \N \N \N +7065 359857082918012 ACC_OFF 2026-04-23 13:37:50+00 0101000020E6100000A4A5F276846B42402BF697DD9307F3BF -1.18935 36.83998 0.00 \N 2026-04-23 13:39:37.369912+00 ACC OFF poll \N \N \N \N \N +7066 359857082910589 ACC_OFF 2026-04-23 13:37:38+00 0101000020E6100000A2EE0390DA784240ED9925016A6AF2BF -1.15098 36.94417 0.00 \N 2026-04-23 13:39:37.369912+00 ACC OFF poll \N \N \N \N \N +7067 359857081892101 ACC_ON 2026-04-23 13:37:02+00 0101000020E6100000744694F606634240A3586E6935A4F4BF -1.29009 36.77365 0.00 \N 2026-04-23 13:39:37.369912+00 ACC ON poll \N \N \N \N \N +7068 359857082897091 ACC_OFF 2026-04-23 13:36:50+00 0101000020E61000006DCA15DEE572424062670A9DD758F3BF -1.20919 36.89764 0.00 \N 2026-04-23 13:39:37.369912+00 ACC OFF poll \N \N \N \N \N +7070 359857082912239 ACC_ON 2026-04-23 13:35:54+00 0101000020E6100000857CD0B359494340FD304278B4310BC0 -3.39927 38.57305 0.00 \N 2026-04-23 13:39:37.369912+00 ACC ON poll \N \N \N \N \N +7072 862798050288345 ACC_ON 2026-04-23 13:35:27+00 0101000020E6100000D78A36C7B99143400A849D62D56011C0 -4.344564 39.138482 0.00 \N 2026-04-23 13:39:37.369912+00 ACC ON poll \N \N \N \N \N +7073 359857082908500 ACC_ON 2026-04-23 13:35:27+00 0101000020E6100000EFE6A90EB9914340FFCF61BEBC6011C0 -4.34447 39.13846 0.00 \N 2026-04-23 13:39:37.369912+00 ACC ON poll \N \N \N \N \N +7074 862798050288345 128 2026-04-23 13:34:34+00 0101000020E610000072C5C551B991434082AE7D01BD6011C0 -4.344471 39.138468 0.00 \N 2026-04-23 13:39:37.369912+00 DVR vibration alert poll \N \N \N \N \N +7151 865135061569131 3 2026-04-23 13:39:52+00 0101000020E6100000755776C1E04240402B8A5759DB14BB3F 0.105787 32.522484 20.00 \N 2026-04-23 13:39:53.596061+00 Vibration alert push \N \N \N \N \N +7152 359857081886905 1002 2026-04-23 13:40:21+00 0101000020E61000009A081B9E5ED943402C4833164D2710C0 -4.03838 39.6982 \N \N 2026-04-23 13:40:23.127409+00 ACC ON push \N \N \N \N \N +7153 359857082912239 1001 2026-04-23 13:40:43+00 0101000020E6100000AE122C0E674A434054573ECBF3200BC0 -3.39109 38.58127 \N \N 2026-04-23 13:40:44.219847+00 ACC OFF push \N \N \N \N \N +7154 862798050523337 128 2026-04-23 13:40:53+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 0.00 \N 2026-04-23 13:40:55.333435+00 DVR vibration alert push \N \N \N \N \N +7155 865135061562722 3 2026-04-23 13:39:32+00 0101000020E6100000A2ED98BA2B694240D255BABBCE86F2BF -1.157912 36.821647 \N \N 2026-04-23 13:41:08.580384+00 Vibration alert push \N \N \N \N \N +7156 359857082910589 stayAlertOn 2026-04-23 13:41:35+00 0101000020E6100000863DEDF0D77842407D0569C6A269F2BF -1.15079 36.94409 \N \N 2026-04-23 13:41:36.010861+00 Idling alert push \N \N \N \N \N +7157 359857082912239 1004 2026-04-23 13:41:43+00 0101000020E61000009886E123624A4340A9BC1DE1B4200BC0 -3.39097 38.58112 \N \N 2026-04-23 13:41:43.493927+00 Parking alert push \N \N \N \N \N +7158 359857081892101 stayAlertOn 2026-04-23 13:42:02+00 0101000020E6100000744694F606634240A3586E6935A4F4BF -1.29009 36.77365 \N \N 2026-04-23 13:42:03.026927+00 Idling alert push \N \N \N \N \N +7161 865135061581904 1002 2026-04-23 13:43:29+00 0101000020E6100000C8B3CBB73E564240A3B1F677B6C7F3BF -1.236258 36.673789 \N \N 2026-04-23 13:43:31.168672+00 ACC ON push \N \N \N \N \N +7163 865135061053748 1001 2026-04-23 13:43:54+00 0101000020E6100000463F1A4E99D343402A00C633683810C0 -4.055085 39.653116 \N \N 2026-04-23 13:43:55.004647+00 ACC OFF push \N \N \N \N \N +7164 862798050523139 128 2026-04-23 13:43:54+00 0101000020E610000021C8410933ED43406CB3B112F30C0DC0 -3.631323 39.85312 0.00 \N 2026-04-23 13:43:56.713693+00 DVR vibration alert push \N \N \N \N \N +7165 862798050526231 1001 2026-04-23 13:43:56+00 0101000020E6100000813D26529AD34340A7954220973810C0 -4.055264 39.653147 \N \N 2026-04-23 13:43:57.244366+00 ACC OFF push \N \N \N \N \N +7166 862798050523337 1002 2026-04-23 13:43:57+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 \N \N 2026-04-23 13:43:57.650405+00 ACC ON push \N \N \N \N \N +7171 359857082910886 1003 2026-04-23 13:44:33+00 0101000020E610000005A8A9656BD943406458C51B992710C0 -4.03867 39.69859 \N \N 2026-04-23 13:44:33.616561+00 Offline alert push \N \N \N \N \N +7172 865135061569131 3 2026-04-23 13:44:32+00 0101000020E6100000111D0247024340409A779CA223B9BC3F 0.1122 32.523507 9.00 \N 2026-04-23 13:44:34.851507+00 Vibration alert push \N \N \N \N \N +7298 865135061053748 1004 2026-04-23 13:44:54+00 0101000020E6100000A4DFBE0E9CD34340A609DB4FC63810C0 -4.055444 39.6532 \N \N 2026-04-23 13:44:54.251906+00 Parking alert push \N \N \N \N \N +7300 862798050523337 1001 2026-04-23 13:45:43+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 \N \N 2026-04-23 13:45:44.168567+00 ACC OFF push \N \N \N \N \N +7303 862798052707946 1002 2026-04-23 13:46:04+00 0101000020E6100000ADBF2500FF764240EDD5C743DF1DF3BF -1.194793 36.929657 \N \N 2026-04-23 13:46:05.875634+00 ACC ON push \N \N \N \N \N +7306 359857082918186 1001 2026-04-23 13:47:41+00 0101000020E61000000DAB7823F354424001C11C3D7EEFF3BF -1.24597 36.66367 \N \N 2026-04-23 13:47:42.825938+00 ACC OFF push \N \N \N \N \N +7307 865135061563639 stayAlertOn 2026-04-23 13:47:55+00 0101000020E61000000BEF7211DFE942400053060E68A9F9BF -1.603859 37.82712 \N \N 2026-04-23 13:47:55.396845+00 Idling alert push \N \N \N \N \N +7308 359857082918012 1002 2026-04-23 13:47:55+00 0101000020E6100000A4A5F276846B42400F971C774A07F3BF -1.18928 36.83998 \N \N 2026-04-23 13:47:55.602043+00 ACC ON push \N \N \N \N \N +7309 359857082897794 1001 2026-04-23 13:48:37+00 0101000020E61000006649809A5A6642408048BF7D1D38F4BF -1.2637 36.79964 \N \N 2026-04-23 13:48:38.012768+00 ACC OFF push \N \N \N \N \N +7310 862798050523295 128 2026-04-23 13:48:39+00 0101000020E61000000EA48B4D2B614240C0B167CF656AF4BF -1.275976 36.759134 0.00 \N 2026-04-23 13:48:40.87074+00 DVR vibration alert push \N \N \N \N \N +7159 359857082912239 1002 2026-04-23 13:42:08+00 0101000020E61000002E043928614A4340C63368E89F200BC0 -3.39093 38.58109 \N \N 2026-04-23 13:42:09.149028+00 ACC ON push \N \N \N \N \N +7160 865135061569131 3 2026-04-23 13:42:12+00 0101000020E610000074D3669C864240409566F3380CE6BB3F 0.108979 32.519733 7.00 \N 2026-04-23 13:42:13.755685+00 Vibration alert push \N \N \N \N \N +7162 359857082898487 1002 2026-04-23 13:43:46+00 0101000020E61000002310AFEB177C4240AA0EB9196EC0F2BF -1.17198 36.96948 \N \N 2026-04-23 13:43:46.758084+00 ACC ON push \N \N \N \N \N +7167 865135061048276 1002 2026-04-23 13:44:06+00 0101000020E6100000802DAF5C6FD9434000E5EFDE510310C0 -4.003242 39.698711 \N \N 2026-04-23 13:44:07.204102+00 ACC ON push \N \N \N \N \N +7168 359857082918186 1002 2026-04-23 13:44:08+00 0101000020E6100000454772F90F554240726DA818E7EFF3BF -1.24607 36.66455 \N \N 2026-04-23 13:44:08.795521+00 ACC ON push \N \N \N \N \N +7169 359857082907973 1002 2026-04-23 13:44:12+00 0101000020E61000003EAE0D15E3B44340D673D2FBC67711C0 -4.36697 39.41318 \N \N 2026-04-23 13:44:13.099812+00 ACC ON push \N \N \N \N \N +7170 359857082046145 1002 2026-04-23 13:44:23+00 0101000020E61000000A4B3CA06CDA4340BA490C022B0710C0 -4.007 39.70644 \N \N 2026-04-23 13:44:24.318444+00 ACC ON push \N \N \N \N \N +7299 865135061048276 1001 2026-04-23 13:45:23+00 0101000020E6100000802DAF5C6FD9434000E5EFDE510310C0 -4.003242 39.698711 \N \N 2026-04-23 13:45:25.121935+00 ACC OFF push \N \N \N \N \N +7301 865135061053748 1002 2026-04-23 13:45:57+00 0101000020E6100000A4DFBE0E9CD34340A609DB4FC63810C0 -4.055444 39.6532 \N \N 2026-04-23 13:45:58.453952+00 ACC ON push \N \N \N \N \N +7302 862798050526231 1002 2026-04-23 13:45:58+00 0101000020E6100000813D26529AD34340A7954220973810C0 -4.055264 39.653147 \N \N 2026-04-23 13:45:59.586733+00 ACC ON push \N \N \N \N \N +7304 865135061569131 3 2026-04-23 13:46:53+00 0101000020E6100000ABE97AA2EB4240403123BC3D0801BD3F 0.113297 32.522816 \N \N 2026-04-23 13:46:54.191195+00 Vibration alert push \N \N \N \N \N +7305 865135061562847 3 2026-04-23 13:46:42+00 0101000020E610000031D28BDAFD7E424012F92EA52E59F1BF -1.084273 36.992122 \N \N 2026-04-23 13:47:30.272603+00 Vibration alert push \N \N \N \N \N +7311 359857082897257 1001 2026-04-23 13:48:52+00 0101000020E61000005DF92CCF83774240A306D3307CC4F3BF -1.23547 36.93371 \N \N 2026-04-23 13:48:52.401378+00 ACC OFF push \N \N \N \N \N +7312 862798050523337 stayAlertOn 2026-04-23 13:48:57+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 \N \N 2026-04-23 13:48:57.604144+00 Idling alert push \N \N \N \N \N +7313 865135061569131 3 2026-04-23 13:49:33+00 0101000020E6100000A06F0B96EA4240402FF834272F32BD3F 0.114047 32.522784 \N \N 2026-04-23 13:49:34.769902+00 Vibration alert push \N \N \N \N \N +7433 359857082918012 1001 2026-04-23 13:49:52+00 0101000020E610000081CF0F23846B4240BA490C022B07F3BF -1.18925 36.83997 \N \N 2026-04-23 13:49:53.193084+00 ACC OFF push \N \N \N \N \N +7174 865135061053748 ACC_OFF 2026-04-23 13:43:54+00 0101000020E6100000463F1A4E99D343402A00C633683810C0 -4.055085 39.653116 0.00 \N 2026-04-23 13:44:38.308191+00 ACC OFF poll \N \N \N \N \N +7175 865135061581904 ACC_ON 2026-04-23 13:43:29+00 0101000020E6100000C8B3CBB73E564240A3B1F677B6C7F3BF -1.236258 36.673789 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7209 359857082046145 ACC_ON 2026-04-23 13:44:23+00 0101000020E61000000A4B3CA06CDA4340BA490C022B0710C0 -4.007 39.70644 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7210 359857082907973 ACC_ON 2026-04-23 13:44:12+00 0101000020E61000003EAE0D15E3B44340D673D2FBC67711C0 -4.36697 39.41318 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7211 359857082918186 ACC_ON 2026-04-23 13:44:08+00 0101000020E6100000454772F90F554240726DA818E7EFF3BF -1.24607 36.66455 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7212 862798050523337 ACC_ON 2026-04-23 13:43:57+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7213 862798050526231 ACC_OFF 2026-04-23 13:43:56+00 0101000020E6100000813D26529AD34340A7954220973810C0 -4.055264 39.653147 0.00 \N 2026-04-23 13:44:38.308191+00 ACC OFF poll \N \N \N \N \N +7214 359857082898487 ACC_ON 2026-04-23 13:43:46+00 0101000020E61000002310AFEB177C4240AA0EB9196EC0F2BF -1.17198 36.96948 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7215 359857082912239 ACC_ON 2026-04-23 13:42:08+00 0101000020E61000002E043928614A4340C63368E89F200BC0 -3.39093 38.58109 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7217 359857082912239 stayAlert 2026-04-23 13:41:43+00 0101000020E61000009886E123624A4340A9BC1DE1B4200BC0 -3.39097 38.58112 0.00 \N 2026-04-23 13:44:38.308191+00 Parking alert poll \N \N \N \N \N +7219 862798050523337 128 2026-04-23 13:40:54+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 0.00 \N 2026-04-23 13:44:38.308191+00 DVR vibration alert poll \N \N \N \N \N +7220 359857082912239 ACC_OFF 2026-04-23 13:40:43+00 0101000020E6100000AE122C0E674A434054573ECBF3200BC0 -3.39109 38.58127 0.00 \N 2026-04-23 13:44:38.308191+00 ACC OFF poll \N \N \N \N \N +7221 359857081886905 ACC_ON 2026-04-23 13:40:21+00 0101000020E61000009A081B9E5ED943402C4833164D2710C0 -4.03838 39.6982 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7281 359857082910886 offline 2026-04-23 13:44:33+00 0101000020E610000005A8A9656BD943406458C51B992710C0 -4.03867 39.69859 0.00 \N 2026-04-23 13:44:38.308191+00 Offline alert poll \N \N \N \N \N +7282 865135061048276 ACC_ON 2026-04-23 13:44:06+00 0101000020E6100000802DAF5C6FD9434000E5EFDE510310C0 -4.003242 39.698711 0.00 \N 2026-04-23 13:44:38.308191+00 ACC ON poll \N \N \N \N \N +7283 862798050523139 128 2026-04-23 13:43:55+00 0101000020E610000021C8410933ED43406CB3B112F30C0DC0 -3.631323 39.85312 0.00 \N 2026-04-23 13:44:38.308191+00 DVR vibration alert poll \N \N \N \N \N +7317 865135061053748 ACC_ON 2026-04-23 13:45:57+00 0101000020E6100000A4DFBE0E9CD34340A609DB4FC63810C0 -4.055444 39.6532 0.00 \N 2026-04-23 13:49:39.182175+00 ACC ON poll \N \N \N \N \N +7318 865135061053748 stayAlert 2026-04-23 13:44:54+00 0101000020E6100000A4DFBE0E9CD34340A609DB4FC63810C0 -4.055444 39.6532 0.00 \N 2026-04-23 13:49:39.182175+00 Parking alert poll \N \N \N \N \N +7348 359857082897257 ACC_OFF 2026-04-23 13:48:52+00 0101000020E61000005DF92CCF83774240A306D3307CC4F3BF -1.23547 36.93371 0.00 \N 2026-04-23 13:49:39.182175+00 ACC OFF poll \N \N \N \N \N +7349 359857082897794 ACC_OFF 2026-04-23 13:48:37+00 0101000020E61000006649809A5A6642408048BF7D1D38F4BF -1.2637 36.79964 0.00 \N 2026-04-23 13:49:39.182175+00 ACC OFF poll \N \N \N \N \N +7350 359857082918012 ACC_ON 2026-04-23 13:47:55+00 0101000020E6100000A4A5F276846B42400F971C774A07F3BF -1.18928 36.83998 0.00 \N 2026-04-23 13:49:39.182175+00 ACC ON poll \N \N \N \N \N +7351 359857082918186 ACC_OFF 2026-04-23 13:47:41+00 0101000020E61000000DAB7823F354424001C11C3D7EEFF3BF -1.24597 36.66367 0.00 \N 2026-04-23 13:49:39.182175+00 ACC OFF poll \N \N \N \N \N +7353 862798052707946 ACC_ON 2026-04-23 13:46:04+00 0101000020E6100000ADBF2500FF764240EDD5C743DF1DF3BF -1.194793 36.929657 0.00 \N 2026-04-23 13:49:39.182175+00 ACC ON poll \N \N \N \N \N +7354 862798050526231 ACC_ON 2026-04-23 13:45:58+00 0101000020E6100000813D26529AD34340A7954220973810C0 -4.055264 39.653147 0.00 \N 2026-04-23 13:49:39.182175+00 ACC ON poll \N \N \N \N \N +7355 862798050523337 ACC_OFF 2026-04-23 13:45:43+00 0101000020E610000074B33F506ED943403E213B6F630310C0 -4.003309 39.698679 0.00 \N 2026-04-23 13:49:39.182175+00 ACC OFF poll \N \N \N \N \N +7419 865135061048276 ACC_OFF 2026-04-23 13:45:23+00 0101000020E6100000802DAF5C6FD9434000E5EFDE510310C0 -4.003242 39.698711 0.00 \N 2026-04-23 13:49:39.182175+00 ACC OFF poll \N \N \N \N \N +7434 862798050523139 128 2026-04-23 13:50:10+00 0101000020E610000021C8410933ED43406CB3B112F30C0DC0 -3.631323 39.85312 0.00 \N 2026-04-23 13:50:12.807425+00 DVR vibration alert push \N \N \N \N \N +7435 862798050525266 1002 2026-04-23 13:50:23+00 0101000020E61000005AF2785A7E1C43401B4B581B63A704C0 -2.581732 38.222606 \N \N 2026-04-23 13:50:24.21992+00 ACC ON push \N \N \N \N \N +7436 359857081891632 1001 2026-04-23 13:50:55+00 0101000020E610000068CBB914576D424000E31934F4CFF3BF -1.23827 36.85422 \N \N 2026-04-23 13:50:56.868382+00 ACC OFF push \N \N \N \N \N +7437 359857081892101 1001 2026-04-23 13:50:58+00 0101000020E6100000978BF84ECC624240A3586E6935A4F4BF -1.29009 36.77186 \N \N 2026-04-23 13:50:59.313164+00 ACC OFF push \N \N \N \N \N +7438 862798050523139 1002 2026-04-23 13:51:25+00 0101000020E610000021C8410933ED4340C18C2958E30C0DC0 -3.631293 39.85312 \N \N 2026-04-23 13:51:26.135+00 ACC ON push \N \N \N \N \N +7439 865135061569131 1004 2026-04-23 13:51:31+00 0101000020E610000067F1626188424040560E2DB29DEFBB3F 0.109125 32.519787 \N \N 2026-04-23 13:51:32.150345+00 Parking alert push \N \N \N \N \N +7440 862798050523295 1002 2026-04-23 13:51:33+00 0101000020E6100000E4DC26DC2B614240983446EBA86AF4BF -1.27604 36.759151 \N \N 2026-04-23 13:51:34.365526+00 ACC ON push \N \N \N \N \N +7441 865135061037980 1002 2026-04-23 13:51:40+00 0101000020E6100000D575A8A6246142405FD218ADA36AF4BF -1.276035 36.758931 \N \N 2026-04-23 13:51:41.459919+00 ACC ON push \N \N \N \N \N +7442 359857082042953 1001 2026-04-23 13:51:52+00 0101000020E6100000541D7233DC004340D95A5F24B4E5F5BF -1.36858 38.00672 \N \N 2026-04-23 13:51:53.541493+00 ACC OFF push \N \N \N \N \N +7443 862798052708068 128 2026-04-23 13:51:53+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 0.00 \N 2026-04-23 13:51:54.234602+00 DVR vibration alert push \N \N \N \N \N +7444 359857081891632 1004 2026-04-23 13:51:55+00 0101000020E610000068CBB914576D424000E31934F4CFF3BF -1.23827 36.85422 \N \N 2026-04-23 13:51:56.056488+00 Parking alert push \N \N \N \N \N +7445 359857082912239 1001 2026-04-23 13:51:58+00 0101000020E6100000B3295778974743407AAA436E861B0BC0 -3.38844 38.55931 \N \N 2026-04-23 13:51:59.39183+00 ACC OFF push \N \N \N \N \N +7446 359857082898016 stayAlertOn 2026-04-23 13:52:09+00 0101000020E610000065A54929E8DA4340452FA3586EE90FC0 -3.98898 39.71021 \N \N 2026-04-23 13:52:09.731276+00 Idling alert push \N \N \N \N \N +7447 862798052708068 1002 2026-04-23 13:52:12+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 \N \N 2026-04-23 13:52:12.48139+00 ACC ON push \N \N \N \N \N +7448 865135061569131 3 2026-04-23 13:52:11+00 0101000020E610000021E692AAED4240405875560BEC31BD3F 0.114043 32.522878 \N \N 2026-04-23 13:52:14.154981+00 Vibration alert push \N \N \N \N \N +7449 359857082918012 1002 2026-04-23 13:52:25+00 0101000020E6100000EC51B81E856B424065FCFB8C0B07F3BF -1.18922 36.84 \N \N 2026-04-23 13:52:25.797434+00 ACC ON push \N \N \N \N \N +7450 862798052708068 1001 2026-04-23 13:52:39+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 \N \N 2026-04-23 13:52:39.825807+00 ACC OFF push \N \N \N \N \N +7451 865135061563597 3 2026-04-23 13:51:53+00 0101000020E6100000B88FDC9A745342408C6A11514CDEF1BF -1.116772 36.651996 \N \N 2026-04-23 13:52:40.624003+00 Vibration alert push \N \N \N \N \N +7452 359857082898487 1001 2026-04-23 13:52:45+00 0101000020E6100000BF9A0304737C42400E84640113B8F2BF -1.16994 36.97226 \N \N 2026-04-23 13:52:46.204507+00 ACC OFF push \N \N \N \N \N +7453 359857082912239 1004 2026-04-23 13:52:58+00 0101000020E6100000B3295778974743407AAA436E861B0BC0 -3.38844 38.55931 \N \N 2026-04-23 13:52:58.75393+00 Parking alert push \N \N \N \N \N +7454 359857082897794 stayAlertOn 2026-04-23 13:53:18+00 0101000020E6100000FCC6D79E5966424063D174763238F4BF -1.26372 36.79961 \N \N 2026-04-23 13:53:19.081687+00 Idling alert push \N \N \N \N \N +7455 359857082897257 stayAlertOn 2026-04-23 13:53:38+00 0101000020E61000005DF92CCF83774240A306D3307CC4F3BF -1.23547 36.93371 \N \N 2026-04-23 13:53:39.135417+00 Idling alert push \N \N \N \N \N +7456 862798052708068 1004 2026-04-23 13:53:39+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 \N \N 2026-04-23 13:53:39.34575+00 Parking alert push \N \N \N \N \N +7457 862798050525423 1003 2026-04-23 13:53:55+00 0101000020E6100000C4211B4817DB4340FD6B79E57AFB0FC0 -3.997793 39.711648 \N \N 2026-04-23 13:53:56.085304+00 Offline alert push \N \N \N \N \N +7458 865135061043079 1002 2026-04-23 13:53:59+00 0101000020E61000009697FC4FFEEC434063416150A6110DC0 -3.633618 39.851511 \N \N 2026-04-23 13:54:00.20097+00 ACC ON push \N \N \N \N \N +7459 359857081892309 1002 2026-04-23 13:54:02+00 0101000020E6100000CD069964E4704240E7525C55F65DF3BF -1.21044 36.88197 \N \N 2026-04-23 13:54:02.562401+00 ACC ON push \N \N \N \N \N +7460 359857081891566 1002 2026-04-23 13:54:19+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 13:54:19.481474+00 ACC ON push \N \N \N \N \N +7461 862798050525423 offline 2026-04-23 13:53:55+00 0101000020E6100000C4211B4817DB4340FD6B79E57AFB0FC0 -3.997793 39.711648 0.00 \N 2026-04-23 13:54:40.127209+00 Offline alert poll \N \N \N \N \N +7462 862798052708068 stayAlert 2026-04-23 13:53:39+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 0.00 \N 2026-04-23 13:54:40.127209+00 Parking alert poll \N \N \N \N \N +7463 862798052708068 ACC_OFF 2026-04-23 13:52:39+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 0.00 \N 2026-04-23 13:54:40.127209+00 ACC OFF poll \N \N \N \N \N +7464 862798052708068 ACC_ON 2026-04-23 13:52:12+00 0101000020E61000007808E3A771534240A8E15B5837DEF1BF -1.116752 36.651906 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7467 865135061037980 ACC_ON 2026-04-23 13:51:40+00 0101000020E6100000D575A8A6246142405FD218ADA36AF4BF -1.276035 36.758931 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7468 865135061569131 stayAlert 2026-04-23 13:51:31+00 0101000020E610000067F1626188424040560E2DB29DEFBB3F 0.109125 32.519787 0.00 \N 2026-04-23 13:54:40.127209+00 Parking alert poll \N \N \N \N \N +7499 359857081891566 ACC_ON 2026-04-23 13:54:19+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7500 359857081892309 ACC_ON 2026-04-23 13:54:02+00 0101000020E6100000CD069964E4704240E7525C55F65DF3BF -1.21044 36.88197 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7503 359857082912239 stayAlert 2026-04-23 13:52:58+00 0101000020E6100000B3295778974743407AAA436E861B0BC0 -3.38844 38.55931 0.00 \N 2026-04-23 13:54:40.127209+00 Parking alert poll \N \N \N \N \N +7504 359857082898487 ACC_OFF 2026-04-23 13:52:45+00 0101000020E6100000BF9A0304737C42400E84640113B8F2BF -1.16994 36.97226 0.00 \N 2026-04-23 13:54:40.127209+00 ACC OFF poll \N \N \N \N \N +7505 359857082918012 ACC_ON 2026-04-23 13:52:25+00 0101000020E6100000EC51B81E856B424065FCFB8C0B07F3BF -1.18922 36.84 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7506 359857082912239 ACC_OFF 2026-04-23 13:51:58+00 0101000020E6100000B3295778974743407AAA436E861B0BC0 -3.38844 38.55931 0.00 \N 2026-04-23 13:54:40.127209+00 ACC OFF poll \N \N \N \N \N +7507 359857081891632 stayAlert 2026-04-23 13:51:55+00 0101000020E610000068CBB914576D424000E31934F4CFF3BF -1.23827 36.85422 0.00 \N 2026-04-23 13:54:40.127209+00 Parking alert poll \N \N \N \N \N +7509 359857081892101 ACC_OFF 2026-04-23 13:50:58+00 0101000020E6100000978BF84ECC624240A3586E6935A4F4BF -1.29009 36.77186 0.00 \N 2026-04-23 13:54:40.127209+00 ACC OFF poll \N \N \N \N \N +7510 359857081891632 ACC_OFF 2026-04-23 13:50:55+00 0101000020E610000068CBB914576D424000E31934F4CFF3BF -1.23827 36.85422 0.00 \N 2026-04-23 13:54:40.127209+00 ACC OFF poll \N \N \N \N \N +7511 359857082918012 ACC_OFF 2026-04-23 13:49:52+00 0101000020E610000081CF0F23846B4240BA490C022B07F3BF -1.18925 36.83997 0.00 \N 2026-04-23 13:54:40.127209+00 ACC OFF poll \N \N \N \N \N +7571 865135061043079 ACC_ON 2026-04-23 13:53:59+00 0101000020E61000009697FC4FFEEC434063416150A6110DC0 -3.633618 39.851511 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7573 359857082042953 ACC_OFF 2026-04-23 13:51:52+00 0101000020E6100000541D7233DC004340D95A5F24B4E5F5BF -1.36858 38.00672 0.00 \N 2026-04-23 13:54:40.127209+00 ACC OFF poll \N \N \N \N \N +7574 862798050523295 ACC_ON 2026-04-23 13:51:33+00 0101000020E6100000E4DC26DC2B614240983446EBA86AF4BF -1.27604 36.759151 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7575 862798050523139 ACC_ON 2026-04-23 13:51:25+00 0101000020E610000021C8410933ED4340C18C2958E30C0DC0 -3.631293 39.85312 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7576 862798050525266 ACC_ON 2026-04-23 13:50:23+00 0101000020E61000005AF2785A7E1C43401B4B581B63A704C0 -2.581732 38.222606 0.00 \N 2026-04-23 13:54:40.127209+00 ACC ON poll \N \N \N \N \N +7577 862798050523139 128 2026-04-23 13:50:11+00 0101000020E610000021C8410933ED43406CB3B112F30C0DC0 -3.631323 39.85312 0.00 \N 2026-04-23 13:54:40.127209+00 DVR vibration alert poll \N \N \N \N \N +7588 865135061562847 1002 2026-04-23 13:54:44+00 0101000020E610000031D28BDAFD7E424012F92EA52E59F1BF -1.084273 36.992122 \N \N 2026-04-23 13:54:45.151639+00 ACC ON push \N \N \N \N \N +7591 862798050525266 stayAlertOn 2026-04-23 13:55:23+00 0101000020E61000005AF2785A7E1C43401B4B581B63A704C0 -2.581732 38.222606 \N \N 2026-04-23 13:55:24.094264+00 Idling alert push \N \N \N \N \N +7595 865135061047435 1002 2026-04-23 13:56:44+00 0101000020E6100000A20BEA5BE66442407218CC5F2173F4BF -1.278108 36.78828 \N \N 2026-04-23 13:56:45.243594+00 ACC ON push \N \N \N \N \N +7596 865135061581904 1004 2026-04-23 13:56:52+00 0101000020E610000088F6B182DF544240F6F065A208E9F3BF -1.244393 36.663071 \N \N 2026-04-23 13:56:52.924183+00 Parking alert push \N \N \N \N \N +7597 359857082898016 stayAlertOn 2026-04-23 13:57:10+00 0101000020E6100000C9022670EBDA4340D3DEE00B93E90FC0 -3.98905 39.71031 \N \N 2026-04-23 13:57:10.800277+00 Idling alert push \N \N \N \N \N +7598 359857082898487 stayAlertOn 2026-04-23 13:57:23+00 0101000020E6100000E370E657737C42400E84640113B8F2BF -1.16994 36.97227 \N \N 2026-04-23 13:57:23.851668+00 Idling alert push \N \N \N \N \N +7589 359857081891566 1001 2026-04-23 13:55:13+00 0101000020E61000007845F0BF957042407D7901F6D129F4BF -1.26021 36.87957 \N \N 2026-04-23 13:55:14.248003+00 ACC OFF push \N \N \N \N \N +7590 359857082918012 1001 2026-04-23 13:55:16+00 0101000020E61000001630815B776B4240F2EF332E1C08F3BF -1.18948 36.83958 \N \N 2026-04-23 13:55:16.90596+00 ACC OFF push \N \N \N \N \N +7592 865135061581904 1001 2026-04-23 13:55:53+00 0101000020E610000088F6B182DF544240F6F065A208E9F3BF -1.244393 36.663071 \N \N 2026-04-23 13:55:54.329193+00 ACC OFF push \N \N \N \N \N +7593 359857082900358 1002 2026-04-23 13:56:28+00 0101000020E6100000224F92AE997C42400B98C0ADBBF9F6BF -1.43597 36.97344 \N \N 2026-04-23 13:56:28.820937+00 ACC ON push \N \N \N \N \N +7594 862798052707946 1001 2026-04-23 13:56:38+00 0101000020E610000070EA03C93B774240FE0DDAAB8F07F3BF -1.189346 36.931512 \N \N 2026-04-23 13:56:39.04207+00 ACC OFF push \N \N \N \N \N +\. + + +-- +-- TOC entry 6900 (class 0 OID 24859) +-- Dependencies: 292 +-- Data for Name: api_token_cache; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.api_token_cache (id, account, access_token, refresh_token, app_key, expires_at, obtained_at, updated_at) FROM stdin; +1 Fireside Communications 8bc0adf42217dff16156741191089ff3 a0da312bacd4be20a540b1a6fb6fd03c \N 2026-04-23 15:25:31.58111+00 2026-04-23 13:25:31.581283+00 2026-04-23 13:25:31.581283+00 +\. + + +-- +-- TOC entry 6917 (class 0 OID 25159) +-- Dependencies: 319 +-- Data for Name: device_events; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.device_events (id, imei, event_type, event_time, timezone, created_at) FROM stdin; +\. + + +-- +-- TOC entry 6898 (class 0 OID 24843) +-- Dependencies: 290 +-- Data for Name: devices; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.devices (imei, device_name, mc_type, mc_type_use_scope, vehicle_name, vehicle_number, vehicle_models, vehicle_icon, vin, engine_number, vehicle_brand, fuel_100km, driver_name, driver_phone, sim, iccid, imsi, account, customer_name, device_group_id, device_group, activation_time, expiration, enabled_flag, status, city, current_mileage_km, created_at, updated_at, last_synced_at, vehicle_category, cost_centre, assigned_route, depot_geom, depot_address, assigned_city) FROM stdin; +865135061568968 X3-68968 X3 aotomobile \N \N \N automobile \N \N \N \N \N \N \N 89254021414206816915 639021410681691 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2026-03-11 06:19:14+00 2036-03-11 23:59:59+00 1 1 \N 16.23 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061563423 Joel Ntumba - UMA 826AB X3 aotomobile UMA 826AB UMA 826AB Motorbike mtc \N \N \N \N Joel Ntumba \N 119051036 89254021414206652690 639021410665269 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2026-01-28 13:55:39+00 2036-01-28 23:59:59+00 1 1 \N 1174.05 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061563639 Benjamin Ananda - KDV 438W X3 aotomobile KDV 438W KDV 438W Probox automobile \N \N \N \N Benjamin Ananda \N 758047065 89254021414206816683 639021410681668 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-12-13 16:02:37+00 2035-12-13 23:59:59+00 1 1 \N 14348.77 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061569131 UMA 418EK X3 aotomobile UMA 418EK UMA 418EK \N automobile \N \N \N \N UG \N 256792997053 8925610001837573385F 641101970467664 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2026-02-26 08:15:44+00 2036-02-26 23:59:59+00 1 1 \N 2289.03 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061581904 Robert Kipruto - KDV 072L X3 aotomobile KDV 072L KDV 072L Probox automobile \N \N \N \N Robert Kipruto \N 114149576 89254021264261503993 639021266150399 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-11-21 15:30:29+00 2035-11-21 23:59:59+00 1 1 \N 15115.99 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061564280 Rodin Kiberu - UMA 011EK X3 aotomobile UMA 011EK UMA 011EK Motorbike mtc \N \N \N \N Rodin Kiberu \N 118081642 89254021414206817244 639021410681724 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2026-01-28 13:13:57+00 2036-01-28 23:59:59+00 1 1 \N 841.39 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061569479 UMA 382EK X3 aotomobile UMA 382EK UMA 382EK \N automobile \N \N \N \N UG \N 256792997079 8925610001837573419F 641101970467667 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2026-02-26 08:21:10+00 2036-02-26 23:59:59+00 1 1 \N 1922.93 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061564470 Silvanus Kipkorir - KDV 064S X3 aotomobile KDV 064S KDV 064S Probox automobile \N \N \N \N Silvanus Kipkorir \N 113669866 89254021414206378718 639021410637871 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-11-21 16:49:17+00 2035-11-21 23:59:59+00 1 1 \N 23806.94 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061563282 X3-63282 X3 aotomobile \N \N \N automobile \N \N \N \N \N \N \N 8925610001837573427F 641101970467668 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2026-02-14 07:20:10+00 2036-02-14 23:59:59+00 1 1 \N 4749.64 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061569123 Albert Mutwiri - KDV 437W X3 aotomobile KDV 437W KDV 437W Probox automobile \N \N \N \N Albert Mutwiri \N 758047101 89254021414206816881 639021410681688 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-12-13 14:26:17+00 2035-12-13 23:59:59+00 1 1 \N 12984.58 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798052707896 John Mbugua - KDW 573B JC400P aotomobile KDW 573B KDW 573B Probox automobile \N \N \N \N John Mbugua \N \N 89254021414206816725 639021410681672 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2026-01-30 14:48:17+00 2036-01-30 23:59:59+00 1 1 \N 515.16 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798052713654 Garage/ISP_KCL 502T_CAM JC400P aotomobile \N \N \N automobile \N \N \N \N \N \N 0780215879 89254035061001753803 639035060175380 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-09-02 10:09:57+00 2035-09-02 23:59:59+00 1 1 \N 5199.72 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798052715220 Rofas Njagi - KDT 728R JC400P aotomobile KDT 728R KDT 728R Probox automobile \N \N \N \N Rofas Njagi \N 704573658 89254021334258495873 639021335849587 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-16 07:09:25+00 2035-07-16 23:59:59+00 1 1 \N 16385.58 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798052708035 862798052708035 JC400P aotomobile \N \N Probox automobile \N \N \N \N \N \N \N \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group \N \N 1 1 \N \N 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798052708167 Levine Wasike - KDV 439W JC400P aotomobile KDV 439W KDV 439W Probox automobile \N \N \N \N Levine Wasike \N 758046738 89254021414206816741 639021410681674 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-12-13 19:49:29+00 2035-12-13 23:59:59+00 1 1 \N 4569.72 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798052708068 Dominic Wambua - KDV 683Z JC400P aotomobile KDV 683Z KDV 683Z Probox automobile \N \N \N \N Dominic Wambua \N 758048043 89254021414206816964 639021410681696 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2026-01-24 09:20:09+00 2036-01-24 23:59:59+00 1 1 \N 4417.27 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798052713779 Benard Kimutai - KDN 759G JC400P aotomobile KDN 759G KDN 759G Probox automobile \N \N \N \N Benard Kimutai \N 752143258 89254035061001753860 639035060175386 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-08-23 11:15:59+00 2035-08-23 23:59:59+00 1 1 \N 5344.24 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798052713811 James Onyango - KDU 613B JC400P aotomobile KDU 613B KDU 613B Probox automobile \N \N \N \N James Onyango \N 790176542 89254021394215205880 639021391520588 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-09 19:24:14+00 2035-07-09 23:59:59+00 1 1 \N 9657.42 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061042261 Kelvin Wambugu - KDR 592N X3 aotomobile KDR 592N KDR 592N Probox automobile \N \N \N \N Kelvin Wambugu \N 797680464 89254021334258159693 639021335815969 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-10 10:23:44+00 2035-07-10 23:59:59+00 1 1 \N 18721.62 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061053748 Rashid Hassan - KDM 840V X3 aotomobile KDM 840V KDM 840V Probox automobile \N \N \N \N Rashid Hassan \N 768445963 89254021334212352574 639021331235257 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-10 13:54:11+00 2035-07-10 23:59:59+00 1 1 \N 26522.86 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061047435 Management_Mazda - KDU 613A X3 aotomobile KDU 613A KDU 613A Mazda automobile \N \N \N \N Management_Mazda \N 790175971 89254021394215205971 639021391520597 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-09 08:02:26+00 2035-07-09 23:59:59+00 1 1 \N 9738.11 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061053714 Samuel Kihara - KMEL 225X X3 aotomobile KMEL 225X KMEL 225X Motorbike mtc \N \N \N \N Samuel Kihara \N 768696832 89254021394274518934 639021397451893 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-08-02 13:51:47+00 2035-08-02 23:59:59+00 1 1 \N 26792.56 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061048615 Office-KMDG 902Z X3 aotomobile \N \N \N automobile \N \N \N \N \N \N 0768697276 89254021394274518876 639021397451887 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-31 09:59:43+00 2035-07-31 23:59:59+00 1 1 \N 5721.21 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061036164 Brian Njenga - KMFF 113Z X3 aotomobile KMFF 113Z KMFF 113Z Motorbike mtc \N \N \N \N Brian Njenga \N 768696705 89254021394274518850 639021397451885 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-31 10:06:46+00 2035-07-31 23:59:59+00 1 1 \N 22990.33 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061037980 Emmanuel Luseno - KDS 453Y X3 aotomobile KDS 453Y KDS 453Y Pick-Up automobile \N \N \N \N Emmanuel Luseno \N 790176734 89254021394215205856 639021391520585 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-15 06:30:34+00 2035-07-15 23:59:59+00 1 1 \N 42425.33 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061043426 Geoffrey Karanja - KMGS 239H X3 aotomobile KMGS 239H KMGS 239H Motorbike mtc \N \N \N \N Geoffrey Karanja \N 768696658 89254021394274518926 639021397451892 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-08-22 13:32:25+00 2035-08-22 23:59:59+00 1 1 \N 21102.56 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857082900358 Geoffrey Too - KDM 308S \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 12:35:06.661934+00 2026-04-23 12:35:06.661934+00 \N \N \N \N \N \N \N +865135061035778 John Kimeria - KDS 525D X3 aotomobile KDS 525D KDS 525D Crane truck \N \N \N \N John Kimeria \N 790176738 89254021394215205922 639021391520592 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-11 05:50:36+00 2035-07-11 23:59:59+00 1 1 \N 17585.24 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +865135061049001 Parked - KMGK 596V X3 aotomobile KMGK 596V KMGK 596V Motorbike mtc \N \N \N \N Parked \N 768697064 89254021394274518884 639021397451888 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2025-07-31 08:40:18+00 2035-07-31 23:59:59+00 1 1 \N 20612.89 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050524657 Felix Andole - KDC 207R JC400P aotomobile KDC 207R KDC 207R Probox automobile \N \N \N \N Felix Andole \N 758689195 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-22 07:17:47+00 2042-01-22 23:59:59+00 1 1 \N 46233.99 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050524897 Cornelius Kimutai - KCU 938R JC400P aotomobile KCU 938R KCU 938R Van automobile \N \N \N \N Cornelius Kimutai \N 114924404 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-22 09:03:40+00 2042-01-22 23:59:59+00 1 1 \N 12668.43 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050525423 Makori John - KDB 585E JC400P aotomobile KDB 585E KDB 585E Probox automobile \N \N \N \N Makori John \N 701211724 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-15 10:59:19+00 2042-01-15 23:59:59+00 1 1 \N 48750.85 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050525225 Sadique Wakayula - KDC 490Q JC400P aotomobile KDC 490Q KDC 490Q Crane truck \N \N \N \N Sadique Wakayula \N 768652386 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2023-12-22 20:52:08+00 2043-12-22 20:52:08+00 1 1 \N 19138.05 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050525589 Simon Kamau - KCE 090R JC400P aotomobile KCE 090R KCE 090R Probox automobile \N \N \N \N Simon Kamau \N 796276387 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-19 10:10:04+00 2042-01-19 23:59:59+00 1 1 \N 15874.39 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050525068 Samuel Ng'ang'a - KDE 264M JC400P aotomobile KDE 264M KDE 264M Probox automobile \N \N \N \N Samuel Ng'ang'a \N 768658564 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2023-12-22 13:33:42+00 2033-12-22 23:59:59+00 1 1 \N 12299.13 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050522107 Cassius Wakiyo - KDB 323M JC400P aotomobile KDB 323M KDB 323M Probox automobile \N \N \N \N Cassius Wakiyo \N 114149576 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-22 08:18:15+00 2042-01-22 23:59:59+00 1 1 \N 23316.09 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050522743 Charles Nyambane - KCB 711C JC400P aotomobile KCB 711C KCB 711C Probox automobile \N \N \N \N Charles Nyambane \N 768657106 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2023-12-22 21:53:57+00 2033-12-22 23:59:59+00 1 1 \N 12133.75 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050524368 862798050524368 JC400P aotomobile \N \N \N automobile \N \N \N \N \N \N \N \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-10-29 09:24:53+00 2042-10-29 23:59:59+00 1 1 \N 169208.91 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050524608 Peter Mbugua - KDK 728K JC400P aotomobile KDK 728K KDK 728K Probox automobile \N \N \N \N Peter Mbugua \N 706742413 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-12-03 12:11:32+00 2042-12-03 23:59:59+00 1 1 \N 7219.31 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050525605 John Ondego - KCA 542Q JC400P aotomobile KCA 542Q KCA 542Q Probox automobile \N \N \N \N John Ondego \N 110526783 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-15 05:56:11+00 2042-01-15 23:59:59+00 1 1 \N 23976.94 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050524558 Mutuku Joseph - KDC 739F JC400P aotomobile KDC 739F KDC 739F Probox automobile \N \N \N \N Mutuku Joseph \N 100858817 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-22 10:38:25+00 2042-01-22 23:59:59+00 1 1 \N 23711.63 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050523386 George Ochieng' - KDD 684Y JC400P aotomobile KDD 684Y KDD 684Y Probox automobile \N \N \N \N George Ochieng' \N 785586834 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-22 06:36:08+00 2042-01-22 23:59:59+00 1 1 \N 33979.83 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050522859 Garage - KCH 167M JC400P aotomobile KCH 167M KCH 167M Probox automobile \N \N \N \N Garage \N 706740252 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-15 08:23:21+00 2042-01-15 23:59:59+00 1 1 \N 6934.86 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050525837 Kennedy Ondieki - KCU 237Z JC400P aotomobile KCU 237Z KCU 237Z Probox automobile \N \N \N \N Kennedy Ondieki \N 113669852 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2023-12-21 19:32:44+00 2033-12-21 23:59:59+00 1 1 \N \N 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050525951 Wright Oseko - KCG 668W JC400P aotomobile KCG 668W KCG 668W Probox automobile \N \N \N \N Wright Oseko \N 741943212 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-15 09:36:45+00 2042-01-15 23:59:59+00 1 1 \N 13116.00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050522883 Dan Watila - KDE 638J JC400P aotomobile KDE 638J KDE 638J Probox automobile \N \N \N \N Dan Watila \N 112615393 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-15 07:17:21+00 2042-01-15 23:59:59+00 1 1 \N 14483.01 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050524384 Hamisi Pande - KDD 689Y JC400P aotomobile KDD 689Y KDD 689Y Probox automobile \N \N \N 0.00 Hamisi Pande \N 701211744 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-22 05:49:19+00 2042-01-22 23:59:59+00 1 1 \N 13685.18 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050523816 Job Ngare - KDM 309S JC400P aotomobile KDM 309S KDM 309S Probox automobile \N \N \N \N Job Ngare \N 707936781 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2023-08-15 14:05:52+00 2033-08-15 23:59:59+00 1 1 \N 54320.21 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050523618 Geoffrey Too - KDM 308S JC400P aotomobile KDM 308S KDM 308S Probox automobile \N \N \N \N Geoffrey Too \N 701211625 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2023-08-15 15:42:32+00 2033-08-15 23:59:59+00 1 1 \N 26496.50 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050524707 Garage - KCE 699F JC400P aotomobile KCE 699F KCE 699F Probox automobile \N \N \N \N Garage \N 110525751 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-01-15 07:58:49+00 2042-01-15 23:59:59+00 1 1 \N 34715.97 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050288261 Patric Bett - KDA 609E JC400P aotomobile KDA 609E KDA 609E Probox automobile \N \N \N \N Patric Bett 112693340 790176509 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2021-10-23 11:50:11+00 2041-10-23 23:59:59+00 1 1 \N 18538.42 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +862798050288360 Brian Ngetich - KDA 717B JC400P aotomobile KDA 717B KDA 717B Probox automobile \N \N \N \N Brian Ngetich \N 717867861 \N \N fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2021-11-05 08:47:08+00 2041-11-05 23:59:59+00 1 1 \N 17754.74 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857082897091 Peter Mbugua - KDK 728K GT06E aotomobile KDK 728K KDK 728K Probox automobile \N \N \N \N Peter Mbugua \N 790262984 89254021234222500396 639021232250039 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2022-12-14 11:31:57+00 2042-12-14 23:59:59+00 1 1 \N 131064.08 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857082912239 Dickson Jaoko - KDK 815R GT06E aotomobile KDK 815R KDK 815R Probox automobile \N \N Probox 0.00 Dickson Jaoko \N 706392117 89254021234296021287 639021239602128 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2023-06-21 07:14:51+00 2033-06-21 23:59:59+00 1 1 \N 76985.73 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857081891798 Garage - KCH 167M GT06E aotomobile KCH 167M KCH 167M Probox automobile \N \N \N \N Garage \N 746760102 89254021084186499493 639021088649949 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2019-06-16 10:18:57+00 2039-06-16 23:59:59+00 1 1 \N 168840.95 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857081885410 Allan Owana - KDK 780K GT06E aotomobile KDK 780K KDK 780K Probox automobile \N \N \N \N Allan Owana \N 703616117 89254021234222499854 639021232249985 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2019-06-19 09:32:22+00 2039-06-19 23:59:59+00 1 1 \N 128796.19 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857081891632 John Ondego - KCA 542Q GT06E aotomobile KCA 542Q KCA 542Q Probox automobile \N \N \N \N John Ondego \N 746760038 89254021084186499485 639021088649948 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2019-06-15 09:17:53+00 2039-06-15 23:59:59+00 1 1 \N 178845.80 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857081892762 Nicholas GT06E aotomobile \N \N Station Wagon bus \N \N Toyota \N \N \N 0746760503 89254021274233125361 639021273312536 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2019-06-16 08:31:46+00 2039-06-16 23:59:59+00 1 1 \N 51048.97 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857081892440 KAZ 489Z GT06E aotomobile \N \N \N bus \N \N \N \N \N \N 0700023806 89254021084178504698 639021087850469 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2019-06-09 10:04:39+00 2039-06-09 23:59:59+00 1 1 \N 38197.20 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857082042052 Gabriel Musumba - KCE 690F GT06E aotomobile KCE 690F KCE 690F Probox automobile \N \N \N \N Gabriel Musumba \N 110094466 89254021164215938024 639021161593802 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2020-04-03 17:30:13+00 2040-04-03 23:59:59+00 1 1 \N 192628.95 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857081886871 Kamonde KBA 467S GT06E aotomobile \N \N \N bus \N \N \N \N \N \N 0746763083 89254021084186499873 639021088649987 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2019-06-30 09:09:14+00 2039-06-30 23:59:59+00 1 1 \N 74183.36 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +353549090566885 Wireless GPS AT4 personal \N \N \N bus \N \N \N \N \N \N 0768445963 89254021334212352574 639021331235257 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2024-10-15 13:16:57+00 2034-10-15 23:59:59+00 1 1 \N 17036.41 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +353549090566281 KDR 592N AT4 personal \N \N \N bus \N \N \N \N \N \N 0797680464 89254021334258159693 639021335815969 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2024-11-08 04:01:30+00 2034-11-08 23:59:59+00 1 1 \N 7771.90 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +353549090567701 Wireless AT4 personal \N \N \N bus \N \N \N \N \N \N 0790176094 89254021394215205906 639021391520590 fireside Fireside Group HQ 2f1acaef6c884214b4598719180fe68d Default group 2024-11-08 04:04:44+00 2034-11-08 23:59:59+00 1 1 \N 16896.20 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 2026-04-23 10:23:56.546784+00 \N \N \N \N \N \N +359857082038977 Wilfred Kinyanjui - KCU 729C \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:24:33.914628+00 2026-04-23 10:24:33.914628+00 \N \N \N \N \N \N \N +865135061035653 Richardson Komu - KDT 923R \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:24:50.340401+00 2026-04-23 10:24:50.340401+00 \N \N \N \N \N \N \N +865135061054555 Rofas Njagi - KDT 728R \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:25:21.085437+00 2026-04-23 10:25:21.085437+00 \N \N \N \N \N \N \N +862798050523527 Allan Owana - KDK 780K \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:25:24.360765+00 2026-04-23 10:25:24.360765+00 \N \N \N \N \N \N \N +862798052707946 Tom Wekesa/OSP-KCY 930Y_CAM \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:25:24.363965+00 2026-04-23 10:25:24.363965+00 \N \N \N \N \N \N \N +865135061562722 John Mbugua - KDW 573B \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:25:38.887433+00 2026-04-23 10:25:38.887433+00 \N \N \N \N \N \N \N +865135061563597 Dominic Wambua - KDV 683Z \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:25:40.125927+00 2026-04-23 10:25:40.125927+00 \N \N \N \N \N \N \N +359857082918012 Charles Nyambane - KCB 711C \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:25:52.843474+00 2026-04-23 10:25:52.843474+00 \N \N \N \N \N \N \N +359857082896911 Hamisi Pande - KDD 689Y \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:26:09.922447+00 2026-04-23 10:26:09.922447+00 \N \N \N \N \N \N \N +862798050523014 Samuel Muriithy - KDR 594N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:26:17.747928+00 2026-04-23 10:26:17.747928+00 \N \N \N \N \N \N \N +865135061054548 James Onyango - KDU 613B \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:26:24.667167+00 2026-04-23 10:26:24.667167+00 \N \N \N \N \N \N \N +359857082907973 Felix Muema - KCZ 223P \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:26:48.220151+00 2026-04-23 10:26:48.220151+00 \N \N \N \N \N \N \N +862798050523337 Victor Kimutai - KDS 919Y \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:27:13.522675+00 2026-04-23 10:27:13.522675+00 \N \N \N \N \N \N \N +359857082897257 Cassius Wakiyo - KDB 323M \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:28:26.388654+00 2026-04-23 10:28:26.388654+00 \N \N \N \N \N \N \N +862798050521521 John Kimeria - KDS 525D \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:28:34.917147+00 2026-04-23 10:28:34.917147+00 \N \N \N \N \N \N \N +359857081892101 Cornelius Kimutai - KCU 938R \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:29:21.507861+00 2026-04-23 10:29:21.507861+00 \N \N \N \N \N \N \N +862798050526231 Rashid Hassan - KDM 840V \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:29:41.575467+00 2026-04-23 10:29:41.575467+00 \N \N \N \N \N \N \N +862798050288345 Santoes Omondi - KCZ 181P \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:29:45.563231+00 2026-04-23 10:29:45.563231+00 \N \N \N \N \N \N \N +359857082897794 Mutuku Joseph - KDC 739F \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:30:22.530563+00 2026-04-23 10:30:22.530563+00 \N \N \N \N \N \N \N +359857081891566 Simon Kamau - KCE 090R \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:30:55.739184+00 2026-04-23 10:30:55.739184+00 \N \N \N \N \N \N \N +359857082898487 Dan Watila - KDE 638J \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:31:45.186653+00 2026-04-23 10:31:45.186653+00 \N \N \N \N \N \N \N +359857082042854 Elias Baya - KCZ 476E \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:33:56.216621+00 2026-04-23 10:33:56.216621+00 \N \N \N \N \N \N \N +359857082910589 Patric Bett - KDA 609E \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:34:25.350862+00 2026-04-23 10:34:25.350862+00 \N \N \N \N \N \N \N +359857081887192 Ndegwa Dancun - KCG 669W \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:34:29.074112+00 2026-04-23 10:34:29.074112+00 \N \N \N \N \N \N \N +359857081886905 Kennedy Chege - KCQ 618K \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:35:37.678371+00 2026-04-23 10:35:37.678371+00 \N \N \N \N \N \N \N +865135061562847 Levine Wasike - KDV 439W \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:35:50.779597+00 2026-04-23 10:35:50.779597+00 \N \N \N \N \N \N \N +359857082911983 Brian Ngetich - KDA 717B \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:36:11.774166+00 2026-04-23 10:36:11.774166+00 \N \N \N \N \N \N \N +359857082918186 KDD 977T Fielder \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:36:25.832836+00 2026-04-23 10:36:25.832836+00 \N \N \N \N \N \N \N +359857082897737 John Makori - KDB 585E \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:38:57.445964+00 2026-04-23 10:38:57.445964+00 \N \N \N \N \N \N \N +359857081892309 Nicholas Erastus - KCQ 581M \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:40:40.169684+00 2026-04-23 10:40:40.169684+00 \N \N \N \N \N \N \N +359857082912486 Moses Wambua - KCZ 751V \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:41:00.207177+00 2026-04-23 10:41:00.207177+00 \N \N \N \N \N \N \N +865135061559538 FRED KMGW 538W HULETI \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:42:18.5831+00 2026-04-23 10:42:18.5831+00 \N \N \N \N \N \N \N +359857082900341 Simon Munda - KCZ 154S \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:45:21.454595+00 2026-04-23 10:45:21.454595+00 \N \N \N \N \N \N \N +359857082046145 Joseph Kabandi - KCY 076X \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:47:40.895504+00 2026-04-23 10:47:40.895504+00 \N \N \N \N \N \N \N +359857082908500 Santoes Omondi - KCZ 181P \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:48:09.537346+00 2026-04-23 10:48:09.537346+00 \N \N \N \N \N \N \N +359857082037185 Amani Kazungu - KCY 084X \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:51:08.665273+00 2026-04-23 10:51:08.665273+00 \N \N \N \N \N \N \N +862798050523626 Major Simiyu - KDS 949Y \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:51:18.245194+00 2026-04-23 10:51:18.245194+00 \N \N \N \N \N \N \N +865135061048953 Timothy Gitau - KDT 916R \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:53:31.102315+00 2026-04-23 10:53:31.102315+00 \N \N \N \N \N \N \N +865135061048276 Victor Kimutai - KDS 919Y \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:54:41.63532+00 2026-04-23 10:54:41.63532+00 \N \N \N \N \N \N \N +359857081886467 Gideon Kiprono - KCQ 215F \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 10:56:37.983314+00 2026-04-23 10:56:37.983314+00 \N \N \N \N \N \N \N +359857081887069 Wright Oseko - KCG 668W \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:00:08.769463+00 2026-04-23 11:00:08.769463+00 \N \N \N \N \N \N \N +359857082902461 Sadique Wakayula - KDC 490Q \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:16:03.730519+00 2026-04-23 11:16:03.730519+00 \N \N \N \N \N \N \N +865135061043079 Mike Wanaswa - KDT 724R \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:16:35.682194+00 2026-04-23 11:16:35.682194+00 \N \N \N \N \N \N \N +862798050523139 Mike Wanaswa - KDT 724R \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:16:37.277518+00 2026-04-23 11:16:37.277518+00 \N \N \N \N \N \N \N +359857082898016 Job Ngare - KDM 309S \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:20:25.939244+00 2026-04-23 11:20:25.939244+00 \N \N \N \N \N \N \N +865135061563415 Barack Orwa - KDW 781E \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:22:00.676215+00 2026-04-23 11:22:00.676215+00 \N \N \N \N \N \N \N +862798050523295 Emmanuel Luseno - KDS 453 Y \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:29:48.369147+00 2026-04-23 11:29:48.369147+00 \N \N \N \N \N \N \N +359857082898008 Samuel Ng'ang'a - KDE 264M \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:35:59.816581+00 2026-04-23 11:35:59.816581+00 \N \N \N \N \N \N \N +359857082910886 Makanda Andrew - KCZ 155P \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:36:31.150282+00 2026-04-23 11:36:31.150282+00 \N \N \N \N \N \N \N +865135061048466 Samuel Muriithy - KDR 594N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 11:43:39.178819+00 2026-04-23 11:43:39.178819+00 \N \N \N \N \N \N \N +865135061035133 Major Simiyu - KDS 949Y \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 12:07:56.044395+00 2026-04-23 12:07:56.044395+00 \N \N \N \N \N \N \N +359857082918038 Mbuvi Kioko - KCC 199P \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 12:09:05.609075+00 2026-04-23 12:09:05.609075+00 \N \N \N \N \N \N \N +862798050288212 Nicholas Erastus - KCQ 581M \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 13:05:18.326254+00 2026-04-23 13:05:18.326254+00 \N \N \N \N \N \N \N +862798050525266 Dickson Jaoko - KDK 815R \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 13:50:24.21992+00 2026-04-23 13:50:24.21992+00 \N \N \N \N \N \N \N +359857082042953 KCU 865Q Vanguard \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 1 unknown \N \N 2026-04-23 13:24:33.293453+00 2026-04-23 13:24:33.293453+00 \N \N \N \N \N \N \N +\. + + +-- +-- TOC entry 6925 (class 0 OID 25240) +-- Dependencies: 327 +-- Data for Name: dispatch_log; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.dispatch_log (dispatch_id, ticket_id, imei, driver_name, job_lat, job_lng, job_geom, assigned_at, first_movement_at, on_site_at, resolved_at, cancelled_at, distance_km, created_at) FROM stdin; +\. + + +-- +-- TOC entry 6914 (class 0 OID 25122) +-- Dependencies: 316 +-- Data for Name: fault_codes; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.fault_codes (id, imei, reported_at, fault_code, status_flags, lat, lng, geom, event_time, created_at) FROM stdin; +\. + + +-- +-- TOC entry 6918 (class 0 OID 25176) +-- Dependencies: 320 +-- Data for Name: fuel_readings; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.fuel_readings (imei, reading_time, sensor_path, value, unit, lat, lng, geom, created_at) FROM stdin; +\. + + +-- +-- TOC entry 6923 (class 0 OID 25225) +-- Dependencies: 325 +-- Data for Name: geofences; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.geofences (id, fence_id, fence_name, fence_type, geom, radius_m, description, created_at, updated_at) FROM stdin; +\. + + +-- +-- TOC entry 6915 (class 0 OID 25140) +-- Dependencies: 317 +-- Data for Name: heartbeats; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.heartbeats (imei, gate_time, power_level, gsm_signal, acc_status, power_status, fortify, created_at) FROM stdin; +\. + + +-- +-- TOC entry 6902 (class 0 OID 24874) +-- Dependencies: 294 +-- Data for Name: ingestion_log; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.ingestion_log (id, run_at, endpoint, imei_count, rows_upserted, rows_inserted, duration_ms, success, error_code, error_message) FROM stdin; +1 2026-04-23 10:23:56.546784+00 jimi.user.device.list+detail 63 63 0 1205 t \N \N +2 2026-04-23 10:23:56.750839+00 jimi.user.device.location.list 63 61 61 761 t \N \N +3 2026-04-23 10:23:58.790821+00 jimi.device.track.mileage 63 0 -20 2472 t \N \N +4 2026-04-23 10:24:14.397218+00 jimi.open.platform.report.parking 63 0 0 14569 t \N \N +5 2026-04-23 10:24:19.907647+00 jimi.device.track.list 63 0 231 5534 t \N \N +6 2026-04-23 10:24:33.914628+00 webhook/pushalarm 1 0 1 36 t \N \N +7 2026-04-23 10:24:50.340401+00 webhook/pushalarm 1 0 1 1 t \N \N +8 2026-04-23 10:24:51.841909+00 webhook/pushalarm 1 0 1 2 t \N \N +9 2026-04-23 10:25:15.719559+00 webhook/pushalarm 1 0 1 1 t \N \N +10 2026-04-23 10:25:20.144717+00 jimi.user.device.location.list 63 61 8 234 t \N \N +11 2026-04-23 10:25:21.085437+00 webhook/pushalarm 1 0 1 31 t \N \N +12 2026-04-23 10:25:24.360765+00 webhook/pushalarm 1 0 1 1 t \N \N +13 2026-04-23 10:25:24.363965+00 webhook/pushalarm 1 0 1 0 t \N \N +14 2026-04-23 10:25:38.887433+00 webhook/pushalarm 1 0 1 1 t \N \N +15 2026-04-23 10:25:40.125927+00 webhook/pushalarm 1 0 1 1 t \N \N +16 2026-04-23 10:25:46.478217+00 webhook/pushalarm 1 0 1 1 t \N \N +17 2026-04-23 10:25:52.843474+00 webhook/pushalarm 1 0 1 1 t \N \N +18 2026-04-23 10:26:09.922447+00 webhook/pushalarm 1 0 1 1 t \N \N +19 2026-04-23 10:26:14.341837+00 webhook/pushalarm 1 0 1 1 t \N \N +20 2026-04-23 10:26:17.747928+00 webhook/pushalarm 1 0 1 4 t \N \N +21 2026-04-23 10:26:20.363121+00 jimi.user.device.location.list 63 61 7 201 t \N \N +22 2026-04-23 10:26:24.667167+00 webhook/pushalarm 1 0 1 1 t \N \N +23 2026-04-23 10:26:43.604438+00 webhook/pushalarm 1 0 1 1 t \N \N +24 2026-04-23 10:26:44.355226+00 webhook/pushalarm 1 0 1 1 t \N \N +25 2026-04-23 10:26:48.220151+00 webhook/pushalarm 1 0 1 1 t \N \N +26 2026-04-23 10:27:07.548485+00 webhook/pushalarm 1 0 1 1 t \N \N +27 2026-04-23 10:27:13.522675+00 webhook/pushalarm 1 0 1 1 t \N \N +28 2026-04-23 10:27:20.620112+00 jimi.user.device.location.list 63 61 6 244 t \N \N +29 2026-04-23 10:27:27.796815+00 webhook/pushalarm 1 0 1 2 t \N \N +30 2026-04-23 10:28:20.887898+00 jimi.user.device.location.list 63 61 8 244 t \N \N +31 2026-04-23 10:28:26.388654+00 webhook/pushalarm 1 0 1 1 t \N \N +32 2026-04-23 10:28:33.146047+00 webhook/pushalarm 1 0 1 1 t \N \N +33 2026-04-23 10:28:34.917147+00 webhook/pushalarm 1 0 1 2 t \N \N +34 2026-04-23 10:28:36.286951+00 webhook/pushalarm 1 0 1 2 t \N \N +35 2026-04-23 10:28:44.949511+00 webhook/pushalarm 1 0 1 3 t \N \N +36 2026-04-23 10:28:55.624014+00 jimi.device.alarm.list 78 0 -104 605 t \N \N +37 2026-04-23 10:29:21.166245+00 jimi.user.device.location.list 63 61 6 262 t \N \N +38 2026-04-23 10:29:21.507861+00 webhook/pushalarm 1 0 1 4 t \N \N +39 2026-04-23 10:29:40.350152+00 webhook/pushalarm 1 0 1 1 t \N \N +40 2026-04-23 10:29:41.575467+00 webhook/pushalarm 1 0 1 1 t \N \N +41 2026-04-23 10:29:45.563231+00 webhook/pushalarm 1 0 1 2 t \N \N +42 2026-04-23 10:29:58.878951+00 webhook/pushalarm 1 0 1 1 t \N \N +43 2026-04-23 10:29:59.071853+00 webhook/pushalarm 1 0 1 2 t \N \N +44 2026-04-23 10:29:59.915009+00 webhook/pushalarm 1 0 1 1 t \N \N +45 2026-04-23 10:30:18.936705+00 webhook/pushalarm 1 0 1 3 t \N \N +46 2026-04-23 10:30:21.41733+00 jimi.user.device.location.list 63 61 8 220 t \N \N +47 2026-04-23 10:30:22.530563+00 webhook/pushalarm 1 0 1 1 t \N \N +48 2026-04-23 10:30:39.523741+00 webhook/pushalarm 1 0 1 1 t \N \N +49 2026-04-23 10:30:55.739184+00 webhook/pushalarm 1 0 1 1 t \N \N +50 2026-04-23 10:30:58.888543+00 webhook/pushalarm 1 0 1 1 t \N \N +51 2026-04-23 10:31:13.716399+00 webhook/pushalarm 1 0 1 3 t \N \N +52 2026-04-23 10:31:21.645043+00 jimi.user.device.location.list 63 61 5 204 t \N \N +53 2026-04-23 10:31:28.367569+00 webhook/pushalarm 1 0 1 1 t \N \N +54 2026-04-23 10:31:31.885731+00 webhook/pushalarm 1 0 1 1 t \N \N +55 2026-04-23 10:31:38.855908+00 webhook/pushalarm 1 0 1 1 t \N \N +56 2026-04-23 10:31:45.186653+00 webhook/pushalarm 1 0 1 1 t \N \N +57 2026-04-23 10:32:20.45537+00 webhook/pushalarm 1 0 1 2 t \N \N +58 2026-04-23 10:32:21.934615+00 jimi.user.device.location.list 63 61 4 275 t \N \N +59 2026-04-23 10:32:34.55597+00 webhook/pushalarm 1 0 1 1 t \N \N +60 2026-04-23 10:32:49.567954+00 webhook/pushalarm 1 0 1 1 t \N \N +61 2026-04-23 10:33:05.125505+00 webhook/pushalarm 1 0 1 1 t \N \N +62 2026-04-23 10:33:22.180556+00 jimi.user.device.location.list 63 61 5 225 t \N \N +63 2026-04-23 10:33:39.716162+00 webhook/pushalarm 1 0 1 1 t \N \N +64 2026-04-23 10:33:44.658475+00 webhook/pushalarm 1 0 1 1 t \N \N +65 2026-04-23 10:33:56.216621+00 webhook/pushalarm 1 0 1 1 t \N \N +66 2026-04-23 10:33:56.689807+00 jimi.device.alarm.list 84 0 -110 1036 t \N \N +67 2026-04-23 10:34:00.079245+00 webhook/pushalarm 1 0 1 1 t \N \N +68 2026-04-23 10:34:22.429402+00 jimi.user.device.location.list 63 61 4 224 t \N \N +69 2026-04-23 10:34:25.350862+00 webhook/pushalarm 1 0 1 1 t \N \N +70 2026-04-23 10:34:29.074112+00 webhook/pushalarm 1 0 1 1 t \N \N +71 2026-04-23 10:34:39.64845+00 webhook/pushalarm 1 0 1 1 t \N \N +72 2026-04-23 10:34:43.677593+00 webhook/pushalarm 1 0 1 1 t \N \N +73 2026-04-23 10:34:50.048025+00 webhook/pushalarm 1 0 1 1 t \N \N +74 2026-04-23 10:34:54.787+00 webhook/pushalarm 1 0 1 1 t \N \N +75 2026-04-23 10:34:59.620927+00 webhook/pushalarm 1 0 1 1 t \N \N +76 2026-04-23 10:34:59.733443+00 webhook/pushalarm 1 0 1 0 t \N \N +77 2026-04-23 10:35:08.333452+00 webhook/pushalarm 1 0 1 1 t \N \N +78 2026-04-23 10:35:10.698625+00 webhook/pushalarm 1 0 1 1 t \N \N +79 2026-04-23 10:35:22.674549+00 jimi.user.device.location.list 63 61 6 230 t \N \N +80 2026-04-23 10:35:26.071915+00 webhook/pushalarm 1 0 1 1 t \N \N +81 2026-04-23 10:35:37.678371+00 webhook/pushalarm 1 0 1 1 t \N \N +82 2026-04-23 10:35:48.813654+00 webhook/pushalarm 1 0 1 1 t \N \N +83 2026-04-23 10:35:50.779597+00 webhook/pushalarm 1 0 1 1 t \N \N +84 2026-04-23 10:35:55.478764+00 webhook/pushalarm 1 0 1 4 t \N \N +85 2026-04-23 10:36:11.774166+00 webhook/pushalarm 1 0 1 2 t \N \N +86 2026-04-23 10:36:22.074001+00 webhook/pushalarm 1 0 1 2 t \N \N +87 2026-04-23 10:36:22.928539+00 jimi.user.device.location.list 63 61 5 240 t \N \N +95 2026-04-23 10:37:23.193198+00 jimi.user.device.location.list 63 61 5 282 t \N \N +103 2026-04-23 10:38:23.487268+00 jimi.user.device.location.list 63 61 5 224 t \N \N +1222 2026-04-23 13:24:33.293453+00 webhook/pushalarm 1 0 1 1 t \N \N +1224 2026-04-23 13:24:44.568816+00 webhook/pushalarm 1 0 1 1 t \N \N +1225 2026-04-23 13:25:17.635457+00 webhook/pushalarm 1 0 1 1 t \N \N +1226 2026-04-23 13:25:30.968658+00 webhook/pushalarm 1 0 1 1 t \N \N +1228 2026-04-23 13:25:37.504939+00 webhook/pushalarm 1 0 1 6 t \N \N +1229 2026-04-23 13:25:45.50816+00 webhook/pushalarm 1 0 1 0 t \N \N +1230 2026-04-23 13:25:51.817241+00 webhook/pushalarm 1 0 1 0 t \N \N +1244 2026-04-23 13:28:01.9258+00 webhook/pushalarm 1 0 1 0 t \N \N +1245 2026-04-23 13:28:12.651329+00 webhook/pushalarm 1 0 1 1 t \N \N +1246 2026-04-23 13:28:22.496366+00 webhook/pushalarm 1 0 1 1 t \N \N +1247 2026-04-23 13:28:23.435268+00 webhook/pushalarm 1 0 1 1 t \N \N +1250 2026-04-23 13:29:06.553179+00 webhook/pushalarm 1 0 1 1 t \N \N +1257 2026-04-23 13:30:45.05413+00 webhook/pushalarm 1 0 1 1 t \N \N +1261 2026-04-23 13:31:51.450856+00 webhook/pushalarm 1 0 1 1 t \N \N +1262 2026-04-23 13:31:57.59337+00 webhook/pushalarm 1 0 1 2 t \N \N +1265 2026-04-23 13:32:27.56684+00 webhook/pushalarm 1 0 1 1 t \N \N +1266 2026-04-23 13:32:37.319935+00 webhook/pushalarm 1 0 1 1 t \N \N +1267 2026-04-23 13:32:39.046268+00 webhook/pushalarm 1 0 1 1 t \N \N +88 2026-04-23 10:36:25.832836+00 webhook/pushalarm 1 0 1 1 t \N \N +89 2026-04-23 10:36:43.003989+00 webhook/pushalarm 1 0 1 1 t \N \N +91 2026-04-23 10:37:13.778213+00 webhook/pushalarm 1 0 1 1 t \N \N +92 2026-04-23 10:37:18.448261+00 webhook/pushalarm 1 0 1 1 t \N \N +93 2026-04-23 10:37:19.775789+00 webhook/pushalarm 1 0 1 1 t \N \N +94 2026-04-23 10:37:23.231336+00 webhook/pushalarm 1 0 1 1 t \N \N +96 2026-04-23 10:37:26.905114+00 webhook/pushalarm 1 0 1 1 t \N \N +97 2026-04-23 10:37:29.086999+00 webhook/pushalarm 1 0 1 1 t \N \N +99 2026-04-23 10:37:42.873202+00 webhook/pushalarm 1 0 1 1 t \N \N +100 2026-04-23 10:37:47.227847+00 webhook/pushalarm 1 0 1 1 t \N \N +101 2026-04-23 10:37:58.567658+00 webhook/pushalarm 1 0 1 1 t \N \N +102 2026-04-23 10:38:19.055158+00 webhook/pushalarm 1 0 1 1 t \N \N +104 2026-04-23 10:38:57.445964+00 webhook/pushalarm 1 0 1 0 t \N \N +1223 2026-04-23 13:24:34.670912+00 jimi.device.alarm.list 118 0 -147 903 t \N \N +1251 2026-04-23 13:29:35.576482+00 jimi.device.alarm.list 118 0 -138 784 t \N \N +90 2026-04-23 10:36:56.309426+00 webhook/pushalarm 1 0 1 1 t \N \N +98 2026-04-23 10:37:36.14343+00 webhook/pushalarm 1 0 1 1 t \N \N +106 2026-04-23 10:39:05.907821+00 webhook/pushalarm 1 0 1 1 t \N \N +107 2026-04-23 10:39:09.642503+00 webhook/pushalarm 1 0 1 1 t \N \N +108 2026-04-23 10:39:13.585947+00 webhook/pushalarm 1 0 1 1 t \N \N +1227 2026-04-23 13:25:31.765429+00 jimi.user.device.location.list 63 61 5 7494 t \N \N +1231 2026-04-23 13:26:05.207548+00 jimi.device.track.list 118 0 51 10507 t \N \N +1232 2026-04-23 13:26:08.016798+00 jimi.device.track.mileage 118 0 -68 4292 t \N \N +1234 2026-04-23 13:26:32.825934+00 jimi.user.device.location.list 63 61 2 249 t \N \N +1242 2026-04-23 13:27:33.087531+00 jimi.user.device.location.list 63 61 8 241 t \N \N +1248 2026-04-23 13:28:43.005242+00 jimi.open.platform.report.parking 118 0 0 21855 t \N \N +1249 2026-04-23 13:28:44.180909+00 jimi.user.device.location.list 63 61 8 212 t \N \N +1252 2026-04-23 13:29:44.420094+00 jimi.user.device.location.list 63 61 8 214 t \N \N +1256 2026-04-23 13:30:44.619975+00 jimi.user.device.location.list 63 61 7 183 t \N \N +1260 2026-04-23 13:31:44.860229+00 jimi.user.device.location.list 63 61 8 227 t \N \N +1268 2026-04-23 13:32:45.060859+00 jimi.user.device.location.list 63 61 9 171 t \N \N +105 2026-04-23 10:38:57.394836+00 jimi.device.alarm.list 91 0 -135 577 t \N \N +109 2026-04-23 10:39:22.296127+00 jimi.device.track.mileage 92 0 -58 3620 t \N \N +110 2026-04-23 10:39:38.383678+00 webhook/pushalarm 1 0 1 1 t \N \N +111 2026-04-23 10:39:38.723543+00 jimi.open.platform.report.parking 92 0 0 14556 t \N \N +112 2026-04-23 10:39:39.902271+00 jimi.user.device.location.list 63 61 8 213 t \N \N +113 2026-04-23 10:40:07.192575+00 webhook/pushalarm 1 0 1 1 t \N \N +114 2026-04-23 10:40:25.276579+00 webhook/pushalarm 1 0 1 3 t \N \N +115 2026-04-23 10:40:40.169684+00 webhook/pushalarm 1 0 1 1 t \N \N +116 2026-04-23 10:40:40.141309+00 jimi.user.device.location.list 63 61 8 227 t \N \N +117 2026-04-23 10:40:43.719646+00 webhook/pushalarm 1 0 1 1 t \N \N +118 2026-04-23 10:41:00.207177+00 webhook/pushalarm 1 0 1 0 t \N \N +119 2026-04-23 10:41:40.376717+00 jimi.user.device.location.list 63 61 6 217 t \N \N +120 2026-04-23 10:41:47.056343+00 webhook/pushalarm 1 0 1 1 t \N \N +121 2026-04-23 10:42:04.074474+00 webhook/pushalarm 1 0 1 1 t \N \N +122 2026-04-23 10:42:18.5831+00 webhook/pushalarm 1 0 1 1 t \N \N +123 2026-04-23 10:42:19.235922+00 webhook/pushalarm 1 0 1 3 t \N \N +124 2026-04-23 10:42:40.585872+00 jimi.user.device.location.list 63 61 6 196 t \N \N +125 2026-04-23 10:42:44.976491+00 webhook/pushalarm 1 0 1 1 t \N \N +126 2026-04-23 10:43:08.956411+00 webhook/pushalarm 1 0 1 1 t \N \N +127 2026-04-23 10:43:28.872634+00 webhook/pushalarm 1 0 1 1 t \N \N +128 2026-04-23 10:43:36.765166+00 webhook/pushalarm 1 0 1 1 t \N \N +129 2026-04-23 10:43:40.766746+00 jimi.user.device.location.list 63 61 6 156 t \N \N +130 2026-04-23 10:43:41.56367+00 webhook/pushalarm 1 0 1 1 t \N \N +131 2026-04-23 10:43:58.441362+00 webhook/pushalarm 1 0 1 1 t \N \N +132 2026-04-23 10:43:58.339409+00 jimi.device.alarm.list 95 0 -140 844 t \N \N +133 2026-04-23 10:44:07.777272+00 webhook/pushalarm 1 0 1 2 t \N \N +134 2026-04-23 10:44:10.60745+00 webhook/pushalarm 1 0 1 1 t \N \N +135 2026-04-23 10:44:12.766978+00 webhook/pushalarm 1 0 1 1 t \N \N +136 2026-04-23 10:44:19.189444+00 webhook/pushalarm 1 0 1 1 t \N \N +137 2026-04-23 10:44:40.213384+00 webhook/pushalarm 1 0 1 1 t \N \N +138 2026-04-23 10:44:40.993802+00 jimi.user.device.location.list 63 61 5 227 t \N \N +139 2026-04-23 10:44:54.668349+00 webhook/pushalarm 1 0 1 2 t \N \N +140 2026-04-23 10:44:56.392793+00 webhook/pushalarm 1 0 1 1 t \N \N +141 2026-04-23 10:45:04.594229+00 webhook/pushalarm 1 0 1 1 t \N \N +142 2026-04-23 10:45:10.37653+00 webhook/pushalarm 1 0 1 1 t \N \N +143 2026-04-23 10:45:11.850453+00 webhook/pushalarm 1 0 1 1 t \N \N +144 2026-04-23 10:45:21.454595+00 webhook/pushalarm 1 0 1 5 t \N \N +145 2026-04-23 10:45:40.464617+00 webhook/pushalarm 1 0 1 1 t \N \N +146 2026-04-23 10:45:41.200854+00 jimi.user.device.location.list 63 61 6 175 t \N \N +147 2026-04-23 10:45:52.444147+00 webhook/pushalarm 1 0 1 1 t \N \N +148 2026-04-23 10:45:56.019402+00 webhook/pushalarm 1 0 1 1 t \N \N +149 2026-04-23 10:46:06.825817+00 webhook/pushalarm 1 0 1 1 t \N \N +150 2026-04-23 10:46:13.186281+00 webhook/pushalarm 1 0 1 1 t \N \N +151 2026-04-23 10:46:15.007021+00 webhook/pushalarm 1 0 1 1 t \N \N +152 2026-04-23 10:46:15.342154+00 webhook/pushalarm 1 0 1 1 t \N \N +153 2026-04-23 10:46:30.359396+00 webhook/pushalarm 1 0 1 2 t \N \N +154 2026-04-23 10:46:39.073902+00 webhook/pushalarm 1 0 1 2 t \N \N +155 2026-04-23 10:46:41.405865+00 jimi.user.device.location.list 63 61 8 186 t \N \N +156 2026-04-23 10:46:56.560417+00 webhook/pushalarm 1 0 1 1 t \N \N +157 2026-04-23 10:46:58.213452+00 webhook/pushalarm 1 0 1 1 t \N \N +158 2026-04-23 10:47:23.902318+00 webhook/pushalarm 1 0 1 1 t \N \N +159 2026-04-23 10:47:27.536244+00 webhook/pushalarm 1 0 1 1 t \N \N +160 2026-04-23 10:47:40.895504+00 webhook/pushalarm 1 0 1 2 t \N \N +161 2026-04-23 10:47:41.598078+00 jimi.user.device.location.list 63 61 3 172 t \N \N +162 2026-04-23 10:48:03.954861+00 webhook/pushalarm 1 0 1 1 t \N \N +163 2026-04-23 10:48:06.753427+00 webhook/pushalarm 1 0 1 1 t \N \N +164 2026-04-23 10:48:09.537346+00 webhook/pushalarm 1 0 1 0 t \N \N +165 2026-04-23 10:48:12.414201+00 webhook/pushalarm 1 0 1 1 t \N \N +166 2026-04-23 10:48:27.049925+00 webhook/pushalarm 1 0 1 4 t \N \N +167 2026-04-23 10:48:27.410396+00 webhook/pushalarm 1 0 1 1 t \N \N +168 2026-04-23 10:48:31.028756+00 webhook/pushalarm 1 0 1 1 t \N \N +169 2026-04-23 10:48:37.954778+00 webhook/pushalarm 1 0 1 1 t \N \N +170 2026-04-23 10:48:38.313193+00 webhook/pushalarm 1 0 1 1 t \N \N +171 2026-04-23 10:48:41.773087+00 jimi.user.device.location.list 63 61 5 157 t \N \N +172 2026-04-23 10:48:58.63197+00 webhook/pushalarm 1 0 1 1 t \N \N +173 2026-04-23 10:48:59.108685+00 jimi.device.alarm.list 98 0 -156 725 t \N \N +174 2026-04-23 10:49:00.169937+00 webhook/pushalarm 1 0 1 1 t \N \N +175 2026-04-23 10:49:21.387551+00 webhook/pushalarm 1 0 1 1 t \N \N +176 2026-04-23 10:49:23.548936+00 webhook/pushalarm 1 0 1 1 t \N \N +177 2026-04-23 10:49:42.004608+00 jimi.user.device.location.list 63 61 8 215 t \N \N +178 2026-04-23 10:49:53.932099+00 webhook/pushalarm 1 0 1 1 t \N \N +179 2026-04-23 10:49:58.449469+00 webhook/pushalarm 1 0 1 1 t \N \N +180 2026-04-23 10:50:02.152481+00 webhook/pushalarm 1 0 1 5 t \N \N +181 2026-04-23 10:50:20.840815+00 webhook/pushalarm 1 0 1 1 t \N \N +182 2026-04-23 10:50:25.639416+00 webhook/pushalarm 1 0 1 1 t \N \N +183 2026-04-23 10:50:42.199281+00 jimi.user.device.location.list 63 61 7 172 t \N \N +184 2026-04-23 10:50:44.605571+00 webhook/pushalarm 1 0 1 0 t \N \N +185 2026-04-23 10:51:08.665273+00 webhook/pushalarm 1 0 1 1 t \N \N +186 2026-04-23 10:51:08.74392+00 webhook/pushalarm 1 0 1 3 t \N \N +187 2026-04-23 10:51:18.245194+00 webhook/pushalarm 1 0 1 1 t \N \N +188 2026-04-23 10:51:20.524907+00 webhook/pushalarm 1 0 1 1 t \N \N +189 2026-04-23 10:51:36.307625+00 webhook/pushalarm 1 0 1 1 t \N \N +190 2026-04-23 10:51:42.404284+00 jimi.user.device.location.list 63 61 3 188 t \N \N +191 2026-04-23 10:52:10.189668+00 webhook/pushalarm 1 0 1 1 t \N \N +192 2026-04-23 10:52:15.027963+00 webhook/pushalarm 1 0 1 1 t \N \N +193 2026-04-23 10:52:18.738221+00 webhook/pushalarm 1 0 1 1 t \N \N +194 2026-04-23 10:52:42.635112+00 jimi.user.device.location.list 63 61 5 241 t \N \N +201 2026-04-23 10:53:42.850191+00 jimi.user.device.location.list 63 61 5 172 t \N \N +204 2026-04-23 10:54:29.290717+00 jimi.device.track.list 101 0 469 8498 t \N \N +206 2026-04-23 10:54:32.11435+00 jimi.device.track.mileage 101 0 -63 4279 t \N \N +209 2026-04-23 10:55:01.483817+00 jimi.open.platform.report.parking 101 0 0 21803 t \N \N +211 2026-04-23 10:55:02.634418+00 jimi.user.device.location.list 63 61 5 201 t \N \N +218 2026-04-23 10:56:02.871474+00 jimi.user.device.location.list 63 61 7 196 t \N \N +229 2026-04-23 10:57:03.097616+00 jimi.user.device.location.list 63 61 5 215 t \N \N +236 2026-04-23 10:58:03.30256+00 jimi.user.device.location.list 63 61 4 173 t \N \N +1233 2026-04-23 13:26:24.188872+00 webhook/pushalarm 1 0 1 1 t \N \N +1235 2026-04-23 13:26:37.054248+00 webhook/pushalarm 1 0 1 1 t \N \N +1236 2026-04-23 13:26:45.177295+00 webhook/pushalarm 1 0 1 1 t \N \N +1237 2026-04-23 13:26:48.153495+00 webhook/pushalarm 1 0 1 1 t \N \N +1238 2026-04-23 13:26:50.704395+00 webhook/pushalarm 1 0 1 1 t \N \N +1239 2026-04-23 13:26:53.881375+00 webhook/pushalarm 1 0 1 1 t \N \N +1240 2026-04-23 13:27:06.538654+00 webhook/pushalarm 1 0 1 1 t \N \N +1241 2026-04-23 13:27:24.04331+00 webhook/pushalarm 1 0 1 1 t \N \N +1243 2026-04-23 13:27:46.040366+00 webhook/pushalarm 1 0 1 1 t \N \N +1253 2026-04-23 13:29:51.919973+00 webhook/pushalarm 1 0 1 3 t \N \N +1254 2026-04-23 13:30:28.350996+00 webhook/pushalarm 1 0 1 3 t \N \N +1255 2026-04-23 13:30:31.980318+00 webhook/pushalarm 1 0 1 1 t \N \N +1258 2026-04-23 13:30:59.172476+00 webhook/pushalarm 1 0 1 1 t \N \N +1259 2026-04-23 13:31:19.084542+00 webhook/pushalarm 1 0 1 2 t \N \N +1263 2026-04-23 13:32:07.313108+00 webhook/pushalarm 1 0 1 2 t \N \N +1264 2026-04-23 13:32:21.600237+00 webhook/pushalarm 1 0 1 1 t \N \N +195 2026-04-23 10:53:15.834798+00 webhook/pushalarm 1 0 1 1 t \N \N +203 2026-04-23 10:54:12.160021+00 webhook/pushalarm 1 0 1 1 t \N \N +205 2026-04-23 10:54:34.626388+00 webhook/pushalarm 1 0 1 1 t \N \N +210 2026-04-23 10:55:01.745225+00 webhook/pushalarm 1 0 1 1 t \N \N +212 2026-04-23 10:55:03.857849+00 webhook/pushalarm 1 0 1 1 t \N \N +213 2026-04-23 10:55:03.944903+00 webhook/pushalarm 1 0 1 1 t \N \N +214 2026-04-23 10:55:22.845912+00 webhook/pushalarm 1 0 1 0 t \N \N +219 2026-04-23 10:56:03.288768+00 webhook/pushalarm 1 0 1 1 t \N \N +220 2026-04-23 10:56:03.840923+00 webhook/pushalarm 1 0 1 1 t \N \N +225 2026-04-23 10:56:27.75897+00 webhook/pushalarm 1 0 1 2 t \N \N +226 2026-04-23 10:56:37.983314+00 webhook/pushalarm 1 0 1 1 t \N \N +227 2026-04-23 10:56:59.910387+00 webhook/pushalarm 1 0 1 1 t \N \N +228 2026-04-23 10:57:02.049262+00 webhook/pushalarm 1 0 1 1 t \N \N +230 2026-04-23 10:57:32.550587+00 webhook/pushalarm 1 0 1 1 t \N \N +231 2026-04-23 10:57:51.748233+00 webhook/pushalarm 1 0 1 1 t \N \N +232 2026-04-23 10:57:56.318133+00 webhook/pushalarm 1 0 1 1 t \N \N +233 2026-04-23 10:57:58.966863+00 webhook/pushalarm 1 0 1 1 t \N \N +234 2026-04-23 10:57:59.904684+00 webhook/pushalarm 1 0 1 1 t \N \N +235 2026-04-23 10:58:01.532038+00 webhook/pushalarm 1 0 1 2 t \N \N +237 2026-04-23 10:58:04.81593+00 webhook/pushalarm 1 0 1 2 t \N \N +238 2026-04-23 10:58:08.615422+00 webhook/pushalarm 1 0 1 1 t \N \N +1269 2026-04-23 13:32:50.186848+00 webhook/pushalarm 1 0 1 1 t \N \N +1270 2026-04-23 13:32:52.674181+00 webhook/pushalarm 1 0 1 1 t \N \N +1272 2026-04-23 13:33:22.551649+00 webhook/pushalarm 1 0 1 1 t \N \N +1273 2026-04-23 13:33:27.523607+00 webhook/pushalarm 1 0 1 1 t \N \N +1276 2026-04-23 13:34:14.061689+00 webhook/pushalarm 1 0 1 1 t \N \N +1277 2026-04-23 13:34:28.759749+00 webhook/pushalarm 1 0 1 0 t \N \N +1278 2026-04-23 13:34:35.182422+00 webhook/pushalarm 1 0 1 1 t \N \N +1281 2026-04-23 13:35:12.991571+00 webhook/pushalarm 1 0 1 1 t \N \N +1285 2026-04-23 13:35:36.895589+00 webhook/pushalarm 1 0 1 1 t \N \N +1294 2026-04-23 13:37:39.118129+00 webhook/pushalarm 1 0 1 1 t \N \N +1296 2026-04-23 13:37:50.731176+00 webhook/pushalarm 1 0 1 1 t \N \N +1297 2026-04-23 13:37:52.017975+00 webhook/pushalarm 1 0 1 1 t \N \N +1298 2026-04-23 13:38:00.03846+00 webhook/pushalarm 1 0 1 1 t \N \N +1301 2026-04-23 13:38:50.501925+00 webhook/pushalarm 1 0 1 1 t \N \N +1306 2026-04-23 13:39:53.596061+00 webhook/pushalarm 1 0 1 1 t \N \N +1307 2026-04-23 13:40:23.127409+00 webhook/pushalarm 1 0 1 1 t \N \N +1311 2026-04-23 13:41:08.580384+00 webhook/pushalarm 1 0 1 1 t \N \N +1313 2026-04-23 13:41:36.010861+00 webhook/pushalarm 1 0 1 1 t \N \N +1314 2026-04-23 13:41:43.493927+00 webhook/pushalarm 1 0 1 1 t \N \N +1316 2026-04-23 13:42:03.026927+00 webhook/pushalarm 1 0 1 1 t \N \N +1320 2026-04-23 13:43:31.168672+00 webhook/pushalarm 1 0 1 1 t \N \N +1322 2026-04-23 13:43:55.004647+00 webhook/pushalarm 1 0 1 1 t \N \N +1323 2026-04-23 13:43:56.713693+00 webhook/pushalarm 1 0 1 0 t \N \N +1324 2026-04-23 13:43:57.244366+00 webhook/pushalarm 1 0 1 1 t \N \N +1325 2026-04-23 13:43:57.650405+00 webhook/pushalarm 1 0 1 1 t \N \N +1332 2026-04-23 13:44:33.616561+00 webhook/pushalarm 1 0 1 1 t \N \N +1333 2026-04-23 13:44:34.851507+00 webhook/pushalarm 1 0 1 1 t \N \N +1335 2026-04-23 13:44:54.251906+00 webhook/pushalarm 1 0 1 0 t \N \N +1338 2026-04-23 13:45:44.168567+00 webhook/pushalarm 1 0 1 1 t \N \N +1341 2026-04-23 13:46:05.875634+00 webhook/pushalarm 1 0 1 1 t \N \N +1346 2026-04-23 13:47:42.825938+00 webhook/pushalarm 1 0 1 1 t \N \N +1347 2026-04-23 13:47:55.396845+00 webhook/pushalarm 1 0 1 1 t \N \N +1348 2026-04-23 13:47:55.602043+00 webhook/pushalarm 1 0 1 2 t \N \N +1350 2026-04-23 13:48:38.012768+00 webhook/pushalarm 1 0 1 1 t \N \N +1351 2026-04-23 13:48:40.87074+00 webhook/pushalarm 1 0 1 1 t \N \N +1360 2026-04-23 13:50:24.21992+00 webhook/pushalarm 1 0 1 1 t \N \N +1367 2026-04-23 13:51:41.459919+00 webhook/pushalarm 1 0 1 1 t \N \N +1376 2026-04-23 13:52:25.797434+00 webhook/pushalarm 1 0 1 1 t \N \N +1377 2026-04-23 13:52:39.825807+00 webhook/pushalarm 1 0 1 2 t \N \N +1378 2026-04-23 13:52:40.624003+00 webhook/pushalarm 1 0 1 2 t \N \N +1379 2026-04-23 13:52:46.204507+00 webhook/pushalarm 1 0 1 2 t \N \N +1393 2026-04-23 13:55:14.248003+00 webhook/pushalarm 1 0 1 1 t \N \N +1394 2026-04-23 13:55:16.90596+00 webhook/pushalarm 1 0 1 1 t \N \N +1396 2026-04-23 13:55:54.329193+00 webhook/pushalarm 1 0 1 1 t \N \N +1400 2026-04-23 13:56:28.820937+00 webhook/pushalarm 1 0 1 2 t \N \N +1401 2026-04-23 13:56:39.04207+00 webhook/pushalarm 1 0 1 1 t \N \N +196 2026-04-23 10:53:26.35683+00 webhook/pushalarm 1 0 1 1 t \N \N +197 2026-04-23 10:53:27.653953+00 webhook/pushalarm 1 0 1 1 t \N \N +198 2026-04-23 10:53:31.102315+00 webhook/pushalarm 1 0 1 1 t \N \N +199 2026-04-23 10:53:38.37469+00 webhook/pushalarm 1 0 1 1 t \N \N +200 2026-04-23 10:53:42.501573+00 webhook/pushalarm 1 0 1 1 t \N \N +207 2026-04-23 10:54:41.63532+00 webhook/pushalarm 1 0 1 1 t \N \N +208 2026-04-23 10:54:42.39286+00 webhook/pushalarm 1 0 1 1 t \N \N +215 2026-04-23 10:55:36.704574+00 webhook/pushalarm 1 0 1 0 t \N \N +216 2026-04-23 10:55:40.227234+00 webhook/pushalarm 1 0 1 1 t \N \N +217 2026-04-23 10:55:51.612563+00 webhook/pushalarm 1 0 1 1 t \N \N +221 2026-04-23 10:56:12.565735+00 webhook/pushalarm 1 0 1 1 t \N \N +222 2026-04-23 10:56:16.061195+00 webhook/pushalarm 1 0 1 1 t \N \N +223 2026-04-23 10:56:21.606103+00 webhook/pushalarm 1 0 1 1 t \N \N +224 2026-04-23 10:56:21.913803+00 webhook/pushalarm 1 0 1 2 t \N \N +1271 2026-04-23 13:33:15.01051+00 webhook/pushalarm 1 0 1 0 t \N \N +1274 2026-04-23 13:33:44.218045+00 webhook/pushalarm 1 0 1 1 t \N \N +1282 2026-04-23 13:35:23.878995+00 webhook/pushalarm 1 0 1 1 t \N \N +1283 2026-04-23 13:35:28.019411+00 webhook/pushalarm 1 0 1 1 t \N \N +1284 2026-04-23 13:35:28.129385+00 webhook/pushalarm 1 0 1 1 t \N \N +1287 2026-04-23 13:35:54.589969+00 webhook/pushalarm 1 0 1 2 t \N \N +1289 2026-04-23 13:36:51.378206+00 webhook/pushalarm 1 0 1 1 t \N \N +1290 2026-04-23 13:36:53.190129+00 webhook/pushalarm 1 0 1 1 t \N \N +1291 2026-04-23 13:37:03.935059+00 webhook/pushalarm 1 0 1 2 t \N \N +1292 2026-04-23 13:37:04.094538+00 webhook/pushalarm 1 0 1 1 t \N \N +1293 2026-04-23 13:37:33.047062+00 webhook/pushalarm 1 0 1 1 t \N \N +1299 2026-04-23 13:38:21.108237+00 webhook/pushalarm 1 0 1 1 t \N \N +1302 2026-04-23 13:38:58.523495+00 webhook/pushalarm 1 0 1 1 t \N \N +1303 2026-04-23 13:39:16.024025+00 webhook/pushalarm 1 0 1 1 t \N \N +1308 2026-04-23 13:40:44.219847+00 webhook/pushalarm 1 0 1 1 t \N \N +1310 2026-04-23 13:40:55.333435+00 webhook/pushalarm 1 0 1 1 t \N \N +1317 2026-04-23 13:42:09.149028+00 webhook/pushalarm 1 0 1 1 t \N \N +1318 2026-04-23 13:42:13.755685+00 webhook/pushalarm 1 0 1 3 t \N \N +1321 2026-04-23 13:43:46.758084+00 webhook/pushalarm 1 0 1 0 t \N \N +1328 2026-04-23 13:44:07.204102+00 webhook/pushalarm 1 0 1 0 t \N \N +1329 2026-04-23 13:44:08.795521+00 webhook/pushalarm 1 0 1 1 t \N \N +1330 2026-04-23 13:44:13.099812+00 webhook/pushalarm 1 0 1 2 t \N \N +1331 2026-04-23 13:44:24.318444+00 webhook/pushalarm 1 0 1 1 t \N \N +1337 2026-04-23 13:45:25.121935+00 webhook/pushalarm 1 0 1 3 t \N \N +1339 2026-04-23 13:45:58.453952+00 webhook/pushalarm 1 0 1 1 t \N \N +1340 2026-04-23 13:45:59.586733+00 webhook/pushalarm 1 0 1 1 t \N \N +1343 2026-04-23 13:46:54.191195+00 webhook/pushalarm 1 0 1 3 t \N \N +1345 2026-04-23 13:47:30.272603+00 webhook/pushalarm 1 0 1 1 t \N \N +1352 2026-04-23 13:48:52.401378+00 webhook/pushalarm 1 0 1 1 t \N \N +1353 2026-04-23 13:48:57.604144+00 webhook/pushalarm 1 0 1 1 t \N \N +1355 2026-04-23 13:49:34.769902+00 webhook/pushalarm 1 0 1 1 t \N \N +1357 2026-04-23 13:49:53.193084+00 webhook/pushalarm 1 0 1 1 t \N \N +1359 2026-04-23 13:50:12.807425+00 webhook/pushalarm 1 0 1 1 t \N \N +1361 2026-04-23 13:50:56.868382+00 webhook/pushalarm 1 0 1 1 t \N \N +1362 2026-04-23 13:50:59.313164+00 webhook/pushalarm 1 0 1 1 t \N \N +1364 2026-04-23 13:51:26.135+00 webhook/pushalarm 1 0 1 2 t \N \N +1365 2026-04-23 13:51:32.150345+00 webhook/pushalarm 1 0 1 1 t \N \N +1366 2026-04-23 13:51:34.365526+00 webhook/pushalarm 1 0 1 1 t \N \N +1368 2026-04-23 13:51:53.541493+00 webhook/pushalarm 1 0 1 0 t \N \N +1369 2026-04-23 13:51:54.234602+00 webhook/pushalarm 1 0 1 1 t \N \N +1370 2026-04-23 13:51:56.056488+00 webhook/pushalarm 1 0 1 1 t \N \N +1371 2026-04-23 13:51:59.39183+00 webhook/pushalarm 1 0 1 1 t \N \N +1373 2026-04-23 13:52:09.731276+00 webhook/pushalarm 1 0 1 1 t \N \N +1374 2026-04-23 13:52:12.48139+00 webhook/pushalarm 1 0 1 1 t \N \N +1375 2026-04-23 13:52:14.154981+00 webhook/pushalarm 1 0 1 1 t \N \N +1380 2026-04-23 13:52:58.75393+00 webhook/pushalarm 1 0 1 0 t \N \N +1382 2026-04-23 13:53:19.081687+00 webhook/pushalarm 1 0 1 1 t \N \N +1383 2026-04-23 13:53:39.135417+00 webhook/pushalarm 1 0 1 0 t \N \N +1384 2026-04-23 13:53:39.34575+00 webhook/pushalarm 1 0 1 0 t \N \N +1385 2026-04-23 13:53:56.085304+00 webhook/pushalarm 1 0 1 1 t \N \N +1386 2026-04-23 13:54:00.20097+00 webhook/pushalarm 1 0 1 1 t \N \N +1387 2026-04-23 13:54:02.562401+00 webhook/pushalarm 1 0 1 2 t \N \N +1389 2026-04-23 13:54:19.481474+00 webhook/pushalarm 1 0 1 1 t \N \N +1391 2026-04-23 13:54:45.151639+00 webhook/pushalarm 1 0 1 1 t \N \N +1395 2026-04-23 13:55:24.094264+00 webhook/pushalarm 1 0 1 2 t \N \N +1402 2026-04-23 13:56:45.243594+00 webhook/pushalarm 1 0 1 1 t \N \N +1403 2026-04-23 13:56:52.924183+00 webhook/pushalarm 1 0 1 1 t \N \N +1404 2026-04-23 13:57:10.800277+00 webhook/pushalarm 1 0 1 1 t \N \N +1406 2026-04-23 13:57:23.851668+00 webhook/pushalarm 1 0 1 1 t \N \N +202 2026-04-23 10:54:00.191865+00 jimi.device.alarm.list 101 0 -159 1492 t \N \N +239 2026-04-23 10:58:12.575165+00 webhook/pushalarm 1 0 1 1 t \N \N +240 2026-04-23 10:58:12.812931+00 webhook/pushalarm 1 0 1 1 t \N \N +241 2026-04-23 10:58:45.093112+00 webhook/pushalarm 1 0 1 1 t \N \N +242 2026-04-23 10:58:51.181769+00 webhook/pushalarm 1 0 1 2 t \N \N +243 2026-04-23 10:59:01.490835+00 jimi.device.alarm.list 103 0 -163 904 t \N \N +244 2026-04-23 10:59:03.522963+00 jimi.user.device.location.list 63 61 5 205 t \N \N +245 2026-04-23 10:59:31.994216+00 webhook/pushalarm 1 0 1 1 t \N \N +246 2026-04-23 10:59:35.528789+00 webhook/pushalarm 1 0 1 3 t \N \N +247 2026-04-23 10:59:35.725915+00 webhook/pushalarm 1 0 1 1 t \N \N +248 2026-04-23 10:59:54.99037+00 webhook/pushalarm 1 0 1 1 t \N \N +249 2026-04-23 11:00:03.467945+00 webhook/pushalarm 1 0 1 2 t \N \N +250 2026-04-23 11:00:03.790235+00 jimi.user.device.location.list 63 61 6 281 t \N \N +251 2026-04-23 11:00:08.769463+00 webhook/pushalarm 1 0 1 1 t \N \N +252 2026-04-23 11:00:14.848068+00 webhook/pushalarm 1 0 1 1 t \N \N +253 2026-04-23 11:00:16.757462+00 webhook/pushalarm 1 0 1 1 t \N \N +254 2026-04-23 11:00:21.683122+00 webhook/pushalarm 1 0 1 1 t \N \N +255 2026-04-23 11:00:23.778683+00 webhook/pushalarm 1 0 1 1 t \N \N +256 2026-04-23 11:00:30.892508+00 webhook/pushalarm 1 0 1 1 t \N \N +257 2026-04-23 11:00:54.349508+00 webhook/pushalarm 1 0 1 1 t \N \N +258 2026-04-23 11:01:04.017021+00 jimi.user.device.location.list 63 61 7 168 t \N \N +259 2026-04-23 11:01:38.30331+00 webhook/pushalarm 1 0 1 4 t \N \N +260 2026-04-23 11:01:41.370707+00 webhook/pushalarm 1 0 1 0 t \N \N +261 2026-04-23 11:01:45.007986+00 webhook/pushalarm 1 0 1 1 t \N \N +262 2026-04-23 11:01:51.907157+00 webhook/pushalarm 1 0 1 1 t \N \N +263 2026-04-23 11:01:53.869927+00 webhook/pushalarm 1 0 1 4 t \N \N +264 2026-04-23 11:01:56.169815+00 webhook/pushalarm 1 0 1 1 t \N \N +265 2026-04-23 11:02:04.219331+00 jimi.user.device.location.list 63 61 9 175 t \N \N +266 2026-04-23 11:02:19.094364+00 webhook/pushalarm 1 0 1 1 t \N \N +267 2026-04-23 11:02:37.650273+00 webhook/pushalarm 1 0 1 1 t \N \N +268 2026-04-23 11:02:48.415276+00 webhook/pushalarm 1 0 1 1 t \N \N +269 2026-04-23 11:02:51.408105+00 webhook/pushalarm 1 0 1 3 t \N \N +270 2026-04-23 11:02:59.163313+00 webhook/pushalarm 1 0 1 1 t \N \N +271 2026-04-23 11:03:04.501362+00 jimi.user.device.location.list 63 61 6 268 t \N \N +272 2026-04-23 11:03:19.18092+00 webhook/pushalarm 1 0 1 1 t \N \N +273 2026-04-23 11:03:50.091794+00 webhook/pushalarm 1 0 1 1 t \N \N +274 2026-04-23 11:04:02.44253+00 jimi.device.alarm.list 104 0 -162 841 t \N \N +275 2026-04-23 11:04:04.744389+00 jimi.user.device.location.list 63 61 5 219 t \N \N +276 2026-04-23 11:04:11.474974+00 webhook/pushalarm 1 0 1 1 t \N \N +277 2026-04-23 11:04:12.538702+00 webhook/pushalarm 1 0 1 1 t \N \N +278 2026-04-23 11:04:13.865539+00 webhook/pushalarm 1 0 1 1 t \N \N +279 2026-04-23 11:04:14.887253+00 webhook/pushalarm 1 0 1 1 t \N \N +280 2026-04-23 11:04:40.618444+00 webhook/pushalarm 1 0 1 1 t \N \N +281 2026-04-23 11:04:41.043288+00 webhook/pushalarm 1 0 1 1 t \N \N +282 2026-04-23 11:04:51.525563+00 webhook/pushalarm 1 0 1 1 t \N \N +283 2026-04-23 11:04:54.058921+00 webhook/pushalarm 1 0 1 3 t \N \N +284 2026-04-23 11:04:57.727454+00 webhook/pushalarm 1 0 1 1 t \N \N +285 2026-04-23 11:05:03.24254+00 webhook/pushalarm 1 0 1 1 t \N \N +286 2026-04-23 11:05:04.946385+00 jimi.user.device.location.list 63 61 8 189 t \N \N +287 2026-04-23 11:05:08.655984+00 webhook/pushalarm 1 0 1 1 t \N \N +288 2026-04-23 11:05:12.266962+00 webhook/pushalarm 1 0 1 1 t \N \N +289 2026-04-23 11:05:20.327363+00 webhook/pushalarm 1 0 1 1 t \N \N +290 2026-04-23 11:05:24.789733+00 webhook/pushalarm 1 0 1 1 t \N \N +291 2026-04-23 11:05:38.032513+00 webhook/pushalarm 1 0 1 1 t \N \N +292 2026-04-23 11:05:45.948217+00 webhook/pushalarm 1 0 1 1 t \N \N +293 2026-04-23 11:05:55.727581+00 webhook/pushalarm 1 0 1 1 t \N \N +294 2026-04-23 11:05:59.083518+00 webhook/pushalarm 1 0 1 1 t \N \N +295 2026-04-23 11:06:04.445403+00 webhook/pushalarm 1 0 1 1 t \N \N +296 2026-04-23 11:06:05.176943+00 jimi.user.device.location.list 63 61 9 215 t \N \N +297 2026-04-23 11:06:10.152494+00 webhook/pushalarm 1 0 1 1 t \N \N +298 2026-04-23 11:06:16.418001+00 webhook/pushalarm 1 0 1 2 t \N \N +299 2026-04-23 11:06:39.929334+00 webhook/pushalarm 1 0 1 1 t \N \N +300 2026-04-23 11:07:05.390747+00 jimi.user.device.location.list 63 61 9 190 t \N \N +301 2026-04-23 11:07:17.168825+00 webhook/pushalarm 1 0 1 2 t \N \N +302 2026-04-23 11:07:18.687247+00 webhook/pushalarm 1 0 1 1 t \N \N +303 2026-04-23 11:07:38.796791+00 webhook/pushalarm 1 0 1 1 t \N \N +304 2026-04-23 11:07:58.994507+00 webhook/pushalarm 1 0 1 1 t \N \N +305 2026-04-23 11:08:03.043908+00 webhook/pushalarm 1 0 1 1 t \N \N +306 2026-04-23 11:08:05.628329+00 jimi.user.device.location.list 63 61 7 218 t \N \N +307 2026-04-23 11:08:13.267024+00 webhook/pushalarm 1 0 1 1 t \N \N +308 2026-04-23 11:08:13.907264+00 webhook/pushalarm 1 0 1 1 t \N \N +309 2026-04-23 11:08:14.170685+00 webhook/pushalarm 1 0 1 0 t \N \N +310 2026-04-23 11:09:01.264476+00 webhook/pushalarm 1 0 1 2 t \N \N +311 2026-04-23 11:09:01.631697+00 webhook/pushalarm 1 0 1 2 t \N \N +312 2026-04-23 11:09:03.286277+00 jimi.device.alarm.list 104 0 -164 773 t \N \N +313 2026-04-23 11:09:04.908692+00 webhook/pushalarm 1 0 1 1 t \N \N +314 2026-04-23 11:09:05.849288+00 jimi.user.device.location.list 63 61 8 216 t \N \N +315 2026-04-23 11:09:08.198516+00 webhook/pushalarm 1 0 1 4 t \N \N +316 2026-04-23 11:09:20.07277+00 webhook/pushalarm 1 0 1 1 t \N \N +317 2026-04-23 11:09:28.555421+00 webhook/pushalarm 1 0 1 1 t \N \N +318 2026-04-23 11:09:28.911404+00 webhook/pushalarm 1 0 1 1 t \N \N +319 2026-04-23 11:09:36.445771+00 webhook/pushalarm 1 0 1 1 t \N \N +320 2026-04-23 11:09:38.16728+00 webhook/pushalarm 1 0 1 1 t \N \N +321 2026-04-23 11:09:36.391704+00 jimi.device.track.mileage 104 0 -76 4367 t \N \N +322 2026-04-23 11:10:00.451452+00 webhook/pushalarm 1 0 1 2 t \N \N +323 2026-04-23 11:10:24.07089+00 jimi.open.platform.report.parking 104 0 0 21782 t \N \N +324 2026-04-23 11:10:25.241759+00 jimi.user.device.location.list 63 61 9 215 t \N \N +327 2026-04-23 11:11:25.461655+00 jimi.user.device.location.list 63 61 8 200 t \N \N +331 2026-04-23 11:12:25.646618+00 jimi.user.device.location.list 63 61 7 176 t \N \N +335 2026-04-23 11:13:25.876566+00 jimi.user.device.location.list 63 61 7 215 t \N \N +340 2026-04-23 11:14:26.071618+00 jimi.user.device.location.list 63 61 9 172 t \N \N +350 2026-04-23 11:15:26.320389+00 jimi.user.device.location.list 63 61 7 226 t \N \N +357 2026-04-23 11:16:26.573076+00 jimi.user.device.location.list 63 61 8 234 t \N \N +365 2026-04-23 11:17:26.787369+00 jimi.user.device.location.list 63 61 7 198 t \N \N +370 2026-04-23 11:18:27.01793+00 jimi.user.device.location.list 63 61 6 207 t \N \N +376 2026-04-23 11:19:27.309592+00 jimi.user.device.location.list 63 61 5 273 t \N \N +382 2026-04-23 11:20:27.493607+00 jimi.user.device.location.list 63 61 6 163 t \N \N +389 2026-04-23 11:21:27.721631+00 jimi.user.device.location.list 63 61 5 218 t \N \N +1275 2026-04-23 13:33:45.348189+00 jimi.user.device.location.list 63 61 9 307 t \N \N +1280 2026-04-23 13:34:45.668145+00 jimi.user.device.location.list 63 61 9 285 t \N \N +1286 2026-04-23 13:35:45.888683+00 jimi.user.device.location.list 63 61 9 202 t \N \N +1288 2026-04-23 13:36:46.262922+00 jimi.user.device.location.list 63 61 8 359 t \N \N +1295 2026-04-23 13:37:46.538493+00 jimi.user.device.location.list 63 61 10 238 t \N \N +1300 2026-04-23 13:38:46.765986+00 jimi.user.device.location.list 63 61 9 201 t \N \N +1305 2026-04-23 13:39:47.015319+00 jimi.user.device.location.list 63 61 7 226 t \N \N +1309 2026-04-23 13:40:47.231709+00 jimi.user.device.location.list 63 61 8 199 t \N \N +1312 2026-04-23 13:41:12.699355+00 jimi.device.track.mileage 118 0 -65 4359 t \N \N +1315 2026-04-23 13:41:47.807001+00 jimi.user.device.location.list 63 61 6 205 t \N \N +1319 2026-04-23 13:42:48.037633+00 jimi.user.device.location.list 63 61 8 213 t \N \N +1326 2026-04-23 13:44:04.890632+00 jimi.open.platform.report.parking 118 0 0 21783 t \N \N +1327 2026-04-23 13:44:06.031848+00 jimi.user.device.location.list 63 61 9 180 t \N \N +1336 2026-04-23 13:45:06.27576+00 jimi.user.device.location.list 63 61 8 223 t \N \N +1342 2026-04-23 13:46:06.503693+00 jimi.user.device.location.list 63 61 7 225 t \N \N +1344 2026-04-23 13:47:06.740931+00 jimi.user.device.location.list 63 61 7 202 t \N \N +1349 2026-04-23 13:48:06.924489+00 jimi.user.device.location.list 63 61 7 167 t \N \N +1354 2026-04-23 13:49:07.146736+00 jimi.user.device.location.list 63 61 8 220 t \N \N +1358 2026-04-23 13:50:07.406521+00 jimi.user.device.location.list 63 61 7 219 t \N \N +1363 2026-04-23 13:51:07.622598+00 jimi.user.device.location.list 63 61 8 207 t \N \N +1372 2026-04-23 13:52:07.890789+00 jimi.user.device.location.list 63 61 10 237 t \N \N +1381 2026-04-23 13:53:08.109686+00 jimi.user.device.location.list 63 61 8 203 t \N \N +1388 2026-04-23 13:54:08.373798+00 jimi.user.device.location.list 63 61 7 236 t \N \N +1392 2026-04-23 13:55:08.551457+00 jimi.user.device.location.list 63 61 7 167 t \N \N +1397 2026-04-23 13:56:16.24374+00 jimi.device.track.list 119 0 433 10772 t \N \N +1398 2026-04-23 13:56:17.547509+00 jimi.user.device.location.list 63 61 3 217 t \N \N +1399 2026-04-23 13:56:19.217141+00 jimi.device.track.mileage 119 0 -61 4430 t \N \N +1405 2026-04-23 13:57:18.178462+00 jimi.user.device.location.list 63 61 7 172 t \N \N +325 2026-04-23 11:10:45.643131+00 webhook/pushalarm 1 0 1 1 t \N \N +329 2026-04-23 11:11:58.866927+00 webhook/pushalarm 1 0 1 1 t \N \N +351 2026-04-23 11:15:43.709512+00 webhook/pushalarm 1 0 1 1 t \N \N +352 2026-04-23 11:15:44.711301+00 webhook/pushalarm 1 0 1 1 t \N \N +353 2026-04-23 11:15:49.1392+00 webhook/pushalarm 1 0 1 1 t \N \N +354 2026-04-23 11:16:03.730519+00 webhook/pushalarm 1 0 1 1 t \N \N +377 2026-04-23 11:19:51.77385+00 webhook/pushalarm 1 0 1 1 t \N \N +381 2026-04-23 11:20:25.939244+00 webhook/pushalarm 1 0 1 3 t \N \N +383 2026-04-23 11:20:58.818192+00 webhook/pushalarm 1 0 1 1 t \N \N +385 2026-04-23 11:21:17.085035+00 webhook/pushalarm 1 0 1 1 t \N \N +386 2026-04-23 11:21:17.870283+00 webhook/pushalarm 1 0 1 1 t \N \N +387 2026-04-23 11:21:25.280248+00 webhook/pushalarm 1 0 1 1 t \N \N +388 2026-04-23 11:21:25.75713+00 webhook/pushalarm 1 0 1 1 t \N \N +390 2026-04-23 11:21:31.047758+00 webhook/pushalarm 1 0 1 1 t \N \N +391 2026-04-23 11:21:33.095858+00 webhook/pushalarm 1 0 1 1 t \N \N +392 2026-04-23 11:22:00.676215+00 webhook/pushalarm 1 0 1 1 t \N \N +393 2026-04-23 11:22:01.975796+00 webhook/pushalarm 1 0 1 1 t \N \N +394 2026-04-23 11:22:02.641609+00 webhook/pushalarm 1 0 1 1 t \N \N +395 2026-04-23 11:22:07.568836+00 webhook/pushalarm 1 0 1 1 t \N \N +1279 2026-04-23 13:34:36.40955+00 jimi.device.alarm.list 118 0 -135 783 t \N \N +1304 2026-04-23 13:39:37.369912+00 jimi.device.alarm.list 118 0 -127 850 t \N \N +1334 2026-04-23 13:44:38.308191+00 jimi.device.alarm.list 118 0 -125 846 t \N \N +1356 2026-04-23 13:49:39.182175+00 jimi.device.alarm.list 118 0 -119 886 t \N \N +1390 2026-04-23 13:54:40.127209+00 jimi.device.alarm.list 119 0 -127 759 t \N \N +326 2026-04-23 11:11:05.056423+00 webhook/pushalarm 1 0 1 1 t \N \N +328 2026-04-23 11:11:27.224417+00 webhook/pushalarm 1 0 1 1 t \N \N +330 2026-04-23 11:12:05.24806+00 webhook/pushalarm 1 0 1 0 t \N \N +332 2026-04-23 11:12:37.037564+00 webhook/pushalarm 1 0 1 1 t \N \N +333 2026-04-23 11:13:20.629767+00 webhook/pushalarm 1 0 1 1 t \N \N +334 2026-04-23 11:13:20.712736+00 webhook/pushalarm 1 0 1 1 t \N \N +336 2026-04-23 11:14:04.175934+00 jimi.device.alarm.list 104 0 -164 724 t \N \N +337 2026-04-23 11:14:15.974532+00 webhook/pushalarm 1 0 1 1 t \N \N +338 2026-04-23 11:14:22.767136+00 webhook/pushalarm 1 0 1 0 t \N \N +339 2026-04-23 11:14:23.546661+00 webhook/pushalarm 1 0 1 1 t \N \N +341 2026-04-23 11:14:29.278008+00 webhook/pushalarm 1 0 1 1 t \N \N +342 2026-04-23 11:14:31.327055+00 webhook/pushalarm 1 0 1 1 t \N \N +343 2026-04-23 11:14:38.363404+00 webhook/pushalarm 1 0 1 1 t \N \N +344 2026-04-23 11:14:40.560786+00 webhook/pushalarm 1 0 1 1 t \N \N +345 2026-04-23 11:14:49.666439+00 webhook/pushalarm 1 0 1 1 t \N \N +346 2026-04-23 11:15:07.398358+00 webhook/pushalarm 1 0 1 1 t \N \N +347 2026-04-23 11:15:12.742835+00 webhook/pushalarm 1 0 1 1 t \N \N +348 2026-04-23 11:15:22.004803+00 webhook/pushalarm 1 0 1 2 t \N \N +349 2026-04-23 11:15:24.035249+00 webhook/pushalarm 1 0 1 1 t \N \N +355 2026-04-23 11:16:21.405947+00 webhook/pushalarm 1 0 1 2 t \N \N +356 2026-04-23 11:16:22.073023+00 webhook/pushalarm 1 0 1 1 t \N \N +358 2026-04-23 11:16:34.107091+00 webhook/pushalarm 1 0 1 1 t \N \N +359 2026-04-23 11:16:35.682194+00 webhook/pushalarm 1 0 1 1 t \N \N +360 2026-04-23 11:16:37.277518+00 webhook/pushalarm 1 0 1 2 t \N \N +361 2026-04-23 11:17:20.020548+00 webhook/pushalarm 1 0 1 1 t \N \N +362 2026-04-23 11:17:25.920751+00 webhook/pushalarm 1 0 1 1 t \N \N +363 2026-04-23 11:17:26.58767+00 webhook/pushalarm 1 0 1 1 t \N \N +364 2026-04-23 11:17:26.711316+00 webhook/pushalarm 1 0 1 0 t \N \N +366 2026-04-23 11:17:46.904371+00 webhook/pushalarm 1 0 1 1 t \N \N +367 2026-04-23 11:17:53.477565+00 webhook/pushalarm 1 0 1 1 t \N \N +368 2026-04-23 11:17:54.609674+00 webhook/pushalarm 1 0 1 1 t \N \N +369 2026-04-23 11:18:12.729921+00 webhook/pushalarm 1 0 1 3 t \N \N +371 2026-04-23 11:18:28.06315+00 webhook/pushalarm 1 0 1 1 t \N \N +372 2026-04-23 11:19:05.011566+00 jimi.device.alarm.list 107 0 -157 769 t \N \N +373 2026-04-23 11:19:12.545554+00 webhook/pushalarm 1 0 1 1 t \N \N +374 2026-04-23 11:19:24.126637+00 webhook/pushalarm 1 0 1 1 t \N \N +375 2026-04-23 11:19:25.130836+00 webhook/pushalarm 1 0 1 1 t \N \N +378 2026-04-23 11:19:59.956311+00 webhook/pushalarm 1 0 1 0 t \N \N +379 2026-04-23 11:20:11.160476+00 webhook/pushalarm 1 0 1 1 t \N \N +380 2026-04-23 11:20:11.788696+00 webhook/pushalarm 1 0 1 2 t \N \N +384 2026-04-23 11:21:10.627653+00 webhook/pushalarm 1 0 1 1 t \N \N +396 2026-04-23 11:22:12.601456+00 webhook/pushalarm 1 0 1 1 t \N \N +397 2026-04-23 11:22:16.818146+00 webhook/pushalarm 1 0 1 1 t \N \N +398 2026-04-23 11:22:24.00373+00 webhook/pushalarm 1 0 1 1 t \N \N +399 2026-04-23 11:22:27.123347+00 webhook/pushalarm 1 0 1 1 t \N \N +400 2026-04-23 11:22:27.96863+00 jimi.user.device.location.list 63 61 6 227 t \N \N +401 2026-04-23 11:22:28.928417+00 webhook/pushalarm 1 0 1 0 t \N \N +402 2026-04-23 11:22:29.098416+00 webhook/pushalarm 1 0 1 1 t \N \N +403 2026-04-23 11:22:39.11657+00 webhook/pushalarm 1 0 1 2 t \N \N +404 2026-04-23 11:22:46.429113+00 webhook/pushalarm 1 0 1 1 t \N \N +405 2026-04-23 11:22:47.369097+00 webhook/pushalarm 1 0 1 1 t \N \N +406 2026-04-23 11:22:48.137965+00 webhook/pushalarm 1 0 1 1 t \N \N +407 2026-04-23 11:22:51.092233+00 webhook/pushalarm 1 0 1 1 t \N \N +408 2026-04-23 11:23:04.812554+00 webhook/pushalarm 1 0 1 2 t \N \N +409 2026-04-23 11:23:12.920925+00 webhook/pushalarm 1 0 1 1 t \N \N +410 2026-04-23 11:23:27.169918+00 webhook/pushalarm 1 0 1 1 t \N \N +411 2026-04-23 11:23:27.83541+00 webhook/pushalarm 1 0 1 1 t \N \N +412 2026-04-23 11:23:28.21191+00 jimi.user.device.location.list 63 61 7 225 t \N \N +413 2026-04-23 11:23:49.87186+00 webhook/pushalarm 1 0 1 1 t \N \N +414 2026-04-23 11:23:53.343519+00 webhook/pushalarm 1 0 1 0 t \N \N +415 2026-04-23 11:23:55.944894+00 webhook/pushalarm 1 0 1 1 t \N \N +416 2026-04-23 11:24:02.15914+00 webhook/pushalarm 1 0 1 1 t \N \N +417 2026-04-23 11:24:05.833718+00 jimi.device.alarm.list 109 0 -175 721 t \N \N +418 2026-04-23 11:24:13.287831+00 webhook/pushalarm 1 0 1 1 t \N \N +419 2026-04-23 11:24:13.65017+00 webhook/pushalarm 1 0 1 1 t \N \N +420 2026-04-23 11:24:23.835079+00 webhook/pushalarm 1 0 1 1 t \N \N +421 2026-04-23 11:24:28.431799+00 jimi.user.device.location.list 63 61 7 205 t \N \N +422 2026-04-23 11:24:38.854316+00 jimi.device.track.list 109 0 45 9540 t \N \N +423 2026-04-23 11:24:41.700843+00 jimi.device.track.mileage 109 0 -82 4229 t \N \N +424 2026-04-23 11:25:03.029206+00 webhook/pushalarm 1 0 1 3 t \N \N +425 2026-04-23 11:25:33.169829+00 webhook/pushalarm 1 0 1 1 t \N \N +426 2026-04-23 11:25:39.844822+00 webhook/pushalarm 1 0 1 0 t \N \N +427 2026-04-23 11:25:45.871922+00 webhook/pushalarm 1 0 1 1 t \N \N +428 2026-04-23 11:25:46.093837+00 jimi.open.platform.report.parking 109 0 0 21828 t \N \N +429 2026-04-23 11:25:47.262917+00 jimi.user.device.location.list 63 61 6 209 t \N \N +430 2026-04-23 11:25:53.336934+00 webhook/pushalarm 1 0 1 1 t \N \N +431 2026-04-23 11:26:05.12646+00 webhook/pushalarm 1 0 1 1 t \N \N +432 2026-04-23 11:26:25.71407+00 webhook/pushalarm 1 0 1 1 t \N \N +433 2026-04-23 11:26:38.910791+00 webhook/pushalarm 1 0 1 1 t \N \N +434 2026-04-23 11:26:42.045856+00 webhook/pushalarm 1 0 1 1 t \N \N +435 2026-04-23 11:26:42.175725+00 webhook/pushalarm 1 0 1 1 t \N \N +436 2026-04-23 11:26:47.456683+00 jimi.user.device.location.list 63 61 4 178 t \N \N +437 2026-04-23 11:26:59.132922+00 webhook/pushalarm 1 0 1 3 t \N \N +438 2026-04-23 11:27:02.695477+00 webhook/pushalarm 1 0 1 1 t \N \N +439 2026-04-23 11:27:14.762969+00 webhook/pushalarm 1 0 1 3 t \N \N +440 2026-04-23 11:27:17.683805+00 webhook/pushalarm 1 0 1 1 t \N \N +441 2026-04-23 11:27:47.696259+00 jimi.user.device.location.list 63 61 4 208 t \N \N +442 2026-04-23 11:27:59.999942+00 webhook/pushalarm 1 0 1 1 t \N \N +443 2026-04-23 11:28:00.63359+00 webhook/pushalarm 1 0 1 4 t \N \N +444 2026-04-23 11:28:04.404506+00 webhook/pushalarm 1 0 1 1 t \N \N +445 2026-04-23 11:28:04.593612+00 webhook/pushalarm 1 0 1 1 t \N \N +446 2026-04-23 11:28:16.695488+00 webhook/pushalarm 1 0 1 1 t \N \N +447 2026-04-23 11:28:44.39047+00 webhook/pushalarm 1 0 1 1 t \N \N +448 2026-04-23 11:28:45.989257+00 webhook/pushalarm 1 0 1 1 t \N \N +454 2026-04-23 11:29:18.025469+00 webhook/pushalarm 1 0 1 1 t \N \N +455 2026-04-23 11:29:34.338376+00 webhook/pushalarm 1 0 1 1 t \N \N +460 2026-04-23 11:30:20.455355+00 webhook/pushalarm 1 0 1 0 t \N \N +462 2026-04-23 11:30:39.666247+00 webhook/pushalarm 1 0 1 1 t \N \N +463 2026-04-23 11:30:43.808778+00 webhook/pushalarm 1 0 1 2 t \N \N +464 2026-04-23 11:30:46.088809+00 webhook/pushalarm 1 0 1 1 t \N \N +466 2026-04-23 11:30:57.204825+00 webhook/pushalarm 1 0 1 1 t \N \N +467 2026-04-23 11:31:45.727711+00 webhook/pushalarm 1 0 1 2 t \N \N +469 2026-04-23 11:31:58.818525+00 webhook/pushalarm 1 0 1 1 t \N \N +470 2026-04-23 11:32:01.849927+00 webhook/pushalarm 1 0 1 2 t \N \N +471 2026-04-23 11:32:23.67999+00 webhook/pushalarm 1 0 1 1 t \N \N +472 2026-04-23 11:32:24.304208+00 webhook/pushalarm 1 0 1 1 t \N \N +473 2026-04-23 11:32:25.324682+00 webhook/pushalarm 1 0 1 1 t \N \N +474 2026-04-23 11:32:26.321651+00 webhook/pushalarm 1 0 1 1 t \N \N +479 2026-04-23 11:33:26.992798+00 webhook/pushalarm 1 0 1 1 t \N \N +449 2026-04-23 11:28:47.880759+00 jimi.user.device.location.list 63 61 6 181 t \N \N +457 2026-04-23 11:29:48.102809+00 jimi.user.device.location.list 63 61 4 195 t \N \N +465 2026-04-23 11:30:48.353279+00 jimi.user.device.location.list 63 61 5 239 t \N \N +468 2026-04-23 11:31:48.552492+00 jimi.user.device.location.list 63 61 8 170 t \N \N +475 2026-04-23 11:32:48.759511+00 jimi.user.device.location.list 63 61 6 178 t \N \N +480 2026-04-23 11:33:49.031309+00 jimi.user.device.location.list 63 61 5 243 t \N \N +486 2026-04-23 11:34:49.227531+00 jimi.user.device.location.list 63 61 7 173 t \N \N +450 2026-04-23 11:29:04.630021+00 webhook/pushalarm 1 0 1 1 t \N \N +451 2026-04-23 11:29:05.52703+00 webhook/pushalarm 1 0 1 0 t \N \N +453 2026-04-23 11:29:10.091093+00 webhook/pushalarm 1 0 1 1 t \N \N +456 2026-04-23 11:29:47.013419+00 webhook/pushalarm 1 0 1 1 t \N \N +458 2026-04-23 11:29:48.369147+00 webhook/pushalarm 1 0 1 1 t \N \N +459 2026-04-23 11:29:49.121015+00 webhook/pushalarm 1 0 1 1 t \N \N +461 2026-04-23 11:30:33.967498+00 webhook/pushalarm 1 0 1 1 t \N \N +476 2026-04-23 11:33:00.472089+00 webhook/pushalarm 1 0 1 1 t \N \N +477 2026-04-23 11:33:02.979583+00 webhook/pushalarm 1 0 1 1 t \N \N +478 2026-04-23 11:33:06.426059+00 webhook/pushalarm 1 0 1 1 t \N \N +481 2026-04-23 11:33:58.191776+00 webhook/pushalarm 1 0 1 2 t \N \N +482 2026-04-23 11:33:59.124843+00 webhook/pushalarm 1 0 1 2 t \N \N +484 2026-04-23 11:34:25.26934+00 webhook/pushalarm 1 0 1 1 t \N \N +485 2026-04-23 11:34:42.166141+00 webhook/pushalarm 1 0 1 4 t \N \N +452 2026-04-23 11:29:06.719063+00 jimi.device.alarm.list 109 0 -165 833 t \N \N +483 2026-04-23 11:34:07.571496+00 jimi.device.alarm.list 110 0 -167 723 t \N \N +487 2026-04-23 11:34:57.522732+00 webhook/pushalarm 1 0 1 1 t \N \N +488 2026-04-23 11:35:24.496612+00 webhook/pushalarm 1 0 1 2 t \N \N +489 2026-04-23 11:35:32.873904+00 webhook/pushalarm 1 0 1 2 t \N \N +490 2026-04-23 11:35:41.302167+00 webhook/pushalarm 1 0 1 1 t \N \N +491 2026-04-23 11:35:42.914323+00 webhook/pushalarm 1 0 1 1 t \N \N +492 2026-04-23 11:35:49.473458+00 jimi.user.device.location.list 63 61 7 234 t \N \N +493 2026-04-23 11:35:56.15491+00 webhook/pushalarm 1 0 1 1 t \N \N +494 2026-04-23 11:35:59.816581+00 webhook/pushalarm 1 0 1 1 t \N \N +495 2026-04-23 11:36:01.969529+00 webhook/pushalarm 1 0 1 1 t \N \N +496 2026-04-23 11:36:30.978376+00 webhook/pushalarm 1 0 1 1 t \N \N +497 2026-04-23 11:36:31.150282+00 webhook/pushalarm 1 0 1 1 t \N \N +498 2026-04-23 11:36:33.563761+00 webhook/pushalarm 1 0 1 0 t \N \N +499 2026-04-23 11:36:49.672163+00 jimi.user.device.location.list 63 61 8 169 t \N \N +500 2026-04-23 11:36:49.727036+00 webhook/pushalarm 1 0 1 1 t \N \N +501 2026-04-23 11:36:59.27963+00 webhook/pushalarm 1 0 1 1 t \N \N +502 2026-04-23 11:37:00.997663+00 webhook/pushalarm 1 0 1 0 t \N \N +503 2026-04-23 11:37:03.552918+00 webhook/pushalarm 1 0 1 6 t \N \N +504 2026-04-23 11:37:22.064442+00 webhook/pushalarm 1 0 1 0 t \N \N +505 2026-04-23 11:37:43.177552+00 webhook/pushalarm 1 0 1 1 t \N \N +506 2026-04-23 11:37:45.446659+00 webhook/pushalarm 1 0 1 1 t \N \N +507 2026-04-23 11:37:49.891775+00 jimi.user.device.location.list 63 61 9 205 t \N \N +508 2026-04-23 11:37:50.970828+00 webhook/pushalarm 1 0 1 0 t \N \N +509 2026-04-23 11:38:20.225267+00 webhook/pushalarm 1 0 1 2 t \N \N +510 2026-04-23 11:38:22.963369+00 webhook/pushalarm 1 0 1 1 t \N \N +511 2026-04-23 11:38:25.118579+00 webhook/pushalarm 1 0 1 1 t \N \N +512 2026-04-23 11:38:25.847399+00 webhook/pushalarm 1 0 1 1 t \N \N +513 2026-04-23 11:38:34.411009+00 webhook/pushalarm 1 0 1 1 t \N \N +514 2026-04-23 11:38:49.251812+00 webhook/pushalarm 1 0 1 1 t \N \N +515 2026-04-23 11:38:50.082713+00 jimi.user.device.location.list 63 61 6 178 t \N \N +516 2026-04-23 11:38:51.371396+00 webhook/pushalarm 1 0 1 1 t \N \N +517 2026-04-23 11:38:54.498506+00 webhook/pushalarm 1 0 1 3 t \N \N +518 2026-04-23 11:38:55.078483+00 webhook/pushalarm 1 0 1 2 t \N \N +519 2026-04-23 11:39:03.511613+00 webhook/pushalarm 1 0 1 2 t \N \N +520 2026-04-23 11:39:03.645194+00 webhook/pushalarm 1 0 1 1 t \N \N +521 2026-04-23 11:39:07.846619+00 webhook/pushalarm 1 0 1 1 t \N \N +522 2026-04-23 11:39:08.358279+00 jimi.device.alarm.list 112 0 -165 697 t \N \N +523 2026-04-23 11:39:15.334726+00 webhook/pushalarm 1 0 1 1 t \N \N +524 2026-04-23 11:39:18.383488+00 webhook/pushalarm 1 0 1 1 t \N \N +525 2026-04-23 11:39:20.9955+00 webhook/pushalarm 1 0 1 1 t \N \N +526 2026-04-23 11:39:22.055653+00 webhook/pushalarm 1 0 1 1 t \N \N +527 2026-04-23 11:39:23.94002+00 webhook/pushalarm 1 0 1 2 t \N \N +528 2026-04-23 11:39:30.873719+00 webhook/pushalarm 1 0 1 3 t \N \N +529 2026-04-23 11:39:34.10731+00 webhook/pushalarm 1 0 1 1 t \N \N +530 2026-04-23 11:39:49.883166+00 webhook/pushalarm 1 0 1 1 t \N \N +531 2026-04-23 11:39:46.779828+00 jimi.device.track.mileage 112 0 -79 4895 t \N \N +532 2026-04-23 11:39:51.230078+00 jimi.user.device.location.list 63 61 8 233 t \N \N +533 2026-04-23 11:39:58.741101+00 webhook/pushalarm 1 0 1 1 t \N \N +534 2026-04-23 11:40:00.198383+00 webhook/pushalarm 1 0 1 1 t \N \N +535 2026-04-23 11:40:01.393101+00 webhook/pushalarm 1 0 1 1 t \N \N +536 2026-04-23 11:40:04.41808+00 webhook/pushalarm 1 0 1 1 t \N \N +537 2026-04-23 11:40:24.642285+00 webhook/pushalarm 1 0 1 1 t \N \N +538 2026-04-23 11:40:47.914321+00 webhook/pushalarm 1 0 1 1 t \N \N +539 2026-04-23 11:40:49.223504+00 webhook/pushalarm 1 0 1 1 t \N \N +540 2026-04-23 11:40:52.523835+00 webhook/pushalarm 1 0 1 1 t \N \N +541 2026-04-23 11:40:52.860976+00 webhook/pushalarm 1 0 1 1 t \N \N +542 2026-04-23 11:40:59.825021+00 webhook/pushalarm 1 0 1 1 t \N \N +543 2026-04-23 11:41:04.427598+00 webhook/pushalarm 1 0 1 3 t \N \N +544 2026-04-23 11:41:08.132039+00 jimi.open.platform.report.parking 112 0 0 21821 t \N \N +545 2026-04-23 11:41:09.30426+00 jimi.user.device.location.list 63 61 12 210 t \N \N +546 2026-04-23 11:41:10.004327+00 webhook/pushalarm 1 0 1 0 t \N \N +547 2026-04-23 11:41:24.304761+00 webhook/pushalarm 1 0 1 1 t \N \N +548 2026-04-23 11:41:28.470756+00 webhook/pushalarm 1 0 1 4 t \N \N +549 2026-04-23 11:41:33.028549+00 webhook/pushalarm 1 0 1 3 t \N \N +550 2026-04-23 11:41:48.767366+00 webhook/pushalarm 1 0 1 1 t \N \N +551 2026-04-23 11:41:52.150239+00 webhook/pushalarm 1 0 1 3 t \N \N +552 2026-04-23 11:42:09.502872+00 jimi.user.device.location.list 63 61 9 182 t \N \N +553 2026-04-23 11:43:08.705352+00 webhook/pushalarm 1 0 1 1 t \N \N +554 2026-04-23 11:43:09.698438+00 jimi.user.device.location.list 63 61 10 178 t \N \N +555 2026-04-23 11:43:20.762793+00 webhook/pushalarm 1 0 1 1 t \N \N +556 2026-04-23 11:43:24.538722+00 webhook/pushalarm 1 0 1 1 t \N \N +557 2026-04-23 11:43:30.609577+00 webhook/pushalarm 1 0 1 1 t \N \N +558 2026-04-23 11:43:36.020357+00 webhook/pushalarm 1 0 1 2 t \N \N +559 2026-04-23 11:43:38.856932+00 webhook/pushalarm 1 0 1 2 t \N \N +560 2026-04-23 11:43:39.178819+00 webhook/pushalarm 1 0 1 1 t \N \N +561 2026-04-23 11:43:44.326966+00 webhook/pushalarm 1 0 1 1 t \N \N +562 2026-04-23 11:43:44.403949+00 webhook/pushalarm 1 0 1 1 t \N \N +563 2026-04-23 11:44:09.385177+00 webhook/pushalarm 1 0 1 2 t \N \N +564 2026-04-23 11:44:09.187279+00 jimi.device.alarm.list 113 0 -185 770 t \N \N +565 2026-04-23 11:44:09.69249+00 webhook/pushalarm 1 0 1 1 t \N \N +566 2026-04-23 11:44:09.952157+00 jimi.user.device.location.list 63 61 6 245 t \N \N +567 2026-04-23 11:44:30.793818+00 webhook/pushalarm 1 0 1 1 t \N \N +568 2026-04-23 11:44:38.194932+00 webhook/pushalarm 1 0 1 1 t \N \N +569 2026-04-23 11:44:46.993481+00 webhook/pushalarm 1 0 1 1 t \N \N +570 2026-04-23 11:44:49.387089+00 webhook/pushalarm 1 0 1 1 t \N \N +571 2026-04-23 11:44:58.239991+00 webhook/pushalarm 1 0 1 1 t \N \N +572 2026-04-23 11:44:58.275939+00 webhook/pushalarm 1 0 1 1 t \N \N +573 2026-04-23 11:45:00.066843+00 webhook/pushalarm 1 0 1 1 t \N \N +574 2026-04-23 11:45:01.493673+00 webhook/pushalarm 1 0 1 2 t \N \N +577 2026-04-23 11:45:22.977229+00 webhook/pushalarm 1 0 1 2 t \N \N +578 2026-04-23 11:45:23.60991+00 webhook/pushalarm 1 0 1 1 t \N \N +579 2026-04-23 11:45:37.226859+00 webhook/pushalarm 1 0 1 1 t \N \N +584 2026-04-23 11:47:09.511236+00 webhook/pushalarm 1 0 1 1 t \N \N +575 2026-04-23 11:45:10.204099+00 jimi.user.device.location.list 63 61 7 226 t \N \N +581 2026-04-23 11:46:10.513239+00 jimi.user.device.location.list 63 61 9 299 t \N \N +585 2026-04-23 11:47:10.785952+00 jimi.user.device.location.list 63 61 10 223 t \N \N +576 2026-04-23 11:45:11.466102+00 webhook/pushalarm 1 0 1 1 t \N \N +580 2026-04-23 11:45:59.828647+00 webhook/pushalarm 1 0 1 2 t \N \N +582 2026-04-23 11:46:10.607399+00 webhook/pushalarm 1 0 1 1 t \N \N +583 2026-04-23 11:46:14.90584+00 webhook/pushalarm 1 0 1 1 t \N \N +586 2026-04-23 11:47:17.611544+00 webhook/pushalarm 1 0 1 1 t \N \N +587 2026-04-23 11:47:26.53068+00 webhook/pushalarm 1 0 1 1 t \N \N +588 2026-04-23 11:47:31.715429+00 webhook/pushalarm 1 0 1 1 t \N \N +589 2026-04-23 11:47:45.420683+00 webhook/pushalarm 1 0 1 1 t \N \N +590 2026-04-23 11:47:57.147338+00 webhook/pushalarm 1 0 1 3 t \N \N +591 2026-04-23 11:48:11.017779+00 jimi.user.device.location.list 63 61 8 218 t \N \N +592 2026-04-23 11:48:17.943586+00 webhook/pushalarm 1 0 1 1 t \N \N +593 2026-04-23 11:48:44.269213+00 webhook/pushalarm 1 0 1 1 t \N \N +594 2026-04-23 11:48:59.573573+00 webhook/pushalarm 1 0 1 1 t \N \N +595 2026-04-23 11:49:03.149533+00 webhook/pushalarm 1 0 1 1 t \N \N +596 2026-04-23 11:49:10.038939+00 jimi.device.alarm.list 113 0 -182 776 t \N \N +597 2026-04-23 11:49:11.247186+00 jimi.user.device.location.list 63 61 10 222 t \N \N +598 2026-04-23 11:49:14.915141+00 webhook/pushalarm 1 0 1 1 t \N \N +599 2026-04-23 11:49:16.671528+00 webhook/pushalarm 1 0 1 1 t \N \N +600 2026-04-23 11:49:25.397516+00 webhook/pushalarm 1 0 1 1 t \N \N +601 2026-04-23 11:49:45.464063+00 webhook/pushalarm 1 0 1 1 t \N \N +602 2026-04-23 11:49:57.82753+00 webhook/pushalarm 1 0 1 1 t \N \N +603 2026-04-23 11:50:08.940739+00 webhook/pushalarm 1 0 1 1 t \N \N +604 2026-04-23 11:50:11.537659+00 jimi.user.device.location.list 63 61 8 239 t \N \N +605 2026-04-23 11:50:14.308908+00 webhook/pushalarm 1 0 1 1 t \N \N +606 2026-04-23 11:50:16.123959+00 webhook/pushalarm 1 0 1 1 t \N \N +607 2026-04-23 11:50:16.823172+00 webhook/pushalarm 1 0 1 0 t \N \N +608 2026-04-23 11:50:23.642632+00 webhook/pushalarm 1 0 1 1 t \N \N +609 2026-04-23 11:50:45.042799+00 webhook/pushalarm 1 0 1 1 t \N \N +610 2026-04-23 11:50:50.291914+00 webhook/pushalarm 1 0 1 4 t \N \N +611 2026-04-23 11:50:54.018559+00 webhook/pushalarm 1 0 1 1 t \N \N +612 2026-04-23 11:50:56.39106+00 webhook/pushalarm 1 0 1 1 t \N \N +613 2026-04-23 11:51:01.109521+00 webhook/pushalarm 1 0 1 1 t \N \N +614 2026-04-23 11:51:08.566145+00 webhook/pushalarm 1 0 1 1 t \N \N +615 2026-04-23 11:51:10.67645+00 webhook/pushalarm 1 0 1 2 t \N \N +616 2026-04-23 11:51:10.736382+00 webhook/pushalarm 1 0 1 2 t \N \N +617 2026-04-23 11:51:11.763525+00 jimi.user.device.location.list 63 61 9 213 t \N \N +618 2026-04-23 11:51:16.867534+00 webhook/pushalarm 1 0 1 1 t \N \N +619 2026-04-23 11:51:25.058045+00 webhook/pushalarm 1 0 1 1 t \N \N +620 2026-04-23 11:51:36.207475+00 webhook/pushalarm 1 0 1 1 t \N \N +621 2026-04-23 11:51:55.580765+00 webhook/pushalarm 1 0 1 1 t \N \N +622 2026-04-23 11:52:06.770369+00 webhook/pushalarm 1 0 1 1 t \N \N +623 2026-04-23 11:52:11.252037+00 webhook/pushalarm 1 0 1 1 t \N \N +624 2026-04-23 11:52:12.001604+00 jimi.user.device.location.list 63 61 10 218 t \N \N +625 2026-04-23 11:52:12.831595+00 webhook/pushalarm 1 0 1 1 t \N \N +626 2026-04-23 11:52:26.315771+00 webhook/pushalarm 1 0 1 0 t \N \N +627 2026-04-23 11:52:32.451937+00 webhook/pushalarm 1 0 1 1 t \N \N +628 2026-04-23 11:52:35.555839+00 webhook/pushalarm 1 0 1 1 t \N \N +629 2026-04-23 11:53:12.227398+00 jimi.user.device.location.list 63 61 12 195 t \N \N +630 2026-04-23 11:53:17.386491+00 webhook/pushalarm 1 0 1 1 t \N \N +631 2026-04-23 11:54:01.555941+00 webhook/pushalarm 1 0 1 7 t \N \N +632 2026-04-23 11:54:18.23207+00 jimi.device.alarm.list 113 0 -172 8142 t \N \N +633 2026-04-23 11:55:02.180934+00 webhook/pushalarm 1 0 1 4 t \N \N +634 2026-04-23 11:55:03.805789+00 webhook/pushalarm 1 0 1 0 t \N \N +635 2026-04-23 11:55:05.330716+00 webhook/pushalarm 1 0 1 1 t \N \N +636 2026-04-23 11:55:18.965643+00 webhook/pushalarm 1 0 1 1 t \N \N +637 2026-04-23 11:55:19.962743+00 jimi.user.device.location.list 63 61 12 67728 t \N \N +638 2026-04-23 11:55:31.133458+00 jimi.device.track.list 113 0 402 10290 t \N \N +639 2026-04-23 11:55:34.822281+00 webhook/pushalarm 1 0 1 1 t \N \N +640 2026-04-23 11:55:33.001929+00 jimi.device.track.mileage 113 0 -78 4915 t \N \N +641 2026-04-23 11:55:40.54252+00 webhook/pushalarm 1 0 1 1 t \N \N +642 2026-04-23 11:55:42.800733+00 webhook/pushalarm 1 0 1 1 t \N \N +643 2026-04-23 11:55:46.803287+00 webhook/pushalarm 1 0 1 1 t \N \N +644 2026-04-23 11:55:56.030573+00 webhook/pushalarm 1 0 1 2 t \N \N +645 2026-04-23 11:56:23.567161+00 webhook/pushalarm 1 0 1 1 t \N \N +646 2026-04-23 11:56:30.013665+00 jimi.open.platform.report.parking 113 0 0 21779 t \N \N +647 2026-04-23 11:56:31.174584+00 jimi.user.device.location.list 63 61 13 203 t \N \N +648 2026-04-23 11:57:01.014988+00 webhook/pushalarm 1 0 1 1 t \N \N +649 2026-04-23 11:57:09.781946+00 webhook/pushalarm 1 0 1 1 t \N \N +650 2026-04-23 11:57:31.393917+00 jimi.user.device.location.list 63 61 10 238 t \N \N +651 2026-04-23 11:57:46.255619+00 webhook/pushalarm 1 0 1 1 t \N \N +652 2026-04-23 11:57:53.336777+00 webhook/pushalarm 1 0 1 1 t \N \N +653 2026-04-23 11:58:24.519675+00 webhook/pushalarm 1 0 1 1 t \N \N +654 2026-04-23 11:58:26.342094+00 webhook/pushalarm 1 0 1 1 t \N \N +655 2026-04-23 11:58:29.853921+00 webhook/pushalarm 1 0 1 1 t \N \N +656 2026-04-23 11:58:30.199822+00 webhook/pushalarm 1 0 1 1 t \N \N +657 2026-04-23 11:58:31.648065+00 jimi.user.device.location.list 63 61 10 213 t \N \N +658 2026-04-23 11:58:47.374115+00 webhook/pushalarm 1 0 1 1 t \N \N +659 2026-04-23 11:58:49.116573+00 webhook/pushalarm 1 0 1 0 t \N \N +660 2026-04-23 11:58:53.686698+00 webhook/pushalarm 1 0 1 1 t \N \N +661 2026-04-23 11:59:02.510327+00 webhook/pushalarm 1 0 1 1 t \N \N +662 2026-04-23 11:59:14.116751+00 webhook/pushalarm 1 0 1 1 t \N \N +663 2026-04-23 11:59:15.480873+00 webhook/pushalarm 1 0 1 1 t \N \N +664 2026-04-23 11:59:17.310925+00 webhook/pushalarm 1 0 1 9 t \N \N +665 2026-04-23 11:59:19.184132+00 jimi.device.alarm.list 113 0 -169 892 t \N \N +666 2026-04-23 11:59:26.577594+00 webhook/pushalarm 1 0 1 1 t \N \N +667 2026-04-23 11:59:27.464538+00 webhook/pushalarm 1 0 1 1 t \N \N +668 2026-04-23 11:59:29.955642+00 webhook/pushalarm 1 0 1 0 t \N \N +670 2026-04-23 11:59:33.606514+00 webhook/pushalarm 1 0 1 0 t \N \N +674 2026-04-23 12:00:00.671677+00 webhook/pushalarm 1 0 1 1 t \N \N +675 2026-04-23 12:00:00.704231+00 webhook/pushalarm 1 0 1 3 t \N \N +676 2026-04-23 12:00:03.192516+00 webhook/pushalarm 1 0 1 6 t \N \N +677 2026-04-23 12:00:13.545584+00 webhook/pushalarm 1 0 1 1 t \N \N +681 2026-04-23 12:00:35.243372+00 webhook/pushalarm 1 0 1 1 t \N \N +682 2026-04-23 12:00:51.497902+00 webhook/pushalarm 1 0 1 1 t \N \N +690 2026-04-23 12:02:20.884188+00 webhook/pushalarm 1 0 1 1 t \N \N +691 2026-04-23 12:02:23.12374+00 webhook/pushalarm 1 0 1 1 t \N \N +692 2026-04-23 12:02:23.93126+00 webhook/pushalarm 1 0 1 2 t \N \N +693 2026-04-23 12:02:24.073925+00 webhook/pushalarm 1 0 1 1 t \N \N +694 2026-04-23 12:02:31.998096+00 webhook/pushalarm 1 0 1 1 t \N \N +696 2026-04-23 12:02:33.10062+00 webhook/pushalarm 1 0 1 2 t \N \N +669 2026-04-23 11:59:31.932824+00 jimi.user.device.location.list 63 61 10 263 t \N \N +680 2026-04-23 12:00:32.194417+00 jimi.user.device.location.list 63 61 12 252 t \N \N +688 2026-04-23 12:01:32.427615+00 jimi.user.device.location.list 63 61 10 205 t \N \N +695 2026-04-23 12:02:32.690521+00 jimi.user.device.location.list 63 61 10 235 t \N \N +671 2026-04-23 11:59:39.215021+00 webhook/pushalarm 1 0 1 1 t \N \N +672 2026-04-23 11:59:40.714701+00 webhook/pushalarm 1 0 1 1 t \N \N +673 2026-04-23 11:59:45.725194+00 webhook/pushalarm 1 0 1 1 t \N \N +678 2026-04-23 12:00:22.731268+00 webhook/pushalarm 1 0 1 0 t \N \N +679 2026-04-23 12:00:26.191728+00 webhook/pushalarm 1 0 1 1 t \N \N +683 2026-04-23 12:01:14.545025+00 webhook/pushalarm 1 0 1 1 t \N \N +684 2026-04-23 12:01:24.028742+00 webhook/pushalarm 1 0 1 1 t \N \N +685 2026-04-23 12:01:26.18201+00 webhook/pushalarm 1 0 1 3 t \N \N +686 2026-04-23 12:01:28.665239+00 webhook/pushalarm 1 0 1 2 t \N \N +687 2026-04-23 12:01:30.324981+00 webhook/pushalarm 1 0 1 2 t \N \N +689 2026-04-23 12:01:56.066439+00 webhook/pushalarm 1 0 1 1 t \N \N +697 2026-04-23 12:02:45.645486+00 webhook/pushalarm 1 0 1 1 t \N \N +698 2026-04-23 12:02:51.309831+00 webhook/pushalarm 1 0 1 1 t \N \N +699 2026-04-23 12:03:02.306265+00 webhook/pushalarm 1 0 1 1 t \N \N +700 2026-04-23 12:03:10.060714+00 webhook/pushalarm 1 0 1 1 t \N \N +701 2026-04-23 12:03:32.91041+00 jimi.user.device.location.list 63 61 13 203 t \N \N +702 2026-04-23 12:03:48.486071+00 webhook/pushalarm 1 0 1 0 t \N \N +703 2026-04-23 12:04:11.802978+00 webhook/pushalarm 1 0 1 1 t \N \N +704 2026-04-23 12:04:13.261804+00 webhook/pushalarm 1 0 1 1 t \N \N +705 2026-04-23 12:04:20.177607+00 jimi.device.alarm.list 113 0 -182 850 t \N \N +706 2026-04-23 12:04:21.868202+00 webhook/pushalarm 1 0 1 1 t \N \N +707 2026-04-23 12:04:28.442461+00 webhook/pushalarm 1 0 1 1 t \N \N +708 2026-04-23 12:04:33.269655+00 jimi.user.device.location.list 63 61 12 360 t \N \N +709 2026-04-23 12:04:45.742739+00 webhook/pushalarm 1 0 1 1 t \N \N +710 2026-04-23 12:04:52.824855+00 webhook/pushalarm 1 0 1 1 t \N \N +711 2026-04-23 12:04:57.27236+00 webhook/pushalarm 1 0 1 1 t \N \N +712 2026-04-23 12:05:13.08349+00 webhook/pushalarm 1 0 1 1 t \N \N +713 2026-04-23 12:05:14.089391+00 webhook/pushalarm 1 0 1 1 t \N \N +714 2026-04-23 12:05:17.646649+00 webhook/pushalarm 1 0 1 0 t \N \N +715 2026-04-23 12:05:30.555986+00 webhook/pushalarm 1 0 1 1 t \N \N +716 2026-04-23 12:05:33.51026+00 jimi.user.device.location.list 63 61 12 196 t \N \N +717 2026-04-23 12:05:36.312786+00 webhook/pushalarm 1 0 1 1 t \N \N +718 2026-04-23 12:05:48.387688+00 webhook/pushalarm 1 0 1 1 t \N \N +719 2026-04-23 12:05:55.010016+00 webhook/pushalarm 1 0 1 1 t \N \N +720 2026-04-23 12:06:01.641168+00 webhook/pushalarm 1 0 1 1 t \N \N +721 2026-04-23 12:06:04.957392+00 webhook/pushalarm 1 0 1 0 t \N \N +722 2026-04-23 12:06:06.228985+00 webhook/pushalarm 1 0 1 1 t \N \N +723 2026-04-23 12:06:13.870046+00 webhook/pushalarm 1 0 1 0 t \N \N +724 2026-04-23 12:06:14.150693+00 webhook/pushalarm 1 0 1 1 t \N \N +725 2026-04-23 12:06:25.62192+00 webhook/pushalarm 1 0 1 1 t \N \N +726 2026-04-23 12:06:29.308746+00 webhook/pushalarm 1 0 1 2 t \N \N +727 2026-04-23 12:06:32.247467+00 webhook/pushalarm 1 0 1 1 t \N \N +728 2026-04-23 12:06:33.69812+00 jimi.user.device.location.list 63 61 11 179 t \N \N +729 2026-04-23 12:06:37.342758+00 webhook/pushalarm 1 0 1 1 t \N \N +730 2026-04-23 12:06:43.963297+00 webhook/pushalarm 1 0 1 1 t \N \N +731 2026-04-23 12:06:55.632924+00 webhook/pushalarm 1 0 1 1 t \N \N +732 2026-04-23 12:07:01.764391+00 webhook/pushalarm 1 0 1 1 t \N \N +733 2026-04-23 12:07:14.119902+00 webhook/pushalarm 1 0 1 0 t \N \N +734 2026-04-23 12:07:32.628115+00 webhook/pushalarm 1 0 1 0 t \N \N +735 2026-04-23 12:07:33.91778+00 jimi.user.device.location.list 63 61 12 197 t \N \N +736 2026-04-23 12:07:43.038348+00 webhook/pushalarm 1 0 1 1 t \N \N +737 2026-04-23 12:07:43.151187+00 webhook/pushalarm 1 0 1 1 t \N \N +738 2026-04-23 12:07:45.140789+00 webhook/pushalarm 1 0 1 1 t \N \N +739 2026-04-23 12:07:45.208807+00 webhook/pushalarm 1 0 1 1 t \N \N +740 2026-04-23 12:07:51.582267+00 webhook/pushalarm 1 0 1 1 t \N \N +741 2026-04-23 12:07:54.346049+00 webhook/pushalarm 1 0 1 1 t \N \N +742 2026-04-23 12:07:56.044395+00 webhook/pushalarm 1 0 1 1 t \N \N +743 2026-04-23 12:08:01.06509+00 webhook/pushalarm 1 0 1 1 t \N \N +744 2026-04-23 12:08:23.953457+00 webhook/pushalarm 1 0 1 1 t \N \N +745 2026-04-23 12:08:28.56417+00 webhook/pushalarm 1 0 1 1 t \N \N +746 2026-04-23 12:08:34.146645+00 jimi.user.device.location.list 63 61 11 215 t \N \N +747 2026-04-23 12:08:48.6038+00 webhook/pushalarm 1 0 1 1 t \N \N +748 2026-04-23 12:08:50.585479+00 webhook/pushalarm 1 0 1 1 t \N \N +749 2026-04-23 12:09:05.609075+00 webhook/pushalarm 1 0 1 1 t \N \N +750 2026-04-23 12:09:10.177248+00 webhook/pushalarm 1 0 1 1 t \N \N +751 2026-04-23 12:09:21.044173+00 jimi.device.alarm.list 115 0 -185 782 t \N \N +752 2026-04-23 12:09:29.0104+00 webhook/pushalarm 1 0 1 1 t \N \N +753 2026-04-23 12:09:34.404399+00 jimi.user.device.location.list 63 61 7 227 t \N \N +754 2026-04-23 12:10:12.427301+00 webhook/pushalarm 1 0 1 0 t \N \N +755 2026-04-23 12:10:21.97883+00 webhook/pushalarm 1 0 1 0 t \N \N +756 2026-04-23 12:10:34.624874+00 jimi.user.device.location.list 63 61 9 202 t \N \N +757 2026-04-23 12:10:40.635406+00 webhook/pushalarm 1 0 1 2 t \N \N +758 2026-04-23 12:10:40.893719+00 webhook/pushalarm 1 0 1 1 t \N \N +759 2026-04-23 12:10:38.317354+00 jimi.device.track.mileage 115 0 -82 4640 t \N \N +760 2026-04-23 12:10:46.551076+00 webhook/pushalarm 1 0 1 1 t \N \N +761 2026-04-23 12:10:53.360791+00 webhook/pushalarm 1 0 1 1 t \N \N +762 2026-04-23 12:10:57.127995+00 webhook/pushalarm 1 0 1 1 t \N \N +763 2026-04-23 12:10:58.352354+00 webhook/pushalarm 1 0 1 1 t \N \N +764 2026-04-23 12:11:02.497761+00 webhook/pushalarm 1 0 1 0 t \N \N +765 2026-04-23 12:11:09.491946+00 webhook/pushalarm 1 0 1 1 t \N \N +766 2026-04-23 12:11:12.662022+00 webhook/pushalarm 1 0 1 0 t \N \N +767 2026-04-23 12:11:23.363819+00 webhook/pushalarm 1 0 1 1 t \N \N +768 2026-04-23 12:11:28.020581+00 webhook/pushalarm 1 0 1 1 t \N \N +769 2026-04-23 12:11:31.561355+00 webhook/pushalarm 1 0 1 0 t \N \N +770 2026-04-23 12:11:42.428604+00 webhook/pushalarm 1 0 1 1 t \N \N +771 2026-04-23 12:11:44.339024+00 webhook/pushalarm 1 0 1 1 t \N \N +772 2026-04-23 12:11:51.657913+00 webhook/pushalarm 1 0 1 2 t \N \N +773 2026-04-23 12:11:52.146053+00 jimi.open.platform.report.parking 115 0 0 21824 t \N \N +774 2026-04-23 12:11:53.276221+00 jimi.user.device.location.list 63 61 10 165 t \N \N +780 2026-04-23 12:12:53.465355+00 jimi.user.device.location.list 63 61 9 169 t \N \N +784 2026-04-23 12:13:53.688328+00 jimi.user.device.location.list 63 61 9 198 t \N \N +788 2026-04-23 12:14:53.906415+00 jimi.user.device.location.list 63 61 10 207 t \N \N +793 2026-04-23 12:15:54.152539+00 jimi.user.device.location.list 63 61 9 242 t \N \N +799 2026-04-23 12:16:54.34739+00 jimi.user.device.location.list 63 61 7 167 t \N \N +806 2026-04-23 12:17:54.542551+00 jimi.user.device.location.list 63 61 9 176 t \N \N +812 2026-04-23 12:18:54.735118+00 jimi.user.device.location.list 63 61 8 189 t \N \N +775 2026-04-23 12:11:56.112364+00 webhook/pushalarm 1 0 1 1 t \N \N +777 2026-04-23 12:12:23.474577+00 webhook/pushalarm 1 0 1 0 t \N \N +781 2026-04-23 12:13:10.006513+00 webhook/pushalarm 1 0 1 1 t \N \N +782 2026-04-23 12:13:11.901573+00 webhook/pushalarm 1 0 1 1 t \N \N +787 2026-04-23 12:14:51.569542+00 webhook/pushalarm 1 0 1 1 t \N \N +791 2026-04-23 12:15:32.405722+00 webhook/pushalarm 1 0 1 1 t \N \N +794 2026-04-23 12:16:00.871925+00 webhook/pushalarm 1 0 1 1 t \N \N +797 2026-04-23 12:16:51.648702+00 webhook/pushalarm 1 0 1 1 t \N \N +798 2026-04-23 12:16:53.238639+00 webhook/pushalarm 1 0 1 2 t \N \N +801 2026-04-23 12:17:16.799953+00 webhook/pushalarm 1 0 1 1 t \N \N +802 2026-04-23 12:17:25.221111+00 webhook/pushalarm 1 0 1 1 t \N \N +803 2026-04-23 12:17:27.724433+00 webhook/pushalarm 1 0 1 1 t \N \N +804 2026-04-23 12:17:27.800251+00 webhook/pushalarm 1 0 1 1 t \N \N +805 2026-04-23 12:17:37.572464+00 webhook/pushalarm 1 0 1 1 t \N \N +808 2026-04-23 12:18:22.285464+00 webhook/pushalarm 1 0 1 0 t \N \N +809 2026-04-23 12:18:25.022665+00 webhook/pushalarm 1 0 1 1 t \N \N +815 2026-04-23 12:19:04.691654+00 webhook/pushalarm 1 0 1 1 t \N \N +776 2026-04-23 12:12:02.158919+00 webhook/pushalarm 1 0 1 2 t \N \N +778 2026-04-23 12:12:32.384614+00 webhook/pushalarm 1 0 1 1 t \N \N +779 2026-04-23 12:12:40.307513+00 webhook/pushalarm 1 0 1 1 t \N \N +783 2026-04-23 12:13:20.364788+00 webhook/pushalarm 1 0 1 3 t \N \N +785 2026-04-23 12:14:14.172074+00 webhook/pushalarm 1 0 1 1 t \N \N +789 2026-04-23 12:15:20.70427+00 webhook/pushalarm 1 0 1 1 t \N \N +790 2026-04-23 12:15:25.041999+00 webhook/pushalarm 1 0 1 1 t \N \N +792 2026-04-23 12:15:53.888871+00 webhook/pushalarm 1 0 1 1 t \N \N +795 2026-04-23 12:16:09.157058+00 webhook/pushalarm 1 0 1 1 t \N \N +796 2026-04-23 12:16:12.34345+00 webhook/pushalarm 1 0 1 0 t \N \N +800 2026-04-23 12:17:07.07515+00 webhook/pushalarm 1 0 1 4 t \N \N +807 2026-04-23 12:18:15.635848+00 webhook/pushalarm 1 0 1 1 t \N \N +810 2026-04-23 12:18:41.6277+00 webhook/pushalarm 1 0 1 1 t \N \N +811 2026-04-23 12:18:51.860787+00 webhook/pushalarm 1 0 1 1 t \N \N +813 2026-04-23 12:18:56.13835+00 webhook/pushalarm 1 0 1 1 t \N \N +814 2026-04-23 12:18:57.819336+00 webhook/pushalarm 1 0 1 1 t \N \N +786 2026-04-23 12:14:21.942944+00 jimi.device.alarm.list 115 0 -179 761 t \N \N +816 2026-04-23 12:19:14.84519+00 webhook/pushalarm 1 0 1 1 t \N \N +817 2026-04-23 12:19:17.913977+00 webhook/pushalarm 1 0 1 1 t \N \N +818 2026-04-23 12:19:22.870501+00 jimi.device.alarm.list 115 0 -178 868 t \N \N +819 2026-04-23 12:19:54.933048+00 jimi.user.device.location.list 63 61 7 160 t \N \N +820 2026-04-23 12:19:57.45604+00 webhook/pushalarm 1 0 1 1 t \N \N +821 2026-04-23 12:20:14.447736+00 webhook/pushalarm 1 0 1 1 t \N \N +822 2026-04-23 12:20:20.395645+00 webhook/pushalarm 1 0 1 1 t \N \N +823 2026-04-23 12:20:31.668181+00 webhook/pushalarm 1 0 1 1 t \N \N +824 2026-04-23 12:20:55.15309+00 jimi.user.device.location.list 63 61 9 201 t \N \N +825 2026-04-23 12:20:58.701434+00 webhook/pushalarm 1 0 1 1 t \N \N +826 2026-04-23 12:21:18.049658+00 webhook/pushalarm 1 0 1 2 t \N \N +827 2026-04-23 12:21:18.686279+00 webhook/pushalarm 1 0 1 1 t \N \N +828 2026-04-23 12:21:34.487032+00 webhook/pushalarm 1 0 1 1 t \N \N +829 2026-04-23 12:21:35.738393+00 webhook/pushalarm 1 0 1 0 t \N \N +830 2026-04-23 12:21:36.482713+00 webhook/pushalarm 1 0 1 1 t \N \N +831 2026-04-23 12:21:42.378736+00 webhook/pushalarm 1 0 1 1 t \N \N +832 2026-04-23 12:21:51.459331+00 webhook/pushalarm 1 0 1 1 t \N \N +833 2026-04-23 12:21:55.394671+00 jimi.user.device.location.list 63 61 8 228 t \N \N +834 2026-04-23 12:22:20.973664+00 webhook/pushalarm 1 0 1 1 t \N \N +835 2026-04-23 12:22:23.471672+00 webhook/pushalarm 1 0 1 1 t \N \N +836 2026-04-23 12:22:27.116403+00 webhook/pushalarm 1 0 1 1 t \N \N +837 2026-04-23 12:22:50.771196+00 webhook/pushalarm 1 0 1 1 t \N \N +838 2026-04-23 12:22:52.278912+00 webhook/pushalarm 1 0 1 1 t \N \N +839 2026-04-23 12:22:55.664316+00 jimi.user.device.location.list 63 61 12 244 t \N \N +840 2026-04-23 12:23:03.16313+00 webhook/pushalarm 1 0 1 1 t \N \N +841 2026-04-23 12:23:21.263558+00 webhook/pushalarm 1 0 1 1 t \N \N +842 2026-04-23 12:23:26.67043+00 webhook/pushalarm 1 0 1 2 t \N \N +843 2026-04-23 12:23:26.917611+00 webhook/pushalarm 1 0 1 2 t \N \N +844 2026-04-23 12:23:34.479585+00 webhook/pushalarm 1 0 1 1 t \N \N +845 2026-04-23 12:23:52.310388+00 webhook/pushalarm 1 0 1 2 t \N \N +846 2026-04-23 12:23:55.888992+00 jimi.user.device.location.list 63 61 7 203 t \N \N +847 2026-04-23 12:24:03.15332+00 webhook/pushalarm 1 0 1 1 t \N \N +848 2026-04-23 12:24:09.427448+00 webhook/pushalarm 1 0 1 1 t \N \N +849 2026-04-23 12:24:10.819929+00 webhook/pushalarm 1 0 1 2 t \N \N +850 2026-04-23 12:24:16.807341+00 webhook/pushalarm 1 0 1 1 t \N \N +851 2026-04-23 12:24:23.74299+00 jimi.device.alarm.list 115 0 -177 776 t \N \N +852 2026-04-23 12:24:25.786406+00 webhook/pushalarm 1 0 1 1 t \N \N +853 2026-04-23 12:24:44.198295+00 webhook/pushalarm 1 0 1 1 t \N \N +854 2026-04-23 12:24:48.057096+00 webhook/pushalarm 1 0 1 1 t \N \N +855 2026-04-23 12:24:48.091302+00 webhook/pushalarm 1 0 1 2 t \N \N +856 2026-04-23 12:24:56.144217+00 jimi.user.device.location.list 63 61 8 244 t \N \N +857 2026-04-23 12:25:07.754038+00 webhook/pushalarm 1 0 1 1 t \N \N +858 2026-04-23 12:25:42.29309+00 jimi.device.track.list 115 0 127 10271 t \N \N +859 2026-04-23 12:25:45.284558+00 jimi.device.track.mileage 115 0 -78 4740 t \N \N +860 2026-04-23 12:25:50.392016+00 webhook/pushalarm 1 0 1 1 t \N \N +861 2026-04-23 12:25:50.520335+00 webhook/pushalarm 1 0 1 1 t \N \N +862 2026-04-23 12:25:56.373376+00 jimi.user.device.location.list 63 61 4 204 t \N \N +863 2026-04-23 12:26:00.845835+00 webhook/pushalarm 1 0 1 5 t \N \N +864 2026-04-23 12:26:03.822479+00 webhook/pushalarm 1 0 1 0 t \N \N +865 2026-04-23 12:26:31.357318+00 webhook/pushalarm 1 0 1 1 t \N \N +866 2026-04-23 12:26:39.014433+00 webhook/pushalarm 1 0 1 1 t \N \N +867 2026-04-23 12:26:47.391437+00 webhook/pushalarm 1 0 1 1 t \N \N +868 2026-04-23 12:26:51.183714+00 webhook/pushalarm 1 0 1 1 t \N \N +869 2026-04-23 12:26:54.249926+00 webhook/pushalarm 1 0 1 2 t \N \N +870 2026-04-23 12:27:07.966437+00 webhook/pushalarm 1 0 1 1 t \N \N +871 2026-04-23 12:27:14.26712+00 jimi.open.platform.report.parking 115 0 0 21829 t \N \N +872 2026-04-23 12:27:15.429372+00 jimi.user.device.location.list 63 61 10 201 t \N \N +873 2026-04-23 12:27:22.054704+00 webhook/pushalarm 1 0 1 1 t \N \N +874 2026-04-23 12:27:29.750449+00 webhook/pushalarm 1 0 1 1 t \N \N +875 2026-04-23 12:27:43.391231+00 webhook/pushalarm 1 0 1 1 t \N \N +876 2026-04-23 12:27:44.460469+00 webhook/pushalarm 1 0 1 1 t \N \N +877 2026-04-23 12:27:52.360864+00 webhook/pushalarm 1 0 1 1 t \N \N +878 2026-04-23 12:27:52.78642+00 webhook/pushalarm 1 0 1 1 t \N \N +879 2026-04-23 12:27:52.864322+00 webhook/pushalarm 1 0 1 1 t \N \N +880 2026-04-23 12:28:02.969816+00 webhook/pushalarm 1 0 1 1 t \N \N +881 2026-04-23 12:28:15.611176+00 jimi.user.device.location.list 63 61 10 169 t \N \N +882 2026-04-23 12:28:35.189397+00 webhook/pushalarm 1 0 1 1 t \N \N +883 2026-04-23 12:28:59.130228+00 webhook/pushalarm 1 0 1 1 t \N \N +884 2026-04-23 12:28:59.90587+00 webhook/pushalarm 1 0 1 1 t \N \N +885 2026-04-23 12:29:13.397338+00 webhook/pushalarm 1 0 1 2 t \N \N +886 2026-04-23 12:29:15.827653+00 jimi.user.device.location.list 63 61 9 201 t \N \N +887 2026-04-23 12:29:18.295601+00 webhook/pushalarm 1 0 1 1 t \N \N +888 2026-04-23 12:29:20.492416+00 webhook/pushalarm 1 0 1 1 t \N \N +889 2026-04-23 12:29:25.054268+00 webhook/pushalarm 1 0 1 1 t \N \N +890 2026-04-23 12:29:24.573475+00 jimi.device.alarm.list 115 0 -179 818 t \N \N +891 2026-04-23 12:29:34.78066+00 webhook/pushalarm 1 0 1 1 t \N \N +892 2026-04-23 12:29:50.768089+00 webhook/pushalarm 1 0 1 1 t \N \N +893 2026-04-23 12:29:57.008429+00 webhook/pushalarm 1 0 1 1 t \N \N +894 2026-04-23 12:30:16.042024+00 jimi.user.device.location.list 63 61 9 191 t \N \N +895 2026-04-23 12:30:17.532498+00 webhook/pushalarm 1 0 1 1 t \N \N +896 2026-04-23 12:30:32.841828+00 webhook/pushalarm 1 0 1 1 t \N \N +897 2026-04-23 12:30:48.0306+00 webhook/pushalarm 1 0 1 1 t \N \N +898 2026-04-23 12:30:53.561866+00 webhook/pushalarm 1 0 1 1 t \N \N +899 2026-04-23 12:30:58.586195+00 webhook/pushalarm 1 0 1 0 t \N \N +900 2026-04-23 12:31:01.037398+00 webhook/pushalarm 1 0 1 1 t \N \N +901 2026-04-23 12:31:05.437097+00 webhook/pushalarm 1 0 1 1 t \N \N +902 2026-04-23 12:31:06.295724+00 webhook/pushalarm 1 0 1 1 t \N \N +904 2026-04-23 12:31:16.447005+00 webhook/pushalarm 1 0 1 0 t \N \N +910 2026-04-23 12:32:22.839642+00 webhook/pushalarm 1 0 1 1 t \N \N +913 2026-04-23 12:33:10.024715+00 webhook/pushalarm 1 0 1 3 t \N \N +929 2026-04-23 12:35:39.988665+00 webhook/pushalarm 1 0 1 1 t \N \N +939 2026-04-23 12:38:17.657928+00 webhook/pushalarm 1 0 1 3 t \N \N +941 2026-04-23 12:38:18.645715+00 webhook/pushalarm 1 0 1 0 t \N \N +943 2026-04-23 12:38:37.084542+00 webhook/pushalarm 1 0 1 1 t \N \N +944 2026-04-23 12:38:37.80921+00 webhook/pushalarm 1 0 1 1 t \N \N +947 2026-04-23 12:39:51.038929+00 webhook/pushalarm 1 0 1 0 t \N \N +903 2026-04-23 12:31:16.259219+00 jimi.user.device.location.list 63 61 8 189 t \N \N +909 2026-04-23 12:32:16.474115+00 jimi.user.device.location.list 63 61 7 200 t \N \N +914 2026-04-23 12:33:16.688329+00 jimi.user.device.location.list 63 61 7 199 t \N \N +920 2026-04-23 12:34:16.931693+00 jimi.user.device.location.list 63 61 7 229 t \N \N +927 2026-04-23 12:35:17.212268+00 jimi.user.device.location.list 63 61 7 278 t \N \N +932 2026-04-23 12:36:17.458856+00 jimi.user.device.location.list 63 61 7 238 t \N \N +936 2026-04-23 12:37:17.684435+00 jimi.user.device.location.list 63 61 6 184 t \N \N +940 2026-04-23 12:38:17.921047+00 jimi.user.device.location.list 63 61 8 240 t \N \N +945 2026-04-23 12:39:18.17396+00 jimi.user.device.location.list 63 61 7 221 t \N \N +905 2026-04-23 12:31:32.04782+00 webhook/pushalarm 1 0 1 1 t \N \N +906 2026-04-23 12:31:34.392409+00 webhook/pushalarm 1 0 1 1 t \N \N +907 2026-04-23 12:31:41.058363+00 webhook/pushalarm 1 0 1 1 t \N \N +908 2026-04-23 12:31:41.064331+00 webhook/pushalarm 1 0 1 1 t \N \N +911 2026-04-23 12:32:47.156339+00 webhook/pushalarm 1 0 1 1 t \N \N +912 2026-04-23 12:32:56.669016+00 webhook/pushalarm 1 0 1 1 t \N \N +915 2026-04-23 12:33:19.687547+00 webhook/pushalarm 1 0 1 1 t \N \N +916 2026-04-23 12:33:38.574852+00 webhook/pushalarm 1 0 1 0 t \N \N +917 2026-04-23 12:33:39.710088+00 webhook/pushalarm 1 0 1 1 t \N \N +918 2026-04-23 12:33:58.868922+00 webhook/pushalarm 1 0 1 3 t \N \N +919 2026-04-23 12:33:58.960774+00 webhook/pushalarm 1 0 1 6 t \N \N +921 2026-04-23 12:34:24.804829+00 webhook/pushalarm 1 0 1 1 t \N \N +923 2026-04-23 12:34:27.256636+00 webhook/pushalarm 1 0 1 1 t \N \N +924 2026-04-23 12:34:27.68109+00 webhook/pushalarm 1 0 1 1 t \N \N +925 2026-04-23 12:34:27.783385+00 webhook/pushalarm 1 0 1 1 t \N \N +926 2026-04-23 12:35:06.661934+00 webhook/pushalarm 1 0 1 1 t \N \N +928 2026-04-23 12:35:22.881941+00 webhook/pushalarm 1 0 1 1 t \N \N +930 2026-04-23 12:36:04.001506+00 webhook/pushalarm 1 0 1 1 t \N \N +931 2026-04-23 12:36:07.909474+00 webhook/pushalarm 1 0 1 1 t \N \N +933 2026-04-23 12:36:21.75439+00 webhook/pushalarm 1 0 1 1 t \N \N +934 2026-04-23 12:36:42.939518+00 webhook/pushalarm 1 0 1 1 t \N \N +935 2026-04-23 12:36:46.568216+00 webhook/pushalarm 1 0 1 1 t \N \N +937 2026-04-23 12:37:21.743479+00 webhook/pushalarm 1 0 1 1 t \N \N +938 2026-04-23 12:38:00.151531+00 webhook/pushalarm 1 0 1 1 t \N \N +942 2026-04-23 12:38:26.95571+00 webhook/pushalarm 1 0 1 0 t \N \N +922 2026-04-23 12:34:25.561416+00 jimi.device.alarm.list 115 0 -172 847 t \N \N +946 2026-04-23 12:39:26.465869+00 jimi.device.alarm.list 116 0 -153 834 t \N \N +948 2026-04-23 12:40:09.132822+00 webhook/pushalarm 1 0 1 1 t \N \N +949 2026-04-23 12:40:18.370864+00 jimi.user.device.location.list 63 61 8 185 t \N \N +950 2026-04-23 12:40:45.194964+00 webhook/pushalarm 1 0 1 1 t \N \N +951 2026-04-23 12:40:48.044566+00 webhook/pushalarm 1 0 1 1 t \N \N +952 2026-04-23 12:40:50.034583+00 jimi.device.track.mileage 116 0 -76 4658 t \N \N +953 2026-04-23 12:40:56.628146+00 webhook/pushalarm 1 0 1 1 t \N \N +954 2026-04-23 12:41:12.821915+00 webhook/pushalarm 1 0 1 1 t \N \N +955 2026-04-23 12:41:19.247336+00 jimi.user.device.location.list 63 61 9 205 t \N \N +956 2026-04-23 12:41:45.714099+00 webhook/pushalarm 1 0 1 1 t \N \N +957 2026-04-23 12:41:48.600714+00 webhook/pushalarm 1 0 1 1 t \N \N +958 2026-04-23 12:42:11.647717+00 webhook/pushalarm 1 0 1 1 t \N \N +959 2026-04-23 12:42:14.09627+00 webhook/pushalarm 1 0 1 0 t \N \N +960 2026-04-23 12:42:35.463631+00 webhook/pushalarm 1 0 1 1 t \N \N +961 2026-04-23 12:42:36.136961+00 jimi.open.platform.report.parking 116 0 0 21800 t \N \N +962 2026-04-23 12:42:37.305727+00 jimi.user.device.location.list 63 61 9 210 t \N \N +963 2026-04-23 12:42:38.526965+00 webhook/pushalarm 1 0 1 1 t \N \N +964 2026-04-23 12:43:03.470413+00 webhook/pushalarm 1 0 1 1 t \N \N +965 2026-04-23 12:43:06.141014+00 webhook/pushalarm 1 0 1 1 t \N \N +966 2026-04-23 12:43:12.69309+00 webhook/pushalarm 1 0 1 1 t \N \N +967 2026-04-23 12:43:21.672923+00 webhook/pushalarm 1 0 1 5 t \N \N +968 2026-04-23 12:43:30.333779+00 webhook/pushalarm 1 0 1 1 t \N \N +969 2026-04-23 12:43:37.499311+00 jimi.user.device.location.list 63 61 9 173 t \N \N +970 2026-04-23 12:43:42.232942+00 webhook/pushalarm 1 0 1 2 t \N \N +971 2026-04-23 12:44:27.352578+00 jimi.device.alarm.list 116 0 -144 720 t \N \N +972 2026-04-23 12:44:31.119493+00 webhook/pushalarm 1 0 1 1 t \N \N +973 2026-04-23 12:44:33.748147+00 webhook/pushalarm 1 0 1 1 t \N \N +974 2026-04-23 12:44:37.745038+00 jimi.user.device.location.list 63 61 7 226 t \N \N +975 2026-04-23 12:44:51.710448+00 webhook/pushalarm 1 0 1 1 t \N \N +976 2026-04-23 12:45:20.255871+00 webhook/pushalarm 1 0 1 2 t \N \N +977 2026-04-23 12:45:37.92394+00 jimi.user.device.location.list 63 61 7 162 t \N \N +978 2026-04-23 12:46:03.780646+00 webhook/pushalarm 1 0 1 0 t \N \N +979 2026-04-23 12:46:19.497584+00 webhook/pushalarm 1 0 1 1 t \N \N +980 2026-04-23 12:46:34.941964+00 webhook/pushalarm 1 0 1 1 t \N \N +981 2026-04-23 12:46:37.870852+00 webhook/pushalarm 1 0 1 1 t \N \N +982 2026-04-23 12:46:38.103301+00 jimi.user.device.location.list 63 61 8 167 t \N \N +983 2026-04-23 12:46:43.183623+00 webhook/pushalarm 1 0 1 1 t \N \N +984 2026-04-23 12:46:51.480256+00 webhook/pushalarm 1 0 1 0 t \N \N +985 2026-04-23 12:47:03.773771+00 webhook/pushalarm 1 0 1 1 t \N \N +986 2026-04-23 12:47:08.619021+00 webhook/pushalarm 1 0 1 1 t \N \N +987 2026-04-23 12:47:09.272553+00 webhook/pushalarm 1 0 1 1 t \N \N +988 2026-04-23 12:47:34.58461+00 webhook/pushalarm 1 0 1 1 t \N \N +989 2026-04-23 12:47:38.367916+00 jimi.user.device.location.list 63 61 7 258 t \N \N +990 2026-04-23 12:48:19.434568+00 webhook/pushalarm 1 0 1 1 t \N \N +991 2026-04-23 12:48:20.856785+00 webhook/pushalarm 1 0 1 1 t \N \N +992 2026-04-23 12:48:38.592825+00 jimi.user.device.location.list 63 61 7 200 t \N \N +993 2026-04-23 12:49:02.647466+00 webhook/pushalarm 1 0 1 1 t \N \N +994 2026-04-23 12:49:04.636464+00 webhook/pushalarm 1 0 1 1 t \N \N +995 2026-04-23 12:49:17.846809+00 webhook/pushalarm 1 0 1 1 t \N \N +996 2026-04-23 12:49:28.168907+00 jimi.device.alarm.list 116 0 -137 728 t \N \N +997 2026-04-23 12:49:38.835254+00 jimi.user.device.location.list 63 61 4 227 t \N \N +998 2026-04-23 12:49:54.783006+00 webhook/pushalarm 1 0 1 1 t \N \N +999 2026-04-23 12:50:00.281765+00 webhook/pushalarm 1 0 1 2 t \N \N +1000 2026-04-23 12:50:04.400573+00 webhook/pushalarm 1 0 1 1 t \N \N +1001 2026-04-23 12:50:15.634136+00 webhook/pushalarm 1 0 1 1 t \N \N +1002 2026-04-23 12:50:16.225119+00 webhook/pushalarm 1 0 1 0 t \N \N +1003 2026-04-23 12:50:38.020258+00 webhook/pushalarm 1 0 1 1 t \N \N +1004 2026-04-23 12:50:39.065707+00 jimi.user.device.location.list 63 61 6 194 t \N \N +1005 2026-04-23 12:50:58.076265+00 webhook/pushalarm 1 0 1 1 t \N \N +1006 2026-04-23 12:51:04.657822+00 webhook/pushalarm 1 0 1 1 t \N \N +1007 2026-04-23 12:51:05.058691+00 webhook/pushalarm 1 0 1 1 t \N \N +1008 2026-04-23 12:51:05.391322+00 webhook/pushalarm 1 0 1 1 t \N \N +1009 2026-04-23 12:51:15.915126+00 webhook/pushalarm 1 0 1 1 t \N \N +1010 2026-04-23 12:51:27.927677+00 webhook/pushalarm 1 0 1 2 t \N \N +1011 2026-04-23 12:51:39.248456+00 jimi.user.device.location.list 63 61 7 163 t \N \N +1012 2026-04-23 12:51:39.41849+00 webhook/pushalarm 1 0 1 1 t \N \N +1013 2026-04-23 12:51:56.692747+00 webhook/pushalarm 1 0 1 1 t \N \N +1014 2026-04-23 12:51:57.125603+00 webhook/pushalarm 1 0 1 1 t \N \N +1015 2026-04-23 12:51:59.184388+00 webhook/pushalarm 1 0 1 1 t \N \N +1016 2026-04-23 12:52:04.444613+00 webhook/pushalarm 1 0 1 2 t \N \N +1017 2026-04-23 12:52:04.91656+00 webhook/pushalarm 1 0 1 1 t \N \N +1018 2026-04-23 12:52:08.840489+00 webhook/pushalarm 1 0 1 1 t \N \N +1019 2026-04-23 12:52:11.678894+00 webhook/pushalarm 1 0 1 2 t \N \N +1020 2026-04-23 12:52:13.92329+00 webhook/pushalarm 1 0 1 1 t \N \N +1021 2026-04-23 12:52:16.023263+00 webhook/pushalarm 1 0 1 1 t \N \N +1022 2026-04-23 12:52:28.502356+00 webhook/pushalarm 1 0 1 1 t \N \N +1023 2026-04-23 12:52:39.491163+00 jimi.user.device.location.list 63 61 10 231 t \N \N +1024 2026-04-23 12:53:04.573184+00 webhook/pushalarm 1 0 1 1 t \N \N +1025 2026-04-23 12:53:39.67382+00 jimi.user.device.location.list 63 61 9 163 t \N \N +1026 2026-04-23 12:53:48.191788+00 webhook/pushalarm 1 0 1 4 t \N \N +1027 2026-04-23 12:53:52.916446+00 webhook/pushalarm 1 0 1 2 t \N \N +1028 2026-04-23 12:53:55.408923+00 webhook/pushalarm 1 0 1 1 t \N \N +1029 2026-04-23 12:54:01.879645+00 webhook/pushalarm 1 0 1 1 t \N \N +1030 2026-04-23 12:54:02.535371+00 webhook/pushalarm 1 0 1 2 t \N \N +1031 2026-04-23 12:54:10.779+00 webhook/pushalarm 1 0 1 1 t \N \N +1045 2026-04-23 12:55:54.703007+00 webhook/pushalarm 1 0 1 1 t \N \N +1046 2026-04-23 12:55:58.943818+00 webhook/pushalarm 1 0 1 1 t \N \N +1057 2026-04-23 12:57:41.941765+00 webhook/pushalarm 1 0 1 2 t \N \N +1058 2026-04-23 12:57:42.60097+00 webhook/pushalarm 1 0 1 1 t \N \N +1059 2026-04-23 12:57:50.171266+00 webhook/pushalarm 1 0 1 1 t \N \N +1060 2026-04-23 12:57:51.153422+00 webhook/pushalarm 1 0 1 1 t \N \N +1063 2026-04-23 12:58:03.046612+00 webhook/pushalarm 1 0 1 1 t \N \N +1067 2026-04-23 12:58:33.427948+00 webhook/pushalarm 1 0 1 1 t \N \N +1068 2026-04-23 12:58:36.086146+00 webhook/pushalarm 1 0 1 1 t \N \N +1069 2026-04-23 12:58:36.339187+00 webhook/pushalarm 1 0 1 1 t \N \N +1078 2026-04-23 13:00:55.313396+00 webhook/pushalarm 1 0 1 1 t \N \N +1080 2026-04-23 13:01:05.184426+00 webhook/pushalarm 1 0 1 1 t \N \N +1032 2026-04-23 12:54:19.089374+00 webhook/pushalarm 1 0 1 1 t \N \N +1033 2026-04-23 12:54:29.331776+00 webhook/pushalarm 1 0 1 1 t \N \N +1036 2026-04-23 12:54:44.70298+00 webhook/pushalarm 1 0 1 1 t \N \N +1037 2026-04-23 12:54:44.901952+00 webhook/pushalarm 1 0 1 1 t \N \N +1038 2026-04-23 12:54:48.322316+00 webhook/pushalarm 1 0 1 1 t \N \N +1039 2026-04-23 12:54:49.146402+00 webhook/pushalarm 1 0 1 1 t \N \N +1040 2026-04-23 12:54:58.808423+00 webhook/pushalarm 1 0 1 1 t \N \N +1041 2026-04-23 12:55:29.468248+00 webhook/pushalarm 1 0 1 1 t \N \N +1043 2026-04-23 12:55:44.600526+00 webhook/pushalarm 1 0 1 1 t \N \N +1048 2026-04-23 12:56:18.435367+00 webhook/pushalarm 1 0 1 1 t \N \N +1050 2026-04-23 12:56:42.556578+00 webhook/pushalarm 1 0 1 1 t \N \N +1051 2026-04-23 12:56:43.363589+00 webhook/pushalarm 1 0 1 1 t \N \N +1052 2026-04-23 12:56:47.937917+00 webhook/pushalarm 1 0 1 1 t \N \N +1053 2026-04-23 12:56:58.556023+00 webhook/pushalarm 1 0 1 1 t \N \N +1054 2026-04-23 12:57:02.13083+00 webhook/pushalarm 1 0 1 1 t \N \N +1055 2026-04-23 12:57:06.644361+00 webhook/pushalarm 1 0 1 1 t \N \N +1056 2026-04-23 12:57:09.887352+00 webhook/pushalarm 1 0 1 0 t \N \N +1064 2026-04-23 12:58:16.03825+00 webhook/pushalarm 1 0 1 1 t \N \N +1065 2026-04-23 12:58:21.548954+00 webhook/pushalarm 1 0 1 1 t \N \N +1066 2026-04-23 12:58:25.82051+00 webhook/pushalarm 1 0 1 1 t \N \N +1071 2026-04-23 12:59:00.599232+00 webhook/pushalarm 1 0 1 1 t \N \N +1073 2026-04-23 12:59:35.167703+00 webhook/pushalarm 1 0 1 0 t \N \N +1074 2026-04-23 12:59:56.586132+00 webhook/pushalarm 1 0 1 0 t \N \N +1075 2026-04-23 12:59:58.709285+00 webhook/pushalarm 1 0 1 1 t \N \N +1077 2026-04-23 13:00:02.20393+00 webhook/pushalarm 1 0 1 27 t \N \N +1081 2026-04-23 13:01:41.71764+00 webhook/pushalarm 1 0 1 1 t \N \N +1082 2026-04-23 13:01:41.861132+00 webhook/pushalarm 1 0 1 1 t \N \N +1083 2026-04-23 13:01:51.286443+00 webhook/pushalarm 1 0 1 1 t \N \N +1084 2026-04-23 13:01:58.606644+00 webhook/pushalarm 1 0 1 1 t \N \N +1085 2026-04-23 13:01:59.316463+00 webhook/pushalarm 1 0 1 1 t \N \N +1086 2026-04-23 13:01:59.769428+00 webhook/pushalarm 1 0 1 2 t \N \N +1088 2026-04-23 13:02:04.856614+00 webhook/pushalarm 1 0 1 1 t \N \N +1089 2026-04-23 13:02:19.498925+00 webhook/pushalarm 1 0 1 4 t \N \N +1090 2026-04-23 13:02:26.487415+00 webhook/pushalarm 1 0 1 1 t \N \N +1091 2026-04-23 13:02:30.556819+00 webhook/pushalarm 1 0 1 2 t \N \N +1092 2026-04-23 13:02:57.843387+00 webhook/pushalarm 1 0 1 1 t \N \N +1094 2026-04-23 13:03:01.017068+00 webhook/pushalarm 1 0 1 1 t \N \N +1095 2026-04-23 13:03:05.165119+00 webhook/pushalarm 1 0 1 1 t \N \N +1034 2026-04-23 12:54:28.942767+00 jimi.device.alarm.list 116 0 -140 714 t \N \N +1072 2026-04-23 12:59:29.728597+00 jimi.device.alarm.list 116 0 -142 727 t \N \N +1035 2026-04-23 12:54:39.870726+00 jimi.user.device.location.list 63 61 9 174 t \N \N +1042 2026-04-23 12:55:40.070097+00 jimi.user.device.location.list 63 61 10 184 t \N \N +1044 2026-04-23 12:55:54.32034+00 jimi.device.track.list 116 0 397 11319 t \N \N +1047 2026-04-23 12:55:57.18912+00 jimi.device.track.mileage 116 0 -78 4582 t \N \N +1049 2026-04-23 12:56:41.169588+00 jimi.user.device.location.list 63 61 9 169 t \N \N +1061 2026-04-23 12:57:58.022704+00 jimi.open.platform.report.parking 116 0 0 21785 t \N \N +1062 2026-04-23 12:57:59.151934+00 jimi.user.device.location.list 63 61 10 168 t \N \N +1070 2026-04-23 12:58:59.362063+00 jimi.user.device.location.list 63 61 11 193 t \N \N +1076 2026-04-23 12:59:59.572581+00 jimi.user.device.location.list 63 61 11 198 t \N \N +1079 2026-04-23 13:00:59.765747+00 jimi.user.device.location.list 63 61 11 170 t \N \N +1087 2026-04-23 13:01:59.987317+00 jimi.user.device.location.list 63 61 11 205 t \N \N +1093 2026-04-23 13:03:00.217604+00 jimi.user.device.location.list 63 61 10 214 t \N \N +1096 2026-04-23 13:03:13.628577+00 webhook/pushalarm 1 0 1 1 t \N \N +1097 2026-04-23 13:03:22.321912+00 webhook/pushalarm 1 0 1 1 t \N \N +1098 2026-04-23 13:03:43.58834+00 webhook/pushalarm 1 0 1 1 t \N \N +1099 2026-04-23 13:03:57.135536+00 webhook/pushalarm 1 0 1 3 t \N \N +1100 2026-04-23 13:04:00.427934+00 webhook/pushalarm 1 0 1 5 t \N \N +1101 2026-04-23 13:04:00.411927+00 jimi.user.device.location.list 63 61 8 180 t \N \N +1102 2026-04-23 13:04:20.888387+00 webhook/pushalarm 1 0 1 1 t \N \N +1103 2026-04-23 13:04:30.949212+00 jimi.device.alarm.list 116 0 -138 1148 t \N \N +1104 2026-04-23 13:04:41.718756+00 webhook/pushalarm 1 0 1 1 t \N \N +1105 2026-04-23 13:05:00.338189+00 webhook/pushalarm 1 0 1 1 t \N \N +1106 2026-04-23 13:05:00.650166+00 jimi.user.device.location.list 63 61 9 214 t \N \N +1107 2026-04-23 13:05:18.326254+00 webhook/pushalarm 1 0 1 2 t \N \N +1108 2026-04-23 13:05:24.306352+00 webhook/pushalarm 1 0 1 1 t \N \N +1109 2026-04-23 13:05:33.380942+00 webhook/pushalarm 1 0 1 1 t \N \N +1110 2026-04-23 13:05:45.135218+00 webhook/pushalarm 1 0 1 1 t \N \N +1111 2026-04-23 13:05:45.157162+00 webhook/pushalarm 1 0 1 0 t \N \N +1112 2026-04-23 13:05:51.474812+00 webhook/pushalarm 1 0 1 1 t \N \N +1113 2026-04-23 13:06:00.956472+00 jimi.user.device.location.list 63 61 9 292 t \N \N +1114 2026-04-23 13:06:22.02791+00 webhook/pushalarm 1 0 1 1 t \N \N +1115 2026-04-23 13:06:24.040615+00 webhook/pushalarm 1 0 1 1 t \N \N +1116 2026-04-23 13:06:26.862829+00 webhook/pushalarm 1 0 1 1 t \N \N +1117 2026-04-23 13:06:27.799836+00 webhook/pushalarm 1 0 1 0 t \N \N +1118 2026-04-23 13:06:27.99904+00 webhook/pushalarm 1 0 1 1 t \N \N +1119 2026-04-23 13:06:44.276038+00 webhook/pushalarm 1 0 1 1 t \N \N +1120 2026-04-23 13:07:01.227109+00 jimi.user.device.location.list 63 61 8 224 t \N \N +1121 2026-04-23 13:07:33.452406+00 webhook/pushalarm 1 0 1 1 t \N \N +1122 2026-04-23 13:07:42.876973+00 webhook/pushalarm 1 0 1 1 t \N \N +1123 2026-04-23 13:07:46.745028+00 webhook/pushalarm 1 0 1 2 t \N \N +1124 2026-04-23 13:08:01.419592+00 jimi.user.device.location.list 63 61 6 181 t \N \N +1125 2026-04-23 13:08:03.937896+00 webhook/pushalarm 1 0 1 1 t \N \N +1126 2026-04-23 13:08:20.562328+00 webhook/pushalarm 1 0 1 1 t \N \N +1127 2026-04-23 13:08:29.90808+00 webhook/pushalarm 1 0 1 1 t \N \N +1128 2026-04-23 13:08:29.957532+00 webhook/pushalarm 1 0 1 1 t \N \N +1129 2026-04-23 13:08:38.498821+00 webhook/pushalarm 1 0 1 1 t \N \N +1130 2026-04-23 13:08:39.562454+00 webhook/pushalarm 1 0 1 2 t \N \N +1131 2026-04-23 13:08:44.739458+00 webhook/pushalarm 1 0 1 1 t \N \N +1132 2026-04-23 13:08:52.324349+00 webhook/pushalarm 1 0 1 1 t \N \N +1133 2026-04-23 13:09:01.641113+00 jimi.user.device.location.list 63 61 6 228 t \N \N +1134 2026-04-23 13:09:14.853724+00 webhook/pushalarm 1 0 1 0 t \N \N +1135 2026-04-23 13:09:22.379671+00 webhook/pushalarm 1 0 1 1 t \N \N +1136 2026-04-23 13:09:23.208146+00 webhook/pushalarm 1 0 1 1 t \N \N +1137 2026-04-23 13:09:31.781259+00 jimi.device.alarm.list 117 0 -151 795 t \N \N +1138 2026-04-23 13:09:37.466196+00 webhook/pushalarm 1 0 1 1 t \N \N +1139 2026-04-23 13:10:01.909603+00 jimi.user.device.location.list 63 61 7 320 t \N \N +1140 2026-04-23 13:10:17.747556+00 webhook/pushalarm 1 0 1 1 t \N \N +1141 2026-04-23 13:10:59.261744+00 webhook/pushalarm 1 0 1 3 t \N \N +1142 2026-04-23 13:11:01.447384+00 webhook/pushalarm 1 0 1 1 t \N \N +1143 2026-04-23 13:11:01.600694+00 jimi.device.track.mileage 117 0 -66 4858 t \N \N +1144 2026-04-23 13:11:06.088014+00 jimi.user.device.location.list 63 61 6 190 t \N \N +1145 2026-04-23 13:11:19.188619+00 webhook/pushalarm 1 0 1 4 t \N \N +1146 2026-04-23 13:11:29.570428+00 webhook/pushalarm 1 0 1 1 t \N \N +1147 2026-04-23 13:11:46.92011+00 webhook/pushalarm 1 0 1 1 t \N \N +1148 2026-04-23 13:12:06.318866+00 jimi.user.device.location.list 63 61 8 217 t \N \N +1149 2026-04-23 13:12:24.431745+00 webhook/pushalarm 1 0 1 1 t \N \N +1150 2026-04-23 13:12:26.072429+00 webhook/pushalarm 1 0 1 1 t \N \N +1151 2026-04-23 13:12:40.485303+00 webhook/pushalarm 1 0 1 1 t \N \N +1152 2026-04-23 13:12:43.780215+00 webhook/pushalarm 1 0 1 1 t \N \N +1153 2026-04-23 13:12:51.469166+00 webhook/pushalarm 1 0 1 1 t \N \N +1154 2026-04-23 13:13:14.164844+00 webhook/pushalarm 1 0 1 1 t \N \N +1155 2026-04-23 13:13:20.364554+00 jimi.open.platform.report.parking 117 0 0 21986 t \N \N +1156 2026-04-23 13:13:21.506662+00 jimi.user.device.location.list 63 61 7 176 t \N \N +1157 2026-04-23 13:13:28.895113+00 webhook/pushalarm 1 0 1 1 t \N \N +1158 2026-04-23 13:14:06.599615+00 webhook/pushalarm 1 0 1 1 t \N \N +1159 2026-04-23 13:14:08.147325+00 webhook/pushalarm 1 0 1 1 t \N \N +1160 2026-04-23 13:14:14.742696+00 webhook/pushalarm 1 0 1 1 t \N \N +1161 2026-04-23 13:14:15.910041+00 webhook/pushalarm 1 0 1 1 t \N \N +1162 2026-04-23 13:14:17.787561+00 webhook/pushalarm 1 0 1 6 t \N \N +1163 2026-04-23 13:14:21.725251+00 jimi.user.device.location.list 63 61 7 198 t \N \N +1164 2026-04-23 13:14:22.310394+00 webhook/pushalarm 1 0 1 1 t \N \N +1165 2026-04-23 13:14:23.459811+00 webhook/pushalarm 1 0 1 0 t \N \N +1166 2026-04-23 13:14:30.916242+00 webhook/pushalarm 1 0 1 1 t \N \N +1167 2026-04-23 13:14:31.122742+00 webhook/pushalarm 1 0 1 1 t \N \N +1168 2026-04-23 13:14:32.019595+00 webhook/pushalarm 1 0 1 1 t \N \N +1174 2026-04-23 13:15:50.176946+00 webhook/pushalarm 1 0 1 1 t \N \N +1178 2026-04-23 13:16:16.285193+00 webhook/pushalarm 1 0 1 1 t \N \N +1179 2026-04-23 13:16:16.75393+00 webhook/pushalarm 1 0 1 1 t \N \N +1185 2026-04-23 13:17:14.84865+00 webhook/pushalarm 1 0 1 1 t \N \N +1186 2026-04-23 13:17:21.241761+00 webhook/pushalarm 1 0 1 1 t \N \N +1188 2026-04-23 13:17:28.778952+00 webhook/pushalarm 1 0 1 1 t \N \N +1190 2026-04-23 13:18:22.746515+00 webhook/pushalarm 1 0 1 1 t \N \N +1191 2026-04-23 13:18:24.836776+00 webhook/pushalarm 1 0 1 1 t \N \N +1195 2026-04-23 13:19:24.029679+00 webhook/pushalarm 1 0 1 1 t \N \N +1197 2026-04-23 13:19:38.570858+00 webhook/pushalarm 1 0 1 2 t \N \N +1198 2026-04-23 13:19:38.883521+00 webhook/pushalarm 1 0 1 1 t \N \N +1201 2026-04-23 13:20:56.998512+00 webhook/pushalarm 1 0 1 2 t \N \N +1206 2026-04-23 13:21:25.832156+00 webhook/pushalarm 1 0 1 1 t \N \N +1209 2026-04-23 13:22:03.467837+00 webhook/pushalarm 1 0 1 2 t \N \N +1210 2026-04-23 13:22:20.804144+00 webhook/pushalarm 1 0 1 1 t \N \N +1169 2026-04-23 13:14:32.648974+00 jimi.device.alarm.list 117 0 -153 969 t \N \N +1196 2026-04-23 13:19:33.757754+00 jimi.device.alarm.list 117 0 -158 790 t \N \N +1170 2026-04-23 13:15:06.1535+00 webhook/pushalarm 1 0 1 1 t \N \N +1171 2026-04-23 13:15:10.876993+00 webhook/pushalarm 1 0 1 0 t \N \N +1173 2026-04-23 13:15:36.722912+00 webhook/pushalarm 1 0 1 2 t \N \N +1175 2026-04-23 13:15:57.391564+00 webhook/pushalarm 1 0 1 1 t \N \N +1176 2026-04-23 13:16:02.518337+00 webhook/pushalarm 1 0 1 0 t \N \N +1177 2026-04-23 13:16:04.155898+00 webhook/pushalarm 1 0 1 1 t \N \N +1180 2026-04-23 13:16:21.979229+00 webhook/pushalarm 1 0 1 1 t \N \N +1182 2026-04-23 13:16:28.863778+00 webhook/pushalarm 1 0 1 1 t \N \N +1183 2026-04-23 13:16:29.320685+00 webhook/pushalarm 1 0 1 1 t \N \N +1184 2026-04-23 13:17:02.013333+00 webhook/pushalarm 1 0 1 2 t \N \N +1192 2026-04-23 13:18:50.705433+00 webhook/pushalarm 1 0 1 1 t \N \N +1193 2026-04-23 13:18:55.089852+00 webhook/pushalarm 1 0 1 1 t \N \N +1199 2026-04-23 13:19:54.342228+00 webhook/pushalarm 1 0 1 1 t \N \N +1202 2026-04-23 13:21:03.265447+00 webhook/pushalarm 1 0 1 1 t \N \N +1203 2026-04-23 13:21:05.531336+00 webhook/pushalarm 1 0 1 2 t \N \N +1204 2026-04-23 13:21:11.158259+00 webhook/pushalarm 1 0 1 0 t \N \N +1207 2026-04-23 13:21:44.108179+00 webhook/pushalarm 1 0 1 1 t \N \N +1208 2026-04-23 13:21:57.273849+00 webhook/pushalarm 1 0 1 2 t \N \N +1212 2026-04-23 13:22:46.179937+00 webhook/pushalarm 1 0 1 2 t \N \N +1213 2026-04-23 13:22:58.003505+00 webhook/pushalarm 1 0 1 0 t \N \N +1214 2026-04-23 13:23:07.057046+00 webhook/pushalarm 1 0 1 1 t \N \N +1215 2026-04-23 13:23:11.39991+00 webhook/pushalarm 1 0 1 1 t \N \N +1216 2026-04-23 13:23:23.331447+00 webhook/pushalarm 1 0 1 2 t \N \N +1218 2026-04-23 13:23:31.355587+00 webhook/pushalarm 1 0 1 1 t \N \N +1219 2026-04-23 13:24:00.374382+00 webhook/pushalarm 1 0 1 3 t \N \N +1220 2026-04-23 13:24:20.548109+00 webhook/pushalarm 1 0 1 1 t \N \N +1172 2026-04-23 13:15:21.964192+00 jimi.user.device.location.list 63 61 8 235 t \N \N +1181 2026-04-23 13:16:22.194431+00 jimi.user.device.location.list 63 61 7 206 t \N \N +1187 2026-04-23 13:17:22.452297+00 jimi.user.device.location.list 63 61 7 239 t \N \N +1189 2026-04-23 13:18:22.680374+00 jimi.user.device.location.list 63 61 9 209 t \N \N +1194 2026-04-23 13:19:22.906008+00 jimi.user.device.location.list 63 61 6 206 t \N \N +1200 2026-04-23 13:20:23.162863+00 jimi.user.device.location.list 63 61 5 231 t \N \N +1205 2026-04-23 13:21:23.379148+00 jimi.user.device.location.list 63 61 5 199 t \N \N +1211 2026-04-23 13:22:23.68477+00 jimi.user.device.location.list 63 61 6 296 t \N \N +1217 2026-04-23 13:23:23.928138+00 jimi.user.device.location.list 63 61 6 235 t \N \N +1221 2026-04-23 13:24:24.250408+00 jimi.user.device.location.list 63 61 5 302 t \N \N +\. + + +-- +-- TOC entry 6921 (class 0 OID 25207) +-- Dependencies: 323 +-- Data for Name: lbs_readings; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.lbs_readings (id, imei, gate_time, post_type, lbs_data, created_at) FROM stdin; +\. + + +-- +-- TOC entry 6903 (class 0 OID 24890) +-- Dependencies: 295 +-- Data for Name: live_positions; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.live_positions (imei, geom, lat, lng, pos_type, confidence, gps_time, hb_time, speed, direction, acc_status, gps_signal, gps_num, elec_quantity, power_value, battery_power_val, tracker_oil, temperature, current_mileage, device_status, expire_flag, activation_flag, loc_desc, recorded_at, updated_at) FROM stdin; +359857081885410 0101000020E6100000A6B8AAECBB72424045F5D6C05609F3BF -1.18978 36.89636 GPS \N 2026-03-05 18:10:16+00 2026-04-23 10:22:52+00 0.00 221.00 0 3 10 \N \N 0.03 \N \N 128797.89 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +359857081891632 0101000020E6100000D34D6210586D424055302AA913D0F3BF -1.2383 36.85425 GPS \N 2026-04-23 13:51:15+00 2026-04-23 10:23:22+00 0.00 124.00 0 3 11 \N \N 0.06 \N \N 178854.85 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +359857081892762 0101000020E610000063EE5A423ECC4340CEC29E76F82B10C0 -4.04294 39.59565 GPS \N 2026-04-22 09:55:07+00 2026-04-23 09:58:39+00 51.00 81.00 0 3 11 \N \N 0.06 \N \N 51048.97 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +359857081892440 0101000020E6100000A5315A4755634240F870C971A7F4F3BF -1.24723 36.77604 GPS \N 2025-03-21 17:41:08+00 2025-03-24 16:11:35+00 43.00 293.00 0 3 9 \N \N 0.05 \N \N 38197.20 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +359857082042052 0101000020E6100000BA490C022B5B4240D235936FB639F4BF -1.26409 36.71225 GPS \N 2026-04-23 13:01:05+00 2026-04-23 10:20:58+00 0.00 67.00 0 4 11 \N \N 0.06 \N \N 192660.24 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +359857081886871 0101000020E6100000382D78D1577C4240E71DA7E8482EF2BF -1.1363 36.97143 GPS \N 2025-12-29 12:35:39+00 2026-03-27 03:39:32+00 37.00 213.00 1 3 7 \N \N 0.06 \N \N 74183.36 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +353549090566885 0101000020E6100000336FD575A8644240F226BF4527CBF4BF -1.299598 36.786391 GPS \N 2025-07-10 13:40:28+00 2025-07-10 13:40:20+00 0.00 58.00 0 4 15 30.00 \N 3.68 \N \N 17036.41 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +353549090566281 0101000020E6100000931E8656276942405BEB8B84B69CF4BF -1.28826 36.821513 GPS \N 2025-06-30 06:33:37+00 2025-06-30 06:30:45+00 0.00 242.00 0 4 10 0.00 \N 3.54 \N \N 7771.90 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +353549090567701 0101000020E6100000209BE447FC5C4240A5A14621C9ECF3BF -1.245309 36.726449 LBS \N 2025-09-02 05:03:32+00 2025-09-02 05:11:19+00 \N \N 0 4 \N 100.00 \N 4.11 \N \N 16896.20 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061568968 0101000020E61000003672DD94F25C424090662C9ACECEF3BF -1.23799 36.726153 GPS \N 2026-03-11 20:59:28+00 2026-03-11 20:59:29+00 0.00 165.00 0 4 15 \N \N 0.06 \N \N 16.23 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061563423 0101000020E6100000DF3653211E4540403EAF78EA9106C93F 0.195513 32.539982 GPS \N 2026-04-20 21:50:15+00 2026-04-20 21:50:17+00 0.00 146.00 0 4 10 \N \N 0.04 \N \N 1174.05 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061563639 0101000020E61000007E1D386744E94240F816D68D7787F9BF -1.595573 37.8224 GPS \N 2026-04-23 13:57:07+00 2026-04-23 10:22:51+00 29.00 335.00 1 4 15 \N \N 0.06 \N \N 14380.22 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061569131 0101000020E610000021E692AAED4240405875560BEC31BD3F 0.114043 32.522878 GPS \N 2026-04-23 13:57:16+00 2026-04-23 09:45:22+00 0.00 42.00 0 4 15 \N \N 0.00 \N \N 2312.07 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061581904 0101000020E610000088F6B182DF544240F6F065A208E9F3BF -1.244393 36.663071 GPS \N 2026-04-23 13:55:52+00 2026-04-23 10:23:03+00 0.00 248.00 0 4 15 \N \N 0.06 \N \N 15139.68 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061564280 0101000020E6100000988A8D791D4540402368CC24EA05C93F 0.195493 32.539962 GPS \N 2026-04-22 15:51:33+00 2026-04-22 15:51:34+00 0.00 178.00 0 4 15 \N \N 0.02 \N \N 841.39 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061569479 0101000020E6100000C85F5AD42743404011397D3D5FB3BC3F 0.112112 32.524653 GPS \N 2026-04-23 12:53:07+00 2026-04-23 09:20:49+00 0.00 270.00 0 4 14 \N \N 0.00 \N \N 1933.45 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061564470 0101000020E6100000DE8D0585415D42400742B28009DCF3BF -1.24122 36.728562 GPS \N 2026-04-23 13:51:57+00 2026-04-23 10:18:54+00 0.00 255.00 0 4 15 \N \N 0.06 \N \N 23840.60 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061563282 0101000020E610000087DEE2E13D454040E5D4CE30B5A5CA3F 0.208182 32.540951 GPS \N 2026-04-23 13:56:45+00 2026-04-23 10:21:00+00 0.00 12.00 1 4 15 \N \N 0.04 \N \N 4752.66 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061569123 0101000020E61000004374081C09664240EED0B01875ADF4BF -1.292348 36.797153 GPS \N 2026-04-23 13:57:11+00 2026-04-23 10:18:17+00 0.00 196.00 0 4 15 \N \N 0.06 \N \N 13009.71 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798052707896 0101000020E6100000ABEAE5779A6A4240520DFB3DB1CEF2BF -1.175462 36.832839 GPS \N 2026-02-05 08:08:15+00 2026-02-05 08:06:59+00 10.00 162.00 1 4 15 \N \N 0.06 \N \N 515.16 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798052713654 0101000020E6100000C097C283666942403FC8B260E28FF3BF -1.222628 36.823441 GPS \N 2025-11-03 21:04:12+00 2025-11-04 14:10:56+00 0.00 0.00 0 4 0 \N \N 0.06 \N \N 5199.72 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798052715220 0101000020E6100000677DCA31593042407D957CEC2E50D1BF -0.270519 36.377722 GPS \N 2026-04-23 08:09:08+00 2026-04-23 08:09:06+00 4.00 39.00 1 4 11 \N \N 0.06 \N \N 16385.58 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798052708167 0101000020E6100000EFFFE3840981424086C954C1A8A4F1BF -1.1027 37.008103 GPS \N 2026-04-22 18:17:30+00 2026-04-22 20:58:04+00 0.00 296.00 0 4 0 \N \N 0.06 \N \N 4569.72 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798052708068 0101000020E61000002FC03E3A75534240F240649126DEF1BF -1.116736 36.652015 GPS \N 2026-04-23 13:56:07+00 2026-04-23 10:22:52+00 0.00 93.00 0 4 0 \N \N 0.06 \N \N 4421.10 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798052713779 0101000020E6100000650113B87571424067BAD7497D99F4BF -1.287473 36.886405 GPS \N 2025-11-15 08:39:18+00 2025-11-15 09:51:22+00 0.00 352.00 0 4 0 \N \N 0.06 \N \N 5344.24 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798052713811 0101000020E61000004FCFBBB1A07242406C0723F60960F3BF -1.210947 36.895529 GPS \N 2026-04-17 11:13:36+00 2026-04-17 11:12:01+00 7.00 195.00 1 4 13 \N \N 0.06 \N \N 9657.42 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061042261 0101000020E61000007B12D89C83674240CE716E13EE55F4BF -1.270979 36.808704 GPS \N 2026-04-23 03:53:54+00 2026-04-23 10:14:41+00 14.00 258.00 0 4 4 \N \N 0.06 \N \N 18721.62 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061053748 0101000020E6100000105B7A34D5D5434067D65240DA3F10C0 -4.062356 39.670569 GPS \N 2026-04-23 13:55:01+00 2026-04-23 10:23:14+00 7.00 101.00 1 4 15 \N \N 0.06 \N \N 26549.70 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061047435 0101000020E6100000A20BEA5BE66442407218CC5F2173F4BF -1.278108 36.78828 GPS \N 2026-04-23 12:42:41+00 2026-04-23 10:14:33+00 0.00 51.00 1 3 15 \N \N 0.06 \N \N 9748.87 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061053714 0101000020E6100000E63FA4DFBE5E4240C45F9335EA61F4BF -1.273905 36.7402 GPS \N 2026-04-23 13:57:15+00 2026-04-23 10:20:29+00 20.00 79.00 1 4 15 \N \N 0.06 \N \N 26823.32 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061048615 0101000020E6100000B7B3AF3C485D4240A7069ACFB9DBF3BF -1.241144 36.728767 GPS \N 2025-09-29 04:36:10+00 2025-09-29 05:17:36+00 0.00 266.00 0 2 14 \N \N 0.00 \N \N 5721.21 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061036164 0101000020E6100000312592E8655C4240FF78AF5A99B0F3BF -1.230615 36.72186 GPS \N 2026-04-10 19:57:22+00 2026-04-10 20:59:29+00 0.00 267.00 0 4 15 \N \N 0.06 \N \N 22990.33 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061037980 0101000020E6100000BE2D58AA0B604240643E20D09974F4BF -1.278467 36.750356 GPS \N 2026-04-23 13:57:08+00 2026-04-23 10:18:49+00 13.00 250.00 1 4 12 \N \N 0.06 \N \N 42463.06 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061043426 0101000020E61000002121CA17B466424074EACA67799EF2BF -1.16369 36.802371 GPS \N 2026-04-23 13:57:11+00 2026-04-23 10:13:12+00 80.00 274.00 1 4 15 \N \N 0.06 \N \N 21171.05 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061035778 0101000020E61000004089CF9D607D424026A77686A92DF2BF -1.136148 36.979511 GPS \N 2026-04-23 12:42:10+00 2026-04-23 10:22:14+00 0.00 196.00 0 4 12 \N \N 0.06 \N \N 17643.14 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +865135061049001 0101000020E61000000551F701485D4240EB6E9EEA90DBF3BF -1.241105 36.72876 GPS \N 2026-04-03 04:07:39+00 2026-04-11 15:13:26+00 0.00 2.00 0 4 4 \N \N 0.00 \N \N 20612.89 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050524657 0101000020E6100000B7D4415E0F724240215C01857A7AF4BF -1.279902 36.891094 GPS \N 2025-09-05 20:40:21+00 2025-09-05 23:57:33+00 7.00 71.00 0 4 15 \N \N 0.06 \N \N 46233.99 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050524897 0101000020E610000021B1DD3D406542405C7347FFCBB5F4BF -1.294384 36.791023 GPS \N 2026-01-30 08:18:39+00 2026-02-23 22:30:20+00 7.00 342.00 0 4 9 \N \N 0.06 \N \N 12668.43 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050525423 0101000020E6100000C4211B4817DB4340FD6B79E57AFB0FC0 -3.997793 39.711648 GPS \N 2026-04-23 13:29:15+00 2026-04-23 10:23:56+00 11.00 348.00 0 4 15 \N \N 0.06 \N \N 48768.16 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050525225 0101000020E6100000A0A4C00298744240E6EB32FCA75BF3BF -1.209877 36.910889 GPS \N 2025-12-17 11:12:12+00 2025-12-17 11:09:56+00 71.00 244.00 1 4 15 \N \N 0.06 \N \N 19138.05 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050525589 0101000020E610000074D190F128734240D576137CD334F3BF -1.200397 36.899687 GPS \N 2026-04-01 07:57:42+00 2026-04-19 20:21:10+00 13.00 53.00 0 4 8 \N \N 0.06 \N \N 15874.39 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050525068 0101000020E6100000F6D4EAABAB724240895FB1868B5CF3BF -1.210094 36.895864 GPS \N 2025-12-04 13:46:24+00 2026-01-31 14:59:00+00 9.00 27.00 0 4 10 \N \N 0.06 \N \N 12299.13 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050522107 0101000020E61000002E1A321EA57A4240849A2155146FF4BF -1.277119 36.958164 GPS \N 2025-10-11 18:36:41+00 2025-12-04 13:19:08+00 7.00 7.00 1 4 14 \N \N 0.06 \N \N 23316.09 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050522743 0101000020E6100000B14F00C5C8724240116DC7D45D59F3BF -1.209318 36.896752 GPS \N 2025-11-23 16:07:52+00 2025-11-23 18:07:34+00 10.00 28.00 0 4 15 \N \N 0.06 \N \N 12133.75 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050524368 0101000020E61000009C6B98A1F1724240C007AF5DDA70F5BF -1.340052 36.897999 GPS \N 2026-04-14 09:29:24+00 2026-04-15 14:44:13+00 53.00 131.00 1 4 12 \N \N 0.06 \N \N 169208.91 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050524608 0101000020E61000004F965AEF377C424004711E4E60BAF2BF -1.170502 36.970457 GPS \N 2026-04-09 15:22:36+00 2026-04-09 18:22:59+00 8.00 116.00 0 4 15 \N \N 0.06 \N \N 7219.31 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050525605 0101000020E6100000DA0418963F5D42400742B28009DCF3BF -1.24122 36.728503 GPS \N 2025-12-24 10:33:08+00 2025-12-24 14:08:06+00 12.00 228.00 0 4 7 \N \N 0.06 \N \N 23976.94 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050524558 0101000020E610000031D28BDAFD54424091D26C1E8701F4BF -1.250373 36.663997 GPS \N 2026-01-30 15:12:30+00 2026-02-23 21:10:05+00 11.00 282.00 0 4 11 \N \N 0.06 \N \N 23711.63 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050523386 0101000020E6100000942F682101774240378DEDB5A037F3BF -1.201081 36.929722 GPS \N 2026-03-29 15:43:39+00 2026-03-29 18:02:35+00 13.00 191.00 0 4 5 \N \N 0.06 \N \N 33979.83 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050522859 0101000020E61000002881CD39786A4240D40D1478275FF4BF -1.273231 36.831794 GPS \N 2025-02-22 07:42:12+00 2025-02-25 15:25:27+00 7.00 197.00 1 4 13 \N \N 0.06 \N \N 6934.86 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050525951 0101000020E61000000A815CE2C86F42404C512E8D5FF8F3BF -1.248138 36.873318 GPS \N 2025-02-19 19:38:33+00 2025-02-19 21:50:18+00 12.00 349.00 0 4 11 \N \N 0.06 \N \N 13116.00 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050522883 0101000020E6100000593332C85D5A4240BF2A172AFF9AF3BF -1.225341 36.705987 GPS \N 2026-04-22 19:24:29+00 2026-04-22 19:36:50+00 9.00 140.00 0 4 15 \N \N 0.06 \N \N 14483.01 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050524384 0101000020E61000006ABDDF68C7754240A7CCCD37A2BBF2BF -1.170809 36.920148 GPS \N 2025-11-15 16:28:09+00 2025-11-15 18:33:46+00 7.00 38.00 0 4 15 \N \N 0.06 \N \N 13685.18 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050523816 0101000020E61000001C78B5DC99DD4340DB4C857824BE0FC0 -3.967843 39.731258 GPS \N 2025-10-30 18:04:32+00 2025-10-30 20:17:51+00 11.00 184.00 0 4 10 \N \N 0.06 \N \N 54320.21 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050523618 0101000020E610000019E6046D72804240566133C00559F2BF -1.146734 37.003492 GPS \N 2026-04-19 19:48:15+00 2026-04-19 23:07:21+00 7.00 110.00 0 3 14 \N \N 0.06 \N \N 26496.50 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050524707 0101000020E6100000E42EC214E55E4240AD86C43D963EF4BF -1.26528 36.741366 GPS \N 2025-12-24 07:29:52+00 2025-12-24 07:29:03+00 7.00 179.00 1 4 8 \N \N 0.06 \N \N 34715.97 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050288261 0101000020E61000007506465ED67642402882380F2770F2BF -1.152381 36.928417 GPS \N 2026-04-19 16:13:40+00 2026-04-19 16:53:59+00 8.00 289.00 1 4 8 \N \N 0.06 \N \N 18538.42 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +862798050288360 0101000020E61000008978EBFCDB6F4240CAA65CE15DAEF3BF -1.23007 36.873901 GPS \N 2026-04-23 12:22:42+00 2026-04-23 10:23:19+00 9.00 68.00 0 4 15 \N \N 0.06 \N \N 17782.35 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +359857082897091 0101000020E6100000026553AEF07242409A25016A6A59F3BF -1.20933 36.89797 GPS \N 2026-04-23 13:43:47+00 2026-04-23 10:20:38+00 0.00 249.00 0 4 11 \N \N 0.05 \N \N 131068.31 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +359857082912239 0101000020E61000008F537424974743407AAA436E861B0BC0 -3.38844 38.5593 GPS \N 2026-04-23 13:52:18+00 2026-04-23 10:22:22+00 0.00 112.00 0 2 9 \N \N 0.05 \N \N 76988.25 1 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +359857081891798 0101000020E610000043E21E4B1F6A424003B2D7BB3F5EF4BF -1.27301 36.82908 GPS \N 2025-06-16 09:18:18+00 2025-06-17 07:26:15+00 0.00 268.00 1 3 4 \N \N 0.06 \N \N 168840.95 0 \N \N \N 2026-04-23 10:23:56.750839+00 2026-04-23 13:57:18.178462+00 +\. + + +-- +-- TOC entry 6912 (class 0 OID 24988) +-- Dependencies: 304 +-- Data for Name: obd_readings; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.obd_readings (id, imei, reading_time, engine_rpm, fuel_level_pct, updated_at, car_type, acc_state, status_flags, lat, lng, geom, obd_data, coolant_temp_c, battery_voltage, intake_pressure, throttle_pct, vehicle_speed, engine_load_pct) FROM stdin; +\. + + +-- +-- TOC entry 6908 (class 0 OID 24949) +-- Dependencies: 300 +-- Data for Name: parking_events; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.parking_events (id, imei, event_type, start_time, end_time, duration_seconds, geom, address, updated_at) FROM stdin; +\. + + +-- +-- TOC entry 6904 (class 0 OID 24910) +-- Dependencies: 296 +-- Data for Name: position_history; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.position_history (imei, gps_time, geom, lat, lng, speed, direction, acc_status, satellite, current_mileage, recorded_at, altitude, post_type, source) FROM stdin; +\. + + +-- +-- TOC entry 6897 (class 0 OID 22994) +-- Dependencies: 284 +-- Data for Name: schema_migrations; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.schema_migrations (filename, applied_at) FROM stdin; +02_tracksolid_full_schema_rev.sql 2026-04-23 10:23:52.312261+00 +03_webhook_schema_migration.sql 2026-04-23 10:23:52.348921+00 +04_bug_fix_migration.sql 2026-04-23 10:23:52.556443+00 +05_enhancement_migration.sql 2026-04-23 10:23:52.663325+00 +06_business_analytics_migration.sql 2026-04-23 10:23:52.849259+00 +07_analytics_views.sql 2026-04-23 10:23:53.023867+00 +\. + + +-- +-- TOC entry 6919 (class 0 OID 25191) +-- Dependencies: 321 +-- Data for Name: temperature_readings; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.temperature_readings (imei, reading_time, temperature, humidity_pct, created_at) FROM stdin; +\. + + +-- +-- TOC entry 6906 (class 0 OID 24930) +-- Dependencies: 298 +-- Data for Name: trips; Type: TABLE DATA; Schema: tracksolid; Owner: postgres +-- + +COPY tracksolid.trips (id, imei, start_time, end_time, start_geom, end_geom, distance_km, avg_speed_kmh, max_speed_kmh, updated_at, fuel_consumed_l, idle_time_s, driving_time_s, trip_seq, source) FROM stdin; +8 865135061569123 2026-04-23 09:05:09+00 2026-04-23 09:26:44+00 \N \N 6.05 16.82 \N 2026-04-23 10:23:58.790821+00 \N \N 1294 \N poll +970 865135061581904 2026-04-23 13:40:32+00 2026-04-23 13:55:53+00 \N \N 2.32 9.07 \N 2026-04-23 13:56:19.217141+00 \N \N 921 \N poll +971 865135061053748 2026-04-23 13:27:52+00 2026-04-23 13:43:54+00 \N \N 3.49 13.08 \N 2026-04-23 13:56:19.217141+00 \N \N 961 \N poll +21 865135061569123 2026-04-23 10:29:25+00 2026-04-23 10:33:39+00 \N \N 0.64 8.99 \N 2026-04-23 11:24:41.700843+00 \N \N 254 \N poll +22 865135061564470 2026-04-23 10:28:03+00 2026-04-23 10:33:42+00 \N \N 0.99 10.49 \N 2026-04-23 11:24:41.700843+00 \N \N 339 \N poll +17 359857081891632 2026-04-23 09:35:30+00 2026-04-23 09:37:27+00 \N \N 0.21 6.45 \N 2026-04-23 10:23:58.790821+00 \N \N 116 \N poll +18 862798050288360 2026-04-23 09:32:38+00 2026-04-23 09:34:27+00 \N \N 0.15 4.97 \N 2026-04-23 10:23:58.790821+00 \N \N 109 \N poll +19 862798050288360 2026-04-23 09:28:01+00 2026-04-23 09:29:01+00 \N \N 0.19 11.37 \N 2026-04-23 10:23:58.790821+00 \N \N 60 \N poll +20 359857082912239 2026-04-23 09:18:57+00 2026-04-23 09:24:49+00 \N \N 2.06 21.08 \N 2026-04-23 10:23:58.790821+00 \N \N 351 \N poll +973 865135061569131 2026-04-23 13:13:05+00 2026-04-23 13:42:18+00 \N \N 8.68 17.83 \N 2026-04-23 13:56:19.217141+00 \N \N 1752 \N poll +981 359857082918012 2026-04-23 13:52:54+00 2026-04-23 13:55:16+00 \N \N 0.06 1.41 \N 2026-04-23 13:56:19.217141+00 \N \N 142 \N poll +982 359857082918186 2026-04-23 13:46:44+00 2026-04-23 13:47:43+00 \N \N 0.11 6.82 \N 2026-04-23 13:56:19.217141+00 \N \N 59 \N poll +4 865135061569123 2026-04-23 09:39:17+00 2026-04-23 09:49:45+00 \N \N 6.83 39.18 \N 2026-04-23 10:39:22.296127+00 \N \N 627 \N poll +5 865135061581904 2026-04-23 09:30:03+00 2026-04-23 09:44:10+00 \N \N 2.98 12.70 \N 2026-04-23 10:39:22.296127+00 \N \N 846 \N poll +6 865135061053748 2026-04-23 09:26:25+00 2026-04-23 09:40:30+00 \N \N 3.62 15.43 \N 2026-04-23 10:39:22.296127+00 \N \N 845 \N poll +1 865135061563282 2026-04-23 10:18:02+00 2026-04-23 10:20:01+00 \N \N 0.77 23.61 \N 2026-04-23 11:09:36.391704+00 \N \N 118 \N poll +23 862798052708068 2026-04-23 10:24:29+00 2026-04-23 10:25:14+00 \N \N 0.10 8.02 \N 2026-04-23 11:24:41.700843+00 \N \N 45 \N poll +25 865135061053748 2026-04-23 10:12:15+00 2026-04-23 10:29:39+00 \N \N 3.51 12.11 \N 2026-04-23 11:24:41.700843+00 \N \N 1044 \N poll +983 359857082898487 2026-04-23 13:45:05+00 2026-04-23 13:52:46+00 \N \N 1.80 14.02 \N 2026-04-23 13:56:19.217141+00 \N \N 461 \N poll +984 359857082912239 2026-04-23 13:42:14+00 2026-04-23 13:51:58+00 \N \N 3.20 19.70 \N 2026-04-23 13:56:19.217141+00 \N \N 584 \N poll +226 862798050525423 2026-04-23 10:41:22+00 2026-04-23 10:41:44+00 \N \N 0.11 18.72 \N 2026-04-23 11:39:46.779828+00 \N \N 21 \N poll +987 359857081891632 2026-04-23 13:32:44+00 2026-04-23 13:51:46+00 \N \N 4.30 13.57 \N 2026-04-23 13:56:19.217141+00 \N \N 1141 \N poll +991 865135061054555 2026-04-23 13:27:54+00 2026-04-23 13:43:41+00 \N \N 12.73 48.36 \N 2026-04-23 13:56:19.217141+00 \N \N 947 \N poll +992 862798050526231 2026-04-23 13:25:46+00 2026-04-23 13:41:55+00 \N \N 3.60 13.39 \N 2026-04-23 13:56:19.217141+00 \N \N 968 \N poll +993 359857082897257 2026-04-23 13:23:43+00 2026-04-23 13:48:51+00 \N \N 7.04 16.82 \N 2026-04-23 13:56:19.217141+00 \N \N 1507 \N poll +929 865135061562847 2026-04-23 13:15:47+00 2026-04-23 13:28:23+00 \N \N 3.17 15.14 \N 2026-04-23 13:56:19.217141+00 \N \N 755 \N poll +932 359857082918012 2026-04-23 13:11:37+00 2026-04-23 13:30:47+00 \N \N 7.03 22.02 \N 2026-04-23 13:56:19.217141+00 \N \N 1150 \N poll +1006 359857082897794 2026-04-23 12:59:28+00 2026-04-23 13:48:36+00 \N \N 10.85 13.25 \N 2026-04-23 13:56:19.217141+00 \N \N 2947 \N poll +746 862798050523337 2026-04-23 11:56:45+00 2026-04-23 12:02:38+00 \N \N 1.42 14.53 \N 2026-04-23 12:55:57.18912+00 \N \N 352 \N poll +754 862798050523014 2026-04-23 11:42:39+00 2026-04-23 11:59:02+00 \N \N 4.84 17.72 \N 2026-04-23 12:55:57.18912+00 \N \N 982 \N poll +32 359857082898487 2026-04-23 10:35:08+00 2026-04-23 10:39:05+00 \N \N 0.13 1.92 \N 2026-04-23 11:24:41.700843+00 \N \N 237 \N poll +1018 359857082042953 2026-04-23 13:31:14+00 2026-04-23 13:48:44+00 \N \N 5.45 18.67 \N 2026-04-23 13:56:19.217141+00 \N \N 1050 \N poll +957 865135061035133 2026-04-23 13:23:28+00 2026-04-23 13:32:08+00 \N \N 5.86 40.66 \N 2026-04-23 13:56:19.217141+00 \N \N 519 \N poll +33 865135061054548 2026-04-23 10:34:48+00 2026-04-23 10:37:36+00 \N \N 0.34 7.36 \N 2026-04-23 11:24:41.700843+00 \N \N 167 \N poll +218 862798050525423 2026-04-23 11:12:24+00 2026-04-23 11:13:53+00 \N \N 0.35 14.22 \N 2026-04-23 12:10:38.317354+00 \N \N 89 \N poll +64 359857082898487 2026-04-23 09:52:41+00 2026-04-23 09:53:43+00 \N \N 0.16 9.07 \N 2026-04-23 10:39:22.296127+00 \N \N 62 \N poll +65 865135061054555 2026-04-23 09:47:34+00 2026-04-23 09:49:39+00 \N \N 0.77 22.27 \N 2026-04-23 10:39:22.296127+00 \N \N 124 \N poll +34 359857082898487 2026-04-23 10:33:31+00 2026-04-23 10:34:58+00 \N \N 0.12 4.90 \N 2026-04-23 11:24:41.700843+00 \N \N 86 \N poll +35 359857082897794 2026-04-23 10:32:59+00 2026-04-23 10:36:43+00 \N \N 0.60 9.65 \N 2026-04-23 11:24:41.700843+00 \N \N 223 \N poll +68 865135061054548 2026-04-23 09:43:15+00 2026-04-23 09:48:59+00 \N \N 0.78 8.19 \N 2026-04-23 10:39:22.296127+00 \N \N 343 \N poll +1020 359857082918038 2026-04-23 13:22:47+00 2026-04-23 13:32:24+00 \N \N 3.82 23.82 \N 2026-04-23 13:56:19.217141+00 \N \N 577 \N poll +15 359857082042052 2026-04-23 09:41:45+00 2026-04-23 09:44:59+00 \N \N 0.02 0.37 \N 2026-04-23 10:39:22.296127+00 \N \N 193 \N poll +36 359857082918012 2026-04-23 10:25:07+00 2026-04-23 10:26:43+00 \N \N 0.19 7.28 \N 2026-04-23 11:24:41.700843+00 \N \N 96 \N poll +37 865135061035653 2026-04-23 10:24:18+00 2026-04-23 10:24:50+00 \N \N 0.05 6.26 \N 2026-04-23 11:24:41.700843+00 \N \N 31 \N poll +38 359857082910589 2026-04-23 10:23:53+00 2026-04-23 10:34:24+00 \N \N 1.74 9.94 \N 2026-04-23 11:24:41.700843+00 \N \N 631 \N poll +39 865135061054548 2026-04-23 10:23:49+00 2026-04-23 10:26:25+00 \N \N 0.47 10.82 \N 2026-04-23 11:24:41.700843+00 \N \N 156 \N poll +40 359857082907973 2026-04-23 10:23:30+00 2026-04-23 10:26:47+00 \N \N 0.35 6.36 \N 2026-04-23 11:24:41.700843+00 \N \N 197 \N poll +2 865135061053748 2026-04-23 10:01:42+00 2026-04-23 10:08:32+00 \N \N 1.85 16.24 \N 2026-04-23 10:54:32.11435+00 \N \N 410 \N poll +3 865135061053748 2026-04-23 09:43:52+00 2026-04-23 09:57:32+00 \N \N 3.51 15.42 \N 2026-04-23 10:54:32.11435+00 \N \N 819 \N poll +7 865135061037980 2026-04-23 09:10:22+00 2026-04-23 10:03:05+00 \N \N 34.99 39.82 \N 2026-04-23 10:54:32.11435+00 \N \N 3163 \N poll +194 862798050523527 2026-04-23 10:23:09+00 2026-04-23 10:27:35+00 \N \N 0.48 6.50 \N 2026-04-23 11:24:41.700843+00 \N \N 266 \N poll +43 359857082911983 2026-04-23 10:19:00+00 2026-04-23 10:31:41+00 \N \N 8.47 40.12 \N 2026-04-23 11:24:41.700843+00 \N \N 760 \N poll +44 862798050288360 2026-04-23 10:18:03+00 2026-04-23 10:31:10+00 \N \N 8.74 39.96 \N 2026-04-23 11:24:41.700843+00 \N \N 787 \N poll +46 862798052707946 2026-04-23 10:16:03+00 2026-04-23 10:25:23+00 \N \N 3.11 20.02 \N 2026-04-23 11:24:41.700843+00 \N \N 559 \N poll +47 359857081891632 2026-04-23 10:15:35+00 2026-04-23 10:27:58+00 \N \N 3.16 15.31 \N 2026-04-23 11:24:41.700843+00 \N \N 743 \N poll +48 862798050526231 2026-04-23 10:11:25+00 2026-04-23 10:27:25+00 \N \N 3.58 13.44 \N 2026-04-23 11:24:41.700843+00 \N \N 959 \N poll +219 865135061569123 2026-04-23 11:09:01+00 2026-04-23 11:22:28+00 \N \N 2.43 10.84 \N 2026-04-23 12:10:38.317354+00 \N \N 806 \N poll +53 359857082897257 2026-04-23 10:05:30+00 2026-04-23 10:28:25+00 \N \N 6.62 17.35 \N 2026-04-23 11:24:41.700843+00 \N \N 1374 \N poll +56 359857082897794 2026-04-23 10:01:02+00 2026-04-23 10:30:20+00 \N \N 6.33 12.96 \N 2026-04-23 11:24:41.700843+00 \N \N 1758 \N poll +959 865135061048276 2026-04-23 13:14:58+00 2026-04-23 13:26:23+00 \N \N 1.77 9.29 \N 2026-04-23 13:56:19.217141+00 \N \N 685 \N poll +1030 862798050523295 2026-04-23 11:47:51+00 2026-04-23 13:14:41+00 \N \N 35.49 24.52 \N 2026-04-23 13:56:19.217141+00 \N \N 5210 \N poll +384 865135061569123 2026-04-23 11:36:51+00 2026-04-23 11:39:36+00 \N \N 1.61 35.23 \N 2026-04-23 12:25:45.284558+00 \N \N 164 \N poll +386 865135061037980 2026-04-23 11:31:17+00 2026-04-23 11:40:46+00 \N \N 1.50 9.45 \N 2026-04-23 12:25:45.284558+00 \N \N 569 \N poll +379 865135061564470 2026-04-23 11:51:15+00 2026-04-23 11:54:02+00 \N \N 0.18 3.82 \N 2026-04-23 12:40:50.034583+00 \N \N 167 \N poll +380 865135061564470 2026-04-23 11:44:08+00 2026-04-23 11:49:14+00 \N \N 0.15 1.82 \N 2026-04-23 12:40:50.034583+00 \N \N 305 \N poll +381 865135061569123 2026-04-23 11:40:36+00 2026-04-23 11:47:44+00 \N \N 2.87 24.17 \N 2026-04-23 12:40:50.034583+00 \N \N 428 \N poll +382 865135061564470 2026-04-23 11:40:34+00 2026-04-23 11:43:20+00 \N \N 0.44 9.45 \N 2026-04-23 12:40:50.034583+00 \N \N 166 \N poll +383 862798050525423 2026-04-23 11:38:52+00 2026-04-23 11:42:40+00 \N \N 0.84 13.25 \N 2026-04-23 12:40:50.034583+00 \N \N 227 \N poll +71 862798050523014 2026-04-23 09:41:41+00 2026-04-23 09:53:43+00 \N \N 3.31 16.52 \N 2026-04-23 10:39:22.296127+00 \N \N 721 \N poll +16 862798050288360 2026-04-23 09:39:34+00 2026-04-23 09:40:03+00 \N \N 0.11 13.65 \N 2026-04-23 10:39:22.296127+00 \N \N 28 \N poll +73 359857082911983 2026-04-23 09:39:15+00 2026-04-23 09:40:10+00 \N \N 0.18 11.78 \N 2026-04-23 10:39:22.296127+00 \N \N 55 \N poll +74 359857082918186 2026-04-23 09:38:36+00 2026-04-23 09:44:44+00 \N \N 1.73 16.95 \N 2026-04-23 10:39:22.296127+00 \N \N 368 \N poll +75 865135061562722 2026-04-23 09:35:57+00 2026-04-23 09:51:08+00 \N \N 3.93 15.53 \N 2026-04-23 10:39:22.296127+00 \N \N 911 \N poll +76 359857082896911 2026-04-23 09:32:32+00 2026-04-23 09:41:51+00 \N \N 2.93 18.87 \N 2026-04-23 10:39:22.296127+00 \N \N 559 \N poll +77 359857082897794 2026-04-23 09:30:35+00 2026-04-23 09:43:56+00 \N \N 7.99 35.94 \N 2026-04-23 10:39:22.296127+00 \N \N 800 \N poll +78 862798050526231 2026-04-23 09:26:13+00 2026-04-23 09:39:27+00 \N \N 3.67 16.66 \N 2026-04-23 10:39:22.296127+00 \N \N 793 \N poll +300 865135061564470 2026-04-23 11:33:19+00 2026-04-23 11:37:20+00 \N \N 0.07 1.02 \N 2026-04-23 12:25:45.284558+00 \N \N 241 \N poll +301 865135061053748 2026-04-23 11:30:06+00 2026-04-23 11:33:57+00 \N \N 0.28 4.29 \N 2026-04-23 12:25:45.284558+00 \N \N 231 \N poll +302 865135061569123 2026-04-23 11:24:31+00 2026-04-23 11:35:36+00 \N \N 1.77 9.59 \N 2026-04-23 12:25:45.284558+00 \N \N 665 \N poll +321 359857082918012 2026-04-23 11:27:18+00 2026-04-23 11:38:51+00 \N \N 0.33 1.71 \N 2026-04-23 12:25:45.284558+00 \N \N 692 \N poll +142 865135061053748 2026-04-23 10:56:49+00 2026-04-23 11:01:51+00 \N \N 1.67 19.90 \N 2026-04-23 11:55:33.001929+00 \N \N 302 \N poll +143 865135061043426 2026-04-23 10:51:52+00 2026-04-23 11:01:57+00 \N \N 5.70 33.89 \N 2026-04-23 11:55:33.001929+00 \N \N 605 \N poll +144 865135061569123 2026-04-23 10:49:22+00 2026-04-23 11:05:47+00 \N \N 4.78 17.47 \N 2026-04-23 11:55:33.001929+00 \N \N 984 \N poll +322 865135061054548 2026-04-23 11:24:14+00 2026-04-23 11:29:35+00 \N \N 0.72 8.12 \N 2026-04-23 12:25:45.284558+00 \N \N 321 \N poll +326 865135061035653 2026-04-23 11:18:29+00 2026-04-23 11:26:57+00 \N \N 1.40 9.92 \N 2026-04-23 12:25:45.284558+00 \N \N 508 \N poll +328 865135061559538 2026-04-23 11:16:13+00 2026-04-23 11:26:25+00 \N \N 3.84 22.58 \N 2026-04-23 12:25:45.284558+00 \N \N 612 \N poll +420 862798050523337 2026-04-23 11:13:54+00 2026-04-23 11:38:25+00 \N \N 9.58 23.44 \N 2026-04-23 12:25:45.284558+00 \N \N 1471 \N poll +410 359857082046145 2026-04-23 11:28:47+00 2026-04-23 11:42:44+00 \N \N 2.70 11.62 \N 2026-04-23 12:40:50.034583+00 \N \N 837 \N poll +123 359857082046145 2026-04-23 10:07:50+00 2026-04-23 10:08:41+00 \N \N 0.10 7.47 \N 2026-04-23 10:54:32.11435+00 \N \N 50 \N poll +54 359857082911983 2026-04-23 10:04:02+00 2026-04-23 10:04:42+00 \N \N 0.12 11.07 \N 2026-04-23 10:54:32.11435+00 \N \N 40 \N poll +55 862798050526231 2026-04-23 10:01:37+00 2026-04-23 10:08:07+00 \N \N 1.87 17.33 \N 2026-04-23 10:54:32.11435+00 \N \N 389 \N poll +606 359857082918038 2026-04-23 12:10:14+00 2026-04-23 12:22:20+00 \N \N 3.83 19.03 \N 2026-04-23 13:11:01.600694+00 \N \N 725 \N poll +79 865135061053748 2026-04-23 10:45:22+00 2026-04-23 10:49:59+00 \N \N 1.68 21.88 \N 2026-04-23 11:39:46.779828+00 \N \N 277 \N poll +60 359857082911983 2026-04-23 10:00:28+00 2026-04-23 10:01:44+00 \N \N 0.17 7.99 \N 2026-04-23 10:54:32.11435+00 \N \N 75 \N poll +13 862798050288360 2026-04-23 10:00:26+00 2026-04-23 10:04:25+00 \N \N 0.32 4.80 \N 2026-04-23 10:54:32.11435+00 \N \N 238 \N poll +62 865135061054548 2026-04-23 09:56:50+00 2026-04-23 10:08:36+00 \N \N 3.88 19.83 \N 2026-04-23 10:54:32.11435+00 \N \N 705 \N poll +14 359857082912239 2026-04-23 09:56:17+00 2026-04-23 10:00:09+00 \N \N 1.44 22.36 \N 2026-04-23 10:54:32.11435+00 \N \N 232 \N poll +146 865135061569479 2026-04-23 10:38:35+00 2026-04-23 10:51:55+00 \N \N 5.24 23.56 \N 2026-04-23 11:39:46.779828+00 \N \N 800 \N poll +80 865135061053748 2026-04-23 10:37:35+00 2026-04-23 10:40:52+00 \N \N 0.81 14.80 \N 2026-04-23 11:39:46.779828+00 \N \N 196 \N poll +67 862798050526231 2026-04-23 09:43:49+00 2026-04-23 09:57:45+00 \N \N 3.69 15.93 \N 2026-04-23 10:54:32.11435+00 \N \N 835 \N poll +69 359857082910589 2026-04-23 09:42:51+00 2026-04-23 09:55:22+00 \N \N 2.22 10.65 \N 2026-04-23 10:54:32.11435+00 \N \N 750 \N poll +81 865135061043426 2026-04-23 10:37:15+00 2026-04-23 10:46:36+00 \N \N 5.93 38.08 \N 2026-04-23 11:39:46.779828+00 \N \N 561 \N poll +87 865135061581904 2026-04-23 10:03:25+00 2026-04-23 10:45:50+00 \N \N 19.35 27.38 \N 2026-04-23 11:39:46.779828+00 \N \N 2545 \N poll +89 865135061035778 2026-04-23 09:48:48+00 2026-04-23 10:44:54+00 \N \N 38.12 40.78 \N 2026-04-23 11:39:46.779828+00 \N \N 3365 \N poll +156 865135061563639 2026-04-23 08:47:44+00 2026-04-23 10:54:51+00 \N \N 37.98 17.93 \N 2026-04-23 11:39:46.779828+00 \N \N 7627 \N poll +607 865135061035133 2026-04-23 12:08:45+00 2026-04-23 12:11:40+00 \N \N 0.71 14.54 \N 2026-04-23 13:11:01.600694+00 \N \N 175 \N poll +685 862798050523626 2026-04-23 12:08:39+00 2026-04-23 12:11:09+00 \N \N 0.69 16.68 \N 2026-04-23 13:11:01.600694+00 \N \N 149 \N poll +608 865135061048953 2026-04-23 12:02:09+00 2026-04-23 12:12:38+00 \N \N 2.25 12.91 \N 2026-04-23 13:11:01.600694+00 \N \N 628 \N poll +303 862798050525423 2026-04-23 11:22:59+00 2026-04-23 11:25:09+00 \N \N 0.32 8.84 \N 2026-04-23 12:10:38.317354+00 \N \N 129 \N poll +308 865135061035778 2026-04-23 11:00:32+00 2026-04-23 11:24:57+00 \N \N 11.34 27.87 \N 2026-04-23 12:10:38.317354+00 \N \N 1464 \N poll +313 865135061569131 2026-04-23 10:43:15+00 2026-04-23 11:11:14+00 \N \N 17.49 37.51 \N 2026-04-23 12:10:38.317354+00 \N \N 1679 \N poll +323 359857082897737 2026-04-23 11:23:00+00 2026-04-23 11:25:31+00 \N \N 0.37 8.81 \N 2026-04-23 12:10:38.317354+00 \N \N 150 \N poll +237 865135061054555 2026-04-23 11:22:38+00 2026-04-23 11:23:48+00 \N \N 0.38 19.54 \N 2026-04-23 12:10:38.317354+00 \N \N 69 \N poll +238 359857082908500 2026-04-23 11:21:53+00 2026-04-23 11:22:28+00 \N \N 0.03 2.68 \N 2026-04-23 12:10:38.317354+00 \N \N 34 \N poll +239 359857082897737 2026-04-23 11:18:13+00 2026-04-23 11:21:17+00 \N \N 0.09 1.83 \N 2026-04-23 12:10:38.317354+00 \N \N 184 \N poll +911 865135061564470 2026-04-23 12:48:19+00 2026-04-23 13:36:52+00 \N \N 23.21 28.68 \N 2026-04-23 13:56:19.217141+00 \N \N 2913 \N poll +919 359857082912239 2026-04-23 13:36:33+00 2026-04-23 13:40:43+00 \N \N 1.39 20.01 \N 2026-04-23 13:56:19.217141+00 \N \N 249 \N poll +240 359857082918186 2026-04-23 11:08:34+00 2026-04-23 11:14:29+00 \N \N 1.89 19.19 \N 2026-04-23 12:10:38.317354+00 \N \N 354 \N poll +418 359857082897794 2026-04-23 11:17:02+00 2026-04-23 11:44:47+00 \N \N 5.01 10.84 \N 2026-04-23 12:40:50.034583+00 \N \N 1665 \N poll +920 359857082897091 2026-04-23 13:35:03+00 2026-04-23 13:37:00+00 \N \N 0.08 2.57 \N 2026-04-23 13:56:19.217141+00 \N \N 116 \N poll +921 865135061054548 2026-04-23 13:32:42+00 2026-04-23 13:33:23+00 \N \N 0.06 5.36 \N 2026-04-23 13:56:19.217141+00 \N \N 40 \N poll +922 359857082897091 2026-04-23 13:30:35+00 2026-04-23 13:31:39+00 \N \N 0.09 5.21 \N 2026-04-23 13:56:19.217141+00 \N \N 63 \N poll +923 359857082910589 2026-04-23 13:29:25+00 2026-04-23 13:37:38+00 \N \N 2.75 20.08 \N 2026-04-23 13:56:19.217141+00 \N \N 493 \N poll +926 359857082896911 2026-04-23 13:19:05+00 2026-04-23 13:28:21+00 \N \N 2.94 19.07 \N 2026-04-23 13:56:19.217141+00 \N \N 556 \N poll +927 865135061035653 2026-04-23 13:18:09+00 2026-04-23 13:27:05+00 \N \N 1.12 7.54 \N 2026-04-23 13:56:19.217141+00 \N \N 536 \N poll +157 865135061054555 2026-04-23 11:07:24+00 2026-04-23 11:09:08+00 \N \N 1.04 36.22 \N 2026-04-23 11:55:33.001929+00 \N \N 103 \N poll +158 359857082897091 2026-04-23 11:06:14+00 2026-04-23 11:06:58+00 \N \N 0.01 0.94 \N 2026-04-23 11:55:33.001929+00 \N \N 44 \N poll +159 359857082918012 2026-04-23 11:05:48+00 2026-04-23 11:07:17+00 \N \N 0.15 6.08 \N 2026-04-23 11:55:33.001929+00 \N \N 88 \N poll +160 359857082918012 2026-04-23 11:02:25+00 2026-04-23 11:02:59+00 \N \N 0.05 4.86 \N 2026-04-23 11:55:33.001929+00 \N \N 33 \N poll +9 359857082042052 2026-04-23 10:19:51+00 2026-04-23 10:21:41+00 \N \N 0.03 0.97 \N 2026-04-23 11:09:36.391704+00 \N \N 110 \N poll +10 359857082897091 2026-04-23 10:19:07+00 2026-04-23 10:20:39+00 \N \N 0.04 1.44 \N 2026-04-23 11:09:36.391704+00 \N \N 92 \N poll +115 359857082046145 2026-04-23 10:16:50+00 2026-04-23 10:19:03+00 \N \N 0.13 3.42 \N 2026-04-23 11:09:36.391704+00 \N \N 133 \N poll +45 359857082896911 2026-04-23 10:16:19+00 2026-04-23 10:21:52+00 \N \N 1.85 20.03 \N 2026-04-23 11:09:36.391704+00 \N \N 332 \N poll +161 865135061054548 2026-04-23 10:58:28+00 2026-04-23 11:00:22+00 \N \N 0.35 10.92 \N 2026-04-23 11:55:33.001929+00 \N \N 114 \N poll +162 359857082897091 2026-04-23 10:58:08+00 2026-04-23 11:06:03+00 \N \N 1.78 13.52 \N 2026-04-23 11:55:33.001929+00 \N \N 475 \N poll +163 359857082896911 2026-04-23 10:56:55+00 2026-04-23 11:04:54+00 \N \N 2.17 16.27 \N 2026-04-23 11:55:33.001929+00 \N \N 479 \N poll +11 359857082897091 2026-04-23 10:10:57+00 2026-04-23 10:18:57+00 \N \N 1.33 9.96 \N 2026-04-23 11:09:36.391704+00 \N \N 479 \N poll +12 359857082912239 2026-04-23 10:10:49+00 2026-04-23 10:15:32+00 \N \N 1.38 17.60 \N 2026-04-23 11:09:36.391704+00 \N \N 282 \N poll +51 359857082896911 2026-04-23 10:10:13+00 2026-04-23 10:13:14+00 \N \N 0.03 0.69 \N 2026-04-23 11:09:36.391704+00 \N \N 180 \N poll +52 865135061035653 2026-04-23 10:07:39+00 2026-04-23 10:20:58+00 \N \N 1.67 7.52 \N 2026-04-23 11:09:36.391704+00 \N \N 798 \N poll +164 359857082897794 2026-04-23 10:55:06+00 2026-04-23 10:58:13+00 \N \N 0.55 10.65 \N 2026-04-23 11:55:33.001929+00 \N \N 186 \N poll +165 359857081891632 2026-04-23 10:54:58+00 2026-04-23 10:56:44+00 \N \N 0.07 2.43 \N 2026-04-23 11:55:33.001929+00 \N \N 105 \N poll +57 359857082918012 2026-04-23 10:00:56+00 2026-04-23 10:18:13+00 \N \N 2.20 7.63 \N 2026-04-23 11:09:36.391704+00 \N \N 1036 \N poll +58 862798052707946 2026-04-23 10:00:34+00 2026-04-23 10:09:43+00 \N \N 2.25 14.79 \N 2026-04-23 11:09:36.391704+00 \N \N 548 \N poll +59 359857082910589 2026-04-23 10:00:33+00 2026-04-23 10:16:59+00 \N \N 1.45 5.29 \N 2026-04-23 11:09:36.391704+00 \N \N 986 \N poll +166 862798050526231 2026-04-23 10:53:15+00 2026-04-23 11:00:21+00 \N \N 1.73 14.66 \N 2026-04-23 11:55:33.001929+00 \N \N 426 \N poll +66 359857082918186 2026-04-23 09:46:55+00 2026-04-23 10:20:09+00 \N \N 18.66 33.71 \N 2026-04-23 11:09:36.391704+00 \N \N 1993 \N poll +168 862798050288360 2026-04-23 10:52:15+00 2026-04-23 10:55:56+00 \N \N 0.84 13.70 \N 2026-04-23 11:55:33.001929+00 \N \N 220 \N poll +171 359857082911983 2026-04-23 10:46:03+00 2026-04-23 10:56:03+00 \N \N 1.90 11.38 \N 2026-04-23 11:55:33.001929+00 \N \N 600 \N poll +176 865135061559538 2026-04-23 10:42:04+00 2026-04-23 11:09:03+00 \N \N 17.83 39.68 \N 2026-04-23 11:55:33.001929+00 \N \N 1618 \N poll +771 359857082900358 2026-04-23 12:56:04+00 2026-04-23 12:59:57+00 \N \N 0.15 2.33 \N 2026-04-23 13:56:19.217141+00 \N \N 233 \N poll +241 359857082897737 2026-04-23 11:08:32+00 2026-04-23 11:14:22+00 \N \N 0.96 9.85 \N 2026-04-23 12:10:38.317354+00 \N \N 350 \N poll +245 359857082910589 2026-04-23 11:05:33+00 2026-04-23 11:11:04+00 \N \N 1.79 19.54 \N 2026-04-23 12:10:38.317354+00 \N \N 330 \N poll +335 862798050526231 2026-04-23 11:04:44+00 2026-04-23 11:15:14+00 \N \N 3.33 19.03 \N 2026-04-23 12:10:38.317354+00 \N \N 630 \N poll +246 359857082908500 2026-04-23 11:03:35+00 2026-04-23 11:17:26+00 \N \N 7.98 34.56 \N 2026-04-23 12:10:38.317354+00 \N \N 831 \N poll +247 862798050288345 2026-04-23 11:03:31+00 2026-04-23 11:17:18+00 \N \N 8.00 34.88 \N 2026-04-23 12:10:38.317354+00 \N \N 826 \N poll +539 865135061564470 2026-04-23 12:10:28+00 2026-04-23 12:22:21+00 \N \N 4.10 20.71 \N 2026-04-23 13:11:01.600694+00 \N \N 713 \N poll +432 862798050521521 2026-04-23 11:00:25+00 2026-04-23 11:25:00+00 \N \N 11.44 27.94 \N 2026-04-23 12:10:38.317354+00 \N \N 1474 \N poll +558 865135061563282 2026-04-23 11:32:19+00 2026-04-23 12:16:00+00 \N \N 1.23 1.69 \N 2026-04-23 13:11:01.600694+00 \N \N 2620 \N poll +249 359857082897794 2026-04-23 11:00:00+00 2026-04-23 11:11:16+00 \N \N 3.23 17.19 \N 2026-04-23 12:10:38.317354+00 \N \N 676 \N poll +563 865135061563639 2026-04-23 11:00:54+00 2026-04-23 12:15:47+00 \N \N 11.33 9.08 \N 2026-04-23 13:11:01.600694+00 \N \N 4492 \N poll +564 359857082898487 2026-04-23 12:14:34+00 2026-04-23 12:17:08+00 \N \N 0.15 3.51 \N 2026-04-23 13:11:01.600694+00 \N \N 153 \N poll +541 865135061569479 2026-04-23 12:02:09+00 2026-04-23 12:08:11+00 \N \N 3.16 31.39 \N 2026-04-23 12:55:57.18912+00 \N \N 362 \N poll +167 359857082897091 2026-04-23 10:52:26+00 2026-04-23 10:54:50+00 \N \N 0.15 3.68 \N 2026-04-23 11:39:46.779828+00 \N \N 143 \N poll +545 862798050525423 2026-04-23 11:55:18+00 2026-04-23 12:08:06+00 \N \N 4.01 18.82 \N 2026-04-23 12:55:57.18912+00 \N \N 767 \N poll +92 359857082908500 2026-04-23 10:47:34+00 2026-04-23 10:49:53+00 \N \N 0.07 1.68 \N 2026-04-23 11:39:46.779828+00 \N \N 139 \N poll +170 359857082046145 2026-04-23 10:46:08+00 2026-04-23 10:55:26+00 \N \N 0.51 3.30 \N 2026-04-23 11:39:46.779828+00 \N \N 557 \N poll +554 865135061035778 2026-04-23 11:40:13+00 2026-04-23 12:10:44+00 \N \N 14.25 28.01 \N 2026-04-23 12:55:57.18912+00 \N \N 1831 \N poll +93 862798050288360 2026-04-23 10:46:00+00 2026-04-23 10:49:10+00 \N \N 1.05 19.86 \N 2026-04-23 11:39:46.779828+00 \N \N 190 \N poll +173 862798052707946 2026-04-23 10:45:29+00 2026-04-23 10:54:11+00 \N \N 3.09 21.35 \N 2026-04-23 11:39:46.779828+00 \N \N 521 \N poll +94 865135061054548 2026-04-23 10:44:23+00 2026-04-23 10:46:57+00 \N \N 0.57 13.39 \N 2026-04-23 11:39:46.779828+00 \N \N 154 \N poll +95 359857082918012 2026-04-23 10:44:19+00 2026-04-23 10:46:11+00 \N \N 0.22 6.91 \N 2026-04-23 11:39:46.779828+00 \N \N 112 \N poll +339 862798052707946 2026-04-23 11:00:43+00 2026-04-23 11:33:06+00 \N \N 17.80 33.00 \N 2026-04-23 12:25:45.284558+00 \N \N 1942 \N poll +96 359857082910589 2026-04-23 10:40:41+00 2026-04-23 10:43:58+00 \N \N 1.43 26.10 \N 2026-04-23 11:39:46.779828+00 \N \N 197 \N poll +340 359857082911983 2026-04-23 11:00:04+00 2026-04-23 11:32:23+00 \N \N 12.41 23.03 \N 2026-04-23 12:25:45.284558+00 \N \N 1939 \N poll +772 865135061053748 2026-04-23 12:53:06+00 2026-04-23 13:05:24+00 \N \N 3.15 15.38 \N 2026-04-23 13:56:19.217141+00 \N \N 738 \N poll +448 862798050523295 2026-04-23 11:31:15+00 2026-04-23 11:38:14+00 \N \N 1.51 13.04 \N 2026-04-23 12:25:45.284558+00 \N \N 418 \N poll +565 865135061054555 2026-04-23 12:12:28+00 2026-04-23 12:14:13+00 \N \N 0.52 17.81 \N 2026-04-23 13:11:01.600694+00 \N \N 105 \N poll +566 359857082896911 2026-04-23 12:11:09+00 2026-04-23 12:21:18+00 \N \N 3.68 21.81 \N 2026-04-23 13:11:01.600694+00 \N \N 608 \N poll +567 359857082911983 2026-04-23 12:10:37+00 2026-04-23 12:23:26+00 \N \N 2.93 13.70 \N 2026-04-23 13:11:01.600694+00 \N \N 769 \N poll +568 359857082907973 2026-04-23 12:09:06+00 2026-04-23 12:18:40+00 \N \N 4.60 28.90 \N 2026-04-23 13:11:01.600694+00 \N \N 573 \N poll +773 862798052708068 2026-04-23 12:51:22+00 2026-04-23 13:06:21+00 \N \N 1.37 5.47 \N 2026-04-23 13:56:19.217141+00 \N \N 898 \N poll +693 359857082900358 2026-04-23 12:45:44+00 2026-04-23 12:49:56+00 \N \N 1.46 20.92 \N 2026-04-23 13:41:12.699355+00 \N \N 251 \N poll +97 359857082897737 2026-04-23 10:39:55+00 2026-04-23 10:44:01+00 \N \N 0.84 12.30 \N 2026-04-23 11:39:46.779828+00 \N \N 245 \N poll +179 865135061562847 2026-04-23 10:38:50+00 2026-04-23 10:50:52+00 \N \N 1.07 5.32 \N 2026-04-23 11:39:46.779828+00 \N \N 721 \N poll +98 359857082911983 2026-04-23 10:38:02+00 2026-04-23 10:40:32+00 \N \N 1.14 27.37 \N 2026-04-23 11:39:46.779828+00 \N \N 150 \N poll +99 862798050288360 2026-04-23 10:37:51+00 2026-04-23 10:39:52+00 \N \N 1.12 33.56 \N 2026-04-23 11:39:46.779828+00 \N \N 120 \N poll +457 865135061043426 2026-04-23 12:06:43+00 2026-04-23 12:07:13+00 \N \N 0.26 31.19 \N 2026-04-23 12:55:57.18912+00 \N \N 30 \N poll +101 862798050526231 2026-04-23 10:34:50+00 2026-04-23 10:50:03+00 \N \N 3.62 14.27 \N 2026-04-23 11:39:46.779828+00 \N \N 913 \N poll +105 865135061054555 2026-04-23 10:26:45+00 2026-04-23 10:42:18+00 \N \N 6.16 23.75 \N 2026-04-23 11:39:46.779828+00 \N \N 933 \N poll +136 862798050521521 2026-04-23 09:48:50+00 2026-04-23 10:44:20+00 \N \N 38.12 41.22 \N 2026-04-23 11:39:46.779828+00 \N \N 3330 \N poll +140 862798050288345 2026-04-23 09:25:07+00 2026-04-23 10:44:47+00 \N \N 71.87 54.12 \N 2026-04-23 11:39:46.779828+00 \N \N 4780 \N poll +141 359857082908500 2026-04-23 09:15:07+00 2026-04-23 10:47:23+00 \N \N 74.30 48.33 \N 2026-04-23 11:39:46.779828+00 \N \N 5535 \N poll +458 862798052708068 2026-04-23 12:00:46+00 2026-04-23 12:05:14+00 \N \N 0.35 4.67 \N 2026-04-23 12:55:57.18912+00 \N \N 267 \N poll +253 862798050523337 2026-04-23 10:55:26+00 2026-04-23 11:04:39+00 \N \N 2.74 17.85 \N 2026-04-23 11:55:33.001929+00 \N \N 553 \N poll +180 359857082918186 2026-04-23 10:38:23+00 2026-04-23 10:59:54+00 \N \N 18.02 50.28 \N 2026-04-23 11:55:33.001929+00 \N \N 1290 \N poll +459 865135061564470 2026-04-23 12:00:06+00 2026-04-23 12:06:54+00 \N \N 1.88 16.64 \N 2026-04-23 12:55:57.18912+00 \N \N 407 \N poll +460 865135061581904 2026-04-23 11:56:10+00 2026-04-23 12:04:28+00 \N \N 3.20 23.19 \N 2026-04-23 12:55:57.18912+00 \N \N 497 \N poll +461 865135061043426 2026-04-23 11:52:40+00 2026-04-23 11:59:03+00 \N \N 4.05 38.03 \N 2026-04-23 12:55:57.18912+00 \N \N 383 \N poll +463 865135061569123 2026-04-23 11:50:31+00 2026-04-23 12:04:55+00 \N \N 4.31 17.97 \N 2026-04-23 12:55:57.18912+00 \N \N 863 \N poll +464 862798052708068 2026-04-23 11:44:38+00 2026-04-23 11:58:30+00 \N \N 1.16 5.04 \N 2026-04-23 12:55:57.18912+00 \N \N 831 \N poll +296 359857082898016 2026-04-23 11:01:56+00 2026-04-23 11:05:56+00 \N \N 0.90 13.49 \N 2026-04-23 11:55:33.001929+00 \N \N 239 \N poll +217 865135061048276 2026-04-23 10:55:28+00 2026-04-23 11:04:51+00 \N \N 2.68 17.19 \N 2026-04-23 11:55:33.001929+00 \N \N 562 \N poll +466 865135061053748 2026-04-23 11:41:05+00 2026-04-23 12:06:02+00 \N \N 4.00 9.62 \N 2026-04-23 12:55:57.18912+00 \N \N 1496 \N poll +483 359857082897091 2026-04-23 12:05:36+00 2026-04-23 12:06:44+00 \N \N 0.05 2.87 \N 2026-04-23 12:55:57.18912+00 \N \N 67 \N poll +220 865135061564470 2026-04-23 11:07:16+00 2026-04-23 11:18:12+00 \N \N 2.27 12.45 \N 2026-04-23 12:10:38.317354+00 \N \N 656 \N poll +221 865135061053748 2026-04-23 11:04:47+00 2026-04-23 11:16:20+00 \N \N 3.30 17.15 \N 2026-04-23 12:10:38.317354+00 \N \N 693 \N poll +484 359857082910589 2026-04-23 12:00:10+00 2026-04-23 12:02:24+00 \N \N 0.07 1.83 \N 2026-04-23 12:55:57.18912+00 \N \N 134 \N poll +485 865135061563597 2026-04-23 12:00:02+00 2026-04-23 12:05:12+00 \N \N 0.32 3.69 \N 2026-04-23 12:55:57.18912+00 \N \N 309 \N poll +486 359857082897091 2026-04-23 11:59:54+00 2026-04-23 12:05:26+00 \N \N 0.44 4.74 \N 2026-04-23 12:55:57.18912+00 \N \N 332 \N poll +790 862798050523014 2026-04-23 13:02:13+00 2026-04-23 13:04:48+00 \N \N 0.40 9.36 \N 2026-04-23 13:56:19.217141+00 \N \N 155 \N poll +791 359857082912239 2026-04-23 13:01:45+00 2026-04-23 13:03:21+00 \N \N 0.42 15.78 \N 2026-04-23 13:56:19.217141+00 \N \N 95 \N poll +792 359857082897737 2026-04-23 13:00:28+00 2026-04-23 13:03:57+00 \N \N 0.25 4.35 \N 2026-04-23 13:56:19.217141+00 \N \N 209 \N poll +793 359857082042052 2026-04-23 12:59:20+00 2026-04-23 13:01:47+00 \N \N 0.14 3.46 \N 2026-04-23 13:56:19.217141+00 \N \N 146 \N poll +794 865135061563597 2026-04-23 12:58:43+00 2026-04-23 13:06:20+00 \N \N 0.65 5.15 \N 2026-04-23 13:56:19.217141+00 \N \N 457 \N poll +295 359857082902461 2026-04-23 11:21:40+00 2026-04-23 11:24:23+00 \N \N 0.49 10.85 \N 2026-04-23 12:10:38.317354+00 \N \N 163 \N poll +372 865135061048953 2026-04-23 11:16:14+00 2026-04-23 11:24:18+00 \N \N 3.45 25.72 \N 2026-04-23 12:10:38.317354+00 \N \N 483 \N poll +373 359857082898016 2026-04-23 11:14:26+00 2026-04-23 11:15:26+00 \N \N 0.10 5.67 \N 2026-04-23 12:10:38.317354+00 \N \N 60 \N poll +298 865135061043079 2026-04-23 10:21:17+00 2026-04-23 11:16:34+00 \N \N 18.49 20.07 \N 2026-04-23 12:10:38.317354+00 \N \N 3317 \N poll +299 359857082902461 2026-04-23 09:13:44+00 2026-04-23 11:16:03+00 \N \N 43.17 21.18 \N 2026-04-23 12:10:38.317354+00 \N \N 7338 \N poll +393 865135061043426 2026-04-23 11:05:37+00 2026-04-23 11:39:52+00 \N \N 32.54 57.01 \N 2026-04-23 12:25:45.284558+00 \N \N 2055 \N poll +694 865135061043426 2026-04-23 12:42:40+00 2026-04-23 12:46:04+00 \N \N 2.48 44.05 \N 2026-04-23 13:41:12.699355+00 \N \N 203 \N poll +696 865135061563282 2026-04-23 12:36:03+00 2026-04-23 12:50:25+00 \N \N 0.10 0.43 \N 2026-04-23 13:41:12.699355+00 \N \N 861 \N poll +697 865135061569123 2026-04-23 12:34:51+00 2026-04-23 12:47:07+00 \N \N 2.04 10.00 \N 2026-04-23 13:41:12.699355+00 \N \N 735 \N poll +698 865135061047435 2026-04-23 12:28:04+00 2026-04-23 12:41:11+00 \N \N 2.47 11.29 \N 2026-04-23 13:41:12.699355+00 \N \N 787 \N poll +714 865135061037980 2026-04-23 11:49:36+00 2026-04-23 12:46:20+00 \N \N 26.87 28.43 \N 2026-04-23 13:41:12.699355+00 \N \N 3403 \N poll +720 865135061054555 2026-04-23 12:52:49+00 2026-04-23 12:54:50+00 \N \N 0.60 17.92 \N 2026-04-23 13:41:12.699355+00 \N \N 120 \N poll +796 862798050523527 2026-04-23 12:51:07+00 2026-04-23 12:54:07+00 \N \N 0.17 3.42 \N 2026-04-23 13:41:12.699355+00 \N \N 180 \N poll +406 865135061054555 2026-04-23 11:32:58+00 2026-04-23 11:36:48+00 \N \N 1.55 24.18 \N 2026-04-23 12:25:45.284558+00 \N \N 230 \N poll +409 862798050526231 2026-04-23 11:30:02+00 2026-04-23 11:32:06+00 \N \N 0.24 7.05 \N 2026-04-23 12:25:45.284558+00 \N \N 124 \N poll +524 862798050288360 2026-04-23 11:00:02+00 2026-04-23 11:31:19+00 \N \N 12.45 23.90 \N 2026-04-23 12:25:45.284558+00 \N \N 1876 \N poll +365 359857082907973 2026-04-23 10:35:18+00 2026-04-23 11:29:00+00 \N \N 47.92 53.54 \N 2026-04-23 12:25:45.284558+00 \N \N 3222 \N poll +837 862798052708068 2026-04-23 13:16:07+00 2026-04-23 13:18:24+00 \N \N 0.28 7.38 \N 2026-04-23 13:56:19.217141+00 \N \N 137 \N poll +838 865135061569123 2026-04-23 12:57:43+00 2026-04-23 13:25:37+00 \N \N 4.26 9.17 \N 2026-04-23 13:56:19.217141+00 \N \N 1674 \N poll +842 865135061037980 2026-04-23 12:49:39+00 2026-04-23 13:16:02+00 \N \N 8.32 18.94 \N 2026-04-23 13:56:19.217141+00 \N \N 1582 \N poll +848 862798050525423 2026-04-23 12:31:09+00 2026-04-23 13:02:34+00 \N \N 6.94 13.26 \N 2026-04-23 13:56:19.217141+00 \N \N 1884 \N poll +617 359857082900358 2026-04-23 12:36:56+00 2026-04-23 12:39:51+00 \N \N 1.26 26.08 \N 2026-04-23 13:26:08.016798+00 \N \N 174 \N poll +618 862798052708068 2026-04-23 12:27:16+00 2026-04-23 12:30:32+00 \N \N 0.29 5.30 \N 2026-04-23 13:26:08.016798+00 \N \N 195 \N poll +619 865135061581904 2026-04-23 12:27:01+00 2026-04-23 12:30:16+00 \N \N 0.49 8.98 \N 2026-04-23 13:26:08.016798+00 \N \N 195 \N poll +620 865135061053748 2026-04-23 12:25:32+00 2026-04-23 12:40:46+00 \N \N 3.72 14.66 \N 2026-04-23 13:26:08.016798+00 \N \N 913 \N poll +374 865135061048276 2026-04-23 11:13:55+00 2026-04-23 11:38:33+00 \N \N 9.43 22.99 \N 2026-04-23 12:25:45.284558+00 \N \N 1477 \N poll +856 865135061054555 2026-04-23 13:23:35+00 2026-04-23 13:25:18+00 \N \N 0.60 21.06 \N 2026-04-23 13:56:19.217141+00 \N \N 103 \N poll +857 865135061054555 2026-04-23 13:19:31+00 2026-04-23 13:21:05+00 \N \N 0.90 34.84 \N 2026-04-23 13:56:19.217141+00 \N \N 93 \N poll +858 865135061563597 2026-04-23 13:17:19+00 2026-04-23 13:18:23+00 \N \N 0.08 4.65 \N 2026-04-23 13:56:19.217141+00 \N \N 64 \N poll +859 359857082910589 2026-04-23 13:15:43+00 2026-04-23 13:24:42+00 \N \N 7.03 46.94 \N 2026-04-23 13:56:19.217141+00 \N \N 539 \N poll +860 359857082912239 2026-04-23 13:15:10+00 2026-04-23 13:18:54+00 \N \N 0.47 7.51 \N 2026-04-23 13:56:19.217141+00 \N \N 224 \N poll +865 359857082907973 2026-04-23 12:59:14+00 2026-04-23 13:24:17+00 \N \N 8.66 20.74 \N 2026-04-23 13:56:19.217141+00 \N \N 1503 \N poll +400 359857082898487 2026-04-23 11:46:12+00 2026-04-23 11:47:18+00 \N \N 0.11 5.89 \N 2026-04-23 12:40:50.034583+00 \N \N 65 \N poll +494 862798050523337 2026-04-23 11:44:21+00 2026-04-23 11:45:25+00 \N \N 0.26 14.44 \N 2026-04-23 12:40:50.034583+00 \N \N 64 \N poll +401 359857082918012 2026-04-23 11:43:28+00 2026-04-23 11:49:00+00 \N \N 0.98 10.69 \N 2026-04-23 12:40:50.034583+00 \N \N 331 \N poll +402 865135061054555 2026-04-23 11:41:38+00 2026-04-23 11:43:07+00 \N \N 0.14 5.55 \N 2026-04-23 12:40:50.034583+00 \N \N 89 \N poll +625 865135061047435 2026-04-23 12:05:17+00 2026-04-23 12:24:24+00 \N \N 8.22 25.83 \N 2026-04-23 13:11:01.600694+00 \N \N 1146 \N poll +403 359857082896911 2026-04-23 11:39:37+00 2026-04-23 11:55:30+00 \N \N 4.45 16.83 \N 2026-04-23 12:40:50.034583+00 \N \N 953 \N poll +404 359857082897737 2026-04-23 11:36:58+00 2026-04-23 11:43:44+00 \N \N 1.58 14.05 \N 2026-04-23 12:40:50.034583+00 \N \N 405 \N poll +405 359857081891632 2026-04-23 11:36:49+00 2026-04-23 11:40:57+00 \N \N 0.39 5.58 \N 2026-04-23 12:40:50.034583+00 \N \N 248 \N poll +407 359857082907973 2026-04-23 11:30:39+00 2026-04-23 11:50:15+00 \N \N 9.87 30.22 \N 2026-04-23 12:40:50.034583+00 \N \N 1175 \N poll +408 865135061035653 2026-04-23 11:30:27+00 2026-04-23 11:49:03+00 \N \N 5.12 16.52 \N 2026-04-23 12:40:50.034583+00 \N \N 1115 \N poll +867 359857081891632 2026-04-23 12:58:10+00 2026-04-23 13:14:35+00 \N \N 1.99 7.26 \N 2026-04-23 13:56:19.217141+00 \N \N 985 \N poll +868 862798050523337 2026-04-23 12:54:30+00 2026-04-23 13:00:40+00 \N \N 1.67 16.29 \N 2026-04-23 13:56:19.217141+00 \N \N 369 \N poll +869 862798050526231 2026-04-23 12:53:07+00 2026-04-23 13:03:47+00 \N \N 3.14 17.66 \N 2026-04-23 13:56:19.217141+00 \N \N 640 \N poll +621 865135061563282 2026-04-23 12:18:59+00 2026-04-23 12:27:42+00 \N \N 0.03 0.21 \N 2026-04-23 13:26:08.016798+00 \N \N 522 \N poll +622 865135061043426 2026-04-23 12:11:03+00 2026-04-23 12:34:10+00 \N \N 15.85 41.17 \N 2026-04-23 13:26:08.016798+00 \N \N 1386 \N poll +571 359857082046145 2026-04-23 12:01:25+00 2026-04-23 12:10:37+00 \N \N 2.27 14.81 \N 2026-04-23 12:55:57.18912+00 \N \N 551 \N poll +487 359857082046145 2026-04-23 11:58:01+00 2026-04-23 11:59:38+00 \N \N 0.05 1.99 \N 2026-04-23 12:55:57.18912+00 \N \N 97 \N poll +488 865135061562722 2026-04-23 11:55:03+00 2026-04-23 11:58:33+00 \N \N 0.34 5.85 \N 2026-04-23 12:55:57.18912+00 \N \N 210 \N poll +489 865135061054548 2026-04-23 11:53:46+00 2026-04-23 11:59:40+00 \N \N 1.28 13.00 \N 2026-04-23 12:55:57.18912+00 \N \N 354 \N poll +490 865135061054555 2026-04-23 11:51:07+00 2026-04-23 12:00:30+00 \N \N 3.71 23.70 \N 2026-04-23 12:55:57.18912+00 \N \N 563 \N poll +579 359857082897737 2026-04-23 11:51:02+00 2026-04-23 12:10:58+00 \N \N 4.85 14.61 \N 2026-04-23 12:55:57.18912+00 \N \N 1195 \N poll +491 865135061562847 2026-04-23 11:51:00+00 2026-04-23 11:57:55+00 \N \N 1.27 11.00 \N 2026-04-23 12:55:57.18912+00 \N \N 415 \N poll +492 865135061563597 2026-04-23 11:49:34+00 2026-04-23 11:58:27+00 \N \N 0.66 4.47 \N 2026-04-23 12:55:57.18912+00 \N \N 533 \N poll +586 862798050526231 2026-04-23 11:41:01+00 2026-04-23 12:03:21+00 \N \N 4.01 10.78 \N 2026-04-23 12:55:57.18912+00 \N \N 1339 \N poll +649 865135061035653 2026-04-23 12:11:30+00 2026-04-23 12:12:28+00 \N \N 0.12 7.51 \N 2026-04-23 13:11:01.600694+00 \N \N 57 \N poll +569 359857082910589 2026-04-23 12:07:07+00 2026-04-23 12:19:03+00 \N \N 5.89 29.63 \N 2026-04-23 13:11:01.600694+00 \N \N 716 \N poll +871 359857082910589 2026-04-23 12:52:11+00 2026-04-23 13:08:40+00 \N \N 6.48 23.60 \N 2026-04-23 13:56:19.217141+00 \N \N 989 \N poll +605 359857082902461 2026-04-23 12:14:29+00 2026-04-23 12:22:22+00 \N \N 1.59 12.15 \N 2026-04-23 13:11:01.600694+00 \N \N 472 \N poll +721 865135061054548 2026-04-23 12:50:25+00 2026-04-23 12:54:44+00 \N \N 0.27 3.73 \N 2026-04-23 13:41:12.699355+00 \N \N 259 \N poll +447 865135061048276 2026-04-23 11:43:54+00 2026-04-23 11:45:22+00 \N \N 0.34 13.93 \N 2026-04-23 12:40:50.034583+00 \N \N 88 \N poll +527 865135061048276 2026-04-23 11:56:43+00 2026-04-23 12:02:32+00 \N \N 1.38 14.25 \N 2026-04-23 12:55:57.18912+00 \N \N 348 \N poll +529 359857082902461 2026-04-23 11:43:03+00 2026-04-23 11:56:24+00 \N \N 1.10 4.95 \N 2026-04-23 12:55:57.18912+00 \N \N 800 \N poll +530 865135061048466 2026-04-23 11:42:51+00 2026-04-23 11:59:32+00 \N \N 4.75 17.07 \N 2026-04-23 12:55:57.18912+00 \N \N 1001 \N poll +532 865135061048953 2026-04-23 11:27:38+00 2026-04-23 12:00:21+00 \N \N 8.53 15.64 \N 2026-04-23 12:55:57.18912+00 \N \N 1963 \N poll +758 359857082918038 2026-04-23 12:33:43+00 2026-04-23 12:42:14+00 \N \N 3.80 26.76 \N 2026-04-23 13:41:12.699355+00 \N \N 511 \N poll +615 865135061043079 2026-04-23 11:20:26+00 2026-04-23 12:21:34+00 \N \N 43.28 42.49 \N 2026-04-23 13:11:01.600694+00 \N \N 3667 \N poll +643 359857082918186 2026-04-23 12:31:44+00 2026-04-23 12:36:04+00 \N \N 0.57 7.92 \N 2026-04-23 13:26:08.016798+00 \N \N 259 \N poll +644 359857082898487 2026-04-23 12:31:37+00 2026-04-23 12:33:39+00 \N \N 0.24 7.11 \N 2026-04-23 13:26:08.016798+00 \N \N 122 \N poll +645 359857082898487 2026-04-23 12:27:57+00 2026-04-23 12:28:58+00 \N \N 0.10 5.60 \N 2026-04-23 13:26:08.016798+00 \N \N 61 \N poll +646 865135061563597 2026-04-23 12:27:39+00 2026-04-23 12:30:29+00 \N \N 0.25 5.32 \N 2026-04-23 13:26:08.016798+00 \N \N 169 \N poll +731 862798050526231 2026-04-23 12:16:46+00 2026-04-23 12:39:32+00 \N \N 4.24 11.18 \N 2026-04-23 13:26:08.016798+00 \N \N 1366 \N poll +658 359857081891632 2026-04-23 12:00:00+00 2026-04-23 12:29:08+00 \N \N 3.02 6.22 \N 2026-04-23 13:26:08.016798+00 \N \N 1747 \N poll +662 359857082918186 2026-04-23 11:54:30+00 2026-04-23 12:26:55+00 \N \N 19.34 35.81 \N 2026-04-23 13:26:08.016798+00 \N \N 1944 \N poll +680 359857082902461 2026-04-23 12:31:27+00 2026-04-23 12:34:27+00 \N \N 1.19 23.88 \N 2026-04-23 13:26:08.016798+00 \N \N 179 \N poll +681 865135061048953 2026-04-23 12:25:51+00 2026-04-23 12:38:16+00 \N \N 2.21 10.70 \N 2026-04-23 13:26:08.016798+00 \N \N 745 \N poll +722 862798050526231 2026-04-23 12:47:29+00 2026-04-23 12:49:00+00 \N \N 0.60 23.82 \N 2026-04-23 13:41:12.699355+00 \N \N 90 \N poll +723 865135061054555 2026-04-23 12:45:51+00 2026-04-23 12:47:09+00 \N \N 0.69 32.35 \N 2026-04-23 13:41:12.699355+00 \N \N 77 \N poll +801 359857082907973 2026-04-23 12:45:25+00 2026-04-23 12:55:52+00 \N \N 3.80 21.79 \N 2026-04-23 13:41:12.699355+00 \N \N 627 \N poll +724 359857082897091 2026-04-23 12:44:05+00 2026-04-23 12:46:35+00 \N \N 0.14 3.42 \N 2026-04-23 13:41:12.699355+00 \N \N 150 \N poll +729 359857082918012 2026-04-23 12:27:07+00 2026-04-23 12:44:49+00 \N \N 5.44 18.46 \N 2026-04-23 13:41:12.699355+00 \N \N 1061 \N poll +730 865135061035653 2026-04-23 12:26:38+00 2026-04-23 12:51:14+00 \N \N 7.16 17.45 \N 2026-04-23 13:41:12.699355+00 \N \N 1476 \N poll +820 359857082897794 2026-04-23 11:48:03+00 2026-04-23 12:54:02+00 \N \N 17.40 15.82 \N 2026-04-23 13:41:12.699355+00 \N \N 3959 \N poll +756 359857082918038 2026-04-23 12:51:36+00 2026-04-23 12:53:04+00 \N \N 0.23 9.54 \N 2026-04-23 13:41:12.699355+00 \N \N 87 \N poll +757 865135061048953 2026-04-23 12:46:31+00 2026-04-23 12:50:02+00 \N \N 0.57 9.81 \N 2026-04-23 13:41:12.699355+00 \N \N 210 \N poll +798 862798050523014 2026-04-23 12:47:36+00 2026-04-23 12:56:49+00 \N \N 1.86 12.13 \N 2026-04-23 13:56:19.217141+00 \N \N 553 \N poll +879 359857082897257 2026-04-23 12:43:09+00 2026-04-23 13:12:23+00 \N \N 6.91 14.19 \N 2026-04-23 13:56:19.217141+00 \N \N 1754 \N poll +809 359857082897737 2026-04-23 12:24:59+00 2026-04-23 12:56:41+00 \N \N 8.64 16.36 \N 2026-04-23 13:56:19.217141+00 \N \N 1902 \N poll +821 359857082042052 2026-04-23 11:31:36+00 2026-04-23 12:56:40+00 \N \N 31.01 21.87 \N 2026-04-23 13:56:19.217141+00 \N \N 5104 \N poll +892 865135061048953 2026-04-23 13:21:36+00 2026-04-23 13:23:59+00 \N \N 0.21 5.32 \N 2026-04-23 13:56:19.217141+00 \N \N 143 \N poll +893 865135061048466 2026-04-23 13:08:32+00 2026-04-23 13:16:16+00 \N \N 0.96 7.45 \N 2026-04-23 13:56:19.217141+00 \N \N 464 \N poll +822 865135061048953 2026-04-23 13:02:38+00 2026-04-23 13:06:49+00 \N \N 0.57 8.16 \N 2026-04-23 13:56:19.217141+00 \N \N 251 \N poll +823 865135061048466 2026-04-23 13:02:22+00 2026-04-23 13:04:52+00 \N \N 0.38 9.16 \N 2026-04-23 13:56:19.217141+00 \N \N 149 \N poll +824 865135061048276 2026-04-23 12:55:53+00 2026-04-23 13:01:59+00 \N \N 1.27 12.56 \N 2026-04-23 13:56:19.217141+00 \N \N 365 \N poll +826 865135061048466 2026-04-23 12:47:43+00 2026-04-23 12:58:16+00 \N \N 1.75 9.97 \N 2026-04-23 13:56:19.217141+00 \N \N 632 \N poll +900 865135061035133 2026-04-23 12:34:48+00 2026-04-23 13:19:21+00 \N \N 34.64 46.65 \N 2026-04-23 13:56:19.217141+00 \N \N 2673 \N poll +901 862798050523626 2026-04-23 12:34:47+00 2026-04-23 13:19:22+00 \N \N 34.65 46.63 \N 2026-04-23 13:56:19.217141+00 \N \N 2675 \N poll +\. + + +-- +-- TOC entry 7031 (class 0 OID 0) +-- Dependencies: 301 +-- Name: alarms_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.alarms_id_seq', 7599, true); + + +-- +-- TOC entry 7032 (class 0 OID 0) +-- Dependencies: 291 +-- Name: api_token_cache_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.api_token_cache_id_seq', 4, true); + + +-- +-- TOC entry 7033 (class 0 OID 0) +-- Dependencies: 318 +-- Name: device_events_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.device_events_id_seq', 1, false); + + +-- +-- TOC entry 7034 (class 0 OID 0) +-- Dependencies: 326 +-- Name: dispatch_log_dispatch_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.dispatch_log_dispatch_id_seq', 1, false); + + +-- +-- TOC entry 7035 (class 0 OID 0) +-- Dependencies: 315 +-- Name: fault_codes_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.fault_codes_id_seq', 1, false); + + +-- +-- TOC entry 7036 (class 0 OID 0) +-- Dependencies: 324 +-- Name: geofences_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.geofences_id_seq', 1, false); + + +-- +-- TOC entry 7037 (class 0 OID 0) +-- Dependencies: 293 +-- Name: ingestion_log_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.ingestion_log_id_seq', 1407, true); + + +-- +-- TOC entry 7038 (class 0 OID 0) +-- Dependencies: 322 +-- Name: lbs_readings_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.lbs_readings_id_seq', 1, false); + + +-- +-- TOC entry 7039 (class 0 OID 0) +-- Dependencies: 303 +-- Name: obd_readings_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.obd_readings_id_seq', 1, false); + + +-- +-- TOC entry 7040 (class 0 OID 0) +-- Dependencies: 299 +-- Name: parking_events_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.parking_events_id_seq', 1, false); + + +-- +-- TOC entry 7041 (class 0 OID 0) +-- Dependencies: 297 +-- Name: trips_id_seq; Type: SEQUENCE SET; Schema: tracksolid; Owner: postgres +-- + +SELECT pg_catalog.setval('tracksolid.trips_id_seq', 1030, true); + + +-- +-- TOC entry 6653 (class 2606 OID 24980) +-- Name: alarms alarms_dedup; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.alarms + ADD CONSTRAINT alarms_dedup UNIQUE (imei, alarm_type, alarm_time); + + +-- +-- TOC entry 6655 (class 2606 OID 24977) +-- Name: alarms alarms_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.alarms + ADD CONSTRAINT alarms_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6634 (class 2606 OID 24871) +-- Name: api_token_cache api_token_cache_account_key; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.api_token_cache + ADD CONSTRAINT api_token_cache_account_key UNIQUE (account); + + +-- +-- TOC entry 6636 (class 2606 OID 24869) +-- Name: api_token_cache api_token_cache_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.api_token_cache + ADD CONSTRAINT api_token_cache_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6670 (class 2606 OID 25169) +-- Name: device_events device_events_imei_event_type_event_time_key; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.device_events + ADD CONSTRAINT device_events_imei_event_type_event_time_key UNIQUE (imei, event_type, event_time); + + +-- +-- TOC entry 6672 (class 2606 OID 25167) +-- Name: device_events device_events_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.device_events + ADD CONSTRAINT device_events_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6631 (class 2606 OID 24856) +-- Name: devices devices_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.devices + ADD CONSTRAINT devices_pkey PRIMARY KEY (imei); + + +-- +-- TOC entry 6690 (class 2606 OID 25249) +-- Name: dispatch_log dispatch_log_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.dispatch_log + ADD CONSTRAINT dispatch_log_pkey PRIMARY KEY (dispatch_id); + + +-- +-- TOC entry 6661 (class 2606 OID 25132) +-- Name: fault_codes fault_codes_dedup; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.fault_codes + ADD CONSTRAINT fault_codes_dedup UNIQUE (imei, reported_at, fault_code); + + +-- +-- TOC entry 6663 (class 2606 OID 25130) +-- Name: fault_codes fault_codes_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.fault_codes + ADD CONSTRAINT fault_codes_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6675 (class 2606 OID 25183) +-- Name: fuel_readings fuel_readings_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.fuel_readings + ADD CONSTRAINT fuel_readings_pkey PRIMARY KEY (imei, reading_time); + + +-- +-- TOC entry 6686 (class 2606 OID 25236) +-- Name: geofences geofences_fence_id_key; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.geofences + ADD CONSTRAINT geofences_fence_id_key UNIQUE (fence_id); + + +-- +-- TOC entry 6688 (class 2606 OID 25234) +-- Name: geofences geofences_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.geofences + ADD CONSTRAINT geofences_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6668 (class 2606 OID 25147) +-- Name: heartbeats heartbeats_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.heartbeats + ADD CONSTRAINT heartbeats_pkey PRIMARY KEY (imei, gate_time); + + +-- +-- TOC entry 6638 (class 2606 OID 24889) +-- Name: ingestion_log ingestion_log_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.ingestion_log + ADD CONSTRAINT ingestion_log_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6682 (class 2606 OID 25217) +-- Name: lbs_readings lbs_readings_imei_gate_time_key; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.lbs_readings + ADD CONSTRAINT lbs_readings_imei_gate_time_key UNIQUE (imei, gate_time); + + +-- +-- TOC entry 6684 (class 2606 OID 25215) +-- Name: lbs_readings lbs_readings_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.lbs_readings + ADD CONSTRAINT lbs_readings_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6640 (class 2606 OID 24898) +-- Name: live_positions live_positions_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.live_positions + ADD CONSTRAINT live_positions_pkey PRIMARY KEY (imei); + + +-- +-- TOC entry 6657 (class 2606 OID 25000) +-- Name: obd_readings obd_readings_dedup; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.obd_readings + ADD CONSTRAINT obd_readings_dedup UNIQUE (imei, reading_time); + + +-- +-- TOC entry 6659 (class 2606 OID 24998) +-- Name: obd_readings obd_readings_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.obd_readings + ADD CONSTRAINT obd_readings_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6649 (class 2606 OID 24962) +-- Name: parking_events parking_dedup; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.parking_events + ADD CONSTRAINT parking_dedup UNIQUE (imei, start_time, event_type); + + +-- +-- TOC entry 6651 (class 2606 OID 24959) +-- Name: parking_events parking_events_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.parking_events + ADD CONSTRAINT parking_events_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6643 (class 2606 OID 24923) +-- Name: position_history position_history_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.position_history + ADD CONSTRAINT position_history_pkey PRIMARY KEY (imei, gps_time); + + +-- +-- TOC entry 6629 (class 2606 OID 23001) +-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.schema_migrations + ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (filename); + + +-- +-- TOC entry 6678 (class 2606 OID 25198) +-- Name: temperature_readings temperature_readings_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.temperature_readings + ADD CONSTRAINT temperature_readings_pkey PRIMARY KEY (imei, reading_time); + + +-- +-- TOC entry 6645 (class 2606 OID 24942) +-- Name: trips trips_imei_start_unique; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.trips + ADD CONSTRAINT trips_imei_start_unique UNIQUE (imei, start_time); + + +-- +-- TOC entry 6647 (class 2606 OID 24940) +-- Name: trips trips_pkey; Type: CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.trips + ADD CONSTRAINT trips_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 6676 (class 1259 OID 25190) +-- Name: fuel_readings_reading_time_idx; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX fuel_readings_reading_time_idx ON tracksolid.fuel_readings USING btree (reading_time DESC); + + +-- +-- TOC entry 6666 (class 1259 OID 25154) +-- Name: heartbeats_gate_time_idx; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX heartbeats_gate_time_idx ON tracksolid.heartbeats USING btree (gate_time DESC); + + +-- +-- TOC entry 6673 (class 1259 OID 25175) +-- Name: idx_device_events_imei_time; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_device_events_imei_time ON tracksolid.device_events USING btree (imei, event_time DESC); + + +-- +-- TOC entry 6632 (class 1259 OID 25238) +-- Name: idx_devices_assigned_city; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_devices_assigned_city ON tracksolid.devices USING btree (assigned_city) WHERE (assigned_city IS NOT NULL); + + +-- +-- TOC entry 6691 (class 1259 OID 25257) +-- Name: idx_dispatch_log_assigned_at; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_dispatch_log_assigned_at ON tracksolid.dispatch_log USING btree (assigned_at DESC); + + +-- +-- TOC entry 6692 (class 1259 OID 25256) +-- Name: idx_dispatch_log_imei_assigned; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_dispatch_log_imei_assigned ON tracksolid.dispatch_log USING btree (imei, assigned_at DESC); + + +-- +-- TOC entry 6693 (class 1259 OID 25258) +-- Name: idx_dispatch_log_job_geom; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_dispatch_log_job_geom ON tracksolid.dispatch_log USING gist (job_geom); + + +-- +-- TOC entry 6694 (class 1259 OID 25255) +-- Name: idx_dispatch_log_ticket; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_dispatch_log_ticket ON tracksolid.dispatch_log USING btree (ticket_id); + + +-- +-- TOC entry 6664 (class 1259 OID 25139) +-- Name: idx_fault_codes_code; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_fault_codes_code ON tracksolid.fault_codes USING btree (fault_code); + + +-- +-- TOC entry 6665 (class 1259 OID 25138) +-- Name: idx_fault_codes_imei_time; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_fault_codes_imei_time ON tracksolid.fault_codes USING btree (imei, reported_at DESC); + + +-- +-- TOC entry 6680 (class 1259 OID 25223) +-- Name: idx_lbs_readings_imei_time; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX idx_lbs_readings_imei_time ON tracksolid.lbs_readings USING btree (imei, gate_time DESC); + + +-- +-- TOC entry 6641 (class 1259 OID 25007) +-- Name: position_history_gps_time_idx; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX position_history_gps_time_idx ON tracksolid.position_history USING btree (gps_time DESC); + + +-- +-- TOC entry 6679 (class 1259 OID 25205) +-- Name: temperature_readings_reading_time_idx; Type: INDEX; Schema: tracksolid; Owner: postgres +-- + +CREATE INDEX temperature_readings_reading_time_idx ON tracksolid.temperature_readings USING btree (reading_time DESC); + + +-- +-- TOC entry 6715 (class 2620 OID 25049) +-- Name: alarms trg_upd_alarms; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER trg_upd_alarms BEFORE UPDATE ON tracksolid.alarms FOR EACH ROW EXECUTE FUNCTION tracksolid.set_updated_at(); + + +-- +-- TOC entry 6709 (class 2620 OID 25044) +-- Name: api_token_cache trg_upd_api_token_cache; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER trg_upd_api_token_cache BEFORE UPDATE ON tracksolid.api_token_cache FOR EACH ROW EXECUTE FUNCTION tracksolid.set_updated_at(); + + +-- +-- TOC entry 6708 (class 2620 OID 25045) +-- Name: devices trg_upd_devices; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER trg_upd_devices BEFORE UPDATE ON tracksolid.devices FOR EACH ROW EXECUTE FUNCTION tracksolid.set_updated_at(); + + +-- +-- TOC entry 6710 (class 2620 OID 25046) +-- Name: live_positions trg_upd_live_positions; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER trg_upd_live_positions BEFORE UPDATE ON tracksolid.live_positions FOR EACH ROW EXECUTE FUNCTION tracksolid.set_updated_at(); + + +-- +-- TOC entry 6716 (class 2620 OID 25050) +-- Name: obd_readings trg_upd_obd_readings; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER trg_upd_obd_readings BEFORE UPDATE ON tracksolid.obd_readings FOR EACH ROW EXECUTE FUNCTION tracksolid.set_updated_at(); + + +-- +-- TOC entry 6714 (class 2620 OID 25048) +-- Name: parking_events trg_upd_parking_events; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER trg_upd_parking_events BEFORE UPDATE ON tracksolid.parking_events FOR EACH ROW EXECUTE FUNCTION tracksolid.set_updated_at(); + + +-- +-- TOC entry 6713 (class 2620 OID 25047) +-- Name: trips trg_upd_trips; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER trg_upd_trips BEFORE UPDATE ON tracksolid.trips FOR EACH ROW EXECUTE FUNCTION tracksolid.set_updated_at(); + + +-- +-- TOC entry 6711 (class 2620 OID 25103) +-- Name: position_history ts_cagg_invalidation_trigger; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER ts_cagg_invalidation_trigger AFTER INSERT OR DELETE OR UPDATE ON tracksolid.position_history FOR EACH ROW EXECUTE FUNCTION _timescaledb_functions.continuous_agg_invalidation_trigger('1'); + + +-- +-- TOC entry 6718 (class 2620 OID 25189) +-- Name: fuel_readings ts_insert_blocker; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER ts_insert_blocker BEFORE INSERT ON tracksolid.fuel_readings FOR EACH ROW EXECUTE FUNCTION _timescaledb_functions.insert_blocker(); + + +-- +-- TOC entry 6717 (class 2620 OID 25153) +-- Name: heartbeats ts_insert_blocker; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER ts_insert_blocker BEFORE INSERT ON tracksolid.heartbeats FOR EACH ROW EXECUTE FUNCTION _timescaledb_functions.insert_blocker(); + + +-- +-- TOC entry 6712 (class 2620 OID 25006) +-- Name: position_history ts_insert_blocker; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER ts_insert_blocker BEFORE INSERT ON tracksolid.position_history FOR EACH ROW EXECUTE FUNCTION _timescaledb_functions.insert_blocker(); + + +-- +-- TOC entry 6719 (class 2620 OID 25204) +-- Name: temperature_readings ts_insert_blocker; Type: TRIGGER; Schema: tracksolid; Owner: postgres +-- + +CREATE TRIGGER ts_insert_blocker BEFORE INSERT ON tracksolid.temperature_readings FOR EACH ROW EXECUTE FUNCTION _timescaledb_functions.insert_blocker(); + + +-- +-- TOC entry 6699 (class 2606 OID 24982) +-- Name: alarms alarms_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.alarms + ADD CONSTRAINT alarms_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6703 (class 2606 OID 25170) +-- Name: device_events device_events_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.device_events + ADD CONSTRAINT device_events_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6707 (class 2606 OID 25250) +-- Name: dispatch_log dispatch_log_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.dispatch_log + ADD CONSTRAINT dispatch_log_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6701 (class 2606 OID 25133) +-- Name: fault_codes fault_codes_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.fault_codes + ADD CONSTRAINT fault_codes_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6704 (class 2606 OID 25184) +-- Name: fuel_readings fuel_readings_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.fuel_readings + ADD CONSTRAINT fuel_readings_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6702 (class 2606 OID 25148) +-- Name: heartbeats heartbeats_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.heartbeats + ADD CONSTRAINT heartbeats_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6706 (class 2606 OID 25218) +-- Name: lbs_readings lbs_readings_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.lbs_readings + ADD CONSTRAINT lbs_readings_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6695 (class 2606 OID 24899) +-- Name: live_positions live_positions_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.live_positions + ADD CONSTRAINT live_positions_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6700 (class 2606 OID 25001) +-- Name: obd_readings obd_readings_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.obd_readings + ADD CONSTRAINT obd_readings_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6698 (class 2606 OID 24963) +-- Name: parking_events parking_events_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.parking_events + ADD CONSTRAINT parking_events_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6696 (class 2606 OID 24924) +-- Name: position_history position_history_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.position_history + ADD CONSTRAINT position_history_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6705 (class 2606 OID 25199) +-- Name: temperature_readings temperature_readings_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.temperature_readings + ADD CONSTRAINT temperature_readings_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6697 (class 2606 OID 24943) +-- Name: trips trips_imei_fkey; Type: FK CONSTRAINT; Schema: tracksolid; Owner: postgres +-- + +ALTER TABLE ONLY tracksolid.trips + ADD CONSTRAINT trips_imei_fkey FOREIGN KEY (imei) REFERENCES tracksolid.devices(imei); + + +-- +-- TOC entry 6932 (class 0 OID 0) +-- Dependencies: 6931 +-- Name: DATABASE tracksolid_db; Type: ACL; Schema: -; Owner: postgres +-- + +GRANT CONNECT ON DATABASE tracksolid_db TO tracksolid_owner; +GRANT CONNECT ON DATABASE tracksolid_db TO grafana_ro; + + +-- +-- TOC entry 6934 (class 0 OID 0) +-- Dependencies: 21 +-- Name: SCHEMA tracksolid; Type: ACL; Schema: -; Owner: postgres +-- + +GRANT USAGE ON SCHEMA tracksolid TO tracksolid_owner; +GRANT USAGE ON SCHEMA tracksolid TO grafana_ro; + + +-- +-- TOC entry 6935 (class 0 OID 0) +-- Dependencies: 296 +-- Name: TABLE position_history; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.position_history TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.position_history TO grafana_ro; + + +-- +-- TOC entry 6942 (class 0 OID 0) +-- Dependencies: 290 +-- Name: TABLE devices; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.devices TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.devices TO grafana_ro; + + +-- +-- TOC entry 6946 (class 0 OID 0) +-- Dependencies: 298 +-- Name: TABLE trips; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.trips TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.trips TO grafana_ro; + + +-- +-- TOC entry 6952 (class 0 OID 0) +-- Dependencies: 302 +-- Name: TABLE alarms; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.alarms TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.alarms TO grafana_ro; + + +-- +-- TOC entry 6954 (class 0 OID 0) +-- Dependencies: 301 +-- Name: SEQUENCE alarms_id_seq; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,USAGE ON SEQUENCE tracksolid.alarms_id_seq TO tracksolid_owner; +GRANT SELECT,USAGE ON SEQUENCE tracksolid.alarms_id_seq TO grafana_ro; + + +-- +-- TOC entry 6955 (class 0 OID 0) +-- Dependencies: 292 +-- Name: TABLE api_token_cache; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.api_token_cache TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.api_token_cache TO grafana_ro; + + +-- +-- TOC entry 6957 (class 0 OID 0) +-- Dependencies: 291 +-- Name: SEQUENCE api_token_cache_id_seq; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,USAGE ON SEQUENCE tracksolid.api_token_cache_id_seq TO tracksolid_owner; +GRANT SELECT,USAGE ON SEQUENCE tracksolid.api_token_cache_id_seq TO grafana_ro; + + +-- +-- TOC entry 6960 (class 0 OID 0) +-- Dependencies: 319 +-- Name: TABLE device_events; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.device_events TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.device_events TO grafana_ro; + + +-- +-- TOC entry 6966 (class 0 OID 0) +-- Dependencies: 327 +-- Name: TABLE dispatch_log; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.dispatch_log TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.dispatch_log TO grafana_ro; + + +-- +-- TOC entry 6968 (class 0 OID 0) +-- Dependencies: 316 +-- Name: TABLE fault_codes; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.fault_codes TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.fault_codes TO grafana_ro; + + +-- +-- TOC entry 6970 (class 0 OID 0) +-- Dependencies: 315 +-- Name: SEQUENCE fault_codes_id_seq; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,USAGE ON SEQUENCE tracksolid.fault_codes_id_seq TO tracksolid_owner; +GRANT SELECT,USAGE ON SEQUENCE tracksolid.fault_codes_id_seq TO grafana_ro; + + +-- +-- TOC entry 6974 (class 0 OID 0) +-- Dependencies: 320 +-- Name: TABLE fuel_readings; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.fuel_readings TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.fuel_readings TO grafana_ro; + + +-- +-- TOC entry 6978 (class 0 OID 0) +-- Dependencies: 325 +-- Name: TABLE geofences; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.geofences TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.geofences TO grafana_ro; + + +-- +-- TOC entry 6980 (class 0 OID 0) +-- Dependencies: 317 +-- Name: TABLE heartbeats; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.heartbeats TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.heartbeats TO grafana_ro; + + +-- +-- TOC entry 6981 (class 0 OID 0) +-- Dependencies: 294 +-- Name: TABLE ingestion_log; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.ingestion_log TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.ingestion_log TO grafana_ro; + + +-- +-- TOC entry 6983 (class 0 OID 0) +-- Dependencies: 293 +-- Name: SEQUENCE ingestion_log_id_seq; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,USAGE ON SEQUENCE tracksolid.ingestion_log_id_seq TO tracksolid_owner; +GRANT SELECT,USAGE ON SEQUENCE tracksolid.ingestion_log_id_seq TO grafana_ro; + + +-- +-- TOC entry 6987 (class 0 OID 0) +-- Dependencies: 323 +-- Name: TABLE lbs_readings; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.lbs_readings TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.lbs_readings TO grafana_ro; + + +-- +-- TOC entry 6989 (class 0 OID 0) +-- Dependencies: 295 +-- Name: TABLE live_positions; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.live_positions TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.live_positions TO grafana_ro; + + +-- +-- TOC entry 6999 (class 0 OID 0) +-- Dependencies: 304 +-- Name: TABLE obd_readings; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.obd_readings TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.obd_readings TO grafana_ro; + + +-- +-- TOC entry 7001 (class 0 OID 0) +-- Dependencies: 303 +-- Name: SEQUENCE obd_readings_id_seq; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,USAGE ON SEQUENCE tracksolid.obd_readings_id_seq TO tracksolid_owner; +GRANT SELECT,USAGE ON SEQUENCE tracksolid.obd_readings_id_seq TO grafana_ro; + + +-- +-- TOC entry 7002 (class 0 OID 0) +-- Dependencies: 300 +-- Name: TABLE parking_events; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.parking_events TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.parking_events TO grafana_ro; + + +-- +-- TOC entry 7004 (class 0 OID 0) +-- Dependencies: 299 +-- Name: SEQUENCE parking_events_id_seq; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,USAGE ON SEQUENCE tracksolid.parking_events_id_seq TO tracksolid_owner; +GRANT SELECT,USAGE ON SEQUENCE tracksolid.parking_events_id_seq TO grafana_ro; + + +-- +-- TOC entry 7005 (class 0 OID 0) +-- Dependencies: 284 +-- Name: TABLE schema_migrations; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.schema_migrations TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.schema_migrations TO grafana_ro; + + +-- +-- TOC entry 7007 (class 0 OID 0) +-- Dependencies: 321 +-- Name: TABLE temperature_readings; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.temperature_readings TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.temperature_readings TO grafana_ro; + + +-- +-- TOC entry 7009 (class 0 OID 0) +-- Dependencies: 297 +-- Name: SEQUENCE trips_id_seq; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,USAGE ON SEQUENCE tracksolid.trips_id_seq TO tracksolid_owner; +GRANT SELECT,USAGE ON SEQUENCE tracksolid.trips_id_seq TO grafana_ro; + + +-- +-- TOC entry 7011 (class 0 OID 0) +-- Dependencies: 336 +-- Name: TABLE v_active_dispatch_map; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_active_dispatch_map TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_active_dispatch_map TO grafana_ro; + + +-- +-- TOC entry 7013 (class 0 OID 0) +-- Dependencies: 340 +-- Name: TABLE v_alarms_daily; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_alarms_daily TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_alarms_daily TO grafana_ro; + + +-- +-- TOC entry 7015 (class 0 OID 0) +-- Dependencies: 337 +-- Name: TABLE v_currently_idle; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_currently_idle TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_currently_idle TO grafana_ro; + + +-- +-- TOC entry 7017 (class 0 OID 0) +-- Dependencies: 338 +-- Name: TABLE v_driver_aggregates_daily; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_driver_aggregates_daily TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_driver_aggregates_daily TO grafana_ro; + + +-- +-- TOC entry 7019 (class 0 OID 0) +-- Dependencies: 339 +-- Name: TABLE v_fleet_km_daily; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_fleet_km_daily TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_fleet_km_daily TO grafana_ro; + + +-- +-- TOC entry 7020 (class 0 OID 0) +-- Dependencies: 309 +-- Name: TABLE v_fleet_status; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_fleet_status TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_fleet_status TO grafana_ro; + + +-- +-- TOC entry 7022 (class 0 OID 0) +-- Dependencies: 334 +-- Name: TABLE v_fleet_today; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_fleet_today TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_fleet_today TO grafana_ro; + + +-- +-- TOC entry 7023 (class 0 OID 0) +-- Dependencies: 310 +-- Name: TABLE v_ingestion_health; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_ingestion_health TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_ingestion_health TO grafana_ro; + + +-- +-- TOC entry 7024 (class 0 OID 0) +-- Dependencies: 312 +-- Name: TABLE v_mileage_daily_cagg; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_mileage_daily_cagg TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_mileage_daily_cagg TO grafana_ro; + + +-- +-- TOC entry 7026 (class 0 OID 0) +-- Dependencies: 342 +-- Name: TABLE v_sla_inflight; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_sla_inflight TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_sla_inflight TO grafana_ro; + + +-- +-- TOC entry 7028 (class 0 OID 0) +-- Dependencies: 341 +-- Name: TABLE v_utilisation_daily; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_utilisation_daily TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_utilisation_daily TO grafana_ro; + + +-- +-- TOC entry 7030 (class 0 OID 0) +-- Dependencies: 335 +-- Name: TABLE v_vehicles_not_moved_today; Type: ACL; Schema: tracksolid; Owner: postgres +-- + +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE tracksolid.v_vehicles_not_moved_today TO tracksolid_owner; +GRANT SELECT ON TABLE tracksolid.v_vehicles_not_moved_today TO grafana_ro; + + +-- +-- TOC entry 5404 (class 826 OID 25111) +-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: tracksolid; Owner: postgres +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA tracksolid GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLES TO tracksolid_owner; +ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA tracksolid GRANT SELECT ON TABLES TO grafana_ro; + + +-- Completed on 2026-04-23 16:57:55 EAT + +-- +-- PostgreSQL database dump complete +-- + +\unrestrict dPJmPZ0BDsHeyfTnAmlhf9NGlz7PqKG3XWgDOSnH5CrV9vRAMYsNh1loEhu4Y7m + diff --git a/fireside_logistics_cleaned_v2.csv b/fireside_logistics_cleaned_v2.csv new file mode 100644 index 0000000..1a8f4ed --- /dev/null +++ b/fireside_logistics_cleaned_v2.csv @@ -0,0 +1,145 @@ +IMEI,Device Name,Vehicle Name,Vehicle Icon,License Plate No.,Vehicle Model,Vehicle Brand,Driver Name,Telephone,SIM,Fuel/100km,VIN,Engine Number,Remarks,Group,Department,Account,Customer Name,Model,Activated Date,Sales Time,MAC,Subscription Expiration,User Expiration Date,Battery replacement date,ICCID,IMSI,ID Number,Installation Time +865135061569479,UMA 382EK,UMA 382EK,automobile,UMA 382EK,,,UG,,+256792997079,,,,Dept: MTN,Default Group,MTN,fireside,Fireside Group HQ,X3,2026-02-26,2025-09-08,,2036-02-27,2036-02-27,,8925610001837573419F,641101970467667,, +865135061569131,UMA 418EK,UMA 418EK,automobile,UMA 418EK,,,UG,,+256792997053,,,,Dept: MTN,Default Group,MTN,fireside,Fireside Group HQ,X3,2026-02-26,2025-09-08,,2036-02-27,2036-02-27,,8925610001837573385F,641101970467664,, +862798052707896,John Mbugua - KDW 573B,KDW 573B,automobile,KDW 573B,Probox,,John Mbugua,,,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,JC400P,2026-01-30,2025-06-11,,2036-01-31,2036-01-31,,89254021414206816725,639021410681672,, +865135061563423,Joel Ntumba - UMA 826AB,UMA 826AB,mtc,UMA 826AB,Motorbike,,Joel Ntumba,,0119051036,,,,Dept: MTN,Default Group,MTN,fireside,Fireside Group HQ,X3,2026-01-28,2025-09-08,,2036-01-29,2036-01-29,,89254021414206652690,639021410665269,, +865135061564280,Rodin Kiberu - UMA 011EK,UMA 011EK,mtc,UMA 011EK,Motorbike,,Rodin Kiberu,,0118081642,,,,Dept: MTN,Default Group,MTN,fireside,Fireside Group HQ,X3,2026-01-28,2025-09-08,,2036-01-29,2036-01-29,,89254021414206817244,639021410681724,, +862798052708068,Dominic Wambua - KDV 683Z,KDV 683Z,automobile,KDV 683Z,Probox,,Dominic Wambua,,0758048043,,,,Dept: ROLLOUT,Default Group,ROLLOUT,fireside,Fireside Group HQ,JC400P,2026-01-24,2025-06-11,,2036-01-25,2036-01-25,,89254021414206816964,639021410681696,, +862798052708167,Levine Wasike - KDV 439W,KDV 439W,automobile,KDV 439W,Probox,,Levine Wasike,,0758046738,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group HQ,JC400P,2025-12-13,2025-06-11,,2035-12-14,2035-12-14,,89254021414206816741,639021410681674,, +865135061563639,Benjamin Ananda - KDV 438W,KDV 438W,automobile,KDV 438W,Probox,,Benjamin Ananda,,0758047065,,,,Dept: PLANNING,Default Group,PLANNING,fireside,Fireside Group HQ,X3,2025-12-13,2025-09-08,,2035-12-14,2035-12-14,,89254021414206816683,639021410681668,, +865135061569123,Albert Mutwiri - KDV 437W,KDV 437W,automobile,KDV 437W,Probox,,Albert Mutwiri,,0758047101,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group HQ,X3,2025-12-13,2025-09-08,,2035-12-14,2035-12-14,,89254021414206816881,639021410681688,, +865135061564470,Silvanus Kipkorir - KDV 064S,KDV 064S,automobile,KDV 064S,Probox,,Silvanus Kipkorir,,0113669866,,,,Dept: AIRTEL,Default Group,AIRTEL,fireside,Fireside Group HQ,X3,2025-11-21,2025-09-08,,2035-11-22,2035-11-22,,89254021414206378718,639021410637871,, +865135061581904,Robert Kipruto - KDV 072L,KDV 072L,automobile,KDV 072L,Probox,,Robert Kipruto,,0114149576,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group HQ,X3,2025-11-21,2025-09-08,,2035-11-22,2035-11-22,,89254021264261503993,639021266150399,, +862798052713779,Benard Kimutai - KDN 759G,KDN 759G,automobile,KDN 759G,Probox,,Benard Kimutai,,0752143258,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,JC400P,2025-08-23,2025-06-11,,2035-08-24,2035-08-24,,89254035061001753860,639035060175386,, +865135061043426,Geoffrey Karanja - KMGS 239H,KMGS 239H,mtc,KMGS 239H,Motorbike,,Geoffrey Karanja,,0768696658,,,,Dept: OSP-PATROL,Default Group,OSP-PATROL,fireside,Fireside Group HQ,X3,2025-08-22,2025-06-11,,2035-08-23,2035-08-23,,89254021394274518926,639021397451892,, +865135061053714,Samuel Kihara - KMEL 225X,KMEL 225X,mtc,KMEL 225X,Motorbike,,Samuel Kihara,,0768696832,,,,Dept: OSP-PATROL,Default Group,OSP-PATROL,fireside,Fireside Group HQ,X3,2025-08-02,2025-06-11,,2035-08-03,2035-08-03,,89254021394274518934,639021397451893,, +865135061036164,Brian Njenga - KMFF 113Z,KMFF 113Z,mtc,KMFF 113Z,Motorbike,,Brian Njenga,,0768696705,,,,Dept: OSP-PATROL,Default Group,OSP-PATROL,fireside,Fireside Group HQ,X3,2025-07-31,2025-06-11,,2035-08-01,2035-08-01,,89254021394274518850,639021397451885,, +865135061049001,Parked - KMGK 596V,KMGK 596V,mtc,KMGK 596V,Motorbike,,Parked,,0768697064,,,,Dept: DELIVERIES,Default Group,DELIVERIES,fireside,Fireside Group HQ,X3,2025-07-31,2025-06-11,,2035-08-01,2035-08-01,,89254021394274518884,639021397451888,, +862798052715220,Rofas Njagi - KDT 728R,KDT 728R,automobile,KDT 728R,Probox,,Rofas Njagi,,0704573658,,,,Dept: REGIONAL,Default Group,REGIONAL,fireside,Fireside Group HQ,JC400P,2025-07-16,2025-06-11,,2035-07-17,2035-07-17,,89254021334258495873,639021335849587,, +865135061037980,Emmanuel Luseno - KDS 453Y,KDS 453Y,automobile,KDS 453Y,Pick-Up,,Emmanuel Luseno,,0790176734,,,,Dept: GENERAL,Default Group,GENERAL,fireside,Fireside Group HQ,X3,2025-07-15,2025-06-11,,,2035-07-15,,89254021394215205856,639021391520585,, +865135061035778,John Kimeria - KDS 525D,KDS 525D,truck,KDS 525D,Crane,,John Kimeria,,0790176738,,,,Dept: GENERAL,Default Group,GENERAL,fireside,Fireside Group HQ,X3,2025-07-11,2025-06-11,,2035-07-12,2035-07-12,,89254021394215205922,639021391520592,, +865135061053748,Rashid Hassan - KDM 840V,KDM 840V,automobile,KDM 840V,Probox,,Rashid Hassan,,0768445963,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,X3,2025-07-10,2025-06-11,,2035-07-11,2035-07-11,,89254021334212352574,639021331235257,, +865135061042261,Kelvin Wambugu - KDR 592N,KDR 592N,automobile,KDR 592N,Probox,,Kelvin Wambugu,,0797680464,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group HQ,X3,2025-07-10,2025-06-11,,2035-07-11,2035-07-11,,89254021334258159693,639021335815969,, +862798052713811,James Onyango - KDU 613B,KDU 613B,automobile,KDU 613B,Probox,,James Onyango,,0790176542,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2025-07-09,2025-06-11,,2035-07-10,2035-07-10,,89254021394215205880,639021391520588,, +865135061047435,Management_Mazda - KDU 613A,KDU 613A,automobile,KDU 613A,Mazda,,Management_Mazda,,0790175971,,,,Dept: MGT,Default Group,MGT,fireside,Fireside Group HQ,X3,2025-07-09,2025-06-11,,2035-07-10,2035-07-10,,89254021394215205971,639021391520597,, +862798050522743,Charles Nyambane - KCB 711C,KCB 711C,automobile,KCB 711C,Probox,,Charles Nyambane,,0768657106,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2023-12-22,2024-11-08,,2033-12-23,2033-12-23,,,,, +862798050525225,Sadique Wakayula - KDC 490Q,KDC 490Q,truck,KDC 490Q,Crane,,Sadique Wakayula,,0768652386,,,,Dept: GENERAL,Default Group,GENERAL,fireside,Fireside Group HQ,JC400P,2023-12-22,2024-11-08,,2043-12-22,2043-12-22,,,,, +862798050525068,Samuel Ng'ang'a - KDE 264M,KDE 264M,automobile,KDE 264M,Probox,,Samuel Ng'ang'a,,0768658564,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2023-12-22,2024-11-08,,2033-12-23,2033-12-23,,,,, +862798050525837,Kennedy Ondieki - KCU 237Z,KCU 237Z,automobile,KCU 237Z,Probox,,Kennedy Ondieki,,0113669852,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2023-12-21,,,2033-12-22,2033-12-22,,,,, +862798050523618,Geoffrey Too - KDM 308S,KDM 308S,automobile,KDM 308S,Probox,,Geoffrey Too,,0701211625,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,JC400P,2023-08-15,2023-08-22,,2033-08-16,2033-08-16,,,,, +862798050523816,Job Ngare - KDM 309S,KDM 309S,automobile,KDM 309S,Probox,,Job Ngare,,0707936781,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2023-08-15,2023-08-22,,2033-08-16,2033-08-16,,,,, +359857082912239,Dickson Jaoko - KDK 815R,KDK 815R,automobile,KDK 815R,Probox,,Dickson Jaoko,,0706392117,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,GT06E,2023-06-21,2023-07-27,,2033-06-22,2033-06-22,,89254021234296021287,639021239602128,, +359857082897091,Peter Mbugua - KDK 728K,KDK 728K,automobile,KDK 728K,Probox,,Peter Mbugua,,0790262984,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,GT06E,2022-12-14,2022-12-16,,2042-12-15,2042-12-15,,89254021234222500396,639021232250039,, +862798050524608,Peter Mbugua - KDK 728K,KDK 728K,automobile,KDK 728K,Probox,,Peter Mbugua,,0706742413,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2022-12-03,2022-12-15,,2042-12-04,2042-12-04,,,,, +862798050524368,862798050524368,,automobile,,,,,,,,,,,Default Group,,fireside,Fireside Group HQ,JC400P,2022-10-29,2022-12-17,,2042-10-30,2042-10-30,,,,, +862798050524558,Mutuku Joseph - KDC 739F,KDC 739F,automobile,KDC 739F,Probox,,Mutuku Joseph,,0100858817,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group HQ,JC400P,2022-01-22,2022-01-25,,2042-01-23,2042-01-23,,,,, +862798050524897,Cornelius Kimutai - KCU 938R,KCU 938R,automobile,KCU 938R,Van,,Cornelius Kimutai,,0114924404,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group HQ,JC400P,2022-01-22,2022-01-25,,2042-01-23,2042-01-23,,,,, +862798050522107,Cassius Wakiyo - KDB 323M,KDB 323M,automobile,KDB 323M,Probox,,Cassius Wakiyo,,0114149576,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,JC400P,2022-01-22,2022-01-25,,2042-01-23,2042-01-23,,,,, +862798050524657,Felix Andole - KDC 207R,KDC 207R,automobile,KDC 207R,Probox,,Felix Andole,,0758689195,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2022-01-22,2022-01-25,,2042-01-23,2042-01-23,,,,, +862798050523386,George Ochieng' - KDD 684Y,KDD 684Y,automobile,KDD 684Y,Probox,,George Ochieng',,0785586834,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,JC400P,2022-01-22,2022-01-27,,2042-01-23,2042-01-23,,,,, +862798050524384,Hamisi Pande - KDD 689Y,KDD 689Y,automobile,KDD 689Y,Probox,,Hamisi Pande,,0701211744,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2022-01-22,2022-01-27,,2042-01-23,2042-01-23,,,,, +862798050525589,Simon Kamau - KCE 090R,KCE 090R,automobile,KCE 090R,Probox,,Simon Kamau,,0796276387,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2022-01-19,2022-01-17,,2042-01-20,2042-01-20,,,,, +862798050525423,Makori John - KDB 585E,KDB 585E,automobile,KDB 585E,Probox,,Makori John,,0701211724,,,,Dept: PLANNING,Default Group,PLANNING,fireside,Fireside Group HQ,JC400P,2022-01-15,2022-01-17,,2042-01-16,2042-01-16,,,,, +862798050525951,Wright Oseko - KCG 668W,KCG 668W,automobile,KCG 668W,Probox,,Wright Oseko,,0741943212,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,JC400P,2022-01-15,2022-01-17,,2042-01-16,2042-01-16,,,,, +862798050522859,Garage - KCH 167M,KCH 167M,automobile,KCH 167M,Probox,,Garage,,0706740252,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,JC400P,2022-01-15,2022-01-17,,2042-01-16,2042-01-16,,,,, +862798050524707,Garage - KCE 699F,KCE 699F,automobile,KCE 699F,Probox,,Garage,,0110525751,,,,Dept: ROLLOUT,Default Group,ROLLOUT,fireside,Fireside Group HQ,JC400P,2022-01-15,2022-01-17,,2042-01-16,2042-01-16,,,,, +862798050522883,Dan Watila - KDE 638J,KDE 638J,automobile,KDE 638J,Probox,,Dan Watila,,0112615393,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2022-01-15,2022-01-17,,2042-01-16,2042-01-16,,,,, +862798050525605,John Ondego - KCA 542Q,KCA 542Q,automobile,KCA 542Q,Probox,,John Ondego,,0110526783,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2022-01-15,2022-01-17,,2042-01-16,2042-01-16,,,,, +862798050288360,Brian Ngetich - KDA 717B,KDA 717B,automobile,KDA 717B,Probox,,Brian Ngetich,,0717867861,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,JC400P,2021-11-05,2021-11-08,,2041-11-06,2041-11-06,,,,, +862798050288261,Patric Bett - KDA 609E,KDA 609E,automobile,KDA 609E,Probox,,Patric Bett,0112693340,0790176509,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,JC400P,2021-10-23,2021-10-25,,2041-10-24,2041-10-24,,,,, +359857082042052,Gabriel Musumba - KCE 690F,KCE 690F,automobile,KCE 690F,Probox,,Gabriel Musumba,,0110094466,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,GT06E,2020-04-03,2020-04-16,,2040-04-04,2040-04-04,,89254021164215938024,639021161593802,, +359857081885410,Allan Owana - KDK 780K,KDK 780K,automobile,KDK 780K,Probox,,Allan Owana,,0703616117,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,GT06E,2019-06-19,2019-07-01,,2039-06-20,2039-06-20,,89254021234222499854,639021232249985,, +359857081891798,Garage - KCH 167M,KCH 167M,automobile,KCH 167M,Probox,,Garage,,0746760102,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group HQ,GT06E,2019-06-16,2019-07-01,,2039-06-17,2039-06-17,,89254021084186499493,639021088649949,, +359857081891632,John Ondego - KCA 542Q,KCA 542Q,automobile,KCA 542Q,Probox,,John Ondego,,0746760038,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group HQ,GT06E,2019-06-15,2019-07-01,,2039-06-16,2039-06-16,,89254021084186499485,639021088649948,, +862798052708035,862798052708035,,automobile,,Probox,,,,,,,,,Default Group,,fireside,Fireside Group HQ,JC400P,Inactive,2025-06-11,,120Month,——,,,,, +865135061563597,Dominic Wambua - KDV 683Z,KDV 683Z,automobile,KDV 683Z,Probox,,Dominic Wambua,,0758052405,,,,Dept: ROLLOUT,Default Group,ROLLOUT,fireside,Fireside Telematics ,X3,2026-01-30,2026-02-24,,2036-01-31,2036-01-31,,89254021414206816733,639021410681673,, +865135061562722,John Mbugua - KDW 573B,KDW 573B,automobile,KDW 573B,Probox,,John Mbugua,,0758052508,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,X3,2026-01-30,2026-02-24,,2036-01-31,2036-01-31,,89254021414206816832,639021410681683,, +862798052708282,Godffrey Nandwa - KCN 496A,KCN 496A,automobile,KCN 496A,Probox,,Godffrey Nandwa,,0758047934,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2026-01-25,2026-02-20,,2036-01-26,2036-01-26,,89254021414206816865,639021410681686,, +862798052707888,Benjamin Ananda - KDV 438W,KDV 438W,automobile,KDV 438W,Probox,,Benjamin Ananda,,0758047312,,,,Dept: PLANNING,Default Group,PLANNING,fireside,Fireside Telematics ,JC400P,2025-12-15,2026-02-20,,2035-12-16,2035-12-16,,89254021414206816980,639021410681698,, +862798052708076,Albert Mutwiri - KDV 437W,KDV 437W,automobile,KDV 437W,Probox,,Albert Mutwiri,,0758047094,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Telematics ,JC400P,2025-12-13,2026-02-20,,2035-12-14,2035-12-14,,89254021414206816782,639021410681678,, +865135061562847,Levine Wasike - KDV 439W,KDV 439W,automobile,KDV 439W,Probox,,Levine Wasike,,0758047032,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,X3,2025-12-13,2026-02-24,,2035-12-14,2035-12-14,,89254021414206816840,639021410681684,, +862798052714066,862798052714066,,automobile,,Probox,,,,,,,,,Default Group,,fireside,Fireside Telematics ,JC400P,2025-11-21,2025-06-11,,2035-11-22,2035-11-22,,89254021414206378684,639021410637868,, +862798052713837,Kennedy Ondieki - KCU 237Z,KCU 237Z,automobile,KCU 237Z,Probox,,Kennedy Ondieki,,0113669852,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2025-10-08,2026-02-20,,2035-10-09,2035-10-09,,89254021414206327855,639021410632785,, +862798052713696,862798052713696,,automobile,,Probox,,,,,,,,,Default Group,,fireside,Fireside Telematics ,JC400P,2025-09-02,2025-06-11,,2035-09-03,2035-09-03,,89254021394215205906,639021391520590,, +862798052713985,Timothy Gitau - KDT 916R,KDT 916R,automobile,KDT 916R,Probox,,Timothy Gitau,,0768696668,,,,Dept: REGIONAL,Default Group,REGIONAL,fireside,Fireside Telematics ,JC400P,2025-08-02,2026-02-20,,2035-08-03,2035-08-03,,89254021394274518892,639021397451889,, +865135061035653,Richardson Komu - KDT 923R,KDT 923R,automobile,KDT 923R,Probox,,Richardson Komu,,0768697292,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,X3,2025-08-02,2026-02-24,,2035-08-03,2035-08-03,,89254021394274518942,639021397451894,, +865135061048466,Samuel Muriithy - KDR 594N,KDR 594N,automobile,KDR 594N,Probox,,Samuel Muriithy,,0797680395,,,,Dept: ROLLOUT,Default Group,ROLLOUT,fireside,Fireside Telematics ,X3,2025-07-24,2026-02-24,,2035-07-25,2035-07-25,,89254021334258159628,639021335815962,, +865135061054555,Rofas Njagi - KDT 728R,KDT 728R,automobile,KDT 728R,Probox,,Rofas Njagi,,0790176726,,,,Dept: REGIONAL,Default Group,REGIONAL,fireside,Fireside Telematics ,X3,2025-07-16,2026-02-24,,2035-07-17,2035-07-17,,89254021394215205823,639021391520582,, +862798052713761,Management_Mazda - KDU 613A,KDU 613A,automobile,KDU 613A,Mazda,,Management_Mazda,,0790176786,,,,Dept: MGT,Default Group,MGT,fireside,Fireside Telematics ,JC400P,2025-07-09,2026-02-20,,2035-07-10,2035-07-10,,89254021394215205955,639021391520595,, +865135061054548,James Onyango - KDU 613B,KDU 613B,automobile,KDU 613B,Probox,,James Onyango,,0790175997,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,X3,2025-07-09,2026-02-24,,2035-07-10,2035-07-10,,89254021394215205948,639021391520594,, +862798050526231,Rashid Hassan - KDM 840V,KDM 840V,automobile,KDM 840V,Probox,,Rashid Hassan,,0790175526,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2023-12-22,2026-02-20,,2043-12-23,2043-12-23,,,,, +862798050523139,Mike Wanaswa - KDT 724R,KDT 724R,automobile,KDT 724R,Probox,,Mike Wanaswa,,0790175045,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2023-12-22,2026-02-20,,2043-12-23,2043-12-23,,,,, +862798050523063,Kelvin Wambugu - KDR 594N,KDR 594N,automobile,KDR 594N,Probox,,Kelvin Wambugu,,0701211876,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Telematics ,JC400P,2023-12-22,2026-02-20,,2043-12-22,2043-12-22,,,,, +862798050523626,Major Simiyu - KDS 949Y,KDS 949Y,automobile,KDS 949Y,Probox,,Major Simiyu,,0701211892,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Telematics ,JC400P,2023-12-22,2026-02-20,,2033-12-23,2033-12-23,,,,, +862798050523337,Victor Kimutai - KDS 919Y,KDS 919Y,automobile,KDS 919Y,Probox,,Victor Kimutai,,0700242527,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,JC400P,2023-12-22,2026-02-20,,2043-12-22,2043-12-22,,,,, +862798050523295,Emmanuel Luseno - KDS 453 Y,KDS 453 Y,automobile,KDS 453 Y,Pick-Up,,Emmanuel Luseno,,0700242474,,,,Dept: GENERAL,Default Group,GENERAL,fireside,Fireside Telematics ,JC400P,2023-12-22,2026-02-20,,2033-12-23,2033-12-23,,,,, +862798050523014,Samuel Muriithy - KDR 594N,KDR 594N,automobile,KDR 594N,Probox,,Samuel Muriithy,,0790175423,,,,Dept: ROLLOUT,Default Group,ROLLOUT,fireside,Fireside Telematics ,JC400P,2023-12-21,2026-02-20,,2033-12-22,2033-12-22,,,,, +862798050521521,John Kimeria - KDS 525D,KDS 525D,truck,KDS 525D,Crane,,John Kimeria,,0752958416,,,,Dept: GENERAL,Default Group,GENERAL,fireside,Fireside Telematics ,JC400P,2023-11-26,2026-02-20,,2033-11-27,2033-11-27,,,,, +862798050524533,Leonard Nzai - KDM 306S,KDM 306S,automobile,KDM 306S,Probox,,Leonard Nzai,,0703487162,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2023-08-21,2026-02-20,,2033-08-22,2033-08-22,,,,, +359857082898016,Job Ngare - KDM 309S,KDM 309S,automobile,KDM 309S,Probox,,Job Ngare,,0706895756,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,GT06E,2023-08-15,2026-02-24,,2033-08-16,2033-08-16,,89254021324273007563,639021327300756,, +862798050525266,Dickson Jaoko - KDK 815R,KDK 815R,automobile,KDK 815R,Probox,,Dickson Jaoko,,0706665867,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,JC400P,2023-06-21,2026-02-20,,2033-06-22,2033-06-22,,,,, +862798050523527,Allan Owana - KDK 780K,KDK 780K,automobile,KDK 780K,Probox,,Allan Owana,,0792375024,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2022-12-03,2026-02-20,,2042-12-04,2042-12-04,,,,, +862798050524426,Amani Sulubu - KCY 090X,KCY 090X,automobile,KCY 090X,Probox,,Amani Sulubu,,0113823350,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2022-01-16,2026-02-20,,2042-01-17,2042-01-17,,,,, +862798050522065,Gideon Kiprono - KCQ 215F,KCQ 215F,automobile,KCQ 215F,Probox,,Gideon Kiprono,,0113343715,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2022-01-16,2026-02-20,,2042-01-17,2042-01-17,,,,, +862798050525670,Gabriel Musumba - KCE 690F,KCE 690F,automobile,KCE 690F,Probox,,Gabriel Musumba,,0701211996,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,JC400P,2022-01-15,2026-02-20,,2042-01-16,2042-01-16,,,,, +862798050288345,Santoes Omondi - KCZ 181P,KCZ 181P,automobile,KCZ 181P,Pick-Up,,Santoes Omondi,,0768446105,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,JC400P,2021-11-06,2026-02-20,,2041-11-07,2041-11-07,,,,, +862798050288303,Elias Baya - KCZ 476E,KCZ 476E,automobile,KCZ 476E,Probox,,Elias Baya,,0115870439,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Telematics ,JC400P,2021-11-06,2026-02-20,,2041-11-07,2041-11-07,,,,, +862798050288212,Nicholas Erastus - KCQ 581M,KCQ 581M,automobile,KCQ 581M,Probox,,Nicholas Erastus,,0746979531,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,JC400P,2021-11-02,2026-02-20,,2041-11-03,2041-11-03,,,,, +359857082898008,Samuel Ng'ang'a - KDE 264M,KDE 264M,automobile,KDE 264M,Probox,,Samuel Ng'ang'a,,0711731539,,,,Dept: ISP,Default Group,ISP ,fireside,Fireside Telematics ,GT06E,2021-10-28,2026-02-24,,2041-10-29,2041-10-29,,89254021264260342245,639021266034224,, +359857082898487,Dan Watila - KDE 638J,KDE 638J,automobile,KDE 638J,Probox,,Dan Watila,,0116242996,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,GT06E,2021-10-21,2026-02-24,,2041-10-22,2041-10-22,,89254021334258404214,639021335840421,, +359857082900358,Geoffrey Too - KDM 308S,KDM 308S,automobile,KDM 308S,Probox,,Geoffrey Too,,0796527601,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,GT06E,2021-10-21,2026-02-24,,2041-10-22,2041-10-22,,89254021264260126572,639021266012657,, +359857082896911,Hamisi Pande - KDD 689Y,KDD 689Y,automobile,KDD 689Y,Probox,,Hamisi Pande,,0112714612,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,GT06E,2021-09-17,2026-02-24,,2041-09-18,2041-09-18,,89254021214211314660,639021211131466,, +359857082900697,George Ochieng' - KDD 684Y,KDD 684Y,automobile,KDD 684Y,Probox,,George Ochieng',,0114879518,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,GT06E,2021-09-17,2026-02-24,,2041-09-18,2041-09-18,,89254021214211314678,639021211131467,, +359857082897257,Cassius Wakiyo - KDB 323M,KDB 323M,automobile,KDB 323M,Probox,,Cassius Wakiyo,,0746428882,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,GT06E,2021-08-29,2026-02-24,,2041-08-29,2041-08-29,,89254021234222500818,639021232250081,, +359857082897737,John Makori - KDB 585E,KDB 585E,automobile,KDB 585E,Probox,,John Makori,,0114596734,,,,Dept: PLANNING,Default Group,PLANNING,fireside,Fireside Telematics ,GT06E,2021-08-29,2026-02-24,,2041-08-29,2041-08-29,,89254021214211145262,639021211114526,, +359857082911983,Brian Ngetich - KDA 717B,KDA 717B,automobile,KDA 717B,Probox,,Brian Ngetich,0795188807,0795188807,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,GT06E,2021-08-29,2026-02-24,,2041-08-29,2041-08-29,,89254021214211145288,639021211114528,, +359857082902461,Sadique Wakayula - KDC 490Q,KDC 490Q,truck,KDC 490Q,Crane,,Sadique Wakayula,,0757556468,,,,Dept: GENERAL,Default Group,GENERAL,fireside,Fireside Telematics ,GT06E,2021-05-22,2026-02-24,,2041-05-22,2041-05-22,,89254021154296722488,639021159672248,, +359857082902503,Felix Andole - KDC 207R,KDC 207R,automobile,KDC 207R,Probox,,Felix Andole,,0794820817,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,GT06E,2021-05-15,2026-02-24,,2041-05-15,2041-05-15,,89254021224270993254,639021227099325,, +359857082897794,Mutuku Joseph - KDC 739F,KDC 739F,automobile,KDC 739F,Probox,,Mutuku Joseph,0115019037,0115019037,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Telematics ,GT06E,2021-04-10,2026-02-24,,2041-04-10,2041-04-10,,89254021224222632356,639021222263235,, +359857082910589,Patric Bett - KDA 609E,KDA 609E,automobile,KDA 609E,Probox,,Patric Bett,,0797622637,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,GT06E,2020-10-26,2026-02-24,,2040-10-27,2040-10-27,,89254021154296722496,639021159672249,, +359857082918012,Charles Nyambane - KCB 711C,KCB 711C,automobile,KCB 711C,Probox,,Charles Nyambane,,0793704231,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,GT06E,2020-09-21,2026-02-24,,2040-09-22,2040-09-22,,89254021154287138363,639021158713836,, +359857081887069,Wright Oseko - KCG 668W,KCG 668W,automobile,KCG 668W,Probox,,Wright Oseko,,0746763106,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Telematics ,GT06E,2019-06-30,2026-02-24,,2039-07-01,2039-07-01,,89254021084186499915,639021088649991,, +359857081891590,Garage - KCE 699F,KCE 699F,automobile,KCE 699F,Probox,,Garage,,0746760215,,,,Dept: ROLLOUT,Default Group,ROLLOUT,fireside,Fireside Telematics ,GT06E,2019-06-16,2026-02-24,,2039-06-17,2039-06-17,,89254021084186499519,639021088649951,, +359857081891566,Simon Kamau - KCE 090R,KCE 090R,automobile,KCE 090R,Probox,,Simon Kamau,,0746760404,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,GT06E,2019-06-16,2026-02-24,,2039-06-17,2039-06-17,,89254021084186499527,639021088649952,, +359857081892101,Cornelius Kimutai - KCU 938R,KCU 938R,automobile,KCU 938R,Van,,Cornelius Kimutai,,0746759919,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Telematics ,GT06E,2019-06-12,2026-02-24,,2039-06-13,2039-06-13,,89254021084186499451,639021088649945,,2019-06-12 +359857081892309,Nicholas Erastus - KCQ 581M,KCQ 581M,automobile,KCQ 581M,Probox,,Nicholas Erastus,,0700023776,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Telematics ,GT06E,2019-06-09,2026-02-24,,2039-06-10,2039-06-10,,89254021084178504672,639021087850467,, +865135061563415,Barack Orwa - KDW 781E,KDW 781E,automobile,KDW 781E,Vazel,,Barack Orwa,,0758052541,,,,Dept: MGT,Default Group,MGT,fireside,Fireside Group MSA,X3,2026-01-13,2025-09-08,,2036-01-14,2036-01-14,,89254021414206816931,639021410681693,, +865135061035133,Major Simiyu - KDS 949Y,KDS 949Y,automobile,KDS 949Y,Probox,,Major Simiyu,,0768696642,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group MSA,X3,2025-08-02,2025-06-11,,2035-08-03,2035-08-03,,89254021394274518918,639021397451891,, +865135061043079,Mike Wanaswa - KDT 724R,KDT 724R,automobile,KDT 724R,Probox,,Mike Wanaswa,,0768696664,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,X3,2025-08-02,2025-06-11,,2035-08-03,2035-08-03,,89254021394274518959,639021397451895,, +865135061048953,Timothy Gitau - KDT 916R,KDT 916R,automobile,KDT 916R,Probox,,Timothy Gitau,,0768697056,,,,Dept: REGIONAL,Default Group,REGIONAL,fireside,Fireside Group MSA,X3,2025-08-02,2025-06-11,,2035-08-03,2035-08-03,,89254021394274518967,639021397451896,, +865135061048276,Victor Kimutai - KDS 919Y,KDS 919Y,automobile,KDS 919Y,Probox,,Victor Kimutai,,0768696755,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,X3,2025-08-02,2025-06-11,,2035-08-03,2035-08-03,,89254021394274518900,639021397451890,, +862798050526256,Ian Dancun - KDT 923R,KDT 923R,automobile,KDT 923R,Probox,,Ian Dancun,,0794873610,,,,Dept: QEHS,Default Group,QEHS,fireside,Fireside Group MSA,JC400P,2023-12-22,,,2043-12-22,2043-12-22,,,,, +862798050526165,Wilfred Kinyanjui - KCU 729C,KCU 729C,truck,KCU 729C,Crane,,Wilfred Kinyanjui,,0790564929,,,,Dept: GENERAL,Default Group,GENERAL,fireside,Fireside Group MSA,JC400P,2023-11-26,2024-11-08,,2033-11-27,2033-11-27,,,,, +359857082916826,Denis Kazungu - KDM 794R,KDM 794R,automobile,KDM 794R,Probox,,Denis Kazungu,,0705700971,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group MSA,GT06E,2023-08-21,2023-08-22,,2033-08-22,2033-08-22,,89254021324273006854,639021327300685,, +359857082898073,Mutuku Antony - KDK 732K,KDK 732K,automobile,KDK 732K,Probox,,Mutuku Antony,,0793026954,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group MSA,GT06E,2022-12-20,2022-12-20,,2042-12-21,2042-12-21,,89254021234222387539,639021232238753,, +862798050524681,Mutuku Antony - KDK 732K,KDK 732K,automobile,KDK 732K,Probox,,Mutuku Antony,,0796275746,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group MSA,JC400P,2022-12-06,2022-12-16,,2042-12-07,2042-12-07,,,,, +862798050524566,Makanda Andrew - KCZ 155P,KCZ 155P,automobile,KCZ 155P,Pick-Up,,Makanda Andrew,,0758781444,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,JC400P,2022-01-22,2025-02-24,,2042-01-23,2042-01-23,,,,, +862798050521612,Denis Kazungu - KDM 794R,KDM 794R,automobile,KDM 794R,Probox,,Denis Kazungu,,0704113731,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group MSA,JC400P,2022-01-22,2024-11-19,,2042-01-23,2042-01-23,,,,, +862798050522719,Mbuvi Kioko - KCZ 199P,KCZ 199P,automobile,KCZ 199P,Pick-Up,,Mbuvi Kioko,,0768218655,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,JC400P,2022-01-16,2022-12-16,,2042-01-17,2042-01-17,,,,, +862798050524087,Felix Muema - KCZ 223P,KCZ 223P,automobile,KCZ 223P,Pick-Up,,Felix Muema,,0113973875,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,JC400P,2022-01-16,2024-12-30,,2042-01-17,2042-01-17,,,,, +862798050522891,Lawrence Kijogi - KCY 080X,KCY 080X,automobile,KCY 080X,Pick-Up,,Lawrence Kijogi,,0113287191,,,,Dept: ROLLOUT,Default Group,ROLLOUT,fireside,Fireside Group MSA,JC400P,2022-01-16,2022-12-16,,2042-01-17,2042-01-17,,,,, +862798050524392,Ndegwa Dancun - KCG 669W,KCG 669W,automobile,KCG 669W,Probox,,Ndegwa Dancun,,0113799173,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,JC400P,2022-01-16,2022-12-16,,2042-01-17,2042-01-17,,,,, +862798050521752,Simon Munda - KCZ 154S,KCZ 154S,automobile,KCZ 154S,Probox,,Simon Munda,,0113805921,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,JC400P,2022-01-16,2022-12-16,,2042-01-17,2042-01-17,,,,, +862798050524012,Moses Wambua - KCZ 751V,KCZ 751V,automobile,KCZ 751V,Probox,,Moses Wambua,,0113313797,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,JC400P,2022-01-16,2022-12-16,,2042-01-17,2042-01-17,,,,, +862798050523204,Amani Kazungu - KCY 084X,KCY 084X,automobile,KCY 084X,Probox,,Amani Kazungu,,0707892547,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,JC400P,2022-01-16,2022-12-16,,2042-01-17,2042-01-17,,,,, +862798050523949,Joseph Kabandi - KCY 076X,KCY 076X,automobile,KCY 076X,Probox,,Joseph Kabandi,,0113288492,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,JC400P,2022-01-16,2022-12-16,,2042-01-17,2042-01-17,,,,, +862798050525613,Kennedy Chege - KCQ 618K,KCQ 618K,automobile,KCQ 618K,Probox,,Kennedy Chege,,0729994247,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,JC400P,2022-01-16,2022-12-19,,2042-01-17,2042-01-17,,,,, +862798050525753,Noel Merengeni - KCY 838X,KCY 838X,automobile,KCY 838X,Probox,,Noel Merengeni,,,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group MSA,JC400P,2022-01-15,2023-08-23,,2042-01-16,2042-01-16,,,,, +359857082925330,Noel Merengeni - KCY 838X,KCY 838X,automobile,KCY 838X,Probox,,Noel Merengeni,,0794873610,,,,Dept: FDS,Default Group,FDS,fireside,Fireside Group MSA,GT06E,2020-10-26,2023-08-22,,2040-10-27,2040-10-27,,89254021154296723429,639021159672342,, +359857082900341,Simon Munda - KCZ 154S,KCZ 154S,automobile,KCZ 154S,Probox,,Simon Munda,,0757236135,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,GT06E,2020-09-23,2022-12-16,,2040-09-24,2040-09-24,,89254021154296723312,639021159672331,, +359857082912486,Moses Wambua - KCZ 751V,KCZ 751V,automobile,KCZ 751V,Probox,,Moses Wambua,,0792756503,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,GT06E,2020-09-23,2022-12-16,,2040-09-24,2040-09-24,,89254021154296723437,639021159672343,, +353549090553685,Daniel Omondi - KMFF 099Z,KMFF 099Z,mtc,KMFF 099Z,Motorbike,,Daniel Omondi,0112794067,0759336150,,,,Dept: OSP-PATROL,Default Group,OSP-PATROL,fireside,Fireside Group MSA,AT4,2020-09-23,2022-12-16,,2040-09-24,2040-09-24,,89254021334258404099,639021335840409,, +353549090567685,Daniel Kipkirui - KMFF 162Z,KMFF 162Z,mtc,KMFF 162Z,Motorbike,,Daniel Kipkirui,0112795498,0742532058,,,,Dept: OSP-PATROL,Default Group,OSP-PATROL,fireside,Fireside Group MSA,AT4,2020-09-23,2022-12-16,,2040-09-24,2040-09-24,,89254021264260388966,639021266038896,, +359857082910886,Makanda Andrew - KCZ 155P,KCZ 155P,automobile,KCZ 155P,Pick-Up,,Makanda Andrew,,0745067338,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,GT06E,2020-08-23,2025-02-24,,2040-08-24,2040-08-24,,89254021154287138397,639021158713839,, +359857082908500,Santoes Omondi - KCZ 181P,KCZ 181P,automobile,KCZ 181P,Pick-Up,,Santoes Omondi,,0701211974,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,GT06E,2020-08-23,2022-12-16,,2040-08-24,2040-08-24,,89254021374215155087,639021371515508,, +359857082918038,Mbuvi Kioko - KCC 199P,KCC 199P,automobile,KCC 199P,Pick-Up,,Mbuvi Kioko,,0797318126,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,GT06E,2020-08-22,2022-12-16,,2040-08-23,2040-08-23,,89254021154287138389,639021158713838,, +359857082907973,Felix Muema - KCZ 223P,KCZ 223P,automobile,KCZ 223P,Probox,,Felix Muema,,0757843826,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,GT06E,2020-08-22,2024-12-30,,2040-08-23,2040-08-23,,89254021154287138371,639021158713837,, +359857082042854,Elias Baya - KCZ 476E,KCZ 476E,automobile,KCZ 476E,Probox,,Elias Baya,,0110941187,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,GT06E,2020-08-09,2022-12-16,,2040-08-10,2040-08-10,,89254021164224352993,639021162435299,, +359857082044280,Lawrence Kijogi - KCY 080X,KCY 080X,automobile,KCY 080X,Probox,,Lawrence Kijogi,,0708155933,,,,Dept: ROLLOUT,Default Group,ROLLOUT,fireside,Fireside Group MSA,GT06E,2020-07-13,2022-12-16,,2040-07-13,2040-07-13,,89254029851005131222,639029850513122,, +359857082037185,Amani Kazungu - KCY 084X,KCY 084X,automobile,KCY 084X,Probox,,Amani Kazungu,,0757338522,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,GT06E,2020-07-13,2022-12-16,,2040-07-14,2040-07-14,,89254021154287000597,639021158700059,, +359857082046145,Joseph Kabandi - KCY 076X,KCY 076X,automobile,KCY 076X,Probox,,Joseph Kabandi,,0110850007,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,GT06E,2020-07-13,2022-12-16,,2040-07-14,2040-07-14,,89254021164223447158,639021162344715,, +359857082040981,Amani Sulubu - KCY 090X,KCY 090X,automobile,KCY 090X,Probox,,Amani Sulubu,,0793375853,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,GT06E,2020-07-13,2022-12-16,,2040-07-14,2040-07-14,,89254021064168004164,639021066800416,, +359857082038977,Wilfred Kinyanjui - KCU 729C,KCU 729C,truck,KCU 729C,Crane,,Wilfred Kinyanjui,,0110094469,,,,Dept: GENERAL,Default Group,GENERAL,fireside,Fireside Group MSA,GT06E,2020-04-05,2022-12-16,,2040-04-06,2040-04-06,,89254021164215938057,639021161593805,, +359857081886467,Gideon Kiprono - KCQ 215F,KCQ 215F,automobile,KCQ 215F,Probox,,Gideon Kiprono,,0746763076,,,,Dept: ISP,Default Group,ISP,fireside,Fireside Group MSA,GT06E,2019-06-30,2022-12-16,,2039-07-01,2039-07-01,,89254021084186499865,639021088649986,, +359857081886905,Kennedy Chege - KCQ 618K,KCQ 618K,automobile,KCQ 618K,Probox,,Kennedy Chege,,0746763132,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,GT06E,2019-06-30,2022-12-16,,2039-07-01,2039-07-01,,89254021084186499923,639021088649992,, +359857081887192,Ndegwa Dancun - KCG 669W,KCG 669W,automobile,KCG 669W,Probox,,Ndegwa Dancun,,0746760191,,,,Dept: OSP,Default Group,OSP,fireside,Fireside Group MSA,GT06E,2019-06-15,2022-12-16,,2039-06-16,2039-06-16,,89254021084186499501,639021088649950,, diff --git a/new_feature.txt b/new_feature.txt new file mode 100644 index 0000000..8f5209c --- /dev/null +++ b/new_feature.txt @@ -0,0 +1,5 @@ + What I'd skip (for now) + + - ML/forecasting sections until 6+ months of trip data exist — with 3 recorded trips, anything is noise. + - Temperature, fuel-theft, OBD-RPM queries — already gated behind webhook registration in §8; duplicating them in §3 just adds clutter. + - Route-optimisation queries — that's a separate product, not an analytics-doc addition. \ No newline at end of file diff --git a/push_webhook.md b/push_webhook.md new file mode 100644 index 0000000..e69de29 diff --git a/tracksolid_analytics_pipeline.txt b/tracksolid_analytics_pipeline.txt new file mode 100644 index 0000000..ccc1af2 --- /dev/null +++ b/tracksolid_analytics_pipeline.txt @@ -0,0 +1,377 @@ +pgcli "postgres://postgres:U1pm3f5SX34DXkHoW6aKFsBHOlMA9binDPNG4aT0FAcg7AubEvYm0e6kU2dZiYrR@stage.rahamafresh.com:5433/tracksolid_db" + +postgresql://postgres:U1pm3f5SX34DXkHoW6aKFsBHOlMA9binDPNG4aT0FAcg7AubEvYm0e6kU2dZiYrR@timescale_db-bo3nov2ija7g8wn9b1g2paxs-104717464280:5432/tracksolid_db + +---- CURRENT LIVE POSITIONS ------- All devices with a position in the last hour ---- +SELECT + d.device_name, + d.mc_type, + ROUND(lp.lat::numeric, 5) AS lat, + ROUND(lp.lng::numeric, 5) AS lng, + lp.speed, + lp.acc_status, + lp.gps_signal, + lp.gps_num AS satellites, + lp.gps_time AT TIME ZONE 'Africa/Nairobi' AS last_fix_eat, + ROUND(EXTRACT(EPOCH FROM (now() - lp.gps_time)) / 60.0, 0) AS mins_ago + FROM tracksolid.live_positions lp + JOIN tracksolid.devices d ON d.imei = lp.imei + WHERE lp.gps_time > now() - interval '1 hour' + ORDER BY lp.gps_time DESC; + +----- All 19 live positions — current snapshot ---- + +SELECT + d.device_name, + d.mc_type, + ROUND(lp.lat::numeric, 5) AS lat, + ROUND(lp.lng::numeric, 5) AS lng, + lp.speed, + lp.acc_status, + lp.gps_time AT TIME ZONE 'Africa/Nairobi' AS last_fix_eat, + ROUND(EXTRACT(EPOCH FROM (now() - lp.gps_time)) / 3600.0, 1) AS hours_ago, + lp.current_mileage AS odometer_km +FROM tracksolid.live_positions lp +JOIN tracksolid.devices d ON d.imei = lp.imei +ORDER BY lp.gps_time DESC; + +-------- Devices with no position (silent fleet) ----- + +SELECT d.imei, d.device_name, d.mc_type, d.sim, d.expiration::date +FROM tracksolid.devices d +LEFT JOIN tracksolid.live_positions lp ON lp.imei = d.imei +WHERE lp.imei IS NULL +ORDER BY d.mc_type, d.device_name; + +---- Vehicles currently moving (ACC on OR speed > 0) + +SELECT + d.device_name, + lp.speed, + lp.acc_status, + lp.gps_time AT TIME ZONE 'Africa/Nairobi' AS last_fix_eat +FROM tracksolid.live_positions lp +JOIN tracksolid.devices d ON d.imei = lp.imei +WHERE lp.speed > 0 OR lp.acc_status = '1' +ORDER BY lp.speed DESC; + +---- Vehicles in Uganda ----- + +SELECT + d.device_name, + ROUND(lp.lat::numeric, 4) AS lat, + ROUND(lp.lng::numeric, 4) AS lng, + lp.gps_time AT TIME ZONE 'Africa/Nairobi' AS last_fix_eat +FROM tracksolid.live_positions lp +JOIN tracksolid.devices d ON d.imei = lp.imei +WHERE lp.lat NOT BETWEEN -5.0 AND 5.0 + OR lp.lng NOT BETWEEN 33.9 AND 42.0; + +---- Vehicles in Kenya ----- + +SELECT + d.device_name, + ROUND(lp.lat::numeric, 4) AS lat, + ROUND(lp.lng::numeric, 4) AS lng, + lp.gps_time AT TIME ZONE 'Africa/Nairobi' AS last_fix_eat +FROM tracksolid.live_positions lp +JOIN tracksolid.devices d ON d.imei = lp.imei +WHERE lp.lat BETWEEN -5.0 AND 5.0 + OR lp.lng BETWEEN 33.9 AND 42.0; + + +========== TRIPS AND MOVEMENT ====== + +SELECT + d.device_name, + d.vehicle_number, + d.driver_name, + COUNT(*) AS trips, + ROUND(SUM(t.distance_km)::numeric, 2) AS total_km, + ROUND(AVG(t.avg_speed_kmh)::numeric, 1) AS avg_speed_kmh, + MAX(t.max_speed_kmh) AS top_speed_kmh, + ROUND(SUM(t.driving_time_s) / 3600.0, 2) AS drive_hours, + ROUND(SUM(t.idle_time_s) / 3600.0, 2) AS idle_hours, + MIN(t.start_time AT TIME ZONE 'Africa/Nairobi') AS day_start, + MAX(t.end_time AT TIME ZONE 'Africa/Nairobi') AS day_end +FROM tracksolid.trips t +JOIN tracksolid.devices d ON d.imei = t.imei +WHERE t.start_time >= CURRENT_DATE AT TIME ZONE 'Africa/Nairobi' +GROUP BY d.device_name, d.vehicle_number, d.driver_name +ORDER BY total_km DESC; + +------ trips summary LAST 24 HOURS per vehicle ------- + +SELECT + d.device_name, + t.start_time AT TIME ZONE 'Africa/Nairobi' AS start_eat, + t.end_time AT TIME ZONE 'Africa/Nairobi' AS end_eat, + ROUND(t.distance_km::numeric / 1000.0, 2) AS distance_km, + t.avg_speed_kmh, + t.max_speed_kmh, + ROUND(t.driving_time_s / 60.0, 0) AS drive_mins, + ROUND(t.idle_time_s / 60.0, 0) AS idle_mins, + t.source + FROM tracksolid.trips t + JOIN tracksolid.devices d ON d.imei = t.imei + WHERE t.start_time > now() - interval '24 hours' + ORDER BY t.start_time DESC; + +------- Fleet utilisation rate per vehicle (today) + +SELECT + d.device_name, + d.driver_name, + ROUND(SUM(t.driving_time_s) / 3600.0, 2) AS drive_hours, + ROUND(SUM(t.idle_time_s) / 3600.0, 2) AS idle_hours, + LEAST(ROUND(SUM(t.driving_time_s + COALESCE(t.idle_time_s, 0)) / (12.0 * 3600) * 100, 1), 100) AS utilisation_pct + FROM tracksolid.trips t + JOIN tracksolid.devices d ON d.imei = t.imei + WHERE t.start_time >= CURRENT_DATE AT TIME ZONE 'Africa/Nairobi' + GROUP BY d.device_name, d.driver_name + ORDER BY utilisation_pct DESC; + + KDK 829A GP | | 1.87 | | 15.5 + FRED KMGW 538W HULETI | | 1.65 | | 13.7 + X3-63282 | | 1.25 | | 10.4 + +-----Tracking to this point of the day ---- + + SELECT + d.device_name, + d.driver_name, + ROUND(SUM(t.driving_time_s) / 3600.0, 2) AS drive_hours, + ROUND(SUM(t.idle_time_s) / 3600.0, 2) AS idle_hours, + LEAST(ROUND( + SUM(t.driving_time_s + COALESCE(t.idle_time_s, 0)) + / (EXTRACT(EPOCH FROM ( + LEAST(now(), CURRENT_DATE::timestamp AT TIME ZONE 'Africa/Nairobi' + interval '19 hours 30 minutes') + - (CURRENT_DATE::timestamp AT TIME ZONE 'Africa/Nairobi' + interval '7 hours 30 minutes') + ))) * 100 + , 1), 100) AS utilisation_pct_so_far + FROM tracksolid.trips t + JOIN tracksolid.devices d ON d.imei = t.imei + WHERE t.start_time >= (CURRENT_DATE::timestamp AT TIME ZONE 'Africa/Nairobi' + interval '7 hours 30 minutes') + GROUP BY d.device_name, d.driver_name + ORDER BY utilisation_pct_so_far DESC; + + + ------ Vehicles that have not moved today ------- + +SELECT d.device_name, d.mc_type, d.driver_name +FROM tracksolid.devices d +LEFT JOIN tracksolid.trips t + ON t.imei = d.imei + AND t.start_time >= CURRENT_DATE AT TIME ZONE 'Africa/Nairobi' +WHERE t.imei IS NULL +ORDER BY d.device_name; + +------ Distance per driver — last 30 days + +SELECT + d.device_name, + d.driver_name, + COUNT(DISTINCT DATE(t.start_time AT TIME ZONE 'Africa/Nairobi')) AS active_days, + COUNT(*) AS total_trips, + ROUND(SUM(t.distance_km / 1000.0)::numeric, 0) AS total_km, + ROUND(AVG(t.distance_km / 1000.0)::numeric, 1) AS avg_km_per_trip, + MAX(t.max_speed_kmh) AS top_speed_ever + FROM tracksolid.trips t + JOIN tracksolid.devices d ON d.imei = t.imei + WHERE t.start_time > now() - interval '30 days' + GROUP BY d.device_name, d.driver_name + ORDER BY total_km DESC; + + + ====== ALL ALARMS ===== + + ----Alarms in 24 hours ---- + + SELECT + d.device_name, + a.alarm_type, + a.alarm_name, + a.alarm_time AT TIME ZONE 'Africa/Nairobi' AS alarm_time_eat, + ROUND(a.lat::numeric, 5) AS lat, + ROUND(a.lng::numeric, 5) AS lng, + a.speed, + a.severity, + a.acknowledged_at +FROM tracksolid.alarms a +JOIN tracksolid.devices d ON d.imei = a.imei +WHERE a.alarm_time > now() - interval '24 hours' +ORDER BY a.alarm_time DESC; + +----Alarms in 7 Days ---- +SELECT + a.alarm_name, + a.alarm_type, + COUNT(*) AS occurrences, + COUNT(DISTINCT a.imei) AS devices_affected, + MAX(a.alarm_time AT TIME ZONE 'Africa/Nairobi') AS last_seen_eat +FROM tracksolid.alarms a +WHERE a.alarm_time > now() - interval '7 days' +GROUP BY a.alarm_name, a.alarm_type +ORDER BY occurrences DESC; + +------ unacknowledged alarms ------ + +SELECT + d.device_name, + a.alarm_name, + a.alarm_time AT TIME ZONE 'Africa/Nairobi' AS alarm_time_eat, + ROUND(EXTRACT(EPOCH FROM (now() - a.alarm_time)) / 3600.0, 1) AS hours_open +FROM tracksolid.alarms a +JOIN tracksolid.devices d ON d.imei = a.imei +WHERE a.acknowledged_at IS NULL +ORDER BY a.alarm_time DESC; + +------ acknowledged alarms ------ + +UPDATE tracksolid.alarms +SET acknowledged_at = now(), + acknowledged_by = 'operator_name' +WHERE id = ; + +=========== + +------ Position history by source — counts ---- + +SELECT + source, + COUNT(*) AS fixes, + MIN(gps_time AT TIME ZONE 'Africa/Nairobi') AS earliest, + MAX(gps_time AT TIME ZONE 'Africa/Nairobi') AS latest +FROM tracksolid.position_history +GROUP BY source; + +--------- Route replay for a specific vehicle — last 24 hours + +device = name <'FRED KMGW 538W HULETI'> + +SELECT + ph.gps_time AT TIME ZONE 'Africa/Nairobi' AS gps_time_eat, + ROUND(ph.lat::numeric, 5) AS lat, + ROUND(ph.lng::numeric, 5) AS lng, + ph.speed, + ph.direction, + ph.acc_status, + ph.source +FROM tracksolid.position_history ph +JOIN tracksolid.devices d ON d.imei = ph.imei +WHERE d.device_name = <'FRED KMGW 538W HULETI'> + AND ph.gps_time > now() - interval '24 hours' +ORDER BY ph.gps_time ASC; + + +-------- Fix density per device — last 24 hours --------- + +SELECT + d.device_name, + COUNT(*) AS total_fixes, + COUNT(*) FILTER (WHERE ph.source = 'poll') AS poll_fixes, + COUNT(*) FILTER (WHERE ph.source = 'track_list') AS track_list_fixes, + MIN(ph.gps_time AT TIME ZONE 'Africa/Nairobi') AS first_fix, + MAX(ph.gps_time AT TIME ZONE 'Africa/Nairobi') AS last_fix +FROM tracksolid.position_history ph +JOIN tracksolid.devices d ON d.imei = ph.imei +WHERE ph.gps_time > now() - interval '24 hours' +GROUP BY d.device_name +ORDER BY total_fixes DESC; + +### Device & Fleet Registry + +-------- Full fleet — all 63 devices ------ + +SELECT + device_name, + mc_type, + vehicle_number, + driver_name, + sim, + ROUND(current_mileage_km::numeric, 0) AS odometer_km, + expiration::date AS expires, + enabled_flag +FROM tracksolid.devices +ORDER BY mc_type, device_name; + +-------- Fleet by devices model ------ + +SELECT mc_type, COUNT(*) AS devices +FROM tracksolid.devices +GROUP BY mc_type ORDER BY devices DESC; + + +------ fleet by odometer readings ----- + +SELECT + device_name, + mc_type, + sim, + ROUND(current_mileage_km::numeric, 0) AS odometer_km, + expiration::date AS expires +FROM tracksolid.devices +WHERE current_mileage_km IS NOT NULL AND current_mileage_km > 0 +ORDER BY current_mileage_km DESC +LIMIT 15; + +---- fleet blank driver sim vehicle number blanks ---- + +SELECT device_name, mc_type, sim +FROM tracksolid.devices +WHERE vehicle_number IS NULL OR vehicle_number = '' + OR driver_name IS NULL OR driver_name = '' +ORDER BY mc_type, device_name; + +----- fleet by expiry dates --- + +SELECT + COUNT(*) FILTER (WHERE expiration IS NULL) AS no_expiry_set, + COUNT(*) FILTER (WHERE expiration < now()) AS already_expired, + COUNT(*) FILTER (WHERE expiration BETWEEN now() AND now() + interval '90 days') AS expiring_90days, + COUNT(*) FILTER (WHERE expiration > now() + interval '90 days') AS valid_long_term +FROM tracksolid.devices; + + +-----no of rows in db ----- + +SELECT + (SELECT COUNT(*) FROM tracksolid.devices) AS devices, + (SELECT COUNT(*) FROM tracksolid.live_positions) AS live_positions, + (SELECT COUNT(*) FROM tracksolid.position_history) AS position_history, + (SELECT COUNT(*) FROM tracksolid.trips) AS trips, + (SELECT COUNT(*) FROM tracksolid.alarms) AS alarms, + (SELECT COUNT(*) FROM tracksolid.parking_events) AS parking_events, + (SELECT COUNT(*) FROM tracksolid.obd_readings) AS obd_readings, + (SELECT COUNT(*) FROM tracksolid.device_events) AS device_events, + (SELECT COUNT(*) FROM tracksolid.fuel_readings) AS fuel_readings, + (SELECT COUNT(*) FROM tracksolid.temperature_readings) AS temperature_readings, + (SELECT COUNT(*) FROM tracksolid.lbs_readings) AS lbs_readings, + (SELECT COUNT(*) FROM tracksolid.ingestion_log) AS ingestion_log; + +===== + + SELECT 'devices' AS table_name, COUNT(*) FROM tracksolid.devices + UNION ALL + SELECT 'live_positions', COUNT(*) FROM tracksolid.live_positions + UNION ALL + SELECT 'position_history', COUNT(*) FROM tracksolid.position_history + UNION ALL + SELECT 'trips', COUNT(*) FROM tracksolid.trips + UNION ALL + SELECT 'alarms', COUNT(*) FROM tracksolid.alarms + UNION ALL + SELECT 'parking_events', COUNT(*) FROM tracksolid.parking_events + UNION ALL + SELECT 'obd_readings', COUNT(*) FROM tracksolid.obd_readings + UNION ALL + SELECT 'device_events', COUNT(*) FROM tracksolid.device_events + UNION ALL + SELECT 'fuel_readings', COUNT(*) FROM tracksolid.fuel_readings + UNION ALL + SELECT 'temperature_readings', COUNT(*) FROM tracksolid.temperature_readings + UNION ALL + SELECT 'lbs_readings', COUNT(*) FROM tracksolid.lbs_readings + UNION ALL + SELECT 'ingestion_log', COUNT(*) FROM tracksolid.ingestion_log + ORDER BY table_name; \ No newline at end of file diff --git a/tracksolid_extract.py b/tracksolid_extract.py new file mode 100644 index 0000000..598e237 --- /dev/null +++ b/tracksolid_extract.py @@ -0,0 +1,297 @@ +#!/usr/bin/env python3 +""" +Tracksolid Pro - Device List Extractor +Calls jimi.user.device.list and saves all vehicle/device data to CSV and JSON. + +Uses the same signing approach as tracksolid_update.py (confirmed working): + - POST as x-www-form-urlencoded + - All parameter values cast to strings before signing + +Usage: + python3 tracksolid_extract.py + python3 tracksolid_extract.py --target "Fireside Communications" + python3 tracksolid_extract.py --format json + python3 tracksolid_extract.py --format both + +Environment variables (same .env file as tracksolid_update.py): + TS_USER_ID - Your Tracksolid account username + TS_USER_PWD_MD5 - MD5 hash of your password (lowercase) + TS_APP_KEY - Your appKey from JIMI + TS_APP_SECRET - Your appSecret from JIMI + TS_API_URL - API base URL (defaults to EU node) + TS_TARGET - Account to query (defaults to TS_USER_ID) +""" + +import hashlib +import os +import sys +import json +import logging +import argparse +import time +from datetime import datetime, timezone +from pathlib import Path + +import requests +import pandas as pd + +# ────────────────────────────────────────────────────────────────────────────── +# CONFIGURATION — reads from environment / same .env as the updater +# ────────────────────────────────────────────────────────────────────────────── +CONFIG = { + "user_id": os.getenv("TS_USER_ID", "Fireside Communications"), + "user_pwd_md5": os.getenv("TS_USER_PWD_MD5", "81a1b005efd3596073e38efd8a2fd3fd"), + "app_key": os.getenv("TS_APP_KEY", "8FB345B8693CCD00BB70D528C0D4019E"), + "app_secret": os.getenv("TS_APP_SECRET", "3177c89993b446c6aced0d7c56375d2c"), + "api_url": os.getenv("TS_API_URL", "https://eu-open.tracksolidpro.com/route/rest"), + "target": os.getenv("TS_TARGET", ""), # account to query; defaults to user_id + "expires_in": "7200", +} + +# ────────────────────────────────────────────────────────────────────────────── +# LOGGING +# ────────────────────────────────────────────────────────────────────────────── +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(levelname)-8s %(message)s", + handlers=[ + logging.StreamHandler(sys.stdout), + logging.FileHandler("tracksolid_extract.log", encoding="utf-8"), + ], +) +log = logging.getLogger(__name__) + + +# ────────────────────────────────────────────────────────────────────────────── +# SIGNING UTILITIES (identical to tracksolid_update.py) +# ────────────────────────────────────────────────────────────────────────────── + +def utc_timestamp() -> str: + return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S") + + +def build_sign(params: dict, app_secret: str) -> str: + sorted_keys = sorted( + k for k in params + if k != "sign" and params[k] is not None and str(params[k]).strip() != "" + ) + param_string = "".join(f"{k}{params[k]}" for k in sorted_keys) + raw_string = f"{app_secret}{param_string}{app_secret}" + return hashlib.md5(raw_string.encode("utf-8")).hexdigest().upper() + + +# ────────────────────────────────────────────────────────────────────────────── +# TRACKSOLID CLIENT +# ────────────────────────────────────────────────────────────────────────────── + +class TracksolidClient: + def __init__(self, cfg: dict): + self.cfg = cfg + self._token: str | None = None + self._token_expires_at: float = 0.0 + self.session = requests.Session() + + def _post(self, params: dict) -> dict: + str_params = { + k: str(v) + for k, v in params.items() + if v is not None and str(v).strip() != "" + } + str_params["sign"] = build_sign(str_params, self.cfg["app_secret"]) + + log.debug("POST %s params=%s", self.cfg["api_url"], str_params) + resp = self.session.post( + self.cfg["api_url"], + data=str_params, # form-encoded — confirmed working + timeout=30, + ) + resp.raise_for_status() + data = resp.json() + log.debug("Response: %s", json.dumps(data)) + return data + + def _common_params(self, method: str) -> dict: + return { + "method": method, + "timestamp": utc_timestamp(), + "app_key": self.cfg["app_key"], + "sign_method": "md5", + "v": "1.0", + "format": "json", + } + + def get_token(self) -> str: + if self._token and time.time() < self._token_expires_at - 60: + return self._token + + log.info("Obtaining access token ...") + params = self._common_params("jimi.oauth.token.get") + params.update({ + "user_id": self.cfg["user_id"], + "user_pwd_md5": self.cfg["user_pwd_md5"], + "expires_in": self.cfg["expires_in"], + }) + + data = self._post(params) + if data.get("code") != 0: + raise RuntimeError( + f"Auth failed — code={data.get('code')} message={data.get('message')}" + ) + + self._token = data["result"]["accessToken"] + self._token_expires_at = time.time() + int(data["result"]["expiresIn"]) + log.info("Token acquired. Valid for %s seconds.", data["result"]["expiresIn"]) + return self._token + + def get_device_list(self, target: str) -> list[dict]: + """ + Call jimi.user.device.list for the given target account. + Returns the full list of device/vehicle records. + """ + log.info("Fetching device list for account: %s", target) + token = self.get_token() + + params = self._common_params("jimi.user.device.list") + params["access_token"] = token + params["target"] = target + + data = self._post(params) + + if data.get("code") != 0: + raise RuntimeError( + f"Device list failed — code={data.get('code')} message={data.get('message')}" + ) + + devices = data.get("result", []) + log.info("Retrieved %d devices.", len(devices)) + return devices + + +# ────────────────────────────────────────────────────────────────────────────── +# OUTPUT HELPERS +# ────────────────────────────────────────────────────────────────────────────── + +# Friendly column names for the CSV output +COLUMN_RENAME = { + "imei": "IMEI", + "deviceName": "Device Name", + "mcType": "Model", + "mcTypeUseScope": "Vehicle Type", + "sim": "SIM", + "expiration": "Platform Expiry", + "activationTime": "Activated", + "reMark": "Remarks", + "vehicleName": "Vehicle Name", + "vehicleIcon": "Icon", + "vehicleNumber": "License Plate", + "vehicleModels": "Vehicle Model", + "carFrame": "VIN", + "driverName": "Driver Name", + "driverPhone": "Driver Phone", + "enabledFlag": "Active", + "engineNumber": "Engine Number", + "deviceGroupId": "Group ID", + "deviceGroup": "Group", +} + +def save_csv(devices: list[dict], path: str): + df = pd.DataFrame(devices) + df.rename(columns=COLUMN_RENAME, inplace=True) + # Put the most useful columns first + priority = ["IMEI", "License Plate", "Driver Name", "Driver Phone", + "Device Name", "Vehicle Model", "Vehicle Type", "Group", + "SIM", "Platform Expiry", "Activated", "Active", + "VIN", "Engine Number", "Remarks"] + ordered = [c for c in priority if c in df.columns] + rest = [c for c in df.columns if c not in ordered] + df = df[ordered + rest] + df.to_csv(path, index=False) + log.info("CSV saved → %s (%d rows, %d columns)", path, len(df), len(df.columns)) + + +def save_json(devices: list[dict], path: str): + with open(path, "w", encoding="utf-8") as f: + json.dump(devices, f, indent=2, ensure_ascii=False) + log.info("JSON saved → %s (%d records)", path, len(devices)) + + +def print_summary(devices: list[dict]): + df = pd.DataFrame(devices) + total = len(df) + active = df["enabledFlag"].eq(1).sum() if "enabledFlag" in df.columns else "?" + groups = df["deviceGroup"].nunique() if "deviceGroup" in df.columns else "?" + with_plate = df["vehicleNumber"].notna().sum() if "vehicleNumber" in df.columns else "?" + with_driver = df["driverName"].notna().sum() if "driverName" in df.columns else "?" + + print() + print("=" * 50) + print(" DEVICE LIST SUMMARY") + print("=" * 50) + print(f" Total devices : {total}") + print(f" Active : {active}") + print(f" Device groups : {groups}") + print(f" With plate no. : {with_plate}") + print(f" With driver name : {with_driver}") + print("=" * 50) + + if "deviceGroup" in df.columns: + print("\n Breakdown by group:") + for group, count in df["deviceGroup"].value_counts().items(): + print(f" {group:<25} {count} devices") + print() + + +# ────────────────────────────────────────────────────────────────────────────── +# MAIN +# ────────────────────────────────────────────────────────────────────────────── + +def main(): + parser = argparse.ArgumentParser( + description="Extract Tracksolid device list to CSV / JSON." + ) + parser.add_argument( + "--target", default="", + help="Account to query (default: same as TS_USER_ID / user_id in CONFIG)." + ) + parser.add_argument( + "--format", choices=["csv", "json", "both"], default="csv", + help="Output format (default: csv)." + ) + parser.add_argument( + "--out", default="", + help="Output filename without extension (default: tracksolid_devices_YYYYMMDD_HHMMSS)." + ) + args = parser.parse_args() + + # Resolve target account + target = args.target or CONFIG["target"] or CONFIG["user_id"] + + # Resolve output filename base + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + out_base = args.out or f"tracksolid_devices_{timestamp}" + + # ── Fetch ────────────────────────────────────────────────────────────────── + client = TracksolidClient(CONFIG) + try: + devices = client.get_device_list(target) + except Exception as exc: + log.error("Failed to fetch device list: %s", exc) + sys.exit(1) + + if not devices: + log.warning("No devices returned for account: %s", target) + sys.exit(0) + + # ── Save ─────────────────────────────────────────────────────────────────── + if args.format in ("csv", "both"): + save_csv(devices, f"{out_base}.csv") + + if args.format in ("json", "both"): + save_json(devices, f"{out_base}.json") + + # ── Summary ──────────────────────────────────────────────────────────────── + print_summary(devices) + + +if __name__ == "__main__": + main() diff --git a/tracksolid_ingestion_pipeline.txt b/tracksolid_ingestion_pipeline.txt new file mode 100644 index 0000000..dfdeece --- /dev/null +++ b/tracksolid_ingestion_pipeline.txt @@ -0,0 +1,56 @@ +### Pipeline health — last hour (key check) + +SELECT + endpoint, + COUNT(*) AS calls, + SUM(rows_upserted) AS upserted, + SUM(rows_inserted) AS inserted, + ROUND(AVG(duration_ms)::numeric, 0) AS avg_ms, + COUNT(*) FILTER (WHERE success = false) AS failures, + MAX(run_at AT TIME ZONE 'Africa/Nairobi') AS last_call_eat +FROM tracksolid.ingestion_log +WHERE run_at > now() - interval '1 hour' +GROUP BY endpoint +ORDER BY calls DESC; + +-------- Ingestion Pipeline Health + +SELECT + endpoint, + COUNT(*) AS total_calls, + SUM(rows_upserted) AS total_upserted, + SUM(rows_inserted) AS total_inserted, + ROUND(AVG(duration_ms)::numeric, 0) AS avg_ms, + COUNT(*) FILTER (WHERE success = false) AS failures, + MIN(run_at AT TIME ZONE 'Africa/Nairobi') AS first_call, + MAX(run_at AT TIME ZONE 'Africa/Nairobi') AS last_call +FROM tracksolid.ingestion_log +GROUP BY endpoint +ORDER BY total_calls DESC; + +### Recent calls — last 20 entries + +SELECT + run_at AT TIME ZONE 'Africa/Nairobi' AS run_eat, + endpoint, + imei_count, + rows_upserted, + rows_inserted, + duration_ms, + success, + error_message +FROM tracksolid.ingestion_log +ORDER BY run_at DESC +LIMIT 20; + +### Recent calls — FAILED CALLS entries + +SELECT + run_at AT TIME ZONE 'Africa/Nairobi' AS run_eat, + endpoint, + error_code, + error_message +FROM tracksolid.ingestion_log +WHERE success = false +ORDER BY run_at DESC; + diff --git a/tracksolid_update_v2.py b/tracksolid_update_v2.py new file mode 100644 index 0000000..4021fc8 --- /dev/null +++ b/tracksolid_update_v2.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 +""" +Tracksolid Pro - Bulk Vehicle Information Updater +Updates vehicle details via the jimi.open.device.update API endpoint +using data from the Fireside logistics CSV. + +Signing approach taken directly from tspostman.py (confirmed working): + - POST as x-www-form-urlencoded (NOT JSON) + - All parameter values cast to strings before signing + - expires_in passed as string '7200', not integer + +Usage: + python tracksolid_update.py [--dry-run] [--csv path/to/file.csv] [--limit N] + +Environment variables (or edit CONFIG below): + TS_USER_ID - Your Tracksolid account username + TS_USER_PWD_MD5 - MD5 hash of your password (lowercase) + TS_APP_KEY - Your appKey from JIMI + TS_APP_SECRET - Your appSecret from JIMI + TS_API_URL - API base URL (defaults to EU node) + TS_CSV_PATH - Path to the logistics CSV +""" + +import hashlib +import time +import json +import logging +import argparse +import os +import sys +from datetime import datetime, timezone +from pathlib import Path + +import requests +import pandas as pd + +# ────────────────────────────────────────────────────────────────────────────── +# CONFIGURATION — edit here or set environment variables +# ────────────────────────────────────────────────────────────────────────────── +CONFIG = { + "user_id": os.getenv("TS_USER_ID", "Fireside Communications"), + "user_pwd_md5": os.getenv("TS_USER_PWD_MD5", "81a1b005efd3596073e38efd8a2fd3fd"), + "app_key": os.getenv("TS_APP_KEY", "8FB345B8693CCD00BB70D528C0D4019E"), + "app_secret": os.getenv("TS_APP_SECRET", "3177c89993b446c6aced0d7c56375d2c"), + # EU node confirmed for this account + "api_url": os.getenv("TS_API_URL", "https://eu-open.tracksolidpro.com/route/rest"), + "expires_in": "7200", # string, not int — matches tspostman.py + "request_delay": 0.5, # seconds between API calls +} + +CSV_PATH = os.getenv("TS_CSV_PATH", "20260414_FS__Logistics_-_final_fixed.csv") + +# ────────────────────────────────────────────────────────────────────────────── +# LOGGING +# ────────────────────────────────────────────────────────────────────────────── +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(levelname)-8s %(message)s", + handlers=[ + logging.StreamHandler(sys.stdout), + logging.FileHandler("tracksolid_update.log", encoding="utf-8"), + ], +) +log = logging.getLogger(__name__) + + +# ────────────────────────────────────────────────────────────────────────────── +# SIGNING UTILITIES (ported directly from tspostman.py) +# ────────────────────────────────────────────────────────────────────────────── + +def utc_timestamp() -> str: + """UTC time formatted as yyyy-MM-dd HH:mm:ss.""" + return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S") + + +def build_sign(params: dict, app_secret: str) -> str: + """ + Tracksolid signing algorithm (matches tspostman.py exactly): + 1. Sort all param keys alphabetically, exclude 'sign' and empty values. + 2. Concatenate key+value pairs with no separators. + 3. Wrap with appSecret on both sides. + 4. MD5 -> UPPERCASE 32-char string. + + All values must already be strings before calling this. + """ + sorted_keys = sorted( + k for k in params + if k != "sign" and params[k] is not None and str(params[k]).strip() != "" + ) + param_string = "".join(f"{k}{params[k]}" for k in sorted_keys) + raw_string = f"{app_secret}{param_string}{app_secret}" + return hashlib.md5(raw_string.encode("utf-8")).hexdigest().upper() + + +# ────────────────────────────────────────────────────────────────────────────── +# TRACKSOLID CLIENT +# ────────────────────────────────────────────────────────────────────────────── + +class TracksolidClient: + def __init__(self, cfg: dict): + self.cfg = cfg + self._token: str | None = None + self._token_expires_at: float = 0.0 + self.session = requests.Session() + # No Content-Type set here — requests sets it automatically to + # application/x-www-form-urlencoded when data= is used (matching tspostman.py) + + def _post(self, params: dict) -> dict: + """ + Sign and POST params using x-www-form-urlencoded encoding. + Confirmed working approach from tspostman.py: + - Cast all values to strings + - Use data= (form-encoded), NOT json= + """ + str_params = { + k: str(v) + for k, v in params.items() + if v is not None and str(v).strip() != "" + } + str_params["sign"] = build_sign(str_params, self.cfg["app_secret"]) + + log.debug("POST %s params=%s", self.cfg["api_url"], str_params) + resp = self.session.post( + self.cfg["api_url"], + data=str_params, # form-encoded, NOT json= + timeout=30, + ) + resp.raise_for_status() + data = resp.json() + log.debug("Response: %s", json.dumps(data)) + return data + + def _common_params(self, method: str) -> dict: + return { + "method": method, + "timestamp": utc_timestamp(), + "app_key": self.cfg["app_key"], + "sign_method": "md5", + "v": "1.0", + "format": "json", + } + + def get_token(self) -> str: + """Return a valid access token, fetching a new one only when needed.""" + if self._token and time.time() < self._token_expires_at - 60: + log.debug("Reusing cached token.") + return self._token + + log.info("Obtaining new access token ...") + params = self._common_params("jimi.oauth.token.get") + params.update({ + "user_id": self.cfg["user_id"], + "user_pwd_md5": self.cfg["user_pwd_md5"], + "expires_in": self.cfg["expires_in"], # already a string per tspostman.py + }) + + data = self._post(params) + if data.get("code") != 0: + raise RuntimeError( + f"Auth failed — code={data.get('code')} message={data.get('message')}" + ) + + self._token = data["result"]["accessToken"] + self._token_expires_at = time.time() + int(data["result"]["expiresIn"]) + log.info("Token acquired. Valid for %s seconds.", data["result"]["expiresIn"]) + return self._token + + def update_vehicle(self, imei: str, fields: dict, dry_run: bool = False) -> dict: + """ + Call jimi.open.device.update for one IMEI. + fields: dict using local key names (see row_to_fields below). + Returns the API response dict. + """ + if dry_run: + log.info("[DRY-RUN] IMEI %s -> %s", imei, fields) + return {"code": 0, "message": "dry-run"} + + token = self.get_token() + params = self._common_params("jimi.open.device.update") + params["access_token"] = token + params["imei"] = str(imei) + + # Map local field names -> Tracksolid API field names + api_field_map = { + "license_plate": "vehicle_number", + "vehicle_name": "vehicle_name", + "vehicle_icon": "vehicle_icon", + "driver_name": "driver_name", + "driver_phone": "driver_phone", + "vehicle_model": "vehicle_models", + "vin": "carFrame", + "engine_number": "engineNumber", + "device_name": "device_name", + "fuel_per_100": "oilWear", + "sim": "sim", + "remarks": "remarks", + } + for local_key, api_key in api_field_map.items(): + val = fields.get(local_key) + if val: + params[api_key] = str(val) + + return self._post(params) + + +# ────────────────────────────────────────────────────────────────────────────── +# CSV PARSING +# ────────────────────────────────────────────────────────────────────────────── + +def clean(val) -> str | None: + """Return None for NaN/empty values, else a stripped string.""" + if pd.isna(val) or str(val).strip() in ("", "nan", "NaN"): + return None + s = str(val).strip() + if s.endswith(".0") and s[:-2].lstrip("+-").isdigit(): + s = s[:-2] + return s + + +def row_to_fields(row: pd.Series) -> dict: + """Map one CSV row to local field names used by update_vehicle().""" + return { + "device_name": clean(row.get("Device Name")), + "vehicle_name": clean(row.get("Vehicle Name")), + "vehicle_icon": clean(row.get("Vehicle Icon")), + "license_plate": clean(row.get("License Plate No.")), + "vehicle_model": clean(row.get("Vehicle Model")), + "driver_name": clean(row.get("Driver Name")), + "driver_phone": clean(row.get("Telephone")), + "sim": clean(row.get("SIM")), + "vin": clean(row.get("VIN")), + "engine_number": clean(row.get("Engine Number")), + "fuel_per_100": clean(row.get("Fuel/100km")), + "remarks": clean(row.get("Remarks")), + } + + +# ────────────────────────────────────────────────────────────────────────────── +# MAIN +# ────────────────────────────────────────────────────────────────────────────── + +def main(): + parser = argparse.ArgumentParser( + description="Bulk-update Tracksolid vehicle info from CSV." + ) + parser.add_argument( + "--dry-run", action="store_true", + help="Show what would be sent without making update API calls." + ) + parser.add_argument( + "--csv", default=CSV_PATH, + help=f"Path to the logistics CSV (default: {CSV_PATH})" + ) + parser.add_argument( + "--limit", type=int, default=None, + help="Only process the first N rows (useful for testing)." + ) + args = parser.parse_args() + + # ── Load CSV ─────────────────────────────────────────────────────────────── + csv_file = Path(args.csv) + if not csv_file.exists(): + log.error("CSV file not found: %s", csv_file) + sys.exit(1) + + df = pd.read_csv(csv_file, dtype={"IMEI": str}) + log.info("Loaded %d rows from %s", len(df), csv_file) + + if args.limit: + df = df.head(args.limit) + log.info("Limiting to first %d rows.", args.limit) + + df = df[df["IMEI"].notna() & (df["IMEI"].str.strip() != "")] + log.info("%d rows have a valid IMEI.", len(df)) + + if df.empty: + log.warning("No rows to process. Exiting.") + sys.exit(0) + + # ── Initialise client & verify auth ─────────────────────────────────────── + client = TracksolidClient(CONFIG) + + if not args.dry_run: + try: + client.get_token() + except Exception as exc: + log.error("Authentication failed: %s", exc) + log.error("Check TS_USER_ID, TS_USER_PWD_MD5, TS_APP_KEY, TS_APP_SECRET.") + sys.exit(1) + + # ── Process rows ─────────────────────────────────────────────────────────── + results = [] + success = 0 + failed = 0 + skipped = 0 + + for idx, row in df.iterrows(): + imei = str(row["IMEI"]).strip() + fields = row_to_fields(row) + + # Skip rows where every updatable field is empty + if not any(fields.values()): + log.warning("Row %d (IMEI %s): no updatable fields, skipping.", idx + 1, imei) + skipped += 1 + continue + + log.info( + "Row %d/%d — IMEI: %s | Plate: %s | Driver: %s", + idx + 1, len(df), imei, + fields.get("license_plate") or "—", + fields.get("driver_name") or "—", + ) + + try: + resp = client.update_vehicle(imei, fields, dry_run=args.dry_run) + if resp.get("code") == 0: + log.info(" OK") + success += 1 + else: + log.warning( + " API error — code=%s message=%s", + resp.get("code"), resp.get("message") + ) + failed += 1 + + results.append({ + "imei": imei, + **fields, + "api_code": resp.get("code"), + "api_message": resp.get("message"), + }) + + except Exception as exc: + log.error(" Exception for IMEI %s: %s", imei, exc) + failed += 1 + results.append({ + "imei": imei, + **fields, + "api_code": "EXCEPTION", + "api_message": str(exc), + }) + + if not args.dry_run: + time.sleep(CONFIG["request_delay"]) + + # ── Summary & audit CSV ─────────────────────────────────────────────────── + log.info("-" * 60) + log.info( + "Done. OK: %d Failed: %d Skipped: %d | Total: %d", + success, failed, skipped, success + failed + skipped + ) + + out_path = "tracksolid_update_results.csv" + pd.DataFrame(results).to_csv(out_path, index=False) + log.info("Audit results written to %s", out_path) + + +if __name__ == "__main__": + main() diff --git a/tracksolid_vehicle_update.py b/tracksolid_vehicle_update.py new file mode 100644 index 0000000..e6cb61f --- /dev/null +++ b/tracksolid_vehicle_update.py @@ -0,0 +1,348 @@ +#!/usr/bin/env python3 +""" +Tracksolid Pro - Bulk Vehicle Information Updater +Updates vehicle details via the jimi.open.device.update API endpoint +using data from the Fireside logistics CSV. + +Signing approach taken directly from tspostman.py (confirmed working): + - POST as x-www-form-urlencoded (NOT JSON) + - All parameter values cast to strings before signing + - expires_in passed as string '7200', not integer + +Usage: + python tracksolid_update.py [--dry-run] [--csv path/to/file.csv] [--limit N] + +Environment variables (or edit CONFIG below): + TS_USER_ID - Your Tracksolid account username + TS_USER_PWD_MD5 - MD5 hash of your password (lowercase) + TS_APP_KEY - Your appKey from JIMI + TS_APP_SECRET - Your appSecret from JIMI + TS_API_URL - API base URL (defaults to EU node) + TS_CSV_PATH - Path to the logistics CSV +""" + +import hashlib +import time +import json +import logging +import argparse +import os +import sys +from datetime import datetime, timezone +from pathlib import Path + +import requests +import pandas as pd + +# ────────────────────────────────────────────────────────────────────────────── +# CONFIGURATION — edit here or set environment variables +# ────────────────────────────────────────────────────────────────────────────── +CONFIG = { + "user_id": os.getenv("TS_USER_ID", "Fireside Communications"), + "user_pwd_md5": os.getenv("TS_USER_PWD_MD5", "81a1b005efd3596073e38efd8a2fd3fd"), + "app_key": os.getenv("TS_APP_KEY", "8FB345B8693CCD00BB70D528C0D4019E"), + "app_secret": os.getenv("TS_APP_SECRET", "3177c89993b446c6aced0d7c56375d2c"), + # EU node confirmed for this account + "api_url": os.getenv("TS_API_URL", "https://eu-open.tracksolidpro.com/route/rest"), + "expires_in": "7200", # string, not int — matches tspostman.py + "request_delay": 0.5, # seconds between API calls +} + +CSV_PATH = os.getenv("TS_CSV_PATH", "20260414_FS__Logistics_-_final_fixed.csv") + +# ────────────────────────────────────────────────────────────────────────────── +# LOGGING +# ────────────────────────────────────────────────────────────────────────────── +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(levelname)-8s %(message)s", + handlers=[ + logging.StreamHandler(sys.stdout), + logging.FileHandler("tracksolid_update.log", encoding="utf-8"), + ], +) +log = logging.getLogger(__name__) + + +# ────────────────────────────────────────────────────────────────────────────── +# SIGNING UTILITIES (ported directly from tspostman.py) +# ────────────────────────────────────────────────────────────────────────────── + +def utc_timestamp() -> str: + """UTC time formatted as yyyy-MM-dd HH:mm:ss.""" + return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S") + + +def build_sign(params: dict, app_secret: str) -> str: + """ + Tracksolid signing algorithm (matches tspostman.py exactly): + 1. Sort all param keys alphabetically, exclude 'sign' and empty values. + 2. Concatenate key+value pairs with no separators. + 3. Wrap with appSecret on both sides. + 4. MD5 -> UPPERCASE 32-char string. + + All values must already be strings before calling this. + """ + sorted_keys = sorted( + k for k in params + if k != "sign" and params[k] is not None and str(params[k]).strip() != "" + ) + param_string = "".join(f"{k}{params[k]}" for k in sorted_keys) + raw_string = f"{app_secret}{param_string}{app_secret}" + return hashlib.md5(raw_string.encode("utf-8")).hexdigest().upper() + + +# ────────────────────────────────────────────────────────────────────────────── +# TRACKSOLID CLIENT +# ────────────────────────────────────────────────────────────────────────────── + +class TracksolidClient: + def __init__(self, cfg: dict): + self.cfg = cfg + self._token: str | None = None + self._token_expires_at: float = 0.0 + self.session = requests.Session() + # No Content-Type set here — requests sets it automatically to + # application/x-www-form-urlencoded when data= is used (matching tspostman.py) + + def _post(self, params: dict) -> dict: + """ + Sign and POST params using x-www-form-urlencoded encoding. + Confirmed working approach from tspostman.py: + - Cast all values to strings + - Use data= (form-encoded), NOT json= + """ + str_params = { + k: str(v) + for k, v in params.items() + if v is not None and str(v).strip() != "" + } + str_params["sign"] = build_sign(str_params, self.cfg["app_secret"]) + + log.debug("POST %s params=%s", self.cfg["api_url"], str_params) + resp = self.session.post( + self.cfg["api_url"], + data=str_params, # form-encoded, NOT json= + timeout=30, + ) + resp.raise_for_status() + data = resp.json() + log.debug("Response: %s", json.dumps(data)) + return data + + def _common_params(self, method: str) -> dict: + return { + "method": method, + "timestamp": utc_timestamp(), + "app_key": self.cfg["app_key"], + "sign_method": "md5", + "v": "1.0", + "format": "json", + } + + def get_token(self) -> str: + """Return a valid access token, fetching a new one only when needed.""" + if self._token and time.time() < self._token_expires_at - 60: + log.debug("Reusing cached token.") + return self._token + + log.info("Obtaining new access token ...") + params = self._common_params("jimi.oauth.token.get") + params.update({ + "user_id": self.cfg["user_id"], + "user_pwd_md5": self.cfg["user_pwd_md5"], + "expires_in": self.cfg["expires_in"], # already a string per tspostman.py + }) + + data = self._post(params) + if data.get("code") != 0: + raise RuntimeError( + f"Auth failed — code={data.get('code')} message={data.get('message')}" + ) + + self._token = data["result"]["accessToken"] + self._token_expires_at = time.time() + int(data["result"]["expiresIn"]) + log.info("Token acquired. Valid for %s seconds.", data["result"]["expiresIn"]) + return self._token + + def update_vehicle(self, imei: str, fields: dict, dry_run: bool = False) -> dict: + """ + Call jimi.open.device.update for one IMEI. + fields: dict using local key names (see row_to_fields below). + Returns the API response dict. + """ + if dry_run: + log.info("[DRY-RUN] IMEI %s -> %s", imei, fields) + return {"code": 0, "message": "dry-run"} + + token = self.get_token() + params = self._common_params("jimi.open.device.update") + params["access_token"] = token + params["imei"] = str(imei) + + # Map local field names -> Tracksolid API field names + api_field_map = { + "license_plate": "vehicleNumber", + "driver_name": "driverName", + "driver_phone": "driverPhone", + "vehicle_model": "vehicleModels", + "vin": "carFrame", + "engine_number": "engineNumber", + "device_name": "deviceName", + "fuel_per_100": "fuelPer100km", + } + for local_key, api_key in api_field_map.items(): + val = fields.get(local_key) + if val: + params[api_key] = str(val) + + return self._post(params) + + +# ────────────────────────────────────────────────────────────────────────────── +# CSV PARSING +# ────────────────────────────────────────────────────────────────────────────── + +def clean(val) -> str | None: + """Return None for NaN/empty values, else a stripped string.""" + if pd.isna(val) or str(val).strip() in ("", "nan", "NaN"): + return None + return str(val).strip() + + +def row_to_fields(row: pd.Series) -> dict: + """Map one CSV row to local field names used by update_vehicle().""" + return { + "license_plate": clean(row.get("License Plate No.")), + "driver_name": clean(row.get("Driver Name")), + "driver_phone": clean(row.get("Telephone")), + "vehicle_model": clean(row.get("Vehicle Model")), + "vin": clean(row.get("VIN")), + "engine_number": clean(row.get("Engine Number")), + "device_name": clean(row.get("Device Name")), + "fuel_per_100": clean(row.get("Fuel/100km")), + } + + +# ────────────────────────────────────────────────────────────────────────────── +# MAIN +# ────────────────────────────────────────────────────────────────────────────── + +def main(): + parser = argparse.ArgumentParser( + description="Bulk-update Tracksolid vehicle info from CSV." + ) + parser.add_argument( + "--dry-run", action="store_true", + help="Show what would be sent without making update API calls." + ) + parser.add_argument( + "--csv", default=CSV_PATH, + help=f"Path to the logistics CSV (default: {CSV_PATH})" + ) + parser.add_argument( + "--limit", type=int, default=None, + help="Only process the first N rows (useful for testing)." + ) + args = parser.parse_args() + + # ── Load CSV ─────────────────────────────────────────────────────────────── + csv_file = Path(args.csv) + if not csv_file.exists(): + log.error("CSV file not found: %s", csv_file) + sys.exit(1) + + df = pd.read_csv(csv_file, dtype={"IMEI": str}) + log.info("Loaded %d rows from %s", len(df), csv_file) + + if args.limit: + df = df.head(args.limit) + log.info("Limiting to first %d rows.", args.limit) + + df = df[df["IMEI"].notna() & (df["IMEI"].str.strip() != "")] + log.info("%d rows have a valid IMEI.", len(df)) + + if df.empty: + log.warning("No rows to process. Exiting.") + sys.exit(0) + + # ── Initialise client & verify auth ─────────────────────────────────────── + client = TracksolidClient(CONFIG) + + if not args.dry_run: + try: + client.get_token() + except Exception as exc: + log.error("Authentication failed: %s", exc) + log.error("Check TS_USER_ID, TS_USER_PWD_MD5, TS_APP_KEY, TS_APP_SECRET.") + sys.exit(1) + + # ── Process rows ─────────────────────────────────────────────────────────── + results = [] + success = 0 + failed = 0 + skipped = 0 + + for idx, row in df.iterrows(): + imei = str(row["IMEI"]).strip() + fields = row_to_fields(row) + + # Skip rows where every updatable field is empty + if not any(fields.values()): + log.warning("Row %d (IMEI %s): no updatable fields, skipping.", idx + 1, imei) + skipped += 1 + continue + + log.info( + "Row %d/%d — IMEI: %s | Plate: %s | Driver: %s", + idx + 1, len(df), imei, + fields.get("license_plate") or "—", + fields.get("driver_name") or "—", + ) + + try: + resp = client.update_vehicle(imei, fields, dry_run=args.dry_run) + if resp.get("code") == 0: + log.info(" OK") + success += 1 + else: + log.warning( + " API error — code=%s message=%s", + resp.get("code"), resp.get("message") + ) + failed += 1 + + results.append({ + "imei": imei, + **fields, + "api_code": resp.get("code"), + "api_message": resp.get("message"), + }) + + except Exception as exc: + log.error(" Exception for IMEI %s: %s", imei, exc) + failed += 1 + results.append({ + "imei": imei, + **fields, + "api_code": "EXCEPTION", + "api_message": str(exc), + }) + + if not args.dry_run: + time.sleep(CONFIG["request_delay"]) + + # ── Summary & audit CSV ─────────────────────────────────────────────────── + log.info("-" * 60) + log.info( + "Done. OK: %d Failed: %d Skipped: %d | Total: %d", + success, failed, skipped, success + failed + skipped + ) + + out_path = "tracksolid_update_results.csv" + pd.DataFrame(results).to_csv(out_path, index=False) + log.info("Audit results written to %s", out_path) + + +if __name__ == "__main__": + main() From 80c0e6510f56bc7c77a19558b45222093409b4c7 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Mon, 27 Apr 2026 17:25:58 +0300 Subject: [PATCH 02/31] fix(grafana): stop SI auto-scaling on km/hours stats; bound geomap to East Africa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grafana's lengthkm and h units auto-scale with SI prefixes — fleet km totals rendered as "Mm" (megametres) and drive-hour totals as days/weeks, which read as "millions" and "weeks" on the Daily Ops dashboard. Switched the affected panels (Fleet km today, Drive/Idle hours today, the per-vehicle roll-up table, the driver leaderboard, and the 7-day distance trend) to unit "none" with decimals: 1 so values stay in km/h with units carried by panel titles and column displayNames. Geomap view recentred to lat -2.0, lon 35.5, zoom 5 with minZoom 5 / maxZoom 12 so the Active Vehicles map opens on the East African Community region and cannot zoom out past it. Co-Authored-By: Claude Opus 4.7 --- .../daily_operations_dashboard.json | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/grafana/provisioning/dashboards-json/daily_operations_dashboard.json b/grafana/provisioning/dashboards-json/daily_operations_dashboard.json index d4a935b..364a7e0 100644 --- a/grafana/provisioning/dashboards-json/daily_operations_dashboard.json +++ b/grafana/provisioning/dashboards-json/daily_operations_dashboard.json @@ -111,7 +111,7 @@ }, "fieldConfig": { "defaults": { - "unit": "lengthkm", + "unit": "none", "decimals": 1, "color": { "mode": "fixed", "fixedColor": "blue" } } @@ -133,7 +133,7 @@ "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } }, "fieldConfig": { - "defaults": { "unit": "h", "decimals": 1, "color": { "mode": "fixed", "fixedColor": "green" } } + "defaults": { "unit": "none", "decimals": 1, "color": { "mode": "fixed", "fixedColor": "green" } } }, "targets": [ { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, @@ -154,7 +154,7 @@ }, "fieldConfig": { "defaults": { - "unit": "h", "decimals": 1, + "unit": "none", "decimals": 1, "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", @@ -256,7 +256,7 @@ } ], "tooltip": { "mode": "details" }, - "view": { "allLayers": true, "id": "coords", "lat": -1.5, "lon": 36.5, "zoom": 6 } + "view": { "allLayers": true, "id": "coords", "lat": -2.0, "lon": 35.5, "zoom": 5, "minZoom": 5, "maxZoom": 12 } }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic-by-name" } }, @@ -335,11 +335,11 @@ "defaults": { "custom": { "align": "auto", "filterable": true } }, "overrides": [ { "matcher": { "id": "byName", "options": "km_today" }, - "properties": [{ "id": "unit", "value": "lengthkm" }, { "id": "decimals", "value": 1 }] }, + "properties": [{ "id": "unit", "value": "none" }, { "id": "decimals", "value": 1 }, { "id": "displayName", "value": "km today" }] }, { "matcher": { "id": "byName", "options": "drive_hours" }, - "properties": [{ "id": "unit", "value": "h" }, { "id": "decimals", "value": 1 }] }, + "properties": [{ "id": "unit", "value": "none" }, { "id": "decimals", "value": 1 }, { "id": "displayName", "value": "Drive h" }] }, { "matcher": { "id": "byName", "options": "idle_hours" }, - "properties": [{ "id": "unit", "value": "h" }, { "id": "decimals", "value": 1 }] }, + "properties": [{ "id": "unit", "value": "none" }, { "id": "decimals", "value": 1 }, { "id": "displayName", "value": "Idle h" }] }, { "matcher": { "id": "byName", "options": "did_not_move" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "color-background" } }, @@ -378,7 +378,7 @@ "defaults": { "custom": { "align": "auto", "filterable": true } }, "overrides": [ { "matcher": { "id": "byName", "options": "km" }, - "properties": [{ "id": "unit", "value": "lengthkm" }, { "id": "decimals", "value": 0 }] }, + "properties": [{ "id": "unit", "value": "none" }, { "id": "decimals", "value": 0 }, { "id": "displayName", "value": "km" }] }, { "matcher": { "id": "byName", "options": "speeding_per_100km" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "color-background" } }, @@ -424,8 +424,9 @@ "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, "fieldConfig": { "defaults": { - "unit": "lengthkm", - "custom": { "drawStyle": "bars", "fillOpacity": 60, "lineWidth": 1 } + "unit": "none", + "decimals": 1, + "custom": { "drawStyle": "bars", "fillOpacity": 60, "lineWidth": 1, "axisLabel": "km" } } }, "targets": [ From bf17d5fa80254bc9bcc3a73365d8eeb8dd84fbe7 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Mon, 27 Apr 2026 18:31:01 +0300 Subject: [PATCH 03/31] fix(grafana): tighten Active Vehicles map to Kenya, Uganda and Tanzania Recentred geomap view from lat -2.0/lon 35.5/zoom 5 to lat -3.0/lon 34.5/ zoom 5.5 (Lake Victoria area, the geographic intersection of the three countries) and raised minZoom to 5.5 so the dashboard can't be panned out to show neighbouring countries. Co-Authored-By: Claude Opus 4.7 --- .../dashboards-json/daily_operations_dashboard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grafana/provisioning/dashboards-json/daily_operations_dashboard.json b/grafana/provisioning/dashboards-json/daily_operations_dashboard.json index 364a7e0..68cf577 100644 --- a/grafana/provisioning/dashboards-json/daily_operations_dashboard.json +++ b/grafana/provisioning/dashboards-json/daily_operations_dashboard.json @@ -256,7 +256,7 @@ } ], "tooltip": { "mode": "details" }, - "view": { "allLayers": true, "id": "coords", "lat": -2.0, "lon": 35.5, "zoom": 5, "minZoom": 5, "maxZoom": 12 } + "view": { "allLayers": true, "id": "coords", "lat": -3.0, "lon": 34.5, "zoom": 5.5, "minZoom": 5.5, "maxZoom": 12 } }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic-by-name" } }, From 0b45f8d0f7cf7858e0c0c559596c51a407785165 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Mon, 27 Apr 2026 18:32:14 +0300 Subject: [PATCH 04/31] fix(grafana): raise geomap maxZoom from 12 to 22 for full-resolution drill-in Carto basemap tiles render up to ~19-20; OpenLayers caps at 28. 22 leaves no practical ceiling for street-level inspection while keeping the EAC- bounded minZoom in place. Co-Authored-By: Claude Opus 4.7 --- .../dashboards-json/daily_operations_dashboard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grafana/provisioning/dashboards-json/daily_operations_dashboard.json b/grafana/provisioning/dashboards-json/daily_operations_dashboard.json index 68cf577..227dd3d 100644 --- a/grafana/provisioning/dashboards-json/daily_operations_dashboard.json +++ b/grafana/provisioning/dashboards-json/daily_operations_dashboard.json @@ -256,7 +256,7 @@ } ], "tooltip": { "mode": "details" }, - "view": { "allLayers": true, "id": "coords", "lat": -3.0, "lon": 34.5, "zoom": 5.5, "minZoom": 5.5, "maxZoom": 12 } + "view": { "allLayers": true, "id": "coords", "lat": -3.0, "lon": 34.5, "zoom": 5.5, "minZoom": 5.5, "maxZoom": 22 } }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic-by-name" } }, From 5418fc48c5ad132562634a35b6650cd14e977b1e Mon Sep 17 00:00:00 2001 From: David Kiania Date: Mon, 27 Apr 2026 23:42:20 +0300 Subject: [PATCH 05/31] fix(api): map new Mitieng CSV columns in tracksolid_update_v2 Switches column references from the old title-case logistics CSV (IMEI, Device Name, License Plate No., Telephone, Fuel/100km, ...) to the snake_case Mitieng export shipped on 2026-04-27 (imei, device_name, vehicle_number, driver_phone, fuel_100km, ...). Without this, the bulk device-update API tool fails with KeyError: 'IMEI' on the new CSV. Co-Authored-By: Claude Opus 4.7 --- tracksolid_update_v2.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tracksolid_update_v2.py b/tracksolid_update_v2.py index 4021fc8..cabed61 100644 --- a/tracksolid_update_v2.py +++ b/tracksolid_update_v2.py @@ -220,18 +220,18 @@ def clean(val) -> str | None: def row_to_fields(row: pd.Series) -> dict: """Map one CSV row to local field names used by update_vehicle().""" return { - "device_name": clean(row.get("Device Name")), - "vehicle_name": clean(row.get("Vehicle Name")), - "vehicle_icon": clean(row.get("Vehicle Icon")), - "license_plate": clean(row.get("License Plate No.")), - "vehicle_model": clean(row.get("Vehicle Model")), - "driver_name": clean(row.get("Driver Name")), - "driver_phone": clean(row.get("Telephone")), - "sim": clean(row.get("SIM")), - "vin": clean(row.get("VIN")), - "engine_number": clean(row.get("Engine Number")), - "fuel_per_100": clean(row.get("Fuel/100km")), - "remarks": clean(row.get("Remarks")), + "device_name": clean(row.get("device_name")), + "vehicle_name": clean(row.get("vehicle_name")), + "vehicle_icon": clean(row.get("vehicle_icon")), + "license_plate": clean(row.get("vehicle_number")), + "vehicle_model": clean(row.get("vehicle_models")), + "driver_name": clean(row.get("driver_name")), + "driver_phone": clean(row.get("driver_phone")), + "sim": clean(row.get("sim")), + "vin": clean(row.get("vin")), + "engine_number": clean(row.get("engine_number")), + "fuel_per_100": clean(row.get("fuel_100km")), + "remarks": clean(row.get("remarks")), } @@ -263,14 +263,14 @@ def main(): log.error("CSV file not found: %s", csv_file) sys.exit(1) - df = pd.read_csv(csv_file, dtype={"IMEI": str}) + df = pd.read_csv(csv_file, dtype={"imei": str}) log.info("Loaded %d rows from %s", len(df), csv_file) if args.limit: df = df.head(args.limit) log.info("Limiting to first %d rows.", args.limit) - df = df[df["IMEI"].notna() & (df["IMEI"].str.strip() != "")] + df = df[df["imei"].notna() & (df["imei"].str.strip() != "")] log.info("%d rows have a valid IMEI.", len(df)) if df.empty: @@ -295,7 +295,7 @@ def main(): skipped = 0 for idx, row in df.iterrows(): - imei = str(row["IMEI"]).strip() + imei = str(row["imei"]).strip() fields = row_to_fields(row) # Skip rows where every updatable field is empty From 898fd25a5aa5cc38ef787b245c9f1d0207601cc1 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Mon, 27 Apr 2026 23:42:37 +0300 Subject: [PATCH 06/31] =?UTF-8?q?feat(analytics):=20Phase=200=20=E2=80=94?= =?UTF-8?q?=20analytics-config=20migration=20and=20CSV=20importer=20rewrit?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 0 of the three-stakeholder analytics redesign: - 08_analytics_config.sql: ops.cost_rates + ops.kpi_targets with seed fuel rates (KES 195/L NBO+MBA, UGX 5200/L KLA) and 6 seed KPI targets (utilisation_pct, idle_pct global+osp-patrol, fuel_kes_per_100km, mttr_hours, alarms_per_100km). Granted SELECT to grafana_ro. Wired into run_migrations.py MIGRATIONS. - import_drivers_csv.py: full rewrite for the new Mitieng CSV (20260427_FSG_Vehicles_mitieng.csv). Snake_case columns, drops _infer_city() plate-prefix logic in favour of reading assigned_city directly. Adds cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address. Treats the literal "NULL" string as missing. Reuses clean(), clean_num(), clean_ts(), get_conn(), get_logger() from ts_shared_rev. Special-cases numeric and timestamptz columns in the UPDATE clause. - audit_device_reconciliation.py: read-only audit comparing the CSV against tracksolid.devices. Reports per-account row counts, IMEIs on one side only, and devices on both sides whose metadata is still NULL. - 260427_device_reconciliation.md + 260427_audit_output.txt: Phase 0.2 reconciliation record. First run: DB has 172 devices, CSV has 162, delta +10 (10 IMEIs in DB-only, mostly fireside-account auto-syncs). Importer run with --only-null --apply filled 154 rows; coverage now assigned_city 152/172, cost_centre 150/172. Applied to stage on 2026-04-27 23:35 UTC. Co-Authored-By: Claude Opus 4.7 --- 08_analytics_config.sql | 121 ++++++++++++++++ 20260427_FSG_Vehicles_mitieng.csv | 163 ++++++++++++++++++++++ 260427_audit_output.txt | 75 ++++++++++ 260427_device_reconciliation.md | 91 ++++++++++++ audit_device_reconciliation.py | 205 ++++++++++++++++++++++++++++ import_drivers_csv.py | 220 ++++++++++++++++++------------ run_migrations.py | 1 + 7 files changed, 785 insertions(+), 91 deletions(-) create mode 100644 08_analytics_config.sql create mode 100644 20260427_FSG_Vehicles_mitieng.csv create mode 100644 260427_audit_output.txt create mode 100644 260427_device_reconciliation.md create mode 100644 audit_device_reconciliation.py diff --git a/08_analytics_config.sql b/08_analytics_config.sql new file mode 100644 index 0000000..859d8f0 --- /dev/null +++ b/08_analytics_config.sql @@ -0,0 +1,121 @@ +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +-- Migration 08 — Analytics Configuration Tables +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +-- Adds reference data driving the three-stakeholder analytics redesign +-- (Phase 0.3 of the plan). These tables let downstream views monetise idle +-- and fuel costs, and apply traffic-light targets to KPIs without hard-coding +-- thresholds in SQL. +-- +-- • ops.cost_rates — fuel price per litre by city, labour rate by role. +-- • ops.kpi_targets — green / amber / red thresholds per KPI per scope. +-- +-- Run after migration 07. Safe to re-run (CREATE TABLE IF NOT EXISTS, +-- INSERT ... ON CONFLICT DO NOTHING). +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +BEGIN; + +-- ── 1. ops.cost_rates ─────────────────────────────────────────────────────── +-- Reference rates that power monetisation in analytics views. Lookup pattern +-- in views: WHERE scope_type = 'city' AND scope_value = AND metric = ... +-- ORDER BY effective_from DESC LIMIT 1. + +CREATE TABLE IF NOT EXISTS ops.cost_rates ( + rate_key TEXT PRIMARY KEY, + scope_type TEXT NOT NULL, -- 'city' | 'role' | 'global' + scope_value TEXT, -- 'nairobi' | 'driver' | NULL for global + metric TEXT NOT NULL, -- 'fuel_per_litre' | 'labour_per_hour' + amount NUMERIC(12,2) NOT NULL, + currency TEXT NOT NULL, -- 'KES' | 'UGX' + effective_from DATE NOT NULL DEFAULT CURRENT_DATE, + notes TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_cost_rates_lookup + ON ops.cost_rates (scope_type, scope_value, metric, effective_from DESC); + +COMMENT ON TABLE ops.cost_rates + IS 'Reference rates for analytics monetisation: fuel price per litre by city, ' + 'labour cost per hour by role. Resolution order in views: scope_type=city ' + '> scope_type=role > scope_type=global.'; +COMMENT ON COLUMN ops.cost_rates.metric + IS 'fuel_per_litre | labour_per_hour'; +COMMENT ON COLUMN ops.cost_rates.scope_type + IS 'city | role | global'; + +-- ── 2. ops.kpi_targets ────────────────────────────────────────────────────── +-- Traffic-light thresholds per KPI. Same KPI can have global + per-CC + per-city +-- rows; views use a CASE / COALESCE chain to pick the most specific match. + +CREATE TABLE IF NOT EXISTS ops.kpi_targets ( + target_id BIGSERIAL PRIMARY KEY, + kpi_key TEXT NOT NULL, -- e.g. 'utilisation_pct' + scope_type TEXT NOT NULL, -- 'global' | 'city' | 'cost_centre' | 'vehicle_category' + scope_value TEXT, -- NULL for global + target_value NUMERIC(12,2) NOT NULL, + amber_threshold NUMERIC(12,2), -- between target and red + red_threshold NUMERIC(12,2), -- worse than amber + direction TEXT NOT NULL DEFAULT 'higher_is_better', + -- 'higher_is_better' | 'lower_is_better' + effective_from DATE NOT NULL DEFAULT CURRENT_DATE, + notes TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + UNIQUE (kpi_key, scope_type, scope_value, effective_from) +); + +CREATE INDEX IF NOT EXISTS idx_kpi_targets_lookup + ON ops.kpi_targets (kpi_key, scope_type, scope_value, effective_from DESC); + +COMMENT ON TABLE ops.kpi_targets + IS 'Traffic-light targets per KPI per scope. Resolution order in views: ' + 'cost_centre > vehicle_category > city > global.'; +COMMENT ON COLUMN ops.kpi_targets.direction + IS 'higher_is_better -> green when value >= target. ' + 'lower_is_better -> green when value <= target.'; + +-- ── 3. Seed cost rates ────────────────────────────────────────────────────── +-- Placeholder values — confirm with Finance and update via a follow-up insert +-- with a later effective_from date (do NOT mutate historical rows). + +INSERT INTO ops.cost_rates + (rate_key, scope_type, scope_value, metric, amount, currency, notes) +VALUES + ('fuel.nairobi', 'city', 'nairobi', 'fuel_per_litre', 195.00, 'KES', + 'Placeholder pump price — confirm with Finance.'), + ('fuel.mombasa', 'city', 'mombasa', 'fuel_per_litre', 195.00, 'KES', + 'Placeholder pump price — confirm with Finance.'), + ('fuel.kampala', 'city', 'kampala', 'fuel_per_litre', 5200.00, 'UGX', + 'Placeholder pump price — confirm with Finance.') +ON CONFLICT (rate_key) DO NOTHING; + +-- ── 4. Seed KPI targets ───────────────────────────────────────────────────── +-- Initial Exco-relevant targets. Calibrate after one month of clean data. + +INSERT INTO ops.kpi_targets + (kpi_key, scope_type, scope_value, target_value, amber_threshold, + red_threshold, direction, notes) +VALUES + ('utilisation_pct', 'global', NULL, 70, 60, 50, 'higher_is_better', + 'Fleet utilisation: drive_hours / engine_on_hours.'), + ('idle_pct', 'global', NULL, 15, 20, 25, 'lower_is_better', + 'Idle as % of engine-on time.'), + ('idle_pct', 'cost_centre', 'osp patrol', 15, 20, 25, 'lower_is_better', + 'OSP patrol idle target — same as global until calibrated.'), + ('fuel_kes_per_100km', 'global', NULL, 12, 14, 16, 'lower_is_better', + 'Fuel litres per 100km equivalent — uses fuel_100km on devices.'), + ('mttr_hours', 'global', NULL, 4, 6, 8, 'lower_is_better', + 'Mean Time To Resolve, field-service ticket.'), + ('alarms_per_100km', 'global', NULL, 2, 3, 5, 'lower_is_better', + 'Safety event density.') +ON CONFLICT (kpi_key, scope_type, scope_value, effective_from) DO NOTHING; + +-- ── 5. Read access for Grafana ────────────────────────────────────────────── + +GRANT USAGE ON SCHEMA ops TO grafana_ro; +GRANT SELECT ON ops.cost_rates TO grafana_ro; +GRANT SELECT ON ops.kpi_targets TO grafana_ro; + +COMMIT; diff --git a/20260427_FSG_Vehicles_mitieng.csv b/20260427_FSG_Vehicles_mitieng.csv new file mode 100644 index 0000000..e0ef7bc --- /dev/null +++ b/20260427_FSG_Vehicles_mitieng.csv @@ -0,0 +1,163 @@ +imei,device_name,mc_type,mc_type_use_scope,vehicle_name,vehicle_number,vehicle_models,vehicle_icon,vin,engine_number,vehicle_brand,fuel_100km,driver_name,driver_phone,sim,iccid,imsi,account,customer_name,device_group_id,device_group,activation_time,expiration,enabled_flag,status,city,current_mileage_km,created_at,updated_at,last_synced_at,vehicle_category,cost_centre,assigned_route,depot_geom,depot_address,assigned_city +353549090553685,Daniel Omondi - KMFF 099Z,AT4,personal,KMFF 099Z,KMFF 099Z,Motorbike,mtc,NULL,NULL,NULL,NULL,Robert,112794067,759336150,89254021334258404099,639021335840409,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-09-23 05:50:30+00,2040-09-23 23:59:59+00,1,1,mombasa,2354.7,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp patrol,NULL,NULL,NULL,mombasa +353549090561720,Wireless_Git,AT4,personal,NULL,NULL,NULL,bus,NULL,NULL,NULL,NULL,NULL,NULL,701211913,89254021374215155053,639021371515505,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2025-06-09 09:12:50+00,2035-06-09 23:59:59+00,1,1,mombasa,5992.43,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,regional,NULL,NULL,NULL,mombasa +353549090566281,KDR 592N,AT4,personal,NULL,NULL,NULL,bus,NULL,NULL,NULL,NULL,NULL,NULL,797680464,89254021334258159693,639021335815969,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2024-11-08 04:01:30+00,2034-11-08 23:59:59+00,1,1,nairobi,7771.9,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +353549090566885,Wireless GPS,AT4,personal,NULL,NULL,NULL,bus,NULL,NULL,NULL,NULL,NULL,NULL,768445963,89254021334212352574,639021331235257,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2024-10-15 13:16:57+00,2034-10-15 23:59:59+00,1,1,nairobi,17036.41,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,null,NULL,NULL,NULL,nairobi +353549090567685,Daniel Kipkirui - KMFF 162Z,AT4,personal,KMFF 162Z,KMFF 162Z,Motorbike,mtc,NULL,NULL,NULL,NULL,Daniel Kipkirui,112795498,742532058,89254021264260388966,639021266038896,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-09-23 05:09:39+00,2040-09-23 23:59:59+00,1,1,mombasa,462.33,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp patrol,NULL,NULL,NULL,mombasa +353549090567701,Wireless,AT4,personal,NULL,NULL,NULL,bus,NULL,NULL,NULL,NULL,NULL,NULL,790176094,89254021394215205906,639021391520590,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2024-11-08 04:04:44+00,2034-11-08 23:59:59+00,1,1,nairobi,16896.2,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,null,NULL,NULL,NULL,nairobi +359857081885410,Allan Owana - KDK 780K,GT06E,automobile,KDK 780K,KDK 780K,Probox,automobile,NULL,NULL,NULL,NULL,Allan Owana,NULL,703616117,89254021234222499854,639021232249985,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2019-06-19 09:32:22+00,2039-06-19 23:59:59+00,1,1,nairobi,128853.11,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857081886467,Gideon Kiprono - KCQ 215F,GT06E,automobile,KCQ 215F,OHS,Probox,automobile,NULL,NULL,NULL,0,Gideon Kiprono,NULL,746763076,89254021084186499865,639021088649986,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2019-06-30 09:30:00+00,2039-06-30 23:59:59+00,1,1,mombasa,141057.46,2026-04-23 10:56:37.983314+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +359857081886871,Kamonde KBA 467S,GT06E,automobile,NULL,NULL,NULL,bus,NULL,NULL,NULL,NULL,NULL,NULL,746763083,89254021084186499873,639021088649987,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2019-06-30 09:09:14+00,2039-06-30 23:59:59+00,1,1,nairobi,74183.36,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,personal,NULL,NULL,NULL,nairobi +359857081886905,Kennedy Chege - KCQ 618K,GT06E,automobile,KCQ 618K,KCQ 618K,Probox,automobile,NULL,NULL,NULL,NULL,Kennedy Chege,NULL,746763132,89254021084186499923,639021088649992,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2019-06-30 07:08:35+00,2039-06-30 23:59:59+00,1,1,mombasa,215608.19,2026-04-23 10:35:37.678371+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +359857081887069,Wright Oseko - KCG 668W,GT06E,automobile,KCG 668W,KCG 668W,Probox,automobile,NULL,NULL,NULL,NULL,Wright Oseko,NULL,746763106,89254021084186499915,639021088649991,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2019-06-30 06:17:43+00,2039-06-30 23:59:59+00,1,1,nairobi,239001.19,2026-04-23 11:00:08.769463+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +359857081887192,Ndegwa Dancun - KCG 669W,GT06E,automobile,KCG 669W,KCG 669W,Probox,automobile,NULL,NULL,NULL,NULL,Ndegwa Dancun,NULL,746760191,89254021084186499501,639021088649950,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2019-06-15 10:26:15+00,2039-06-15 23:59:59+00,1,1,mombasa,199191.85,2026-04-23 10:34:29.074112+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +359857081891566,Simon Kamau - KCE 090R,GT06E,automobile,KCE 090R,KCE 090R,Probox,automobile,NULL,NULL,NULL,NULL,Simon Kamau,NULL,746760404,89254021084186499527,639021088649952,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2019-06-16 07:06:15+00,2039-06-16 23:59:59+00,1,1,nairobi,215592.36,2026-04-23 10:30:55.739184+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857081891590,Garage - KCE 699F,GT06E,automobile,KCE 699F,KCE 699F,Probox,automobile,NULL,NULL,NULL,NULL,Garage,NULL,746760215,89254021084186499519,639021088649951,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2019-06-16 11:11:24+00,2039-06-16 23:59:59+00,1,1,nairobi,207814.05,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +359857081891632,Samuel Kamau - KCA 542Q,GT06E,automobile,KCA 542Q,KCA 542Q,Probox,automobile,NULL,NULL,NULL,NULL,John Ondego,NULL,746760038,89254021084186499485,639021088649948,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2019-06-15 09:17:53+00,2039-06-15 23:59:59+00,1,1,nairobi,178914.47,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,nairobi +359857081891798,Garage - KCH 167M,GT06E,automobile,KCH 167M,KCH 167M,Probox,automobile,NULL,NULL,NULL,NULL,Garage,NULL,746760102,89254021084186499493,639021088649949,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2019-06-16 10:18:57+00,2039-06-16 23:59:59+00,1,1,nairobi,168840.95,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +359857081892101,Cornelius Kimutai - KCU 938R,GT06E,automobile,KCU 938R,KCU 938R,Van,automobile,NULL,NULL,NULL,NULL,Cornelius Kimutai,NULL,746759919,89254021084186499451,639021088649945,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2019-06-12 08:13:48+00,2039-06-12 23:59:59+00,1,1,nairobi,149558.5,2026-04-23 10:29:21.507861+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +359857081892309,Nicholas Erastus - KCQ 581M,GT06E,automobile,KCQ 581M,KCQ 581M,Probox,automobile,NULL,NULL,NULL,NULL,Nicholas Erastus,NULL,700023776,89254021084178504672,639021087850467,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2019-06-09 09:39:40+00,2039-06-09 23:59:59+00,1,1,nairobi,209105.89,2026-04-23 10:40:40.169684+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857081892440,KAZ 489Z,GT06E,automobile,NULL,NULL,NULL,bus,NULL,NULL,NULL,NULL,NULL,NULL,700023806,89254021084178504698,639021087850469,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2019-06-09 10:04:39+00,2039-06-09 23:59:59+00,1,1,nairobi,38197.2,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,personal,NULL,NULL,NULL,nairobi +359857081892762,Nicholas,GT06E,automobile,NULL,NULL,Station Wagon,bus,NULL,NULL,Toyota,NULL,NULL,NULL,746760503,89254021274233125361,639021273312536,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2019-06-16 08:31:46+00,2039-06-16 23:59:59+00,1,1,mombasa,51048.97,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,personal,NULL,NULL,NULL,nairobi +359857082037185,Amani Kazungu - KCY 084X,GT06E,automobile,KCY 084X,KCY 084X,Probox,automobile,NULL,NULL,NULL,NULL,Amani Kazungu,NULL,757338522,89254021154287000597,639021158700059,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-07-13 09:42:28+00,2040-07-13 23:59:59+00,1,1,mombasa,172298.81,2026-04-23 10:51:08.665273+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +359857082038977,Wilfred Kinyanjui - KCU 729C,GT06E,automobile,KCU 729C,KCU 729C,Crane,truck,NULL,NULL,NULL,NULL,Wilfred Kinyanjui,NULL,110094469,89254021164215938057,639021161593805,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-04-05 09:26:00+00,2040-04-05 23:59:59+00,1,1,nairobi,172487.09,2026-04-23 10:24:33.914628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,general,NULL,NULL,NULL,mombasa +359857082040981,Amani Sulubu - KCY 090X,GT06E,automobile,KCY 090X,KCY 090X,Probox,automobile,NULL,NULL,NULL,NULL,Amani Sulubu,NULL,793375853,89254021064168004164,639021066800416,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-07-13 07:25:16+00,2040-07-13 23:59:59+00,1,1,mombasa,166028.15,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +359857082042052,Gabriel Musumba - KCE 690F,GT06E,automobile,KCE 690F,KCE 690F,Probox,automobile,NULL,NULL,NULL,NULL,Gabriel Musumba,NULL,110094466,89254021164215938024,639021161593802,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2020-04-03 17:30:13+00,2040-04-03 23:59:59+00,1,1,nairobi,192693.23,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +359857082042854,Elias Baya - KCZ 476E,GT06E,automobile,KCZ 476E,KCZ 476E,Probox,automobile,NULL,NULL,NULL,NULL,Elias Baya,NULL,110941187,89254021164224352993,639021162435299,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-08-09 05:06:42+00,2040-08-09 23:59:59+00,1,1,mombasa,217595.68,2026-04-23 10:33:56.216621+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +359857082042953,KCU 865Q Vanguard,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,unknown,null,NULL,2026-04-23 13:24:33.293453+00,2026-04-23 13:24:33.293453+00,NULL,NULL,null,NULL,NULL,NULL,null +359857082044280,Lawrence Kijogi - KCY 080X,GT06E,automobile,KCY 080X,KCY 080X,Probox,automobile,NULL,NULL,NULL,NULL,Lawrence Kijogi,NULL,708155933,89254029851005131222,639029850513122,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-07-13 11:05:02+00,2040-07-13 11:05:02+00,1,1,mombasa,169740.37,2026-04-23 14:52:58.983571+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,mombasa +359857082046145,Joseph Kabandi - KCY 076X,GT06E,automobile,KCY 076X,KCY 076X,Probox,automobile,NULL,NULL,NULL,NULL,Joseph Kabandi,NULL,110850007,89254021164223447158,639021162344715,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-07-13 08:31:26+00,2040-07-13 23:59:59+00,1,1,mombasa,122254.48,2026-04-23 10:47:40.895504+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +359857082896911,Hamisi Pande - KDD 689Y,GT06E,automobile,KDD 689Y,KDD 689Y,Probox,automobile,NULL,NULL,NULL,NULL,Hamisi Pande,NULL,112714612,89254021214211314660,639021211131466,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-09-17 11:50:53+00,2041-09-17 23:59:59+00,1,1,nairobi,163435.74,2026-04-23 10:26:09.922447+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857082897091,Peter Mbugua - KDK 728K,GT06E,automobile,KDK 728K,KDK 728K,Probox,automobile,NULL,NULL,NULL,NULL,Peter Mbugua,NULL,790262984,89254021234222500396,639021232250039,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-12-14 11:31:57+00,2042-12-14 23:59:59+00,1,1,nairobi,131109.26,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857082897257,Cassius Wakiyo - KDB 323M,GT06E,automobile,KDB 323M,KDB 323M,Probox,automobile,NULL,NULL,NULL,NULL,Cassius Wakiyo,NULL,746428882,89254021234222500818,639021232250081,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-08-29 15:07:26+00,2041-08-29 15:07:26+00,1,1,nairobi,121688.92,2026-04-23 10:28:26.388654+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +359857082897737,John Makori - KDB 585E,GT06E,automobile,KDB 585E,KDB 585E,Probox,automobile,NULL,NULL,NULL,NULL,John Makori,NULL,114596734,89254021214211145262,639021211114526,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-08-29 14:29:28+00,2041-08-29 14:29:28+00,1,1,nairobi,156765.03,2026-04-23 10:38:57.445964+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,planning,NULL,NULL,NULL,nairobi +359857082897794,Mutuku Joseph - KDC 739F,GT06E,automobile,KDC 739F,KDC 739F,Probox,automobile,NULL,NULL,NULL,NULL,Mutuku Joseph,115019037,115019037,89254021224222632356,639021222263235,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-04-10 14:55:32+00,2041-04-10 14:55:32+00,1,1,nairobi,205169.79,2026-04-23 10:30:22.530563+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +359857082898008,Samuel Ng'ang'a - KDE 264M,GT06E,automobile,KDE 264M,KDE 264M,Probox,automobile,NULL,NULL,NULL,NULL,Samuel Ng'ang'a,NULL,711731539,89254021264260342245,639021266034224,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-10-28 09:43:11+00,2041-10-28 23:59:59+00,1,1,nairobi,126584.24,2026-04-23 11:35:59.816581+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857082898016,Job Ngare - KDM 309S,GT06E,automobile,KDM 309S,KDM 309S,Probox,automobile,NULL,NULL,NULL,NULL,Job Ngare,NULL,706895756,89254021324273007563,639021327300756,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-08-15 13:45:26+00,2033-08-15 23:59:59+00,1,1,mombasa,107726.56,2026-04-23 11:20:25.939244+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +359857082898073,Mutuku Antony - KDK 732K,GT06E,automobile,KDK 732K,KDK 732K,Probox,automobile,NULL,NULL,NULL,NULL,Mutuku Antony,NULL,793026954,89254021234222387539,639021232238753,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-12-20 06:33:12+00,2042-12-20 23:59:59+00,1,1,mombasa,82096.79,2026-04-23 14:52:07.094447+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +359857082898487,Dan Watila - KDE 638J,GT06E,automobile,KDE 638J,KDE 638J,Probox,automobile,NULL,NULL,NULL,NULL,Dan Watila,NULL,116242996,89254021334258404214,639021335840421,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-10-21 15:50:06+00,2041-10-21 23:59:59+00,1,1,nairobi,123872.36,2026-04-23 10:31:45.186653+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857082900168,KDD 913G_Ruth Mazda,NULL,NULL,KDD 913G,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,unknown,nairobi,NULL,2026-04-23 15:09:48.575568+00,2026-04-23 15:09:48.575568+00,NULL,NULL,personal,NULL,NULL,NULL,nairobi +359857082900341,Simon Munda - KCZ 154S,GT06E,automobile,KCZ 154S,KCZ 154S,Probox,automobile,NULL,NULL,NULL,NULL,Simon Munda,NULL,757236135,89254021154296723312,639021159672331,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-09-23 17:12:51+00,2040-09-23 23:59:59+00,1,1,mombasa,186504.1,2026-04-23 10:45:21.454595+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +359857082900358,Geoffrey Too - KDM 308S,GT06E,automobile,KDM 308S,KDM 308S,Probox,automobile,NULL,NULL,NULL,NULL,Geoffrey Too,NULL,796527601,89254021264260126572,639021266012657,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-10-21 15:25:28+00,2041-10-21 23:59:59+00,1,1,nairobi,142216.91,2026-04-23 12:35:06.661934+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +359857082900697,George Ochieng' - KDD 684Y,GT06E,automobile,KDD 684Y,KDD 684Y,Probox,automobile,NULL,NULL,NULL,NULL,George Ochieng',NULL,114879518,89254021214211314678,639021211131467,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-09-17 10:53:11+00,2041-09-17 23:59:59+00,1,1,nairobi,152820.07,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +359857082902461,Sadique Wakayula - KDC 490Q,GT06E,automobile,KDC 490Q,KDC 490Q,Crane,truck,NULL,NULL,NULL,NULL,Sadique Wakayula,NULL,757556468,89254021154296722488,639021159672248,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-05-22 11:27:30+00,2041-05-22 11:27:30+00,1,1,mombasa,183009.52,2026-04-23 11:16:03.730519+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,general,NULL,NULL,NULL,mombasa +359857082902503,Felix Andole - KDC 207R,GT06E,automobile,KDC 207R,KDC 207R,Probox,automobile,NULL,NULL,NULL,NULL,Felix Andole,NULL,794820817,89254021224270993254,639021227099325,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-05-15 11:38:24+00,2041-05-15 11:38:24+00,1,1,mombasa,208724.46,2026-04-23 15:32:46.935568+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +359857082907973,Felix Muema - KCZ 223P,GT06E,automobile,KCZ 223P,KCZ 223P,Probox,automobile,NULL,NULL,NULL,NULL,Felix Muema,NULL,757843826,89254021154287138371,639021158713837,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-08-22 14:01:25+00,2040-08-22 23:59:59+00,1,1,mombasa,222126.36,2026-04-23 10:26:48.220151+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +359857082908500,Santoes Omondi - KCZ 181P,GT06E,automobile,KCZ 181P,KCZ 181P,Pick-Up,automobile,NULL,NULL,NULL,NULL,Santoes Omondi,NULL,701211974,89254021374215155087,639021371515508,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-08-23 08:58:55+00,2040-08-23 23:59:59+00,1,1,mombasa,221339.62,2026-04-23 10:48:09.537346+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +359857082910589,Patric Bett - KDA 609E,GT06E,automobile,KDA 609E,KDA 609E,Probox,automobile,NULL,NULL,NULL,NULL,Patric Bett,NULL,797622637,89254021154296722496,639021159672249,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2020-10-26 15:46:41+00,2040-10-26 23:59:59+00,1,1,nairobi,194618.69,2026-04-23 10:34:25.350862+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +359857082910886,Makanda Andrew - KCZ 155P,GT06E,automobile,KCZ 155P,KCZ 155P,Pick-Up,automobile,NULL,NULL,NULL,NULL,Makanda Andrew,NULL,745067338,89254021154287138397,639021158713839,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-08-23 11:52:35+00,2040-08-23 23:59:59+00,1,1,mombasa,231065.89,2026-04-23 11:36:31.150282+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +359857082911983,Brian Ngetich - KDA 717B,GT06E,automobile,KDA 717B,KDA 717B,Probox,automobile,NULL,NULL,NULL,NULL,Brian Ngetich,795188807,795188807,89254021214211145288,639021211114528,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-08-29 07:21:43+00,2041-08-29 07:21:43+00,1,1,nairobi,145404.96,2026-04-23 10:36:11.774166+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857082912239,Dickson Jaoko - KDK 815R,GT06E,automobile,KDK 815R,KDK 815R,Probox,automobile,NULL,NULL,Probox,0,Sammy,NULL,706392117,89254021234296021287,639021239602128,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2023-06-21 07:14:51+00,2033-06-21 23:59:59+00,1,1,voi,77008.75,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +359857082912486,Moses Wambua - KCZ 751V,GT06E,automobile,KCZ 751V,KCZ 751V,Probox,automobile,NULL,NULL,NULL,NULL,Moses Wambua,792756503,792756503,89254021154296723437,639021159672343,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-09-23 10:14:28+00,2040-09-23 23:59:59+00,1,1,mombasa,139762.2,2026-04-23 10:41:00.207177+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +359857082916826,Denis Kazungu - KDM 794R,GT06E,automobile,KDM 794R,KDM 794R,Probox,automobile,NULL,NULL,NULL,NULL,Denis Kazungu,NULL,705700971,89254021324273006854,639021327300685,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2023-08-21 06:38:00+00,2033-08-21 23:59:59+00,1,1,mombasa,79639.71,2026-04-23 20:18:46.496567+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +359857082918012,Charles Nyambane - KCB 711C,GT06E,automobile,KCB 711C,KCB 711C,Probox,automobile,NULL,NULL,NULL,NULL,Charles Nyambane,NULL,793704231,89254021154287138363,639021158713836,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2020-09-21 10:48:35+00,2040-09-21 23:59:59+00,1,1,nairobi,159597.27,2026-04-23 10:25:52.843474+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +359857082918038,Mbuvi Kioko - KCC 199P,GT06E,automobile,KCC 199P,KCC 199P,Pick-Up,automobile,NULL,NULL,NULL,NULL,Mbuvi Kioko,NULL,797318126,89254021154287138389,639021158713838,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-08-22 15:26:27+00,2040-08-22 23:59:59+00,1,1,mombasa,222106.8,2026-04-23 12:09:05.609075+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +359857082918186,KDD 977T Fielder,NULL,NULL,KDD 977T,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,unknown,null,NULL,2026-04-23 10:36:25.832836+00,2026-04-23 10:36:25.832836+00,NULL,NULL,null,NULL,NULL,NULL,null +359857082925330,Noel Merengeni - KCY 838X,GT06E,automobile,KCY 838X,KCY 838X,Probox,automobile,NULL,NULL,NULL,NULL,Noel Merengeni,NULL,794873610,89254021154296723429,639021159672342,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2020-10-26 16:36:37+00,2040-10-26 23:59:59+00,1,1,voi,194429.24,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +862798050288212,Nicholas Erastus - KCQ 581M,JC400P,automobile,KCQ 581M,KCQ 581M,Probox,automobile,NULL,NULL,NULL,NULL,Nicholas Erastus,NULL,746979531,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-11-02 09:07:41+00,2041-11-02 23:59:59+00,1,1,nairobi,40898.98,2026-04-23 13:05:18.326254+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050288261,Patric Bett - KDA 609E,JC400P,automobile,KDA 609E,KDA 609E,Probox,automobile,NULL,NULL,NULL,NULL,Patric Bett,112693340,790176509,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2021-10-23 11:50:11+00,2041-10-23 23:59:59+00,1,1,nairobi,18538.42,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798050288303,Elias Baya - KCZ 476E,JC400P,automobile,KCZ 476E,KCZ 476E,Probox,automobile,NULL,NULL,NULL,NULL,Elias Baya,NULL,115870439,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-11-06 08:50:28+00,2041-11-06 23:59:59+00,1,1,mombasa,116091.42,2026-04-23 17:46:09.993791+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +862798050288345,Santoes Omondi - KCZ 181P,JC400P,automobile,KCZ 181P,KCZ 181P,Pick-Up,automobile,NULL,NULL,NULL,NULL,Santoes Omondi,NULL,768446105,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2021-11-06 10:17:51+00,2041-11-06 23:59:59+00,1,1,mombasa,107462.79,2026-04-23 10:29:45.563231+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050288360,Brian Ngetich - KDA 717B,JC400P,automobile,KDA 717B,KDA 717B,Probox,automobile,NULL,NULL,NULL,NULL,Brian Ngetich,NULL,717867861,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2021-11-05 08:47:08+00,2041-11-05 23:59:59+00,1,1,nairobi,17808.56,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050521521,John Kimeria - KDS 525D,JC400P,automobile,KDS 525D,KDS 525D,Crane,truck,NULL,NULL,NULL,NULL,John Kimeria,NULL,752958416,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-11-26 07:58:13+00,2033-11-26 23:59:59+00,1,1,nairobi,19354.92,2026-04-23 10:28:34.917147+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,general,NULL,NULL,NULL,nairobi +862798050521612,Denis Kazungu - KDM 794R,JC400P,automobile,KDM 794R,KDM 794R,Probox,automobile,NULL,NULL,NULL,NULL,Denis Kazungu,NULL,704113731,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-22 07:52:12+00,2042-01-22 23:59:59+00,1,1,mombasa,4350.75,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +862798050521752,Simon Munda - KCZ 154S,JC400P,automobile,KCZ 154S,KCZ 154S,Probox,automobile,NULL,NULL,NULL,NULL,Simon Munda,NULL,113805921,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 08:14:37+00,2042-01-16 23:59:59+00,1,1,mombasa,4698.02,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050522065,Gideon Kiprono - KCQ 215F,JC400P,automobile,KCQ 215F,KCQ 215F,Probox,automobile,NULL,NULL,NULL,NULL,Gideon Kiprono,NULL,113343715,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2022-01-16 07:10:16+00,2042-01-16 23:59:59+00,1,1,mombasa,8111.98,2026-04-23 18:23:51.445608+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050522107,Cassius Wakiyo - KDB 323M,JC400P,automobile,KDB 323M,KDB 323M,Probox,automobile,NULL,NULL,NULL,NULL,Cassius Wakiyo,NULL,114149576,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-22 08:18:15+00,2042-01-22 23:59:59+00,1,1,nairobi,23316.09,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798050522719,Mbuvi Kioko - KCZ 199P,JC400P,automobile,KCZ 199P,KCZ 199P,Pick-Up,automobile,NULL,NULL,NULL,NULL,Mbuvi Kioko,NULL,768218655,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 22:07:24+00,2042-01-16 23:59:59+00,1,1,voi,16973.89,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050522743,Charles Nyambane - KCB 711C,JC400P,automobile,KCB 711C,KCB 711C,Probox,automobile,NULL,NULL,NULL,NULL,Charles Nyambane,NULL,768657106,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2023-12-22 21:53:57+00,2033-12-22 23:59:59+00,1,1,nairobi,12133.75,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050522859,Garage - KCH 167M,JC400P,automobile,KCH 167M,KCH 167M,Probox,automobile,NULL,NULL,NULL,NULL,Garage,NULL,706740252,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-15 08:23:21+00,2042-01-15 23:59:59+00,1,1,nairobi,6934.86,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798050522883,Dan Watila - KDE 638J,JC400P,automobile,KDE 638J,KDE 638J,Probox,automobile,NULL,NULL,NULL,NULL,Dan Watila,NULL,112615393,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-15 07:17:21+00,2042-01-15 23:59:59+00,1,1,nairobi,14483.01,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050522891,Lawrence Kijogi - KCY 080X,JC400P,automobile,KCY 080X,KCY 080X,Pick-Up,automobile,NULL,NULL,NULL,NULL,Lawrence Kijogi,NULL,113287191,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 10:51:30+00,2042-01-16 23:59:59+00,1,1,mombasa,11585.33,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,mombasa +862798050523014,Samuel Muriithy - KDR 594N,JC400P,automobile,KDR 594N,KDR 594N,Probox,automobile,NULL,NULL,NULL,NULL,Samuel Muriithy,NULL,790175423,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-12-21 15:54:32+00,2033-12-21 23:59:59+00,1,1,nairobi,27275.43,2026-04-23 10:26:17.747928+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,nairobi +862798050523063,Kelvin Wambugu - KDR 594N,JC400P,automobile,KDR 594N,KDR 594N,Probox,automobile,NULL,NULL,NULL,NULL,Kelvin Wambugu,NULL,701211876,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-12-22 19:24:51+00,2043-12-22 19:24:51+00,1,1,nairobi,32698.94,2026-04-23 15:31:08.065856+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +862798050523139,Mike Wanaswa - KDT 724R,JC400P,automobile,KDT 724R,KDT 724R,Probox,automobile,NULL,NULL,NULL,NULL,Mike Wanaswa,NULL,790175045,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-12-22 22:28:09+00,2043-12-22 22:28:09+00,1,1,mombasa,29559.82,2026-04-23 11:16:37.277518+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050523204,Amani Kazungu - KCY 084X,JC400P,automobile,KCY 084X,KCY 084X,Probox,automobile,NULL,NULL,NULL,NULL,Amani Kazungu,NULL,707892547,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 06:18:20+00,2042-01-16 23:59:59+00,1,1,mombasa,66955.7,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +862798050523295,Emmanuel Luseno - KDS 453 Y,JC400P,automobile,KDS 453 Y,KDS 453 Y,Pick-Up,automobile,NULL,NULL,NULL,NULL,Emmanuel Luseno,NULL,700242474,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-12-22 14:39:50+00,2033-12-22 23:59:59+00,1,1,nairobi,37098.35,2026-04-23 11:29:48.369147+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,general,NULL,NULL,NULL,nairobi +862798050523337,Victor Kimutai - KDS 919Y,JC400P,automobile,KDS 919Y,KDS 919Y,Probox,automobile,NULL,NULL,NULL,NULL,Victor Kimutai,NULL,700242527,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-12-22 18:00:49+00,2043-12-22 18:00:49+00,1,1,mombasa,50756.64,2026-04-23 10:27:13.522675+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050523386,George Ochieng' - KDD 684Y,JC400P,automobile,KDD 684Y,KDD 684Y,Probox,automobile,NULL,NULL,NULL,NULL,George Ochieng',NULL,785586834,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-22 06:36:08+00,2042-01-22 23:59:59+00,1,1,nairobi,33979.83,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798050523527,Allan Owana - KDK 780K,JC400P,automobile,KDK 780K,KDK 780K,Probox,automobile,NULL,NULL,NULL,NULL,Allan Owana,NULL,792375024,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2022-12-03 10:43:41+00,2042-12-03 23:59:59+00,1,1,nairobi,109564.95,2026-04-23 10:25:24.360765+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050523618,Geoffrey Too - KDM 308S,JC400P,automobile,KDM 308S,KDM 308S,Probox,automobile,NULL,NULL,NULL,NULL,Geoffrey Too,NULL,701211625,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2023-08-15 15:42:32+00,2033-08-15 23:59:59+00,1,1,nairobi,26496.5,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798050523626,Major Simiyu - KDS 949Y,JC400P,automobile,KDS 949Y,KDS 949Y,Probox,automobile,NULL,NULL,NULL,NULL,Major Simiyu,NULL,701211892,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-12-22 18:05:16+00,2033-12-22 23:59:59+00,1,1,mombasa,37042.97,2026-04-23 10:51:18.245194+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +862798050523816,Job Ngare - KDM 309S,JC400P,automobile,KDM 309S,KDM 309S,Probox,automobile,NULL,NULL,NULL,NULL,Job Ngare,NULL,707936781,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2023-08-15 14:05:52+00,2033-08-15 23:59:59+00,1,1,mombasa,54320.21,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050523949,Joseph Kabandi - KCY 076X,JC400P,automobile,KCY 076X,KCY 076X,Probox,automobile,NULL,NULL,NULL,NULL,Joseph Kabandi,NULL,113288492,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 05:52:54+00,2042-01-16 23:59:59+00,1,1,mombasa,14427.5,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050524012,Moses Wambua - KCZ 751V,JC400P,automobile,KCZ 751V,KCZ 751V,Probox,automobile,NULL,NULL,NULL,NULL,Moses Wambua,NULL,113313797,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 07:40:10+00,2042-01-16 23:59:59+00,1,1,mombasa,26551.46,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050524087,Felix Muema - KCZ 223P,JC400P,automobile,KCZ 223P,KCZ 223P,Pick-Up,automobile,NULL,NULL,NULL,NULL,Felix Muema,NULL,113973875,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 13:02:24+00,2042-01-16 23:59:59+00,1,1,mombasa,11543.26,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050524368,862798050524368,JC400P,automobile,NULL,NULL,NULL,automobile,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-10-29 09:24:53+00,2042-10-29 23:59:59+00,1,1,null,169208.91,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,null,NULL,NULL,NULL,null +862798050524384,Hamisi Pande - KDD 689Y,JC400P,automobile,KDD 689Y,KDD 689Y,Probox,automobile,NULL,NULL,NULL,0,Hamisi Pande,NULL,701211744,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-22 05:49:19+00,2042-01-22 23:59:59+00,1,1,nairobi,13685.18,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050524392,Ndegwa Dancun - KCG 669W,JC400P,automobile,KCG 669W,KCG 669W,Probox,automobile,NULL,NULL,NULL,NULL,Ndegwa Dancun,NULL,113799173,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 09:43:10+00,2042-01-16 23:59:59+00,1,1,mombasa,13638.25,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050524426,Amani Sulubu - KCY 090X,JC400P,automobile,KCY 090X,KCY 090X,Probox,automobile,NULL,NULL,NULL,NULL,Amani Sulubu,NULL,113823350,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2022-01-16 08:56:25+00,2042-01-16 23:59:59+00,1,1,mombasa,14243.83,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050524533,Leonard Nzai - KDM 306S,JC400P,automobile,KDM 306S,KDM 306S,Probox,automobile,NULL,NULL,NULL,NULL,Leonard Nzai,NULL,703487162,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-08-21 08:22:12+00,2033-08-21 23:59:59+00,1,1,mombasa,68942.41,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050524558,Mutuku Joseph - KDC 739F,JC400P,automobile,KDC 739F,KDC 739F,Probox,automobile,NULL,NULL,NULL,NULL,Mutuku Joseph,NULL,100858817,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-22 10:38:25+00,2042-01-22 23:59:59+00,1,1,nairobi,23711.63,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +862798050524566,Makanda Andrew - KCZ 155P,JC400P,automobile,KCZ 155P,KCZ 155P,Pick-Up,automobile,NULL,NULL,NULL,NULL,Makanda Andrew,NULL,758781444,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-22 09:47:33+00,2042-01-22 23:59:59+00,1,1,mombasa,31663.3,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050524608,Peter Mbugua - KDK 728K,JC400P,automobile,KDK 728K,KDK 728K,Probox,automobile,NULL,NULL,NULL,NULL,Peter Mbugua,NULL,706742413,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-12-03 12:11:32+00,2042-12-03 23:59:59+00,1,1,nairobi,7219.31,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050524657,Felix Andole - KDC 207R,JC400P,automobile,KDC 207R,KDC 207R,Probox,automobile,NULL,NULL,NULL,NULL,Felix Andole,NULL,758689195,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-22 07:17:47+00,2042-01-22 23:59:59+00,1,1,mombasa,46233.99,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050524681,Mutuku Antony - KDK 732K,JC400P,automobile,KDK 732K,KDK 732K,Probox,automobile,NULL,NULL,NULL,NULL,Mutuku Antony,NULL,796275746,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-12-06 13:37:49+00,2042-12-06 23:59:59+00,1,1,mombasa,14993.36,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +862798050524707,Garage - KCE 699F,JC400P,automobile,KCE 699F,KCE 699F,Probox,automobile,NULL,NULL,NULL,NULL,Garage,NULL,110525751,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-15 07:58:49+00,2042-01-15 23:59:59+00,1,1,nairobi,34715.97,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,nairobi +862798050524897,Cornelius Kimutai - KCU 938R,JC400P,automobile,KCU 938R,KCU 938R,Van,automobile,NULL,NULL,NULL,NULL,Cornelius Kimutai,NULL,114924404,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-22 09:03:40+00,2042-01-22 23:59:59+00,1,1,nairobi,12668.43,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +862798050525068,Samuel Ng'ang'a - KDE 264M,JC400P,automobile,KDE 264M,KDE 264M,Probox,automobile,NULL,NULL,NULL,NULL,Samuel Ng'ang'a,NULL,768658564,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2023-12-22 13:33:42+00,2033-12-22 23:59:59+00,1,1,nairobi,12299.13,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050525225,Sadique Wakayula - KDC 490Q,JC400P,automobile,KDC 490Q,KDC 490Q,Crane,truck,NULL,NULL,NULL,NULL,Sadique Wakayula,NULL,768652386,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2023-12-22 20:52:08+00,2043-12-22 20:52:08+00,1,1,mombasa,19138.05,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,general,NULL,NULL,NULL,nairobi +862798050525266,Dickson Jaoko - KDK 815R,JC400P,automobile,KDK 815R,KDK 815R,Probox,automobile,NULL,NULL,NULL,NULL,Dickson Jaoko,NULL,706665867,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-06-21 07:50:00+00,2033-06-21 23:59:59+00,1,1,mombasa,63754.71,2026-04-23 13:50:24.21992+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050525423,Makori John - KDB 585E,JC400P,automobile,KDB 585E,KDB 585E,Probox,automobile,NULL,NULL,NULL,NULL,Makori John,NULL,701211724,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-15 10:59:19+00,2042-01-15 23:59:59+00,1,1,mombasa,48804.83,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,planning,NULL,NULL,NULL,mombasa +862798050525589,Simon Kamau - KCE 090R,JC400P,automobile,KCE 090R,KCE 090R,Probox,automobile,NULL,NULL,NULL,NULL,Simon Kamau,NULL,796276387,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-19 10:10:04+00,2042-01-19 23:59:59+00,1,1,nairobi,15874.39,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050525605,Samuel Kamau - KCA 542Q,JC400P,automobile,KCA 542Q,KCA 542Q,Probox,automobile,NULL,NULL,NULL,NULL,John Ondego,NULL,110526783,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-15 05:56:11+00,2042-01-15 23:59:59+00,1,1,nairobi,23976.94,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,nairobi +862798050525613,Kennedy Chege - KCQ 618K,JC400P,automobile,KCQ 618K,KCQ 618K,Probox,automobile,NULL,NULL,NULL,NULL,Kennedy Chege,NULL,729994247,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-16 05:21:05+00,2042-01-16 23:59:59+00,1,1,mombasa,12804.24,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +862798050525670,Gabriel Musumba - KCE 690F,JC400P,automobile,KCE 690F,KCE 690F,Probox,automobile,NULL,NULL,NULL,NULL,Gabriel Musumba,NULL,701211996,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2022-01-15 06:40:01+00,2042-01-15 23:59:59+00,1,1,nairobi,20110.93,2026-04-24 05:34:23.167312+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798050525753,Noel Merengeni - KCY 838X,JC400P,automobile,KCY 838X,KCY 838X,Probox,automobile,NULL,NULL,NULL,NULL,Noel Merengeni,NULL,NULL,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2022-01-15 05:24:00+00,2042-01-15 23:59:59+00,1,1,voi,14596.59,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,voi +862798050525837,Kennedy Ondieki - KCU 237Z,JC400P,automobile,KCU 237Z,KCU 237Z,Probox,automobile,NULL,NULL,NULL,NULL,Kennedy Ondieki,NULL,113669852,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2023-12-21 19:32:44+00,2033-12-21 23:59:59+00,1,1,nairobi,NULL,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798050525951,Wright Oseko - KCG 668W,JC400P,automobile,KCG 668W,KCG 668W,Probox,automobile,NULL,NULL,NULL,NULL,Wright Oseko,NULL,741943212,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2022-01-15 09:36:45+00,2042-01-15 23:59:59+00,1,1,nairobi,13116,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798050526165,Wilfred Kinyanjui - KCU 729C,JC400P,automobile,KCU 729C,KCU 729C,Crane,truck,NULL,NULL,NULL,NULL,Wilfred Kinyanjui,NULL,790564929,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2023-11-26 10:17:19+00,2033-11-26 23:59:59+00,1,1,nairobi,24270.2,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,general,NULL,NULL,NULL,nairobi +862798050526231,Rashid Hassan - KDM 840V,JC400P,automobile,KDM 840V,KDM 840V,Probox,automobile,NULL,NULL,NULL,NULL,Rashid Hassan,NULL,790175526,NULL,NULL,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2023-12-22 22:36:15+00,2043-12-22 22:36:15+00,1,1,mombasa,45418.38,2026-04-23 10:29:41.575467+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +862798050526256,Ian Dancun - KDT 923R,JC400P,automobile,KDT 923R,KDT 923R,Probox,automobile,NULL,NULL,NULL,NULL,Ian Dancun,NULL,794873610,NULL,NULL,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2023-12-22 19:37:24+00,2043-12-22 19:37:24+00,1,1,mombasa,11093.11,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,qehs,NULL,NULL,NULL,mombasa +862798052707888,Benjamin Ananda - KDV 438W,JC400P,automobile,KDV 438W,KDV 438W,Probox,automobile,NULL,NULL,NULL,NULL,Benjamin Ananda,NULL,758047312,89254021414206816980,639021410681698,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-12-15 07:39:23+00,2035-12-15 23:59:59+00,1,1,nairobi,8720.87,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,planning,NULL,NULL,NULL,nairobi +862798052707896,John Mbugua - KDW 573B,JC400P,automobile,KDW 573B,KDW 573B,Probox,automobile,NULL,NULL,NULL,NULL,John Mbugua,NULL,NULL,89254021414206816725,639021410681672,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2026-01-30 14:48:17+00,2036-01-30 23:59:59+00,1,1,nairobi,515.16,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798052707946,Tom Wekesa/OSP-KCY 930Y_CAM,JC400P,automobile,KCY 930Y,NULL,NULL,automobile,NULL,NULL,NULL,NULL,NULL,NULL,758047806,89254021414206816766,639021410681676,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2026-01-20 21:02:13+00,2036-01-20 23:59:59+00,1,1,nairobi,10079.17,2026-04-23 10:25:24.363965+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798052708035,862798052708035,JC400P,automobile,NULL,NULL,Probox,automobile,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,NULL,NULL,1,1,null,NULL,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,null,NULL,NULL,NULL,null +862798052708068,Dominic Wambua - KDV 683Z,JC400P,automobile,KDV 683Z,KDV 683Z,Probox,automobile,NULL,NULL,NULL,NULL,Dominic Wambua,NULL,758048043,89254021414206816964,639021410681696,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2026-01-24 09:20:09+00,2036-01-24 23:59:59+00,1,1,nairobi,4438.55,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,nairobi +862798052708076,Albert Mutwiri - KDV 437W,JC400P,automobile,KDV 437W,KDV 437W,Probox,automobile,NULL,NULL,NULL,NULL,Albert Mutwiri,NULL,758047094,89254021414206816782,639021410681678,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-12-13 15:03:30+00,2035-12-13 23:59:59+00,1,1,nairobi,5575.64,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +862798052708167,Levine Wasike - KDV 439W,JC400P,automobile,KDV 439W,KDV 439W,Probox,automobile,NULL,NULL,NULL,NULL,Levine Wasike,NULL,758046738,89254021414206816741,639021410681674,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-12-13 19:49:29+00,2035-12-13 23:59:59+00,1,1,nairobi,4601.08,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798052708282,Godffrey Nandwa - KCN 496A,JC400P,automobile,KCN 496A,KCN 496A,Probox,automobile,NULL,NULL,NULL,NULL,Godffrey Nandwa,NULL,758047934,89254021414206816865,639021410681686,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2026-01-25 18:55:54+00,2036-01-25 23:59:59+00,1,1,nairobi,7040.6,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798052713654,Garage/ISP_KCL 502T_CAM,JC400P,automobile,KCL 502T,NULL,NULL,automobile,NULL,NULL,NULL,NULL,NULL,NULL,780215879,89254035061001753803,639035060175380,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-09-02 10:09:57+00,2035-09-02 23:59:59+00,1,1,nairobi,5199.72,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798052713696,862798052713696,JC400P,automobile,NULL,NULL,Probox,automobile,NULL,NULL,NULL,NULL,NULL,NULL,NULL,89254021394215205906,639021391520590,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-09-02 10:20:58+00,2035-09-02 23:59:59+00,1,1,null,6214.49,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,null,NULL,NULL,NULL,null +862798052713761,Management_Mazda - KDU 613A,JC400P,automobile,KDU 613A,KDU 613A,Mazda,automobile,NULL,NULL,NULL,NULL,Management_Mazda,NULL,790176786,89254021394215205955,639021391520595,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-07-09 15:49:26+00,2035-07-09 23:59:59+00,1,1,nairobi,9262.78,2026-04-23 16:40:48.879666+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,management,NULL,NULL,NULL,nairobi +862798052713779,Benard Kimutai - KDN 759G,JC400P,automobile,KDN 759G,KDN 759G,Probox,automobile,NULL,NULL,NULL,NULL,Benard Kimutai,NULL,752143258,89254035061001753860,639035060175386,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-08-23 11:15:59+00,2035-08-23 23:59:59+00,1,1,nairobi,5344.24,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +862798052713811,James Onyango - KDU 613B,JC400P,automobile,KDU 613B,KDU 613B,Probox,automobile,NULL,NULL,NULL,NULL,James Onyango,NULL,790176542,89254021394215205880,639021391520588,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-09 19:24:14+00,2035-07-09 23:59:59+00,1,1,nairobi,9657.42,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798052713837,Kennedy Ondieki - KCU 237Z,JC400P,automobile,KCU 237Z,KCU 237Z,Probox,automobile,NULL,NULL,NULL,NULL,Kennedy Ondieki,NULL,113669852,89254021414206327855,639021410632785,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-10-08 14:55:23+00,2035-10-08 23:59:59+00,1,1,nairobi,9346.02,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +862798052713985,Timothy Gitau - KDT 916R,JC400P,automobile,KDT 916R,KDT 916R,Probox,automobile,NULL,NULL,NULL,NULL,Timothy Gitau,NULL,768696668,89254021394274518892,639021397451889,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-08-02 18:21:23+00,2035-08-02 23:59:59+00,1,1,mombasa,19998.22,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,regional,NULL,NULL,NULL,mombasa +862798052714066,862798052714066,JC400P,automobile,NULL,NULL,Probox,automobile,NULL,NULL,NULL,NULL,NULL,NULL,NULL,89254021414206378684,639021410637868,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-11-21 17:44:44+00,2035-11-21 23:59:59+00,1,1,null,10755.28,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,null,NULL,NULL,NULL,null +862798052715220,Rofas Njagi - KDT 728R,JC400P,automobile,KDT 728R,KDT 728R,Probox,automobile,NULL,NULL,NULL,NULL,Rofas Njagi,NULL,704573658,89254021334258495873,639021335849587,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-16 07:09:25+00,2035-07-16 23:59:59+00,1,1,nairobi,16385.58,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,regional,NULL,NULL,NULL,nairobi +865135061035133,Major Simiyu - KDS 949Y,X3,automobile,KDS 949Y,KDS 949Y,Probox,automobile,NULL,NULL,NULL,NULL,Major Simiyu,NULL,768696642,89254021394274518918,639021397451891,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2025-08-02 13:14:33+00,2035-08-02 23:59:59+00,1,1,mombasa,25089.98,2026-04-23 12:07:56.044395+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,mombasa +865135061035653,Richardson Komu - KDT 923R,X3,automobile,KDT 923R,KDT 923R,Probox,automobile,NULL,NULL,NULL,NULL,Richardson Komu,NULL,768697292,89254021394274518942,639021397451894,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-08-02 08:11:46+00,2035-08-02 23:59:59+00,1,1,mombasa,23556.65,2026-04-23 10:24:50.340401+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +865135061035778,John Kimeria - KDS 525D,X3,automobile,KDS 525D,KDS 525D,Crane,truck,NULL,NULL,NULL,NULL,John Kimeria,NULL,790176738,89254021394215205922,639021391520592,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-11 05:50:36+00,2035-07-11 23:59:59+00,1,1,nairobi,17653.96,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,general,NULL,NULL,NULL,nairobi +865135061036164,Brian Njenga - KMFF 113Z,X3,automobile,KMFF 113Z,KMFF 113Z,Motorbike,mtc,NULL,NULL,NULL,NULL,Brian Njenga,NULL,768696705,89254021394274518850,639021397451885,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-31 10:06:46+00,2035-07-31 23:59:59+00,1,1,nairobi,22990.33,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,deliveries,NULL,NULL,NULL,nairobi +865135061037980,Emmanuel Luseno - KDS 453Y,X3,automobile,KDS 453Y,KDS 453Y,Pick-Up,automobile,NULL,NULL,NULL,NULL,Emmanuel Luseno,NULL,790176734,89254021394215205856,639021391520585,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-15 06:30:34+00,2035-07-15 23:59:59+00,1,1,nairobi,42609.03,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,general,NULL,NULL,NULL,nairobi +865135061042261,Kelvin Wambugu - KDR 592N,X3,automobile,KDR 592N,KDR 592N,Probox,automobile,NULL,NULL,NULL,NULL,Kelvin Wambugu,NULL,797680464,89254021334258159693,639021335815969,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-10 10:23:44+00,2035-07-10 23:59:59+00,1,1,nairobi,18755.66,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +865135061043079,Mike Wanaswa - KDT 724R,X3,automobile,KDT 724R,KDT 724R,Probox,automobile,NULL,NULL,NULL,NULL,Mike Wanaswa,NULL,768696664,89254021394274518959,639021397451895,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2025-08-02 12:16:11+00,2035-08-02 23:59:59+00,1,1,mombasa,27470.11,2026-04-23 11:16:35.682194+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +865135061043426,Geoffrey Karanja - KMGS 239H,X3,automobile,KMGS 239H,KMGS 239H,Motorbike,mtc,NULL,NULL,NULL,NULL,Geoffrey Karanja,NULL,768696658,89254021394274518926,639021397451892,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-08-22 13:32:25+00,2035-08-22 23:59:59+00,1,1,nairobi,21267.01,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp patrol,NULL,NULL,NULL,nairobi +865135061047435,Management_Mazda - KDU 613A,X3,automobile,KDU 613A,KDU 613A,Mazda,automobile,NULL,NULL,NULL,NULL,Management_Mazda,NULL,790175971,89254021394215205971,639021391520597,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-09 08:02:26+00,2035-07-09 23:59:59+00,1,1,nairobi,9761.38,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,management,NULL,NULL,NULL,nairobi +865135061048276,Victor Kimutai - KDS 919Y,X3,automobile,KDS 919Y,KDS 919Y,Probox,automobile,NULL,NULL,NULL,NULL,Victor Kimutai,NULL,768696755,89254021394274518900,639021397451890,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2025-08-02 07:38:01+00,2035-08-02 23:59:59+00,1,1,mombasa,23296.79,2026-04-23 10:54:41.63532+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,mombasa +865135061048300,KMGR 409U HENRY JAZZ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,unknown,nairobi,NULL,2026-04-24 04:30:20.231102+00,2026-04-24 04:30:20.231102+00,NULL,NULL,personal,NULL,NULL,NULL,nairobi +865135061048466,Samuel Muriithy - KDR 594N,X3,automobile,KDR 594N,KDR 594N,Probox,automobile,NULL,NULL,NULL,NULL,Samuel Muriithy,NULL,797680395,89254021334258159628,639021335815962,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-07-24 09:37:31+00,2035-07-24 23:59:59+00,1,1,nairobi,27634.1,2026-04-23 11:43:39.178819+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,nairobi +865135061048615,Office-KMDG 902Z,X3,automobile,KMDG 902Z,NULL,NULL,automobile,NULL,NULL,NULL,NULL,NULL,NULL,768697276,89254021394274518876,639021397451887,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-31 09:59:43+00,2035-07-31 23:59:59+00,1,1,nairobi,5721.21,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp patrol,NULL,NULL,NULL,nairobi +865135061048953,Timothy Gitau - KDT 916R,X3,automobile,KDT 916R,KDT 916R,Probox,automobile,NULL,NULL,NULL,NULL,Timothy Gitau,NULL,768697056,89254021394274518967,639021397451896,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2025-08-02 08:48:05+00,2035-08-02 23:59:59+00,1,1,mombasa,28536.23,2026-04-23 10:53:31.102315+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,regional,NULL,NULL,NULL,mombasa +865135061049001,Parked - KMGK 596V,X3,automobile,KMGK 596V,KMGK 596V,Motorbike,mtc,NULL,NULL,NULL,NULL,Parked,NULL,768697064,89254021394274518884,639021397451888,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-31 08:40:18+00,2035-07-31 23:59:59+00,1,1,nairobi,20612.89,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,deliveries,NULL,NULL,NULL,nairobi +865135061053714,Samuel Kihara - KMEL 225X,X3,automobile,KMEL 225X,KMEL 225X,Motorbike,mtc,NULL,NULL,NULL,NULL,Samuel Kihara,NULL,768696832,89254021394274518934,639021397451893,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-08-02 13:51:47+00,2035-08-02 23:59:59+00,1,1,nairobi,26897.18,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp patrol,NULL,NULL,NULL,nairobi +865135061053748,Rashid Hassan - KDM 840V,X3,automobile,KDM 840V,KDM 840V,Probox,automobile,NULL,NULL,NULL,NULL,Rashid Hassan,NULL,768445963,89254021334212352574,639021331235257,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-07-10 13:54:11+00,2035-07-10 23:59:59+00,1,1,mombasa,26612.42,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,mombasa +865135061054548,James Onyango - KDU 613B,X3,automobile,KDU 613B,KDU 613B,Probox,automobile,NULL,NULL,NULL,NULL,James Onyango,NULL,790175997,89254021394215205948,639021391520594,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-07-09 07:11:15+00,2035-07-09 23:59:59+00,1,1,nairobi,13446.05,2026-04-23 10:26:24.667167+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,isp,NULL,NULL,NULL,nairobi +865135061054555,Rofas Njagi - KDT 728R,X3,automobile,KDT 728R,KDT 728R,Probox,automobile,NULL,NULL,NULL,NULL,Rofas Njagi,NULL,790176726,89254021394215205823,639021391520582,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-07-16 06:44:33+00,2035-07-16 23:59:59+00,1,1,nairobi,27250.8,2026-04-23 10:25:21.085437+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,regional,NULL,NULL,NULL,nairobi +865135061559538,FRED KMGW 538W HULETI,NULL,NULL,KMGW 538W,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,unknown,null,NULL,2026-04-23 10:42:18.5831+00,2026-04-23 10:42:18.5831+00,NULL,NULL,null,NULL,NULL,NULL,null +865135061562722,John Mbugua - KDW 573B,X3,automobile,KDW 573B,KDW 573B,Probox,automobile,NULL,NULL,NULL,NULL,John Mbugua,NULL,758052508,89254021414206816832,639021410681683,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2026-01-30 06:53:57+00,2036-01-30 23:59:59+00,1,1,nairobi,4488.19,2026-04-23 10:25:38.887433+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +865135061562847,Levine Wasike - KDV 439W,X3,automobile,KDV 439W,KDV 439W,Probox,automobile,NULL,NULL,NULL,NULL,Levine Wasike,NULL,758047032,89254021414206816840,639021410681684,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2025-12-13 11:14:14+00,2035-12-13 23:59:59+00,1,1,nairobi,7880.92,2026-04-23 10:35:50.779597+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,osp,NULL,NULL,NULL,nairobi +865135061563282,X3-63282,X3,automobile,NULL,NULL,NULL,automobile,NULL,NULL,NULL,NULL,NULL,NULL,NULL,8925610001837573427F,641101970467668,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2026-02-14 07:20:10+00,2036-02-14 23:59:59+00,1,1,null,4758.32,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,null,NULL,NULL,NULL,null +865135061563415,Barack Orwa - KDW 781E,X3,automobile,KDW 781E,KDW 781E,Vazel,automobile,NULL,NULL,NULL,NULL,Barack Orwa,NULL,758052541,89254021414206816931,639021410681693,Fireside_MSA,Fireside Group MSA,9d0927d235e44fe7abf254902fc68921,Default group,2026-01-13 12:37:42+00,2036-01-13 23:59:59+00,1,1,nairobi,4165.95,2026-04-23 11:22:00.676215+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,personal,NULL,NULL,NULL,nairobi +865135061563423,Joel Ntumba - UMA 826AB,X3,automobile,UMA 826AB,UMA 826AB,Motorbike,mtc,NULL,NULL,NULL,NULL,Joel Ntumba,NULL,119051036,89254021414206652690,639021410665269,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2026-01-28 13:55:39+00,2036-01-28 23:59:59+00,1,1,uganda,1174.05,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,mtn,NULL,NULL,NULL,uganda +865135061563597,Dominic Wambua - KDV 683Z,X3,automobile,KDV 683Z,KDV 683Z,Probox,automobile,NULL,NULL,NULL,NULL,Dominic Wambua,NULL,758052405,89254021414206816733,639021410681673,Fireside@HQ,Fireside Telematics,6ef0b0fc2d964b358b70dc2cfcbc5b7e,Default group,2026-01-30 06:55:35+00,2036-01-30 23:59:59+00,1,1,nairobi,6790.53,2026-04-23 10:25:40.125927+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,roll out,NULL,NULL,NULL,nairobi +865135061563639,Benjamin Ananda - KDV 438W,X3,automobile,KDV 438W,KDV 438W,Probox,automobile,NULL,NULL,NULL,NULL,Benjamin Ananda,NULL,758047065,89254021414206816683,639021410681668,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-12-13 16:02:37+00,2035-12-13 23:59:59+00,1,1,nairobi,14446.33,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,planning,NULL,NULL,NULL,nairobi +865135061564280,Rodin Kiberu - UMA 011EK,X3,automobile,UMA 011EK,UMA 011EK,Motorbike,mtc,NULL,NULL,NULL,NULL,Rodin Kiberu,NULL,118081642,89254021414206817244,639021410681724,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2026-01-28 13:13:57+00,2036-01-28 23:59:59+00,1,1,uganda,841.39,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,mtn,NULL,NULL,NULL,uganda +865135061564470,Silvanus Kipkorir - KDV 064S,X3,automobile,KDV 064S,KDV 064S,Probox,automobile,NULL,NULL,NULL,NULL,Silvanus Kipkorir,NULL,113669866,89254021414206378718,639021410637871,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-11-21 16:49:17+00,2035-11-21 23:59:59+00,1,1,nairobi,23869.16,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,airtel,NULL,NULL,NULL,nairobi +865135061568968,X3-68968,X3,automobile,NULL,NULL,NULL,automobile,NULL,NULL,NULL,NULL,NULL,NULL,NULL,89254021414206816915,639021410681691,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2026-03-11 06:19:14+00,2036-03-11 23:59:59+00,1,1,null,16.23,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,null,NULL,NULL,NULL,null +865135061569123,Albert Mutwiri - KDV 437W,X3,automobile,KDV 437W,KDV 437W,Probox,automobile,NULL,NULL,NULL,NULL,Albert Mutwiri,NULL,758047101,89254021414206816881,639021410681688,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-12-13 14:26:17+00,2035-12-13 23:59:59+00,1,1,nairobi,13032.6,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi +865135061569131,UMA 418EK,X3,automobile,UMA 418EK,UMA 418EK,NULL,automobile,NULL,NULL,NULL,NULL,UG,NULL,256792997053,8925610001837573385F,641101970467664,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2026-02-26 08:15:44+00,2036-02-26 23:59:59+00,1,1,uganda,2333.45,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,mtn,NULL,NULL,NULL,uganda +865135061569479,UMA 382EK,X3,automobile,UMA 382EK,UMA 382EK,NULL,automobile,NULL,NULL,NULL,NULL,UG,NULL,256792997079,8925610001837573419F,641101970467667,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2026-02-26 08:21:10+00,2036-02-26 23:59:59+00,1,1,uganda,1954.86,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,mtn,NULL,NULL,NULL,uganda +865135061578553,X3-78553,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,unknown,null,NULL,2026-04-23 15:30:19.981271+00,2026-04-23 15:30:19.981271+00,NULL,NULL,null,NULL,NULL,NULL,null +865135061581904,Robert Kipruto - KDV 072L,X3,automobile,KDV 072L,KDV 072L,Probox,automobile,NULL,NULL,NULL,NULL,Robert Kipruto,NULL,114149576,89254021264261503993,639021266150399,fireside,Fireside Group HQ,2f1acaef6c884214b4598719180fe68d,Default group,2025-11-21 15:30:29+00,2035-11-21 23:59:59+00,1,1,nairobi,15252.84,2026-04-23 10:23:56.546784+00,2026-04-24 07:43:45.210628+00,2026-04-24 07:43:45.210628+00,NULL,fds,NULL,NULL,NULL,nairobi \ No newline at end of file diff --git a/260427_audit_output.txt b/260427_audit_output.txt new file mode 100644 index 0000000..ac94022 --- /dev/null +++ b/260427_audit_output.txt @@ -0,0 +1,75 @@ +============================================================================ + Device reconciliation — CSV vs tracksolid.devices +============================================================================ + CSV file : 20260427_FSG_Vehicles_mitieng.csv + CSV row count : 162 + DB row count : 172 + Delta (DB-CSV) : +10 + +─ Per-account breakdown ───────────────────────────────────────────────── + account CSV DB delta + (blank) 0 10 +10 + Fireside@HQ 52 52 +0 + Fireside_MSA 41 41 +0 + NULL 6 0 -6 + fireside 63 69 +6 + +─ IMEIs in DB but NOT in CSV (10) ───────────────────────────── + imei account city last_synced_at device_name + 359857081891921 JK Subaru KCS 903Y + 359857082898297 KDK 829A GP + 862798052707995 fireside 2026-04-27 19:30:53.484218+00:00 JC400P-07995 + 862798052715071 KDU 878T_CAM + 862798052785751 fireside 2026-04-27 19:30:53.484218+00:00 JC400P-85751 + 862798052786270 fireside 2026-04-27 19:30:53.484218+00:00 JC400P-86270 + 865135061040349 KDU 878T_Track + 865135061559405 X3-59405 + 865135061569172 fireside 2026-04-27 19:30:53.484218+00:00 X3-69172 + 865135061569529 fireside 2026-04-27 19:30:53.484218+00:00 X3-69529 + +─ IMEIs in CSV but NOT in DB (0) ───────────────────────────── + (none — every CSV row has a corresponding device row) + +─ Devices in both, but DB metadata still NULL (162) ────────────── + Likely cause: import_drivers_csv.py has not been re-run with --apply + against the new CSV, or rows had 'Identification' placeholders. + + imei blank_fields + 353549090553685 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 353549090561720 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address, driver_name, vehicle_number + 353549090566281 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address, driver_name, vehicle_number + 353549090566885 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address, driver_name, vehicle_number + 353549090567685 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 353549090567701 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address, driver_name, vehicle_number + 359857081885410 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081886467 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, depot_address + 359857081886871 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address, driver_name, vehicle_number + 359857081886905 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081887069 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081887192 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081891566 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081891590 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081891632 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081891798 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081892101 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081892309 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857081892440 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address, driver_name, vehicle_number + 359857081892762 assigned_city, cost_centre, assigned_route, vehicle_category, fuel_100km, depot_address, driver_name, vehicle_number + 359857082037185 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857082038977 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857082040981 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857082042052 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857082042854 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857082042953 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address, driver_name, vehicle_number + 359857082044280 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857082046145 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857082896911 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + 359857082897091 assigned_city, cost_centre, assigned_route, vehicle_category, vehicle_brand, fuel_100km, depot_address + ... and 132 more + +─ Suggested next step ─────────────────────────────────────────────────── + Inspect the IMEIs above. Decide one of: + (a) Prune — delete from tracksolid.devices if they are stale test/decommissioned units. + (b) Leave-as-NULL — keep them as auto-synced API rows; their metadata stays NULL until added to a future CSV. + (c) Addendum — add them to the CSV (or a sidecar CSV) and re-run import_drivers_csv.py --apply. + Document the choice in 260427_device_reconciliation.md. \ No newline at end of file diff --git a/260427_device_reconciliation.md b/260427_device_reconciliation.md new file mode 100644 index 0000000..188a65d --- /dev/null +++ b/260427_device_reconciliation.md @@ -0,0 +1,91 @@ +# Device Reconciliation — 162 vs 182 (2026-04-27) + +Phase 0.2 of the Business Analytics redesign. Resolves the gap between +`20260427_FSG_Vehicles_mitieng.csv` (162 rows) and `tracksolid.devices` +(~182 rows at last check). + +## How to populate this report + +1. Pull this branch onto the Coolify host (or rebuild containers so the + ingest container has `audit_device_reconciliation.py`). + +2. Run inside the ingest container so it has `DATABASE_URL`: + ```bash + ING=$(docker ps --filter name=ingest_movement --format "{{.Names}}" | head -1) + docker cp 20260427_FSG_Vehicles_mitieng.csv "$ING":/app/ + docker exec "$ING" python audit_device_reconciliation.py \ + --csv 20260427_FSG_Vehicles_mitieng.csv \ + --out /tmp/260427_audit_output.txt + docker cp "$ING":/tmp/260427_audit_output.txt ./ + ``` + +3. Paste the audit output into the **Audit output** section below. + +4. Mark the chosen disposition for each IMEI in the **Disposition** section. + +## Audit output + +First run: 2026-04-27 23:35 UTC against `tracksolid_db` on stage. Full output in +`260427_audit_output.txt`. Headline numbers: + +| Metric | Value | +|---|---| +| CSV rows | 162 | +| `tracksolid.devices` rows | 172 | +| Delta (DB − CSV) | +10 | +| In CSV but not in DB | 0 | +| In DB but not in CSV | 10 | +| Devices both sides, DB metadata still NULL on ≥1 field | 162 (resolved by importer run) | + +After running `import_drivers_csv.py --only-null --apply` (2026-04-27): 154 +devices updated, 8 already complete, 0 inserted. Coverage now: `assigned_city` +152/172, `cost_centre` 150/172, `vehicle_brand` 2/172, `fuel_100km` 3/172. +`assigned_route` / `vehicle_category` / `depot_address` remain 0/172 (CSV +provided no values for these — Phase 1 follow-up). + +The 10 in-DB-not-in-CSV IMEIs are listed in `260427_audit_output.txt`. They +sit in `(blank)` or `fireside` accounts and surface in Grafana as +`assigned_city = 'unassigned'` thanks to the existing COALESCE in +`07_analytics_views.sql`. + +## Disposition + +For each IMEI in the "in DB but not in CSV" list, choose one and record why: + +| IMEI | Account | Last seen | Disposition | Notes | +|---|---|---|---|---| +| | | | | | + +**Disposition options:** + +- **prune** — Delete from `tracksolid.devices`. Use when the unit is a stale + test/decommissioned device that should never have synced. Capture the SQL + before running: + ```sql + DELETE FROM tracksolid.devices WHERE imei = ''; + ``` + *Caveat:* foreign keys from `position_history`, `trips`, `alarms` must be + considered first — these will block the delete if there's any history. + Usually safer to leave-as-NULL. + +- **leave-as-NULL** — Keep the row; metadata fields stay NULL. The device + was auto-synced from a Tracksolid account that the CSV doesn't cover + (likely `Fireside@HQ` rows that were left out of this Mitieng export). + Grafana views already use `COALESCE(d.assigned_city, d.city, 'unassigned')` + so these surface as "unassigned" but don't break dashboards. + +- **addendum** — Add to a follow-up CSV and re-run the importer with + `--apply`. Use when the device is legitimate fleet metadata was just + missing from the export. + +## Decision + + + +- Total devices reviewed: ___ +- Pruned: ___ +- Left-as-NULL: ___ +- Added via addendum: ___ + +After action, re-run `audit_device_reconciliation.py` and confirm the +delta is what you expect. diff --git a/audit_device_reconciliation.py b/audit_device_reconciliation.py new file mode 100644 index 0000000..7368921 --- /dev/null +++ b/audit_device_reconciliation.py @@ -0,0 +1,205 @@ +""" +audit_device_reconciliation.py — 162-vs-182 device delta audit +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Phase 0.2 of the Business Analytics redesign. + +Compares `20260427_FSG_Vehicles_mitieng.csv` (162 rows) to `tracksolid.devices` +(182 rows at last check) and reports: + 1. Per-account row counts on each side. + 2. IMEIs in DB but not in CSV (the unexplained delta — typically auto-synced + API rows with no business metadata). + 3. IMEIs in CSV but not in DB (should be empty after a successful import). + 4. IMEIs present on both sides where DB metadata is still NULL on key fields. + +Usage: + # Read-only audit, prints to stdout. + python audit_device_reconciliation.py + + # Same, but write output to a file (useful for the reconciliation report). + python audit_device_reconciliation.py --out 260427_audit_output.txt + + # Use a different CSV path + python audit_device_reconciliation.py --csv path/to/file.csv + +This script makes no writes — safe to run on prod. +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +""" + +import argparse +import csv +import sys +from collections import Counter +from pathlib import Path + +from ts_shared_rev import get_conn, get_logger + +log = get_logger("device_audit") + +DEFAULT_CSV_PATH = Path(__file__).parent / "20260427_FSG_Vehicles_mitieng.csv" + +# Fields whose NULL-ness on devices that DO appear in CSV would indicate +# a stale import. +META_FIELDS = ("assigned_city", "cost_centre", "assigned_route", + "vehicle_category", "vehicle_brand", "fuel_100km", + "depot_address", "driver_name", "vehicle_number") + + +def load_csv_index(csv_path: Path) -> dict[str, dict]: + rows: dict[str, dict] = {} + with open(csv_path, encoding="utf-8-sig", newline="") as f: + for row in csv.DictReader(f): + imei = (row.get("imei") or "").strip() + if imei: + rows[imei] = row + return rows + + +def load_db_index() -> dict[str, dict]: + cols = ( + "imei", "account", "assigned_city", "city", "cost_centre", + "assigned_route", "vehicle_category", "vehicle_brand", "fuel_100km", + "depot_address", "driver_name", "vehicle_number", "device_name", + "last_synced_at", "created_at", + ) + devices: dict[str, dict] = {} + with get_conn() as conn: + with conn.cursor() as cur: + cur.execute(f"SELECT {', '.join(cols)} FROM tracksolid.devices") + names = [d[0] for d in cur.description] + for row in cur.fetchall(): + rec = dict(zip(names, row)) + devices[rec["imei"]] = rec + return devices + + +def _csv_account(row: dict) -> str: + return (row.get("account") or "").strip() or "(blank)" + + +def _db_account(row: dict) -> str: + return (row.get("account") or "").strip() or "(blank)" + + +def _is_blank(v) -> bool: + if v is None: + return True + s = str(v).strip() + return s == "" or s.upper() == "NULL" + + +def main() -> int: + parser = argparse.ArgumentParser(description="Reconcile vehicle CSV against tracksolid.devices") + parser.add_argument("--csv", default=str(DEFAULT_CSV_PATH)) + parser.add_argument("--out", default=None, help="Write report to this file in addition to stdout") + args = parser.parse_args() + + csv_path = Path(args.csv) + if not csv_path.exists(): + log.error("CSV not found: %s", csv_path) + return 1 + + csv_idx = load_csv_index(csv_path) + db_idx = load_db_index() + + csv_imeis = set(csv_idx) + db_imeis = set(db_idx) + + only_db = sorted(db_imeis - csv_imeis) + only_csv = sorted(csv_imeis - db_imeis) + both = csv_imeis & db_imeis + + csv_accounts = Counter(_csv_account(r) for r in csv_idx.values()) + db_accounts = Counter(_db_account(r) for r in db_idx.values()) + + out_lines: list[str] = [] + def w(line: str = "") -> None: + out_lines.append(line) + print(line) + + w("=" * 76) + w(" Device reconciliation — CSV vs tracksolid.devices") + w("=" * 76) + w(f" CSV file : {csv_path.name}") + w(f" CSV row count : {len(csv_idx)}") + w(f" DB row count : {len(db_idx)}") + w(f" Delta (DB-CSV) : {len(only_db):+d}") + w("") + + w("─ Per-account breakdown ─────────────────────────────────────────────────") + all_accounts = sorted(set(csv_accounts) | set(db_accounts)) + w(f" {'account':<30} {'CSV':>6} {'DB':>6} {'delta':>7}") + for acct in all_accounts: + c, d = csv_accounts.get(acct, 0), db_accounts.get(acct, 0) + w(f" {acct:<30} {c:>6} {d:>6} {d-c:>+7}") + w("") + + w(f"─ IMEIs in DB but NOT in CSV ({len(only_db)}) ─────────────────────────────") + if not only_db: + w(" (none — DB is a strict subset of CSV)") + else: + w(f" {'imei':<18} {'account':<22} {'city':<10} {'last_synced_at':<28} {'device_name'}") + for imei in only_db: + r = db_idx[imei] + w(f" {imei:<18} {(r.get('account') or ''):<22} " + f"{(r.get('assigned_city') or r.get('city') or ''):<10} " + f"{str(r.get('last_synced_at') or ''):<28} " + f"{r.get('device_name') or ''}") + w("") + + w(f"─ IMEIs in CSV but NOT in DB ({len(only_csv)}) ─────────────────────────────") + if not only_csv: + w(" (none — every CSV row has a corresponding device row)") + else: + w(f" {'imei':<18} {'account':<22} {'assigned_city':<14} {'cost_centre':<14} {'driver_name'}") + for imei in only_csv: + r = csv_idx[imei] + w(f" {imei:<18} {(r.get('account') or ''):<22} " + f"{(r.get('assigned_city') or ''):<14} " + f"{(r.get('cost_centre') or ''):<14} " + f"{r.get('driver_name') or ''}") + w("") + + # Stale-metadata audit: in both, but DB is still NULL on key fields. + stale: list[tuple[str, list[str]]] = [] + for imei in sorted(both): + d = db_idx[imei] + blanks = [f for f in META_FIELDS if _is_blank(d.get(f))] + if blanks: + stale.append((imei, blanks)) + + w(f"─ Devices in both, but DB metadata still NULL ({len(stale)}) ──────────────") + if not stale: + w(" (none — import looks complete on intersecting devices)") + else: + w(" Likely cause: import_drivers_csv.py has not been re-run with --apply") + w(" against the new CSV, or rows had 'Identification' placeholders.") + w("") + w(f" {'imei':<18} blank_fields") + for imei, blanks in stale[:30]: # cap output + w(f" {imei:<18} {', '.join(blanks)}") + if len(stale) > 30: + w(f" ... and {len(stale) - 30} more") + w("") + + w("─ Suggested next step ───────────────────────────────────────────────────") + if only_db: + w(" Inspect the IMEIs above. Decide one of:") + w(" (a) Prune — delete from tracksolid.devices if they are stale " + "test/decommissioned units.") + w(" (b) Leave-as-NULL — keep them as auto-synced API rows; their " + "metadata stays NULL until added to a future CSV.") + w(" (c) Addendum — add them to the CSV (or a sidecar CSV) and re-run " + "import_drivers_csv.py --apply.") + w(" Document the choice in 260427_device_reconciliation.md.") + else: + w(" CSV and DB are reconciled. No further action.") + + if args.out: + Path(args.out).write_text("\n".join(out_lines), encoding="utf-8") + print(f"\nReport also written to {args.out}") + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/import_drivers_csv.py b/import_drivers_csv.py index ab209bb..0c29664 100644 --- a/import_drivers_csv.py +++ b/import_drivers_csv.py @@ -1,8 +1,24 @@ """ import_drivers_csv.py — Fireside Communications · Driver & Vehicle CSV Import ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -One-shot script: reads 20260414_FS__Logistics - final_fixed.csv, compares -each row against the current tracksolid.devices values, and updates the DB. +One-shot script: reads the snake_case Fireside Group vehicle CSV +(`20260427_FSG_Vehicles_mitieng.csv`), compares each row against the +current `tracksolid.devices` values, and updates the DB. + +The CSV columns mirror the DB schema directly — no inference. Cells with the +literal string "NULL" are treated as missing. + +Fields imported (per Phase 0.1 of the Business Analytics redesign plan): + Identity : driver_name, driver_phone, vehicle_number, vehicle_name, + vehicle_models, mc_type, device_name + SIM : sim, iccid, imsi + Lifecycle : activation_time, expiration + Business meta : assigned_city, cost_centre, assigned_route, + vehicle_category, vehicle_brand, fuel_100km, depot_address + +`depot_geom` (PostGIS Point) is intentionally NOT imported — needs WKT and +isn't present as coordinates in the CSV. Set it via a follow-up migration +when geofences are loaded. Usage: # Dry-run — shows diff, writes nothing @@ -17,68 +33,75 @@ Usage: # Only fill fields that are currently NULL in the DB (never overwrite) python import_drivers_csv.py --only-null --apply + # Use a different CSV + python import_drivers_csv.py --csv path/to/file.csv + Pre-requisite: - Migration 06 must be applied first (adds assigned_city / cost_centre columns). + Migrations 02, 05, 06 must be applied (they add the metadata columns). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ """ import argparse import csv -import os -import sys -import time -from datetime import date from pathlib import Path from ts_shared_rev import clean, clean_num, clean_ts, get_conn, get_logger log = get_logger("csv_import") -CSV_PATH = Path(__file__).parent / "20260414_FS__Logistics - final_fixed.csv" +DEFAULT_CSV_PATH = Path(__file__).parent / "20260427_FSG_Vehicles_mitieng.csv" -# Columns fetched from DB for comparison +# Columns fetched from DB for diff comparison. DB_COLS = [ - "imei", "driver_name", "driver_phone", "vehicle_number", "vehicle_name", - "vehicle_models", "cost_centre", "sim", "iccid", "imsi", "mc_type", - "activation_time", "expiration", "device_name", "assigned_city", + "imei", + # Identity + "driver_name", "driver_phone", "vehicle_number", "vehicle_name", + "vehicle_models", "mc_type", "device_name", + # SIM + "sim", "iccid", "imsi", + # Lifecycle + "activation_time", "expiration", + # Business metadata (Phase 0.1 additions) + "assigned_city", "cost_centre", "assigned_route", + "vehicle_category", "vehicle_brand", "fuel_100km", "depot_address", ] -# Driver Name values that are placeholders — skip writing driver_name for these +# Driver Name values that are placeholders — skip writing driver_name for these. _DRIVER_SKIP = {"identification", "ug"} - -def _infer_city(plate: str) -> str | None: - """Derive assigned_city from license plate prefix.""" - p = (plate or "").strip().upper() - if p.startswith("UMA") or p.startswith("UAG"): - return "KLA" - if p.startswith("K"): - return "NBO" - return None +# Columns that need an explicit cast in the UPDATE statement. +_TIMESTAMPTZ_COLS = {"activation_time", "expiration"} +_NUMERIC_COLS = {"fuel_100km"} -def _clean_date(v: str) -> str | None: - """Accept YYYY-MM-DD and return as ISO string suitable for TIMESTAMPTZ cast.""" - s = (v or "").strip() - if not s: - return None - try: - date.fromisoformat(s) - return s - except ValueError: +def _read(row: dict, col: str) -> str | None: + """Read a CSV column treating literal 'NULL'/'None' (case-insensitive) as missing.""" + v = clean(row.get(col)) + if v is None: return None + return None if v.upper() in ("NULL", "NONE") else v -def load_csv() -> dict[str, dict]: +def _read_num(row: dict, col: str) -> float | None: + v = _read(row, col) + return clean_num(v) if v is not None else None + + +def _read_ts(row: dict, col: str) -> str | None: + v = _read(row, col) + return clean_ts(v) if v is not None else None + + +def load_csv(csv_path: Path) -> dict[str, dict]: """Load CSV into a dict keyed by IMEI.""" rows: dict[str, dict] = {} - with open(CSV_PATH, encoding="utf-8-sig", newline="") as f: + with open(csv_path, encoding="utf-8-sig", newline="") as f: for row in csv.DictReader(f): - imei = (row.get("IMEI") or "").strip() + imei = (row.get("imei") or "").strip() if not imei: continue rows[imei] = row - log.info("CSV loaded: %d rows from %s", len(rows), CSV_PATH.name) + log.info("CSV loaded: %d rows from %s", len(rows), csv_path.name) return rows @@ -102,42 +125,46 @@ def build_update(csv_row: dict, db_row: dict | None, only_null: bool) -> dict[st When only_null=True, skip any DB column that already has a value. The driver_name column is skipped for placeholder-labelled devices. """ - driver_raw = clean(csv_row.get("Driver Name")) or "" - plate = clean(csv_row.get("License Plate No.")) or "" + driver_raw = (_read(csv_row, "driver_name") or "") is_placeholder = driver_raw.lower() in _DRIVER_SKIP - skip_row = driver_raw.lower() == "identification" - - if skip_row: + if driver_raw.lower() == "identification": return {} proposed: dict[str, object] = { - "vehicle_number": clean(plate), - "vehicle_name": clean(plate), - "vehicle_models": clean(csv_row.get("Vehicle Model")), - "cost_centre": clean(csv_row.get("Department")), - "sim": clean(csv_row.get("SIM")), - "iccid": clean(csv_row.get("ICCID")), - "imsi": clean(csv_row.get("IMSI")), - "mc_type": clean(csv_row.get("Model")), - "activation_time": _clean_date(csv_row.get("Activated Date", "")), - "expiration": _clean_date(csv_row.get("Subscription Expiration", "")), - "driver_phone": clean(csv_row.get("Telephone")), - "assigned_city": _infer_city(plate), + # Identity + "driver_phone": _read(csv_row, "driver_phone"), + "vehicle_number": _read(csv_row, "vehicle_number"), + "vehicle_name": _read(csv_row, "vehicle_name"), + "vehicle_models": _read(csv_row, "vehicle_models"), + "mc_type": _read(csv_row, "mc_type"), + "device_name": _read(csv_row, "device_name"), + # SIM + "sim": _read(csv_row, "sim"), + "iccid": _read(csv_row, "iccid"), + "imsi": _read(csv_row, "imsi"), + # Lifecycle + "activation_time": _read_ts(csv_row, "activation_time"), + "expiration": _read_ts(csv_row, "expiration"), + # Business metadata + "assigned_city": _read(csv_row, "assigned_city"), + "cost_centre": _read(csv_row, "cost_centre"), + "assigned_route": _read(csv_row, "assigned_route"), + "vehicle_category": _read(csv_row, "vehicle_category"), + "vehicle_brand": _read(csv_row, "vehicle_brand"), + "fuel_100km": _read_num(csv_row, "fuel_100km"), + "depot_address": _read(csv_row, "depot_address"), } - if not is_placeholder: - proposed["driver_name"] = driver_raw or None + if not is_placeholder and driver_raw: + proposed["driver_name"] = driver_raw - # Drop None values — no point sending a NULL to overwrite another NULL + # Drop None values — no point sending NULL to overwrite NULL. proposed = {k: v for k, v in proposed.items() if v is not None} if not only_null or db_row is None: return proposed - # only_null: drop any column that already has a non-null value in the DB - return { - k: v for k, v in proposed.items() - if db_row.get(k) is None - } + # only_null: drop any column that already has a non-null value in the DB. + return {k: v for k, v in proposed.items() if db_row.get(k) is None} def print_diff(imei: str, updates: dict[str, object], db_row: dict | None) -> None: @@ -148,12 +175,31 @@ def print_diff(imei: str, updates: dict[str, object], db_row: dict | None) -> No print(f"\n IMEI {imei}:") for col, new_val in sorted(updates.items()): old_val = db.get(col) - if old_val != new_val: + if str(old_val) != str(new_val): print(f" {col:<20} {str(old_val):<30} → {new_val}") -def run(apply: bool, only_null: bool, filter_imei: str | None) -> None: - csv_rows = load_csv() +def _set_clause(col: str) -> str: + """SQL fragment for `col = ...` honouring per-column casts.""" + if col in _TIMESTAMPTZ_COLS: + return f"{col} = COALESCE(%s::TIMESTAMPTZ, {col})" + if col in _NUMERIC_COLS: + # %s already a float; no NULLIF dance needed. + return f"{col} = COALESCE(%s::NUMERIC, {col})" + return f"{col} = COALESCE(NULLIF(%s, ''), {col})" + + +def _placeholder(col: str) -> str: + """SQL fragment for a single VALUES placeholder honouring per-column casts.""" + if col in _TIMESTAMPTZ_COLS: + return "%s::TIMESTAMPTZ" + if col in _NUMERIC_COLS: + return "%s::NUMERIC" + return "%s" + + +def run(apply: bool, only_null: bool, filter_imei: str | None, csv_path: Path) -> None: + csv_rows = load_csv(csv_path) db_rows = load_db_devices() if filter_imei: @@ -168,12 +214,10 @@ def run(apply: bool, only_null: bool, filter_imei: str | None) -> None: with conn.cursor() as cur: for imei, csv_row in csv_rows.items(): db_row = db_rows.get(imei) - updates = build_update(csv_row, db_row, only_null) if not updates: - # Either an "Identification" placeholder or nothing to change - driver_raw = (csv_row.get("Driver Name") or "").strip().lower() + driver_raw = (_read(csv_row, "driver_name") or "").lower() if driver_raw == "identification": skipped += 1 else: @@ -181,20 +225,15 @@ def run(apply: bool, only_null: bool, filter_imei: str | None) -> None: continue if db_row is None: - # Device not yet synced from API — insert a stub row now so + # Device not yet synced from API — insert a stub row so # incoming alarms / positions don't trip the FK constraint. print(f"\n [NEW] IMEI {imei}:") for col, new_val in sorted(updates.items()): print(f" {col:<20} → {new_val}") if apply: cols = ["imei"] + list(updates.keys()) - vals = [imei] + [str(v) if v is not None else None for v in updates.values()] - placeholders = [] - for col in cols: - if col in ("activation_time", "expiration"): - placeholders.append("%s::TIMESTAMPTZ") - else: - placeholders.append("%s") + vals = [imei] + list(updates.values()) + placeholders = ["%s"] + [_placeholder(c) for c in updates.keys()] cur.execute( f"INSERT INTO tracksolid.devices ({', '.join(cols)}) " f"VALUES ({', '.join(placeholders)}) " @@ -207,20 +246,10 @@ def run(apply: bool, only_null: bool, filter_imei: str | None) -> None: print_diff(imei, updates, db_row) if apply: - set_clauses = [] - params = [] - for col, val in updates.items(): - if col in ("activation_time", "expiration"): - set_clauses.append(f"{col} = COALESCE(%s::TIMESTAMPTZ, {col})") - else: - set_clauses.append( - f"{col} = COALESCE(NULLIF(%s, ''), {col})" - ) - params.append(str(val) if val is not None else None) - + set_clauses = [_set_clause(c) for c in updates.keys()] + params = list(updates.values()) set_clauses.append("updated_at = NOW()") params.append(imei) - cur.execute( f"UPDATE tracksolid.devices SET {', '.join(set_clauses)} WHERE imei = %s", params, @@ -233,19 +262,28 @@ def run(apply: bool, only_null: bool, filter_imei: str | None) -> None: print(f"\n{'='*60}") print(f" {mode} COMPLETE") print(f"{'='*60}") - print(f" Would update / updated : {updated}") - print(f" Would insert / inserted: {inserted}") - print(f" No change needed : {no_change}") + print(f" Would update / updated : {updated}") + print(f" Would insert / inserted : {inserted}") + print(f" No change needed : {no_change}") print(f" Skipped (Identification): {skipped}") if not apply: print("\n Run with --apply to commit changes.") if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Import driver/vehicle details from CSV into tracksolid.devices") + parser = argparse.ArgumentParser( + description="Import driver/vehicle details from CSV into tracksolid.devices" + ) parser.add_argument("--apply", action="store_true", help="Write changes to DB (default: dry-run)") parser.add_argument("--only-null", action="store_true", help="Only update fields currently NULL in the DB") parser.add_argument("--imei", default=None, help="Limit to a single IMEI") + parser.add_argument("--csv", default=str(DEFAULT_CSV_PATH), + help=f"Path to the CSV (default: {DEFAULT_CSV_PATH.name})") args = parser.parse_args() - run(apply=args.apply, only_null=args.only_null, filter_imei=args.imei) + csv_path = Path(args.csv) + if not csv_path.exists(): + log.error("CSV file not found: %s", csv_path) + raise SystemExit(1) + + run(apply=args.apply, only_null=args.only_null, filter_imei=args.imei, csv_path=csv_path) diff --git a/run_migrations.py b/run_migrations.py index 3a98169..3ae4166 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -31,6 +31,7 @@ MIGRATIONS = [ "05_enhancement_migration.sql", # new tables, OBD columns, dwh_gold expansion "06_business_analytics_migration.sql", # ops schema, dispatch_log, assigned_city "07_analytics_views.sql", # Grafana-facing views in tracksolid.* + "08_analytics_config.sql", # ops.cost_rates, ops.kpi_targets + seed data ] # ── Tables that must exist before the service is allowed to start ───────────── From 144dedee90b7011dba7711951f4720e535610983 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Fri, 1 May 2026 21:30:20 +0300 Subject: [PATCH 07/31] feat(trips): [FIX-M20] enrich tracksolid.trips with coords, route polyline, addresses, plate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Polling jimi.device.track.mileage does not return start/end coordinates, fuel, idle, or trip sequence — leaving most trip columns NULL. This change closes those gaps using data we already have in position_history plus a best-effort Nominatim lookup. Migration 09_trips_enrichment.sql adds: • route_geom (LineString), start_address, end_address, vehicle_plate, waypoints_count on tracksolid.trips • GIST indexes on the three geometry columns • view tracksolid.v_trips_enriched exposing daily_seq + trip_date_eat (replaces reliance on the device-supplied trip_seq, which is only populated when /pushtripreport fires) ingest_movement_rev.py::poll_trips now: • extracts idleSecond from the poll response (was previously dropped) • per-trip: SELECTs start fix, end fix, ST_MakeLine route, and waypoint count from position_history within (start_time, end_time) • reverse-geocodes start/end via the new ts_shared_rev.reverse_geocode helper (Nominatim, LRU-cached at ~11m precision, 1 req/sec, never raises) • caches vehicle_plate from a per-cycle plates dict • ON CONFLICT preserves webhook-supplied data when /pushtripreport later delivers native coords/fuel/trip_seq backfill_trips_enrichment.py is a one-shot script (dry-run by default, --apply to commit, --imei / --since flags) that runs the same enrichment against historical NULL rows and COALESCEs only — never overwrites. DWH bronze mirrors and Grafana panels intentionally not touched (frozen on this branch until the schema work lands). Co-Authored-By: Claude Opus 4.7 --- 09_trips_enrichment.sql | 82 +++++++++++++ backfill_trips_enrichment.py | 215 +++++++++++++++++++++++++++++++++++ ingest_movement_rev.py | 125 ++++++++++++++++++-- run_migrations.py | 1 + ts_shared_rev.py | 86 +++++++++++++- 5 files changed, 497 insertions(+), 12 deletions(-) create mode 100644 09_trips_enrichment.sql create mode 100644 backfill_trips_enrichment.py diff --git a/09_trips_enrichment.sql b/09_trips_enrichment.sql new file mode 100644 index 0000000..afe84db --- /dev/null +++ b/09_trips_enrichment.sql @@ -0,0 +1,82 @@ +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +-- Migration 09 — tracksolid.trips Enrichment +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +-- The polling endpoint jimi.device.track.mileage does not return start/end +-- coordinates, fuel, idle, or trip sequence. This migration adds the columns +-- needed to enrich every poll-ingested trip from data we already have: +-- • start/end coordinates and full route polyline reconstructed from +-- position_history at insert time (see ingest_movement_rev.py::poll_trips) +-- • reverse-geocoded human-readable addresses (Nominatim) +-- • denormalised vehicle_plate so trip displays don't need a join +-- • waypoint count for audit / data-quality checks +-- +-- Adds a v_trips_enriched view exposing daily_seq (Nth trip for IMEI on this +-- Africa/Nairobi date) — replaces reliance on the device-supplied trip_seq +-- which is only populated when the rarely-firing /pushtripreport webhook +-- delivers a payload. +-- +-- Run after migration 08. Safe to re-run (ADD COLUMN IF NOT EXISTS, +-- CREATE INDEX IF NOT EXISTS, CREATE OR REPLACE VIEW). +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +BEGIN; + +-- ── 1. New columns on tracksolid.trips ────────────────────────────────────── + +ALTER TABLE tracksolid.trips + ADD COLUMN IF NOT EXISTS route_geom geometry(LineString, 4326), + ADD COLUMN IF NOT EXISTS start_address TEXT, + ADD COLUMN IF NOT EXISTS end_address TEXT, + ADD COLUMN IF NOT EXISTS vehicle_plate TEXT, + ADD COLUMN IF NOT EXISTS waypoints_count INTEGER; + +COMMENT ON COLUMN tracksolid.trips.route_geom IS + 'Full GPS route polyline built at ingest from position_history points ' + 'where gps_time BETWEEN start_time AND end_time. NULL when fewer than ' + '2 fixes are available for the trip window.'; +COMMENT ON COLUMN tracksolid.trips.start_address IS + 'Reverse-geocoded human-readable address near start_geom (Nominatim). ' + 'NULL on lookup failure; address is best-effort, not authoritative.'; +COMMENT ON COLUMN tracksolid.trips.end_address IS + 'Reverse-geocoded human-readable address near end_geom (Nominatim). ' + 'NULL on lookup failure; address is best-effort, not authoritative.'; +COMMENT ON COLUMN tracksolid.trips.vehicle_plate IS + 'Denormalised tracksolid.devices.vehicle_number cached at trip-insert ' + 'time. Avoids a join for trip displays; refreshed only on next ingest.'; +COMMENT ON COLUMN tracksolid.trips.waypoints_count IS + 'Number of position_history fixes that contributed to route_geom. ' + 'Audit aid: 0 or 1 means route_geom is NULL or degenerate.'; + +-- ── 2. Spatial indexes for replay / map queries ───────────────────────────── + +CREATE INDEX IF NOT EXISTS idx_trips_route_geom + ON tracksolid.trips USING GIST (route_geom); +CREATE INDEX IF NOT EXISTS idx_trips_start_geom + ON tracksolid.trips USING GIST (start_geom); +CREATE INDEX IF NOT EXISTS idx_trips_end_geom + ON tracksolid.trips USING GIST (end_geom); + +-- ── 3. v_trips_enriched view ──────────────────────────────────────────────── +-- Adds trip_date_eat (Africa/Nairobi local date) and daily_seq (Nth trip on +-- that date for the IMEI) without depending on the device-supplied trip_seq. + +CREATE OR REPLACE VIEW tracksolid.v_trips_enriched AS +SELECT + t.*, + (t.start_time AT TIME ZONE 'Africa/Nairobi')::date AS trip_date_eat, + ROW_NUMBER() OVER ( + PARTITION BY t.imei, (t.start_time AT TIME ZONE 'Africa/Nairobi')::date + ORDER BY t.start_time + ) AS daily_seq +FROM tracksolid.trips t; + +COMMENT ON VIEW tracksolid.v_trips_enriched IS + 'tracksolid.trips with computed daily_seq (Nth trip per IMEI per local ' + 'Africa/Nairobi day) and trip_date_eat. Replaces reliance on the ' + 'device-supplied trip_seq column, which is NULL for poll-ingested trips.'; + +-- ── 4. Read access for grafana_ro ─────────────────────────────────────────── + +GRANT SELECT ON tracksolid.v_trips_enriched TO grafana_ro; + +COMMIT; diff --git a/backfill_trips_enrichment.py b/backfill_trips_enrichment.py new file mode 100644 index 0000000..a619b9e --- /dev/null +++ b/backfill_trips_enrichment.py @@ -0,0 +1,215 @@ +""" +backfill_trips_enrichment.py — One-shot enrichment of historical tracksolid.trips rows +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Migration 09 added route_geom, start/end_address, vehicle_plate, waypoints_count. +poll_trips() fills these for new trips going forward; this script backfills +existing rows where the new columns are NULL by reconstructing data from +position_history (the GPS trail is already there) and Nominatim. + +Behaviour: + • Selects rows where route_geom IS NULL OR start_geom IS NULL + (covers the original 8 historical poll-ingested trips and any future + rows that landed before position_history caught up). + • Per row: runs the same 4-subquery enrichment poll_trips uses, then + reverse-geocodes start/end via Nominatim. + • Writes only via COALESCE — never overwrites webhook-supplied data. + • Logs each run to tracksolid.ingestion_log with endpoint='backfill_trips_enrichment'. + +Usage: + # Dry-run — shows counts only, writes nothing + python backfill_trips_enrichment.py + + # Apply changes + python backfill_trips_enrichment.py --apply + + # Scope to a single device + python backfill_trips_enrichment.py --imei 862798052707896 --apply + + # Limit to trips since a date (UTC) + python backfill_trips_enrichment.py --since 2026-04-01 --apply +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +""" + +import argparse +import time + +from ts_shared_rev import ( + get_conn, + get_logger, + log_ingestion, + reverse_geocode, +) + +log = get_logger("backfill_trips") + +_ENRICH_QUERY = """ + SELECT + (SELECT geom FROM tracksolid.position_history + WHERE imei = %s AND gps_time >= %s + ORDER BY gps_time ASC LIMIT 1) AS start_geom, + (SELECT ST_Y(geom) FROM tracksolid.position_history + WHERE imei = %s AND gps_time >= %s + ORDER BY gps_time ASC LIMIT 1) AS start_lat, + (SELECT ST_X(geom) FROM tracksolid.position_history + WHERE imei = %s AND gps_time >= %s + ORDER BY gps_time ASC LIMIT 1) AS start_lng, + (SELECT geom FROM tracksolid.position_history + WHERE imei = %s AND gps_time <= %s + ORDER BY gps_time DESC LIMIT 1) AS end_geom, + (SELECT ST_Y(geom) FROM tracksolid.position_history + WHERE imei = %s AND gps_time <= %s + ORDER BY gps_time DESC LIMIT 1) AS end_lat, + (SELECT ST_X(geom) FROM tracksolid.position_history + WHERE imei = %s AND gps_time <= %s + ORDER BY gps_time DESC LIMIT 1) AS end_lng, + (SELECT ST_MakeLine(geom ORDER BY gps_time) + FROM tracksolid.position_history + WHERE imei = %s AND gps_time BETWEEN %s AND %s + AND geom IS NOT NULL) AS route_geom, + (SELECT COUNT(*) FROM tracksolid.position_history + WHERE imei = %s AND gps_time BETWEEN %s AND %s) AS waypoints_count +""" + + +def _select_targets(cur, imei: str | None, since: str | None) -> list[tuple]: + """Return rows that need enrichment, as (id, imei, start_time, end_time).""" + sql = """ + SELECT id, imei, start_time, end_time, vehicle_plate + FROM tracksolid.trips + WHERE (route_geom IS NULL OR start_geom IS NULL) + AND end_time IS NOT NULL + """ + params: list = [] + if imei: + sql += " AND imei = %s" + params.append(imei) + if since: + sql += " AND start_time >= %s" + params.append(since) + sql += " ORDER BY start_time" + cur.execute(sql, params) + return cur.fetchall() + + +def _load_plates_cache(cur) -> dict[str, str]: + cur.execute(""" + SELECT imei, vehicle_number + FROM tracksolid.devices + WHERE vehicle_number IS NOT NULL + """) + return {imei: plate for imei, plate in cur.fetchall()} + + +def run(apply: bool, filter_imei: str | None, since: str | None) -> None: + t0 = time.time() + enriched = degenerate = no_fixes = failed = 0 + + with get_conn() as conn: + with conn.cursor() as cur: + plates = _load_plates_cache(cur) + targets = _select_targets(cur, filter_imei, since) + + log.info( + "Found %d trip(s) needing enrichment%s%s.", + len(targets), + f" for imei={filter_imei}" if filter_imei else "", + f" since={since}" if since else "", + ) + + for trip_id, imei, start_time, end_time, existing_plate in targets: + try: + cur.execute(_ENRICH_QUERY, ( + imei, start_time, + imei, start_time, + imei, start_time, + imei, end_time, + imei, end_time, + imei, end_time, + imei, start_time, end_time, + imei, start_time, end_time, + )) + (start_geom, start_lat, start_lng, + end_geom, end_lat, end_lng, + route_geom, waypoints_count) = cur.fetchone() + + if waypoints_count == 0: + no_fixes += 1 + log.info( + " trip id=%s imei=%s start=%s — no GPS fixes in window, skipping", + trip_id, imei, start_time, + ) + continue + + if waypoints_count < 2: + # Not enough fixes for a polyline. Still capture the + # single endpoint geom and address. + degenerate += 1 + log.info( + " trip id=%s imei=%s — only %d fix(es), no route_geom", + trip_id, imei, waypoints_count, + ) + + start_address = reverse_geocode(start_lat, start_lng) + end_address = reverse_geocode(end_lat, end_lng) + vehicle_plate = existing_plate or plates.get(imei) + + log.info( + " trip id=%s imei=%s waypoints=%d start=%s end=%s", + trip_id, imei, waypoints_count, start_address, end_address, + ) + + if apply: + cur.execute(""" + UPDATE tracksolid.trips SET + start_geom = COALESCE(start_geom, %s), + end_geom = COALESCE(end_geom, %s), + route_geom = COALESCE(route_geom, %s), + waypoints_count = COALESCE(waypoints_count, %s), + start_address = COALESCE(start_address, %s), + end_address = COALESCE(end_address, %s), + vehicle_plate = COALESCE(vehicle_plate, %s) + WHERE id = %s + """, ( + start_geom, end_geom, route_geom, waypoints_count, + start_address, end_address, vehicle_plate, + trip_id, + )) + enriched += 1 + except Exception: + failed += 1 + log.warning( + "Failed to enrich trip id=%s imei=%s", + trip_id, imei, exc_info=True, + ) + + if apply: + log_ingestion( + cur, "backfill_trips_enrichment", + imei_count=len(targets), + upserted=0, inserted=enriched, + duration_ms=int((time.time() - t0) * 1000), + success=(failed == 0), + ) + + mode = "APPLIED" if apply else "DRY-RUN" + print(f"\n{'='*60}") + print(f" {mode} COMPLETE") + print(f"{'='*60}") + print(f" Trips enriched : {enriched}") + print(f" Degenerate (<2 fixes) : {degenerate}") + print(f" Skipped (no fixes) : {no_fixes}") + print(f" Failed : {failed}") + if not apply: + print("\n Run with --apply to commit changes.") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Backfill route_geom / start_geom / end_geom / addresses on tracksolid.trips." + ) + parser.add_argument("--apply", action="store_true", help="Write changes to DB (default: dry-run)") + parser.add_argument("--imei", default=None, help="Limit to a single IMEI") + parser.add_argument("--since", default=None, help="Only trips with start_time >= YYYY-MM-DD (UTC)") + args = parser.parse_args() + + run(apply=args.apply, filter_imei=args.imei, since=args.since) diff --git a/ingest_movement_rev.py b/ingest_movement_rev.py index 90651d5..20498e6 100644 --- a/ingest_movement_rev.py +++ b/ingest_movement_rev.py @@ -38,6 +38,12 @@ REVISIONS (QA-Verified): Tracksolid sub-accounts. sync_devices, poll_live_positions and poll_parking now iterate every target in TRACKSOLID_TARGETS and dedupe/scope per-target before writing. + [FIX-M20] Trip enrichment: poll_trips now backfills start_geom/end_geom/ + route_geom/waypoints_count from position_history at insert + time, extracts idleSecond, reverse-geocodes start/end addresses + (Nominatim), and caches vehicle_plate from devices. Closes the + NULL-column gaps that were inherent to jimi.device.track.mileage + (it does not return coordinates, idle, or trip sequence). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ """ @@ -63,6 +69,7 @@ from ts_shared_rev import ( clean_int, clean_ts, get_logger, + reverse_geocode, safe_task, setup_shutdown, ) @@ -259,6 +266,57 @@ def poll_live_positions(): # ── 3. Trip Reports (Every 15m) ─────────────────────────────────────────────── +# [FIX-M20] Migration 09 added route_geom, start/end_address, vehicle_plate, +# waypoints_count to tracksolid.trips. poll_trips now enriches every poll- +# ingested trip from position_history (start/end fix + LineString polyline) +# and reverse-geocodes the endpoints, since jimi.device.track.mileage does +# not return coordinates. ON CONFLICT preserves webhook-supplied data when +# /pushtripreport later delivers native coords. + +# Per-trip enrichment from position_history. Four readable scalar subqueries +# rather than a tighter CTE — runs sub-ms each given the (imei, gps_time) PK, +# and the readable form survives the edge case where start_time is just +# before the first available fix in the window (single CTE bounded by +# BETWEEN would return NULL there). +_ENRICH_QUERY = """ + SELECT + (SELECT geom FROM tracksolid.position_history + WHERE imei = %s AND gps_time >= %s + ORDER BY gps_time ASC LIMIT 1) AS start_geom, + (SELECT ST_Y(geom) FROM tracksolid.position_history + WHERE imei = %s AND gps_time >= %s + ORDER BY gps_time ASC LIMIT 1) AS start_lat, + (SELECT ST_X(geom) FROM tracksolid.position_history + WHERE imei = %s AND gps_time >= %s + ORDER BY gps_time ASC LIMIT 1) AS start_lng, + (SELECT geom FROM tracksolid.position_history + WHERE imei = %s AND gps_time <= %s + ORDER BY gps_time DESC LIMIT 1) AS end_geom, + (SELECT ST_Y(geom) FROM tracksolid.position_history + WHERE imei = %s AND gps_time <= %s + ORDER BY gps_time DESC LIMIT 1) AS end_lat, + (SELECT ST_X(geom) FROM tracksolid.position_history + WHERE imei = %s AND gps_time <= %s + ORDER BY gps_time DESC LIMIT 1) AS end_lng, + (SELECT ST_MakeLine(geom ORDER BY gps_time) + FROM tracksolid.position_history + WHERE imei = %s AND gps_time BETWEEN %s AND %s + AND geom IS NOT NULL) AS route_geom, + (SELECT COUNT(*) FROM tracksolid.position_history + WHERE imei = %s AND gps_time BETWEEN %s AND %s) AS waypoints_count +""" + + +def _load_plates_cache(cur) -> dict[str, str]: + """Build {imei: vehicle_number} for active devices once per poll cycle.""" + cur.execute(""" + SELECT imei, vehicle_number + FROM tracksolid.devices + WHERE enabled_flag = 1 AND vehicle_number IS NOT NULL + """) + return {imei: plate for imei, plate in cur.fetchall()} + + def poll_trips(): t0 = time.time() token, imeis = get_token(), get_active_imeis() @@ -270,6 +328,8 @@ def poll_trips(): with get_conn() as conn: with conn.cursor() as cur: + plates = _load_plates_cache(cur) + for i in range(0, len(imeis), 50): batch = imeis[i:i+50] resp = api_post("jimi.device.track.mileage", { @@ -288,20 +348,67 @@ def poll_trips(): # Divide by 1000 to store as distance_km. raw_dist = clean_num(t.get("distance")) dist_km = round(raw_dist / 1000.0, 4) if raw_dist is not None else None + + imei = t.get("imei") + trip_start = clean_ts(t.get("startTime")) + trip_end = clean_ts(t.get("endTime")) + idle_s = clean_int(t.get("idleSecond")) + + # [FIX-M20] Enrich from position_history. trip_start/end + # may be None (rare malformed payload) — skip enrichment + # in that case so we still capture the row. + start_geom = end_geom = route_geom = None + start_lat = start_lng = end_lat = end_lng = None + waypoints_count = 0 + if trip_start and trip_end: + cur.execute(_ENRICH_QUERY, ( + imei, trip_start, # start_geom + imei, trip_start, # start_lat + imei, trip_start, # start_lng + imei, trip_end, # end_geom + imei, trip_end, # end_lat + imei, trip_end, # end_lng + imei, trip_start, trip_end, # route_geom + imei, trip_start, trip_end, # waypoints_count + )) + (start_geom, start_lat, start_lng, + end_geom, end_lat, end_lng, + route_geom, waypoints_count) = cur.fetchone() + + start_address = reverse_geocode(start_lat, start_lng) + end_address = reverse_geocode(end_lat, end_lng) + vehicle_plate = plates.get(imei) + cur.execute(""" INSERT INTO tracksolid.trips ( imei, start_time, end_time, distance_km, - avg_speed_kmh, max_speed_kmh, driving_time_s, source - ) VALUES (%s, %s, %s, %s, %s, %s, %s, 'poll') + avg_speed_kmh, max_speed_kmh, driving_time_s, idle_time_s, + start_geom, end_geom, route_geom, waypoints_count, + start_address, end_address, vehicle_plate, source + ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, + %s, %s, %s, 'poll') ON CONFLICT (imei, start_time) DO UPDATE SET - end_time = EXCLUDED.end_time, - distance_km = EXCLUDED.distance_km, - max_speed_kmh = COALESCE(EXCLUDED.max_speed_kmh, tracksolid.trips.max_speed_kmh), - driving_time_s = COALESCE(EXCLUDED.driving_time_s, tracksolid.trips.driving_time_s) + end_time = EXCLUDED.end_time, + distance_km = EXCLUDED.distance_km, + max_speed_kmh = COALESCE(EXCLUDED.max_speed_kmh, tracksolid.trips.max_speed_kmh), + driving_time_s = COALESCE(EXCLUDED.driving_time_s, tracksolid.trips.driving_time_s), + idle_time_s = COALESCE(EXCLUDED.idle_time_s, tracksolid.trips.idle_time_s), + start_geom = COALESCE(tracksolid.trips.start_geom, EXCLUDED.start_geom), + end_geom = COALESCE(EXCLUDED.end_geom, tracksolid.trips.end_geom), + route_geom = COALESCE(EXCLUDED.route_geom, tracksolid.trips.route_geom), + waypoints_count = EXCLUDED.waypoints_count, + start_address = COALESCE(tracksolid.trips.start_address, EXCLUDED.start_address), + end_address = COALESCE(EXCLUDED.end_address, tracksolid.trips.end_address), + vehicle_plate = COALESCE(EXCLUDED.vehicle_plate, tracksolid.trips.vehicle_plate) """, ( - t.get("imei"), clean_ts(t.get("startTime")), clean_ts(t.get("endTime")), - dist_km, clean_num(t.get("avgSpeed")), - clean_num(t.get("maxSpeed")), clean_int(t.get("runTimeSecond")) + imei, trip_start, trip_end, dist_km, + clean_num(t.get("avgSpeed")), + clean_num(t.get("maxSpeed")), + clean_int(t.get("runTimeSecond")), + idle_s, + start_geom, end_geom, route_geom, waypoints_count, + start_address, end_address, vehicle_plate, )) cur.execute("RELEASE SAVEPOINT sp") inserted += cur.rowcount diff --git a/run_migrations.py b/run_migrations.py index 3ae4166..143f71e 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -32,6 +32,7 @@ MIGRATIONS = [ "06_business_analytics_migration.sql", # ops schema, dispatch_log, assigned_city "07_analytics_views.sql", # Grafana-facing views in tracksolid.* "08_analytics_config.sql", # ops.cost_rates, ops.kpi_targets + seed data + "09_trips_enrichment.sql", # trips.route_geom + addresses + plate + v_trips_enriched ] # ── Tables that must exist before the service is allowed to start ───────────── diff --git a/ts_shared_rev.py b/ts_shared_rev.py index e782faf..72a5504 100644 --- a/ts_shared_rev.py +++ b/ts_shared_rev.py @@ -24,9 +24,11 @@ import logging import os import signal import sys +import threading import time from contextlib import contextmanager from datetime import datetime, timezone, timedelta +from functools import lru_cache from typing import Optional, Any import psycopg2 @@ -304,9 +306,87 @@ def _update_token_cache(r: dict) -> str: cur.execute(""" INSERT INTO tracksolid.api_token_cache (account, access_token, refresh_token, expires_at) VALUES (%s, %s, %s, %s) - ON CONFLICT (account) DO UPDATE SET - access_token=EXCLUDED.access_token, refresh_token=EXCLUDED.refresh_token, + ON CONFLICT (account) DO UPDATE SET + access_token=EXCLUDED.access_token, refresh_token=EXCLUDED.refresh_token, expires_at=EXCLUDED.expires_at, obtained_at=NOW() """, (USER_ID, token, r.get("refreshToken"), expires_at)) conn.commit() - return token \ No newline at end of file + return token + +# ── Reverse Geocoding (Nominatim) ──────────────────────────────────────────── +# Best-effort lookup used by poll_trips() to populate trips.start_address / +# end_address. Must NEVER raise — failure returns None and the trip insert +# proceeds without the address. + +_NOMINATIM_URL = os.getenv( + "NOMINATIM_URL", + "https://nominatim.openstreetmap.org/reverse", +) +_NOMINATIM_USER_AGENT = os.getenv( + "NOMINATIM_USER_AGENT", + "fireside-tracksolid/1.0 (kianiadee@gmail.com)", +) +_GEOCODE_LOCK = threading.Lock() +_GEOCODE_LAST_CALL_AT: float = 0.0 +_GEOCODE_MIN_INTERVAL_S: float = 1.0 # Nominatim TOS — 1 req/sec absolute max + + +def _geocode_throttle() -> None: + """Sleep just long enough since the previous call to honour 1 req/sec.""" + global _GEOCODE_LAST_CALL_AT + with _GEOCODE_LOCK: + elapsed = time.monotonic() - _GEOCODE_LAST_CALL_AT + if elapsed < _GEOCODE_MIN_INTERVAL_S: + time.sleep(_GEOCODE_MIN_INTERVAL_S - elapsed) + _GEOCODE_LAST_CALL_AT = time.monotonic() + + +@lru_cache(maxsize=2048) +def _reverse_geocode_cached(lat_round: float, lng_round: float) -> Optional[str]: + """Cached HTTP call. Key is lat/lng rounded to 4 dp (~11 m precision).""" + _geocode_throttle() + try: + r = _session.get( + _NOMINATIM_URL, + params={ + "lat": lat_round, + "lon": lng_round, + "format": "json", + "zoom": 18, + "addressdetails": 0, + }, + headers={"User-Agent": _NOMINATIM_USER_AGENT}, + timeout=10, + ) + r.raise_for_status() + data = r.json() + addr = data.get("display_name") + if addr: + return addr.strip() + return None + except (requests.RequestException, ValueError) as e: + _log.warning("reverse_geocode failed lat=%s lng=%s: %s", + lat_round, lng_round, e) + return None + + +def reverse_geocode(lat: Any, lng: Any) -> Optional[str]: + """ + Reverse-geocode a coordinate to a human-readable address via Nominatim. + + Best-effort. Never raises. Returns None on: + • missing / invalid lat or lng + • HTTP/timeout/JSON failure + • Nominatim returns no display_name + + Cached on lat/lng rounded to 4 decimal places (~11 m), which keeps + repeated visits to the same depot/site from re-querying. + """ + flat, flng = clean_num(lat), clean_num(lng) + if flat is None or flng is None: + return None + if flat == 0.0 and flng == 0.0: + return None + if not (-90 <= flat <= 90 and -180 <= flng <= 180): + return None + return _reverse_geocode_cached(round(flat, 4), round(flng, 4)) \ No newline at end of file From f94d14864fe1c6df796997ccaaa79f50f5b4e562 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Fri, 1 May 2026 22:12:07 +0300 Subject: [PATCH 08/31] feat(trips): add --skip-geocode flag to backfill script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The historical trips table is much larger than the spec assumed (7,634 rows on prod, not the 8 the CLAUDE.md snapshot suggested). Reverse-geocoding all of them via Nominatim's 1 req/sec TOS throttle would take ~4¼ hours end-to-end. --skip-geocode bypasses the Nominatim calls entirely. Geometry, plate, and idle backfills run in minutes; addresses stay NULL on historical rows and will only be populated for future trips by poll_trips. Co-Authored-By: Claude Opus 4.7 --- backfill_trips_enrichment.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/backfill_trips_enrichment.py b/backfill_trips_enrichment.py index a619b9e..810e0de 100644 --- a/backfill_trips_enrichment.py +++ b/backfill_trips_enrichment.py @@ -27,6 +27,12 @@ Usage: # Limit to trips since a date (UTC) python backfill_trips_enrichment.py --since 2026-04-01 --apply + + # Skip Nominatim reverse-geocoding (geometry/plate/idle only — runs in + # minutes instead of hours when backfilling thousands of rows). Addresses + # remain NULL for these rows and will be filled by future poll_trips + # cycles only for new trips, not retroactively. + python backfill_trips_enrichment.py --skip-geocode --apply ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ """ @@ -100,9 +106,12 @@ def _load_plates_cache(cur) -> dict[str, str]: return {imei: plate for imei, plate in cur.fetchall()} -def run(apply: bool, filter_imei: str | None, since: str | None) -> None: +def run(apply: bool, filter_imei: str | None, since: str | None, + skip_geocode: bool = False) -> None: t0 = time.time() enriched = degenerate = no_fixes = failed = 0 + if skip_geocode: + log.info("Reverse-geocoding disabled (--skip-geocode). Addresses will stay NULL.") with get_conn() as conn: with conn.cursor() as cur: @@ -149,8 +158,11 @@ def run(apply: bool, filter_imei: str | None, since: str | None) -> None: trip_id, imei, waypoints_count, ) - start_address = reverse_geocode(start_lat, start_lng) - end_address = reverse_geocode(end_lat, end_lng) + if skip_geocode: + start_address = end_address = None + else: + start_address = reverse_geocode(start_lat, start_lng) + end_address = reverse_geocode(end_lat, end_lng) vehicle_plate = existing_plate or plates.get(imei) log.info( @@ -207,9 +219,11 @@ if __name__ == "__main__": parser = argparse.ArgumentParser( description="Backfill route_geom / start_geom / end_geom / addresses on tracksolid.trips." ) - parser.add_argument("--apply", action="store_true", help="Write changes to DB (default: dry-run)") - parser.add_argument("--imei", default=None, help="Limit to a single IMEI") - parser.add_argument("--since", default=None, help="Only trips with start_time >= YYYY-MM-DD (UTC)") + parser.add_argument("--apply", action="store_true", help="Write changes to DB (default: dry-run)") + parser.add_argument("--imei", default=None, help="Limit to a single IMEI") + parser.add_argument("--since", default=None, help="Only trips with start_time >= YYYY-MM-DD (UTC)") + parser.add_argument("--skip-geocode", action="store_true", help="Skip Nominatim reverse-geocoding (fast path for large backfills)") args = parser.parse_args() - run(apply=args.apply, filter_imei=args.imei, since=args.since) + run(apply=args.apply, filter_imei=args.imei, since=args.since, + skip_geocode=args.skip_geocode) From 737ca67712460be59a072154463bf60143cdd892 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Mon, 4 May 2026 14:03:40 +0300 Subject: [PATCH 09/31] feat(analytics): add v_driver_clock_daily/today views for tardiness monitoring Two read-only views in the tracksolid schema feeding n8n's working-hours checks: per-IMEI per-Nairobi-day reporting/closing times, start/end locations + Nominatim addresses, and trip-count/km/drive-hours context. No policy embedded; cost-centre filtering and tardiness thresholds live in n8n. Co-Authored-By: Claude Opus 4.7 --- 10_driver_clock_views.sql | 111 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 10_driver_clock_views.sql diff --git a/10_driver_clock_views.sql b/10_driver_clock_views.sql new file mode 100644 index 0000000..801a0ae --- /dev/null +++ b/10_driver_clock_views.sql @@ -0,0 +1,111 @@ +-- 10_driver_clock_views.sql +-- Driver clock-in / clock-out views for n8n tardiness + working-hours monitoring. +-- +-- Two views, both keyed by IMEI per local Africa/Nairobi date: +-- • v_driver_clock_daily — historical, one row per IMEI per day with activity +-- • v_driver_clock_today — thin pass-through filtered to today (EAT) +-- +-- The view exposes raw times, locations, and addresses; n8n owns tardiness +-- thresholds and cost-centre filtering. Closing time is the latest end_time +-- of any trip whose start_time falls on the local Nairobi date — kept lossless +-- so n8n can detect midnight crossings via reporting_ts/closing_ts. +-- +-- Reuses: +-- • tracksolid.trips.distance_km (renamed in migration 04) +-- • tracksolid.trips.driving_time_s (referenced in migration 05) +-- • tracksolid.trips.start_geom/end_geom (migration 02 §3.06) +-- • tracksolid.trips.start_address/end_address (migration 09 — Nominatim) +-- +-- Pattern follows 07_analytics_views.sql: regular views (not materialised), +-- COMMENT ON VIEW with provenance, GRANT SELECT TO grafana_ro. + +BEGIN; + +-- ───────────────────────────────────────────────────────────────────────────── +-- v_driver_clock_daily +-- One row per IMEI per local Africa/Nairobi date with at least one trip. +-- ───────────────────────────────────────────────────────────────────────────── +CREATE OR REPLACE VIEW tracksolid.v_driver_clock_daily AS +WITH daily_agg AS ( + SELECT + t.imei, + (t.start_time AT TIME ZONE 'Africa/Nairobi')::date AS report_date, + MIN(t.start_time) AS reporting_ts, + MAX(t.end_time) AS closing_ts, + COUNT(*) AS trips_count, + SUM(t.distance_km) AS total_km, + SUM(t.driving_time_s)::numeric / 3600 AS drive_hours + FROM tracksolid.trips t + GROUP BY t.imei, (t.start_time AT TIME ZONE 'Africa/Nairobi')::date +), +start_row AS ( + SELECT DISTINCT ON (t.imei, (t.start_time AT TIME ZONE 'Africa/Nairobi')::date) + t.imei, + (t.start_time AT TIME ZONE 'Africa/Nairobi')::date AS report_date, + ST_Y(t.start_geom::geometry) AS start_lat, + ST_X(t.start_geom::geometry) AS start_lng, + t.start_address AS start_address + FROM tracksolid.trips t + ORDER BY t.imei, (t.start_time AT TIME ZONE 'Africa/Nairobi')::date, t.start_time ASC +), +end_row AS ( + SELECT DISTINCT ON (t.imei, (t.start_time AT TIME ZONE 'Africa/Nairobi')::date) + t.imei, + (t.start_time AT TIME ZONE 'Africa/Nairobi')::date AS report_date, + ST_Y(t.end_geom::geometry) AS end_lat, + ST_X(t.end_geom::geometry) AS end_lng, + t.end_address AS end_address + FROM tracksolid.trips t + ORDER BY t.imei, (t.start_time AT TIME ZONE 'Africa/Nairobi')::date, t.end_time DESC NULLS LAST +) +SELECT + a.imei, + d.driver_name, + d.vehicle_number, + d.cost_centre, + COALESCE(d.assigned_city, d.city, 'unassigned') AS assigned_city, + a.report_date, + (a.reporting_ts AT TIME ZONE 'Africa/Nairobi')::time AS reporting_time, + (a.closing_ts AT TIME ZONE 'Africa/Nairobi')::time AS closing_time, + a.reporting_ts, + a.closing_ts, + s.start_lat, + s.start_lng, + s.start_address, + e.end_lat, + e.end_lng, + e.end_address, + a.trips_count, + a.total_km, + a.drive_hours +FROM daily_agg a +LEFT JOIN start_row s ON s.imei = a.imei AND s.report_date = a.report_date +LEFT JOIN end_row e ON e.imei = a.imei AND e.report_date = a.report_date +LEFT JOIN tracksolid.devices d ON d.imei = a.imei; + +COMMENT ON VIEW tracksolid.v_driver_clock_daily IS + 'Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi ' + 'date with at least one trip. Reporting/closing times are derived from trip ' + 'start_time/end_time bounded by local-date start; closing_ts may cross ' + 'midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre ' + 'filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).'; + +GRANT SELECT ON tracksolid.v_driver_clock_daily TO grafana_ro; + + +-- ───────────────────────────────────────────────────────────────────────────── +-- v_driver_clock_today +-- Pass-through filter: today's row from v_driver_clock_daily. +-- ───────────────────────────────────────────────────────────────────────────── +CREATE OR REPLACE VIEW tracksolid.v_driver_clock_today AS +SELECT * +FROM tracksolid.v_driver_clock_daily +WHERE report_date = (NOW() AT TIME ZONE 'Africa/Nairobi')::date; + +COMMENT ON VIEW tracksolid.v_driver_clock_today IS + 'Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE ' + '''Africa/Nairobi'')::date. Refreshes as trips land throughout the day.'; + +GRANT SELECT ON tracksolid.v_driver_clock_today TO grafana_ro; + +COMMIT; From e811dd8f347d2f4c0c48406a1a9152d85493bf53 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Thu, 7 May 2026 13:21:35 +0300 Subject: [PATCH 10/31] feat(infra): add pgbouncer sidecar to cap tracksolid_db connections Phase 1 of the pgbouncer + pgAdmin rollout (runbook: 260507_pgbouncer_deployment.md). pgAdmin4 on the maintainer's laptop has been exhausting tracksolid_db's max_connections, cascading to pgcli and operations. Adds an internal-only pgbouncer service in transaction mode with a small backend pool (default 15) so admin-tool sprawl can no longer starve the ingest pipeline. No client cutover this round - ingest, Grafana, webhook, and backup all keep talking to timescale_db:5432 directly. SCRAM passthrough is wired via a new pgbouncer role + public.user_lookup() function (migration 10). The role is created with a placeholder password; sync_role_passwords() in run_migrations.py replaces it from PGBOUNCER_AUTH_PASSWORD on every container startup, mirroring the existing grafana_ro convention. Requires PGBOUNCER_AUTH_PASSWORD to be set in .env before deploy. Co-Authored-By: Claude Opus 4.7 --- 10_pgbouncer_auth.sql | 32 ++++ 260507_pgbouncer_deployment.md | 328 +++++++++++++++++++++++++++++++++ docker-compose.yaml | 36 ++++ run_migrations.py | 2 + 4 files changed, 398 insertions(+) create mode 100644 10_pgbouncer_auth.sql create mode 100644 260507_pgbouncer_deployment.md diff --git a/10_pgbouncer_auth.sql b/10_pgbouncer_auth.sql new file mode 100644 index 0000000..00c1a5c --- /dev/null +++ b/10_pgbouncer_auth.sql @@ -0,0 +1,32 @@ +-- 10_pgbouncer_auth.sql +-- pgbouncer SCRAM passthrough auth: dedicated role + user_lookup() function. +-- Runbook: 260507_pgbouncer_deployment.md +-- +-- Idempotent. Re-applying is a no-op: +-- * Role created only when missing (placeholder password, replaced on every +-- container startup by run_migrations.py:sync_role_passwords from +-- PGBOUNCER_AUTH_PASSWORD). +-- * Function uses CREATE OR REPLACE. +-- * GRANT/REVOKE are safe to re-run. + +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'pgbouncer') THEN + CREATE ROLE pgbouncer LOGIN PASSWORD 'SET_PASSWORD_IN_ENV'; + END IF; +END +$$; + +CREATE OR REPLACE FUNCTION public.user_lookup(in_user text, + OUT uname text, OUT phash text) RETURNS record AS $$ +BEGIN + SELECT usename, passwd + FROM pg_catalog.pg_shadow + WHERE usename = in_user + INTO uname, phash; + RETURN; +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +REVOKE ALL ON FUNCTION public.user_lookup(text) FROM public; +GRANT EXECUTE ON FUNCTION public.user_lookup(text) TO pgbouncer; diff --git a/260507_pgbouncer_deployment.md b/260507_pgbouncer_deployment.md new file mode 100644 index 0000000..7decf0f --- /dev/null +++ b/260507_pgbouncer_deployment.md @@ -0,0 +1,328 @@ +# pgbouncer + pgAdmin4 sidecar deployment + +**Date:** 2026-05-07 +**Branch:** `quality-program-2026-04-12` +**Status:** Plan approved; implementation pending + +--- + +## Context + +**Driver:** pgAdmin4 running on the maintainer's laptop has been exhausting +`tracksolid_db`'s `max_connections`. Each Query Tool tab in pgAdmin holds its +own long-lived backend connection; combined with the existing peak of ~50–60 +connections from the ingest pipeline, the budget tips over and cascades — +pgcli (and anything else trying to connect) starts failing. + +**Goal:** Add pgbouncer in front of `timescale_db` to enforce a connection +budget via transaction-mode pooling, and deploy pgAdmin4 as a Coolify-managed +sidecar that connects through pgbouncer over the Docker network. Net effect: +pgAdmin sprawl is multiplexed onto a small fixed pool of backends, admin +tooling moves on-VM (lower latency, persistent workspace, smaller external +attack surface), and host port 5433 becomes optional/closeable in a follow-up. + +**Frozen scope (unchanged this round):** +- DWH bronze pipeline (`dwh/*.sql`, `tracksolid_dwh@31.97.44.246:5888`) +- n8n DWH workflows (`n8n-workflows/dwh_extract*`, `dwh_load_bronze*`) +- Grafana provisioning (`grafana/provisioning/datasources/...`) +- Python ingest containers (`ingest_movement_rev.py`, `ingest_events_rev.py`, + `webhook_receiver_rev.py`) — they keep talking to `timescale_db:5432` + directly. Cutover, if desired, is a separate plan. +- `db_backup` sidecar — `pg_dump` is incompatible with transaction-mode + pooling and stays on `timescale_db:5432`. + +--- + +## Phase 1 — pgbouncer sidecar, no client cutover + +Add a new service to `docker-compose.yaml`. Internal Docker network only; +no host port binding. + +```yaml + pgbouncer: + image: edoburu/pgbouncer:1.23.1 + restart: always + depends_on: + timescale_db: + condition: service_healthy + env_file: .env + environment: + - DB_HOST=timescale_db + - DB_PORT=5432 + - DB_USER=${POSTGRES_USER} + - DB_PASSWORD=${POSTGRES_PASSWORD} + - DB_NAME=${POSTGRES_DB} + - POOL_MODE=transaction + - AUTH_TYPE=scram-sha-256 + - MAX_CLIENT_CONN=200 + - DEFAULT_POOL_SIZE=15 + - MIN_POOL_SIZE=2 + - RESERVE_POOL_SIZE=5 + - SERVER_RESET_QUERY=DISCARD ALL + - SERVER_IDLE_TIMEOUT=600 + - ADMIN_USERS=${POSTGRES_USER} + - LISTEN_PORT=6432 + - AUTH_USER=pgbouncer + - AUTH_QUERY=SELECT uname, phash FROM public.user_lookup($$1) + healthcheck: + test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -p 6432 -U ${POSTGRES_USER}"] + interval: 30s + timeout: 5s + retries: 3 +``` + +**Why these values:** +- `POOL_MODE=transaction` — recycles backend on every transaction boundary. + Cuts pgAdmin's per-tab idle conn from 1 backend → ~0 when idle. +- `DEFAULT_POOL_SIZE=15` — total backend slots per (user, db) pair. Sits + comfortably under Postgres `max_connections` (default 100) leaving room for + ingest's existing ~50–60. +- `MAX_CLIENT_CONN=200` — pgAdmin can open as many tabs as it wants; they + queue rather than fail. +- `RESERVE_POOL_SIZE=5` — emergency slack when `default_pool_size` saturates. +- `SERVER_RESET_QUERY=DISCARD ALL` — wipes session state between transactions + so leaked `SET`s from one client don't bleed into the next. + +### Auth: SCRAM passthrough via `auth_query` + +Avoids hand-maintaining `userlist.txt`. pgbouncer authenticates as a +dedicated `pgbouncer` Postgres role and looks up SCRAM hashes for the +requesting user via a SECURITY DEFINER function. + +New migration `10_pgbouncer_auth.sql` (08 and 09 are taken by +`08_analytics_config.sql` and `09_trips_enrichment.sql`): + +```sql +-- Role created with placeholder password; run_migrations.py:sync_role_passwords +-- replaces it with PGBOUNCER_AUTH_PASSWORD on every container startup. +-- Same convention used today for grafana_ro. +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'pgbouncer') THEN + CREATE ROLE pgbouncer LOGIN PASSWORD 'SET_PASSWORD_IN_ENV'; + END IF; +END +$$; + +CREATE OR REPLACE FUNCTION public.user_lookup(in_user text, + OUT uname text, OUT phash text) RETURNS record AS $$ +BEGIN + SELECT usename, passwd FROM pg_catalog.pg_shadow + WHERE usename = in_user INTO uname, phash; + RETURN; +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +REVOKE ALL ON FUNCTION public.user_lookup(text) FROM public; +GRANT EXECUTE ON FUNCTION public.user_lookup(text) TO pgbouncer; +``` + +Two changes to `run_migrations.py`: +1. Append `"10_pgbouncer_auth.sql"` to `MIGRATIONS`. +2. Extend `sync_role_passwords()` `roles` dict with + `"pgbouncer": os.getenv("PGBOUNCER_AUTH_PASSWORD")`. + +The migration is applied by the next ingest container restart and recorded +in `tracksolid.schema_migrations`. `sync_role_passwords` then ALTER ROLEs +the password from the env var so the placeholder is never live. + +### New env vars in `.env` + +- `PGBOUNCER_AUTH_PASSWORD` — password for the new `pgbouncer` Postgres role +- (existing vars reused: `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`) + +### Phase 1 verification + +1. Apply migration via ingest container restart; confirm in + `tracksolid.schema_migrations` that `10_pgbouncer_auth.sql` is recorded. +2. `docker compose up -d pgbouncer`. +3. From inside any compose service: + ```bash + psql -h pgbouncer -p 6432 -U postgres -d tracksolid_db -c 'SELECT 1' + ``` +4. From the pgbouncer container's admin console: + ```bash + psql -h 127.0.0.1 -p 6432 -U postgres -d pgbouncer -c 'SHOW POOLS;' + ``` + Confirm pool mode = `transaction`, server connections within + `default_pool_size`. +5. `SHOW STATS;` and `SHOW CLIENTS;` should both respond. +6. Confirm no client has cut over: `tracksolid.ingestion_log` continues + accumulating; Grafana panels keep refreshing. + +--- + +## Phase 2 — pgAdmin4 sidecar pointed at pgbouncer + +Coolify UI maps an HTTPS subdomain (e.g. `pgadmin.stage.rahamafresh.com`) to +internal port 80, mirroring the Grafana pattern at `docker-compose.yaml:78–80`. + +```yaml + pgadmin: + image: dpage/pgadmin4:8.14 + restart: always + depends_on: + pgbouncer: + condition: service_healthy + env_file: .env + environment: + - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL} + - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD} + - PGADMIN_CONFIG_SERVER_MODE=True + - PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=False + - PGADMIN_DISABLE_POSTFIX=True + volumes: + - pgadmin-data:/var/lib/pgadmin + - ./pgadmin/servers.json:/pgadmin4/servers.json:ro + # COOLIFY DOMAIN LOGIC: + # Set the actual URL in the Coolify UI; service exposes port 80 internally. +``` + +Add `pgadmin-data` to the `volumes:` block at the bottom of the compose file. + +### Pre-registered server (`pgadmin/servers.json`) + +```json +{ + "Servers": { + "1": { + "Name": "tracksolid_db (via pgbouncer)", + "Group": "Servers", + "Host": "pgbouncer", + "Port": 6432, + "MaintenanceDB": "tracksolid_db", + "Username": "postgres", + "SSLMode": "disable", + "ConnectionParameters": { + "sslmode": "disable", + "connect_timeout": 10 + } + } + } +} +``` + +### New env vars in `.env` + +- `PGADMIN_DEFAULT_EMAIL` +- `PGADMIN_DEFAULT_PASSWORD` + +### Phase 2 verification + +1. In the Coolify UI, point a subdomain at the `pgadmin` service, port 80. +2. Open the URL, log in with `PGADMIN_DEFAULT_EMAIL` / + `PGADMIN_DEFAULT_PASSWORD`. +3. The pre-registered "tracksolid_db (via pgbouncer)" server appears in the + left tree. Connect; provide the `postgres` password when prompted (pgAdmin + stores it in its own keyring after first use). +4. Open a Query Tool, run `SELECT now(), current_user;`. +5. From the `pgbouncer` container admin console: + ```sql + SHOW POOLS; + ``` + `cl_active` should reflect the open pgAdmin tab(s); `sv_active` / + `sv_idle` should sum to ≤ `default_pool_size` (15). +6. **Stress test:** open ~30 Query Tool tabs, run `SELECT pg_sleep(0.1);` in + each. Confirm `tracksolid_db` total connection count stays bounded: + ```sql + SELECT count(*) FROM pg_stat_activity; + ``` + Should be `default_pool_size + reserve_pool_size + (other clients)`, + not the number of pgAdmin tabs. + +--- + +## Files to modify / create + +| Path | Change | +|---|---| +| `260507_pgbouncer_deployment.md` | THIS FILE — runbook for the rollout | +| `docker-compose.yaml` | Add `pgbouncer` and `pgadmin` services; add `pgadmin-data` volume | +| `10_pgbouncer_auth.sql` | NEW — creates `pgbouncer` role + `public.user_lookup` SECURITY DEFINER function | +| `pgadmin/servers.json` | NEW — pre-registers `pgbouncer:6432` as the default server | +| `.env` | Add `PGBOUNCER_AUTH_PASSWORD`, `PGADMIN_DEFAULT_EMAIL`, `PGADMIN_DEFAULT_PASSWORD` (do not commit values) | +| `docs/CONNECTIONS.md` | Add a "pgbouncer + pgAdmin" section: pool mode, exposure, who uses it, how to connect for ad-hoc admin | +| `CLAUDE.md` §3 / §4 | Note that admin tooling now goes through `pgbouncer:6432`; ingest/grafana/backup remain direct; reference this runbook | + +## Files NOT to modify (frozen scope) + +- `grafana/provisioning/datasources/tracksolid_postgres.yaml` +- `n8n-workflows/dwh_extract*.json`, `n8n-workflows/dwh_load_bronze*.json` +- `dwh/*.sql` +- `ingest_movement_rev.py`, `ingest_events_rev.py`, `webhook_receiver_rev.py`, + `ts_shared_rev.py` +- `backup/` — `pg_dump` keeps using `timescale_db:5432` directly + +--- + +## Reused conventions and utilities + +- `run_migrations.py` already applies new `NN_*.sql` files in order against + `tracksolid_db` and tracks them in `tracksolid.schema_migrations`. Phase 1 + adds `10_pgbouncer_auth.sql` to this flow — no new tooling needed. +- `env_file: .env` + `depends_on: condition: service_healthy` mirrors + the existing pattern at `docker-compose.yaml:28–31, 39–42, 50–53, 67–70, + 87–90`. +- Coolify domain-via-UI mirrors the Grafana comment at + `docker-compose.yaml:78–80` and the webhook_receiver comment at + `docker-compose.yaml:54–55`. +- Container-name resolution rule from CLAUDE.md §3 still applies for any + `docker exec` against the new services: + ```bash + docker ps --filter name=pgbouncer --format "{{.Names}}" | head -1 + docker ps --filter name=pgadmin --format "{{.Names}}" | head -1 + ``` + +--- + +## Out-of-scope follow-ups (separate plans) + +1. **Cut over Python ingest to pgbouncer.** Change `DATABASE_URL` in `.env` + from `timescale_db:5432` to `pgbouncer:6432`. Requires verifying psycopg2 + pool + SAVEPOINTs against transaction-mode pgbouncer (low risk per + exploration — no LISTEN/NOTIFY, no advisory locks across statements, no + prepared statements in the codebase). +2. **Close host port 5433** on `timescale_db` once pgAdmin web UI is the + established admin path. Removes the public-IP Postgres exposure entirely. +3. **Rotate `dwh_owner` / `grafana_ro` plaintext passwords** still in + `dwh/260423_dwh_ddl_v1.sql` (pre-existing item from CLAUDE.md §10). + +--- + +## Rollback + +If pgbouncer or pgAdmin misbehaves: + +1. **Stop the new services without touching the rest of the stack:** + ```bash + docker compose stop pgbouncer pgadmin + docker compose rm -f pgbouncer pgadmin + ``` + Ingest, Grafana, webhook, backup are unaffected — they were never cut + over. +2. **Revert the SQL migration if needed:** + ```sql + DROP FUNCTION public.user_lookup(text); + DROP ROLE pgbouncer; + DELETE FROM tracksolid.schema_migrations + WHERE filename = '10_pgbouncer_auth.sql'; + ``` +3. **Revert compose changes** by checking out the prior `docker-compose.yaml`. + +--- + +## End-to-end verification checklist + +- [ ] `10_pgbouncer_auth.sql` applied — visible in + `tracksolid.schema_migrations` +- [ ] `pgbouncer` service healthy — `docker compose ps` shows `healthy` +- [ ] `psql -h pgbouncer -p 6432 -U postgres -d tracksolid_db -c 'SELECT 1'` + from inside the network +- [ ] `SHOW POOLS;` in pgbouncer admin shows `transaction` mode +- [ ] `pgadmin` service healthy — Coolify domain reachable over HTTPS +- [ ] Login + query through pgAdmin succeeds +- [ ] `SELECT count(*) FROM pg_stat_activity;` stays bounded under + 30-tab stress test +- [ ] Existing pipelines unaffected: `tracksolid.ingestion_log` continues + growing at current rate; Grafana dashboards still render +- [ ] pgcli no longer hits "too many connections" when used alongside pgAdmin diff --git a/docker-compose.yaml b/docker-compose.yaml index 882b3d0..d672140 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -79,6 +79,42 @@ services: # You will set the actual URL in the Coolify UI, # but the service needs to expose port 3000 internally. + pgbouncer: + # Connection pooler in front of timescale_db. + # Runbook: 260507_pgbouncer_deployment.md + # Internal Docker network only — no host port. SCRAM passthrough via + # auth_query against the public.user_lookup() function (migration 10). + image: edoburu/pgbouncer:1.23.1 + restart: always + depends_on: + timescale_db: + condition: service_healthy + env_file: .env + environment: + - DB_HOST=timescale_db + - DB_PORT=5432 + - DB_USER=${POSTGRES_USER} + - DB_PASSWORD=${POSTGRES_PASSWORD} + - DB_NAME=${POSTGRES_DB} + - POOL_MODE=transaction + - AUTH_TYPE=scram-sha-256 + - AUTH_USER=pgbouncer + # $$1 escapes docker-compose interpolation; pgbouncer sees literal $1. + - AUTH_QUERY=SELECT uname, phash FROM public.user_lookup($$1) + - MAX_CLIENT_CONN=200 + - DEFAULT_POOL_SIZE=15 + - MIN_POOL_SIZE=2 + - RESERVE_POOL_SIZE=5 + - SERVER_RESET_QUERY=DISCARD ALL + - SERVER_IDLE_TIMEOUT=600 + - ADMIN_USERS=${POSTGRES_USER} + - LISTEN_PORT=6432 + healthcheck: + test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -p 6432 -U ${POSTGRES_USER}"] + interval: 30s + timeout: 5s + retries: 3 + db_backup: build: context: ./backup diff --git a/run_migrations.py b/run_migrations.py index 143f71e..0618a55 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -33,6 +33,7 @@ MIGRATIONS = [ "07_analytics_views.sql", # Grafana-facing views in tracksolid.* "08_analytics_config.sql", # ops.cost_rates, ops.kpi_targets + seed data "09_trips_enrichment.sql", # trips.route_geom + addresses + plate + v_trips_enriched + "10_pgbouncer_auth.sql", # pgbouncer role + user_lookup() for SCRAM passthrough ] # ── Tables that must exist before the service is allowed to start ───────────── @@ -180,6 +181,7 @@ def sync_role_passwords(conn): """ roles = { "grafana_ro": os.getenv("GRAFANA_DB_RO_PASSWORD"), + "pgbouncer": os.getenv("PGBOUNCER_AUTH_PASSWORD"), } with conn.cursor() as cur: for role, password in roles.items(): From f3ad612a1c9f2418e4998ee9b3e53ee98333faf2 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Thu, 7 May 2026 13:48:31 +0300 Subject: [PATCH 11/31] =?UTF-8?q?fix(infra):=20drop=20pgbouncer=20image=20?= =?UTF-8?q?tag=20=E2=80=94=20pin=201.23.1=20unavailable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pinned tag failed to pull on Coolify deploy. Switching to the untagged edoburu/pgbouncer (rolling latest) so the sidecar can come up. Will revisit pinning to a known-good tag once verified live. Co-Authored-By: Claude Opus 4.7 --- 260507_pgbouncer_deployment.md | 2 +- docker-compose.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/260507_pgbouncer_deployment.md b/260507_pgbouncer_deployment.md index 7decf0f..fd0329a 100644 --- a/260507_pgbouncer_deployment.md +++ b/260507_pgbouncer_deployment.md @@ -40,7 +40,7 @@ no host port binding. ```yaml pgbouncer: - image: edoburu/pgbouncer:1.23.1 + image: edoburu/pgbouncer restart: always depends_on: timescale_db: diff --git a/docker-compose.yaml b/docker-compose.yaml index d672140..e8cb20b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -84,7 +84,7 @@ services: # Runbook: 260507_pgbouncer_deployment.md # Internal Docker network only — no host port. SCRAM passthrough via # auth_query against the public.user_lookup() function (migration 10). - image: edoburu/pgbouncer:1.23.1 + image: edoburu/pgbouncer restart: always depends_on: timescale_db: From bc020cb1a8cbac0a612beecdfe4d65ad020f9618 Mon Sep 17 00:00:00 2001 From: David Kiania Date: Thu, 7 May 2026 14:03:32 +0300 Subject: [PATCH 12/31] feat(infra): add pgAdmin4 web sidecar pointed at pgbouncer Phase 2 of the pgbouncer + pgAdmin rollout. pgAdmin4 runs as a Coolify- managed container on the same Docker network as pgbouncer, with a pre-registered server entry so the tracksolid_db (via pgbouncer) tree appears immediately on first login. Net effect: admin tooling moves on-VM (low latency, persistent workspace in pgadmin-data volume) and connects through pgbouncer:6432 in transaction mode, so opening many Query Tool tabs no longer exhausts max_connections. The desktop pgAdmin can be retired once this is verified live, after which host port 5433 can also be closed. Requires PGADMIN_DEFAULT_EMAIL and PGADMIN_DEFAULT_PASSWORD in the Coolify env, plus a subdomain mapping to this service on port 80. Co-Authored-By: Claude Opus 4.7 --- docker-compose.yaml | 22 ++++++++++++++++++++++ pgadmin/servers.json | 17 +++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 pgadmin/servers.json diff --git a/docker-compose.yaml b/docker-compose.yaml index e8cb20b..260258e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -115,6 +115,26 @@ services: timeout: 5s retries: 3 + pgadmin: + # Web pgAdmin4, connecting to tracksolid_db through pgbouncer. + # Runbook: 260507_pgbouncer_deployment.md (Phase 2) + # Coolify UI maps a subdomain to this service on internal port 80. + image: dpage/pgadmin4 + restart: always + depends_on: + pgbouncer: + condition: service_healthy + env_file: .env + environment: + - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL} + - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD} + - PGADMIN_CONFIG_SERVER_MODE=True + - PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=False + - PGADMIN_DISABLE_POSTFIX=True + volumes: + - pgadmin-data:/var/lib/pgadmin + - ./pgadmin/servers.json:/pgadmin4/servers.json:ro + db_backup: build: context: ./backup @@ -141,3 +161,5 @@ volumes: name: timescale-data grafana-data: name: grafana-data + pgadmin-data: + name: pgadmin-data diff --git a/pgadmin/servers.json b/pgadmin/servers.json new file mode 100644 index 0000000..3ec4934 --- /dev/null +++ b/pgadmin/servers.json @@ -0,0 +1,17 @@ +{ + "Servers": { + "1": { + "Name": "tracksolid_db (via pgbouncer)", + "Group": "Servers", + "Host": "pgbouncer", + "Port": 6432, + "MaintenanceDB": "tracksolid_db", + "Username": "postgres", + "SSLMode": "disable", + "ConnectionParameters": { + "sslmode": "disable", + "connect_timeout": 10 + } + } + } +} From 3b79d5a62e39343f8cf46d8d3ef0b02d461a8cfc Mon Sep 17 00:00:00 2001 From: David Kiania Date: Fri, 8 May 2026 00:34:10 +0300 Subject: [PATCH 13/31] revert(infra): remove pgAdmin4 sidecar and configs Reverts the Phase 2 pgAdmin web sidecar from bc020cb. pgbouncer (Phase 1) stays in place. On the instance the pgadmin container has been stopped and removed and the pgadmin-data volume dropped; Coolify subdomain and PGADMIN_DEFAULT_* env vars to be removed in the UI separately. Files: - docker-compose.yaml: drop pgadmin service block + pgadmin-data volume - pgadmin/servers.json: delete (directory removed) - 260507_pgbouncer_deployment.md: strip Phase 2, runbook is pgbouncer-only Co-Authored-By: Claude Opus 4.7 --- 260507_pgbouncer_deployment.md | 121 ++++----------------------------- docker-compose.yaml | 22 ------ pgadmin/servers.json | 17 ----- 3 files changed, 14 insertions(+), 146 deletions(-) delete mode 100644 pgadmin/servers.json diff --git a/260507_pgbouncer_deployment.md b/260507_pgbouncer_deployment.md index fd0329a..726b288 100644 --- a/260507_pgbouncer_deployment.md +++ b/260507_pgbouncer_deployment.md @@ -1,8 +1,8 @@ -# pgbouncer + pgAdmin4 sidecar deployment +# pgbouncer sidecar deployment **Date:** 2026-05-07 **Branch:** `quality-program-2026-04-12` -**Status:** Plan approved; implementation pending +**Status:** Phase 1 deployed. Phase 2 (pgAdmin4 sidecar) was rolled back on 2026-05-08 — see git history (`bc020cb`, then reverted). --- @@ -15,11 +15,9 @@ connections from the ingest pipeline, the budget tips over and cascades — pgcli (and anything else trying to connect) starts failing. **Goal:** Add pgbouncer in front of `timescale_db` to enforce a connection -budget via transaction-mode pooling, and deploy pgAdmin4 as a Coolify-managed -sidecar that connects through pgbouncer over the Docker network. Net effect: -pgAdmin sprawl is multiplexed onto a small fixed pool of backends, admin -tooling moves on-VM (lower latency, persistent workspace, smaller external -attack surface), and host port 5433 becomes optional/closeable in a follow-up. +budget via transaction-mode pooling. Desktop pgAdmin (or any other admin +client) connects through pgbouncer and is multiplexed onto a small fixed +pool of backends. **Frozen scope (unchanged this round):** - DWH bronze pipeline (`dwh/*.sql`, `tracksolid_dwh@31.97.44.246:5888`) @@ -152,96 +150,15 @@ the password from the env var so the placeholder is never live. --- -## Phase 2 — pgAdmin4 sidecar pointed at pgbouncer - -Coolify UI maps an HTTPS subdomain (e.g. `pgadmin.stage.rahamafresh.com`) to -internal port 80, mirroring the Grafana pattern at `docker-compose.yaml:78–80`. - -```yaml - pgadmin: - image: dpage/pgadmin4:8.14 - restart: always - depends_on: - pgbouncer: - condition: service_healthy - env_file: .env - environment: - - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL} - - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD} - - PGADMIN_CONFIG_SERVER_MODE=True - - PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=False - - PGADMIN_DISABLE_POSTFIX=True - volumes: - - pgadmin-data:/var/lib/pgadmin - - ./pgadmin/servers.json:/pgadmin4/servers.json:ro - # COOLIFY DOMAIN LOGIC: - # Set the actual URL in the Coolify UI; service exposes port 80 internally. -``` - -Add `pgadmin-data` to the `volumes:` block at the bottom of the compose file. - -### Pre-registered server (`pgadmin/servers.json`) - -```json -{ - "Servers": { - "1": { - "Name": "tracksolid_db (via pgbouncer)", - "Group": "Servers", - "Host": "pgbouncer", - "Port": 6432, - "MaintenanceDB": "tracksolid_db", - "Username": "postgres", - "SSLMode": "disable", - "ConnectionParameters": { - "sslmode": "disable", - "connect_timeout": 10 - } - } - } -} -``` - -### New env vars in `.env` - -- `PGADMIN_DEFAULT_EMAIL` -- `PGADMIN_DEFAULT_PASSWORD` - -### Phase 2 verification - -1. In the Coolify UI, point a subdomain at the `pgadmin` service, port 80. -2. Open the URL, log in with `PGADMIN_DEFAULT_EMAIL` / - `PGADMIN_DEFAULT_PASSWORD`. -3. The pre-registered "tracksolid_db (via pgbouncer)" server appears in the - left tree. Connect; provide the `postgres` password when prompted (pgAdmin - stores it in its own keyring after first use). -4. Open a Query Tool, run `SELECT now(), current_user;`. -5. From the `pgbouncer` container admin console: - ```sql - SHOW POOLS; - ``` - `cl_active` should reflect the open pgAdmin tab(s); `sv_active` / - `sv_idle` should sum to ≤ `default_pool_size` (15). -6. **Stress test:** open ~30 Query Tool tabs, run `SELECT pg_sleep(0.1);` in - each. Confirm `tracksolid_db` total connection count stays bounded: - ```sql - SELECT count(*) FROM pg_stat_activity; - ``` - Should be `default_pool_size + reserve_pool_size + (other clients)`, - not the number of pgAdmin tabs. - ---- - ## Files to modify / create | Path | Change | |---|---| | `260507_pgbouncer_deployment.md` | THIS FILE — runbook for the rollout | -| `docker-compose.yaml` | Add `pgbouncer` and `pgadmin` services; add `pgadmin-data` volume | +| `docker-compose.yaml` | Add `pgbouncer` service | | `10_pgbouncer_auth.sql` | NEW — creates `pgbouncer` role + `public.user_lookup` SECURITY DEFINER function | -| `pgadmin/servers.json` | NEW — pre-registers `pgbouncer:6432` as the default server | -| `.env` | Add `PGBOUNCER_AUTH_PASSWORD`, `PGADMIN_DEFAULT_EMAIL`, `PGADMIN_DEFAULT_PASSWORD` (do not commit values) | -| `docs/CONNECTIONS.md` | Add a "pgbouncer + pgAdmin" section: pool mode, exposure, who uses it, how to connect for ad-hoc admin | +| `.env` | Add `PGBOUNCER_AUTH_PASSWORD` (do not commit values) | +| `docs/CONNECTIONS.md` | Add a "pgbouncer" section: pool mode, exposure, who uses it, how to connect for ad-hoc admin | | `CLAUDE.md` §3 / §4 | Note that admin tooling now goes through `pgbouncer:6432`; ingest/grafana/backup remain direct; reference this runbook | ## Files NOT to modify (frozen scope) @@ -263,14 +180,10 @@ Add `pgadmin-data` to the `volumes:` block at the bottom of the compose file. - `env_file: .env` + `depends_on: condition: service_healthy` mirrors the existing pattern at `docker-compose.yaml:28–31, 39–42, 50–53, 67–70, 87–90`. -- Coolify domain-via-UI mirrors the Grafana comment at - `docker-compose.yaml:78–80` and the webhook_receiver comment at - `docker-compose.yaml:54–55`. - Container-name resolution rule from CLAUDE.md §3 still applies for any - `docker exec` against the new services: + `docker exec` against the new service: ```bash docker ps --filter name=pgbouncer --format "{{.Names}}" | head -1 - docker ps --filter name=pgadmin --format "{{.Names}}" | head -1 ``` --- @@ -282,21 +195,19 @@ Add `pgadmin-data` to the `volumes:` block at the bottom of the compose file. pool + SAVEPOINTs against transaction-mode pgbouncer (low risk per exploration — no LISTEN/NOTIFY, no advisory locks across statements, no prepared statements in the codebase). -2. **Close host port 5433** on `timescale_db` once pgAdmin web UI is the - established admin path. Removes the public-IP Postgres exposure entirely. -3. **Rotate `dwh_owner` / `grafana_ro` plaintext passwords** still in +2. **Rotate `dwh_owner` / `grafana_ro` plaintext passwords** still in `dwh/260423_dwh_ddl_v1.sql` (pre-existing item from CLAUDE.md §10). --- ## Rollback -If pgbouncer or pgAdmin misbehaves: +If pgbouncer misbehaves: -1. **Stop the new services without touching the rest of the stack:** +1. **Stop the service without touching the rest of the stack:** ```bash - docker compose stop pgbouncer pgadmin - docker compose rm -f pgbouncer pgadmin + docker compose stop pgbouncer + docker compose rm -f pgbouncer ``` Ingest, Grafana, webhook, backup are unaffected — they were never cut over. @@ -319,10 +230,6 @@ If pgbouncer or pgAdmin misbehaves: - [ ] `psql -h pgbouncer -p 6432 -U postgres -d tracksolid_db -c 'SELECT 1'` from inside the network - [ ] `SHOW POOLS;` in pgbouncer admin shows `transaction` mode -- [ ] `pgadmin` service healthy — Coolify domain reachable over HTTPS -- [ ] Login + query through pgAdmin succeeds -- [ ] `SELECT count(*) FROM pg_stat_activity;` stays bounded under - 30-tab stress test - [ ] Existing pipelines unaffected: `tracksolid.ingestion_log` continues growing at current rate; Grafana dashboards still render - [ ] pgcli no longer hits "too many connections" when used alongside pgAdmin diff --git a/docker-compose.yaml b/docker-compose.yaml index 260258e..e8cb20b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -115,26 +115,6 @@ services: timeout: 5s retries: 3 - pgadmin: - # Web pgAdmin4, connecting to tracksolid_db through pgbouncer. - # Runbook: 260507_pgbouncer_deployment.md (Phase 2) - # Coolify UI maps a subdomain to this service on internal port 80. - image: dpage/pgadmin4 - restart: always - depends_on: - pgbouncer: - condition: service_healthy - env_file: .env - environment: - - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL} - - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD} - - PGADMIN_CONFIG_SERVER_MODE=True - - PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=False - - PGADMIN_DISABLE_POSTFIX=True - volumes: - - pgadmin-data:/var/lib/pgadmin - - ./pgadmin/servers.json:/pgadmin4/servers.json:ro - db_backup: build: context: ./backup @@ -161,5 +141,3 @@ volumes: name: timescale-data grafana-data: name: grafana-data - pgadmin-data: - name: pgadmin-data diff --git a/pgadmin/servers.json b/pgadmin/servers.json deleted file mode 100644 index 3ec4934..0000000 --- a/pgadmin/servers.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "Servers": { - "1": { - "Name": "tracksolid_db (via pgbouncer)", - "Group": "Servers", - "Host": "pgbouncer", - "Port": 6432, - "MaintenanceDB": "tracksolid_db", - "Username": "postgres", - "SSLMode": "disable", - "ConnectionParameters": { - "sslmode": "disable", - "connect_timeout": 10 - } - } - } -} From 2309464ab8549a0b50cab79eed9544b4e7e3225a Mon Sep 17 00:00:00 2001 From: david kiania Date: Thu, 21 May 2026 21:05:26 +0300 Subject: [PATCH 14/31] FIX-M21: alarm cross-feed + stale-IMEI recovery for live_positions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-pick of c8f5907 (originally FIX-M20 on main) onto quality-program-2026-04-12 — renamed to FIX-M21 here to avoid clashing with this branch's existing [FIX-M20] (trip enrichment, commit 144dede). Behaviour and code are unchanged from the main-branch original; the annotation tag is the only difference. Background ---------- A field audit of liveposition.rahamafresh.com on 2026-05-21 surfaced two freshness gaps that share a single root cause: tracksolid.live_positions was being written by only one path (the 60s polled sweep), and that path silently omits devices that don't have a "current" fix in Jimi's location.list response. Effect on the dashboard: * 18 vehicles show OFFLINE for days-to-months — last fix is whatever the sweep wrote before Jimi dropped them. * 3 vehicles (KDK 780K, KCQ 618K, KCZ 476E) depend on dashcam fallback because their dedicated tracker has been silent; the camera's lat/lng arrives via /pushalarm webhooks (5,287/day, 100% lat/lng fill) but we discard it after writing to tracksolid.alarms. Verified upstream subscription state: only /pushalarm is registered with Jimi; the n8n forwarders for /pushgps, /pushtripreport, /pushobd are inactive. This change uses only data that already arrives. What's in this commit --------------------- ts_shared_rev.py * upsert_live_position(cur, imei, lat, lng, gps_time, ..., extras=None) — single time-guarded upsert all three writers will share. Guards on is_valid_fix() (filters Zero-Island and out-of-range) and EXCLUDED.gps_time > stored.gps_time so late-arriving alarms or webhook retries can't rewind a fresher marker. COALESCE on optional columns so sparse callers don't blank dense ones' values. * get_stale_imeis(stale_minutes=30) — SELECT enabled_flag=1 devices whose live_positions.gps_time is NULL or older than the threshold, ordered NULLS FIRST so worst-offenders are in batch #1. * ensure_device(cur, imei, device_name=None) — relocated from webhook_receiver_rev so every live_positions writer can satisfy the FK without re-defining the helper. The original underscore-prefixed name in webhook_receiver_rev becomes a backwards-compat alias. webhook_receiver_rev.py * /pushalarm — after the alarm row insert, call upsert_live_position with the alarm's lat/lng and alarmTime. Sits inside the existing per-item SAVEPOINT, so a cross-feed failure rolls back only that one alarm's cross-feed, not the alarm row. ingest_movement_rev.py * poll_live_positions — inline INSERT replaced with upsert_live_position (extras dict carries the sweep-only columns). Same data, time-guarded. * get_device_locations — inline INSERT replaced; also gains an ensure_device call so it can be safely fed arbitrary IMEIs. * poll_stale_locations() — new wrapper. Pulls get_stale_imeis() and hands it to get_device_locations. Scheduled every 10 minutes plus a startup catch-up call. Uses jimi.device.location.get which returns *last-known* fix, so devices the 60s sweep drops can be re-warmed. Expected post-deploy effect (estimates, see 06_live_location/260521_timescale_location_upgrade_major.md §4) * ~1,100-1,600 additional live_positions upserts/day from the alarm cross-feed, after the time-guard rejects ~70-80% of races vs the fresher 60s sweep. * The 3 camera-fallback plates flip to "seconds-after-alarm" cadence (JC400P emits ~107 alarms/day per device). * 8-14 of the 24 OFFLINE plates expected to recover via location.get's last-known-fix path within the first 30 minutes. * Dashboard's "Offline 24h+" KPI: 24 → 10-14 within the first hour. * No 06_live_location code changes required — reads through reporting.v_live_positions transparently. Tests ----- 12 webhook integration tests pass (3 new: cross-feed fires on valid fix; skips without lat/lng; skips Zero-Island). 8 new unit tests in test_stale_imeis.py cover the stale selector, the poll wrapper, and the time-guard contract on upsert_live_position. Full suite: 77 passed. Deployment ---------- No schema migration. Both webhook_receiver and ingest_movement containers must be rebuilt — source is image-baked, not bind-mounted. Rollback is git revert + rebuild. Plan & monitoring SQL: 06_live_location/260521_timescale_location_upgrade_major.md Verification playbook: 06_live_location/260521_timescale_location_upgrade_verification.md Co-Authored-By: Claude Opus 4.7 --- ingest_movement_rev.py | 121 ++++++++++-------- tests/fixtures/api_responses.py | 24 ++++ tests/integration/test_webhook_endpoints.py | 46 +++++++ tests/unit/test_stale_imeis.py | 112 +++++++++++++++++ ts_shared_rev.py | 132 ++++++++++++++++++++ webhook_receiver_rev.py | 33 ++--- 6 files changed, 402 insertions(+), 66 deletions(-) create mode 100644 tests/unit/test_stale_imeis.py diff --git a/ingest_movement_rev.py b/ingest_movement_rev.py index 20498e6..a618520 100644 --- a/ingest_movement_rev.py +++ b/ingest_movement_rev.py @@ -44,6 +44,17 @@ REVISIONS (QA-Verified): (Nominatim), and caches vehicle_plate from devices. Closes the NULL-column gaps that were inherent to jimi.device.track.mileage (it does not return coordinates, idle, or trip sequence). + [FIX-M21] Live-position freshness: (a) /pushalarm now cross-feeds its + lat/lng into live_positions via the new shared + upsert_live_position() helper, time-guarded so older + timestamps can't rewind fresher fixes; (b) new + poll_stale_locations() runs every 10 min and calls + get_device_locations() for IMEIs whose live_positions.gps_time + is missing or > 30 min stale, recovering devices the 60s + sweep silently drops. Both the 60s sweep and + get_device_locations() now share the same time-guarded + upsert. _ensure_device → ensure_device relocated to + ts_shared_rev for FK-guard reuse. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ """ @@ -61,6 +72,7 @@ from ts_shared_rev import ( get_active_imeis, get_active_imeis_by_target, get_conn, + get_stale_imeis, get_token, is_valid_fix, log_ingestion, @@ -69,9 +81,11 @@ from ts_shared_rev import ( clean_int, clean_ts, get_logger, + ensure_device, reverse_geocode, safe_task, setup_shutdown, + upsert_live_position, ) log = get_logger("movement") @@ -224,30 +238,30 @@ def poll_live_positions(): gps_num = clean_int(p.get("gpsNum")) current_mileage = clean_num(p.get("currentMileage")) - cur.execute(""" - INSERT INTO tracksolid.live_positions ( - imei, geom, lat, lng, pos_type, confidence, gps_time, hb_time, - speed, direction, acc_status, gps_signal, gps_num, - elec_quantity, power_value, battery_power_val, tracker_oil, - temperature, current_mileage, device_status, loc_desc, recorded_at - ) VALUES ( - %s, ST_SetSRID(ST_MakePoint(%s, %s), 4326), %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW() - ) - ON CONFLICT (imei) DO UPDATE SET - geom=EXCLUDED.geom, lat=EXCLUDED.lat, lng=EXCLUDED.lng, - gps_time=EXCLUDED.gps_time, speed=EXCLUDED.speed, direction=EXCLUDED.direction, - acc_status=EXCLUDED.acc_status, current_mileage=EXCLUDED.current_mileage, - updated_at=NOW() - """, ( - imei, lng, lat, lat, lng, clean(p.get("posType")), clean_int(p.get("confidence")), - gps_time, clean_ts(p.get("hbTime")), speed, - direction, acc_status, clean_int(p.get("gpsSignal")), - gps_num, clean_num(p.get("electQuantity")), clean_num(p.get("powerValue")), - clean_num(p.get("batteryPowerVal")), clean(p.get("trackerOil")), clean_num(p.get("temperature")), - current_mileage, clean(p.get("status")), clean(p.get("locDesc")) - )) - upserted += cur.rowcount + # [FIX-M21] Time-guarded upsert via shared helper so the + # 60s sweep, the alarm cross-feed, and get_device_locations + # all agree about freshness ordering. The sweep is normally + # the freshest source so the guard rarely rejects its writes. + upserted += upsert_live_position( + cur, imei, lat, lng, gps_time, + speed=speed, direction=direction, + acc_status=acc_status, + current_mileage=current_mileage, + extras={ + "pos_type": clean(p.get("posType")), + "confidence": clean_int(p.get("confidence")), + "hb_time": clean_ts(p.get("hbTime")), + "gps_signal": clean_int(p.get("gpsSignal")), + "gps_num": gps_num, + "elec_quantity": clean_num(p.get("electQuantity")), + "power_value": clean_num(p.get("powerValue")), + "battery_power_val": clean_num(p.get("batteryPowerVal")), + "tracker_oil": clean(p.get("trackerOil")), + "temperature": clean_num(p.get("temperature")), + "device_status": clean(p.get("status")), + "loc_desc": clean(p.get("locDesc")), + }, + ) # History (Hypertable Source) if gps_time: @@ -617,39 +631,44 @@ def get_device_locations(imeis: list) -> int: if not imei or not is_valid_fix(lat, lng): continue - cur.execute(""" - INSERT INTO tracksolid.live_positions ( - imei, geom, lat, lng, speed, direction, - gps_time, acc_status, current_mileage, recorded_at - ) VALUES ( - %s, ST_SetSRID(ST_MakePoint(%s, %s), 4326), - %s, %s, %s, %s, %s, %s, %s, NOW() - ) - ON CONFLICT (imei) DO UPDATE SET - geom = EXCLUDED.geom, - lat = EXCLUDED.lat, - lng = EXCLUDED.lng, - speed = EXCLUDED.speed, - direction = EXCLUDED.direction, - gps_time = EXCLUDED.gps_time, - acc_status = EXCLUDED.acc_status, - current_mileage = EXCLUDED.current_mileage, - updated_at = NOW() - """, ( - imei, lng, lat, lat, lng, - clean_num(p.get("speed")), - clean_num(p.get("direction")), + # [FIX-M21] FK guard — this path can see IMEIs the daily + # sync_devices hasn't picked up yet (especially when used + # as the stale-IMEI rescue path). + ensure_device(cur, imei, clean(p.get("deviceName"))) + + upserted += upsert_live_position( + cur, imei, lat, lng, clean_ts(p.get("gpsTime")), - clean(p.get("accStatus")), - clean_num(p.get("currentMileage")), - )) - upserted += 1 + speed=clean_num(p.get("speed")), + direction=clean_num(p.get("direction")), + acc_status=clean(p.get("accStatus")), + current_mileage=clean_num(p.get("currentMileage")), + ) conn.commit() log.info("get_device_locations: %d positions refreshed.", upserted) return upserted +# ── 7. Stale-IMEI Recovery — POLL-04 ───────────────────────────────────────── + +def poll_stale_locations(): + """[FIX-M21] Refresh live_positions for IMEIs whose stored gps_time is + missing or older than 30 minutes. + + Complements poll_live_positions (the 60s sweep), which silently omits + devices Jimi's location.list endpoint doesn't return. jimi.device.location.get + returns *last-known* fix per IMEI, so this path can re-warm devices + the sweep has dropped. + """ + stale = get_stale_imeis(stale_minutes=30) + if not stale: + log.info("poll_stale_locations: no stale IMEIs.") + return + log.info("poll_stale_locations: refreshing %d stale IMEI(s).", len(stale)) + get_device_locations(stale) + + # ── Main Loop ───────────────────────────────────────────────────────────────── def main(): @@ -661,12 +680,14 @@ def main(): safe_task(poll_trips, log)() safe_task(poll_parking, log)() safe_task(poll_track_list, log)() + safe_task(poll_stale_locations, log)() # Schedule schedule.every(60).seconds.do(safe_task(poll_live_positions, log)) schedule.every(15).minutes.do(safe_task(poll_trips, log)) schedule.every(15).minutes.do(safe_task(poll_parking, log)) schedule.every(30).minutes.do(safe_task(poll_track_list, log)) # [FIX-M14] + schedule.every(10).minutes.do(safe_task(poll_stale_locations, log)) # [FIX-M21] schedule.every().day.at("02:00").do(safe_task(sync_devices, log)) while True: diff --git a/tests/fixtures/api_responses.py b/tests/fixtures/api_responses.py index edebe26..c25183d 100644 --- a/tests/fixtures/api_responses.py +++ b/tests/fixtures/api_responses.py @@ -107,3 +107,27 @@ WEBHOOK_ALARM_NULL_TYPE = { "alarmType": None, "gateTime": "2024-04-12 07:30:00", } + +# Alarm with no lat/lng — cross-feed (FIX-M21) must skip live_positions +# but still write the alarm row. +WEBHOOK_ALARM_NO_POSITION = { + "deviceImei": "123456789012345", + "alarmType": "4", + "alarmName": "Speeding", + "gateTime": "2024-04-12 07:30:00", + "lat": None, + "lng": None, + "speed": 0.0, +} + +# Alarm with Zero-Island (0, 0) coordinates — is_valid_fix must reject; +# alarm row still writes, live_positions cross-feed must NOT fire. +WEBHOOK_ALARM_ZERO_ISLAND = { + "deviceImei": "123456789012345", + "alarmType": "4", + "alarmName": "Speeding", + "gateTime": "2024-04-12 07:30:00", + "lat": 0, + "lng": 0, + "speed": 0.0, +} diff --git a/tests/integration/test_webhook_endpoints.py b/tests/integration/test_webhook_endpoints.py index dd87e25..3acc403 100644 --- a/tests/integration/test_webhook_endpoints.py +++ b/tests/integration/test_webhook_endpoints.py @@ -20,6 +20,8 @@ import webhook_receiver_rev from tests.fixtures.api_responses import ( WEBHOOK_ALARM_PAYLOAD, WEBHOOK_ALARM_NULL_TYPE, + WEBHOOK_ALARM_NO_POSITION, + WEBHOOK_ALARM_ZERO_ISLAND, WEBHOOK_TRIP_BCD_PAYLOAD, WEBHOOK_TRIP_ISO_PAYLOAD, WEBHOOK_OBD_PAYLOAD, @@ -96,6 +98,50 @@ class TestPushAlarm: assert response.status_code == 200 assert response.json()["code"] == 0 + def test_alarm_cross_feeds_live_position(self, client, mock_db): + """FIX-M21: a valid alarm must additionally upsert live_positions.""" + mock_conn, mock_cur = mock_db + data_list = json.dumps([WEBHOOK_ALARM_PAYLOAD]) + response = client.post("/pushalarm", data={"token": "", "data_list": data_list}) + assert response.status_code == 200 + # Exactly one INSERT INTO live_positions should have fired. + lp_inserts = [ + c for c in mock_cur.execute.call_args_list + if "tracksolid.live_positions" in str(c) and "INSERT" in str(c) + ] + assert len(lp_inserts) == 1, "Cross-feed must upsert live_positions exactly once" + + def test_alarm_without_lat_lng_skips_cross_feed(self, client, mock_db): + """FIX-M21: an alarm without lat/lng must NOT touch live_positions + (but must still insert the alarm row).""" + mock_conn, mock_cur = mock_db + data_list = json.dumps([WEBHOOK_ALARM_NO_POSITION]) + response = client.post("/pushalarm", data={"token": "", "data_list": data_list}) + assert response.status_code == 200 + lp_inserts = [ + c for c in mock_cur.execute.call_args_list + if "tracksolid.live_positions" in str(c) and "INSERT" in str(c) + ] + assert len(lp_inserts) == 0, "No live_positions write without a valid fix" + alarm_inserts = [ + c for c in mock_cur.execute.call_args_list + if "tracksolid.alarms" in str(c) and "INSERT" in str(c) + ] + assert len(alarm_inserts) == 1, "Alarm row must still write" + + def test_alarm_with_zero_island_skips_cross_feed(self, client, mock_db): + """FIX-M21: a (0, 0) fix must NOT propagate to live_positions — + is_valid_fix in the shared helper guards Zero Island.""" + mock_conn, mock_cur = mock_db + data_list = json.dumps([WEBHOOK_ALARM_ZERO_ISLAND]) + response = client.post("/pushalarm", data={"token": "", "data_list": data_list}) + assert response.status_code == 200 + lp_inserts = [ + c for c in mock_cur.execute.call_args_list + if "tracksolid.live_positions" in str(c) and "INSERT" in str(c) + ] + assert len(lp_inserts) == 0, "Zero-Island fix must not reach live_positions" + class TestPushTripReport: def test_bcd_timestamp_parsed(self, client, mock_db): diff --git a/tests/unit/test_stale_imeis.py b/tests/unit/test_stale_imeis.py new file mode 100644 index 0000000..8d841df --- /dev/null +++ b/tests/unit/test_stale_imeis.py @@ -0,0 +1,112 @@ +"""Unit tests for the FIX-M21 stale-IMEI recovery helpers. + +Covers: + - ts_shared_rev.get_stale_imeis — the SQL selector + - ingest_movement_rev.poll_stale_locations — the scheduler wrapper +""" +import sys +import os +import pytest +from unittest.mock import MagicMock, patch +from contextlib import contextmanager + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) + +os.environ.setdefault("TRACKSOLID_APP_KEY", "test_key") +os.environ.setdefault("TRACKSOLID_APP_SECRET", "test_secret") +os.environ.setdefault("TRACKSOLID_USER_ID", "test_user") +os.environ.setdefault("TRACKSOLID_PWD_MD5", "test_md5") +os.environ.setdefault("DATABASE_URL", "postgresql://test:test@localhost:5432/test") + + +def _make_mock_conn(rows=None): + """Cursor/connection double that returns `rows` from fetchall().""" + mock_cur = MagicMock() + mock_cur.fetchall.return_value = rows or [] + mock_conn = MagicMock() + mock_conn.cursor.return_value.__enter__ = lambda s: mock_cur + mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=False) + return mock_conn, mock_cur + + +@contextmanager +def _conn_ctx(mock_conn): + yield mock_conn + + +class TestGetStaleImeis: + def test_returns_devices_with_old_gps_time(self): + from ts_shared_rev import get_stale_imeis + mock_conn, mock_cur = _make_mock_conn(rows=[("imei_a",), ("imei_b",)]) + with patch("ts_shared_rev.get_conn") as mock_get_conn: + mock_get_conn.return_value = _conn_ctx(mock_conn) + result = get_stale_imeis(stale_minutes=30) + + assert result == ["imei_a", "imei_b"] + sql = str(mock_cur.execute.call_args) + assert "enabled_flag = 1" in sql + assert "INTERVAL" in sql.upper() or "interval" in sql + assert "NULLS FIRST" in sql + + def test_returns_empty_when_no_stale(self): + from ts_shared_rev import get_stale_imeis + mock_conn, _ = _make_mock_conn(rows=[]) + with patch("ts_shared_rev.get_conn") as mock_get_conn: + mock_get_conn.return_value = _conn_ctx(mock_conn) + assert get_stale_imeis() == [] + + +class TestPollStaleLocations: + def test_noop_when_empty(self): + """If no IMEIs are stale, get_device_locations must NOT be called.""" + import ingest_movement_rev as mod + with patch.object(mod, "get_stale_imeis", return_value=[]), \ + patch.object(mod, "get_device_locations") as mock_refresh: + mod.poll_stale_locations() + mock_refresh.assert_not_called() + + def test_invokes_refresh_with_stale_list(self): + """When stale IMEIs are present, get_device_locations is called once + with the exact list returned by get_stale_imeis.""" + import ingest_movement_rev as mod + stale = ["imei_a", "imei_b", "imei_c"] + with patch.object(mod, "get_stale_imeis", return_value=stale), \ + patch.object(mod, "get_device_locations") as mock_refresh: + mod.poll_stale_locations() + mock_refresh.assert_called_once_with(stale) + + +class TestUpsertLivePositionGuards: + """Spot-checks on the time-guard contract — covers what the dashboard + relies on (no rewinding the marker on stale alarm arrivals).""" + + def test_skips_invalid_fix(self): + from ts_shared_rev import upsert_live_position + mock_cur = MagicMock() + # Zero-Island + assert upsert_live_position(mock_cur, "imei_x", 0, 0, "2026-05-21 10:00:00") == 0 + mock_cur.execute.assert_not_called() + + def test_skips_missing_gps_time(self): + from ts_shared_rev import upsert_live_position + mock_cur = MagicMock() + assert upsert_live_position(mock_cur, "imei_x", -1.29, 36.82, None) == 0 + mock_cur.execute.assert_not_called() + + def test_skips_missing_imei(self): + from ts_shared_rev import upsert_live_position + mock_cur = MagicMock() + assert upsert_live_position(mock_cur, None, -1.29, 36.82, "2026-05-21 10:00:00") == 0 + mock_cur.execute.assert_not_called() + + def test_executes_upsert_for_valid_fix(self): + from ts_shared_rev import upsert_live_position + mock_cur = MagicMock() + mock_cur.rowcount = 1 + n = upsert_live_position(mock_cur, "imei_x", -1.29, 36.82, "2026-05-21 10:00:00", + speed=42.5) + assert n == 1 + mock_cur.execute.assert_called_once() + sql = str(mock_cur.execute.call_args) + # The time-guard is the load-bearing detail — verify it's present. + assert "EXCLUDED.gps_time > tracksolid.live_positions.gps_time" in sql diff --git a/ts_shared_rev.py b/ts_shared_rev.py index 72a5504..6f9d42c 100644 --- a/ts_shared_rev.py +++ b/ts_shared_rev.py @@ -237,6 +237,138 @@ def get_active_imeis() -> list[str]: cur.execute("SELECT imei FROM tracksolid.devices WHERE enabled_flag = 1") return [r[0] for r in cur.fetchall()] +def get_stale_imeis(stale_minutes: int = 30) -> list[str]: + """[FIX-M21] IMEIs whose live_positions fix is missing or older than N minutes. + + Used by poll_stale_locations() to feed get_device_locations() with the + set the 60s sweep silently dropped. Ordered oldest-first (NULLs first) + so worst-offenders get the first seats in each 50-IMEI batch. + """ + with get_conn() as conn: + with conn.cursor() as cur: + cur.execute(""" + SELECT d.imei + FROM tracksolid.devices d + LEFT JOIN tracksolid.live_positions lp USING (imei) + WHERE d.enabled_flag = 1 + AND (lp.gps_time IS NULL + OR lp.gps_time < NOW() - (%s || ' minutes')::interval) + ORDER BY lp.gps_time ASC NULLS FIRST + """, (str(stale_minutes),)) + return [r[0] for r in cur.fetchall()] + +def ensure_device(cur, imei: str, device_name: Optional[str] = None) -> None: + """[FIX-M21] Upsert a stub row into tracksolid.devices so FK-constrained + inserts don't fail when ingest paths see an IMEI before sync_devices does. + + Lifted out of webhook_receiver_rev.py to be shareable by every writer + of live_positions / alarms / position_history. Idempotent. + """ + cur.execute( + """ + INSERT INTO tracksolid.devices (imei, device_name, status, created_at, updated_at) + VALUES (%s, %s, 'unknown', NOW(), NOW()) + ON CONFLICT (imei) DO NOTHING + """, + (imei, device_name), + ) + +def upsert_live_position( + cur, + imei: str, + lat, + lng, + gps_time, + speed=None, + direction=None, + acc_status=None, + current_mileage=None, + extras: Optional[dict] = None, +) -> int: + """[FIX-M21] Time-guarded upsert into tracksolid.live_positions. + + Only overwrites the stored row when the incoming gps_time is strictly + newer than what's already there. NULL stored gps_time always loses + (any fix beats no fix). Returns 1 if a row was written/updated, else 0. + + `extras` carries the columns only the 60s sweep emits + (pos_type, confidence, hb_time, gps_signal, gps_num, elec_quantity, + power_value, battery_power_val, tracker_oil, temperature, + device_status, loc_desc). When omitted, those columns are left alone + on update via COALESCE so a sparse caller (e.g. alarm cross-feed) + doesn't blank them out. + """ + if not imei or not gps_time or not is_valid_fix(lat, lng): + return 0 + + extras = extras or {} + cur.execute(""" + INSERT INTO tracksolid.live_positions ( + imei, geom, lat, lng, gps_time, speed, direction, + acc_status, current_mileage, + pos_type, confidence, hb_time, gps_signal, gps_num, + elec_quantity, power_value, battery_power_val, + tracker_oil, temperature, device_status, loc_desc, + recorded_at + ) VALUES ( + %(imei)s, + ST_SetSRID(ST_MakePoint(%(lng)s, %(lat)s), 4326), + %(lat)s, %(lng)s, %(gps_time)s, %(speed)s, %(direction)s, + %(acc_status)s, %(current_mileage)s, + %(pos_type)s, %(confidence)s, %(hb_time)s, %(gps_signal)s, %(gps_num)s, + %(elec_quantity)s, %(power_value)s, %(battery_power_val)s, + %(tracker_oil)s, %(temperature)s, %(device_status)s, %(loc_desc)s, + NOW() + ) + ON CONFLICT (imei) DO UPDATE SET + geom = EXCLUDED.geom, + lat = EXCLUDED.lat, + lng = EXCLUDED.lng, + gps_time = EXCLUDED.gps_time, + speed = COALESCE(EXCLUDED.speed, tracksolid.live_positions.speed), + direction = COALESCE(EXCLUDED.direction, tracksolid.live_positions.direction), + acc_status = COALESCE(EXCLUDED.acc_status, tracksolid.live_positions.acc_status), + current_mileage = COALESCE(EXCLUDED.current_mileage, tracksolid.live_positions.current_mileage), + pos_type = COALESCE(EXCLUDED.pos_type, tracksolid.live_positions.pos_type), + confidence = COALESCE(EXCLUDED.confidence, tracksolid.live_positions.confidence), + hb_time = COALESCE(EXCLUDED.hb_time, tracksolid.live_positions.hb_time), + gps_signal = COALESCE(EXCLUDED.gps_signal, tracksolid.live_positions.gps_signal), + gps_num = COALESCE(EXCLUDED.gps_num, tracksolid.live_positions.gps_num), + elec_quantity = COALESCE(EXCLUDED.elec_quantity, tracksolid.live_positions.elec_quantity), + power_value = COALESCE(EXCLUDED.power_value, tracksolid.live_positions.power_value), + battery_power_val = COALESCE(EXCLUDED.battery_power_val, tracksolid.live_positions.battery_power_val), + tracker_oil = COALESCE(EXCLUDED.tracker_oil, tracksolid.live_positions.tracker_oil), + temperature = COALESCE(EXCLUDED.temperature, tracksolid.live_positions.temperature), + device_status = COALESCE(EXCLUDED.device_status, tracksolid.live_positions.device_status), + loc_desc = COALESCE(EXCLUDED.loc_desc, tracksolid.live_positions.loc_desc), + updated_at = NOW() + WHERE EXCLUDED.gps_time IS NOT NULL + AND (tracksolid.live_positions.gps_time IS NULL + OR EXCLUDED.gps_time > tracksolid.live_positions.gps_time) + """, { + "imei": imei, + "lat": lat, + "lng": lng, + "gps_time": gps_time, + "speed": speed, + "direction": direction, + "acc_status": acc_status, + "current_mileage": current_mileage, + "pos_type": extras.get("pos_type"), + "confidence": extras.get("confidence"), + "hb_time": extras.get("hb_time"), + "gps_signal": extras.get("gps_signal"), + "gps_num": extras.get("gps_num"), + "elec_quantity": extras.get("elec_quantity"), + "power_value": extras.get("power_value"), + "battery_power_val": extras.get("battery_power_val"), + "tracker_oil": extras.get("tracker_oil"), + "temperature": extras.get("temperature"), + "device_status": extras.get("device_status"), + "loc_desc": extras.get("loc_desc"), + }) + return cur.rowcount + def get_active_imeis_by_target() -> dict[str, list[str]]: """[FIX-M19] Group active IMEIs by their Tracksolid sub-account so endpoints that require an `account`/`target` param (e.g. parking) can diff --git a/webhook_receiver_rev.py b/webhook_receiver_rev.py index b0d7108..125a2d7 100644 --- a/webhook_receiver_rev.py +++ b/webhook_receiver_rev.py @@ -55,6 +55,8 @@ from ts_shared_rev import ( clean_ts, is_valid_fix, get_logger, + ensure_device, + upsert_live_position, ) log = get_logger("webhook") @@ -178,22 +180,11 @@ def _make_geom_params(lat, lng): return (lng, lat, lng, lat) -def _ensure_device(cur, imei: str, device_name: Optional[str] = None) -> None: - """Upsert a stub row into tracksolid.devices so FK-constrained inserts don't fail. - - Jimi pushes alarms/GPS for devices that may not yet be in our devices table - (neither API-sync'd nor in the onboarding CSV). Rather than drop the event, - register the IMEI with whatever context the push carried; the nightly - `sync_devices()` and the CSV import fill in the remaining fields later. - """ - cur.execute( - """ - INSERT INTO tracksolid.devices (imei, device_name, status, created_at, updated_at) - VALUES (%s, %s, 'unknown', NOW(), NOW()) - ON CONFLICT (imei) DO NOTHING - """, - (imei, device_name), - ) +# Backwards-compat shim. The implementation was relocated to ts_shared_rev +# (as `ensure_device`) so ingest_movement_rev and any future writer can share +# the FK-guard without re-defining it. Existing call sites in this file +# continue to use the underscore-prefixed name. +_ensure_device = ensure_device # ── Health Check ────────────────────────────────────────────────────────────── @@ -392,6 +383,16 @@ async def push_alarm(request: Request): lat, lng, clean_num(item.get("speed")), )) + + # [FIX-M21] Cross-feed: every Jimi alarm carries lat/lng. + # Refresh live_positions so dashboard markers don't have to + # wait up to 60s for the next polled sweep. Time-guarded + # inside the helper — alarms older than the current fix lose. + upsert_live_position( + cur, imei, lat, lng, alarm_time, + speed=clean_num(item.get("speed")), + ) + cur.execute("RELEASE SAVEPOINT sp") inserted += 1 except Exception: From e5b0e192d88697995693a72d3b3cc315fbe9f3d3 Mon Sep 17 00:00:00 2001 From: david kiania Date: Mon, 1 Jun 2026 02:27:30 +0300 Subject: [PATCH 15/31] chore(repo): reorganize tree into migrations/ data/ legacy/ docs/ Group root-level files (accreted from incremental changes) by purpose without moving any deployment entrypoint or breaking imports: - migrations/ : numbered SQL 02-10 - data/ : source CSVs - legacy/ : superseded pre-_rev scripts + old pipeline notes (not deployed) - docs/{manuals,reference,reports}/ : loose manuals, references, reports - strip stray ** / *** prefixes from 5 doc filenames - delete empty documents.txt / push_webhook.md Reference updates so nothing breaks: - run_migrations.py -> /app/migrations/ - run_migrations.sh -> $SCRIPT_DIR/migrations - import_drivers_csv.py -> data/ - docker-compose.yaml -> runbook path comment - CLAUDE.md -> codebase map + inline doc references Deployed Python (3 services + ts_shared_rev + run_migrations) and the documented ops one-shots stay at root, preserving the flat-import layout and all documented commands. Verified: py_compile clean across all modules, every MIGRATIONS entry resolves under migrations/, CI-referenced paths (tests/, mypy targets, db_audit) and the grafana build context intact. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 26 +- .../20260414_FS__Logistics - final_fixed.csv | 0 .../20260427_FSG_Vehicles_mitieng.csv | 0 .../fireside_logistics_cleaned_v2.csv | 0 docker-compose.yaml | 2 +- .../manuals/DWH_Execution_Manual.md | 0 .../manuals/OPERATIONS_MANUAL.md | 0 .../manuals/connecting_python_tracksolid.md | 0 .../manuals/grafanaDeployment.md | 0 .../manuals/grafanaOperationalManual.md | 0 .../manuals/tracksolid_DB_manual.md | 0 .../manuals/tracksolid_docker_commands.md | 0 .../reference/01_BusinessAnalytics.md | 0 .../reference/260507_pgbouncer_deployment.md | 0 .../reference/tracksolidApiDocumentation.md | 0 .../reports/260410_baseline_report.md | 0 .../reports/260412_baseline_report.md | 0 .../reports/260427_audit_output.txt | 0 .../reports/260427_device_reconciliation.md | 0 .../reports/260601_improvement_claude_48.html | 374 ++++++++++++++++++ .../reports/new_feature.txt | 0 documents.txt | 0 import_drivers_csv.py | 2 +- .../tracksolid_analytics_pipeline.txt | 0 .../tracksolid_extract.py | 0 .../tracksolid_ingestion_pipeline.txt | 0 .../tracksolid_update_v2.py | 0 .../tracksolid_vehicle_update.py | 0 .../02_tracksolid_full_schema_rev.sql | 0 .../03_webhook_schema_migration.sql | 0 .../04_bug_fix_migration.sql | 0 .../05_enhancement_migration.sql | 0 .../06_business_analytics_migration.sql | 0 .../07_analytics_views.sql | 0 .../08_analytics_config.sql | 0 .../09_trips_enrichment.sql | 0 .../10_driver_clock_views.sql | 0 .../10_pgbouncer_auth.sql | 0 push_webhook.md | 0 run_migrations.py | 2 +- run_migrations.sh | 4 +- 41 files changed, 393 insertions(+), 17 deletions(-) rename 20260414_FS__Logistics - final_fixed.csv => data/20260414_FS__Logistics - final_fixed.csv (100%) rename 20260427_FSG_Vehicles_mitieng.csv => data/20260427_FSG_Vehicles_mitieng.csv (100%) rename fireside_logistics_cleaned_v2.csv => data/fireside_logistics_cleaned_v2.csv (100%) rename DWH_Execution_Manual.md => docs/manuals/DWH_Execution_Manual.md (100%) rename **OPERATIONS_MANUAL.md => docs/manuals/OPERATIONS_MANUAL.md (100%) rename connecting_python_tracksolid.md => docs/manuals/connecting_python_tracksolid.md (100%) rename grafanaDeployment.md => docs/manuals/grafanaDeployment.md (100%) rename grafanaOperationalManual.md => docs/manuals/grafanaOperationalManual.md (100%) rename ***tracksolid_DB_manual.md => docs/manuals/tracksolid_DB_manual.md (100%) rename **02_tracksolid_docker_commands.md => docs/manuals/tracksolid_docker_commands.md (100%) rename **01_BusinessAnalytics.md => docs/reference/01_BusinessAnalytics.md (100%) rename 260507_pgbouncer_deployment.md => docs/reference/260507_pgbouncer_deployment.md (100%) rename tracksolidApiDocumentation.md => docs/reference/tracksolidApiDocumentation.md (100%) rename **260410_baseline_report.md => docs/reports/260410_baseline_report.md (100%) rename 260412_baseline_report.md => docs/reports/260412_baseline_report.md (100%) rename 260427_audit_output.txt => docs/reports/260427_audit_output.txt (100%) rename 260427_device_reconciliation.md => docs/reports/260427_device_reconciliation.md (100%) create mode 100644 docs/reports/260601_improvement_claude_48.html rename new_feature.txt => docs/reports/new_feature.txt (100%) delete mode 100644 documents.txt rename tracksolid_analytics_pipeline.txt => legacy/tracksolid_analytics_pipeline.txt (100%) rename tracksolid_extract.py => legacy/tracksolid_extract.py (100%) rename tracksolid_ingestion_pipeline.txt => legacy/tracksolid_ingestion_pipeline.txt (100%) rename tracksolid_update_v2.py => legacy/tracksolid_update_v2.py (100%) rename tracksolid_vehicle_update.py => legacy/tracksolid_vehicle_update.py (100%) rename 02_tracksolid_full_schema_rev.sql => migrations/02_tracksolid_full_schema_rev.sql (100%) rename 03_webhook_schema_migration.sql => migrations/03_webhook_schema_migration.sql (100%) rename 04_bug_fix_migration.sql => migrations/04_bug_fix_migration.sql (100%) rename 05_enhancement_migration.sql => migrations/05_enhancement_migration.sql (100%) rename 06_business_analytics_migration.sql => migrations/06_business_analytics_migration.sql (100%) rename 07_analytics_views.sql => migrations/07_analytics_views.sql (100%) rename 08_analytics_config.sql => migrations/08_analytics_config.sql (100%) rename 09_trips_enrichment.sql => migrations/09_trips_enrichment.sql (100%) rename 10_driver_clock_views.sql => migrations/10_driver_clock_views.sql (100%) rename 10_pgbouncer_auth.sql => migrations/10_pgbouncer_auth.sql (100%) delete mode 100644 push_webhook.md diff --git a/CLAUDE.md b/CLAUDE.md index 0a6de32..a31aa91 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,7 +19,7 @@ docker exec $DB psql -U postgres -d tracksolid_db -c "SELECT COUNT(*) FROM track **Run a migration file:** ```bash -docker exec -i $DB psql -U postgres -d tracksolid_db < 07_your_migration.sql +docker exec -i $DB psql -U postgres -d tracksolid_db < migrations/07_your_migration.sql ``` --- @@ -91,17 +91,19 @@ dwh/ # DWH migrations for tracksolid_dwh@31.97.44.246:588 # 261002_bronze_constraints_audit.sql — ON CONFLICT key assertion # 261003_dwh_roles.sql — role contract assertion # 261004_dwh_observability_views.sql — freshness/failure views -02_tracksolid_full_schema_rev.sql # Full schema bootstrap -03..06_*.sql # Incremental migrations (06 adds assigned_city, dispatch_log, ops.*) -07_analytics_views.sql # Analytics views migration (applied 2026-04-21) +migrations/ # Numbered SQL migrations 02–10, applied in order by run_migrations.py + # 02 full schema · 03 webhook · 04 distance fix · 05 enhancements + # 06 ops/analytics · 07 views · 08 config · 09 trips enrichment + # 10_driver_clock_views.sql · 10_pgbouncer_auth.sql Dockerfile # Custom image for ingest/webhook containers pyproject.toml # Python project + uv dependency spec -OPERATIONS_MANUAL.md # Day-to-day ops runbook backup/ # pg_dump sidecar scripts and config -01_BusinessAnalytics.md # SQL analytics library — read before writing queries -20260414_FS__Logistics - final_fixed.csv # 144-device driver/vehicle source data -tracksolidApiDocumentation.md # API endpoint reference -260412_baseline_report.md # Fleet state snapshot (Apr 2026) +data/ # Source CSVs (FS Logistics 144-device list, FSG vehicles) +legacy/ # Superseded pre-_rev scripts + old pipeline notes (NOT deployed) +docs/manuals/ # OPERATIONS_MANUAL, grafana + DWH manuals, docker commands, DB manual +docs/reference/ # 01_BusinessAnalytics.md (SQL library — read before writing queries), + # tracksolidApiDocumentation.md, 260507_pgbouncer_deployment.md +docs/reports/ # Baseline reports, audit output, improvement reviews ``` --- @@ -171,7 +173,7 @@ dwh_control.v_watermark_lag -- Grafana: extract vs. load lag per table ## 6. API Critical Facts -**Always read `tracksolidApiDocumentation.md` before adding a new endpoint call.** +**Always read `docs/reference/tracksolidApiDocumentation.md` before adding a new endpoint call.** | Fact | Detail | |---|---| @@ -209,7 +211,7 @@ dwh_control.v_watermark_lag -- Grafana: extract vs. load lag per table 1. **No prod push without explicit user confirmation.** Always state what you are about to push and wait. 2. **Never rewrite a migration that is already applied.** Check `tracksolid.schema_migrations` first. Add a new numbered migration file for any schema change. -3. **Read before writing.** Before suggesting any code change, read the relevant source file. Before writing a query, check `01_BusinessAnalytics.md` for an existing pattern. +3. **Read before writing.** Before suggesting any code change, read the relevant source file. Before writing a query, check `docs/reference/01_BusinessAnalytics.md` for an existing pattern. 4. **Reuse shared utilities.** All DB access via `get_conn()`, all API calls via `api_post()`, all cleaning via `clean()` / `clean_num()` / `clean_int()` / `clean_ts()` in `ts_shared_rev.py`. Do not reinvent these. 5. **Resolve container names dynamically.** Never hardcode the Coolify suffix. Use `docker ps --filter name=`. 6. **SSH only when asked.** Default workflow is local code → commit → push. SSH into the instance only when explicitly asked to test or run something live. @@ -235,7 +237,7 @@ dwh_control.v_watermark_lag -- Grafana: extract vs. load lag per table | Cities active | Nairobi (primary), Mombasa (deploying), Kampala (4 devices in CSV) | | Service flags | KDK 829A GP (239,264 km), Belta KCU-647D (235,000 km) | -Latest full snapshot: `260412_baseline_report.md` +Latest full snapshot: `docs/reports/260412_baseline_report.md` --- diff --git a/20260414_FS__Logistics - final_fixed.csv b/data/20260414_FS__Logistics - final_fixed.csv similarity index 100% rename from 20260414_FS__Logistics - final_fixed.csv rename to data/20260414_FS__Logistics - final_fixed.csv diff --git a/20260427_FSG_Vehicles_mitieng.csv b/data/20260427_FSG_Vehicles_mitieng.csv similarity index 100% rename from 20260427_FSG_Vehicles_mitieng.csv rename to data/20260427_FSG_Vehicles_mitieng.csv diff --git a/fireside_logistics_cleaned_v2.csv b/data/fireside_logistics_cleaned_v2.csv similarity index 100% rename from fireside_logistics_cleaned_v2.csv rename to data/fireside_logistics_cleaned_v2.csv diff --git a/docker-compose.yaml b/docker-compose.yaml index e8cb20b..67d10c5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -81,7 +81,7 @@ services: pgbouncer: # Connection pooler in front of timescale_db. - # Runbook: 260507_pgbouncer_deployment.md + # Runbook: docs/reference/260507_pgbouncer_deployment.md # Internal Docker network only — no host port. SCRAM passthrough via # auth_query against the public.user_lookup() function (migration 10). image: edoburu/pgbouncer diff --git a/DWH_Execution_Manual.md b/docs/manuals/DWH_Execution_Manual.md similarity index 100% rename from DWH_Execution_Manual.md rename to docs/manuals/DWH_Execution_Manual.md diff --git a/**OPERATIONS_MANUAL.md b/docs/manuals/OPERATIONS_MANUAL.md similarity index 100% rename from **OPERATIONS_MANUAL.md rename to docs/manuals/OPERATIONS_MANUAL.md diff --git a/connecting_python_tracksolid.md b/docs/manuals/connecting_python_tracksolid.md similarity index 100% rename from connecting_python_tracksolid.md rename to docs/manuals/connecting_python_tracksolid.md diff --git a/grafanaDeployment.md b/docs/manuals/grafanaDeployment.md similarity index 100% rename from grafanaDeployment.md rename to docs/manuals/grafanaDeployment.md diff --git a/grafanaOperationalManual.md b/docs/manuals/grafanaOperationalManual.md similarity index 100% rename from grafanaOperationalManual.md rename to docs/manuals/grafanaOperationalManual.md diff --git a/***tracksolid_DB_manual.md b/docs/manuals/tracksolid_DB_manual.md similarity index 100% rename from ***tracksolid_DB_manual.md rename to docs/manuals/tracksolid_DB_manual.md diff --git a/**02_tracksolid_docker_commands.md b/docs/manuals/tracksolid_docker_commands.md similarity index 100% rename from **02_tracksolid_docker_commands.md rename to docs/manuals/tracksolid_docker_commands.md diff --git a/**01_BusinessAnalytics.md b/docs/reference/01_BusinessAnalytics.md similarity index 100% rename from **01_BusinessAnalytics.md rename to docs/reference/01_BusinessAnalytics.md diff --git a/260507_pgbouncer_deployment.md b/docs/reference/260507_pgbouncer_deployment.md similarity index 100% rename from 260507_pgbouncer_deployment.md rename to docs/reference/260507_pgbouncer_deployment.md diff --git a/tracksolidApiDocumentation.md b/docs/reference/tracksolidApiDocumentation.md similarity index 100% rename from tracksolidApiDocumentation.md rename to docs/reference/tracksolidApiDocumentation.md diff --git a/**260410_baseline_report.md b/docs/reports/260410_baseline_report.md similarity index 100% rename from **260410_baseline_report.md rename to docs/reports/260410_baseline_report.md diff --git a/260412_baseline_report.md b/docs/reports/260412_baseline_report.md similarity index 100% rename from 260412_baseline_report.md rename to docs/reports/260412_baseline_report.md diff --git a/260427_audit_output.txt b/docs/reports/260427_audit_output.txt similarity index 100% rename from 260427_audit_output.txt rename to docs/reports/260427_audit_output.txt diff --git a/260427_device_reconciliation.md b/docs/reports/260427_device_reconciliation.md similarity index 100% rename from 260427_device_reconciliation.md rename to docs/reports/260427_device_reconciliation.md diff --git a/docs/reports/260601_improvement_claude_48.html b/docs/reports/260601_improvement_claude_48.html new file mode 100644 index 0000000..cfa42c2 --- /dev/null +++ b/docs/reports/260601_improvement_claude_48.html @@ -0,0 +1,374 @@ + + + + + +Tracksolid Stack — Engineering Review & Improvement Plan (2026-06-01) + + + +
+ +
+
Engineering Review · Fireside Communications · Tracksolid Fleet Stack
+

Database & Microservice Assessment — Opportunities & Refactoring

+

+ Date: 2026-06-01  ·  + Reviewer: Claude (Opus 4.8)  ·  + Scope: TimescaleDB/PostGIS schema + migrations, and the three ingestion microservices + (ingest_movement_rev.py, ingest_events_rev.py, webhook_receiver_rev.py + shared ts_shared_rev.py) +

+

Findings are ordered by greatest performance upside first, as requested.

+
+ +
+

Access caveat — read this first. The remote instance was unreachable from the review environment: + every probed port (22, 5433, 5432, 443) timed out, so the IP is not whitelisted (or the host was down). + I could not run EXPLAIN, read live row/chunk counts, confirm which indexes actually exist, + or inspect the running images. Everything below is a static review of the source and migration files. + Items needing live confirmation are tagged verify live.

+

Immediate security note: .env is committed to git (it is listed in + .gitignore, but was tracked before that rule existed, so the rule is a no-op). The live Tracksolid app + secret, the Postgres superuser password, and the Grafana admin password are all in the repo history on Forgejo. + Treat all three as compromised and rotate them.

+
+ + + + +

1Single-threaded scheduler holds a DB transaction open across throttled geocodingHighest upside

+
+

ingest_movement_rev.py runs every job on one schedule thread + (main(), lines 674–695). Within that, poll_trips() opens a transaction + (with get_conn(), line 343) and then, inside that open transaction, calls + reverse_geocode() twice per trip (lines 392–393). + reverse_geocode enforces a global 1 request/second Nominatim throttle + (ts_shared_rev.py:463, _geocode_throttle).

+ +

Consequences

+
    +
  • A batch of N new trips can hold a single pooled connection open for N×~2 seconds of network I/O — a + long-running transaction that pins a snapshot (bad for autovacuum's cleanup horizon) and ties up a connection.
  • +
  • Because the scheduler is one thread, while poll_trips is geocoding, the 60-second live-position + sweep cannot run. The "live" freshness SLA silently degrades to minutes whenever trips/parking work through a + backlog. poll_track_list (30 min) and poll_stale_locations (10 min) share the same + thread and also block each other.
  • +
  • Every 15 min, poll_trips re-runs the 8-subquery enrichment block (_ENRICH_QUERY, + lines 295–321) for the entire last hour of trips, even though the + ON CONFLICT mostly COALESCEs the result away.
  • +
+ +

Recommendation

+
    +
  • Move geocoding out of the DB transaction: collect trip rows, commit, then geocode + UPDATE + in a second pass (or delegate geocoding to a queue / n8n).
  • +
  • Gate enrichment on WHERE start_address IS NULL so already-enriched trips don't re-pay the cost.
  • +
  • Run the 60s live sweep on its own thread/process so slow reporting jobs cannot starve it. + schedule + time.sleep(1) on one thread is the wrong concurrency model when one job is + latency-critical and others do long network I/O.
  • +
+
+ + +

2The dwh_gold daily-metrics ETL is non-functionalHigh

+
+

dwh_gold.refresh_daily_metrics() (migration 05, lines 212–264) selects + t.imei AS vehicle_key and inserts into fact_daily_fleet_metrics.vehicle_key, which is + INTEGER REFERENCES dwh_gold.dim_vehicles(vehicle_key) (schema lines 237–243). + But imei is a 12–15-digit TEXT string:

+
    +
  • 15-digit IMEIs overflow int4"integer out of range".
  • +
  • Shorter ones violate the FK because nothing ever populates dim_vehicles — no code path + inserts into it.
  • +
+

So the function cannot succeed as written, and v_utilisation_daily (which joins + fact → dim_vehicles → devices, migration 07, lines 268–286) will always be + empty. CLAUDE.md lists "schedule the nightly ETL" as a LOW open item — but scheduling it today would error on every + run.

+

Recommendation: redesign the gold layer around imei (drop the surrogate + key, or populate dim_vehicles from devices first and look up the key), and fix the column + type. This is a real bug hiding behind "not scheduled yet."

+
+ + +

3v_driver_aggregates_daily will not scale, and the safeguard wasn't appliedHigh

+
+

Migration 07 (lines 159–223) builds this view with two 31-day scans of + position_history plus a LAG() window over source='track_list' rows. There is + no index on position_history.source, and the only index on the hypertable is the + (imei, gps_time) primary key.

+

The view's own header comment says "convert to a continuous aggregate once the hypertable exceeds ~100k rows." + At 156 devices writing a row/minute from the poll sweep plus track_list waypoints, you cross 100k in days, not + months. verify live current row + chunk count.

+

Recommendation: build the speeding/harsh aggregates as a TimescaleDB continuous + aggregate (the pattern already exists in v_mileage_daily_cagg), or at minimum add a partial index + supporting the source='track_list' + time filter. As-is, the daily driver dashboard does a growing full + hypertable scan on every load.

+
+ + +

4pgbouncer is deployed but the application bypasses it entirelyMedium

+
+

docker-compose.yaml adds a pgbouncer sidecar (lines 82–116) "to cap + tracksolid_db connections," but .env sets + DATABASE_URL=...@timescale_db:5432/... — the Python pools connect straight to Postgres, not to + pgbouncer's 6432.

+

So the connection cap does nothing for the three services. The real ceiling today is the sum of per-process pools:

+
webhook   : uvicorn --workers 2  →  2 procs × ThreadedConnectionPool(max=12) = 24
+ingest_movement                                                          = 12
+ingest_events                                                            = 12
+                                                              total ≈ 48 direct conns
+

At 80–156 devices this is not a live performance problem — it is wasted/contradictory infrastructure and an + intent-vs-reality gap. You also maintain a SCRAM-passthrough user_lookup() SECURITY DEFINER function + (migration 10) with no consumer.

+

Recommendation: either point DATABASE_URL at pgbouncer:6432 + (transaction-pool mode disallows session features, but the code uses none beyond client_encoding), or + remove the sidecar.

+
+ + +

5Migrations race across three containers with no lockMedium · reliability

+
+

All three services run python run_migrations.py on startup (compose lines 26, 37, + 48) and start in parallel once the DB is healthy. run_migrations.py does check-then-act + (already_applied()run_file(), lines 231–242) with no + advisory lock. On a fresh database, three containers can pass already_applied()==False + simultaneously and run the same file.

+
    +
  • Migration 02's CREATE TRIGGER loop (lines 255–267) has no + IF NOT EXISTS — concurrent runs throw, and run_file() treats any ERROR: as + fatal → sys.exit(1) → a service refuses to start.
  • +
  • run_file() greps stderr for ERROR: without -v ON_ERROR_STOP=1, and files + 02/03 have no BEGIN/COMMIT, so a mid-file failure can leave partial schema that later gets mis-seeded + as "applied."
  • +
+

Recommendation: wrap the run in pg_advisory_lock(<const>) / + unlock, and run psql with ON_ERROR_STOP=1. Low effort, removes a class of cold-start flakiness.

+
+ + +

6Orphaned migration: 10_driver_clock_views.sql is never appliedMedium

+
+

The runner's MIGRATIONS list (run_migrations.py:27–37) includes + 10_pgbouncer_auth.sql but not 10_driver_clock_views.sql. Two files share the + 10_ prefix and the list is hand-maintained, so v_driver_clock_daily/_today (which the n8n + tardiness workflow depends on, per the file header) exist only if someone applied them by hand — they are not + reproducible from a clean deploy.

+

Recommendation: rename to 11_ and add to the list. Better: switch the + runner from a hardcoded list to globbing NN_*.sql sorted, so this cannot recur.

+
+ + +

7Security gaps worth fixing nowSecurity

+
+
    +
  • Webhook auth is effectively off. _validate_token + (webhook_receiver_rev.py:84–87) skips validation entirely when + JIMI_WEBHOOK_TOKEN is empty, and it is not set in .env. The push endpoints are + exposed via Traefik, so anyone who learns the URL can inject arbitrary telemetry/alarms (each /pushgps + accepts up to 5000 rows, no rate limit). Set the token and make an unset token fail closed in production.
  • +
  • Committed secrets (see top banner). Rotate the Tracksolid app secret, Postgres password, and Grafana admin + password; git rm --cached .env and scrub history.
  • +
  • dwh/260423_dwh_ddl_v1.sql plaintext passwords are an existing known item in CLAUDE.md — same class of + problem.
  • +
+
+ + +

8Smaller DB-design notesLow — queue these

+
+
    +
  • v_mileage_daily_cagg is built on a column that's mostly NULL. It computes + MAX(current_mileage) - MIN(current_mileage) (schema lines 293–301), but + current_mileage is only populated by the poll sweep — track_list and /pushgps + inserts leave it NULL, and odometer resets/device swaps produce negative or huge deltas. The aggregate's + dist_km is unreliable. Prefer deriving daily distance from trips.distance_km.
  • +
  • ingestion_log has no retention and no index. v_ingestion_health does + DISTINCT ON (endpoint) … ORDER BY endpoint, run_at DESC over the whole table, which grows ~875 + rows/day forever. Add (endpoint, run_at DESC) plus a retention/partition policy.
  • +
  • Alarm dedup is leaky on the poll path. alarms_dedup UNIQUE (imei, alarm_type, alarm_time) + (schema line 199) — the poll path inserts alertTypeId as + alarm_type with no NOT-NULL guard, and NULL defeats the unique constraint + (NULL ≠ NULL), so a null-type alarm can duplicate. The webhook path guards this; the poll path + doesn't.
  • +
  • live_positions/staleness queries are seq scans (no index on gps_time) — totally + fine at ~156 rows today; just don't carry that pattern into anything that scans position_history.
  • +
  • Dead/ambiguous code in _parse_request (webhook lines 90–143): the + JSON-array branch _parse_data_list is never reached (it always falls through to + request.form()); harmless but misleading given the docstring claims it handles both.
  • +
+
+ + +
+

What's genuinely good

+

So this is balanced — the bones are solid:

+
    +
  • Per-row SAVEPOINT isolation so one bad item can't abort a batch.
  • +
  • Time-guarded upserts via the shared upsert_live_position helper.
  • +
  • Batched execute_values on the high-volume push / track-list paths.
  • +
  • Hypertables with compression + retention policies.
  • +
  • Parameterized SQL throughout — no injection surface.
  • +
  • Clean signal handling and pool teardown.
  • +
  • Idempotent migrations with a tracking table and COMMENT ON VIEW provenance.
  • +
  • sync_devices N+1 already parallelized with a bounded thread pool.
  • +
+

The issues above are mostly about coupling, one broken ETL, and + scale-ahead-of-indexing — not a bad foundation.

+
+ + +

»Suggested order of attack (effort vs. upside)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#ActionUpsideEffort
1Pull geocoding out of the trips transaction + gate on start_address IS NULL; isolate the 60s sweep on its own threadHigh — restores live freshness, frees connectionsM
2Fix or redesign refresh_daily_metrics / dim_vehicles (imei vs int key)High — unblocks all utilisation reportingM
3Convert v_driver_aggregates_daily to a continuous aggregate (or add source+time index)High and growingM
4Set JIMI_WEBHOOK_TOKEN; rotate + untrack .envHigh (security)S
5Advisory-lock the migration runner + ON_ERROR_STOP=1; add 10_driver_clock_views / switch to globMedium (reliability)S
6Decide pgbouncer in-or-out; point DATABASE_URL accordinglyMedium (clarity)S
7ingestion_log index + retention; fix poll-path alarm null dedup; fix cagg distance sourceLow–mediumS
+ +
+

Next step for live confirmation: if I can get onto the box (whitelist the review IP for + 5433, or an SSH tunnel), I'll confirm the verify live items — actual + position_history row/chunk counts, which indexes really exist, whether refresh_daily_metrics + has ever succeeded, and EXPLAIN ANALYZE on the heavier views — and tighten the priority order with real + numbers.

+
+ +
+ Generated 2026-06-01 by Claude (Opus 4.8) for Fireside Communications · Tracksolid Fleet Intelligence. + Static review only — no live database access was available at review time. File references use + file:line against the repository state on branch + quality-program-2026-04-12. +
+ + + + diff --git a/new_feature.txt b/docs/reports/new_feature.txt similarity index 100% rename from new_feature.txt rename to docs/reports/new_feature.txt diff --git a/documents.txt b/documents.txt deleted file mode 100644 index e69de29..0000000 diff --git a/import_drivers_csv.py b/import_drivers_csv.py index 0c29664..5828329 100644 --- a/import_drivers_csv.py +++ b/import_drivers_csv.py @@ -49,7 +49,7 @@ from ts_shared_rev import clean, clean_num, clean_ts, get_conn, get_logger log = get_logger("csv_import") -DEFAULT_CSV_PATH = Path(__file__).parent / "20260427_FSG_Vehicles_mitieng.csv" +DEFAULT_CSV_PATH = Path(__file__).parent / "data" / "20260427_FSG_Vehicles_mitieng.csv" # Columns fetched from DB for diff comparison. DB_COLS = [ diff --git a/tracksolid_analytics_pipeline.txt b/legacy/tracksolid_analytics_pipeline.txt similarity index 100% rename from tracksolid_analytics_pipeline.txt rename to legacy/tracksolid_analytics_pipeline.txt diff --git a/tracksolid_extract.py b/legacy/tracksolid_extract.py similarity index 100% rename from tracksolid_extract.py rename to legacy/tracksolid_extract.py diff --git a/tracksolid_ingestion_pipeline.txt b/legacy/tracksolid_ingestion_pipeline.txt similarity index 100% rename from tracksolid_ingestion_pipeline.txt rename to legacy/tracksolid_ingestion_pipeline.txt diff --git a/tracksolid_update_v2.py b/legacy/tracksolid_update_v2.py similarity index 100% rename from tracksolid_update_v2.py rename to legacy/tracksolid_update_v2.py diff --git a/tracksolid_vehicle_update.py b/legacy/tracksolid_vehicle_update.py similarity index 100% rename from tracksolid_vehicle_update.py rename to legacy/tracksolid_vehicle_update.py diff --git a/02_tracksolid_full_schema_rev.sql b/migrations/02_tracksolid_full_schema_rev.sql similarity index 100% rename from 02_tracksolid_full_schema_rev.sql rename to migrations/02_tracksolid_full_schema_rev.sql diff --git a/03_webhook_schema_migration.sql b/migrations/03_webhook_schema_migration.sql similarity index 100% rename from 03_webhook_schema_migration.sql rename to migrations/03_webhook_schema_migration.sql diff --git a/04_bug_fix_migration.sql b/migrations/04_bug_fix_migration.sql similarity index 100% rename from 04_bug_fix_migration.sql rename to migrations/04_bug_fix_migration.sql diff --git a/05_enhancement_migration.sql b/migrations/05_enhancement_migration.sql similarity index 100% rename from 05_enhancement_migration.sql rename to migrations/05_enhancement_migration.sql diff --git a/06_business_analytics_migration.sql b/migrations/06_business_analytics_migration.sql similarity index 100% rename from 06_business_analytics_migration.sql rename to migrations/06_business_analytics_migration.sql diff --git a/07_analytics_views.sql b/migrations/07_analytics_views.sql similarity index 100% rename from 07_analytics_views.sql rename to migrations/07_analytics_views.sql diff --git a/08_analytics_config.sql b/migrations/08_analytics_config.sql similarity index 100% rename from 08_analytics_config.sql rename to migrations/08_analytics_config.sql diff --git a/09_trips_enrichment.sql b/migrations/09_trips_enrichment.sql similarity index 100% rename from 09_trips_enrichment.sql rename to migrations/09_trips_enrichment.sql diff --git a/10_driver_clock_views.sql b/migrations/10_driver_clock_views.sql similarity index 100% rename from 10_driver_clock_views.sql rename to migrations/10_driver_clock_views.sql diff --git a/10_pgbouncer_auth.sql b/migrations/10_pgbouncer_auth.sql similarity index 100% rename from 10_pgbouncer_auth.sql rename to migrations/10_pgbouncer_auth.sql diff --git a/push_webhook.md b/push_webhook.md deleted file mode 100644 index e69de29..0000000 diff --git a/run_migrations.py b/run_migrations.py index 0618a55..2192f66 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -221,7 +221,7 @@ def main(): applied = skipped = 0 for sql_file in MIGRATIONS: - path = os.path.join("/app", sql_file) + path = os.path.join("/app", "migrations", sql_file) if not os.path.exists(path): print(f" SKIP {sql_file} (file not found in /app)") diff --git a/run_migrations.sh b/run_migrations.sh index 103b74c..6a34bc2 100755 --- a/run_migrations.sh +++ b/run_migrations.sh @@ -55,10 +55,10 @@ run_sql -c " " > /dev/null # ── Find and apply pending migrations ──────────────────────────────────────── -MIGRATION_FILES=$(find "$SCRIPT_DIR" -maxdepth 1 -name '[0-9][0-9]_*.sql' | sort) +MIGRATION_FILES=$(find "$SCRIPT_DIR/migrations" -maxdepth 1 -name '[0-9][0-9]_*.sql' | sort) if [[ -z "$MIGRATION_FILES" ]]; then - echo "No migration files found in $SCRIPT_DIR" + echo "No migration files found in $SCRIPT_DIR/migrations" exit 0 fi From 5703d70aa6fa4ab57f183fe87144b4725f3e034f Mon Sep 17 00:00:00 2001 From: david kiania Date: Mon, 1 Jun 2026 04:23:37 +0300 Subject: [PATCH 16/31] feat(api): dedicated FastAPI read-API for map dashboards (replaces n8n) n8n was a thin HTTP->SQL proxy for the Live Position and Fleet Trips maps and proved fragile (credential reloads, :latest drift, shared connection limits). This service calls the same proven reporting.* functions directly, reusing the existing psycopg2 pool / Docker image / Coolify deploy. Endpoints mirror the n8n webhook paths so the only frontend change is N8N_BASE: GET /webhook/live-positions -> {summary, geojson} (fn_live_positions) GET /webhook/vehicle-track -> GeoJSON Feature (fn_vehicle_track) GET /webhook/fleet-dashboard -> filter options POST /webhook/fleet-dashboard -> trips payload (fn_trips_for_map) Response shapes replicate the n8n "Build response JSON" nodes exactly; empty filters/sentinels ('', null, undefined) normalize to SQL wildcards. CORS limited to the dashboard origins. Added dashboard_api service to docker-compose (port 8890, Coolify-routed). SQL contracts validated against prod. Co-Authored-By: Claude Opus 4.8 --- dashboard_api_rev.py | 238 +++++++++++++++++++++++++++++++++++++++++++ docker-compose.yaml | 25 +++++ 2 files changed, 263 insertions(+) create mode 100644 dashboard_api_rev.py diff --git a/dashboard_api_rev.py b/dashboard_api_rev.py new file mode 100644 index 0000000..d4dfc4c --- /dev/null +++ b/dashboard_api_rev.py @@ -0,0 +1,238 @@ +""" +dashboard_api_rev.py — Fireside Communications · Map Dashboard Read API +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Stable replacement for the n8n webhooks that fed the Live Position and Fleet +Trips map dashboards. n8n was acting only as a thin HTTP→SQL proxy; this +service does the same job directly against the proven reporting.* functions, +removing n8n's credential-management / reload / version-drift fragility from +the live-data path. + +It REUSES the existing stack: ts_shared_rev's psycopg2 pool and DATABASE_URL, +the same Docker image, the same Coolify deploy. The reporting.* functions +(already verified to return correct GeoJSON) are the single source of truth. + +Endpoints mirror the original n8n webhook paths so the only frontend change +is the base URL (the `N8N_BASE` constant in each dashboard SPA): + + GET /webhook/live-positions?cost_centre=&acc_status= + → { summary, geojson } (reporting.fn_live_positions) + GET /webhook/vehicle-track?vehicle_number=&hours= + → GeoJSON Feature (reporting.fn_vehicle_track) + GET /webhook/fleet-dashboard + → { drivers, cost_centres, cities, vehicles } (filter options) + POST /webhook/fleet-dashboard body: {period, vehicle_numbers, driver, + cost_centre, assigned_city, + start_date, end_date} + → trips payload (reporting.fn_trips_for_map) + GET /health +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +""" + +from __future__ import annotations + +import os +from contextlib import asynccontextmanager +from datetime import date, datetime, timedelta, timezone + +import psycopg2.extras +from fastapi import FastAPI, Request +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse + +from ts_shared_rev import close_pool, get_conn, get_logger + +log = get_logger("dashboard_api") + +# Comma-separated list of allowed browser origins (the dashboard domains). +_ALLOWED_ORIGINS = [ + o.strip() + for o in os.getenv( + "DASHBOARD_CORS_ORIGINS", + "https://liveposition.rahamafresh.com,https://fleetintelligence.rahamafresh.com", + ).split(",") + if o.strip() +] + + +@asynccontextmanager +async def lifespan(app: FastAPI): + log.info("Dashboard API starting (v1.0). Origins=%s", _ALLOWED_ORIGINS) + yield + close_pool() + + +app = FastAPI(title="Fireside Map Dashboard API", lifespan=lifespan) +app.add_middleware( + CORSMiddleware, + allow_origins=_ALLOWED_ORIGINS, + allow_methods=["GET", "POST", "OPTIONS"], + allow_headers=["*"], +) + +_EMPTY_GEOJSON = {"type": "FeatureCollection", "features": []} + + +def _clean(v): + """Treat missing / blank / sentinel values as None (= SQL wildcard).""" + if v is None: + return None + s = str(v).strip() + return s if s and s.lower() not in ("null", "undefined") else None + + +# ── Health ──────────────────────────────────────────────────────────────────── + +@app.get("/health") +def health(): + return {"status": "ok"} + + +# ── Live positions (#004) ─────────────────────────────────────────────────── + +@app.get("/webhook/live-positions") +def live_positions(cost_centre: str | None = None, acc_status: str | None = None): + try: + with get_conn() as conn: + with conn.cursor() as cur: + cur.execute( + "SELECT reporting.fn_live_positions(%s, %s)", + (_clean(cost_centre), _clean(acc_status)), + ) + payload = cur.fetchone()[0] or {} + return JSONResponse( + { + "summary": payload.get("summary") or {}, + "geojson": payload.get("geojson") or _EMPTY_GEOJSON, + } + ) + except Exception: + log.exception("live-positions failed") + return JSONResponse( + { + "error": { + "type": "unknown", + "message": "Live-position feed is unavailable. Try again in a few seconds.", + } + } + ) + + +@app.get("/webhook/vehicle-track") +def vehicle_track(vehicle_number: str | None = None, hours: int = 1): + veh = _clean(vehicle_number) + if not veh: + return JSONResponse({"error": "vehicle_number is required"}) + hours = max(1, min(24, hours or 1)) + try: + with get_conn() as conn: + with conn.cursor() as cur: + cur.execute( + "SELECT reporting.fn_vehicle_track(%s, %s::int)", (veh, hours) + ) + feature = cur.fetchone()[0] + return JSONResponse( + feature + or {"type": "Feature", "geometry": {"type": "LineString", "coordinates": []}, "properties": {}} + ) + except Exception: + log.exception("vehicle-track failed for %s", veh) + return JSONResponse({"error": "vehicle-track unavailable"}) + + +# ── Fleet trips (#002) ─────────────────────────────────────────────────────── + +_FILTER_OPTIONS_SQL = """ +SELECT + (SELECT array_agg(driver ORDER BY driver) FROM reporting.v_filter_drivers) AS drivers, + (SELECT array_agg(cost_centre ORDER BY cost_centre) FROM reporting.v_filter_cost_centres) AS cost_centres, + (SELECT array_agg(assigned_city ORDER BY assigned_city) FROM reporting.v_filter_cities) AS cities, + (SELECT jsonb_agg(jsonb_build_object( + 'vehicle_number', vehicle_number, 'drivers', drivers, + 'cost_centre', cost_centre, 'assigned_city', assigned_city) + ORDER BY vehicle_number) FROM reporting.v_filter_vehicles) AS vehicles +""" + + +@app.get("/webhook/fleet-dashboard") +def fleet_filter_options(): + try: + with get_conn() as conn: + with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: + cur.execute(_FILTER_OPTIONS_SQL) + row = cur.fetchone() or {} + return JSONResponse( + { + "drivers": row.get("drivers") or [], + "cost_centres": row.get("cost_centres") or [], + "cities": row.get("cities") or [], + "vehicles": row.get("vehicles") or [], + } + ) + except Exception: + log.exception("fleet-dashboard filter options failed") + return JSONResponse({"drivers": [], "cost_centres": [], "cities": [], "vehicles": []}) + + +def _preset_to_range(period: str | None, start_date, end_date): + """Mirror of the n8n preset_to_range node.""" + today = datetime.now(timezone.utc).date() + p = (period or "").strip() + if p == "today": + return today, today + if p == "30d": + return today - timedelta(days=29), today + if p == "custom": + def _d(v, default): + v = _clean(v) + if not v: + return default + try: + return date.fromisoformat(v) + except ValueError: + return default + return _d(start_date, today), _d(end_date, today) + # default + '7d' + return today - timedelta(days=6), today + + +@app.post("/webhook/fleet-dashboard") +async def fleet_trips(request: Request): + try: + body = await request.json() + except Exception: + body = {} + if not isinstance(body, dict): + body = {} + body = body.get("body", body) if isinstance(body.get("body"), dict) else body + + start, end = _preset_to_range( + body.get("period"), body.get("start_date"), body.get("end_date") + ) + veh = _clean(body.get("vehicle_numbers")) # comma-separated string or None + try: + with get_conn() as conn: + with conn.cursor() as cur: + cur.execute( + """ + SELECT reporting.fn_trips_for_map( + CASE WHEN %(veh)s IS NULL THEN NULL + ELSE string_to_array(%(veh)s, ',') END, + %(driver)s, %(cc)s, %(city)s, %(start)s::date, %(end)s::date + ) + """, + { + "veh": veh, + "driver": _clean(body.get("driver")), + "cc": _clean(body.get("cost_centre")), + "city": _clean(body.get("assigned_city")), + "start": start, + "end": end, + }, + ) + payload = cur.fetchone()[0] + return JSONResponse(payload if payload is not None else {}) + except Exception: + log.exception("fleet-dashboard trips failed") + return JSONResponse( + {"error": {"type": "unknown", "message": "Fleet feed is unavailable. Try again in a few seconds."}} + ) diff --git a/docker-compose.yaml b/docker-compose.yaml index 67d10c5..5d80f6b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -59,6 +59,31 @@ services: timeout: 5s retries: 3 + dashboard_api: + # Stable read-API for the Live Position + Fleet Trips map dashboards. + # Replaces the n8n webhooks (n8n was only a thin HTTP->SQL proxy). + # Calls reporting.fn_live_positions / fn_vehicle_track / fn_trips_for_map. + build: + context: . + dockerfile: Dockerfile + command: sh -c "uvicorn dashboard_api_rev:app --host 0.0.0.0 --port 8890 --workers 2" + restart: always + depends_on: + timescale_db: + condition: service_healthy + env_file: .env + environment: + # Browser origins allowed to call this API (the dashboard domains). + - DASHBOARD_CORS_ORIGINS=${DASHBOARD_CORS_ORIGINS:-https://liveposition.rahamafresh.com,https://fleetintelligence.rahamafresh.com} + # No host port binding — set a domain (e.g. fleetapi.rahamafresh.com) in the + # Coolify UI pointing to this service on port 8890. The dashboards then point + # their N8N_BASE at that domain; paths (/webhook/...) are unchanged. + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8890/health"] + interval: 30s + timeout: 5s + retries: 3 + grafana: build: context: ./grafana From 831f683b8334f810f6a17a8e9763f1393b9506d2 Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 00:54:58 +0300 Subject: [PATCH 17/31] fix(api): expose /webhook/live-positions/track so map trail matches SPA path The Live Positions SPA calls GET /webhook/live-positions/track, but the read-API only exposed /webhook/vehicle-track. Clicking a vehicle to view its 1-hour trail therefore 404'd even after repointing N8N_BASE. Register the SPA's actual path as a route alias to the same handler (vehicle-track kept as alias), so the only frontend change remains the base URL. Docstring updated to match. Co-Authored-By: Claude Opus 4.8 --- dashboard_api_rev.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dashboard_api_rev.py b/dashboard_api_rev.py index d4dfc4c..6537e83 100644 --- a/dashboard_api_rev.py +++ b/dashboard_api_rev.py @@ -16,7 +16,8 @@ is the base URL (the `N8N_BASE` constant in each dashboard SPA): GET /webhook/live-positions?cost_centre=&acc_status= → { summary, geojson } (reporting.fn_live_positions) - GET /webhook/vehicle-track?vehicle_number=&hours= + GET /webhook/live-positions/track?vehicle_number=&hours= + (alias: /webhook/vehicle-track) → GeoJSON Feature (reporting.fn_vehicle_track) GET /webhook/fleet-dashboard → { drivers, cost_centres, cities, vehicles } (filter options) @@ -117,6 +118,10 @@ def live_positions(cost_centre: str | None = None, acc_status: str | None = None ) +# `/webhook/live-positions/track` is the path the Live Positions SPA actually +# calls; `/webhook/vehicle-track` is kept as an alias. Both hit the same handler +# so the only frontend change is the base URL (N8N_BASE). +@app.get("/webhook/live-positions/track") @app.get("/webhook/vehicle-track") def vehicle_track(vehicle_number: str | None = None, hours: int = 1): veh = _clean(vehicle_number) From 00e81a063b2fa597364ea7e4ad8f6d0c8bb1e22a Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 12:32:44 +0300 Subject: [PATCH 18/31] feat(db): capture reporting.* map-dashboard schema as migration 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reporting schema (fn_live_positions/fn_vehicle_track/fn_trips_for_map, the v_trips materialized view + indexes, filter/summary views, refresh_log) backs the dashboard_api map endpoints but existed only on the prod DB, in no migration — a rebuild would have lost it. Captured the live DDL into migrations/11_reporting_schema.sql (idempotent: IF NOT EXISTS / CREATE OR REPLACE, search_path set for unqualified base-table refs, guarded grants) and registered it in run_migrations.py. Verified it applies cleanly against prod inside a rolled-back transaction. Co-Authored-By: Claude Opus 4.8 --- migrations/11_reporting_schema.sql | 554 +++++++++++++++++++++++++++++ run_migrations.py | 1 + 2 files changed, 555 insertions(+) create mode 100644 migrations/11_reporting_schema.sql diff --git a/migrations/11_reporting_schema.sql b/migrations/11_reporting_schema.sql new file mode 100644 index 0000000..911b45f --- /dev/null +++ b/migrations/11_reporting_schema.sql @@ -0,0 +1,554 @@ +-- 11_reporting_schema.sql +-- Map-dashboard read layer consumed by dashboard_api_rev.py: +-- reporting.fn_live_positions / fn_vehicle_track / fn_trips_for_map +-- + the v_trips materialized view, filter/summary views, and refresh_log. +-- Captured from prod 2026-06-05 to close the reproducibility gap (these objects +-- lived only on the live DB, in no migration). Every object uses IF NOT EXISTS / +-- CREATE OR REPLACE so the file is safe to re-apply. +-- +-- NOTE: the v_trips materialized view is created WITH DATA (populated once). On +-- prod it is owned by role `reporting_refresher` and kept current by an external +-- REFRESH job; that role + refresh schedule are infrastructure, NOT created here. +-- On a fresh rebuild v_trips is populated at creation but will go stale until a +-- refresh job is wired (see docs). The dashboard map functions still work, just +-- against the snapshot until then. + +CREATE SCHEMA IF NOT EXISTS reporting; + +-- Bodies reference base tables unqualified (devices, trips, …) + PostGIS; +-- resolve via search_path so this applies cleanly on a fresh DB. +SET search_path = tracksolid, reporting, public; + +-- ── helper ─────────────────────────────────────────────────────────────────── +CREATE OR REPLACE FUNCTION reporting.normalize_plate(p text) + RETURNS text + LANGUAGE sql + IMMUTABLE PARALLEL SAFE +AS $function$ + SELECT regexp_replace( + regexp_replace(trim(p), '\s+', ' ', 'g'), + '(\d) ([A-Z])$', '\1\2' + ) +$function$; + +-- ── refresh audit table ────────────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS reporting.refresh_log ( + refreshed_at timestamptz DEFAULT now() NOT NULL, + source text DEFAULT 'n8n'::text NOT NULL, + duration_ms integer, + row_count integer, + notes text +); + +-- ── v_trips materialized view (+ indexes) ──────────────────────────────────── +CREATE MATERIALIZED VIEW IF NOT EXISTS reporting.v_trips AS + WITH device_trip_counts AS ( + SELECT trips.imei, + count(*) AS trip_count + FROM trips + GROUP BY trips.imei + ), primary_device AS ( + SELECT DISTINCT ON ((reporting.normalize_plate(d_1.vehicle_number))) reporting.normalize_plate(d_1.vehicle_number) AS vehicle_number_norm, + d_1.imei AS primary_imei + FROM devices d_1 + LEFT JOIN device_trip_counts c USING (imei) + WHERE d_1.vehicle_number IS NOT NULL AND d_1.enabled_flag = 1 + ORDER BY (reporting.normalize_plate(d_1.vehicle_number)), (COALESCE(c.trip_count, 0::bigint)) DESC, d_1.activation_time, d_1.imei + ) + SELECT t.id AS trip_id, + t.imei, + d.device_name, + reporting.normalize_plate(d.vehicle_number) AS vehicle_number, + d.vehicle_models, + d.vehicle_category, + d.cost_centre, + d.assigned_city, + d.driver_name AS assigned_driver, + (t.start_time AT TIME ZONE 'Africa/Nairobi'::text) AS start_time, + (t.end_time AT TIME ZONE 'Africa/Nairobi'::text) AS end_time, + (t.start_time AT TIME ZONE 'Africa/Nairobi'::text)::date AS trip_date, + EXTRACT(hour FROM (t.start_time AT TIME ZONE 'Africa/Nairobi'::text))::integer AS start_hour, + EXTRACT(dow FROM (t.start_time AT TIME ZONE 'Africa/Nairobi'::text))::integer AS start_dow, + row_number() OVER (PARTITION BY t.imei, ((t.start_time AT TIME ZONE 'Africa/Nairobi'::text)::date) ORDER BY t.start_time) AS daily_seq, + t.distance_km, + t.avg_speed_kmh, + t.max_speed_kmh, + t.idle_time_s, + t.driving_time_s, + t.fuel_consumed_l, + t.waypoints_count, + t.start_address, + t.end_address, + t.start_geom, + t.end_geom, + t.route_geom, + st_asgeojson(st_simplifypreservetopology(t.route_geom, 0.00005::double precision))::json AS route_geojson, + st_numpoints(t.route_geom) >= 2 AND st_length(t.route_geom::geography) > 50::double precision AS is_meaningful_route, + (t.updated_at AT TIME ZONE 'Africa/Nairobi'::text) AS updated_at + FROM trips t + LEFT JOIN devices d USING (imei) + LEFT JOIN primary_device pd ON pd.vehicle_number_norm = reporting.normalize_plate(d.vehicle_number) + WHERE d.vehicle_number IS NULL OR pd.primary_imei IS NULL OR t.imei = pd.primary_imei +WITH DATA; + +CREATE INDEX IF NOT EXISTS ix_v_trips_city_trip_date ON reporting.v_trips USING btree (assigned_city, trip_date); +CREATE INDEX IF NOT EXISTS ix_v_trips_cost_centre_trip_date ON reporting.v_trips USING btree (cost_centre, trip_date); +CREATE INDEX IF NOT EXISTS ix_v_trips_driver_trip_date ON reporting.v_trips USING btree (assigned_driver, trip_date); +CREATE INDEX IF NOT EXISTS ix_v_trips_imei_trip_date ON reporting.v_trips USING btree (imei, trip_date); +CREATE INDEX IF NOT EXISTS ix_v_trips_meaningful_date ON reporting.v_trips USING btree (trip_date) WHERE is_meaningful_route; +CREATE INDEX IF NOT EXISTS ix_v_trips_trip_date ON reporting.v_trips USING btree (trip_date); +CREATE UNIQUE INDEX IF NOT EXISTS ix_v_trips_trip_id ON reporting.v_trips USING btree (trip_id); + +-- ── views (dependency-ordered) ─────────────────────────────────────────────── +CREATE OR REPLACE VIEW reporting.v_live_positions AS + WITH primary_device AS ( + SELECT DISTINCT ON ((reporting.normalize_plate(d_1.vehicle_number))) reporting.normalize_plate(d_1.vehicle_number) AS vehicle_number, + d_1.imei AS primary_imei + FROM devices d_1 + LEFT JOIN live_positions lp_1 ON lp_1.imei = d_1.imei + WHERE d_1.vehicle_number IS NOT NULL AND d_1.enabled_flag = 1 + ORDER BY (reporting.normalize_plate(d_1.vehicle_number)), ( + CASE + WHEN (d_1.mc_type = ANY (ARRAY['GT06E'::text, 'X3'::text, 'AT4'::text])) AND lp_1.gps_time >= (now() - '24:00:00'::interval) THEN 0 + ELSE 1 + END), lp_1.gps_time DESC NULLS LAST, ( + CASE d_1.mc_type + WHEN 'GT06E'::text THEN 1 + WHEN 'X3'::text THEN 2 + WHEN 'AT4'::text THEN 3 + WHEN 'JC400P'::text THEN 4 + ELSE 5 + END), d_1.activation_time, d_1.imei + ) + SELECT lp.imei, + pd.vehicle_number, + d.driver_name AS assigned_driver, + d.cost_centre, + d.assigned_city, + d.vehicle_category, + d.vehicle_models, + d.mc_type, + CASE d.mc_type + WHEN 'GT06E'::text THEN 'tracker'::text + WHEN 'X3'::text THEN 'tracker'::text + WHEN 'AT4'::text THEN 'tracker'::text + WHEN 'JC400P'::text THEN 'camera'::text + ELSE 'other'::text + END AS device_kind, + lp.lat, + lp.lng, + lp.speed, + lp.direction, + lp.acc_status, + lp.device_status, + lp.gps_signal, + lp.gps_num, + lp.current_mileage, + lp.loc_desc, + lp.gps_time, + lp.updated_at, + (lp.gps_time AT TIME ZONE 'Africa/Nairobi'::text) AS gps_time_eat, + (lp.updated_at AT TIME ZONE 'Africa/Nairobi'::text) AS updated_at_eat, + round(EXTRACT(epoch FROM now() - lp.gps_time) / 3600::numeric, 2) AS source_age_hours + FROM live_positions lp + JOIN primary_device pd ON pd.primary_imei = lp.imei + JOIN devices d ON d.imei = lp.imei; + +CREATE OR REPLACE VIEW reporting.v_trips_today AS + SELECT trip_id, + imei, + device_name, + vehicle_number, + vehicle_models, + vehicle_category, + cost_centre, + assigned_city, + assigned_driver, + start_time, + end_time, + trip_date, + start_hour, + start_dow, + daily_seq, + distance_km, + avg_speed_kmh, + max_speed_kmh, + idle_time_s, + driving_time_s, + fuel_consumed_l, + waypoints_count, + start_address, + end_address, + start_geom, + end_geom, + route_geom, + route_geojson, + is_meaningful_route, + updated_at + FROM reporting.v_trips + WHERE trip_date = (now() AT TIME ZONE 'Africa/Nairobi'::text)::date; + +CREATE OR REPLACE VIEW reporting.v_filter_drivers AS + SELECT DISTINCT assigned_driver AS driver + FROM reporting.v_trips + WHERE assigned_driver IS NOT NULL + ORDER BY assigned_driver; + +CREATE OR REPLACE VIEW reporting.v_filter_cost_centres AS + SELECT DISTINCT cost_centre + FROM reporting.v_trips + WHERE cost_centre IS NOT NULL + ORDER BY cost_centre; + +CREATE OR REPLACE VIEW reporting.v_filter_vehicles AS + SELECT vehicle_number, + string_agg(DISTINCT assigned_driver, ', '::text ORDER BY assigned_driver) AS drivers, + (array_agg(cost_centre ORDER BY start_time DESC NULLS LAST))[1] AS cost_centre, + (array_agg(assigned_city ORDER BY start_time DESC NULLS LAST))[1] AS assigned_city + FROM reporting.v_trips + WHERE vehicle_number IS NOT NULL + GROUP BY vehicle_number + ORDER BY vehicle_number; + +CREATE OR REPLACE VIEW reporting.v_filter_cities AS + SELECT DISTINCT assigned_city + FROM reporting.v_trips + WHERE assigned_city IS NOT NULL + ORDER BY assigned_city; + +CREATE OR REPLACE VIEW reporting.v_daily_summary AS + SELECT trip_date, + cost_centre, + assigned_city, + vehicle_number, + assigned_driver, + count(*) AS trip_count, + sum(distance_km) AS total_km, + sum(driving_time_s)::numeric / 3600.0 AS driving_hours, + sum(idle_time_s)::numeric / 3600.0 AS idle_hours, + round(100.0 * sum(idle_time_s)::numeric / NULLIF(sum(idle_time_s + driving_time_s), 0)::numeric, 1) AS idle_pct, + min(start_time) AS first_trip_start, + max(end_time) AS last_trip_end, + avg(avg_speed_kmh) AS avg_speed_kmh, + max(max_speed_kmh) AS max_speed_kmh, + st_asgeojson(st_simplifypreservetopology(st_collect(route_geom), 0.00005::double precision))::json AS day_routes_geojson + FROM reporting.v_trips + WHERE is_meaningful_route + GROUP BY trip_date, cost_centre, assigned_city, vehicle_number, assigned_driver; + +CREATE OR REPLACE VIEW reporting.v_weekly_summary AS + SELECT date_trunc('week'::text, trip_date::timestamp with time zone)::date AS week_start, + cost_centre, + assigned_city, + vehicle_number, + assigned_driver, + count(*) AS trip_count, + count(DISTINCT trip_date) AS active_days, + sum(distance_km) AS total_km, + sum(driving_time_s)::numeric / 3600.0 AS driving_hours, + sum(idle_time_s)::numeric / 3600.0 AS idle_hours, + avg(distance_km) AS avg_trip_km + FROM reporting.v_trips + WHERE is_meaningful_route + GROUP BY (date_trunc('week'::text, trip_date::timestamp with time zone)::date), cost_centre, assigned_city, vehicle_number, assigned_driver; + +CREATE OR REPLACE VIEW reporting.v_monthly_summary AS + SELECT date_trunc('month'::text, trip_date::timestamp with time zone)::date AS month_start, + to_char(trip_date::timestamp with time zone, 'YYYY-MM'::text) AS month_label, + cost_centre, + assigned_city, + vehicle_category, + vehicle_number, + assigned_driver, + count(*) AS trip_count, + count(DISTINCT trip_date) AS active_days, + sum(distance_km) AS total_km, + sum(driving_time_s)::numeric / 3600.0 AS driving_hours, + sum(idle_time_s)::numeric / 3600.0 AS idle_hours, + round(100.0 * sum(idle_time_s)::numeric / NULLIF(sum(idle_time_s + driving_time_s), 0)::numeric, 1) AS idle_pct, + round(sum(distance_km) / NULLIF(count(DISTINCT trip_date), 0)::numeric, 1) AS km_per_active_day, + round(sum(distance_km) / NULLIF(count(*), 0)::numeric, 1) AS km_per_trip, + avg(avg_speed_kmh) AS avg_speed_kmh, + max(max_speed_kmh) AS peak_speed_kmh + FROM reporting.v_trips + WHERE is_meaningful_route + GROUP BY (date_trunc('month'::text, trip_date::timestamp with time zone)::date), (to_char(trip_date::timestamp with time zone, 'YYYY-MM'::text)), cost_centre, assigned_city, vehicle_category, vehicle_number, assigned_driver; + +CREATE OR REPLACE VIEW reporting.v_daily_cost_centre AS + SELECT trip_date, + cost_centre, + count(DISTINCT imei) AS active_vehicles, + count(DISTINCT assigned_driver) AS active_drivers, + count(*) AS trip_count, + sum(distance_km) AS total_km, + sum(driving_time_s)::numeric / 3600.0 AS driving_hours, + sum(idle_time_s)::numeric / 3600.0 AS idle_hours, + round(100.0 * sum(idle_time_s)::numeric / NULLIF(sum(idle_time_s + driving_time_s), 0)::numeric, 1) AS idle_pct, + round(sum(distance_km) / NULLIF(count(DISTINCT imei), 0)::numeric, 1) AS km_per_vehicle + FROM reporting.v_trips + WHERE is_meaningful_route AND cost_centre IS NOT NULL + GROUP BY trip_date, cost_centre; + +CREATE OR REPLACE VIEW reporting.v_weekly_cost_centre AS + SELECT date_trunc('week'::text, trip_date::timestamp with time zone)::date AS week_start, + cost_centre, + count(DISTINCT imei) AS active_vehicles, + count(DISTINCT assigned_driver) AS active_drivers, + count(DISTINCT trip_date) AS active_days, + count(*) AS trip_count, + sum(distance_km) AS total_km, + sum(driving_time_s)::numeric / 3600.0 AS driving_hours, + sum(idle_time_s)::numeric / 3600.0 AS idle_hours, + round(100.0 * sum(idle_time_s)::numeric / NULLIF(sum(idle_time_s + driving_time_s), 0)::numeric, 1) AS idle_pct, + round(sum(distance_km) / NULLIF(count(DISTINCT imei), 0)::numeric, 1) AS km_per_vehicle + FROM reporting.v_trips + WHERE is_meaningful_route AND cost_centre IS NOT NULL + GROUP BY (date_trunc('week'::text, trip_date::timestamp with time zone)::date), cost_centre; + +CREATE OR REPLACE VIEW reporting.v_monthly_cost_centre AS + SELECT date_trunc('month'::text, trip_date::timestamp with time zone)::date AS month_start, + to_char(trip_date::timestamp with time zone, 'YYYY-MM'::text) AS month_label, + cost_centre, + count(DISTINCT imei) AS active_vehicles, + count(DISTINCT assigned_driver) AS active_drivers, + count(DISTINCT trip_date) AS active_days, + count(*) AS trip_count, + sum(distance_km) AS total_km, + sum(driving_time_s)::numeric / 3600.0 AS driving_hours, + sum(idle_time_s)::numeric / 3600.0 AS idle_hours, + round(100.0 * sum(idle_time_s)::numeric / NULLIF(sum(idle_time_s + driving_time_s), 0)::numeric, 1) AS idle_pct, + round(sum(distance_km) / NULLIF(count(DISTINCT imei), 0)::numeric, 1) AS km_per_vehicle + FROM reporting.v_trips + WHERE is_meaningful_route AND cost_centre IS NOT NULL + GROUP BY (date_trunc('month'::text, trip_date::timestamp with time zone)::date), (to_char(trip_date::timestamp with time zone, 'YYYY-MM'::text)), cost_centre; + +-- ── refresh_log index ──────────────────────────────────────────────────────── +CREATE INDEX IF NOT EXISTS ix_refresh_log_refreshed_at ON reporting.refresh_log USING btree (refreshed_at DESC); + +-- ── map functions ──────────────────────────────────────────────────────────── +CREATE OR REPLACE FUNCTION reporting.fn_live_positions(p_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text) + RETURNS jsonb + LANGUAGE plpgsql + STABLE +AS $function$ +DECLARE + v_result jsonb; +BEGIN + p_cost_centre := NULLIF(p_cost_centre, ''); + p_acc_status := NULLIF(p_acc_status, ''); + WITH filtered AS ( + SELECT * FROM reporting.v_live_positions + WHERE (p_cost_centre IS NULL OR cost_centre = p_cost_centre) + AND (p_acc_status IS NULL OR acc_status = p_acc_status) + ) + SELECT jsonb_build_object( + 'summary', jsonb_build_object( + 'vehicle_count', COUNT(*), + -- "moving" and "parked" both restrict to devices that have reported + -- within the OFFLINE_THRESHOLD (24 h) so they represent the live + -- fleet, not equipment-failure stragglers. "offline" is its own + -- counter for the > 24 h tail. + 'moving', COUNT(*) FILTER (WHERE acc_status = '1' + AND source_age_hours < 24), + 'parked', COUNT(*) FILTER (WHERE acc_status = '0' + AND source_age_hours < 24), + 'offline', COUNT(*) FILTER (WHERE source_age_hours >= 24), + 'median_speed_moving', percentile_cont(0.5) WITHIN GROUP (ORDER BY speed) + FILTER (WHERE acc_status = '1' + AND source_age_hours < 24 + AND speed > 0), + 'last_batch_at', to_char(MAX(updated_at) AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'oldest_fix_at', to_char(MIN(gps_time) AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'newest_fix_at', to_char(MAX(gps_time) AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'last_batch_utc', MAX(updated_at), + 'newest_fix_utc', MAX(gps_time) + ), + 'geojson', jsonb_build_object( + 'type', 'FeatureCollection', + 'features', COALESCE(jsonb_agg( + jsonb_build_object( + 'type', 'Feature', + 'properties', jsonb_build_object( + 'imei', imei, + 'vehicle_number', vehicle_number, + 'driver', assigned_driver, + 'cost_centre', cost_centre, + 'assigned_city', assigned_city, + 'vehicle_category', vehicle_category, + 'mc_type', mc_type, + 'device_kind', device_kind, + 'source_age_hours', source_age_hours, + 'speed', speed, + 'direction', direction, + 'acc_status', acc_status, + 'device_status', device_status, + 'gps_signal', gps_signal, + 'gps_num', gps_num, + 'current_mileage', current_mileage, + 'loc_desc', loc_desc, + 'gps_time', to_char(gps_time AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'updated_at', to_char(updated_at AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'gps_time_utc', gps_time, + 'updated_at_utc', updated_at + ), + 'geometry', jsonb_build_object( + 'type', 'Point', + 'coordinates', jsonb_build_array(lng, lat) + ) + ) + ), '[]'::jsonb) + ) + ) INTO v_result FROM filtered; + + RETURN v_result; +END $function$; + +CREATE OR REPLACE FUNCTION reporting.fn_vehicle_track(p_vehicle_number text, p_hours integer DEFAULT 1) + RETURNS jsonb + LANGUAGE sql + STABLE +AS $function$ + -- IMEI lookup reuses the already-deduped reporting.v_live_positions instead + -- of re-running the primary_device CTE against tracksolid.trips. That keeps + -- reporting_reader off tracksolid.trips entirely. + WITH pts AS ( + SELECT ph.gps_time, ph.lat, ph.lng, ph.speed, ph.direction + FROM tracksolid.position_history ph + JOIN reporting.v_live_positions lv ON lv.imei = ph.imei + WHERE lv.vehicle_number = reporting.normalize_plate(p_vehicle_number) + AND ph.gps_time >= NOW() - make_interval(hours => GREATEST(p_hours, 1)) + ORDER BY ph.gps_time + ) + SELECT jsonb_build_object( + 'type', 'Feature', + 'properties', jsonb_build_object( + 'vehicle_number', reporting.normalize_plate(p_vehicle_number), + 'hours', p_hours, + 'points', (SELECT COUNT(*) FROM pts), + 'first_fix', (SELECT to_char(MIN(gps_time) AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS') FROM pts), + 'last_fix', (SELECT to_char(MAX(gps_time) AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS') FROM pts) + ), + 'geometry', jsonb_build_object( + 'type', 'LineString', + 'coordinates', COALESCE( + (SELECT jsonb_agg(jsonb_build_array(lng, lat) ORDER BY gps_time) FROM pts), + '[]'::jsonb) + ) + ); +$function$; + +CREATE OR REPLACE FUNCTION reporting.fn_trips_for_map(p_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date) + RETURNS jsonb + LANGUAGE plpgsql + STABLE +AS $function$ +DECLARE + v_start date := COALESCE(p_start_date, (NOW() AT TIME ZONE 'Africa/Nairobi')::date); + v_end date := COALESCE(p_end_date, (NOW() AT TIME ZONE 'Africa/Nairobi')::date); + v_days int := v_end - v_start + 1; + v_result jsonb; +BEGIN + p_driver := NULLIF(p_driver, ''); + p_cost_centre := NULLIF(p_cost_centre, ''); + p_assigned_city := NULLIF(p_assigned_city, ''); + -- 31-day guardrail: tripped only when NO filter is set AND range > 31 days. + -- Vehicle list (non-empty), driver, cost-centre, OR city each waives it. + IF (p_vehicle_numbers IS NULL OR cardinality(p_vehicle_numbers) = 0) + AND p_driver IS NULL + AND p_cost_centre IS NULL + AND p_assigned_city IS NULL + AND v_days > 31 THEN + RAISE EXCEPTION + 'Range too wide for trip-grain map (% days). Pick a vehicle, driver, cost centre, or city — or narrow the period to 31 days or fewer.', + v_days + USING ERRCODE = 'check_violation'; + END IF; + + WITH filtered AS ( + SELECT * + FROM reporting.v_trips + WHERE is_meaningful_route + AND (p_vehicle_numbers IS NULL + OR cardinality(p_vehicle_numbers) = 0 + OR vehicle_number = ANY(p_vehicle_numbers)) + AND (p_driver IS NULL OR assigned_driver = p_driver) + AND (p_cost_centre IS NULL OR cost_centre = p_cost_centre) + AND (p_assigned_city IS NULL OR assigned_city = p_assigned_city) + AND (p_start_date IS NULL OR trip_date >= p_start_date) + AND (p_end_date IS NULL OR trip_date <= p_end_date) + ) + SELECT jsonb_build_object( + 'summary', jsonb_build_object( + 'trip_count', COUNT(*), + 'total_km', ROUND(COALESCE(SUM(distance_km), 0)::numeric, 1), + 'driving_hours', ROUND((COALESCE(SUM(driving_time_s), 0) / 3600.0)::numeric, 1), + 'idle_hours', ROUND((COALESCE(SUM(idle_time_s), 0) / 3600.0)::numeric, 1), + 'unique_vehicles', COUNT(DISTINCT vehicle_number), + 'unique_drivers', COUNT(DISTINCT assigned_driver), + 'date_min', MIN(trip_date), + 'date_max', MAX(trip_date), + -- First trip's start (chronologically first) + reverse-geocoded location + 'first_trip_start_time', + (array_agg(to_char(start_time, 'YYYY-MM-DD HH24:MI:SS') ORDER BY start_time))[1], + 'first_trip_start_address', + (array_agg(start_address ORDER BY start_time))[1], + 'first_trip_vehicle', + (array_agg(vehicle_number ORDER BY start_time))[1], + -- Last trip's end (chronologically latest) + reverse-geocoded location + 'last_trip_end_time', + (array_agg(to_char(end_time, 'YYYY-MM-DD HH24:MI:SS') ORDER BY end_time DESC NULLS LAST))[1], + 'last_trip_end_address', + (array_agg(end_address ORDER BY end_time DESC NULLS LAST))[1], + 'last_trip_vehicle', + (array_agg(vehicle_number ORDER BY end_time DESC NULLS LAST))[1] + ), + 'geojson', jsonb_build_object( + 'type', 'FeatureCollection', + 'features', COALESCE(jsonb_agg( + jsonb_build_object( + 'type', 'Feature', + 'properties', jsonb_build_object( + 'trip_id', trip_id, + 'vehicle_number', vehicle_number, + 'driver', assigned_driver, + 'cost_centre', cost_centre, + 'assigned_city', assigned_city, + 'trip_date', trip_date, + 'daily_seq', daily_seq, + 'start_time', to_char(start_time, 'YYYY-MM-DD HH24:MI:SS'), + 'end_time', to_char(end_time, 'YYYY-MM-DD HH24:MI:SS'), + 'distance_km', ROUND(COALESCE(distance_km, 0)::numeric, 2), + 'duration_min', ROUND((COALESCE(driving_time_s, 0) / 60.0)::numeric, 0) + ), + 'geometry', route_geojson + ) + ORDER BY vehicle_number, trip_date, daily_seq + ), '[]'::jsonb) + ) + ) + INTO v_result + FROM filtered; + + RETURN v_result; +END +$function$; + +-- ── grants (guarded: roles may not exist on a fresh DB) ─────────────────────── +DO $grants$ +BEGIN + IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname='grafana_ro') THEN + GRANT USAGE ON SCHEMA reporting TO grafana_ro; + GRANT SELECT ON ALL TABLES IN SCHEMA reporting TO grafana_ro; + GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA reporting TO grafana_ro; + END IF; + IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname='tracksolid_owner') THEN + GRANT USAGE ON SCHEMA reporting TO tracksolid_owner; + END IF; +END $grants$; diff --git a/run_migrations.py b/run_migrations.py index 2192f66..69129c4 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -34,6 +34,7 @@ MIGRATIONS = [ "08_analytics_config.sql", # ops.cost_rates, ops.kpi_targets + seed data "09_trips_enrichment.sql", # trips.route_geom + addresses + plate + v_trips_enriched "10_pgbouncer_auth.sql", # pgbouncer role + user_lookup() for SCRAM passthrough + "11_reporting_schema.sql", # reporting.* map-dashboard read layer (dashboard_api) ] # ── Tables that must exist before the service is allowed to start ───────────── From 83a2d06148817851912f99e006fd15c3df64f4d2 Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 12:47:18 +0300 Subject: [PATCH 19/31] =?UTF-8?q?docs:=20add=20PLATFORM=5FOVERVIEW.html=20?= =?UTF-8?q?=E2=80=94=20current-state=20platform=20reference?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Self-contained HTML reference generated from the live DB, documenting the platform after the maps moved off n8n onto dashboard_api (fleetapi). Covers architecture/data flow, the n8n→fleetapi migration, deployment topology, the read-API endpoint reference, and the full database schema — every table (with columns + row estimates), view, and function across tracksolid / reporting / ops / dwh_gold / public — plus operational notes. Co-Authored-By: Claude Opus 4.8 --- docs/PLATFORM_OVERVIEW.html | 94 +++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 docs/PLATFORM_OVERVIEW.html diff --git a/docs/PLATFORM_OVERVIEW.html b/docs/PLATFORM_OVERVIEW.html new file mode 100644 index 0000000..b57e154 --- /dev/null +++ b/docs/PLATFORM_OVERVIEW.html @@ -0,0 +1,94 @@ + + +Fireside · Tracksolid Fleet Intelligence — Platform Overview +
+

Fireside Communications — Tracksolid Fleet Intelligence

+

Platform reference · generated 2026-06-05 09:46 UTC from the live database (tracksolid_db @ twala.rahamafresh.com:5433)

+
What this document is. A current-state reference for the fleet telematics platform after the +map dashboards were moved off n8n onto the dedicated dashboard_api service (fleetapi.rahamafresh.com). +Covers data flow, deployment, the read-API, and the full database schema (tables, views, functions).

1 · Architecture & data flow

+
Tracksolid Pro / Jimi IoT APIeu-open.tracksolidpro.com — GPS, trips, alarms, OBD
+
+
Ingestion (Python)ingest_movement · ingest_events · webhook_receiver
+
+
TimescaleDB + PostGISschema tracksolid — single source of truth
+
+
+
reporting.* read layerv_live_positions · v_trips (matview) · fn_* functions
+
+
dashboard_api (FastAPI)https://fleetapi.rahamafresh.com :8890
+
+
Map SPAs (rustfs/S3)liveposition · fleetintelligence
+
+

Grafana reads the same TimescaleDB directly via the tracksolid.v_* views (NOC + daily-ops dashboards).

2 · The n8n → fleetapi migration

The two map dashboards previously fetched data from n8n webhooks at +https://automate.rahamafresh.com/webhook/…. n8n was only a thin HTTP→SQL proxy and a fragile link in the +live-data path. It has been replaced by dashboard_api, a small FastAPI service that calls the proven +reporting.* functions directly. The SPAs now point their N8N_BASE constant at +https://fleetapi.rahamafresh.com; all webhook paths are unchanged, so the migration was a one-line +front-end change per SPA plus the new service.

+ + + + + + +
AspectBefore (n8n)After (fleetapi)
SPA base URLautomate.rahamafresh.comfleetapi.rahamafresh.com
Live Positions/webhook/live-positionssame path → reporting.fn_live_positions
Vehicle trail/webhook/live-positions/tracksame path (route alias added) → fn_vehicle_track
Fleet trips/webhook/fleet-dashboard (GET+POST)same paths → fn_trips_for_map
Transportn8n workflow + credentialsFastAPI + psycopg2 pool (shared with ingestion)

3 · Deployment topology

Host twala.rahamafresh.com (31.97.44.246, Hostinger VPS) running Coolify 4.1. The Tracksolid stack +is a docker-compose application (container suffix bo3nov2ija7g8wn9b1g2paxs); the reverse proxy is +Traefik on the coolify network with Let's Encrypt TLS.

+ + + + + + + + + +
ServiceRolePort / domain
timescale_dbPostgreSQL 16 + TimescaleDB 2.15 + PostGIS 35432 internal · 5433 host
ingest_movementGPS positions, trips, parking, track-list, device sync
ingest_eventsAlarm event polling
webhook_receiverPush receiver (/pushobd /pushevent /pushtripreport …)8888 (Traefik)
dashboard_apiMap read-API (replaces n8n)8890 → fleetapi.rahamafresh.com
grafanaNOC + daily-ops dashboards3000 → grafana.rahamafresh.com
pgbouncerConnection pooler (SCRAM via public.user_lookup)6432 internal
db_backuppg_dump → rustfs S3 (bucket fleet-db), scheduled
+

The two map front-ends are single-file SPAs stored as index.html objects in rustfs (S3) at +s3.rahamafresh.com (buckets liveposition, fleetintelligence), each served by a small nginx +proxy container. The dashboard_api enforces CORS for both SPA origins.

+
Operational note. dashboard_api currently runs as a standalone Traefik-labelled container reusing the +app image with dashboard_api_rev.py bind-mounted. The durable form is the compose dashboard_api service +(already in docker-compose.yaml) once the branch is merged and the fleetapi domain is set in Coolify.

4 · Read-API reference (dashboard_api)

Base: https://fleetapi.rahamafresh.com · all responses JSON · CORS limited to the two SPA origins.

MethodPathParamsReturnsNotes
GET/health{status: ok}Liveness probe.
GET/webhook/live-positionscost_centre?, acc_status?{summary, geojson}Live Positions map feed → reporting.fn_live_positions. ~80 vehicle point features.
GET/webhook/live-positions/trackvehicle_number, hours(1-24)GeoJSON Feature (LineString)One vehicle's recent trail. Alias: /webhook/vehicle-track.
GET/webhook/vehicle-trackvehicle_number, hoursGeoJSON FeatureAlias of live-positions/track (kept for compatibility).
GET/webhook/fleet-dashboard{drivers, cost_centres, cities, vehicles}Filter options for the Fleet Intelligence UI.
POST/webhook/fleet-dashboardJSON: period|start_date|end_date, vehicle_numbers, driver, cost_centre, assigned_citytrips GeoJSON payloadTrips for the map → reporting.fn_trips_for_map. period preset: today|7d|30d|custom.

5 · Database schema

tracksolid · Live data — the single source of truth. Ingested from the Tracksolid API.

18 table(s) · 17 view(s) · 1 function(s) documented.

tracksolid.alarmstable344,356 rows

Alarm events (alarm_type, alarm_name, alarm_time).

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('alarms_id_seq'::regclass)
imeitext
alarm_typetext
alarm_timetimestamp with time zone
geomgeometry(Point,4326)
latdouble precision
lngdouble precision
speednumeric(7,2)
acc_statustext
updated_attimestamp with time zonenow()
alarm_nametext
sourcetext'poll'::text
severitytextAlarm severity level: critical | warning | info
geofence_idtextTracksolid geofence ID if this is a geofence alarm
geofence_nametextHuman-readable geofence name
acknowledged_attimestamp with time zoneTimestamp when alarm was acknowledged by an operator
acknowledged_bytextUsername or ID of operator who acknowledged the alarm
tracksolid.api_token_cachetable1 rows

OAuth2 token cache for the Jimi/Tracksolid API.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('api_token_cache_id_seq'::regclass)
accounttextNOT NULL
access_tokentextNOT NULL
refresh_tokentext
app_keytext
expires_attimestamp with time zoneNOT NULL
obtained_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
tracksolid.device_eventstable0 rows

Device network connection and disconnection events from /pushevent webhook.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('device_events_id_seq'::regclass)
imeitextNOT NULL
event_typetextNOT NULLLOGIN = device connected to network; LOGOUT = device disconnected
event_timetimestamp with time zoneNOT NULL
timezonetext
created_attimestamp with time zoneNOT NULLnow()
tracksolid.devicestable181 rows

Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.

ColumnTypeNullDefaultComment
imeitextNOT NULL
device_nametext
mc_typetext
mc_type_use_scopetext
vehicle_nametext
vehicle_numbertext
vehicle_modelstext
vehicle_icontext
vintext
engine_numbertext
vehicle_brandtext
fuel_100kmnumeric(6,2)
driver_nametext
driver_phonetext
simtext
iccidtext
imsitext
accounttext
customer_nametext
device_group_idtext
device_grouptext
activation_timetimestamp with time zone
expirationtimestamp with time zone
enabled_flagsmallintNOT NULL1
statustext'active'::text
citytext
current_mileage_kmnumeric(12,2)
created_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
last_synced_attimestamp with time zone
vehicle_categorytextVehicle type: truck | van | motorcycle | car | other
cost_centretextBusiness unit or department this vehicle belongs to
assigned_routetextRegular route name or ID for route-based reporting
depot_geomgeometry(Point,4326)Home base/depot coordinates (WGS84)
depot_addresstextHuman-readable depot address
assigned_citytextOperating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection.
tracksolid.dispatch_logtable0 rows

Persistent record of every dispatch decision. Powers SLA metrics: dispatch latency, depart delay, time-to-site, wrench time.

ColumnTypeNullDefaultComment
dispatch_idbigintNOT NULLnextval('dispatch_log_dispatch_id_seq'::regclass)
ticket_idtextNOT NULL
imeitextNOT NULL
driver_nametext
job_latdouble precisionNOT NULL
job_lngdouble precisionNOT NULL
job_geomgeometry(Point,4326)
assigned_attimestamp with time zoneNOT NULLnow()
first_movement_attimestamp with time zoneFirst trip start after assigned_at. Back-filled nightly from trips.
on_site_attimestamp with time zoneTime vehicle entered 150 m radius of job_geom. Back-filled nightly.
resolved_attimestamp with time zoneTicket close time from the ops system (ops.tickets.closed_at).
cancelled_attimestamp with time zone
distance_kmnumeric(8,2)
created_attimestamp with time zoneNOT NULLnow()
tracksolid.fault_codestable0 rows

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('fault_codes_id_seq'::regclass)
imeitextNOT NULL
reported_attimestamp with time zoneNOT NULL
fault_codetextNOT NULL
status_flagsinteger
latdouble precision
lngdouble precision
geomgeometry(Point,4326)
event_timetimestamp with time zone
created_attimestamp with time zoneNOT NULLnow()
tracksolid.fuel_readingshypertable~0 rows

Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.

ColumnTypeNullDefaultComment
imeitextNOT NULL
reading_timetimestamp with time zoneNOT NULL
sensor_pathtextSensor channel identifier from the device (path field in API payload)
valuenumeric(10,3)
unittextMeasurement unit: cm (tank depth), % (percentage), V (voltage), L (litres)
latdouble precision
lngdouble precision
geomgeometry(Point,4326)
created_attimestamp with time zoneNOT NULLnow()
tracksolid.geofencestable0 rows

Geofence boundary definitions synced from the Tracksolid platform.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('geofences_id_seq'::regclass)
fence_idtext
fence_nametextNOT NULL
fence_typetextcircle | polygon
geomgeometry(Geometry,4326)
radius_mnumeric(10,2)Radius in metres — only applicable for circle type geofences
descriptiontext
created_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
tracksolid.heartbeatshypertable~0 rows

Device heartbeat hypertable.

ColumnTypeNullDefaultComment
imeitextNOT NULL
gate_timetimestamp with time zoneNOT NULL
power_levelsmallint
gsm_signalsmallint
acc_statussmallint
power_statussmallint
fortifysmallint
created_attimestamp with time zoneNOT NULLnow()
tracksolid.ingestion_logtable274,181 rows

API call audit trail — one row per ingestion run.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('ingestion_log_id_seq'::regclass)
run_attimestamp with time zoneNOT NULLnow()
endpointtextNOT NULL
imei_countintegerNOT NULL0
rows_upsertedintegerNOT NULL0
rows_insertedintegerNOT NULL0
duration_msintegerNOT NULL0
successbooleanNOT NULLtrue
error_codetext
error_messagetext
tracksolid.lbs_readingstable0 rows

Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('lbs_readings_id_seq'::regclass)
imeitextNOT NULL
gate_timetimestamp with time zoneNOT NULL
post_typetextPositioning technology: WIFI | LBS (cell tower)
lbs_datajsonbRaw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding.
created_attimestamp with time zoneNOT NULLnow()
tracksolid.live_positionstable179 rows

Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.

ColumnTypeNullDefaultComment
imeitextNOT NULL
geomgeometry(Point,4326)
latdouble precision
lngdouble precision
pos_typetext
confidencesmallint
gps_timetimestamp with time zone
hb_timetimestamp with time zone
speednumeric(7,2)
directionnumeric(6,2)
acc_statustext
gps_signalsmallint
gps_numsmallint
elec_quantitynumeric(5,2)
power_valuenumeric(5,2)
battery_power_valnumeric(5,2)
tracker_oiltext
temperaturenumeric(8,2)
current_mileagenumeric(12,2)
device_statustext
expire_flagtext
activation_flagtext
loc_desctext
recorded_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
tracksolid.obd_readingstable0 rows

OBD diagnostics — push only via /pushobd webhook.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('obd_readings_id_seq'::regclass)
imeitext
reading_timetimestamp with time zone
engine_rpmintegerEngine RPM from OBD PID 0x0C
fuel_level_pctnumeric(5,2)Fuel tank level % from OBD PID 0x2F
updated_attimestamp with time zonenow()
car_typesmallint
acc_statesmallint
status_flagsinteger
latdouble precision
lngdouble precision
geomgeometry(Point,4326)
obd_datajsonbRaw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.)
coolant_temp_cnumeric(6,2)Coolant temperature °C from OBD PID 0x05
battery_voltagenumeric(5,2)Battery voltage (V) from OBD PID 0x42
intake_pressurenumeric(6,2)Intake manifold pressure kPa from OBD PID 0x0B
throttle_pctnumeric(5,2)Throttle position % from OBD PID 0x11
vehicle_speednumeric(7,2)Vehicle speed km/h from OBD PID 0x0D
engine_load_pctnumeric(5,2)Calculated engine load % from OBD PID 0x04
tracksolid.parking_eventstable0 rows

Stop events with duration + address.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('parking_events_id_seq'::regclass)
imeitextNOT NULL
event_typetext
start_timetimestamp with time zoneNOT NULL
end_timetimestamp with time zone
duration_secondsinteger
geomgeometry(Point,4326)
addresstext
updated_attimestamp with time zonenow()
tracksolid.position_historyhypertable~3,596,013 rows

All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).

ColumnTypeNullDefaultComment
imeitextNOT NULL
gps_timetimestamp with time zoneNOT NULL
geomgeometry(Point,4326)
latdouble precision
lngdouble precision
speednumeric(7,2)
directionnumeric(6,2)
acc_statustext
satellitesmallint
current_mileagenumeric(12,2)
recorded_attimestamp with time zonenow()
altitudenumeric(8,2)
post_typesmallint
sourcetext'poll'::text
tracksolid.schema_migrationstable9 rows

ColumnTypeNullDefaultComment
filenametextNOT NULL
applied_attimestamp with time zoneNOT NULLnow()
tracksolid.temperature_readingshypertable~0 rows

Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.

ColumnTypeNullDefaultComment
imeitextNOT NULL
reading_timetimestamp with time zoneNOT NULL
temperaturenumeric(6,2)
humidity_pctnumeric(5,2)
created_attimestamp with time zoneNOT NULLnow()
tracksolid.tripstable43,765 rows

Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('trips_id_seq'::regclass)
imeitextNOT NULL
start_timetimestamp with time zoneNOT NULL
end_timetimestamp with time zone
start_geomgeometry(Point,4326)
end_geomgeometry(Point,4326)
distance_kmnumeric(12,2)Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10).
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
updated_attimestamp with time zonenow()
fuel_consumed_lnumeric(8,2)
idle_time_sinteger
driving_time_sintegerrunTimeSecond from API: total driving time in seconds
trip_seqinteger
sourcetext'poll'::textpoll = from API polling, push = from webhook push
route_geomgeometry(LineString,4326)Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window.
start_addresstextReverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
end_addresstextReverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
vehicle_platetextDenormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest.
waypoints_countintegerNumber of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate.
tracksolid.v_active_dispatch_mapview

01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.

ColumnTypeNullDefaultComment
imeitext
vehicle_numbertext
vehicle_nametext
driver_nametext
driver_phonetext
assigned_citytext
latdouble precision
lngdouble precision
speednumeric(7,2)
directionnumeric(6,2)
acc_statustext
last_fixtimestamp without time zone
statustext
tracksolid.v_alarms_dailyview

01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.

ColumnTypeNullDefaultComment
daydate
alarm_nametext
alarm_countbigint
tracksolid.v_currently_idleview

01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.

ColumnTypeNullDefaultComment
imeitext
vehicle_numbertext
driver_nametext
assigned_citytext
latdouble precision
lngdouble precision
sincetimestamp without time zone
idle_secondsinteger
tracksolid.v_driver_aggregates_dailyview

01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
assigned_citytext
daydate
kmnumeric
tripsbigint
events_80bigint
events_100bigint
events_120bigint
harsh_eventsbigint
speeding_per_100kmnumeric
harsh_per_100kmnumeric
tracksolid.v_driver_attendance_dailyview

ColumnTypeNullDefaultComment
report_datedate
driver_nametext
vehicle_numbertext
cost_centretext
assigned_citytext
reporting_timetime without time zone
start_addresstext
start_latdouble precision
start_lngdouble precision
statustext
mins_from_startinteger
tracksolid.v_driver_clock_dailyview

Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
cost_centretext
assigned_citytext
report_datedate
reporting_timetime without time zone
closing_timetime without time zone
reporting_tstimestamp with time zone
closing_tstimestamp with time zone
start_latdouble precision
start_lngdouble precision
start_addresstext
end_latdouble precision
end_lngdouble precision
end_addresstext
trips_countbigint
total_kmnumeric
drive_hoursnumeric
tracksolid.v_driver_clock_todayview

Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
cost_centretext
assigned_citytext
report_datedate
reporting_timetime without time zone
closing_timetime without time zone
reporting_tstimestamp with time zone
closing_tstimestamp with time zone
start_latdouble precision
start_lngdouble precision
start_addresstext
end_latdouble precision
end_lngdouble precision
end_addresstext
trips_countbigint
total_kmnumeric
drive_hoursnumeric
tracksolid.v_fleet_km_dailyview

01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.

ColumnTypeNullDefaultComment
daydate
assigned_citytext
kmnumeric
active_vehiclesbigint
tripsbigint
tracksolid.v_fleet_statusview

ColumnTypeNullDefaultComment
imeitext
vehicle_numbertext
driver_nametext
latdouble precision
lngdouble precision
geomgeometry(Point,4326)
speednumeric(7,2)
acc_statustext
gps_timetimestamp with time zone
connectivity_statustext
seconds_since_fixinteger
tracksolid.v_fleet_todayview

01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
vehicle_nametext
assigned_citytext
enabled_flagsmallint
km_todaynumeric
trips_todaybigint
drive_hoursnumeric
idle_hoursnumeric
first_departuretime without time zone
last_returntime without time zone
alarms_todaybigint
last_fixtimestamp without time zone
last_speednumeric(7,2)
did_not_moveboolean
tracksolid.v_fleet_traceview

ColumnTypeNullDefaultComment
gidbigint
driver_nametext
vehicle_nametext
device_nametext
imeitext
geomgeometry(Point,4326)
latnumeric
lngnumeric
start_timetimestamp without time zone
end_timetimestamp without time zone
day_localdate
hour_localinteger
dow_localinteger
gps_time_utctimestamp with time zone
recorded_attimestamp with time zone
speednumeric(7,2)
directionnumeric(6,2)
current_mileagenumeric(12,2)
stationaryboolean
trip_idbigint
tracksolid.v_ingestion_healthview

ColumnTypeNullDefaultComment
endpointtext
run_attimestamp with time zone
successboolean
error_messagetext
seconds_agointeger
tracksolid.v_mileage_daily_caggview

ColumnTypeNullDefaultComment
buckettimestamp with time zone
imeitext
dist_kmnumeric
avg_speednumeric
tracksolid.v_sla_inflightview

01_BusinessAnalytics.md §4.5 Field-Service SLA Metrics. Open tickets + last 24h resolved.

ColumnTypeNullDefaultComment
ticket_idtext
customertext
prioritytext
job_typetext
statustext
created_attimestamp with time zone
assigned_attimestamp with time zone
closed_attimestamp with time zone
assigned_imeitext
driver_nametext
first_movement_attimestamp with time zone
on_site_attimestamp with time zone
resolved_attimestamp with time zone
dispatch_minsnumeric
enroute_minsnumeric
onsite_minsnumeric
resolution_minsnumeric
ticket_stagetext
tracksolid.v_trips_enrichedview

tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.

ColumnTypeNullDefaultComment
idbigint
imeitext
start_timetimestamp with time zone
end_timetimestamp with time zone
start_geomgeometry(Point,4326)
end_geomgeometry(Point,4326)
distance_kmnumeric(12,2)
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
updated_attimestamp with time zone
fuel_consumed_lnumeric(8,2)
idle_time_sinteger
driving_time_sinteger
trip_seqinteger
sourcetext
route_geomgeometry(LineString,4326)
start_addresstext
end_addresstext
vehicle_platetext
waypoints_countinteger
trip_date_eatdate
daily_seqbigint
tracksolid.v_utilisation_dailyview

01_BusinessAnalytics.md §7 Panel 8 Utilisation Heatmap. Empty until nightly ETL runs.

ColumnTypeNullDefaultComment
daydate
imeitext
vehicle_numbertext
driver_nametext
assigned_citytext
total_distance_kmnumeric(12,2)
total_drive_hoursnumeric(8,2)
total_idle_hoursnumeric(8,2)
alarm_countinteger
overspeed_countinteger
utilisation_pctnumeric
tracksolid.v_vehicles_not_moved_todayview

01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.

ColumnTypeNullDefaultComment
imeitext
vehicle_nametext
vehicle_numbertext
driver_nametext
assigned_citytext
last_seentimestamp without time zone
speednumeric(7,2)
tracksolid.set_updated_at(…)function · plpgsql

arguments()
returnstrigger

reporting · Read layer that backs the map dashboards (consumed by dashboard_api).

2 table(s) · 12 view(s) · 4 function(s) documented.

reporting.refresh_logtable3,558 rows

One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. n8n inserts; read MAX(refreshed_at) for staleness check.

ColumnTypeNullDefaultComment
refreshed_attimestamp with time zoneNOT NULLnow()
sourcetextNOT NULL'n8n'::text
duration_msinteger
row_countinteger
notestext
reporting.v_tripsmatview31,670 rows

Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.

ColumnTypeNullDefaultComment
trip_idbigint
imeitext
device_nametext
vehicle_numbertext
vehicle_modelstext
vehicle_categorytext
cost_centretext
assigned_citytext
assigned_drivertext
start_timetimestamp without time zone
end_timetimestamp without time zone
trip_datedate
start_hourinteger
start_dowinteger
daily_seqbigint
distance_kmnumeric(12,2)
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
idle_time_sinteger
driving_time_sinteger
fuel_consumed_lnumeric(8,2)
waypoints_countinteger
start_addresstext
end_addresstext
start_geomgeometry(Point,4326)
end_geomgeometry(Point,4326)
route_geomgeometry(LineString,4326)
route_geojsonjson
is_meaningful_routeboolean
updated_attimestamp without time zone
reporting.v_daily_cost_centreview

Cost-centre × day rollup. Excludes trips with NULL cost_centre.

ColumnTypeNullDefaultComment
trip_datedate
cost_centretext
active_vehiclesbigint
active_driversbigint
trip_countbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
km_per_vehiclenumeric
reporting.v_daily_summaryview

Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.

ColumnTypeNullDefaultComment
trip_datedate
cost_centretext
assigned_citytext
vehicle_numbertext
assigned_drivertext
trip_countbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
first_trip_starttimestamp without time zone
last_trip_endtimestamp without time zone
avg_speed_kmhnumeric
max_speed_kmhnumeric
day_routes_geojsonjson
reporting.v_filter_citiesview

Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.

ColumnTypeNullDefaultComment
assigned_citytext
reporting.v_filter_cost_centresview

Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.

ColumnTypeNullDefaultComment
cost_centretext
reporting.v_filter_driversview

Driver dropdown source for the n8n dashboard. Distinct non-null drivers.

ColumnTypeNullDefaultComment
drivertext
reporting.v_filter_vehiclesview

Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.

ColumnTypeNullDefaultComment
vehicle_numbertext
driverstext
cost_centretext
assigned_citytext
reporting.v_live_positionsview

Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.

ColumnTypeNullDefaultComment
imeitext
vehicle_numbertext
assigned_drivertext
cost_centretext
assigned_citytext
vehicle_categorytext
vehicle_modelstext
mc_typetext
device_kindtext
latdouble precision
lngdouble precision
speednumeric(7,2)
directionnumeric(6,2)
acc_statustext
device_statustext
gps_signalsmallint
gps_numsmallint
current_mileagenumeric(12,2)
loc_desctext
gps_timetimestamp with time zone
updated_attimestamp with time zone
gps_time_eattimestamp without time zone
updated_at_eattimestamp without time zone
source_age_hoursnumeric
reporting.v_monthly_cost_centreview

Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.

ColumnTypeNullDefaultComment
month_startdate
month_labeltext
cost_centretext
active_vehiclesbigint
active_driversbigint
active_daysbigint
trip_countbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
km_per_vehiclenumeric
reporting.v_monthly_summaryview

Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).

ColumnTypeNullDefaultComment
month_startdate
month_labeltext
cost_centretext
assigned_citytext
vehicle_categorytext
vehicle_numbertext
assigned_drivertext
trip_countbigint
active_daysbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
km_per_active_daynumeric
km_per_tripnumeric
avg_speed_kmhnumeric
peak_speed_kmhnumeric
reporting.v_trips_todayview

Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

ColumnTypeNullDefaultComment
trip_idbigint
imeitext
device_nametext
vehicle_numbertext
vehicle_modelstext
vehicle_categorytext
cost_centretext
assigned_citytext
assigned_drivertext
start_timetimestamp without time zone
end_timetimestamp without time zone
trip_datedate
start_hourinteger
start_dowinteger
daily_seqbigint
distance_kmnumeric(12,2)
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
idle_time_sinteger
driving_time_sinteger
fuel_consumed_lnumeric(8,2)
waypoints_countinteger
start_addresstext
end_addresstext
start_geomgeometry(Point,4326)
end_geomgeometry(Point,4326)
route_geomgeometry(LineString,4326)
route_geojsonjson
is_meaningful_routeboolean
updated_attimestamp without time zone
reporting.v_weekly_cost_centreview

Cost-centre × week rollup. Excludes trips with NULL cost_centre.

ColumnTypeNullDefaultComment
week_startdate
cost_centretext
active_vehiclesbigint
active_driversbigint
active_daysbigint
trip_countbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
km_per_vehiclenumeric
reporting.v_weekly_summaryview

Vehicle × week rollup. Numeric only, no geometry.

ColumnTypeNullDefaultComment
week_startdate
cost_centretext
assigned_citytext
vehicle_numbertext
assigned_drivertext
trip_countbigint
active_daysbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
avg_trip_kmnumeric
reporting.fn_live_positions(…)function · plpgsql

Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.

argumentsp_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text
returnsjsonb
reporting.fn_trips_for_map(…)function · plpgsql

Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.

argumentsp_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date
returnsjsonb
reporting.fn_vehicle_track(…)function · sql

Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.

argumentsp_vehicle_number text, p_hours integer DEFAULT 1
returnsjsonb
reporting.normalize_plate(…)function · sql

Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.

argumentsp text
returnstext

ops · Workshop / tickets / odometer integrations.

5 table(s) · 1 view(s) · 0 function(s) documented.

ops.cost_ratestable3 rows

Reference rates for analytics monetisation: fuel price per litre by city, labour cost per hour by role. Resolution order in views: scope_type=city > scope_type=role > scope_type=global.

ColumnTypeNullDefaultComment
rate_keytextNOT NULL
scope_typetextNOT NULLcity | role | global
scope_valuetext
metrictextNOT NULLfuel_per_litre | labour_per_hour
amountnumeric(12,2)NOT NULL
currencytextNOT NULL
effective_fromdateNOT NULLCURRENT_DATE
notestext
created_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
ops.kpi_targetstable12 rows

Traffic-light targets per KPI per scope. Resolution order in views: cost_centre > vehicle_category > city > global.

ColumnTypeNullDefaultComment
target_idbigintNOT NULLnextval('ops.kpi_targets_target_id_seq'::regclass)
kpi_keytextNOT NULL
scope_typetextNOT NULL
scope_valuetext
target_valuenumeric(12,2)NOT NULL
amber_thresholdnumeric(12,2)
red_thresholdnumeric(12,2)
directiontextNOT NULL'higher_is_better'::texthigher_is_better -> green when value >= target. lower_is_better -> green when value <= target.
effective_fromdateNOT NULLCURRENT_DATE
notestext
created_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
ops.odometer_readingstable0 rows

Physical odometer captures from service, fuel card, or manual entry. Powers §3.8 Odometer Divergence audit.

ColumnTypeNullDefaultComment
reading_idbigintNOT NULLnextval('ops.odometer_readings_reading_id_seq'::regclass)
imeitextNOT NULL
reading_datedateNOT NULL
reading_kmintegerNOT NULL
sourcetextservice | fuel_card | driver_manual | workshop_form
recorded_bytext
created_attimestamp with time zoneNOT NULLnow()
ops.service_logtable0 rows

Workshop service history. Powers §10 Service-Interval Forecaster.

ColumnTypeNullDefaultComment
service_idbigintNOT NULLnextval('ops.service_log_service_id_seq'::regclass)
imeitextNOT NULL
service_datedateNOT NULL
odometer_kmintegerNOT NULLPhysical odometer reading at service time (integer km).
service_typetextscheduled | repair | tyre | bodywork | inspection | other
cost_kesinteger
notestext
created_attimestamp with time zoneNOT NULLnow()
ops.ticketstable0 rows

Skeleton for ticket data sourced from the Fireside ops system. Replace or extend to match the actual feed (Zoho Desk, Freshdesk, etc).

ColumnTypeNullDefaultComment
ticket_idtextNOT NULL
assigned_imeitext
driver_nametext
customertext
job_typetext
prioritytext
statustextNOT NULL'open'::textopen | assigned | in_progress | resolved | cancelled
created_attimestamp with time zoneNOT NULL
assigned_attimestamp with time zone
closed_attimestamp with time zone
job_latdouble precision
job_lngdouble precision
job_geomgeometry(Point,4326)
ingested_attimestamp with time zoneNOT NULLnow()
ops.vw_service_forecastview

Projected next-service date per vehicle based on 30-day km rate. Service interval default 10,000 km — override at query time if needed.

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
last_service_datedate
last_service_odointeger
current_odonumeric(12,2)
km_since_servicenumeric
km_to_next_servicenumeric
km_per_day_30dnumeric
projected_service_datedate

dwh_gold · Nightly ETL aggregates.

2 table(s) · 0 view(s) · 1 function(s) documented.

dwh_gold.dim_vehiclestable0 rows

ColumnTypeNullDefaultComment
vehicle_keyintegerNOT NULLnextval('dim_vehicles_vehicle_key_seq'::regclass)
imeitext
vehicle_numbertext
is_activebooleantrue
dwh_gold.fact_daily_fleet_metricstable0 rows

ColumnTypeNullDefaultComment
daydateNOT NULL
vehicle_keyintegerNOT NULL
total_distance_kmnumeric(12,2)Total km driven that day across all trips
max_speed_kmhnumeric(7,2)
idle_hoursnumeric(5,2)
total_tripsintegerNumber of completed trips
total_drive_hoursnumeric(8,2)Total hours of active driving (engine on + moving)
total_idle_hoursnumeric(8,2)Total hours engine on but stationary
fuel_consumed_lnumeric(10,3)Total fuel consumed in litres (from webhook trip reports)
alarm_countintegerTotal alarm events triggered that day
overspeed_countintegerNumber of overspeed alarm events
day_start_timetime without time zoneTime of first trip start (Africa/Nairobi)
day_end_timetime without time zoneTime of last trip end (Africa/Nairobi)
avg_speed_kmhnumeric(7,2)Fleet average speed across all trips that day
peak_speed_kmhnumeric(7,2)Highest max_speed_kmh recorded across all trips
dwh_gold.refresh_daily_metrics(…)function · plpgsql

Populates or refreshes fact_daily_fleet_metrics for the given date. Call nightly: SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1);

argumentstarget_date date
returnsvoid

public · Extension objects + pgbouncer auth helper.

1 table(s) · 3 view(s) · 1 function(s) documented.

public.spatial_ref_systable8,500 rows

ColumnTypeNullDefaultComment
sridintegerNOT NULL
auth_namecharacter varying(256)
auth_sridinteger
srtextcharacter varying(2048)
proj4textcharacter varying(2048)
public.geography_columnsview

ColumnTypeNullDefaultComment
f_table_catalogname
f_table_schemaname
f_table_namename
f_geography_columnname
coord_dimensioninteger
sridinteger
typetext
public.geometry_columnsview

ColumnTypeNullDefaultComment
f_table_catalogcharacter varying(256)
f_table_schemaname
f_table_namename
f_geometry_columnname
coord_dimensioninteger
sridinteger
typecharacter varying(30)
public.trips_viz_v1view

ColumnTypeNullDefaultComment
trip_idbigint
imeitext
vehicle_nametext
vehicle_numbertext
cost_centretext
start_timetimestamp with time zone
end_timetimestamp with time zone
distance_kmnumeric(12,2)
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
vehicle_platetext
start_addresstext
end_addresstext
waypoints_countinteger
driving_time_sinteger
idle_time_sinteger
fuel_consumed_lnumeric(8,2)
trip_date_eatdate
daily_seqbigint
public.user_lookup(…)function · plpgsql

pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.

argumentsin_user text, OUT uname text, OUT phash text
returnsrecord

6 · Operational notes

    +
  • Hypertables (position_history, heartbeats, fuel_readings, +temperature_readings) report 0 in pg_stat_user_tables — counts above use TimescaleDB's +approximate_row_count().
  • +
  • API distance fields are metres, not km (divide by 1000) — see FIX-M16.
  • +
  • reporting.v_trips is a materialized view kept current by an external refresh job (role +reporting_refresher); it is captured in migrations/11_reporting_schema.sql but the refresh schedule is +infrastructure, not schema.
  • +
  • Migrations apply at container startup via run_migrations.py (idempotent, tracked in +tracksolid.schema_migrations). Latest: 11_reporting_schema.sql.
  • +
  • Backups: db_backup sidecar → rustfs bucket fleet-db, scheduled (default 02:30/08:30/14:30/20:30 Africa/Nairobi).
  • +
+

See also: docs/CONNECTIONS.md, docs/reference/01_BusinessAnalytics.md, +docs/manuals/OPERATIONS_MANUAL.md, and the project CLAUDE.md.

\ No newline at end of file From 26fa1a4dc5f9e80a0db8d668985cfb7ecc765715 Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 12:50:48 +0300 Subject: [PATCH 20/31] docs: add Grafana dashboards appendix + link PLATFORM_OVERVIEW from CLAUDE.md Adds section 6 (Grafana dashboards) to PLATFORM_OVERVIEW.html, generated from the provisioned dashboard JSON: every panel in the NOC Fleet (9 panels) and Daily Operations (23 panels) dashboards with type and source view/table. Renumbers Operational notes to section 7. Links the doc from the CLAUDE.md codebase map. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 2 ++ docs/PLATFORM_OVERVIEW.html | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index a31aa91..41af6d8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -83,6 +83,8 @@ docker-compose.yaml # Services: timescale_db, ingest_movement, ingest_ev grafana/ # Grafana provisioning (baked into image) n8n-workflows/ # n8n workflow exports (incl. dwh_extract, dwh_load_bronze) docs/ # Reference docs (connections, API, KPIs, project context) +docs/PLATFORM_OVERVIEW.html # Current-state platform reference (architecture, deploy, read-API, + # full DB schema, Grafana panels) — open in a browser. Post n8n→fleetapi. docs/DWH_PIPELINE.md # DWH pipeline operations runbook (setup, troubleshooting) docs/superpowers/ # Pitch specs and implementation plans (not deployed code) dwh/ # DWH migrations for tracksolid_dwh@31.97.44.246:5888 diff --git a/docs/PLATFORM_OVERVIEW.html b/docs/PLATFORM_OVERVIEW.html index b57e154..d2704e6 100644 --- a/docs/PLATFORM_OVERVIEW.html +++ b/docs/PLATFORM_OVERVIEW.html @@ -78,7 +78,7 @@ is a docker-compose application (container suffix bo3nov2ija7g8wn9b1g2paxs proxy container. The dashboard_api enforces CORS for both SPA origins.

Operational note. dashboard_api currently runs as a standalone Traefik-labelled container reusing the app image with dashboard_api_rev.py bind-mounted. The durable form is the compose dashboard_api service -(already in docker-compose.yaml) once the branch is merged and the fleetapi domain is set in Coolify.

4 · Read-API reference (dashboard_api)

Base: https://fleetapi.rahamafresh.com · all responses JSON · CORS limited to the two SPA origins.

MethodPathParamsReturnsNotes
GET/health{status: ok}Liveness probe.
GET/webhook/live-positionscost_centre?, acc_status?{summary, geojson}Live Positions map feed → reporting.fn_live_positions. ~80 vehicle point features.
GET/webhook/live-positions/trackvehicle_number, hours(1-24)GeoJSON Feature (LineString)One vehicle's recent trail. Alias: /webhook/vehicle-track.
GET/webhook/vehicle-trackvehicle_number, hoursGeoJSON FeatureAlias of live-positions/track (kept for compatibility).
GET/webhook/fleet-dashboard{drivers, cost_centres, cities, vehicles}Filter options for the Fleet Intelligence UI.
POST/webhook/fleet-dashboardJSON: period|start_date|end_date, vehicle_numbers, driver, cost_centre, assigned_citytrips GeoJSON payloadTrips for the map → reporting.fn_trips_for_map. period preset: today|7d|30d|custom.

5 · Database schema

tracksolid · Live data — the single source of truth. Ingested from the Tracksolid API.

18 table(s) · 17 view(s) · 1 function(s) documented.

tracksolid.alarmstable344,356 rows

Alarm events (alarm_type, alarm_name, alarm_time).

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('alarms_id_seq'::regclass)
imeitext
alarm_typetext
alarm_timetimestamp with time zone
geomgeometry(Point,4326)
latdouble precision
lngdouble precision
speednumeric(7,2)
acc_statustext
updated_attimestamp with time zonenow()
alarm_nametext
sourcetext'poll'::text
severitytextAlarm severity level: critical | warning | info
geofence_idtextTracksolid geofence ID if this is a geofence alarm
geofence_nametextHuman-readable geofence name
acknowledged_attimestamp with time zoneTimestamp when alarm was acknowledged by an operator
acknowledged_bytextUsername or ID of operator who acknowledged the alarm
tracksolid.api_token_cachetable1 rows

OAuth2 token cache for the Jimi/Tracksolid API.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('api_token_cache_id_seq'::regclass)
accounttextNOT NULL
access_tokentextNOT NULL
refresh_tokentext
app_keytext
expires_attimestamp with time zoneNOT NULL
obtained_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
tracksolid.device_eventstable0 rows

Device network connection and disconnection events from /pushevent webhook.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('device_events_id_seq'::regclass)
imeitextNOT NULL
event_typetextNOT NULLLOGIN = device connected to network; LOGOUT = device disconnected
event_timetimestamp with time zoneNOT NULL
timezonetext
created_attimestamp with time zoneNOT NULLnow()
tracksolid.devicestable181 rows

Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.

ColumnTypeNullDefaultComment
imeitextNOT NULL
device_nametext
mc_typetext
mc_type_use_scopetext
vehicle_nametext
vehicle_numbertext
vehicle_modelstext
vehicle_icontext
vintext
engine_numbertext
vehicle_brandtext
fuel_100kmnumeric(6,2)
driver_nametext
driver_phonetext
simtext
iccidtext
imsitext
accounttext
customer_nametext
device_group_idtext
device_grouptext
activation_timetimestamp with time zone
expirationtimestamp with time zone
enabled_flagsmallintNOT NULL1
statustext'active'::text
citytext
current_mileage_kmnumeric(12,2)
created_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
last_synced_attimestamp with time zone
vehicle_categorytextVehicle type: truck | van | motorcycle | car | other
cost_centretextBusiness unit or department this vehicle belongs to
assigned_routetextRegular route name or ID for route-based reporting
depot_geomgeometry(Point,4326)Home base/depot coordinates (WGS84)
depot_addresstextHuman-readable depot address
assigned_citytextOperating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection.
tracksolid.dispatch_logtable0 rows

Persistent record of every dispatch decision. Powers SLA metrics: dispatch latency, depart delay, time-to-site, wrench time.

ColumnTypeNullDefaultComment
dispatch_idbigintNOT NULLnextval('dispatch_log_dispatch_id_seq'::regclass)
ticket_idtextNOT NULL
imeitextNOT NULL
driver_nametext
job_latdouble precisionNOT NULL
job_lngdouble precisionNOT NULL
job_geomgeometry(Point,4326)
assigned_attimestamp with time zoneNOT NULLnow()
first_movement_attimestamp with time zoneFirst trip start after assigned_at. Back-filled nightly from trips.
on_site_attimestamp with time zoneTime vehicle entered 150 m radius of job_geom. Back-filled nightly.
resolved_attimestamp with time zoneTicket close time from the ops system (ops.tickets.closed_at).
cancelled_attimestamp with time zone
distance_kmnumeric(8,2)
created_attimestamp with time zoneNOT NULLnow()
tracksolid.fault_codestable0 rows

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('fault_codes_id_seq'::regclass)
imeitextNOT NULL
reported_attimestamp with time zoneNOT NULL
fault_codetextNOT NULL
status_flagsinteger
latdouble precision
lngdouble precision
geomgeometry(Point,4326)
event_timetimestamp with time zone
created_attimestamp with time zoneNOT NULLnow()
tracksolid.fuel_readingshypertable~0 rows

Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.

ColumnTypeNullDefaultComment
imeitextNOT NULL
reading_timetimestamp with time zoneNOT NULL
sensor_pathtextSensor channel identifier from the device (path field in API payload)
valuenumeric(10,3)
unittextMeasurement unit: cm (tank depth), % (percentage), V (voltage), L (litres)
latdouble precision
lngdouble precision
geomgeometry(Point,4326)
created_attimestamp with time zoneNOT NULLnow()
tracksolid.geofencestable0 rows

Geofence boundary definitions synced from the Tracksolid platform.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('geofences_id_seq'::regclass)
fence_idtext
fence_nametextNOT NULL
fence_typetextcircle | polygon
geomgeometry(Geometry,4326)
radius_mnumeric(10,2)Radius in metres — only applicable for circle type geofences
descriptiontext
created_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
tracksolid.heartbeatshypertable~0 rows

Device heartbeat hypertable.

ColumnTypeNullDefaultComment
imeitextNOT NULL
gate_timetimestamp with time zoneNOT NULL
power_levelsmallint
gsm_signalsmallint
acc_statussmallint
power_statussmallint
fortifysmallint
created_attimestamp with time zoneNOT NULLnow()
tracksolid.ingestion_logtable274,181 rows

API call audit trail — one row per ingestion run.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('ingestion_log_id_seq'::regclass)
run_attimestamp with time zoneNOT NULLnow()
endpointtextNOT NULL
imei_countintegerNOT NULL0
rows_upsertedintegerNOT NULL0
rows_insertedintegerNOT NULL0
duration_msintegerNOT NULL0
successbooleanNOT NULLtrue
error_codetext
error_messagetext
tracksolid.lbs_readingstable0 rows

Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('lbs_readings_id_seq'::regclass)
imeitextNOT NULL
gate_timetimestamp with time zoneNOT NULL
post_typetextPositioning technology: WIFI | LBS (cell tower)
lbs_datajsonbRaw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding.
created_attimestamp with time zoneNOT NULLnow()
tracksolid.live_positionstable179 rows

Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.

ColumnTypeNullDefaultComment
imeitextNOT NULL
geomgeometry(Point,4326)
latdouble precision
lngdouble precision
pos_typetext
confidencesmallint
gps_timetimestamp with time zone
hb_timetimestamp with time zone
speednumeric(7,2)
directionnumeric(6,2)
acc_statustext
gps_signalsmallint
gps_numsmallint
elec_quantitynumeric(5,2)
power_valuenumeric(5,2)
battery_power_valnumeric(5,2)
tracker_oiltext
temperaturenumeric(8,2)
current_mileagenumeric(12,2)
device_statustext
expire_flagtext
activation_flagtext
loc_desctext
recorded_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
tracksolid.obd_readingstable0 rows

OBD diagnostics — push only via /pushobd webhook.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('obd_readings_id_seq'::regclass)
imeitext
reading_timetimestamp with time zone
engine_rpmintegerEngine RPM from OBD PID 0x0C
fuel_level_pctnumeric(5,2)Fuel tank level % from OBD PID 0x2F
updated_attimestamp with time zonenow()
car_typesmallint
acc_statesmallint
status_flagsinteger
latdouble precision
lngdouble precision
geomgeometry(Point,4326)
obd_datajsonbRaw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.)
coolant_temp_cnumeric(6,2)Coolant temperature °C from OBD PID 0x05
battery_voltagenumeric(5,2)Battery voltage (V) from OBD PID 0x42
intake_pressurenumeric(6,2)Intake manifold pressure kPa from OBD PID 0x0B
throttle_pctnumeric(5,2)Throttle position % from OBD PID 0x11
vehicle_speednumeric(7,2)Vehicle speed km/h from OBD PID 0x0D
engine_load_pctnumeric(5,2)Calculated engine load % from OBD PID 0x04
tracksolid.parking_eventstable0 rows

Stop events with duration + address.

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('parking_events_id_seq'::regclass)
imeitextNOT NULL
event_typetext
start_timetimestamp with time zoneNOT NULL
end_timetimestamp with time zone
duration_secondsinteger
geomgeometry(Point,4326)
addresstext
updated_attimestamp with time zonenow()
tracksolid.position_historyhypertable~3,596,013 rows

All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).

ColumnTypeNullDefaultComment
imeitextNOT NULL
gps_timetimestamp with time zoneNOT NULL
geomgeometry(Point,4326)
latdouble precision
lngdouble precision
speednumeric(7,2)
directionnumeric(6,2)
acc_statustext
satellitesmallint
current_mileagenumeric(12,2)
recorded_attimestamp with time zonenow()
altitudenumeric(8,2)
post_typesmallint
sourcetext'poll'::text
tracksolid.schema_migrationstable9 rows

ColumnTypeNullDefaultComment
filenametextNOT NULL
applied_attimestamp with time zoneNOT NULLnow()
tracksolid.temperature_readingshypertable~0 rows

Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.

ColumnTypeNullDefaultComment
imeitextNOT NULL
reading_timetimestamp with time zoneNOT NULL
temperaturenumeric(6,2)
humidity_pctnumeric(5,2)
created_attimestamp with time zoneNOT NULLnow()
tracksolid.tripstable43,765 rows

Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).

ColumnTypeNullDefaultComment
idbigintNOT NULLnextval('trips_id_seq'::regclass)
imeitextNOT NULL
start_timetimestamp with time zoneNOT NULL
end_timetimestamp with time zone
start_geomgeometry(Point,4326)
end_geomgeometry(Point,4326)
distance_kmnumeric(12,2)Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10).
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
updated_attimestamp with time zonenow()
fuel_consumed_lnumeric(8,2)
idle_time_sinteger
driving_time_sintegerrunTimeSecond from API: total driving time in seconds
trip_seqinteger
sourcetext'poll'::textpoll = from API polling, push = from webhook push
route_geomgeometry(LineString,4326)Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window.
start_addresstextReverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
end_addresstextReverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
vehicle_platetextDenormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest.
waypoints_countintegerNumber of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate.
tracksolid.v_active_dispatch_mapview

01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.

ColumnTypeNullDefaultComment
imeitext
vehicle_numbertext
vehicle_nametext
driver_nametext
driver_phonetext
assigned_citytext
latdouble precision
lngdouble precision
speednumeric(7,2)
directionnumeric(6,2)
acc_statustext
last_fixtimestamp without time zone
statustext
tracksolid.v_alarms_dailyview

01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.

ColumnTypeNullDefaultComment
daydate
alarm_nametext
alarm_countbigint
tracksolid.v_currently_idleview

01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.

ColumnTypeNullDefaultComment
imeitext
vehicle_numbertext
driver_nametext
assigned_citytext
latdouble precision
lngdouble precision
sincetimestamp without time zone
idle_secondsinteger
tracksolid.v_driver_aggregates_dailyview

01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
assigned_citytext
daydate
kmnumeric
tripsbigint
events_80bigint
events_100bigint
events_120bigint
harsh_eventsbigint
speeding_per_100kmnumeric
harsh_per_100kmnumeric
tracksolid.v_driver_attendance_dailyview

ColumnTypeNullDefaultComment
report_datedate
driver_nametext
vehicle_numbertext
cost_centretext
assigned_citytext
reporting_timetime without time zone
start_addresstext
start_latdouble precision
start_lngdouble precision
statustext
mins_from_startinteger
tracksolid.v_driver_clock_dailyview

Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
cost_centretext
assigned_citytext
report_datedate
reporting_timetime without time zone
closing_timetime without time zone
reporting_tstimestamp with time zone
closing_tstimestamp with time zone
start_latdouble precision
start_lngdouble precision
start_addresstext
end_latdouble precision
end_lngdouble precision
end_addresstext
trips_countbigint
total_kmnumeric
drive_hoursnumeric
tracksolid.v_driver_clock_todayview

Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
cost_centretext
assigned_citytext
report_datedate
reporting_timetime without time zone
closing_timetime without time zone
reporting_tstimestamp with time zone
closing_tstimestamp with time zone
start_latdouble precision
start_lngdouble precision
start_addresstext
end_latdouble precision
end_lngdouble precision
end_addresstext
trips_countbigint
total_kmnumeric
drive_hoursnumeric
tracksolid.v_fleet_km_dailyview

01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.

ColumnTypeNullDefaultComment
daydate
assigned_citytext
kmnumeric
active_vehiclesbigint
tripsbigint
tracksolid.v_fleet_statusview

ColumnTypeNullDefaultComment
imeitext
vehicle_numbertext
driver_nametext
latdouble precision
lngdouble precision
geomgeometry(Point,4326)
speednumeric(7,2)
acc_statustext
gps_timetimestamp with time zone
connectivity_statustext
seconds_since_fixinteger
tracksolid.v_fleet_todayview

01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
vehicle_nametext
assigned_citytext
enabled_flagsmallint
km_todaynumeric
trips_todaybigint
drive_hoursnumeric
idle_hoursnumeric
first_departuretime without time zone
last_returntime without time zone
alarms_todaybigint
last_fixtimestamp without time zone
last_speednumeric(7,2)
did_not_moveboolean
tracksolid.v_fleet_traceview

ColumnTypeNullDefaultComment
gidbigint
driver_nametext
vehicle_nametext
device_nametext
imeitext
geomgeometry(Point,4326)
latnumeric
lngnumeric
start_timetimestamp without time zone
end_timetimestamp without time zone
day_localdate
hour_localinteger
dow_localinteger
gps_time_utctimestamp with time zone
recorded_attimestamp with time zone
speednumeric(7,2)
directionnumeric(6,2)
current_mileagenumeric(12,2)
stationaryboolean
trip_idbigint
tracksolid.v_ingestion_healthview

ColumnTypeNullDefaultComment
endpointtext
run_attimestamp with time zone
successboolean
error_messagetext
seconds_agointeger
tracksolid.v_mileage_daily_caggview

ColumnTypeNullDefaultComment
buckettimestamp with time zone
imeitext
dist_kmnumeric
avg_speednumeric
tracksolid.v_sla_inflightview

01_BusinessAnalytics.md §4.5 Field-Service SLA Metrics. Open tickets + last 24h resolved.

ColumnTypeNullDefaultComment
ticket_idtext
customertext
prioritytext
job_typetext
statustext
created_attimestamp with time zone
assigned_attimestamp with time zone
closed_attimestamp with time zone
assigned_imeitext
driver_nametext
first_movement_attimestamp with time zone
on_site_attimestamp with time zone
resolved_attimestamp with time zone
dispatch_minsnumeric
enroute_minsnumeric
onsite_minsnumeric
resolution_minsnumeric
ticket_stagetext
tracksolid.v_trips_enrichedview

tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.

ColumnTypeNullDefaultComment
idbigint
imeitext
start_timetimestamp with time zone
end_timetimestamp with time zone
start_geomgeometry(Point,4326)
end_geomgeometry(Point,4326)
distance_kmnumeric(12,2)
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
updated_attimestamp with time zone
fuel_consumed_lnumeric(8,2)
idle_time_sinteger
driving_time_sinteger
trip_seqinteger
sourcetext
route_geomgeometry(LineString,4326)
start_addresstext
end_addresstext
vehicle_platetext
waypoints_countinteger
trip_date_eatdate
daily_seqbigint
tracksolid.v_utilisation_dailyview

01_BusinessAnalytics.md §7 Panel 8 Utilisation Heatmap. Empty until nightly ETL runs.

ColumnTypeNullDefaultComment
daydate
imeitext
vehicle_numbertext
driver_nametext
assigned_citytext
total_distance_kmnumeric(12,2)
total_drive_hoursnumeric(8,2)
total_idle_hoursnumeric(8,2)
alarm_countinteger
overspeed_countinteger
utilisation_pctnumeric
tracksolid.v_vehicles_not_moved_todayview

01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.

ColumnTypeNullDefaultComment
imeitext
vehicle_nametext
vehicle_numbertext
driver_nametext
assigned_citytext
last_seentimestamp without time zone
speednumeric(7,2)
tracksolid.set_updated_at(…)function · plpgsql

arguments()
returnstrigger

reporting · Read layer that backs the map dashboards (consumed by dashboard_api).

2 table(s) · 12 view(s) · 4 function(s) documented.

reporting.refresh_logtable3,558 rows

One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. n8n inserts; read MAX(refreshed_at) for staleness check.

ColumnTypeNullDefaultComment
refreshed_attimestamp with time zoneNOT NULLnow()
sourcetextNOT NULL'n8n'::text
duration_msinteger
row_countinteger
notestext
reporting.v_tripsmatview31,670 rows

Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.

ColumnTypeNullDefaultComment
trip_idbigint
imeitext
device_nametext
vehicle_numbertext
vehicle_modelstext
vehicle_categorytext
cost_centretext
assigned_citytext
assigned_drivertext
start_timetimestamp without time zone
end_timetimestamp without time zone
trip_datedate
start_hourinteger
start_dowinteger
daily_seqbigint
distance_kmnumeric(12,2)
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
idle_time_sinteger
driving_time_sinteger
fuel_consumed_lnumeric(8,2)
waypoints_countinteger
start_addresstext
end_addresstext
start_geomgeometry(Point,4326)
end_geomgeometry(Point,4326)
route_geomgeometry(LineString,4326)
route_geojsonjson
is_meaningful_routeboolean
updated_attimestamp without time zone
reporting.v_daily_cost_centreview

Cost-centre × day rollup. Excludes trips with NULL cost_centre.

ColumnTypeNullDefaultComment
trip_datedate
cost_centretext
active_vehiclesbigint
active_driversbigint
trip_countbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
km_per_vehiclenumeric
reporting.v_daily_summaryview

Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.

ColumnTypeNullDefaultComment
trip_datedate
cost_centretext
assigned_citytext
vehicle_numbertext
assigned_drivertext
trip_countbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
first_trip_starttimestamp without time zone
last_trip_endtimestamp without time zone
avg_speed_kmhnumeric
max_speed_kmhnumeric
day_routes_geojsonjson
reporting.v_filter_citiesview

Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.

ColumnTypeNullDefaultComment
assigned_citytext
reporting.v_filter_cost_centresview

Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.

ColumnTypeNullDefaultComment
cost_centretext
reporting.v_filter_driversview

Driver dropdown source for the n8n dashboard. Distinct non-null drivers.

ColumnTypeNullDefaultComment
drivertext
reporting.v_filter_vehiclesview

Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.

ColumnTypeNullDefaultComment
vehicle_numbertext
driverstext
cost_centretext
assigned_citytext
reporting.v_live_positionsview

Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.

ColumnTypeNullDefaultComment
imeitext
vehicle_numbertext
assigned_drivertext
cost_centretext
assigned_citytext
vehicle_categorytext
vehicle_modelstext
mc_typetext
device_kindtext
latdouble precision
lngdouble precision
speednumeric(7,2)
directionnumeric(6,2)
acc_statustext
device_statustext
gps_signalsmallint
gps_numsmallint
current_mileagenumeric(12,2)
loc_desctext
gps_timetimestamp with time zone
updated_attimestamp with time zone
gps_time_eattimestamp without time zone
updated_at_eattimestamp without time zone
source_age_hoursnumeric
reporting.v_monthly_cost_centreview

Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.

ColumnTypeNullDefaultComment
month_startdate
month_labeltext
cost_centretext
active_vehiclesbigint
active_driversbigint
active_daysbigint
trip_countbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
km_per_vehiclenumeric
reporting.v_monthly_summaryview

Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).

ColumnTypeNullDefaultComment
month_startdate
month_labeltext
cost_centretext
assigned_citytext
vehicle_categorytext
vehicle_numbertext
assigned_drivertext
trip_countbigint
active_daysbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
km_per_active_daynumeric
km_per_tripnumeric
avg_speed_kmhnumeric
peak_speed_kmhnumeric
reporting.v_trips_todayview

Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

ColumnTypeNullDefaultComment
trip_idbigint
imeitext
device_nametext
vehicle_numbertext
vehicle_modelstext
vehicle_categorytext
cost_centretext
assigned_citytext
assigned_drivertext
start_timetimestamp without time zone
end_timetimestamp without time zone
trip_datedate
start_hourinteger
start_dowinteger
daily_seqbigint
distance_kmnumeric(12,2)
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
idle_time_sinteger
driving_time_sinteger
fuel_consumed_lnumeric(8,2)
waypoints_countinteger
start_addresstext
end_addresstext
start_geomgeometry(Point,4326)
end_geomgeometry(Point,4326)
route_geomgeometry(LineString,4326)
route_geojsonjson
is_meaningful_routeboolean
updated_attimestamp without time zone
reporting.v_weekly_cost_centreview

Cost-centre × week rollup. Excludes trips with NULL cost_centre.

ColumnTypeNullDefaultComment
week_startdate
cost_centretext
active_vehiclesbigint
active_driversbigint
active_daysbigint
trip_countbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
idle_pctnumeric
km_per_vehiclenumeric
reporting.v_weekly_summaryview

Vehicle × week rollup. Numeric only, no geometry.

ColumnTypeNullDefaultComment
week_startdate
cost_centretext
assigned_citytext
vehicle_numbertext
assigned_drivertext
trip_countbigint
active_daysbigint
total_kmnumeric
driving_hoursnumeric
idle_hoursnumeric
avg_trip_kmnumeric
reporting.fn_live_positions(…)function · plpgsql

Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.

argumentsp_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text
returnsjsonb
reporting.fn_trips_for_map(…)function · plpgsql

Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.

argumentsp_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date
returnsjsonb
reporting.fn_vehicle_track(…)function · sql

Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.

argumentsp_vehicle_number text, p_hours integer DEFAULT 1
returnsjsonb
reporting.normalize_plate(…)function · sql

Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.

argumentsp text
returnstext

ops · Workshop / tickets / odometer integrations.

5 table(s) · 1 view(s) · 0 function(s) documented.

ops.cost_ratestable3 rows

Reference rates for analytics monetisation: fuel price per litre by city, labour cost per hour by role. Resolution order in views: scope_type=city > scope_type=role > scope_type=global.

ColumnTypeNullDefaultComment
rate_keytextNOT NULL
scope_typetextNOT NULLcity | role | global
scope_valuetext
metrictextNOT NULLfuel_per_litre | labour_per_hour
amountnumeric(12,2)NOT NULL
currencytextNOT NULL
effective_fromdateNOT NULLCURRENT_DATE
notestext
created_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
ops.kpi_targetstable12 rows

Traffic-light targets per KPI per scope. Resolution order in views: cost_centre > vehicle_category > city > global.

ColumnTypeNullDefaultComment
target_idbigintNOT NULLnextval('ops.kpi_targets_target_id_seq'::regclass)
kpi_keytextNOT NULL
scope_typetextNOT NULL
scope_valuetext
target_valuenumeric(12,2)NOT NULL
amber_thresholdnumeric(12,2)
red_thresholdnumeric(12,2)
directiontextNOT NULL'higher_is_better'::texthigher_is_better -> green when value >= target. lower_is_better -> green when value <= target.
effective_fromdateNOT NULLCURRENT_DATE
notestext
created_attimestamp with time zoneNOT NULLnow()
updated_attimestamp with time zoneNOT NULLnow()
ops.odometer_readingstable0 rows

Physical odometer captures from service, fuel card, or manual entry. Powers §3.8 Odometer Divergence audit.

ColumnTypeNullDefaultComment
reading_idbigintNOT NULLnextval('ops.odometer_readings_reading_id_seq'::regclass)
imeitextNOT NULL
reading_datedateNOT NULL
reading_kmintegerNOT NULL
sourcetextservice | fuel_card | driver_manual | workshop_form
recorded_bytext
created_attimestamp with time zoneNOT NULLnow()
ops.service_logtable0 rows

Workshop service history. Powers §10 Service-Interval Forecaster.

ColumnTypeNullDefaultComment
service_idbigintNOT NULLnextval('ops.service_log_service_id_seq'::regclass)
imeitextNOT NULL
service_datedateNOT NULL
odometer_kmintegerNOT NULLPhysical odometer reading at service time (integer km).
service_typetextscheduled | repair | tyre | bodywork | inspection | other
cost_kesinteger
notestext
created_attimestamp with time zoneNOT NULLnow()
ops.ticketstable0 rows

Skeleton for ticket data sourced from the Fireside ops system. Replace or extend to match the actual feed (Zoho Desk, Freshdesk, etc).

ColumnTypeNullDefaultComment
ticket_idtextNOT NULL
assigned_imeitext
driver_nametext
customertext
job_typetext
prioritytext
statustextNOT NULL'open'::textopen | assigned | in_progress | resolved | cancelled
created_attimestamp with time zoneNOT NULL
assigned_attimestamp with time zone
closed_attimestamp with time zone
job_latdouble precision
job_lngdouble precision
job_geomgeometry(Point,4326)
ingested_attimestamp with time zoneNOT NULLnow()
ops.vw_service_forecastview

Projected next-service date per vehicle based on 30-day km rate. Service interval default 10,000 km — override at query time if needed.

ColumnTypeNullDefaultComment
imeitext
driver_nametext
vehicle_numbertext
last_service_datedate
last_service_odointeger
current_odonumeric(12,2)
km_since_servicenumeric
km_to_next_servicenumeric
km_per_day_30dnumeric
projected_service_datedate

dwh_gold · Nightly ETL aggregates.

2 table(s) · 0 view(s) · 1 function(s) documented.

dwh_gold.dim_vehiclestable0 rows

ColumnTypeNullDefaultComment
vehicle_keyintegerNOT NULLnextval('dim_vehicles_vehicle_key_seq'::regclass)
imeitext
vehicle_numbertext
is_activebooleantrue
dwh_gold.fact_daily_fleet_metricstable0 rows

ColumnTypeNullDefaultComment
daydateNOT NULL
vehicle_keyintegerNOT NULL
total_distance_kmnumeric(12,2)Total km driven that day across all trips
max_speed_kmhnumeric(7,2)
idle_hoursnumeric(5,2)
total_tripsintegerNumber of completed trips
total_drive_hoursnumeric(8,2)Total hours of active driving (engine on + moving)
total_idle_hoursnumeric(8,2)Total hours engine on but stationary
fuel_consumed_lnumeric(10,3)Total fuel consumed in litres (from webhook trip reports)
alarm_countintegerTotal alarm events triggered that day
overspeed_countintegerNumber of overspeed alarm events
day_start_timetime without time zoneTime of first trip start (Africa/Nairobi)
day_end_timetime without time zoneTime of last trip end (Africa/Nairobi)
avg_speed_kmhnumeric(7,2)Fleet average speed across all trips that day
peak_speed_kmhnumeric(7,2)Highest max_speed_kmh recorded across all trips
dwh_gold.refresh_daily_metrics(…)function · plpgsql

Populates or refreshes fact_daily_fleet_metrics for the given date. Call nightly: SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1);

argumentstarget_date date
returnsvoid

public · Extension objects + pgbouncer auth helper.

1 table(s) · 3 view(s) · 1 function(s) documented.

public.spatial_ref_systable8,500 rows

ColumnTypeNullDefaultComment
sridintegerNOT NULL
auth_namecharacter varying(256)
auth_sridinteger
srtextcharacter varying(2048)
proj4textcharacter varying(2048)
public.geography_columnsview

ColumnTypeNullDefaultComment
f_table_catalogname
f_table_schemaname
f_table_namename
f_geography_columnname
coord_dimensioninteger
sridinteger
typetext
public.geometry_columnsview

ColumnTypeNullDefaultComment
f_table_catalogcharacter varying(256)
f_table_schemaname
f_table_namename
f_geometry_columnname
coord_dimensioninteger
sridinteger
typecharacter varying(30)
public.trips_viz_v1view

ColumnTypeNullDefaultComment
trip_idbigint
imeitext
vehicle_nametext
vehicle_numbertext
cost_centretext
start_timetimestamp with time zone
end_timetimestamp with time zone
distance_kmnumeric(12,2)
avg_speed_kmhnumeric(7,2)
max_speed_kmhnumeric(7,2)
vehicle_platetext
start_addresstext
end_addresstext
waypoints_countinteger
driving_time_sinteger
idle_time_sinteger
fuel_consumed_lnumeric(8,2)
trip_date_eatdate
daily_seqbigint
public.user_lookup(…)function · plpgsql

pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.

argumentsin_user text, OUT uname text, OUT phash text
returnsrecord

6 · Operational notes

    +(already in docker-compose.yaml) once the branch is merged and the fleetapi domain is set in Coolify.

    4 · Read-API reference (dashboard_api)

    Base: https://fleetapi.rahamafresh.com · all responses JSON · CORS limited to the two SPA origins.

    MethodPathParamsReturnsNotes
    GET/health{status: ok}Liveness probe.
    GET/webhook/live-positionscost_centre?, acc_status?{summary, geojson}Live Positions map feed → reporting.fn_live_positions. ~80 vehicle point features.
    GET/webhook/live-positions/trackvehicle_number, hours(1-24)GeoJSON Feature (LineString)One vehicle's recent trail. Alias: /webhook/vehicle-track.
    GET/webhook/vehicle-trackvehicle_number, hoursGeoJSON FeatureAlias of live-positions/track (kept for compatibility).
    GET/webhook/fleet-dashboard{drivers, cost_centres, cities, vehicles}Filter options for the Fleet Intelligence UI.
    POST/webhook/fleet-dashboardJSON: period|start_date|end_date, vehicle_numbers, driver, cost_centre, assigned_citytrips GeoJSON payloadTrips for the map → reporting.fn_trips_for_map. period preset: today|7d|30d|custom.

    5 · Database schema

    tracksolid · Live data — the single source of truth. Ingested from the Tracksolid API.

    18 table(s) · 17 view(s) · 1 function(s) documented.

    tracksolid.alarmstable344,356 rows

    Alarm events (alarm_type, alarm_name, alarm_time).

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('alarms_id_seq'::regclass)
    imeitext
    alarm_typetext
    alarm_timetimestamp with time zone
    geomgeometry(Point,4326)
    latdouble precision
    lngdouble precision
    speednumeric(7,2)
    acc_statustext
    updated_attimestamp with time zonenow()
    alarm_nametext
    sourcetext'poll'::text
    severitytextAlarm severity level: critical | warning | info
    geofence_idtextTracksolid geofence ID if this is a geofence alarm
    geofence_nametextHuman-readable geofence name
    acknowledged_attimestamp with time zoneTimestamp when alarm was acknowledged by an operator
    acknowledged_bytextUsername or ID of operator who acknowledged the alarm
    tracksolid.api_token_cachetable1 rows

    OAuth2 token cache for the Jimi/Tracksolid API.

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('api_token_cache_id_seq'::regclass)
    accounttextNOT NULL
    access_tokentextNOT NULL
    refresh_tokentext
    app_keytext
    expires_attimestamp with time zoneNOT NULL
    obtained_attimestamp with time zoneNOT NULLnow()
    updated_attimestamp with time zoneNOT NULLnow()
    tracksolid.device_eventstable0 rows

    Device network connection and disconnection events from /pushevent webhook.

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('device_events_id_seq'::regclass)
    imeitextNOT NULL
    event_typetextNOT NULLLOGIN = device connected to network; LOGOUT = device disconnected
    event_timetimestamp with time zoneNOT NULL
    timezonetext
    created_attimestamp with time zoneNOT NULLnow()
    tracksolid.devicestable181 rows

    Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.

    ColumnTypeNullDefaultComment
    imeitextNOT NULL
    device_nametext
    mc_typetext
    mc_type_use_scopetext
    vehicle_nametext
    vehicle_numbertext
    vehicle_modelstext
    vehicle_icontext
    vintext
    engine_numbertext
    vehicle_brandtext
    fuel_100kmnumeric(6,2)
    driver_nametext
    driver_phonetext
    simtext
    iccidtext
    imsitext
    accounttext
    customer_nametext
    device_group_idtext
    device_grouptext
    activation_timetimestamp with time zone
    expirationtimestamp with time zone
    enabled_flagsmallintNOT NULL1
    statustext'active'::text
    citytext
    current_mileage_kmnumeric(12,2)
    created_attimestamp with time zoneNOT NULLnow()
    updated_attimestamp with time zoneNOT NULLnow()
    last_synced_attimestamp with time zone
    vehicle_categorytextVehicle type: truck | van | motorcycle | car | other
    cost_centretextBusiness unit or department this vehicle belongs to
    assigned_routetextRegular route name or ID for route-based reporting
    depot_geomgeometry(Point,4326)Home base/depot coordinates (WGS84)
    depot_addresstextHuman-readable depot address
    assigned_citytextOperating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection.
    tracksolid.dispatch_logtable0 rows

    Persistent record of every dispatch decision. Powers SLA metrics: dispatch latency, depart delay, time-to-site, wrench time.

    ColumnTypeNullDefaultComment
    dispatch_idbigintNOT NULLnextval('dispatch_log_dispatch_id_seq'::regclass)
    ticket_idtextNOT NULL
    imeitextNOT NULL
    driver_nametext
    job_latdouble precisionNOT NULL
    job_lngdouble precisionNOT NULL
    job_geomgeometry(Point,4326)
    assigned_attimestamp with time zoneNOT NULLnow()
    first_movement_attimestamp with time zoneFirst trip start after assigned_at. Back-filled nightly from trips.
    on_site_attimestamp with time zoneTime vehicle entered 150 m radius of job_geom. Back-filled nightly.
    resolved_attimestamp with time zoneTicket close time from the ops system (ops.tickets.closed_at).
    cancelled_attimestamp with time zone
    distance_kmnumeric(8,2)
    created_attimestamp with time zoneNOT NULLnow()
    tracksolid.fault_codestable0 rows

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('fault_codes_id_seq'::regclass)
    imeitextNOT NULL
    reported_attimestamp with time zoneNOT NULL
    fault_codetextNOT NULL
    status_flagsinteger
    latdouble precision
    lngdouble precision
    geomgeometry(Point,4326)
    event_timetimestamp with time zone
    created_attimestamp with time zoneNOT NULLnow()
    tracksolid.fuel_readingshypertable~0 rows

    Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.

    ColumnTypeNullDefaultComment
    imeitextNOT NULL
    reading_timetimestamp with time zoneNOT NULL
    sensor_pathtextSensor channel identifier from the device (path field in API payload)
    valuenumeric(10,3)
    unittextMeasurement unit: cm (tank depth), % (percentage), V (voltage), L (litres)
    latdouble precision
    lngdouble precision
    geomgeometry(Point,4326)
    created_attimestamp with time zoneNOT NULLnow()
    tracksolid.geofencestable0 rows

    Geofence boundary definitions synced from the Tracksolid platform.

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('geofences_id_seq'::regclass)
    fence_idtext
    fence_nametextNOT NULL
    fence_typetextcircle | polygon
    geomgeometry(Geometry,4326)
    radius_mnumeric(10,2)Radius in metres — only applicable for circle type geofences
    descriptiontext
    created_attimestamp with time zoneNOT NULLnow()
    updated_attimestamp with time zoneNOT NULLnow()
    tracksolid.heartbeatshypertable~0 rows

    Device heartbeat hypertable.

    ColumnTypeNullDefaultComment
    imeitextNOT NULL
    gate_timetimestamp with time zoneNOT NULL
    power_levelsmallint
    gsm_signalsmallint
    acc_statussmallint
    power_statussmallint
    fortifysmallint
    created_attimestamp with time zoneNOT NULLnow()
    tracksolid.ingestion_logtable274,181 rows

    API call audit trail — one row per ingestion run.

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('ingestion_log_id_seq'::regclass)
    run_attimestamp with time zoneNOT NULLnow()
    endpointtextNOT NULL
    imei_countintegerNOT NULL0
    rows_upsertedintegerNOT NULL0
    rows_insertedintegerNOT NULL0
    duration_msintegerNOT NULL0
    successbooleanNOT NULLtrue
    error_codetext
    error_messagetext
    tracksolid.lbs_readingstable0 rows

    Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('lbs_readings_id_seq'::regclass)
    imeitextNOT NULL
    gate_timetimestamp with time zoneNOT NULL
    post_typetextPositioning technology: WIFI | LBS (cell tower)
    lbs_datajsonbRaw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding.
    created_attimestamp with time zoneNOT NULLnow()
    tracksolid.live_positionstable179 rows

    Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.

    ColumnTypeNullDefaultComment
    imeitextNOT NULL
    geomgeometry(Point,4326)
    latdouble precision
    lngdouble precision
    pos_typetext
    confidencesmallint
    gps_timetimestamp with time zone
    hb_timetimestamp with time zone
    speednumeric(7,2)
    directionnumeric(6,2)
    acc_statustext
    gps_signalsmallint
    gps_numsmallint
    elec_quantitynumeric(5,2)
    power_valuenumeric(5,2)
    battery_power_valnumeric(5,2)
    tracker_oiltext
    temperaturenumeric(8,2)
    current_mileagenumeric(12,2)
    device_statustext
    expire_flagtext
    activation_flagtext
    loc_desctext
    recorded_attimestamp with time zoneNOT NULLnow()
    updated_attimestamp with time zoneNOT NULLnow()
    tracksolid.obd_readingstable0 rows

    OBD diagnostics — push only via /pushobd webhook.

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('obd_readings_id_seq'::regclass)
    imeitext
    reading_timetimestamp with time zone
    engine_rpmintegerEngine RPM from OBD PID 0x0C
    fuel_level_pctnumeric(5,2)Fuel tank level % from OBD PID 0x2F
    updated_attimestamp with time zonenow()
    car_typesmallint
    acc_statesmallint
    status_flagsinteger
    latdouble precision
    lngdouble precision
    geomgeometry(Point,4326)
    obd_datajsonbRaw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.)
    coolant_temp_cnumeric(6,2)Coolant temperature °C from OBD PID 0x05
    battery_voltagenumeric(5,2)Battery voltage (V) from OBD PID 0x42
    intake_pressurenumeric(6,2)Intake manifold pressure kPa from OBD PID 0x0B
    throttle_pctnumeric(5,2)Throttle position % from OBD PID 0x11
    vehicle_speednumeric(7,2)Vehicle speed km/h from OBD PID 0x0D
    engine_load_pctnumeric(5,2)Calculated engine load % from OBD PID 0x04
    tracksolid.parking_eventstable0 rows

    Stop events with duration + address.

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('parking_events_id_seq'::regclass)
    imeitextNOT NULL
    event_typetext
    start_timetimestamp with time zoneNOT NULL
    end_timetimestamp with time zone
    duration_secondsinteger
    geomgeometry(Point,4326)
    addresstext
    updated_attimestamp with time zonenow()
    tracksolid.position_historyhypertable~3,596,013 rows

    All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).

    ColumnTypeNullDefaultComment
    imeitextNOT NULL
    gps_timetimestamp with time zoneNOT NULL
    geomgeometry(Point,4326)
    latdouble precision
    lngdouble precision
    speednumeric(7,2)
    directionnumeric(6,2)
    acc_statustext
    satellitesmallint
    current_mileagenumeric(12,2)
    recorded_attimestamp with time zonenow()
    altitudenumeric(8,2)
    post_typesmallint
    sourcetext'poll'::text
    tracksolid.schema_migrationstable9 rows

    ColumnTypeNullDefaultComment
    filenametextNOT NULL
    applied_attimestamp with time zoneNOT NULLnow()
    tracksolid.temperature_readingshypertable~0 rows

    Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.

    ColumnTypeNullDefaultComment
    imeitextNOT NULL
    reading_timetimestamp with time zoneNOT NULL
    temperaturenumeric(6,2)
    humidity_pctnumeric(5,2)
    created_attimestamp with time zoneNOT NULLnow()
    tracksolid.tripstable43,765 rows

    Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).

    ColumnTypeNullDefaultComment
    idbigintNOT NULLnextval('trips_id_seq'::regclass)
    imeitextNOT NULL
    start_timetimestamp with time zoneNOT NULL
    end_timetimestamp with time zone
    start_geomgeometry(Point,4326)
    end_geomgeometry(Point,4326)
    distance_kmnumeric(12,2)Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10).
    avg_speed_kmhnumeric(7,2)
    max_speed_kmhnumeric(7,2)
    updated_attimestamp with time zonenow()
    fuel_consumed_lnumeric(8,2)
    idle_time_sinteger
    driving_time_sintegerrunTimeSecond from API: total driving time in seconds
    trip_seqinteger
    sourcetext'poll'::textpoll = from API polling, push = from webhook push
    route_geomgeometry(LineString,4326)Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window.
    start_addresstextReverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
    end_addresstextReverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
    vehicle_platetextDenormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest.
    waypoints_countintegerNumber of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate.
    tracksolid.v_active_dispatch_mapview

    01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.

    ColumnTypeNullDefaultComment
    imeitext
    vehicle_numbertext
    vehicle_nametext
    driver_nametext
    driver_phonetext
    assigned_citytext
    latdouble precision
    lngdouble precision
    speednumeric(7,2)
    directionnumeric(6,2)
    acc_statustext
    last_fixtimestamp without time zone
    statustext
    tracksolid.v_alarms_dailyview

    01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.

    ColumnTypeNullDefaultComment
    daydate
    alarm_nametext
    alarm_countbigint
    tracksolid.v_currently_idleview

    01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.

    ColumnTypeNullDefaultComment
    imeitext
    vehicle_numbertext
    driver_nametext
    assigned_citytext
    latdouble precision
    lngdouble precision
    sincetimestamp without time zone
    idle_secondsinteger
    tracksolid.v_driver_aggregates_dailyview

    01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).

    ColumnTypeNullDefaultComment
    imeitext
    driver_nametext
    vehicle_numbertext
    assigned_citytext
    daydate
    kmnumeric
    tripsbigint
    events_80bigint
    events_100bigint
    events_120bigint
    harsh_eventsbigint
    speeding_per_100kmnumeric
    harsh_per_100kmnumeric
    tracksolid.v_driver_attendance_dailyview

    ColumnTypeNullDefaultComment
    report_datedate
    driver_nametext
    vehicle_numbertext
    cost_centretext
    assigned_citytext
    reporting_timetime without time zone
    start_addresstext
    start_latdouble precision
    start_lngdouble precision
    statustext
    mins_from_startinteger
    tracksolid.v_driver_clock_dailyview

    Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).

    ColumnTypeNullDefaultComment
    imeitext
    driver_nametext
    vehicle_numbertext
    cost_centretext
    assigned_citytext
    report_datedate
    reporting_timetime without time zone
    closing_timetime without time zone
    reporting_tstimestamp with time zone
    closing_tstimestamp with time zone
    start_latdouble precision
    start_lngdouble precision
    start_addresstext
    end_latdouble precision
    end_lngdouble precision
    end_addresstext
    trips_countbigint
    total_kmnumeric
    drive_hoursnumeric
    tracksolid.v_driver_clock_todayview

    Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

    ColumnTypeNullDefaultComment
    imeitext
    driver_nametext
    vehicle_numbertext
    cost_centretext
    assigned_citytext
    report_datedate
    reporting_timetime without time zone
    closing_timetime without time zone
    reporting_tstimestamp with time zone
    closing_tstimestamp with time zone
    start_latdouble precision
    start_lngdouble precision
    start_addresstext
    end_latdouble precision
    end_lngdouble precision
    end_addresstext
    trips_countbigint
    total_kmnumeric
    drive_hoursnumeric
    tracksolid.v_fleet_km_dailyview

    01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.

    ColumnTypeNullDefaultComment
    daydate
    assigned_citytext
    kmnumeric
    active_vehiclesbigint
    tripsbigint
    tracksolid.v_fleet_statusview

    ColumnTypeNullDefaultComment
    imeitext
    vehicle_numbertext
    driver_nametext
    latdouble precision
    lngdouble precision
    geomgeometry(Point,4326)
    speednumeric(7,2)
    acc_statustext
    gps_timetimestamp with time zone
    connectivity_statustext
    seconds_since_fixinteger
    tracksolid.v_fleet_todayview

    01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.

    ColumnTypeNullDefaultComment
    imeitext
    driver_nametext
    vehicle_numbertext
    vehicle_nametext
    assigned_citytext
    enabled_flagsmallint
    km_todaynumeric
    trips_todaybigint
    drive_hoursnumeric
    idle_hoursnumeric
    first_departuretime without time zone
    last_returntime without time zone
    alarms_todaybigint
    last_fixtimestamp without time zone
    last_speednumeric(7,2)
    did_not_moveboolean
    tracksolid.v_fleet_traceview

    ColumnTypeNullDefaultComment
    gidbigint
    driver_nametext
    vehicle_nametext
    device_nametext
    imeitext
    geomgeometry(Point,4326)
    latnumeric
    lngnumeric
    start_timetimestamp without time zone
    end_timetimestamp without time zone
    day_localdate
    hour_localinteger
    dow_localinteger
    gps_time_utctimestamp with time zone
    recorded_attimestamp with time zone
    speednumeric(7,2)
    directionnumeric(6,2)
    current_mileagenumeric(12,2)
    stationaryboolean
    trip_idbigint
    tracksolid.v_ingestion_healthview

    ColumnTypeNullDefaultComment
    endpointtext
    run_attimestamp with time zone
    successboolean
    error_messagetext
    seconds_agointeger
    tracksolid.v_mileage_daily_caggview

    ColumnTypeNullDefaultComment
    buckettimestamp with time zone
    imeitext
    dist_kmnumeric
    avg_speednumeric
    tracksolid.v_sla_inflightview

    01_BusinessAnalytics.md §4.5 Field-Service SLA Metrics. Open tickets + last 24h resolved.

    ColumnTypeNullDefaultComment
    ticket_idtext
    customertext
    prioritytext
    job_typetext
    statustext
    created_attimestamp with time zone
    assigned_attimestamp with time zone
    closed_attimestamp with time zone
    assigned_imeitext
    driver_nametext
    first_movement_attimestamp with time zone
    on_site_attimestamp with time zone
    resolved_attimestamp with time zone
    dispatch_minsnumeric
    enroute_minsnumeric
    onsite_minsnumeric
    resolution_minsnumeric
    ticket_stagetext
    tracksolid.v_trips_enrichedview

    tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.

    ColumnTypeNullDefaultComment
    idbigint
    imeitext
    start_timetimestamp with time zone
    end_timetimestamp with time zone
    start_geomgeometry(Point,4326)
    end_geomgeometry(Point,4326)
    distance_kmnumeric(12,2)
    avg_speed_kmhnumeric(7,2)
    max_speed_kmhnumeric(7,2)
    updated_attimestamp with time zone
    fuel_consumed_lnumeric(8,2)
    idle_time_sinteger
    driving_time_sinteger
    trip_seqinteger
    sourcetext
    route_geomgeometry(LineString,4326)
    start_addresstext
    end_addresstext
    vehicle_platetext
    waypoints_countinteger
    trip_date_eatdate
    daily_seqbigint
    tracksolid.v_utilisation_dailyview

    01_BusinessAnalytics.md §7 Panel 8 Utilisation Heatmap. Empty until nightly ETL runs.

    ColumnTypeNullDefaultComment
    daydate
    imeitext
    vehicle_numbertext
    driver_nametext
    assigned_citytext
    total_distance_kmnumeric(12,2)
    total_drive_hoursnumeric(8,2)
    total_idle_hoursnumeric(8,2)
    alarm_countinteger
    overspeed_countinteger
    utilisation_pctnumeric
    tracksolid.v_vehicles_not_moved_todayview

    01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.

    ColumnTypeNullDefaultComment
    imeitext
    vehicle_nametext
    vehicle_numbertext
    driver_nametext
    assigned_citytext
    last_seentimestamp without time zone
    speednumeric(7,2)
    tracksolid.set_updated_at(…)function · plpgsql

    arguments()
    returnstrigger

    reporting · Read layer that backs the map dashboards (consumed by dashboard_api).

    2 table(s) · 12 view(s) · 4 function(s) documented.

    reporting.refresh_logtable3,558 rows

    One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. n8n inserts; read MAX(refreshed_at) for staleness check.

    ColumnTypeNullDefaultComment
    refreshed_attimestamp with time zoneNOT NULLnow()
    sourcetextNOT NULL'n8n'::text
    duration_msinteger
    row_countinteger
    notestext
    reporting.v_tripsmatview31,670 rows

    Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.

    ColumnTypeNullDefaultComment
    trip_idbigint
    imeitext
    device_nametext
    vehicle_numbertext
    vehicle_modelstext
    vehicle_categorytext
    cost_centretext
    assigned_citytext
    assigned_drivertext
    start_timetimestamp without time zone
    end_timetimestamp without time zone
    trip_datedate
    start_hourinteger
    start_dowinteger
    daily_seqbigint
    distance_kmnumeric(12,2)
    avg_speed_kmhnumeric(7,2)
    max_speed_kmhnumeric(7,2)
    idle_time_sinteger
    driving_time_sinteger
    fuel_consumed_lnumeric(8,2)
    waypoints_countinteger
    start_addresstext
    end_addresstext
    start_geomgeometry(Point,4326)
    end_geomgeometry(Point,4326)
    route_geomgeometry(LineString,4326)
    route_geojsonjson
    is_meaningful_routeboolean
    updated_attimestamp without time zone
    reporting.v_daily_cost_centreview

    Cost-centre × day rollup. Excludes trips with NULL cost_centre.

    ColumnTypeNullDefaultComment
    trip_datedate
    cost_centretext
    active_vehiclesbigint
    active_driversbigint
    trip_countbigint
    total_kmnumeric
    driving_hoursnumeric
    idle_hoursnumeric
    idle_pctnumeric
    km_per_vehiclenumeric
    reporting.v_daily_summaryview

    Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.

    ColumnTypeNullDefaultComment
    trip_datedate
    cost_centretext
    assigned_citytext
    vehicle_numbertext
    assigned_drivertext
    trip_countbigint
    total_kmnumeric
    driving_hoursnumeric
    idle_hoursnumeric
    idle_pctnumeric
    first_trip_starttimestamp without time zone
    last_trip_endtimestamp without time zone
    avg_speed_kmhnumeric
    max_speed_kmhnumeric
    day_routes_geojsonjson
    reporting.v_filter_citiesview

    Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.

    ColumnTypeNullDefaultComment
    assigned_citytext
    reporting.v_filter_cost_centresview

    Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.

    ColumnTypeNullDefaultComment
    cost_centretext
    reporting.v_filter_driversview

    Driver dropdown source for the n8n dashboard. Distinct non-null drivers.

    ColumnTypeNullDefaultComment
    drivertext
    reporting.v_filter_vehiclesview

    Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.

    ColumnTypeNullDefaultComment
    vehicle_numbertext
    driverstext
    cost_centretext
    assigned_citytext
    reporting.v_live_positionsview

    Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.

    ColumnTypeNullDefaultComment
    imeitext
    vehicle_numbertext
    assigned_drivertext
    cost_centretext
    assigned_citytext
    vehicle_categorytext
    vehicle_modelstext
    mc_typetext
    device_kindtext
    latdouble precision
    lngdouble precision
    speednumeric(7,2)
    directionnumeric(6,2)
    acc_statustext
    device_statustext
    gps_signalsmallint
    gps_numsmallint
    current_mileagenumeric(12,2)
    loc_desctext
    gps_timetimestamp with time zone
    updated_attimestamp with time zone
    gps_time_eattimestamp without time zone
    updated_at_eattimestamp without time zone
    source_age_hoursnumeric
    reporting.v_monthly_cost_centreview

    Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.

    ColumnTypeNullDefaultComment
    month_startdate
    month_labeltext
    cost_centretext
    active_vehiclesbigint
    active_driversbigint
    active_daysbigint
    trip_countbigint
    total_kmnumeric
    driving_hoursnumeric
    idle_hoursnumeric
    idle_pctnumeric
    km_per_vehiclenumeric
    reporting.v_monthly_summaryview

    Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).

    ColumnTypeNullDefaultComment
    month_startdate
    month_labeltext
    cost_centretext
    assigned_citytext
    vehicle_categorytext
    vehicle_numbertext
    assigned_drivertext
    trip_countbigint
    active_daysbigint
    total_kmnumeric
    driving_hoursnumeric
    idle_hoursnumeric
    idle_pctnumeric
    km_per_active_daynumeric
    km_per_tripnumeric
    avg_speed_kmhnumeric
    peak_speed_kmhnumeric
    reporting.v_trips_todayview

    Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

    ColumnTypeNullDefaultComment
    trip_idbigint
    imeitext
    device_nametext
    vehicle_numbertext
    vehicle_modelstext
    vehicle_categorytext
    cost_centretext
    assigned_citytext
    assigned_drivertext
    start_timetimestamp without time zone
    end_timetimestamp without time zone
    trip_datedate
    start_hourinteger
    start_dowinteger
    daily_seqbigint
    distance_kmnumeric(12,2)
    avg_speed_kmhnumeric(7,2)
    max_speed_kmhnumeric(7,2)
    idle_time_sinteger
    driving_time_sinteger
    fuel_consumed_lnumeric(8,2)
    waypoints_countinteger
    start_addresstext
    end_addresstext
    start_geomgeometry(Point,4326)
    end_geomgeometry(Point,4326)
    route_geomgeometry(LineString,4326)
    route_geojsonjson
    is_meaningful_routeboolean
    updated_attimestamp without time zone
    reporting.v_weekly_cost_centreview

    Cost-centre × week rollup. Excludes trips with NULL cost_centre.

    ColumnTypeNullDefaultComment
    week_startdate
    cost_centretext
    active_vehiclesbigint
    active_driversbigint
    active_daysbigint
    trip_countbigint
    total_kmnumeric
    driving_hoursnumeric
    idle_hoursnumeric
    idle_pctnumeric
    km_per_vehiclenumeric
    reporting.v_weekly_summaryview

    Vehicle × week rollup. Numeric only, no geometry.

    ColumnTypeNullDefaultComment
    week_startdate
    cost_centretext
    assigned_citytext
    vehicle_numbertext
    assigned_drivertext
    trip_countbigint
    active_daysbigint
    total_kmnumeric
    driving_hoursnumeric
    idle_hoursnumeric
    avg_trip_kmnumeric
    reporting.fn_live_positions(…)function · plpgsql

    Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.

    argumentsp_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text
    returnsjsonb
    reporting.fn_trips_for_map(…)function · plpgsql

    Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.

    argumentsp_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date
    returnsjsonb
    reporting.fn_vehicle_track(…)function · sql

    Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.

    argumentsp_vehicle_number text, p_hours integer DEFAULT 1
    returnsjsonb
    reporting.normalize_plate(…)function · sql

    Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.

    argumentsp text
    returnstext

    ops · Workshop / tickets / odometer integrations.

    5 table(s) · 1 view(s) · 0 function(s) documented.

    ops.cost_ratestable3 rows

    Reference rates for analytics monetisation: fuel price per litre by city, labour cost per hour by role. Resolution order in views: scope_type=city > scope_type=role > scope_type=global.

    ColumnTypeNullDefaultComment
    rate_keytextNOT NULL
    scope_typetextNOT NULLcity | role | global
    scope_valuetext
    metrictextNOT NULLfuel_per_litre | labour_per_hour
    amountnumeric(12,2)NOT NULL
    currencytextNOT NULL
    effective_fromdateNOT NULLCURRENT_DATE
    notestext
    created_attimestamp with time zoneNOT NULLnow()
    updated_attimestamp with time zoneNOT NULLnow()
    ops.kpi_targetstable12 rows

    Traffic-light targets per KPI per scope. Resolution order in views: cost_centre > vehicle_category > city > global.

    ColumnTypeNullDefaultComment
    target_idbigintNOT NULLnextval('ops.kpi_targets_target_id_seq'::regclass)
    kpi_keytextNOT NULL
    scope_typetextNOT NULL
    scope_valuetext
    target_valuenumeric(12,2)NOT NULL
    amber_thresholdnumeric(12,2)
    red_thresholdnumeric(12,2)
    directiontextNOT NULL'higher_is_better'::texthigher_is_better -> green when value >= target. lower_is_better -> green when value <= target.
    effective_fromdateNOT NULLCURRENT_DATE
    notestext
    created_attimestamp with time zoneNOT NULLnow()
    updated_attimestamp with time zoneNOT NULLnow()
    ops.odometer_readingstable0 rows

    Physical odometer captures from service, fuel card, or manual entry. Powers §3.8 Odometer Divergence audit.

    ColumnTypeNullDefaultComment
    reading_idbigintNOT NULLnextval('ops.odometer_readings_reading_id_seq'::regclass)
    imeitextNOT NULL
    reading_datedateNOT NULL
    reading_kmintegerNOT NULL
    sourcetextservice | fuel_card | driver_manual | workshop_form
    recorded_bytext
    created_attimestamp with time zoneNOT NULLnow()
    ops.service_logtable0 rows

    Workshop service history. Powers §10 Service-Interval Forecaster.

    ColumnTypeNullDefaultComment
    service_idbigintNOT NULLnextval('ops.service_log_service_id_seq'::regclass)
    imeitextNOT NULL
    service_datedateNOT NULL
    odometer_kmintegerNOT NULLPhysical odometer reading at service time (integer km).
    service_typetextscheduled | repair | tyre | bodywork | inspection | other
    cost_kesinteger
    notestext
    created_attimestamp with time zoneNOT NULLnow()
    ops.ticketstable0 rows

    Skeleton for ticket data sourced from the Fireside ops system. Replace or extend to match the actual feed (Zoho Desk, Freshdesk, etc).

    ColumnTypeNullDefaultComment
    ticket_idtextNOT NULL
    assigned_imeitext
    driver_nametext
    customertext
    job_typetext
    prioritytext
    statustextNOT NULL'open'::textopen | assigned | in_progress | resolved | cancelled
    created_attimestamp with time zoneNOT NULL
    assigned_attimestamp with time zone
    closed_attimestamp with time zone
    job_latdouble precision
    job_lngdouble precision
    job_geomgeometry(Point,4326)
    ingested_attimestamp with time zoneNOT NULLnow()
    ops.vw_service_forecastview

    Projected next-service date per vehicle based on 30-day km rate. Service interval default 10,000 km — override at query time if needed.

    ColumnTypeNullDefaultComment
    imeitext
    driver_nametext
    vehicle_numbertext
    last_service_datedate
    last_service_odointeger
    current_odonumeric(12,2)
    km_since_servicenumeric
    km_to_next_servicenumeric
    km_per_day_30dnumeric
    projected_service_datedate

    dwh_gold · Nightly ETL aggregates.

    2 table(s) · 0 view(s) · 1 function(s) documented.

    dwh_gold.dim_vehiclestable0 rows

    ColumnTypeNullDefaultComment
    vehicle_keyintegerNOT NULLnextval('dim_vehicles_vehicle_key_seq'::regclass)
    imeitext
    vehicle_numbertext
    is_activebooleantrue
    dwh_gold.fact_daily_fleet_metricstable0 rows

    ColumnTypeNullDefaultComment
    daydateNOT NULL
    vehicle_keyintegerNOT NULL
    total_distance_kmnumeric(12,2)Total km driven that day across all trips
    max_speed_kmhnumeric(7,2)
    idle_hoursnumeric(5,2)
    total_tripsintegerNumber of completed trips
    total_drive_hoursnumeric(8,2)Total hours of active driving (engine on + moving)
    total_idle_hoursnumeric(8,2)Total hours engine on but stationary
    fuel_consumed_lnumeric(10,3)Total fuel consumed in litres (from webhook trip reports)
    alarm_countintegerTotal alarm events triggered that day
    overspeed_countintegerNumber of overspeed alarm events
    day_start_timetime without time zoneTime of first trip start (Africa/Nairobi)
    day_end_timetime without time zoneTime of last trip end (Africa/Nairobi)
    avg_speed_kmhnumeric(7,2)Fleet average speed across all trips that day
    peak_speed_kmhnumeric(7,2)Highest max_speed_kmh recorded across all trips
    dwh_gold.refresh_daily_metrics(…)function · plpgsql

    Populates or refreshes fact_daily_fleet_metrics for the given date. Call nightly: SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1);

    argumentstarget_date date
    returnsvoid

    public · Extension objects + pgbouncer auth helper.

    1 table(s) · 3 view(s) · 1 function(s) documented.

    public.spatial_ref_systable8,500 rows

    ColumnTypeNullDefaultComment
    sridintegerNOT NULL
    auth_namecharacter varying(256)
    auth_sridinteger
    srtextcharacter varying(2048)
    proj4textcharacter varying(2048)
    public.geography_columnsview

    ColumnTypeNullDefaultComment
    f_table_catalogname
    f_table_schemaname
    f_table_namename
    f_geography_columnname
    coord_dimensioninteger
    sridinteger
    typetext
    public.geometry_columnsview

    ColumnTypeNullDefaultComment
    f_table_catalogcharacter varying(256)
    f_table_schemaname
    f_table_namename
    f_geometry_columnname
    coord_dimensioninteger
    sridinteger
    typecharacter varying(30)
    public.trips_viz_v1view

    ColumnTypeNullDefaultComment
    trip_idbigint
    imeitext
    vehicle_nametext
    vehicle_numbertext
    cost_centretext
    start_timetimestamp with time zone
    end_timetimestamp with time zone
    distance_kmnumeric(12,2)
    avg_speed_kmhnumeric(7,2)
    max_speed_kmhnumeric(7,2)
    vehicle_platetext
    start_addresstext
    end_addresstext
    waypoints_countinteger
    driving_time_sinteger
    idle_time_sinteger
    fuel_consumed_lnumeric(8,2)
    trip_date_eatdate
    daily_seqbigint
    public.user_lookup(…)function · plpgsql

    pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.

    argumentsin_user text, OUT uname text, OUT phash text
    returnsrecord

    6 · Grafana dashboards

    Grafana is provisioned via a baked image and reads TimescaleDB directly (read-only role grafana_ro), mostly through the tracksolid.v_* analytics views documented in §5. Two dashboards ship with the stack.

    NOC Fleet Operations — Live · uid noc-fleet-live · 9 panels

    SectionPanelTypeSource view / table
    Total Vehiclesstattracksolid.devices
    Online Nowstattracksolid.v_fleet_status
    Recent (5-30 min)stattracksolid.v_fleet_status
    Offlinestattracksolid.v_fleet_status
    Moving Nowstattracksolid.v_fleet_status
    Avg Speed (km/h)stattracksolid.v_fleet_status
    Live Vehicle Locationsgeomaptracksolid.devices, tracksolid.live_positions
    Vehicle Statustabletracksolid.devices, tracksolid.live_positions
    Ingestion Healthtabletracksolid.v_ingestion_health

    Daily Operations — Fleet & Dispatch · uid daily-ops · 21 panels

    SectionPanelTypeSource view / table
    Last GPS Fix (fleet)stattracksolid.live_positions
    Vehicles reporting todaystattracksolid.v_fleet_today
    Fleet km todaystattracksolid.v_fleet_today
    Drive hours todaystattracksolid.v_fleet_today
    Idle hours todaystattracksolid.v_fleet_today
    Open alarms (24h)stattracksolid.alarms
    In-flight SLA jobsstattracksolid.v_sla_inflight
    Active Vehicles Mapgeomaptracksolid.v_active_dispatch_map
    Currently Idle (engine on, speed < 2)tabletracksolid.v_currently_idle
    Vehicles Not Moved Todaytabletracksolid.v_vehicles_not_moved_today
    Per-Vehicle Daily Roll-uptabletracksolid.v_fleet_today
    Driver Leaderboardtabletracksolid.v_driver_aggregates_daily
    Fleet Distance — 7-day (by city)timeseriestracksolid.v_fleet_km_daily
    Alarm Frequency — 30-day (by type)timeseriestracksolid.v_alarms_daily
    Idle Cost (month-to-date)stattracksolid.v_utilisation_daily
    Utilisation Heatmap (30-day)heatmaptracksolid.v_utilisation_daily
    Row 7 — Field-Service SLAs (data-gated)Dispatch SLA (median mins, 24h)stattracksolid.v_sla_inflight
    En-route SLA (median mins, 24h)stattracksolid.v_sla_inflight
    On-site SLA (median mins, 24h)stattracksolid.v_sla_inflight
    Resolution SLA (median mins, 24h)stattracksolid.v_sla_inflight
    At-risk ticketstabletracksolid.v_sla_inflight

    SLA panels (v_sla_inflight) and the utilisation heatmap (v_utilisation_daily) are data-gated on the ops ticket integration and nightly dwh_gold ETL respectively.

    7 · Operational notes

    • Hypertables (position_history, heartbeats, fuel_readings, temperature_readings) report 0 in pg_stat_user_tables — counts above use TimescaleDB's approximate_row_count().
    • From f1387d14768cc89b4e19fd419a67ea4ffb4f1691 Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 13:23:10 +0300 Subject: [PATCH 21/31] fix(api): parse form-urlencoded POST body in fleet-dashboard handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Fleet Trips SPA posts application/x-www-form-urlencoded, but the POST /webhook/fleet-dashboard handler read the body with request.json(). That threw on every request, the except swallowed it to body={}, and all filters (vehicle_numbers, cost_centre, assigned_city) plus period/dates were dropped — so every query returned the full unfiltered fleet (1,266 trips) regardless of the dropdowns. The map/KPIs/trips never changed, which read as "the dropdowns don't work." Parse by Content-Type: urllib.parse.parse_qs for form bodies (no new dependency — avoids python-multipart), JSON still accepted defensively for n8n-compat callers. Co-Authored-By: Claude Opus 4.8 --- dashboard_api_rev.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/dashboard_api_rev.py b/dashboard_api_rev.py index 6537e83..92985c4 100644 --- a/dashboard_api_rev.py +++ b/dashboard_api_rev.py @@ -31,9 +31,11 @@ is the base URL (the `N8N_BASE` constant in each dashboard SPA): from __future__ import annotations +import json import os from contextlib import asynccontextmanager from datetime import date, datetime, timedelta, timezone +from urllib.parse import parse_qs import psycopg2.extras from fastapi import FastAPI, Request @@ -202,13 +204,23 @@ def _preset_to_range(period: str | None, start_date, end_date): @app.post("/webhook/fleet-dashboard") async def fleet_trips(request: Request): + # The dashboard SPA posts application/x-www-form-urlencoded (not JSON), so + # parse by content-type. Reading the raw body + parse_qs avoids pulling in + # python-multipart. JSON is still accepted defensively (n8n-compat callers). + body: dict = {} + ctype = request.headers.get("content-type", "").lower() try: - body = await request.json() + raw = await request.body() + if "application/json" in ctype: + parsed = json.loads(raw or b"{}") + body = parsed if isinstance(parsed, dict) else {} + else: + # x-www-form-urlencoded — parse_qs yields lists; keep the last value. + body = {k: v[-1] for k, v in parse_qs(raw.decode("utf-8", "replace")).items()} except Exception: body = {} - if not isinstance(body, dict): - body = {} - body = body.get("body", body) if isinstance(body.get("body"), dict) else body + if isinstance(body.get("body"), dict): + body = body["body"] start, end = _preset_to_range( body.get("period"), body.get("start_date"), body.get("end_date") From 30b351576c51c55480a26df785e25a6c94a67b31 Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 16:25:45 +0300 Subject: [PATCH 22/31] feat(api): self-refresh reporting.v_trips in dashboard_api The Fleet Trips dashboard reads reporting.v_trips (a materialized view). Its refresh was a scheduled n8n workflow; when n8n was retired the matview froze (last refresh 2026-06-01) so the dashboard showed no recent trips even though tracksolid.trips kept ingesting live. Move the refresh into the owned stack: a background loop in dashboard_api runs REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips every VTRIPS_REFRESH_INTERVAL_S (default 300s). Safe across uvicorn --workers via a pg advisory lock (one worker refreshes per tick); runs in a thread so the ~9s refresh never blocks the event loop; logs to reporting.refresh_log (source='dashboard_api') for continuity. Uses a dedicated autocommit connection because REFRESH ... CONCURRENTLY cannot run inside a transaction block. Co-Authored-By: Claude Opus 4.8 --- dashboard_api_rev.py | 71 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/dashboard_api_rev.py b/dashboard_api_rev.py index 92985c4..98530e1 100644 --- a/dashboard_api_rev.py +++ b/dashboard_api_rev.py @@ -31,12 +31,15 @@ is the base URL (the `N8N_BASE` constant in each dashboard SPA): from __future__ import annotations +import asyncio import json import os +import time from contextlib import asynccontextmanager from datetime import date, datetime, timedelta, timezone from urllib.parse import parse_qs +import psycopg2 import psycopg2.extras from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware @@ -57,10 +60,76 @@ _ALLOWED_ORIGINS = [ ] +# ── v_trips materialized-view refresher ───────────────────────────────────── +# The Fleet Trips dashboard reads reporting.v_trips (a materialized view). Its +# refresh used to be a scheduled n8n workflow; when n8n was retired the matview +# went stale (data froze). We now keep it fresh in-process: a background loop +# refreshes it on an interval. A Postgres advisory lock makes this safe across +# uvicorn workers (only one worker refreshes per tick); the work runs in a +# thread so the async event loop never blocks on the ~9s REFRESH. +_DATABASE_URL = os.environ["DATABASE_URL"] +_REFRESH_INTERVAL_S = int(os.getenv("VTRIPS_REFRESH_INTERVAL_S", "300")) +_REFRESH_LOCK_KEY = 920_145 # arbitrary, stable advisory-lock key for this job + + +def _refresh_v_trips_once() -> str: + """Refresh reporting.v_trips. Blocking — call via asyncio.to_thread. + + Uses a dedicated autocommit connection: REFRESH ... CONCURRENTLY cannot run + inside a transaction block (so the pooled get_conn, which wraps a txn, won't + do). DATABASE_URL connects as a superuser, which may REFRESH the matview + even though reporting_refresher owns it. + """ + conn = psycopg2.connect(_DATABASE_URL, connect_timeout=10) + try: + conn.autocommit = True + with conn.cursor() as cur: + cur.execute("SELECT pg_try_advisory_lock(%s)", (_REFRESH_LOCK_KEY,)) + if not cur.fetchone()[0]: + return "skipped (another worker holds the lock)" + try: + t0 = time.monotonic() + cur.execute("REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips") + dur_ms = int((time.monotonic() - t0) * 1000) + cur.execute( + "INSERT INTO reporting.refresh_log" + "(refreshed_at, source, duration_ms, row_count, notes) " + "VALUES (now(), 'dashboard_api', %s," + " (SELECT count(*) FROM reporting.v_trips), 'scheduled')", + (dur_ms,), + ) + return f"refreshed in {dur_ms}ms" + finally: + cur.execute("SELECT pg_advisory_unlock(%s)", (_REFRESH_LOCK_KEY,)) + finally: + conn.close() + + +async def _refresh_loop(): + # Brief startup delay so the first refresh doesn't race container init. + await asyncio.sleep(15) + while True: + try: + result = await asyncio.to_thread(_refresh_v_trips_once) + log.info("v_trips refresh: %s", result) + except Exception: + log.exception("v_trips refresh failed (will retry next interval)") + await asyncio.sleep(_REFRESH_INTERVAL_S) + + @asynccontextmanager async def lifespan(app: FastAPI): - log.info("Dashboard API starting (v1.0). Origins=%s", _ALLOWED_ORIGINS) + log.info( + "Dashboard API starting (v1.1). Origins=%s. v_trips refresh every %ss.", + _ALLOWED_ORIGINS, _REFRESH_INTERVAL_S, + ) + refresher = asyncio.create_task(_refresh_loop()) yield + refresher.cancel() + try: + await refresher + except asyncio.CancelledError: + pass close_pool() From e060933c5549484a66a598341be10111ed58edb7 Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 16:58:20 +0300 Subject: [PATCH 23/31] docs: record fleet-dashboard filter fix + v_trips self-refresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update PLATFORM_OVERVIEW.html (§2 migration, §4 read-API, §5 refresh_log, §7 ops notes) and CLAUDE.md §7 fix history (FIX-D01, FIX-D02) to reflect the two 2026-06-05 fixes that closed out the n8n→fleetapi cutover: form-urlencoded POST body parsing, and moving the reporting.v_trips matview refresh from the retired n8n job into dashboard_api. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 2 ++ docs/PLATFORM_OVERVIEW.html | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 41af6d8..5ad556c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -206,6 +206,8 @@ dwh_control.v_watermark_lag -- Grafana: extract vs. load lag per table | FIX-M19 | `ts_shared_rev.py`, `ingest_movement_rev.py` | Multi-account support: fleet spans `fireside`, `Fireside@HQ`, `Fireside_MSA` (156 devices total). `sync_devices`, `poll_live_positions`, `poll_parking` iterate `TRACKSOLID_TARGETS` (comma-separated env var). New helper `get_active_imeis_by_target()` scopes parking calls to the right account | | FIX-E06 | `ingest_events_rev.py` | Alarm field mapping: `alertTypeId`/`alarmTypeName`/`alertTime` | | BUG-02 | Migration 04 | Historical `distance_m` rows ÷1,000,000 → renamed to `distance_km` | +| FIX-D01 | `dashboard_api_rev.py` | `POST /webhook/fleet-dashboard` read body as JSON, but the SPA posts `x-www-form-urlencoded` → `request.json()` threw, filters silently dropped, map always returned the whole fleet. Now parsed by Content-Type (`parse_qs` for form, JSON still accepted). Commit `f1387d1` | +| FIX-D02 | `dashboard_api_rev.py` | `reporting.v_trips` matview froze on 2026-06-01 when n8n (which ran the scheduled refresh) was retired → dashboard showed "no trips". Added an in-process background refresher (`REFRESH MATERIALIZED VIEW CONCURRENTLY` every `VTRIPS_REFRESH_INTERVAL_S`, default 300s; pg advisory-lock guarded for `--workers`; logs to `reporting.refresh_log` source=`dashboard_api`). Commit `30b3515` | --- diff --git a/docs/PLATFORM_OVERVIEW.html b/docs/PLATFORM_OVERVIEW.html index d2704e6..600e3b4 100644 --- a/docs/PLATFORM_OVERVIEW.html +++ b/docs/PLATFORM_OVERVIEW.html @@ -60,7 +60,12 @@ front-end change per SPA plus the new service.

      Vehicle trail/webhook/live-positions/tracksame path (route alias added) → fn_vehicle_track Fleet trips/webhook/fleet-dashboard (GET+POST)same paths → fn_trips_for_map Transportn8n workflow + credentialsFastAPI + psycopg2 pool (shared with ingestion) -

      3 · Deployment topology

      Host twala.rahamafresh.com (31.97.44.246, Hostinger VPS) running Coolify 4.1. The Tracksolid stack +v_trips refreshn8n scheduled workflowdashboard_api background loop (every 5 min) + +

      Cutover completed 2026-06-05. Two follow-ups closed the last gaps left when n8n was switched off: (1) the POST +body parser was made Content-Type aware so the SPA's form-encoded filters actually apply (f1387d1); (2) the +reporting.v_trips refresh — previously a scheduled n8n workflow — was moved into dashboard_api so the +read layer keeps itself fresh (30b3515). See §4 and §7.

      3 · Deployment topology

      Host twala.rahamafresh.com (31.97.44.246, Hostinger VPS) running Coolify 4.1. The Tracksolid stack is a docker-compose application (container suffix bo3nov2ija7g8wn9b1g2paxs); the reverse proxy is Traefik on the coolify network with Let's Encrypt TLS.

      @@ -78,14 +83,18 @@ is a docker-compose application (container suffix bo3nov2ija7g8wn9b1g2paxs proxy container. The dashboard_api enforces CORS for both SPA origins.

      Operational note. dashboard_api currently runs as a standalone Traefik-labelled container reusing the app image with dashboard_api_rev.py bind-mounted. The durable form is the compose dashboard_api service -(already in docker-compose.yaml) once the branch is merged and the fleetapi domain is set in Coolify.

      4 · Read-API reference (dashboard_api)

      Base: https://fleetapi.rahamafresh.com · all responses JSON · CORS limited to the two SPA origins.

      ServiceRolePort / domain
      MethodPathParamsReturnsNotes
      GET/health{status: ok}Liveness probe.
      GET/webhook/live-positionscost_centre?, acc_status?{summary, geojson}Live Positions map feed → reporting.fn_live_positions. ~80 vehicle point features.
      GET/webhook/live-positions/trackvehicle_number, hours(1-24)GeoJSON Feature (LineString)One vehicle's recent trail. Alias: /webhook/vehicle-track.
      GET/webhook/vehicle-trackvehicle_number, hoursGeoJSON FeatureAlias of live-positions/track (kept for compatibility).
      GET/webhook/fleet-dashboard{drivers, cost_centres, cities, vehicles}Filter options for the Fleet Intelligence UI.
      POST/webhook/fleet-dashboardJSON: period|start_date|end_date, vehicle_numbers, driver, cost_centre, assigned_citytrips GeoJSON payloadTrips for the map → reporting.fn_trips_for_map. period preset: today|7d|30d|custom.

      5 · Database schema

      tracksolid · Live data — the single source of truth. Ingested from the Tracksolid API.

      18 table(s) · 17 view(s) · 1 function(s) documented.

      tracksolid.alarmstable344,356 rows

      Alarm events (alarm_type, alarm_name, alarm_time).

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('alarms_id_seq'::regclass)
      imeitext
      alarm_typetext
      alarm_timetimestamp with time zone
      geomgeometry(Point,4326)
      latdouble precision
      lngdouble precision
      speednumeric(7,2)
      acc_statustext
      updated_attimestamp with time zonenow()
      alarm_nametext
      sourcetext'poll'::text
      severitytextAlarm severity level: critical | warning | info
      geofence_idtextTracksolid geofence ID if this is a geofence alarm
      geofence_nametextHuman-readable geofence name
      acknowledged_attimestamp with time zoneTimestamp when alarm was acknowledged by an operator
      acknowledged_bytextUsername or ID of operator who acknowledged the alarm
      tracksolid.api_token_cachetable1 rows

      OAuth2 token cache for the Jimi/Tracksolid API.

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('api_token_cache_id_seq'::regclass)
      accounttextNOT NULL
      access_tokentextNOT NULL
      refresh_tokentext
      app_keytext
      expires_attimestamp with time zoneNOT NULL
      obtained_attimestamp with time zoneNOT NULLnow()
      updated_attimestamp with time zoneNOT NULLnow()
      tracksolid.device_eventstable0 rows

      Device network connection and disconnection events from /pushevent webhook.

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('device_events_id_seq'::regclass)
      imeitextNOT NULL
      event_typetextNOT NULLLOGIN = device connected to network; LOGOUT = device disconnected
      event_timetimestamp with time zoneNOT NULL
      timezonetext
      created_attimestamp with time zoneNOT NULLnow()
      tracksolid.devicestable181 rows

      Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.

      ColumnTypeNullDefaultComment
      imeitextNOT NULL
      device_nametext
      mc_typetext
      mc_type_use_scopetext
      vehicle_nametext
      vehicle_numbertext
      vehicle_modelstext
      vehicle_icontext
      vintext
      engine_numbertext
      vehicle_brandtext
      fuel_100kmnumeric(6,2)
      driver_nametext
      driver_phonetext
      simtext
      iccidtext
      imsitext
      accounttext
      customer_nametext
      device_group_idtext
      device_grouptext
      activation_timetimestamp with time zone
      expirationtimestamp with time zone
      enabled_flagsmallintNOT NULL1
      statustext'active'::text
      citytext
      current_mileage_kmnumeric(12,2)
      created_attimestamp with time zoneNOT NULLnow()
      updated_attimestamp with time zoneNOT NULLnow()
      last_synced_attimestamp with time zone
      vehicle_categorytextVehicle type: truck | van | motorcycle | car | other
      cost_centretextBusiness unit or department this vehicle belongs to
      assigned_routetextRegular route name or ID for route-based reporting
      depot_geomgeometry(Point,4326)Home base/depot coordinates (WGS84)
      depot_addresstextHuman-readable depot address
      assigned_citytextOperating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection.
      tracksolid.dispatch_logtable0 rows

      Persistent record of every dispatch decision. Powers SLA metrics: dispatch latency, depart delay, time-to-site, wrench time.

      ColumnTypeNullDefaultComment
      dispatch_idbigintNOT NULLnextval('dispatch_log_dispatch_id_seq'::regclass)
      ticket_idtextNOT NULL
      imeitextNOT NULL
      driver_nametext
      job_latdouble precisionNOT NULL
      job_lngdouble precisionNOT NULL
      job_geomgeometry(Point,4326)
      assigned_attimestamp with time zoneNOT NULLnow()
      first_movement_attimestamp with time zoneFirst trip start after assigned_at. Back-filled nightly from trips.
      on_site_attimestamp with time zoneTime vehicle entered 150 m radius of job_geom. Back-filled nightly.
      resolved_attimestamp with time zoneTicket close time from the ops system (ops.tickets.closed_at).
      cancelled_attimestamp with time zone
      distance_kmnumeric(8,2)
      created_attimestamp with time zoneNOT NULLnow()
      tracksolid.fault_codestable0 rows

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('fault_codes_id_seq'::regclass)
      imeitextNOT NULL
      reported_attimestamp with time zoneNOT NULL
      fault_codetextNOT NULL
      status_flagsinteger
      latdouble precision
      lngdouble precision
      geomgeometry(Point,4326)
      event_timetimestamp with time zone
      created_attimestamp with time zoneNOT NULLnow()
      tracksolid.fuel_readingshypertable~0 rows

      Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.

      ColumnTypeNullDefaultComment
      imeitextNOT NULL
      reading_timetimestamp with time zoneNOT NULL
      sensor_pathtextSensor channel identifier from the device (path field in API payload)
      valuenumeric(10,3)
      unittextMeasurement unit: cm (tank depth), % (percentage), V (voltage), L (litres)
      latdouble precision
      lngdouble precision
      geomgeometry(Point,4326)
      created_attimestamp with time zoneNOT NULLnow()
      tracksolid.geofencestable0 rows

      Geofence boundary definitions synced from the Tracksolid platform.

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('geofences_id_seq'::regclass)
      fence_idtext
      fence_nametextNOT NULL
      fence_typetextcircle | polygon
      geomgeometry(Geometry,4326)
      radius_mnumeric(10,2)Radius in metres — only applicable for circle type geofences
      descriptiontext
      created_attimestamp with time zoneNOT NULLnow()
      updated_attimestamp with time zoneNOT NULLnow()
      tracksolid.heartbeatshypertable~0 rows

      Device heartbeat hypertable.

      ColumnTypeNullDefaultComment
      imeitextNOT NULL
      gate_timetimestamp with time zoneNOT NULL
      power_levelsmallint
      gsm_signalsmallint
      acc_statussmallint
      power_statussmallint
      fortifysmallint
      created_attimestamp with time zoneNOT NULLnow()
      tracksolid.ingestion_logtable274,181 rows

      API call audit trail — one row per ingestion run.

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('ingestion_log_id_seq'::regclass)
      run_attimestamp with time zoneNOT NULLnow()
      endpointtextNOT NULL
      imei_countintegerNOT NULL0
      rows_upsertedintegerNOT NULL0
      rows_insertedintegerNOT NULL0
      duration_msintegerNOT NULL0
      successbooleanNOT NULLtrue
      error_codetext
      error_messagetext
      tracksolid.lbs_readingstable0 rows

      Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('lbs_readings_id_seq'::regclass)
      imeitextNOT NULL
      gate_timetimestamp with time zoneNOT NULL
      post_typetextPositioning technology: WIFI | LBS (cell tower)
      lbs_datajsonbRaw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding.
      created_attimestamp with time zoneNOT NULLnow()
      tracksolid.live_positionstable179 rows

      Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.

      ColumnTypeNullDefaultComment
      imeitextNOT NULL
      geomgeometry(Point,4326)
      latdouble precision
      lngdouble precision
      pos_typetext
      confidencesmallint
      gps_timetimestamp with time zone
      hb_timetimestamp with time zone
      speednumeric(7,2)
      directionnumeric(6,2)
      acc_statustext
      gps_signalsmallint
      gps_numsmallint
      elec_quantitynumeric(5,2)
      power_valuenumeric(5,2)
      battery_power_valnumeric(5,2)
      tracker_oiltext
      temperaturenumeric(8,2)
      current_mileagenumeric(12,2)
      device_statustext
      expire_flagtext
      activation_flagtext
      loc_desctext
      recorded_attimestamp with time zoneNOT NULLnow()
      updated_attimestamp with time zoneNOT NULLnow()
      tracksolid.obd_readingstable0 rows

      OBD diagnostics — push only via /pushobd webhook.

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('obd_readings_id_seq'::regclass)
      imeitext
      reading_timetimestamp with time zone
      engine_rpmintegerEngine RPM from OBD PID 0x0C
      fuel_level_pctnumeric(5,2)Fuel tank level % from OBD PID 0x2F
      updated_attimestamp with time zonenow()
      car_typesmallint
      acc_statesmallint
      status_flagsinteger
      latdouble precision
      lngdouble precision
      geomgeometry(Point,4326)
      obd_datajsonbRaw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.)
      coolant_temp_cnumeric(6,2)Coolant temperature °C from OBD PID 0x05
      battery_voltagenumeric(5,2)Battery voltage (V) from OBD PID 0x42
      intake_pressurenumeric(6,2)Intake manifold pressure kPa from OBD PID 0x0B
      throttle_pctnumeric(5,2)Throttle position % from OBD PID 0x11
      vehicle_speednumeric(7,2)Vehicle speed km/h from OBD PID 0x0D
      engine_load_pctnumeric(5,2)Calculated engine load % from OBD PID 0x04
      tracksolid.parking_eventstable0 rows

      Stop events with duration + address.

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('parking_events_id_seq'::regclass)
      imeitextNOT NULL
      event_typetext
      start_timetimestamp with time zoneNOT NULL
      end_timetimestamp with time zone
      duration_secondsinteger
      geomgeometry(Point,4326)
      addresstext
      updated_attimestamp with time zonenow()
      tracksolid.position_historyhypertable~3,596,013 rows

      All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).

      ColumnTypeNullDefaultComment
      imeitextNOT NULL
      gps_timetimestamp with time zoneNOT NULL
      geomgeometry(Point,4326)
      latdouble precision
      lngdouble precision
      speednumeric(7,2)
      directionnumeric(6,2)
      acc_statustext
      satellitesmallint
      current_mileagenumeric(12,2)
      recorded_attimestamp with time zonenow()
      altitudenumeric(8,2)
      post_typesmallint
      sourcetext'poll'::text
      tracksolid.schema_migrationstable9 rows

      ColumnTypeNullDefaultComment
      filenametextNOT NULL
      applied_attimestamp with time zoneNOT NULLnow()
      tracksolid.temperature_readingshypertable~0 rows

      Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.

      ColumnTypeNullDefaultComment
      imeitextNOT NULL
      reading_timetimestamp with time zoneNOT NULL
      temperaturenumeric(6,2)
      humidity_pctnumeric(5,2)
      created_attimestamp with time zoneNOT NULLnow()
      tracksolid.tripstable43,765 rows

      Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).

      ColumnTypeNullDefaultComment
      idbigintNOT NULLnextval('trips_id_seq'::regclass)
      imeitextNOT NULL
      start_timetimestamp with time zoneNOT NULL
      end_timetimestamp with time zone
      start_geomgeometry(Point,4326)
      end_geomgeometry(Point,4326)
      distance_kmnumeric(12,2)Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10).
      avg_speed_kmhnumeric(7,2)
      max_speed_kmhnumeric(7,2)
      updated_attimestamp with time zonenow()
      fuel_consumed_lnumeric(8,2)
      idle_time_sinteger
      driving_time_sintegerrunTimeSecond from API: total driving time in seconds
      trip_seqinteger
      sourcetext'poll'::textpoll = from API polling, push = from webhook push
      route_geomgeometry(LineString,4326)Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window.
      start_addresstextReverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
      end_addresstextReverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
      vehicle_platetextDenormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest.
      waypoints_countintegerNumber of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate.
      tracksolid.v_active_dispatch_mapview

      01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.

      ColumnTypeNullDefaultComment
      imeitext
      vehicle_numbertext
      vehicle_nametext
      driver_nametext
      driver_phonetext
      assigned_citytext
      latdouble precision
      lngdouble precision
      speednumeric(7,2)
      directionnumeric(6,2)
      acc_statustext
      last_fixtimestamp without time zone
      statustext
      tracksolid.v_alarms_dailyview

      01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.

      ColumnTypeNullDefaultComment
      daydate
      alarm_nametext
      alarm_countbigint
      tracksolid.v_currently_idleview

      01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.

      ColumnTypeNullDefaultComment
      imeitext
      vehicle_numbertext
      driver_nametext
      assigned_citytext
      latdouble precision
      lngdouble precision
      sincetimestamp without time zone
      idle_secondsinteger
      tracksolid.v_driver_aggregates_dailyview

      01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).

      ColumnTypeNullDefaultComment
      imeitext
      driver_nametext
      vehicle_numbertext
      assigned_citytext
      daydate
      kmnumeric
      tripsbigint
      events_80bigint
      events_100bigint
      events_120bigint
      harsh_eventsbigint
      speeding_per_100kmnumeric
      harsh_per_100kmnumeric
      tracksolid.v_driver_attendance_dailyview

      ColumnTypeNullDefaultComment
      report_datedate
      driver_nametext
      vehicle_numbertext
      cost_centretext
      assigned_citytext
      reporting_timetime without time zone
      start_addresstext
      start_latdouble precision
      start_lngdouble precision
      statustext
      mins_from_startinteger
      tracksolid.v_driver_clock_dailyview

      Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).

      ColumnTypeNullDefaultComment
      imeitext
      driver_nametext
      vehicle_numbertext
      cost_centretext
      assigned_citytext
      report_datedate
      reporting_timetime without time zone
      closing_timetime without time zone
      reporting_tstimestamp with time zone
      closing_tstimestamp with time zone
      start_latdouble precision
      start_lngdouble precision
      start_addresstext
      end_latdouble precision
      end_lngdouble precision
      end_addresstext
      trips_countbigint
      total_kmnumeric
      drive_hoursnumeric
      tracksolid.v_driver_clock_todayview

      Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

      ColumnTypeNullDefaultComment
      imeitext
      driver_nametext
      vehicle_numbertext
      cost_centretext
      assigned_citytext
      report_datedate
      reporting_timetime without time zone
      closing_timetime without time zone
      reporting_tstimestamp with time zone
      closing_tstimestamp with time zone
      start_latdouble precision
      start_lngdouble precision
      start_addresstext
      end_latdouble precision
      end_lngdouble precision
      end_addresstext
      trips_countbigint
      total_kmnumeric
      drive_hoursnumeric
      tracksolid.v_fleet_km_dailyview

      01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.

      ColumnTypeNullDefaultComment
      daydate
      assigned_citytext
      kmnumeric
      active_vehiclesbigint
      tripsbigint
      tracksolid.v_fleet_statusview

      ColumnTypeNullDefaultComment
      imeitext
      vehicle_numbertext
      driver_nametext
      latdouble precision
      lngdouble precision
      geomgeometry(Point,4326)
      speednumeric(7,2)
      acc_statustext
      gps_timetimestamp with time zone
      connectivity_statustext
      seconds_since_fixinteger
      tracksolid.v_fleet_todayview

      01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.

      ColumnTypeNullDefaultComment
      imeitext
      driver_nametext
      vehicle_numbertext
      vehicle_nametext
      assigned_citytext
      enabled_flagsmallint
      km_todaynumeric
      trips_todaybigint
      drive_hoursnumeric
      idle_hoursnumeric
      first_departuretime without time zone
      last_returntime without time zone
      alarms_todaybigint
      last_fixtimestamp without time zone
      last_speednumeric(7,2)
      did_not_moveboolean
      tracksolid.v_fleet_traceview

      ColumnTypeNullDefaultComment
      gidbigint
      driver_nametext
      vehicle_nametext
      device_nametext
      imeitext
      geomgeometry(Point,4326)
      latnumeric
      lngnumeric
      start_timetimestamp without time zone
      end_timetimestamp without time zone
      day_localdate
      hour_localinteger
      dow_localinteger
      gps_time_utctimestamp with time zone
      recorded_attimestamp with time zone
      speednumeric(7,2)
      directionnumeric(6,2)
      current_mileagenumeric(12,2)
      stationaryboolean
      trip_idbigint
      tracksolid.v_ingestion_healthview

      ColumnTypeNullDefaultComment
      endpointtext
      run_attimestamp with time zone
      successboolean
      error_messagetext
      seconds_agointeger
      tracksolid.v_mileage_daily_caggview

      ColumnTypeNullDefaultComment
      buckettimestamp with time zone
      imeitext
      dist_kmnumeric
      avg_speednumeric
      tracksolid.v_sla_inflightview

      01_BusinessAnalytics.md §4.5 Field-Service SLA Metrics. Open tickets + last 24h resolved.

      ColumnTypeNullDefaultComment
      ticket_idtext
      customertext
      prioritytext
      job_typetext
      statustext
      created_attimestamp with time zone
      assigned_attimestamp with time zone
      closed_attimestamp with time zone
      assigned_imeitext
      driver_nametext
      first_movement_attimestamp with time zone
      on_site_attimestamp with time zone
      resolved_attimestamp with time zone
      dispatch_minsnumeric
      enroute_minsnumeric
      onsite_minsnumeric
      resolution_minsnumeric
      ticket_stagetext
      tracksolid.v_trips_enrichedview

      tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.

      ColumnTypeNullDefaultComment
      idbigint
      imeitext
      start_timetimestamp with time zone
      end_timetimestamp with time zone
      start_geomgeometry(Point,4326)
      end_geomgeometry(Point,4326)
      distance_kmnumeric(12,2)
      avg_speed_kmhnumeric(7,2)
      max_speed_kmhnumeric(7,2)
      updated_attimestamp with time zone
      fuel_consumed_lnumeric(8,2)
      idle_time_sinteger
      driving_time_sinteger
      trip_seqinteger
      sourcetext
      route_geomgeometry(LineString,4326)
      start_addresstext
      end_addresstext
      vehicle_platetext
      waypoints_countinteger
      trip_date_eatdate
      daily_seqbigint
      tracksolid.v_utilisation_dailyview

      01_BusinessAnalytics.md §7 Panel 8 Utilisation Heatmap. Empty until nightly ETL runs.

      ColumnTypeNullDefaultComment
      daydate
      imeitext
      vehicle_numbertext
      driver_nametext
      assigned_citytext
      total_distance_kmnumeric(12,2)
      total_drive_hoursnumeric(8,2)
      total_idle_hoursnumeric(8,2)
      alarm_countinteger
      overspeed_countinteger
      utilisation_pctnumeric
      tracksolid.v_vehicles_not_moved_todayview

      01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.

      ColumnTypeNullDefaultComment
      imeitext
      vehicle_nametext
      vehicle_numbertext
      driver_nametext
      assigned_citytext
      last_seentimestamp without time zone
      speednumeric(7,2)
      tracksolid.set_updated_at(…)function · plpgsql

      arguments()
      returnstrigger

      reporting · Read layer that backs the map dashboards (consumed by dashboard_api).

      2 table(s) · 12 view(s) · 4 function(s) documented.

      reporting.refresh_logtable3,558 rows

      One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. n8n inserts; read MAX(refreshed_at) for staleness check.

      ColumnTypeNullDefaultComment
      refreshed_attimestamp with time zoneNOT NULLnow()
      sourcetextNOT NULL'n8n'::text
      duration_msinteger
      row_countinteger
      notestext
      reporting.v_tripsmatview31,670 rows

      Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.

      ColumnTypeNullDefaultComment
      trip_idbigint
      imeitext
      device_nametext
      vehicle_numbertext
      vehicle_modelstext
      vehicle_categorytext
      cost_centretext
      assigned_citytext
      assigned_drivertext
      start_timetimestamp without time zone
      end_timetimestamp without time zone
      trip_datedate
      start_hourinteger
      start_dowinteger
      daily_seqbigint
      distance_kmnumeric(12,2)
      avg_speed_kmhnumeric(7,2)
      max_speed_kmhnumeric(7,2)
      idle_time_sinteger
      driving_time_sinteger
      fuel_consumed_lnumeric(8,2)
      waypoints_countinteger
      start_addresstext
      end_addresstext
      start_geomgeometry(Point,4326)
      end_geomgeometry(Point,4326)
      route_geomgeometry(LineString,4326)
      route_geojsonjson
      is_meaningful_routeboolean
      updated_attimestamp without time zone
      reporting.v_daily_cost_centreview

      Cost-centre × day rollup. Excludes trips with NULL cost_centre.

      ColumnTypeNullDefaultComment
      trip_datedate
      cost_centretext
      active_vehiclesbigint
      active_driversbigint
      trip_countbigint
      total_kmnumeric
      driving_hoursnumeric
      idle_hoursnumeric
      idle_pctnumeric
      km_per_vehiclenumeric
      reporting.v_daily_summaryview

      Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.

      ColumnTypeNullDefaultComment
      trip_datedate
      cost_centretext
      assigned_citytext
      vehicle_numbertext
      assigned_drivertext
      trip_countbigint
      total_kmnumeric
      driving_hoursnumeric
      idle_hoursnumeric
      idle_pctnumeric
      first_trip_starttimestamp without time zone
      last_trip_endtimestamp without time zone
      avg_speed_kmhnumeric
      max_speed_kmhnumeric
      day_routes_geojsonjson
      reporting.v_filter_citiesview

      Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.

      ColumnTypeNullDefaultComment
      assigned_citytext
      reporting.v_filter_cost_centresview

      Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.

      ColumnTypeNullDefaultComment
      cost_centretext
      reporting.v_filter_driversview

      Driver dropdown source for the n8n dashboard. Distinct non-null drivers.

      ColumnTypeNullDefaultComment
      drivertext
      reporting.v_filter_vehiclesview

      Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.

      ColumnTypeNullDefaultComment
      vehicle_numbertext
      driverstext
      cost_centretext
      assigned_citytext
      reporting.v_live_positionsview

      Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.

      ColumnTypeNullDefaultComment
      imeitext
      vehicle_numbertext
      assigned_drivertext
      cost_centretext
      assigned_citytext
      vehicle_categorytext
      vehicle_modelstext
      mc_typetext
      device_kindtext
      latdouble precision
      lngdouble precision
      speednumeric(7,2)
      directionnumeric(6,2)
      acc_statustext
      device_statustext
      gps_signalsmallint
      gps_numsmallint
      current_mileagenumeric(12,2)
      loc_desctext
      gps_timetimestamp with time zone
      updated_attimestamp with time zone
      gps_time_eattimestamp without time zone
      updated_at_eattimestamp without time zone
      source_age_hoursnumeric
      reporting.v_monthly_cost_centreview

      Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.

      ColumnTypeNullDefaultComment
      month_startdate
      month_labeltext
      cost_centretext
      active_vehiclesbigint
      active_driversbigint
      active_daysbigint
      trip_countbigint
      total_kmnumeric
      driving_hoursnumeric
      idle_hoursnumeric
      idle_pctnumeric
      km_per_vehiclenumeric
      reporting.v_monthly_summaryview

      Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).

      ColumnTypeNullDefaultComment
      month_startdate
      month_labeltext
      cost_centretext
      assigned_citytext
      vehicle_categorytext
      vehicle_numbertext
      assigned_drivertext
      trip_countbigint
      active_daysbigint
      total_kmnumeric
      driving_hoursnumeric
      idle_hoursnumeric
      idle_pctnumeric
      km_per_active_daynumeric
      km_per_tripnumeric
      avg_speed_kmhnumeric
      peak_speed_kmhnumeric
      reporting.v_trips_todayview

      Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

      ColumnTypeNullDefaultComment
      trip_idbigint
      imeitext
      device_nametext
      vehicle_numbertext
      vehicle_modelstext
      vehicle_categorytext
      cost_centretext
      assigned_citytext
      assigned_drivertext
      start_timetimestamp without time zone
      end_timetimestamp without time zone
      trip_datedate
      start_hourinteger
      start_dowinteger
      daily_seqbigint
      distance_kmnumeric(12,2)
      avg_speed_kmhnumeric(7,2)
      max_speed_kmhnumeric(7,2)
      idle_time_sinteger
      driving_time_sinteger
      fuel_consumed_lnumeric(8,2)
      waypoints_countinteger
      start_addresstext
      end_addresstext
      start_geomgeometry(Point,4326)
      end_geomgeometry(Point,4326)
      route_geomgeometry(LineString,4326)
      route_geojsonjson
      is_meaningful_routeboolean
      updated_attimestamp without time zone
      reporting.v_weekly_cost_centreview

      Cost-centre × week rollup. Excludes trips with NULL cost_centre.

      ColumnTypeNullDefaultComment
      week_startdate
      cost_centretext
      active_vehiclesbigint
      active_driversbigint
      active_daysbigint
      trip_countbigint
      total_kmnumeric
      driving_hoursnumeric
      idle_hoursnumeric
      idle_pctnumeric
      km_per_vehiclenumeric
      reporting.v_weekly_summaryview

      Vehicle × week rollup. Numeric only, no geometry.

      ColumnTypeNullDefaultComment
      week_startdate
      cost_centretext
      assigned_citytext
      vehicle_numbertext
      assigned_drivertext
      trip_countbigint
      active_daysbigint
      total_kmnumeric
      driving_hoursnumeric
      idle_hoursnumeric
      avg_trip_kmnumeric
      reporting.fn_live_positions(…)function · plpgsql

      Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.

      argumentsp_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text
      returnsjsonb
      reporting.fn_trips_for_map(…)function · plpgsql

      Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.

      argumentsp_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date
      returnsjsonb
      reporting.fn_vehicle_track(…)function · sql

      Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.

      argumentsp_vehicle_number text, p_hours integer DEFAULT 1
      returnsjsonb
      reporting.normalize_plate(…)function · sql

      Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.

      argumentsp text
      returnstext

      ops · Workshop / tickets / odometer integrations.

      5 table(s) · 1 view(s) · 0 function(s) documented.

      ops.cost_ratestable3 rows

      Reference rates for analytics monetisation: fuel price per litre by city, labour cost per hour by role. Resolution order in views: scope_type=city > scope_type=role > scope_type=global.

      ColumnTypeNullDefaultComment
      rate_keytextNOT NULL
      scope_typetextNOT NULLcity | role | global
      scope_valuetext
      metrictextNOT NULLfuel_per_litre | labour_per_hour
      amountnumeric(12,2)NOT NULL
      currencytextNOT NULL
      effective_fromdateNOT NULLCURRENT_DATE
      notestext
      created_attimestamp with time zoneNOT NULLnow()
      updated_attimestamp with time zoneNOT NULLnow()
      ops.kpi_targetstable12 rows

      Traffic-light targets per KPI per scope. Resolution order in views: cost_centre > vehicle_category > city > global.

      ColumnTypeNullDefaultComment
      target_idbigintNOT NULLnextval('ops.kpi_targets_target_id_seq'::regclass)
      kpi_keytextNOT NULL
      scope_typetextNOT NULL
      scope_valuetext
      target_valuenumeric(12,2)NOT NULL
      amber_thresholdnumeric(12,2)
      red_thresholdnumeric(12,2)
      directiontextNOT NULL'higher_is_better'::texthigher_is_better -> green when value >= target. lower_is_better -> green when value <= target.
      effective_fromdateNOT NULLCURRENT_DATE
      notestext
      created_attimestamp with time zoneNOT NULLnow()
      updated_attimestamp with time zoneNOT NULLnow()
      ops.odometer_readingstable0 rows

      Physical odometer captures from service, fuel card, or manual entry. Powers §3.8 Odometer Divergence audit.

      ColumnTypeNullDefaultComment
      reading_idbigintNOT NULLnextval('ops.odometer_readings_reading_id_seq'::regclass)
      imeitextNOT NULL
      reading_datedateNOT NULL
      reading_kmintegerNOT NULL
      sourcetextservice | fuel_card | driver_manual | workshop_form
      recorded_bytext
      created_attimestamp with time zoneNOT NULLnow()
      ops.service_logtable0 rows

      Workshop service history. Powers §10 Service-Interval Forecaster.

      ColumnTypeNullDefaultComment
      service_idbigintNOT NULLnextval('ops.service_log_service_id_seq'::regclass)
      imeitextNOT NULL
      service_datedateNOT NULL
      odometer_kmintegerNOT NULLPhysical odometer reading at service time (integer km).
      service_typetextscheduled | repair | tyre | bodywork | inspection | other
      cost_kesinteger
      notestext
      created_attimestamp with time zoneNOT NULLnow()
      ops.ticketstable0 rows

      Skeleton for ticket data sourced from the Fireside ops system. Replace or extend to match the actual feed (Zoho Desk, Freshdesk, etc).

      ColumnTypeNullDefaultComment
      ticket_idtextNOT NULL
      assigned_imeitext
      driver_nametext
      customertext
      job_typetext
      prioritytext
      statustextNOT NULL'open'::textopen | assigned | in_progress | resolved | cancelled
      created_attimestamp with time zoneNOT NULL
      assigned_attimestamp with time zone
      closed_attimestamp with time zone
      job_latdouble precision
      job_lngdouble precision
      job_geomgeometry(Point,4326)
      ingested_attimestamp with time zoneNOT NULLnow()
      ops.vw_service_forecastview

      Projected next-service date per vehicle based on 30-day km rate. Service interval default 10,000 km — override at query time if needed.

      ColumnTypeNullDefaultComment
      imeitext
      driver_nametext
      vehicle_numbertext
      last_service_datedate
      last_service_odointeger
      current_odonumeric(12,2)
      km_since_servicenumeric
      km_to_next_servicenumeric
      km_per_day_30dnumeric
      projected_service_datedate

      dwh_gold · Nightly ETL aggregates.

      2 table(s) · 0 view(s) · 1 function(s) documented.

      dwh_gold.dim_vehiclestable0 rows

      ColumnTypeNullDefaultComment
      vehicle_keyintegerNOT NULLnextval('dim_vehicles_vehicle_key_seq'::regclass)
      imeitext
      vehicle_numbertext
      is_activebooleantrue
      dwh_gold.fact_daily_fleet_metricstable0 rows

      ColumnTypeNullDefaultComment
      daydateNOT NULL
      vehicle_keyintegerNOT NULL
      total_distance_kmnumeric(12,2)Total km driven that day across all trips
      max_speed_kmhnumeric(7,2)
      idle_hoursnumeric(5,2)
      total_tripsintegerNumber of completed trips
      total_drive_hoursnumeric(8,2)Total hours of active driving (engine on + moving)
      total_idle_hoursnumeric(8,2)Total hours engine on but stationary
      fuel_consumed_lnumeric(10,3)Total fuel consumed in litres (from webhook trip reports)
      alarm_countintegerTotal alarm events triggered that day
      overspeed_countintegerNumber of overspeed alarm events
      day_start_timetime without time zoneTime of first trip start (Africa/Nairobi)
      day_end_timetime without time zoneTime of last trip end (Africa/Nairobi)
      avg_speed_kmhnumeric(7,2)Fleet average speed across all trips that day
      peak_speed_kmhnumeric(7,2)Highest max_speed_kmh recorded across all trips
      dwh_gold.refresh_daily_metrics(…)function · plpgsql

      Populates or refreshes fact_daily_fleet_metrics for the given date. Call nightly: SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1);

      argumentstarget_date date
      returnsvoid

      public · Extension objects + pgbouncer auth helper.

      1 table(s) · 3 view(s) · 1 function(s) documented.

      public.spatial_ref_systable8,500 rows

      ColumnTypeNullDefaultComment
      sridintegerNOT NULL
      auth_namecharacter varying(256)
      auth_sridinteger
      srtextcharacter varying(2048)
      proj4textcharacter varying(2048)
      public.geography_columnsview

      ColumnTypeNullDefaultComment
      f_table_catalogname
      f_table_schemaname
      f_table_namename
      f_geography_columnname
      coord_dimensioninteger
      sridinteger
      typetext
      public.geometry_columnsview

      ColumnTypeNullDefaultComment
      f_table_catalogcharacter varying(256)
      f_table_schemaname
      f_table_namename
      f_geometry_columnname
      coord_dimensioninteger
      sridinteger
      typecharacter varying(30)
      public.trips_viz_v1view

      ColumnTypeNullDefaultComment
      trip_idbigint
      imeitext
      vehicle_nametext
      vehicle_numbertext
      cost_centretext
      start_timetimestamp with time zone
      end_timetimestamp with time zone
      distance_kmnumeric(12,2)
      avg_speed_kmhnumeric(7,2)
      max_speed_kmhnumeric(7,2)
      vehicle_platetext
      start_addresstext
      end_addresstext
      waypoints_countinteger
      driving_time_sinteger
      idle_time_sinteger
      fuel_consumed_lnumeric(8,2)
      trip_date_eatdate
      daily_seqbigint
      public.user_lookup(…)function · plpgsql

      pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.

      argumentsin_user text, OUT uname text, OUT phash text
      returnsrecord

      6 · Grafana dashboards

      Grafana is provisioned via a baked image and reads TimescaleDB directly (read-only role grafana_ro), mostly through the tracksolid.v_* analytics views documented in §5. Two dashboards ship with the stack.

      NOC Fleet Operations — Live · uid noc-fleet-live · 9 panels

      SectionPanelTypeSource view / table
      Total Vehiclesstattracksolid.devices
      Online Nowstattracksolid.v_fleet_status
      Recent (5-30 min)stattracksolid.v_fleet_status
      Offlinestattracksolid.v_fleet_status
      Moving Nowstattracksolid.v_fleet_status
      Avg Speed (km/h)stattracksolid.v_fleet_status
      Live Vehicle Locationsgeomaptracksolid.devices, tracksolid.live_positions
      Vehicle Statustabletracksolid.devices, tracksolid.live_positions
      Ingestion Healthtabletracksolid.v_ingestion_health

      Daily Operations — Fleet & Dispatch · uid daily-ops · 21 panels

      SectionPanelTypeSource view / table
      Last GPS Fix (fleet)stattracksolid.live_positions
      Vehicles reporting todaystattracksolid.v_fleet_today
      Fleet km todaystattracksolid.v_fleet_today
      Drive hours todaystattracksolid.v_fleet_today
      Idle hours todaystattracksolid.v_fleet_today
      Open alarms (24h)stattracksolid.alarms
      In-flight SLA jobsstattracksolid.v_sla_inflight
      Active Vehicles Mapgeomaptracksolid.v_active_dispatch_map
      Currently Idle (engine on, speed < 2)tabletracksolid.v_currently_idle
      Vehicles Not Moved Todaytabletracksolid.v_vehicles_not_moved_today
      Per-Vehicle Daily Roll-uptabletracksolid.v_fleet_today
      Driver Leaderboardtabletracksolid.v_driver_aggregates_daily
      Fleet Distance — 7-day (by city)timeseriestracksolid.v_fleet_km_daily
      Alarm Frequency — 30-day (by type)timeseriestracksolid.v_alarms_daily
      Idle Cost (month-to-date)stattracksolid.v_utilisation_daily
      Utilisation Heatmap (30-day)heatmaptracksolid.v_utilisation_daily
      Row 7 — Field-Service SLAs (data-gated)Dispatch SLA (median mins, 24h)stattracksolid.v_sla_inflight
      En-route SLA (median mins, 24h)stattracksolid.v_sla_inflight
      On-site SLA (median mins, 24h)stattracksolid.v_sla_inflight
      Resolution SLA (median mins, 24h)stattracksolid.v_sla_inflight
      At-risk ticketstabletracksolid.v_sla_inflight

      SLA panels (v_sla_inflight) and the utilisation heatmap (v_utilisation_daily) are data-gated on the ops ticket integration and nightly dwh_gold ETL respectively.

      7 · Operational notes

        +(already in docker-compose.yaml) once the branch is merged and the fleetapi domain is set in Coolify.

        4 · Read-API reference (dashboard_api)

        Base: https://fleetapi.rahamafresh.com · all responses JSON · CORS limited to the two SPA origins.

        MethodPathParamsReturnsNotes
        GET/health{status: ok}Liveness probe.
        GET/webhook/live-positionscost_centre?, acc_status?{summary, geojson}Live Positions map feed → reporting.fn_live_positions. ~80 vehicle point features.
        GET/webhook/live-positions/trackvehicle_number, hours(1-24)GeoJSON Feature (LineString)One vehicle's recent trail. Alias: /webhook/vehicle-track.
        GET/webhook/vehicle-trackvehicle_number, hoursGeoJSON FeatureAlias of live-positions/track (kept for compatibility).
        GET/webhook/fleet-dashboard{drivers, cost_centres, cities, vehicles}Filter options for the Fleet Intelligence UI.
        POST/webhook/fleet-dashboardform-urlencoded: period|start_date|end_date, vehicle_numbers, driver, cost_centre, assigned_citytrips GeoJSON payloadTrips for the map → reporting.fn_trips_for_map. period preset: today|7d|30d|custom. Body parsed by Content-Type — the SPA posts application/x-www-form-urlencoded; JSON also accepted.
        +
        Fix (2026-06-05). The POST handler originally read the body as JSON only, but the SPA sends x-www-form-urlencoded; the mismatch silently dropped every filter so the map always returned the whole fleet. Now parsed by Content-Type (parse_qs for form bodies). Commit f1387d1.

        5 · Database schema

        tracksolid · Live data — the single source of truth. Ingested from the Tracksolid API.

        18 table(s) · 17 view(s) · 1 function(s) documented.

        tracksolid.alarmstable344,356 rows

        Alarm events (alarm_type, alarm_name, alarm_time).

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('alarms_id_seq'::regclass)
        imeitext
        alarm_typetext
        alarm_timetimestamp with time zone
        geomgeometry(Point,4326)
        latdouble precision
        lngdouble precision
        speednumeric(7,2)
        acc_statustext
        updated_attimestamp with time zonenow()
        alarm_nametext
        sourcetext'poll'::text
        severitytextAlarm severity level: critical | warning | info
        geofence_idtextTracksolid geofence ID if this is a geofence alarm
        geofence_nametextHuman-readable geofence name
        acknowledged_attimestamp with time zoneTimestamp when alarm was acknowledged by an operator
        acknowledged_bytextUsername or ID of operator who acknowledged the alarm
        tracksolid.api_token_cachetable1 rows

        OAuth2 token cache for the Jimi/Tracksolid API.

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('api_token_cache_id_seq'::regclass)
        accounttextNOT NULL
        access_tokentextNOT NULL
        refresh_tokentext
        app_keytext
        expires_attimestamp with time zoneNOT NULL
        obtained_attimestamp with time zoneNOT NULLnow()
        updated_attimestamp with time zoneNOT NULLnow()
        tracksolid.device_eventstable0 rows

        Device network connection and disconnection events from /pushevent webhook.

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('device_events_id_seq'::regclass)
        imeitextNOT NULL
        event_typetextNOT NULLLOGIN = device connected to network; LOGOUT = device disconnected
        event_timetimestamp with time zoneNOT NULL
        timezonetext
        created_attimestamp with time zoneNOT NULLnow()
        tracksolid.devicestable181 rows

        Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.

        ColumnTypeNullDefaultComment
        imeitextNOT NULL
        device_nametext
        mc_typetext
        mc_type_use_scopetext
        vehicle_nametext
        vehicle_numbertext
        vehicle_modelstext
        vehicle_icontext
        vintext
        engine_numbertext
        vehicle_brandtext
        fuel_100kmnumeric(6,2)
        driver_nametext
        driver_phonetext
        simtext
        iccidtext
        imsitext
        accounttext
        customer_nametext
        device_group_idtext
        device_grouptext
        activation_timetimestamp with time zone
        expirationtimestamp with time zone
        enabled_flagsmallintNOT NULL1
        statustext'active'::text
        citytext
        current_mileage_kmnumeric(12,2)
        created_attimestamp with time zoneNOT NULLnow()
        updated_attimestamp with time zoneNOT NULLnow()
        last_synced_attimestamp with time zone
        vehicle_categorytextVehicle type: truck | van | motorcycle | car | other
        cost_centretextBusiness unit or department this vehicle belongs to
        assigned_routetextRegular route name or ID for route-based reporting
        depot_geomgeometry(Point,4326)Home base/depot coordinates (WGS84)
        depot_addresstextHuman-readable depot address
        assigned_citytextOperating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection.
        tracksolid.dispatch_logtable0 rows

        Persistent record of every dispatch decision. Powers SLA metrics: dispatch latency, depart delay, time-to-site, wrench time.

        ColumnTypeNullDefaultComment
        dispatch_idbigintNOT NULLnextval('dispatch_log_dispatch_id_seq'::regclass)
        ticket_idtextNOT NULL
        imeitextNOT NULL
        driver_nametext
        job_latdouble precisionNOT NULL
        job_lngdouble precisionNOT NULL
        job_geomgeometry(Point,4326)
        assigned_attimestamp with time zoneNOT NULLnow()
        first_movement_attimestamp with time zoneFirst trip start after assigned_at. Back-filled nightly from trips.
        on_site_attimestamp with time zoneTime vehicle entered 150 m radius of job_geom. Back-filled nightly.
        resolved_attimestamp with time zoneTicket close time from the ops system (ops.tickets.closed_at).
        cancelled_attimestamp with time zone
        distance_kmnumeric(8,2)
        created_attimestamp with time zoneNOT NULLnow()
        tracksolid.fault_codestable0 rows

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('fault_codes_id_seq'::regclass)
        imeitextNOT NULL
        reported_attimestamp with time zoneNOT NULL
        fault_codetextNOT NULL
        status_flagsinteger
        latdouble precision
        lngdouble precision
        geomgeometry(Point,4326)
        event_timetimestamp with time zone
        created_attimestamp with time zoneNOT NULLnow()
        tracksolid.fuel_readingshypertable~0 rows

        Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.

        ColumnTypeNullDefaultComment
        imeitextNOT NULL
        reading_timetimestamp with time zoneNOT NULL
        sensor_pathtextSensor channel identifier from the device (path field in API payload)
        valuenumeric(10,3)
        unittextMeasurement unit: cm (tank depth), % (percentage), V (voltage), L (litres)
        latdouble precision
        lngdouble precision
        geomgeometry(Point,4326)
        created_attimestamp with time zoneNOT NULLnow()
        tracksolid.geofencestable0 rows

        Geofence boundary definitions synced from the Tracksolid platform.

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('geofences_id_seq'::regclass)
        fence_idtext
        fence_nametextNOT NULL
        fence_typetextcircle | polygon
        geomgeometry(Geometry,4326)
        radius_mnumeric(10,2)Radius in metres — only applicable for circle type geofences
        descriptiontext
        created_attimestamp with time zoneNOT NULLnow()
        updated_attimestamp with time zoneNOT NULLnow()
        tracksolid.heartbeatshypertable~0 rows

        Device heartbeat hypertable.

        ColumnTypeNullDefaultComment
        imeitextNOT NULL
        gate_timetimestamp with time zoneNOT NULL
        power_levelsmallint
        gsm_signalsmallint
        acc_statussmallint
        power_statussmallint
        fortifysmallint
        created_attimestamp with time zoneNOT NULLnow()
        tracksolid.ingestion_logtable274,181 rows

        API call audit trail — one row per ingestion run.

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('ingestion_log_id_seq'::regclass)
        run_attimestamp with time zoneNOT NULLnow()
        endpointtextNOT NULL
        imei_countintegerNOT NULL0
        rows_upsertedintegerNOT NULL0
        rows_insertedintegerNOT NULL0
        duration_msintegerNOT NULL0
        successbooleanNOT NULLtrue
        error_codetext
        error_messagetext
        tracksolid.lbs_readingstable0 rows

        Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('lbs_readings_id_seq'::regclass)
        imeitextNOT NULL
        gate_timetimestamp with time zoneNOT NULL
        post_typetextPositioning technology: WIFI | LBS (cell tower)
        lbs_datajsonbRaw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding.
        created_attimestamp with time zoneNOT NULLnow()
        tracksolid.live_positionstable179 rows

        Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.

        ColumnTypeNullDefaultComment
        imeitextNOT NULL
        geomgeometry(Point,4326)
        latdouble precision
        lngdouble precision
        pos_typetext
        confidencesmallint
        gps_timetimestamp with time zone
        hb_timetimestamp with time zone
        speednumeric(7,2)
        directionnumeric(6,2)
        acc_statustext
        gps_signalsmallint
        gps_numsmallint
        elec_quantitynumeric(5,2)
        power_valuenumeric(5,2)
        battery_power_valnumeric(5,2)
        tracker_oiltext
        temperaturenumeric(8,2)
        current_mileagenumeric(12,2)
        device_statustext
        expire_flagtext
        activation_flagtext
        loc_desctext
        recorded_attimestamp with time zoneNOT NULLnow()
        updated_attimestamp with time zoneNOT NULLnow()
        tracksolid.obd_readingstable0 rows

        OBD diagnostics — push only via /pushobd webhook.

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('obd_readings_id_seq'::regclass)
        imeitext
        reading_timetimestamp with time zone
        engine_rpmintegerEngine RPM from OBD PID 0x0C
        fuel_level_pctnumeric(5,2)Fuel tank level % from OBD PID 0x2F
        updated_attimestamp with time zonenow()
        car_typesmallint
        acc_statesmallint
        status_flagsinteger
        latdouble precision
        lngdouble precision
        geomgeometry(Point,4326)
        obd_datajsonbRaw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.)
        coolant_temp_cnumeric(6,2)Coolant temperature °C from OBD PID 0x05
        battery_voltagenumeric(5,2)Battery voltage (V) from OBD PID 0x42
        intake_pressurenumeric(6,2)Intake manifold pressure kPa from OBD PID 0x0B
        throttle_pctnumeric(5,2)Throttle position % from OBD PID 0x11
        vehicle_speednumeric(7,2)Vehicle speed km/h from OBD PID 0x0D
        engine_load_pctnumeric(5,2)Calculated engine load % from OBD PID 0x04
        tracksolid.parking_eventstable0 rows

        Stop events with duration + address.

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('parking_events_id_seq'::regclass)
        imeitextNOT NULL
        event_typetext
        start_timetimestamp with time zoneNOT NULL
        end_timetimestamp with time zone
        duration_secondsinteger
        geomgeometry(Point,4326)
        addresstext
        updated_attimestamp with time zonenow()
        tracksolid.position_historyhypertable~3,596,013 rows

        All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).

        ColumnTypeNullDefaultComment
        imeitextNOT NULL
        gps_timetimestamp with time zoneNOT NULL
        geomgeometry(Point,4326)
        latdouble precision
        lngdouble precision
        speednumeric(7,2)
        directionnumeric(6,2)
        acc_statustext
        satellitesmallint
        current_mileagenumeric(12,2)
        recorded_attimestamp with time zonenow()
        altitudenumeric(8,2)
        post_typesmallint
        sourcetext'poll'::text
        tracksolid.schema_migrationstable9 rows

        ColumnTypeNullDefaultComment
        filenametextNOT NULL
        applied_attimestamp with time zoneNOT NULLnow()
        tracksolid.temperature_readingshypertable~0 rows

        Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.

        ColumnTypeNullDefaultComment
        imeitextNOT NULL
        reading_timetimestamp with time zoneNOT NULL
        temperaturenumeric(6,2)
        humidity_pctnumeric(5,2)
        created_attimestamp with time zoneNOT NULLnow()
        tracksolid.tripstable43,765 rows

        Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).

        ColumnTypeNullDefaultComment
        idbigintNOT NULLnextval('trips_id_seq'::regclass)
        imeitextNOT NULL
        start_timetimestamp with time zoneNOT NULL
        end_timetimestamp with time zone
        start_geomgeometry(Point,4326)
        end_geomgeometry(Point,4326)
        distance_kmnumeric(12,2)Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10).
        avg_speed_kmhnumeric(7,2)
        max_speed_kmhnumeric(7,2)
        updated_attimestamp with time zonenow()
        fuel_consumed_lnumeric(8,2)
        idle_time_sinteger
        driving_time_sintegerrunTimeSecond from API: total driving time in seconds
        trip_seqinteger
        sourcetext'poll'::textpoll = from API polling, push = from webhook push
        route_geomgeometry(LineString,4326)Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window.
        start_addresstextReverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
        end_addresstextReverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
        vehicle_platetextDenormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest.
        waypoints_countintegerNumber of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate.
        tracksolid.v_active_dispatch_mapview

        01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.

        ColumnTypeNullDefaultComment
        imeitext
        vehicle_numbertext
        vehicle_nametext
        driver_nametext
        driver_phonetext
        assigned_citytext
        latdouble precision
        lngdouble precision
        speednumeric(7,2)
        directionnumeric(6,2)
        acc_statustext
        last_fixtimestamp without time zone
        statustext
        tracksolid.v_alarms_dailyview

        01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.

        ColumnTypeNullDefaultComment
        daydate
        alarm_nametext
        alarm_countbigint
        tracksolid.v_currently_idleview

        01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.

        ColumnTypeNullDefaultComment
        imeitext
        vehicle_numbertext
        driver_nametext
        assigned_citytext
        latdouble precision
        lngdouble precision
        sincetimestamp without time zone
        idle_secondsinteger
        tracksolid.v_driver_aggregates_dailyview

        01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).

        ColumnTypeNullDefaultComment
        imeitext
        driver_nametext
        vehicle_numbertext
        assigned_citytext
        daydate
        kmnumeric
        tripsbigint
        events_80bigint
        events_100bigint
        events_120bigint
        harsh_eventsbigint
        speeding_per_100kmnumeric
        harsh_per_100kmnumeric
        tracksolid.v_driver_attendance_dailyview

        ColumnTypeNullDefaultComment
        report_datedate
        driver_nametext
        vehicle_numbertext
        cost_centretext
        assigned_citytext
        reporting_timetime without time zone
        start_addresstext
        start_latdouble precision
        start_lngdouble precision
        statustext
        mins_from_startinteger
        tracksolid.v_driver_clock_dailyview

        Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).

        ColumnTypeNullDefaultComment
        imeitext
        driver_nametext
        vehicle_numbertext
        cost_centretext
        assigned_citytext
        report_datedate
        reporting_timetime without time zone
        closing_timetime without time zone
        reporting_tstimestamp with time zone
        closing_tstimestamp with time zone
        start_latdouble precision
        start_lngdouble precision
        start_addresstext
        end_latdouble precision
        end_lngdouble precision
        end_addresstext
        trips_countbigint
        total_kmnumeric
        drive_hoursnumeric
        tracksolid.v_driver_clock_todayview

        Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

        ColumnTypeNullDefaultComment
        imeitext
        driver_nametext
        vehicle_numbertext
        cost_centretext
        assigned_citytext
        report_datedate
        reporting_timetime without time zone
        closing_timetime without time zone
        reporting_tstimestamp with time zone
        closing_tstimestamp with time zone
        start_latdouble precision
        start_lngdouble precision
        start_addresstext
        end_latdouble precision
        end_lngdouble precision
        end_addresstext
        trips_countbigint
        total_kmnumeric
        drive_hoursnumeric
        tracksolid.v_fleet_km_dailyview

        01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.

        ColumnTypeNullDefaultComment
        daydate
        assigned_citytext
        kmnumeric
        active_vehiclesbigint
        tripsbigint
        tracksolid.v_fleet_statusview

        ColumnTypeNullDefaultComment
        imeitext
        vehicle_numbertext
        driver_nametext
        latdouble precision
        lngdouble precision
        geomgeometry(Point,4326)
        speednumeric(7,2)
        acc_statustext
        gps_timetimestamp with time zone
        connectivity_statustext
        seconds_since_fixinteger
        tracksolid.v_fleet_todayview

        01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.

        ColumnTypeNullDefaultComment
        imeitext
        driver_nametext
        vehicle_numbertext
        vehicle_nametext
        assigned_citytext
        enabled_flagsmallint
        km_todaynumeric
        trips_todaybigint
        drive_hoursnumeric
        idle_hoursnumeric
        first_departuretime without time zone
        last_returntime without time zone
        alarms_todaybigint
        last_fixtimestamp without time zone
        last_speednumeric(7,2)
        did_not_moveboolean
        tracksolid.v_fleet_traceview

        ColumnTypeNullDefaultComment
        gidbigint
        driver_nametext
        vehicle_nametext
        device_nametext
        imeitext
        geomgeometry(Point,4326)
        latnumeric
        lngnumeric
        start_timetimestamp without time zone
        end_timetimestamp without time zone
        day_localdate
        hour_localinteger
        dow_localinteger
        gps_time_utctimestamp with time zone
        recorded_attimestamp with time zone
        speednumeric(7,2)
        directionnumeric(6,2)
        current_mileagenumeric(12,2)
        stationaryboolean
        trip_idbigint
        tracksolid.v_ingestion_healthview

        ColumnTypeNullDefaultComment
        endpointtext
        run_attimestamp with time zone
        successboolean
        error_messagetext
        seconds_agointeger
        tracksolid.v_mileage_daily_caggview

        ColumnTypeNullDefaultComment
        buckettimestamp with time zone
        imeitext
        dist_kmnumeric
        avg_speednumeric
        tracksolid.v_sla_inflightview

        01_BusinessAnalytics.md §4.5 Field-Service SLA Metrics. Open tickets + last 24h resolved.

        ColumnTypeNullDefaultComment
        ticket_idtext
        customertext
        prioritytext
        job_typetext
        statustext
        created_attimestamp with time zone
        assigned_attimestamp with time zone
        closed_attimestamp with time zone
        assigned_imeitext
        driver_nametext
        first_movement_attimestamp with time zone
        on_site_attimestamp with time zone
        resolved_attimestamp with time zone
        dispatch_minsnumeric
        enroute_minsnumeric
        onsite_minsnumeric
        resolution_minsnumeric
        ticket_stagetext
        tracksolid.v_trips_enrichedview

        tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.

        ColumnTypeNullDefaultComment
        idbigint
        imeitext
        start_timetimestamp with time zone
        end_timetimestamp with time zone
        start_geomgeometry(Point,4326)
        end_geomgeometry(Point,4326)
        distance_kmnumeric(12,2)
        avg_speed_kmhnumeric(7,2)
        max_speed_kmhnumeric(7,2)
        updated_attimestamp with time zone
        fuel_consumed_lnumeric(8,2)
        idle_time_sinteger
        driving_time_sinteger
        trip_seqinteger
        sourcetext
        route_geomgeometry(LineString,4326)
        start_addresstext
        end_addresstext
        vehicle_platetext
        waypoints_countinteger
        trip_date_eatdate
        daily_seqbigint
        tracksolid.v_utilisation_dailyview

        01_BusinessAnalytics.md §7 Panel 8 Utilisation Heatmap. Empty until nightly ETL runs.

        ColumnTypeNullDefaultComment
        daydate
        imeitext
        vehicle_numbertext
        driver_nametext
        assigned_citytext
        total_distance_kmnumeric(12,2)
        total_drive_hoursnumeric(8,2)
        total_idle_hoursnumeric(8,2)
        alarm_countinteger
        overspeed_countinteger
        utilisation_pctnumeric
        tracksolid.v_vehicles_not_moved_todayview

        01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.

        ColumnTypeNullDefaultComment
        imeitext
        vehicle_nametext
        vehicle_numbertext
        driver_nametext
        assigned_citytext
        last_seentimestamp without time zone
        speednumeric(7,2)
        tracksolid.set_updated_at(…)function · plpgsql

        arguments()
        returnstrigger

        reporting · Read layer that backs the map dashboards (consumed by dashboard_api).

        2 table(s) · 12 view(s) · 4 function(s) documented.

        reporting.refresh_logtable3,558 rows

        One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. Written by dashboard_api's built-in refresher (source='dashboard_api', every 5 min); the retired n8n job (source='n8n') was the previous writer. Read MAX(refreshed_at) for staleness.

        ColumnTypeNullDefaultComment
        refreshed_attimestamp with time zoneNOT NULLnow()
        sourcetextNOT NULL'n8n'::text
        duration_msinteger
        row_countinteger
        notestext
        reporting.v_tripsmatview31,670 rows

        Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.

        ColumnTypeNullDefaultComment
        trip_idbigint
        imeitext
        device_nametext
        vehicle_numbertext
        vehicle_modelstext
        vehicle_categorytext
        cost_centretext
        assigned_citytext
        assigned_drivertext
        start_timetimestamp without time zone
        end_timetimestamp without time zone
        trip_datedate
        start_hourinteger
        start_dowinteger
        daily_seqbigint
        distance_kmnumeric(12,2)
        avg_speed_kmhnumeric(7,2)
        max_speed_kmhnumeric(7,2)
        idle_time_sinteger
        driving_time_sinteger
        fuel_consumed_lnumeric(8,2)
        waypoints_countinteger
        start_addresstext
        end_addresstext
        start_geomgeometry(Point,4326)
        end_geomgeometry(Point,4326)
        route_geomgeometry(LineString,4326)
        route_geojsonjson
        is_meaningful_routeboolean
        updated_attimestamp without time zone
        reporting.v_daily_cost_centreview

        Cost-centre × day rollup. Excludes trips with NULL cost_centre.

        ColumnTypeNullDefaultComment
        trip_datedate
        cost_centretext
        active_vehiclesbigint
        active_driversbigint
        trip_countbigint
        total_kmnumeric
        driving_hoursnumeric
        idle_hoursnumeric
        idle_pctnumeric
        km_per_vehiclenumeric
        reporting.v_daily_summaryview

        Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.

        ColumnTypeNullDefaultComment
        trip_datedate
        cost_centretext
        assigned_citytext
        vehicle_numbertext
        assigned_drivertext
        trip_countbigint
        total_kmnumeric
        driving_hoursnumeric
        idle_hoursnumeric
        idle_pctnumeric
        first_trip_starttimestamp without time zone
        last_trip_endtimestamp without time zone
        avg_speed_kmhnumeric
        max_speed_kmhnumeric
        day_routes_geojsonjson
        reporting.v_filter_citiesview

        Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.

        ColumnTypeNullDefaultComment
        assigned_citytext
        reporting.v_filter_cost_centresview

        Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.

        ColumnTypeNullDefaultComment
        cost_centretext
        reporting.v_filter_driversview

        Driver dropdown source for the n8n dashboard. Distinct non-null drivers.

        ColumnTypeNullDefaultComment
        drivertext
        reporting.v_filter_vehiclesview

        Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.

        ColumnTypeNullDefaultComment
        vehicle_numbertext
        driverstext
        cost_centretext
        assigned_citytext
        reporting.v_live_positionsview

        Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.

        ColumnTypeNullDefaultComment
        imeitext
        vehicle_numbertext
        assigned_drivertext
        cost_centretext
        assigned_citytext
        vehicle_categorytext
        vehicle_modelstext
        mc_typetext
        device_kindtext
        latdouble precision
        lngdouble precision
        speednumeric(7,2)
        directionnumeric(6,2)
        acc_statustext
        device_statustext
        gps_signalsmallint
        gps_numsmallint
        current_mileagenumeric(12,2)
        loc_desctext
        gps_timetimestamp with time zone
        updated_attimestamp with time zone
        gps_time_eattimestamp without time zone
        updated_at_eattimestamp without time zone
        source_age_hoursnumeric
        reporting.v_monthly_cost_centreview

        Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.

        ColumnTypeNullDefaultComment
        month_startdate
        month_labeltext
        cost_centretext
        active_vehiclesbigint
        active_driversbigint
        active_daysbigint
        trip_countbigint
        total_kmnumeric
        driving_hoursnumeric
        idle_hoursnumeric
        idle_pctnumeric
        km_per_vehiclenumeric
        reporting.v_monthly_summaryview

        Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).

        ColumnTypeNullDefaultComment
        month_startdate
        month_labeltext
        cost_centretext
        assigned_citytext
        vehicle_categorytext
        vehicle_numbertext
        assigned_drivertext
        trip_countbigint
        active_daysbigint
        total_kmnumeric
        driving_hoursnumeric
        idle_hoursnumeric
        idle_pctnumeric
        km_per_active_daynumeric
        km_per_tripnumeric
        avg_speed_kmhnumeric
        peak_speed_kmhnumeric
        reporting.v_trips_todayview

        Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

        ColumnTypeNullDefaultComment
        trip_idbigint
        imeitext
        device_nametext
        vehicle_numbertext
        vehicle_modelstext
        vehicle_categorytext
        cost_centretext
        assigned_citytext
        assigned_drivertext
        start_timetimestamp without time zone
        end_timetimestamp without time zone
        trip_datedate
        start_hourinteger
        start_dowinteger
        daily_seqbigint
        distance_kmnumeric(12,2)
        avg_speed_kmhnumeric(7,2)
        max_speed_kmhnumeric(7,2)
        idle_time_sinteger
        driving_time_sinteger
        fuel_consumed_lnumeric(8,2)
        waypoints_countinteger
        start_addresstext
        end_addresstext
        start_geomgeometry(Point,4326)
        end_geomgeometry(Point,4326)
        route_geomgeometry(LineString,4326)
        route_geojsonjson
        is_meaningful_routeboolean
        updated_attimestamp without time zone
        reporting.v_weekly_cost_centreview

        Cost-centre × week rollup. Excludes trips with NULL cost_centre.

        ColumnTypeNullDefaultComment
        week_startdate
        cost_centretext
        active_vehiclesbigint
        active_driversbigint
        active_daysbigint
        trip_countbigint
        total_kmnumeric
        driving_hoursnumeric
        idle_hoursnumeric
        idle_pctnumeric
        km_per_vehiclenumeric
        reporting.v_weekly_summaryview

        Vehicle × week rollup. Numeric only, no geometry.

        ColumnTypeNullDefaultComment
        week_startdate
        cost_centretext
        assigned_citytext
        vehicle_numbertext
        assigned_drivertext
        trip_countbigint
        active_daysbigint
        total_kmnumeric
        driving_hoursnumeric
        idle_hoursnumeric
        avg_trip_kmnumeric
        reporting.fn_live_positions(…)function · plpgsql

        Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.

        argumentsp_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text
        returnsjsonb
        reporting.fn_trips_for_map(…)function · plpgsql

        Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.

        argumentsp_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date
        returnsjsonb
        reporting.fn_vehicle_track(…)function · sql

        Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.

        argumentsp_vehicle_number text, p_hours integer DEFAULT 1
        returnsjsonb
        reporting.normalize_plate(…)function · sql

        Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.

        argumentsp text
        returnstext

        ops · Workshop / tickets / odometer integrations.

        5 table(s) · 1 view(s) · 0 function(s) documented.

        ops.cost_ratestable3 rows

        Reference rates for analytics monetisation: fuel price per litre by city, labour cost per hour by role. Resolution order in views: scope_type=city > scope_type=role > scope_type=global.

        ColumnTypeNullDefaultComment
        rate_keytextNOT NULL
        scope_typetextNOT NULLcity | role | global
        scope_valuetext
        metrictextNOT NULLfuel_per_litre | labour_per_hour
        amountnumeric(12,2)NOT NULL
        currencytextNOT NULL
        effective_fromdateNOT NULLCURRENT_DATE
        notestext
        created_attimestamp with time zoneNOT NULLnow()
        updated_attimestamp with time zoneNOT NULLnow()
        ops.kpi_targetstable12 rows

        Traffic-light targets per KPI per scope. Resolution order in views: cost_centre > vehicle_category > city > global.

        ColumnTypeNullDefaultComment
        target_idbigintNOT NULLnextval('ops.kpi_targets_target_id_seq'::regclass)
        kpi_keytextNOT NULL
        scope_typetextNOT NULL
        scope_valuetext
        target_valuenumeric(12,2)NOT NULL
        amber_thresholdnumeric(12,2)
        red_thresholdnumeric(12,2)
        directiontextNOT NULL'higher_is_better'::texthigher_is_better -> green when value >= target. lower_is_better -> green when value <= target.
        effective_fromdateNOT NULLCURRENT_DATE
        notestext
        created_attimestamp with time zoneNOT NULLnow()
        updated_attimestamp with time zoneNOT NULLnow()
        ops.odometer_readingstable0 rows

        Physical odometer captures from service, fuel card, or manual entry. Powers §3.8 Odometer Divergence audit.

        ColumnTypeNullDefaultComment
        reading_idbigintNOT NULLnextval('ops.odometer_readings_reading_id_seq'::regclass)
        imeitextNOT NULL
        reading_datedateNOT NULL
        reading_kmintegerNOT NULL
        sourcetextservice | fuel_card | driver_manual | workshop_form
        recorded_bytext
        created_attimestamp with time zoneNOT NULLnow()
        ops.service_logtable0 rows

        Workshop service history. Powers §10 Service-Interval Forecaster.

        ColumnTypeNullDefaultComment
        service_idbigintNOT NULLnextval('ops.service_log_service_id_seq'::regclass)
        imeitextNOT NULL
        service_datedateNOT NULL
        odometer_kmintegerNOT NULLPhysical odometer reading at service time (integer km).
        service_typetextscheduled | repair | tyre | bodywork | inspection | other
        cost_kesinteger
        notestext
        created_attimestamp with time zoneNOT NULLnow()
        ops.ticketstable0 rows

        Skeleton for ticket data sourced from the Fireside ops system. Replace or extend to match the actual feed (Zoho Desk, Freshdesk, etc).

        ColumnTypeNullDefaultComment
        ticket_idtextNOT NULL
        assigned_imeitext
        driver_nametext
        customertext
        job_typetext
        prioritytext
        statustextNOT NULL'open'::textopen | assigned | in_progress | resolved | cancelled
        created_attimestamp with time zoneNOT NULL
        assigned_attimestamp with time zone
        closed_attimestamp with time zone
        job_latdouble precision
        job_lngdouble precision
        job_geomgeometry(Point,4326)
        ingested_attimestamp with time zoneNOT NULLnow()
        ops.vw_service_forecastview

        Projected next-service date per vehicle based on 30-day km rate. Service interval default 10,000 km — override at query time if needed.

        ColumnTypeNullDefaultComment
        imeitext
        driver_nametext
        vehicle_numbertext
        last_service_datedate
        last_service_odointeger
        current_odonumeric(12,2)
        km_since_servicenumeric
        km_to_next_servicenumeric
        km_per_day_30dnumeric
        projected_service_datedate

        dwh_gold · Nightly ETL aggregates.

        2 table(s) · 0 view(s) · 1 function(s) documented.

        dwh_gold.dim_vehiclestable0 rows

        ColumnTypeNullDefaultComment
        vehicle_keyintegerNOT NULLnextval('dim_vehicles_vehicle_key_seq'::regclass)
        imeitext
        vehicle_numbertext
        is_activebooleantrue
        dwh_gold.fact_daily_fleet_metricstable0 rows

        ColumnTypeNullDefaultComment
        daydateNOT NULL
        vehicle_keyintegerNOT NULL
        total_distance_kmnumeric(12,2)Total km driven that day across all trips
        max_speed_kmhnumeric(7,2)
        idle_hoursnumeric(5,2)
        total_tripsintegerNumber of completed trips
        total_drive_hoursnumeric(8,2)Total hours of active driving (engine on + moving)
        total_idle_hoursnumeric(8,2)Total hours engine on but stationary
        fuel_consumed_lnumeric(10,3)Total fuel consumed in litres (from webhook trip reports)
        alarm_countintegerTotal alarm events triggered that day
        overspeed_countintegerNumber of overspeed alarm events
        day_start_timetime without time zoneTime of first trip start (Africa/Nairobi)
        day_end_timetime without time zoneTime of last trip end (Africa/Nairobi)
        avg_speed_kmhnumeric(7,2)Fleet average speed across all trips that day
        peak_speed_kmhnumeric(7,2)Highest max_speed_kmh recorded across all trips
        dwh_gold.refresh_daily_metrics(…)function · plpgsql

        Populates or refreshes fact_daily_fleet_metrics for the given date. Call nightly: SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1);

        argumentstarget_date date
        returnsvoid

        public · Extension objects + pgbouncer auth helper.

        1 table(s) · 3 view(s) · 1 function(s) documented.

        public.spatial_ref_systable8,500 rows

        ColumnTypeNullDefaultComment
        sridintegerNOT NULL
        auth_namecharacter varying(256)
        auth_sridinteger
        srtextcharacter varying(2048)
        proj4textcharacter varying(2048)
        public.geography_columnsview

        ColumnTypeNullDefaultComment
        f_table_catalogname
        f_table_schemaname
        f_table_namename
        f_geography_columnname
        coord_dimensioninteger
        sridinteger
        typetext
        public.geometry_columnsview

        ColumnTypeNullDefaultComment
        f_table_catalogcharacter varying(256)
        f_table_schemaname
        f_table_namename
        f_geometry_columnname
        coord_dimensioninteger
        sridinteger
        typecharacter varying(30)
        public.trips_viz_v1view

        ColumnTypeNullDefaultComment
        trip_idbigint
        imeitext
        vehicle_nametext
        vehicle_numbertext
        cost_centretext
        start_timetimestamp with time zone
        end_timetimestamp with time zone
        distance_kmnumeric(12,2)
        avg_speed_kmhnumeric(7,2)
        max_speed_kmhnumeric(7,2)
        vehicle_platetext
        start_addresstext
        end_addresstext
        waypoints_countinteger
        driving_time_sinteger
        idle_time_sinteger
        fuel_consumed_lnumeric(8,2)
        trip_date_eatdate
        daily_seqbigint
        public.user_lookup(…)function · plpgsql

        pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.

        argumentsin_user text, OUT uname text, OUT phash text
        returnsrecord

        6 · Grafana dashboards

        Grafana is provisioned via a baked image and reads TimescaleDB directly (read-only role grafana_ro), mostly through the tracksolid.v_* analytics views documented in §5. Two dashboards ship with the stack.

        NOC Fleet Operations — Live · uid noc-fleet-live · 9 panels

        SectionPanelTypeSource view / table
        Total Vehiclesstattracksolid.devices
        Online Nowstattracksolid.v_fleet_status
        Recent (5-30 min)stattracksolid.v_fleet_status
        Offlinestattracksolid.v_fleet_status
        Moving Nowstattracksolid.v_fleet_status
        Avg Speed (km/h)stattracksolid.v_fleet_status
        Live Vehicle Locationsgeomaptracksolid.devices, tracksolid.live_positions
        Vehicle Statustabletracksolid.devices, tracksolid.live_positions
        Ingestion Healthtabletracksolid.v_ingestion_health

        Daily Operations — Fleet & Dispatch · uid daily-ops · 21 panels

        SectionPanelTypeSource view / table
        Last GPS Fix (fleet)stattracksolid.live_positions
        Vehicles reporting todaystattracksolid.v_fleet_today
        Fleet km todaystattracksolid.v_fleet_today
        Drive hours todaystattracksolid.v_fleet_today
        Idle hours todaystattracksolid.v_fleet_today
        Open alarms (24h)stattracksolid.alarms
        In-flight SLA jobsstattracksolid.v_sla_inflight
        Active Vehicles Mapgeomaptracksolid.v_active_dispatch_map
        Currently Idle (engine on, speed < 2)tabletracksolid.v_currently_idle
        Vehicles Not Moved Todaytabletracksolid.v_vehicles_not_moved_today
        Per-Vehicle Daily Roll-uptabletracksolid.v_fleet_today
        Driver Leaderboardtabletracksolid.v_driver_aggregates_daily
        Fleet Distance — 7-day (by city)timeseriestracksolid.v_fleet_km_daily
        Alarm Frequency — 30-day (by type)timeseriestracksolid.v_alarms_daily
        Idle Cost (month-to-date)stattracksolid.v_utilisation_daily
        Utilisation Heatmap (30-day)heatmaptracksolid.v_utilisation_daily
        Row 7 — Field-Service SLAs (data-gated)Dispatch SLA (median mins, 24h)stattracksolid.v_sla_inflight
        En-route SLA (median mins, 24h)stattracksolid.v_sla_inflight
        On-site SLA (median mins, 24h)stattracksolid.v_sla_inflight
        Resolution SLA (median mins, 24h)stattracksolid.v_sla_inflight
        At-risk ticketstabletracksolid.v_sla_inflight

        SLA panels (v_sla_inflight) and the utilisation heatmap (v_utilisation_daily) are data-gated on the ops ticket integration and nightly dwh_gold ETL respectively.

        7 · Operational notes

        • Hypertables (position_history, heartbeats, fuel_readings, temperature_readings) report 0 in pg_stat_user_tables — counts above use TimescaleDB's approximate_row_count().
        • API distance fields are metres, not km (divide by 1000) — see FIX-M16.
        • -
        • reporting.v_trips is a materialized view kept current by an external refresh job (role -reporting_refresher); it is captured in migrations/11_reporting_schema.sql but the refresh schedule is -infrastructure, not schema.
        • +
        • reporting.v_trips is a materialized view (owned by reporting_refresher, DDL in +migrations/11_reporting_schema.sql). It is kept current by dashboard_api's built-in background +refresher — REFRESH MATERIALIZED VIEW CONCURRENTLY every VTRIPS_REFRESH_INTERVAL_S (default 300s), +advisory-lock guarded so only one uvicorn worker refreshes per tick. This replaced the n8n scheduled workflow that +refreshed it until n8n was retired (2026-06-01); a stale matview was the cause of the "no trips" incident on 2026-06-05. +The container's DATABASE_URL connects as a superuser, which is why it may REFRESH a matview it does not own.
        • Migrations apply at container startup via run_migrations.py (idempotent, tracked in tracksolid.schema_migrations). Latest: 11_reporting_schema.sql.
        • Backups: db_backup sidecar → rustfs bucket fleet-db, scheduled (default 02:30/08:30/14:30/20:30 Africa/Nairobi).
        • From 8c5a43f3b8b244a6d1ec8eeb91539c29b771ec6c Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 18:11:03 +0300 Subject: [PATCH 24/31] chore(db): purge unused ops + dwh_gold schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the dormant ops (workshop / tickets / dispatch / SLA / odometer) and dwh_gold (nightly ETL aggregates) schemas plus their dependents — features never implemented, no live writer or scheduled refresh. - Prod DB (already applied): DROP SCHEMA ops/dwh_gold CASCADE, plus tracksolid.dispatch_log, v_sla_inflight, v_utilisation_daily. - migrations/12_drop_ops.sql + 13_drop_dwh_gold.sql (forward, all IF EXISTS) registered in run_migrations.py for rebuild durability. - grafana: removed 8 now-broken panels (In-flight SLA, Idle Cost, Utilisation Heatmap, Row 7 Field-Service SLAs) from daily_operations; panel count 21 -> 13. - docs: scrubbed CLAUDE.md, PLATFORM_OVERVIEW.html (-19KB), DATA_FLOW.md; pre-drop seed snapshot in docs/reports/260605_ops_purge_backup.md. The separate tracksolid_dwh server (31.97.44.246:5888) is unrelated and untouched. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 27 +- docs/DATA_FLOW.md | 240 ++++ docs/PLATFORM_OVERVIEW.html | 2 +- docs/reports/260605_ops_purge_backup.md | 47 + .../daily_operations_dashboard.json | 1103 ++++++++++++----- migrations/12_drop_ops.sql | 30 + migrations/13_drop_dwh_gold.sql | 23 + run_migrations.py | 2 + 8 files changed, 1152 insertions(+), 322 deletions(-) create mode 100644 docs/DATA_FLOW.md create mode 100644 docs/reports/260605_ops_purge_backup.md create mode 100644 migrations/12_drop_ops.sql create mode 100644 migrations/13_drop_dwh_gold.sql diff --git a/CLAUDE.md b/CLAUDE.md index 5ad556c..9718983 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -56,7 +56,7 @@ See `docs/CONNECTIONS.md` for the full shape. Summary: - **SSH:** `ssh -i ~/.ssh/id_ed25519 kianiadee@stage.rahamafresh.com` - **DB name:** `tracksolid_db` · **DB user:** `postgres` (internal) · `tracksolid_owner` (app) · `grafana_ro` (read-only) -- **DB schemas:** `tracksolid` (live, single source of truth) · `dwh_gold` (aggregates) · `ops` (workshop / tickets / odometer) · `infrastructure`. The legacy `tracksolid_2` schema no longer exists — migrations 02–06 applied 2026-04-18. +- **DB schemas:** `tracksolid` (live, single source of truth) · `reporting` (map-dashboard read layer) · `infrastructure`. The legacy `tracksolid_2` schema no longer exists (migrations 02–06, 2026-04-18); the `ops` and `dwh_gold` schemas were purged 2026-06-05 (migrations 12/13) as unused. - **DB access:** `DATABASE_URL` points to `timescale_db:5432` (internal Docker network — not reachable locally). Use `docker exec` pattern above. See `docs/CONNECTIONS.md` for full reference. - **DWH target DB:** `tracksolid_dwh` at `31.97.44.246:5888` (separate PostGIS instance, public IP). Users: `dwh_owner` (bronze writes + `dwh_control`), `grafana_ro` (reads bronze/silver/gold/`dwh_control`). Always connect with `sslmode=require`. Fed by the n8n `dwh_extract` + `dwh_load_bronze` workflows — see `docs/DWH_PIPELINE.md`. - **Container naming:** Coolify appends a random suffix. Always resolve with: @@ -93,10 +93,11 @@ dwh/ # DWH migrations for tracksolid_dwh@31.97.44.246:588 # 261002_bronze_constraints_audit.sql — ON CONFLICT key assertion # 261003_dwh_roles.sql — role contract assertion # 261004_dwh_observability_views.sql — freshness/failure views -migrations/ # Numbered SQL migrations 02–10, applied in order by run_migrations.py +migrations/ # Numbered SQL migrations 02–13, applied in order by run_migrations.py # 02 full schema · 03 webhook · 04 distance fix · 05 enhancements # 06 ops/analytics · 07 views · 08 config · 09 trips enrichment - # 10_driver_clock_views.sql · 10_pgbouncer_auth.sql + # 10_driver_clock_views.sql · 10_pgbouncer_auth.sql · 11 reporting + # 12 drop ops schema · 13 drop dwh_gold schema (both 2026-06-05) Dockerfile # Custom image for ingest/webhook containers pyproject.toml # Python project + uv dependency spec backup/ # pg_dump sidecar scripts and config @@ -126,12 +127,13 @@ tracksolid.alarms -- Alarm events (alarm_type, alarm_name, alarm_time tracksolid.obd_readings -- OBD diagnostics (push only, awaiting webhook registration) tracksolid.device_events -- Power on/off tamper events (push only) tracksolid.ingestion_log -- API call audit trail — 875 runs / 24h, 0 failures at last check (2026-04-19) -tracksolid.dispatch_log -- Dispatch decisions for SLA tracking (migration 06; empty until ops integration) -tracksolid.schema_migrations -- Applied files: 02,03,04,05,06 (last 06 on 2026-04-18) -dwh_gold.fact_daily_fleet_metrics -- Nightly ETL aggregates per vehicle per day (run refresh_daily_metrics) -ops.service_log -- Workshop service history (migration 06) -ops.odometer_readings -- Physical odometer captures (migration 06) -ops.tickets -- Ticket skeleton for ops integration (migration 06; empty) +tracksolid.schema_migrations -- Applied migrations 02–13 +-- PURGED 2026-06-05 (migrations 12 + 13): the dormant `ops` schema (tickets, service_log, +-- odometer_readings, cost_rates, kpi_targets, vw_service_forecast), tracksolid.dispatch_log, +-- and the `dwh_gold` schema (dim_vehicles, fact_daily_fleet_metrics, refresh_daily_metrics). +-- Those workshop/dispatch/SLA/utilisation features were never implemented. Do NOT reintroduce +-- references to ops.* or dwh_gold.* — they no longer exist. (The separate tracksolid_dwh DB +-- at 31.97.44.246:5888 is unrelated and untouched.) ``` Full DDL: `02_tracksolid_full_schema_rev.sql` + migrations `03`–`06`. @@ -146,8 +148,8 @@ tracksolid.v_currently_idle -- §2.2 idle lens tracksolid.v_driver_aggregates_daily -- §3.1 + §3.2 aggression index source tracksolid.v_fleet_km_daily -- §7 Panel 5 distance trend tracksolid.v_alarms_daily -- §7 Panel 7 alarm frequency -tracksolid.v_utilisation_daily -- §7 Panel 8 utilisation heatmap (gated on dwh_gold ETL) -tracksolid.v_sla_inflight -- §4.5 SLA panels (gated on ops.tickets) +-- v_utilisation_daily (dwh_gold) and v_sla_inflight (ops) were DROPPED 2026-06-05 with +-- their schemas (migrations 12/13); their Grafana panels were removed from the dashboard. ``` All views carry a `COMMENT ON VIEW` referencing their spec — `\d+ tracksolid.v_*` shows the provenance. @@ -222,7 +224,7 @@ dwh_control.v_watermark_lag -- Grafana: extract vs. load lag per table 7. **Secrets from env only.** Connection strings, API keys, and passwords live in `.env`. Reference variable names from `docs/CONNECTIONS.md`, never values. 8. **Two developers, one incoming.** Write code and docs that a second developer (mixed technical/operations background) can follow without prior context. 9. **Forgejo API auth:** credentials stored in macOS keychain. Retrieve with `git credential fill` (host=repo.rahamafresh.com). Use basic auth against `https://repo.rahamafresh.com/api/v1` directly — no `tea` or `gh` needed. -10. **Single live schema.** All live data lives in `tracksolid`. Aggregates live in `dwh_gold`; workshop/ticket integrations live in `ops`. Do not reintroduce references to the retired `tracksolid_2` schema. +10. **Single live schema.** All live data lives in `tracksolid`; the map-dashboard read layer lives in `reporting`. Do not reintroduce references to the retired `tracksolid_2`, `ops`, or `dwh_gold` schemas (the latter two purged 2026-06-05, migrations 12/13). --- @@ -256,6 +258,5 @@ Latest full snapshot: `docs/reports/260412_baseline_report.md` | MEDIUM | Investigate 44 silent devices (only 19 of 63 reporting) — SIM installed? Activated? | | MEDIUM | Co-develop client KPI framework (see `docs/KPI_FRAMEWORK.md`) | | LOW | Populate geofences — depot boundaries, city zones | -| LOW | Schedule nightly ETL: `SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1)` (cron or n8n) | | HIGH | Deploy DWH bronze pipeline: apply `dwh/26100{1,2,3,4}.sql` to `tracksolid_dwh`, import + wire the two n8n workflows, verify first run via `dwh_control.v_table_freshness`. Runbook: `docs/DWH_PIPELINE.md` | | MEDIUM | Rotate `dwh_owner` / `grafana_ro` passwords on `tracksolid_dwh` — plaintext in `dwh/260423_dwh_ddl_v1.sql` is a pre-existing flaw to clean up separately | diff --git a/docs/DATA_FLOW.md b/docs/DATA_FLOW.md new file mode 100644 index 0000000..1314cda --- /dev/null +++ b/docs/DATA_FLOW.md @@ -0,0 +1,240 @@ +# Data Flow — Ingestion → Aggregation → Views → Functions → Consumers + +**Scope:** the *live* fleet pipeline only (`tracksolid` + `reporting`). The `ops` and +`dwh_gold` schemas were **purged on 2026-06-05** (migrations 12/13) — those workshop / +dispatch / SLA / utilisation features were never implemented. They are shown below only as +a struck-out "removed" footnote for historical context. (The *separate* `tracksolid_dwh` +server at 31.97.44.246:5888 is unrelated and was not touched.) + +**Verified against prod 2026-06-05** (TimescaleDB hypertable + continuous-aggregate +catalog, `pg_depend` view graph, ingestion `INSERT` targets, `dashboard_api` queries, +Grafana panel SQL). Key facts that surprised the docs: + +- Only `position_history` (and the empty/planned `heartbeats`, `fuel_readings`, + `temperature_readings`) are **hypertables**. `trips` and `alarms` are **plain tables**. +- `tracksolid.v_mileage_daily_cagg` is a **real TimescaleDB continuous aggregate**, not a + plain view — and it currently has **no downstream consumer**. +- `reporting.v_trips` is a **matview**, refreshed every 5 min by the in-process + `dashboard_api` background loop (FIX-D02), pg advisory-lock `920145`. + +--- + +## Mermaid + +```mermaid +flowchart TD + API["Tracksolid / Jimi API
          poll + push webhooks · OAuth2"] + + subgraph ING["Ingestion — ts_shared_rev.py: get_conn() · api_post() · clean*()"] + IM["ingest_movement_rev.py"] + IE["ingest_events_rev.py"] + WR["webhook_receiver_rev.py"] + end + API --> IM & IE & WR + + subgraph L1["L1 · Base tables + hypertables — schema: tracksolid (single source of truth)"] + LP["live_positions
          current fix / IMEI"] + PH[("position_history
          HYPERTABLE · high-res GPS trail")] + TR["trips
          plain table — NOT a hypertable"] + DV["devices
          vehicle / driver registry"] + AL["alarms
          plain table"] + ILOG["ingestion_log · api_token_cache"] + EMPTY["heartbeats* · fuel_readings* · temperature_readings* (HYPERTABLES, empty)
          device_events · fault_codes · obd_readings · parking_events · lbs_readings · geofences (empty)"] + end + IM --> LP & PH & TR & DV + IM --> ILOG + IE --> AL + WR --> EMPTY + + subgraph L2["L2 · Aggregation"] + CAGG[("v_mileage_daily_cagg
          CONTINUOUS AGGREGATE")] + VT[("reporting.v_trips
          MATVIEW · ix_v_trips_trip_id")] + RLOG["reporting.refresh_log"] + end + PH -->|Timescale cont-agg policy| CAGG + TR --> VT + DV --> VT + VT -->|"REFRESH CONCURRENTLY every 300s
          (dashboard_api loop, adv-lock 920145)"| RLOG + + subgraph L3L["L3 · Reporting views — fed by v_trips matview"] + FILT["v_filter_vehicles · v_filter_drivers
          v_filter_cost_centres · v_filter_cities"] + SUMM["v_daily/weekly/monthly_summary
          v_*_cost_centre · v_trips_today"] + VLP["v_live_positions"] + end + VT --> FILT & SUMM + LP --> VLP + + subgraph L3R["L3 · Grafana views — tracksolid.* (read base tables directly)"] + GV["v_fleet_today · v_fleet_status · v_active_dispatch_map
          v_currently_idle · v_alarms_daily · v_fleet_km_daily
          v_ingestion_health · v_vehicles_not_moved_today
          v_driver_aggregates_daily · v_fleet_trace · v_driver_clock_*"] + end + LP --> GV + TR --> GV + DV --> GV + AL --> GV + PH --> GV + + subgraph L4["L4 · Functions — reporting.* (the only API entrypoints)"] + FLP["fn_live_positions(cost_centre, acc_status)"] + FVT["fn_vehicle_track(vehicle_number, hours)"] + FTM["fn_trips_for_map(veh[], driver, cc, city, start, end)"] + NP["normalize_plate(p) · helper"] + end + LP --> FLP + DV --> FLP + PH --> FVT + VT --> FTM + NP -.-> FTM + + subgraph L5["L5 · Consumers"] + DAPI["dashboard_api_rev.py
          FastAPI :8890 · 2 workers"] + SPA["SPAs: liveposition.* · fleetintelligence.*
          (rustfs / S3 single-file maps)"] + GRAF["Grafana"] + end + FLP --> DAPI + FVT --> DAPI + FTM --> DAPI + FILT --> DAPI + DAPI -->|"HTTPS · fleetapi.rahamafresh.com"| SPA + GV --> GRAF + + CAGG -.->|no consumer yet| NONE(["⚠ unconsumed — no panel / API reads it"]) + + subgraph PARK["REMOVED 2026-06-05 — purged via migrations 12 / 13 (never implemented)"] + GONE["ops.* (tickets · dispatch_log · service_log · odometer_readings · cost_rates · kpi_targets · vw_service_forecast)
          dwh_gold.* (dim_vehicles · fact_daily_fleet_metrics · refresh_daily_metrics)
          tracksolid.v_sla_inflight · tracksolid.v_utilisation_daily + their Grafana panels"] + end + + classDef hyper fill:#e1f0ff,stroke:#3b82f6,color:#0b3d91; + classDef mat fill:#fff3cd,stroke:#d4a017,color:#664d03; + classDef cagg fill:#e7f7e7,stroke:#2e9e2e,color:#1e5e1e; + classDef parked fill:#f0f0f0,stroke:#999,stroke-dasharray:5 5,color:#555; + classDef warn fill:#fdecea,stroke:#d93025,color:#a52714; + class PH hyper; + class VT mat; + class CAGG cagg; + class PARK,GONE parked; + class NONE warn; +``` + +--- + +## ASCII + +``` + ╔══════════════════════════════════════════════╗ + ║ TRACKSOLID / JIMI API ║ + ║ (poll + push webhooks, OAuth2) ║ + ╚════════════════════╤═════════════════════════╝ + │ + ┌──────────────────────────┬───────────┴───────────┬────────────────────────────┐ + ▼ ▼ ▼ ▼ +┌─────────────────┐ ┌────────────────────┐ ┌──────────────────────┐ +│ ingest_movement │ │ ingest_events │ │ webhook_receiver │ (all via ts_shared_rev.py: +│ _rev.py │ │ _rev.py │ │ _rev.py │ get_conn() pool, api_post(), +└────────┬────────┘ └─────────┬──────────┘ └──────────┬───────────┘ clean*() , token cache) + │ │ │ + │ writes │ writes │ writes (push) + ▼ ▼ ▼ +╔════════════════════════════════════════════════════════════════════════════════════════════╗ +║ L1 · BASE TABLES + HYPERTABLES schema: tracksolid (single source of truth) ║ +║ ║ +║ live_positions ── current fix / IMEI (plain) api_token_cache (auth) ║ +║ position_history ◀═══ HYPERTABLE (high-res GPS trail, partitioned by gps_time) ║ +║ trips ── trip summaries (plain table — NOT a hypertable) ║ +║ devices ── vehicle/driver registry (plain) ║ +║ alarms ── alarm events (plain table) ║ +║ ingestion_log ── API audit trail (plain) ║ +║ heartbeats*, fuel_readings*, temperature_readings* ◀═ HYPERTABLES (empty / planned push) ║ +║ device_events, fault_codes, obd_readings, parking_events, lbs_readings, geofences (empty) ║ +╚══════╤══════════════════════════╤══════════════════════════════════╤════════════════════════╝ + │ │ │ + │ TimescaleDB │ matview refresh │ direct reads + │ cont-agg policy │ (in-app loop) │ (Grafana SQL) + ▼ ▼ ▼ +╔══════════════════╗ ╔════════════════════════════════╗ ╔══════════════════════════════════╗ +║ L2 · AGGREGATION ║ ║ L2 · AGGREGATION (matview) ║ ║ L3 · GRAFANA VIEWS (tracksolid.*) ║ +║ ║ ║ ║ ║ read base tables directly ║ +║ v_mileage_daily ║ ║ reporting.v_trips [MATVIEW] ║ ║ ║ +║ _cagg ║ ║ ◀── trips + devices ║ ║ v_fleet_today v_fleet_status ║ +║ CONTINUOUS AGG ║ ║ unique ix_v_trips_trip_id ║ ║ v_active_dispatch_map ║ +║ ◀═ position_ ║ ║ ║ ║ v_currently_idle v_alarms_daily ║ +║ history ║ ║ REFRESH … CONCURRENTLY every ║ ║ v_fleet_km_daily v_ingestion_health║ +║ (auto refresh ║ ║ VTRIPS_REFRESH_INTERVAL_S=300 ║ ║ v_vehicles_not_moved_today ║ +║ policy) ║ ║ by dashboard_api bg asyncio ║ ║ v_driver_aggregates_daily ║ +╚════════╤═════════╝ ║ loop, pg advisory-lock 920145 ║ ║ v_fleet_trace ║ + │ ║ │ ║ ║ v_driver_clock_daily/_today/_attnd ║ + │ ║ └──▶ reporting.refresh_log ║ ╚══════════════╤═════════════════════╝ + │ ╚═══════════════╤════════════════╝ │ + │ │ │ + │ ▼ │ + │ ╔════════════════════════════════════════════╗ │ + │ ║ L3 · REPORTING VIEWS (← v_trips matview) ║ │ + │ ║ v_filter_vehicles v_filter_drivers ║ │ + │ ║ v_filter_cost_centres v_filter_cities ║ │ + │ ║ v_daily/weekly/monthly_summary ║ │ + │ ║ v_*_cost_centre v_trips_today ║ │ + │ ║ v_live_positions (view, ← live_positions) ║ │ + │ ╚════════════════════════╤═══════════════════╝ │ + │ │ │ + │ ╔══════════════════════════════════╧═══════════════════╗ │ + │ ║ L4 · FUNCTIONS (schema reporting — API entrypoints) ║ │ + │ ║ ║ │ + │ ║ fn_live_positions(cost_centre, acc_status) ║ │ + │ ║ ◀── live_positions + devices ║ │ + │ ║ fn_vehicle_track(vehicle_number, hours) ║ │ + │ ║ ◀── position_history (hypertable trail) ────────╫─────┘ (also reads L1) + │ ║ fn_trips_for_map(veh[],driver,cc,city,start,end) ║ + │ ║ ◀── reporting.v_trips (matview) ║ + │ ║ normalize_plate(p) ── helper used by the above ║ + │ ╚════════════════════════════╤══════════════════════════╝ + │ │ + ▼ ▼ + (cagg currently ╔═══════════════════════════════════════════════╗ + unconsumed — ║ L5 · CONSUMERS ║ + no panel/API yet) ║ ║ + ║ dashboard_api_rev.py (FastAPI :8890, ×2 wkrs) ║ + ║ POST /webhook/fleet-dashboard → fn_trips_for_map + v_filter_* + ║ GET /webhook/live-positions → fn_live_positions + ║ GET /webhook/live-positions/track → fn_vehicle_track + ║ │ ║ + ║ ▼ HTTPS (fleetapi.rahamafresh.com) ║ + ║ SPAs: liveposition.* · fleetintelligence.* ║ + ║ (rustfs/S3 single-file maps) ║ + ║ ║ + ║ Grafana ──SQL──▶ tracksolid.v_* (L3 right) ║ + ╚═══════════════════════════════════════════════╝ + + + ┌─ REMOVED 2026-06-05 · purged via migrations 12 / 13 (never implemented) ───────────────┐ + │ ops.* : tickets, dispatch_log, service_log, odometer_readings, │ + │ cost_rates, kpi_targets, vw_service_forecast │ + │ dwh_gold.* : dim_vehicles, fact_daily_fleet_metrics, refresh_daily_metrics() │ + │ tracksolid : v_sla_inflight, v_utilisation_daily (+ their Grafana panels removed) │ + │ → Schemas dropped from prod. The separate tracksolid_dwh server is unrelated/untouched.│ + └────────────────────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## How to read it + +- **L1** is where ingestion lands. Only `position_history` (and three empty/planned + hypertables) are TimescaleDB hypertables; `trips`/`alarms` are ordinary tables. +- **Two aggregation mechanisms** run in parallel: the TimescaleDB **continuous aggregate** + `v_mileage_daily_cagg` (refreshed by a Timescale policy off `position_history`), and the + **`reporting.v_trips` matview** (refreshed every 5 min by the in-process `dashboard_api` + loop — the FIX-D02 self-refresher that replaced the dead n8n job). +- **L4 functions are the only thing the API calls.** SPAs never touch tables directly: + SPA → `dashboard_api` → `fn_*` → (matview / tables). +- **Grafana** takes the right-hand path, reading the `tracksolid.v_*` analytics views + straight off L1. + +## Caveats / housekeeping notes + +1. **`v_mileage_daily_cagg` has no consumer** — nothing in the API or Grafana reads it. It + is a live continuous aggregate maintaining itself for nobody. Candidate for removal or + wiring into a panel. +2. **`ops` and `dwh_gold` were purged** (2026-06-05, migrations 12/13) along with + `v_utilisation_daily`, `v_sla_inflight`, and their Grafana panels — the features were + never implemented. +3. See the companion housekeeping audit (2026-06-05) for the full unused-object list; the + only clean ad-hoc drop is `public.trips_viz_v1`. diff --git a/docs/PLATFORM_OVERVIEW.html b/docs/PLATFORM_OVERVIEW.html index 600e3b4..a4ad785 100644 --- a/docs/PLATFORM_OVERVIEW.html +++ b/docs/PLATFORM_OVERVIEW.html @@ -84,7 +84,7 @@ proxy container. The dashboard_api enforces CORS for both SPA origins.

          Operational note. dashboard_api currently runs as a standalone Traefik-labelled container reusing the app image with dashboard_api_rev.py bind-mounted. The durable form is the compose dashboard_api service (already in docker-compose.yaml) once the branch is merged and the fleetapi domain is set in Coolify.

          4 · Read-API reference (dashboard_api)

          Base: https://fleetapi.rahamafresh.com · all responses JSON · CORS limited to the two SPA origins.

          MethodPathParamsReturnsNotes
          GET/health{status: ok}Liveness probe.
          GET/webhook/live-positionscost_centre?, acc_status?{summary, geojson}Live Positions map feed → reporting.fn_live_positions. ~80 vehicle point features.
          GET/webhook/live-positions/trackvehicle_number, hours(1-24)GeoJSON Feature (LineString)One vehicle's recent trail. Alias: /webhook/vehicle-track.
          GET/webhook/vehicle-trackvehicle_number, hoursGeoJSON FeatureAlias of live-positions/track (kept for compatibility).
          GET/webhook/fleet-dashboard{drivers, cost_centres, cities, vehicles}Filter options for the Fleet Intelligence UI.
          POST/webhook/fleet-dashboardform-urlencoded: period|start_date|end_date, vehicle_numbers, driver, cost_centre, assigned_citytrips GeoJSON payloadTrips for the map → reporting.fn_trips_for_map. period preset: today|7d|30d|custom. Body parsed by Content-Type — the SPA posts application/x-www-form-urlencoded; JSON also accepted.
          -
          Fix (2026-06-05). The POST handler originally read the body as JSON only, but the SPA sends x-www-form-urlencoded; the mismatch silently dropped every filter so the map always returned the whole fleet. Now parsed by Content-Type (parse_qs for form bodies). Commit f1387d1.

          5 · Database schema

          tracksolid · Live data — the single source of truth. Ingested from the Tracksolid API.

          18 table(s) · 17 view(s) · 1 function(s) documented.

          tracksolid.alarmstable344,356 rows

          Alarm events (alarm_type, alarm_name, alarm_time).

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('alarms_id_seq'::regclass)
          imeitext
          alarm_typetext
          alarm_timetimestamp with time zone
          geomgeometry(Point,4326)
          latdouble precision
          lngdouble precision
          speednumeric(7,2)
          acc_statustext
          updated_attimestamp with time zonenow()
          alarm_nametext
          sourcetext'poll'::text
          severitytextAlarm severity level: critical | warning | info
          geofence_idtextTracksolid geofence ID if this is a geofence alarm
          geofence_nametextHuman-readable geofence name
          acknowledged_attimestamp with time zoneTimestamp when alarm was acknowledged by an operator
          acknowledged_bytextUsername or ID of operator who acknowledged the alarm
          tracksolid.api_token_cachetable1 rows

          OAuth2 token cache for the Jimi/Tracksolid API.

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('api_token_cache_id_seq'::regclass)
          accounttextNOT NULL
          access_tokentextNOT NULL
          refresh_tokentext
          app_keytext
          expires_attimestamp with time zoneNOT NULL
          obtained_attimestamp with time zoneNOT NULLnow()
          updated_attimestamp with time zoneNOT NULLnow()
          tracksolid.device_eventstable0 rows

          Device network connection and disconnection events from /pushevent webhook.

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('device_events_id_seq'::regclass)
          imeitextNOT NULL
          event_typetextNOT NULLLOGIN = device connected to network; LOGOUT = device disconnected
          event_timetimestamp with time zoneNOT NULL
          timezonetext
          created_attimestamp with time zoneNOT NULLnow()
          tracksolid.devicestable181 rows

          Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.

          ColumnTypeNullDefaultComment
          imeitextNOT NULL
          device_nametext
          mc_typetext
          mc_type_use_scopetext
          vehicle_nametext
          vehicle_numbertext
          vehicle_modelstext
          vehicle_icontext
          vintext
          engine_numbertext
          vehicle_brandtext
          fuel_100kmnumeric(6,2)
          driver_nametext
          driver_phonetext
          simtext
          iccidtext
          imsitext
          accounttext
          customer_nametext
          device_group_idtext
          device_grouptext
          activation_timetimestamp with time zone
          expirationtimestamp with time zone
          enabled_flagsmallintNOT NULL1
          statustext'active'::text
          citytext
          current_mileage_kmnumeric(12,2)
          created_attimestamp with time zoneNOT NULLnow()
          updated_attimestamp with time zoneNOT NULLnow()
          last_synced_attimestamp with time zone
          vehicle_categorytextVehicle type: truck | van | motorcycle | car | other
          cost_centretextBusiness unit or department this vehicle belongs to
          assigned_routetextRegular route name or ID for route-based reporting
          depot_geomgeometry(Point,4326)Home base/depot coordinates (WGS84)
          depot_addresstextHuman-readable depot address
          assigned_citytextOperating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection.
          tracksolid.dispatch_logtable0 rows

          Persistent record of every dispatch decision. Powers SLA metrics: dispatch latency, depart delay, time-to-site, wrench time.

          ColumnTypeNullDefaultComment
          dispatch_idbigintNOT NULLnextval('dispatch_log_dispatch_id_seq'::regclass)
          ticket_idtextNOT NULL
          imeitextNOT NULL
          driver_nametext
          job_latdouble precisionNOT NULL
          job_lngdouble precisionNOT NULL
          job_geomgeometry(Point,4326)
          assigned_attimestamp with time zoneNOT NULLnow()
          first_movement_attimestamp with time zoneFirst trip start after assigned_at. Back-filled nightly from trips.
          on_site_attimestamp with time zoneTime vehicle entered 150 m radius of job_geom. Back-filled nightly.
          resolved_attimestamp with time zoneTicket close time from the ops system (ops.tickets.closed_at).
          cancelled_attimestamp with time zone
          distance_kmnumeric(8,2)
          created_attimestamp with time zoneNOT NULLnow()
          tracksolid.fault_codestable0 rows

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('fault_codes_id_seq'::regclass)
          imeitextNOT NULL
          reported_attimestamp with time zoneNOT NULL
          fault_codetextNOT NULL
          status_flagsinteger
          latdouble precision
          lngdouble precision
          geomgeometry(Point,4326)
          event_timetimestamp with time zone
          created_attimestamp with time zoneNOT NULLnow()
          tracksolid.fuel_readingshypertable~0 rows

          Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.

          ColumnTypeNullDefaultComment
          imeitextNOT NULL
          reading_timetimestamp with time zoneNOT NULL
          sensor_pathtextSensor channel identifier from the device (path field in API payload)
          valuenumeric(10,3)
          unittextMeasurement unit: cm (tank depth), % (percentage), V (voltage), L (litres)
          latdouble precision
          lngdouble precision
          geomgeometry(Point,4326)
          created_attimestamp with time zoneNOT NULLnow()
          tracksolid.geofencestable0 rows

          Geofence boundary definitions synced from the Tracksolid platform.

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('geofences_id_seq'::regclass)
          fence_idtext
          fence_nametextNOT NULL
          fence_typetextcircle | polygon
          geomgeometry(Geometry,4326)
          radius_mnumeric(10,2)Radius in metres — only applicable for circle type geofences
          descriptiontext
          created_attimestamp with time zoneNOT NULLnow()
          updated_attimestamp with time zoneNOT NULLnow()
          tracksolid.heartbeatshypertable~0 rows

          Device heartbeat hypertable.

          ColumnTypeNullDefaultComment
          imeitextNOT NULL
          gate_timetimestamp with time zoneNOT NULL
          power_levelsmallint
          gsm_signalsmallint
          acc_statussmallint
          power_statussmallint
          fortifysmallint
          created_attimestamp with time zoneNOT NULLnow()
          tracksolid.ingestion_logtable274,181 rows

          API call audit trail — one row per ingestion run.

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('ingestion_log_id_seq'::regclass)
          run_attimestamp with time zoneNOT NULLnow()
          endpointtextNOT NULL
          imei_countintegerNOT NULL0
          rows_upsertedintegerNOT NULL0
          rows_insertedintegerNOT NULL0
          duration_msintegerNOT NULL0
          successbooleanNOT NULLtrue
          error_codetext
          error_messagetext
          tracksolid.lbs_readingstable0 rows

          Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('lbs_readings_id_seq'::regclass)
          imeitextNOT NULL
          gate_timetimestamp with time zoneNOT NULL
          post_typetextPositioning technology: WIFI | LBS (cell tower)
          lbs_datajsonbRaw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding.
          created_attimestamp with time zoneNOT NULLnow()
          tracksolid.live_positionstable179 rows

          Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.

          ColumnTypeNullDefaultComment
          imeitextNOT NULL
          geomgeometry(Point,4326)
          latdouble precision
          lngdouble precision
          pos_typetext
          confidencesmallint
          gps_timetimestamp with time zone
          hb_timetimestamp with time zone
          speednumeric(7,2)
          directionnumeric(6,2)
          acc_statustext
          gps_signalsmallint
          gps_numsmallint
          elec_quantitynumeric(5,2)
          power_valuenumeric(5,2)
          battery_power_valnumeric(5,2)
          tracker_oiltext
          temperaturenumeric(8,2)
          current_mileagenumeric(12,2)
          device_statustext
          expire_flagtext
          activation_flagtext
          loc_desctext
          recorded_attimestamp with time zoneNOT NULLnow()
          updated_attimestamp with time zoneNOT NULLnow()
          tracksolid.obd_readingstable0 rows

          OBD diagnostics — push only via /pushobd webhook.

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('obd_readings_id_seq'::regclass)
          imeitext
          reading_timetimestamp with time zone
          engine_rpmintegerEngine RPM from OBD PID 0x0C
          fuel_level_pctnumeric(5,2)Fuel tank level % from OBD PID 0x2F
          updated_attimestamp with time zonenow()
          car_typesmallint
          acc_statesmallint
          status_flagsinteger
          latdouble precision
          lngdouble precision
          geomgeometry(Point,4326)
          obd_datajsonbRaw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.)
          coolant_temp_cnumeric(6,2)Coolant temperature °C from OBD PID 0x05
          battery_voltagenumeric(5,2)Battery voltage (V) from OBD PID 0x42
          intake_pressurenumeric(6,2)Intake manifold pressure kPa from OBD PID 0x0B
          throttle_pctnumeric(5,2)Throttle position % from OBD PID 0x11
          vehicle_speednumeric(7,2)Vehicle speed km/h from OBD PID 0x0D
          engine_load_pctnumeric(5,2)Calculated engine load % from OBD PID 0x04
          tracksolid.parking_eventstable0 rows

          Stop events with duration + address.

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('parking_events_id_seq'::regclass)
          imeitextNOT NULL
          event_typetext
          start_timetimestamp with time zoneNOT NULL
          end_timetimestamp with time zone
          duration_secondsinteger
          geomgeometry(Point,4326)
          addresstext
          updated_attimestamp with time zonenow()
          tracksolid.position_historyhypertable~3,596,013 rows

          All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).

          ColumnTypeNullDefaultComment
          imeitextNOT NULL
          gps_timetimestamp with time zoneNOT NULL
          geomgeometry(Point,4326)
          latdouble precision
          lngdouble precision
          speednumeric(7,2)
          directionnumeric(6,2)
          acc_statustext
          satellitesmallint
          current_mileagenumeric(12,2)
          recorded_attimestamp with time zonenow()
          altitudenumeric(8,2)
          post_typesmallint
          sourcetext'poll'::text
          tracksolid.schema_migrationstable9 rows

          ColumnTypeNullDefaultComment
          filenametextNOT NULL
          applied_attimestamp with time zoneNOT NULLnow()
          tracksolid.temperature_readingshypertable~0 rows

          Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.

          ColumnTypeNullDefaultComment
          imeitextNOT NULL
          reading_timetimestamp with time zoneNOT NULL
          temperaturenumeric(6,2)
          humidity_pctnumeric(5,2)
          created_attimestamp with time zoneNOT NULLnow()
          tracksolid.tripstable43,765 rows

          Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).

          ColumnTypeNullDefaultComment
          idbigintNOT NULLnextval('trips_id_seq'::regclass)
          imeitextNOT NULL
          start_timetimestamp with time zoneNOT NULL
          end_timetimestamp with time zone
          start_geomgeometry(Point,4326)
          end_geomgeometry(Point,4326)
          distance_kmnumeric(12,2)Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10).
          avg_speed_kmhnumeric(7,2)
          max_speed_kmhnumeric(7,2)
          updated_attimestamp with time zonenow()
          fuel_consumed_lnumeric(8,2)
          idle_time_sinteger
          driving_time_sintegerrunTimeSecond from API: total driving time in seconds
          trip_seqinteger
          sourcetext'poll'::textpoll = from API polling, push = from webhook push
          route_geomgeometry(LineString,4326)Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window.
          start_addresstextReverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
          end_addresstextReverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
          vehicle_platetextDenormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest.
          waypoints_countintegerNumber of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate.
          tracksolid.v_active_dispatch_mapview

          01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.

          ColumnTypeNullDefaultComment
          imeitext
          vehicle_numbertext
          vehicle_nametext
          driver_nametext
          driver_phonetext
          assigned_citytext
          latdouble precision
          lngdouble precision
          speednumeric(7,2)
          directionnumeric(6,2)
          acc_statustext
          last_fixtimestamp without time zone
          statustext
          tracksolid.v_alarms_dailyview

          01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.

          ColumnTypeNullDefaultComment
          daydate
          alarm_nametext
          alarm_countbigint
          tracksolid.v_currently_idleview

          01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.

          ColumnTypeNullDefaultComment
          imeitext
          vehicle_numbertext
          driver_nametext
          assigned_citytext
          latdouble precision
          lngdouble precision
          sincetimestamp without time zone
          idle_secondsinteger
          tracksolid.v_driver_aggregates_dailyview

          01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).

          ColumnTypeNullDefaultComment
          imeitext
          driver_nametext
          vehicle_numbertext
          assigned_citytext
          daydate
          kmnumeric
          tripsbigint
          events_80bigint
          events_100bigint
          events_120bigint
          harsh_eventsbigint
          speeding_per_100kmnumeric
          harsh_per_100kmnumeric
          tracksolid.v_driver_attendance_dailyview

          ColumnTypeNullDefaultComment
          report_datedate
          driver_nametext
          vehicle_numbertext
          cost_centretext
          assigned_citytext
          reporting_timetime without time zone
          start_addresstext
          start_latdouble precision
          start_lngdouble precision
          statustext
          mins_from_startinteger
          tracksolid.v_driver_clock_dailyview

          Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).

          ColumnTypeNullDefaultComment
          imeitext
          driver_nametext
          vehicle_numbertext
          cost_centretext
          assigned_citytext
          report_datedate
          reporting_timetime without time zone
          closing_timetime without time zone
          reporting_tstimestamp with time zone
          closing_tstimestamp with time zone
          start_latdouble precision
          start_lngdouble precision
          start_addresstext
          end_latdouble precision
          end_lngdouble precision
          end_addresstext
          trips_countbigint
          total_kmnumeric
          drive_hoursnumeric
          tracksolid.v_driver_clock_todayview

          Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

          ColumnTypeNullDefaultComment
          imeitext
          driver_nametext
          vehicle_numbertext
          cost_centretext
          assigned_citytext
          report_datedate
          reporting_timetime without time zone
          closing_timetime without time zone
          reporting_tstimestamp with time zone
          closing_tstimestamp with time zone
          start_latdouble precision
          start_lngdouble precision
          start_addresstext
          end_latdouble precision
          end_lngdouble precision
          end_addresstext
          trips_countbigint
          total_kmnumeric
          drive_hoursnumeric
          tracksolid.v_fleet_km_dailyview

          01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.

          ColumnTypeNullDefaultComment
          daydate
          assigned_citytext
          kmnumeric
          active_vehiclesbigint
          tripsbigint
          tracksolid.v_fleet_statusview

          ColumnTypeNullDefaultComment
          imeitext
          vehicle_numbertext
          driver_nametext
          latdouble precision
          lngdouble precision
          geomgeometry(Point,4326)
          speednumeric(7,2)
          acc_statustext
          gps_timetimestamp with time zone
          connectivity_statustext
          seconds_since_fixinteger
          tracksolid.v_fleet_todayview

          01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.

          ColumnTypeNullDefaultComment
          imeitext
          driver_nametext
          vehicle_numbertext
          vehicle_nametext
          assigned_citytext
          enabled_flagsmallint
          km_todaynumeric
          trips_todaybigint
          drive_hoursnumeric
          idle_hoursnumeric
          first_departuretime without time zone
          last_returntime without time zone
          alarms_todaybigint
          last_fixtimestamp without time zone
          last_speednumeric(7,2)
          did_not_moveboolean
          tracksolid.v_fleet_traceview

          ColumnTypeNullDefaultComment
          gidbigint
          driver_nametext
          vehicle_nametext
          device_nametext
          imeitext
          geomgeometry(Point,4326)
          latnumeric
          lngnumeric
          start_timetimestamp without time zone
          end_timetimestamp without time zone
          day_localdate
          hour_localinteger
          dow_localinteger
          gps_time_utctimestamp with time zone
          recorded_attimestamp with time zone
          speednumeric(7,2)
          directionnumeric(6,2)
          current_mileagenumeric(12,2)
          stationaryboolean
          trip_idbigint
          tracksolid.v_ingestion_healthview

          ColumnTypeNullDefaultComment
          endpointtext
          run_attimestamp with time zone
          successboolean
          error_messagetext
          seconds_agointeger
          tracksolid.v_mileage_daily_caggview

          ColumnTypeNullDefaultComment
          buckettimestamp with time zone
          imeitext
          dist_kmnumeric
          avg_speednumeric
          tracksolid.v_sla_inflightview

          01_BusinessAnalytics.md §4.5 Field-Service SLA Metrics. Open tickets + last 24h resolved.

          ColumnTypeNullDefaultComment
          ticket_idtext
          customertext
          prioritytext
          job_typetext
          statustext
          created_attimestamp with time zone
          assigned_attimestamp with time zone
          closed_attimestamp with time zone
          assigned_imeitext
          driver_nametext
          first_movement_attimestamp with time zone
          on_site_attimestamp with time zone
          resolved_attimestamp with time zone
          dispatch_minsnumeric
          enroute_minsnumeric
          onsite_minsnumeric
          resolution_minsnumeric
          ticket_stagetext
          tracksolid.v_trips_enrichedview

          tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.

          ColumnTypeNullDefaultComment
          idbigint
          imeitext
          start_timetimestamp with time zone
          end_timetimestamp with time zone
          start_geomgeometry(Point,4326)
          end_geomgeometry(Point,4326)
          distance_kmnumeric(12,2)
          avg_speed_kmhnumeric(7,2)
          max_speed_kmhnumeric(7,2)
          updated_attimestamp with time zone
          fuel_consumed_lnumeric(8,2)
          idle_time_sinteger
          driving_time_sinteger
          trip_seqinteger
          sourcetext
          route_geomgeometry(LineString,4326)
          start_addresstext
          end_addresstext
          vehicle_platetext
          waypoints_countinteger
          trip_date_eatdate
          daily_seqbigint
          tracksolid.v_utilisation_dailyview

          01_BusinessAnalytics.md §7 Panel 8 Utilisation Heatmap. Empty until nightly ETL runs.

          ColumnTypeNullDefaultComment
          daydate
          imeitext
          vehicle_numbertext
          driver_nametext
          assigned_citytext
          total_distance_kmnumeric(12,2)
          total_drive_hoursnumeric(8,2)
          total_idle_hoursnumeric(8,2)
          alarm_countinteger
          overspeed_countinteger
          utilisation_pctnumeric
          tracksolid.v_vehicles_not_moved_todayview

          01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.

          ColumnTypeNullDefaultComment
          imeitext
          vehicle_nametext
          vehicle_numbertext
          driver_nametext
          assigned_citytext
          last_seentimestamp without time zone
          speednumeric(7,2)
          tracksolid.set_updated_at(…)function · plpgsql

          arguments()
          returnstrigger

          reporting · Read layer that backs the map dashboards (consumed by dashboard_api).

          2 table(s) · 12 view(s) · 4 function(s) documented.

          reporting.refresh_logtable3,558 rows

          One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. Written by dashboard_api's built-in refresher (source='dashboard_api', every 5 min); the retired n8n job (source='n8n') was the previous writer. Read MAX(refreshed_at) for staleness.

          ColumnTypeNullDefaultComment
          refreshed_attimestamp with time zoneNOT NULLnow()
          sourcetextNOT NULL'n8n'::text
          duration_msinteger
          row_countinteger
          notestext
          reporting.v_tripsmatview31,670 rows

          Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.

          ColumnTypeNullDefaultComment
          trip_idbigint
          imeitext
          device_nametext
          vehicle_numbertext
          vehicle_modelstext
          vehicle_categorytext
          cost_centretext
          assigned_citytext
          assigned_drivertext
          start_timetimestamp without time zone
          end_timetimestamp without time zone
          trip_datedate
          start_hourinteger
          start_dowinteger
          daily_seqbigint
          distance_kmnumeric(12,2)
          avg_speed_kmhnumeric(7,2)
          max_speed_kmhnumeric(7,2)
          idle_time_sinteger
          driving_time_sinteger
          fuel_consumed_lnumeric(8,2)
          waypoints_countinteger
          start_addresstext
          end_addresstext
          start_geomgeometry(Point,4326)
          end_geomgeometry(Point,4326)
          route_geomgeometry(LineString,4326)
          route_geojsonjson
          is_meaningful_routeboolean
          updated_attimestamp without time zone
          reporting.v_daily_cost_centreview

          Cost-centre × day rollup. Excludes trips with NULL cost_centre.

          ColumnTypeNullDefaultComment
          trip_datedate
          cost_centretext
          active_vehiclesbigint
          active_driversbigint
          trip_countbigint
          total_kmnumeric
          driving_hoursnumeric
          idle_hoursnumeric
          idle_pctnumeric
          km_per_vehiclenumeric
          reporting.v_daily_summaryview

          Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.

          ColumnTypeNullDefaultComment
          trip_datedate
          cost_centretext
          assigned_citytext
          vehicle_numbertext
          assigned_drivertext
          trip_countbigint
          total_kmnumeric
          driving_hoursnumeric
          idle_hoursnumeric
          idle_pctnumeric
          first_trip_starttimestamp without time zone
          last_trip_endtimestamp without time zone
          avg_speed_kmhnumeric
          max_speed_kmhnumeric
          day_routes_geojsonjson
          reporting.v_filter_citiesview

          Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.

          ColumnTypeNullDefaultComment
          assigned_citytext
          reporting.v_filter_cost_centresview

          Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.

          ColumnTypeNullDefaultComment
          cost_centretext
          reporting.v_filter_driversview

          Driver dropdown source for the n8n dashboard. Distinct non-null drivers.

          ColumnTypeNullDefaultComment
          drivertext
          reporting.v_filter_vehiclesview

          Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.

          ColumnTypeNullDefaultComment
          vehicle_numbertext
          driverstext
          cost_centretext
          assigned_citytext
          reporting.v_live_positionsview

          Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.

          ColumnTypeNullDefaultComment
          imeitext
          vehicle_numbertext
          assigned_drivertext
          cost_centretext
          assigned_citytext
          vehicle_categorytext
          vehicle_modelstext
          mc_typetext
          device_kindtext
          latdouble precision
          lngdouble precision
          speednumeric(7,2)
          directionnumeric(6,2)
          acc_statustext
          device_statustext
          gps_signalsmallint
          gps_numsmallint
          current_mileagenumeric(12,2)
          loc_desctext
          gps_timetimestamp with time zone
          updated_attimestamp with time zone
          gps_time_eattimestamp without time zone
          updated_at_eattimestamp without time zone
          source_age_hoursnumeric
          reporting.v_monthly_cost_centreview

          Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.

          ColumnTypeNullDefaultComment
          month_startdate
          month_labeltext
          cost_centretext
          active_vehiclesbigint
          active_driversbigint
          active_daysbigint
          trip_countbigint
          total_kmnumeric
          driving_hoursnumeric
          idle_hoursnumeric
          idle_pctnumeric
          km_per_vehiclenumeric
          reporting.v_monthly_summaryview

          Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).

          ColumnTypeNullDefaultComment
          month_startdate
          month_labeltext
          cost_centretext
          assigned_citytext
          vehicle_categorytext
          vehicle_numbertext
          assigned_drivertext
          trip_countbigint
          active_daysbigint
          total_kmnumeric
          driving_hoursnumeric
          idle_hoursnumeric
          idle_pctnumeric
          km_per_active_daynumeric
          km_per_tripnumeric
          avg_speed_kmhnumeric
          peak_speed_kmhnumeric
          reporting.v_trips_todayview

          Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

          ColumnTypeNullDefaultComment
          trip_idbigint
          imeitext
          device_nametext
          vehicle_numbertext
          vehicle_modelstext
          vehicle_categorytext
          cost_centretext
          assigned_citytext
          assigned_drivertext
          start_timetimestamp without time zone
          end_timetimestamp without time zone
          trip_datedate
          start_hourinteger
          start_dowinteger
          daily_seqbigint
          distance_kmnumeric(12,2)
          avg_speed_kmhnumeric(7,2)
          max_speed_kmhnumeric(7,2)
          idle_time_sinteger
          driving_time_sinteger
          fuel_consumed_lnumeric(8,2)
          waypoints_countinteger
          start_addresstext
          end_addresstext
          start_geomgeometry(Point,4326)
          end_geomgeometry(Point,4326)
          route_geomgeometry(LineString,4326)
          route_geojsonjson
          is_meaningful_routeboolean
          updated_attimestamp without time zone
          reporting.v_weekly_cost_centreview

          Cost-centre × week rollup. Excludes trips with NULL cost_centre.

          ColumnTypeNullDefaultComment
          week_startdate
          cost_centretext
          active_vehiclesbigint
          active_driversbigint
          active_daysbigint
          trip_countbigint
          total_kmnumeric
          driving_hoursnumeric
          idle_hoursnumeric
          idle_pctnumeric
          km_per_vehiclenumeric
          reporting.v_weekly_summaryview

          Vehicle × week rollup. Numeric only, no geometry.

          ColumnTypeNullDefaultComment
          week_startdate
          cost_centretext
          assigned_citytext
          vehicle_numbertext
          assigned_drivertext
          trip_countbigint
          active_daysbigint
          total_kmnumeric
          driving_hoursnumeric
          idle_hoursnumeric
          avg_trip_kmnumeric
          reporting.fn_live_positions(…)function · plpgsql

          Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.

          argumentsp_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text
          returnsjsonb
          reporting.fn_trips_for_map(…)function · plpgsql

          Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.

          argumentsp_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date
          returnsjsonb
          reporting.fn_vehicle_track(…)function · sql

          Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.

          argumentsp_vehicle_number text, p_hours integer DEFAULT 1
          returnsjsonb
          reporting.normalize_plate(…)function · sql

          Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.

          argumentsp text
          returnstext

          ops · Workshop / tickets / odometer integrations.

          5 table(s) · 1 view(s) · 0 function(s) documented.

          ops.cost_ratestable3 rows

          Reference rates for analytics monetisation: fuel price per litre by city, labour cost per hour by role. Resolution order in views: scope_type=city > scope_type=role > scope_type=global.

          ColumnTypeNullDefaultComment
          rate_keytextNOT NULL
          scope_typetextNOT NULLcity | role | global
          scope_valuetext
          metrictextNOT NULLfuel_per_litre | labour_per_hour
          amountnumeric(12,2)NOT NULL
          currencytextNOT NULL
          effective_fromdateNOT NULLCURRENT_DATE
          notestext
          created_attimestamp with time zoneNOT NULLnow()
          updated_attimestamp with time zoneNOT NULLnow()
          ops.kpi_targetstable12 rows

          Traffic-light targets per KPI per scope. Resolution order in views: cost_centre > vehicle_category > city > global.

          ColumnTypeNullDefaultComment
          target_idbigintNOT NULLnextval('ops.kpi_targets_target_id_seq'::regclass)
          kpi_keytextNOT NULL
          scope_typetextNOT NULL
          scope_valuetext
          target_valuenumeric(12,2)NOT NULL
          amber_thresholdnumeric(12,2)
          red_thresholdnumeric(12,2)
          directiontextNOT NULL'higher_is_better'::texthigher_is_better -> green when value >= target. lower_is_better -> green when value <= target.
          effective_fromdateNOT NULLCURRENT_DATE
          notestext
          created_attimestamp with time zoneNOT NULLnow()
          updated_attimestamp with time zoneNOT NULLnow()
          ops.odometer_readingstable0 rows

          Physical odometer captures from service, fuel card, or manual entry. Powers §3.8 Odometer Divergence audit.

          ColumnTypeNullDefaultComment
          reading_idbigintNOT NULLnextval('ops.odometer_readings_reading_id_seq'::regclass)
          imeitextNOT NULL
          reading_datedateNOT NULL
          reading_kmintegerNOT NULL
          sourcetextservice | fuel_card | driver_manual | workshop_form
          recorded_bytext
          created_attimestamp with time zoneNOT NULLnow()
          ops.service_logtable0 rows

          Workshop service history. Powers §10 Service-Interval Forecaster.

          ColumnTypeNullDefaultComment
          service_idbigintNOT NULLnextval('ops.service_log_service_id_seq'::regclass)
          imeitextNOT NULL
          service_datedateNOT NULL
          odometer_kmintegerNOT NULLPhysical odometer reading at service time (integer km).
          service_typetextscheduled | repair | tyre | bodywork | inspection | other
          cost_kesinteger
          notestext
          created_attimestamp with time zoneNOT NULLnow()
          ops.ticketstable0 rows

          Skeleton for ticket data sourced from the Fireside ops system. Replace or extend to match the actual feed (Zoho Desk, Freshdesk, etc).

          ColumnTypeNullDefaultComment
          ticket_idtextNOT NULL
          assigned_imeitext
          driver_nametext
          customertext
          job_typetext
          prioritytext
          statustextNOT NULL'open'::textopen | assigned | in_progress | resolved | cancelled
          created_attimestamp with time zoneNOT NULL
          assigned_attimestamp with time zone
          closed_attimestamp with time zone
          job_latdouble precision
          job_lngdouble precision
          job_geomgeometry(Point,4326)
          ingested_attimestamp with time zoneNOT NULLnow()
          ops.vw_service_forecastview

          Projected next-service date per vehicle based on 30-day km rate. Service interval default 10,000 km — override at query time if needed.

          ColumnTypeNullDefaultComment
          imeitext
          driver_nametext
          vehicle_numbertext
          last_service_datedate
          last_service_odointeger
          current_odonumeric(12,2)
          km_since_servicenumeric
          km_to_next_servicenumeric
          km_per_day_30dnumeric
          projected_service_datedate

          dwh_gold · Nightly ETL aggregates.

          2 table(s) · 0 view(s) · 1 function(s) documented.

          dwh_gold.dim_vehiclestable0 rows

          ColumnTypeNullDefaultComment
          vehicle_keyintegerNOT NULLnextval('dim_vehicles_vehicle_key_seq'::regclass)
          imeitext
          vehicle_numbertext
          is_activebooleantrue
          dwh_gold.fact_daily_fleet_metricstable0 rows

          ColumnTypeNullDefaultComment
          daydateNOT NULL
          vehicle_keyintegerNOT NULL
          total_distance_kmnumeric(12,2)Total km driven that day across all trips
          max_speed_kmhnumeric(7,2)
          idle_hoursnumeric(5,2)
          total_tripsintegerNumber of completed trips
          total_drive_hoursnumeric(8,2)Total hours of active driving (engine on + moving)
          total_idle_hoursnumeric(8,2)Total hours engine on but stationary
          fuel_consumed_lnumeric(10,3)Total fuel consumed in litres (from webhook trip reports)
          alarm_countintegerTotal alarm events triggered that day
          overspeed_countintegerNumber of overspeed alarm events
          day_start_timetime without time zoneTime of first trip start (Africa/Nairobi)
          day_end_timetime without time zoneTime of last trip end (Africa/Nairobi)
          avg_speed_kmhnumeric(7,2)Fleet average speed across all trips that day
          peak_speed_kmhnumeric(7,2)Highest max_speed_kmh recorded across all trips
          dwh_gold.refresh_daily_metrics(…)function · plpgsql

          Populates or refreshes fact_daily_fleet_metrics for the given date. Call nightly: SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1);

          argumentstarget_date date
          returnsvoid

          public · Extension objects + pgbouncer auth helper.

          1 table(s) · 3 view(s) · 1 function(s) documented.

          public.spatial_ref_systable8,500 rows

          ColumnTypeNullDefaultComment
          sridintegerNOT NULL
          auth_namecharacter varying(256)
          auth_sridinteger
          srtextcharacter varying(2048)
          proj4textcharacter varying(2048)
          public.geography_columnsview

          ColumnTypeNullDefaultComment
          f_table_catalogname
          f_table_schemaname
          f_table_namename
          f_geography_columnname
          coord_dimensioninteger
          sridinteger
          typetext
          public.geometry_columnsview

          ColumnTypeNullDefaultComment
          f_table_catalogcharacter varying(256)
          f_table_schemaname
          f_table_namename
          f_geometry_columnname
          coord_dimensioninteger
          sridinteger
          typecharacter varying(30)
          public.trips_viz_v1view

          ColumnTypeNullDefaultComment
          trip_idbigint
          imeitext
          vehicle_nametext
          vehicle_numbertext
          cost_centretext
          start_timetimestamp with time zone
          end_timetimestamp with time zone
          distance_kmnumeric(12,2)
          avg_speed_kmhnumeric(7,2)
          max_speed_kmhnumeric(7,2)
          vehicle_platetext
          start_addresstext
          end_addresstext
          waypoints_countinteger
          driving_time_sinteger
          idle_time_sinteger
          fuel_consumed_lnumeric(8,2)
          trip_date_eatdate
          daily_seqbigint
          public.user_lookup(…)function · plpgsql

          pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.

          argumentsin_user text, OUT uname text, OUT phash text
          returnsrecord

          6 · Grafana dashboards

          Grafana is provisioned via a baked image and reads TimescaleDB directly (read-only role grafana_ro), mostly through the tracksolid.v_* analytics views documented in §5. Two dashboards ship with the stack.

          NOC Fleet Operations — Live · uid noc-fleet-live · 9 panels

          SectionPanelTypeSource view / table
          Total Vehiclesstattracksolid.devices
          Online Nowstattracksolid.v_fleet_status
          Recent (5-30 min)stattracksolid.v_fleet_status
          Offlinestattracksolid.v_fleet_status
          Moving Nowstattracksolid.v_fleet_status
          Avg Speed (km/h)stattracksolid.v_fleet_status
          Live Vehicle Locationsgeomaptracksolid.devices, tracksolid.live_positions
          Vehicle Statustabletracksolid.devices, tracksolid.live_positions
          Ingestion Healthtabletracksolid.v_ingestion_health

          Daily Operations — Fleet & Dispatch · uid daily-ops · 21 panels

          SectionPanelTypeSource view / table
          Last GPS Fix (fleet)stattracksolid.live_positions
          Vehicles reporting todaystattracksolid.v_fleet_today
          Fleet km todaystattracksolid.v_fleet_today
          Drive hours todaystattracksolid.v_fleet_today
          Idle hours todaystattracksolid.v_fleet_today
          Open alarms (24h)stattracksolid.alarms
          In-flight SLA jobsstattracksolid.v_sla_inflight
          Active Vehicles Mapgeomaptracksolid.v_active_dispatch_map
          Currently Idle (engine on, speed < 2)tabletracksolid.v_currently_idle
          Vehicles Not Moved Todaytabletracksolid.v_vehicles_not_moved_today
          Per-Vehicle Daily Roll-uptabletracksolid.v_fleet_today
          Driver Leaderboardtabletracksolid.v_driver_aggregates_daily
          Fleet Distance — 7-day (by city)timeseriestracksolid.v_fleet_km_daily
          Alarm Frequency — 30-day (by type)timeseriestracksolid.v_alarms_daily
          Idle Cost (month-to-date)stattracksolid.v_utilisation_daily
          Utilisation Heatmap (30-day)heatmaptracksolid.v_utilisation_daily
          Row 7 — Field-Service SLAs (data-gated)Dispatch SLA (median mins, 24h)stattracksolid.v_sla_inflight
          En-route SLA (median mins, 24h)stattracksolid.v_sla_inflight
          On-site SLA (median mins, 24h)stattracksolid.v_sla_inflight
          Resolution SLA (median mins, 24h)stattracksolid.v_sla_inflight
          At-risk ticketstabletracksolid.v_sla_inflight

          SLA panels (v_sla_inflight) and the utilisation heatmap (v_utilisation_daily) are data-gated on the ops ticket integration and nightly dwh_gold ETL respectively.

          7 · Operational notes

            +
            Fix (2026-06-05). The POST handler originally read the body as JSON only, but the SPA sends x-www-form-urlencoded; the mismatch silently dropped every filter so the map always returned the whole fleet. Now parsed by Content-Type (parse_qs for form bodies). Commit f1387d1.

            5 · Database schema

            tracksolid · Live data — the single source of truth. Ingested from the Tracksolid API.

            17 table(s) · 15 view(s) · 1 function(s) documented.

            tracksolid.alarmstable344,356 rows

            Alarm events (alarm_type, alarm_name, alarm_time).

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('alarms_id_seq'::regclass)
            imeitext
            alarm_typetext
            alarm_timetimestamp with time zone
            geomgeometry(Point,4326)
            latdouble precision
            lngdouble precision
            speednumeric(7,2)
            acc_statustext
            updated_attimestamp with time zonenow()
            alarm_nametext
            sourcetext'poll'::text
            severitytextAlarm severity level: critical | warning | info
            geofence_idtextTracksolid geofence ID if this is a geofence alarm
            geofence_nametextHuman-readable geofence name
            acknowledged_attimestamp with time zoneTimestamp when alarm was acknowledged by an operator
            acknowledged_bytextUsername or ID of operator who acknowledged the alarm
            tracksolid.api_token_cachetable1 rows

            OAuth2 token cache for the Jimi/Tracksolid API.

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('api_token_cache_id_seq'::regclass)
            accounttextNOT NULL
            access_tokentextNOT NULL
            refresh_tokentext
            app_keytext
            expires_attimestamp with time zoneNOT NULL
            obtained_attimestamp with time zoneNOT NULLnow()
            updated_attimestamp with time zoneNOT NULLnow()
            tracksolid.device_eventstable0 rows

            Device network connection and disconnection events from /pushevent webhook.

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('device_events_id_seq'::regclass)
            imeitextNOT NULL
            event_typetextNOT NULLLOGIN = device connected to network; LOGOUT = device disconnected
            event_timetimestamp with time zoneNOT NULL
            timezonetext
            created_attimestamp with time zoneNOT NULLnow()
            tracksolid.devicestable181 rows

            Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.

            ColumnTypeNullDefaultComment
            imeitextNOT NULL
            device_nametext
            mc_typetext
            mc_type_use_scopetext
            vehicle_nametext
            vehicle_numbertext
            vehicle_modelstext
            vehicle_icontext
            vintext
            engine_numbertext
            vehicle_brandtext
            fuel_100kmnumeric(6,2)
            driver_nametext
            driver_phonetext
            simtext
            iccidtext
            imsitext
            accounttext
            customer_nametext
            device_group_idtext
            device_grouptext
            activation_timetimestamp with time zone
            expirationtimestamp with time zone
            enabled_flagsmallintNOT NULL1
            statustext'active'::text
            citytext
            current_mileage_kmnumeric(12,2)
            created_attimestamp with time zoneNOT NULLnow()
            updated_attimestamp with time zoneNOT NULLnow()
            last_synced_attimestamp with time zone
            vehicle_categorytextVehicle type: truck | van | motorcycle | car | other
            cost_centretextBusiness unit or department this vehicle belongs to
            assigned_routetextRegular route name or ID for route-based reporting
            depot_geomgeometry(Point,4326)Home base/depot coordinates (WGS84)
            depot_addresstextHuman-readable depot address
            assigned_citytextOperating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection.
            tracksolid.fault_codestable0 rows

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('fault_codes_id_seq'::regclass)
            imeitextNOT NULL
            reported_attimestamp with time zoneNOT NULL
            fault_codetextNOT NULL
            status_flagsinteger
            latdouble precision
            lngdouble precision
            geomgeometry(Point,4326)
            event_timetimestamp with time zone
            created_attimestamp with time zoneNOT NULLnow()
            tracksolid.fuel_readingshypertable~0 rows

            Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.

            ColumnTypeNullDefaultComment
            imeitextNOT NULL
            reading_timetimestamp with time zoneNOT NULL
            sensor_pathtextSensor channel identifier from the device (path field in API payload)
            valuenumeric(10,3)
            unittextMeasurement unit: cm (tank depth), % (percentage), V (voltage), L (litres)
            latdouble precision
            lngdouble precision
            geomgeometry(Point,4326)
            created_attimestamp with time zoneNOT NULLnow()
            tracksolid.geofencestable0 rows

            Geofence boundary definitions synced from the Tracksolid platform.

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('geofences_id_seq'::regclass)
            fence_idtext
            fence_nametextNOT NULL
            fence_typetextcircle | polygon
            geomgeometry(Geometry,4326)
            radius_mnumeric(10,2)Radius in metres — only applicable for circle type geofences
            descriptiontext
            created_attimestamp with time zoneNOT NULLnow()
            updated_attimestamp with time zoneNOT NULLnow()
            tracksolid.heartbeatshypertable~0 rows

            Device heartbeat hypertable.

            ColumnTypeNullDefaultComment
            imeitextNOT NULL
            gate_timetimestamp with time zoneNOT NULL
            power_levelsmallint
            gsm_signalsmallint
            acc_statussmallint
            power_statussmallint
            fortifysmallint
            created_attimestamp with time zoneNOT NULLnow()
            tracksolid.ingestion_logtable274,181 rows

            API call audit trail — one row per ingestion run.

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('ingestion_log_id_seq'::regclass)
            run_attimestamp with time zoneNOT NULLnow()
            endpointtextNOT NULL
            imei_countintegerNOT NULL0
            rows_upsertedintegerNOT NULL0
            rows_insertedintegerNOT NULL0
            duration_msintegerNOT NULL0
            successbooleanNOT NULLtrue
            error_codetext
            error_messagetext
            tracksolid.lbs_readingstable0 rows

            Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('lbs_readings_id_seq'::regclass)
            imeitextNOT NULL
            gate_timetimestamp with time zoneNOT NULL
            post_typetextPositioning technology: WIFI | LBS (cell tower)
            lbs_datajsonbRaw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding.
            created_attimestamp with time zoneNOT NULLnow()
            tracksolid.live_positionstable179 rows

            Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.

            ColumnTypeNullDefaultComment
            imeitextNOT NULL
            geomgeometry(Point,4326)
            latdouble precision
            lngdouble precision
            pos_typetext
            confidencesmallint
            gps_timetimestamp with time zone
            hb_timetimestamp with time zone
            speednumeric(7,2)
            directionnumeric(6,2)
            acc_statustext
            gps_signalsmallint
            gps_numsmallint
            elec_quantitynumeric(5,2)
            power_valuenumeric(5,2)
            battery_power_valnumeric(5,2)
            tracker_oiltext
            temperaturenumeric(8,2)
            current_mileagenumeric(12,2)
            device_statustext
            expire_flagtext
            activation_flagtext
            loc_desctext
            recorded_attimestamp with time zoneNOT NULLnow()
            updated_attimestamp with time zoneNOT NULLnow()
            tracksolid.obd_readingstable0 rows

            OBD diagnostics — push only via /pushobd webhook.

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('obd_readings_id_seq'::regclass)
            imeitext
            reading_timetimestamp with time zone
            engine_rpmintegerEngine RPM from OBD PID 0x0C
            fuel_level_pctnumeric(5,2)Fuel tank level % from OBD PID 0x2F
            updated_attimestamp with time zonenow()
            car_typesmallint
            acc_statesmallint
            status_flagsinteger
            latdouble precision
            lngdouble precision
            geomgeometry(Point,4326)
            obd_datajsonbRaw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.)
            coolant_temp_cnumeric(6,2)Coolant temperature °C from OBD PID 0x05
            battery_voltagenumeric(5,2)Battery voltage (V) from OBD PID 0x42
            intake_pressurenumeric(6,2)Intake manifold pressure kPa from OBD PID 0x0B
            throttle_pctnumeric(5,2)Throttle position % from OBD PID 0x11
            vehicle_speednumeric(7,2)Vehicle speed km/h from OBD PID 0x0D
            engine_load_pctnumeric(5,2)Calculated engine load % from OBD PID 0x04
            tracksolid.parking_eventstable0 rows

            Stop events with duration + address.

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('parking_events_id_seq'::regclass)
            imeitextNOT NULL
            event_typetext
            start_timetimestamp with time zoneNOT NULL
            end_timetimestamp with time zone
            duration_secondsinteger
            geomgeometry(Point,4326)
            addresstext
            updated_attimestamp with time zonenow()
            tracksolid.position_historyhypertable~3,596,013 rows

            All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).

            ColumnTypeNullDefaultComment
            imeitextNOT NULL
            gps_timetimestamp with time zoneNOT NULL
            geomgeometry(Point,4326)
            latdouble precision
            lngdouble precision
            speednumeric(7,2)
            directionnumeric(6,2)
            acc_statustext
            satellitesmallint
            current_mileagenumeric(12,2)
            recorded_attimestamp with time zonenow()
            altitudenumeric(8,2)
            post_typesmallint
            sourcetext'poll'::text
            tracksolid.schema_migrationstable9 rows

            ColumnTypeNullDefaultComment
            filenametextNOT NULL
            applied_attimestamp with time zoneNOT NULLnow()
            tracksolid.temperature_readingshypertable~0 rows

            Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.

            ColumnTypeNullDefaultComment
            imeitextNOT NULL
            reading_timetimestamp with time zoneNOT NULL
            temperaturenumeric(6,2)
            humidity_pctnumeric(5,2)
            created_attimestamp with time zoneNOT NULLnow()
            tracksolid.tripstable43,765 rows

            Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).

            ColumnTypeNullDefaultComment
            idbigintNOT NULLnextval('trips_id_seq'::regclass)
            imeitextNOT NULL
            start_timetimestamp with time zoneNOT NULL
            end_timetimestamp with time zone
            start_geomgeometry(Point,4326)
            end_geomgeometry(Point,4326)
            distance_kmnumeric(12,2)Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10).
            avg_speed_kmhnumeric(7,2)
            max_speed_kmhnumeric(7,2)
            updated_attimestamp with time zonenow()
            fuel_consumed_lnumeric(8,2)
            idle_time_sinteger
            driving_time_sintegerrunTimeSecond from API: total driving time in seconds
            trip_seqinteger
            sourcetext'poll'::textpoll = from API polling, push = from webhook push
            route_geomgeometry(LineString,4326)Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window.
            start_addresstextReverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
            end_addresstextReverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative.
            vehicle_platetextDenormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest.
            waypoints_countintegerNumber of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate.
            tracksolid.v_active_dispatch_mapview

            01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.

            ColumnTypeNullDefaultComment
            imeitext
            vehicle_numbertext
            vehicle_nametext
            driver_nametext
            driver_phonetext
            assigned_citytext
            latdouble precision
            lngdouble precision
            speednumeric(7,2)
            directionnumeric(6,2)
            acc_statustext
            last_fixtimestamp without time zone
            statustext
            tracksolid.v_alarms_dailyview

            01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.

            ColumnTypeNullDefaultComment
            daydate
            alarm_nametext
            alarm_countbigint
            tracksolid.v_currently_idleview

            01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.

            ColumnTypeNullDefaultComment
            imeitext
            vehicle_numbertext
            driver_nametext
            assigned_citytext
            latdouble precision
            lngdouble precision
            sincetimestamp without time zone
            idle_secondsinteger
            tracksolid.v_driver_aggregates_dailyview

            01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).

            ColumnTypeNullDefaultComment
            imeitext
            driver_nametext
            vehicle_numbertext
            assigned_citytext
            daydate
            kmnumeric
            tripsbigint
            events_80bigint
            events_100bigint
            events_120bigint
            harsh_eventsbigint
            speeding_per_100kmnumeric
            harsh_per_100kmnumeric
            tracksolid.v_driver_attendance_dailyview

            ColumnTypeNullDefaultComment
            report_datedate
            driver_nametext
            vehicle_numbertext
            cost_centretext
            assigned_citytext
            reporting_timetime without time zone
            start_addresstext
            start_latdouble precision
            start_lngdouble precision
            statustext
            mins_from_startinteger
            tracksolid.v_driver_clock_dailyview

            Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).

            ColumnTypeNullDefaultComment
            imeitext
            driver_nametext
            vehicle_numbertext
            cost_centretext
            assigned_citytext
            report_datedate
            reporting_timetime without time zone
            closing_timetime without time zone
            reporting_tstimestamp with time zone
            closing_tstimestamp with time zone
            start_latdouble precision
            start_lngdouble precision
            start_addresstext
            end_latdouble precision
            end_lngdouble precision
            end_addresstext
            trips_countbigint
            total_kmnumeric
            drive_hoursnumeric
            tracksolid.v_driver_clock_todayview

            Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

            ColumnTypeNullDefaultComment
            imeitext
            driver_nametext
            vehicle_numbertext
            cost_centretext
            assigned_citytext
            report_datedate
            reporting_timetime without time zone
            closing_timetime without time zone
            reporting_tstimestamp with time zone
            closing_tstimestamp with time zone
            start_latdouble precision
            start_lngdouble precision
            start_addresstext
            end_latdouble precision
            end_lngdouble precision
            end_addresstext
            trips_countbigint
            total_kmnumeric
            drive_hoursnumeric
            tracksolid.v_fleet_km_dailyview

            01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.

            ColumnTypeNullDefaultComment
            daydate
            assigned_citytext
            kmnumeric
            active_vehiclesbigint
            tripsbigint
            tracksolid.v_fleet_statusview

            ColumnTypeNullDefaultComment
            imeitext
            vehicle_numbertext
            driver_nametext
            latdouble precision
            lngdouble precision
            geomgeometry(Point,4326)
            speednumeric(7,2)
            acc_statustext
            gps_timetimestamp with time zone
            connectivity_statustext
            seconds_since_fixinteger
            tracksolid.v_fleet_todayview

            01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.

            ColumnTypeNullDefaultComment
            imeitext
            driver_nametext
            vehicle_numbertext
            vehicle_nametext
            assigned_citytext
            enabled_flagsmallint
            km_todaynumeric
            trips_todaybigint
            drive_hoursnumeric
            idle_hoursnumeric
            first_departuretime without time zone
            last_returntime without time zone
            alarms_todaybigint
            last_fixtimestamp without time zone
            last_speednumeric(7,2)
            did_not_moveboolean
            tracksolid.v_fleet_traceview

            ColumnTypeNullDefaultComment
            gidbigint
            driver_nametext
            vehicle_nametext
            device_nametext
            imeitext
            geomgeometry(Point,4326)
            latnumeric
            lngnumeric
            start_timetimestamp without time zone
            end_timetimestamp without time zone
            day_localdate
            hour_localinteger
            dow_localinteger
            gps_time_utctimestamp with time zone
            recorded_attimestamp with time zone
            speednumeric(7,2)
            directionnumeric(6,2)
            current_mileagenumeric(12,2)
            stationaryboolean
            trip_idbigint
            tracksolid.v_ingestion_healthview

            ColumnTypeNullDefaultComment
            endpointtext
            run_attimestamp with time zone
            successboolean
            error_messagetext
            seconds_agointeger
            tracksolid.v_mileage_daily_caggview

            ColumnTypeNullDefaultComment
            buckettimestamp with time zone
            imeitext
            dist_kmnumeric
            avg_speednumeric
            tracksolid.v_trips_enrichedview

            tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.

            ColumnTypeNullDefaultComment
            idbigint
            imeitext
            start_timetimestamp with time zone
            end_timetimestamp with time zone
            start_geomgeometry(Point,4326)
            end_geomgeometry(Point,4326)
            distance_kmnumeric(12,2)
            avg_speed_kmhnumeric(7,2)
            max_speed_kmhnumeric(7,2)
            updated_attimestamp with time zone
            fuel_consumed_lnumeric(8,2)
            idle_time_sinteger
            driving_time_sinteger
            trip_seqinteger
            sourcetext
            route_geomgeometry(LineString,4326)
            start_addresstext
            end_addresstext
            vehicle_platetext
            waypoints_countinteger
            trip_date_eatdate
            daily_seqbigint
            tracksolid.v_vehicles_not_moved_todayview

            01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.

            ColumnTypeNullDefaultComment
            imeitext
            vehicle_nametext
            vehicle_numbertext
            driver_nametext
            assigned_citytext
            last_seentimestamp without time zone
            speednumeric(7,2)
            tracksolid.set_updated_at(…)function · plpgsql

            arguments()
            returnstrigger

            reporting · Read layer that backs the map dashboards (consumed by dashboard_api).

            2 table(s) · 12 view(s) · 4 function(s) documented.

            reporting.refresh_logtable3,558 rows

            One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. Written by dashboard_api's built-in refresher (source='dashboard_api', every 5 min); the retired n8n job (source='n8n') was the previous writer. Read MAX(refreshed_at) for staleness.

            ColumnTypeNullDefaultComment
            refreshed_attimestamp with time zoneNOT NULLnow()
            sourcetextNOT NULL'n8n'::text
            duration_msinteger
            row_countinteger
            notestext
            reporting.v_tripsmatview31,670 rows

            Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.

            ColumnTypeNullDefaultComment
            trip_idbigint
            imeitext
            device_nametext
            vehicle_numbertext
            vehicle_modelstext
            vehicle_categorytext
            cost_centretext
            assigned_citytext
            assigned_drivertext
            start_timetimestamp without time zone
            end_timetimestamp without time zone
            trip_datedate
            start_hourinteger
            start_dowinteger
            daily_seqbigint
            distance_kmnumeric(12,2)
            avg_speed_kmhnumeric(7,2)
            max_speed_kmhnumeric(7,2)
            idle_time_sinteger
            driving_time_sinteger
            fuel_consumed_lnumeric(8,2)
            waypoints_countinteger
            start_addresstext
            end_addresstext
            start_geomgeometry(Point,4326)
            end_geomgeometry(Point,4326)
            route_geomgeometry(LineString,4326)
            route_geojsonjson
            is_meaningful_routeboolean
            updated_attimestamp without time zone
            reporting.v_daily_cost_centreview

            Cost-centre × day rollup. Excludes trips with NULL cost_centre.

            ColumnTypeNullDefaultComment
            trip_datedate
            cost_centretext
            active_vehiclesbigint
            active_driversbigint
            trip_countbigint
            total_kmnumeric
            driving_hoursnumeric
            idle_hoursnumeric
            idle_pctnumeric
            km_per_vehiclenumeric
            reporting.v_daily_summaryview

            Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.

            ColumnTypeNullDefaultComment
            trip_datedate
            cost_centretext
            assigned_citytext
            vehicle_numbertext
            assigned_drivertext
            trip_countbigint
            total_kmnumeric
            driving_hoursnumeric
            idle_hoursnumeric
            idle_pctnumeric
            first_trip_starttimestamp without time zone
            last_trip_endtimestamp without time zone
            avg_speed_kmhnumeric
            max_speed_kmhnumeric
            day_routes_geojsonjson
            reporting.v_filter_citiesview

            Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.

            ColumnTypeNullDefaultComment
            assigned_citytext
            reporting.v_filter_cost_centresview

            Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.

            ColumnTypeNullDefaultComment
            cost_centretext
            reporting.v_filter_driversview

            Driver dropdown source for the n8n dashboard. Distinct non-null drivers.

            ColumnTypeNullDefaultComment
            drivertext
            reporting.v_filter_vehiclesview

            Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.

            ColumnTypeNullDefaultComment
            vehicle_numbertext
            driverstext
            cost_centretext
            assigned_citytext
            reporting.v_live_positionsview

            Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.

            ColumnTypeNullDefaultComment
            imeitext
            vehicle_numbertext
            assigned_drivertext
            cost_centretext
            assigned_citytext
            vehicle_categorytext
            vehicle_modelstext
            mc_typetext
            device_kindtext
            latdouble precision
            lngdouble precision
            speednumeric(7,2)
            directionnumeric(6,2)
            acc_statustext
            device_statustext
            gps_signalsmallint
            gps_numsmallint
            current_mileagenumeric(12,2)
            loc_desctext
            gps_timetimestamp with time zone
            updated_attimestamp with time zone
            gps_time_eattimestamp without time zone
            updated_at_eattimestamp without time zone
            source_age_hoursnumeric
            reporting.v_monthly_cost_centreview

            Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.

            ColumnTypeNullDefaultComment
            month_startdate
            month_labeltext
            cost_centretext
            active_vehiclesbigint
            active_driversbigint
            active_daysbigint
            trip_countbigint
            total_kmnumeric
            driving_hoursnumeric
            idle_hoursnumeric
            idle_pctnumeric
            km_per_vehiclenumeric
            reporting.v_monthly_summaryview

            Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).

            ColumnTypeNullDefaultComment
            month_startdate
            month_labeltext
            cost_centretext
            assigned_citytext
            vehicle_categorytext
            vehicle_numbertext
            assigned_drivertext
            trip_countbigint
            active_daysbigint
            total_kmnumeric
            driving_hoursnumeric
            idle_hoursnumeric
            idle_pctnumeric
            km_per_active_daynumeric
            km_per_tripnumeric
            avg_speed_kmhnumeric
            peak_speed_kmhnumeric
            reporting.v_trips_todayview

            Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.

            ColumnTypeNullDefaultComment
            trip_idbigint
            imeitext
            device_nametext
            vehicle_numbertext
            vehicle_modelstext
            vehicle_categorytext
            cost_centretext
            assigned_citytext
            assigned_drivertext
            start_timetimestamp without time zone
            end_timetimestamp without time zone
            trip_datedate
            start_hourinteger
            start_dowinteger
            daily_seqbigint
            distance_kmnumeric(12,2)
            avg_speed_kmhnumeric(7,2)
            max_speed_kmhnumeric(7,2)
            idle_time_sinteger
            driving_time_sinteger
            fuel_consumed_lnumeric(8,2)
            waypoints_countinteger
            start_addresstext
            end_addresstext
            start_geomgeometry(Point,4326)
            end_geomgeometry(Point,4326)
            route_geomgeometry(LineString,4326)
            route_geojsonjson
            is_meaningful_routeboolean
            updated_attimestamp without time zone
            reporting.v_weekly_cost_centreview

            Cost-centre × week rollup. Excludes trips with NULL cost_centre.

            ColumnTypeNullDefaultComment
            week_startdate
            cost_centretext
            active_vehiclesbigint
            active_driversbigint
            active_daysbigint
            trip_countbigint
            total_kmnumeric
            driving_hoursnumeric
            idle_hoursnumeric
            idle_pctnumeric
            km_per_vehiclenumeric
            reporting.v_weekly_summaryview

            Vehicle × week rollup. Numeric only, no geometry.

            ColumnTypeNullDefaultComment
            week_startdate
            cost_centretext
            assigned_citytext
            vehicle_numbertext
            assigned_drivertext
            trip_countbigint
            active_daysbigint
            total_kmnumeric
            driving_hoursnumeric
            idle_hoursnumeric
            avg_trip_kmnumeric
            reporting.fn_live_positions(…)function · plpgsql

            Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.

            argumentsp_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text
            returnsjsonb
            reporting.fn_trips_for_map(…)function · plpgsql

            Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.

            argumentsp_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date
            returnsjsonb
            reporting.fn_vehicle_track(…)function · sql

            Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.

            argumentsp_vehicle_number text, p_hours integer DEFAULT 1
            returnsjsonb
            reporting.normalize_plate(…)function · sql

            Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.

            argumentsp text
            returnstext

            ops · dwh_gold · REMOVED 2026-06-05

            The ops schema (workshop / tickets / dispatch / SLA / odometer / cost_rates / kpi_targets) and the dwh_gold schema (dim_vehicles, fact_daily_fleet_metrics, refresh_daily_metrics) were purged 2026-06-05 via migrations 12 / 13 — those features were never implemented. Also dropped: tracksolid.dispatch_log, tracksolid.v_sla_inflight, tracksolid.v_utilisation_daily, and their Grafana panels. The separate tracksolid_dwh server (31.97.44.246:5888) is unrelated and untouched.

            public · Extension objects + pgbouncer auth helper.

            1 table(s) · 3 view(s) · 1 function(s) documented.

            public.spatial_ref_systable8,500 rows

            ColumnTypeNullDefaultComment
            sridintegerNOT NULL
            auth_namecharacter varying(256)
            auth_sridinteger
            srtextcharacter varying(2048)
            proj4textcharacter varying(2048)
            public.geography_columnsview

            ColumnTypeNullDefaultComment
            f_table_catalogname
            f_table_schemaname
            f_table_namename
            f_geography_columnname
            coord_dimensioninteger
            sridinteger
            typetext
            public.geometry_columnsview

            ColumnTypeNullDefaultComment
            f_table_catalogcharacter varying(256)
            f_table_schemaname
            f_table_namename
            f_geometry_columnname
            coord_dimensioninteger
            sridinteger
            typecharacter varying(30)
            public.trips_viz_v1view

            ColumnTypeNullDefaultComment
            trip_idbigint
            imeitext
            vehicle_nametext
            vehicle_numbertext
            cost_centretext
            start_timetimestamp with time zone
            end_timetimestamp with time zone
            distance_kmnumeric(12,2)
            avg_speed_kmhnumeric(7,2)
            max_speed_kmhnumeric(7,2)
            vehicle_platetext
            start_addresstext
            end_addresstext
            waypoints_countinteger
            driving_time_sinteger
            idle_time_sinteger
            fuel_consumed_lnumeric(8,2)
            trip_date_eatdate
            daily_seqbigint
            public.user_lookup(…)function · plpgsql

            pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.

            argumentsin_user text, OUT uname text, OUT phash text
            returnsrecord

            6 · Grafana dashboards

            Grafana is provisioned via a baked image and reads TimescaleDB directly (read-only role grafana_ro), mostly through the tracksolid.v_* analytics views documented in §5. Two dashboards ship with the stack.

            NOC Fleet Operations — Live · uid noc-fleet-live · 9 panels

            SectionPanelTypeSource view / table
            Total Vehiclesstattracksolid.devices
            Online Nowstattracksolid.v_fleet_status
            Recent (5-30 min)stattracksolid.v_fleet_status
            Offlinestattracksolid.v_fleet_status
            Moving Nowstattracksolid.v_fleet_status
            Avg Speed (km/h)stattracksolid.v_fleet_status
            Live Vehicle Locationsgeomaptracksolid.devices, tracksolid.live_positions
            Vehicle Statustabletracksolid.devices, tracksolid.live_positions
            Ingestion Healthtabletracksolid.v_ingestion_health

            Daily Operations — Fleet & Dispatch · uid daily-ops · 13 panels

            SectionPanelTypeSource view / table
            Last GPS Fix (fleet)stattracksolid.live_positions
            Vehicles reporting todaystattracksolid.v_fleet_today
            Fleet km todaystattracksolid.v_fleet_today
            Drive hours todaystattracksolid.v_fleet_today
            Idle hours todaystattracksolid.v_fleet_today
            Open alarms (24h)stattracksolid.alarms
            Active Vehicles Mapgeomaptracksolid.v_active_dispatch_map
            Currently Idle (engine on, speed < 2)tabletracksolid.v_currently_idle
            Vehicles Not Moved Todaytabletracksolid.v_vehicles_not_moved_today
            Per-Vehicle Daily Roll-uptabletracksolid.v_fleet_today
            Driver Leaderboardtabletracksolid.v_driver_aggregates_daily
            Fleet Distance — 7-day (by city)timeseriestracksolid.v_fleet_km_daily
            Alarm Frequency — 30-day (by type)timeseriestracksolid.v_alarms_daily

            7 · Operational notes

            • Hypertables (position_history, heartbeats, fuel_readings, temperature_readings) report 0 in pg_stat_user_tables — counts above use TimescaleDB's approximate_row_count().
            • diff --git a/docs/reports/260605_ops_purge_backup.md b/docs/reports/260605_ops_purge_backup.md new file mode 100644 index 0000000..962e660 --- /dev/null +++ b/docs/reports/260605_ops_purge_backup.md @@ -0,0 +1,47 @@ +# ops schema purge — pre-drop backup (2026-06-05) + +Snapshot taken immediately before dropping the `ops` schema + `tracksolid.dispatch_log` ++ the dependent view `tracksolid.v_sla_inflight`. The dispatch/SLA/workshop features were +never implemented and are being purged (may take a different direction later). + +Only two `ops` tables held rows, and both are **migration-08 seed data** +(`migrations/08_analytics_config.sql`), i.e. regenerable — this file is belt-and-suspenders. +Every other ops table (`tickets`, `service_log`, `odometer_readings`) and the view +`vw_service_forecast` were empty. `tracksolid.dispatch_log` was empty. + +## ops.cost_rates (3 rows) + +| rate_key | scope_type | scope_value | metric | amount | currency | effective_from | notes | +|---|---|---|---|---|---|---|---| +| fuel.nairobi | city | nairobi | fuel_per_litre | 195.00 | KES | 2026-04-27 | Placeholder pump price — confirm with Finance. | +| fuel.mombasa | city | mombasa | fuel_per_litre | 195.00 | KES | 2026-04-27 | Placeholder pump price — confirm with Finance. | +| fuel.kampala | city | kampala | fuel_per_litre | 5200.00 | UGX | 2026-04-27 | Placeholder pump price — confirm with Finance. | + +## ops.kpi_targets (12 rows) + +| target_id | kpi_key | scope_type | scope_value | target | amber | red | direction | effective_from | notes | +|---|---|---|---|---|---|---|---|---|---| +| 1 | utilisation_pct | global | | 70.00 | 60.00 | 50.00 | higher_is_better | 2026-04-27 | Fleet utilisation: drive_hours / engine_on_hours. | +| 2 | idle_pct | global | | 15.00 | 20.00 | 25.00 | lower_is_better | 2026-04-27 | Idle as % of engine-on time. | +| 3 | idle_pct | cost_centre | osp patrol | 15.00 | 20.00 | 25.00 | lower_is_better | 2026-04-27 | OSP patrol idle target — same as global until calibrated. | +| 4 | fuel_kes_per_100km | global | | 12.00 | 14.00 | 16.00 | lower_is_better | 2026-04-27 | Fuel litres per 100km equivalent — uses fuel_100km on devices. | +| 5 | mttr_hours | global | | 4.00 | 6.00 | 8.00 | lower_is_better | 2026-04-27 | Mean Time To Resolve, field-service ticket. | +| 6 | alarms_per_100km | global | | 2.00 | 3.00 | 5.00 | lower_is_better | 2026-04-27 | Safety event density. | +| 7 | utilisation_pct | global | | 70.00 | 60.00 | 50.00 | higher_is_better | 2026-05-01 | Fleet utilisation: drive_hours / engine_on_hours. | +| 8 | idle_pct | global | | 15.00 | 20.00 | 25.00 | lower_is_better | 2026-05-01 | Idle as % of engine-on time. | +| 9 | idle_pct | cost_centre | osp patrol | 15.00 | 20.00 | 25.00 | lower_is_better | 2026-05-01 | OSP patrol idle target — same as global until calibrated. | +| 10 | fuel_kes_per_100km | global | | 12.00 | 14.00 | 16.00 | lower_is_better | 2026-05-01 | Fuel litres per 100km equivalent — uses fuel_100km on devices. | +| 11 | mttr_hours | global | | 4.00 | 6.00 | 8.00 | lower_is_better | 2026-05-01 | Mean Time To Resolve, field-service ticket. | +| 12 | alarms_per_100km | global | | 2.00 | 3.00 | 5.00 | lower_is_better | 2026-05-01 | Safety event density. | + +## What was dropped + +```sql +DROP VIEW IF EXISTS tracksolid.v_sla_inflight; -- depended on ops.tickets + dispatch_log +DROP SCHEMA IF EXISTS ops CASCADE; -- tickets, service_log, odometer_readings, + -- cost_rates, kpi_targets, vw_service_forecast +DROP TABLE IF EXISTS tracksolid.dispatch_log; -- empty; only fed v_sla_inflight +``` + +**Not dropped in this step:** `dwh_gold` schema and `tracksolid.v_utilisation_daily` +(separate decision, pending). diff --git a/grafana/provisioning/dashboards-json/daily_operations_dashboard.json b/grafana/provisioning/dashboards-json/daily_operations_dashboard.json index 227dd3d..6b17adf 100644 --- a/grafana/provisioning/dashboards-json/daily_operations_dashboard.json +++ b/grafana/provisioning/dashboards-json/daily_operations_dashboard.json @@ -2,15 +2,30 @@ "title": "Daily Operations — Fleet & Dispatch", "uid": "daily-ops", "schemaVersion": 39, - "version": 1, + "version": 2, "refresh": "1m", - "time": { "from": "now/d", "to": "now" }, + "time": { + "from": "now/d", + "to": "now" + }, "timezone": "Africa/Nairobi", "timepicker": { - "refresh_intervals": ["30s", "1m", "5m", "15m", "30m", "1h"] + "refresh_intervals": [ + "30s", + "1m", + "5m", + "15m", + "30m", + "1h" + ] }, "editable": false, - "tags": ["fleet", "daily", "dispatch", "ops"], + "tags": [ + "fleet", + "daily", + "dispatch", + "ops" + ], "fiscalYearStartMonth": 0, "graphTooltip": 0, "templating": { @@ -19,13 +34,20 @@ "name": "city", "label": "City", "type": "query", - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "query": "SELECT DISTINCT COALESCE(assigned_city, city, 'unassigned') AS city FROM tracksolid.devices ORDER BY 1", "refresh": 1, "multi": true, "includeAll": true, "allValue": ".*", - "current": { "selected": true, "text": "All", "value": "$__all" } + "current": { + "selected": true, + "text": "All", + "value": "$__all" + } } ] }, @@ -35,33 +57,61 @@ "type": "stat", "title": "Last GPS Fix (fleet)", "description": "Most recent live position across all devices. Green < 5 min, amber 5–30 min, red > 30 min.", - "gridPos": { "x": 0, "y": 0, "w": 24, "h": 3 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "gridPos": { + "x": 0, + "y": 0, + "w": 24, + "h": 3 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, "textMode": "value_and_name" }, "fieldConfig": { "defaults": { "unit": "s", - "color": { "mode": "thresholds" }, + "color": { + "mode": "thresholds" + }, "thresholds": { "mode": "absolute", "steps": [ - { "color": "green", "value": null }, - { "color": "yellow", "value": 300 }, - { "color": "red", "value": 1800 } + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 300 + }, + { + "color": "red", + "value": 1800 + } ] } } }, "targets": [ { - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT EXTRACT(EPOCH FROM (NOW() - MAX(gps_time)))::int AS \"Seconds since latest fleet fix\" FROM tracksolid.live_positions;", "format": "table", "refId": "A" @@ -73,72 +123,164 @@ "type": "row", "title": "Row 1 — Today at a Glance", "collapsed": false, - "gridPos": { "x": 0, "y": 3, "w": 24, "h": 1 }, + "gridPos": { + "x": 0, + "y": 3, + "w": 24, + "h": 1 + }, "panels": [] }, { "id": 110, "type": "stat", "title": "Vehicles reporting today", - "gridPos": { "x": 0, "y": 4, "w": 4, "h": 4 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "gridPos": { + "x": 0, + "y": 4, + "w": 4, + "h": 4 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "options": { - "colorMode": "background", "graphMode": "none", - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, + "colorMode": "background", + "graphMode": "none", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, "textMode": "auto" }, "fieldConfig": { "defaults": { - "color": { "mode": "thresholds" }, - "thresholds": { "mode": "absolute", "steps": [{ "color": "red", "value": null }, { "color": "green", "value": 1 }] } + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } } }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT COUNT(*) FILTER (WHERE trips_today > 0) AS \"Reporting today\" FROM tracksolid.v_fleet_today WHERE assigned_city ~ '${city:regex}';", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { "id": 111, "type": "stat", "title": "Fleet km today", - "gridPos": { "x": 4, "y": 4, "w": 4, "h": 4 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "gridPos": { + "x": 4, + "y": 4, + "w": 4, + "h": 4 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "options": { - "colorMode": "value", "graphMode": "area", - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + "colorMode": "value", + "graphMode": "area", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + } }, "fieldConfig": { "defaults": { "unit": "none", "decimals": 1, - "color": { "mode": "fixed", "fixedColor": "blue" } + "color": { + "mode": "fixed", + "fixedColor": "blue" + } } }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT ROUND(SUM(km_today)::numeric, 1) AS \"Fleet km today\" FROM tracksolid.v_fleet_today WHERE assigned_city ~ '${city:regex}';", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { "id": 112, "type": "stat", "title": "Drive hours today", - "gridPos": { "x": 8, "y": 4, "w": 4, "h": 4 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "gridPos": { + "x": 8, + "y": 4, + "w": 4, + "h": 4 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "options": { - "colorMode": "value", "graphMode": "none", - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + "colorMode": "value", + "graphMode": "none", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + } }, "fieldConfig": { - "defaults": { "unit": "none", "decimals": 1, "color": { "mode": "fixed", "fixedColor": "green" } } + "defaults": { + "unit": "none", + "decimals": 1, + "color": { + "mode": "fixed", + "fixedColor": "green" + } + } }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT ROUND(SUM(drive_hours)::numeric, 1) AS \"Drive h\" FROM tracksolid.v_fleet_today WHERE assigned_city ~ '${city:regex}';", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { @@ -146,79 +288,124 @@ "type": "stat", "title": "Idle hours today", "description": "Ignition on, speed ~0. Fuel burn with no movement.", - "gridPos": { "x": 12, "y": 4, "w": 4, "h": 4 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "gridPos": { + "x": 12, + "y": 4, + "w": 4, + "h": 4 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "options": { - "colorMode": "value", "graphMode": "none", - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + "colorMode": "value", + "graphMode": "none", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + } }, "fieldConfig": { "defaults": { - "unit": "none", "decimals": 1, - "color": { "mode": "thresholds" }, + "unit": "none", + "decimals": 1, + "color": { + "mode": "thresholds" + }, "thresholds": { "mode": "absolute", "steps": [ - { "color": "green", "value": null }, - { "color": "yellow", "value": 10 }, - { "color": "red", "value": 30 } + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 10 + }, + { + "color": "red", + "value": 30 + } ] } } }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT ROUND(SUM(idle_hours)::numeric, 1) AS \"Idle h\" FROM tracksolid.v_fleet_today WHERE assigned_city ~ '${city:regex}';", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { "id": 114, "type": "stat", "title": "Open alarms (24h)", - "gridPos": { "x": 16, "y": 4, "w": 4, "h": 4 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "gridPos": { + "x": 16, + "y": 4, + "w": 4, + "h": 4 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "options": { - "colorMode": "background", "graphMode": "none", - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + "colorMode": "background", + "graphMode": "none", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + } }, "fieldConfig": { "defaults": { - "color": { "mode": "thresholds" }, + "color": { + "mode": "thresholds" + }, "thresholds": { "mode": "absolute", "steps": [ - { "color": "green", "value": null }, - { "color": "yellow", "value": 1 }, - { "color": "red", "value": 10 } + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "red", + "value": 10 + } ] } } }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT COUNT(*) AS \"Alarms 24h\" FROM tracksolid.alarms WHERE alarm_time > NOW() - INTERVAL '24 hours';", - "format": "table", "refId": "A" } - ] - }, - { - "id": 115, - "type": "stat", - "title": "In-flight SLA jobs", - "description": "Tickets currently open and dispatched. Empty until ops.tickets flows.", - "gridPos": { "x": 20, "y": 4, "w": 4, "h": 4 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { - "colorMode": "value", "graphMode": "none", - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } - }, - "fieldConfig": { - "defaults": { "color": { "mode": "fixed", "fixedColor": "purple" } } - }, - "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT COUNT(*) AS \"In-flight\" FROM tracksolid.v_sla_inflight WHERE ticket_stage NOT IN ('resolved', 'cancelled');", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { @@ -226,94 +413,261 @@ "type": "row", "title": "Row 2 — Live Dispatch", "collapsed": false, - "gridPos": { "x": 0, "y": 8, "w": 24, "h": 1 }, + "gridPos": { + "x": 0, + "y": 8, + "w": 24, + "h": 1 + }, "panels": [] }, { "id": 121, "type": "geomap", "title": "Active Vehicles Map", - "gridPos": { "x": 0, "y": 9, "w": 14, "h": 14 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + "gridPos": { + "x": 0, + "y": 9, + "w": 14, + "h": 14 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "options": { - "basemap": { "config": { "theme": "dark" }, "name": "Basemap", "type": "carto" }, - "controls": { "mouseWheelZoom": true, "showAttribution": true, "showScale": true, "showZoom": true }, + "basemap": { + "config": { + "theme": "dark" + }, + "name": "Basemap", + "type": "carto" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showScale": true, + "showZoom": true + }, "layers": [ { "config": { "showLegend": true, "style": { - "color": { "field": "status", "fixed": "green", "mode": "field" }, + "color": { + "field": "status", + "fixed": "green", + "mode": "field" + }, "opacity": 0.9, - "rotation": { "field": "direction", "fixed": 0, "max": 360, "min": -360, "mode": "field" }, - "size": { "fixed": 14, "max": 15, "min": 2, "mode": "fixed" }, - "symbol": { "fixed": "img/icons/marker/circle.svg", "mode": "fixed" } + "rotation": { + "field": "direction", + "fixed": 0, + "max": 360, + "min": -360, + "mode": "field" + }, + "size": { + "fixed": 14, + "max": 15, + "min": 2, + "mode": "fixed" + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + } } }, - "filterData": { "id": "byRefId", "options": "A" }, - "location": { "latitude": "lat", "longitude": "lng", "mode": "coords" }, - "name": "Vehicles", "tooltip": true, "type": "markers" + "filterData": { + "id": "byRefId", + "options": "A" + }, + "location": { + "latitude": "lat", + "longitude": "lng", + "mode": "coords" + }, + "name": "Vehicles", + "tooltip": true, + "type": "markers" } ], - "tooltip": { "mode": "details" }, - "view": { "allLayers": true, "id": "coords", "lat": -3.0, "lon": 34.5, "zoom": 5.5, "minZoom": 5.5, "maxZoom": 22 } + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "coords", + "lat": -3.0, + "lon": 34.5, + "zoom": 5.5, + "minZoom": 5.5, + "maxZoom": 22 + } }, "fieldConfig": { - "defaults": { "color": { "mode": "palette-classic-by-name" } }, + "defaults": { + "color": { + "mode": "palette-classic-by-name" + } + }, "overrides": [ - { "matcher": { "id": "byName", "options": "status" }, + { + "matcher": { + "id": "byName", + "options": "status" + }, "properties": [ - { "id": "mappings", "value": [{ "type": "value", "options": { - "moving": { "color": "green", "index": 0, "text": "Moving" }, - "idle_ignition_on": { "color": "yellow", "index": 1, "text": "Idle (engine on)" }, - "parked": { "color": "blue", "index": 2, "text": "Parked" }, - "stale": { "color": "orange", "index": 3, "text": "Stale > 10m" }, - "never_reported": { "color": "red", "index": 4, "text": "Never reported" } - } }] } + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "moving": { + "color": "green", + "index": 0, + "text": "Moving" + }, + "idle_ignition_on": { + "color": "yellow", + "index": 1, + "text": "Idle (engine on)" + }, + "parked": { + "color": "blue", + "index": 2, + "text": "Parked" + }, + "stale": { + "color": "orange", + "index": 3, + "text": "Stale > 10m" + }, + "never_reported": { + "color": "red", + "index": 4, + "text": "Never reported" + } + } + } + ] + } ] } ] }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT imei, vehicle_number, driver_name, assigned_city, lat, lng, speed, direction, status, last_fix FROM tracksolid.v_active_dispatch_map WHERE lat IS NOT NULL AND lng IS NOT NULL AND assigned_city ~ '${city:regex}';", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { "id": 122, "type": "table", "title": "Currently Idle (engine on, speed < 2)", - "gridPos": { "x": 14, "y": 9, "w": 10, "h": 7 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "cellHeight": "sm", "showHeader": true, "footer": { "show": false } }, + "gridPos": { + "x": 14, + "y": 9, + "w": 10, + "h": 7 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, + "options": { + "cellHeight": "sm", + "showHeader": true, + "footer": { + "show": false + } + }, "fieldConfig": { - "defaults": { "custom": { "align": "auto", "filterable": true } }, + "defaults": { + "custom": { + "align": "auto", + "filterable": true + } + }, "overrides": [ - { "matcher": { "id": "byName", "options": "idle_seconds" }, - "properties": [{ "id": "unit", "value": "s" }, { "id": "displayName", "value": "Idle for" }] } + { + "matcher": { + "id": "byName", + "options": "idle_seconds" + }, + "properties": [ + { + "id": "unit", + "value": "s" + }, + { + "id": "displayName", + "value": "Idle for" + } + ] + } ] }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT vehicle_number, driver_name, assigned_city, since, idle_seconds FROM tracksolid.v_currently_idle WHERE assigned_city ~ '${city:regex}' ORDER BY idle_seconds DESC;", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { "id": 123, "type": "table", "title": "Vehicles Not Moved Today", - "gridPos": { "x": 14, "y": 16, "w": 10, "h": 7 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "cellHeight": "sm", "showHeader": true, "footer": { "show": false } }, + "gridPos": { + "x": 14, + "y": 16, + "w": 10, + "h": 7 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, + "options": { + "cellHeight": "sm", + "showHeader": true, + "footer": { + "show": false + } + }, "fieldConfig": { - "defaults": { "custom": { "align": "auto", "filterable": true } } + "defaults": { + "custom": { + "align": "auto", + "filterable": true + } + } }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT vehicle_number, driver_name, assigned_city, last_seen FROM tracksolid.v_vehicles_not_moved_today WHERE assigned_city ~ '${city:regex}' ORDER BY last_seen DESC NULLS LAST;", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { @@ -321,41 +675,153 @@ "type": "row", "title": "Row 3 — Daily KPI Table", "collapsed": false, - "gridPos": { "x": 0, "y": 23, "w": 24, "h": 1 }, + "gridPos": { + "x": 0, + "y": 23, + "w": 24, + "h": 1 + }, "panels": [] }, { "id": 131, "type": "table", "title": "Per-Vehicle Daily Roll-up", - "gridPos": { "x": 0, "y": 24, "w": 24, "h": 12 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "cellHeight": "sm", "showHeader": true, "footer": { "show": false } }, + "gridPos": { + "x": 0, + "y": 24, + "w": 24, + "h": 12 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, + "options": { + "cellHeight": "sm", + "showHeader": true, + "footer": { + "show": false + } + }, "fieldConfig": { - "defaults": { "custom": { "align": "auto", "filterable": true } }, + "defaults": { + "custom": { + "align": "auto", + "filterable": true + } + }, "overrides": [ - { "matcher": { "id": "byName", "options": "km_today" }, - "properties": [{ "id": "unit", "value": "none" }, { "id": "decimals", "value": 1 }, { "id": "displayName", "value": "km today" }] }, - { "matcher": { "id": "byName", "options": "drive_hours" }, - "properties": [{ "id": "unit", "value": "none" }, { "id": "decimals", "value": 1 }, { "id": "displayName", "value": "Drive h" }] }, - { "matcher": { "id": "byName", "options": "idle_hours" }, - "properties": [{ "id": "unit", "value": "none" }, { "id": "decimals", "value": 1 }, { "id": "displayName", "value": "Idle h" }] }, - { "matcher": { "id": "byName", "options": "did_not_move" }, + { + "matcher": { + "id": "byName", + "options": "km_today" + }, "properties": [ - { "id": "custom.cellOptions", "value": { "type": "color-background" } }, - { "id": "mappings", "value": [{ "type": "value", "options": { - "true": { "color": "red", "index": 0, "text": "No" }, - "false": { "color": "transparent", "index": 1, "text": "Yes" } - } }] }, - { "id": "displayName", "value": "Moved?" } + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "displayName", + "value": "km today" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "drive_hours" + }, + "properties": [ + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "displayName", + "value": "Drive h" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "idle_hours" + }, + "properties": [ + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "displayName", + "value": "Idle h" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "did_not_move" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-background" + } + }, + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "true": { + "color": "red", + "index": 0, + "text": "No" + }, + "false": { + "color": "transparent", + "index": 1, + "text": "Yes" + } + } + } + ] + }, + { + "id": "displayName", + "value": "Moved?" + } ] } ] }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT vehicle_number, driver_name, assigned_city, km_today, trips_today, drive_hours, idle_hours, first_departure, last_return, alarms_today, did_not_move FROM tracksolid.v_fleet_today WHERE enabled_flag = 1 AND assigned_city ~ '${city:regex}' ORDER BY km_today DESC NULLS LAST;", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { @@ -363,7 +829,12 @@ "type": "row", "title": "Row 4 — Driver Behaviour Leaderboard (30-day)", "collapsed": false, - "gridPos": { "x": 0, "y": 36, "w": 24, "h": 1 }, + "gridPos": { + "x": 0, + "y": 36, + "w": 24, + "h": 1 + }, "panels": [] }, { @@ -371,40 +842,131 @@ "type": "table", "title": "Driver Leaderboard", "description": "Rolling 30-day aggression index. Red/amber/green per BA-file §3.1–§3.2 thresholds.", - "gridPos": { "x": 0, "y": 37, "w": 24, "h": 12 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "cellHeight": "sm", "showHeader": true, "footer": { "show": false } }, + "gridPos": { + "x": 0, + "y": 37, + "w": 24, + "h": 12 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, + "options": { + "cellHeight": "sm", + "showHeader": true, + "footer": { + "show": false + } + }, "fieldConfig": { - "defaults": { "custom": { "align": "auto", "filterable": true } }, + "defaults": { + "custom": { + "align": "auto", + "filterable": true + } + }, "overrides": [ - { "matcher": { "id": "byName", "options": "km" }, - "properties": [{ "id": "unit", "value": "none" }, { "id": "decimals", "value": 0 }, { "id": "displayName", "value": "km" }] }, - { "matcher": { "id": "byName", "options": "speeding_per_100km" }, + { + "matcher": { + "id": "byName", + "options": "km" + }, "properties": [ - { "id": "custom.cellOptions", "value": { "type": "color-background" } }, - { "id": "thresholds", "value": { "mode": "absolute", "steps": [ - { "color": "green", "value": null }, - { "color": "yellow", "value": 1 }, - { "color": "red", "value": 5 } - ] } } + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "displayName", + "value": "km" + } ] }, - { "matcher": { "id": "byName", "options": "harsh_per_100km" }, + { + "matcher": { + "id": "byName", + "options": "speeding_per_100km" + }, "properties": [ - { "id": "custom.cellOptions", "value": { "type": "color-background" } }, - { "id": "thresholds", "value": { "mode": "absolute", "steps": [ - { "color": "green", "value": null }, - { "color": "yellow", "value": 0.5 }, - { "color": "red", "value": 2 } - ] } } + { + "id": "custom.cellOptions", + "value": { + "type": "color-background" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "red", + "value": 5 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "harsh_per_100km" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-background" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "red", + "value": 2 + } + ] + } + } ] } ] }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT driver_name, vehicle_number, assigned_city, SUM(km)::numeric(10,0) AS km, SUM(events_80) AS events_80, SUM(events_100) AS events_100, SUM(events_120) AS events_120, SUM(harsh_events) AS harsh_events, ROUND(SUM(events_80)::numeric / NULLIF(SUM(km), 0) * 100, 2) AS speeding_per_100km, ROUND(SUM(harsh_events)::numeric / NULLIF(SUM(km), 0) * 100, 2) AS harsh_per_100km FROM tracksolid.v_driver_aggregates_daily WHERE day > CURRENT_DATE - INTERVAL '30 days' AND assigned_city ~ '${city:regex}' GROUP BY driver_name, vehicle_number, assigned_city ORDER BY harsh_per_100km DESC NULLS LAST;", - "format": "table", "refId": "A" } + "format": "table", + "refId": "A" + } ] }, { @@ -412,182 +974,107 @@ "type": "row", "title": "Row 5 — Trends", "collapsed": false, - "gridPos": { "x": 0, "y": 49, "w": 24, "h": 1 }, + "gridPos": { + "x": 0, + "y": 49, + "w": 24, + "h": 1 + }, "panels": [] }, { "id": 151, "type": "timeseries", "title": "Fleet Distance — 7-day (by city)", - "gridPos": { "x": 0, "y": 50, "w": 12, "h": 9 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, + "gridPos": { + "x": 0, + "y": 50, + "w": 12, + "h": 9 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, "fieldConfig": { "defaults": { "unit": "none", "decimals": 1, - "custom": { "drawStyle": "bars", "fillOpacity": 60, "lineWidth": 1, "axisLabel": "km" } + "custom": { + "drawStyle": "bars", + "fillOpacity": 60, + "lineWidth": 1, + "axisLabel": "km" + } } }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, + { + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, "rawSql": "SELECT day::timestamptz AS time, assigned_city AS metric, km AS value FROM tracksolid.v_fleet_km_daily WHERE day > CURRENT_DATE - INTERVAL '7 days' AND assigned_city ~ '${city:regex}' ORDER BY day;", - "format": "time_series", "refId": "A" } + "format": "time_series", + "refId": "A" + } ] }, { "id": 152, "type": "timeseries", "title": "Alarm Frequency — 30-day (by type)", - "gridPos": { "x": 12, "y": 50, "w": 12, "h": 9 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, + "gridPos": { + "x": 12, + "y": 50, + "w": 12, + "h": 9 + }, + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, "fieldConfig": { "defaults": { "unit": "short", - "custom": { "drawStyle": "bars", "fillOpacity": 60, "lineWidth": 1, "stacking": { "mode": "normal", "group": "A" } } + "custom": { + "drawStyle": "bars", + "fillOpacity": 60, + "lineWidth": 1, + "stacking": { + "mode": "normal", + "group": "A" + } + } } }, "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT day::timestamptz AS time, alarm_name AS metric, alarm_count AS value FROM tracksolid.v_alarms_daily WHERE day > CURRENT_DATE - INTERVAL '30 days' ORDER BY day;", - "format": "time_series", "refId": "A" } - ] - }, - { - "id": 160, - "type": "row", - "title": "Row 6 — Efficiency", - "collapsed": false, - "gridPos": { "x": 0, "y": 59, "w": 24, "h": 1 }, - "panels": [] - }, - { - "id": 161, - "type": "stat", - "title": "Idle Cost (month-to-date)", - "description": "Sum of idle hours × 0.8 L/h × 180 KES/L across fleet for this month. Empty until nightly ETL refreshes dwh_gold.", - "gridPos": { "x": 0, "y": 60, "w": 12, "h": 6 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { - "colorMode": "value", "graphMode": "area", "textMode": "value_and_name", - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } - }, - "fieldConfig": { - "defaults": { - "unit": "currencyKES", "decimals": 0, - "color": { "mode": "thresholds" }, - "thresholds": { "mode": "absolute", "steps": [ - { "color": "green", "value": null }, - { "color": "yellow", "value": 50000 }, - { "color": "red", "value": 200000 } - ] } - } - }, - "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT ROUND(SUM(total_idle_hours) * 0.8 * 180) AS \"Idle cost KES (MTD)\" FROM tracksolid.v_utilisation_daily WHERE day >= DATE_TRUNC('month', CURRENT_DATE) AND assigned_city ~ '${city:regex}';", - "format": "table", "refId": "A" } - ] - }, - { - "id": 162, - "type": "heatmap", - "title": "Utilisation Heatmap (30-day)", - "description": "Per-vehicle daily utilisation %. Empty until dwh_gold.fact_daily_fleet_metrics is refreshed by the nightly ETL.", - "gridPos": { "x": 12, "y": 60, "w": 12, "h": 9 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { - "calculate": false, - "cellGap": 2, - "color": { "mode": "scheme", "scheme": "RdYlGn", "steps": 64 }, - "yAxis": { "axisLabel": "Vehicle" } - }, - "fieldConfig": { "defaults": { "custom": { "scaleDistribution": { "type": "linear" } } } }, - "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT day::timestamptz AS time, vehicle_number AS metric, utilisation_pct AS value FROM tracksolid.v_utilisation_daily WHERE day > CURRENT_DATE - INTERVAL '30 days' AND assigned_city ~ '${city:regex}' ORDER BY day;", - "format": "time_series", "refId": "A" } - ] - }, - { - "id": 170, - "type": "row", - "title": "Row 7 — Field-Service SLAs (data-gated)", - "collapsed": true, - "gridPos": { "x": 0, "y": 69, "w": 24, "h": 1 }, - "panels": [ { - "id": 171, - "type": "stat", - "title": "Dispatch SLA (median mins, 24h)", - "gridPos": { "x": 0, "y": 70, "w": 6, "h": 5 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { - "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + "datasource": { + "type": "postgres", + "uid": "tracksolid_pg" }, - "fieldConfig": { "defaults": { "unit": "m", "decimals": 0 } }, - "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY dispatch_mins) AS \"Dispatch p50 (min)\" FROM tracksolid.v_sla_inflight WHERE created_at > NOW() - INTERVAL '24 hours';", - "format": "table", "refId": "A" } - ] - }, - { - "id": 172, - "type": "stat", - "title": "En-route SLA (median mins, 24h)", - "gridPos": { "x": 6, "y": 70, "w": 6, "h": 5 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } }, - "fieldConfig": { "defaults": { "unit": "m", "decimals": 0 } }, - "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY enroute_mins) AS \"En-route p50 (min)\" FROM tracksolid.v_sla_inflight WHERE created_at > NOW() - INTERVAL '24 hours';", - "format": "table", "refId": "A" } - ] - }, - { - "id": 173, - "type": "stat", - "title": "On-site SLA (median mins, 24h)", - "gridPos": { "x": 12, "y": 70, "w": 6, "h": 5 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } }, - "fieldConfig": { "defaults": { "unit": "m", "decimals": 0 } }, - "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY onsite_mins) AS \"On-site p50 (min)\" FROM tracksolid.v_sla_inflight WHERE created_at > NOW() - INTERVAL '24 hours';", - "format": "table", "refId": "A" } - ] - }, - { - "id": 174, - "type": "stat", - "title": "Resolution SLA (median mins, 24h)", - "gridPos": { "x": 18, "y": 70, "w": 6, "h": 5 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } }, - "fieldConfig": { "defaults": { "unit": "m", "decimals": 0 } }, - "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY resolution_mins) AS \"Resolution p50 (min)\" FROM tracksolid.v_sla_inflight WHERE created_at > NOW() - INTERVAL '24 hours';", - "format": "table", "refId": "A" } - ] - }, - { - "id": 175, - "type": "table", - "title": "At-risk tickets", - "gridPos": { "x": 0, "y": 75, "w": 24, "h": 10 }, - "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "options": { "cellHeight": "sm", "showHeader": true, "footer": { "show": false } }, - "fieldConfig": { "defaults": { "custom": { "align": "auto", "filterable": true } } }, - "targets": [ - { "datasource": { "type": "postgres", "uid": "tracksolid_pg" }, - "rawSql": "SELECT ticket_id, customer, priority, ticket_stage, driver_name, created_at, dispatch_mins, enroute_mins, onsite_mins, resolution_mins FROM tracksolid.v_sla_inflight WHERE ticket_stage NOT IN ('resolved', 'cancelled') ORDER BY resolution_mins DESC NULLS LAST LIMIT 50;", - "format": "table", "refId": "A" } - ] + "rawSql": "SELECT day::timestamptz AS time, alarm_name AS metric, alarm_count AS value FROM tracksolid.v_alarms_daily WHERE day > CURRENT_DATE - INTERVAL '30 days' ORDER BY day;", + "format": "time_series", + "refId": "A" } ] } diff --git a/migrations/12_drop_ops.sql b/migrations/12_drop_ops.sql new file mode 100644 index 0000000..73a30d7 --- /dev/null +++ b/migrations/12_drop_ops.sql @@ -0,0 +1,30 @@ +-- 12_drop_ops.sql +-- Purge the dormant `ops` schema (workshop / tickets / dispatch / SLA / odometer) +-- and the dispatch/SLA artefacts that lived in `tracksolid`. These features were +-- never implemented and may take a different direction; the schema and views were +-- empty (or seed-only) and unused by the live map/dashboard pipeline. +-- +-- Created by migrations 06 (ops schema + dispatch_log), 07 (v_sla_inflight) and +-- 08 (ops.cost_rates / ops.kpi_targets seed). Per the repo rule we do NOT rewrite +-- those applied migrations — this forward migration drops the objects instead. On +-- a fresh rebuild 06/07/08 create them, then this file removes them again. +-- +-- Pre-drop snapshot of the only seeded tables: docs/reports/260605_ops_purge_backup.md +-- (the seed is also reproducible from 08_analytics_config.sql). +-- +-- Every statement is IF EXISTS so the file is safe to re-apply. +-- +-- NOTE: dwh_gold and tracksolid.v_utilisation_daily are intentionally NOT touched +-- here — that is a separate decision. + +-- View first: it reads ops.tickets + tracksolid.dispatch_log, so it must go before +-- the objects it depends on (avoids an implicit CASCADE surprise). +DROP VIEW IF EXISTS tracksolid.v_sla_inflight; + +-- The whole ops schema: tickets, service_log, odometer_readings, cost_rates, +-- kpi_targets, and the view vw_service_forecast. CASCADE clears intra-schema deps. +DROP SCHEMA IF EXISTS ops CASCADE; + +-- Dispatch feature table — lived in the tracksolid schema, empty, only fed +-- v_sla_inflight (now dropped). +DROP TABLE IF EXISTS tracksolid.dispatch_log; diff --git a/migrations/13_drop_dwh_gold.sql b/migrations/13_drop_dwh_gold.sql new file mode 100644 index 0000000..3c93f1a --- /dev/null +++ b/migrations/13_drop_dwh_gold.sql @@ -0,0 +1,23 @@ +-- 13_drop_dwh_gold.sql +-- Purge the dormant `dwh_gold` aggregate schema and its dependent view. The nightly +-- ETL (dwh_gold.refresh_daily_metrics) was never scheduled, both fact/dim tables were +-- empty, and nothing in the live map/dashboard pipeline reads them. These analytics +-- may take a different direction later. +-- +-- Created by migrations 02 (schema), 05 (dwh_gold expansion + refresh_daily_metrics) +-- and 07 (tracksolid.v_utilisation_daily). Per the repo rule we do NOT rewrite those +-- applied migrations — this forward migration drops the objects instead. On a fresh +-- rebuild 02/05/07 create them, then this file removes them again. +-- +-- Both tables were empty at drop time, so there is no data backup (cf. the ops purge, +-- which had seed rows — docs/reports/260605_ops_purge_backup.md). Companion to +-- 12_drop_ops.sql; together they retire the unused ops + dwh_gold analytics layers. +-- +-- Every statement is IF EXISTS so the file is safe to re-apply. + +-- View first: it reads dwh_gold.dim_vehicles + dwh_gold.fact_daily_fleet_metrics. +DROP VIEW IF EXISTS tracksolid.v_utilisation_daily; + +-- The whole dwh_gold schema: dim_vehicles, fact_daily_fleet_metrics, the +-- dim_vehicles sequence/indexes, and the refresh_daily_metrics() function. +DROP SCHEMA IF EXISTS dwh_gold CASCADE; diff --git a/run_migrations.py b/run_migrations.py index 69129c4..578d7e4 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -35,6 +35,8 @@ MIGRATIONS = [ "09_trips_enrichment.sql", # trips.route_geom + addresses + plate + v_trips_enriched "10_pgbouncer_auth.sql", # pgbouncer role + user_lookup() for SCRAM passthrough "11_reporting_schema.sql", # reporting.* map-dashboard read layer (dashboard_api) + "12_drop_ops.sql", # purge dormant ops schema + dispatch_log + v_sla_inflight + "13_drop_dwh_gold.sql", # purge dormant dwh_gold schema + v_utilisation_daily ] # ── Tables that must exist before the service is allowed to start ───────────── From 9986d3b4116177a7bcf4a88054be481954cc422f Mon Sep 17 00:00:00 2001 From: david kiania Date: Fri, 5 Jun 2026 20:39:56 +0300 Subject: [PATCH 25/31] docs(claude): add pending Grafana redeploy to open items (post ops/dwh_gold purge) Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CLAUDE.md b/CLAUDE.md index 9718983..a2cfaef 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -251,6 +251,7 @@ Latest full snapshot: `docs/reports/260412_baseline_report.md` | Priority | Item | |---|---| +| HIGH | **Redeploy the Grafana service in Coolify** to apply `daily_operations_dashboard.json` — 5 panel areas (In-flight SLA, Idle Cost, Utilisation Heatmap, Row 7 Field-Service SLAs) that queried the now-dropped `v_sla_inflight`/`v_utilisation_daily` were removed. The DB views are already gone, so **live Grafana shows errors on those panels until the redeploy** (purge commit `8c5a43f`, 2026-06-05). | | HIGH | Run `import_drivers_csv.py --apply` — 144 X3/JC400P devices with names + plates waiting | | HIGH | Register webhooks: `/pushoil` `/pushtem` `/pushlbs` (auto-register on push now done — commit 257643c) | | HIGH | Investigate X3-63282 in Kampala — legitimate or unauthorised? | From d95e5c2dbdc38c1ba9d24a41b327b41c93457aa5 Mon Sep 17 00:00:00 2001 From: kianiadee Date: Sat, 6 Jun 2026 10:07:46 +0300 Subject: [PATCH 26/31] config(cors): allow fleetnow.rahamafresh.com origin on dashboard_api The merged FleetNow dashboard (separate repo, Coolify) reads this read-API, so its origin must be in DASHBOARD_CORS_ORIGINS. Added to the code default; live config is set via the env in ~/deploy_dashboard_api.sh on the host. Co-Authored-By: Claude Opus 4.8 --- dashboard_api_rev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashboard_api_rev.py b/dashboard_api_rev.py index 98530e1..5cf0539 100644 --- a/dashboard_api_rev.py +++ b/dashboard_api_rev.py @@ -54,7 +54,7 @@ _ALLOWED_ORIGINS = [ o.strip() for o in os.getenv( "DASHBOARD_CORS_ORIGINS", - "https://liveposition.rahamafresh.com,https://fleetintelligence.rahamafresh.com", + "https://liveposition.rahamafresh.com,https://fleetintelligence.rahamafresh.com,https://fleetnow.rahamafresh.com", ).split(",") if o.strip() ] From 94cbd2a85ec425f7509771a5d11d9a8905eddbd5 Mon Sep 17 00:00:00 2001 From: kianiadee Date: Sat, 6 Jun 2026 10:09:48 +0300 Subject: [PATCH 27/31] docs: document FleetNow merged dashboard + read-API topology + FIX-D03 - New '3. Map dashboards & read-API' subsection: the three SPAs (liveposition, fleetintelligence, fleetnow), how dashboard_api is deployed (standalone bridge container, not Coolify), and that FleetNow lives in its own repo. - FIX-D03: fleetnow CORS origin + the deploy-script strip/guard fixes. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index a2cfaef..cfc0c56 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -66,6 +66,25 @@ See `docs/CONNECTIONS.md` for the full shape. Summary: e.g. `docker ps --filter name=timescale_db --format "{{.Names}}" | head -1` - **Env vars:** loaded from `.env` via `env_file` in `docker-compose.yaml`. See `docs/CONNECTIONS.md` for variable names. Never hardcode secrets. +### Map dashboards & read-API + +The map UIs read the **`dashboard_api`** service (FastAPI, `dashboard_api_rev.py`) at +`https://fleetapi.rahamafresh.com` — the stable replacement for the retired n8n webhooks. It serves +GeoJSON from the `reporting.*` functions (`fn_live_positions`, `fn_vehicle_track`, `fn_trips_for_map`) ++ filter options. **`dashboard_api` is a STANDALONE Traefik-labelled bridge container, NOT Coolify-managed** — +it bind-mounts the host file `~/dashboard_api/dashboard_api_rev.py` and is (re)deployed by +`~/deploy_dashboard_api.sh` on the host (an env/CORS change needs a *recreate*, not a restart). Three +single-page apps consume it: + +| Dashboard | What | Hosting | +|---|---|---| +| `liveposition.rahamafresh.com` | live positions only | `index.html` in rustfs bucket `liveposition` behind an nginx proxy | +| `fleetintelligence.rahamafresh.com` | historical trips only | `index.html` in rustfs bucket `fleetintelligence` behind an nginx proxy | +| `fleetnow.rahamafresh.com` | **merged** live + trips (current best UI) | **own repo** `repo.rahamafresh.com/kianiadee/fleetnow.git`, deployed via **Coolify (Dockerfile → nginx)** | + +All three origins must be in the API's `DASHBOARD_CORS_ORIGINS` (see FIX-D03). **FleetNow is the +single source of truth for the merged map and lives in its own repo — edit it there, not here.** + --- ## 4. Codebase Map @@ -210,6 +229,7 @@ dwh_control.v_watermark_lag -- Grafana: extract vs. load lag per table | BUG-02 | Migration 04 | Historical `distance_m` rows ÷1,000,000 → renamed to `distance_km` | | FIX-D01 | `dashboard_api_rev.py` | `POST /webhook/fleet-dashboard` read body as JSON, but the SPA posts `x-www-form-urlencoded` → `request.json()` threw, filters silently dropped, map always returned the whole fleet. Now parsed by Content-Type (`parse_qs` for form, JSON still accepted). Commit `f1387d1` | | FIX-D02 | `dashboard_api_rev.py` | `reporting.v_trips` matview froze on 2026-06-01 when n8n (which ran the scheduled refresh) was retired → dashboard showed "no trips". Added an in-process background refresher (`REFRESH MATERIALIZED VIEW CONCURRENTLY` every `VTRIPS_REFRESH_INTERVAL_S`, default 300s; pg advisory-lock guarded for `--workers`; logs to `reporting.refresh_log` source=`dashboard_api`). Commit `30b3515` | +| FIX-D03 | `dashboard_api_rev.py`, `~/deploy_dashboard_api.sh` (host) | Added `https://fleetnow.rahamafresh.com` to `DASHBOARD_CORS_ORIGINS` default for the merged **FleetNow** dashboard. The standalone bridge container inherits its env from `webhook_receiver`, which already carries the old two-origin value — so the deploy script's *conditional* append never fired. The script now **strips any inherited `DASHBOARD_CORS_ORIGINS` and sets all three origins unconditionally**, and **guards the `mv`** so a missing staged `dashboard_api_rev.py` doesn't abort the run under `set -e` (env changes need a container *recreate*, not a restart). Commit `d95e5c2` | --- From 347c97ec4c7f8ca29cb79425fef8245f386fb01b Mon Sep 17 00:00:00 2001 From: david kiania Date: Mon, 8 Jun 2026 13:54:47 +0300 Subject: [PATCH 28/31] feat(reporting): fleet segmentation + deduped vehicle roster (migration 14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add reporting.fn_fleet_segment() and reporting.v_vehicles, splitting the fleet into ticket-closing field_service vs specialist plant (crane/pick-up/motorbike) that does not close immediate customer tickets. The segment is DERIVED from tracksolid.devices.vehicle_models — itself an authoritative Tracksolid API field (sync_devices maps jimi.user.device.list -> vehicleModels) — so it stays API-current with no re-seeding; the manual vehicle_category column is intentionally unused. v_vehicles collapses the tracker+dashcam device pairs to one row per vehicle by reusing reporting.normalize_plate() and the same primary-device precedence as reporting.v_trips / v_live_positions (auto-merges 'KDS 453Y'/'KDS 453 Y', resolves within-plate model conflicts via the primary tracker). Verified live: 80 vehicles (61 field_service / 16 specialist / 3 unassigned), grafana_ro granted. Includes the supporting data-quality report. Co-Authored-By: Claude Opus 4.8 --- .../260608_fleet_registry_data_quality.md | 117 + .../260608_fleet_registry_data_quality.pdf | 6144 +++++++++++++++++ .../14_fleet_segment_and_vehicles_view.sql | 104 + run_migrations.py | 1 + 4 files changed, 6366 insertions(+) create mode 100644 docs/reports/260608_fleet_registry_data_quality.md create mode 100644 docs/reports/260608_fleet_registry_data_quality.pdf create mode 100644 migrations/14_fleet_segment_and_vehicles_view.sql diff --git a/docs/reports/260608_fleet_registry_data_quality.md b/docs/reports/260608_fleet_registry_data_quality.md new file mode 100644 index 0000000..c75904e --- /dev/null +++ b/docs/reports/260608_fleet_registry_data_quality.md @@ -0,0 +1,117 @@ +# Fleet Registry — Data Quality Report + +**Date:** 2026-06-08 +**Source:** `tracksolid.devices` (the single registry of record) +**Prepared for:** Fireside leadership / fleet operations +**Scope:** 181 tracking devices → **80 physical vehicles** after de-duplicating the GPS-tracker + dashcam pairs that share a number plate. + +--- + +## 1. Executive summary + +The fleet registry is **operationally usable but materially incomplete**, and the gaps concentrate in exactly the fields the business needs to run field-service KPIs: driver identity, driver contact, vehicle type, and device pairing. + +| Theme | Headline | Business impact | +|---|---|---| +| **Driver contact** | **97%** of records have **no driver phone** (175 / 181) | Dispatch and escalation can't reach the driver from our own systems | +| **Driver identity** | **23%** have **no driver name** (41 / 181) | Trips, speeding and idle time can't be attributed to a person — no accountability | +| **Vehicle type** | **22%** have **no model** (40 / 181) | We can't cleanly separate ticket-closing service cars from cranes / bikes | +| **Device pairing** | **29%** of vehicles (23 / 80) are **missing a tracker or a camera** | Blind spots: 6 vehicles have **no GPS at all**; 16 have **no dashcam evidence** | +| **Unidentified hardware** | **41** device rows carry **no plate**; 19 of those are fully blank | Hardware we are paying to track but cannot tie to a vehicle, driver or city | + +**Root cause is upstream, not in our database.** Almost every gap is a field that was never entered in the **Tracksolid Pro portal** at provisioning time — our pipeline faithfully stores whatever the portal holds. This is a **data-entry discipline** problem at vehicle onboarding, plus an **incomplete driver/plate import** that is still pending (the 144-device CSV). + +--- + +## 2. The fleet, de-duplicated + +After collapsing tracker+camera pairs to one row per number plate: + +| Segment | Vehicles | Detail | +|---|---|---| +| **Field service** (closes customer tickets) | ~62 | Probox ×57, Van, Vezel, Mazda, + a few UG/other cars | +| **Specialist** (cranes, bikes, pick-ups — *not* immediate tickets) | ~17 | Crane ×3, Motorbike ×8, Pick-Up ×~6 | +| **Ambiguous** (type conflicts — see §3) | 2 | KCY 080X, KCZ 223P | +| **Total physical vehicles** | **80** | from 181 devices | +| **Unassigned spare devices** (no plate) | 41 rows | cannot be counted as vehicles | + +--- + +## 3. Findings by severity + +### 🔴 Critical — operational blind spots + +**C1. 6 vehicles have a dashcam but NO GPS tracker** — they are invisible on the live fleet map and contribute no trips/mileage. +`KCN 496A · KCQ 215F · KCU 237Z · KDM 306S · KDN 759G · KCZ 199P` + +**C2. 16 vehicles have a GPS tracker but NO dashcam** — no video evidence for incidents, disputes, or safety review. Concentrated in the **specialist fleet** (all 8 motorbikes, the Uganda vehicles) plus several Proboxes. + +**C3. 41 device rows (23%) carry no number plate** — they cannot be tied to a vehicle, driver, or city. **19 of these are entirely blank** (no plate, no model, no driver, status "unknown") — hardware we track but cannot identify at all. + +### 🟠 High — accountability & classification gaps + +**H1. 97% of records have no driver phone** (175 / 181). Only 6 drivers are contactable from our data. + +**H2. 23% have no driver name** (41 / 181). Behaviour analytics (speeding, idle, harsh events) cannot be attributed. + +**H3. 22% have no vehicle model** (40 / 181) — this is the field that drives the field-service vs specialist split. Until it's populated, ~22% of the fleet can only be classified by guessing from the device name. + +**H4. Plate data-entry inconsistencies** corrupting the vehicle count: +- **`KDS 453Y` is entered twice** — `KDS 453Y` (tracker) and `KDS 453 Y` (camera, stray space). One vehicle, counted as two. +- **`KCC 199P` vs `KCZ 199P`** — both pick-ups, both driver *Mbuvi Kioko*, one tracker + one camera. Almost certainly **one vehicle mis-keyed under two plates**. + +**H5. Two plates disagree with themselves** — the tracker and dashcam on the *same plate* report different vehicle types: + +| Plate | Tracker says | Camera says | Driver | +|---|---|---|---| +| KCY 080X | Pick-Up | Probox | Lawrence Kijogi | +| KCZ 223P | Pick-Up | Probox | Felix Muema | + +### 🟡 Medium — analytics reliability + +**M1. `assigned_city` is unreliable.** 4 vehicles have their two devices assigned to *different cities* (e.g. KDC 490Q: Mombasa vs Nairobi; KCY 838X: Mombasa vs Voi). The field appears **derived from the Tracksolid account** the device sits in, not the vehicle's actual base — so **regional (Nairobi / Mombasa / Kampala) reporting is suspect**. + +**M2. Placeholder / non-person driver names** pollute driver-level analytics: `Garage` (×4), `UG` (×2), `Management_Mazda` (×2), `Parked` (×1). These are slots, not people. + +**M3. One driver, multiple plates** — 5 cases (`Garage`, `Gideon Kiprono`, `Kelvin Wambugu`, `Mbuvi Kioko`, `UG`). Some are the duplicate-plate issues above; the rest need confirmation of whether a driver genuinely rotates vehicles. + +### ⚪ Low — asset-register completeness (low operational impact today) + +**L1. `vehicle_brand` is 99% empty** (179 / 181) and **`vin` is 100% empty** (181 / 181). Not currently used in any KPI, but would be needed for a formal asset/insurance register. + +--- + +## 4. Completeness scorecard (device-level, 181 rows) + +| Field | Populated | Missing | % missing | +|---|---|---|---| +| Number plate | 140 | 41 | 23% | +| Vehicle model | 141 | 40 | 22% | +| Driver name | 140 | 41 | 23% | +| Driver phone | 6 | 175 | **97%** | +| SIM | 155 | 26 | 14% | +| Assigned city | 152 | 29 | 16% | +| Vehicle brand | 2 | 179 | **99%** | +| VIN | 0 | 181 | **100%** | + +--- + +## 5. Recommended actions + +| # | Action | Owner | Effort | Fixes | +|---|---|---|---|---| +| 1 | **Run the pending driver/plate CSV import** (144 devices with names + plates already prepared) | Engineering | Low — one command | H1, H2, H3 (large chunk) | +| 2 | **Mandate model + driver + phone at vehicle onboarding** in the Tracksolid Pro portal; make them required fields in the process | Operations | Process change | Root cause of most gaps | +| 3 | **Resolve the 4 specific record issues** in §3 (KDS 453Y dup, KCC/KCZ 199P, KCY 080X, KCZ 223P) | Operations to confirm, Engineering to correct | Low | H4, H5 | +| 4 | **Audit the 22 vehicles missing a tracker or camera** (§3 C1/C2) — install missing hardware or confirm intentional | Field ops | Medium | C1, C2 | +| 5 | **Identify the 19 fully-blank devices** — match serial → vehicle, or decommission | Field ops | Medium | C3 | +| 6 | **Stop trusting `assigned_city` for regional reporting** until it's set per-vehicle rather than inherited from the account | Engineering + Ops | Medium | M1 | +| 7 | Replace placeholder driver names with real assignments or a clear "unassigned" convention | Operations | Low | M2, M3 | + +**Quick wins:** Actions 1 and 3 are low-effort and would clear the majority of the High-severity gaps immediately. + +--- + +## 6. Method & reproducibility + +All figures derived from a single read-only scan of `tracksolid.devices`. De-duplication keys on a normalised plate (`UPPER(REPLACE(vehicle_number,' ',''))`) so spacing variants collapse. Tracker = device types `GT06E / X3 / AT4`; camera = `JC400P`. The scan script and the proposed `tracksolid.v_vehicles` de-duplicated view are tracked in the repository; re-running the scan after each remediation step will show progress against this baseline. diff --git a/docs/reports/260608_fleet_registry_data_quality.pdf b/docs/reports/260608_fleet_registry_data_quality.pdf new file mode 100644 index 0000000..2eba271 --- /dev/null +++ b/docs/reports/260608_fleet_registry_data_quality.pdf @@ -0,0 +1,6144 @@ +%PDF-1.7 +% + +1 0 obj +<< + /Type /Pages + /Count 6 + /Kids [389 0 R 391 0 R 393 0 R 395 0 R 397 0 R 399 0 R] +>> +endobj + +2 0 obj +<< + /Type /Outlines + /First 3 0 R + /Last 3 0 R + /Count 1 +>> +endobj + +3 0 obj +<< + /Parent 2 0 R + /First 4 0 R + /Last 13 0 R + /Count -6 + /Title + /Dest 384 0 R +>> +endobj + +4 0 obj +<< + /Parent 3 0 R + /Next 5 0 R + /Title (1. Executive summary) + /Dest 374 0 R +>> +endobj + +5 0 obj +<< + /Parent 3 0 R + /Next 6 0 R + /Prev 4 0 R + /Title (2. The fleet, de-duplicated) + /Dest 375 0 R +>> +endobj + +6 0 obj +<< + /Parent 3 0 R + /Next 11 0 R + /Prev 5 0 R + /First 7 0 R + /Last 10 0 R + /Count -4 + /Title (3. Findings by severity) + /Dest 380 0 R +>> +endobj + +7 0 obj +<< + /Parent 6 0 R + /Next 8 0 R + /Title + /Dest 376 0 R +>> +endobj + +8 0 obj +<< + /Parent 6 0 R + /Next 9 0 R + /Prev 7 0 R + /Title + /Dest 377 0 R +>> +endobj + +9 0 obj +<< + /Parent 6 0 R + /Next 10 0 R + /Prev 8 0 R + /Title + /Dest 378 0 R +>> +endobj + +10 0 obj +<< + /Parent 6 0 R + /Prev 9 0 R + /Title + /Dest 379 0 R +>> +endobj + +11 0 obj +<< + /Parent 3 0 R + /Next 12 0 R + /Prev 6 0 R + /Title (4. Completeness scorecard (device-level, 181 rows)) + /Dest 381 0 R +>> +endobj + +12 0 obj +<< + /Parent 3 0 R + /Next 13 0 R + /Prev 11 0 R + /Title (5. Recommended actions) + /Dest 382 0 R +>> +endobj + +13 0 obj +<< + /Parent 3 0 R + /Prev 12 0 R + /Title (6. Method & reproducibility) + /Dest 383 0 R +>> +endobj + +14 0 obj +<< + /Nums [0 327 0 R 1 328 0 R 2 329 0 R 3 330 0 R 4 331 0 R 5 332 0 R] +>> +endobj + +15 0 obj +<< + /Type /StructTreeRoot + /RoleMap << + /Datetime /Span + /Terms /Part + /Title /P + /Strong /Span + /Em /Span + >> + /K [22 0 R] + /ParentTree << + /Nums [0 16 0 R 1 17 0 R 2 18 0 R 3 19 0 R 4 20 0 R 5 21 0 R] + >> + /IDTree << + /Names [(U1x0y0) 315 0 R (U1x1y0) 314 0 R (U1x2y0) 313 0 R (U2x0y0) 264 0 R (U2x1y0) 263 0 R (U2x2y0) 262 0 R (U3x0y0) 194 0 R (U3x1y0) 193 0 R (U3x2y0) 192 0 R (U3x3y0) 191 0 R (U4x0y0) 144 0 R (U4x1y0) 143 0 R (U4x2y0) 142 0 R (U4x3y0) 141 0 R (U5x0y0) 92 0 R (U5x1y0) 91 0 R (U5x2y0) 90 0 R (U5x3y0) 89 0 R (U5x4y0) 88 0 R] + >> + /ParentTreeNextKey 6 +>> +endobj + +16 0 obj +[326 0 R 325 0 R 319 0 R 324 0 R 319 0 R 323 0 R 319 0 R 322 0 R 319 0 R 319 0 R 321 0 R 319 0 R 320 0 R 319 0 R 319 0 R 318 0 R 316 0 R 317 0 R 316 0 R 316 0 R 316 0 R 315 0 R 314 0 R 313 0 R 310 0 R 308 0 R 306 0 R 307 0 R 307 0 R 306 0 R 305 0 R 305 0 R 305 0 R 303 0 R 301 0 R 299 0 R 300 0 R 299 0 R 299 0 R 298 0 R 298 0 R 298 0 R 296 0 R 294 0 R 292 0 R 293 0 R 292 0 R 291 0 R 291 0 R 291 0 R 289 0 R 287 0 R 285 0 R 286 0 R 286 0 R 286 0 R 282 0 R 284 0 R 284 0 R 282 0 R 283 0 R 283 0 R 283 0 R 280 0 R 278 0 R 276 0 R 277 0 R 276 0 R 276 0 R 275 0 R 275 0 R 275 0 R 271 0 R 267 0 R 267 0 R 270 0 R 267 0 R 267 0 R 269 0 R 267 0 R 268 0 R 268 0 R 267 0 R 266 0 R 265 0 R 264 0 R 263 0 R 262 0 R 259 0 R 258 0 R 258 0 R 257 0 R 256 0 R 256 0 R 254 0 R 252 0 R 252 0 R 253 0 R 252 0 R 251 0 R 250 0 R 250 0 R 248 0 R 247 0 R 247 0 R 246 0 R 245 0 R 243 0 R 241 0 R 239 0 R 237 0 R 236 0 R 236 0 R 235 0 R 234 0 R] +endobj + +17 0 obj +[229 0 R 228 0 R 228 0 R 227 0 R 225 0 R 225 0 R 226 0 R 224 0 R 222 0 R 222 0 R 223 0 R 222 0 R 222 0 R 221 0 R 219 0 R 220 0 R 219 0 R 219 0 R 218 0 R 218 0 R 217 0 R 216 0 R 215 0 R 214 0 R 214 0 R 213 0 R 212 0 R 212 0 R 211 0 R 198 0 R 210 0 R 208 0 R 198 0 R 207 0 R 198 0 R 206 0 R 198 0 R 205 0 R 203 0 R 202 0 R 198 0 R 200 0 R 198 0 R 199 0 R 199 0 R 198 0 R 197 0 R 195 0 R 196 0 R 195 0 R 195 0 R 194 0 R 193 0 R 192 0 R 191 0 R 188 0 R 187 0 R 186 0 R 185 0 R 183 0 R 182 0 R 181 0 R 180 0 R 176 0 R 176 0 R 175 0 R 174 0 R 172 0 R 168 0 R 171 0 R 168 0 R 168 0 R 170 0 R 170 0 R 170 0 R 168 0 R 169 0 R 169 0 R 168 0 R 167 0 R 162 0 R 166 0 R 162 0 R 165 0 R 162 0 R 164 0 R 162 0 R 163 0 R 162 0 R 161 0 R 155 0 R 160 0 R 155 0 R 159 0 R 155 0 R 158 0 R 155 0 R 157 0 R 155 0 R 156 0 R 155 0 R 155 0 R 154 0 R 154 0 R 153 0 R 152 0 R 150 0 R 146 0 R 149 0 R 147 0 R 146 0 R 146 0 R] +endobj + +18 0 obj +[145 0 R 144 0 R 143 0 R 142 0 R 141 0 R 138 0 R 137 0 R 136 0 R 135 0 R 133 0 R 132 0 R 131 0 R 130 0 R 128 0 R 127 0 R 126 0 R 125 0 R 123 0 R 122 0 R 121 0 R 120 0 R 117 0 R 116 0 R 115 0 R 114 0 R 112 0 R 111 0 R 110 0 R 109 0 R 107 0 R 106 0 R 105 0 R 104 0 R 101 0 R 100 0 R 99 0 R 98 0 R] +endobj + +19 0 obj +[93 0 R] +endobj + +20 0 obj +[92 0 R 91 0 R 90 0 R 89 0 R 88 0 R 85 0 R 84 0 R 84 0 R 84 0 R 84 0 R 83 0 R 83 0 R 83 0 R 83 0 R 82 0 R 81 0 R 81 0 R 81 0 R 80 0 R 80 0 R 78 0 R 77 0 R 77 0 R 77 0 R 77 0 R 77 0 R 77 0 R 77 0 R 76 0 R 76 0 R 76 0 R 76 0 R 76 0 R 76 0 R 76 0 R 75 0 R 74 0 R 73 0 R 73 0 R 71 0 R 70 0 R 70 0 R 70 0 R 69 0 R 69 0 R 69 0 R 69 0 R 68 0 R 68 0 R 68 0 R 68 0 R 68 0 R 68 0 R 67 0 R 66 0 R 64 0 R 63 0 R 63 0 R 63 0 R 63 0 R 63 0 R 63 0 R 62 0 R 62 0 R 62 0 R 62 0 R 62 0 R 61 0 R 60 0 R 59 0 R 57 0 R 56 0 R 56 0 R 56 0 R 56 0 R 55 0 R 55 0 R 55 0 R 54 0 R 53 0 R 52 0 R 50 0 R 49 0 R 48 0 R 46 0 R 46 0 R 46 0 R 46 0 R 45 0 R 45 0 R 45 0 R 45 0 R 45 0 R 45 0 R 44 0 R 44 0 R 43 0 R 42 0 R 40 0 R 39 0 R 39 0 R 39 0 R 39 0 R 39 0 R 39 0 R 39 0 R 39 0 R 39 0 R 39 0 R 38 0 R 37 0 R 36 0 R] +endobj + +21 0 obj +[31 0 R 30 0 R 30 0 R 29 0 R 23 0 R 28 0 R 23 0 R 23 0 R 27 0 R 23 0 R 23 0 R 26 0 R 23 0 R 25 0 R 23 0 R 24 0 R 23 0 R 23 0 R] +endobj + +22 0 obj +<< + /Type /StructElem + /S /Document + /P 15 0 R + /K [326 0 R 319 0 R 318 0 R 316 0 R 272 0 R 267 0 R 266 0 R 265 0 R 230 0 R 229 0 R 228 0 R 225 0 R 222 0 R 219 0 R 218 0 R 216 0 R 214 0 R 212 0 R 198 0 R 195 0 R 177 0 R 176 0 R 168 0 R 162 0 R 155 0 R 154 0 R 146 0 R 145 0 R 94 0 R 93 0 R 32 0 R 30 0 R 29 0 R 23 0 R] +>> +endobj + +23 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [4 28 0 R 6 7 27 0 R 9 10 26 0 R 12 25 0 R 14 24 0 R 16 17] + /Pg 399 0 R +>> +endobj + +24 0 obj +<< + /Type /StructElem + /S /Code + /P 23 0 R + /K [15] + /Pg 399 0 R +>> +endobj + +25 0 obj +<< + /Type /StructElem + /S /Code + /P 23 0 R + /K [13] + /Pg 399 0 R +>> +endobj + +26 0 obj +<< + /Type /StructElem + /S /Code + /P 23 0 R + /K [11] + /Pg 399 0 R +>> +endobj + +27 0 obj +<< + /Type /StructElem + /S /Code + /P 23 0 R + /K [8] + /Pg 399 0 R +>> +endobj + +28 0 obj +<< + /Type /StructElem + /S /Code + /P 23 0 R + /K [5] + /Pg 399 0 R +>> +endobj + +29 0 obj +<< + /Type /StructElem + /S /H2 + /P 22 0 R + /T (6. Method & reproducibility) + /K [3] + /Pg 399 0 R +>> +endobj + +30 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [31 0 R 1 2] + /Pg 399 0 R +>> +endobj + +31 0 obj +<< + /Type /StructElem + /S /Strong + /P 30 0 R + /K [0] + /Pg 399 0 R +>> +endobj + +32 0 obj +<< + /Type /StructElem + /S /Div + /P 22 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [33 0 R] +>> +endobj + +33 0 obj +<< + /Type /StructElem + /S /Table + /P 32 0 R + /K [86 0 R 34 0 R] +>> +endobj + +34 0 obj +<< + /Type /StructElem + /S /TBody + /P 33 0 R + /K [79 0 R 72 0 R 65 0 R 58 0 R 51 0 R 41 0 R 35 0 R] +>> +endobj + +35 0 obj +<< + /Type /StructElem + /S /TR + /P 34 0 R + /K [40 0 R 39 0 R 38 0 R 37 0 R 36 0 R] +>> +endobj + +36 0 obj +<< + /Type /StructElem + /S /TD + /P 35 0 R + /A [<< + /O /Table + /Headers [(U5x4y0)] + >>] + /K [111] + /Pg 397 0 R +>> +endobj + +37 0 obj +<< + /Type /StructElem + /S /TD + /P 35 0 R + /A [<< + /O /Table + /Headers [(U5x3y0)] + >>] + /K [110] + /Pg 397 0 R +>> +endobj + +38 0 obj +<< + /Type /StructElem + /S /TD + /P 35 0 R + /A [<< + /O /Table + /Headers [(U5x2y0)] + >>] + /K [109] + /Pg 397 0 R +>> +endobj + +39 0 obj +<< + /Type /StructElem + /S /TD + /P 35 0 R + /A [<< + /O /Table + /Headers [(U5x1y0)] + >>] + /K [99 100 101 102 103 104 105 106 107 108] + /Pg 397 0 R +>> +endobj + +40 0 obj +<< + /Type /StructElem + /S /TD + /P 35 0 R + /A [<< + /O /Table + /Headers [(U5x0y0)] + >>] + /K [98] + /Pg 397 0 R +>> +endobj + +41 0 obj +<< + /Type /StructElem + /S /TR + /P 34 0 R + /K [50 0 R 45 0 R 44 0 R 43 0 R 42 0 R] +>> +endobj + +42 0 obj +<< + /Type /StructElem + /S /TD + /P 41 0 R + /A [<< + /O /Table + /Headers [(U5x4y0)] + >>] + /K [97] + /Pg 397 0 R +>> +endobj + +43 0 obj +<< + /Type /StructElem + /S /TD + /P 41 0 R + /A [<< + /O /Table + /Headers [(U5x3y0)] + >>] + /K [96] + /Pg 397 0 R +>> +endobj + +44 0 obj +<< + /Type /StructElem + /S /TD + /P 41 0 R + /A [<< + /O /Table + /Headers [(U5x2y0)] + >>] + /K [94 95] + /Pg 397 0 R +>> +endobj + +45 0 obj +<< + /Type /StructElem + /S /TD + /P 41 0 R + /A [<< + /O /Table + /Headers [(U5x1y0)] + >>] + /K [49 0 R 47 0 R 46 0 R 88 89 90 91 92 93] + /Pg 397 0 R +>> +endobj + +46 0 obj +<< + /Type /StructElem + /S /Strong + /P 45 0 R + /K [84 85 86 87] + /Pg 397 0 R +>> +endobj + +47 0 obj +<< + /Type /StructElem + /S /Code + /P 45 0 R + /K [48 0 R] +>> +endobj + +48 0 obj +<< + /Type /StructElem + /S /Strong + /P 47 0 R + /K [83] + /Pg 397 0 R +>> +endobj + +49 0 obj +<< + /Type /StructElem + /S /Strong + /P 45 0 R + /K [82] + /Pg 397 0 R +>> +endobj + +50 0 obj +<< + /Type /StructElem + /S /TD + /P 41 0 R + /A [<< + /O /Table + /Headers [(U5x0y0)] + >>] + /K [81] + /Pg 397 0 R +>> +endobj + +51 0 obj +<< + /Type /StructElem + /S /TR + /P 34 0 R + /K [57 0 R 55 0 R 54 0 R 53 0 R 52 0 R] +>> +endobj + +52 0 obj +<< + /Type /StructElem + /S /TD + /P 51 0 R + /A [<< + /O /Table + /Headers [(U5x4y0)] + >>] + /K [80] + /Pg 397 0 R +>> +endobj + +53 0 obj +<< + /Type /StructElem + /S /TD + /P 51 0 R + /A [<< + /O /Table + /Headers [(U5x3y0)] + >>] + /K [79] + /Pg 397 0 R +>> +endobj + +54 0 obj +<< + /Type /StructElem + /S /TD + /P 51 0 R + /A [<< + /O /Table + /Headers [(U5x2y0)] + >>] + /K [78] + /Pg 397 0 R +>> +endobj + +55 0 obj +<< + /Type /StructElem + /S /TD + /P 51 0 R + /A [<< + /O /Table + /Headers [(U5x1y0)] + >>] + /K [56 0 R 75 76 77] + /Pg 397 0 R +>> +endobj + +56 0 obj +<< + /Type /StructElem + /S /Strong + /P 55 0 R + /K [71 72 73 74] + /Pg 397 0 R +>> +endobj + +57 0 obj +<< + /Type /StructElem + /S /TD + /P 51 0 R + /A [<< + /O /Table + /Headers [(U5x0y0)] + >>] + /K [70] + /Pg 397 0 R +>> +endobj + +58 0 obj +<< + /Type /StructElem + /S /TR + /P 34 0 R + /K [64 0 R 62 0 R 61 0 R 60 0 R 59 0 R] +>> +endobj + +59 0 obj +<< + /Type /StructElem + /S /TD + /P 58 0 R + /A [<< + /O /Table + /Headers [(U5x4y0)] + >>] + /K [69] + /Pg 397 0 R +>> +endobj + +60 0 obj +<< + /Type /StructElem + /S /TD + /P 58 0 R + /A [<< + /O /Table + /Headers [(U5x3y0)] + >>] + /K [68] + /Pg 397 0 R +>> +endobj + +61 0 obj +<< + /Type /StructElem + /S /TD + /P 58 0 R + /A [<< + /O /Table + /Headers [(U5x2y0)] + >>] + /K [67] + /Pg 397 0 R +>> +endobj + +62 0 obj +<< + /Type /StructElem + /S /TD + /P 58 0 R + /A [<< + /O /Table + /Headers [(U5x1y0)] + >>] + /K [63 0 R 62 63 64 65 66] + /Pg 397 0 R +>> +endobj + +63 0 obj +<< + /Type /StructElem + /S /Strong + /P 62 0 R + /K [56 57 58 59 60 61] + /Pg 397 0 R +>> +endobj + +64 0 obj +<< + /Type /StructElem + /S /TD + /P 58 0 R + /A [<< + /O /Table + /Headers [(U5x0y0)] + >>] + /K [55] + /Pg 397 0 R +>> +endobj + +65 0 obj +<< + /Type /StructElem + /S /TR + /P 34 0 R + /K [71 0 R 69 0 R 68 0 R 67 0 R 66 0 R] +>> +endobj + +66 0 obj +<< + /Type /StructElem + /S /TD + /P 65 0 R + /A [<< + /O /Table + /Headers [(U5x4y0)] + >>] + /K [54] + /Pg 397 0 R +>> +endobj + +67 0 obj +<< + /Type /StructElem + /S /TD + /P 65 0 R + /A [<< + /O /Table + /Headers [(U5x3y0)] + >>] + /K [53] + /Pg 397 0 R +>> +endobj + +68 0 obj +<< + /Type /StructElem + /S /TD + /P 65 0 R + /A [<< + /O /Table + /Headers [(U5x2y0)] + >>] + /K [47 48 49 50 51 52] + /Pg 397 0 R +>> +endobj + +69 0 obj +<< + /Type /StructElem + /S /TD + /P 65 0 R + /A [<< + /O /Table + /Headers [(U5x1y0)] + >>] + /K [70 0 R 43 44 45 46] + /Pg 397 0 R +>> +endobj + +70 0 obj +<< + /Type /StructElem + /S /Strong + /P 69 0 R + /K [40 41 42] + /Pg 397 0 R +>> +endobj + +71 0 obj +<< + /Type /StructElem + /S /TD + /P 65 0 R + /A [<< + /O /Table + /Headers [(U5x0y0)] + >>] + /K [39] + /Pg 397 0 R +>> +endobj + +72 0 obj +<< + /Type /StructElem + /S /TR + /P 34 0 R + /K [78 0 R 76 0 R 75 0 R 74 0 R 73 0 R] +>> +endobj + +73 0 obj +<< + /Type /StructElem + /S /TD + /P 72 0 R + /A [<< + /O /Table + /Headers [(U5x4y0)] + >>] + /K [37 38] + /Pg 397 0 R +>> +endobj + +74 0 obj +<< + /Type /StructElem + /S /TD + /P 72 0 R + /A [<< + /O /Table + /Headers [(U5x3y0)] + >>] + /K [36] + /Pg 397 0 R +>> +endobj + +75 0 obj +<< + /Type /StructElem + /S /TD + /P 72 0 R + /A [<< + /O /Table + /Headers [(U5x2y0)] + >>] + /K [35] + /Pg 397 0 R +>> +endobj + +76 0 obj +<< + /Type /StructElem + /S /TD + /P 72 0 R + /A [<< + /O /Table + /Headers [(U5x1y0)] + >>] + /K [77 0 R 28 29 30 31 32 33 34] + /Pg 397 0 R +>> +endobj + +77 0 obj +<< + /Type /StructElem + /S /Strong + /P 76 0 R + /K [21 22 23 24 25 26 27] + /Pg 397 0 R +>> +endobj + +78 0 obj +<< + /Type /StructElem + /S /TD + /P 72 0 R + /A [<< + /O /Table + /Headers [(U5x0y0)] + >>] + /K [20] + /Pg 397 0 R +>> +endobj + +79 0 obj +<< + /Type /StructElem + /S /TR + /P 34 0 R + /K [85 0 R 83 0 R 82 0 R 81 0 R 80 0 R] +>> +endobj + +80 0 obj +<< + /Type /StructElem + /S /TD + /P 79 0 R + /A [<< + /O /Table + /Headers [(U5x4y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [18 19] + /Pg 397 0 R +>> +endobj + +81 0 obj +<< + /Type /StructElem + /S /TD + /P 79 0 R + /A [<< + /O /Table + /Headers [(U5x3y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [15 16 17] + /Pg 397 0 R +>> +endobj + +82 0 obj +<< + /Type /StructElem + /S /TD + /P 79 0 R + /A [<< + /O /Table + /Headers [(U5x2y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [14] + /Pg 397 0 R +>> +endobj + +83 0 obj +<< + /Type /StructElem + /S /TD + /P 79 0 R + /A [<< + /O /Table + /Headers [(U5x1y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [84 0 R 10 11 12 13] + /Pg 397 0 R +>> +endobj + +84 0 obj +<< + /Type /StructElem + /S /Strong + /P 83 0 R + /K [6 7 8 9] + /Pg 397 0 R +>> +endobj + +85 0 obj +<< + /Type /StructElem + /S /TD + /P 79 0 R + /A [<< + /O /Table + /Headers [(U5x0y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [5] + /Pg 397 0 R +>> +endobj + +86 0 obj +<< + /Type /StructElem + /S /THead + /P 33 0 R + /K [87 0 R] +>> +endobj + +87 0 obj +<< + /Type /StructElem + /S /TR + /P 86 0 R + /K [92 0 R 91 0 R 90 0 R 89 0 R 88 0 R] +>> +endobj + +88 0 obj +<< + /Type /StructElem + /S /TH + /P 87 0 R + /ID (U5x4y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [4] + /Pg 397 0 R +>> +endobj + +89 0 obj +<< + /Type /StructElem + /S /TH + /P 87 0 R + /ID (U5x3y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [3] + /Pg 397 0 R +>> +endobj + +90 0 obj +<< + /Type /StructElem + /S /TH + /P 87 0 R + /ID (U5x2y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [2] + /Pg 397 0 R +>> +endobj + +91 0 obj +<< + /Type /StructElem + /S /TH + /P 87 0 R + /ID (U5x1y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [1] + /Pg 397 0 R +>> +endobj + +92 0 obj +<< + /Type /StructElem + /S /TH + /P 87 0 R + /ID (U5x0y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [0] + /Pg 397 0 R +>> +endobj + +93 0 obj +<< + /Type /StructElem + /S /H2 + /P 22 0 R + /T (5. Recommended actions) + /K [0] + /Pg 395 0 R +>> +endobj + +94 0 obj +<< + /Type /StructElem + /S /Table + /P 22 0 R + /K [139 0 R 95 0 R] +>> +endobj + +95 0 obj +<< + /Type /StructElem + /S /TBody + /P 94 0 R + /K [134 0 R 129 0 R 124 0 R 118 0 R 113 0 R 108 0 R 102 0 R 96 0 R] +>> +endobj + +96 0 obj +<< + /Type /StructElem + /S /TR + /P 95 0 R + /K [101 0 R 100 0 R 99 0 R 97 0 R] +>> +endobj + +97 0 obj +<< + /Type /StructElem + /S /TD + /P 96 0 R + /A [<< + /O /Table + /Headers [(U4x3y0)] + >>] + /K [98 0 R] +>> +endobj + +98 0 obj +<< + /Type /StructElem + /S /Strong + /P 97 0 R + /K [36] + /Pg 393 0 R +>> +endobj + +99 0 obj +<< + /Type /StructElem + /S /TD + /P 96 0 R + /A [<< + /O /Table + /Headers [(U4x2y0)] + >>] + /K [35] + /Pg 393 0 R +>> +endobj + +100 0 obj +<< + /Type /StructElem + /S /TD + /P 96 0 R + /A [<< + /O /Table + /Headers [(U4x1y0)] + >>] + /K [34] + /Pg 393 0 R +>> +endobj + +101 0 obj +<< + /Type /StructElem + /S /TD + /P 96 0 R + /A [<< + /O /Table + /Headers [(U4x0y0)] + >>] + /K [33] + /Pg 393 0 R +>> +endobj + +102 0 obj +<< + /Type /StructElem + /S /TR + /P 95 0 R + /K [107 0 R 106 0 R 105 0 R 103 0 R] +>> +endobj + +103 0 obj +<< + /Type /StructElem + /S /TD + /P 102 0 R + /A [<< + /O /Table + /Headers [(U4x3y0)] + >>] + /K [104 0 R] +>> +endobj + +104 0 obj +<< + /Type /StructElem + /S /Strong + /P 103 0 R + /K [32] + /Pg 393 0 R +>> +endobj + +105 0 obj +<< + /Type /StructElem + /S /TD + /P 102 0 R + /A [<< + /O /Table + /Headers [(U4x2y0)] + >>] + /K [31] + /Pg 393 0 R +>> +endobj + +106 0 obj +<< + /Type /StructElem + /S /TD + /P 102 0 R + /A [<< + /O /Table + /Headers [(U4x1y0)] + >>] + /K [30] + /Pg 393 0 R +>> +endobj + +107 0 obj +<< + /Type /StructElem + /S /TD + /P 102 0 R + /A [<< + /O /Table + /Headers [(U4x0y0)] + >>] + /K [29] + /Pg 393 0 R +>> +endobj + +108 0 obj +<< + /Type /StructElem + /S /TR + /P 95 0 R + /K [112 0 R 111 0 R 110 0 R 109 0 R] +>> +endobj + +109 0 obj +<< + /Type /StructElem + /S /TD + /P 108 0 R + /A [<< + /O /Table + /Headers [(U4x3y0)] + >>] + /K [28] + /Pg 393 0 R +>> +endobj + +110 0 obj +<< + /Type /StructElem + /S /TD + /P 108 0 R + /A [<< + /O /Table + /Headers [(U4x2y0)] + >>] + /K [27] + /Pg 393 0 R +>> +endobj + +111 0 obj +<< + /Type /StructElem + /S /TD + /P 108 0 R + /A [<< + /O /Table + /Headers [(U4x1y0)] + >>] + /K [26] + /Pg 393 0 R +>> +endobj + +112 0 obj +<< + /Type /StructElem + /S /TD + /P 108 0 R + /A [<< + /O /Table + /Headers [(U4x0y0)] + >>] + /K [25] + /Pg 393 0 R +>> +endobj + +113 0 obj +<< + /Type /StructElem + /S /TR + /P 95 0 R + /K [117 0 R 116 0 R 115 0 R 114 0 R] +>> +endobj + +114 0 obj +<< + /Type /StructElem + /S /TD + /P 113 0 R + /A [<< + /O /Table + /Headers [(U4x3y0)] + >>] + /K [24] + /Pg 393 0 R +>> +endobj + +115 0 obj +<< + /Type /StructElem + /S /TD + /P 113 0 R + /A [<< + /O /Table + /Headers [(U4x2y0)] + >>] + /K [23] + /Pg 393 0 R +>> +endobj + +116 0 obj +<< + /Type /StructElem + /S /TD + /P 113 0 R + /A [<< + /O /Table + /Headers [(U4x1y0)] + >>] + /K [22] + /Pg 393 0 R +>> +endobj + +117 0 obj +<< + /Type /StructElem + /S /TD + /P 113 0 R + /A [<< + /O /Table + /Headers [(U4x0y0)] + >>] + /K [21] + /Pg 393 0 R +>> +endobj + +118 0 obj +<< + /Type /StructElem + /S /TR + /P 95 0 R + /K [123 0 R 122 0 R 121 0 R 119 0 R] +>> +endobj + +119 0 obj +<< + /Type /StructElem + /S /TD + /P 118 0 R + /A [<< + /O /Table + /Headers [(U4x3y0)] + >>] + /K [120 0 R] +>> +endobj + +120 0 obj +<< + /Type /StructElem + /S /Strong + /P 119 0 R + /K [20] + /Pg 393 0 R +>> +endobj + +121 0 obj +<< + /Type /StructElem + /S /TD + /P 118 0 R + /A [<< + /O /Table + /Headers [(U4x2y0)] + >>] + /K [19] + /Pg 393 0 R +>> +endobj + +122 0 obj +<< + /Type /StructElem + /S /TD + /P 118 0 R + /A [<< + /O /Table + /Headers [(U4x1y0)] + >>] + /K [18] + /Pg 393 0 R +>> +endobj + +123 0 obj +<< + /Type /StructElem + /S /TD + /P 118 0 R + /A [<< + /O /Table + /Headers [(U4x0y0)] + >>] + /K [17] + /Pg 393 0 R +>> +endobj + +124 0 obj +<< + /Type /StructElem + /S /TR + /P 95 0 R + /K [128 0 R 127 0 R 126 0 R 125 0 R] +>> +endobj + +125 0 obj +<< + /Type /StructElem + /S /TD + /P 124 0 R + /A [<< + /O /Table + /Headers [(U4x3y0)] + >>] + /K [16] + /Pg 393 0 R +>> +endobj + +126 0 obj +<< + /Type /StructElem + /S /TD + /P 124 0 R + /A [<< + /O /Table + /Headers [(U4x2y0)] + >>] + /K [15] + /Pg 393 0 R +>> +endobj + +127 0 obj +<< + /Type /StructElem + /S /TD + /P 124 0 R + /A [<< + /O /Table + /Headers [(U4x1y0)] + >>] + /K [14] + /Pg 393 0 R +>> +endobj + +128 0 obj +<< + /Type /StructElem + /S /TD + /P 124 0 R + /A [<< + /O /Table + /Headers [(U4x0y0)] + >>] + /K [13] + /Pg 393 0 R +>> +endobj + +129 0 obj +<< + /Type /StructElem + /S /TR + /P 95 0 R + /K [133 0 R 132 0 R 131 0 R 130 0 R] +>> +endobj + +130 0 obj +<< + /Type /StructElem + /S /TD + /P 129 0 R + /A [<< + /O /Table + /Headers [(U4x3y0)] + >>] + /K [12] + /Pg 393 0 R +>> +endobj + +131 0 obj +<< + /Type /StructElem + /S /TD + /P 129 0 R + /A [<< + /O /Table + /Headers [(U4x2y0)] + >>] + /K [11] + /Pg 393 0 R +>> +endobj + +132 0 obj +<< + /Type /StructElem + /S /TD + /P 129 0 R + /A [<< + /O /Table + /Headers [(U4x1y0)] + >>] + /K [10] + /Pg 393 0 R +>> +endobj + +133 0 obj +<< + /Type /StructElem + /S /TD + /P 129 0 R + /A [<< + /O /Table + /Headers [(U4x0y0)] + >>] + /K [9] + /Pg 393 0 R +>> +endobj + +134 0 obj +<< + /Type /StructElem + /S /TR + /P 95 0 R + /K [138 0 R 137 0 R 136 0 R 135 0 R] +>> +endobj + +135 0 obj +<< + /Type /StructElem + /S /TD + /P 134 0 R + /A [<< + /O /Table + /Headers [(U4x3y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [8] + /Pg 393 0 R +>> +endobj + +136 0 obj +<< + /Type /StructElem + /S /TD + /P 134 0 R + /A [<< + /O /Table + /Headers [(U4x2y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [7] + /Pg 393 0 R +>> +endobj + +137 0 obj +<< + /Type /StructElem + /S /TD + /P 134 0 R + /A [<< + /O /Table + /Headers [(U4x1y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [6] + /Pg 393 0 R +>> +endobj + +138 0 obj +<< + /Type /StructElem + /S /TD + /P 134 0 R + /A [<< + /O /Table + /Headers [(U4x0y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [5] + /Pg 393 0 R +>> +endobj + +139 0 obj +<< + /Type /StructElem + /S /THead + /P 94 0 R + /K [140 0 R] +>> +endobj + +140 0 obj +<< + /Type /StructElem + /S /TR + /P 139 0 R + /K [144 0 R 143 0 R 142 0 R 141 0 R] +>> +endobj + +141 0 obj +<< + /Type /StructElem + /S /TH + /P 140 0 R + /ID (U4x3y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [4] + /Pg 393 0 R +>> +endobj + +142 0 obj +<< + /Type /StructElem + /S /TH + /P 140 0 R + /ID (U4x2y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [3] + /Pg 393 0 R +>> +endobj + +143 0 obj +<< + /Type /StructElem + /S /TH + /P 140 0 R + /ID (U4x1y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [2] + /Pg 393 0 R +>> +endobj + +144 0 obj +<< + /Type /StructElem + /S /TH + /P 140 0 R + /ID (U4x0y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [1] + /Pg 393 0 R +>> +endobj + +145 0 obj +<< + /Type /StructElem + /S /H2 + /P 22 0 R + /T (4. Completeness scorecard (device-level, 181 rows)) + /K [0] + /Pg 393 0 R +>> +endobj + +146 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [153 0 R 151 0 R 150 0 R 107 148 0 R 147 0 R 110 111] + /Pg 391 0 R +>> +endobj + +147 0 obj +<< + /Type /StructElem + /S /Strong + /P 146 0 R + /K [109] + /Pg 391 0 R +>> +endobj + +148 0 obj +<< + /Type /StructElem + /S /Code + /P 146 0 R + /K [149 0 R] +>> +endobj + +149 0 obj +<< + /Type /StructElem + /S /Strong + /P 148 0 R + /K [108] + /Pg 391 0 R +>> +endobj + +150 0 obj +<< + /Type /StructElem + /S /Strong + /P 146 0 R + /K [106] + /Pg 391 0 R +>> +endobj + +151 0 obj +<< + /Type /StructElem + /S /Code + /P 146 0 R + /K [152 0 R] +>> +endobj + +152 0 obj +<< + /Type /StructElem + /S /Strong + /P 151 0 R + /K [105] + /Pg 391 0 R +>> +endobj + +153 0 obj +<< + /Type /StructElem + /S /Strong + /P 146 0 R + /K [104] + /Pg 391 0 R +>> +endobj + +154 0 obj +<< + /Type /StructElem + /S /H3 + /P 22 0 R + /T + /K [102 103] + /Pg 391 0 R +>> +endobj + +155 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [161 0 R 90 160 0 R 92 159 0 R 94 158 0 R 96 157 0 R 98 156 0 R 100 101] + /Pg 391 0 R +>> +endobj + +156 0 obj +<< + /Type /StructElem + /S /Code + /P 155 0 R + /K [99] + /Pg 391 0 R +>> +endobj + +157 0 obj +<< + /Type /StructElem + /S /Code + /P 155 0 R + /K [97] + /Pg 391 0 R +>> +endobj + +158 0 obj +<< + /Type /StructElem + /S /Code + /P 155 0 R + /K [95] + /Pg 391 0 R +>> +endobj + +159 0 obj +<< + /Type /StructElem + /S /Code + /P 155 0 R + /K [93] + /Pg 391 0 R +>> +endobj + +160 0 obj +<< + /Type /StructElem + /S /Code + /P 155 0 R + /K [91] + /Pg 391 0 R +>> +endobj + +161 0 obj +<< + /Type /StructElem + /S /Strong + /P 155 0 R + /K [89] + /Pg 391 0 R +>> +endobj + +162 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [167 0 R 80 166 0 R 82 165 0 R 84 164 0 R 86 163 0 R 88] + /Pg 391 0 R +>> +endobj + +163 0 obj +<< + /Type /StructElem + /S /Code + /P 162 0 R + /K [87] + /Pg 391 0 R +>> +endobj + +164 0 obj +<< + /Type /StructElem + /S /Code + /P 162 0 R + /K [85] + /Pg 391 0 R +>> +endobj + +165 0 obj +<< + /Type /StructElem + /S /Code + /P 162 0 R + /K [83] + /Pg 391 0 R +>> +endobj + +166 0 obj +<< + /Type /StructElem + /S /Code + /P 162 0 R + /K [81] + /Pg 391 0 R +>> +endobj + +167 0 obj +<< + /Type /StructElem + /S /Strong + /P 162 0 R + /K [79] + /Pg 391 0 R +>> +endobj + +168 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [175 0 R 173 0 R 172 0 R 68 171 0 R 70 71 170 0 R 75 169 0 R 78] + /Pg 391 0 R +>> +endobj + +169 0 obj +<< + /Type /StructElem + /S /Strong + /P 168 0 R + /K [76 77] + /Pg 391 0 R +>> +endobj + +170 0 obj +<< + /Type /StructElem + /S /Strong + /P 168 0 R + /K [72 73 74] + /Pg 391 0 R +>> +endobj + +171 0 obj +<< + /Type /StructElem + /S /Em + /P 168 0 R + /K [69] + /Pg 391 0 R +>> +endobj + +172 0 obj +<< + /Type /StructElem + /S /Strong + /P 168 0 R + /K [67] + /Pg 391 0 R +>> +endobj + +173 0 obj +<< + /Type /StructElem + /S /Code + /P 168 0 R + /K [174 0 R] +>> +endobj + +174 0 obj +<< + /Type /StructElem + /S /Strong + /P 173 0 R + /K [66] + /Pg 391 0 R +>> +endobj + +175 0 obj +<< + /Type /StructElem + /S /Strong + /P 168 0 R + /K [65] + /Pg 391 0 R +>> +endobj + +176 0 obj +<< + /Type /StructElem + /S /H3 + /P 22 0 R + /T + /K [63 64] + /Pg 391 0 R +>> +endobj + +177 0 obj +<< + /Type /StructElem + /S /Table + /P 22 0 R + /K [189 0 R 178 0 R] +>> +endobj + +178 0 obj +<< + /Type /StructElem + /S /TBody + /P 177 0 R + /K [184 0 R 179 0 R] +>> +endobj + +179 0 obj +<< + /Type /StructElem + /S /TR + /P 178 0 R + /K [183 0 R 182 0 R 181 0 R 180 0 R] +>> +endobj + +180 0 obj +<< + /Type /StructElem + /S /TD + /P 179 0 R + /A [<< + /O /Table + /Headers [(U3x3y0)] + >>] + /K [62] + /Pg 391 0 R +>> +endobj + +181 0 obj +<< + /Type /StructElem + /S /TD + /P 179 0 R + /A [<< + /O /Table + /Headers [(U3x2y0)] + >>] + /K [61] + /Pg 391 0 R +>> +endobj + +182 0 obj +<< + /Type /StructElem + /S /TD + /P 179 0 R + /A [<< + /O /Table + /Headers [(U3x1y0)] + >>] + /K [60] + /Pg 391 0 R +>> +endobj + +183 0 obj +<< + /Type /StructElem + /S /TD + /P 179 0 R + /A [<< + /O /Table + /Headers [(U3x0y0)] + >>] + /K [59] + /Pg 391 0 R +>> +endobj + +184 0 obj +<< + /Type /StructElem + /S /TR + /P 178 0 R + /K [188 0 R 187 0 R 186 0 R 185 0 R] +>> +endobj + +185 0 obj +<< + /Type /StructElem + /S /TD + /P 184 0 R + /A [<< + /O /Table + /Headers [(U3x3y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [58] + /Pg 391 0 R +>> +endobj + +186 0 obj +<< + /Type /StructElem + /S /TD + /P 184 0 R + /A [<< + /O /Table + /Headers [(U3x2y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [57] + /Pg 391 0 R +>> +endobj + +187 0 obj +<< + /Type /StructElem + /S /TD + /P 184 0 R + /A [<< + /O /Table + /Headers [(U3x1y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [56] + /Pg 391 0 R +>> +endobj + +188 0 obj +<< + /Type /StructElem + /S /TD + /P 184 0 R + /A [<< + /O /Table + /Headers [(U3x0y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [55] + /Pg 391 0 R +>> +endobj + +189 0 obj +<< + /Type /StructElem + /S /THead + /P 177 0 R + /K [190 0 R] +>> +endobj + +190 0 obj +<< + /Type /StructElem + /S /TR + /P 189 0 R + /K [194 0 R 193 0 R 192 0 R 191 0 R] +>> +endobj + +191 0 obj +<< + /Type /StructElem + /S /TH + /P 190 0 R + /ID (U3x3y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [54] + /Pg 391 0 R +>> +endobj + +192 0 obj +<< + /Type /StructElem + /S /TH + /P 190 0 R + /ID (U3x2y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [53] + /Pg 391 0 R +>> +endobj + +193 0 obj +<< + /Type /StructElem + /S /TH + /P 190 0 R + /ID (U3x1y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [52] + /Pg 391 0 R +>> +endobj + +194 0 obj +<< + /Type /StructElem + /S /TH + /P 190 0 R + /ID (U3x0y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [51] + /Pg 391 0 R +>> +endobj + +195 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [197 0 R 47 196 0 R 49 50] + /Pg 391 0 R +>> +endobj + +196 0 obj +<< + /Type /StructElem + /S /Em + /P 195 0 R + /K [48] + /Pg 391 0 R +>> +endobj + +197 0 obj +<< + /Type /StructElem + /S /Strong + /P 195 0 R + /K [46] + /Pg 391 0 R +>> +endobj + +198 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [211 0 R 29 209 0 R 208 0 R 32 207 0 R 34 206 0 R 36 204 0 R 203 0 R 201 0 R 40 200 0 R 42 199 0 R 45] + /Pg 391 0 R +>> +endobj + +199 0 obj +<< + /Type /StructElem + /S /Strong + /P 198 0 R + /K [43 44] + /Pg 391 0 R +>> +endobj + +200 0 obj +<< + /Type /StructElem + /S /Em + /P 198 0 R + /K [41] + /Pg 391 0 R +>> +endobj + +201 0 obj +<< + /Type /StructElem + /S /Code + /P 198 0 R + /K [202 0 R] +>> +endobj + +202 0 obj +<< + /Type /StructElem + /S /Strong + /P 201 0 R + /K [39] + /Pg 391 0 R +>> +endobj + +203 0 obj +<< + /Type /StructElem + /S /Strong + /P 198 0 R + /K [38] + /Pg 391 0 R +>> +endobj + +204 0 obj +<< + /Type /StructElem + /S /Code + /P 198 0 R + /K [205 0 R] +>> +endobj + +205 0 obj +<< + /Type /StructElem + /S /Strong + /P 204 0 R + /K [37] + /Pg 391 0 R +>> +endobj + +206 0 obj +<< + /Type /StructElem + /S /Code + /P 198 0 R + /K [35] + /Pg 391 0 R +>> +endobj + +207 0 obj +<< + /Type /StructElem + /S /Code + /P 198 0 R + /K [33] + /Pg 391 0 R +>> +endobj + +208 0 obj +<< + /Type /StructElem + /S /Strong + /P 198 0 R + /K [31] + /Pg 391 0 R +>> +endobj + +209 0 obj +<< + /Type /StructElem + /S /Code + /P 198 0 R + /K [210 0 R] +>> +endobj + +210 0 obj +<< + /Type /StructElem + /S /Strong + /P 209 0 R + /K [30] + /Pg 391 0 R +>> +endobj + +211 0 obj +<< + /Type /StructElem + /S /Strong + /P 198 0 R + /K [28] + /Pg 391 0 R +>> +endobj + +212 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [213 0 R 26 27] + /Pg 391 0 R +>> +endobj + +213 0 obj +<< + /Type /StructElem + /S /Strong + /P 212 0 R + /K [25] + /Pg 391 0 R +>> +endobj + +214 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [215 0 R 23 24] + /Pg 391 0 R +>> +endobj + +215 0 obj +<< + /Type /StructElem + /S /Strong + /P 214 0 R + /K [22] + /Pg 391 0 R +>> +endobj + +216 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [217 0 R 21] + /Pg 391 0 R +>> +endobj + +217 0 obj +<< + /Type /StructElem + /S /Strong + /P 216 0 R + /K [20] + /Pg 391 0 R +>> +endobj + +218 0 obj +<< + /Type /StructElem + /S /H3 + /P 22 0 R + /T + /K [18 19] + /Pg 391 0 R +>> +endobj + +219 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [221 0 R 14 220 0 R 16 17] + /Pg 391 0 R +>> +endobj + +220 0 obj +<< + /Type /StructElem + /S /Strong + /P 219 0 R + /K [15] + /Pg 391 0 R +>> +endobj + +221 0 obj +<< + /Type /StructElem + /S /Strong + /P 219 0 R + /K [13] + /Pg 391 0 R +>> +endobj + +222 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [224 0 R 8 9 223 0 R 11 12] + /Pg 391 0 R +>> +endobj + +223 0 obj +<< + /Type /StructElem + /S /Strong + /P 222 0 R + /K [10] + /Pg 391 0 R +>> +endobj + +224 0 obj +<< + /Type /StructElem + /S /Strong + /P 222 0 R + /K [7] + /Pg 391 0 R +>> +endobj + +225 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [227 0 R 4 5 226 0 R] + /Pg 391 0 R +>> +endobj + +226 0 obj +<< + /Type /StructElem + /S /Code + /P 225 0 R + /K [6] + /Pg 391 0 R +>> +endobj + +227 0 obj +<< + /Type /StructElem + /S /Strong + /P 225 0 R + /K [3] + /Pg 391 0 R +>> +endobj + +228 0 obj +<< + /Type /StructElem + /S /H3 + /P 22 0 R + /T + /K [1 2] + /Pg 391 0 R +>> +endobj + +229 0 obj +<< + /Type /StructElem + /S /H2 + /P 22 0 R + /T (3. Findings by severity) + /K [0] + /Pg 391 0 R +>> +endobj + +230 0 obj +<< + /Type /StructElem + /S /Div + /P 22 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [231 0 R] +>> +endobj + +231 0 obj +<< + /Type /StructElem + /S /Table + /P 230 0 R + /K [260 0 R 232 0 R] +>> +endobj + +232 0 obj +<< + /Type /StructElem + /S /TBody + /P 231 0 R + /K [255 0 R 249 0 R 244 0 R 238 0 R 233 0 R] +>> +endobj + +233 0 obj +<< + /Type /StructElem + /S /TR + /P 232 0 R + /K [236 0 R 235 0 R 234 0 R] +>> +endobj + +234 0 obj +<< + /Type /StructElem + /S /TD + /P 233 0 R + /A [<< + /O /Table + /Headers [(U2x2y0)] + >>] + /K [114] + /Pg 389 0 R +>> +endobj + +235 0 obj +<< + /Type /StructElem + /S /TD + /P 233 0 R + /A [<< + /O /Table + /Headers [(U2x1y0)] + >>] + /K [113] + /Pg 389 0 R +>> +endobj + +236 0 obj +<< + /Type /StructElem + /S /TD + /P 233 0 R + /A [<< + /O /Table + /Headers [(U2x0y0)] + >>] + /K [237 0 R 111 112] + /Pg 389 0 R +>> +endobj + +237 0 obj +<< + /Type /StructElem + /S /Strong + /P 236 0 R + /K [110] + /Pg 389 0 R +>> +endobj + +238 0 obj +<< + /Type /StructElem + /S /TR + /P 232 0 R + /K [242 0 R 240 0 R 239 0 R] +>> +endobj + +239 0 obj +<< + /Type /StructElem + /S /TD + /P 238 0 R + /A [<< + /O /Table + /Headers [(U2x2y0)] + >>] + /K [109] + /Pg 389 0 R +>> +endobj + +240 0 obj +<< + /Type /StructElem + /S /TD + /P 238 0 R + /A [<< + /O /Table + /Headers [(U2x1y0)] + >>] + /K [241 0 R] +>> +endobj + +241 0 obj +<< + /Type /StructElem + /S /Strong + /P 240 0 R + /K [108] + /Pg 389 0 R +>> +endobj + +242 0 obj +<< + /Type /StructElem + /S /TD + /P 238 0 R + /A [<< + /O /Table + /Headers [(U2x0y0)] + >>] + /K [243 0 R] +>> +endobj + +243 0 obj +<< + /Type /StructElem + /S /Strong + /P 242 0 R + /K [107] + /Pg 389 0 R +>> +endobj + +244 0 obj +<< + /Type /StructElem + /S /TR + /P 232 0 R + /K [247 0 R 246 0 R 245 0 R] +>> +endobj + +245 0 obj +<< + /Type /StructElem + /S /TD + /P 244 0 R + /A [<< + /O /Table + /Headers [(U2x2y0)] + >>] + /K [106] + /Pg 389 0 R +>> +endobj + +246 0 obj +<< + /Type /StructElem + /S /TD + /P 244 0 R + /A [<< + /O /Table + /Headers [(U2x1y0)] + >>] + /K [105] + /Pg 389 0 R +>> +endobj + +247 0 obj +<< + /Type /StructElem + /S /TD + /P 244 0 R + /A [<< + /O /Table + /Headers [(U2x0y0)] + >>] + /K [248 0 R 103 104] + /Pg 389 0 R +>> +endobj + +248 0 obj +<< + /Type /StructElem + /S /Strong + /P 247 0 R + /K [102] + /Pg 389 0 R +>> +endobj + +249 0 obj +<< + /Type /StructElem + /S /TR + /P 232 0 R + /K [252 0 R 251 0 R 250 0 R] +>> +endobj + +250 0 obj +<< + /Type /StructElem + /S /TD + /P 249 0 R + /A [<< + /O /Table + /Headers [(U2x2y0)] + >>] + /K [100 101] + /Pg 389 0 R +>> +endobj + +251 0 obj +<< + /Type /StructElem + /S /TD + /P 249 0 R + /A [<< + /O /Table + /Headers [(U2x1y0)] + >>] + /K [99] + /Pg 389 0 R +>> +endobj + +252 0 obj +<< + /Type /StructElem + /S /TD + /P 249 0 R + /A [<< + /O /Table + /Headers [(U2x0y0)] + >>] + /K [254 0 R 95 96 253 0 R 98] + /Pg 389 0 R +>> +endobj + +253 0 obj +<< + /Type /StructElem + /S /Em + /P 252 0 R + /K [97] + /Pg 389 0 R +>> +endobj + +254 0 obj +<< + /Type /StructElem + /S /Strong + /P 252 0 R + /K [94] + /Pg 389 0 R +>> +endobj + +255 0 obj +<< + /Type /StructElem + /S /TR + /P 232 0 R + /K [258 0 R 257 0 R 256 0 R] +>> +endobj + +256 0 obj +<< + /Type /StructElem + /S /TD + /P 255 0 R + /A [<< + /O /Table + /Headers [(U2x2y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [92 93] + /Pg 389 0 R +>> +endobj + +257 0 obj +<< + /Type /StructElem + /S /TD + /P 255 0 R + /A [<< + /O /Table + /Headers [(U2x1y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [91] + /Pg 389 0 R +>> +endobj + +258 0 obj +<< + /Type /StructElem + /S /TD + /P 255 0 R + /A [<< + /O /Table + /Headers [(U2x0y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [259 0 R 89 90] + /Pg 389 0 R +>> +endobj + +259 0 obj +<< + /Type /StructElem + /S /Strong + /P 258 0 R + /K [88] + /Pg 389 0 R +>> +endobj + +260 0 obj +<< + /Type /StructElem + /S /THead + /P 231 0 R + /K [261 0 R] +>> +endobj + +261 0 obj +<< + /Type /StructElem + /S /TR + /P 260 0 R + /K [264 0 R 263 0 R 262 0 R] +>> +endobj + +262 0 obj +<< + /Type /StructElem + /S /TH + /P 261 0 R + /ID (U2x2y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [87] + /Pg 389 0 R +>> +endobj + +263 0 obj +<< + /Type /StructElem + /S /TH + /P 261 0 R + /ID (U2x1y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [86] + /Pg 389 0 R +>> +endobj + +264 0 obj +<< + /Type /StructElem + /S /TH + /P 261 0 R + /ID (U2x0y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [85] + /Pg 389 0 R +>> +endobj + +265 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [84] + /Pg 389 0 R +>> +endobj + +266 0 obj +<< + /Type /StructElem + /S /H2 + /P 22 0 R + /T (2. The fleet, de-duplicated) + /K [83] + /Pg 389 0 R +>> +endobj + +267 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [271 0 R 73 74 270 0 R 76 77 269 0 R 79 268 0 R 82] + /Pg 389 0 R +>> +endobj + +268 0 obj +<< + /Type /StructElem + /S /Strong + /P 267 0 R + /K [80 81] + /Pg 389 0 R +>> +endobj + +269 0 obj +<< + /Type /StructElem + /S /Strong + /P 267 0 R + /K [78] + /Pg 389 0 R +>> +endobj + +270 0 obj +<< + /Type /StructElem + /S /Strong + /P 267 0 R + /K [75] + /Pg 389 0 R +>> +endobj + +271 0 obj +<< + /Type /StructElem + /S /Strong + /P 267 0 R + /K [72] + /Pg 389 0 R +>> +endobj + +272 0 obj +<< + /Type /StructElem + /S /Table + /P 22 0 R + /K [311 0 R 273 0 R] +>> +endobj + +273 0 obj +<< + /Type /StructElem + /S /TBody + /P 272 0 R + /K [304 0 R 297 0 R 290 0 R 281 0 R 274 0 R] +>> +endobj + +274 0 obj +<< + /Type /StructElem + /S /TR + /P 273 0 R + /K [279 0 R 276 0 R 275 0 R] +>> +endobj + +275 0 obj +<< + /Type /StructElem + /S /TD + /P 274 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [69 70 71] + /Pg 389 0 R +>> +endobj + +276 0 obj +<< + /Type /StructElem + /S /TD + /P 274 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [278 0 R 65 277 0 R 67 68] + /Pg 389 0 R +>> +endobj + +277 0 obj +<< + /Type /StructElem + /S /Strong + /P 276 0 R + /K [66] + /Pg 389 0 R +>> +endobj + +278 0 obj +<< + /Type /StructElem + /S /Strong + /P 276 0 R + /K [64] + /Pg 389 0 R +>> +endobj + +279 0 obj +<< + /Type /StructElem + /S /TD + /P 274 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [280 0 R] +>> +endobj + +280 0 obj +<< + /Type /StructElem + /S /Strong + /P 279 0 R + /K [63] + /Pg 389 0 R +>> +endobj + +281 0 obj +<< + /Type /StructElem + /S /TR + /P 273 0 R + /K [288 0 R 285 0 R 282 0 R] +>> +endobj + +282 0 obj +<< + /Type /StructElem + /S /TD + /P 281 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [56 284 0 R 59 283 0 R] + /Pg 389 0 R +>> +endobj + +283 0 obj +<< + /Type /StructElem + /S /Strong + /P 282 0 R + /K [60 61 62] + /Pg 389 0 R +>> +endobj + +284 0 obj +<< + /Type /StructElem + /S /Strong + /P 282 0 R + /K [57 58] + /Pg 389 0 R +>> +endobj + +285 0 obj +<< + /Type /StructElem + /S /TD + /P 281 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [287 0 R 52 286 0 R] + /Pg 389 0 R +>> +endobj + +286 0 obj +<< + /Type /StructElem + /S /Strong + /P 285 0 R + /K [53 54 55] + /Pg 389 0 R +>> +endobj + +287 0 obj +<< + /Type /StructElem + /S /Strong + /P 285 0 R + /K [51] + /Pg 389 0 R +>> +endobj + +288 0 obj +<< + /Type /StructElem + /S /TD + /P 281 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [289 0 R] +>> +endobj + +289 0 obj +<< + /Type /StructElem + /S /Strong + /P 288 0 R + /K [50] + /Pg 389 0 R +>> +endobj + +290 0 obj +<< + /Type /StructElem + /S /TR + /P 273 0 R + /K [295 0 R 292 0 R 291 0 R] +>> +endobj + +291 0 obj +<< + /Type /StructElem + /S /TD + /P 290 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [47 48 49] + /Pg 389 0 R +>> +endobj + +292 0 obj +<< + /Type /StructElem + /S /TD + /P 290 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [294 0 R 44 293 0 R 46] + /Pg 389 0 R +>> +endobj + +293 0 obj +<< + /Type /StructElem + /S /Strong + /P 292 0 R + /K [45] + /Pg 389 0 R +>> +endobj + +294 0 obj +<< + /Type /StructElem + /S /Strong + /P 292 0 R + /K [43] + /Pg 389 0 R +>> +endobj + +295 0 obj +<< + /Type /StructElem + /S /TD + /P 290 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [296 0 R] +>> +endobj + +296 0 obj +<< + /Type /StructElem + /S /Strong + /P 295 0 R + /K [42] + /Pg 389 0 R +>> +endobj + +297 0 obj +<< + /Type /StructElem + /S /TR + /P 273 0 R + /K [302 0 R 299 0 R 298 0 R] +>> +endobj + +298 0 obj +<< + /Type /StructElem + /S /TD + /P 297 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [39 40 41] + /Pg 389 0 R +>> +endobj + +299 0 obj +<< + /Type /StructElem + /S /TD + /P 297 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [301 0 R 35 300 0 R 37 38] + /Pg 389 0 R +>> +endobj + +300 0 obj +<< + /Type /StructElem + /S /Strong + /P 299 0 R + /K [36] + /Pg 389 0 R +>> +endobj + +301 0 obj +<< + /Type /StructElem + /S /Strong + /P 299 0 R + /K [34] + /Pg 389 0 R +>> +endobj + +302 0 obj +<< + /Type /StructElem + /S /TD + /P 297 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [303 0 R] +>> +endobj + +303 0 obj +<< + /Type /StructElem + /S /Strong + /P 302 0 R + /K [33] + /Pg 389 0 R +>> +endobj + +304 0 obj +<< + /Type /StructElem + /S /TR + /P 273 0 R + /K [309 0 R 306 0 R 305 0 R] +>> +endobj + +305 0 obj +<< + /Type /StructElem + /S /TD + /P 304 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [30 31 32] + /Pg 389 0 R +>> +endobj + +306 0 obj +<< + /Type /StructElem + /S /TD + /P 304 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [308 0 R 26 307 0 R 29] + /Pg 389 0 R +>> +endobj + +307 0 obj +<< + /Type /StructElem + /S /Strong + /P 306 0 R + /K [27 28] + /Pg 389 0 R +>> +endobj + +308 0 obj +<< + /Type /StructElem + /S /Strong + /P 306 0 R + /K [25] + /Pg 389 0 R +>> +endobj + +309 0 obj +<< + /Type /StructElem + /S /TD + /P 304 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [310 0 R] +>> +endobj + +310 0 obj +<< + /Type /StructElem + /S /Strong + /P 309 0 R + /K [24] + /Pg 389 0 R +>> +endobj + +311 0 obj +<< + /Type /StructElem + /S /THead + /P 272 0 R + /K [312 0 R] +>> +endobj + +312 0 obj +<< + /Type /StructElem + /S /TR + /P 311 0 R + /K [315 0 R 314 0 R 313 0 R] +>> +endobj + +313 0 obj +<< + /Type /StructElem + /S /TH + /P 312 0 R + /ID (U1x2y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [23] + /Pg 389 0 R +>> +endobj + +314 0 obj +<< + /Type /StructElem + /S /TH + /P 312 0 R + /ID (U1x1y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [22] + /Pg 389 0 R +>> +endobj + +315 0 obj +<< + /Type /StructElem + /S /TH + /P 312 0 R + /ID (U1x0y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [21] + /Pg 389 0 R +>> +endobj + +316 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [16 317 0 R 18 19 20] + /Pg 389 0 R +>> +endobj + +317 0 obj +<< + /Type /StructElem + /S /Strong + /P 316 0 R + /K [17] + /Pg 389 0 R +>> +endobj + +318 0 obj +<< + /Type /StructElem + /S /H2 + /P 22 0 R + /T (1. Executive summary) + /K [15] + /Pg 389 0 R +>> +endobj + +319 0 obj +<< + /Type /StructElem + /S /P + /P 22 0 R + /K [325 0 R 2 324 0 R 4 323 0 R 6 322 0 R 8 9 321 0 R 11 320 0 R 13 14] + /Pg 389 0 R +>> +endobj + +320 0 obj +<< + /Type /StructElem + /S /Strong + /P 319 0 R + /K [12] + /Pg 389 0 R +>> +endobj + +321 0 obj +<< + /Type /StructElem + /S /Strong + /P 319 0 R + /K [10] + /Pg 389 0 R +>> +endobj + +322 0 obj +<< + /Type /StructElem + /S /Strong + /P 319 0 R + /K [7] + /Pg 389 0 R +>> +endobj + +323 0 obj +<< + /Type /StructElem + /S /Code + /P 319 0 R + /K [5] + /Pg 389 0 R +>> +endobj + +324 0 obj +<< + /Type /StructElem + /S /Strong + /P 319 0 R + /K [3] + /Pg 389 0 R +>> +endobj + +325 0 obj +<< + /Type /StructElem + /S /Strong + /P 319 0 R + /K [1] + /Pg 389 0 R +>> +endobj + +326 0 obj +<< + /Type /StructElem + /S /H1 + /P 22 0 R + /T + /K [0] + /Pg 389 0 R +>> +endobj + +327 0 obj +<< + /Type /PageLabel + /S /D + /St 1 +>> +endobj + +328 0 obj +<< + /Type /PageLabel + /S /D + /St 2 +>> +endobj + +329 0 obj +<< + /Type /PageLabel + /S /D + /St 3 +>> +endobj + +330 0 obj +<< + /Type /PageLabel + /S /D + /St 4 +>> +endobj + +331 0 obj +<< + /Type /PageLabel + /S /D + /St 5 +>> +endobj + +332 0 obj +<< + /Type /PageLabel + /S /D + /St 6 +>> +endobj + +333 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /GWPTFZ+LibertinusSerif-Bold-Identity-H + /Encoding /Identity-H + /DescendantFonts [334 0 R] + /ToUnicode 337 0 R +>> +endobj + +334 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /GWPTFZ+LibertinusSerif-Bold + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 336 0 R + /DW 0 + /W [0 0 500 1 1 545 2 2 325 3 3 489 4 4 358 5 5 250 6 6 716 7 7 521 8 8 322 9 9 427 10 10 428 11 11 558 12 12 742 13 13 734 14 14 505.99997 15 15 730 16 16 598 17 17 581 18 18 551 19 19 256 20 20 504 21 21 456 22 22 614 23 23 561 24 24 391 25 26 514 27 27 619 28 28 529 29 29 514 30 30 244 31 31 609 32 32 561 33 33 905 34 34 616 35 35 542 36 37 514 38 38 637 39 40 514 41 41 700 42 42 613 43 43 358 44 45 732 46 46 641 47 47 777 48 48 514 49 49 244 50 50 652 51 51 316 52 52 680 53 53 740 54 54 706 55 55 514 56 56 740 57 57 730 58 59 315 60 60 817 61 61 729 62 62 514 63 63 899 64 64 736 65 65 577 66 66 537 67 67 367] +>> +endobj + +335 0 obj +<< + /Length 13 + /Filter /FlateDecode +>> +stream +x>, +endstream +endobj + +336 0 obj +<< + /Type /FontDescriptor + /FontName /GWPTFZ+LibertinusSerif-Bold + /Flags 131078 + /FontBBox [0 -238 1135 720] + /ItalicAngle 0 + /Ascent 894 + /Descent -246 + /CapHeight 645 + /StemV 168.6 + /CIDSet 335 0 R + /FontFile3 338 0 R +>> +endobj + +337 0 obj +<< + /Length 1552 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +67 beginbfchar +<0001> <0046> +<0002> <006C> +<0003> <0065> +<0004> <0074> +<0005> <0020> +<0006> <0052> +<0007> <0067> +<0008> <0069> +<0009> <0073> +<000A> <0072> +<000B> <0079> +<000C> <2014> +<000D> <0044> +<000E> <0061> +<000F> <0051> +<0010> <0075> +<0011> <0070> +<0012> <006F> +<0013> <003A> +<0014> <0053> +<0015> <0063> +<0016> <0050> +<0017> <0064> +<0018> <0066> +<0019> <0038> +<001A> <0030> +<001B> <0068> +<001C> <0076> +<001D> <0031> +<001E> <002E> +<001F> <0045> +<0020> <0078> +<0021> <006D> +<0022> <006E> +<0023> <0062> +<0024> <0039> +<0025> <0037> +<0026> <0025> +<0027> <0032> +<0028> <0033> +<0029> <0056> +<002A> <006B> +<002B> <00AD> +<002C> <0047> +<002D> <0055> +<002E> <00660069> +<002F> <0077> +<0030> <0034> +<0031> <002C> +<0032> <0054> +<0033> <002F> +<0034> <0066006C> +<0035> <0041> +<0036> <0043> +<0037> <0036> +<0038> <004E> +<0039> <004F> +<003A> <0028> +<003B> <0029> +<003C> <0048> +<003D> <0026> +<003E> <0035> +<003F> <004D> +<0040> <004B> +<0041> <004C> +<0042> <002B> +<0043> <0049> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +338 0 obj +<< + /Length 7372 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xyy\W6-2mBYUD"4 V44-;'bbLEgLL2s:_Ff2^Ωs=s.ix'o + %E%Ņn Od]('jV?xwO.]N}ɩw NNIϿp,./99s8<DDQ a kcBB<[ _[`BEc. +LX?iL RfkqJO..:&$p38NNNNkQ5A8{vif= pv?k|!w:S9v_'Ln"5{IE.k]w-&܋ ]'coaU?\5ǝnOFb !{a .Srxx܋3_iy|/{g`g 8dz{+y_a`2qcr0^#_‘ sT6(^x6aw@B]㏔$hAm4 +T +BcQ2!L&إg'Wi߳.TYf1 FIaw)9L<xo %2J| qIbԉfCsYqpe6˥F.H5GpZ _EН]ӭ9q92hTˌ-F>Ե\}6vZ2SeOBx0k+k/t@iryk3Gm/r4kOD|mK)qMTPy\@ִƾ-SgT~ |כ0_γxz"+5͠)Dh~XY2Tђ]I8[[[JʌfJH"E|Wjv Mil\E]0*ur +JFrي !b=C mvtx08 ޛ"}n 9R'%XƯ'O`Wshl&w~ ΐt3cJ&_B=F!{c?ig6R +VVM^GeC.#!%@vXbx mA଼ +s 9Ć^{$Nt`{xluZ?41 KꋥUb|$D.ӜFa92)DpM~AG o| +h 2:Lv1 +iiY@bCz]W]M GRfSSϓttX\EbW=P+$5 W%"7lQX>/:3vs5A)!J-;$)%lc:,3[%J2 9gvdג]34d-t7DQxxexGwuKu}BA߄HJ\;Dui xw<q6\[xJllw`L)X'y5]V;*T2Mi~Z 0kaw [+ 1R*ʬ5 +4&ޜ0zu_l Tcu8rKRIV]å +ZPm){{<݀+J]e:y%馣g@zsNuy$bj{݁[-#YGdp#nޑ 9:8orKuӍsh=,*3mGfq(_qvK/ "psf`_i3+ @f Q(1Grh3_jT\@* 4|LO["#Ut1_ӺS6N&25&yj>S45JUFnC֑!?\< &a?LVI«w9sAts=dЈPZS*D!cH'[ )q#Q]j ;фőg*9 +8" ..m 0u4w( Jt e6aQ2rY/wEZr +М30\aklk `p'''Jv}k'<+fޛvK~"OE$ճFHAODwNbؖ'(Tc"M!`!W +)Nynih9GKlll*=v]*RT CS'p1C3[PUE%Ep:1z8(BGj$dcEUCӈ&|bG{0ޓv<3b?F ϖ t' +(BQ危Q5t*ɘ^ML%yzSDh^, T9#7"@צF^|ӌGƤxCpE\4m[gnJ&k.w^2TS}4E@m~/MJ^jTPqE[DZ +o]/y¯kz5GusR90۹ԿpXm$cLc/׼DRlTޑwʿW=Iݾ$uS-Mo5?tрiPjLf(k$~;WyIe54$ gaӔkBlx ~0 v0Voti} Re|Xc҇)l DS&NN†G|9Ą<VҔ%ڽ])y~W-m~Hldv{ +Kck[) +Y/.@VadHAxqlVA _Fk-xM]Ǡ6fOTER"`)UGȎgU5ZFlm#Cֈ"vX^Y&kl}R8?:rqCqϯ(-x}= E)A9,=EN/,2`8DQQEag=$83O&Gҝ!>f/W8=DKpCxySo4 G%V$ i'@{; X Ηpe&$\ r Gт}GxxRF mޡ@#4"*\=r[NwqL- y?e绞ac#㰇MG<etZ/ +P%wFM^ʬOZI3>Y(LVe-~ԮCTKo;P-ڿ}׎Iyxp~\Q2%e7W_KcCFCHK#qU3ٳeeɔڃ4&:g%z-ƺ4oN?9PCޠ*QRJ'2'(%NHOJ)R#OFa*:a,)><"SSmeT@T4 6oں^M =&D+c#p$O K#Ohi?}&o`3=_L1W&.4쇸,w-@P{F}\ q5>RLJMg-C$L@{~ƾ*:Kt_D̃QTDA ++F +aNa[Mgl^y1!F2LD;oG&BbSRsp/Uߧ{3s-Mb?힒W(+",Qٍ]2 'ܱ564_1=b `DZWɎ +LL$ 2Do#큈6hvj+*-9hq)Yi%-vi`Eݵ ܅6{9o?}j/$'hiT͇͵:hTWɌhƗog )ˏ%;a1cuj?Q6Dۅhm1.D]Ռ'Gdq aK >1a ^M(@W SczI8!`IX{< dh?2";ZB OC;>euԾ^g›R,4/[d2GLv63UOl-_>|q&R(s/ԕ7" +[CV8|e7ywZH0OtqL~XpZ@ ,9D{i!$0 qcOas2 V +Ç A.O;3 +/c Sr_#|l4r3 +( +7ƕ&f.kvhFjK{Vs'o=thp*ny>ٳl)VBGc \ tlo81ҳ=[kmSR1svhst#B%9  PejQ Sk)k޳SXaҰ-ևxHpUla{tRI8q8鎦Z9xMgۻIs $kswvƺ!全uڪBv Fnl[B_'tg;wIJRҌ`2$-.1pBU-i?G´o.? M<)WO;WxIe'[t7 nd@QDnͧydoZw-1 \<e +F@+^4=L2{OnDK #h+mQU˶f4j*+0n0 +Ic>_Oc jyBx_es\_-ş9ws<^[M(5J=UԷw0'bQ4fXMDLcMNʄiDLq{PMjb,lx:Tٟ$cGO{XD2g׶SϫJMI bmJFs)L=ai4d5ZVheX +/hK `x0KE +endstream +endobj + +339 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /AUKGYS+LibertinusSerif-Regular-Identity-H + /Encoding /Identity-H + /DescendantFonts [340 0 R] + /ToUnicode 343 0 R +>> +endobj + +340 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /AUKGYS+LibertinusSerif-Regular + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 342 0 R + /DW 0 + /W [0 0 500 1 1 250 2 4 465 5 5 338 6 6 465 7 7 298 8 8 316 9 9 538 10 10 447 11 11 390 12 12 271 13 13 542 14 14 500 15 15 264 16 16 372 17 17 515 18 18 504 19 19 310 20 20 428 21 21 505.99997 22 22 298 23 23 485 24 24 457 25 25 519 26 26 323 27 27 540 28 28 465 29 29 512 30 30 497 31 31 1130 32 32 596 33 33 531 34 34 685 35 35 541 36 36 485 37 37 550 38 38 790 39 39 493 40 40 220 41 41 597 42 42 220 43 43 490 44 44 560 45 45 637 46 46 297 47 47 236 48 48 730 49 49 588 50 51 465 52 52 701 53 53 268 54 54 747 55 55 465 56 56 742 57 57 951 58 58 465 59 59 236 60 60 465 61 61 695 62 62 646 63 63 652 64 64 449 65 65 550 66 66 424 67 67 839 68 68 661 69 69 473 70 70 575 71 71 660 72 72 604 73 74 375 75 75 702 76 76 637 77 77 582 78 78 528 79 79 272 80 80 250 81 81 702 82 82 699 83 83 465 84 84 557 85 85 503.00003 86 86 587 87 87 550] +>> +endobj + +341 0 obj +<< + /Length 11 + /Filter /FlateDecode +>> +stream +xA + +endstream +endobj + +342 0 obj +<< + /Type /FontDescriptor + /FontName /AUKGYS+LibertinusSerif-Regular + /Flags 131078 + /FontBBox [-48 -238 1072 736] + /ItalicAngle 0 + /Ascent 894 + /Descent -246 + /CapHeight 658 + /StemV 95.4 + /CIDSet 341 0 R + /FontFile3 344 0 R +>> +endobj + +343 0 obj +<< + /Length 1840 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +87 beginbfchar +<0001> <0020> +<0002> <0032> +<0003> <0030> +<0004> <0036> +<0005> <002D> +<0006> <0038> +<0007> <0028> +<0008> <0074> +<0009> <0068> +<000A> <0065> +<000B> <0073> +<000C> <0069> +<000D> <006E> +<000E> <0067> +<000F> <006C> +<0010> <0072> +<0011> <0079> +<0012> <006F> +<0013> <0066> +<0014> <0063> +<0015> <0064> +<0016> <0029> +<0017> <0046> +<0018> <0061> +<0019> <0070> +<001A> <002F> +<001B> <0066006C> +<001C> <0031> +<001D> <006B> +<001E> <0076> +<001F> <2192> +<0020> <00660074> +<0021> <0075> +<0022> <0047> +<0023> <0050> +<0024> <0053> +<0025> <002B> +<0026> <006D> +<0027> <0062> +<0028> <002E> +<0029> <0054> +<002A> <002C> +<002B> <0078> +<002C> <00660069> +<002D> <004B> +<002E> <0049> +<002F> <003A> +<0030> <0048> +<0031> <0042> +<0032> <0037> +<0033> <0035> +<0034> <0044> +<0035> <2019> +<0036> <0077> +<0037> <0034> +<0038> <2014> +<0039> <0057> +<003A> <0033> +<003B> <003B> +<003C> <0039> +<003D> <0041> +<003E> <0043> +<003F> <0056> +<0040> <007E> +<0041> <00D7> +<0042> <007A> +<0043> <004D> +<0044> <0055> +<0045> <00A7> +<0046> <0059> +<0047> <0058> +<0048> <005A> +<0049> <201C> +<004A> <201D> +<004B> <004F> +<004C> <0025> +<004D> <00660066> +<004E> <004C> +<004F> <006A> +<0050> <00A0> +<0051> <0051> +<0052> <004E> +<0053> <0023> +<0054> <0045> +<0055> <0071> +<0056> <0052> +<0057> <003D> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +344 0 obj +<< + /Length 9475 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xz|TUb"ÚH +(JY&HBz!Mz2L}33I&!=RĠ? Ⱥ~g23{Ͻ=m87wwww#C"b$D9$,9* l53O&3݈nJ}"鯳i/{g'=>g~m4O?Mw{ 7ww6o!1IIi+c"“4/ϟ;[Ceٍ B]817wm9Vfy~4;lk=,M|\5qB a=vv$RѮ x{65zn[{[1~3>/NO6DӼٓ:0_<yʰǰw]'SN.lS +BGt3AE%12 <7&MmڇL?،KG> _0|3Z0^{9p6U?wU?3C5Q`_|X +X l\  CXuRгN3/-+N`Ҵ→ +R4Aj2 +k/4H.i ,2|7 +TMd7u+Ud!%AVU a8Z={F#~utcڹN#Ջ6bpwހ*_?=F:|_FѮgm/ l%cYN\|/.dc|H xEnbQ4|޼ԉ.7_W!L;گNSV)OG<>`;+]'2L> {.󲢉0~F=s׻fF_OP$woTA"?j$ed'Mzv=vyIrh&]{!dM  K 8s&ۚU,VOO h}ߚ/]?JIJNT,ݏ.*=>RȨRֻ[8C&sW=:AӢ FofѠ1rǁ"x Yb\4ay x(W<ptAf9?KGfsd4%C٫c+:,ՋinJ|t^<'m8Ig@k"8ZZFNim+42y\KbY#+$92J̔PlVx~1؇rh"ZZT8$+iNQE KEbv!:)mm66qN*[t"g%5Qp|׆5$E(PeRdviE\K`_%e)y Ѩ4x¢Z&9!z)Fm6nt^U.swhsWg} 6-~HhL&<,@b>&R%j[> k!ziK- $?>8F*R]Es*Kz\&"yhئ2lρ`ؾ^ ]LpѠW) Vނ3TXʠA{sX 빘EӬnm\V[_ˑՈR`0-b2R)bTJ*PsYkP߫R.H&Ut\̦S*5yx(~2lEb.6jg%Z 9al趶f$.IkK$QB !O*ųlg+%rf#3_ZRRVZObʍ96mxŧ*.c3#ae5vqOd.ϟ*)-:>OKP*I*SL2}̪8/>GOVmLi6"WObb ]NߟWXu?QO:YSC慽^Ʈw؅rsvѩs,$xTxoZnP$V _åv +oHwUpz;->&+ xR!?~sˇU+_FոDDba|;r.GsU$VZK"K͊LJĎ bKv N"|Hf x(2o˰ D`-YOOa\2B%QQt9n5)a/4/IF"l>{헕>$ 8:eM[ ,TeJ)#ٗMe&d5"<&3:[XQ[fSֈm EZI-ЗŚ rƍ>>[E?" VWB>0,5}}}&[xva*GR2+,y\kƅ^T:am6Ύ`\ZZ%alNy8uKIÐrD2h&!3nW Oir}pb+#Xؿ|zC,©}GԐQDg2zi>n6 $LJ;-GţPT:aDy̅ dޯJLw׿H_1En All=8~~W6/Owa +0+:MR ɪrB.@ێUŅj?դ/V+ + ++n҂B0%ɈL$*IJѦfFj͐P\xnjv b]-;{\3 w ƈQKQhdʤ2#舑;S`]ȇ3 c! x΂$_I{wh+gu<,nfrz̓˽h Z&86=[`cgHIfq5^깉To7whD;  ˜Ȉ>8:^00}k5-:~Y[yyCyl vR<ɷof"WG7;c&RJpdFI}} b>kBgܶֈjqs6{r?Ǻqt&NEyDJk K,9f$&*X6jIYD7X,_]H,3skܗ-:" t+o(d[>}9ZֺķI(O#PFU|;*@U@YC]N"m,˶?Bpen}@;s3ܫ;֧nN(Rm nڎo;d2rybBȐ'q% Jj`McqL{dr4Etr+כMF٪WYr R#Loޥ!Q!_Y`O/{^{)JXQBS5[!~~LUb}}UU}}bULLbb PژNc'\O.sLT//-&-Db-nK+UD XR4^ !J%EE\JYq앲>v9ěw)ڒ1{nk=0Fі<^tMTw6?*YU#.Qbi@g{6!VK X9xg[_i,O `fG͆HO`d7]kQ{h:~؊uu7楓r_:r ڑWNyȻ ꨚQ'Q6O[W^F[PF*FF7RU4~LMyyFw?[zt͚a\gtt(\E\/XNY<2K#cO}.(9AR>͉q((H4g6e';g4@2`W]?q\@5]e94Svh+vL7;ThZ]UڠlwA,-.7pT,]^eq Vh2:.GjQ,{dF@^}mڶC"`:tDvyZVy \XŹZ;7D.=n*4d7r tݴzԡDRgR^{/fKw}tss,.l~ǹp`ܿ?*ܾHBB}(kh ~?6 +v Cdt/Gu>m{閖˳+mp*ki-MtOaF/{wXPM9_uØțQY6 qg`#;{eV("5ɵ:z1Дq;r+Krq5 +S3>;^/p_h&)5 3ge!A*H/ގf2T9Sg5$}w=ݍwb0vC &!PC+`]<5ʈN?r{|W؋8mKdZRxi,h L}t|f~xlG#Л8i ɃJg&k`2|^[Cz"U W-loM&k#4(9땛'Q}[hF7!ڢv.??Y1kҳA,vF{WpOf3I&ы7V#|_brdṻLrҪ)X@Ó54nnJ!HB +=Vm4}aVi$,Vu.AEX/d*abKY&a._XN3쮷mtCC{FJF3ugt4YkYbBĕ +QAbPC3rVWJqAJ7$l K\YU6uGXU+3fC"Dz%1HfjXj6v5g,cW uG<.*88!0XM@*Ja $E!$)V, e"z7>գ-kgj?xVM<݄'W~aѾhݽ ݂=3[DL\ C|_lw؅0ijvG|K( 1:sr ^k*.w5}ڵ$v3'}O-J(,ܿk(˨NoL *-61+m' K?v֡0_⍧9 tQq @k$]"KH, B(+/SF!.x%ךhQ!TPCw~EԱ &x(TGcヴ?&6.<>`]Ь{MVa6vqG/C(K/5&d wt5w!TRR(u*J$+O*q\k1X&P*ѽ74˘ \i^DX͈=9~ao++f5jRuUv^F^ZEUuAZі1B9mԄ:ts1._ʜv3vW1g=UKDlr< f 8m?13Tc+TH",i!f ‡]EC>{5t[K蠻njhŐJqB"J.&.zV%?/0YKI&sXnėvS=cRGX9I|7!f|CzX +aǢ5,f7 }AkXsyXizX®,ǎCYXm8zbKQ9 ;?fwZؗ:Y}"=Jt>DoӼrT9lweJ7qedwMT Ug:,mLL+a8vM:$b;*GIזCS $> +endobj + +346 0 obj +<< + /Type /Font + /Subtype /CIDFontType2 + /BaseFont /HVKUYV+DejaVuSansMono + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 348 0 R + /DW 0 + /CIDToGIDMap /Identity + /W [0 59 602.0508] +>> +endobj + +347 0 obj +<< + /Length 13 + /Filter /FlateDecode +>> +stream +x ># +endstream +endobj + +348 0 obj +<< + /Type /FontDescriptor + /FontName /HVKUYV+DejaVuSansMono + /Flags 131077 + /FontBBox [0 -235.83984 602.0508 765.1367] + /ItalicAngle 0 + /Ascent 759.7656 + /Descent -240.23438 + /CapHeight 759.7656 + /StemV 95.4 + /CIDSet 347 0 R + /FontFile2 350 0 R +>> +endobj + +349 0 obj +<< + /Length 1432 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +59 beginbfchar +<0001> <0074> +<0002> <0072> +<0003> <0061> +<0004> <0063> +<0005> <006B> +<0006> <0073> +<0007> <006F> +<0008> <006C> +<0009> <0069> +<000A> <0064> +<000B> <002E> +<000C> <0065> +<000D> <0076> +<000E> <004B> +<000F> <0043> +<0010> <004E> +<0011> <0020> +<0012> <0034> +<0013> <0039> +<0014> <0036> +<0015> <0041> +<0016> <00B7> +<0017> <0051> +<0018> <0032> +<0019> <0031> +<001A> <0035> +<001B> <0046> +<001C> <0055> +<001D> <0033> +<001E> <0037> +<001F> <005A> +<0020> <0044> +<0021> <004D> +<0022> <0030> +<0023> <0053> +<0024> <0047> +<0025> <0050> +<0026> <0059> +<0027> <0067> +<0028> <006E> +<0029> <006D> +<002A> <005F> +<002B> <007A> +<002C> <0070> +<002D> <0057> +<002E> <0062> +<002F> <0075> +<0030> <0045> +<0031> <0052> +<0032> <0028> +<0033> <004C> +<0034> <0068> +<0035> <002C> +<0036> <0027> +<0037> <0029> +<0038> <0054> +<0039> <002F> +<003A> <0058> +<003B> <004A> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +350 0 obj +<< + /Length 10507 + /Filter /FlateDecode +>> +stream +x{ xUڵjWU?~G Ly%!H `Ȁ A0 j#  AEd%:22'$ :sw&jzk`9 x|Qܕ oH3*$ͽ yY|M >hZz.t<=i 4:,z""Q N'Θf?_K=UO+)nXPZR3l]hAGUEj4)WG6B=zX--)ĺzr%1ۤ'/)m* N§P_,<ȇO.@=m cT`'vWI),*^UpZ> a5M Jᴐl%~f"] 9͟?ېJnn5u/u{f=k}֕(; $(fr1*ľ2qBFWJ2475oseaKVB F!5AAڃs94H64zmYYos&L[|fMIvG-?sLk"]رi)ijy +#H2啽,xGV.I~|(Ot񲄎 Vݹ$ +0AyBT9¢u=2HuA$B 6*qfoϛH;fٞegz:ƦƥƧ&døô3lG;' qa=zf2 G{$Sfj8׿yrޖWwM4}㤌-P-+vNyscYң{}NFo}%-W@$x̕AGPy4lZ6*ne@1f5_޸&8Y!>=,<4{b>)q 6MC_oV׮q@7frx}Lp“4P5\Q!%-\P +P$I+klTb!=!@ <@QA1 5[y}8&-4+}}B._<1s >A'R;F pL8D:`빜^_3Hxo'.cROJE[_/OTUa +ǭ%ٮ8 +1ꉢZX70\Ehup9K8ta$+Aɵ\}h+Yrժ5xVOHoJl8fg>=@KS"@,M%64v+ b ߓaHJ "oF iR@Aף y 6_OB&42"KG^dI6;O}qͪWңz׮$3񰿜m@@.E..SY +'o()p%OB8Frf768I"0J4dJnIL&dHq!d[yo r{X M`O[zG fϛn={d熪4k4Q! i ғtVa*ERNUMԲ*I8Wƫ㴹$>֞rX"M-Җ_K]-"T޹$ ɞ? yPLҔ(sy4prڰEvv\7Dc/dvB2vrN?=}tY PQD$EUT aFJ69MAӃk߾I7!a_8&Kj)Q +9jjPIe)PƑYX8b|#`qt;C>}|vH7KiHyXAhRk(5b6Sc;Ë/NFzrBc-#es3 8olYM;Ӿ]l)<;:#$(P;kPy&ANu(Hb Nsbdy[Me PGo HFUP2$Y6 Y+q%ƣK*n"u7ɳ[n;K]-2z+Y*D>R/q* @n smI A9N~^t>8pZm EX{D+NtXeٳY4A ^jHHHKUjv}-߯|ƺzkյ[WGKd9y&rg +{R@WuVϾ"@` !t7UhDdGYm/8ej`ŎFQ]]Vmx7O=D.zq/:5rU_aY8`I,OiBa$'kF,ݐエ+ztQ߯xlmFH8Fjj Kq"z(~yS6 &U2]N\>~:OsINMZ !FUZ78jXT9 NbLk^,X=+5\Mu@:SpFjni:߈]~k_|hT6Z-U/w:=mn p@/yGOu55JTtBw}Uu`i#RQ 8Au-=\]x-hj"jdⴥINHk쵅g2lޗ d)%nqO[f ȫ3_~%#{|dfnqrOz:@O 5Vv(qcj\Jm]BDb.V_c{KV^mp-+U]w%m6huB6mcܘѬoM߽oߖ[+m|fBC?'t-vz?}dfO~sCqqVH\ۓ6HPBLdH +NsY ~gȠV d6R%T%«{wǤܡV.y~G斝.+87HЅ t9QH൦/>.迶bq) ;N@`KHz:@'>2 +0&4C@S_3vM4?ݍ\ȇN=.F!}eCuSN8V.CRʛg3O$k'w\.bKtD+حFMӐ̿E +'6v-w%6?gC[Dbwn_}ټjզݗ>-/9Pj0,B{^7Jh w"HeCaȈ'`ϵl<2[idtW OH3!auΰu\ױi9"A1TA.>^ܨ[MVYbB2{86#gf+VoZlu=}GtRxjz)9yb$w۹W[#$D#c'nShB'DYgk03IA4amպeӅmU<>߽,h,ZVS_:WE7NvAVCaCH +66Lnf1,*emJGh||v ++9R)*O`ZൃL +@7rKڡ<=q8^+9Z9>ە0ewXZ<%gu~c +1Ĵkq$<ąɄLHJk:~>ԩO )&Q~7<'(͊ɒ_OnYK҄kO?b-RǾrA( Ю@?gHGV7(RJ䣱XjU;j6oQYﯾd_]#ǿ@@c?1&81 +jFSY_!mݻ?')IG..Jߑ! ; ?~ϯxF(BM߉3H,>&YNjM`d?DjnI Ҧ<¾NUJLDvSua|z3KU+W*v/˹pxF޺t1Kw&P!`g&Q{ŧe,Jn5Әy'Oq@r"קU#>^[v6d 1&V5 <Pu LN34* ISDA@o#BpwhkѣE *"h'Dxd7h!EivܦLai6T$ICq'c?!OX_rKV~4ӦRFKe)%|6 yͪF`\cjk,v4A;ϭnG؞A|{INJc+~??|vn\'=Z_5w)ᱮ?o?BhE}j cg8h5,J2VqB*BX |63a7nB\M6X caTL8nڃS;HoqRqIG f]Hq iKAq$«(yHۺxt4H>g)۾Dŏ`wv]Hܽ%ssta]Ri@Kn^_W94rdgPw-lCv$e<ŧ_>a\K^\'|kQ]E7p3,Rw\6NVńVcd݄vަroC)̾bEYi<ho]1܎//b'lp w,Zsvۮ (^A{%=K34S"7"OkWZ:#`8|F/ +`4H#`,@ȇ.}~=AqP (-(+hO8AWŧ!Pá7 0ZPa0Bטá 8(Qp!aB]10׻GJ6 aA}! +=.??@os_Ҿ#NP}FHrÅ`_|!n ]~0Fb 1B +i%Åe+tzj._ì"9 fe?F?. _Ž +}[I\/:g` > +wbN+n r<9Nz$ocW>حFBQ`YkUʄWzZx7^k1-tneA2Խ"c)/|W X߷A@??[&(Eg y=짻?kÄ#OJzqj?C9I;uiRsa6O@@=%&~<Oq"0V0l0&@2$_ CwD@a}B r`0<#!&h3d R`Xf v I$tɴo j@ +od$DHl*^-} }$3 Q3UU+b Dz8$aR1V:0~uxs|9ޘ7_.o~M7Oy_2n<ϹM&MMb6Zgm>Faʆp%çmyѸ'pSK2O-ťNÊ`|b3,_d,'9//2㢣r:D Ʌ;8iNrDN`8ށept$}80pÇH#80D1zttpO,g8(?b8,tȁOgد^x r^_ ͳa^LZo=91Ȟ\3,\1x< $0fhV!J`O=!=5vQ4a-3LKrд(L”$MdCM>IBh%ζF`7.n7C}]lڅag&ZGт.  M`Db\A-:v`IcFFGbH h May$tX14āv[3$jCB6YbA]p1X.lAF 'ـf[=eC!PP!ITaHR6[($*e#+%IV$pz-/hf;Y +endstream +endobj + +351 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /OHYPAK+LibertinusSerif-Italic-Identity-H + /Encoding /Identity-H + /DescendantFonts [352 0 R] + /ToUnicode 355 0 R +>> +endobj + +352 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /OHYPAK+LibertinusSerif-Italic + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 354 0 R + /DW 0 + /W [0 0 500 1 1 518 2 2 447 3 3 307 4 4 804 5 5 478 6 6 521 7 7 472 8 8 276 9 9 250 10 10 637 11 11 486 12 12 353 13 13 486 14 14 783 15 15 401 16 16 489 17 17 266 18 18 489 19 19 568 20 20 357 21 21 389] +>> +endobj + +353 0 obj +<< + /Length 11 + /Filter /FlateDecode +>> +stream +x +endstream +endobj + +354 0 obj +<< + /Type /FontDescriptor + /FontName /OHYPAK+LibertinusSerif-Italic + /Flags 131142 + /FontBBox [-83 -238 874 705] + /ItalicAngle -12 + /Ascent 894 + /Descent -246 + /CapHeight 645 + /StemV 95.4 + /CIDSet 353 0 R + /FontFile3 356 0 R +>> +endobj + +355 0 obj +<< + /Length 904 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +21 beginbfchar +<0001> <006E> +<0002> <006F> +<0003> <0074> +<0004> <004D> +<0005> <0062> +<0006> <0075> +<0007> <0076> +<0008> <0069> +<0009> <0020> +<000A> <004B> +<000B> <006B> +<000C> <0073> +<000D> <0061> +<000E> <006D> +<000F> <0065> +<0010> <0070> +<0011> <006C> +<0012> <0064> +<0013> <00660066> +<0014> <0072> +<0015> <0063> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +356 0 obj +<< + /Length 3277 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xypWǥeǍ;t3'25ݰ$$aͱ26-lْ-h%uKݭۖ/,C6m$pIp&7[3jvzʹ% LM?~~~_h"X,^@Y+ޭ*Q%+%ɭxؓ+SERS?Ixtk"VD?Z)-,>\ZHH>@꣢X"۶H]|HY+e5uU%Gt[T_yjU{(W}ժ*uPjsIX៍7lK[bK` .T%ecK.ߖ"H3N24я,U.JYpI勍Rɒ%K7-M,O?؃O=')E  +ۑYMGõ藘B#2zie2sH;kƩ&F vv ,۫hL'!,U7ޝ93v6;-5ƕZ^f+0 FЙ) B#hB+z%)_LCv.:X/ω<İ&.K+u_ + Oo2Tl.(r . OBh(քeldE,wZ|grJkZ:夜n644Ęؐ{25e(c\ղP5t"&4XE/ 4pzEry4\ h9LRcVW +- 91ǘQwj2QGqN iCL a +XVd}.?qA+m  /Ӿ +,7 $?hy/"~$x1v̉ɳ@E\VĤ}HhBڈpWX$m>e?Zg >5+(89E抃Ja57:hsZlR !RK]'G[ [=Yd=.[} շ`n,*tgvA-a_}~U`Xߌ6FZ;x|(1)cSgK[FF~s\` ΅=-:WrsMVLH$5 ~ۿKKun h_XX=@䑎\ .)\:NAaM + | νnI3.Kb2* Zi-,| VQbAye,-zg7%yC`*p))6zmIfKL'R38/AJ"Lw:mz,@3g VF0&Fے|2>bF Z!T_ 1 6z?a7JPVi r9E4J$b1aAE+`4*˶BCgr4 xh0@|x{Y㾎+Z5XQAw4SS}(e46F5M,j5֢W9 ̄}PDcbйO>Hɭ3ofgy^a\xymζ]("{ + yZº)@ZiT\Yb,_䟗s3W2ݑqzYͯ@[C@;[X Q`$P6(O^ !QZJ6 -!Oߞ"-QCj&Us`5xڭVF֛D"u>6v +, +?~΄ߎh+8\(*2!^`C33C|TIUV5ul׈* ƣȻG˷Nke#6u֜g1a%1r)29ԘLXK̂?ss`48(ᓞBztg e x.zkt:|t. W~+ <#| ^EG"J\%D$KJf.Un[Ef_4?sQOҎ*G&olGb]R-c>ߡn9 +rno4,fi\]=B}4b0j}![b1ߘ4=%`+Ye5\KheS|ȷp#urR 9]|!*E-T(UJq!sOq©Uy]/eۧo~ug]\lQ w>|oJ- -_'p4>I˹hxONpW>Cݡݚ]֬}8~|@u?մ-vo+Y] +l mz+jhh1lä-\V:uN}cWԧ'qPõm'쁈ku6pxfΗe³ s7AIȯw4 /*,A ި oX}kRm墭6tQo mW92@^w)V9d8 CK +endstream +endobj + +357 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0Pp +Q +endstream +endobj + +358 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0TpR +endstream +endobj + +359 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0RpS +endstream +endobj + +360 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0VpT +endstream +endobj + +361 0 obj +<< + /Type /FontDescriptor + /FontName /AppleColorEmoji + /Flags 131076 + /FontBBox [0 -102.400024 800 697.6] + /ItalicAngle 0 + /Ascent 697.6 + /Descent -102.400024 + /FontFamily (AppleColorEmoji) + /FontStretch /Normal + /FontWeight 400 +>> +endobj + +362 0 obj +<< + /Type /Font + /Subtype /Type3 + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 385 0 R + /x1 386 0 R + /x2 387 0 R + /x3 388 0 R + >> + >> + /Name /AppleColorEmoji + /FontBBox [0 -102.400024 800 697.6] + /ToUnicode 363 0 R + /FontMatrix [0.00125 0 0 0.00125 0 0] + /FirstChar 0 + /LastChar 3 + /Widths [800 800 800 800] + /FontDescriptor 361 0 R + /CharProcs << + /g0 357 0 R + /g1 358 0 R + /g2 359 0 R + /g3 360 0 R + >> + /Encoding << + /Type /Encoding + /Differences [0 /g0 /g1 /g2 /g3] + >> +>> +endobj + +363 0 obj +<< + /Length 661 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<00> +endcodespacerange +4 beginbfchar +<00> +<01> +<02> +<03> <26AA> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +364 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /ALDRXP+DejaVuSansMono-Bold + /Encoding /Identity-H + /DescendantFonts [365 0 R] + /ToUnicode 368 0 R +>> +endobj + +365 0 obj +<< + /Type /Font + /Subtype /CIDFontType2 + /BaseFont /ALDRXP+DejaVuSansMono-Bold + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 367 0 R + /DW 0 + /CIDToGIDMap /Identity + /W [0 29 602.0508] +>> +endobj + +366 0 obj +<< + /Length 12 + /Filter /FlateDecode +>> +stream +x  +endstream +endobj + +367 0 obj +<< + /Type /FontDescriptor + /FontName /ALDRXP+DejaVuSansMono-Bold + /Flags 131077 + /FontBBox [0 -235.83984 602.0508 812.9883] + /ItalicAngle 0 + /Ascent 759.7656 + /Descent -240.23438 + /CapHeight 759.7656 + /StemV 168.6 + /CIDSet 366 0 R + /FontFile2 369 0 R +>> +endobj + +368 0 obj +<< + /Length 1012 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +29 beginbfchar +<0001> <004B> +<0002> <0044> +<0003> <0053> +<0004> <0020> +<0005> <0034> +<0006> <0035> +<0007> <0033> +<0008> <0059> +<0009> <0043> +<000A> <0031> +<000B> <0039> +<000C> <0050> +<000D> <005A> +<000E> <0061> +<000F> <0073> +<0010> <0069> +<0011> <0067> +<0012> <006E> +<0013> <0065> +<0014> <0064> +<0015> <005F> +<0016> <0063> +<0017> <0074> +<0018> <0079> +<0019> <0076> +<001A> <0068> +<001B> <006C> +<001C> <0062> +<001D> <0072> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +369 0 obj +<< + /Length 6745 + /Filter /FlateDecode +>> +stream +xz xU~;;r;΅$$`;\B P"IعAn BV1iSX "22tr63-ֱxZK=޹sg&d}uFE޶]ݞs+z6roCGc΂-} /iu7u +~8kkjտH>G6vQKo-͂̀3[k{;x*im]k JG{W7ͦ{ttw}<}?%$2I.IǐH.L u5TE $$t`c\.be1v@fXҦ:iMl ď/RnpA ~,׈^ץ-^5 ׸08vH" tH8C C|D7eirc %X׵C gjL%l[<XM93N=6,*Κ<YlYtge_ʕ/Z2'{UFٗ. K]ZdNg%?[띓tXJ2Y[Qsֳ$4)r; +-&4I2rG.΅"%,R.(QFWC_{h 1(t+]AUy,tGIѮt[6@JlHOhvM[\gFӅT>#ds' [hd44zPٮ1jMצdC + Rh{IIDI$DdorZ=D#5;:G7zLX(YlCµso/, sUn۴>OC_ f, +$35RԨedE'k& +]*9#lMz^{~TkڥI_)T>N_>^SU=;xᾧ2Tȝ~O>a.:T2dHt@(IKLZHh(Zr;E:۽vYHI +YL>-m ;'q Gǯc"'ۏvw5m6㥄 |"I +)+[Ry,$9[R6P6CeeYaKéRe|,.Y@nga@jA{e4 +b] R!jD{_"+H!I +CL/r%-A*Iؽ}^!imN3f DG" 7qpۓH$f\W|C qDv txyuDkV}d +FD}h|^6%yT!#Ījw?1Ѣ !vzZV'ҁ `: +"'B`>b(]ڽ{aLzv7B)J}wUyp_ WAlRŤ11ZhOj<ߘr} )єƘncNu2lџF~{p-"%Ŀļ&}y -NN+,…$^:ͫSëQbOk(]; #._Q8fFگ9ό_HǓfd1&%֐d11I&Q]}1Mvr}r3#QoLYnKJ.mO`|:假JL}!Әi4gZܨlwf|fBfbfR'ÛUM".IUP2 +抖8/}nc]N|Kiܾ>((,O]iO?WBP4dGC ahQ&nhCL`ZlJFFB%`/QB=i i IUBOyG _"rǸ:e|Fd`E #.֔OKaGJR?b}4!3-nߡq{23բph+.# +Glva9P)[vRI||\u3_Ʈ^o/ fhs?zi?kF7*I6!@\93+yX=%~Hn) 1Oq *f^>xs˹{K|]y$ n|Hzk,S:okNW7reO f,b2#jloB5?Ӥ?D;0Xܳܚx[ht44_*uף^Ū'zJ(ZqB\pi򿕷H'Aczr#;>:{Eg9dqʍ~kHs;!aUN 6c^ qqMWrthnow3;*.(/.}I@In_O6([nmkۺHSuĐxWX$o(EdH?y$[(Y΅ O_}p>>w56qN E¯ԧqZ$VSƔwI +rر]TE .Egg+7|s9v@ˎÉfY݀AgK265T2> +vN뫝<ٯXOߒDv\yUW$_! ApQ>*݁RFLX-VX&3`5[d4|f#Z,fAYe\c:] yOGBHaWɝOR@GRwȥc[g/@O&3B0幍Qyg_yLcrMhn Nb,v= [QPq}fŰOgT#k\c'y 4. 8tdv#%XDgpT^Y2ƋMZs峿RkUy&+&)zhVw,IW횞S7aIEy^ZIfi柼u]* 4Z'S@H + 523ಸUkY1vidk7F/U j)E9Zޟ׿pZSy]U@KgkE=mI:WnDCۺuGV%*?D~M!hA'Cc]`ux[qx1ș!!5IǤt3}X6G3?kcqh24-SZI[a%P>GR^ KzL~>߇) 1> duH&c#擎ٙF΄-hrC'ш&tà lC&<#yȇuЌntG-Z V ېJтxP9!Kգ .#؎Zl@<؆&Ԣ bBhAZЌm vV͔S%p ю6cтL vYpri"GzĺBw1J7:0E0z.؆zqo`$mG7Ma({q:ԣ؍L7s?nYi?iO||acY'vv4|)nY*MF*IՇjZ8 V'Vw;jhG濍a[(x-}KHUj$ՋQ#8yJ$ {ގmhFm>5B +=O xssq~hG=${ux&yb \:aZ#1$r; t"'#km0{w1eדۅ&qVvdOؙ+GHVAfuoou9gӣnҢ݂֯! f-TcD#[.t &ۄC䩅? 2yKU-Su}^:_}[y5 cqɻ1N b˯T}WDh`ϓ9agpԷ[3>}\͡):c4'ޯ +w#9b +@?gKA:"1pip!X%؀2Z܅Xe[ K/(yI&}Au=d:3N +=󴙝I6O=N+S6OO=NmiBO''qrx)=C?;OSߤn(~Gc); +}T(tчnz!;DvO4Cg>z߽Vv_,Jo)~';t_~mHd{tOӾېztBw)̴̺sgTѐ:z)fk-yǶ́qmjHdMAؐiMu +GkzOnmQ]tn`t [tBU:2ʵnV9HVZ75 +-_dtu)tBWptu.IK8}t.5?]h J,lBK4 HG#+;\4/ysl^ -,ahA|ύa ;мܘ-14g$9v6A K^βl;Y-,J<[c`-t09[\E34}MKaiԗ|h*,5hr%S )I\,)&rD&ĻXƻ8'墳xnX;s8Sb4c[qU sҨ"*NȜ7O6?ߤ68O̺Z`Ԭ2s"5̔HVj&RjVc`Zr @5$pNfzʆ > +stream +xuJPFOUvDD@`]\ +FMkIRB|&إnऋ(HrTų9` ըa&ʺ:l +3Ŭ*ުnh)&C|>b纝黓AvCƫ+ y') +̵8+/> +stream +x}Kq?UX 94%MQKSN#ԦQvBˡhFk ! +ՠZP~xx^ޗQx"^P c!H0 + 0l+ߣy7;׫;Q?V._tF3LEK)y z80eIPkT/%[p:8+%d"G `d_{ٹ֖gzm\8rSif1\CU` S] @o _ +endstream +endobj + +374 0 obj +[389 0 R /XYZ 90 686.2198 0] +endobj + +375 0 obj +[389 0 R /XYZ 90 299.86975 0] +endobj + +376 0 obj +[391 0 R /XYZ 90 725.3498 0] +endobj + +377 0 obj +[391 0 R /XYZ 90 584.3098 0] +endobj + +378 0 obj +[391 0 R /XYZ 90 325.2898 0] +endobj + +379 0 obj +[391 0 R /XYZ 90 171.1698 0] +endobj + +380 0 obj +[391 0 R /XYZ 90 747.48975 0] +endobj + +381 0 obj +[393 0 R /XYZ 90 761.8898 0] +endobj + +382 0 obj +[395 0 R /XYZ 90 761.8898 0] +endobj + +383 0 obj +[399 0 R /XYZ 90 715.8298 0] +endobj + +384 0 obj +[389 0 R /XYZ 90 761.8898 0] +endobj + +385 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 402 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +386 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 404 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +387 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 406 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +388 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 408 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +389 0 obj +<< + /Type /Page + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /ColorSpace << + /c0 370 0 R + >> + /Font << + /f0 333 0 R + /f1 339 0 R + /f2 345 0 R + /f3 351 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 0 + /Parent 1 0 R + /Contents 390 0 R +>> +endobj + +390 0 obj +<< + /Length 4576 + /Filter /FlateDecode +>> +stream +xْ_1+9({hHl:V:NYOiELWo~~>|uW_U7Ϟu/^{xw U9}\ݻ_6nzû-@u׷s'qο%n*O.WS&>o3=LMtc ~9_O~Ӳ x8nc}wכm~rsnl3&ֻ~~ep3B d);RP Ή*}X5V)`JW."(w΍4O+EA53 ݊6_kIuΕ%C963g/;tw7#gL Xpq͝ǃ] =_-zX|^>w[ixNlqف"hf!(iX$ 4P 8)IN:Sq-gVH /a'꭬g.hfvzAюu~)2:&B3BMzi63i6د[ 2ٚΕ6mG @ +\@YdIǎ7 Щ~HHOn%sI/6h )%s + nOL(=*%Ÿd[wdz #%0oKV1QiN5L0V#R3 ??fo/ S RM?:epzgK1·_=i.GŽ;z18hqιvIdF=6')sWbx7gdlzXDFtq⬉,)j/G.ٯ +03i(ON|nvai͸=F*4;r ydkLDŽ\_.qe_8,fy2'G( + Rq[,HP3\M]VIn9\Ŗ]#7K +3e4I#S.Ph0gh#ûiGfM=',SRV͗Z>%1= ;B1 +Ỷ BڔR,>|3t)DB7u󾬴W-O_='̈Fn%Ĭ2`s#`NIP0zBP&SM&&uӾL20GCw 2P +$E[Yf阎;>O#)+s|9tʯlN'HJSC2 Nk<,e#bKyMXB3LPT?+B ++W)C3)΃'MڐemK6d*>"M Rd^ +m#PHU$S E -ų0%Fz`R[˨3`:#,zYd{R˂q1N 1Th!}q)]8sݞٌE>~dbDގVQqiQKらDA#~bSSk d*m#͐جNbDw hSC+}s ?FV%=ٵB !~$j?+-iN(`pu-jyf~j[Di͊;΃LɅ$Eޡ98nkQ2x5̻2QUԾI9Vi& N$q[]4+.OUkQthV"$BhWsJG")GivŷDi))523-O iKhڧ#`gOѦqmCi3%)6> +\pQ݃Ԟ )<]?U6)2tyRW3ec1oJ"(_bBXnL3M.+e/~\θװtS9L; +hASHHea=lˑ_\ 8GIEj8ec򻈪fF*ZL 0,.~0=YUcMFBN.YL(0-15J:3 +ueNxMQQnC"t9d塆6Fs&yMn OBc2 +zS(P,=JTWiP`:8'i-|z_¯ҿsBEZ3͗icHqkN1k+R +4ݻO#fpMe+B QwqRMiƥ0maV> z,Y4%SݻU1lj' ✵ޚ8 b- fm5y +]#xnjn=drJN40(a3d5ݕ!>rV2@ 9;&k:aH,kxi 6Lr)t ^߬>w5o~}r,"%sB0僦\ U%50a=+Psh~?wI%ʼ) 9!çy%6/YsMQ0q(r+'OL[ Onc;xNe u_imkwd'ye5fdr9SEfA2өpEFAwH)|diʳ1-~9 +o=N0ՈMc2%E~aB<ۧ CEO9$ZGIiv%/.c̋P=+GBYD35 ֤J򌾫wR;h/:+GBh*l \,Eu^ ^ܘIH{(;39 +L 煒M''s/ϣz%B~n04Uᶙx+9l` +cMρB[zAG:{W,Au) B!K ][*xjAl DPAdPC`Wrh,ƅ_|9tyV?Ǣ inȷ}>/>zIe\qd_;dOpGN& `چfmˏ4af\ݨՁ'GL%YSȂJ]^8Z#S(7HۺzΜѽW<}eAėp!jfAcTi&Up)$ ? +TdL1KvxJQRNփzr*v LDKpQ!#ʧu72gA +Y +:!m;j9UԻ65 ̤Z#@mY-Ѷ>l߿}辽zq7ꛏŸwo?~ܕ+m> + /Font << + /f0 333 0 R + /f1 362 0 R + /f2 339 0 R + /f3 345 0 R + /f4 364 0 R + /f5 351 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 1 + /Parent 1 0 R + /Contents 392 0 R +>> +endobj + +392 0 obj +<< + /Length 5367 + /Filter /FlateDecode +>> +stream +x=ۖ%K~)dI4Ad'1}N9M6Q@(Ns}h\ +w7o^op!‡~x=^mf36a#cV9?ᯛ?l~7pŋo(Ntp6 ~||sBW7{?=s/W)ώ?IWď?w:MvpCSoc2wo6GT Sz?10pQ%2aye +l&79KDIT9=b;\8KOp`!!$Ԧa=߾exawo8 +01-U|l A\ N\) 3PZX +}s 0kjA{Pg"VFZO>rhw4q L#cJk(t%{;\@LTr.Rj aP oO\oj4 6FYz"Fyic9EmELW9τo=@>rA4gz]\g\7AFX`%%`4>v\,Rl%7: j-G2M}fpq&9SA)'SM =@Af+v;d0$鼘k4 s&JSfʝm&Bݕ9T:t0K ˂wď*wѴuQwmc@I 3R~ 8ŕj|TcZP!t-wd6^N:8ZY@U(I",u$'#48sK<0vA' +ͼ ά4(VqU!5/dZ"1B:73~vsW}}e~ݚ.4VcE,v4&-%7tSD#{bFHeIDcǡj9 wp׃buutz3IKPWs4R!Erkvʝ8n=5D>s~-hfQ6_EMܗQvUs12z1Jݞ)E{#M9t#)JJMA p57o ER@QEwYD ܥX1M]9)_/e,oJv뫓g +-u7и2Mdp833W‹&N:?I|6u4+)~p + OAO@)'Պ`^zFxdK:й5RKw 6'DpQ>Jɪ}!)` gR<_Ɂ,rTc"Ј'U\@6XZ^{[ax'I'#!/9d{@)gd>pӖeh!?Sv:?38lS<ۛp~TL/1qROӷ %q+зLF'87cC6 + oaUNS0@tG[.[{HūԗPw6T:+@+?qHǕ!UlP#Bm-|0}Ŷ} BN'rv69v03ᙱ"%Eb!gDJٯ SAX5Z3|aEw@{Xr|8B63$Ԑ 7(^0f gk#jgA:@Z[Ty՗Mڗu py5H{e!$Q q*v- |ۆ)LKۚ5LE@"e5?7cyciPNkLmjt#hqetwvm%vu:#L!2Lv Aƀ)Ύ.g]m$-V#HRHz_>c?<P[UL{Nrʾ8ZA4r[Lv#$dkg=YJGO̴֥+bJK#H$Cg%*'tb׭[)HONq@%fͮMWg ]F1[r[o m[]EA2o3SMo%2h#čbB/ׁ\cBc'-֤dJ:_TO̗2\/=Kf~vs:M"K#s$,T\j?Y<1]DV% [um=a-O=}~pd,=YaOi׭O cn6.uPR<(މP6_[([c+eF0iNͼh#AN)//\FbMua-c:fɮLc*ԁA"WvXDrJ͸rrvS5:2},gV**аk`)йY}BxC:2W h JPKI$PPJRdk";2!jT=th` *.SLj#hPܡ EBѨJ Hr]Htf\Q Bv󃲖ToZδl4X̴ʹ0('0'cS}`ʏ)1bێIe~}OƼ~,q~u/*9ւf;=:αM6 tgb᰽k <c ijb7[<ǬFSbP,^SG;w,lԚ1ߥ;̶O$4bwA6O9͔;C55mu[7IV4Ls +fYe/R2y5L+7L;yʎA.pNaJ\Y)z=r+0YQ!|.Nr`_VKcЂ{&4',/Yk%gO@BE) 8\`k+jGs`Ķ`hn2J-ePUHaistؘw&נK7B[^š1`bjW:vC 0T]}U0})fap#Ă9]$6Cai$ONXX(R*˚GHj%ޓclS;CBZ[v6xVNK%VBƞcZ;r_%ڗBҗ?zY؝j= .!?/ꀼpG\8U´Hںv7_13.O,wNaۨ/ u!K.ѭS~M %B*􆘪jrHU*h|6jOpɌSN|fi~7dLeWz``IkITG>֍@+h/'GZJVfZt0Y?fyPp?{OJ{wh.̸ GȫO|V7qaxi7?ރAdk2Z\}Qݲh2] XiLVxZqpBPiiWl3a#q+5HX׿WF zpU & L ~U۱} ܳ[oXp;<퐧9?Jŕ* B!֕ +P;bbQu7傟ͻ4#ќO?#(FdʭpAꂣ'܎hHSDG"Gmn3W`rofL~7GsJ9=>b-θpW?݀"&'O;PI1V#VxyaVX?PyG2eWg*qktA N*皛#i' ԠWBh_ +OF%7j|\1Qٝ ] )K]|֤@x +Ȝ5X9ڝe"KvAVMm\-Pk-C*4"2*p-=^"Vm[*SZA1/|b8X׍AI9I߽3> + /Font << + /f0 333 0 R + /f1 339 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 2 + /Parent 1 0 R + /Contents 394 0 R +>> +endobj + +394 0 obj +<< + /Length 1116 + /Filter /FlateDecode +>> +stream +xř]o6+حK- y,kѸ-ڻjzzv[W_P"1I%3W!OfO:;+]yH):1/>"h +8Fb&h zW/ b%(Znonx;$sIlZ"l:뀻>xIs- NV_hߣ]4K4U/yBO>-;Xڃ>|0a;u,>.7Vh2- Ͱ01~ۏ%ZSHݥ!ʘ(^? -}w>o|7^.?jjZW"W*hLQS8_-]낂X'f"S`-oq[,, +G~[ KFApQûp~ Aǐ?xKmsrN)) =nN'[Dd4ӄ̵Qߴ@Ԣh +(Έp8 >>xpd|0|h =*U،{s:tL3j_ZCcGkؐJ!-Y4 3)V'#6 $ab1@ +zz )G]^8B,݀QJey3:@ɛN<_DnH@$?2p_ ,5Ey{h1ziՖs9qؑCC&+'yNy;͌H23ԊN|}LGD!)cn{һ6m֠ Bn*Daɔ-wj?j{z;;W=^`-WUuXYOs0Ft bi +endstream +endobj + +395 0 obj +<< + /Type /Page + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /ColorSpace << + /c0 370 0 R + >> + /Font << + /f0 333 0 R + /f1 339 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 3 + /Parent 1 0 R + /Contents 396 0 R +>> +endobj + +396 0 obj +<< + /Length 254 + /Filter /FlateDecode +>> +stream +x}KO@W]ɢКhDٕ.(bT:.f(7}#ǼbAؤ+01UJ$`$"FyEC`'bE Փҁ~ TCc2vg?fь87` ov0({%zgZoR^U^ѠyV`'Nٛ󠿎%}7%5Ok Oȷ]'(tVBÏ o7m1 +endstream +endobj + +397 0 obj +<< + /Type /Page + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /ColorSpace << + /c0 370 0 R + >> + /Font << + /f0 339 0 R + /f1 333 0 R + /f2 364 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 4 + /Parent 1 0 R + /Contents 398 0 R +>> +endobj + +398 0 obj +<< + /Length 3301 + /Filter /FlateDecode +>> +stream +x\Ys~_1+P8E);+)y@2RE9*)bb|YJsw_WglSl1̂|/=}xҹ'oHꢉr,QIRrV<<,ŭ*ĐrB= ]c=ځJUҫTR!e14b`>^٠(@B˅Jؑa&xnmh4XUdnJuY9<d[!AS>cPR zϓZ)ۭ'2uK/QɱNtn)|D)' -XmHa_;IKRކ3> KJjjV ҵ%>yѡ +eɍ^T +e}K1 $}j֛p9z;S+7V8U ٚlk%\I\rKm~b.RE!Gl,.rz"Ymryy2 2CERH_'%yKXQ +k屻%# "y(ž_1ZM:/s\WKQB3.ݣM$TjVT9UDNXF*-Z +Ƽ$$ bs*9J8$VXr2Z?Y̫(!Ulܶ@3%Fdum3[`*rk\գR CϮbx2t+F閘O" N''A +yIJa,y4\֧'~)҈J&l0&>F}@m5g8ƀsS9 IzfĒ/P\,TVa"IADv~:sߩuzZ6ͣĽ_MJ 2),Mk*Ĝ :PAc*5&d F#jp":(Ï_i2&O\7& +Vu֙`|Aa8R_|\ӻٛwWznv?|MٌSlM;g&9>x +endstream +endobj + +399 0 obj +<< + /Type /Page + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /ColorSpace << + /c0 370 0 R + >> + /Font << + /f0 333 0 R + /f1 339 0 R + /f2 345 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 5 + /Parent 1 0 R + /Contents 400 0 R +>> +endobj + +400 0 obj +<< + /Length 1365 + /Filter /FlateDecode +>> +stream +xY[4~P5*_n\&axhMYuJjmIdvbǶtt߹d|ۛ^aSw˲x\).0@K 4qH݇^bF`5CbZ#,;A}kxs{@BA$cݷ>Z׫ME Q0cr,Dؽ*&5"̓toޑ~4:YJkDG鴘\t"ʼF;7F>Oi?8uX [ +z)}xY˖2"c6뇕3QOՉ2Ü)D Q ђ{glU .ƍ[_p 6.bq^fW4 ++ $A 7͏E HBAU,siM RZ7+I@`C'etDHKy]cm`LN̯z D$fRxs$VOY H5b(RpjV.g2H2, |x(b,#@,A\ תeuK36a V!1%HDI o}7 z -r3yp؇0A=83&T/3`'*")Vi_dHsf}Z&ҋJCF`rފC/Z⾼gZ5D zZ}oU6DkK=HE%bA0 +~Q{iTN:)?!"F XdOSi*(id|\Hd +l46ˆ|Yb*ݡVjf0 Pu޿yQ!UScIBFDml6XB`1z6FaiڰmҐ)n44WRM#\A;ʳQG i ӑ";ᔐ>b)mgƹB{y<^BB ;6(3ӌfT{" ƃՀȐ*3$8h"!D/Ϡ0cP-`x~q3fk 1cQŬ3%r|nD(ƶL̅y\*0O b*liz8N%3NuFg'%i\I1JKqz0ӜY}L7Ӵ ZJݚ2uW^EULR4T\4]}-l͊/Pa1Aw^7?~oׇ>> +stream +x坻OSaƏZ-HYA!'AtPRc"()#&86H!f eA$X \ ,8(1 + +s{s}| $^746116Tg/csSly\͐~Zƹl/ݺ /@@oA"/(+|||$MΎ<|.fS5 +~M]o~PS|BA0wt|L|QAn+?Ot*b8N2>u|rыTGϗc)Hip:D|eχ8$bw|{Vk˹ +endstream +endobj + +402 0 obj +<< + /Length 9180 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 371 0 R + /BitsPerComponent 8 + /SMask 401 0 R +>> +stream +x흉wTUcU`"27Ђ<ƅ@ TZ[Ҷ[FlZET[ cddDL2U*zoo9T"5{~g}ν;hIT1?;Zw=:r8I$)J2J CIÇ}VQ\F2Ie9EAi(銲$LפwCdq6EL9YN4%%CQ6AelUUҶ/we(|( +oJq`JJAfpܮ;Uݡ;UuV=G^CxwY'ܺq1&*2SŨ +D}_h!M:GDX镇[v `Je9'/%kMt8M;9PA8~BO)]? ~lO9ۏq8މ&Ǿ n<, LˊskY,oX3xwq5{ $?lgmu.lm, 2EvNt"~T׿.MD7t*iM)Ld*Ҵ#(Qfl9v{ݞgzjr$ZޒBY.PU״|]ϳr=C? 'G`¨w"j.{0s6)+\1,VU )LL@mUe,^-RI*մ޽+*v|w%'RRܩwr;)ѝNH!b"$TWJ +{c|3<7MZ=fLE@@ Vk36I\aDbUun*Qw"g, k0kմajOo#x3>ΕJLpƸ"ݑpȈ؇Ƹ\I8GyN^5lX1вBt~<9ma;0/g Ö"-wZђ׳4f"ٳp6[^EVkRx'}DZX\ѮWx;<"y};<ƾ46Yt|cw߹%KZ@4~g-#[[U3I9Id9r( +p$̂(E٫TԴY@ӊzYJ$rٳ-rFE0Qwh{-StŠ"? + a錏sFE4/ZT?{VС%Tfgyx쓚vTaف1T +s*jEb,o-HSQvDN`=Ζ6\=j忼X㊉v] +Yj Yr%t͕5bѷ7.]XL+6Ʊl忼Z=j ,fD7xB׏`ڃeEوIŒQD>da;Uu2ig,ʲrmBj-#xu +6na5ݫW1YuiՕ5ۍob 76ךRc[Whx#Rj-ĭeQ0 CWf[2ۓU_rl|HK,A.ϙ8ё!U+]+ݫژV_WVn}6\.xm3:sTeYm^ w Y,oHYf{m^ŽzUS7ٖ%ծ]+W.w/o ^ +r`vt%?[ѧ5z!!W.iH5u!oW]YU'X*zI/|s׮oq3-m3xno\~\5ՎK_|-zY +u=Wcj"(_UণF(:i4GDyv{Z5nAk*S_˽`ү8~\5dUj=\j)Wl08i:F(lupY&\U=EVn1/[W-oKWK\_-q}j#DKWK_-iͶ|e݌Pv<@W:jO$)+ u ozuŲ֥_9,v3}Aj#$nŮ,;m]Ue AW_bWj" Ϥ1)^7s){&\z:Ӻd\?gZ۠;B;r-m.gK9郹գGX436 ]?k|q,Kiÿ́6/Z-tBE} DwJwݺh4/ߖJRʊP g GۣcP ^hJ-SO6/Zr8?'ϘwN鮝-p|/>d)j^{+6"Nuq$&JRܲBE-յZֲh[?й#\/{':>e–/>>T׼\LVڭc=CE%4,X@d0A6[f4ӏo]o' r5ߺߎ|Q 0f+R\=jߡ+MQ<Ŧ-e.uPӎ*U|A~AG8!], LJo|!.TU#b.4@k 86*ʶpϣӚ~ym> bqkn5/nƴR]7">n@enXG"IVд1#VSj_c{\NSǼZyܦU;RU-дَg:|TL6jJd4nӼZcBNSјy5͟{+]϶Yvf;i1ԛU]kE&0#Or+GnN6j5AbpZ[?nzƹT=p$cHDa]pL ]"Z$)vEكz.vEUH*mx;o-j5u !jy濿Ͽ7T9|h$y&btcBovuJD| Vk<3;倪Ry]ϱ +$,0/6v_h~;rX57{/r:瀪RN3/} vOa^VP팩_|IS!1\o_}vR ,+3ۖ&b`+[))A<]/ 6-1զ7^iza:$j߂'P~ +" ;WJ\T˦@4ӞbC=㙊ߌ& u%κ> :'.M}ӓꞞT]6{zҥ']d'?WUZH4aHAŠZ^ ͊:6]̤k'OV5Cs5: %%ӱjxUeG@|i +>Il +eɗM^0Q~5| +S=~5tdCSY'G=zh_ -1ܔtĐ_ -<0.=d4\/%3E޽ *6t2S>a .2(w<Ģ;2NWWQZS3d6ܾ} + +<~~cyΑm"@wN17Ͻ d&byӛ?)S^o^2\_?{__)S_E?/~ i^|۲rrMr.=GF-*_^\ pZ6tkʧmg v| +Qow? lPL1FhI44^oߋNu-[Tp4yG_z2sѦ|R㤉/=N%`/ Ĕ|ũh|0I R~R7fg2e#46ΔG:iUu H TI؁i\O߈:=o]wP}7v%D,Glʧ#МhiZp~/4哢IbĹcݬ +V/{FLuYr xFC"E'ә窟3)=|HNJAg#&_{8P<",͗sEK)ؿNYqGzHHGY,S>&{8O 7`/M` !M3^,̕'\B3E`@&lʧ"+=&_\|}^E2y?/0*\=nAlpCQ=l2`r' +Np9s"r$,e)`S0<XaԒsĦ|D'(e߭8˝M7V, K g& %`Č5A59gAɗ\t$v$X#LؔcϰM9j]cP? (6㠕]瘉gt8!%5m'/oXc/&DwPՃ(E:)1`3/ƞPJ;wպB,vPv +bS=X|zbg;a"NX:ꪋFM=(§'q\Y56`eԹsVs͢hԒ2&l"q2}3Z/9(p^&l"Y^K ;E|h!fa|anŦzD4P 4"7Iv,hcE&Lk%aŦ_4 +"+Jkt9{)7t0\lEn`Ȋ+dXH,O OMu9t^]k9(+&2a'2%ʻ5@kG^ +X$C&WDVlDc7V$:ᮂ G,>|pԦ.Y>n8'vZ3`?뜍^: o3n+w[{ nh©ж!T7␍_jBaU:2$[re"f{Є> /KHb„Zx3Dl"vxXٰaeF 3-SQvI}Hm" SLYŠb1B]pGid,rws{ cꖈƓvbv*%c{/;>7nB-H'R]u߻`Ȧn.:4c܀2Q(|K +F]xa#\CiqEyf^J`g;cM F7)XNGix.Negl- GM^X ["#L &y)Lf]/yyuқ1g"h7wXnPoD*{^:J|"6"CtJ .MjK[k%`]ܐM݀hR*ExVy!=x4D|3pkDz+yԚ1Z 1 ʦ_;pxC1q]pIx;pG{wmg҈Pgpx{Fpw) 0!)bl'p7`3 I6)֊ 19j/xCL՝|W;Z1Q66%,WT]p ǷGlw+M@L]si^VLq=x0df!pF\/+^5Qo4jMF4 +Gb [1*a8G:^qz( Gl&R],1[1, .j="EhbYK1VkG6nFLN`&HR q fO"F " 8= %{dphpI,BeZzغIj]7NYɛiŰaiኢf9+E3=z6ʝe+\1n,~tBg `H J[ݡ7(n OFM ? %1zQO$_kdawhq;de ܾ'n4z\pn>"8LLZزXIݦ YAfT MqX7@8"tK'殱ipo\#]6C'h:#i销hȝ"M6 YG"oqZ;,e/s)^&.83q듯|Ob8 +cohﱍ3򺰫kY + fN|0xXT%(3sdqB7YM 5N ֝RUaтuG W0.o=x)Y +W +iYB/JaltFuSnhOv.5Md)Dֶ+NW(J9f7~®}uZ(^ &6e KMS=oM=. phQa ^NGWi vFJN +sŨG7F]DxQN-0@4ksC{y딣Luz0ZȮq諢qLbќ9hEwdeƯڑK^KbjE6`ѱdbMvM!~=Jm%ӫL ʰ$ufO R0&8ąCM*/L p?lb +Ы Fݑ5n8ٸ~-k +S%'lbRbxfD(̊pqN }Wһ n5@=s Ortsg'={;NH? +endstream +endobj + +403 0 obj +<< + /Length 1131 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace /DeviceGray + /BitsPerComponent 8 +>> +stream +x坻OSaE $] HN DDRIGSMp$3" ,8`4|L"|综IbM"G]K{WpoW{Kj&bw]3X~[r3d;=+{ʀǙm.g.nۂL6]DL(D.&958{cZFl{˒K<"kҵpMA\ZkU1][>*UUVi;ngZYOUI 4avoɊr?@C>*ԫZRXRbgx՗6^F?z ͊R6*BEW FX(B(=`az͊*Ba2"'H~RK3*wgErGލE=Ey`a,c2 z2ō9"ܸP]9z_dKWϭW]o;{aH0ʯԇaVzq 3.}8^h Ԃ3zA~.P:6*j@FM^nsP<:N]+n +.8@Hñ^$<ȕ N_ׯ3͂Y@Jӑ^HOپGNy@ $HeZ$N:8-y&Io@)NtDZN̙ fZ,r1u+Pjڻ@MW/5Cf|L?_}|!߳+)}}ľd_op,ߟde?_`?I`8_e?f?ߧ`/yqiMau)=Q,eF?4|@MZOֵ?+'&s:_>>߂>D*o(TO4>HBBG\|.QfﲨWVs|Z}1E5g޾L|jM?5^|e|jI>b~%MJD18=7A~c{g׸g5qo"ˢ +endstream +endobj + +404 0 obj +<< + /Length 8541 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 371 0 R + /BitsPerComponent 8 + /SMask 403 0 R +>> +stream +x tSי/[ i6LҴͤIO30IN%N:iՀwU H@6cc]eI1%mY{ZϏbYtH ˺*D_$&E c>Pv\2 +Kz0}&h3}B> h45Ew"d/cE2̡mݞ9y}I?'*3GOb{M}BǑ535sHKw_Fu}(FÎu`껑\JQOQNj G_4Xb,`,7VcD.OӨRuFy"2 .+`8pENjO:FG3;Vbw_gM%X)S]>ܭ?PhqqBƫvM}}7MC|>W26XgڔcU'%YfeYmR盚v78ypi]=Уmv{;ޗNʩ#&|#HVĒl6ώK6 \aTdҕ;r4E\WMcHg<ݥ$4ғNddQùD X&\^ejH3+R͊4Kc ejbK^Ԫ̰1ͬxEj _,9n +ٓ|%nB=fӇoS:3޽wRۦ"h葂^kl"ܐlnH(R,Tkc1 5DOeP +Sp&E:ߘ>{Y|<'+[FJei%jf|UahX?dr"6ZR&"C4Fn<} \eߘ anaiH4$[T)ƔQ2eT:W+inavn*/ɦq F YijM PAZHG b\M&=/CԶ#0X7RuDK}a ц +T a1`K}܅<Ԑ7K~6lxoC)&CY.b;r5G8="ܶh{!t%]|LzHѶYD[YyYoK'XQ IA‚%Xv\k8ߺ=ɢF&P4(P8(W[{U pǒ +;ɗ)7l!\G\7_ dkc,XK]o0+Y;p|y"\oTX*-@kUН!YkKEԡT̗r$wp6k,(T!F]FY Vs\gT[,w;;tn+Ο+>?7 Ϋ]!n. aL,603xBefYṙ/l>#RΔ|,|Wsg ~LW']M16u™ +GBp3|d'3Gse>|\\m>mmm)6 d*K#53gCb)Ykr nbЭgY/ ҍ(K$K7nzq?[.o)\<¶;v7Dƒ |'_tvUi2pv=tv=_/4l}&[86xϵn\QzlL}{h5W?/^c*0xAk%9T)ghƢڷbK qCD%튓.7xb wƃ?Ttd.^-*VWpg<'h'YK܈۾ u޶hBeO-3~TT|f +tu2hK7t8W2D*fY#Wp'𧖘N-O-5^j>$i|LihKKW`5 J 0qb9YD{1ɥ܉WO +:I҄%$;R`G,Ji"Z7.gAyg wO+T4ab: +V;g_ ț AK3HlWf l%?rte> =8ZhaLiulO_^{;㱗c;$ݜT7{I/ZH|Z6223[{ñ??};[r~'&b =P%h] ~pb3Ao*ผhoLm%:?g%5o[$Cɕ$ҝ{-2|g?^h, PP[$i +d.isi y =){X3Uӆ6|oto}f'ۣFD651'id0gȻ>xJS&AXmO`4!$ A.h}4n8S{k'u?g$M'u=}g{n" R}d@6kxB't'$M~JY}BD_Jj9tDYK%j;ǴE](;i`D-D"Z̚o[$zWmgDwC{Kda5<4xS4`1ڭpc 4oo +#~=Gῒ&M#~9GdszSvNbͷ#|oX8"iҥ=?^d+wcŝsw?5o=y{#%M4o}O#o}p8BcD;ıT66_3۟1{pς7ּȾ4ҼYП1`% c(gpCySTj Pּdr<6]7dBC{ }Pw@ҔڻZ0h-);_;ߝ7m@wvfσ=%MMѽӁ/35> xѽ̿ohC)̿/}6X +dLdȿ]In}%_$ q#쿲=Hr }?۽`$+ylxƓ+d9o ށ{%MD2u|qƯ-fRei%푤s;K.'^ټ{ȹW({zeg\MXc\{$@TК-6Z]Hw>ټ̻)ɭԟywl^wLȐoKlB6{%|DzRfe5y@Ku\N:HW hbIn({)`uFP ՛n'O-#bX#\6@*XmapSDKrC|$k~vCJn& '6buF9XX3>\efzn=)[g+:]!u|qb|rOaV -#ZlaIn(f^ 33 +Gh6bI|/_7 dU^DEhMpqGw)+F{>Y| Eʍ->H +[],ɭ\м3rlpa$xBy۔%uCyopVZo*] *_Oj6-яIK0i %Ig$E.FKMg$`j d@WPȖzέ#^n QUi +" K|ݙ/u S-:,l-nn %" Kr+y;м!Lj%s.sЂ}lm>BG|BD;#O+iju1Z .ss.uD9XSZ*y\*PZ/(~:Qk拈֌( +%M\n.ᖭ%pQ%+914bq+QBM_ɪ.{[uh襫U7A_@c,bU@y囄{3WAvzWәtZk7;[b/KX@UY4SYy݀X#pti j We BN\Z?`ܒ\-뼡UP5PI{z)ZFή$֐ +XE6D"JTT~D- +E-PƺMPjOR|v%|2^Jμ. \Gj(zoվS_YCQJ(饓ͷh)^NJVzRa|S]w[F݄rsP7b;vnΔ,+NϘX^'2:f$_@j7ڍゲ$1Fmk7 +Ýr +A-F\ɞLcwD,nǒVpM.[-l6;Psņd=heb:!fCSViȊ3Gܒ._D\BYV#;XMPtոpݍ%'q;YNo?{VpA_\'7UuX\)fAR Vi%nx†cQ +ie=ݙYGf{dډ),v[dp)_xƓL܅p/^0YmYqUndv^-n<](;VYjqnQjl5_6WZ5.WLm* esmɗ ]{¸ven{l3b2,;R1_Fd)#ehƦH' -]7w_6w9%.AIʘfXaiBCrr-|Lt +c +#+l-]}X.^Gm b_Z6wrR$i4kj[)S) z{5rUrz )ZJ_'gRz Xe\KYS56!q*>V^# +i=Flka1k`aea+aůO/9Sed99k1kO;CigJVa a1e`mgW",%$]ډr"5QRǁuѭ+]`eN/r{ N J(|'BրXǒ߱,"fq}bd4(&pvU{|գW"k͈xbW"GD,Nhߛ.Oeb3a2=œN>__!sk< +endstream +endobj + +405 0 obj +<< + /Length 1131 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace /DeviceGray + /BitsPerComponent 8 +>> +stream +x坻OSaE $] HN DDRIGSMp$3" ,8`4|L"|综IbM"G]K{WpoW{Kj&bw]3X~[r3d;=+{ʀǙm.g.nۂL6]DL(D.&958{cZFl{˒K<"kҵpMA\ZkU1][>*UUVi;ngZYOUI 4avoɊr?@C>*ԫZRXRbgx՗6^F?z ͊R6*BEW FX(B(=`az͊*Ba2"'H~RK3*wgErGލE=Ey`a,c2 z2ō9"ܸP]9z_dKWϭW]o;{aH0ʯԇaVzq 3.}8^h Ԃ3zA~.P:6*j@FM^nsP<:N]+n +.8@Hñ^$<ȕ N_ׯ3͂Y@Jӑ^HOپGNy@ $HeZ$N:8-y&Io@)NtDZN̙ fZ,r1u+Pjڻ@MW/5Cf|L?_}|!߳+)}}ľd_op,ߟde?_`?I`8_e?f?ߧ`/yqiMau)=Q,eF?4|@MZOֵ?+'&s:_>>߂>D*o(TO4>HBBG\|.QfﲨWVs|Z}1E5g޾L|jM?5^|e|jI>b~%MJD18=7A~c{g׸g5qo"ˢ +endstream +endobj + +406 0 obj +<< + /Length 10539 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 371 0 R + /BitsPerComponent 8 + /SMask 405 0 R +>> +stream +x ty +=!ɡPMJ 9I !!@X!/-y-e˶/v3sݙ,d9#K~[ET/A5RuNϭaa>zɰ~;L:ewg{{C=u.eÌ5#ak7kUJFK5ctՎMoƊ-nF|aB ^㤺R}.0IjlCOI MԯP;'dn!{ +z0Yj"5NKMӥ晐md-5ϖH<뛦}}"n>wEqR݄n@f[J-$|ɾ@r,$ȱDr."e_,[ y͸u<)Z]bwuɕ&K Suԁ't-\%wɗ<+$oP|BMxW +$O]q)p_$p)אSJkVOgKp1ᛮeDD$|5ֳ̿,"mdM7"([v\ + pqw۱k©kǓGA[|·zKP4L"3%xJ:SJe$7"Xd;`ѝ],vx{h7Y/&'G뫶{ [| <1S\nam,݀a{Y>~.Tb&$^Co݋vqS gQm6ܙ(a54BxAT9 oձxܤOCۇxA $^HTKWyv3x b +o՝Ƕ/gAVPy6|VN";[J AXxvU#fďmדu/$~j(rMN=3Yǐwf7#㛞N44 oqOO&"-%~{!qc/;8no85nн΋-j0ohyDx.zR5UH c{(9R^Rx#7uÈ CxlZ,OB,M"/VԷ~"Jd}ef݆ukOXa/ydë)krD?ALTJ0W M“լ"[7&"`Le}wZ3=횜N68Dգ;: wA{3_ǼDeꚧS _XĨJyh!yHXEDV5IJe"jhcQW HdIT"2r~Ejj#ϥQq@lի%z mh7dʶI7qEY}CGTR|?gI7:8e#oұs^q pk zT\TSZ$6J%(e,uU}Ox!E?3)F#aR5{O'?^M?YP] 򯣊k N|e Y Jet 2.Jr~$cCvxQwy=~"k׏",ix]G0c#]H8FCU' ^:KPMa +},bs4L wԐ+5O7&nt72η۪M| +e,hTt77%\zQxېK)U+\]K &GY2'U|KvzP?ZP11z7y |+UL23^,-E_|F_!F~GFv*UyS7/ބ ^ S7Nq]jǜtp0+GkJeת55BZuo`F6~HZvX`6[wOOaryP~__p+<|E  +Y";q`"/T7&;^N<,11 -8!\ `) g-u8` 1[^R\P?~H -u0Kea%3 tսB[FS,.d6Үkۉ#?Oe^V??z0N*^4 }S@|f;iTN#̑av=yFMÜw;@҅KΫ[]u|_}/soRH%F^˼bn9;qx&O41jpl\2'r2O(pw{JcrwUw3OdN$Z:&j4Ԣc>.\"_AF٨PZڟgYWkb% WIYLZQz+,_(_"gҜ9_ +n4eN.7}pokC^K,$wRMȜ=YA4(foCW5Ns%RU"{ǘ\b&wڟTlOu>n^cNj<] m>f^}ZU2UwM-st% z;ՖTݑ, 60 aT?4M.rޖ985+ykWlOǸk5 + a[?rTc .Bibً;g2 +ZwR=LmrUc(w$,]1QېɅ[wy5 0gVdeZzl>h5*͏rW5!+)22|Ui~TW/,bk]lVIԫ}^J@-=oRYse¥@o:8KHwgMF[ɗp2m7,[=Pij"Is+M_8"[Xp3fg+bi|ͨ_-skUY<6Q9(-)T439mp0U* _P-i4iHXoyHm~Xi\u+&b(Qջ `k뵲4>ț[ZjKWQv=,J,3\]S$ɽDc!gJ=jxZ n骋,ϛPޓ94q!z "DgQp^38sAjZ n骋,mW>rҧh)u9<i-$.< ̓ԆɧnGUt6DDیp1֘M3IwCpkaoOZ,]#y}j QE1 :IPT1O,YD,q+|RRjRMh6Rk$?oGmOK>)+I&X y*$L eQc{RYx7o[k[ݭXFo7ޭ}V%]i\˰#L]dwF T9Aa,F_Mwi$k*R?+WNB F4 H3 +UP?ÛԚ-;(.ZQknO| S<`Mlf͑=jIZ5XcZJ C C6{oZb[XneZ`G+-3+z=m~Zx`h`Fk!YJ)l[fo|˺鬝s!Ial+g_?)>gg_k&[Sn߅=l?|eSm=X6#>[|'ߎ=vlŷ=s뻾,o9+0';pNF^: ĖjF[ dmaaO:f־ +`)o{ +26G}͓Bk&|U߾ͷ +2tV,AKŷ+_o|J8d:Qn?|˻oD7jv%3%ɻT +sKV[|jo)*u\lɳX +Hk:A>d*) ԧT4nTV m@!:f>Kr/+YDvD KI>r^Qg:f##K,u`}t>!]|-\]|,V3r4B +^&(og=,)(ҸkjT9<X|C̻o-/Rff'[%^Z Yx-,Ul!p{&'ߵ̟OikUJfCt)f +8D-8behfMsADmaYK.̅ ]ހ"S!7}:wVd= >ܞLrgCt1}%1'ɱ^C[J%Jc'`^k^w͗|Aκ5_켦ʹso<4I0h)_8,*suͣ'נ_n{Yˈ*+E6 KWJdmOI +#uhXc ED +Uea~wwk$L]Eed^se̻|…,:[e GRaqk^.ULk+fXk:Ӓ9^-:"Y(+nU8]4*'GYWylR[Թ h"pʳlz&K,1.Y~:Ym0m,b)" g i˅f42~h-Egwfǡ,0e8* +)JW%I=~t`7G.+䱣t 0DדXl& 0|Ò\@x6[ .5J"[\2n*ωϽଚ .՚pZ].k!| مl^ ,:!R:oAY4]،:KΛ9 +'4 +2@Vȳ6 װMS%ȅ(}̏(Jau@<ٝ0^ɢX[*A9Z:X[?-aP +7s#f Ĵ')[  LIe.?\hcXBbQθ- ph¼0u6=](QuZr-W{fTaRv{ab=2@dWQނGPK⋆KY.IYr/E-ὢpQh-1-, 1MqRoXs+`F.+<_BȧDule],@\f +᳔-aa+=,vlvavE+"wRć Y/? +!m#{1.Z %R)TY{1{P顜>a/-g^0IۋaP/pIŒ Sն5^rKg3-\e be0`7xq陽zn)L3p/Хj  z1ris{̓y9_b)U Β ć*F‘1-7hJd9Jw7L׾f f.^sqČxKg#h6p#Y} Nw~9d1V\ipE50Nj7ύ|m_q1{‹Krb3cp`(G`Lb=,`>O|uīXLheJ,*.oG6-{Ȕ,]0Q{1% +*aþ׿i*du};Yұif.DkYdzLNA;aM0TF3 ط.e% ,mmDiÑbn(w_ -6m#L^ shK%,Vb6V:^9d##Ñp>l7-#l+S{a0H[Z C /f) *ֺ^l.1b#WC=VK7brz%[/e~P:c5թ41e3~M[%u)Lԯxd5mQWpp(,! +ȔmQJQܺF@L^>o`)P0E + t9.rd J_|f9Պ rX~0 _(bt ebiׂҫ3:{iVj|zQ:Y +ȝ[mc,lrr<)`1E%|yڇ( XkfU^Iu` +QIV4>2>jlgEնˌ`_|TZR\ 9h2젳/xcŹFaa EXZ .>+)ֱ"Sޅ-=h ΥGg糰>O-S1V{:Y*,-m7ߠPMBV%At©~mtg㞅EiGLA8pXLvd> + 髻vV-=,mx^ͅpER7_i4UJ TXXVK947O(RNOhĎ..5te% TT]JAX`Mltۺ)ԣŷw|G'%ܹuuFw"Mgqc&&TB\"韁?)!,1h@ᧂ.(7ս7v]o=YWsһf:Y\.J}i/~pOq8\6˴Vd@dp]Gjé75 +msIpW4o-FWS^8Z|/oV@nn88A׵& %huљF +|*⛍߬^Ha|k :@zCϘ2*r` {@g^`Bl_w +endstream +endobj + +407 0 obj +<< + /Length 1539 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace /DeviceGray + /BitsPerComponent 8 +>> +stream +x͝Oef"JPHK"rW3Q5ʦ8,M卜m2SW^S"]X"x:xo#z>}4/pIs/^byyƍҕjgAٍچGxJӃ͓Þ;ĴZ zLX4k0oCfd9:pD'c|_p +X%߮ꡔ6": U.22Tc-HnkЄG?$h6^Q h:2A[;wN@SwkOڗXSz ^^T.vh^z} +| ^-W_\/Q#}GoqUn, vn~v4=fS `H6@II0MSn֟<~`IM$oOx)W)ͭ?S3r%7lJ-bB||I%6&IDI`LagZ T@;1lWM|NaxYV8Y\76rfNȸd>XS)_T5U+ˌΨLk^֜֜x)TuN޸5LfH8تHĤ(9h c 4gFJ;A% QDd[ʺk|W]o@Jk~KH5qfkQ6(Xb8,9V +/8n)<ȹBE#ͮ>lP;Q u^좤"vm?M&=8 +M8=;wciA >E8oԌtGmwE+LJ\0hf#å"r7~DǺ#|AjzD3ĞOl=[ Oz8;oz# +.g}_s%ňi6.y*?(](z{#el:GF(qZ*2;1vt[lB imSf2'ɀs9Cߒ5=\qUHj¤S/jGo?ԍvt GnQ<6]S4~S;|ѣzبc*Fv7\:|o33ƀEj +B'5mE +çⴗGegfN6_>/_ѩ-4]^-6\{٭tWJ0N]UXulH%+nԁcL)r_Tỷi#ndz +endstream +endobj + +408 0 obj +<< + /Length 1344 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 371 0 R + /BitsPerComponent 8 + /SMask 407 0 R +>> +stream +xr8Elf5[øR]cl3 =DȘ||lXMߦ{'SSpi28m;>pǶm9c4o\7MӴ,KEQeJ4M0xn80}4rQJeYE²,4{\\)ucL!TJ5M3 ~> C4J))16Y48NEQt]m_O6늢qgdaH)n3WqnL]eEQT8z߿b:4q˲1FZkBq,n*}1YuY9Cc]ky>5}vu]Z'u]%u[ :Ì㨔r]*mgJOWyl6V_t63M3Ii%3-O6I2|߯B3t:Ѧmn < t˨nɞu=mom}uytJzx l$Sp8p޸eeYۋp8!aaZ ڶyzm)qL}ǫFN{}߷jB+5FL4Mk۶i]*Huii·WjL($IV4H)e۶+&mJ)pÐ\F pŴL_6qy莩,*Rwg*u\r4BߪsR.ˢCeYE]ueZ>Y@R0*&}JBo,ˊaVEQdYaa*tcRa0 i93ֶGLR|Rޜt:ebI|iY$Iei.Qy$yB0 Y| K)4M-4Rr15/Q -LDZ-lyt,x3)y˗Q~]^1=ZqLOxEiEQDQikeYaA{Eŷ,k I:hbpcA}_X8mw۞`^?>>6𥻊 _`8z +endstream +endobj + +409 0 obj +<< + /Creator (Typst 0.14.2) + /ModDate (D:20260608130340+03'00) + /CreationDate (D:20260608130340+03'00) +>> +endobj + +410 0 obj +<< + /Length 999 + /Type /Metadata + /Subtype /XML +>> +stream +Typst 0.14.2en-US2026-06-08T13:03:40+03:002026-06-08T13:03:40+03:006application/pdfN87Qy7kU35qwV1OlvKlCOg==N87Qy7kU35qwV1OlvKlCOg==proof1.7 +endstream +endobj + +411 0 obj +<< + /Type /Catalog + /Pages 1 0 R + /Metadata 410 0 R + /PageLabels 14 0 R + /Lang (en-US) + /StructTreeRoot 15 0 R + /MarkInfo << + /Marked true + /Suspects false + >> + /ViewerPreferences << + /Direction /L2R + >> + /Outlines 2 0 R +>> +endobj + +xref +0 412 +0000000000 65535 f +0000000016 00000 n +0000000122 00000 n +0000000202 00000 n +0000000458 00000 n +0000000558 00000 n +0000000679 00000 n +0000000839 00000 n +0000001071 00000 n +0000001353 00000 n +0000001584 00000 n +0000001933 00000 n +0000002079 00000 n +0000002198 00000 n +0000002307 00000 n +0000002400 00000 n +0000003023 00000 n +0000003962 00000 n +0000004877 00000 n +0000005190 00000 n +0000005216 00000 n +0000006019 00000 n +0000006164 00000 n +0000006507 00000 n +0000006649 00000 n +0000006739 00000 n +0000006829 00000 n +0000006919 00000 n +0000007008 00000 n +0000007097 00000 n +0000007219 00000 n +0000007314 00000 n +0000007405 00000 n +0000007536 00000 n +0000007624 00000 n +0000007747 00000 n +0000007853 00000 n +0000007995 00000 n +0000008137 00000 n +0000008279 00000 n +0000008456 00000 n +0000008597 00000 n +0000008703 00000 n +0000008844 00000 n +0000008985 00000 n +0000009129 00000 n +0000009306 00000 n +0000009407 00000 n +0000009487 00000 n +0000009579 00000 n +0000009671 00000 n +0000009812 00000 n +0000009918 00000 n +0000010059 00000 n +0000010200 00000 n +0000010341 00000 n +0000010495 00000 n +0000010596 00000 n +0000010737 00000 n +0000010843 00000 n +0000010984 00000 n +0000011125 00000 n +0000011266 00000 n +0000011426 00000 n +0000011533 00000 n +0000011674 00000 n +0000011780 00000 n +0000011921 00000 n +0000012062 00000 n +0000012218 00000 n +0000012375 00000 n +0000012473 00000 n +0000012614 00000 n +0000012720 00000 n +0000012864 00000 n +0000013005 00000 n +0000013146 00000 n +0000013312 00000 n +0000013422 00000 n +0000013563 00000 n +0000013669 00000 n +0000013936 00000 n +0000014206 00000 n +0000014470 00000 n +0000014750 00000 n +0000014847 00000 n +0000015110 00000 n +0000015191 00000 n +0000015297 00000 n +0000015586 00000 n +0000015875 00000 n +0000016164 00000 n +0000016453 00000 n +0000016742 00000 n +0000016859 00000 n +0000016948 00000 n +0000017085 00000 n +0000017186 00000 n +0000017317 00000 n +0000017409 00000 n +0000017550 00000 n +0000017692 00000 n +0000017834 00000 n +0000017938 00000 n +0000018072 00000 n +0000018166 00000 n +0000018309 00000 n +0000018452 00000 n +0000018595 00000 n +0000018699 00000 n +0000018842 00000 n +0000018985 00000 n +0000019128 00000 n +0000019271 00000 n +0000019375 00000 n +0000019518 00000 n +0000019661 00000 n +0000019804 00000 n +0000019947 00000 n +0000020051 00000 n +0000020185 00000 n +0000020279 00000 n +0000020422 00000 n +0000020565 00000 n +0000020708 00000 n +0000020812 00000 n +0000020955 00000 n +0000021098 00000 n +0000021241 00000 n +0000021384 00000 n +0000021488 00000 n +0000021631 00000 n +0000021774 00000 n +0000021917 00000 n +0000022059 00000 n +0000022163 00000 n +0000022428 00000 n +0000022693 00000 n +0000022958 00000 n +0000023223 00000 n +0000023306 00000 n +0000023411 00000 n +0000023702 00000 n +0000023993 00000 n +0000024284 00000 n +0000024575 00000 n +0000024721 00000 n +0000024858 00000 n +0000024953 00000 n +0000025036 00000 n +0000025131 00000 n +0000025226 00000 n +0000025309 00000 n +0000025404 00000 n +0000025499 00000 n +0000025869 00000 n +0000026025 00000 n +0000026117 00000 n +0000026209 00000 n +0000026301 00000 n +0000026393 00000 n +0000026485 00000 n +0000026579 00000 n +0000026719 00000 n +0000026811 00000 n +0000026903 00000 n +0000026995 00000 n +0000027087 00000 n +0000027181 00000 n +0000027329 00000 n +0000027426 00000 n +0000027526 00000 n +0000027616 00000 n +0000027710 00000 n +0000027793 00000 n +0000027887 00000 n +0000027981 00000 n +0000028217 00000 n +0000028308 00000 n +0000028400 00000 n +0000028505 00000 n +0000028648 00000 n +0000028791 00000 n +0000028934 00000 n +0000029077 00000 n +0000029182 00000 n +0000029448 00000 n +0000029714 00000 n +0000029980 00000 n +0000030246 00000 n +0000030330 00000 n +0000030435 00000 n +0000030727 00000 n +0000031019 00000 n +0000031311 00000 n +0000031603 00000 n +0000031713 00000 n +0000031803 00000 n +0000031897 00000 n +0000032083 00000 n +0000032180 00000 n +0000032270 00000 n +0000032353 00000 n +0000032447 00000 n +0000032541 00000 n +0000032624 00000 n +0000032718 00000 n +0000032810 00000 n +0000032902 00000 n +0000032996 00000 n +0000033079 00000 n +0000033173 00000 n +0000033267 00000 n +0000033366 00000 n +0000033460 00000 n +0000033559 00000 n +0000033653 00000 n +0000033749 00000 n +0000033843 00000 n +0000034131 00000 n +0000034241 00000 n +0000034335 00000 n +0000034429 00000 n +0000034540 00000 n +0000034634 00000 n +0000034727 00000 n +0000034832 00000 n +0000034923 00000 n +0000035016 00000 n +0000035266 00000 n +0000035385 00000 n +0000035518 00000 n +0000035610 00000 n +0000035726 00000 n +0000035823 00000 n +0000035967 00000 n +0000036111 00000 n +0000036267 00000 n +0000036362 00000 n +0000036459 00000 n +0000036603 00000 n +0000036737 00000 n +0000036832 00000 n +0000036966 00000 n +0000037061 00000 n +0000037158 00000 n +0000037302 00000 n +0000037446 00000 n +0000037602 00000 n +0000037697 00000 n +0000037794 00000 n +0000037942 00000 n +0000038085 00000 n +0000038250 00000 n +0000038340 00000 n +0000038434 00000 n +0000038531 00000 n +0000038800 00000 n +0000039066 00000 n +0000039343 00000 n +0000039437 00000 n +0000039521 00000 n +0000039618 00000 n +0000039910 00000 n +0000040202 00000 n +0000040494 00000 n +0000040582 00000 n +0000040706 00000 n +0000040841 00000 n +0000040938 00000 n +0000041032 00000 n +0000041126 00000 n +0000041220 00000 n +0000041311 00000 n +0000041427 00000 n +0000041524 00000 n +0000041673 00000 n +0000041838 00000 n +0000041932 00000 n +0000042026 00000 n +0000042160 00000 n +0000042254 00000 n +0000042351 00000 n +0000042513 00000 n +0000042613 00000 n +0000042710 00000 n +0000042869 00000 n +0000042969 00000 n +0000043063 00000 n +0000043197 00000 n +0000043291 00000 n +0000043388 00000 n +0000043537 00000 n +0000043699 00000 n +0000043793 00000 n +0000043887 00000 n +0000044021 00000 n +0000044115 00000 n +0000044212 00000 n +0000044361 00000 n +0000044526 00000 n +0000044620 00000 n +0000044714 00000 n +0000044848 00000 n +0000044942 00000 n +0000045039 00000 n +0000045311 00000 n +0000045596 00000 n +0000045693 00000 n +0000045787 00000 n +0000046044 00000 n +0000046138 00000 n +0000046222 00000 n +0000046319 00000 n +0000046611 00000 n +0000046903 00000 n +0000047195 00000 n +0000047300 00000 n +0000047394 00000 n +0000047511 00000 n +0000047663 00000 n +0000047757 00000 n +0000047851 00000 n +0000047944 00000 n +0000048035 00000 n +0000048128 00000 n +0000048221 00000 n +0000048465 00000 n +0000048524 00000 n +0000048583 00000 n +0000048642 00000 n +0000048701 00000 n +0000048760 00000 n +0000048819 00000 n +0000049001 00000 n +0000049852 00000 n +0000049943 00000 n +0000050196 00000 n +0000051830 00000 n +0000059308 00000 n +0000059493 00000 n +0000060568 00000 n +0000060657 00000 n +0000060914 00000 n +0000062836 00000 n +0000072417 00000 n +0000072582 00000 n +0000072850 00000 n +0000072941 00000 n +0000073218 00000 n +0000074732 00000 n +0000085320 00000 n +0000085504 00000 n +0000085941 00000 n +0000086030 00000 n +0000086287 00000 n +0000087272 00000 n +0000090655 00000 n +0000090756 00000 n +0000090857 00000 n +0000090958 00000 n +0000091059 00000 n +0000091319 00000 n +0000091902 00000 n +0000092644 00000 n +0000092814 00000 n +0000093087 00000 n +0000093177 00000 n +0000093460 00000 n +0000094554 00000 n +0000101379 00000 n +0000101417 00000 n +0000101455 00000 n +0000101814 00000 n +0000102237 00000 n +0000102284 00000 n +0000102332 00000 n +0000102379 00000 n +0000102426 00000 n +0000102473 00000 n +0000102520 00000 n +0000102568 00000 n +0000102615 00000 n +0000102662 00000 n +0000102709 00000 n +0000102756 00000 n +0000103046 00000 n +0000103336 00000 n +0000103626 00000 n +0000103916 00000 n +0000104244 00000 n +0000108900 00000 n +0000109264 00000 n +0000114711 00000 n +0000115003 00000 n +0000116199 00000 n +0000116491 00000 n +0000116824 00000 n +0000117134 00000 n +0000120515 00000 n +0000120825 00000 n +0000122270 00000 n +0000123588 00000 n +0000132971 00000 n +0000134292 00000 n +0000143036 00000 n +0000144357 00000 n +0000155100 00000 n +0000156829 00000 n +0000158376 00000 n +0000158503 00000 n +0000159592 00000 n +trailer +<< + /Size 412 + /Root 411 0 R + /Info 409 0 R + /ID [(N87Qy7kU35qwV1OlvKlCOg==) (N87Qy7kU35qwV1OlvKlCOg==)] +>> +startxref +159854 +%%EOF \ No newline at end of file diff --git a/migrations/14_fleet_segment_and_vehicles_view.sql b/migrations/14_fleet_segment_and_vehicles_view.sql new file mode 100644 index 0000000..3b0a039 --- /dev/null +++ b/migrations/14_fleet_segment_and_vehicles_view.sql @@ -0,0 +1,104 @@ +-- 14_fleet_segment_and_vehicles_view.sql +-- Fleet segmentation + de-duplicated vehicle roster. +-- +-- Splits the fleet into ticket-closing FIELD SERVICE vehicles vs SPECIALIST plant +-- (cranes / pick-ups / motorbikes) that do NOT close immediate customer tickets. +-- +-- The segment is DERIVED, not stored: it is computed from tracksolid.devices.vehicle_models, +-- which is itself an authoritative Tracksolid API field (sync_devices() maps +-- jimi.user.device.list -> vehicleModels, refreshed daily). Keeping it derived means it +-- always tracks the API and needs no re-seeding. The manual tracksolid.vehicle_category +-- column is intentionally NOT used here. +-- +-- reporting.v_vehicles collapses the GPS-tracker + dashcam device pairs into one row per +-- vehicle, reusing reporting.normalize_plate() and the same "primary device per normalized +-- plate" precedence as reporting.v_trips / reporting.v_live_positions (migration 11). This +-- auto-merges plate-spacing duplicates (e.g. 'KDS 453Y' vs 'KDS 453 Y') and resolves any +-- within-plate model disagreement by letting the primary tracker's value win. +-- +-- Every object uses CREATE OR REPLACE / guarded grants so the file is safe to re-apply. +-- Provenance: docs/reports/260608_fleet_registry_data_quality.md + ~/.claude plan binary-singing-wave. + +SET search_path = tracksolid, reporting, public; + +-- ── classification rule (single source of truth) ───────────────────────────── +CREATE OR REPLACE FUNCTION reporting.fn_fleet_segment(model text) + RETURNS text + LANGUAGE sql + IMMUTABLE PARALLEL SAFE +AS $function$ + SELECT CASE lower(coalesce(trim(model), '')) + WHEN '' THEN 'unassigned' -- no model on record -> triage + WHEN 'crane' THEN 'specialist' + WHEN 'pick-up' THEN 'specialist' + WHEN 'pickup' THEN 'specialist' + WHEN 'truck' THEN 'specialist' + WHEN 'motorbike' THEN 'specialist' + ELSE 'field_service' -- Probox, Mazda, Van, Station Wagon, Vezel + any other named model + END +$function$; + +COMMENT ON FUNCTION reporting.fn_fleet_segment(text) IS + 'Maps tracksolid.devices.vehicle_models -> field_service | specialist | unassigned. ' + 'Specialist = crane/pick-up/motorbike/truck (do not close immediate customer tickets).'; + +-- ── de-duplicated vehicle roster (one row per physical vehicle) ─────────────── +CREATE OR REPLACE VIEW reporting.v_vehicles AS + WITH device_trip_counts AS ( + SELECT trips.imei, count(*) AS trip_count + FROM trips + GROUP BY trips.imei + ), primary_device AS ( + SELECT DISTINCT ON ((reporting.normalize_plate(d.vehicle_number))) + reporting.normalize_plate(d.vehicle_number) AS plate, + d.imei AS primary_imei, + d.vehicle_models, + d.driver_name, + d.driver_phone, + d.account, + d.assigned_city + FROM devices d + LEFT JOIN device_trip_counts c USING (imei) + WHERE d.vehicle_number IS NOT NULL AND d.enabled_flag = 1 + ORDER BY (reporting.normalize_plate(d.vehicle_number)), + (CASE WHEN d.mc_type = ANY (ARRAY['GT06E','X3','AT4']) THEN 0 ELSE 1 END), + (COALESCE(c.trip_count, 0::bigint)) DESC, + d.activation_time, + d.imei + ), plate_agg AS ( + SELECT reporting.normalize_plate(d.vehicle_number) AS plate, + bool_or(d.mc_type = ANY (ARRAY['GT06E','X3','AT4'])) AS has_tracker, + bool_or(d.mc_type = 'JC400P') AS has_camera, + count(*) AS device_count + FROM devices d + WHERE d.vehicle_number IS NOT NULL AND d.enabled_flag = 1 + GROUP BY reporting.normalize_plate(d.vehicle_number) + ) + SELECT pd.plate, + pd.vehicle_models AS vehicle_type, + reporting.fn_fleet_segment(pd.vehicle_models) AS fleet_segment, + pd.driver_name AS driver, + pd.driver_phone, + pd.account, + pd.assigned_city, + pa.has_tracker, + pa.has_camera, + pa.device_count, + pd.primary_imei + FROM primary_device pd + JOIN plate_agg pa USING (plate); + +COMMENT ON VIEW reporting.v_vehicles IS + 'One row per physical vehicle (tracker+dashcam pairs collapsed by normalize_plate, primary ' + 'device = tracker-first then trip-count). fleet_segment derived from API-authoritative ' + 'vehicle_models. Source: docs/reports/260608_fleet_registry_data_quality.md.'; + +-- ── grants (guarded: roles may not exist on a fresh DB) ─────────────────────── +DO $grants$ +BEGIN + IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'grafana_ro') THEN + GRANT USAGE ON SCHEMA reporting TO grafana_ro; + GRANT EXECUTE ON FUNCTION reporting.fn_fleet_segment(text) TO grafana_ro; + GRANT SELECT ON reporting.v_vehicles TO grafana_ro; + END IF; +END $grants$; diff --git a/run_migrations.py b/run_migrations.py index 578d7e4..a2a093a 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -37,6 +37,7 @@ MIGRATIONS = [ "11_reporting_schema.sql", # reporting.* map-dashboard read layer (dashboard_api) "12_drop_ops.sql", # purge dormant ops schema + dispatch_log + v_sla_inflight "13_drop_dwh_gold.sql", # purge dormant dwh_gold schema + v_utilisation_daily + "14_fleet_segment_and_vehicles_view.sql", # reporting.fn_fleet_segment + reporting.v_vehicles roster ] # ── Tables that must exist before the service is allowed to start ───────────── From 0c3209434766747508687d33e2dfb681db07b261 Mon Sep 17 00:00:00 2001 From: david kiania Date: Mon, 8 Jun 2026 14:18:30 +0300 Subject: [PATCH 29/31] feat(reporting): exclude non-operational vehicles from the live map (migration 15) Hide personal + management + mtn (Uganda/Kampala) vehicles from the live tracking map (FleetNow + liveposition SPA). Adds an ops-editable config table reporting.map_excluded_cost_centres and filters reporting.v_live_positions to drop any plate whose device(s) carry an excluded cost centre (robust to the tracker/cam cost_centre inconsistency). Scope is live-map only; reporting.v_trips (trip history) is intentionally untouched. The base view feeds reporting.fn_live_positions, so the change propagates to every live consumer with no dashboard_api redeploy or frontend change. Verified live: 80 -> 74 vehicles, all 6 targets gone (KDU 613A, KDW 781E, UMA 011EK/382EK/418EK/826AB). Co-Authored-By: Claude Opus 4.8 --- migrations/15_map_exclude_cost_centres.sql | 105 +++++++++++++++++++++ run_migrations.py | 1 + 2 files changed, 106 insertions(+) create mode 100644 migrations/15_map_exclude_cost_centres.sql diff --git a/migrations/15_map_exclude_cost_centres.sql b/migrations/15_map_exclude_cost_centres.sql new file mode 100644 index 0000000..3f138eb --- /dev/null +++ b/migrations/15_map_exclude_cost_centres.sql @@ -0,0 +1,105 @@ +-- 15_map_exclude_cost_centres.sql +-- Hide non-operational vehicles from the LIVE tracking map (FleetNow + liveposition SPA). +-- +-- A small, ops-editable config table lists the cost centres to exclude. reporting.v_live_positions +-- (the base view behind reporting.fn_live_positions, which dashboard_api serves) filters out any +-- plate whose device(s) carry an excluded cost centre. Editing the table changes the map on the +-- next query — no code change, no redeploy. +-- +-- Scope: LIVE map only. Trip history (reporting.v_trips materialised view) is deliberately NOT +-- touched. Initial exclusions: personal + management (staff/personal cars) and mtn (the MTN +-- contract / Uganda-Kampala fleet, outside Kenyan ops). +-- +-- The v_live_positions body below is reproduced verbatim from the live prod definition +-- (== migrations/11_reporting_schema.sql) with a single added filter in the primary_device CTE. +-- Safe to re-apply (CREATE TABLE IF NOT EXISTS / INSERT ON CONFLICT / CREATE OR REPLACE VIEW). + +SET search_path = tracksolid, reporting, public; + +-- ── exclusion config (data-driven, editable without a migration) ────────────── +CREATE TABLE IF NOT EXISTS reporting.map_excluded_cost_centres ( + cost_centre text PRIMARY KEY, -- compared case-insensitively (store lowercase) + note text, + added_at timestamptz NOT NULL DEFAULT now() +); + +INSERT INTO reporting.map_excluded_cost_centres (cost_centre, note) VALUES + ('personal', 'staff/personal vehicles — not operational fleet'), + ('management', 'management vehicles — not operational fleet'), + ('mtn', 'MTN contract / Uganda (Kampala) — outside Kenyan ops') +ON CONFLICT (cost_centre) DO NOTHING; + +-- ── v_live_positions: same definition + exclusion filter ────────────────────── +CREATE OR REPLACE VIEW reporting.v_live_positions AS + WITH primary_device AS ( + SELECT DISTINCT ON ((reporting.normalize_plate(d_1.vehicle_number))) reporting.normalize_plate(d_1.vehicle_number) AS vehicle_number, + d_1.imei AS primary_imei + FROM devices d_1 + LEFT JOIN live_positions lp_1 ON lp_1.imei = d_1.imei + WHERE d_1.vehicle_number IS NOT NULL AND d_1.enabled_flag = 1 + -- exclude plates whose device(s) carry a non-operational cost centre + AND reporting.normalize_plate(d_1.vehicle_number) NOT IN ( + SELECT reporting.normalize_plate(x.vehicle_number) + FROM devices x + WHERE x.vehicle_number IS NOT NULL + AND lower(trim(x.cost_centre)) IN ( + SELECT cost_centre FROM reporting.map_excluded_cost_centres) + ) + ORDER BY (reporting.normalize_plate(d_1.vehicle_number)), ( + CASE + WHEN (d_1.mc_type = ANY (ARRAY['GT06E'::text, 'X3'::text, 'AT4'::text])) AND lp_1.gps_time >= (now() - '24:00:00'::interval) THEN 0 + ELSE 1 + END), lp_1.gps_time DESC NULLS LAST, ( + CASE d_1.mc_type + WHEN 'GT06E'::text THEN 1 + WHEN 'X3'::text THEN 2 + WHEN 'AT4'::text THEN 3 + WHEN 'JC400P'::text THEN 4 + ELSE 5 + END), d_1.activation_time, d_1.imei + ) + SELECT lp.imei, + pd.vehicle_number, + d.driver_name AS assigned_driver, + d.cost_centre, + d.assigned_city, + d.vehicle_category, + d.vehicle_models, + d.mc_type, + CASE d.mc_type + WHEN 'GT06E'::text THEN 'tracker'::text + WHEN 'X3'::text THEN 'tracker'::text + WHEN 'AT4'::text THEN 'tracker'::text + WHEN 'JC400P'::text THEN 'camera'::text + ELSE 'other'::text + END AS device_kind, + lp.lat, + lp.lng, + lp.speed, + lp.direction, + lp.acc_status, + lp.device_status, + lp.gps_signal, + lp.gps_num, + lp.current_mileage, + lp.loc_desc, + lp.gps_time, + lp.updated_at, + (lp.gps_time AT TIME ZONE 'Africa/Nairobi'::text) AS gps_time_eat, + (lp.updated_at AT TIME ZONE 'Africa/Nairobi'::text) AS updated_at_eat, + round(EXTRACT(epoch FROM now() - lp.gps_time) / 3600::numeric, 2) AS source_age_hours + FROM live_positions lp + JOIN primary_device pd ON pd.primary_imei = lp.imei + JOIN devices d ON d.imei = lp.imei; + +COMMENT ON TABLE reporting.map_excluded_cost_centres IS + 'Cost centres hidden from the live map (reporting.v_live_positions). Edit to hide/restore; ' + 'effective on next query. Seeded: personal, management, mtn. See migration 15.'; + +-- ── grants (guarded: roles may not exist on a fresh DB) ─────────────────────── +DO $grants$ +BEGIN + IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'grafana_ro') THEN + GRANT SELECT ON reporting.map_excluded_cost_centres TO grafana_ro; + END IF; +END $grants$; diff --git a/run_migrations.py b/run_migrations.py index a2a093a..a56b900 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -38,6 +38,7 @@ MIGRATIONS = [ "12_drop_ops.sql", # purge dormant ops schema + dispatch_log + v_sla_inflight "13_drop_dwh_gold.sql", # purge dormant dwh_gold schema + v_utilisation_daily "14_fleet_segment_and_vehicles_view.sql", # reporting.fn_fleet_segment + reporting.v_vehicles roster + "15_map_exclude_cost_centres.sql", # hide personal/management/mtn vehicles from the live map ] # ── Tables that must exist before the service is allowed to start ───────────── From a8e1327aa81872ed6095b9f28d1de07e25d596f4 Mon Sep 17 00:00:00 2001 From: david kiania Date: Mon, 8 Jun 2026 14:33:21 +0300 Subject: [PATCH 30/31] feat(reporting): add vehicle_type + fleet_segment to live map feed (migration 16) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fn_live_positions now emits 'vehicle_type' (devices.vehicle_models) and 'fleet_segment' (reporting.fn_fleet_segment) in each GeoJSON feature so FleetNow can give specialist vehicles (Crane/Motorbike/Pick-Up) their own marker icons. Additive only — no signature change, STABLE function read immediately by dashboard_api (no redeploy). Function body reproduced verbatim from prod via pg_get_functiondef plus the two new properties. Co-Authored-By: Claude Opus 4.8 --- migrations/16_live_feed_vehicle_type.sql | 99 ++++++++++++++++++++++++ run_migrations.py | 1 + 2 files changed, 100 insertions(+) create mode 100644 migrations/16_live_feed_vehicle_type.sql diff --git a/migrations/16_live_feed_vehicle_type.sql b/migrations/16_live_feed_vehicle_type.sql new file mode 100644 index 0000000..6cc357d --- /dev/null +++ b/migrations/16_live_feed_vehicle_type.sql @@ -0,0 +1,99 @@ +-- 16_live_feed_vehicle_type.sql +-- Expose vehicle_type + fleet_segment on the live-map GeoJSON feed so FleetNow can give the +-- specialist vehicles (Crane / Motorbike / Pick-Up) their own marker icons. All other vehicles +-- (field-service + unassigned) keep their current marker — FleetNow only overrides icons when +-- vehicle_type is one of the specialist types. +-- +-- reporting.fn_live_positions is reproduced verbatim from the live prod definition +-- (== migrations/11_reporting_schema.sql, captured via pg_get_functiondef) with TWO added +-- feature properties: +-- 'vehicle_type' = devices.vehicle_models (authoritative API type, surfaced by v_live_positions) +-- 'fleet_segment' = reporting.fn_fleet_segment(vehicle_models) (field_service|specialist|unassigned) +-- No signature change, so dependents are unaffected; STABLE function, read immediately by +-- dashboard_api (no redeploy/restart). Safe to re-apply (CREATE OR REPLACE). + +SET search_path = tracksolid, reporting, public; + +CREATE OR REPLACE FUNCTION reporting.fn_live_positions(p_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text) + RETURNS jsonb + LANGUAGE plpgsql + STABLE +AS $function$ +DECLARE + v_result jsonb; +BEGIN + p_cost_centre := NULLIF(p_cost_centre, ''); + p_acc_status := NULLIF(p_acc_status, ''); + WITH filtered AS ( + SELECT * FROM reporting.v_live_positions + WHERE (p_cost_centre IS NULL OR cost_centre = p_cost_centre) + AND (p_acc_status IS NULL OR acc_status = p_acc_status) + ) + SELECT jsonb_build_object( + 'summary', jsonb_build_object( + 'vehicle_count', COUNT(*), + -- "moving" and "parked" both restrict to devices that have reported + -- within the OFFLINE_THRESHOLD (24 h) so they represent the live + -- fleet, not equipment-failure stragglers. "offline" is its own + -- counter for the > 24 h tail. + 'moving', COUNT(*) FILTER (WHERE acc_status = '1' + AND source_age_hours < 24), + 'parked', COUNT(*) FILTER (WHERE acc_status = '0' + AND source_age_hours < 24), + 'offline', COUNT(*) FILTER (WHERE source_age_hours >= 24), + 'median_speed_moving', percentile_cont(0.5) WITHIN GROUP (ORDER BY speed) + FILTER (WHERE acc_status = '1' + AND source_age_hours < 24 + AND speed > 0), + 'last_batch_at', to_char(MAX(updated_at) AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'oldest_fix_at', to_char(MIN(gps_time) AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'newest_fix_at', to_char(MAX(gps_time) AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'last_batch_utc', MAX(updated_at), + 'newest_fix_utc', MAX(gps_time) + ), + 'geojson', jsonb_build_object( + 'type', 'FeatureCollection', + 'features', COALESCE(jsonb_agg( + jsonb_build_object( + 'type', 'Feature', + 'properties', jsonb_build_object( + 'imei', imei, + 'vehicle_number', vehicle_number, + 'driver', assigned_driver, + 'cost_centre', cost_centre, + 'assigned_city', assigned_city, + 'vehicle_category', vehicle_category, + 'vehicle_type', vehicle_models, + 'fleet_segment', reporting.fn_fleet_segment(vehicle_models), + 'mc_type', mc_type, + 'device_kind', device_kind, + 'source_age_hours', source_age_hours, + 'speed', speed, + 'direction', direction, + 'acc_status', acc_status, + 'device_status', device_status, + 'gps_signal', gps_signal, + 'gps_num', gps_num, + 'current_mileage', current_mileage, + 'loc_desc', loc_desc, + 'gps_time', to_char(gps_time AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'updated_at', to_char(updated_at AT TIME ZONE 'Africa/Nairobi', + 'YYYY-MM-DD HH24:MI:SS'), + 'gps_time_utc', gps_time, + 'updated_at_utc', updated_at + ), + 'geometry', jsonb_build_object( + 'type', 'Point', + 'coordinates', jsonb_build_array(lng, lat) + ) + ) + ), '[]'::jsonb) + ) + ) INTO v_result FROM filtered; + + RETURN v_result; +END $function$; diff --git a/run_migrations.py b/run_migrations.py index a56b900..8e1e939 100644 --- a/run_migrations.py +++ b/run_migrations.py @@ -39,6 +39,7 @@ MIGRATIONS = [ "13_drop_dwh_gold.sql", # purge dormant dwh_gold schema + v_utilisation_daily "14_fleet_segment_and_vehicles_view.sql", # reporting.fn_fleet_segment + reporting.v_vehicles roster "15_map_exclude_cost_centres.sql", # hide personal/management/mtn vehicles from the live map + "16_live_feed_vehicle_type.sql", # add vehicle_type + fleet_segment to fn_live_positions feed ] # ── Tables that must exist before the service is allowed to start ───────────── From 45d764a5f11a56e0b570ccb57975f22ad58167d9 Mon Sep 17 00:00:00 2001 From: david kiania Date: Mon, 8 Jun 2026 15:42:37 +0300 Subject: [PATCH 31/31] docs: add FleetNow stakeholder briefings (directors + heads of department) Two audience-tailored one-pagers (md + matching PDF) making the case for the merged live+historical platform, plus a shared demo/talking-points script. Co-Authored-By: Claude Opus 4.8 --- docs/briefings/fleetnow_briefing_directors.md | 74 + .../briefings/fleetnow_briefing_directors.pdf | 3447 +++++++++++++++++ .../fleetnow_briefing_heads_of_department.md | 69 + .../fleetnow_briefing_heads_of_department.pdf | 3017 +++++++++++++++ 4 files changed, 6607 insertions(+) create mode 100644 docs/briefings/fleetnow_briefing_directors.md create mode 100644 docs/briefings/fleetnow_briefing_directors.pdf create mode 100644 docs/briefings/fleetnow_briefing_heads_of_department.md create mode 100644 docs/briefings/fleetnow_briefing_heads_of_department.pdf diff --git a/docs/briefings/fleetnow_briefing_directors.md b/docs/briefings/fleetnow_briefing_directors.md new file mode 100644 index 0000000..0e7d2fe --- /dev/null +++ b/docs/briefings/fleetnow_briefing_directors.md @@ -0,0 +1,74 @@ +# FleetNow — One Fleet, One Screen +### Bringing live tracking and trip history together into a single intelligence platform + +*Audience: Senior Directors · Prepared 2026-06-08* + +--- + +## The big idea +The legacy setup answered two questions in two different places: *"Where is the fleet right now?"* on one dashboard, and *"Where has it been?"* on another. **FleetNow merges them into a single live map** — so the moment you see a vehicle, its full history is one click away. No switching tools, no reconciling two screens, no losing the thread. + +> **"Where is it now"** and **"where has it been"** — finally answered in the same place, at the same time. + +## Why one platform beats two + +| | Legacy: two separate dashboards | **FleetNow: unified platform** | +|---|---|---| +| **Workflow** | Toggle between live + history tools, rebuild context each time | One screen, one flow — live and history side by side | +| **Decisions** | Piece the story together across tabs | Dispatch, investigate, and review in a single view | +| **Filters** | Set them twice, hope they match | One filter (city, cost centre, vehicle) applies everywhere | +| **Data trust** | Two sources that can quietly disagree | One source of truth — live and historical always agree | +| **Onboarding** | Learn two tools | Learn one — faster for new staff | +| **Upkeep** | Two apps to maintain | One platform, lower cost and risk | + +**The headline:** merging live + historical isn't just tidier — it's *faster decisions, fewer errors, and a single trusted picture of the fleet.* + +## What's new and powerful + +**🗺️ A living operations map** +- Real-time vehicle positions refreshed continuously, with movement, idle, and offline states colour-coded at a glance. +- Click any vehicle to drop straight into its trip history — routes, stops, distances, timing. + +**🎨 Instant visual read of the fleet** +- **Colour-coordinated by department** (ISP, OSP, FDS…) — spot how each team is deployed across the city in a single glance, with a one-tap colour key. +- **Distinct icons for specialist assets** — cranes, motorbikes, and pick-ups stand out from the field-service fleet, so the vehicles that close customer tickets are never confused with heavy/infrastructure units. + +**🎯 Built for *your* operation, not a generic tracker** +- The map shows the **operational fleet only** — personal, management, and out-of-region vehicles are filtered out, so leaders see what actually matters to service delivery. +- Tracker + dashcam are intelligently paired into **one vehicle**, so counts and lists reflect reality (not double-counted devices). + +**📊 One source of truth, automatically current** +- Vehicle types, drivers, and assignments flow straight from the source system — the platform stays accurate without manual upkeep. +- The same trusted data powers the live map, trip history, and management analytics. + +## What this means for the business +- **Faster, better decisions** — dispatch and respond from a single, current view. +- **Real accountability** — every trip tied to a vehicle, driver, and department. +- **Clarity for leadership** — see fleet activity by team and city at a glance. +- **Lower cost & risk** — one platform to run and train on, not several. +- **A foundation to build on** — utilisation, SLA, and cost insights plug into the same trusted base. + +## Where we're headed +FleetNow is a living platform. On the near-term roadmap: always-on visibility of specialist assets, richer per-department analytics, and deeper KPI dashboards for service performance — all on the same single, trusted foundation. + +> **From two disconnected dashboards to one intelligent platform — that's the leap.** + +--- + +## Demo flow & talking points + +**The one-line message:** *"We merged live tracking and trip history into one intelligent platform — one screen, one source of truth, purpose-built for our field-service fleet."* + +**Live demo (≈3–4 minutes):** +1. **Open the live map** — "This is the whole operational fleet, right now, across our cities." +2. **Point out the colours** — open the **Key**: "Each department has its own colour — here's ISP, OSP, FDS at a glance." +3. **Read the states** — "Bright ones are moving now, faded are recently stopped, grey are offline — instant situational awareness." +4. **Spot a specialist** — "These icons are our cranes and motorbikes — clearly separate from the ticket-closing fleet." +5. **Click a vehicle → its trips** — "And here's the power of merging: from a live pin, straight into where this vehicle has been today, same screen." +6. **Apply a filter** — "Filter by department or city once, and it holds across both live and history." +7. **Land the close** — "One screen. One trusted source. No more switching tools." + +**Three points to repeat:** +- **One platform, not two** — faster decisions, less friction. +- **One source of truth** — live and historical can't disagree. +- **Built for us** — segmented fleet, department colours, real accountability. diff --git a/docs/briefings/fleetnow_briefing_directors.pdf b/docs/briefings/fleetnow_briefing_directors.pdf new file mode 100644 index 0000000..2484c76 --- /dev/null +++ b/docs/briefings/fleetnow_briefing_directors.pdf @@ -0,0 +1,3447 @@ +%PDF-1.7 +% + +1 0 obj +<< + /Type /Pages + /Count 2 + /Kids [181 0 R 183 0 R] +>> +endobj + +2 0 obj +<< + /Type /Outlines + /First 3 0 R + /Last 3 0 R + /Count 1 +>> +endobj + +3 0 obj +<< + /Parent 2 0 R + /First 4 0 R + /Last 10 0 R + /Count -7 + /Title + /Dest 176 0 R +>> +endobj + +4 0 obj +<< + /Parent 3 0 R + /Next 5 0 R + /Title (Bringing live tracking and trip history together into a single intelligence platform) + /Dest 169 0 R +>> +endobj + +5 0 obj +<< + /Parent 3 0 R + /Next 6 0 R + /Prev 4 0 R + /Title (The big idea) + /Dest 170 0 R +>> +endobj + +6 0 obj +<< + /Parent 3 0 R + /Next 7 0 R + /Prev 5 0 R + /Title (Why one platform beats two) + /Dest 171 0 R +>> +endobj + +7 0 obj +<< + /Parent 3 0 R + /Next 8 0 R + /Prev 6 0 R + /Title (What's new and powerful) + /Dest 172 0 R +>> +endobj + +8 0 obj +<< + /Parent 3 0 R + /Next 9 0 R + /Prev 7 0 R + /Title (What this means for the business) + /Dest 173 0 R +>> +endobj + +9 0 obj +<< + /Parent 3 0 R + /Next 10 0 R + /Prev 8 0 R + /Title (Where we're headed) + /Dest 174 0 R +>> +endobj + +10 0 obj +<< + /Parent 3 0 R + /Prev 9 0 R + /Title (Demo flow & talking points) + /Dest 175 0 R +>> +endobj + +11 0 obj +<< + /Nums [0 132 0 R 1 133 0 R] +>> +endobj + +12 0 obj +<< + /Type /StructTreeRoot + /RoleMap << + /Datetime /Span + /Terms /Part + /Title /P + /Strong /Span + /Em /Span + >> + /K [15 0 R] + /ParentTree << + /Nums [0 13 0 R 1 14 0 R] + >> + /IDTree << + /Names [(U1x0y0) 117 0 R (U1x1y0) 116 0 R (U1x2y0) 114 0 R] + >> + /ParentTreeNextKey 2 +>> +endobj + +13 0 obj +[131 0 R 130 0 R 129 0 R 127 0 R 123 0 R 126 0 R 126 0 R 123 0 R 125 0 R 123 0 R 124 0 R 124 0 R 123 0 R 123 0 R 122 0 R 120 0 R 121 0 R 120 0 R 120 0 R 118 0 R 116 0 R 116 0 R 116 0 R 115 0 R 115 0 R 115 0 R 111 0 R 109 0 R 109 0 R 109 0 R 109 0 R 108 0 R 108 0 R 106 0 R 104 0 R 104 0 R 103 0 R 103 0 R 101 0 R 99 0 R 99 0 R 98 0 R 98 0 R 96 0 R 94 0 R 94 0 R 93 0 R 93 0 R 91 0 R 89 0 R 88 0 R 88 0 R 86 0 R 84 0 R 83 0 R 83 0 R 79 0 R 77 0 R 78 0 R 78 0 R 76 0 R 75 0 R 75 0 R 74 0 R 74 0 R 74 0 R 73 0 R 73 0 R 70 0 R 72 0 R 70 0 R 70 0 R 70 0 R 71 0 R 70 0 R] +endobj + +14 0 obj +[70 0 R 70 0 R 69 0 R 69 0 R 68 0 R 66 0 R 63 0 R 65 0 R 65 0 R 63 0 R 63 0 R 64 0 R 64 0 R 63 0 R 62 0 R 62 0 R 61 0 R 61 0 R 61 0 R 60 0 R 59 0 R 58 0 R 57 0 R 55 0 R 54 0 R 53 0 R 51 0 R 50 0 R 49 0 R 47 0 R 46 0 R 45 0 R 43 0 R 42 0 R 41 0 R 41 0 R 38 0 R 37 0 R 37 0 R 37 0 R 36 0 R 34 0 R 33 0 R 31 0 R 32 0 R 32 0 R 30 0 R 21 0 R 29 0 R 21 0 R 21 0 R 28 0 R 21 0 R 27 0 R 21 0 R 21 0 R 26 0 R 21 0 R 21 0 R 21 0 R 25 0 R 21 0 R 21 0 R 24 0 R 21 0 R 21 0 R 23 0 R 21 0 R 21 0 R 22 0 R 22 0 R 21 0 R 20 0 R 16 0 R 19 0 R 16 0 R 18 0 R 18 0 R 16 0 R 17 0 R 16 0 R 16 0 R] +endobj + +15 0 obj +<< + /Type /StructElem + /S /Document + /P 12 0 R + /K [131 0 R 130 0 R 128 0 R 127 0 R 123 0 R 119 0 R 118 0 R 80 0 R 77 0 R 76 0 R 74 0 R 70 0 R 63 0 R 61 0 R 60 0 R 39 0 R 38 0 R 37 0 R 35 0 R 34 0 R 31 0 R 21 0 R 16 0 R] +>> +endobj + +16 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [20 0 R 73 19 0 R 75 18 0 R 78 17 0 R 80 81] + /Pg 183 0 R +>> +endobj + +17 0 obj +<< + /Type /StructElem + /S /Strong + /P 16 0 R + /K [79] + /Pg 183 0 R +>> +endobj + +18 0 obj +<< + /Type /StructElem + /S /Strong + /P 16 0 R + /K [76 77] + /Pg 183 0 R +>> +endobj + +19 0 obj +<< + /Type /StructElem + /S /Strong + /P 16 0 R + /K [74] + /Pg 183 0 R +>> +endobj + +20 0 obj +<< + /Type /StructElem + /S /Strong + /P 16 0 R + /K [72] + /Pg 183 0 R +>> +endobj + +21 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [30 0 R 47 29 0 R 49 50 28 0 R 52 27 0 R 54 55 26 0 R 57 58 59 25 0 R 61 62 24 0 R 64 65 23 0 R 67 68 22 0 R 71] + /Pg 183 0 R +>> +endobj + +22 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [69 70] + /Pg 183 0 R +>> +endobj + +23 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [66] + /Pg 183 0 R +>> +endobj + +24 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [63] + /Pg 183 0 R +>> +endobj + +25 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [60] + /Pg 183 0 R +>> +endobj + +26 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [56] + /Pg 183 0 R +>> +endobj + +27 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [53] + /Pg 183 0 R +>> +endobj + +28 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [51] + /Pg 183 0 R +>> +endobj + +29 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [48] + /Pg 183 0 R +>> +endobj + +30 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [46] + /Pg 183 0 R +>> +endobj + +31 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [33 0 R 43 32 0 R] + /Pg 183 0 R +>> +endobj + +32 0 obj +<< + /Type /StructElem + /S /Em + /P 31 0 R + /K [44 45] + /Pg 183 0 R +>> +endobj + +33 0 obj +<< + /Type /StructElem + /S /Strong + /P 31 0 R + /K [42] + /Pg 183 0 R +>> +endobj + +34 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (Demo flow & talking points) + /K [41] + /Pg 183 0 R +>> +endobj + +35 0 obj +<< + /Type /StructElem + /S /BlockQuote + /P 15 0 R + /K [36 0 R] +>> +endobj + +36 0 obj +<< + /Type /StructElem + /S /Strong + /P 35 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [40] + /Pg 183 0 R +>> +endobj + +37 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [37 38 39] + /Pg 183 0 R +>> +endobj + +38 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (Where we're headed) + /K [36] + /Pg 183 0 R +>> +endobj + +39 0 obj +<< + /Type /StructElem + /S /L + /P 15 0 R + /A [<< + /O /List + /ListNumbering /Circle + >>] + /K [56 0 R 52 0 R 48 0 R 44 0 R 40 0 R] +>> +endobj + +40 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [43 0 R 41 0 R] +>> +endobj + +41 0 obj +<< + /Type /StructElem + /S /LBody + /P 40 0 R + /K [42 0 R 34 35] + /Pg 183 0 R +>> +endobj + +42 0 obj +<< + /Type /StructElem + /S /Strong + /P 41 0 R + /K [33] + /Pg 183 0 R +>> +endobj + +43 0 obj +<< + /Type /StructElem + /S /Lbl + /P 40 0 R + /K [32] + /Pg 183 0 R +>> +endobj + +44 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [47 0 R 45 0 R] +>> +endobj + +45 0 obj +<< + /Type /StructElem + /S /LBody + /P 44 0 R + /K [46 0 R 31] + /Pg 183 0 R +>> +endobj + +46 0 obj +<< + /Type /StructElem + /S /Strong + /P 45 0 R + /K [30] + /Pg 183 0 R +>> +endobj + +47 0 obj +<< + /Type /StructElem + /S /Lbl + /P 44 0 R + /K [29] + /Pg 183 0 R +>> +endobj + +48 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [51 0 R 49 0 R] +>> +endobj + +49 0 obj +<< + /Type /StructElem + /S /LBody + /P 48 0 R + /K [50 0 R 28] + /Pg 183 0 R +>> +endobj + +50 0 obj +<< + /Type /StructElem + /S /Strong + /P 49 0 R + /K [27] + /Pg 183 0 R +>> +endobj + +51 0 obj +<< + /Type /StructElem + /S /Lbl + /P 48 0 R + /K [26] + /Pg 183 0 R +>> +endobj + +52 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [55 0 R 53 0 R] +>> +endobj + +53 0 obj +<< + /Type /StructElem + /S /LBody + /P 52 0 R + /K [54 0 R 25] + /Pg 183 0 R +>> +endobj + +54 0 obj +<< + /Type /StructElem + /S /Strong + /P 53 0 R + /K [24] + /Pg 183 0 R +>> +endobj + +55 0 obj +<< + /Type /StructElem + /S /Lbl + /P 52 0 R + /K [23] + /Pg 183 0 R +>> +endobj + +56 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [59 0 R 57 0 R] +>> +endobj + +57 0 obj +<< + /Type /StructElem + /S /LBody + /P 56 0 R + /K [58 0 R 22] + /Pg 183 0 R +>> +endobj + +58 0 obj +<< + /Type /StructElem + /S /Strong + /P 57 0 R + /K [21] + /Pg 183 0 R +>> +endobj + +59 0 obj +<< + /Type /StructElem + /S /Lbl + /P 56 0 R + /K [20] + /Pg 183 0 R +>> +endobj + +60 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (What this means for the business) + /K [19] + /Pg 183 0 R +>> +endobj + +61 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [62 0 R 16 17 18] + /Pg 183 0 R +>> +endobj + +62 0 obj +<< + /Type /StructElem + /S /Strong + /P 61 0 R + /K [14 15] + /Pg 183 0 R +>> +endobj + +63 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [69 0 R 67 0 R 66 0 R 6 65 0 R 9 10 64 0 R 13] + /Pg 183 0 R +>> +endobj + +64 0 obj +<< + /Type /StructElem + /S /Strong + /P 63 0 R + /K [11 12] + /Pg 183 0 R +>> +endobj + +65 0 obj +<< + /Type /StructElem + /S /Strong + /P 63 0 R + /K [7 8] + /Pg 183 0 R +>> +endobj + +66 0 obj +<< + /Type /StructElem + /S /Strong + /P 63 0 R + /K [5] + /Pg 183 0 R +>> +endobj + +67 0 obj +<< + /Type /StructElem + /S /Em + /P 63 0 R + /K [68 0 R] +>> +endobj + +68 0 obj +<< + /Type /StructElem + /S /Strong + /P 67 0 R + /K [4] + /Pg 183 0 R +>> +endobj + +69 0 obj +<< + /Type /StructElem + /S /Strong + /P 63 0 R + /K [2 3] + /Pg 183 0 R +>> +endobj + +70 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [73 0 R 68 72 0 R 70 71 72 71 0 R 74 << + /Type /MCR + /MCID 0 + /Pg 183 0 R + >> << + /Type /MCR + /MCID 1 + /Pg 183 0 R + >>] + /Pg 181 0 R +>> +endobj + +71 0 obj +<< + /Type /StructElem + /S /Strong + /P 70 0 R + /K [73] + /Pg 181 0 R +>> +endobj + +72 0 obj +<< + /Type /StructElem + /S /Strong + /P 70 0 R + /K [69] + /Pg 181 0 R +>> +endobj + +73 0 obj +<< + /Type /StructElem + /S /Strong + /P 70 0 R + /K [66 67] + /Pg 181 0 R +>> +endobj + +74 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [75 0 R 63 64 65] + /Pg 181 0 R +>> +endobj + +75 0 obj +<< + /Type /StructElem + /S /Strong + /P 74 0 R + /K [61 62] + /Pg 181 0 R +>> +endobj + +76 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (What's new and powerful) + /K [60] + /Pg 181 0 R +>> +endobj + +77 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [79 0 R 57 78 0 R] + /Pg 181 0 R +>> +endobj + +78 0 obj +<< + /Type /StructElem + /S /Em + /P 77 0 R + /K [58 59] + /Pg 181 0 R +>> +endobj + +79 0 obj +<< + /Type /StructElem + /S /Strong + /P 77 0 R + /K [56] + /Pg 181 0 R +>> +endobj + +80 0 obj +<< + /Type /StructElem + /S /Table + /P 15 0 R + /K [112 0 R 81 0 R] +>> +endobj + +81 0 obj +<< + /Type /StructElem + /S /TBody + /P 80 0 R + /K [107 0 R 102 0 R 97 0 R 92 0 R 87 0 R 82 0 R] +>> +endobj + +82 0 obj +<< + /Type /StructElem + /S /TR + /P 81 0 R + /K [85 0 R 84 0 R 83 0 R] +>> +endobj + +83 0 obj +<< + /Type /StructElem + /S /TD + /P 82 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [54 55] + /Pg 181 0 R +>> +endobj + +84 0 obj +<< + /Type /StructElem + /S /TD + /P 82 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [53] + /Pg 181 0 R +>> +endobj + +85 0 obj +<< + /Type /StructElem + /S /TD + /P 82 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [86 0 R] +>> +endobj + +86 0 obj +<< + /Type /StructElem + /S /Strong + /P 85 0 R + /K [52] + /Pg 181 0 R +>> +endobj + +87 0 obj +<< + /Type /StructElem + /S /TR + /P 81 0 R + /K [90 0 R 89 0 R 88 0 R] +>> +endobj + +88 0 obj +<< + /Type /StructElem + /S /TD + /P 87 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [50 51] + /Pg 181 0 R +>> +endobj + +89 0 obj +<< + /Type /StructElem + /S /TD + /P 87 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [49] + /Pg 181 0 R +>> +endobj + +90 0 obj +<< + /Type /StructElem + /S /TD + /P 87 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [91 0 R] +>> +endobj + +91 0 obj +<< + /Type /StructElem + /S /Strong + /P 90 0 R + /K [48] + /Pg 181 0 R +>> +endobj + +92 0 obj +<< + /Type /StructElem + /S /TR + /P 81 0 R + /K [95 0 R 94 0 R 93 0 R] +>> +endobj + +93 0 obj +<< + /Type /StructElem + /S /TD + /P 92 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [46 47] + /Pg 181 0 R +>> +endobj + +94 0 obj +<< + /Type /StructElem + /S /TD + /P 92 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [44 45] + /Pg 181 0 R +>> +endobj + +95 0 obj +<< + /Type /StructElem + /S /TD + /P 92 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [96 0 R] +>> +endobj + +96 0 obj +<< + /Type /StructElem + /S /Strong + /P 95 0 R + /K [43] + /Pg 181 0 R +>> +endobj + +97 0 obj +<< + /Type /StructElem + /S /TR + /P 81 0 R + /K [100 0 R 99 0 R 98 0 R] +>> +endobj + +98 0 obj +<< + /Type /StructElem + /S /TD + /P 97 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [41 42] + /Pg 181 0 R +>> +endobj + +99 0 obj +<< + /Type /StructElem + /S /TD + /P 97 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [39 40] + /Pg 181 0 R +>> +endobj + +100 0 obj +<< + /Type /StructElem + /S /TD + /P 97 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [101 0 R] +>> +endobj + +101 0 obj +<< + /Type /StructElem + /S /Strong + /P 100 0 R + /K [38] + /Pg 181 0 R +>> +endobj + +102 0 obj +<< + /Type /StructElem + /S /TR + /P 81 0 R + /K [105 0 R 104 0 R 103 0 R] +>> +endobj + +103 0 obj +<< + /Type /StructElem + /S /TD + /P 102 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [36 37] + /Pg 181 0 R +>> +endobj + +104 0 obj +<< + /Type /StructElem + /S /TD + /P 102 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [34 35] + /Pg 181 0 R +>> +endobj + +105 0 obj +<< + /Type /StructElem + /S /TD + /P 102 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [106 0 R] +>> +endobj + +106 0 obj +<< + /Type /StructElem + /S /Strong + /P 105 0 R + /K [33] + /Pg 181 0 R +>> +endobj + +107 0 obj +<< + /Type /StructElem + /S /TR + /P 81 0 R + /K [110 0 R 109 0 R 108 0 R] +>> +endobj + +108 0 obj +<< + /Type /StructElem + /S /TD + /P 107 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [31 32] + /Pg 181 0 R +>> +endobj + +109 0 obj +<< + /Type /StructElem + /S /TD + /P 107 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [27 28 29 30] + /Pg 181 0 R +>> +endobj + +110 0 obj +<< + /Type /StructElem + /S /TD + /P 107 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [111 0 R] +>> +endobj + +111 0 obj +<< + /Type /StructElem + /S /Strong + /P 110 0 R + /K [26] + /Pg 181 0 R +>> +endobj + +112 0 obj +<< + /Type /StructElem + /S /THead + /P 80 0 R + /K [113 0 R] +>> +endobj + +113 0 obj +<< + /Type /StructElem + /S /TR + /P 112 0 R + /K [117 0 R 116 0 R 114 0 R] +>> +endobj + +114 0 obj +<< + /Type /StructElem + /S /TH + /P 113 0 R + /ID (U1x2y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [115 0 R] +>> +endobj + +115 0 obj +<< + /Type /StructElem + /S /Strong + /P 114 0 R + /K [23 24 25] + /Pg 181 0 R +>> +endobj + +116 0 obj +<< + /Type /StructElem + /S /TH + /P 113 0 R + /ID (U1x1y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [20 21 22] + /Pg 181 0 R +>> +endobj + +117 0 obj +<< + /Type /StructElem + /S /TH + /P 113 0 R + /ID (U1x0y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [] +>> +endobj + +118 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (Why one platform beats two) + /K [19] + /Pg 181 0 R +>> +endobj + +119 0 obj +<< + /Type /StructElem + /S /BlockQuote + /P 15 0 R + /K [122 0 R 121 0 R 120 0 R] +>> +endobj + +120 0 obj +<< + /Type /StructElem + /S /Span + /P 119 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [15 17 18] + /Pg 181 0 R +>> +endobj + +121 0 obj +<< + /Type /StructElem + /S /Strong + /P 119 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [16] + /Pg 181 0 R +>> +endobj + +122 0 obj +<< + /Type /StructElem + /S /Strong + /P 119 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [14] + /Pg 181 0 R +>> +endobj + +123 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [4 126 0 R 7 125 0 R 9 124 0 R 12 13] + /Pg 181 0 R +>> +endobj + +124 0 obj +<< + /Type /StructElem + /S /Strong + /P 123 0 R + /K [10 11] + /Pg 181 0 R +>> +endobj + +125 0 obj +<< + /Type /StructElem + /S /Em + /P 123 0 R + /K [8] + /Pg 181 0 R +>> +endobj + +126 0 obj +<< + /Type /StructElem + /S /Em + /P 123 0 R + /K [5 6] + /Pg 181 0 R +>> +endobj + +127 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (The big idea) + /K [3] + /Pg 181 0 R +>> +endobj + +128 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [129 0 R] +>> +endobj + +129 0 obj +<< + /Type /StructElem + /S /Em + /P 128 0 R + /K [2] + /Pg 181 0 R +>> +endobj + +130 0 obj +<< + /Type /StructElem + /S /H3 + /P 15 0 R + /T (Bringing live tracking and trip history together into a single intelligence platform) + /K [1] + /Pg 181 0 R +>> +endobj + +131 0 obj +<< + /Type /StructElem + /S /H1 + /P 15 0 R + /T + /K [0] + /Pg 181 0 R +>> +endobj + +132 0 obj +<< + /Type /PageLabel + /S /D + /St 1 +>> +endobj + +133 0 obj +<< + /Type /PageLabel + /S /D + /St 2 +>> +endobj + +134 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /IAYCAY+LibertinusSerif-Bold-Identity-H + /Encoding /Identity-H + /DescendantFonts [135 0 R] + /ToUnicode 138 0 R +>> +endobj + +135 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /IAYCAY+LibertinusSerif-Bold + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 137 0 R + /DW 0 + /W [0 0 500 1 1 545 2 2 325 3 3 489 4 4 358 5 5 740 6 6 551 7 7 777 8 8 250 9 9 742 10 10 730 11 11 616 12 12 244 13 13 504 14 14 456 15 15 428 16 16 654 17 17 322 18 18 521 19 19 529 20 20 505.99997 21 21 613 22 22 561 23 23 581 24 24 619 25 25 427 26 26 558 27 27 391 28 28 905 29 29 652 30 30 542 31 31 440 32 32 1028 33 33 440 34 34 256 35 35 598 36 36 641 37 37 358 38 38 680 39 39 734 40 40 732 41 41 252.99998 42 42 740 43 43 367 44 44 706 45 45 716 46 46 577 47 47 729 48 48 244 49 49 315 50 50 527 51 51 514 52 52 534 53 53 514 54 54 315 55 55 614 56 56 736 57 57 1154] +>> +endobj + +136 0 obj +<< + /Length 13 + /Filter /FlateDecode +>> +stream +x # +endstream +endobj + +137 0 obj +<< + /Type /FontDescriptor + /FontName /IAYCAY+LibertinusSerif-Bold + /Flags 131078 + /FontBBox [0 -238 1094 733] + /ItalicAngle 0 + /Ascent 894 + /Descent -246 + /CapHeight 645 + /StemV 168.6 + /CIDSet 136 0 R + /FontFile3 139 0 R +>> +endobj + +138 0 obj +<< + /Length 1412 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +57 beginbfchar +<0001> <0046> +<0002> <006C> +<0003> <0065> +<0004> <0074> +<0005> <004E> +<0006> <006F> +<0007> <0077> +<0008> <0020> +<0009> <2014> +<000A> <004F> +<000B> <006E> +<000C> <002C> +<000D> <0053> +<000E> <0063> +<000F> <0072> +<0010> <0042> +<0011> <0069> +<0012> <0067> +<0013> <0076> +<0014> <0061> +<0015> <006B> +<0016> <0064> +<0017> <0070> +<0018> <0068> +<0019> <0073> +<001A> <0079> +<001B> <0066> +<001C> <006D> +<001D> <0054> +<001E> <0062> +<001F> <201C> +<0020> <0057> +<0021> <201D> +<0022> <003A> +<0023> <0075> +<0024> <00660069> +<0025> <00AD> +<0026> <0066006C> +<0027> <0044> +<0028> <0055> +<0029> <2019> +<002A> <0041> +<002B> <0049> +<002C> <0043> +<002D> <0052> +<002E> <004C> +<002F> <0026> +<0030> <002E> +<0031> <0028> +<0032> <2248> +<0033> <0033> +<0034> <2013> +<0035> <0034> +<0036> <0029> +<0037> <0050> +<0038> <004B> +<0039> <2192> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +139 0 obj +<< + /Length 6013 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xYy\Sg&b-׋xZkֱsmթ:j+.u aM!@$l},Rhնjծj:cL2/Eťi#]~s9o8^'{q80qbrT\J(?J{^gIv·bz:ݭo?gK2܇Oˋ3~g}z~7&\&.KJN{Apj?,hgvD)`k4Z,JX)MLZ5ɋ4][ZR +6GI>St>:48^^^^=QtzO=:r8g7ܤxN&M~b(7?HG/$LM2M3.vOx`>| ؟f̜~߁3?sK"1ipd}5]-1쒦;+*00z Ф3I$SJ.ŢqsKJԥؕNE}gegݢVX;bBR+dc/߀0|iF^f[ߣf̵XtJ ИaBKG +Ly$gEZ&Gk23 ዊONܾ.  @`_ ۙ+&]7 (՚D_G؍9g*X8u?<9VۅDUP!m棥 "Bji!ڭxlWa! dz2չt_gLvf!"mQUiTjM{^-9|.VZr";QJ8o&7i * +NᜱWGX4F]/dqʂL?XxiS7b&ߜEJ[iA)Vh i6Puש[?xP +8΁/zd(9JZK45)DBJW,u6rtNJWNU..xV/.*[BiI^BlWKnu,V#zar +KͰd3aruWz^5ʁ"O׉)mGc/W +DkOJ84>*Ul!uWk ;pݓRқ]^ȥ$8rW놇\e1F: o%[kZzvD47lВQQZyI'Ux{QYIe +H[QJ:kȦfw}lsD8vZ6uɷfsvem,* $k +0zW! X  15cptmZ4O::;<3B~Ճ>HJ{x|=[1(z?þ[O-geY&Nn20w$kyBQ!c38zv&SUgɢ\;~]ȈdΞ10a;e ;-Ϊx9ź*E'Xϐ=Mf&CB)tXB|xiW_>oH53)x-8R)I8=4Rg}$DcT)pD2-y^j.UUL u /ivMm=ĈH٭GP4٦rY}zƗ5"2¢CAZ11Щ)m OJs6_Xq2|%%L _Wԅ)A+ыvggq9Kj9D8".j}e Khq<]+%>S,-tp3Y_)a#A:`=x K~~nuAE)M파&RLwzD[K>Yg6mv/ +NdL% J8z0[ŧh`d(fu,SԴxA5͚]Z';eB9`0giwSռw݉; +Fc^ G +D!oJ=\ϣfj V'PL1~TUw@z/MW{ͳC V++0WNBK!k-vL]\)"K쥶rAliE/ 0&#ĸ讈}]]8v2ūTk~W˲`e\rqM*-D\E8}5;vf/:Yc6&[{)s S[(Q$ ҄2g﷙YM66I^Ӏ2l}SR] =2AGM} ac^:/+,Þ1`pS edI5Ulh& A_ͫH]ωts;(yA8'G!4@sNf akrj Hi9*ݤK) +*1,ZFboӰ~K$ևܱV)h!aO/4F Wob]n=97f{Uܝ7|v=-ޮ9.NإLe6J+@n<~HUzXS\"ۚ{S[9蠒杙@8q~$3N#?'\`)!(yC=5=%Ev)da%ZZ-&tG<]<nG~>RXaWoQUB۫[HY7k> +{e򄰲2J^XIh + ~ߓ lԺn 7l뼬$~]y}ʷlF>b]%5 +pvTГhl^.%?)Ngߟ9[_)3o{Ft٩D˺ Ɵ$ _)7L3"F[{ڥL4 =/){\Bn#EkN^ozFx=3!%f<,y-)cYFIb=~fQ;ꟗ%2D㶄ͱYwl]wm][5UCKBBJXsogu[xS4;m]2m}i $>h,3h/%/!Vqbi6};`Fo +-wѽ!Yq0JSYavF#6s?u9r:4uoڙu;K>Dl +}a=N1j@w3P9x2T,^CX_U.8o_; {wzƺA9u!єM89Tyr(qځ<،R@VnL;06J䢙;Fa¥ 9/\ccAt5e*Lʮ#;>t\meiMaߞ@J&+4Tf&W?G,k]j+͛Ty+/ S}z Jڿ*0i](Z e$6zB&A?%Jeul,7ZBJKHeViC$L@%4ѝtQFP)re|6eN>]\jNNR +ig9GHoV +ixIئ)ʥr2,6ZuqQ9JVoVbq?V-D^h2@V)5D~uba>2$iz:?旖UՖ\%BzK/wB-R{C+ 9Q1#9@SI5Fqa&pa!<]!V7_xh뛰3uHHe2!JdQR SK^}H'=83tEC6o A悲xL(2DULĚR H ++Q/.SqHIOd"HQ^<%'C{bV#6mF +`dKp(t g9fp9;*~hyDU\[mHʨa[G992y\>a愘LY~,*=V(/$3 +endstream +endobj + +140 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /WVDHZH+LibertinusSerif-Italic-Identity-H + /Encoding /Identity-H + /DescendantFonts [141 0 R] + /ToUnicode 144 0 R +>> +endobj + +141 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /WVDHZH+LibertinusSerif-Italic + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 143 0 R + /DW 0 + /W [0 0 500 1 1 667 2 2 521 3 3 489 4 4 276 5 5 401 6 6 518 7 7 389 8 8 219 9 9 250 10 10 454 11 11 447 12 12 357 13 13 667 14 14 307 15 15 353 16 16 250 17 17 499 18 18 489 19 19 486 20 22 444 23 23 333 24 24 444 25 25 375 26 26 909 27 27 519 28 28 570 29 29 477 30 30 688 31 31 405 32 32 375 33 33 478 34 34 314 35 35 219 36 36 266 37 37 219 38 38 783 39 39 472 40 40 486 41 41 503.00003 42 42 742 43 43 564] +>> +endobj + +142 0 obj +<< + /Length 14 + /Filter /FlateDecode +>> +stream +x +endstream +endobj + +143 0 obj +<< + /Type /FontDescriptor + /FontName /WVDHZH+LibertinusSerif-Italic + /Flags 131142 + /FontBBox [-78 -238 1042 726] + /ItalicAngle -12 + /Ascent 894 + /Descent -246 + /CapHeight 645 + /StemV 95.4 + /CIDSet 142 0 R + /FontFile3 145 0 R +>> +endobj + +144 0 obj +<< + /Length 1216 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +43 beginbfchar +<0001> <0041> +<0002> <0075> +<0003> <0064> +<0004> <0069> +<0005> <0065> +<0006> <006E> +<0007> <0063> +<0008> <003A> +<0009> <0020> +<000A> <0053> +<000B> <006F> +<000C> <0072> +<000D> <0044> +<000E> <0074> +<000F> <0073> +<0010> <00B7> +<0011> <0050> +<0012> <0070> +<0013> <0061> +<0014> <0032> +<0015> <0030> +<0016> <0036> +<0017> <002D> +<0018> <0038> +<0019> <201C> +<001A> <0057> +<001B> <0068> +<001C> <0066006C> +<001D> <0067> +<001E> <0077> +<001F> <003F> +<0020> <201D> +<0021> <0062> +<0022> <0066> +<0023> <002C> +<0024> <006C> +<0025> <002E> +<0026> <006D> +<0027> <0076> +<0028> <006B> +<0029> <0079> +<002A> <2014> +<002B> <00660069> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +145 0 obj +<< + /Length 5231 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xXy|N,q\K\A,S)t tIҦig]&KJZ(HAvQH"wg~Qz&gfs>e&L`LOMy+);) WKyN2,hs 5bݺУ[C? |+V,J'-OLM_"Nٙ;g>;/N[4UM[-HMJȝ(/7YuzYX+^ŕʒť̢pas99/d |n +.bX,_B{d4B tvr Pٽ%w3lbv¡ H2Y~bđ]4\>)YSOfޔ_zz S" +Yۇ<2_e2'04x8+Љs}XhCw8oCa,؏ @j3E̶|& ̺]32ZCXNh#MyRe*M +􈎦J/1Sg0hhn6ͤh )*hQ3AO%2BTfI)xjRAGio:X-:"ˌdn0;mN<cRf6Mf ++^b =v2fK +;- 3}XD~kr4P%Zˏ5[צ~D+-vU9\V&mRRqpy|mknޣ|剈2M/%Y`nEk2"C)VjVU)n&lk∋#Ipp1$Ÿ! >TOZGϒH4V?5$ Gn#-JZ(|82qvd=OLƔuz=wըcItD;pB| X%.C_/#(DU6X#P $"JS`(P/QИ|dݳ;3m.72e閴=k ^OUmB[WxacVR2SY)Ҿe-dgqinr}#Ёke۩=2hk ydoc\Ka#`6 NhkD~wj L_ù`4 '/9AXW*~.HO"2w}G^; \s.C@0g;\AW{Qoq]e k](D|).uɛMA7&!h'nVmC*GYQ9kj*S5+B% 32"@9ps4|7uo§G[ǀa՘kp< ,2ƸVO4m N ZzU_ZƠ&j$}TAu:@C F;=9pjɠDfHsUVdxqӃ^@@ @K j^eb=-N Cit ӧh?hD;hvBJ +sR P)Nw?bJ +;my_A`Ac? +sv?ʨTʎ޺ +BX*Dط +btu mB&khYsʑwOB[ 0lP( )J}pPCv [cZA.riu]N]jk?nڝ|c֓}-9.?>J-Ii)8`j&\NsHռS3jmjEA)qpn{{G/:qERR&-Doey΄?|a;6}DVB" 5> 3ڟS+XEFҒu8do 2Vs6 YAlqЇ, 131]b‡aFg C0k0e"_+H!O;tJY^b{Z]uhͯ9qpR<(9. 9m* +syEBKjd4F\<>->~,du4W69/%ԤN!+ Ҹ'63IWW==.PqpT,>ܹ3NQ-HjD|sH/#؁~fq \/v w0Ƀ1#Ճ_9렍ٍJlZh /%.کs!W$ވ'47[Hóy%ܦ@|Ob-H٬uN&(2Yzeγȭ=D:X|n += 0A[m~{nعDPkJ 욽Y^"\/UI.>fķs I+'R`I DλAAU¾kҙ (z ߶ft^J5mі_7!xg(zyEٿa!{ct[I4R<TwjbV)o.G{O1О۟UY\OO26NZ;E{O!GJ) s-@..*$:w*QIBWB5Z粥"::0ڪLEo֒hSrhu_}STS}QYXDJ{vgPG$[ʝyńJgw:W7{) 9q?p,毠kt*rO]pYZ 9^WVI$EZ2U#s;(t\-ܚ+̿[ D9m[֔ א(_66h[&gu:{ckI4>V +m8>17cl`a7r<~-yt`cbR.V5^݇w֦gdJI?<7G΄ o΁Q$ +ڧկJj۩߻?%{煥ތO&&,K 8>`&xKtdh \:ŃFlcQ ;ǟD; +v\B>}ʫ%9f5gg{5w:08Ft6ʗVrwI[]."rru69)IDTPQڢ)Ouqѳv#}{|z^' > +endobj + +147 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /PVBVPF+LibertinusSerif-Regular + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 149 0 R + /DW 0 + /W [0 0 500 1 1 597 2 2 538 3 3 447 4 4 250 5 5 264 6 6 500 7 7 457 8 8 428 9 9 515 10 10 390 11 11 316 12 12 531 13 13 519 14 14 542 15 15 747 16 16 372 17 17 505.99997 18 18 504 19 19 503.00003 20 20 271 21 21 582 22 22 236 23 23 493 24 25 220 26 26 742 27 27 790 28 28 497 29 29 310 30 30 512 31 31 699 32 32 560 33 33 528 34 34 338 35 35 550 36 36 490 37 37 702 38 38 540 39 39 541 40 40 701 41 41 485 42 43 298 44 44 268 45 45 272 46 46 587 47 47 815 48 48 646 49 49 297 50 50 485 51 51 749 52 52 465 53 53 323 54 54 652 55 55 351 56 56 695 57 57 637 58 59 375 60 60 465 61 61 557 62 62 465 63 63 588 64 67 465] +>> +endobj + +148 0 obj +<< + /Length 13 + /Filter /FlateDecode +>> +stream +x>, +endstream +endobj + +149 0 obj +<< + /Type /FontDescriptor + /FontName /PVBVPF+LibertinusSerif-Regular + /Flags 131078 + /FontBBox [-48 -238 803 736] + /ItalicAngle 0 + /Ascent 894 + /Descent -246 + /CapHeight 658 + /StemV 95.4 + /CIDSet 148 0 R + /FontFile3 151 0 R +>> +endobj + +150 0 obj +<< + /Length 1564 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +67 beginbfchar +<0001> <0054> +<0002> <0068> +<0003> <0065> +<0004> <0020> +<0005> <006C> +<0006> <0067> +<0007> <0061> +<0008> <0063> +<0009> <0079> +<000A> <0073> +<000B> <0074> +<000C> <0075> +<000D> <0070> +<000E> <006E> +<000F> <0077> +<0010> <0072> +<0011> <0064> +<0012> <006F> +<0013> <0071> +<0014> <0069> +<0015> <00660066> +<0016> <003A> +<0017> <0062> +<0018> <002C> +<0019> <002E> +<001A> <2014> +<001B> <006D> +<001C> <0076> +<001D> <0066> +<001E> <006B> +<001F> <004E> +<0020> <00660069> +<0021> <004C> +<0022> <00AD> +<0023> <002B> +<0024> <0078> +<0025> <004F> +<0026> <0066006C> +<0027> <0050> +<0028> <0044> +<0029> <0053> +<002A> <0028> +<002B> <0029> +<002C> <2019> +<002D> <006A> +<002E> <0052> +<002F> <00660066006C> +<0030> <0043> +<0031> <0049> +<0032> <0046> +<0033> <2026> +<0034> <0031> +<0035> <002F> +<0036> <0056> +<0037> <2022> +<0038> <0041> +<0039> <004B> +<003A> <201C> +<003B> <201D> +<003C> <0032> +<003D> <0045> +<003E> <0033> +<003F> <0042> +<0040> <0034> +<0041> <0035> +<0042> <0036> +<0043> <0037> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +151 0 obj +<< + /Length 7197 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xY xo-M"`|v SX7EA١ݡtM6doݓ[I)݁,O9?2iWȨIYq1鏎~ l!BtClԣztMjGg&oA_Tn-F X'ޫ8eA~^"_Fj5K7'|oA~|[wɿ{{2M100eu9{߽cwLs_}WOr>G蠟1{0_>fZ_z궒u?y00o>l0x[Fᰟ!*'scA8\BTNw+#ŴLb.y?ɡU+P:kHJEm0bl8vCjZEgg* L-08t?m&N33W?TIa[cE- b\fLWzpCn#-BMr=Ş#QlrZqi:)iz!7pź0=Mo$*mբHRSTe6> :0*v%Uz^RU18ZZSZկo/gWU g[iof@w}T o.0]EE'cv:I3>TmF/< +Z_"#\i'3"TkyXq\u +^*P$⢎ +%I>^.oXjdݾ!z|rwby>0(_sCQA+}/^d$mR lr|;`0*䔰;0ﶯC~&:>w$ؓjE=I[w,,ל[XM4G.qY*eIJ(9[a78led^uԃyuh/.Fe: +uE+}< =x^*dR D=R1M`fgFT'jZ&a9Zοy^k^܇$)bG&͖DElj݂9CץEFʨ2XM{ml(U* k2m[KsN9n4@ `H&-$|sqEA^&z1z0 +h;>{ឞ?|#Q_4SBT;AT|Gr#QYdux ]y^i}QvvJ鄉VvY,ˉyeKs + +x[w7,bipW^TP +QiYXU;?)7#)b<17A$9ZH.-q?ja@uG0 n6|'_czk2*#)SoPͱ-ޥ5$V*dR|" j[4Ê7󗅽vy>B%LM`MEV Q%'`eLJ&pQd4f>/O_HrEMI]]}<"3Hh0%0O5OGXg&lR#'DkV(P L")9 +R5>7]-cA$l`7N R+'T.'Y^eQr>։Bٙ¼|bOtTN*2 oihXm`/i\ EqHw1]Zaй3 "6qwoڋ7 +V9]D>?CwD1;2׮f]<*ވ,^r\nr +!c; ߠl/<<'S.VXRYN|Ǿ'ҼGgG3:RFbUE:ƌ3ti|4fgQrOOr'9hO$B,7jaЗ>75r }&trm!$EnU#vULUCbRx))ujA}29ӒHn},wЗ6}ʬqwe; .Tqv ͤbɬ%%2ފ#E\si\{򷰲O`+BxE5 }NV!{X}v5wPi~t(%*^A )G03m 9:%<-J +fa-}4MrGƛ'Ҫ cURq ]a.Cd2̇ly #,e +n0X&fP[ 8U27=LN'Fs^ TIв:KKhdÞ3Ir%Y*1[7FjND$7 8ۉ(wz* +xƱ6$&3'/XI._zp2 g-?*|27m Rl;Rڛe$ZS(U kTT͈Fm?sbu1e#tyʌe$ZĞ#oUXݍp'6}9sVfnH(2i/lވzrq{f*/2)W]Y= +vS Bt@f̱o\AV[2# Ê}֚F쎣SG|):c0! Db̮jgci~l1e9jL\.(%SRQK3Yd&X7g |ݴ{j٫:ݩr’;`8/LšVQ~ hIU\b/+bʢ l9f7D2|Vi ;]Iۛ(pP.UBrB:F#6yuN%Q1QtH-OOKITr{6vc #saU `n;efbCؙjT[ޚHRklR1֐¹;$[X:<t']]Eul>vKL8:+sExVA2eFbxިp*M> e)f񹆡(hwJ#zFQا T,6b]w?2-&awb̭v;z[hs0a&p6(>=p{QQn$y!f<q*5i5Ś|g0z|+2dB's +b#ssBY&Ϳ=ݷSxОC xH;kTCfQX$$Jbҳ$3UV AZf)=EB3 wkweĒc~=!!it +2-YR.rzY~#L1ࢥ-ffx  OʓŃ{6􅩈  B%_NöA:ɷ j2sQa8G)j_L&ܾV:E>/+Ů{Y0ؒ0,#+ٳ Gjn=c=v}.χ :  /@5;UI-wwKn[ZYtLnJ2j4>H*}ux %Ǐ# mVLpqþOܚċykLCZ~8 Uixm mPE1l?B L ݷM!7%<Ä?ϱN5gZ=dٔ¾#4sg&2E:J"ӥضp#k|7vi"VW>9ir;aUfGQ/9"3c=o@$ZFX4&݆JP +hn!QLsЄ3\E[K0ש P,8^DR>*E'JR+Ł _ໂ疏lfywk(mHͷ/:@8C26 +V7E:HK3p@ؒWدmj%OZO''ʭu|=ܿk8%M*tn_:`O^e^^L- oy/)-H&ζTWG + :?c\DgJK ?/Nnk"c 4=(ddl.w=p ;sk]8v> Gt |UČhOﰇ"K#ẃeRST-t_mP>c%혰Z:aOAh3 mZ s}{שwѵto Pd JE|&,cY5K*IU5iy{ h% *T*L=Nt;v#ihͅC=o I~mb9ixG ϼdA( +==XB3O63;jK-4-0%98`Zp\l !1VtzD"ӷѻtRہCf[ѿȑ#G6Xi + STNLkaF<3Ez;U[\"L9Z6`8mv.Mp$LY >SK;QC וsv2ZlֿPM Mm`w߼vvumgٿ=wL.Z: [xUCG;h_ YJʠ2)Qf6kj[N>f5 3 [Wk XjRɢtL/HTE٩18Z9~L'*@Ǿ3|{nv,jh5?Yf?Hf.b,Ucs~EYוمT%eѭi'{X=TjCSĐ)9 k^3+_+UKջտVntOO6}}{oʛ{" ԔpڡsP <,lB\ ̉<0Lyg4wyi5DeFlF=ya[อTN8+4qġ4W R|4';!5lKh;Ї,'xмg$BO-վG2P[./IMgXt30 7:Y}jD4{XRL WC4'WkHna3Q#CltmL7E'PugT, +DA;>qᆈp( kpڼxuƞKKxffpׅC/BW.q; Y*Z=xKk'Ǥ@l]-<:F%P{@?ڿC7}<ĜipWw`RǦ0ꉿ'ܹ ʅ^8 ŭg¼ WteוOnFܼe:V54F gŒãW[KS&i0zL{ 0j'(bi,,RI$&^]ѪPV%tqzB8 +endstream +endobj + +152 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0Pp +Q +endstream +endobj + +153 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0TpR +endstream +endobj + +154 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0RpS +endstream +endobj + +155 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0VpT +endstream +endobj + +156 0 obj +<< + /Type /FontDescriptor + /FontName /AppleColorEmoji + /Flags 131076 + /FontBBox [0 -102.400024 800 697.6] + /ItalicAngle 0 + /Ascent 697.6 + /Descent -102.400024 + /FontFamily (AppleColorEmoji) + /FontStretch /Normal + /FontWeight 400 +>> +endobj + +157 0 obj +<< + /Type /Font + /Subtype /Type3 + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 177 0 R + /x1 178 0 R + /x2 179 0 R + /x3 180 0 R + >> + >> + /Name /AppleColorEmoji + /FontBBox [0 -102.400024 800 697.6] + /ToUnicode 158 0 R + /FontMatrix [0.00125 0 0 0.00125 0 0] + /FirstChar 0 + /LastChar 3 + /Widths [800 800 800 800] + /FontDescriptor 156 0 R + /CharProcs << + /g0 152 0 R + /g1 153 0 R + /g2 154 0 R + /g3 155 0 R + >> + /Encoding << + /Type /Encoding + /Differences [0 /g0 /g1 /g2 /g3] + >> +>> +endobj + +158 0 obj +<< + /Length 669 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<00> +endcodespacerange +4 beginbfchar +<00> +<01> +<02> +<03> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +159 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /HBMUBH+LibertinusSerif-BoldItalic-Identity-H + /Encoding /Identity-H + /DescendantFonts [160 0 R] + /ToUnicode 163 0 R +>> +endobj + +160 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /HBMUBH+LibertinusSerif-BoldItalic + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 162 0 R + /DW 0 + /W [0 0 500 1 1 514 2 2 479 3 3 646 4 4 426] +>> +endobj + +161 0 obj +<< + /Length 9 + /Filter /FlateDecode +>> +stream +x +endstream +endobj + +162 0 obj +<< + /Type /FontDescriptor + /FontName /HBMUBH+LibertinusSerif-BoldItalic + /Flags 131142 + /FontBBox [0 -237 654 700] + /ItalicAngle -12 + /Ascent 894 + /Descent -246 + /CapHeight 645 + /StemV 168.6 + /CIDSet 161 0 R + /FontFile3 164 0 R +>> +endobj + +163 0 obj +<< + /Length 661 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +4 beginbfchar +<0001> <0079> +<0002> <006F> +<0003> <0075> +<0004> <0072> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +164 0 obj +<< + /Length 911 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xEmLwgpyWHM7Ftc %[2'ǵڦW(}8ںhJ2+!n$ɢa2b29^~~eeA갵rZMNr'JDI:j Е+׭;)]y%Z jk5Hݶj=^TjQ*Qkښl=>gFZl#laOc}cCc}Q񚾝3rf;gCdײ9fgEO{2RƪB6ӕ*ɃmKOƱ-J1A)Jrm Jғ"ڒJ(O x9BqBSez\|}9sj6n;_莼xgl>`~nl]=g[qmzc){6ywA9`gpAC=z łٿv,fXR031oʙW$2 GIF#o%܃l|h+Yz E7&ov;-t&)i-NrdGY3_e|Czn#dw|Tfli/tsM|?O&r3"wbQn@6w)Sh~^dæD18cSkdp-E* 2Fy/ +WT%ͅBJGP|N\H|h@bSDza$$< ʗ]2 do}Syks+] 9iwGD&s^qƓǛ&:|FsѸCzݭI~ 9yGo|zS5Sn +endstream +endobj + +165 0 obj +[/ICCBased 167 0 R] +endobj + +166 0 obj +[/ICCBased 168 0 R] +endobj + +167 0 obj +<< + /Length 258 + /N 1 + /Range [0 1] + /Filter /FlateDecode +>> +stream +xuJPFOUvDD@`]\ +FMkIRB|&إnऋ(HrTų9` ըa&ʺ:l +3Ŭ*ުnh)&C|>b纝黓AvCƫ+ y') +̵8+/> +stream +x}Kq?UX 94%MQKSN#ԦQvBˡhFk ! +ՠZP~xx^ޗQx"^P c!H0 + 0l+ߣy7;׫;Q?V._tF3LEK)y z80eIPkT/%[p:8+%d"G `d_{ٹ֖gzm\8rSif1\CU` S] @o _ +endstream +endobj + +169 0 obj +[181 0 R /XYZ 90 736.11676 0] +endobj + +170 0 obj +[181 0 R /XYZ 90 684.6368 0] +endobj + +171 0 obj +[181 0 R /XYZ 90 549.6448 0] +endobj + +172 0 obj +[181 0 R /XYZ 90 232.58777 0] +endobj + +173 0 obj +[183 0 R /XYZ 90 604.08374 0] +endobj + +174 0 obj +[183 0 R /XYZ 90 492.30176 0] +endobj + +175 0 obj +[183 0 R /XYZ 90 370.38876 0] +endobj + +176 0 obj +[181 0 R /XYZ 90 761.8898 0] +endobj + +177 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 186 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +178 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 188 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +179 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 190 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +180 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 192 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +181 0 obj +<< + /Type /Page + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /ColorSpace << + /c0 165 0 R + >> + /Font << + /f0 134 0 R + /f1 140 0 R + /f2 146 0 R + /f3 157 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 0 + /Parent 1 0 R + /Contents 182 0 R +>> +endobj + +182 0 obj +<< + /Length 3979 + /Filter /FlateDecode +>> +stream +xɎ_AK=+`dH 49>(džrm zUǥ:E*no_9o~=/1vfbׯvI&`W<뷂u'دo7;nvI57w߾NrϮb?aϮ+z4ݳ%w;{\\I`;'홟a/o^]c\.dB.d Jmez4Gx$N^hAKQ񩭮$"} +W@zrr&޸؄d+hqV t\q|DZšY4`'=^;\;u +kk Bt.#JR)H`:F|J%SD8$tSE?&MF!Q#F#8;L _=}{d/_'>0nM{O;^p܂LwoJT4UYkT!oYt>s|7,j.nA;W9jIC), +`#@hRݧCɁTёMz;b$Ny,2&FR!J#z=K $%Ta8c,SLdӡ: X73Z$d՞) #M=C!_M +rLEG>&oڗzPF`EMQYǩ!- ٩sկkdO&,d6цEGe:B)>jPk6ZIɍټh0}`SVC'ۃ\ sQt6ӂ%6|*El_N9 V#G5贳oҗ \k G͝K@ɔ3 $(M e],3,)f|F ^+" +p<(hAIɌ-\"Pή4XNfapPD)s۽]W +s!IZ"0dW:ETZ,3kÚTPW9J0-[/KrS -o< Ca:ϔ`$ +q4H\4 +l@` /@CΜP,7y8k88J e%cO͗Am͍ $\<P-Mæm$%RC@9%]Pfχb%Egb5F4=p<0p7M,fvz CQfC?3ݲT[;*#J5A$(Rw5H/CK JͲy Y%]\nIܤmB%[5a`6*E1ڢS]7C8\ٕ9zf>|ALK<Ѧ5{(x^eϛhC",Sh-&rK1ڰaumRl6VFq [] +;ٕr/ YW,)ޒnȡ`]-|T7?% 7yd/&LCYVQ<ʟV%55d<uÝW6$ +&iBvɺu${j%D'b].>e}ol.;`6y4= h%FJc-'$5yȦ)띀{Mb7y<C!CyDi} m6y~^q%|5d5r-[VTɍ!C\q.A9a;d`WVYà +$9q>{[GW7lt3̪Ym j +Z.$AKTɩpuԔO +'uzIӥE^d.BozFBZr]5HPdSrRFڞF3)Qte&gz[ӱ4zL 74›7br[P䠻a3CӂQ'0 i=Ls7 %AsCޜ2s&aƄ֔XBtIlwLš iYzSdH΁OLi=I=[=POZMcȡ[¾ZN- ]F(1$qKC o_Ip]Hue)?~&5r^ :t +h?754NIHm-j8#3tiuӲʥJ"`F;lc9b +ROPt>:Ps':+AVOܿ nC qȆ.I!_*##thP][!`P*\F{,`p., b 'A/U x+X)M# ֖P>I=.RB)CJ(|45blA<޾o_~8?~ow]Ç㻇᧛?Op0c U*Syok +endstream +endobj + +183 0 obj +<< + /Type /Page + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /ColorSpace << + /c0 165 0 R + >> + /Font << + /f0 146 0 R + /f1 157 0 R + /f2 134 0 R + /f3 159 0 R + /f4 140 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 1 + /Parent 1 0 R + /Contents 184 0 R +>> +endobj + +184 0 obj +<< + /Length 4958 + /Filter /FlateDecode +>> +stream +xk7,~P)(|3*^˦ +=5;-iv/wVwnwËa~_ |˯^mp%5F[>yÇ6/o6|y\A~6yo9[9bpuǗox?ᓫ5hw0ӓpׯ.R1i "]J+}XW)%].O-ÕFڋov^YtjXV=RMct8vp-._42%rJ۴M1Hn^H927J!AH!ř|),)ԌdOy}n|d`4-_}?|nw7[I2^G 4/ⓄBu@!Cn;RG";nS@Ñ,~Q*،Z8=ՎiYj'39W<>xomzvqk>c&\K@Ɯ6oT6MNI 8 +3ք\nZdt{nz6ϟI&<*Eja>x1BVOVُ@7%H&giS&:Sz*\?/ˌs;IpAU@;l:s Uc̘ZHu:0#-I~{}]9OER 4b 7CU|jY?p.8G¶5MjZmRɄnU)aȩWT8'R2yn_H=`*P bV%9w F̠Y5؋?.TԘ̓- Yn;H:' 烡E֕xF.jQ910UwAfoo"3E٠Y&`ZWz!M!s +td8>dzI)yLHg :`v4dvI8%lD&XT}JtX+a R!4G0Ml +Jô=`|bd`$J閊rʮ6© P~!߿+<ÒjXr͸ +\- pǜqS3Աp`*t: ;YXyfCpLתjVE׎.@(O#`p#lr +0 4 9VNqcVETL8c\f4[惲*G"Gefb)MLP6cޥw[s~Pw +=F]79:BBJ͔gq?=KBjrq"c&Qd#3ڵ'y2] ozW. 0#^e[U\^TLS +*)-80"pR)6}FdvrT\ R\~ 9|'E@[(hw +,ʳiw1rJ\%z2A +q),C( X q5h*&bd^aGGC$)@N;׍Rtv=G3JF{ȷ^ƌ{4 KpG5 +o}O _'$A}T +i0wW0.L=E +RȜje5mnGc0Ło咴S4>~w K?CI^Ч"F arDf1| f4sT;,c;)R +<\@>wtd守&)P,hLmRgZ6a09FK((:Y <ًn r"\m gX̲|kyxE 8Or"dF% f,flRgc(n;ɤց5$@-N jl| IQҩ 7cR2k: GO(T4'܎?5`l'C@g26:֎0SCfCjA#ظ鏯s/:x&.䉆 5#E3)k#Kĩ'11 +ʌ}4ambNk<3K9d]-v,16g]ɬ|cP)AVjVI r.CpN]}>,,Y!^y U kr=U*&[_?9F.W\1縆*H)J,@జ.@/nx&Z-GV,JS&˴VQ$t, J֒mzΤSHk∼@Qb[E=ID ㏾Ircఐ|eJ:֫+: Q0+N ["@9@ ˂DC`?%"b4(4>W2F`fA=:2 (9+.@~X.Oe} F S==H&VbUNcMi55eN0yxPBEЩ@q* +H"RXJXS*ff!c~~x‡A9ˤsث7>y^o7c̪C7$-)#wzUsh3 "z"ī$s{/X(MҲO)˔t7cfq棰*AոXV+x *V >;{?1k*j* $I.١@"" w/j>uNFC1_q4} c|2Цf2_n .;3mP4]ej[r4(0 + +1\Yڛ{py\³18u + M:ts\(9rqX:X佖A)me 9t97)F7;ꏲZGĭJ`'n ̺Ei&Tޭ'}m mCS@ye}5O0 Ѧ~sҲR]#;.'̸ֵDE)*ifDW b{-ҧy*)c3Șn&\J$'oA_,HJ*Ŵ^p]R.9iRV-Q)zD.܈;%4gsg/(e2 GTA^ZГGgNyk֓O/303nȖIɇ-t䳅#4QI亄Q˜96U08ǸJlZALS_-b / 2Ad U@,@ $gFn]k98=c= |bt eu%;5k^c% &N:-2Fp cVoŸËƺ.\uj%p-=ID쵫l_\NFkذmt8+%sܢ4Q]NQjD$Yr4ic0V/i+!ZDDuOm5zzukdRʰ(Y4m~U/[x[0\,>{D{-=xl AҘyr*ŃXXcXq x/.oki]lo %:$y b/1"' S^[ՈF]Xt|nn…>C38W]Ha ·tLs˶|ȯ,l&!.ƤVXŒ%QGq>3T=Yovԕ_±([ܜ&kD^oͧiń#`-Rq/r$#)bQ.ʨըD 9"?8BG$rN:EnW + ^!S|WEnV=p#2ao*PGśZOv]-3j*ltM&"{ <­ϱ 5t'UoƇWw#lJݥ>*hIK]4Фβ&a-V8}&`"t!LKL/G*'6Ռff*YT/vw [2uG Ü"\"[Uz_!0EƞhͫP<$joD]|CS6] ֿ +2Ź;gm (8+t`Z˞VLrp a9]W4A^WNs.0+K|6HL5q]ܙ(Wm]kZٺD-}3aP}he +{M;B8,~i^0%]֫Gh&|fׯ&uIҸ:ܴc.Zh7mVy\:CCy +},./tT.P|C;njK $۷|旻z7\ÇO7v>0!=Wm٦ՋLR +endstream +endobj + +185 0 obj +<< + /Length 1576 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace /DeviceGray + /BitsPerComponent 8 +>> +stream +x3i񏄃[$tQEVRb]cj3ntߕb"BWT{>;_߾ښT>;s^3?8<i&;@BBBBI+S%zfcr_qSlܓqa޹?-bƤ1&}U{ReӽB$n-+9"c Q3LH\PVۂT tbivD_ܴp;Ս_YYaN]|fM=HKI8{|}̼߱GW{c;EoZePsO- + ߕz1];g%}O[ꊽ\-o z|++ąXz $-Ⱥ {>s3$N Yd#aȥ"aե⑰s +% k=KpO$,E/m1`x<@>Um d=6B4!Y +:|!Y2$k3d`L7rcFV!Q-L_b$f,ӧv *5f Q:w,an$Lg$j?E=AV}پIMH;7J$Ne !IuVl_HR)ۧ$aK/ΐbk3ǝ I\WHjop\ߧH7 js=Aꭹ>[Hг\T5q V؇umCH~ Z#A|c+Er]>HN-ߧ}ɩ4."9E| $*Sn}!9eBrvv˃HΎ}[_? s>)76| >W?|#3Bz|_,tJ#HRA_O\7Kj$Չ#z>#:[$r}? p$׷IJfǯ_HmmOe`Ϡ)ޖ)llEl7{Hoۅy> +stream +xwTWyϙ̜IOIĎ+M*EBP %$zG]BAfq;q/\GŽ}z[gm ًge_r?C?Cm]pG':v\:;:]<}扙+G'{]YcÛ7^>{iPst1oJL^':!+v9t(ocvzqVp1$B#B謢KZr@}I@92L]6pݺڏ?wp&+'s]56^4FS"w0<+3QM=7DZ%/ʑa VS'ns}uo m8m):5+~`JqR^ǝ-}yp _R?H*H!0졎`zd@@@@]OyZ"o;;x)ꉱ-i:VވKĖ#X-Gzot ? 5f/YSLM/'g߹yw~Z+0ΚjKL3+q̿?wwn:#|.mIGw0)C 䡎{6z G8aG?e ao`{><"WWy%C-3]_o\pp\['m+߹}ԹNI%\gѦ+'chwogqTYGqAv{("<wtitV.1#'3O+. ԏ +L$! C0ӽ(7G* +[A= ٵ -60eׂ}-!Lj΄'ĵ%b#(5 Gwqa8DZH+co߼~t쌡z +;S{|OIED%IїCpOy6}u; !SVFyM}m_޶bQZpy-ra!jd֕ +(OKQ0\wnk֛<Ю5ƃ#݂}~FbD`FB6vIȐ {f+#]+O. !ډFZq؁YȠ(e:?ui_t =Bb'kHrNjg{j^zr?ֵ'-t:7<MS։q`_OO`P-e@ZEi6HC1|< i_I{e]Ay,%tv*t(+ԟрXML*?סN|W E7q-\+,]>݄>eka\vy sӿ\?߻˃?y|sƝcqԘ>2f2u4zeVȭ +p0AS=ɱJ ?~)c6k[/h1&LbmGHMuv8Xwl$Nգges ʟ_;my޾ Lӧ|1ۿܲ[-2IN5[V}rzbcGMO&X~_ ]]A-JTby-]X{`zފ%+}q=?wn|C硌{G_OL=9[P,EihwWnd|t7/}oxpG?{jkNO>{kF2Ѡ7[lvԛYONLڧZ&fmf{FT+iP5VʪhmF*82'Kÿ=$o]2C]?m~f֏~_o?|3W 9>s+WΟ=3;3e5"ZMB! PP׬^y㆝[G) TQReҫEu2ICc2G-VۄmrzbcSGO9>y}f:u X6<:>08m2*EZ#㷋Ȣ2|TOǯ_o\AqYM-/puUm-jh0bѩ#Ǧ\+bmok0u(t&Y/dž;o2">)v8ŋW޹}ڕ}etǨU55VU\ G |xݻc-;<7ڻn!S|\0UFSJ/GZ_=alj˾/b/Wl껵˾[튕Wٴq-NM 2r|ϩ~-* wuu [lmr>u>}>=74f>{t>|6x0߫W.;{̤<2cP+$Mu">V^GF#I0XHPHݞ{mߵiמ^/d}pFpƖΌ}$QM7z],iM8o|V7^f߮5KWV|ju۶lڳs>hh`, tBȥ<6Jܤzk'&51 +}lVɟa8yjRZK$𔃱`Pp@^;woٽon~n N/! @ty`=Uyy3t`O|{աsNQx(R<U5%E"*Dׄ%~Ϛpi'{%=4A vg @U(K$ dwY[3*6&į 'b௶,ݴ5[\U떭\7lضu˞;샄kjjmS₤"O ]?jot:%\%>gW]@Ӂ#3R 'HGǜy.pC'ǝ9Μ#.ͼ̙~3=9O;r_osMP>crP)k +y0~W;'RU]=S;[;[(v(j0r v1!Tu`Էqh=9`}~"(qwWK~i?l]rW+V~۵;vo~O_Ɛm]$QPqƷ&/ft5$=DpN}g gݙe{cscsYZ_*j]S;hZ@t] C42  c  +bsBya_3X`"en,Ʀ!A| y5i&{Z1ΊR2 f։;SN'~Iu:q3Nܴ?O9 ^&_'Hĉ9iAtd &\ Ivșz낰t[P!Z<@|Cz=0F(tBP^w8 {a}0Q?r rZ9 yMz?ʻm1p0'x57#}8>$M;Iqg`i'zҙ5̲DXqG2\O>uG1Gx%}UO~YW-W+*~J>eLNXew'7? AARm]f`osɱ1JPW/k*+['Xab`w݁9pV;p6 9q D;`R;7| ]A_5Opw\#F(18!g8H8.!L}06p|)=u1G0gWX<;gy3?-sX<Csn^\d!ĸÍw^" 1OV4]_] oҷ\['*T~?.n 30!U)`!ic C!Y9DnΎ9٣ڸɽ^.8$~"1'~At&t gsou,x Y+@h{KV@/0a^0C&;_ 5A #ˀ\ֆ0.@5FQ|c4G \C4WG]SІ0A ֯} gu_Í=B?>Ęϲ9PfG 2]co](|KY.&,G@1&nD.jmJV̫X%05F !faA5A%x te5 +49yRQnB|נhY/`۷Dp92`g[vc1zqfx3t;(rІ]kpM! ]Mev@8P.coEf|C$ փ{Ix(1g"z0Ku m(CLej+^X6K^=$Xϐggp3˭ne!|]u1uEq(,y%r1\9OV^h ]FFtS4j +oʟ as 0!a@k4}^Qdž 6:Kܾ464(Lp6 +˜:VfrlQq4y縱'Q!0S b˜0CJZQ8m:XTD3P>oMP1B`t{9)OGSڒܶ<~K-&0PՃX0. cj,-Q00&M}3rcy4? +wu1¼Ex<іN^OkO=0fW@.a\h0Sꀰ!d^ =,?(M﹕5e~ww @98˕|scøwlcw߷1'^f >`7_zw@St~d-@ׯ#m[c(pn0 zBOl<!!H{[['GΞ9t;2s>@-"vw F p\g]rb/,s5Q䶔ʪ:hlj)Z nW +<-X-(z3ZsݘJiU6I*T,"Y';\%Oi=u0PkAXKweQKb'Wys9e@Rš@89udsd$+P"Xmk qޖk%JSF' +;C: ȕA4Atueay5~Z>ep>`^OtwJKkrv%buiÐ'ڵI'rԑ5@|0]|f?@HIn YYh +zK%r\Mg*kL(TԷ*[$ -r\Ԯ( +^Jam _ DNk#EWTiх;@,&߃4%7[]O>˵s3:t +VhݑR}h[6ۘчlOqywY2޲H9標ypYHKA8&0 kn wUhȺP3C5m]ukz4 5;|Rn3\{,Ff^xd.vb浸iY, 6 U! FeШe!$-%LL1Z~MkGXiH:$UF$jC\,J5zڠ&RWS̬lYu .`l-SPq}JZ4r'4>G]YVG n˶ٶyu.o^lC] +Go͵>ƾ6 .61L:4u]t!Le 94jz?2 㮙 6Pe.f|C"KyqtLֳ{v6T?~,C u.&|X 09xC6s-^*chXY#?-=Fu=&RC戄 rF12b Y ė6&iGB׮4F"6Km +D(uR65I `IH6b hB*d^Ȋ5IH)lM4rj@?ȱ͑E͹2?|heiLp6mh}ݽuku +ʢ*eP b݈CR tH b U:\!LWv#f`O43$ <<:^_*ho[pe=%)'?ޒs‰Sb $c'_4P1eiI.,W'N-?r+XQ+#pJU zcWWPTQ֜וdzYmQ)jP4K;djTm _U50ntʴmrm]%q+ Mn|cy(LFŽc*n?~}f7 #X\9Mu]}q!ú! 4lwt&д\%IԀ:aLa`b +-{L#(؅Qw9S]. KgQQ)Tؗ{҉Ϲk{؀1G͹3 ]]`ڮԽ+S5*_]C[-%+S1Y}CrlA3Ez}r쇙nvR\3y` +*7Yx Ѷ7(STϮf\)1\i(EO71P6Y0Wp`ZunWfa-Z,D O?uejd |Ag1y88ȝqLvh\uG 3riڣU~)}54|/&y +c~|j,pDf[N51:9]!T Z{74M6Mm]o/VVmU5K:\¦'KW/G3&Magg =gNܨ +oÛ`/6e]ȰP6EaL}ŌjJ~;ڪƼSNOK&$ݻ3m> +$7|먚o;~ȵ'[__?~\ߙ9چ%$Tf{(S6M,5ז_)ϭT( F)H+ LQתnZS\.b]/4 BrO=$>Kje/~ۿ<ʶ*/?@䅳:-=W GoXlh6%@Mnޜsyu=ﯫL>A0V OeZ^oxs't&yuD"ZMDi+ҾF ڪVUuT&QBm˿]؟ cɲD.OWDv3?"X!\X놋=O}>i2͎tB9eG=#~8s+9F&O%<>˥0j[]28 +7BGD~Gh#yz0(XF Q,:md'3562f}Yh8*{z}x;$QGpWpβ̳xK7`Xne=Mz̵:s8voϳ{5)3x:-FZ h5+ĭ9 6e +u`! c)Ly}J24I:J,hhԷ~,+?.(#8!q`Ԇ1ue^x.MU@/naGaOp9mεűˮDLy\CG) (<64?ÌFYeϥYftZp|'.mWQynYU[UU UTl Q*I8 + }[3q@.7<cQ%U{n|[%FO 펜oLOuq}R]3$ꀛm'޿ՇSWߴb:s5P:{{ǻ5}|(F_/ԴfaMObwX a(3,=̬nSJhiԵͪ6 +뤩LR"Nc+q|}$0/P>*/ۇ骸ڑT1"z.f1 5E *="{43'kݒı{=VV"W3.L,Rc# Ǭ;HK Fj[TV7荝F^m[$1c:=,a~#I(M(ùz|No(-a-MMjoBC{9G^.^xschQȱ?@,Bg=h/voo>c?ޟnqa*&p[j%MX&E.f ĦX:]z >K mUS]V` 9,jm6PXEa(]7ܛU#)LPc06mc-o#mGcS}GOgYYhe_/kl%SɾC: kT6SWR}3FG%x|BUvBT˕mmRJTJkIl)ۘNk P./ y6W6&.|vT&~'Zvۺ6=dh뷒p}?uc= L$M,N<̶o_>V4GR"mazC=^NrL.0[+l.7666M-RHەJ]rbQM]}CSsSccSc^^ĭ6Dqn z@.SZYR٨m=} ጁw("x1oI: vyhۃ~Mΐ{Z_~%vGoKoXݜpmyI Rfu^ín`S:eɿ\\_,hQj;eJ=\@QpA@|6TZSrY U4HYԮqZlQsCx] g6 o7ⅺx6u`QPCۏt\%N %D4 +f{ I؍t'{zǮ^* ŕZL AmzyM]ӏ^=J?\)e3 qEzϡ +JqeUM-C%d*U*S57ѩ%55ֶFL.Ň H8xAQa SVBM)u@/(N,^2ez[puV3>/Zv6sҔ}!l⅋?^ҕ¹SN<}cfs4F +9RQJtf_7\usg^)Djrd8$t۴XCD5XzCaLhimԎv'c K[Aز2nc\/U{2]CVPoCk*YSݑҴ61LcFJgɨΌ^>~YɹCxr9*1y8l< +ER'<\+౛[Z*"q\^* +K8\VRt\qi00lx\U\soQm_«q[=$pUh.HF5.]tѹx?pIդoP꒙9d4:{:T2vԘT֚r8c+G/zSWz8Ҭh8z@d v1\U'tc_6BST%OJɤM^ yF?$78kST#0 ,)y+RK Kvk +dlAmPT4%}Tlyh>#C5fL(d[ڮnlQV<R )AtjaT.SZ%򪚚v'WШl&C'+ +it*^2b' NHL2&~-S?J,9 SL<1;`s-OZ=R,aiswZ,",mz \ bf#WǎtN,΍LVYo ibiie,,`Q8\Z& +fCFfp٢&4GJ[ +l}G| ˹$5Bx'Ntٺ|jo\9H|>:2k-tesR\)z`DLr蠠<8_F.N(mJy<Ʋej!R\1N{+v畮)d!DB +_il&WQg'`p5q"6#D+L$*-"/7dV򨕕RRPXZ؍5A{?B,6; qU?hSNOζg5y<Ʃ_H*}˭.HC`TIح٦OOG?\!!q|$_No{ ~dԴM}ăi0jkKQf]Z +E1W\)`$v +MA6Ӕ`^}kgb*{"UmiI2܃XlBQ}P&i&\k#l(xR4&]Be#}8L?]isSS ))Ae`)r,oVC&`C9:(WՅsEp<";bJ}CK1R|C,;&qz߽0x]7۱qO\.lK7#Ou 7V By4rEBDG0 W)%~Ȳ݈ Y#so^5}W^mH0rԯ1RAԭ)KR2? `7[ GK]̆A`N'C@ `~opS@LXܣ^:nZ˩#GA"͑='#71n< -63G՟^ǍܩncTjtV2$Dy9 }hB>#)mCapȌ/r(|?0sB1C@B' +0a Nw K`)e  CXP!\= kJ/2ŋ:iDJ;}aiĚkBED zQxU] Я=vgnٝa?ڞww<@n;SspbE?g~\^执~޸څX1y2/Kve|/}擲"`` v&bR1P '}?BQՅQ P87UKGk@P{[ -Im'n#+v/Be#M-d8s"Zj,Vm&NE[2! (>+p~Rw y>Q l߳+l2uqXbW=v㤪Ixek:֎'y$pɁNEx8%m;҄{YVvaq ;ᛸ8f:ru}0w+Z۔oU +=4Zݗ4?K +3a[^gw!<[lfϷ+/߷|Ł+ X +[ge@<tg|bC:Cb(G \luH~+cx *ɎRC|u]??b{@_?#}[O#rdzJ)ZJf8^!}8^]u݊}]ʵz6rq?r%)_w  O' +hoC`$ENxz{ ozuv6Fn;#AYp^c)숤/I9@{1%0ʁ612:.$Ea[ݻ?; o6@ a e $DpQ,mb|gdﻻW>PwO?-ӇQ@}G^KȶjƮJbǙXYU@k>Yr& wm/.Wv${asVu4.v/qIuooUSۆ8jٓK]xw۫{voQQܬxD)Y;X=0[ h4JeKji1:W t(I2ƻ:^p [y푂.# fd7xS{Lc }ke@Ě^iK~4fzژw¶$T?O?Zv$Q!SjK贪 +]QX3FOkԮqJêȫ_{isc]Z~x1ѷԽLC +B +7Vs!q98t!BT rӿT%ՐC/E'WĦz֪#hم)__@Fv^WmCXz\,bkcjao{-]u7yݭPG*)һU#l>M'~pdxqţ2CHȳ-.y +-Xp|vV  @^H65IكMytB\4Ej-vچsCiMրU7#7Dp?uQNfvn{MkJK9T"W*_O?x$2jqkٚp6b~75[%\h=zO5*(r0P>eNPտ] vi5(? YF|90DUTۘKչiqng|G2_A&wQ#x{} "4^+bpd!7nfoj(VU=x㜕WwxdhWo{u}&zhݱOGv;#pl?8>f/>6Ҽf7e盢]ݬ}-%GsExa^}3N!nU>п֞ݸM~ݬ~ ' Zk+zƜ<4Z,ͩ`Λ o,ehA!t-ߋVvQ_D/S\nΛe5aZbv\lrq ڨ$s5 gUf៝:9V{vxCcC%{.:М%2Bk8vEtٜ=C;RI2z9".wߨlڭާ7#<|$9||0O-UʝQ-\+9,͝ؿǾf3RT\ھ򝵪:YAyZa% h \ع1Ti 8$G=N/qg)k'\0XQ6B"@SG_w5GB;6lg=Zm၈Txxp(EtW',ziTZQG)?; +T ;*=2n,=0>E@Yo>E6~Q~۴<ꨑ6^7]2.z=5-z8{EG '}]p}Uh^0 +̕uoE.ػ™oa>vn Ѿ]H_૱Eߩ(q8*m|lej{ +I+՟˪(4UaZZWA|ŘUymY?|f 2"OM쏛j5j \n5|(j7Z ВFIN#W3.QU!e@_dh}3hJ5%He/nj= +f 6Xy"xlLZvM-.Dfh`@A,5`'lBt؜p[]Ѧb avO7<_8DlY5kQ5j~WJ^8zoƪwv&9iWߦ{TuLX*TFV,a %2KW2$WyK"D(&^秔.YvCؒ\BB(%pH>dƁl˻Z߄~|0,hnC[t??D!Oq赱F3G⇛0ScVo,&/5 X_j/GkKVojǘvUO +פ F/)kDœnqAXpsP]Y?M+%dKw\(IHֲ%gM!ƧCe +O'1#q6l9v}>!h^}4*@4&3 *J@p@&ev];Wjg ܨLPɍΌAFLRYʨOÙ"aZHЬi +IHeLgԔ =]=h"lt6_zLz§4ah[2iWE6N`m [VYO:[]jA^CrPnH&)+M;@;|9ЄP갅kߋs:凑(5CNOގV ʱ} "ݟ;#u%?dśj# v?Ͻ4ZUѤM +NuaъQgo_?wȬ}+сtep6#] YJJ,*8D iE/( CLb HYyxԇҀg=O}/i5̔Q_POV};+En{7};t'-DI+Qje3l?FS{-kQo j6dJ{za'̈́htCZeV^_.{c"ejtn`nHH+ Y䋠vdk++}Y&&ՐF+=ajG60_ lPLg,fҒ?c!/f_vVguc~{rI͹7P<2֨3XRe +C |_?*Z`~@@~J~ɪִ1ُ-3 BYJzF f dL̎= Gtn/z#Kw#!녖 h684KJ,h5Z2yx]Q^zX`+'jJPq~|I!V% wX'TaglX{pruwrҲ5B=/hte* +藥cKELeR)kwp3}İ dWD)O웫^?~O}46<61ОyU479-0Z=o$sVCD.=}vg:>iSN{N>+>=\𓓵ZZiMV6YO|]%/oU#膖'32XqXpU:; kkT1\.m, g5ͷz^VZp| +XUYZ JipaI<ȥ'_Ҟr, +ԡ +n^14):Y*(@e8C3YX>>iJ~JLUR杇T$CGzEz!&)ILLϫ11 a?a3j]H^z=3[&d^zM,8.+ρ7ri`}KjS_VvMG_ȕL?_"A{Oڋ[Q{nUu?l^a%{tTpyVfY2- +Ry9XoHI50Rt@8,$xKyC:^ggY[]aG!΁E")V)_PA 'eX)o-|vDzF\cVZ4#FZr@vpB0#xY3T+01L+3]mo"Y\E4E Y)ny^dϬ8Uzkly=3)˿&3][PWXgxopXםWwoq}f}'{M% rKzS7z* Y p=O~߬RlOJ{;(MA9[Bq :WPq_GGt +qEwW-#lL 5j68s& @/jAycsc<[bYc]o +T~J[ /͛W;WBNy"<8㉱p_ Z@`yVu +O䡵qznp+៨}⢳Z@: "Y@v_mӤ1Y/M'U;(Ng$;ne=κot3.2=YvӠZvC]RFާLj32?7;Mv?O$ +"4kx_]88NYcWy&wL䞴h^Ѯmbu?6(^FE )ͅ0liE<aN/fk*S^y1Ϛ~_lngGY>jUɪJbU%YT-Jq,oc͓H[X'=:a~J?dsZAk]p?eQSa2]JP0_"_)qytN1WJJJ#o.i?3M7Oh3ȢRě+qDl!% +l!%Dgǀ8B,Ge_$pDO6pRzhڎ 7S ,ԢL5[fIL R)M) oڥh 0ԋ^)/z'_JVJRMVL?-"/'>Xj½@5Fn6M}׷[Ǻ;G(֠̍u՗[1='Tq)L$|^a2y_wD 0lMj>I3tVkXA+IHTل}2<&|]9&0j绦 3 f՚5U +ەh+9%Yr6tĺbȲlS6*CJF%è1Y[{ X]fOX3eMYcW<=czℙ^%G jPt#I5 %e/bP%e̗pBT!g(U Lk]aTQQ`r 6ԛLZYDXU!bEЂ/ -*sќi4{͞°0I4{;?LcNBGH + \!?cVּYen@kzǫd35-OY9fez +**ƗgJx'Y?U7u?Jmƒm?4s؟-o\қWm2V9>^7v$"uշ6Uk57>V#+XbU1E+FqlBqJj5BG WNxx4/3AQwU>NER.y=B;6r'% 7K5ËB̊2o=Ψ ?ˇk 99/Xssns.msέsέ_[[8| n[:s.snmsms:4|.4C'ItS38ZzO~wX}oQrW:1<;\hVG+yy^VQUwF+4]ƚjK.k^&?ͦۮEm(v& J֡vʨDmTl4)@OPT_ۯ85}vn٩͖96(3cJ/sn_nuyu}֎c +RjYF_]Kx}9:WI7Hh(+j`UKKyݫĿzouݛׯ"^%ZvF(Aa21?d +"I}oy + /M|ۥ7,DꁨPł#`8BY|I+:ͱgYd/Yn +LW)b|!.ŖX@~YPpْ5m󄶜i+֤MgT@֩?*.3cե۴vZfv՟k.7tYsgAcV4lV4dV<,4+zo?`okL16260a3zgՏ5|ql/.=e6Ր]*g]vwߪ0kǫfE ԙ_yv7WܻPEuB^$ J'T- ^bF;D:Xq%ּcVXnhWBq\8-‚a9BOrU:*@U2) 9SSY9VՖ6 +h%  `ohي5mǝ +mB wWZzw]y=Zz~ᄐDʯ":Ȝ%A"aEJG%CrLr{=F.bЮGd_Uwޯi-v!==7Tzf:TAꟕ#wW'])K|;_^З5C2\?b [mT_oW QȜ&Lv :cbY<[FaL0TL˧1e2@ 0gMYTJ̊ⲭO>MNr#%3loy< 5Ϸ/-ߑ+< +퇼?'J"ʯՆ>[9ӟv]yղ&;`3ALl>& Qa 2*,C FQŀ2dĬpجpU<*B70a{Lr{:~ۮi:ulwnzI mz:ZO/.r7u$ u|{@[1}]匛5ya~ %Ge_c .d3+>D`IӘry 9YB,[-,OݪeXȼ{]Ϛoi=(~25%&xx5 W_@ F ,]w|{>'e;О'yZyj9NȆ>d)ݩ[-noH3 TXv!_(zwB] |`-ppI]ѿ+gs A#oi͟# \k|K70Skt٨Y~7lFBi[vM0CS&9-/͙S8"p^p]P`7DvJnp^ȭ3->i.9nFq>dٟٔ8Ȝ`بdpqvia]PNo"u@ up"S)Io5l!+5AHKg +- Z %f\(bܦRP4[gi.dG9LŤYAǜ9mcX" +{L۟xzGm 8}ⱹ1a  +_wp,/g6 +0]"kȖ'Jo([Tr^r=ߵZMhkrwqC˨ReT8xY8$[>.3+1+uޠO.-[ȥ? ʮZ~u2^T^.,^S(SU*s'Qğni nK_RteÑ8S^Vfǂ[EV)Y:Ȫ_LOR0cXΌ9[hV؋.1gY"s6Xu{iRCgEE.g_J(!Sa91z|C +`$w 9 +v,dgOG,V٪R׈uFޫ|oox[>;tЄJlj(w Y2.Cu{dO0_Vmoߖ[&_\-*?|OrbsڟzAX j7>bZM)Koc^?h3J0,px D-eOV}*R +뭪J; X4g9K '",[cK\sH77+1ժBQ4 &&bA gVpK['(mƢO@vu8؂+!rx؆/T_Nx5Շ̗;ʣBkz-um}wSNov~$_-F͜AM5 " d8w\:2D ٿ +:C4LgMOBuh'(Lg P8C!M% +ȷZ|:Q el^)Y`gр`лuΜ#Bb ؂#`K+?ѻ rs҇nZRTFEs>b #8ǙDX-&pOk:06? Vp w0ؿ 0_{]p7z Y,KD䊉\{ǂ'-PR#[{5WiGZf\ݹ;Zw7ˋ\a3e}BiTP)lqT|Uzadi`gȭ{z>.qN]Sa/53mC e4 @1}cU 0o(p|&u.g2ir8#4Kdp9bKˇng?TG~ +_% +~t#̓@ FBZ (zE^XBF_z;͹1µᢆ ^|b7%zWl>V$_"4Ap *L@~_<)İ ג# ϊ7RU['re3wR dLggącYbg\VUFx>'߽;RZ)N`D+yI5eJ 0YFJ1qA-YJ=A)%2d݃d]o|u)i7ak^r²i {U1*-\2bulY<,5B;| +9u@)a/ԅ^ ?`iqg_ +S]J.\*|.\/s>^Qv&1K6P|(?5)&ܼr0d +tJ97.< s0*;_5Wlv_Ule(EnJL%"a[y|FZMx2bvp\![`βoȢQ7_<;l'lC=d$BO;( +y}m)yPڿu9 ],_x@j%`l*͘VCe[U!#~CJФ>w m023gU R-Ű BWLa)"G| #zdW8n IbQĿHɱ;Cpx]dpÅ]@i1 : bJEhތY# !O%ᾧ[eϠQ荫yug1ru͑m ցW̫#rw-y{?;k 76z>oI' +`ϼB/ [=/<[$6 )mg.+RTnXs$e'7c_HA:54Kiϟ<3PY:i0]ߴ8]pR"_N/x!G DWJ+%6<5kx}yvA~ɡ2Ԅ͎1.J{+l4aS °L`ҵ׽(}K+i4sj4c7 + @=$Y΅LY i¥|Q_/&'#w{뀘o.nrT`#ζ?4R7P1T6ߑՒ> +^(=3 +j.OpLAE/t', L@a`̓`yO+Nr]bŞh8@?v0[c6[?TMLrRȒ!9l[\`a0OBT)ԠO32Oi fGyr a-o\H.ī~ȣ̆tpě˓XU}Z OR^Tا䒦j۸y@ujzq˱\l',ʶ(eE"%"A!z%`o($^B$z1MMo=3!))ٳg9yx$g * HV+r^'{pbvĄNQ4g1_*QG57 gIj=Vhۘ7ݖ5=Nh2[hŧ](u =(oƋ.h+oe?ͼCPg ӹL&ImdV].,iwomR{pG "Ν; Kr1vPy*B³XOĦ&j3L,A(ꥮOe-?+zլ6Eeq4<7"ė&*_ +wX.aЯmTjW*|Ԅg9ttU`z(kQ ՚P*Q +Ga'*?IT:T0밲lDm~(t3D6ҍ[k? s~0Eµ0_/Y[榜YhG.o{ Eםg*-茭LyKS&+G⥟gO +q@R9"y{ԣxmߩ~l2 +P&a${ɗT4ޢ/X:^8KQ^bQa'`+ `pB3cz(UKt6lon;y|Yl:Co Ȏi4I\o2}P_ѿ_OOKz zcLeթ]oWݘ^2kW8ܳ3g#?{l~r:aE~~/6X _rv#*aRtV/JllܳZp-iU%- +FlB1%&T8c -mq_JyE F'M0i4 +l|H}d |_`csgkgu;"4 +DYņka; I@ۓ+Mع|&au/ܧQ_^TIv`ٗ%>69 ͓*C"*b+`?Y0K ;T8P" qNolؿ+ԭhyeǞ^ۋxt6NŧD(cYXq.ku/&_ 0Xi#:azlzϪ Fb%/P m4{Qv ȶY2 Lblŕmͷ7_~B~.t#:fۺS8)<YcR}M&So9_45 +칽<çx$pBbcG+6KBm<[ ͺў@ZJu!9j@:%NEh(jێ"!L.1_]fcܡU4nW"?gɓI+ؙfvNjheR@o߬ߘsBU{[-]cf`hXʋNB!˕ ea`rz}[ +GzQ t6N'-+'bqFikl h=@IA8ѣ*=$dH;6uPؘ1oN+YvTHKX[rBo{PUGB5DX=868zG3^Vvnaڏn{VI]0d2$9Hjf` gJ^quw+&GYrN] ]!볽|qv0O,sq!HrOVg:&m-|a3c+{ \+`uaƌpBTbRDycB, ZtqP(k3$x&g<׿dm5ʫ.=iH͊gxHedUIDϊ|ؙɈF;0Ԥ] NWU/ %.IAC8?=R{2my DK|Ҙ/xYo +P%Е;XŁR\,fx +0𾪥PL~c<J@L.YKh0Mqp$6VA3[[ҸLz{K/x3._uB;7?`42J_+W%64Z4R? 7዗>wB'A@7Bb|Mƿ\["0eP43$ TQ_7FJ;, ݶByp.lÈ}T/ 㑖c` 1t=U뱏MX?iJq14wESK`ӥK2"g*ד⹳ytZʉ}nWiï pj(ʈF.U2k8^cIP87jRߝk{ZV`[xJL8ɕƁiv GIp(Jbm<_VX1pcv5l$B$XJ{JE%_ N4DwM4k"j9 t +ۙɅc8z:~h)@=sgÑ3p3gU5#* o U^߃j,pDch5o=$ߝe:4:yo.hhaJy\.>(aN'tXzl%]2  +bs"ͨ}Z< P5TE[t\# NVt:́'!ݰ]7Eoqf`Y<:sWӹ}NϭԱk^F;Ե43˟-)o#EbxQ1jn]CUd> !u+NyR]9:O=Chۀ7O@H;uoJr]h~/0 {f1oXm1YDC{=G~N&VR*=:GutR t3)ك*£$`c,ǔ;N"1FmW"x +w`V}t.6V/ٿ>+]1^MF9s&މg>%Z86A1%X)CI<̗}qNܲ'A­ [s6/DN:αgrA&zkKy|;sYRd23PGAL<%$! }T| (qs,QT>lc-:ձ값&tC3m2dexנct@h Q\ZjQ?/jThCCH)ath,.z79L>’>1년+lw v%x0YJ{O,05$Pt!V,1w]/`>ݱ/'T87BDۉ\8Gʌh'Rx\4/!O/.v9 PU( &|I^]KYh_`JъE#t S :lըR*5a/΀jpL(pZX m9V0 wB"^*](b"d !$r=o' ƔF.ĊqtnőWcl\cl+QO0fBޕ.i I0h\pD|chBוC !p*1 h! ߽p^s&9b +5:eDTTr-Xmcx8rI"k:(r3 # +Mk I +S|.7i:ZZӲǮm/#d+ڹKjySI#Q䤬yYJK4`/Ac[_[@vbR$}'2Y]6/pa'i(u>FOa"`ktNP9(|VL\Xm spSu+L.F,CB;7%Bƀ + G޼4,,V̏Iw{h|U&]7|ɎX/:g$w)[$Fzy)P`f; +||#9L6?GB'V^b=7\NJ\BǴֈj:Noli]gYYmx>)G?к?ng4 GcaM* .Dpzs>y/Ow/řj:$ߧ+K3P0"QDܺ@$9܀DZ&qy/{D&K^,V-mۣVb ɨK2i)U#UZ}4jw$uZ:mmvVd9].Vfcfa<{ow:\ pJ (sd}-𧱢m]mWWh|#@Jqf9H:+bE.I$"ߪ0A,|n*,6+,|&+Iܥ.BNyo5mۭMDsIv0xD $dqqH"_v} 8W갔Ң]S&q'u3]Lbr')tb+:fK6V6&;N7/4c]`߾~=8MD죝OFݿ}k}[Gu6S|*hFT0c]xܰeu7C6)؛ -<OLM,h!mߡԇBnJHe:>I8.d6p Ѣ Ҡ*HW” +5xw˶`p l&,%sb6C`HmvB{1ø9N3f%)J(<$n;B4^ܾko\Rj ΄Np ]3KP2X +}\7J J\k.;jkMq?ٍ" 6uW&{.ܝo>V~>%ϨF;#4bqf9ywǔ3sbtcv_Y„YYsScCm{l}@: +RCT糑ԦB5qUNP!BH +B_ЀuѥP Af%>$#ڏ0BZ[5IUz̜٬כ0#SJRc0&Ӵ`jur^)T:FTruސaHsXҳJlqp&-D뮉6d/Zʛ0fetƖjtD,7VDoʄ 3K +lF:˳TgzFdSeh![ ;\) +Cەi͞h/ TCͼzË1Kp8} {P&T V:gC*G/kCUw'PA(B`/ZY#𷢟+WEFք$WjBTZZG)2V"WK 2FҊ)DV:ZRԚqzf^u0)om$1{ffА7V".j@IH>ٓwDlճ4] 4_4=uxL A g?!"_ hy}AB 6PtnRĔJJNJB#SUZJ+&+(FJj\% CHjR)z=3Yw~_0yzuBRoH>rwGR#@m+U5u +[$Yv1Q`ϣ K%G3G?m\&b|3 +ܤ 2)&ԔH< +ZtyP _ + ?~`0r}s0Mai@><B+W + bT*ડJJ)L"R-SE"SQ +D*Lyirb~CƮ"2zR%sMV_{fhQqT7"Ŏw"bѣZCFr[4'1||&>ğS)HJ&ƺdtNtaḂ$խp#eŎ6v3=J7&)%KǧD"|活N7(bAXLҾY+msi 0n\q;i0*@C!v_\)W*POR#j()0 +Ȕx&`*R-bhjo|g>Sd OYu=ve?]/ ÖE{rnqә9pb56sU9F"=zhߪ2,FtoߌlYµ/\&My }P"E̓~Wn/ 3#ƍX<NGZĦs[FrJ'&'&D"R(N 8P ` AOR1h/jsڜ3cw ` '?۫Pi$RJF)R&WajabLY-bBB)_(T\)W(2J89?V³f +yL^;w0vǏ\?ޫ"2V+)y YU5C[ib Hl0 3F4X 4ϢCUkYmDA=V;=)MEQIÈwT "xJBI(H"%c##'^tb<&{r`tm.HS)'$)lt|rt|R()L,S؝=>?°D=H0<  d^_B>q{<6r{}`ȋAL=~Z+RRB*S +0d K)2KD&WRrD&J'&&'=>P |~ďhu:)K)U9W2J,[B,+bJ$y47ϓe +&;EN-EpJ7_NP`@зiޓv¥:Źhr~]ݟ =6f6]8gћ E;mwErn6=m^bw9hZg* +VUR*UB)S(%2jbJ842:>19>%+ +kBY޿|>&q簝ӂ)VT +R$LLNdKerL>)D2傍vx < CBba F>1nagbW {cM+2L#j+S`ͥH˔J%TRJEQJX6>)vGǙc{.V9:׬5kO~!Һ@u6As{LIzPlLuguN8c` 8s}mNfbw8iq06*RSJd/*\Pʕ*ZmҁpX78E%'۽>"WezBV+JB!+J\+UsѪ{n+(LIMٖ׭_wygŊ+x?ܸqcJjZAajN>sk>aǦDJd[X4/ hO1&ZoHa6SgXrV+5֤OfѬ3͋YafA?=gJzJ(wsݸ}ϟ=Rut}io$&VҔ9nD*+))IOOg7|ɧ׭xWY?x͛7efeܵ\q3TEZ_Z!d4LfR$ZgЛJ#ɇFƺ{8mݟ?nukN*-/޹++'/>!M]}7~__گ_{寿[ow>7&''geeTמ׮]jՇ}f׭ߴiSJJJNN֞?\wxdD& &,;x_1lv`1O̙:ôBPqx݆Wkj,+QZn|^[W/W_}[o;^:n˖Ԕ6oM6V7$~VOHwt Z\&X<88u uufeeG}p'%o*,^^qݻ=4228==h\Cz+ 8\nf3f4RlD7W Q 7PïMfYױw-;^<4}Nܷ}x ;${*Myu*ͦ۹榝smT#-gcYifm6dq{v}aa`0DQF37VwxBNcɐdP3V>v_>:5vLas/~ձMvFA։O*/>"xR'N爛_ ý#{7{{R`׬ËW:ΙoͶm2ئOӜTQb%U:L?or3ԯMש̯Oe~]Ma/xc][82k䅻6$Qϛ-o-z]4iHp|J:YYkaN~ai5?*w|3ɮk- W3g+:ORԧjoVּ/?_lL%y{=>Vl=2~c񹁺¾i3[n٨> +stream +x{LGgAVіRJ((ZBb'j)>VS15JQZÂM}WmP>JU*xݯvvfvwv~3qf?~7Q"OjKewo͞+,l1McecyT_}nWvܺ./֞4#!p /N'Y|(qX9,.*</Pbl \6c?6 +e/d\VCݾS{v2}щOd0H|CD ?7,Ŋh#?fZ +dI38k06HeX f*Ik_SenS֤I{?oӅhI@-a? j#U>/g#eOlq)Aue6ׯړ7ʌ7I̖C "75^$2VՑΔXPDEKޑ2~SePr~(p>Y?O8GE-1q]bNj¼畋;FM3RИz趌'#㖦利BC_H[uF|c_?4^)ʑRt)U+5a%J)u/IG%IR7P{b˦.DK'C+_)]?!Cq& ~7д_4}U=3;ƯH5E +ec,hXx2aCh-_CD?CEgGξD|3~" +E@h|m +=%AL@hs|N"$!ZpeSMMTdR=AfW^Ě(*dJc4pgörN\OWaݸnBَͽqZ +ȩ'@9mp{>%+!ۢSȸ͗Ɗ^.< 3g]'I [Dtk51bh٭> +stream +xupp̌L,ihܞbJI46 ٲha bġi#p;<3{}{F3WE-jQZԢE-jQZԢE-jQZԢE-jQZԢE-jQZԢE-߯}2>Ζwg:#**VkjkjZUI}~+~ )ʚd]C1Y[oH24eS-NVi%PJ_аظиRU]i_blX]3bnz+1čF +'G?E-a"YUjnN1Rݬd3miM2͌T}S1Z]Z]RUZ:Ztj.~2fpz!neJsk$x9N´ fFώq2\LCkPm@-jfmNcb[m- .ff% {[5LbMqF1QۘmJS%j뢵+5˴t+ƪu꺤#T5+ѣ) [k}X;o7%[p+Mu3\31X?F zˎ 3noc[--)vV-Jh[[1QYo]c.ZS׭T%F"ySrj)Q_\ud&Xj\nX[娋70-ǘc[ycdíX/7ύ%fы7΋gўeچX+;ȴ2-)T+#V6̶2LMM6fnf ַA )ں]Cnv>]v׮^1{WvK \rH6-l 6,3,fisҽbԄ4'KN b&x0EU80V*+W*+5Kt16̲0R- SK56e8gb l̸HdZaj60emcXM>F]ؼʈ=sW嗏OڪI268fayFVVUx0/|D;д;Z1cԵ+-926X#Lq@fVif瘙9%$8(SK-kJPF^ה^kԧ)K{6}p?< q7'if ޹QO7ߏ^noXV_̲^f`A\&v'9y9IyJ@ +pRE[2D)CQiTUѣիU{6lA|ScPib%X#E5:F"QB`N1 L鲋mvsoNn _˟}khK u)hc + >z;/1>P*3Kah^n$;;8(7'N+E%3YqL?k0GZNJI6kTQ#ˇ/Q)SƪRV蚲#͊(g + ƃZ /[89vnkdl|_HL]chd٨{66Sc)eE ^cBnbذ;=yLvg?>rS)2WXN!fMv.#αqVVGe>%zɳi`mMUbiԮ44ƪ꒕چњtm}rPj2j`r1UYZ]5(kbQNJ7/8hnff[ +2`N!< GxdXH-c6—)% g!#ieY7oΦWgkmH:4ݟݟ H !?sKNs$8~Sq ^ ʅxA "$ۡN[Dp)q9*rG+fXe~f!MYnȵejUƖ4M周(UUrTemzz9ubfb'G蛒ML'ؚj@|Ss!u .F[t.W'ފ-K7$a#騑LhI*6ߌD7g +9q\P?5/9/9/җ"s߸{@K&80@JX́XBC]c xiQꍮL(Aæ{,] +MuX}]c1Kגm45'jӵYHZu$Ju$JU=z`зK ٚպꥺѺm +K +kKn MlCK5SӜkI21S6-\;UQX}s%Cݘ35ӵ`McbȷQFY9V2?W[CSf&QYlhIuc%vv51- ms5КjlJqsBKvrTMS@mժY٧bR{2&f%A0CYJ9?n^ҟQjTH.a ݓIeSG unnbtN^bad2OHvB@vs,'/ 3țGAԔ'\1#U1cQ#7M7e3M >CSMi!#ǎD"eU.nH6ZRՕQچ,;7K3x8Y }+ВoN52RBS2|H]W{*b.&]Kq%ܛ̠hQ;>}7־5Q3+uI-A@( b/(?pNf +I!#4;Lu tSk $0@ r[an+C鼛Dzwк%؈hE(Uef6YטoL7@f6T]2T:R5T&۫b- F)FT,WDfv.R׬55'(?ƎEZ2\O5rmf-{ynVך2iRq[ҒK c/Ŧ_NȾ K'Jv7?Ooo`@3NQ a(v0dY2(EWc6\橍` -̶0͌dba9^QGN\H6+P'*ԁ^UF઺,u*]SSw3e%FFr@bB`2*I\)&RLKWi1I7~㖏}Z+6ڳcZV%a~vMOxB`OaaW +<\K +2_ W s]|WN d3o0۞3+im"dU@Zrt X=t&{:y"PG+c i*H gO^*W.mzç+o-#oTVX + #A4)4HP>qL2s>L]fd-\c[Yz6N_[זwuŘ7!R"'՗A[o}#(.IqiUGܮ'`rHw; +s ~)+;^ /F2WBbXHPr F:9>9٧Pj;9iڬp?963 -h} RQeTeTN5&icsBb?L7h9+E;(>* EPg~@NuC.cC + 8"/ŰPBiy8 -IW>Fڬ:nJ8kYP:;0b0W} nh52?3Ƈ1^|Dw0JSH7g(!v.It ^Ct7.< ^6Xρ2Z͊:w!:BLؔ2/%$zCYJF#ie5_ȧ>,ewN ֈZ/oJ in@P>.AKQ?y3'Jǻ +J@)n} ĻTrfe˜BZ7% v59cY5z=T9V5X9XKzuMT._C^b{DZ}^?sفP}3kVдCcr;'CۜkE;H+'% .)tpRBWApV.yM+dY+$\M>v1!bb$pO$" eaq/\/溏*7P/@+nK\o;KvJ^[M9u0X`cC2Wȑ^̧w:" +xwGP;:= zdy>9\"WJ@\8qTmIz!S[87V9R{(q*c.k*"CY9Pq _x%W~@ "j~$oTsԉQi- sɋ4 8O/lXnc&mX+o&{~9.;D0'?X3m" l4B^J"r$W/%fi1/4]o^,hzީ5{[gْߛ, TEeSoj`j1@;կ dHYI +t:> %yB@BH9/Xa\bB䧀h +xOtގsdF+* JHz0Gb+3z_6ͧ~.+vg8aЋdRbNN+QVM^Uj+t-6.ĺ"b" %.aGk-| ѴFڒ.:\i2/'f]IMEgPFA'm=E>/7l}7Ε~p +kFT3!΃[6><Бr¸=ޑ,?Jr*8.Adbp>)+󈱀S A?g2OG+V Z9VC)$^rϗ^>R$Ϣk_|w?0z>a`0:APMǂv ^G^]][?]??#(grGA5VP•}rzT C$_{q#,LtzOOm>u@w1 <=bCur`.-&<DyR F"{6㙴oQ#V:>uZWG;&e_ɇWcg),Q=O4"oG0"nGpSSgWi~Wr}kE@tICGp_!@IM)*&q4 \3!ܪĦ\OٓMF GAkuV{k>OoF׼KS/ӆ&G;E(@B41l+a]KaQ,5~_n^{ӥ.!88ࢽ2_Q9|G +OIs 'ݯf}!Cmd@[>zЊV}7z$MWPrCFBA3X# /U ^9^(cn]`|o{H#ըh:DH;dbd#2ڄ?u>%פ,YMKK%c3ih لi#=k褽2G{mM3|y=\y(k ab2KpNiSHH6BY NGJujɝa7"* ~;Ӯ߿.\!@v).H6P*t\ Czy-';p##.yQÀTۋ}uoV襆hs\=>Ş栔 3х(`_!FZ M " {$8H< blu )u! S|/ӻφ?ࣿ=pM8d/#ey1#N ͸,wuLc]izj>NWlm6fkRՕcIt+E}"a4nnZ({ԫNb ņh}oƞ4a'Lc =s֫ʎ nہw%v1)y$o;.wVVS)Hv14e_xmp0cwʛYa0DzK69# +>`CX~?G Ɇy'MKNdVa y$_gK<"h1t3 +]D0Aƶ,U+XՌ<@8|+_bN}{s`f7R3R5 :Գ`.%&EN1DhZvaKLEN1GY ; bmL_ ֬n>J8HOo͗sw'6'aߺISJ]kiJ3 XmM&E_elh QC?FGoqsIe?wւ=BKA4oluw:.񣇧#ڇ^PzxqIȩEKBqK.AoSr[vs<"M3eY.āycMzH#rf,IP16]γn#"CoPU3.L/d4+Hм<; B!?lߟ“7ܓɭУáቍa^CXpa~w`k#B[Dv R8y?wAμ 9J72t6l7 ֶ$'+ܘk 9Es?#NUwpcqCppg'gӎHLnWģh0/ay{1hh}.+pFey^%!x!$Y\ce`$':E8` -Bc|]LS3&.![E1C;PaP-klN43iƆmm6PL{!x=0$h #s؁L48s }.= vY +#EGh._n~xSr;%;x]0ggx+4@Nȉn)¸lB\2 + %9`S\"b@R]qK"Q!!E$;UPy0)v>͇Gn_V.A]|HQYC8xswvii·sm>Mg_Z= m,#}zx6.#Ί3S;ރ.߿Qfj3- SS5ؒlglSS6P`}5컇S䁹B5kkfK L.LNI\lpI;TyN;9קT U3oG@T5U=HSa6VLM+3YZ@Ϸe-W=6<-=.LόOAq҅)iI))SؾX_w{ZN/y{D='wԢ71"@AvD r0~cv>ŇEhH0^)" Gx8l-|SLvp^bl.4W˄rVijus|uN1|rGBs +iVpc?{*Ȃ QnY{!<Fw OPyxх\=}P`?a&̝4INe3N35gpioξ*rG3յ&-ܚni˴r6AN"}ʭ?;0܋# N?3 ;nx~x:5̥kK+wW~,Us^yhG2#jk>}퓐SrKNq662dbDp]5юt.)7.!-&GZ"Kt(b)#b"'Yh#cca<"T@ b=_h6!}׹LQnp-<_vFI֣H-?ނtaӯ. FW[y/!D'4{h\sݹ13 μT#M0UC.KSնu-p B"Y,;䣌,>e_i"W718ȵ7F^{ڎssУDu|wvrqssysGO{x=qG#Q~;,k愺= Qqpr`' @N (V6#2=/EoH@r.)8T$Q|< Rb}2WQ|qI.#%;A9`|GLr 6y֢zX؍_>|=?c'&>껱onO̞={F}82N'P7\@uOϠO_G]#ag=#(zc.ΠOM: Ia<S\.΃8SCyE*(㝅vG1ARn`bJ#/ 9X瓗xT;g`u ""GZۋIc` LO%F_o:G ?sy⛥ O/\9<]OO{1^^XX( ւcBOQ\e7OX#6|^|ڙ]8շp}] dl%hzD3el٘@E +b< 5z0/9 7^=3{g??{hjGc{ly"tA,F:s{'•{Ğ=?zgͅ g'n1Zϵ\+i}T +<;caalsJ; y]`mP4y@;-x¡x+< &9x {4%Td ԓX= а(_XqfYc /6,6, > &.熩3[AOV\;޵++Kg򍭐pCϗ%> }eIThVPV6،4@<$ @Z;#Mp^XGw &6#-KVRL$8ic, !wǏL;hʃ]qE"88, vНKp +(!Ƨ:d畓rO~9<|ݒB;j䩙*E}/aaCᩂ\q TxjBp͂d!y!6lF,Z7y-Iʂ}]kr|>րp}]_|e/# SmZIN!YXh acC,Mԑz䅯r{.cZo}7AԻWCNK'dAN s<&: xiszQ )Kj7=Ќ0btDe#8me", iPM36u~sbS^ +yEཫS_}֮ (BS,J2Mڃn7F,?!P=<0V~diH#i.9`'9Y(]EG%+c`|OBœG 3q|X|kB+%b]@qiN1#/yeEGZ +HY-Fl^BWs)?]¾?3!@ a/)-X1 2]KB'm un̩@ǚ/?ٱÇ\Ks^A0]=DӀҷtxeĤYmlleb]gm4U {w}98a}˾}]{/>ȏrX#70yk+V%}f[cF:HS'9DSt_Wis %;X,9d + е&IȰ@W>9#+tl|KDyv!%"[8E5ycW^ѽ2[{T@B)ʖG ?&[p؅p3zAmE9plGfcCǶM|̖;6MtUE&,5uTlibi#(] VۄHfb` K+FXw)) + ,Aжᇪ{^Қ+ +s'ƭr}DYPn9}}O㋓=QeF`Bos3g}>&Zq6>) Y8 |Pw!((|Ev! مP'T8~l#$d:`=2CoDt#+rKBOr^95Y(@G[ThN%d4_GKTgprk*ױL[s~s ~XpslCvx&nЉmSvjGGN< [11_6<jr[7># +,K2f2VI5MmT#llE9X('ge<]@\Eq /N5 F5Q8*уd_)ӎwNzB$T[m3'PM\;Vja>ah|fb͗b'imCdoBY$m!c+%y4[LL$ Q5V!z&q[/'syWg =8pv$\ Faq}/.~ufO + lCRdѝ"G70auu>9u<84"u;%>mha(ĭ(l}c<"c|C\j8yn %]㖯sK +@JHGNe.Q]Xh>y/{e%.I]Xlj[5ުuŗjOWtu|;]X>_P[bntmuo9D;><}c3YKTYyf*(r7ȷiy*9G|CwN9ݎOOzlǂvL~|Љ&N=>yϜyf fi][z(;ytK45cl\S@2fdfͼBli#XX+n1)zyN~C)uVaC\nh?ؼiH~T{'twwvadOOdD7l>;i M=#¸Xcb\MLJ 2 cfOO+ ӦI3(>Yd%& +Ǐmn](@*}G7 [Rod%4[8 !YHݢDy>qtm+w>YKLqA> xy,[vvhؘhIBr9W)!2`c6`0P9\" rPx\vg +.o3ҒJ%-i:;}>,h$xЀ@wׂF\R o=6cͺy977eܲ_prN/U|8l}[ a)Y0界%'ܗWw/ov$2FuЬκxOcg=\s8j!Yw k"Ƹ!Mk=Q5.i % nt>:1wy)'?BK;žI+VۧNZݤU?vt_=+S/}5|oE>:iC'D i#2mhw|FgNR.L .t<7cMq3t0N +hjLh  i#rkn\] I6iv=1{6jL0i*OBܐc!S}J[W_n|xE:d\JIСm#hƒ&JJX)y7+攃_T >A-9r2~^1()NEi>񵝬 {WM˙i-.n3|x'k;t lD7=>odcLOIq > 2E 䔑_I1-9C%ǚ9:oۼSVq7oYz@򞙗ͽ~~>k9q~L=gghf?Pua{a\ݐ! N̄O-{ʊ=*jHFtFHpp5 bDn0 Mm{vkh眔 2A RF"d|sRF,dBVZ[&"dCVRD$HLԌsq~!|zxY¼_ N,x% }~>dݢ_X ^Q9(+$T˻$#dwqlϹ첟USZT伡]i:҅w!F {'>VzZҀKhphPI-&'de$u0"*Lʈ{9xV'~'kg [&;nu~„c8Fƺ,k$Cf{skhܘ~H9+/ e?eK;JN -С=zT6I'4 F` &Y6&tu#'ߎ2 +^Aѯ=>s3Őr3vFtN:E/flR=\S.xxp]t3p*=WsY#ݢ7r@s~e/.z?w+qz=>`BZT΅':SzlDls 0ң:{GFN *,`zfBK.T)i$$LL SZbBAlՠG!n{ɚuCR_ zdi6iZQqMpׂaC'f%{'ߎȼ YRK^ʘs36| +V1q-*D5(x i]l6L2aSƄ&iH =Qs^_z5ae"$ &s}L7d] +>`BNFHY('}GZ +^v~~Ix7+}JE1y[snA#.9W /ya13 H:% XO UdDGÝhv*& ['wFNbZ<' AGc]ntl܄WSFczPɆ8&8t`ΆioJzhjG:D'!iFhwɺzAR_3j{|nZW5AƲ8`E#$ؤ~DMOƸb!ihL14`RzdʈMۘ~Ȣi[>b||:䅠"㖂.!<[qK +y֫{E?_;WwrQ!k' ԑ|RGI#= ucnOF;1Ę?܅Q5^-a0 +n`G5nT4fʋ15!%&LlJL#P~>Ƶؔ2z$dEZ3U/LPiS]RiژP{:"Us蜄6cnXY<ԧ!LĴӢ"ƨТzLDK 30S$2N/~xƛ>I˛mܟ7~}/LM}_u^^) {yY7sA b^e#ȸ!^ǥ*|)xc!y'I;E,B)zey2Ub`^fєQS@++' uF\BC'#]0I";AQV~HOi0q&ި<# Mq-!aDu#ظ ӒEDLh)#9k!pWh7:5bҖjj!`l隆{q-:ih놻:YCfTڈ,JDT0b0 &c`@AfB.xedq_oB2s 9@jKKk_#FjJĈ3'tHҔ6f$tӠZLDA% 3fL΂MCcֆM :%ĈF\TK 96cƀRI/yc!鑥Mo}!7CuV4/'_%h?=⥌T +NF/倠e=R_i+IE`<˹8ai+yGrK2nI%{rINgY//#\R@Tr^^9( +snN/ʸi0p~}_zEe8eaݿkX`oG͡596/o~kԯ~?g~E $SQ7씄ws~n{xc!i) *O NWfaeA0KJi+ϺY(f,"ȫʜ%SGOȼ} M ζIE/Q-9i`줉3pF~!Lj6hzh7y(Q=3g&t /i<tmⴕ6q==%i3zdaDu4,xI=BGUУ:tD;뢰c"jHRfÀVZ .z%x)A ~@)/"+_k? F'U}BOT`*\Uu?zTxww|9aN˲Ayޯ(Šj-[n%`nEҟ Nox]5lNi+4fn.l|!HZDI0dY9%SzVLYJ0Rf漲[ +X)#et73h Bk =)e' 2y\DGj?%&̌sAq ;0NV΀L، 14؜6"ڦ=҃kI5<hM^|ٗ}iNB _z6iD]qp^Hi %'8ZM𕶆;ΥK{T}K{96kH{d<|5kxSfӚrBޖ_BصM + ҲnHGŻŏY)9em A;2iG6nF >! 𠕜sQ3)n6v-:+ebn-:'3m!gDЌI01/Є˘q).u2S2.~"ۯԭӏ/A %Ub30ŝL6DOI;#eEU˝ 76xy6% խ-V[=uߩ?*X:nI+.B>X Ծ ޏj_9;0n…ҌCsI2^%tw2Niٜf]ʸ0zfTL t(6qƁtJE ng{Iw#>IÖvۊc[M+vw}]51kkFGtxB)x0^8CQ 0 > A.~LYHiZL6bA>cdxbħMx K^ηͧXĤys?G,'<0LOqI-6eVfnȮ\YZWU}TU}X\]=X%KVx<%-o H:㎶-U#/ͬ}Lv+RFzi EY s.i +91 n¹"̒O ZG Ms +R:xb6iҁs3;Q}Dh`mW{9KYIvƢb\ +Y`oyI/\'NsDoΈZ̸KRu' +YPa*"bcM/xZGVT;߫vaHͿ^d\p·=fkO8~B_(loy֣SߥtW63 0efA#K[kb*N[ey,f%[ :됃v d&v8 l Qʊo|X!ݻ涣^8A|U8ղW|oyQk\^tONu5sGTgdDO頃 p\)) 5egpk:h3+9dS>xu/ٹ/3%Ƽ? avn>xd ۊͣ=k{D>*r\eGKifʜWvIFM#96}ÅV3҆=h|QGݣeYX̪Wj{|N_O5қ ,/d%s \,? Olwo?&VQ^}owrN1`᦭ܬ"RNy#:Y S1Ck[q$iS@GQţ2KAVԆ5⾷=`Pԫ&12lkv Qyq;oe׎aS9'1-Yt*Ԩ +a:lRO$ȂȐq * 897/z1 ^փ^ Gaҋ/4MYOtĬWvU Ĭanz|rE˫~(6VJ ҁ|ъQE?}]}rϑP&^WKR%oeʻ,]xZLH̟Ь4d=]\ +مi+rrd`RqKւW +pDÞMXȊ%䐂攫t*Fu#\Ws#Hv]#m뫹.M)sV;]p,\Ҋ/u. ڈtÝ8xె͑ڸ5ԍ{6ҍ&@,䜃w2sfA񐙐@61!;3.n.bb?] v1#=KQ]\(A$وIrM9 +M,jE@4_}^ݲbLSYhqݣGKj++c'oone1*Y/|S)oOyǰoZP:{DZߞi886ՓAĵ.ݜ \+ҞelKyuH=O29r +A +NA)ʸ$EtJ@4d,yiy/*N~uSʹc߲w-8{| ֫"ig]Awaf_20;Y#?ߍ~T%pX}B;gdHWɦ'P#]2"h Y9+%\ Y蠙4A#BbP٨y݌ /Soϴӻw?cޝs;GQƬu^xoة<WMǭq:"$VZ)mW?yRX"B=bW󪟿S /wΩ#%_ '3e[۠[6nKb%S)_%lQ'M$GqKnð~E+{cX@6l5K4{4S:q2oO4mw}jjH?cg =^M疕u]ϸC8IIIprQ#M[7bORY48A'5؄6@# L.hec)yhe&BI+p{+Y݌S ұ8`/ho=o3[&-ظaAy 026f+(_ɋ@//q薉{cRSQ*~Zx|n`ʡ|ޕ38gREkWר<@Aljʉ悿9',O,Sr$퐖a8w+KSGw)5ӃNwp{'ka]Va5:ce] +;A]/}]O܍x uhc'bB9>߉8DoB@Q +5&#c}sw_^x7D Ȭc= +3B@G촌sRJƘ9dc>FŅ}^Q+*xsъnzʻOJ-#ih +523^E1ܑu#)k@N^)V²O0ѿE0V-b]l˛'* NŪpy|rOuŸ" "!V{ꗫwnz@{1(dy)h-ܬS:$|,V𷎇I^q+ }wlpM$t|0jIm.7o' K]F53yw:yrz ꅃ{gbu kHe%eFFBGj)1543^p0AⱠϧA+dO~%䜌^tn^#J٠K:df]R@R NNM8yWmYoDX6c}Yk֯LOd,[^\ ++8jk?޷iIe-҆`*P+rle1Q?9<Z}h1u-s\lm@޼ ~I> .!2Avnz$iST=<V܂Q3*wW/4zY3㼝}'`rO+OG’{~m'㚉xY؃<\PO^>4駶O;0LA›ڛ=VTL̘aaC^Ņ|l"$Ouetxz¦ր<<# +n#y%Sys 0_)XU~ӯx|Py[ʃ멅ikTV +FZ!sXuʢJ+ 9҂~^ݶ8C!߻lV$V?t}gE\ޅ ?%$lܬ ZyEj.Yby#}%(W VQFNɆn ; 3C^!Fܠ3YxuMN]G{M[g,ۧ?[>Ԕ3`rB܌|^.I'Bʉ>7[9>RFÆ-~A{$@k֣{2+㰩Fs K>i/*{a^i9ZJY!RK>)wsq6Вr)RM0Lfl[+h^ḘOߩlM7ɀh@W rOEuKMy^s4zE/{* )!Ą`r3.N&AoXu"EmcZJ~:f]‚ç(Z{[b7p, 'zcyd,,۞ 4 oL7ǂ[v7l]r>á*Bqw}wTZhI}'j L~wme3M?}of]kUF(F$CA?禛:h#^4/.[6 uCW;]pU5{ysik/zXN+׊Oc\LMĬ٩\r'1?a0$,zDok)y,V +Q+$yhuRbXQ +J +XX:< ƃP{)R +CޖBe┼>S<<(U@.i*1_úOb?UT +]a+2ZelSqe)҂++l%}֞b-i^ {]t^bG=bǜg"zܼ_VODyx,(.dI(xq^hë;'? }^q=>% C{~m庝pɊ`]N-uXw];kY7Lsoѿ}S3aAxqm?\/ oe2$4hȂ LE7{qCqc.}cmގ_0$ʻX%8%EB#ZT]Z*^0,y? bP6ۖCEc[)>Va#eMp8rM'(iƫ.0۪Tn騮TT?_Z=_h}ͣ|mXԹ8UXv]4N:bcq N,6]9WX@yumcbyq[]…xC~=?^4 };uc%cE;tK"roql[溛9Գg_Ӿ}S;z ՂA沍y9(zFSA}S΄K1)#%Ńf,ΚYmǞs&oü[^xX'%։>y<삏;9[T *~~OíBpk-hZK ,ŒY4lsIwr|F}?|wd/׏p~NGl'!6All2*0dS(3kժ }OɊ}bW0{] ypVw\7hijG]snyw;.-;}TK3FϜ=iTϽ5]3pnݾe\8ҡ }SBtPzRRO.9}b,, BKe?Kĩb}q=KA+.BPt˃ťPK/)9 kZ򡶌=Šg"w՜AKFd^*EZa*BFEDH%B,V6(?~ +H&;GGXIE|ICl% 6"zƟ//ب%;`AOŠG:YI VfAtB6\ ++!+ ;wmێN-{Ӊ"vرțښy7\;⾷{s7;gSOosΣr~q¹(΅y+2`F@6a}1?wW:ѧ ^^Ń^mzAͺpY,yo~RByLQD k_;UmkԶ(s)m^/wo4+s.nI +V^ +=w[d߉_1] ;'_wiK^rlӮwϺw[f-Uͮ׏-r`B_sMS_69-S|[lwzjw]K{f6p~"oo,䌙 +Y9肝caSx{a׋kW1v`gv&/NZC{u.%MJO+z‹J-吢痃ax<,CB@Rm?2מn%e|`GKK[Qe<ҤIx5;(Sr vYppJiH7WHm^V ǝFSL%v"b|ĆݤqoM/(RPpAg!E;v/un|nK{k7\9Sӥ#~)Lo]|Fp'7N:TGSmNu}:)6w?owЦ{80bl|WcZ\F;YY;c"}җsK9<2v Y^ 큎vڿ_o|-\/-/g|?S< !~),0L1iN9$ tsB-XT +/8x#WE4 Rva1b渽9hkh$7Ղ ]q{wRtC+)QAi|uIT!n%0k'%?'agpX6]5ڿ~I/<ܦ)wοvy޸׽[^|>ٱa7,Oj]?T{OaY;4GSMp?o'>~osM;FNXteue/av*C9AAG\WZ 3 cW~U3ANʿ^mx=gm޶ Md",,y8o6\S}PKwU-EG؄7ie҄E:㍚壦渭5ao2 !JrK-6:Fˢa˚=xO; FEl#!6 ־7[δ9y?dQ-‰ڕe/x>x#Ϧ_:kpW㕭u> 5j\7Ti5SkVN3/nX:]dn 3KږL1n%74ߝ[75u?wSꋒdԒmj5J21i)I:}p 1g7bk+e@+|U $_O:\|%/X=GV4]R>|m`饹@;CNɨUz_MZdQs{ĨZ#Fe*#fQ(R ʈy]mX`җ_n%! Vްकr>N+9E +6iwVaE ?˼fi5lNnZ>ݴz}]}sLbZ6G6[6]%ӱsm#:1;=k'n\裸~}JvCKf/<3ܯM ڦ?waǜ]zGzK9,jߣ="-W ާ3dH%²,4C2D.%N9gJ*zu9?g/kyg;|l_ؙa7dlC >0G<ҐG (Ny"6aW o]dh8Ak\LFpD/3GuQdR/KM5i|JS;,4UhKy_O|vӫ|Ai1|a'`㎪S*s-&v3Nw/oqu:l<2W߃^z{ur* ++4 6T2m463-=Jf"=w͙Aܠ]bGghڥsK'őSȋ|03q?yS;yS?:'4=*6)ڄSeK +yK9=trK_75;cZA&2/rFuQZtшF:ahœF٨V2lWupyK,x +d0 YHQiaG(~#vXsdeoSvrn\s%jK"7m<<|6=w 'igzgz_x{sb+n q'waNC?Clɋz~6bKI\ǕW'V& q%qT3h͚{XZqЂf^kla=ऎ)Vxm_P]Ґ[{> 3x^=wB `$ߺ(%w1t$3+Ǎ]Mˏbkg`=زP&S_kwwAjxJHug>8Ə_Ď]PyhюQxi xUxa{~C.YɪwOb'׼stCkz+t>lgN{u HqeU> Łiy>^ߘquW[fb>.^{DA3wH ع(zRU +lM޵` O긣N8My^FrG- +& M#j]x Z .,upw5;u2@8-o;Ŝ$L0:D=#]ꭽs/ \׻N8n[f|_Gk>5fB虚[/נNJVDR =lE(:E4H}"7dW/lL0 `&E^ZapL' %言K䷠r6ѸQ䵈 8`rlD|.Ss51h M^8[6vrLةg˦.Tոh!ɯ h+-fgx>5&lj hЁ: a+cNfr|!#`k8Y8*@'XBt7379i +xϋ, YY~ ozMIx>g!QAwTӋ&!u$z^~m@E:~\آǷv]@{ ZTA2U3Z|PBOMĠ`k&z׏.񫫂H 鱐 [д}Љ '3DdA5uAdf4,smn[ُ[/\$9q Gv&nt{f,M@TqΙ2;eL|E5|VU +AjRS# +y:Q6卨9FF>ꕣ:gKΟvlvl¦X +b@  9[~M#Ba3ɯâktXE c6jϔ.Ե& h1SBFRm%@&0nVF6B:bH`DL{0ax$/$>26YƹU}Ǯؐ,hbiF6n6=(ܠ7ixuqw(ē&t2V*aF<ycوVxOpW~B ֟^EFwh)ŀh9~M͚gFfJ-䨝}>֣Oյu {AF\J͌C&ψ?!ԏ$A+KȆӺ?w 7@OM &t hq-gKmgLAt* 8AEQQ!ny)rF>шZ8%m7ފOZ*r@|yՓ7}3F̘1a#.'o׆)t~Jyip d$&J&ڔ8'- +eJE,d@^E7=.>$9>~U-y}``(?3bAQ<˾כ?~iĞ̼`KR{% =9hC +At,D!O d-q5Ψ^rW-5^Tf*net>8@B[03!l%C&r@ĠaݐS` )j#FL:YAa3P +3lĆ/h`or6HɈoW4EE`zP-req{mrxIכ31# +dqBj xd] >l vt?jcL$[Q]'M\/ހ쀙ⷀK2gu䀑31xSWS_!մ +q3SV]?C{p+Aإ{*C +- 9ЖQl)< +yCNQpW#Ƚ+f둎JYvk}"A.^P5&)!ç#4(#hh@0zK._֤) IVv.9x+!yjj7]n7$C.)d"Y}x`2$WNuzN<:gV,o*[ \-gB\(r[[?E킰q1'X+q@ ev θ1;`І&|Cw `?.dt$=`tB| w8j' م)nvRRZjcRpݲ#oI僞.o|7Zf.o 6 lhq9g*/;a,I1v\Fq`tf.@N{7֖6O}7ZA}<~Da:Mq-~|2rp}&vʁ4Sb#.1MM䀉 ;|W,ɚdQQ/?[/Z+JcdW&u{' ẏGKt#9]|f.Ο ~ م1 sY=/6`bͳuݞ?9x&#=/^AG71a A% 9ːYٰ &8%>dD ; ;$XժLTQQ28EP"-KQT-m[\1ZKx|{zxr㗡87V%,M=)$sHj> (y/:=51B&r +"NN#MG9y);tHn +Z9ب2ǘЃ!#h-Fp~VkUj.GQL\$JV6.k%K~%ܯj% /5>һmo\([%.O̧%Y8b&P//Kc6JJ ;YA!!:B`[pbB2f;xhD})-9]SB@nf7JI9mԬZ6Κkߎ?Ei.݊}`5E̲DĂ\LF\ 7[9]oz/pPa31lJCBNC\.DDq~=trvf@vF}I.<]]B)N&`yyeIqk{D%?t}u[~IH$ >umSfA&@]zPO*{w +gfYkr%iKk҈EKĂLfbʤxJ΢-3OV_cŮ}5;{r]͟_F_lwI EmkhS\xJ~iEopv}]éXܰ,I[B^T\VF+N/&e.hx<1=Wল{G_o$`$v <+0h:U8맀TYD,Ud+JSE`B$fI2c]2s] +c]*{^i|zmnr6z.N҃PNmg6}iO ٰX MWJs7$q7e˄ŕ˥U+u*̪bfz.޺geU[1ǻ/nʓ{|pg}'L3V V)IErLnzjqyڕmݤ'ſVVio8v=੝m|nŬV"guխp]9E=-Y@U{t+6Y?_en~ f64J]qsYf͚5k֬Yf}OWUqճ~V+t3']>'3@Ȍ'd!e̡fd/e?VXfYf͚5N` +endstream +endobj + +189 0 obj +<< + /Length 1593 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace /DeviceGray + /BitsPerComponent 8 +>> +stream +x}PTU~`ɨ*dIV%L3NQ3JX#Ef&7)K1c9"Kie7v{߻~?{ϻQ赥s my m-Xn9A=3 4GN=WAkIAkY9IL Wۯ|#b~7`D_8nv06v5) THx]裶CcS˺փ09~!ZԶ7<9^emD,Wzr;4W[+vek_%(rf j#gFRD`^&@_WLN_Ek>߽@aeC{0jXۋ,ڠikUݾ´`Ji蕪OJ $td4R~ &.gracC<+ 8SZ$].bIIظs@%}J;72FH4G sط$6tm@;ꐔ3%8 ^|&dU! B%xԥ9_*;ċRkgD7;wȹ.<}4}>|ao&w6t]!◃2b TW0nz +0S 7Z9qcbi?(mG넲-K_w2!VH@qsfo)(>e\4YG-L1d;[&x^ .軼RHN[E># =wBw/*6Iwsv? Z82=gN{yYx-$NSi=Ďu$sӻ2lWO'#$ѝnbײF-j33tv 9/:o?'?@mu@DzK֪d.r+sbT0mwƯ- " +^GS9稩wus8N<'kiv_o7b~0逛~i|,Ǖ̏R;i%Uct_4=WJCR%TNIi׆FYvL3iV``V,gq)ws +1LF?bECM3X&u]?~zoY'f]Da,z_PDbE3]c HƦ!En=zG\WH +)FrUYumϣF xMcwUJ d?BPf%&bSB ;}Xi=HLiWmw9U]|l vW[Y#|-Q)Qa+%wrF +ܗWʊRǬƐZ]R:T%t֟ 5{{="gVEaz#BP?QP֍EWH%jCEj +endstream +endobj + +190 0 obj +<< + /Length 26238 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 166 0 R + /BitsPerComponent 8 + /SMask 189 0 R +>> +stream +xwTT*(R={-"k4MI4QkLE@ + e`az&(қgzs=sν}]c|1>c|1>c|1>c|1>c|1>c|q-hwܥ? U狞)(?X_ +ݲD<ه3ӷ̽%9k2xk`9v;k93{N"y:aq}p˶+ +ܘµLk` ]2nLK:9wHe{$3L("(q`\cAҳ*sdn5u,[&(o\'.5kW\[)GqpD{@S|UT_S{-"`-00.|Wdqfp2Ui읱IV(G)Q*r$GIciWd35R2@ #Mfd9'\YN,LL4U1 _NK#xb]9e;v)Oȸ z\cD[=}d 3kҲA&#d],,Lxc\]\]lꪘQI+#=ŗ\KH-Pp)=JI5vt5^Z.q1)vɫWF&. {<Иnܻ+*aoEޢ'Y Ǝ6-kjrCȺ$d$ܤUQI+W, ~Ԃ{tNj D]0o9 pIL$sBs\4dU +㖅, ^z7b/zs4;Y<|\cJ8r KqIf%\3]YN tձv+.Y$(l>3>;8qiD-(E$ZBQEz.Dͣеz.GҦ(l*N̘ə9;a̹s-cDT (cRcRVG$ +Yq/[\Zw /N|?l?7 S\u{+|^~um FUP/kѢ 3gRid@.$B$8LQCTLE ja@3BѴjT[ VH5)jiʩgd̜1{vܬ+~ڗrMp51:>"!,nAaK]^sN{R|~SO]~k99./tu5/"͞G!K7.~zZ[zK[)J%i)s +2 G* B$8@\ &0M Ss ji*d+)t=O.._xg}~v(Yr3xiHԪiYw5vkyyXcUa(^[OWԂ꙳I# G,&ɔ|%Ly/-!S JWUAT5LUC4%LS"\0O +b+J +T3gN=YXDu}$bc9Rnoז|,p{=žCc?.89> =}{-[tͽo^+Rru+E"$fUT,7^oG\\(ac\_H$H,% XQ4dX +1` QH]p! + z +&C75;t)VF#>3~l3o+&5-8^|qyAy{]tW.]V^ٸPM]6wkm]R'NM=y!{i9./]l;Xj`CE3[SpĚYy/rUvaqvv "V1MO~j[rJUȻ_*li32l1THrP> GȾc< E|DjZ2B(**OYH| C (Rj+S5SgHgΜ37~2yLV_gO$12T]UQXvouˡ1p闃tky[ דysΙKYŞ^w;!?5_=nk{#\o/uVĬzk:2auttpSqՎӲeFA +l _'r`%B- I޶" +Iig{S"Y Z|)C>J)BEl%3$͝3s?EI YB{#9/Եh9fOyi9𙷺}~ik"o3O]{ ]K+/]unY? +іgG&l}WY28JoU +[:sǦ8ĥ3 gig̭#1EXO'PGD(\G!#Ex0U`B&NMeRRIbS3xD$K5Z%}8`>0Uôw|)t .Mҧb͞`Rر<,IONiOhn +[stw?:9g̖`Ħs 1'R +M$0UDs +]$6E:ed֜so̜)>-="!12x1ƥW(P{ss<)9fNNwg_^ rמ{ѻWg^󕀵n=,- 8G,r}/ݸ}@>z/[}mٵ@74.!XmE&E'ǦǦ?LKGΔ3 bQ/[7sS S%HxRK (^/dDQYcƦ*uM<@snxX7`g+mγ}4l.!.1^a>]0sV-_b) q|O,@9@!sd-8s!-];t~ w~>* +&xkt1LRhBƧj+򨶲39?>{RD|BdrJ4W<z81@Z^߃'s=T m;}ՑׇU;[;nT^EG~W[goa_O;ws-\_x3^R/e]Wo< hUPتh6G'G'G%p~f0!91.&fkw!-Rfi!%h\#IxR.lg\r.̵ Y.Lk4?PGNM B NLQh"&|ն)xs>\"x,@:B+u@)Sأ@sQWnGo>3pX;~|Փ͏֗V:kJ\ |9mW zy/|'?g^~K|o,zkwVqoUDp#61,t$7xozUud +]j-D[#I>$3d"YKHGo>LL 0M2PF16U4{^]ByRO;ypb<]Sho}u+4vӷR={u>jyg`xNcH}`tSeӚG.b'i}!ox+xc@oK)~ +]U}V^w9\[v7_Z~=hō{+kBcWFGh{'`=}7yo;锩֘+LW%d&z!|A8I9@%Q46XՄWӱټQDU>cn!AMOS<Txk|䃉{="bT.{G54j>X~ׁkʽՏ-/aݶѯ^lzYQ(T9,$q[wRYͭͭN] W8qx8\tNjWy9v>r{ϵ~fϩʭeB,obO7DbԜdSj-p_"p.XCVh-#  uw74־mhlmэUɎ!D>t 9 \ 2]ݸ}$=ko2ӝ%pw˴Bw}\@m;8b#ãRgh[k}]ټn}59*7u-^Wʓ;ǹ Y=ۀ?)nhy9tֶ| +4]U8yxbb|%BP?`:ԞV{޳orVRϜr2E QUimiKM뫩}tC;0:<>k-45H\-B>=ؓpg݅\wmG{mkU6n9X~`S}-{[^7vyѷWs?Q+r9)59ekr\J7&ԍCِ(aᣪƖCTjDr  +qB,1Gős$-EjqDظHoo{Rrٖ-**2(2 d)B8xGbkR`b&0$%.>_9z FGGFGt#CgcY6X.Vl jOٻxV@ͳmmhc:~9_+䔺jNB#KꯉI #OF3sn̙SBRkPy | 3!:MAH9DHnhxOvt`-AޢŒ 沉2,AIx Td +pF SEQUQe +5乺5=!1/;z;27:4ucO`|=nO1KKqy-n?(׶|O}Ǟ wֵ}ke[{)q +G1G:v`h?fϩBL%XB.7WH4rlbգ'ܗrEѪbSZIU"$ +,'2@JO8Y` wljyGGGߎ  tM*uB_&1v򤠡+([^aU˾g{k[ַ{wx4: fXcsd;WYL+;6\M,*HRLQ"炧Lp+Db*A>a*v&f۩׮u#o:]_?|nu!8}TqM{ZֶmsmmGMխ۫ZU6Y^fcI5Mj֕׭+z,pLp{x/fkws=ЈlqMNj{40cfŴOh"+t!_!|4+"24;vJ}"#%*Dz +.xȀ(ļEb2Z{qP[Sx/ISj4aӦUU6~aKE嵛˪7U+_-qQ8KrJl}z+_ 3E%n + wkO@TgmLj~bmN˙9hl):g N7'*< )A[u1oա#bCj"&zr} #O))rYƉ&['MN[&NYو81 zY2 yEQzނNjX{3<;4F\`W%QSAҪ쨨+궔~]Z改 +yNO.Ҳnk6Gns/[YU/jǎ~'CSEQO~V24t<90@xI ^曯Qh\.X4X_ B6OҀ9Ialڙ7莎~Y2\\%L:%Mtes HGo流63"> , x5tB.ޞ6&!j {j-\qVe7ڒ/sJ?*۠-].Zw8N<9b[cJC\Cdh׃nnn[nM<ՍqHtk>2U/@_DQ_L.LjmEVx@V*LdF +"&Q9+7?r߄|9C;0lIHmby+\ʆ\ +-\j+J׈ҵr)LBҜ |7iD"N#S萖퐘 .Kǭt[F'V5hr ƚ؄Ap'0XicK4.G(@%RWy $Մ77݌MR!'\䱴VQ/w_p0;2TCw;CoT^I0MD49K%AA Q#!m㎡u|Uv(yrl#SvHf:ĥ9D'?Yf㮣-7xmDue}eSi,. OMPM߽ѱ-r1e,>A93OZ|>Z#7PI*YI$+d Ɍ_ VA '5FF\wtxP7<0:4280:8eeJ{'p!`d.DRL :w\o:҉A^P{dר K9gAe +}!&yux}p!7|_oc7$)Ơ|٠%F&4իJ0b4.OE"Q|P#(&|o%&*"N +d"" )Qw9~Dnp#Fu'2L&pdLB ]H~Sb)AQNT[.(vCm?t)")~ +2rH~갇CW=X}m\/]7|w_8v=?6YSYvƢZX1bRJKbɒd*GyKx_ 6,(XD1JI$\~J,2dF+-u:p!;vx@Pѡav`,<_ ۚ_tI! y>A+d9Fz?vPeVa JdH8 ,CdxC'=jIL ܚ|hxxPֽx;oPߛ}CouD 69ɶ #dQTT?y%E\!sW߱ ]}7lu;v7]^~*缷^uko'f6s +ƲXY+&Y(L'HP¥=;{Y9c3>U@9D{Qp~ߎh +8Ld%HȤ?>EzϾ=##z63gOL9Xb}ކ4a7ozjc2SPT!n5\=@]ۋFeBQ0TCT )]rKWV^_y+Wyy];xO_rn+ǯݹ.oy'[MTM(TCeg!_}8k]D+M+6}:)0@rY#Ȭlzҹ$Wey&I8 2E l++Ν^ݣ/ tne/ƛiP(Ty>0@uG_PNx-;?VU=8tg6~fO ާnލ˚_|7u‚?Be:Amd*@J\]:N,5@ +|&bH'M̞~|+lL0UWF -, WFFk}Wy߼)9HJ$XLE$X<dXH +G`&W t=_y勁~U2TYTv J~~$UFD]ۏʾz0̤_?qvC8Ͽ9z|ӯo;qjqW}oǾ-,fƦ*Cc +U~mSscjkq <$i .[!B KJ<@ Yd~]).NbĹ"+D+@+ \O j604.|Wz;.v\E%@iO6ʥVp$8}ߌOY@'NeĵFnhEP:]wΝ W|oF޽ݵ;&I/PĉƦj#ca6 +Uzty@\"Rc `sȤj,Lfad2I#I޹)MuNq%K+"B3.LaYDr"&2LbտR& d,եHr^ֿ8-5_ f[~ogȶg9 +9 zVڛ&#% +,DHL$2DHXPe Ip6Sۜo}jT +ywde)sEbp05Btz$T^ ēXB DE +R#\ $"Gd(H p MߗoYA]sH0(xn:_=olinI;?K!j"DMqf+C]ۺ;;^tu|]*̀|3iTz%Ƹd&j#LsrB"@' h蜑I Π*K<ԡ?n5Wd8|b;}} %W_OB17I@$ d>#A %d1.Plh(@ee|F]ESXp#bXGTaj,^>+bcSWW$9BYh`\lN b|R6m-ē$x@|<@#fO[WJP70? ˲1 fL2e}掦'uO4t6lNA N(2L`^92yk[WG;be  +֦X3)t= bP]~,ghF xF(T-9+G'"K ^%# >·Tfe8"')qD(œnGt )Q# +$2\48ex4;%G)$(I 9Dr Vl~Z[IM}esory"μi5O,g--[;ۻtG4Lfl3wRK ƀa" +U}[S%ZXUXmloy\L jq05 Zcʥڪ9qgPTzEƬF`ggh64dšP9y]| $G y +mt` jRb2I/d +e8@V!(p$imZw`ҟv * b ˳p-mVY6Y\6A,Kn /D7 J`ƪʺ O뚪K`!j D(%MT=xV^=y\ݙHK8 +-%Sh) +i3gwtJ52 XQ 5L=i2ڂ‚g[DShajLKВ(m:}*1(c)0e`44J60L26yף䉢O9ؿ¾ gpVBrL#tCC7sFׅPy6,r!-N/%(ú3}lxQbj&^$XeXq(RpAkjΞE[V5҆cXc8hK'eID(HN"*>kN]CeE#F̴,5@DF_ 8\$;+L 05B Ps +61鋯(8eeϓRj>{{ wJs) dhq0?[:ׇF #:]ombJ& +ś4Yoa[6X8 OL'$) ǘOXiuEnF 姧&]2p( y'pyƬ4F#dg1٬l6ɖIo/_ԫ0L PhTzԋ+WY% | #Q(9>*|Ok $5ѹh4baFGN(]32 NI8)+Ac%6X xrQ''N!GFm{^?:vedF,y6XZdap >G`R +B$ǙML)ji˶ƪꆦ暆ʪbVT+92|\ !y Q.bWKgffd,&3+ U*].`|b +vBG|՘#lCT&%GPq'>pӱ_?gAj38鄉/$h盄F2,AX VlZ cbj/  [%R՚lc,c6Q`iEc g` I\e 5yΆƪkcsmcKMcKmm}eug3f/}8C %ld ,N6W\5TwPTϖurDt*QQ@vM磵k0x[,{Y%Ta%FXȸoܿ|%|SR"MVR-J1AklҲS*?>G/xyX7!+1+{#$S$Kkֲy777jmhmjm|V՚l{}D` wL`^60/TwmF_}ôkT m%jbjhμo*Ο7{6S#bzB +%bo+<J*/V#Bˬ"+LH D5E @F4:yɷ/_vhCCK'ZZ[zjz>kjmjk}ea"Sm.뼥uЖ-L8ᛙ ꯞu>+KQ3`_7n72b&& | " " +w|_wTjp/6dVqJ H$W +w 98 h8ZcĖ`JlN9ԍ  R=e$GF{uC=ѷm=-3uh-bJOnQ [Fl'T@&EdYD2אJ2EPA$@R>zF]w}g}O>v4=ya5tֆlTՊXћH8=k['ð4 ',Y0`ÿ&s6nF܍H+1,88[J[, 'a˼<jKNTn_7H(9(DQLLLŖO37mO* z[ZkkkVWV;}gOU8Uq=:^/s]-׮lu7G}-V ݲlYvA>|!>NEEK~}ee;'zmV r>o~ +dhQ.pٝC* MFnnoilmki9\\Y~l'OWQ}r[nrc#Js^^?77R>_͓n ( O^Zl2g"bcU8f;8i±4hcUvDzKs'Di2l[Ma Dۋ1FI&.uSn*ꦢ.XcXfmZA!&憚X}uU͹sՕ+*ϟ9sTҙg*OV*;*ɺf'Ce(EݡM^їBcr?J 8;?/X6_Uyo5.9R6vC[{\]yn;IgjhiCmAE1n@(y^0Ge^~e˃/T=]Ry cVixܼzUlޟ4/|q㍟J?y+y,AK9ÿIJqvι +~oo?"EQ|z.PEd + ESr RζֆXs]=\qëV4xŖCk#zmSVG骕;RRV)* BA{zllϪq|=rːK\ϙ-i81A_XѦտY}} +ny1^g(^? quÈrυ0,&a#0D(")r:a"0ؙa!OJn媊pCUǎV.?dׇND +^QyHXwPLe*Z YRП5sz9VUyo_ݻEH0 Ȼ S!Tb aSc.}-3wAMkjXL#;_ s_<D#Hn t}O]tJC E_蝝jz( + H&pmFs1"3m HZ͗.-f,Y͒, `!kqeU ;uG;r۹()C%?|)BU'>3ukŚ"!5N,Űt}^k߸-e\[;4ۋ;ߙ7E8>#(.p.."B S 㢼PY> +!!<ʛs)[T$Pdjj⛍%k;Ptm%]\u_>e{Ⱦ6L|zD.=o}iؽl~`2qb-aZ bNeV0oߚ׸/<ً"xy( L^w}[%̸/-LvBMk˽7)Q0 l>E>,唜0$HyqʕI͑W =!2&.t9_qTũcǏǡo~;K JKnˣ7W"ȼ48-JʭT4jۆ#j$LK1|y^deox~Rt .e8~wgGMmo+E=e(D_ Gf,9 +pSf#0Af6L! X0') H~A7[RrD%[Vr_!J=Kѷ,Oijj=;w\ŹSO>}{t) .lpKiw'F_CqJBr´öi7){S !F0PFa .JYQ)#wo!,ݹww0tX[EbQcPnŎxu$,7bʜ|ُJd_9WR')hْE1;[,.n T]:_SϞ)kaZU=}0-ư n?M? SP.t8*EYqJ2yw“-E0͠#?5\ԡD=[Hy>n;{/`w`xɚpdh6@~ˣpemOwQGabCC.ŪA17V3(WTt>|8CV"ԡoPxo{mKaݾl!DƉp] ˹yg~;+R^*FwI`aC$g+z+߿#ʢBΎnan<}L xd/%ТA7D^YЯ>/r5%ݱgĈC:;s674`Q_4755qg˓%ͨS0ZͷZ-EZA{'Gb%pKq|-=wDKPoQjTl[ƥÕ2ee.2O~>]9co0۹ݸQ q'wPBa6 O +O׈M6 mjhj톏 }3UQ4"hRqR}hͷӇ3ӛǪ8b0;8'A: WPd&9bQ*`rN ЀA@3B YY؎S`d( Cw59m]ζ#>C-%(JܸMu-6wwU5L-T_z:W?T_&l|Kaz ěb%O=Yz ^ +ѡ FrвTpxe +|!+YCB9;\3>꽟NR)v|HMnilE mmloЌ^7G_V#G}:@rFKܖUA˵;-<%?̸HƼ<E9_n6U7iK^v۳b}beannff4[g⦥4ۆU-J{ pa]1R3 3?fcYD +x@PF9̋t;\6GՑgg9vˆ)_RS5$K% ^XE"sU.XaEKXC~)<9vǫV۫66+v_펗iiwL;7؜}C,Dx@IwQP@_4uaN3hRqrXaQ I|=:O% " AYa9~,LU߬ ɭo}Br4z_w^r8g83Nt.ϳLm˼n~AN(S,RI 9fDƠQS QܣseAv!4@8׏An\dd?CplpmoFpM$P_=ty{=Lu{!DRϒ$&əvr72I*@R~J9RE4Gy) +aύćS0;o`q! 8 #R=6Re\A7¶ ]Yo\C4,3}) EM$5SIigݹIgCH:r40a[kȈϢ؂C@ǝܪ$o,}Y%φ Yg`a0l&t[T=aU+J]43egSLOH $g{ݹjsfX! tˆi|7JÀcǭh`]XBhb> +!TsPs * ; Y͑~hHCImyO)5d^/x'.L44M?M&:\uVV5l˱9n2̰!N0܊ mdS8S@ D! [ PXBJPk0C80=[ۦzfcU_犹}A$uYR#9v}a&$NTdH#$LumOt5luhp,WsA-J3deWߋekǏI,7 Y8aR^њaR&@I$r8Sl7mw zW[L֏֍&uŶbnsٝiN6'Et7MmP[F7CmЫ=rYL1si%/ 'cvzY=zy>&{T dTwuMf0)zǓt:۝ڝo0;6Rml[cV[l,2cݵtJRdOѪ7TV.WrS;{YėMlMfdM^6eY6)cq4=Ɠd3󂇜!gA=jIMgDK4FQRњ>{_;=rALI,7e5RX6Y> +stream +xIA@-ϐBRav(iXa\ EaLӧUnu=N!l!> +stream +x{duU3EiW0ga#('apI#HbKr罔 +I,+Ȗd;! ZwWWuWu}߯gg}{23wn:u|qώx0 sٖ.1Y)YjSQetTPwEM45QU[ j6p44BWMuW|?]70f(K u5WSmVUOSeQkqi.ej-FE/im'/ummJbih +#ics=0lUi`XG}(Xn9ٚnXbSLY3T4c1:C{ө/TZN[׻[]v!??m9a؜w7+,ˁ8vq}I"9"n>/<dQxEğInr>'D{ŕ9j |EකܽMa 8s:y)*p\=n /CxՅ6P" +\9^v?dÉ䗋<7=k2,M}g6*sf~7FVw;Vm7׷=hhnIm"{AM8 LAU%a~Wx+y$;r?G]VXPlz\Gm6Z}_rnz](p`!o/ɚ"ɲ$MS6k(]^d34uH]8PtMQǛ>P{z{]Sյj Θ@mqUW7ڪyN{}*)`">U{ +j>e6TQ}Š_9P+-qªŠ!-?p隲t(/Y"S>KN:{z-,,0UwZۇyQ7?\,rOK<GҡpW4/j40d }/71@f:+tFo1XnBކ + #tQM7!? `0xv0C4Sc}u]7@#n+ X¡nXV7]qҖۃgB.S}`CISxne7/A-}Y(5PDY}55e[YJg=[w,dc43pL)v;YXkyXXO-y`:k[mEUX}+Lϱ<ȵ8 +dzM߶ZjY;왰Xkv$ka@MP0!laۊ=P曖瘾+ \9 9k.5 Sͧ&{C׬vr"}k\LOǀתTGW4EVeQxZyQX?Z춘pH-N +luFһdp4 N5kց`=<@(h6$앮вA47% j69^l+]G!=GvG~`?oڕ#6@4p9Wl$9xrX[V&<;'jB:ȕ=[i!<.|$hRZlYj1 +!3왇FO2-e1AOo3[ :c}o{oK|-?S YO0ϧGܑuw׾gs͜p<=r;r{p yO{؃?h~xWO O4̷ݻs[#}h6 ㇇{NzyrAٵ8I5?kڞPa|יk|mk-:?ܶXώp3O Ѯ`[Wnrܮ-Ƽ99QdMd<72 ya޳Wa9tMe4 pM]`Fǵ-ױ=ǎ|8N:bz&!a"{UO#? +䥑7m_=ʧE~?0?'aΌ}i y~z!Qo-uakC|w$1 }g/ ) :m0nxn컲<==u,F;J,"8n1EQl%IQUf>996 Ga;bt)8ŽO ?, H O(48:ICz9"TIGIîQd,U@CGi {`kK$ųTaq T-!.tF J^h󳘶VLcwu<]{&2pL*&G-ƾ({LAb%UPte`2nIn9&ʹ + L,gu\l/4tC ]@"Gu" iyD\)D^p&G;bGD8~DR9ŶwÁF6P rh_cͶy7 @BϏbʄ6 .p2zxx\ 70GC?oG걚ۮj8 +Km{ki)(:'i}^sBeܭ Hv{:CG;}=Hu@32ԜXsbËY#Ƭ^u6bӏ570z n4p"ݍWSPIͅqC3NOY4[~+Nj}\ՀjpbݍeQ&x5a|Kwc8 2H)+lXfCݡ'P@?iT1p3Ł#P9Yh%j&#=QksJ[sQ'[* XF~vdhyCqr!q?jzEYB)~E{r\a/C GInq:m>Te;:'"^0-Kҁ/9lK?IG#Y衭Laю$H$QLu/]`R݃@4I鎂O8(IRIiEHt4̅_dtK(MU.D3G F +!ClYwT8K]` D&I ?@1De?㸞t퍾@7UMdUĭķOs~yt;B[젊 6C 2&Zeo\U.Y5nyIp-36nㄿƥvaSebT"^u>];Q'}gTxcGtOjy?}\* 9ڶk_~5w[?miWm6ͯ^?gͿ[G__ݣ~탿>ˠ__gl]8s}!:[gvq`tePp;ܞ1Tey#Xe`Xěoƒ\707F%:UGqSѡ)nӹ^5p,:䤢 2y$'L }K3SpWYػ +48y;zd'tϠyHJN鶌INY|/=Р^hN:`˙57YvmꛛSSlL};թoz2 +\z˄֦~uu^j#~Ϩ=iibmytE4u6u ,r\p^~b%D'Y8JQ&Rn|4B+h~rd>NG9}|(ف}rz$3l4{T4;)2GOFYx?>8+ +T&q6̲5.SrmT?9^>r_4.*((ii\(ٚ5sgt{ҝ;ҝZvt6s{FFFFVuVx2ڿxziCS-Mۤݼ rlq$b&Ҩ3.]7"] '%-!FS2;S=%ݒHC4;fv-pܐ=wnC<qv<f@pCZpXNB &e>cq7uL&#j伢O7^"Jrp'_uv}vx^ 76gnmdAśoUK7*SX'k&bPiupc+` $B:@a^Ħ9wٖ|x +d=2M)+ )79w4^s"|/yp#;S7kg4 +w +ҝF ٙ; 1W-ݪvc}{JuӺxU$i#7 {'t[kB%Q!JPQ`b+@@V쫰Q:mdA̦v{8 oپ'IA/FAL! 8mnY[=h^U>Kɷ|Z0ā":.kQ̝KS4/`h)*hbŗn.M\[EPpJ/R3HH׽8r\1P 1)c^&c|iHM2`f/#r{Gi_ +NMQs|,?w˓h8#zJߔx0$d, Yj{]d4LlQ鏏}絛[A'12@\+ 4is|-ݨO^$ eɶ4RZh;9j[} )3VVP\㪐6r ! +M^)fbZ>IYYuaSpCnن^pk<ׅlSoJٓ^@(Ʌq7É$>nĞiE6{͵pSVEn;wRv`I3uskmb[#Nr.| ϗst{_W7I|͵.4C}n_}#rsu~T6[VWm;[ ypnnK$Hb,b/ d_Iu}5$Pb,$+,gX١=륇{B]k3&\" sY `u Pfʺf6Rt&oL.kݹ>"yfG[s|9ϐȹP!r&%z@i} q@L-X?>;]ޖ5.6?rI~$Y6mDeZ6#EEif\qh +^͏ e~t ZO 4S=;uT8'/rœ +O|A"?23Ϗ~}gfim 3$ТLbI%UB#B[ZFxz^b~b+(F?sM'G 2PY<jL?l|s.?BK?9e'}(J}6~눯`_ l6#jFc.,y%$Kq~D`W4?"31lto'G15Yrt_;o\~c$?R!1 a"? ApK<ٔy~4&pG4-"68? t1p]F +X凲Gcc|wi=`D0͑ $t^UC|{VH~T%3͏V=K!?x| VECS,}01rāQO H$:&,Q|1BOq܆vV,Vs#@ńOZVYd4dtH&M4O k|e8ƃQX't42Dhw\ ߭"x+1\A}urJ$-_*$zg_2lck{ķ9KJs6ֻJǾ,wBo#5\OՅ.bͶTQ+m9iHICByGAa2h[F)!aٔ]RU.0IItvƒ +?,dO;JVy,ʁmJPpD Ozhwm(Y97HF0&G(aMV(>oJP(݂sqF[U)!~^'ߓܵ,({E㜿+bծQ뛕S:ۼo spOwhW(%N%k{_AvAΡ?@ˎS=bg쁖5"ȚcK@aW%4#-{&‡Z(?e0ᓃB覞3q:\Li8ݦ͇ca=qZD eh ]$)ҭh%+[˨?/z-ڑv >1dnZsM̧nq|5JЅD ONl#?JNG1??C-ISGi#"(K$S?#z.d gN Hnu42O2Z> uUfZ<%_">9/9&Uιxk@zfק>׆6r4ȼ !Gu2J1Ttts//x sFaD# E~427_SҺDQ(&?<ˏp' @؏h'hܿt" (IJ|Jptź@ϞT~:?X'n{|ĖiqsD9E{'CF`" MANB9ނX9dtFS|dDݎ1|~p+Te;{.ls|mv&c|p/@0_c|ѳ'4M?xp/3^0nyyA~Q#r.BW?#*ު$;Hձ腢ߋϏ(_+S/*HBM&`W4޲$8_;7@GO~_&:#>Sf0.jMQ +qJ9⛏߾()QQX+sO?:$dv Ĵ°\/<"5+i|+ucGױ`,o7TBza5@7QVI By`(1x2L>&# 2eꝎ{d m''{'Dx t΋~B4`@#Idch1a u!-N[š7:2 R0~0Gx|︷T0&OԬˤ&ҢK\ꟑu_c閮l(Ŷ[ +q$;r0g4X>^7%Pr$){AW ZŽhOv}%QO{:Ɠ.1 c&=#0"BER|&ݭq gO ~փ+f̜70u 9a \tm)=#9@7V]ت>!Y~~U"qm Nj$>7qy-8By)/[M[Y)\/\/OUػi\k ϶-ƹ(jט[]yn_?|zlt/wݕ5GMLf_c5&,3+\ +WhtV'O:BZ%6Ȉ;2c+u 13P.8&|l +nlRBZ 1]bMY*Tyho=$ LnS枙PSт3+9%7Fhr&u|"2n0%rca pZeO^8M:i\S&d4] pSU@+_O5x/\A+x;l^EqԿQNױ e=2RIm&"Bq:? 3$&(dn5%&| &u)S0q`"|2L4#3xB:<[Z.L!宲44"ep:!%HxN@ +)DC|pӗ_DP4g? +X.Hd4l.\/\/X&qlc MG/; ,Ӑ5Lfwmu\1_*nxx~: $,;1cE'Lb cpnLr<'0,qby`*G'YBE}fQrt2<7htub |0MB:̆|7~1uFm>CV$` 7va$Ҳ-;ܬ\"Y~E7G>9|7LA𵀯w'WØNa;r\rN{&,b`2?Y->8b20q8MUy:RA|"*߳)cqr]=^#ӱ,eL͞؟#1wj;K_:Ϊjs^$Ch|1&Ȯ5 |$p[6k?(1P-cۺM^ +&i|Ƨa;e\(sr.f27I6mwGYAn4.|0i|/ FW>ҧ_ Urfk_H, ndQ k_o}LQQ8# Ezg6XpW{W1\v.w=A6YdE V,Xtū &KV"ZhC&@@b-]cxd ȂsnjD8m(\bT{J&d~#1_uㆄiS avY0!'6r=׉-L*/-XQpiZT eIjrFpmu˿WհQ^[l}Q`?]=hw'{ڳ,mҋ-gfXR[K=,np ݬ +UVs k|}Bkd+E 1Rnh8pTGi#E<3ItƖ-08xq]weCGΫn0F@_#5:9'|ł/$ ƒVDYO_Ek,ȵaF0fdI?(߷>|7&r"`& QmlHuKvlRp. k71x}@ =dmu/t+fXIiDee,!K؅Sc*dFxE>Qw= h[:4i+dIl<2LiHt-13d;^lȜLHus#1;9#^RdhFXa Xg3s L7XG9 (ɋlnw^w2A;G{rCqV&Y737fnH( +.kQ|EQzX>7z2Ķ,,QZ]0]r(? 4k<m1B2=!K8Y;&P,?L"Fe h]21!zs6@. +4E:G3\1xHpI.5aV!-"NV3J7֊H|t/!Sgk?IӬ9kG?>E-e$izA 3+wd1`*AHͪ L-X+ Ki=Apr/4{EX[_eձD`q?fo_/Y[/,6қ_~7k_/_zς oտ֗߬m}L}ʜ.B,G| Oa7ĂLc>!eFc a>!9 Ci9h>K_Q8A~7^0Ib~`yZDT$¸)| LZIrt.dls7JôI}A"F_GSM9MIoNߚZkjͩʛSoMm<9~s:>x ??&7~~zo7{",f^]t,)[a@<7`DR'k(XΔ0=9@M sªӵ0(͒ ~IRL 0^ +~:O{Qs ˥kL}}A˶ FPzfv]ݹntEQDt!)1ѻqjlqm6[*ׯά_̖*WRuX}TZڸ}%ՙ Wͫ|?U_$=MbۜE(rpGb)Y4]?&Łc ş/YI.A + &x]-Xe.& NR!qwSא߼6;GqKdIK +k뫹][5BEg:~;c=vX/$I"E(ٙիRji}>;]-V*XZ^зcd W3W7g /bzNE|:^-LwAc\Dd,fyFX[ xD.. +,q%QGw4&Y{c~88ĚƋݐ!LR=l?>IoWV-ڜ-=(d +0"ۥ[A|7V fnN_V骢HD^;ƺ_"VRwk9tDWkli}>[^-V}َf6&թWN4>ѝ.¸&k"n`a|Vf} ˉӧ! , +oo/ 8we1rdk3|2 ?9s|߭܇︑[|+>f5 8U__?jW໹׾=vx/ ""ۺh!]; WK+up {bZ]תEbK|wqz/㓘tBdMFqzD;ρ8BMWj*3ٱ Oc2 +F"􌒠+}3F8=,T>J\Fhnx}/iU)k{D4aTAz{Q\+\'iUB+S.O*XN%_?ho #iw{="GMom륕Kxv<{|U8@-F|3hg7f/gKW*? ?v a‡]mq/o+ߝZ~pi;z6{Z e+Wf.=C_dex,1 U& ?mE3EOZC™_q x֞㣚ٜ^2qшKQИ&-mp1+!I&9/)Kx ++w;Zinkj˭͞qQ7Tn7zmv;gw6~l[D *u`:Sg.\[3qqu[—ZWy,>%Wz)9&Ikt/x5+&^CI0Yt_ d7W4+?xӖ'BL jٜV!9Ƿ0uV@L4|' +HhA8%1#y08$/ms;BUE[}A-0=Y`UI(ݩŕb°bLB9wzt%XԮi\҈qezcvj K89NH{(79 ? 4,t|HȚ~+< vkB$Ɛ.1pJU194Pr`ms%Yyk>EE;)G]2hYo+T8秡ߔn.3Qol>EO74BVJdI|xUn:RpgnM񝾾R2/@%Q8uyY$IWUC }H+DjEItu3$&|e]i}6wVK_?+G77 |t=}o.J{q\<0D ^Gm)_OCo7 EwyQ1NzriL§:(S9HMiQJ^[ԯ_GeI)z߸(+m,(dom+/ϔggʈ/!ܢAle_\$tֿڳ:шXPHCo;  +n751 XEkq׼z1𽥎V>+ܔ.ɋp(w;3 A^';S։@s""byK4JWJV +ח-.?EO͛pt<3%+MOj ڵuPRũW[m|X~/}/VZ뻝~oݮ|^Y8+H+Lwv{(!W*g qόyK4Q"WĶڲזݶvUm7@T ɎulL$QOj^܄ =9 Gնy&ӖHr5&;ˊd@]2A|HoE])|KחJז^ԯ/'[mLuztq(wMlMvݍߜq+_^Kko"MMx41 Y.â?2ve4},wad玢CWfۮ93 4tGR +EF|0YܖI|yៜs*2d&nyRpy ϼ4]j%[;H7>,7{0hAe]U3WKK++_,\)M$JHg 9_DQyE &Ȓpkv3_'m=df^#z2LU/tW.:1 +s|kk; b*|(a87Z64ԉ0&^}4 liߩN[.ad>+":×o1s--]?|?8mEaQ_rA_ៗ,]^&*Iw +c"$^Ec~kh/~ _|C978Y3ur+wx݉1S.xchb?%^d-2>-S<<(;K -~w3|UQTk=㢈Qfc, |_/,]),}Dlq(t1WW4g/W|v6_PzuX0AW2򺉡䝹x?r9+gLc6,wEo.W^o|IEȃR^F .`K<]]s~9al]>uz/Ǘcz$uE2%[KMpˆ ǰS%]c#FuL=BRjlkkǁ# cX5j5zx$pz3{Cwb4%"L^ {N8G&OCo旁Q/ӆ +5R[&Ktf Y]CNT2weZX8smqۊ^{Bݯzm~~WZsNͿQX2˳3+Wp(WWL}vev@{ 5⫧־7zek={{0ΣC{EֺZϩ`zw`=0rϹw<9$PR{j7<V9 +?kOutlUəv/oܩ%( N#@h";PBKr]*^[,][Dr_j[y?ipj/ntzţzkiǮ#i?.~4Q@ER D,bfIYMl^̄$RfbBEhaK~ϲKOMRMj32m$AwUA͛8ެnPC#NdܼQs ݢS'4 @,qOLt0VEXuȘ%jcY%#oaJxg 6WIf)8V*d m$Gz1R[Dp8Z-OT~ Vx? d zݺl}/ "Y.aa>ODSser_̗?|_y',\3Y +Hvř +z{eBo%Z vA>l wFa-s%ޡT/{sUc}O0H܁O==Gz۬șv]6USf5 llBcdOCyo{9Kڏ]=҇[,:aOLʳj$E;Ό Vb* r+`l7ZV*Ԋ@,rL˵jUwjsoAuf:zr~P}AHCF f9R~I~ 47 :r~mmgF`k~>Zڹ&< ! \<̙Xҋ6NF _#47Gb} 5fXr@#1dҴ +\-y/藿`Q\˟7t3=lBvU. b>뉤^sL)pyAYOʶY$O,,JÌ -KYf˸f1V>|0'F-n%x|[#4Gh9,|M |7GƄs#_v Apw̻L3 @Ӎ9Y`XMfV P[n$o/3p*o#C +ˬ`Jiu)]ƹ+W/'w.ELO|B;Нߝr{O;f5 㭭 2ɿlslȌ#Ŀ2gǩ|1ilS% ?̊|v[!MsMs4y'bdSBF-SjwNkV~E`[ FZ)K|{.T˽QA}<&Ax:A%8YغpyѢ8mCԘw)|}w`{sxo{) %܄A;֕t=G6{oG~p?ztGÇA#0wG=|=JZ۷gp4bk`vχc]y5ċG8:8Uo?߈r\,r|cHeR!+ +rY+90_DIXCp̂/:mR:I3RG|07CxWgn/ M7=hǁEIiBqxj^޷SSpqyƘOw#^ԏr_SxN>Ի2y?SNM9NYPrBE= gH)?ExR?VƥxߕF?cBNzl([N " +)_}Q[D挗5e{ܗ_NqݛU`Q.[#_'IɛwfW.W\1!e~X#}8;콜AcgS)_-CX#wdX(W +L2Q+å=LkW<$򏭍GLo׷gzS}iKῙ뇾|` +-9K@i5*+O{ywȟ7 +_}1XS751%{" 9\b(rƗ2b]usf&6rFy#O^;RX(䳙L6-:1WwmqILeKT(%~80RgUXfA9k֕'y /ҼMIa? j.&!e ۃ7ѠgX5+eYPp+\N7*Gn*RRsR6F?:MqG(厦/Y{5*yԲSV)X5Í❲fr}[!Qn+tKtnMU:b+V:nvE* #hv&S(@yrJi<8o8^QrU*]M뱮'T; +XV;+/89no,,N*Z~Y&K5ʅ@,Hy0o:oP7rrNO^~HX'xM©u{ԗms7lE%CkDw(B` y2;e=ɡ%CRXe. ,; ̍xҙ6$;dאSpg%5^*5mG~|9#SL2U:<)?;3}s3UŻT!u?3T}A!e&\4):0Zp +/?o8xy՛_d][otQoWunYcd2-Il6)tVu|hp`L<̅9`J*p7Fb~ٕzgvoNwؤ;#ݹ[u_eD|(v)tA02qBQރnݱ6ZMd;{vosy\P1{^, Ű@żj~|5I n J5M!>~Fl&v oxб;lgs.݆:8LC3etBQa?D']a oej=TZɡ"|y+y=?|jx܁9|6rRZb2I\PJzKNfx3L F%o f"歰tҰ1yQ^2m%~VF Amw3wvہ{|Ij}*%V`,\Cb&vìvdF}v`x{S)쓑 +tN"b^/y=M[l:-eĤݷ|6+.B!_-*ycb 8¾Lk̟m:zՒao2܊u5h(3~O+3T,uj0Dd CFd 6XKv:Ś$W\s蟟W`Y9ĔJX{o#,f3\vD}ꕂN)蕂AወQ0]p ,$ZlWLh^|v딚zV:vNM;LMnEk*PАJ]7Մ ni5MU,6@|\IeqYX`qA8H\-̙Ú;i?~|fav$߸ճ|[cY)H|V7 +w?C;QfIetiC T-z7u袛^&\zzv2X +XO,bJ=r'|ywNh5hS,0hs)93M*1[{9g_C?y78ll>#;!_W϶H,OŒRBH|6>mEꔼ\4&B,II Ѣ>ymT4b'!3gSgh1.՚ZTkV-ceM5k aa?|ѩ#O(S0'j#[Dv8.@2DBPx ! +E/GkNJC*5@ě4fhuPf`/Z/8XەR&܁3/ P WCob!̄?cj{Лia sZ!WϷ0)݌U,L9( a/n#cIsI%{iX &ZNwk7 [. |9YwǏ n+""О2sIȖ:`M4޹14FPEb1ڍuwe|f &Z"gS4_,hqP²@+2ߟ6 8T e48]bL)d[gh*yB;3a|qDkY)S,@\asdg3Jd=j5z%p>dάY3@ Z mB NQpЧ_#!W_oݾsVVo"doc'tw^uh<)O ҵB$Ou.]MU.9x'|t9ЭΫtZJb"fqe׍D %1I#nV` + #dѸc(FLטdrP#1>q;ߞnUv(_#;*XA=nEZYDd˝7RĴ ȗVs%,Y L{et1G)Xg3|C + 렊%蕬"m,PƠL#2pMg%QJ%҉CL1FDJE)fiWjUrZVłY0ش(+Jt]Y7ɔ'A}3+OʑAsXdjzQ7T~ {jzc<.lcǀdkF zhiB ؾ΃QLū@9bN˝Qx߬%)JD"\=̯|+ukwٹjwsȟyRXԁxy h a; a8%ćO_ G,ѡ&ZDMVGsc|Yh )FROx@/Sg^WӣuMnԯ!hCgR5C +ɈO<.B5 ^ Ws<7PSiO]%PqjNgkջhNݒ9ڸzz`{\s0lP` >LpKgx3!v۪0h6@©cƭuW1MSraE[Ymao.;CŚ=pr?l +Y)NSL2b^/ݸnƣ$LZ*f3L(Y-xi(ɳ`X!rΈi]46)쟎ãfSnN(R3|JcBdy[< ^}jZQo5Z}# 6mZ+<_+ede|CZ^4xݞdol[]|5nĻdR,$#*{ʷـ1js ضM`&g 4_["yO脗;rg÷}*S7|^ cT"&ٴXeiWN5ӼfZL \P|qс#_iSTݳW?-6[&nfZU(oԛZ{sT[ǎA2Y +H@k(d`&/!_j7 ݨjՍp-aڝasّ;pь|EET9hj-(xsD?z׭2iQDLG.Wҍk@ +I,~ii"Mk8Ɗ]T܂ d¼wqi?1ӑRhzUu5SfOzM|mǗ:a WnL*ԉQ6">ff:+Q4 &rFDYyɞS]sR/l՘cP=3&7;_LRɵ5c5hO.;SkSplCi &l <rEww'yf)4`ۆ4?}5F{H>ZW.RR+Q&)mcmN>HPS/`?G4M]Ѫ&RꩮavM1]v-k9K-5|Ư3lL9ҞP9ߐz(RP+94тa`_XzЌlg[hp-Ox瓪>*nt =UXU55by#L1rqFJ`P@;knWo D׼<_zRcU)T+CE#9"R)$K,aytS.M㯊乵oLe,ɗ4xzW{e?Rp:өJ>]b~|ӂZ)hf\z%t4)ƝC]l}:^nzF6hU= iTzÊb9v"5b P"b + OA.L; A۬`f^\uЪNzoX_uf.YXy=w G9ҽlo3B>M*Y{z|~xl>ʊI)$V#ʼR>h*T>.JM_AJ)ӹ0k\ hZdFp&%f`%L􇟲>.^~n UcUknT +tV`X~)Mj$ d8E% 0 LkfEjZi*Ju-Pf*:CV՗ FrF:*SI.( ݙ҂gUrgo{,dϐ>Ѱ2oqUFB;|颈|ie“rQCk)u(d᧬oZ!Z፭U+5o |+_է RvN| P4}BVUDKڄ/uŒ/ +#__Q dMϪ fpϬ߷J͎b׸|}+^4^"kY,"Hyמfi" `0u0M{v sv[_`|[o p~B؁J'6ſ׃˯Fcp2J|3Ǭ2q2.#7DK/RٞU gT.d4|?z_"Q)ψRF*gjM 44.XM%@K,E,p汵?fy:Z fteclW xG H LZe]p=pzJ4-!Η_kG:]]/*@9-we:fݯ-i-Dt40NfC,d=j:+%T<yOzӍ7|7͡e[t_wT=/T<eby5ݣK<~~7C~WcVSlozK9eѲ)7 G?xbhȝW!D> ^8sv=G җ)_zZFFEڕ[iy=9a>ygCjheS4 +r& Vu|_QRo$ o]'%+ߕIF_ tF,hX` -[ic4./*SOor BȷR, +Y;|)>mJs`S/-^Gwԇ}Ő(X( +vE?#/'&K 1\22ȋ]άȋ(Jn|{E뉇D)%TN2=O _fiQ8o:!5wE 2Pm>1ӧyڬ Ղ>\D *멗 A`68yRt;嬓\|k~RBTX :+Z)-N'ed)h{V v˨V˝:Ɲ^d?|)1!%ch( ?{ڿyV́ {Xjq'e_6ͯO;iJΞW&Cl fzWs^ +y|5Zfny +K|9leŠ;zLKeŨx%~z2Ns_߷z6y h_uՁ#-(Tע~eRW pgp)Vy+(Y*t9#ƝP9К%Jʼbg+kzMsh])9K/6-+ ˆ jT\;"_4Q>ljym u5g+{( #<ݝv]Lu%iҽcP/Z H:|URAp!ʋAXª#r6ş݀[ٞ^K%k)tŚәyw$C2"&c91OOL3k301 `fi 3dL&V})çYO(rbRJ9m o +e8-Bmgzѣ f7_BX? +ywfǀvnb{] #W-'LeưUiNא7NB9$SQ4OsǔKπ[^\%WYd, V;U+w(Ch$SlxJeNsܚX,l(y$;EwK1RC8SUb>W*Ŝ&3rbN̖-I|5<GJ4<44IFg@qbOrpoJ\6[tI: C!77jrjVP8i0͞vM(w{q2K+gJch8E~ű|k]A/ +B +LxJe JJb:]}O| RnAOz%wP粅\#glfo8[VnH8&)D +?83YY' C&*w LN-SSAa8">9qYhE X*u}7 d, !bK꿮:7^=s { +W.dIԲbH~9iKspD7I?GOhN;G$튦o:Kδ;v9uF}С5lyx&w&3P?jsM|Gg$m /[Z_MOb_7bwh2 iRY%r*O; y={# ;s4}Wew&+{eT՞wu5S9jv+*KxIP*,)11~]IYd ـYէ~pheN-ޮeWMZVj6>w6􈰠U)%|0.!_yu)\vۭ%gצudҒK3=xn +ag7it(UjwUN. +}p_\"bpǯ"W wuwޟ-ٜ^;UykzBA8ͿYO'pee]c!Ǟh~}Z!KzSO9jIO[fuII3kqZ}!<HpAu P}rB.Õ +!on4s1%J'*0*$5˙+9K}/eˈ3<ڮȟm,&!AGe[~;C + ɽ+rkY:)i$.z۫eᏪ?JkW̢2[xbF̤ŌW #ks:Ñu[X?wbGO}%Өg12('1HZm:y~&4mP]x JFviN-ɟxo8 +&J{edk6H` %T8ȍd Fȝ!%a[/}#Ǭe R*)‡&ΤʕIpJ-S)GUGq<G)YU*\{ߟ*N5B~eZMp/)%5[Lf'xY:pvFpR"no3H(~v,xi̕,jv}BG0[~r'ю3ܷ$q/D4v桏)cx,GDt]sDD4A;cT>\]]=rdۖeI'"D8c2Dc6TJ8x,ZZ?DqjIN!J` /\'٫}ӐM~^cMk[\6;6q|^O {_Kry$ص r8$?vl{&v'yGVc@H( G#D4t^P4DfKKGDmQqr B־H6"P(>lp4 H8/Ey:c 5Nk乫]!Wb~u.i[6a:6sgo~œw !?D=J=vlȕ#`WG#`׎kGɵ# Ƥ'M*t"?_3MXNA0K[5B]!d׃{aV ,c2/ g_}= +سw>wYjϡzoN.mVͼcŽ2W kY4OzWywU填`Wr6kh}'5nu" kz-/AP2uCvC=xpRA?c(x}Vvo$|^)ȩk>wsW+/.'vYwvw}C[t#p:6fZ6˲J{&גֺ- cFh<"nYE‚~h` xhxѸ`XX0.  MiEE‚ .3˞ aRJK)/e 2R +-6_s? @ C/`,p|qpv/4ޑ!J)A bNRY# 1;W .^5.llj\xU+?1,_xY2vlwT? [7 vEǣa/4{3( +endstream +endobj + +193 0 obj +<< + /Creator (Typst 0.14.2) + /ModDate (D:20260608153157+03'00) + /CreationDate (D:20260608153157+03'00) +>> +endobj + +194 0 obj +<< + /Length 999 + /Type /Metadata + /Subtype /XML +>> +stream +Typst 0.14.2en-US2026-06-08T15:31:57+03:002026-06-08T15:31:57+03:002application/pdfE0IucPB7Hnqx8XY8S4CR1A==E0IucPB7Hnqx8XY8S4CR1A==proof1.7 +endstream +endobj + +195 0 obj +<< + /Type /Catalog + /Pages 1 0 R + /Metadata 194 0 R + /PageLabels 11 0 R + /Lang (en-US) + /StructTreeRoot 12 0 R + /MarkInfo << + /Marked true + /Suspects false + >> + /ViewerPreferences << + /Direction /L2R + >> + /Outlines 2 0 R +>> +endobj + +xref +0 196 +0000000000 65535 f +0000000016 00000 n +0000000090 00000 n +0000000170 00000 n +0000000410 00000 n +0000000574 00000 n +0000000680 00000 n +0000000800 00000 n +0000000917 00000 n +0000001043 00000 n +0000001156 00000 n +0000001263 00000 n +0000001316 00000 n +0000001636 00000 n +0000002219 00000 n +0000002812 00000 n +0000003057 00000 n +0000003184 00000 n +0000003276 00000 n +0000003371 00000 n +0000003463 00000 n +0000003555 00000 n +0000003750 00000 n +0000003845 00000 n +0000003937 00000 n +0000004029 00000 n +0000004121 00000 n +0000004213 00000 n +0000004305 00000 n +0000004397 00000 n +0000004489 00000 n +0000004581 00000 n +0000004682 00000 n +0000004773 00000 n +0000004865 00000 n +0000004987 00000 n +0000005073 00000 n +0000005217 00000 n +0000005310 00000 n +0000005424 00000 n +0000005584 00000 n +0000005669 00000 n +0000005770 00000 n +0000005862 00000 n +0000005951 00000 n +0000006036 00000 n +0000006134 00000 n +0000006226 00000 n +0000006315 00000 n +0000006400 00000 n +0000006498 00000 n +0000006590 00000 n +0000006679 00000 n +0000006764 00000 n +0000006862 00000 n +0000006954 00000 n +0000007043 00000 n +0000007128 00000 n +0000007226 00000 n +0000007318 00000 n +0000007407 00000 n +0000007535 00000 n +0000007635 00000 n +0000007730 00000 n +0000007859 00000 n +0000007954 00000 n +0000008047 00000 n +0000008138 00000 n +0000008216 00000 n +0000008307 00000 n +0000008400 00000 n +0000008622 00000 n +0000008714 00000 n +0000008806 00000 n +0000008901 00000 n +0000009001 00000 n +0000009096 00000 n +0000009215 00000 n +0000009316 00000 n +0000009407 00000 n +0000009499 00000 n +0000009588 00000 n +0000009706 00000 n +0000009798 00000 n +0000009942 00000 n +0000010083 00000 n +0000010214 00000 n +0000010306 00000 n +0000010398 00000 n +0000010542 00000 n +0000010683 00000 n +0000010814 00000 n +0000010906 00000 n +0000010998 00000 n +0000011142 00000 n +0000011286 00000 n +0000011417 00000 n +0000011509 00000 n +0000011602 00000 n +0000011746 00000 n +0000011890 00000 n +0000012023 00000 n +0000012117 00000 n +0000012213 00000 n +0000012359 00000 n +0000012505 00000 n +0000012639 00000 n +0000012733 00000 n +0000012829 00000 n +0000013098 00000 n +0000013373 00000 n +0000013630 00000 n +0000013724 00000 n +0000013807 00000 n +0000013904 00000 n +0000014187 00000 n +0000014287 00000 n +0000014585 00000 n +0000014861 00000 n +0000014984 00000 n +0000015088 00000 n +0000015238 00000 n +0000015384 00000 n +0000015530 00000 n +0000015651 00000 n +0000015748 00000 n +0000015837 00000 n +0000015928 00000 n +0000016036 00000 n +0000016115 00000 n +0000016204 00000 n +0000016384 00000 n +0000016612 00000 n +0000016671 00000 n +0000016730 00000 n +0000016912 00000 n +0000017721 00000 n +0000017812 00000 n +0000018065 00000 n +0000019559 00000 n +0000025678 00000 n +0000025862 00000 n +0000026505 00000 n +0000026597 00000 n +0000026855 00000 n +0000028153 00000 n +0000033490 00000 n +0000033675 00000 n +0000034525 00000 n +0000034616 00000 n +0000034872 00000 n +0000036518 00000 n +0000043821 00000 n +0000043922 00000 n +0000044023 00000 n +0000044124 00000 n +0000044225 00000 n +0000044485 00000 n +0000045068 00000 n +0000045818 00000 n +0000046006 00000 n +0000046287 00000 n +0000046373 00000 n +0000046633 00000 n +0000047375 00000 n +0000048391 00000 n +0000048429 00000 n +0000048467 00000 n +0000048826 00000 n +0000049249 00000 n +0000049297 00000 n +0000049344 00000 n +0000049391 00000 n +0000049439 00000 n +0000049487 00000 n +0000049535 00000 n +0000049583 00000 n +0000049630 00000 n +0000049920 00000 n +0000050210 00000 n +0000050500 00000 n +0000050790 00000 n +0000051118 00000 n +0000055177 00000 n +0000055523 00000 n +0000060561 00000 n +0000062327 00000 n +0000110956 00000 n +0000112844 00000 n +0000151225 00000 n +0000153008 00000 n +0000179450 00000 n +0000179906 00000 n +0000217177 00000 n +0000217304 00000 n +0000218393 00000 n +trailer +<< + /Size 196 + /Root 195 0 R + /Info 193 0 R + /ID [(E0IucPB7Hnqx8XY8S4CR1A==) (E0IucPB7Hnqx8XY8S4CR1A==)] +>> +startxref +218655 +%%EOF \ No newline at end of file diff --git a/docs/briefings/fleetnow_briefing_heads_of_department.md b/docs/briefings/fleetnow_briefing_heads_of_department.md new file mode 100644 index 0000000..3fb0640 --- /dev/null +++ b/docs/briefings/fleetnow_briefing_heads_of_department.md @@ -0,0 +1,69 @@ +# FleetNow — Your Team, Live and in Full +### One screen to see your crews, dispatch in the moment, and review after + +*Audience: Heads of Department · Prepared 2026-06-08* + +--- + +## The big idea +You shouldn't have to jump between a "where are they now" screen and a separate "where did they go" screen to run your day. **FleetNow puts both on one map** — see your vehicles live, then click straight into any vehicle's trips without losing your place. Act in the moment; review when you need to. + +> See your team **right now**, and everywhere they've **been today** — without ever leaving the map. + +## Why one screen beats two (for your day) + +| | Legacy: two dashboards | **FleetNow: one screen** | +|---|---|---| +| **Running your shift** | Flip between live + history tools | Everything in one place — dispatch and check history together | +| **Finding your team** | Hunt through a full fleet list | Your department has its **own colour** — spot your crews instantly | +| **Settling a question** | Cross-check two tools (and a spreadsheet) | Click the vehicle → see its trips on the spot | +| **Trusting the numbers** | Two sources that can disagree | One source — live and history always match | + +## What's new — and how it helps your team + +**🎨 Your department, in its own colour** +Every team has a dedicated colour on the map (ISP, OSP, FDS…). At a glance you can see *your* crews, where they are, and how they're spread across the city — with a one-tap colour key so nobody has to memorise anything. + +**🟢 Read the situation instantly** +Colour intensity tells the story: **bright = moving now**, softer = stopped recently, grey = offline 24h+. You can see who's active, who's idle, and who's gone quiet — without clicking a thing. + +**🎯 Know your ticket-closers from your heavy units** +Cranes, motorbikes, and pick-ups now carry their **own icons**, clearly set apart from the field-service vehicles that close customer tickets — so the fleet that drives your SLAs is never confused with specialist assets. + +**👤 Every trip tied to a driver** +Live position *and* trip history both link to the vehicle, plate, and driver — so performance conversations, job verification, and dispute resolution are backed by data, not memory. + +**🧹 A clean, honest view** +Personal, management, and out-of-region vehicles are filtered out, and each tracker+dashcam pair shows as **one vehicle** — so your map reflects the real operational fleet, nothing more. + +## What this means for your department +- **Dispatch faster** — find the nearest available crew in seconds. +- **Chase the gaps** — spot idle or silent vehicles before they cost you a missed SLA. +- **Back your team with facts** — utilisation, routes, and timing on demand. +- **Less admin** — one tool, no reconciling screens or spreadsheets. +- **Make your numbers look real** — accurate counts, clear accountability. + +## Where it's headed +More to come on the same trusted foundation: always-on visibility for specialist assets, per-department performance dashboards, and SLA/utilisation insights — built around how your teams actually work. + +> **From two disconnected dashboards to one screen that runs your day.** + +--- + +## Demo flow & talking points + +**The one-line message:** *"We merged live tracking and trip history into one intelligent platform — one screen, one source of truth, purpose-built for our field-service fleet."* + +**Live demo (≈3–4 minutes):** +1. **Open the live map** — "This is the whole operational fleet, right now, across our cities." +2. **Point out the colours** — open the **Key**: "Each department has its own colour — here's ISP, OSP, FDS at a glance." +3. **Read the states** — "Bright ones are moving now, faded are recently stopped, grey are offline — instant situational awareness." +4. **Spot a specialist** — "These icons are our cranes and motorbikes — clearly separate from the ticket-closing fleet." +5. **Click a vehicle → its trips** — "And here's the power of merging: from a live pin, straight into where this vehicle has been today, same screen." +6. **Apply a filter** — "Filter by department or city once, and it holds across both live and history." +7. **Land the close** — "One screen. One trusted source. No more switching tools." + +**Three points to repeat:** +- **One platform, not two** — faster decisions, less friction. +- **One source of truth** — live and historical can't disagree. +- **Built for us** — segmented fleet, department colours, real accountability. diff --git a/docs/briefings/fleetnow_briefing_heads_of_department.pdf b/docs/briefings/fleetnow_briefing_heads_of_department.pdf new file mode 100644 index 0000000..69e4741 --- /dev/null +++ b/docs/briefings/fleetnow_briefing_heads_of_department.pdf @@ -0,0 +1,3017 @@ +%PDF-1.7 +% + +1 0 obj +<< + /Type /Pages + /Count 2 + /Kids [163 0 R 165 0 R] +>> +endobj + +2 0 obj +<< + /Type /Outlines + /First 3 0 R + /Last 3 0 R + /Count 1 +>> +endobj + +3 0 obj +<< + /Parent 2 0 R + /First 4 0 R + /Last 10 0 R + /Count -7 + /Title + /Dest 157 0 R +>> +endobj + +4 0 obj +<< + /Parent 3 0 R + /Next 5 0 R + /Title (One screen to see your crews, dispatch in the moment, and review after) + /Dest 150 0 R +>> +endobj + +5 0 obj +<< + /Parent 3 0 R + /Next 6 0 R + /Prev 4 0 R + /Title (The big idea) + /Dest 151 0 R +>> +endobj + +6 0 obj +<< + /Parent 3 0 R + /Next 7 0 R + /Prev 5 0 R + /Title (Why one screen beats two (for your day)) + /Dest 152 0 R +>> +endobj + +7 0 obj +<< + /Parent 3 0 R + /Next 8 0 R + /Prev 6 0 R + /Title + /Dest 153 0 R +>> +endobj + +8 0 obj +<< + /Parent 3 0 R + /Next 9 0 R + /Prev 7 0 R + /Title (What this means for your department) + /Dest 154 0 R +>> +endobj + +9 0 obj +<< + /Parent 3 0 R + /Next 10 0 R + /Prev 8 0 R + /Title (Where it's headed) + /Dest 155 0 R +>> +endobj + +10 0 obj +<< + /Parent 3 0 R + /Prev 9 0 R + /Title (Demo flow & talking points) + /Dest 156 0 R +>> +endobj + +11 0 obj +<< + /Nums [0 118 0 R 1 119 0 R] +>> +endobj + +12 0 obj +<< + /Type /StructTreeRoot + /RoleMap << + /Datetime /Span + /Terms /Part + /Title /P + /Strong /Span + /Em /Span + >> + /K [15 0 R] + /ParentTree << + /Nums [0 13 0 R 1 14 0 R] + >> + /IDTree << + /Names [(U1x0y0) 105 0 R (U1x1y0) 104 0 R (U1x2y0) 102 0 R] + >> + /ParentTreeNextKey 2 +>> +endobj + +13 0 obj +[117 0 R 116 0 R 115 0 R 113 0 R 111 0 R 111 0 R 112 0 R 111 0 R 111 0 R 111 0 R 108 0 R 110 0 R 108 0 R 109 0 R 108 0 R 108 0 R 106 0 R 104 0 R 103 0 R 99 0 R 97 0 R 97 0 R 96 0 R 96 0 R 96 0 R 94 0 R 92 0 R 90 0 R 91 0 R 90 0 R 90 0 R 88 0 R 86 0 R 86 0 R 85 0 R 85 0 R 83 0 R 81 0 R 81 0 R 81 0 R 80 0 R 80 0 R 80 0 R 76 0 R 75 0 R 75 0 R 73 0 R 73 0 R 74 0 R 73 0 R 73 0 R 72 0 R 72 0 R 70 0 R 71 0 R 70 0 R 70 0 R 70 0 R 69 0 R 69 0 R 67 0 R 67 0 R 68 0 R 67 0 R 67 0 R 66 0 R 66 0 R 64 0 R 65 0 R 64 0 R 64 0 R 64 0 R] +endobj + +14 0 obj +[63 0 R 63 0 R 61 0 R 61 0 R 62 0 R 61 0 R 61 0 R 60 0 R 59 0 R 58 0 R 57 0 R 55 0 R 54 0 R 53 0 R 51 0 R 50 0 R 49 0 R 47 0 R 46 0 R 45 0 R 43 0 R 42 0 R 41 0 R 38 0 R 37 0 R 37 0 R 37 0 R 36 0 R 34 0 R 33 0 R 31 0 R 32 0 R 32 0 R 30 0 R 21 0 R 29 0 R 21 0 R 21 0 R 28 0 R 21 0 R 27 0 R 21 0 R 21 0 R 26 0 R 21 0 R 21 0 R 21 0 R 25 0 R 21 0 R 21 0 R 24 0 R 21 0 R 21 0 R 23 0 R 21 0 R 21 0 R 22 0 R 22 0 R 21 0 R 20 0 R 16 0 R 19 0 R 16 0 R 18 0 R 18 0 R 16 0 R 17 0 R 16 0 R 16 0 R] +endobj + +15 0 obj +<< + /Type /StructElem + /S /Document + /P 12 0 R + /K [117 0 R 116 0 R 114 0 R 113 0 R 111 0 R 107 0 R 106 0 R 77 0 R 76 0 R 73 0 R 70 0 R 67 0 R 64 0 R 61 0 R 60 0 R 39 0 R 38 0 R 37 0 R 35 0 R 34 0 R 31 0 R 21 0 R 16 0 R] +>> +endobj + +16 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [20 0 R 60 19 0 R 62 18 0 R 65 17 0 R 67 68] + /Pg 165 0 R +>> +endobj + +17 0 obj +<< + /Type /StructElem + /S /Strong + /P 16 0 R + /K [66] + /Pg 165 0 R +>> +endobj + +18 0 obj +<< + /Type /StructElem + /S /Strong + /P 16 0 R + /K [63 64] + /Pg 165 0 R +>> +endobj + +19 0 obj +<< + /Type /StructElem + /S /Strong + /P 16 0 R + /K [61] + /Pg 165 0 R +>> +endobj + +20 0 obj +<< + /Type /StructElem + /S /Strong + /P 16 0 R + /K [59] + /Pg 165 0 R +>> +endobj + +21 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [30 0 R 34 29 0 R 36 37 28 0 R 39 27 0 R 41 42 26 0 R 44 45 46 25 0 R 48 49 24 0 R 51 52 23 0 R 54 55 22 0 R 58] + /Pg 165 0 R +>> +endobj + +22 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [56 57] + /Pg 165 0 R +>> +endobj + +23 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [53] + /Pg 165 0 R +>> +endobj + +24 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [50] + /Pg 165 0 R +>> +endobj + +25 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [47] + /Pg 165 0 R +>> +endobj + +26 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [43] + /Pg 165 0 R +>> +endobj + +27 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [40] + /Pg 165 0 R +>> +endobj + +28 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [38] + /Pg 165 0 R +>> +endobj + +29 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [35] + /Pg 165 0 R +>> +endobj + +30 0 obj +<< + /Type /StructElem + /S /Strong + /P 21 0 R + /K [33] + /Pg 165 0 R +>> +endobj + +31 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [33 0 R 30 32 0 R] + /Pg 165 0 R +>> +endobj + +32 0 obj +<< + /Type /StructElem + /S /Em + /P 31 0 R + /K [31 32] + /Pg 165 0 R +>> +endobj + +33 0 obj +<< + /Type /StructElem + /S /Strong + /P 31 0 R + /K [29] + /Pg 165 0 R +>> +endobj + +34 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (Demo flow & talking points) + /K [28] + /Pg 165 0 R +>> +endobj + +35 0 obj +<< + /Type /StructElem + /S /BlockQuote + /P 15 0 R + /K [36 0 R] +>> +endobj + +36 0 obj +<< + /Type /StructElem + /S /Strong + /P 35 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [27] + /Pg 165 0 R +>> +endobj + +37 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [24 25 26] + /Pg 165 0 R +>> +endobj + +38 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (Where it's headed) + /K [23] + /Pg 165 0 R +>> +endobj + +39 0 obj +<< + /Type /StructElem + /S /L + /P 15 0 R + /A [<< + /O /List + /ListNumbering /Circle + >>] + /K [56 0 R 52 0 R 48 0 R 44 0 R 40 0 R] +>> +endobj + +40 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [43 0 R 41 0 R] +>> +endobj + +41 0 obj +<< + /Type /StructElem + /S /LBody + /P 40 0 R + /K [42 0 R 22] + /Pg 165 0 R +>> +endobj + +42 0 obj +<< + /Type /StructElem + /S /Strong + /P 41 0 R + /K [21] + /Pg 165 0 R +>> +endobj + +43 0 obj +<< + /Type /StructElem + /S /Lbl + /P 40 0 R + /K [20] + /Pg 165 0 R +>> +endobj + +44 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [47 0 R 45 0 R] +>> +endobj + +45 0 obj +<< + /Type /StructElem + /S /LBody + /P 44 0 R + /K [46 0 R 19] + /Pg 165 0 R +>> +endobj + +46 0 obj +<< + /Type /StructElem + /S /Strong + /P 45 0 R + /K [18] + /Pg 165 0 R +>> +endobj + +47 0 obj +<< + /Type /StructElem + /S /Lbl + /P 44 0 R + /K [17] + /Pg 165 0 R +>> +endobj + +48 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [51 0 R 49 0 R] +>> +endobj + +49 0 obj +<< + /Type /StructElem + /S /LBody + /P 48 0 R + /K [50 0 R 16] + /Pg 165 0 R +>> +endobj + +50 0 obj +<< + /Type /StructElem + /S /Strong + /P 49 0 R + /K [15] + /Pg 165 0 R +>> +endobj + +51 0 obj +<< + /Type /StructElem + /S /Lbl + /P 48 0 R + /K [14] + /Pg 165 0 R +>> +endobj + +52 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [55 0 R 53 0 R] +>> +endobj + +53 0 obj +<< + /Type /StructElem + /S /LBody + /P 52 0 R + /K [54 0 R 13] + /Pg 165 0 R +>> +endobj + +54 0 obj +<< + /Type /StructElem + /S /Strong + /P 53 0 R + /K [12] + /Pg 165 0 R +>> +endobj + +55 0 obj +<< + /Type /StructElem + /S /Lbl + /P 52 0 R + /K [11] + /Pg 165 0 R +>> +endobj + +56 0 obj +<< + /Type /StructElem + /S /LI + /P 39 0 R + /K [59 0 R 57 0 R] +>> +endobj + +57 0 obj +<< + /Type /StructElem + /S /LBody + /P 56 0 R + /K [58 0 R 10] + /Pg 165 0 R +>> +endobj + +58 0 obj +<< + /Type /StructElem + /S /Strong + /P 57 0 R + /K [9] + /Pg 165 0 R +>> +endobj + +59 0 obj +<< + /Type /StructElem + /S /Lbl + /P 56 0 R + /K [8] + /Pg 165 0 R +>> +endobj + +60 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (What this means for your department) + /K [7] + /Pg 165 0 R +>> +endobj + +61 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [63 0 R 2 3 62 0 R 5 6] + /Pg 165 0 R +>> +endobj + +62 0 obj +<< + /Type /StructElem + /S /Strong + /P 61 0 R + /K [4] + /Pg 165 0 R +>> +endobj + +63 0 obj +<< + /Type /StructElem + /S /Strong + /P 61 0 R + /K [0 1] + /Pg 165 0 R +>> +endobj + +64 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [66 0 R 67 65 0 R 69 70 71] + /Pg 163 0 R +>> +endobj + +65 0 obj +<< + /Type /StructElem + /S /Em + /P 64 0 R + /K [68] + /Pg 163 0 R +>> +endobj + +66 0 obj +<< + /Type /StructElem + /S /Strong + /P 64 0 R + /K [65 66] + /Pg 163 0 R +>> +endobj + +67 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [69 0 R 60 61 68 0 R 63 64] + /Pg 163 0 R +>> +endobj + +68 0 obj +<< + /Type /StructElem + /S /Strong + /P 67 0 R + /K [62] + /Pg 163 0 R +>> +endobj + +69 0 obj +<< + /Type /StructElem + /S /Strong + /P 67 0 R + /K [58 59] + /Pg 163 0 R +>> +endobj + +70 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [72 0 R 53 71 0 R 55 56 57] + /Pg 163 0 R +>> +endobj + +71 0 obj +<< + /Type /StructElem + /S /Strong + /P 70 0 R + /K [54] + /Pg 163 0 R +>> +endobj + +72 0 obj +<< + /Type /StructElem + /S /Strong + /P 70 0 R + /K [51 52] + /Pg 163 0 R +>> +endobj + +73 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [75 0 R 46 47 74 0 R 49 50] + /Pg 163 0 R +>> +endobj + +74 0 obj +<< + /Type /StructElem + /S /Em + /P 73 0 R + /K [48] + /Pg 163 0 R +>> +endobj + +75 0 obj +<< + /Type /StructElem + /S /Strong + /P 73 0 R + /K [44 45] + /Pg 163 0 R +>> +endobj + +76 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T + /K [43] + /Pg 163 0 R +>> +endobj + +77 0 obj +<< + /Type /StructElem + /S /Table + /P 15 0 R + /K [100 0 R 78 0 R] +>> +endobj + +78 0 obj +<< + /Type /StructElem + /S /TBody + /P 77 0 R + /K [95 0 R 89 0 R 84 0 R 79 0 R] +>> +endobj + +79 0 obj +<< + /Type /StructElem + /S /TR + /P 78 0 R + /K [82 0 R 81 0 R 80 0 R] +>> +endobj + +80 0 obj +<< + /Type /StructElem + /S /TD + /P 79 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [40 41 42] + /Pg 163 0 R +>> +endobj + +81 0 obj +<< + /Type /StructElem + /S /TD + /P 79 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [37 38 39] + /Pg 163 0 R +>> +endobj + +82 0 obj +<< + /Type /StructElem + /S /TD + /P 79 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [83 0 R] +>> +endobj + +83 0 obj +<< + /Type /StructElem + /S /Strong + /P 82 0 R + /K [36] + /Pg 163 0 R +>> +endobj + +84 0 obj +<< + /Type /StructElem + /S /TR + /P 78 0 R + /K [87 0 R 86 0 R 85 0 R] +>> +endobj + +85 0 obj +<< + /Type /StructElem + /S /TD + /P 84 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [34 35] + /Pg 163 0 R +>> +endobj + +86 0 obj +<< + /Type /StructElem + /S /TD + /P 84 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [32 33] + /Pg 163 0 R +>> +endobj + +87 0 obj +<< + /Type /StructElem + /S /TD + /P 84 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [88 0 R] +>> +endobj + +88 0 obj +<< + /Type /StructElem + /S /Strong + /P 87 0 R + /K [31] + /Pg 163 0 R +>> +endobj + +89 0 obj +<< + /Type /StructElem + /S /TR + /P 78 0 R + /K [93 0 R 92 0 R 90 0 R] +>> +endobj + +90 0 obj +<< + /Type /StructElem + /S /TD + /P 89 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >>] + /K [27 91 0 R 29 30] + /Pg 163 0 R +>> +endobj + +91 0 obj +<< + /Type /StructElem + /S /Strong + /P 90 0 R + /K [28] + /Pg 163 0 R +>> +endobj + +92 0 obj +<< + /Type /StructElem + /S /TD + /P 89 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >>] + /K [26] + /Pg 163 0 R +>> +endobj + +93 0 obj +<< + /Type /StructElem + /S /TD + /P 89 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >>] + /K [94 0 R] +>> +endobj + +94 0 obj +<< + /Type /StructElem + /S /Strong + /P 93 0 R + /K [25] + /Pg 163 0 R +>> +endobj + +95 0 obj +<< + /Type /StructElem + /S /TR + /P 78 0 R + /K [98 0 R 97 0 R 96 0 R] +>> +endobj + +96 0 obj +<< + /Type /StructElem + /S /TD + /P 95 0 R + /A [<< + /O /Table + /Headers [(U1x2y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [22 23 24] + /Pg 163 0 R +>> +endobj + +97 0 obj +<< + /Type /StructElem + /S /TD + /P 95 0 R + /A [<< + /O /Table + /Headers [(U1x1y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [20 21] + /Pg 163 0 R +>> +endobj + +98 0 obj +<< + /Type /StructElem + /S /TD + /P 95 0 R + /A [<< + /O /Table + /Headers [(U1x0y0)] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/Solid /None /None /None] + /BorderThickness [1 0 0 0] + >>] + /K [99 0 R] +>> +endobj + +99 0 obj +<< + /Type /StructElem + /S /Strong + /P 98 0 R + /K [19] + /Pg 163 0 R +>> +endobj + +100 0 obj +<< + /Type /StructElem + /S /THead + /P 77 0 R + /K [101 0 R] +>> +endobj + +101 0 obj +<< + /Type /StructElem + /S /TR + /P 100 0 R + /K [105 0 R 104 0 R 102 0 R] +>> +endobj + +102 0 obj +<< + /Type /StructElem + /S /TH + /P 101 0 R + /ID (U1x2y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [103 0 R] +>> +endobj + +103 0 obj +<< + /Type /StructElem + /S /Strong + /P 102 0 R + /K [18] + /Pg 163 0 R +>> +endobj + +104 0 obj +<< + /Type /StructElem + /S /TH + /P 101 0 R + /ID (U1x1y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [17] + /Pg 163 0 R +>> +endobj + +105 0 obj +<< + /Type /StructElem + /S /TH + /P 101 0 R + /ID (U1x0y0) + /A [<< + /O /Table + /Scope /Column + /Headers [] + >> << + /O /Layout + /BorderColor [0 0 0] + /BorderStyle [/None /Solid /None /None] + /BorderThickness [0 1 0 0] + >>] + /K [] +>> +endobj + +106 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (Why one screen beats two (for your day)) + /K [16] + /Pg 163 0 R +>> +endobj + +107 0 obj +<< + /Type /StructElem + /S /BlockQuote + /P 15 0 R + /K [110 0 R 109 0 R 108 0 R] +>> +endobj + +108 0 obj +<< + /Type /StructElem + /S /Span + /P 107 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [10 12 14 15] + /Pg 163 0 R +>> +endobj + +109 0 obj +<< + /Type /StructElem + /S /Strong + /P 107 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [13] + /Pg 163 0 R +>> +endobj + +110 0 obj +<< + /Type /StructElem + /S /Strong + /P 107 0 R + /A [<< + /O /Layout + /Placement /Block + >>] + /K [11] + /Pg 163 0 R +>> +endobj + +111 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [4 5 112 0 R 7 8 9] + /Pg 163 0 R +>> +endobj + +112 0 obj +<< + /Type /StructElem + /S /Strong + /P 111 0 R + /K [6] + /Pg 163 0 R +>> +endobj + +113 0 obj +<< + /Type /StructElem + /S /H2 + /P 15 0 R + /T (The big idea) + /K [3] + /Pg 163 0 R +>> +endobj + +114 0 obj +<< + /Type /StructElem + /S /P + /P 15 0 R + /K [115 0 R] +>> +endobj + +115 0 obj +<< + /Type /StructElem + /S /Em + /P 114 0 R + /K [2] + /Pg 163 0 R +>> +endobj + +116 0 obj +<< + /Type /StructElem + /S /H3 + /P 15 0 R + /T (One screen to see your crews, dispatch in the moment, and review after) + /K [1] + /Pg 163 0 R +>> +endobj + +117 0 obj +<< + /Type /StructElem + /S /H1 + /P 15 0 R + /T + /K [0] + /Pg 163 0 R +>> +endobj + +118 0 obj +<< + /Type /PageLabel + /S /D + /St 1 +>> +endobj + +119 0 obj +<< + /Type /PageLabel + /S /D + /St 2 +>> +endobj + +120 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /GMZGTI+LibertinusSerif-Bold-Identity-H + /Encoding /Identity-H + /DescendantFonts [121 0 R] + /ToUnicode 124 0 R +>> +endobj + +121 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /GMZGTI+LibertinusSerif-Bold + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 123 0 R + /DW 0 + /W [0 0 500 1 1 545 2 2 325 3 3 489 4 4 358 5 5 740 6 6 551 7 7 777 8 8 250 9 9 742 10 10 624 11 11 598 12 12 428 13 13 652 14 14 505.99997 15 15 905 16 16 244 17 17 577 18 18 322 19 19 529 20 20 616 21 21 561 22 22 730 23 23 427 24 24 456 25 25 558 26 26 581 27 27 619 28 28 688 29 29 542 30 30 521 31 31 1028 32 32 315 33 33 391 34 34 315 35 35 256 36 36 716 37 37 504 38 38 573 39 39 252.99998 40 40 551 41 41 736 42 42 613 43 43 358 44 44 609 45 45 740 46 46 734 47 47 706 48 48 654 49 49 899 50 50 244 51 51 680 52 52 729 53 53 527 54 54 514 55 55 534 56 56 514 57 57 614 58 58 1154 59 59 641] +>> +endobj + +122 0 obj +<< + /Length 13 + /Filter /FlateDecode +>> +stream +x ># +endstream +endobj + +123 0 obj +<< + /Type /FontDescriptor + /FontName /GMZGTI+LibertinusSerif-Bold + /Flags 131078 + /FontBBox [-1 -238 1094 720] + /ItalicAngle 0 + /Ascent 894 + /Descent -246 + /CapHeight 645 + /StemV 168.6 + /CIDSet 122 0 R + /FontFile3 125 0 R +>> +endobj + +124 0 obj +<< + /Length 1444 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +59 beginbfchar +<0001> <0046> +<0002> <006C> +<0003> <0065> +<0004> <0074> +<0005> <004E> +<0006> <006F> +<0007> <0077> +<0008> <0020> +<0009> <2014> +<000A> <0059> +<000B> <0075> +<000C> <0072> +<000D> <0054> +<000E> <0061> +<000F> <006D> +<0010> <002C> +<0011> <004C> +<0012> <0069> +<0013> <0076> +<0014> <006E> +<0015> <0064> +<0016> <004F> +<0017> <0073> +<0018> <0063> +<0019> <0079> +<001A> <0070> +<001B> <0068> +<001C> <00660074> +<001D> <0062> +<001E> <0067> +<001F> <0057> +<0020> <0028> +<0021> <0066> +<0022> <0029> +<0023> <003A> +<0024> <0052> +<0025> <0053> +<0026> <0071> +<0027> <2019> +<0028> <003D> +<0029> <004B> +<002A> <006B> +<002B> <002D> +<002C> <0045> +<002D> <0041> +<002E> <0044> +<002F> <0043> +<0030> <0042> +<0031> <004D> +<0032> <002E> +<0033> <0066006C> +<0034> <0026> +<0035> <2248> +<0036> <0033> +<0037> <2013> +<0038> <0034> +<0039> <0050> +<003A> <2192> +<003B> <00660069> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +125 0 obj +<< + /Length 6425 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xYy\W^TM( T5:hDʨQAhh6ٺ١ުwfZ@\hV$feLf2skl/ꮪ߽uos}_s\&Ntp8ֈĈݡⅯ qfIvƍbss&̓f3=3\\\NM}Ņ3\\~m?8r{ŕ X9$4&1"1e}єDǿ,ÒK/ykOx5y툏 %zKJ OX22P\T [rj *oI)c +xX~.]Mj4Z&{y8961~Ε ϸM&zL|q{\)wg  +ޝ=)3$Nu{w^;+lg=+{}{{63:iǯ{xgsg |F3N(ɠ;g빌*)/DOh9jtǘQ8fx c<4g +c|8rCۭbN14rGfM|lm}r(q֪ *U6ۘ#xSad Om@" Ǯ +ޛJb`t`$ WmGcf!Eh +!tĉkՖtTF|k['d][*&ShYCxb{3ҕٙt _e <\M#-)TrUkN59t.,3^L&%~_Y oP9ڹ+ aRE8;/N͋rGWBn4I$\W1lFq`?ɧL* hM@v~|1FRx{h'U8R>$U1o\9jo\>h39H]DZtf +)e"jӗi +l'm'3NĤ0qÏ';4%؉x*ZU DB 9 k]1<_xMmg?s@^w`+;YsJ +AdՉ2SaAьIL<?KU= [=%'4%#DL # +y]M2CQ1<1/OUzT}sګCg*}e7X9xRpeawtYՄMY 7Q)Iݢ yjcy/ȴ2*>8RBа&7T{ulwzC9JKYZl^(LrIט},!DϖIL|  xkAIQ e5[KHKALrȆFGmtcXxhCnTi k elSu:`HaEjc sh;0C6!FmgG:Rw(/lSq[ֶV#5]P5Xh-Gqh:FTUDd>V >(PZmL!|\YsY>_x2ro]|:rۄ_va;ý ^ 0aۇץtC-m4vD]4gL}paΒAc [k+1Qjڪ + +㤣%a& .f5}"쳆s͵)-#O4>>-<ԦoVE 2 +jsAF9?fb7!YFHTXmdGc./K ~4k{{HjCb~ SRe'N#;iO0AԿTL:.jAEc}FUn2 R,۞ᝣ$Ҥd4A*8ŁgoD8(1"LAr8 Y"S++m3u kZ[{)a~'n];'(@s CzaK^D3"4ns!Ur91\|]; 5(eݳH!J+iՕ Fa UcʠbW}meH6mmLl O 0"]Kv.~FQ򷂷ڨ62.b<:iLG#&*,4<˻(&I,}D7T``p_Q^+K߿T!0tjQ6j6eGjd_ +@/KХ +bɟ\8cWL ላhƎ +P:&cU\ANᩒ}IY_0L45ucdm*F ?WͥQ`o:X:np<^=콓ڿ-f:@~YjBӭ td +D+w sфpi!r7 \{a.n8`7 +eo |̞[XC6*l DUYYC=ʧ*UhV剜f8*޺'cх e)b(1CБR@DE 8s]Bs4@]¹=ҕ]^.˦Ģr35Cm%!QzNL6W4u=8hTjk ZhDrɨnC* VƏ՗6~ {e&746w~lu<ĆG<VҬjVAiF0Vet"2ZVKٞ Iۙ]Z#4my^YR.Hy$3+% dhR4Sfɦ-"`*rEH __|  ^_%|lo ϮW7¼aɥv%ܯd?7<*_-@*,|h"jڊ^?4iYWMuC%,}&[*o U2ST +ҧ[nįu/,%;Z~`7H;֣߃lξNQ3{J ?)IZtߤ2$S/^^/L )$rabP@hYqz.3aTRWd۞X~C>,т.ݪ0[HS=x7r0YRRIea,*[Je=$$& Gѝa#%14jhE+Ud_[H:&*F^ HN(  a߰A6cmeq ;#bh{К"dItp_@þ8 +Y{}R"YeMS^rp\TB\x.:~YK \ 4W줨 A/#S:Yi"SEvmVҒ/LC>Bc}ai)t_u(9o*("uu. bQZ~`#hlb\4q砵h !DQ8:}-Km +1$Ssx0fHOȧ,ꊓuGN=;58"R5?"XK}P# +\~ w+ I6F p> ӁwX :hzao>(EDP00'ׄLȔ tv?`0`ߣp2SH,g,wb XȒXLc0 h @v!)SՎX1L凧#:/lk*{ +֒_8.yuVU ̑kM,w]1:7-"vdDCPhg툓тnnMCRXr)M0 Ðk +}V/WI65\"N'DBNn +)7>K Կ*Vh +,Aeg9JX~ Hl+Epv=y6c9S*MlII4Mf(]s)oguo6mQF=`3!"¼o]]sQ) j5zsvee>>潋in֛'7& +.l9cIo+(ϳ<8V&PiU\;ml`ǷmH25X(L-ϴ|maνΛq' gEq8/WZUCl-OK&9]xAmqJ`T? +O!|ůoRY骈`XPI':5Wֵt3m#B In$5|`RVĉ3c91i ;Pj4 zB-DUEX$EjZ8q@cU)zBc,_ ;8˟ޫ,Ww):_ǝ:˽,*7>bS! g.7^6LIL`4`r./)L Sf'Jm?vl^v]WFbݰ#|hnd&aKF +bP y#'Kk~m:HL +fGw}^.;A˩ >dݧ5מ5K<.̿PiM(Z+HQ5Ni[1`Jfq%C҃i@Մ*) 1#qųAvzE69aZڿށEX/5|u䁧sJi$<LFo_-{"Q9ġ. +EĖ| +.'M]9dw K+ɭQ񒣒(/Bw,vW&uVd[ދ4U xO^vX7(Rq'{aY g]we1_ +xU"j;3klwhI^k=w%͋%eRL +F!S_urS9Ǫ<[}&T3fq;}ZmQe /* +u%$6rz:rC?ŋC$5L$;RLIKWf)}$L/~e&o"ѕpQc$h&aLů7ErR8Mfmol)o +Aa1ulжr7q,v[,)IugfJfJ"RedBci<QX޷~OpVm>Xc.QG($\n<^\BED- ݥGltio^r_7/~u!< +endstream +endobj + +126 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /UXCZPY+LibertinusSerif-Italic-Identity-H + /Encoding /Identity-H + /DescendantFonts [127 0 R] + /ToUnicode 130 0 R +>> +endobj + +127 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /UXCZPY+LibertinusSerif-Italic + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 129 0 R + /DW 0 + /W [0 0 500 1 1 667 2 2 521 3 3 489 4 4 276 5 5 401 6 6 518 7 7 389 8 8 219 9 9 250 10 10 673 11 11 486 12 12 353 13 13 447 14 14 314 15 15 667 16 16 489 17 17 357 18 18 307 19 19 783 20 20 250 21 21 499 22 24 444 25 25 333 26 26 444 27 27 503.00003 28 28 375 29 29 909 30 30 477 31 31 266 32 32 472 33 33 486 34 34 519 35 35 742 36 36 219 37 37 478 38 38 564 39 39 570 40 40 219 41 41 375] +>> +endobj + +128 0 obj +<< + /Length 14 + /Filter /FlateDecode +>> +stream +x +endstream +endobj + +129 0 obj +<< + /Type /FontDescriptor + /FontName /UXCZPY+LibertinusSerif-Italic + /Flags 131142 + /FontBBox [-78 -238 1042 726] + /ItalicAngle -12 + /Ascent 894 + /Descent -246 + /CapHeight 645 + /StemV 95.4 + /CIDSet 128 0 R + /FontFile3 131 0 R +>> +endobj + +130 0 obj +<< + /Length 1188 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +41 beginbfchar +<0001> <0041> +<0002> <0075> +<0003> <0064> +<0004> <0069> +<0005> <0065> +<0006> <006E> +<0007> <0063> +<0008> <003A> +<0009> <0020> +<000A> <0048> +<000B> <0061> +<000C> <0073> +<000D> <006F> +<000E> <0066> +<000F> <0044> +<0010> <0070> +<0011> <0072> +<0012> <0074> +<0013> <006D> +<0014> <00B7> +<0015> <0050> +<0016> <0032> +<0017> <0030> +<0018> <0036> +<0019> <002D> +<001A> <0038> +<001B> <0079> +<001C> <201C> +<001D> <0057> +<001E> <0067> +<001F> <006C> +<0020> <0076> +<0021> <006B> +<0022> <0068> +<0023> <2014> +<0024> <002C> +<0025> <0062> +<0026> <00660069> +<0027> <0066006C> +<0028> <002E> +<0029> <201D> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +131 0 obj +<< + /Length 4998 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xXy|uO,t#t 32-+.(" +R}H;&=;=RzЂ@A +R.QK_V]ɜO|&c|Ș̄Ԭ1 /m<{=۟A< ɣ^Ef3#f0͜`wkc1,ΦѼȘ1 9kyi9 qs~<[J9;c՜Ę92yLzUnхF; JӫÆi~ӴӽOO1 g߳:V3ǧRDcOf3zw +>E9ԔAWVVi +G?_i3fܚ:s$nAЊgsϚ7kݬQLQzQ?zub]o+xZ1};+ ϐ1Tseq@b=]4<Xr{ CJ,c5YuDGi) +ʓ&RO(J!Biӝе{Vzޅt*bye +o˴qQTIiy$8V'9H)'PBv{>!I!At^YV/<ޤuzD:+NdjX:-5c{R>"FB§z=xNΡԑ5\rȅ)BKWotTqAY(Udd\T ml9z_8&""j>L(US\Nm*䬕&]+q,A/{͕EJX -|Sn¦TZ +4ab"QIِSY(@?O-@J6MjĪsYd,| Ѱ Skc9p6w.D/l4 s'?3sM #9C2=δ㌅bV0 ,X򷷿FÁ|ĵyXR_'dL/6Khb'kR &U<"F"$MEF ?WWeUUnwV'8U y&v,~T;+>6Zf-|K;7ܼpu4QT +m}MJ[JnWJց.DJr??M0VSLu 2^&4: ACJme W 4l#T;dTGlzD)K"qsFt"hRer'1UD$qB ?L8U61oNx(F½2tB?i$) +.T b`Ϯ+j$(Zyu^dFmG$%%ZW'!<;\@/+8~bBnkn$z{<߷9LQ31c9WgrB`js`$ϳ:A1`4*[~M&:f.. +REc@/_JU*uQյ2% sc?P}P=MP25M/ - ԧ8asVIxL0reJ/ + Q8%+n?9AR.83) K"Wh8z5G7Dn7^K$'KHh CTHXkE[wm,@dyntjئC8kb6#J/2UQD5%jLSeñT$$3-̑o,冕mn25\|Ʈ܁+`0'nZw<^QnMKbxQ91xꁎoIBi 7[^WV + KE`. eHe+Еܬz*zoհ:F7nleFD{JfPz>*:e(=,ǫ&2hMM{gg/$A2>FΫ@F.S*Tcj@6CxR@0Mv9T^:tv}yj}u%^~`\BhCѱѺs)5SBD1P&ܭF*(4rbR$'RRޣHcSgP)@_c4j:Y E 1c|s_)=3AV+=pr .zت[ŦDF܉W5T9hܱ/0I$FQ` +TAõMmދj-#SMjJG z  ye w!Ox;Xa^ol#Rbp~ZIC6y"g~Ѿn/Ɂ}O]x&:kmEPkk-ʤ ,<2Xa_Ζay6qCk'4jnR$zJf))( uXسm- 3khWsèɼ z,o.B`-"O' 8m/B|׻9"(<8X~A:{1v:*OߤoF1{uxRF6jTS)(JC荑Y K9W$ddoXg$ iiG,FEbvbyB-ZB S7.VNboGDTyT[ۧk$rVcFKVW=LrAo  8\vl{GGo zDifx3@wdK =L0G7/J`XxIp^EXЅ}oق^N>@T#/OacnOww'"[OuF-c3!×O]!2ʸhlɞ/3 W$;v4 ΄]M9wqtotx0 8`KyvYkq[V_N-P%Ti""W%$^K%`˿L3 +*Ցx-҉V\KDeZ [~j{ۭDXZRL*]6im:LZ*Od ŸP>IQhcWFz9+p[%ͮ,KZRH̦dT_8s)t54&"Y~No''hӓ>ޕ3'f9VظB sF۠+݋<\ɲA8+LfCUx + JjYls ̬INI&eVگA(zt7n掽lw%5|'vQ+wOuυL8@_~:-c]Ca30m u戳$9Cn1f*j頊(1&f^!"Xnv`7Έ@8d ;Klkm5;*0^yNmsxr㉝ _Bh?ZXp +@́Aۄe^?s2hD8YZ>,woY<GH\'Q9g^,#dBrNcksq75k˚jGA~ YS GI2_K3>~4DK_0?M3z%a L ?M]W?9Y]=OW +endstream +endobj + +132 0 obj +<< + /Type /Font + /Subtype /Type0 + /BaseFont /DLORQH+LibertinusSerif-Regular-Identity-H + /Encoding /Identity-H + /DescendantFonts [133 0 R] + /ToUnicode 136 0 R +>> +endobj + +133 0 obj +<< + /Type /Font + /Subtype /CIDFontType0 + /BaseFont /DLORQH+LibertinusSerif-Regular + /CIDSystemInfo << + /Registry (Adobe) + /Ordering (Identity) + /Supplement 0 + >> + /FontDescriptor 135 0 R + /DW 0 + /W [0 0 500 1 1 575 2 2 504 3 3 531 4 4 250 5 5 390 6 6 538 7 7 264 8 8 505.99997 9 9 542 10 10 268 11 11 316 12 12 457 13 13 497 14 14 447 15 15 272 16 16 790 17 17 519 18 18 493 19 19 747 20 20 375 21 21 372 22 22 515 23 23 375 24 24 428 25 25 271 26 26 500 27 27 220 28 28 742 29 29 220 30 30 512 31 31 695 32 32 236 33 33 485 34 34 528 35 35 236 36 36 485 37 37 550 38 38 557 39 39 730 40 40 310 41 41 540 42 42 646 43 43 338 44 45 298 46 46 1130 47 47 597 48 48 702 49 49 297 50 50 541 51 51 701 52 52 749 53 53 596 54 54 550 55 55 815 56 57 465 58 58 503.00003 59 59 560 60 60 465 61 61 351 62 62 839 63 63 323 64 64 465 65 65 588 66 68 465 69 69 699] +>> +endobj + +134 0 obj +<< + /Length 13 + /Filter /FlateDecode +>> +stream +x, +endstream +endobj + +135 0 obj +<< + /Type /FontDescriptor + /FontName /DLORQH+LibertinusSerif-Regular + /Flags 131078 + /FontBBox [-48 -238 1072 736] + /ItalicAngle 0 + /Ascent 894 + /Descent -246 + /CapHeight 658 + /StemV 95.4 + /CIDSet 134 0 R + /FontFile3 137 0 R +>> +endobj + +136 0 obj +<< + /Length 1592 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<0000> +endcodespacerange +69 beginbfchar +<0001> <0059> +<0002> <006F> +<0003> <0075> +<0004> <0020> +<0005> <0073> +<0006> <0068> +<0007> <006C> +<0008> <0064> +<0009> <006E> +<000A> <2019> +<000B> <0074> +<000C> <0061> +<000D> <0076> +<000E> <0065> +<000F> <006A> +<0010> <006D> +<0011> <0070> +<0012> <0062> +<0013> <0077> +<0014> <201C> +<0015> <0072> +<0016> <0079> +<0017> <201D> +<0018> <0063> +<0019> <0069> +<001A> <0067> +<001B> <002E> +<001C> <2014> +<001D> <002C> +<001E> <006B> +<001F> <0041> +<0020> <003B> +<0021> <0053> +<0022> <004C> +<0023> <003A> +<0024> <0046> +<0025> <002B> +<0026> <0045> +<0027> <0048> +<0028> <0066> +<0029> <0066006C> +<002A> <0043> +<002B> <002D> +<002C> <0028> +<002D> <0029> +<002E> <2192> +<002F> <0054> +<0030> <004F> +<0031> <0049> +<0032> <0050> +<0033> <0044> +<0034> <2026> +<0035> <00660074> +<0036> <003D> +<0037> <00660066006C> +<0038> <0032> +<0039> <0034> +<003A> <0071> +<003B> <00660069> +<003C> <0031> +<003D> <2022> +<003E> <004D> +<003F> <002F> +<0040> <0033> +<0041> <0042> +<0042> <0035> +<0043> <0036> +<0044> <0037> +<0045> <004E> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +137 0 obj +<< + /Length 7114 + /Filter /FlateDecode + /Subtype /CIDFontType0C +>> +stream +xY ten Y #%3Ȣ (lBYK e)tKҽIu2Y4ݛn閔.t + +E@w心/Rh4y]c0OOOeB#քG:$,)rkBgjG3#=V{{$w dvGg<<5uS_:eg׆CGLQ:rO,}"?zרFE+aOy^qsXSSA zzӵOѫG[_:&re+[K+I/24?gӏg(_m7Mcw|9~+9`9̾a_6^&6sEÜh4NXn ]XTC)ƘLZP;0z +VdR_ԅRQbt%-+D<ꝰ`=/FPA(-2)v `4.KBLUVE諾n{䄁O֧/ + ̨ϖˠj*wm?@. %W-z\6Fn|.^_'Jw2^_QRsO4,:ZDh9j#mↂ&@aot a-pJKz%ҩatĠyYKX;&k3!ix$,[NUd.Y=Ghԡ1/9bފ`l{'ƭBJqlj̤|NU~ZTIb;W +[>~#0)JiuM4Fs?yvy1D( +%़\)T.iST +S2Pi%"f^\Sd2fS`r,DSsO/g&HX%DpgIU~JBЊ +^5]O\1rѤ+M5F&q{U]5DYj-߰"sIQZ"*&!>jpi J/#kw3Ԛl]IzM,*tjvPՃ7 |Z"Э>&3%JAh6\ޗKV.vApT&B~kCÀ!+݂%?ێGY믴EOqPm+ڎ/ْDƭ+D>~<yPH}|Ow=xcefb)G +Y~֋nyS ~`- +BcR;5N9>4 +]NۯU"?W(lYChy\v;5tr5gt&vjÚE+I>r{' w|I*i,)M~T'7ˉCts|$wN`je +2TYd&WISC6Ih +㢲XE$~Z kPѤ+U2RFHReYz3b /I[u2^? 3ZSiʍƛJ$,O!Ofє0f]`*Ul3Sf)WX;~O*b*5E[$u DCMN}QZrf* +BOrն;>/!-"f A<΂/*S-Ԧ)*>}n©ۣ%7)i:n2)pTd&a |RҖ[y8{T=F.rgӗp<}C +j$ŎPa̦/FtĞ^Y!$o"V1X%v K.zSRJH>j@ mofA+}X-)[Fdr**L%"qJtcF}\}V !6>= v2WZd@ "bBTK`ָ?Oź`&j4J+oc.SvjfCL.v^9]MxsubVT`7Ȍ0ͧlľ<'\D Jd܌{_v=٩ܫ'/O^G +k"6n%.R!l<~8Ab=ЋιIHr)0s/ q#s/0H 3PV!Q-䞎b7oMQOPi)+V*م靏س'a)R\25 +a)n ^-bȶED\ƪa6C +"e\n'e:KS) 6U6dZr,VI+%(` OO I$͑./!ΦD*$v5/@\O&B gf྅p*,$=\F3 +@h DaKQuAL'QQQ[i4:#M-Wi3 ;yκ0}^e.lJ~]Ce֍ ے;N>Z!٫gqYa2{u]%EO&RMB7v#L +xO]Q"^+hin}c3ay~h\T?,-3T㳁v.W0YB XeVL;lŢAٖYWWVخ][7nH`y +2(L»h:Vs| Jw1 ?D*&*y؍:u"-E-OKBwneɁRATXD,-r)dU>Fq&iLHX!P%xtzT4mݕsE Ý_ ?_gr/irx6]f1 TlmL +|c|aNx츽:wMET:B7G%"f`niܰH5*}!GVXO?%a-SGg_$kUEӾZWm {vf%3ZPR\\jO. H#S+V[YKb-1 i°ҘL|Mb +.=:> LרH*]J)RVDfTT˝W{ۓ3KpY-3Y{!OcOAGs 5y|{7t&2Džc] v+``7e9Q{~LHo{:*Hصb׮脄h+ApVwqJmu}'+C|tdOdrjf: _0~[PeӮU>m-):7"+ؖLgԴFOetim-U: a7#ox[eTBVg0_]kq 6T J'DUB,+1:2".9)-6+Y̓ح! 旿J0|q@nfSXZ&&Ca۶Uz}]^ N9-KdH|^'n91;[yBic&l d_b yg gd_ *|wgT ehq;*5YDJNn/IEdq\>s<4 (tǑ33M;jm= 8MߜӰ-]ZO4 iSN8y-2 SΒ!;Mt}cӐ3Cbc{80p1m{aʴJm*ȄwsgʔZCzA%qs!íui sɳ H^z(& EqOW'ɏ?ދ;kFiSY&^ygB7D$MzNEB!O䲠y6*%Q '+31EjYH>ߞlj`A0ZLXu9f}o{3z(B! P[f C#&NF,w=ᝋ,0QЮ4 &[9BqDB!*D#K\#~GgN]~ox ߞ?U+bSGha[|e#o~w~`|sҙ#Kqٍ /ks#Q9'nNO,$$PPĔtCC+R纁ybc`V;31GC=jHu}q#3Rd&(yIr5K#SIzI}7lJ wetKs:&Cv؈ܙՖ!k &W鐵kU=屏)յ֎Ux+m{y/Wj*Z5.Cv/2Av&F ~L`*!U]q$v&dMSGsދsO{} JRE5e9L`4f%GXYx'V ccW'R0Sסђy1S'Ƈh!1[ֶ3BEVbO8bA`&sN]ѱwpJRE.xhk9^[CkM!A.<$n04{׏s JlVIBi"@-h g07<-^ !; #77InSʕْl;RgJw[ {a/aXkyA'&0I!vrS(eJUw˿̊/#~AY*Ga*+u9 +gEES8Zszɶb՞^K9yڔm 2P︣}`[#'z@nZD޽bO;˂?FVEX?mNbZ2S ^O QwfC@x1$>TÇ{zY\.SZW! ,x[~e oEtDݽg92iAw(VdůVa%Fehf&u[ȖM&d0H*GiwbeA`IepS ̞=`_a?椠Us^ ;غbm8yb1SceYd4&E䴠/cg& +endstream +endobj + +138 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0Pp +Q +endstream +endobj + +139 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0TpR +endstream +endobj + +140 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0RpS +endstream +endobj + +141 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0VpT +endstream +endobj + +142 0 obj +<< + /Length 23 + /Filter /FlateDecode +>> +stream +x00P0PH1ү0QpU +endstream +endobj + +143 0 obj +<< + /Type /FontDescriptor + /FontName /AppleColorEmoji + /Flags 131076 + /FontBBox [0 -102.400024 800 697.6] + /ItalicAngle 0 + /Ascent 697.6 + /Descent -102.400024 + /FontFamily (AppleColorEmoji) + /FontStretch /Normal + /FontWeight 400 +>> +endobj + +144 0 obj +<< + /Type /Font + /Subtype /Type3 + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 158 0 R + /x1 159 0 R + /x2 160 0 R + /x3 161 0 R + /x4 162 0 R + >> + >> + /Name /AppleColorEmoji + /FontBBox [0 -102.400024 800 697.6] + /ToUnicode 145 0 R + /FontMatrix [0.00125 0 0 0.00125 0 0] + /FirstChar 0 + /LastChar 4 + /Widths [800 800 800 800 800] + /FontDescriptor 143 0 R + /CharProcs << + /g0 138 0 R + /g1 139 0 R + /g2 140 0 R + /g3 141 0 R + /g4 142 0 R + >> + /Encoding << + /Type /Encoding + /Differences [0 /g0 /g1 /g2 /g3 /g4] + >> +>> +endobj + +145 0 obj +<< + /Length 681 + /Type /CMap + /WMode 0 +>> +stream +%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: procset CIDInit +%%IncludeResource: procset CIDInit +%%BeginResource: CMap Custom +%%Title: (Custom Adobe Identity 0) +%%Version: 1 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo 3 dict dup begin + /Registry (Adobe) def + /Ordering (Identity) def + /Supplement 0 def +end def +/CMapName /Custom def +/CMapVersion 1 def +/CMapType 0 def +/WMode 0 def +1 begincodespacerange +<00> +endcodespacerange +5 beginbfchar +<00> +<01> +<02> +<03> +<04> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF +endstream +endobj + +146 0 obj +[/ICCBased 148 0 R] +endobj + +147 0 obj +[/ICCBased 149 0 R] +endobj + +148 0 obj +<< + /Length 258 + /N 1 + /Range [0 1] + /Filter /FlateDecode +>> +stream +xuJPFOUvDD@`]\ +FMkIRB|&إnऋ(HrTų9` ըa&ʺ:l +3Ŭ*ުnh)&C|>b纝黓AvCƫ+ y') +̵8+/> +stream +x}Kq?UX 94%MQKSN#ԦQvBˡhFk ! +ՠZP~xx^ޗQx"^P c!H0 + 0l+ߣy7;׫;Q?V._tF3LEK)y z80eIPkT/%[p:8+%d"G `d_{ٹ֖gzm\8rSif1\CU` S] @o _ +endstream +endobj + +150 0 obj +[163 0 R /XYZ 90 736.11676 0] +endobj + +151 0 obj +[163 0 R /XYZ 90 684.6368 0] +endobj + +152 0 obj +[163 0 R /XYZ 90 549.6448 0] +endobj + +153 0 obj +[163 0 R /XYZ 90 334.52277 0] +endobj + +154 0 obj +[165 0 R /XYZ 90 706.2738 0] +endobj + +155 0 obj +[165 0 R /XYZ 90 608.87976 0] +endobj + +156 0 obj +[165 0 R /XYZ 90 486.96677 0] +endobj + +157 0 obj +[163 0 R /XYZ 90 761.8898 0] +endobj + +158 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 168 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +159 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 170 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +160 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 172 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +161 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 174 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +162 0 obj +<< + /Length 40 + /Type /XObject + /Subtype /Form + /Filter /FlateDecode + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /XObject << + /x0 176 0 R + >> + >> + /BBox [0 -102.400024 800 697.6] +>> +stream +x+00PAkh`gb```d˥_a +endstream +endobj + +163 0 obj +<< + /Type /Page + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /ColorSpace << + /c0 146 0 R + >> + /Font << + /f0 120 0 R + /f1 126 0 R + /f2 132 0 R + /f3 144 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 0 + /Parent 1 0 R + /Contents 164 0 R +>> +endobj + +164 0 obj +<< + /Length 3909 + /Filter /FlateDecode +>> +stream +xێ]_A8~i-ꢅOIvV"^hC^x,䐇~۫׿ܓg6\zo|y͋Ϳ70ȎψUzm{c #o_o~\*r_&N뷛>1=c|Kv\QO%;SO=?͖,y{~K,?.O=l<\ `yBnK Bg [Ƴ.6^oՋ2^2)seua#?$])8pX`+c$O_U ŗ yE~ ۘHB@U}7 + Nžbߟo$LRc5 ̝XT%SrψTbȇ HpXN\οyT_ B-j@P{IwϨyz(j3 ~R##y]C<#1r!:RRKAd]k(z*ьmH N"A ْTj"?!YFNI!ׅb + <唈bRae14PT7&/o7wz8exuS= +w55W`ǎ W+`g6ϸ(L26`Ͻ>! ʬQ+ U;fOGbjд&QgRY/݋(›+{ ̸ Ĭ-i!&Gq (cBkʌC3&.oPf,s&3hQ25<&(Ybw?ܛ +fhSP!Jp0P!@|!qܲpUN6gK n"7a :FsZzj P#}0pj%z@8 +m8f- %L|pniCQH tꙞ@|+t܈p +9B:}^) @?qNJ)l`lפ.VE1Fm+-%m[F^q%*I0*OiUF. 9.## /LX"ԞrˤkC>]o7?_ρ<{˗}WatKucc +/G2TU1}K=Ur>EjfU'#7j]RyiQ:X/(t{OB[;p'FK.͔"13߳ӷ{eZ1 e̹f S,h)Gʟ;QVk;-7t{?x@%P&[H7m 9GG˺)gJԁbrRQn\Kv{|n )4]1R;ڭ9Vp"@J) t}m=E ܺ[h8˳A̸.q9;Sc~1cUVۖuV8TZv>Fȹp?8H; 9i@Q +9 +df +U+ 氣/FȮ3w#a45P +r`ͻU5Iڱ]=jrZKV8 ^ V^Z7%F9V{Au_]j$5@ Zl80 4SͬL:GbxSDL$۹x&\Q:H@U aR1*ʓ3Iz$8Ժve+񎭤Ũ4s# 1^E#cce0.7ձaCcq1)C0 ĘN; ^" nu}ws{jF v+9Rҗ{ PkѢ F +:PcDPŸ+5LBx*\®6 NMb/ Ԏ~/l#̼z.N'~F Oq*`rK Q`*|vŞx=Tـw_S]ANGur5,%`\fq 1 {fn5cen6ʪK @ƻY,Wc+A&3bdfNQ`d9K0 ɵ4^n)aOXT lB}zgF{}C,sA` 'J#fner]/`iн<(Iv]p(W7ztU| q*6˩dW +T2W#5ƪG-3:5ђIfX:f,_mdґfHrA%i + ٟz(k&A^) 3*ݤ,' *`n**#|0`\䨅'"H2D=5!rD +f'z,!d*.uZn{(&ˀBKޱ}Lv6 `ҭd$MEхz+i \ȩP!O|deR+@!{#`^늽bzP0Eė7le{l$4)ܭ ƀ\U*v6Kak+)j73@YTP0'!lRoAzpx׿rݻÛw6)sSDMLi6듞eJw8 +endstream +endobj + +165 0 obj +<< + /Type /Page + /Resources << + /ProcSet [/PDF /Text /ImageC /ImageB] + /ColorSpace << + /c0 146 0 R + >> + /Font << + /f0 144 0 R + /f1 120 0 R + /f2 132 0 R + /f3 126 0 R + >> + >> + /MediaBox [0 0 595.2756 841.8898] + /StructParents 1 + /Parent 1 0 R + /Contents 166 0 R +>> +endobj + +166 0 obj +<< + /Length 3838 + /Filter /FlateDecode +>> +stream +xْ]7~ʼn7.kKBvB<+9nz%խoiVOHiW^B @C1`|CYOϔB+eig܇7O?~9Ikpk46ñB( jZ1CHm.Cah62/}[7xO ~ߏ R~ӂ"ϧOڭ&'@Fȡ7'I$иi8 D{`묧gpv02I{:nCgSuHK(Es;jS}V8!(y& V`kPIz>V1:H%! CSP}.x]zgv]Ah/;tIU~=1e*6ȔK5!%"]F!F>{F)-2~ZA +IFJCUgѝV%-xFa ԚXӌQr1zh4} "9 1B0oeṰ8XQ*tlb'2F yԐFWKCg#sA Nr#,W#u 2c3$+T7/`BmJRW"s5b:"K'hK i6YZSYflht)K |S3L)\1%`>,mfEj+6Cꮧ(_E#\AwZRoڔQz//}uw5 BJ)6nh?2%2VZY@ ULF- +su%Wk w` '>H.,faz;V6ںWGZJ*ARȳ\KA\x8&WyzJx/aEQێȩAQFdS> mq22aVyVITqp@ze#4r:o'xqvE>z R{qsYKAƉZ}XڜJ,}IZD܉Yi( *2+oZ["yLw/L nG& ~bJ2_74M+CδΎY9ד+Rݛcr@nqxd4.M*ZKDA4) ].K+b8C}23A轮B1ғ'Y0( mcՂ-[Zc~}?҉t/aVF H0Xe+({.+P#r{򖀼_ye|09ҲmH<陕ȹ'<%E͚o&`t؛4nmUauxNΈ7m]>r۫harx~CtKHLQ8::/MD\42 M1mqa)-gk@#qgK(I-#qa#c$;W*a ո2p`IYo$, gUQ7?޾}^8U';k>Q+9~Ǖ^? ›'9c&m}e4K/:[ϠtN^g!% DA']:-fo T NET<zU.qUdŬdC(kFʼHKK-7f"DJ˰˽Tǵ)9G- +{Jy=WdA)OHɝ@nr^5JISQFa(:Ą{t.wʋtY.O0yM[7#Pܦ˿Cr&nMfDž l2  ӣֿ]1rT+r%̹\|TѹDoӄ.` /Zy8œtvtlXEUZ%emDf挨zY!ߠNhB{hLSbv6jCuP_nq{pThS&Dj+ԅqcX}"%X +Ϻ8 Fi5 +c<\JC lEx<ۑU]`J4",УA]s2FGڐ9tlҢXӀ |UE)cQ]#E;aCvۢsro(We,wGSȂʅBGE؅);@4&6cn!QaY']Ԉ.TaVIg%nq{ ]6CU2Y8ΣgSJΠEt7o 6U%۫El "FU零S9yP;OրQ}*d4fUpOim֧x݆&1#]P5F8b &d-(PEaJ+LpBp^z(h/`][rQgߴ˛ۯYfT^&V +|p/!ii[qn+H(a1])xsS̡ȉC֓L)R=!)UXܪY AVuR3g0)i@~[Za(}RGƯʺv>jHVDžR2`YտJXsT5 !d(J"4`=<Wm V/࢙ cϋ5ºZ8gq>N"-l[p8-^HF(~jʹyˉ$n$YpD㿣"QaWa nS +ahsBp3~0j*Nu=f7d,~ t3J X_cA@LuQQm5+"_Gf5~̃T М^Ȇ]rd 왩ePh{L|$hE5m ɨDPf7/N{秢N:gIтRETSFL/Ws-WTt>- ~q̻(-ؕs*p. `PnPv.%1OE%jgV lnB׏] +NI0ZDX=${*$rɞF{[&Pީ* + FR..eunE,0:nYW.W0Q_$twLu9`x瞶lA?nf3`!O7:!g2TT;|Ʃ`]!9}N(B0 `>i 5׮)7Y(q>b_5B#vė!9*ׯ(+gϻ!!CMlzq&񬌳B^ʹhH AbOM^kFzM*+2!=a_3hgSE' W +dRZr w'.|yo:}wfۿ?~O׻n~xGӳ2J3]~#Գ +endstream +endobj + +167 0 obj +<< + /Length 1698 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace /DeviceGray + /BitsPerComponent 8 +>> +stream +x{LGgAVіRJ((ZBb'j)>VS15JQZÂM}WmP>JU*xݯvvfvwv~3qf?~7Q"OjKewo͞+,l1McecyT_}nWvܺ./֞4#!p /N'Y|(qX9,.*</Pbl \6c?6 +e/d\VCݾS{v2}щOd0H|CD ?7,Ŋh#?fZ +dI38k06HeX f*Ik_SenS֤I{?oӅhI@-a? j#U>/g#eOlq)Aue6ׯړ7ʌ7I̖C "75^$2VՑΔXPDEKޑ2~SePr~(p>Y?O8GE-1q]bNj¼畋;FM3RИz趌'#㖦利BC_H[uF|c_?4^)ʑRt)U+5a%J)u/IG%IR7P{b˦.DK'C+_)]?!Cq& ~7д_4}U=3;ƯH5E +ec,hXx2aCh-_CD?CEgGξD|3~" +E@h|m +=%AL@hs|N"$!ZpeSMMTdR=AfW^Ě(*dJc4pgörN\OWaݸnBَͽqZ +ȩ'@9mp{>%+!ۢSȸ͗Ɗ^.< 3g]'I [Dtk51bh٭> +stream +xupp̌L,ihܞbJI46 ٲha bġi#p;<3{}{F3WE-jQZԢE-jQZԢE-jQZԢE-jQZԢE-jQZԢE-߯}2>Ζwg:#**VkjkjZUI}~+~ )ʚd]C1Y[oH24eS-NVi%PJ_аظиRU]i_blX]3bnz+1čF +'G?E-a"YUjnN1Rݬd3miM2͌T}S1Z]Z]RUZ:Ztj.~2fpz!neJsk$x9N´ fFώq2\LCkPm@-jfmNcb[m- .ff% {[5LbMqF1QۘmJS%j뢵+5˴t+ƪu꺤#T5+ѣ) [k}X;o7%[p+Mu3\31X?F zˎ 3noc[--)vV-Jh[[1QYo]c.ZS׭T%F"ySrj)Q_\ud&Xj\nX[娋70-ǘc[ycdíX/7ύ%fы7΋gўeچX+;ȴ2-)T+#V6̶2LMM6fnf ַA )ں]Cnv>]v׮^1{WvK \rH6-l 6,3,fisҽbԄ4'KN b&x0EU80V*+W*+5Kt16̲0R- SK56e8gb l̸HdZaj60emcXM>F]ؼʈ=sW嗏OڪI268fayFVVUx0/|D;д;Z1cԵ+-926X#Lq@fVif瘙9%$8(SK-kJPF^ה^kԧ)K{6}p?< q7'if ޹QO7ߏ^noXV_̲^f`A\&v'9y9IyJ@ +pRE[2D)CQiTUѣիU{6lA|ScPib%X#E5:F"QB`N1 L鲋mvsoNn _˟}khK u)hc + >z;/1>P*3Kah^n$;;8(7'N+E%3YqL?k0GZNJI6kTQ#ˇ/Q)SƪRV蚲#͊(g + ƃZ /[89vnkdl|_HL]chd٨{66Sc)eE ^cBnbذ;=yLvg?>rS)2WXN!fMv.#αqVVGe>%zɳi`mMUbiԮ44ƪ꒕چњtm}rPj2j`r1UYZ]5(kbQNJ7/8hnff[ +2`N!< GxdXH-c6—)% g!#ieY7oΦWgkmH:4ݟݟ H !?sKNs$8~Sq ^ ʅxA "$ۡN[Dp)q9*rG+fXe~f!MYnȵejUƖ4M周(UUrTemzz9ubfb'G蛒ML'ؚj@|Ss!u .F[t.W'ފ-K7$a#騑LhI*6ߌD7g +9q\P?5/9/9/җ"s߸{@K&80@JX́XBC]c xiQꍮL(Aæ{,] +MuX}]c1Kגm45'jӵYHZu$Ju$JU=z`зK ٚպꥺѺm +K +kKn MlCK5SӜkI21S6-\;UQX}s%Cݘ35ӵ`McbȷQFY9V2?W[CSf&QYlhIuc%vv51- ms5КjlJqsBKvrTMS@mժY٧bR{2&f%A0CYJ9?n^ҟQjTH.a ݓIeSG unnbtN^bad2OHvB@vs,'/ 3țGAԔ'\1#U1cQ#7M7e3M >CSMi!#ǎD"eU.nH6ZRՕQچ,;7K3x8Y }+ВoN52RBS2|H]W{*b.&]Kq%ܛ̠hQ;>}7־5Q3+uI-A@( b/(?pNf +I!#4;Lu tSk $0@ r[an+C鼛Dzwк%؈hE(Uef6YטoL7@f6T]2T:R5T&۫b- F)FT,WDfv.R׬55'(?ƎEZ2\O5rmf-{ynVך2iRq[ҒK c/Ŧ_NȾ K'Jv7?Ooo`@3NQ a(v0dY2(EWc6\橍` -̶0͌dba9^QGN\H6+P'*ԁ^UF઺,u*]SSw3e%FFr@bB`2*I\)&RLKWi1I7~㖏}Z+6ڳcZV%a~vMOxB`OaaW +<\K +2_ W s]|WN d3o0۞3+im"dU@Zrt X=t&{:y"PG+c i*H gO^*W.mzç+o-#oTVX + #A4)4HP>qL2s>L]fd-\c[Yz6N_[זwuŘ7!R"'՗A[o}#(.IqiUGܮ'`rHw; +s ~)+;^ /F2WBbXHPr F:9>9٧Pj;9iڬp?963 -h} RQeTeTN5&icsBb?L7h9+E;(>* EPg~@NuC.cC + 8"/ŰPBiy8 -IW>Fڬ:nJ8kYP:;0b0W} nh52?3Ƈ1^|Dw0JSH7g(!v.It ^Ct7.< ^6Xρ2Z͊:w!:BLؔ2/%$zCYJF#ie5_ȧ>,ewN ֈZ/oJ in@P>.AKQ?y3'Jǻ +J@)n} ĻTrfe˜BZ7% v59cY5z=T9V5X9XKzuMT._C^b{DZ}^?sفP}3kVдCcr;'CۜkE;H+'% .)tpRBWApV.yM+dY+$\M>v1!bb$pO$" eaq/\/溏*7P/@+nK\o;KvJ^[M9u0X`cC2Wȑ^̧w:" +xwGP;:= zdy>9\"WJ@\8qTmIz!S[87V9R{(q*c.k*"CY9Pq _x%W~@ "j~$oTsԉQi- sɋ4 8O/lXnc&mX+o&{~9.;D0'?X3m" l4B^J"r$W/%fi1/4]o^,hzީ5{[gْߛ, TEeSoj`j1@;կ dHYI +t:> %yB@BH9/Xa\bB䧀h +xOtގsdF+* JHz0Gb+3z_6ͧ~.+vg8aЋdRbNN+QVM^Uj+t-6.ĺ"b" %.aGk-| ѴFڒ.:\i2/'f]IMEgPFA'm=E>/7l}7Ε~p +kFT3!΃[6><Бr¸=ޑ,?Jr*8.Adbp>)+󈱀S A?g2OG+V Z9VC)$^rϗ^>R$Ϣk_|w?0z>a`0:APMǂv ^G^]][?]??#(grGA5VP•}rzT C$_{q#,LtzOOm>u@w1 <=bCur`.-&<DyR F"{6㙴oQ#V:>uZWG;&e_ɇWcg),Q=O4"oG0"nGpSSgWi~Wr}kE@tICGp_!@IM)*&q4 \3!ܪĦ\OٓMF GAkuV{k>OoF׼KS/ӆ&G;E(@B41l+a]KaQ,5~_n^{ӥ.!88ࢽ2_Q9|G +OIs 'ݯf}!Cmd@[>zЊV}7z$MWPrCFBA3X# /U ^9^(cn]`|o{H#ըh:DH;dbd#2ڄ?u>%פ,YMKK%c3ih لi#=k褽2G{mM3|y=\y(k ab2KpNiSHH6BY NGJujɝa7"* ~;Ӯ߿.\!@v).H6P*t\ Czy-';p##.yQÀTۋ}uoV襆hs\=>Ş栔 3х(`_!FZ M " {$8H< blu )u! S|/ӻφ?ࣿ=pM8d/#ey1#N ͸,wuLc]izj>NWlm6fkRՕcIt+E}"a4nnZ({ԫNb ņh}oƞ4a'Lc =s֫ʎ nہw%v1)y$o;.wVVS)Hv14e_xmp0cwʛYa0DzK69# +>`CX~?G Ɇy'MKNdVa y$_gK<"h1t3 +]D0Aƶ,U+XՌ<@8|+_bN}{s`f7R3R5 :Գ`.%&EN1DhZvaKLEN1GY ; bmL_ ֬n>J8HOo͗sw'6'aߺISJ]kiJ3 XmM&E_elh QC?FGoqsIe?wւ=BKA4oluw:.񣇧#ڇ^PzxqIȩEKBqK.AoSr[vs<"M3eY.āycMzH#rf,IP16]γn#"CoPU3.L/d4+Hм<; B!?lߟ“7ܓɭУáቍa^CXpa~w`k#B[Dv R8y?wAμ 9J72t6l7 ֶ$'+ܘk 9Es?#NUwpcqCppg'gӎHLnWģh0/ay{1hh}.+pFey^%!x!$Y\ce`$':E8` -Bc|]LS3&.![E1C;PaP-klN43iƆmm6PL{!x=0$h #s؁L48s }.= vY +#EGh._n~xSr;%;x]0ggx+4@Nȉn)¸lB\2 + %9`S\"b@R]qK"Q!!E$;UPy0)v>͇Gn_V.A]|HQYC8xswvii·sm>Mg_Z= m,#}zx6.#Ί3S;ރ.߿Qfj3- SS5ؒlglSS6P`}5컇S䁹B5kkfK L.LNI\lpI;TyN;9קT U3oG@T5U=HSa6VLM+3YZ@Ϸe-W=6<-=.LόOAq҅)iI))SؾX_w{ZN/y{D='wԢ71"@AvD r0~cv>ŇEhH0^)" Gx8l-|SLvp^bl.4W˄rVijus|uN1|rGBs +iVpc?{*Ȃ QnY{!<Fw OPyxх\=}P`?a&̝4INe3N35gpioξ*rG3յ&-ܚni˴r6AN"}ʭ?;0܋# N?3 ;nx~x:5̥kK+wW~,Us^yhG2#jk>}퓐SrKNq662dbDp]5юt.)7.!-&GZ"Kt(b)#b"'Yh#cca<"T@ b=_h6!}׹LQnp-<_vFI֣H-?ނtaӯ. FW[y/!D'4{h\sݹ13 μT#M0UC.KSնu-p B"Y,;䣌,>e_i"W718ȵ7F^{ڎssУDu|wvrqssysGO{x=qG#Q~;,k愺= Qqpr`' @N (V6#2=/EoH@r.)8T$Q|< Rb}2WQ|qI.#%;A9`|GLr 6y֢zX؍_>|=?c'&>껱onO̞={F}82N'P7\@uOϠO_G]#ag=#(zc.ΠOM: Ia<S\.΃8SCyE*(㝅vG1ARn`bJ#/ 9X瓗xT;g`u ""GZۋIc` LO%F_o:G ?sy⛥ O/\9<]OO{1^^XX( ւcBOQ\e7OX#6|^|ڙ]8շp}] dl%hzD3el٘@E +b< 5z0/9 7^=3{g??{hjGc{ly"tA,F:s{'•{Ğ=?zgͅ g'n1Zϵ\+i}T +<;caalsJ; y]`mP4y@;-x¡x+< &9x {4%Td ԓX= а(_XqfYc /6,6, > &.熩3[AOV\;޵++Kg򍭐pCϗ%> }eIThVPV6،4@<$ @Z;#Mp^XGw &6#-KVRL$8ic, !wǏL;hʃ]qE"88, vНKp +(!Ƨ:d畓rO~9<|ݒB;j䩙*E}/aaCᩂ\q TxjBp͂d!y!6lF,Z7y-Iʂ}]kr|>րp}]_|e/# SmZIN!YXh acC,Mԑz䅯r{.cZo}7AԻWCNK'dAN s<&: xiszQ )Kj7=Ќ0btDe#8me", iPM36u~sbS^ +yEཫS_}֮ (BS,J2Mڃn7F,?!P=<0V~diH#i.9`'9Y(]EG%+c`|OBœG 3q|X|kB+%b]@qiN1#/yeEGZ +HY-Fl^BWs)?]¾?3!@ a/)-X1 2]KB'm un̩@ǚ/?ٱÇ\Ks^A0]=DӀҷtxeĤYmlleb]gm4U {w}98a}˾}]{/>ȏrX#70yk+V%}f[cF:HS'9DSt_Wis %;X,9d + е&IȰ@W>9#+tl|KDyv!%"[8E5ycW^ѽ2[{T@B)ʖG ?&[p؅p3zAmE9plGfcCǶM|̖;6MtUE&,5uTlibi#(] VۄHfb` K+FXw)) + ,Aжᇪ{^Қ+ +s'ƭr}DYPn9}}O㋓=QeF`Bos3g}>&Zq6>) Y8 |Pw!((|Ev! مP'T8~l#$d:`=2CoDt#+rKBOr^95Y(@G[ThN%d4_GKTgprk*ױL[s~s ~XpslCvx&nЉmSvjGGN< [11_6<jr[7># +,K2f2VI5MmT#llE9X('ge<]@\Eq /N5 F5Q8*уd_)ӎwNzB$T[m3'PM\;Vja>ah|fb͗b'imCdoBY$m!c+%y4[LL$ Q5V!z&q[/'syWg =8pv$\ Faq}/.~ufO + lCRdѝ"G70auu>9u<84"u;%>mha(ĭ(l}c<"c|C\j8yn %]㖯sK +@JHGNe.Q]Xh>y/{e%.I]Xlj[5ުuŗjOWtu|;]X>_P[bntmuo9D;><}c3YKTYyf*(r7ȷiy*9G|CwN9ݎOOzlǂvL~|Љ&N=>yϜyf fi][z(;ytK45cl\S@2fdfͼBli#XX+n1)zyN~C)uVaC\nh?ؼiH~T{'twwvadOOdD7l>;i M=#¸Xcb\MLJ 2 cfOO+ ӦI3(>Yd%& +Ǐmn](@*}G7 [Rod%4[8 !YHݢDy>qtm+w>YKLqA> xy,[vvhؘhIBr9W)!2`c6`0P9\" rPx\vg +.o3ҒJ%-i:;}>,h$xЀ@wׂF\R o=6cͺy977eܲ_prN/U|8l}[ a)Y0界%'ܗWw/ov$2FuЬκxOcg=\s8j!Yw k"Ƹ!Mk=Q5.i % nt>:1wy)'?BK;žI+VۧNZݤU?vt_=+S/}5|oE>:iC'D i#2mhw|FgNR.L .t<7cMq3t0N +hjLh  i#rkn\] I6iv=1{6jL0i*OBܐc!S}J[W_n|xE:d\JIСm#hƒ&JJX)y7+攃_T >A-9r2~^1()NEi>񵝬 {WM˙i-.n3|x'k;t lD7=>odcLOIq > 2E 䔑_I1-9C%ǚ9:oۼSVq7oYz@򞙗ͽ~~>k9q~L=gghf?Pua{a\ݐ! N̄O-{ʊ=*jHFtFHpp5 bDn0 Mm{vkh眔 2A RF"d|sRF,dBVZ[&"dCVRD$HLԌsq~!|zxY¼_ N,x% }~>dݢ_X ^Q9(+$T˻$#dwqlϹ첟USZT伡]i:҅w!F {'>VzZҀKhphPI-&'de$u0"*Lʈ{9xV'~'kg [&;nu~„c8Fƺ,k$Cf{skhܘ~H9+/ e?eK;JN -С=zT6I'4 F` &Y6&tu#'ߎ2 +^Aѯ=>s3Őr3vFtN:E/flR=\S.xxp]t3p*=WsY#ݢ7r@s~e/.z?w+qz=>`BZT΅':SzlDls 0ң:{GFN *,`zfBK.T)i$$LL SZbBAlՠG!n{ɚuCR_ zdi6iZQqMpׂaC'f%{'ߎȼ YRK^ʘs36| +V1q-*D5(x i]l6L2aSƄ&iH =Qs^_z5ae"$ &s}L7d] +>`BNFHY('}GZ +^v~~Ix7+}JE1y[snA#.9W /ya13 H:% XO UdDGÝhv*& ['wFNbZ<' AGc]ntl܄WSFczPɆ8&8t`ΆioJzhjG:D'!iFhwɺzAR_3j{|nZW5AƲ8`E#$ؤ~DMOƸb!ihL14`RzdʈMۘ~Ȣi[>b||:䅠"㖂.!<[qK +y֫{E?_;WwrQ!k' ԑ|RGI#= ucnOF;1Ę?܅Q5^-a0 +n`G5nT4fʋ15!%&LlJL#P~>Ƶؔ2z$dEZ3U/LPiS]RiژP{:"Us蜄6cnXY<ԧ!LĴӢ"ƨТzLDK 30S$2N/~xƛ>I˛mܟ7~}/LM}_u^^) {yY7sA b^e#ȸ!^ǥ*|)xc!y'I;E,B)zey2Ub`^fєQS@++' uF\BC'#]0I";AQV~HOi0q&ި<# Mq-!aDu#ظ ӒEDLh)#9k!pWh7:5bҖjj!`l隆{q-:ih놻:YCfTڈ,JDT0b0 &c`@AfB.xedq_oB2s 9@jKKk_#FjJĈ3'tHҔ6f$tӠZLDA% 3fL΂MCcֆM :%ĈF\TK 96cƀRI/yc!鑥Mo}!7CuV4/'_%h?=⥌T +NF/倠e=R_i+IE`<˹8ai+yGrK2nI%{rINgY//#\R@Tr^^9( +snN/ʸi0p~}_zEe8eaݿkX`oG͡596/o~kԯ~?g~E $SQ7씄ws~n{xc!i) *O NWfaeA0KJi+ϺY(f,"ȫʜ%SGOȼ} M ζIE/Q-9i`줉3pF~!Lj6hzh7y(Q=3g&t /i<tmⴕ6q==%i3zdaDu4,xI=BGUУ:tD;뢰c"jHRfÀVZ .z%x)A ~@)/"+_k? F'U}BOT`*\Uu?zTxww|9aN˲Ayޯ(Šj-[n%`nEҟ Nox]5lNi+4fn.l|!HZDI0dY9%SzVLYJ0Rf漲[ +X)#et73h Bk =)e' 2y\DGj?%&̌sAq ;0NV΀L، 14؜6"ڦ=҃kI5<hM^|ٗ}iNB _z6iD]qp^Hi %'8ZM𕶆;ΥK{T}K{96kH{d<|5kxSfӚrBޖ_BصM + ҲnHGŻŏY)9em A;2iG6nF >! 𠕜sQ3)n6v-:+ebn-:'3m!gDЌI01/Є˘q).u2S2.~"ۯԭӏ/A %Ub30ŝL6DOI;#eEU˝ 76xy6% խ-V[=uߩ?*X:nI+.B>X Ծ ޏj_9;0n…ҌCsI2^%tw2Niٜf]ʸ0zfTL t(6qƁtJE ng{Iw#>IÖvۊc[M+vw}]51kkFGtxB)x0^8CQ 0 > A.~LYHiZL6bA>cdxbħMx K^ηͧXĤys?G,'<0LOqI-6eVfnȮ\YZWU}TU}X\]=X%KVx<%-o H:㎶-U#/ͬ}Lv+RFzi EY s.i +91 n¹"̒O ZG Ms +R:xb6iҁs3;Q}Dh`mW{9KYIvƢb\ +Y`oyI/\'NsDoΈZ̸KRu' +YPa*"bcM/xZGVT;߫vaHͿ^d\p·=fkO8~B_(loy֣SߥtW63 0efA#K[kb*N[ey,f%[ :됃v d&v8 l Qʊo|X!ݻ涣^8A|U8ղW|oyQk\^tONu5sGTgdDO頃 p\)) 5egpk:h3+9dS>xu/ٹ/3%Ƽ? avn>xd ۊͣ=k{D>*r\eGKifʜWvIFM#96}ÅV3҆=h|QGݣeYX̪Wj{|N_O5қ ,/d%s \,? Olwo?&VQ^}owrN1`᦭ܬ"RNy#:Y S1Ck[q$iS@GQţ2KAVԆ5⾷=`Pԫ&12lkv Qyq;oe׎aS9'1-Yt*Ԩ +a:lRO$ȂȐq * 897/z1 ^փ^ Gaҋ/4MYOtĬWvU Ĭanz|rE˫~(6VJ ҁ|ъQE?}]}rϑP&^WKR%oeʻ,]xZLH̟Ь4d=]\ +مi+rrd`RqKւW +pDÞMXȊ%䐂攫t*Fu#\Ws#Hv]#m뫹.M)sV;]p,\Ҋ/u. ڈtÝ8xె͑ڸ5ԍ{6ҍ&@,䜃w2sfA񐙐@61!;3.n.bb?] v1#=KQ]\(A$وIrM9 +M,jE@4_}^ݲbLSYhqݣGKj++c'oone1*Y/|S)oOyǰoZP:{DZߞi886ՓAĵ.ݜ \+ҞelKyuH=O29r +A +NA)ʸ$EtJ@4d,yiy/*N~uSʹc߲w-8{| ֫"ig]Awaf_20;Y#?ߍ~T%pX}B;gdHWɦ'P#]2"h Y9+%\ Y蠙4A#BbP٨y݌ /Soϴӻw?cޝs;GQƬu^xoة<WMǭq:"$VZ)mW?yRX"B=bW󪟿S /wΩ#%_ '3e[۠[6nKb%S)_%lQ'M$GqKnð~E+{cX@6l5K4{4S:q2oO4mw}jjH?cg =^M疕u]ϸC8IIIprQ#M[7bORY48A'5؄6@# L.hec)yhe&BI+p{+Y݌S ұ8`/ho=o3[&-ظaAy 026f+(_ɋ@//q薉{cRSQ*~Zx|n`ʡ|ޕ38gREkWר<@Aljʉ悿9',O,Sr$퐖a8w+KSGw)5ӃNwp{'ka]Va5:ce] +;A]/}]O܍x uhc'bB9>߉8DoB@Q +5&#c}sw_^x7D Ȭc= +3B@G촌sRJƘ9dc>FŅ}^Q+*xsъnzʻOJ-#ih +523^E1ܑu#)k@N^)V²O0ѿE0V-b]l˛'* NŪpy|rOuŸ" "!V{ꗫwnz@{1(dy)h-ܬS:$|,V𷎇I^q+ }wlpM$t|0jIm.7o' K]F53yw:yrz ꅃ{gbu kHe%eFFBGj)1543^p0AⱠϧA+dO~%䜌^tn^#J٠K:df]R@R NNM8yWmYoDX6c}Yk֯LOd,[^\ ++8jk?޷iIe-҆`*P+rle1Q?9<Z}h1u-s\lm@޼ ~I> .!2Avnz$iST=<V܂Q3*wW/4zY3㼝}'`rO+OG’{~m'㚉xY؃<\PO^>4駶O;0LA›ڛ=VTL̘aaC^Ņ|l"$Ouetxz¦ր<<# +n#y%Sys 0_)XU~ӯx|Py[ʃ멅ikTV +FZ!sXuʢJ+ 9҂~^ݶ8C!߻lV$V?t}gE\ޅ ?%$lܬ ZyEj.Yby#}%(W VQFNɆn ; 3C^!Fܠ3YxuMN]G{M[g,ۧ?[>Ԕ3`rB܌|^.I'Bʉ>7[9>RFÆ-~A{$@k֣{2+㰩Fs K>i/*{a^i9ZJY!RK>)wsq6Вr)RM0Lfl[+h^ḘOߩlM7ɀh@W rOEuKMy^s4zE/{* )!Ą`r3.N&AoXu"EmcZJ~:f]‚ç(Z{[b7p, 'zcyd,,۞ 4 oL7ǂ[v7l]r>á*Bqw}wTZhI}'j L~wme3M?}of]kUF(F$CA?禛:h#^4/.[6 uCW;]pU5{ysik/zXN+׊Oc\LMĬ٩\r'1?a0$,zDok)y,V +Q+$yhuRbXQ +J +XX:< ƃP{)R +CޖBe┼>S<<(U@.i*1_úOb?UT +]a+2ZelSqe)҂++l%}֞b-i^ {]t^bG=bǜg"zܼ_VODyx,(.dI(xq^hë;'? }^q=>% C{~m庝pɊ`]N-uXw];kY7Lsoѿ}S3aAxqm?\/ oe2$4hȂ LE7{qCqc.}cmގ_0$ʻX%8%EB#ZT]Z*^0,y? bP6ۖCEc[)>Va#eMp8rM'(iƫ.0۪Tn騮TT?_Z=_h}ͣ|mXԹ8UXv]4N:bcq N,6]9WX@yumcbyq[]…xC~=?^4 };uc%cE;tK"roql[溛9Գg_Ӿ}S;z ՂA沍y9(zFSA}S΄K1)#%Ńf,ΚYmǞs&oü[^xX'%։>y<삏;9[T *~~OíBpk-hZK ,ŒY4lsIwr|F}?|wd/׏p~NGl'!6All2*0dS(3kժ }OɊ}bW0{] ypVw\7hijG]snyw;.-;}TK3FϜ=iTϽ5]3pnݾe\8ҡ }SBtPzRRO.9}b,, BKe?Kĩb}q=KA+.BPt˃ťPK/)9 kZ򡶌=Šg"w՜AKFd^*EZa*BFEDH%B,V6(?~ +H&;GGXIE|ICl% 6"zƟ//ب%;`AOŠG:YI VfAtB6\ ++!+ ;wmێN-{Ӊ"vرțښy7\;⾷{s7;gSOosΣr~q¹(΅y+2`F@6a}1?wW:ѧ ^^Ń^mzAͺpY,yo~RByLQD k_;UmkԶ(s)m^/wo4+s.nI +V^ +=w[d߉_1] ;'_wiK^rlӮwϺw[f-Uͮ׏-r`B_sMS_69-S|[lwzjw]K{f6p~"oo,䌙 +Y9肝caSx{a׋kW1v`gv&/NZC{u.%MJO+z‹J-吢痃ax<,CB@Rm?2מn%e|`GKK[Qe<ҤIx5;(Sr vYppJiH7WHm^V ǝFSL%v"b|ĆݤqoM/(RPpAg!E;v/un|nK{k7\9Sӥ#~)Lo]|Fp'7N:TGSmNu}:)6w?owЦ{80bl|WcZ\F;YY;c"}җsK9<2v Y^ 큎vڿ_o|-\/-/g|?S< !~),0L1iN9$ tsB-XT +/8x#WE4 Rva1b渽9hkh$7Ղ ]q{wRtC+)QAi|uIT!n%0k'%?'agpX6]5ڿ~I/<ܦ)wοvy޸׽[^|>ٱa7,Oj]?T{OaY;4GSMp?o'>~osM;FNXteue/av*C9AAG\WZ 3 cW~U3ANʿ^mx=gm޶ Md",,y8o6\S}PKwU-EG؄7ie҄E:㍚壦渭5ao2 !JrK-6:Fˢa˚=xO; FEl#!6 ־7[δ9y?dQ-‰ڕe/x>x#Ϧ_:kpW㕭u> 5j\7Ti5SkVN3/nX:]dn 3KږL1n%74ߝ[75u?wSꋒdԒmj5J21i)I:}p 1g7bk+e@+|U $_O:\|%/X=GV4]R>|m`饹@;CNɨUz_MZdQs{ĨZ#Fe*#fQ(R ʈy]mX`җ_n%! Vްकr>N+9E +6iwVaE ?˼fi5lNnZ>ݴz}]}sLbZ6G6[6]%ӱsm#:1;=k'n\裸~}JvCKf/<3ܯM ڦ?waǜ]zGzK9,jߣ="-W ާ3dH%²,4C2D.%N9gJ*zu9?g/kyg;|l_ؙa7dlC >0G<ҐG (Ny"6aW o]dh8Ak\LFpD/3GuQdR/KM5i|JS;,4UhKy_O|vӫ|Ai1|a'`㎪S*s-&v3Nw/oqu:l<2W߃^z{ur* ++4 6T2m463-=Jf"=w͙Aܠ]bGghڥsK'őSȋ|03q?yS;yS?:'4=*6)ڄSeK +yK9=trK_75;cZA&2/rFuQZtшF:ahœF٨V2lWupyK,x +d0 YHQiaG(~#vXsdeoSvrn\s%jK"7m<<|6=w 'igzgz_x{sb+n q'waNC?Clɋz~6bKI\ǕW'V& q%qT3h͚{XZqЂf^kla=ऎ)Vxm_P]Ґ[{> 3x^=wB `$ߺ(%w1t$3+Ǎ]Mˏbkg`=زP&S_kwwAjxJHug>8Ə_Ď]PyhюQxi xUxa{~C.YɪwOb'׼stCkz+t>lgN{u HqeU> Łiy>^ߘquW[fb>.^{DA3wH ع(zRU +lM޵` O긣N8My^FrG- +& M#j]x Z .,upw5;u2@8-o;Ŝ$L0:D=#]ꭽs/ \׻N8n[f|_Gk>5fB虚[/נNJVDR =lE(:E4H}"7dW/lL0 `&E^ZapL' %言K䷠r6ѸQ䵈 8`rlD|.Ss51h M^8[6vrLةg˦.Tոh!ɯ h+-fgx>5&lj hЁ: a+cNfr|!#`k8Y8*@'XBt7379i +xϋ, YY~ ozMIx>g!QAwTӋ&!u$z^~m@E:~\آǷv]@{ ZTA2U3Z|PBOMĠ`k&z׏.񫫂H 鱐 [д}Љ '3DdA5uAdf4,smn[ُ[/\$9q Gv&nt{f,M@TqΙ2;eL|E5|VU +AjRS# +y:Q6卨9FF>ꕣ:gKΟvlvl¦X +b@  9[~M#Ba3ɯâktXE c6jϔ.Ե& h1SBFRm%@&0nVF6B:bH`DL{0ax$/$>26YƹU}Ǯؐ,hbiF6n6=(ܠ7ixuqw(ē&t2V*aF<ycوVxOpW~B ֟^EFwh)ŀh9~M͚gFfJ-䨝}>֣Oյu {AF\J͌C&ψ?!ԏ$A+KȆӺ?w 7@OM &t hq-gKmgLAt* 8AEQQ!ny)rF>шZ8%m7ފOZ*r@|yՓ7}3F̘1a#.'o׆)t~Jyip d$&J&ڔ8'- +eJE,d@^E7=.>$9>~U-y}``(?3bAQ<˾כ?~iĞ̼`KR{% =9hC +At,D!O d-q5Ψ^rW-5^Tf*net>8@B[03!l%C&r@ĠaݐS` )j#FL:YAa3P +3lĆ/h`or6HɈoW4EE`zP-req{mrxIכ31# +dqBj xd] >l vt?jcL$[Q]'M\/ހ쀙ⷀK2gu䀑31xSWS_!մ +q3SV]?C{p+Aإ{*C +- 9ЖQl)< +yCNQpW#Ƚ+f둎JYvk}"A.^P5&)!ç#4(#hh@0zK._֤) IVv.9x+!yjj7]n7$C.)d"Y}x`2$WNuzN<:gV,o*[ \-gB\(r[[?E킰q1'X+q@ ev θ1;`І&|Cw `?.dt$=`tB| w8j' م)nvRRZjcRpݲ#oI僞.o|7Zf.o 6 lhq9g*/;a,I1v\Fq`tf.@N{7֖6O}7ZA}<~Da:Mq-~|2rp}&vʁ4Sb#.1MM䀉 ;|W,ɚdQQ/?[/Z+JcdW&u{' ẏGKt#9]|f.Ο ~ م1 sY=/6`bͳuݞ?9x&#=/^AG71a A% 9ːYٰ &8%>dD ; ;$XժLTQQ28EP"-KQT-m[\1ZKx|{zxr㗡87V%,M=)$sHj> (y/:=51B&r +"NN#MG9y);tHn +Z9ب2ǘЃ!#h-Fp~VkUj.GQL\$JV6.k%K~%ܯj% /5>һmo\([%.O̧%Y8b&P//Kc6JJ ;YA!!:B`[pbB2f;xhD})-9]SB@nf7JI9mԬZ6Κkߎ?Ei.݊}`5E̲DĂ\LF\ 7[9]oz/pPa31lJCBNC\.DDq~=trvf@vF}I.<]]B)N&`yyeIqk{D%?t}u[~IH$ >umSfA&@]zPO*{w +gfYkr%iKk҈EKĂLfbʤxJ΢-3OV_cŮ}5;{r]͟_F_lwI EmkhS\xJ~iEopv}]éXܰ,I[B^T\VF+N/&e.hx<1=Wল{G_o$`$v <+0h:U8맀TYD,Ud+JSE`B$fI2c]2s] +c]*{^i|zmnr6z.N҃PNmg6}iO ٰX MWJs7$q7e˄ŕ˥U+u*̪bfz.޺geU[1ǻ/nʓ{|pg}'L3V V)IErLnzjqyڕmݤ'ſVVio8v=੝m|nŬV"guխp]9E=-Y@U{t+6Y?_en~ f64J]qsYf͚5k֬Yf}OWUqճ~V+t3']>'3@Ȍ'd!e̡fd/e?VXfYf͚5N` +endstream +endobj + +169 0 obj +<< + /Length 1131 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace /DeviceGray + /BitsPerComponent 8 +>> +stream +x坻OSaE $] HN DDRIGSMp$3" ,8`4|L"|综IbM"G]K{WpoW{Kj&bw]3X~[r3d;=+{ʀǙm.g.nۂL6]DL(D.&958{cZFl{˒K<"kҵpMA\ZkU1][>*UUVi;ngZYOUI 4avoɊr?@C>*ԫZRXRbgx՗6^F?z ͊R6*BEW FX(B(=`az͊*Ba2"'H~RK3*wgErGލE=Ey`a,c2 z2ō9"ܸP]9z_dKWϭW]o;{aH0ʯԇaVzq 3.}8^h Ԃ3zA~.P:6*j@FM^nsP<:N]+n +.8@Hñ^$<ȕ N_ׯ3͂Y@Jӑ^HOپGNy@ $HeZ$N:8-y&Io@)NtDZN̙ fZ,r1u+Pjڻ@MW/5Cf|L?_}|!߳+)}}ľd_op,ߟde?_`?I`8_e?f?ߧ`/yqiMau)=Q,eF?4|@MZOֵ?+'&s:_>>߂>D*o(TO4>HBBG\|.QfﲨWVs|Z}1E5g޾L|jM?5^|e|jI>b~%MJD18=7A~c{g׸g5qo"ˢ +endstream +endobj + +170 0 obj +<< + /Length 7261 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 147 0 R + /BitsPerComponent 8 + /SMask 169 0 R +>> +stream +x XUeǹ,E2ICB1q˭QlL ۦ̔atR*MIMEs\r@KV44Fm?iː~={E{y½s~~s,S,2UTeʿL~'i}m\.5ӍrGLL1H6lXk\f[,s`x>_Y<e!ސ$\߈OzV"(P"eŲbYŲbYQ%n^ٝr؋;{]bYeXpX 7~V~5J=)+ oI)&ϲb̵EVw 4ۉ 7XõehA'UqNA|MmjNA; wA|'ҕȩCJLV +W]%n#A;4֝V.m^`Yw׆ Njv.uպӪ]#@޽ Z=[_/9,"#V)1c(P]`AsþnmJm;v {7?"Y[:zΊ/$ׅîpŲщ7hGKw׶ڭVkն?7:(XTǹޏ:H?4x_}7OcX3o懷 +ίvMǍډȮ vEV`%'u:l^{4YSmt.pi@ʯ)C/>W2^ W^ȸ1Ë-kʀK_%u;ۭͩ6>jp(tkΣw^({MxqlAv [7a3VS[a1t<ݱ>. H/JuuT&f9,g"8Ma99,g07h+Yv&uuTzQKtǘc9rZћ#h/'y5 ?B}VT7[,[-ۜd !o4:ڨIR~Iɸ1l=Ǝac^f/f6ƒx׌cY6$ƲW3R~IITFGC6gvNd hP}.RQA<^#﯑jX #EvN-}4Ų2Y&bFQ2)5e~33YfFŇ;9Xd`kӣAY;4NʔSFR^Mygɷ ZwZNhUn'[o +^z{ dUrчwׁJz>:`Vw.pP f秆khi<!E@viLݵ5c86~3Xfldx`'F2&2@] +:`6>h}gTi*pdP3|Q$vYƶirI=Ӯ6y6b$ y@\vd !!JZ=o/GAkɑ|g"n5Q{QǣIً#l06f+M.c6 F^oG98vgkle5kEG-*1y6+gmqs >ϞƆ=˞}={K\ZB%al|l8alS% G?%k# bntOӪibpPdl EqNwP4z=4{z(: Mg052Y:i3t{ɢ';xN͑(b 2ͷ2ܥg٪ɔmn{̉KɰL*K[K† aCfOz=S29T$_J9c\#kVn /k\J.me ;uXZ +KIa)L*KMciDL3Jci:>@uXtmxTq;M` +p)kpٶn+E|99fOAlp +K+kU +KY bbO d,5rrGѶ粈mMC/c 8'",례'ho׶VH 6h=ɞ|= @@ 6񫏷;.2Az/pK}j~|vAcd.kCOx=џ=֏? ;T3gXc8ӄGZ&x=W w5xdzca@GcU{=SWHm+kžwKay[)|T{/{AC졇5Dd>>I*J$YwZ755Me4T{\G +5&]MJfɽY$t??%e}kY$Ēz,9jRX$@1&[syTtV!(L\K}4a}jpʚ>OK;M ׉i!7/!dXÄj_u6iekutj8eLчis6Zkm櫊+t 뉕w0[q(t9ۦ޽J,J{I9(F{{]j6g۠u[c 01 ^ipy*1@΍;=۳{&% YsDA2;\\< Jh2jSEzݿ}ϯpF5\ADEbQЌZ3zN}7j% Xc;M?mz/w]wt?yw]0t/w7)9XύD<rEE;bGfoA{ӝ z\Y("#RƸ.8J^͎RbQ u9h{Pw_qGtnp)AcwX[RWscvrKIb t7t8!RB?ߟ!d?\.%t8ᆷop]G(+BKG/nc?t/+\d?tc۾Q/4\N-^aac +B]zwwO|Jw|wGF cr9u{7ߋIf*|J޲(tD}u'-~r뭟܊_TAQF9 +{ʛ*spFe5SWY_w[>%D4tǷ(U0xuWS5dU*ٺJ[bVш&50GM*Y0{шZ;ji|7ҺUY晕!{C"G610*Zdg2~ސM, +%X-3V"G6<ְ(xR 6oxaH88Cek\(oqoxaш*yE0~pNJ?M!mXiq4B+"MhB9"8T<P:o~f|WDSǹigǴ\\ƂraX0Y~C[_ɋaZYJ$sp6ϜEo:xMoww7^`wK2g3 %|(@Xu)y]$gw+ ͅ5JՒﶀ}uU) &R0`JXkYkZl +Z:7ύJ>: #H㋵$r|;BC J>"9 Εw5vƝXllx>Vɻ"]6mPEhJ6iyl`C7$do}"Z :4Y$\WVRJ#(#zo6ߪ=n^פ +Y|o`}PY9b=_2<듷@̝w除tJ,!κb}a<؅|PNa"/,o{amtnBOi|xKg<@pA-0wa%8/_H fo +*KɧT7Ba!*Zɧ\V@j؟CfY, !ZG^*蟤jwXE)(yVVJ|龲8Lӕ %蒔|Qd5S%jVC4BH+ wď ]:9^?%s4|Q\x+ ljgK, +h|Jo S7SJ>uRp~#CpW +R0]#+֊ H-VĚdlY#BpW仄#o*H(pJ@R"\8/%_zF9#D/+w%.ʔX1FXGJj{1vFK+";k~*)%HrdM9T +@uR}pX(WѨ/hTYQDK%RV} +.2bQ9ϒ:#,iP9GPHS"^%+DLi,?@(DcVL$b%k9ǁ$ob߁ȼYfmz'^J^EVu r K4raٜ׃ SVy)^ O4V0xCXrpyb5e{a=i"*MHp^D|¬.f%wmE9w nXG . =b}(NpgT|5hأB!J.ݱ,=p.l%Ý%"DO{\=bEY\NVhM΋ @=G)-UJ\9J48 brg%A p +RU63L׭#"se*>d@:ǪeGFUᢚɍja9K x/Kd+ W,Y1uUvr$[ B/eT_@%2|[K$/2U_2hwN-;dxc LeTAyʟ&S&w~Zk3RHn[s%55rι&&M ?"I@d5Wrl7dkeG#tS˸ e_#"X3NMu eB77\zE(I` 3VŷFk> +stream +x}PTU~`ɨ*dIV%L3NQ3JX#Ef&7)K1c9"Kie7v{߻~?{ϻQ赥s my m-Xn9A=3 4GN=WAkIAkY9IL Wۯ|#b~7`D_8nv06v5) THx]裶CcS˺փ09~!ZԶ7<9^emD,Wzr;4W[+vek_%(rf j#gFRD`^&@_WLN_Ek>߽@aeC{0jXۋ,ڠikUݾ´`Ji蕪OJ $td4R~ &.gracC<+ 8SZ$].bIIظs@%}J;72FH4G sط$6tm@;ꐔ3%8 ^|&dU! B%xԥ9_*;ċRkgD7;wȹ.<}4}>|ao&w6t]!◃2b TW0nz +0S 7Z9qcbi?(mG넲-K_w2!VH@qsfo)(>e\4YG-L1d;[&x^ .軼RHN[E># =wBw/*6Iwsv? Z82=gN{yYx-$NSi=Ďu$sӻ2lWO'#$ѝnbײF-j33tv 9/:o?'?@mu@DzK֪d.r+sbT0mwƯ- " +^GS9稩wus8N<'kiv_o7b~0逛~i|,Ǖ̏R;i%Uct_4=WJCR%TNIi׆FYvL3iV``V,gq)ws +1LF?bECM3X&u]?~zoY'f]Da,z_PDbE3]c HƦ!En=zG\WH +)FrUYumϣF xMcwUJ d?BPf%&bSB ;}Xi=HLiWmw9U]|l vW[Y#|-Q)Qa+%wrF +ܗWʊRǬƐZ]R:T%t֟ 5{{="gVEaz#BP?QP֍EWH%jCEj +endstream +endobj + +172 0 obj +<< + /Length 26238 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 147 0 R + /BitsPerComponent 8 + /SMask 171 0 R +>> +stream +xwTT*(R={-"k4MI4QkLE@ + e`az&(қgzs=sν}]c|1>c|1>c|1>c|1>c|1>c|q-hwܥ? U狞)(?X_ +ݲD<ه3ӷ̽%9k2xk`9v;k93{N"y:aq}p˶+ +ܘµLk` ]2nLK:9wHe{$3L("(q`\cAҳ*sdn5u,[&(o\'.5kW\[)GqpD{@S|UT_S{-"`-00.|Wdqfp2Ui읱IV(G)Q*r$GIciWd35R2@ #Mfd9'\YN,LL4U1 _NK#xb]9e;v)Oȸ z\cD[=}d 3kҲA&#d],,Lxc\]\]lꪘQI+#=ŗ\KH-Pp)=JI5vt5^Z.q1)vɫWF&. {<Иnܻ+*aoEޢ'Y Ǝ6-kjrCȺ$d$ܤUQI+W, ~Ԃ{tNj D]0o9 pIL$sBs\4dU +㖅, ^z7b/zs4;Y<|\cJ8r KqIf%\3]YN tձv+.Y$(l>3>;8qiD-(E$ZBQEz.Dͣеz.GҦ(l*N̘ə9;a̹s-cDT (cRcRVG$ +Yq/[\Zw /N|?l?7 S\u{+|^~um FUP/kѢ 3gRid@.$B$8LQCTLE ja@3BѴjT[ VH5)jiʩgd̜1{vܬ+~ڗrMp51:>"!,nAaK]^sN{R|~SO]~k99./tu5/"͞G!K7.~zZ[zK[)J%i)s +2 G* B$8@\ &0M Ss ji*d+)t=O.._xg}~v(Yr3xiHԪiYw5vkyyXcUa(^[OWԂ꙳I# G,&ɔ|%Ly/-!S JWUAT5LUC4%LS"\0O +b+J +T3gN=YXDu}$bc9Rnoז|,p{=žCc?.89> =}{-[tͽo^+Rru+E"$fUT,7^oG\\(ac\_H$H,% XQ4dX +1` QH]p! + z +&C75;t)VF#>3~l3o+&5-8^|qyAy{]tW.]V^ٸPM]6wkm]R'NM=y!{i9./]l;Xj`CE3[SpĚYy/rUvaqvv "V1MO~j[rJUȻ_*li32l1THrP> GȾc< E|DjZ2B(**OYH| C (Rj+S5SgHgΜ37~2yLV_gO$12T]UQXvouˡ1p闃tky[ דysΙKYŞ^w;!?5_=nk{#\o/uVĬzk:2auttpSqՎӲeFA +l _'r`%B- I޶" +Iig{S"Y Z|)C>J)BEl%3$͝3s?EI YB{#9/Եh9fOyi9𙷺}~ik"o3O]{ ]K+/]unY? +іgG&l}WY28JoU +[:sǦ8ĥ3 gig̭#1EXO'PGD(\G!#Ex0U`B&NMeRRIbS3xD$K5Z%}8`>0Uôw|)t .Mҧb͞`Rر<,IONiOhn +[stw?:9g̖`Ħs 1'R +M$0UDs +]$6E:ed֜so̜)>-="!12x1ƥW(P{ss<)9fNNwg_^ rמ{ѻWg^󕀵n=,- 8G,r}/ݸ}@>z/[}mٵ@74.!XmE&E'ǦǦ?LKGΔ3 bQ/[7sS S%HxRK (^/dDQYcƦ*uM<@snxX7`g+mγ}4l.!.1^a>]0sV-_b) q|O,@9@!sd-8s!-];t~ w~>* +&xkt1LRhBƧj+򨶲39?>{RD|BdrJ4W<z81@Z^߃'s=T m;}ՑׇU;[;nT^EG~W[goa_O;ws-\_x3^R/e]Wo< hUPتh6G'G'G%p~f0!91.&fkw!-Rfi!%h\#IxR.lg\r.̵ Y.Lk4?PGNM B NLQh"&|ն)xs>\"x,@:B+u@)Sأ@sQWnGo>3pX;~|Փ͏֗V:kJ\ |9mW zy/|'?g^~K|o,zkwVqoUDp#61,t$7xozUud +]j-D[#I>$3d"YKHGo>LL 0M2PF16U4{^]ByRO;ypb<]Sho}u+4vӷR={u>jyg`xNcH}`tSeӚG.b'i}!ox+xc@oK)~ +]U}V^w9\[v7_Z~=hō{+kBcWFGh{'`=}7yo;锩֘+LW%d&z!|A8I9@%Q46XՄWӱټQDU>cn!AMOS<Txk|䃉{="bT.{G54j>X~ׁkʽՏ-/aݶѯ^lzYQ(T9,$q[wRYͭͭN] W8qx8\tNjWy9v>r{ϵ~fϩʭeB,obO7DbԜdSj-p_"p.XCVh-#  uw74־mhlmэUɎ!D>t 9 \ 2]ݸ}$=ko2ӝ%pw˴Bw}\@m;8b#ãRgh[k}]ټn}59*7u-^Wʓ;ǹ Y=ۀ?)nhy9tֶ| +4]U8yxbb|%BP?`:ԞV{޳orVRϜr2E QUimiKM뫩}tC;0:<>k-45H\-B>=ؓpg݅\wmG{mkU6n9X~`S}-{[^7vyѷWs?Q+r9)59ekr\J7&ԍCِ(aᣪƖCTjDr  +qB,1Gős$-EjqDظHoo{Rrٖ-**2(2 d)B8xGbkR`b&0$%.>_9z FGGFGt#CgcY6X.Vl jOٻxV@ͳmmhc:~9_+䔺jNB#KꯉI #OF3sn̙SBRkPy | 3!:MAH9DHnhxOvt`-AޢŒ 沉2,AIx Td +pF SEQUQe +5乺5=!1/;z;27:4ucO`|=nO1KKqy-n?(׶|O}Ǟ wֵ}ke[{)q +G1G:v`h?fϩBL%XB.7WH4rlbգ'ܗrEѪbSZIU"$ +,'2@JO8Y` wljyGGGߎ  tM*uB_&1v򤠡+([^aU˾g{k[ַ{wx4: fXcsd;WYL+;6\M,*HRLQ"炧Lp+Db*A>a*v&f۩׮u#o:]_?|nu!8}TqM{ZֶmsmmGMխ۫ZU6Y^fcI5Mj֕׭+z,pLp{x/fkws=ЈlqMNj{40cfŴOh"+t!_!|4+"24;vJ}"#%*Dz +.xȀ(ļEb2Z{qP[Sx/ISj4aӦUU6~aKE嵛˪7U+_-qQ8KrJl}z+_ 3E%n + wkO@TgmLj~bmN˙9hl):g N7'*< )A[u1oա#bCj"&zr} #O))rYƉ&['MN[&NYو81 zY2 yEQzނNjX{3<;4F\`W%QSAҪ쨨+궔~]Z改 +yNO.Ҳnk6Gns/[YU/jǎ~'CSEQO~V24t<90@xI ^曯Qh\.X4X_ B6OҀ9Ialڙ7莎~Y2\\%L:%Mtes HGo流63"> , x5tB.ޞ6&!j {j-\qVe7ڒ/sJ?*۠-].Zw8N<9b[cJC\Cdh׃nnn[nM<ՍqHtk>2U/@_DQ_L.LjmEVx@V*LdF +"&Q9+7?r߄|9C;0lIHmby+\ʆ\ +-\j+J׈ҵr)LBҜ |7iD"N#S萖퐘 .Kǭt[F'V5hr ƚ؄Ap'0XicK4.G(@%RWy $Մ77݌MR!'\䱴VQ/w_p0;2TCw;CoT^I0MD49K%AA Q#!m㎡u|Uv(yrl#SvHf:ĥ9D'?Yf㮣-7xmDue}eSi,. OMPM߽ѱ-r1e,>A93OZ|>Z#7PI*YI$+d Ɍ_ VA '5FF\wtxP7<0:4280:8eeJ{'p!`d.DRL :w\o:҉A^P{dר K9gAe +}!&yux}p!7|_oc7$)Ơ|٠%F&4իJ0b4.OE"Q|P#(&|o%&*"N +d"" )Qw9~Dnp#Fu'2L&pdLB ]H~Sb)AQNT[.(vCm?t)")~ +2rH~갇CW=X}m\/]7|w_8v=?6YSYvƢZX1bRJKbɒd*GyKx_ 6,(XD1JI$\~J,2dF+-u:p!;vx@Pѡav`,<_ ۚ_tI! y>A+d9Fz?vPeVa JdH8 ,CdxC'=jIL ܚ|hxxPֽx;oPߛ}CouD 69ɶ #dQTT?y%E\!sW߱ ]}7lu;v7]^~*缷^uko'f6s +ƲXY+&Y(L'HP¥=;{Y9c3>U@9D{Qp~ߎh +8Ld%HȤ?>EzϾ=##z63gOL9Xb}ކ4a7ozjc2SPT!n5\=@]ۋFeBQ0TCT )]rKWV^_y+Wyy];xO_rn+ǯݹ.oy'[MTM(TCeg!_}8k]D+M+6}:)0@rY#Ȭlzҹ$Wey&I8 2E l++Ν^ݣ/ tne/ƛiP(Ty>0@uG_PNx-;?VU=8tg6~fO ާnލ˚_|7u‚?Be:Amd*@J\]:N,5@ +|&bH'M̞~|+lL0UWF -, WFFk}Wy߼)9HJ$XLE$X<dXH +G`&W t=_y勁~U2TYTv J~~$UFD]ۏʾz0̤_?qvC8Ͽ9z|ӯo;qjqW}oǾ-,fƦ*Cc +U~mSscjkq <$i .[!B KJ<@ Yd~]).NbĹ"+D+@+ \O j604.|Wz;.v\E%@iO6ʥVp$8}ߌOY@'NeĵFnhEP:]wΝ W|oF޽ݵ;&I/PĉƦj#ca6 +Uzty@\"Rc `sȤj,Lfad2I#I޹)MuNq%K+"B3.LaYDr"&2LbտR& d,եHr^ֿ8-5_ f[~ogȶg9 +9 zVڛ&#% +,DHL$2DHXPe Ip6Sۜo}jT +ywde)sEbp05Btz$T^ ēXB DE +R#\ $"Gd(H p MߗoYA]sH0(xn:_=olinI;?K!j"DMqf+C]ۺ;;^tu|]*̀|3iTz%Ƹd&j#LsrB"@' h蜑I Π*K<ԡ?n5Wd8|b;}} %W_OB17I@$ d>#A %d1.Plh(@ee|F]ESXp#bXGTaj,^>+bcSWW$9BYh`\lN b|R6m-ē$x@|<@#fO[WJP70? ˲1 fL2e}掦'uO4t6lNA N(2L`^92yk[WG;be  +֦X3)t= bP]~,ghF xF(T-9+G'"K ^%# >·Tfe8"')qD(œnGt )Q# +$2\48ex4;%G)$(I 9Dr Vl~Z[IM}esory"μi5O,g--[;ۻtG4Lfl3wRK ƀa" +U}[S%ZXUXmloy\L jq05 Zcʥڪ9qgPTzEƬF`ggh64dšP9y]| $G y +mt` jRb2I/d +e8@V!(p$imZw`ҟv * b ˳p-mVY6Y\6A,Kn /D7 J`ƪʺ O뚪K`!j D(%MT=xV^=y\ݙHK8 +-%Sh) +i3gwtJ52 XQ 5L=i2ڂ‚g[DShajLKВ(m:}*1(c)0e`44J60L26yף䉢O9ؿ¾ gpVBrL#tCC7sFׅPy6,r!-N/%(ú3}lxQbj&^$XeXq(RpAkjΞE[V5҆cXc8hK'eID(HN"*>kN]CeE#F̴,5@DF_ 8\$;+L 05B Ps +61鋯(8eeϓRj>{{ wJs) dhq0?[:ׇF #:]ombJ& +ś4Yoa[6X8 OL'$) ǘOXiuEnF 姧&]2p( y'pyƬ4F#dg1٬l6ɖIo/_ԫ0L PhTzԋ+WY% | #Q(9>*|Ok $5ѹh4baFGN(]32 NI8)+Ac%6X xrQ''N!GFm{^?:vedF,y6XZdap >G`R +B$ǙML)ji˶ƪꆦ暆ʪbVT+92|\ !y Q.bWKgffd,&3+ U*].`|b +vBG|՘#lCT&%GPq'>pӱ_?gAj38鄉/$h盄F2,AX VlZ cbj/  [%R՚lc,c6Q`iEc g` I\e 5yΆƪkcsmcKMcKmm}eug3f/}8C %ld ,N6W\5TwPTϖurDt*QQ@vM磵k0x[,{Y%Ta%FXȸoܿ|%|SR"MVR-J1AklҲS*?>G/xyX7!+1+{#$S$Kkֲy777jmhmjm|V՚l{}D` wL`^60/TwmF_}ôkT m%jbjhμo*Ο7{6S#bzB +%bo+<J*/V#Bˬ"+LH D5E @F4:yɷ/_vhCCK'ZZ[zjz>kjmjk}ea"Sm.뼥uЖ-L8ᛙ ꯞu>+KQ3`_7n72b&& | " " +w|_wTjp/6dVqJ H$W +w 98 h8ZcĖ`JlN9ԍ  R=e$GF{uC=ѷm=-3uh-bJOnQ [Fl'T@&EdYD2אJ2EPA$@R>zF]w}g}O>v4=ya5tֆlTՊXћH8=k['ð4 ',Y0`ÿ&s6nF܍H+1,88[J[, 'a˼<jKNTn_7H(9(DQLLLŖO37mO* z[ZkkkVWV;}gOU8Uq=:^/s]-׮lu7G}-V ݲlYvA>|!>NEEK~}ee;'zmV r>o~ +dhQ.pٝC* MFnnoilmki9\\Y~l'OWQ}r[nrc#Js^^?77R>_͓n ( O^Zl2g"bcU8f;8i±4hcUvDzKs'Di2l[Ma Dۋ1FI&.uSn*ꦢ.XcXfmZA!&憚X}uU͹sՕ+*ϟ9sTҙg*OV*;*ɺf'Ce(EݡM^їBcr?J 8;?/X6_Uyo5.9R6vC[{\]yn;IgjhiCmAE1n@(y^0Ge^~e˃/T=]Ry cVixܼzUlޟ4/|q㍟J?y+y,AK9ÿIJqvι +~oo?"EQ|z.PEd + ESr RζֆXs]=\qëV4xŖCk#zmSVG骕;RRV)* BA{zllϪq|=rːK\ϙ-i81A_XѦտY}} +ny1^g(^? quÈrυ0,&a#0D(")r:a"0ؙa!OJn媊pCUǎV.?dׇND +^QyHXwPLe*Z YRП5sz9VUyo_ݻEH0 Ȼ S!Tb aSc.}-3wAMkjXL#;_ s_<D#Hn t}O]tJC E_蝝jz( + H&pmFs1"3m HZ͗.-f,Y͒, `!kqeU ;uG;r۹()C%?|)BU'>3ukŚ"!5N,Űt}^k߸-e\[;4ۋ;ߙ7E8>#(.p.."B S 㢼PY> +!!<ʛs)[T$Pdjj⛍%k;Ptm%]\u_>e{Ⱦ6L|zD.=o}iؽl~`2qb-aZ bNeV0oߚ׸/<ً"xy( L^w}[%̸/-LvBMk˽7)Q0 l>E>,唜0$HyqʕI͑W =!2&.t9_qTũcǏǡo~;K JKnˣ7W"ȼ48-JʭT4jۆ#j$LK1|y^deox~Rt .e8~wgGMmo+E=e(D_ Gf,9 +pSf#0Af6L! X0') H~A7[RrD%[Vr_!J=Kѷ,Oijj=;w\ŹSO>}{t) .lpKiw'F_CqJBr´öi7){S !F0PFa .JYQ)#wo!,ݹww0tX[EbQcPnŎxu$,7bʜ|ُJd_9WR')hْE1;[,.n T]:_SϞ)kaZU=}0-ư n?M? SP.t8*EYqJ2yw“-E0͠#?5\ԡD=[Hy>n;{/`w`xɚpdh6@~ˣpemOwQGabCC.ŪA17V3(WTt>|8CV"ԡoPxo{mKaݾl!DƉp] ˹yg~;+R^*FwI`aC$g+z+߿#ʢBΎnan<}L xd/%ТA7D^YЯ>/r5%ݱgĈC:;s674`Q_4755qg˓%ͨS0ZͷZ-EZA{'Gb%pKq|-=wDKPoQjTl[ƥÕ2ee.2O~>]9co0۹ݸQ q'wPBa6 O +O׈M6 mjhj톏 }3UQ4"hRqR}hͷӇ3ӛǪ8b0;8'A: WPd&9bQ*`rN ЀA@3B YY؎S`d( Cw59m]ζ#>C-%(JܸMu-6wwU5L-T_z:W?T_&l|Kaz ěb%O=Yz ^ +ѡ FrвTpxe +|!+YCB9;\3>꽟NR)v|HMnilE mmloЌ^7G_V#G}:@rFKܖUA˵;-<%?̸HƼ<E9_n6U7iK^v۳b}beannff4[g⦥4ۆU-J{ pa]1R3 3?fcYD +x@PF9̋t;\6GՑgg9vˆ)_RS5$K% ^XE"sU.XaEKXC~)<9vǫV۫66+v_펗iiwL;7؜}C,Dx@IwQP@_4uaN3hRqrXaQ I|=:O% " AYa9~,LU߬ ɭo}Br4z_w^r8g83Nt.ϳLm˼n~AN(S,RI 9fDƠQS QܣseAv!4@8׏An\dd?CplpmoFpM$P_=ty{=Lu{!DRϒ$&əvr72I*@R~J9RE4Gy) +aύćS0;o`q! 8 #R=6Re\A7¶ ]Yo\C4,3}) EM$5SIigݹIgCH:r40a[kȈϢ؂C@ǝܪ$o,}Y%φ Yg`a0l&t[T=aU+J]43egSLOH $g{ݹjsfX! tˆi|7JÀcǭh`]XBhb> +!TsPs * ; Y͑~hHCImyO)5d^/x'.L44M?M&:\uVV5l˱9n2̰!N0܊ mdS8S@ D! [ PXBJPk0C80=[ۦzfcU_犹}A$uYR#9v}a&$NTdH#$LumOt5luhp,WsA-J3deWߋekǏI,7 Y8aR^њaR&@I$r8Sl7mw zW[L֏֍&uŶbnsٝiN6'Et7MmP[F7CmЫ=rYL1si%/ 'cvzY=zy>&{T dTwuMf0)zǓt:۝ڝo0;6Rml[cV[l,2cݵtJRdOѪ7TV.WrS;{YėMlMfdM^6eY6)cq4=Ɠd3󂇜!gA=jIMgDK4FQRњ>{_;=rALI,7e5RX6Y> +stream +xLUe˯@& h**"2"ڴZ6RٜDQ:!THkA THrRL Bޔzvgr/9l|9/c#s?=PiEEY^ kaɬ?kj/ ez[[L qVn \o,SaܩIUH`%tu\:}<"HyUBxDYyg[Pql߄5xsD$ 8%rvϦ筸)< x`\O-N4R!2h$0D}53}} j,,fu|_ og@}c|.Bs0},ׂ:/l?+<ƒ1y'}Vx?ys7Ec ,_-5% +kBԈ5GDךtL-8mD<2 i1|t(2DXL Gq,ITgwHm{ǜf2>uxG,ϸI5+u[*$)mML_l<6^%˳1Wcl5!<m[ xH  ie*clߜR p 1K6rθ)TY/v\R/$y|m5*{wA1_^b+|!W %<|O(wx^ 'qQ$x|jѬ[o3>@'$]4mi|A7zN@7| }eEUſF~YFh}F{}3y+u/46)i̱Ę`7jol:zΚҢho*&dT~J q%?0|5 1!gHfՄ`S۴"19h]QpL_rjǘxT79v2}7E Y^er;K.A9m~] *IsTPMʹi1w.TlU΅|waA1R'|$Z~#ݴv90tEz2[ MM 9Ylz_2 +endstream +endobj + +174 0 obj +<< + /Length 12056 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 147 0 R + /BitsPerComponent 8 + /SMask 173 0 R +>> +stream +x}gwTGc{ <ڞw &("B9K9uT'sN( !$ !ɀ]9[լgk׳wOVQ89xωg<ijGl 3?ǟ:k?M<?ؓ>ȣ?0o#>8cO9& a!U?Fww=7_u^Ѿei 4p~֍Go?7_0#>R>C~t\yI;uLmWMlU].T:Q2^:^:Q>Y9U=_eZk]غ Q{q-c2x/wU{[u3ת&ʆ/\,=s.{5k5\aOj^j~Ϲ¾%C壛Փ;֍G׾]Xe}wsʳ t jˆ7].=kŃ+/nWj|yeߗo} FW[̫wU+6/Y9 7skCSM:]ߗƁ^tW(,;uNi zJkwZ6vxs/Ѿϭu *'.uJ(қW}{y%ke#T7,kZu^?ڮwׁôz׸fff~Znr.p]s$H8?0YƱdb&<@FKSD םfXc:;/} ߃ +ayKˣI@Z ,zppqF~jȆjaa~;CpS̭|36wX9W>[/4_Lo ^Tv%@̡ Dv#]er?G%*`׫57Us7u܍ڙke#yݫ((dX!&+U 6 C|l(p/);W.TM^Q^W9`3Wf՝>#:E6?+3`lE&@:WK/L-8 Gv+%CΕDi?L 8k+gwv,kWr|VɭK=omgq +mKْ3 flg13M gP(;W.VNlUM^Kcec,%=D@#|>9v2 0s ;Q,,M֭g.R- +iS`]e* EP )JV(r2ژ',dEd]4jMڳH1Jo<̬ +h V|:uԉɈ/VV~<-g ,"a}Ş&ƙ9rZNs6)t Bl@j':j>lٛH2N'fOV42m<F[$f1y󒅐U@mZEd8x3鍧SL3Ʃ= +Tq +4R0i`8Nuq +NQ |f9Ir"7WUz:q.8P?7_?hJ4Ik H IB(({ >JRl&,'ŞNgԍґvfR>KI6!L2$$H KOpG~;HNMjtɦYԴYΐ&< LMկiBtS896k9$TXDz4N;lN9Ne9$)̴! Hqdd [p9Qf!?/ (/iIөxhj$V3hN5SEȫix(PVVl`m; +C#O4[Gi&N;٣V&OI?oשTH\ ˩b~R$Hl[BUˆh)0dՎG MD EՍ$ObYc``nϚPΌbbQ29Yrb;:v`c}S1= tN@gRLT^l]%;0qKlJIblodbd2R3Z+Oa6E)pYYf! jlJn,Dtpل''&:| +z*aAe!ܽ,8mʛodl[܃.[l[Li}L|5$!;}fhjFw1HNH.OAh\NMQy^ٳZ<^qrkrJɭ -gR3Ihz,rN%08ŎMID>1_2x$6#kuNslrv䕽፲͒эܮԆYh ׀ 0;&vb(ADA&<4'A%v|Ety&mhb˥cEC೅=+M9x/ NB`J~g" h# ɏ-$_'|%R,g ߋ#aN :Ia +Sh$)` gCd UH5$Rpltօ0umAx*0eoC.,bC fXD=ՐeHbw Aj$F3P?%3OR5SfA8'3T8#yDkWHjI~4 5_Quq/ӎXON +N#P'q!6ETPœZ4dzD`doՃ>l_''p{uȯxDF}qI eC? [K۪Dd5`ȉN4غCq=#]um5Ѫhhj$?#DGbD!zdL&3[~U ZբXZ,j4v(h}' > Yn +*鎬"~3I=Q2v$6\~ɬMDՍUZũ> /,bO+4~y-U4djuSG<*5FdIh:*( &Lr bI(O w$|q*ڡ7(f-~JrΑ U6;%h $ sPq牚AܫHᨺ(IiFlІydij4'&c!%h~֪#Ih1IiQu"4Z ~pigp?ypK?0W S|D ~D/ۋ,Fx@@a{)A[=l +)9Q=xxf0vZ +͇OOP`9N ?\1 +p{gtG +NE5? -Q6Ի$pO3{e5tW:rTrB,U&)~X#j ]uzt~kXEZ:OhT57U38<ijxjp)D%U!"4b z+#_D%I皬ɱvW.WL`Ӊ"GT +d*ٕ\蚤{]U)An (l 菨Fxu?  ?o>#64⯦ _B W UI789P%In.F1*tX )FDT ;rsIhflT(t(-eݾ9M.Iw[ɯ cֹ +*z9i@U`UU%y>$?<ƭ&Њvt8؋|Uee5tUGH{ä@rSP`?F(mbTF"}A&Szt6Y?5E,5H\ +^@%5OY!$a,Bx(0C4n-VRyTJlbjfuR Ph9ї 0YHh9BEoYP<"~p%6 ,8a9S[DT|^ɱtV0BRC'=`~4չޠ. O5~|RYDkX^ | 邯ShXX 9VxP?99QXu+H*DWwtT hDA% fE"E!a٨MȘXlrI9À?wÀ> -sM)[;RDDu l q[R}u:cOR-Njq;]A0DvwaP1p;1eB](BDܼTgO}ߜr? }-Nj:pytRX_Nj;@4gw~&}s +۱p-G Zu/BC)"98'jsmK3()xdmKQlvK,}Y{﬏ٍHŽ$A@!ӥxa;] bq ddH2)r~9yf: @{﬏>.!3I) >*~GQU+tg~NTQZ@i]І?S8X m:F棠vŇy-?[mW +(l/hG lU>S`EQp'bfXZ:"OO@NN4'-ED|Q~ CV@>Mqh~)\cy^Y }'*{#ԸGPq[؟|4lynS60;ūC|S} 5YG⇵GC !'eJ=G(LUG8p0%IeU6cnFfpZD4e `s(|r< N Cqu5kfX|rvHJ l XU6{g7U58%]tG3>9V?J&b +CG~&nFNP;qMc}_9йM>Jv2_fl+O }]U$R9Y}r|x|s>Vߜ&_!eaI=ҍ:&=ҍ^Y Tb0!s&3ssٍG&z&<ҍG&FNMw']Mt;H5 >wh#fpH=8PFNv7̏<^V/@t|rY G&؁Lwva@FΖ^ls7ze;?G3G=/5F" J vCTCC $؉2g^ G3, Uu+hC[Yvha&im:Vvmt q6R?RW +:x8i!CXqlPRv- ol3{92Rl̴!`6VVb pILWvڱlf9~QT,.w.8P|@ + 4E3#C1ƒlpf4l3Pr̭ͤ~ܦfC C+x8sAMsʱ2T?/kT,~wrr|HunLhd + b8"9U6 $-OnU.ݩY{ZOffY݅ sFf*zs_H3L hNP +Nt! +) m +K^*_]wSgt/uW^趾V_zZzpjZ Q;NK75MGґ4vRR/f5wD{VN]>w_}vk(Ձ]x;õWk zI™d`ywŒ^"Z/ So1)!N̆p#+*{cәkų׫\zB+9 p[ݕu+?ֵU?X2{듸5a"lhۗXMQI*{ 5UFx_RXmLY)Rjn7 +C?o` 7.>XԵ MsaFwҌ;(:_3%QL, dLK WS뀒phb|Ţw.>^~im=f}~30\xߛc5 ׿_{RsygnL]^OZoЎ/FO jxg +BRD.p3e;!` +KLO~s`yO 2ֽ3Q8}lv}׾1@ AZ͡!Fo4\ xWڭUOk?\[phrb+kbzJb|dXn߂Vl+Zn?#72YwL?0+&ܨZZfVT$?]pz ++/[_7+]|x|fAܱK)ɐoe3d-m6YHѻ`s\Sh'E3:~ZJᔃ#!4P|J^WNV?>88x[_Z;cJ\R_.] 7%xmG㷉廵ծ?9일+齫߂#T/V`j+KϼȶD;&6򁨽½#I嚪w){ìJ.y8HAḺL#tA7L_a[H@lLz߹튳wj/<[ +([bnݒ#-acVt#ԟDeZp"x +ź'h7&ti{E\щT" W䚢wO7zf7_ZmUzʕ{(Jo-~Y4EzB\p̀O^„7蒬CLpENlc{$rYPYdUٌ +C"Yf5Z)$Ɣz75n(e>gR~!O_->Eʓ[aat_ƍ%⑝$|Qژ* \da,%Y$C +C)yp\ɶLW . rW}[g'J*]]4wgD #f&2s9&!{B$k2`y;$D1~KHٿ341p>Zu䕟Cs7.t-k|[ӌJ g8'i~Id|+Lv(4vX2e٨P~/8%-[Jj_ȝ5[غR;蚢oJQZDbad(xDIY.48N|(|ٺ2?Q'گl_|ѦDM#d@?e9^kUe ^H])H7?wNv鷳٘L/uw\TZ̃Kh#YWZ)lMK eB! +S@YWy:k9g5k͐ `c~uځw~mdF1}rЈf x9PmNl_Lj_x$/$uo>R7cuI;%hm+ 5Px( DCK[Z: +S[NH6VL +&ev NQq1l4V+V ht|||XlB|\\f;EE?{fE1xi셝d(rH3[f c\BmBy-xbs9Iٍ5іXlLmi8-jwKNq7"Nl%e7&îZ+tI{5ӻ xq2B?_0Al`FcEՂ[= syY`Vtw'S۩x!)HS-p#\;i 4ڱޣٍΉdGx5 ~4p<=8 +Sq-4ŕ&A4KH @i$FʐCHjs!.M1!*ℬ oԆonjD͑Lphf4D53k[\R-lkbdSB4?"aa"IS6vI{5VUc%e~ +ZNT=9S_7TV{~I&YZQ]RsCj,SD 'hҍ~E+{{vك;ŷh9YǡTqj0*\^@ NBőfJ6 giWO򈷌OiD5OF7AmkMY i#. d*V3)Q{$ѯӯç<2-Gs=smG* cuZ|A8zBP1 NH*1zȔH *Z'?May '*RFUi/eO~gn=)LG<,7u +/s@e#cȴxX=2-f9Mn&, ɫ9:k;}$4Å[ΊNl qu88!!p;[+,Nm$(U"X>׃t;;vM3ApI5=2.Cj:jD[Ml| ![ (YFѵpH;HBQ^ %Zuk pZ-[7 +'j kEt虳G$IFnָ\G%?U+?4EO$v4) flǎxF[Qyt}#+EV!TP8M>I$3Oh$3h/-"6ۈdȆٱ]`lcl*BG)yf;ӁkxSP!f `?-2m_NU|ϣ~sww#K=3p;#@ +endstream +endobj + +175 0 obj +<< + /Length 1583 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace /DeviceGray + /BitsPerComponent 8 +>> +stream +xiPUeǟ+ek0f@Sii娙褕鄀&dX8 +)$KD"K.rQ\!ra9~o9ݞtӍ8նQ1̀$vGz,uPϡ6=v:h;~zXǢ@^+_zځz7=zƠ^D6+@aW6aʧ=zlB7Pԫ|zՁ@uww&d-վ  A=l ȪVNn.󇜞fdY װN Ȓv&Ni1da# ׼kY̭ZV㤻Tz_AfE ը + BM +_%mx<́eazz=^+EgFo@ +1⬁c +Q[wPCEsP/1*~z F@P/~R\G@PGTpzKA@dԻ8|. z8%ޕ@wm1r=GGXK@9V4(Gn#h&ZdA+}(Gn#he@9F.dfcP^ߜ Crz֎rSW{ovy,s6+/ '%vU8&lڨ Szl|h`,ݐhe:0/R#ۚN"Er3XSZ.6 IsIcByY6Gi`ry&5mwMM,v/x~0Q@4N?iܡ86c|qb-e)'D塨}¿9b~l.K]%XOb1sGE3\d@ Yb.J`3 -3;$tQ%cyMh]_TOא]Uׯtzl_ '/ǥA<[-olJCFj/ dw~̓ȝ#mSY:TXꚎ?h[3?dמ ӯ[F)ϠZcv!t;S@w@+s`"n8nmaod'bO#YʭM7 a8s +endstream +endobj + +176 0 obj +<< + /Length 14984 + /Type /XObject + /Subtype /Image + /Filter /FlateDecode + /Width 160 + /Height 160 + /ColorSpace 147 0 R + /BitsPerComponent 8 + /SMask 175 0 R +>> +stream +xw[WwϺk)&v - &K$ɲ,Leff)N q3۴i ;NǍ.-9+>ϑ.եT0C(gk!!XvE|r[ȭPV,rx֦zgd-~M9~E^l,k*Ӊq2'kn^ i {oP>%1 P2,m9=\.$- +;se +jJRޢn$[Jwd#͸K!:T*4uEO*qPM +뮅uyh`7{{U9*ߋt$z! Al_} Z^6V1V^T_f~*`scܵ,|//U .]~ BY`=[ U H?ĵ`A}&Xoq~+򽨾p C\E8W, +}=t-y5*ߋpyJ]x( +U:V׼ ?;P^DsܤhgfP}D`}U^4_'MM8Jj\ X`}H7::k4J\9j }H5et2 ^L.lRz' M8Y$ٰ zl S7P9^FodT/&S,0[X p 6=_UYMrp[Dx1tlռԀU^@_3$CX}Te^opՔ*: 2$)Ž Ɩ 1 xP^V^P_B\x *'WyR^DߟpdxhR 5R2T^Ls\wa D*q' Tu.TxXȪ|/oM ^&G ٲA9[*_˷ ԍ}c5ڂ0z `Y=W{a|c4.Z7%ƕ֧qumoxϲ*w_dx]`Y e,*w_ pPxƾT{!}č@,,$p}v- |v|6x1pqT;jG&W;|rU7I`zW{|c4Z@L$єXidzd`|/,p)ғkLg@ !7@fW_RR^4hG72 NGz\=0 :D5V^<(7R$gB3 DOPۛ^W@^&T7f" X~B Izav7qU7XP 9.G6FKKho[5 =vUW1OGdb9.ĀL 8|/oh8Y:; x mzHtS*'f\Ce5[3|aH;=l@{+'Wz]}}5"54>iH `r-^䒼"eyTH,Zd~˲eYp`nK,{Eؽ bF*#"@76 ^0+S=\"4 €q ]WyZ6TT^&yXgiH#v 4|>&HL,dңyӓOЍP; ½EBxU|&9[K>[O9]K~x#h5n)N:QJIt̴V[SUѓ g[O$K$ 6򺗱J=xp'xU|zOr~_x@@~9/voK?mkU,b Oښd.E()؄`D 4I?տaP[۳G.ď7_|w:V:{}4#_e}()\jR}:Bja3q'f BuOo~W;4zI3]`r$g?~o)fmqzڋe~w,Gߟ:Q:U|w0CٷGeOR',҈&R/a8V/$pV"޷4f3҈l'c-'OwW%3][9/vsN量y'E;X,GO;Q| зǹ_d˺7P=NᚘZXC&ݙ4gƘ`~C|wMfPWI@ f=XLX-ӞlnM orޗ$} <+Wi0˯O?}X>qkA-F/MnH!<-(o⋰E['AsP nsO{2.$>=|$ϊ;Q<nӼ_# >q ~|RӢ|wr+PO2iy)|}X30_fԣq8+ΊnD +'W'4Tg"Lf<3>iAsĩf\OiByV;#~>Y=H@k)//dgk)_dwxy 8,Dž?(q_):i񫓼rHPb(H魈k3bt.)jdCNh- 0=ZJ\blNr_d=:ZI~y a_|0#G/eN?>)\v|JzZr_4ձbH5n`}p~:}"_-9Ԭ,ښU3?@!i\Jqk vEEV̶G =C| zv)_ȞmIRkd0iޟl^r10o^x\ݱ^L0Q#߇BD]Z־*+6#.'d2JZj\I,,JwMcF0s[GwiǫIwI/k)ǫOKne>Ӣ9{c`#V.p'u'ߝ(S;pSm_ۗ'jd \4]ӣ1'x7nm^Xj+[e!mVۼSV4os5{$VA} +ՉNC|lp%cҷi1(m}<~}>2`]MV@Oet,6<a[PUߘuƱ QZfD W"f5[Adcw"b;^ߟ{GO2Q9qQ ?8Jwx6Ɯ!Nwnw߇~%43Ʌ̀Tf|>#Zru#5ȍ o$Ӧ_Ts"Ҳ8|=F\- 'M}XHt.KG?_"N4{㶦;[[HmIORog'C90[gs‡snR_52l;a Cڜdw5 V\iB[ -vϱg+/6Ke<ɆnBz-^8̀ȵ!^R_ ݔ* -ZE;XMj?Fϫ9'Vi`9|7[d, Пl~@u[(j7{}>ߜQzyX}nH,=]_P5̢͈Z &XNRUED&VE μ\{Mt&f>D7{0ӆinOLҏ_O<[?Z.N/S_, Sla!c;T1݀\۹]evpo +,KŐa8Ğz9!im^tk4l5$wmtw!a~;ILw[ +"rCQ&Lqf\O d#LyN2#5ʄiL+Uzne% +Bkc1kNBv6V_& O Nps~l3p3ٞ~X8P>^Bn#gIWixDJbSR%:Bܐ jbNm(:\J. /ōfɽܰw}z1^Cݮ d #a e(2sygM:CP.L* oC-tb*F`wz i"{6d7:Z}%y\7{g[yn!G4d4f.uNwyUH5,rB==4vC1Vܭ +xor`;7L\ܪLU#jd!UUفO7ѾɱG1G4NJ8W&s}~\$[JCgU ⰉzL r=AٙmRg⏗xEON96 Eޣ{GNf[K?:ݪD0-n+z@q@ʉ$~N |V[/O5ak0%Nbw9Sk gBKޣͦY2lHh_(/E&>dPv5eB2N)^=cUQЮVYpuD=|:yc҇ߞ;Z`?zOxr9Bݛe=H*x^8L=*ip582# <ͿNR* ,M+yzW29_E@KIgt4eT&\:);/IwJU&]DwW+}Y +h>p`7~~?Ɇl5ì ӦLvYpE|a4TItc\*eUB{ nEQgeڴ|omF`wQd6׫6+8_)I-M(L'_iG8SLt(W%yfzwS&x<)7P.nBƪ# +oŌVGN5Q {g؃X3g&<'[KEZGHM]a;q^r[ˢ7%pzե*WDrD2W& Dz @B4` 4l]sʠr`&ۺP %͌wH[K}2s}&D ) m̄VG,u"ڐ-{}۴^`ER7d5F>]-rx/%gw{ Ԏ>Jf ETVnz)OuRܐ.`oUt7Fe"!-#))).Dz7M=.LW5͠XIV< ;Dr,Kpmzէz%lX3%(c:RGDJ1(jBr̊wPp n2soEG.ǵ$x60(6X=JjN5oǯ:0;Ӵad;!psy|{p}(x)ɏ_,Y>٧-8b6ӎ[#gY> f]ߒԜ4\)uco|J 6yh;.*oorn\1Pm$D& 8Y4[” 3ɦq +0;s +.ḱK}$$B_Qhm:t.zg"n 5?BZoRα6G)wz S9xۖ W?X_oJfwT,t; sѶ +jEn|B 5e -9H .]_׵lu0XS$xs1֌֕Y+X\4mͮ5; c8TIϣ=5PWҋ['1ͷa]Ѹ9p{"X/p8[SSn7:Lk5"PԷM|;Kʁۓ.$ 6Y +G:5Fv73 {ۻ!H_㫁DA5]_!Hɱh$EV58sbuJ\S ӵ9!uѲptK<рF>/a6H}[ +zKP2v7H&,UB]rSJs +3+H_m$T<ԥ颠H}z>O[7a̘17D8ɪto%ڗ=jS}sMѝ%!u3Ͱ΂b'z5Ox0A=c.tV-p8OEY,{mp3E&]վTqJWK E5lCFZ^D6Nɴ?ru3S^7#_  nnL +փثp#%g6,dS.=Ze5ui>a5Q}VE\;r 5\v+v 1L$:ׄH@-oi`2R%#<ԘݐU pkJWOa`yTlw8\Y +mE϶[3!R~:z<@ޝa- ܕ[ԕA$s9܈3\"?"ӣQuQ vVGAn;}yM3cu6\JnLL򨖸gӨ%bϞ|21=ׯ8h6rg0^/- ۝$OE7v(K]Nj@yd_Y\c?RP{'3*hz՜" "La&] g1'7Y=teVAl +L0ϢXuY1\Y>ϩLg+Y9.-Yk]:S?Pp7Ye@c"#v( 1Qwzp}%MṼIb78lu9J݆[.G# :xs^H,L +aFSBMhᦪ]P+g^@ 0AWXh(pJA +Ѳ(!0`TLCȽ%ґُ]u+Nݿo z0FlnB+6F)V(u>BjAђR[WaJ6zw}=??/Ͻ>h5 XFa&:oAc,*ݒI6LVt=f>\vҝWQUa)> aB҈[uRoR7,Y9F7GD#5?*ïB[r(sf{\Yh`|.{Z|#MXp69 琈Hէ2gs9.BT}DMԁҝ: +#nrXrW .#C"§[PaR߲THY*KR!EIޅb"UݻX~de?AjW# ftߐ*!XJ.T$.9$J 5b"{KChE !< +mEf@7161&hoWک#u\9\ɦXm2(ֹ TM.˩5ӻ4 VzMք2νEAr+g3X>3Yٔ_gDsP_A- +zsZN:=j[sJ -\ᲠRZ +K}G>Q6Kę',T+}ct%8N!>@a`92Q-HY q֝rh__o_!UvKqK&ZbY/f ML[!, cSLD=\Hmg2Ѻ2Eΰ̈́XUx/aEshcqMkW{w'lF9',DhDʗ0ͦZKb-26ǩ5ԚU"tN@rr鶉X$7jC2e;fxV&aBqF5LDhSULo:92f{ۖ *9QcM3hCN7Z?ջKu.եTmv +endstream +endobj + +177 0 obj +<< + /Creator (Typst 0.14.2) + /ModDate (D:20260608153157+03'00) + /CreationDate (D:20260608153157+03'00) +>> +endobj + +178 0 obj +<< + /Length 999 + /Type /Metadata + /Subtype /XML +>> +stream +Typst 0.14.2en-US2026-06-08T15:31:57+03:002026-06-08T15:31:57+03:002application/pdfx0ieM9WiuhZBBsN6idseuQ==x0ieM9WiuhZBBsN6idseuQ==proof1.7 +endstream +endobj + +179 0 obj +<< + /Type /Catalog + /Pages 1 0 R + /Metadata 178 0 R + /PageLabels 11 0 R + /Lang (en-US) + /StructTreeRoot 12 0 R + /MarkInfo << + /Marked true + /Suspects false + >> + /ViewerPreferences << + /Direction /L2R + >> + /Outlines 2 0 R +>> +endobj + +xref +0 180 +0000000000 65535 f +0000000016 00000 n +0000000090 00000 n +0000000170 00000 n +0000000434 00000 n +0000000584 00000 n +0000000690 00000 n +0000000823 00000 n +0000001077 00000 n +0000001206 00000 n +0000001318 00000 n +0000001425 00000 n +0000001478 00000 n +0000001798 00000 n +0000002340 00000 n +0000002842 00000 n +0000003087 00000 n +0000003214 00000 n +0000003306 00000 n +0000003401 00000 n +0000003493 00000 n +0000003585 00000 n +0000003780 00000 n +0000003875 00000 n +0000003967 00000 n +0000004059 00000 n +0000004151 00000 n +0000004243 00000 n +0000004335 00000 n +0000004427 00000 n +0000004519 00000 n +0000004611 00000 n +0000004712 00000 n +0000004803 00000 n +0000004895 00000 n +0000005017 00000 n +0000005103 00000 n +0000005247 00000 n +0000005340 00000 n +0000005453 00000 n +0000005613 00000 n +0000005698 00000 n +0000005796 00000 n +0000005888 00000 n +0000005977 00000 n +0000006062 00000 n +0000006160 00000 n +0000006252 00000 n +0000006341 00000 n +0000006426 00000 n +0000006524 00000 n +0000006616 00000 n +0000006705 00000 n +0000006790 00000 n +0000006888 00000 n +0000006980 00000 n +0000007069 00000 n +0000007154 00000 n +0000007252 00000 n +0000007343 00000 n +0000007431 00000 n +0000007561 00000 n +0000007667 00000 n +0000007758 00000 n +0000007851 00000 n +0000007961 00000 n +0000008049 00000 n +0000008144 00000 n +0000008254 00000 n +0000008346 00000 n +0000008441 00000 n +0000008551 00000 n +0000008643 00000 n +0000008738 00000 n +0000008848 00000 n +0000008936 00000 n +0000009031 00000 n +0000009287 00000 n +0000009376 00000 n +0000009478 00000 n +0000009570 00000 n +0000009717 00000 n +0000009864 00000 n +0000009995 00000 n +0000010087 00000 n +0000010179 00000 n +0000010323 00000 n +0000010467 00000 n +0000010598 00000 n +0000010690 00000 n +0000010782 00000 n +0000010936 00000 n +0000011028 00000 n +0000011169 00000 n +0000011300 00000 n +0000011392 00000 n +0000011484 00000 n +0000011754 00000 n +0000012021 00000 n +0000012275 00000 n +0000012367 00000 n +0000012450 00000 n +0000012547 00000 n +0000012830 00000 n +0000012924 00000 n +0000013216 00000 n +0000013492 00000 n +0000013628 00000 n +0000013732 00000 n +0000013885 00000 n +0000014031 00000 n +0000014177 00000 n +0000014280 00000 n +0000014373 00000 n +0000014481 00000 n +0000014560 00000 n +0000014649 00000 n +0000014815 00000 n +0000015067 00000 n +0000015126 00000 n +0000015185 00000 n +0000015367 00000 n +0000016196 00000 n +0000016287 00000 n +0000016541 00000 n +0000018067 00000 n +0000024598 00000 n +0000024782 00000 n +0000025405 00000 n +0000025497 00000 n +0000025755 00000 n +0000027025 00000 n +0000032129 00000 n +0000032314 00000 n +0000033205 00000 n +0000033296 00000 n +0000033553 00000 n +0000035227 00000 n +0000042447 00000 n +0000042548 00000 n +0000042649 00000 n +0000042750 00000 n +0000042851 00000 n +0000042952 00000 n +0000043212 00000 n +0000043837 00000 n +0000044599 00000 n +0000044637 00000 n +0000044675 00000 n +0000045034 00000 n +0000045457 00000 n +0000045505 00000 n +0000045552 00000 n +0000045599 00000 n +0000045647 00000 n +0000045694 00000 n +0000045742 00000 n +0000045790 00000 n +0000045837 00000 n +0000046127 00000 n +0000046417 00000 n +0000046707 00000 n +0000046997 00000 n +0000047287 00000 n +0000047615 00000 n +0000051604 00000 n +0000051932 00000 n +0000055850 00000 n +0000057738 00000 n +0000096119 00000 n +0000097440 00000 n +0000104904 00000 n +0000106687 00000 n +0000133129 00000 n +0000134862 00000 n +0000147122 00000 n +0000148895 00000 n +0000164083 00000 n +0000164210 00000 n +0000165299 00000 n +trailer +<< + /Size 180 + /Root 179 0 R + /Info 177 0 R + /ID [(x0ieM9WiuhZBBsN6idseuQ==) (x0ieM9WiuhZBBsN6idseuQ==)] +>> +startxref +165561 +%%EOF \ No newline at end of file