diff --git a/.specify/specs/029-osm-visitor-info/plan.md b/.specify/specs/029-osm-visitor-info/plan.md new file mode 100644 index 00000000..df2ea9c4 --- /dev/null +++ b/.specify/specs/029-osm-visitor-info/plan.md @@ -0,0 +1,94 @@ +# Implementation Plan: OSM-Sourced Visitor Info (Hours, Accessibility, Fee) + +> **Spec ID:** 029-osm-visitor-info +> **Status:** Planning +> **Last Updated:** 2026-05-27 +> **Estimated Effort:** M + +## Summary + +Add three optional POI columns (`opening_hours`, `wheelchair`, `fee`), display +them in the Side Panel's Visitor Information section, make them admin-editable, +and extend the existing OSM amenity snapshot + importer to auto-populate them. + +--- + +## Data Flow + +1. **Refresh OSM snapshot** — re-query Overpass for the region's playgrounds + (`leisure=playground`) and toilets (`amenity=toilets`) with `out tags`, + capture `opening_hours`/`wheelchair`/`fee` per feature, merge into + `backend/data/osm/amenities.json` keyed by `osm_id` (keeps existing fields). +2. **Import** — `import-osm-amenities.js` writes the three fields on INSERT and, + on `ON CONFLICT` UPDATE, refreshes them with `COALESCE(EXCLUDED.x, pois.x)` + so a present DB value is never nulled by a tagless OSM feature. +3. **Read** — existing POI read endpoints already `SELECT *`; new columns flow to + the frontend with no API change. +4. **Display/Edit** — `ReadOnlyView` renders rows; `EditView` + `admin.js` + allowlists handle manual edits for any POI. + +--- + +## Implementation Steps + +### Phase 1: Schema +- [ ] `backend/migrations/067_osm_visitor_info.sql` — add 3 columns + CHECK + constraints, idempotent (`ADD COLUMN IF NOT EXISTS`, + `DROP CONSTRAINT IF EXISTS` before `ADD CONSTRAINT`). + +### Phase 2: Backend API +- [ ] Add `opening_hours`, `wheelchair`, `fee` to the 4 `allowedFields` + allowlists in `backend/routes/admin.js`. + +### Phase 3: OSM import +- [ ] Refresh `backend/data/osm/amenities.json` via Overpass to add the 3 tags. +- [ ] Extend `import-osm-amenities.js` INSERT column list + `ON CONFLICT` SET + with COALESCE non-clobber semantics. + +### Phase 4: Frontend +- [ ] `ReadOnlyView.jsx` — 3 conditional rows in Visitor Information grid, with + a small display-mapping helper for wheelchair/fee labels. +- [ ] `EditView.jsx` — Hours text input + Accessibility/Fee selects. + +### Phase 5: Build, verify, review +- [ ] `./run.sh build` then `./run.sh start` (port 8082, container rotv-osm-visitor). +- [ ] Human verification in browser. +- [ ] `gourmand --full .` + Gatehouse review. + +--- + +## File Changes + +### New Files +| File | Purpose | +|------|---------| +| `backend/migrations/067_osm_visitor_info.sql` | Add 3 columns + constraints | +| `.specify/specs/029-osm-visitor-info/{spec,plan}.md` | Spec & plan | + +### Modified Files +| File | Changes | +|------|---------| +| `backend/routes/admin.js` | Add 3 fields to 4 allowlists | +| `backend/migrations/import-osm-amenities.js` | Write/refresh 3 fields (COALESCE) | +| `backend/data/osm/amenities.json` | Add `opening_hours`/`wheelchair`/`fee` per feature | +| `frontend/src/components/sidebar/ReadOnlyView.jsx` | 3 display rows + label helper | +| `frontend/src/components/sidebar/EditView.jsx` | 3 edit inputs | + +--- + +## Risks and Mitigations + +| Risk | Impact | Mitigation | +|------|--------|------------| +| OSM re-import clobbers admin edits | Med | COALESCE(EXCLUDED, existing) on UPDATE | +| Sparse OSM coverage (few amenities tagged) | Low | Fields optional; rows hide when empty | +| Overpass refresh unavailable offline | Low | Snapshot is committed; import reads the file | +| CHECK constraint rejects unexpected OSM value | Low | Normalize/whitelist on import; skip unknowns | + +--- + +## Changelog + +| Date | Changes | +|------|---------| +| 2026-05-27 | Initial plan | diff --git a/.specify/specs/029-osm-visitor-info/spec.md b/.specify/specs/029-osm-visitor-info/spec.md new file mode 100644 index 00000000..9201cab2 --- /dev/null +++ b/.specify/specs/029-osm-visitor-info/spec.md @@ -0,0 +1,168 @@ +# Specification: OSM-Sourced Visitor Info (Hours, Accessibility, Fee) + +> **Spec ID:** 029-osm-visitor-info +> **Status:** Draft +> **Version:** 0.1.0 +> **Author:** Scott McCarty +> **Date:** 2026-05-27 + +## Overview + +Issue #7 asks for cost, hours, and mobility fields on POIs for One Tank Trip +planning. This adds three new POI fields — **operating hours**, **wheelchair +accessibility**, and **fee (yes/no)** — surfaced in the Side Panel's *Visitor +Information* section. The three map directly to standard OpenStreetMap tags +(`opening_hours`, `wheelchair`, `fee`), so the OSM amenity import pipeline is +extended to pre-populate them for the ~240 OSM-sourced amenity POIs, while all +POIs remain editable by admins. Cost is captured as a yes/no fee flag, not a +dollar amount — OSM rarely tags `charge` and pricing goes stale (see issue note +"need to plan that"). + +--- + +## User Stories + +### Visitor Planning + +**US-029-1: See operating hours** +> As a visitor planning a trip, I want to see a POI's operating hours so that I +> can avoid arriving when it is closed. + +Acceptance Criteria: +- [ ] When a POI has `opening_hours`, the Visitor Information section shows an "Hours" row. +- [ ] The row is hidden when the value is null/empty (no empty rows). + +**US-029-2: See accessibility** +> As a visitor with mobility needs, I want to see wheelchair accessibility so +> that I can decide whether a destination works for me. + +Acceptance Criteria: +- [ ] `wheelchair` value renders as a human label (Accessible / Limited / Not accessible / Designated). +- [ ] Row hidden when unset. + +**US-029-3: See whether there is a fee** +> As a visitor, I want to know whether a POI charges a fee so that I can budget. + +Acceptance Criteria: +- [ ] `fee` renders as Yes / No / Varies. +- [ ] Row hidden when unset. + +### Content Curation + +**US-029-4: Edit the fields** +> As an admin, I want to edit hours, accessibility, and fee on any POI so that I +> can correct or supplement OSM data. + +Acceptance Criteria: +- [ ] EditView exposes inputs for all three fields (text for hours, selects for accessibility/fee). +- [ ] Values persist via the existing admin POI update endpoints. + +### OSM Enrichment + +**US-029-5: Auto-populate amenities from OSM** +> As a maintainer, I want the OSM amenity import to capture these tags so that +> the seeded amenities ship with hours/accessibility/fee where OSM has them. + +Acceptance Criteria: +- [ ] `amenities.json` snapshot includes `opening_hours`, `wheelchair`, `fee` when present in OSM. +- [ ] `import-osm-amenities.js` writes them on insert and refreshes them on re-import, without clobbering a non-null OSM value with null. +- [ ] Idempotent: re-running does not duplicate or wipe data. + +**US-029-6: Match curated POIs to OSM** +> As a maintainer, I want ROTV's hand-curated POIs (parks, trails, visitor +> centers, businesses) matched to their OpenStreetMap features so that they +> record an `osm_id` and gain hours/accessibility/fee where OSM has them. + +Acceptance Criteria: +- [ ] Matching is name-gated (token similarity) with proximity scaled to name + confidence — proximity alone never matches (no shoe-store-inherits-cafe-hours). +- [ ] Matches are written to a committed, reviewable `poi-osm-matches.json`. +- [ ] Apply is idempotent and non-destructive: `osm_id` set once per name on an + unlinked row only if the id is free; visitor-info fields use COALESCE; + `more_info_link` is never touched (curated official links survive). +- [ ] Of ~465 curated POIs, ~248 match at high precision; the ~18 OSM tags are + surfaced. (Most CVNP-area features simply aren't tagged with these fields + in OSM — the ceiling is OSM coverage, not matching.) + +--- + +## Data Model + +### Schema Changes + +```sql +-- Migration 067: OSM visitor-info fields (issue #7) +ALTER TABLE pois ADD COLUMN IF NOT EXISTS opening_hours TEXT; -- raw OSM opening_hours string +ALTER TABLE pois ADD COLUMN IF NOT EXISTS wheelchair VARCHAR(12); -- yes | limited | no | designated +ALTER TABLE pois ADD COLUMN IF NOT EXISTS fee VARCHAR(12); -- yes | no | conditional + +ALTER TABLE pois ADD CONSTRAINT pois_wheelchair_check + CHECK (wheelchair IS NULL OR wheelchair IN ('yes','limited','no','designated')); +ALTER TABLE pois ADD CONSTRAINT pois_fee_check + CHECK (fee IS NULL OR fee IN ('yes','no','conditional')); +``` + +Column names mirror the OSM tag keys so provenance is obvious. Constraints are +added defensively (drop-if-exists first for idempotent re-run). + +--- + +## API Endpoints + +No new endpoints. The three fields are added to the `allowedFields` allowlists +in the existing POI create/update handlers in `backend/routes/admin.js` (4 sites: +point update, linear update, point insert, virtual/linear insert) and returned +by the existing POI read endpoints. + +--- + +## UI/UX Requirements + +### Changed Components + +- `ReadOnlyView.jsx` — add Hours / Accessibility / Fee rows to the existing + *Visitor Information* `details-grid`, each conditionally rendered. +- `EditView.jsx` — add a text input (Hours) and two selects (Accessibility, Fee) + alongside Surface / Pets / Cell Signal. + +### Display mapping + +| Field | Stored | Displayed | +|-------|--------|-----------| +| Hours | raw `opening_hours` | verbatim (e.g. `Mo-Su 06:00-22:00`) | +| Accessibility | `yes`/`limited`/`no`/`designated` | Accessible / Limited / Not accessible / Designated | +| Fee | `yes`/`no`/`conditional` | Yes / No / Varies | + +--- + +## Non-Functional Requirements + +**NFR-028-1: Idempotency** — migration and OSM import re-run safely on every deploy. + +**NFR-028-2: No clobber** — OSM re-import never overwrites a present value with null. + +**NFR-028-3: Sparse data is normal** — every field is optional; rows hide when unset. + +--- + +## Dependencies + +- Builds on spec 027 (amenity POI types) — reuses `pois.osm_id`, `amenities.json`, + and `import-osm-amenities.js`. + +--- + +## Open Questions + +1. Should hours be humanized (parse `opening_hours` syntax) or shown verbatim? + Decision: verbatim for v1; humanization is a future enhancement. +2. Should non-OSM curated POIs (parks, trails, businesses) be matched to OSM for + auto-fill? Decision: out of scope for v1 — those are admin-entered. + +--- + +## Changelog + +| Version | Date | Changes | +|---------|------|---------| +| 0.1.0 | 2026-05-27 | Initial draft | diff --git a/backend/data/osm/amenities.json b/backend/data/osm/amenities.json index 6f32c6d4..d4248f4a 100644 --- a/backend/data/osm/amenities.json +++ b/backend/data/osm/amenities.json @@ -5,7 +5,10 @@ "lat": 41.372601, "lon": -81.6130157, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node10676833085", @@ -13,7 +16,10 @@ "lat": 41.2622703, "lon": -81.5599946, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "no", + "fee": null }, { "osm_id": "node10707691068", @@ -21,7 +27,10 @@ "lat": 41.2170147, "lon": -81.5257278, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node10762282822", @@ -29,7 +38,10 @@ "lat": 41.1390045, "lon": -81.5747406, "osm_name": null, - "park": "F.A. Seiberling Nature Realm" + "park": "F.A. Seiberling Nature Realm", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node10859526305", @@ -37,7 +49,10 @@ "lat": 41.499276, "lon": -81.7115625, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node10859526306", @@ -45,7 +60,10 @@ "lat": 41.4987731, "lon": -81.7155029, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node11020856749", @@ -53,7 +71,10 @@ "lat": 41.5020874, "lon": -81.4893153, "osm_name": null, - "park": "Acacia Reservation" + "park": "Acacia Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node1137180456", @@ -61,7 +82,10 @@ "lat": 41.1592267, "lon": -81.5744783, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "node11916192151", @@ -69,7 +93,10 @@ "lat": 41.3924917, "lon": -81.6308308, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node11978458897", @@ -77,7 +104,10 @@ "lat": 41.224304, "lon": -81.5105508, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": "no" }, { "osm_id": "node12115369022", @@ -85,7 +115,10 @@ "lat": 41.1240971, "lon": -81.5312301, "osm_name": null, - "park": "Cascade Valley Metro Park" + "park": "Cascade Valley Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node12956673576", @@ -93,7 +126,10 @@ "lat": 41.5409742, "lon": -81.6338902, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node1297928834", @@ -101,7 +137,10 @@ "lat": 41.4465345, "lon": -81.7251191, "osm_name": null, - "park": "Brookside Reservation" + "park": "Brookside Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13037793077", @@ -109,7 +148,10 @@ "lat": 41.1721688, "lon": -81.5718225, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13101163329", @@ -117,7 +159,10 @@ "lat": 41.2178774, "lon": -81.5790801, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13115472762", @@ -125,7 +170,10 @@ "lat": 41.1325073, "lon": -81.4220798, "osm_name": null, - "park": "Munroe Falls Metro Park" + "park": "Munroe Falls Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13119545302", @@ -133,7 +181,10 @@ "lat": 41.1303703, "lon": -81.4230127, "osm_name": null, - "park": "Munroe Falls Metro Park" + "park": "Munroe Falls Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13119546749", @@ -141,7 +192,10 @@ "lat": 41.1329089, "lon": -81.4237524, "osm_name": null, - "park": "Munroe Falls Metro Park" + "park": "Munroe Falls Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13120496070", @@ -149,7 +203,10 @@ "lat": 41.2776985, "lon": -81.5372488, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13120522503", @@ -157,7 +214,10 @@ "lat": 41.2318264, "lon": -81.5540243, "osm_name": null, - "park": "Deep Lock Quarry Metro Park" + "park": "Deep Lock Quarry Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13529495791", @@ -165,7 +225,10 @@ "lat": 41.3904225, "lon": -81.5767491, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13568292708", @@ -173,7 +236,10 @@ "lat": 41.3897753, "lon": -81.6951007, "osm_name": null, - "park": "West Creek Reservation" + "park": "West Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13568292732", @@ -181,7 +247,10 @@ "lat": 41.3897834, "lon": -81.6951233, "osm_name": null, - "park": "West Creek Reservation" + "park": "West Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13568292734", @@ -189,7 +258,10 @@ "lat": 41.3908488, "lon": -81.6917027, "osm_name": null, - "park": "West Creek Reservation" + "park": "West Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node1375183996", @@ -197,7 +269,10 @@ "lat": 41.2309378, "lon": -81.4934969, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "node13836877296", @@ -205,7 +280,10 @@ "lat": 41.3189718, "lon": -81.5880832, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node13836877297", @@ -213,7 +291,10 @@ "lat": 41.3189741, "lon": -81.5881326, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2141868525", @@ -221,7 +302,10 @@ "lat": 41.3790138, "lon": -81.551066, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2141917787", @@ -229,7 +313,10 @@ "lat": 41.3758499, "lon": -81.573669, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2148542124", @@ -237,7 +324,10 @@ "lat": 41.3739723, "lon": -81.5721534, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2153810573", @@ -245,7 +335,10 @@ "lat": 41.5796073, "lon": -81.4287785, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2155072348", @@ -253,7 +346,10 @@ "lat": 41.3524398, "lon": -81.5920963, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2158266182", @@ -261,7 +357,10 @@ "lat": 41.5612571, "lon": -81.430438, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2202420723", @@ -269,7 +368,10 @@ "lat": 41.5746917, "lon": -81.4226424, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2202420738", @@ -277,7 +379,10 @@ "lat": 41.5745894, "lon": -81.4214193, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2235614557", @@ -285,7 +390,10 @@ "lat": 41.5501387, "lon": -81.4177555, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2243047166", @@ -293,7 +401,10 @@ "lat": 41.5690731, "lon": -81.4191489, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2251256936", @@ -301,7 +412,10 @@ "lat": 41.5615033, "lon": -81.4346334, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node2283472002", @@ -309,7 +423,10 @@ "lat": 41.4072496, "lon": -81.8863243, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2414613006", @@ -317,7 +434,10 @@ "lat": 41.4569989, "lon": -81.4066279, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": "no" }, { "osm_id": "node2504525020", @@ -325,7 +445,10 @@ "lat": 41.5391942, "lon": -81.5219986, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2505390692", @@ -333,7 +456,10 @@ "lat": 41.5601654, "lon": -81.532329, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2505390702", @@ -341,7 +467,10 @@ "lat": 41.5620921, "lon": -81.5319856, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node2506476021", @@ -349,7 +478,10 @@ "lat": 41.5394272, "lon": -81.5219353, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2509774902", @@ -357,7 +489,10 @@ "lat": 41.5479255, "lon": -81.5285592, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2516687875", @@ -365,7 +500,10 @@ "lat": 41.276319, "lon": -81.5402439, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2519251318", @@ -373,7 +511,10 @@ "lat": 41.3770279, "lon": -81.5589703, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2519265063", @@ -381,7 +522,10 @@ "lat": 41.3805781, "lon": -81.5346332, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2520419082", @@ -389,7 +533,10 @@ "lat": 41.5406539, "lon": -81.6286528, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2525740698", @@ -397,7 +544,10 @@ "lat": 41.5020872, "lon": -81.489358, "osm_name": null, - "park": "Acacia Reservation" + "park": "Acacia Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node2525828377", @@ -405,7 +555,10 @@ "lat": 41.3908153, "lon": -81.6917462, "osm_name": null, - "park": "West Creek Reservation" + "park": "West Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2679582997", @@ -413,7 +566,10 @@ "lat": 41.3154487, "lon": -81.6165565, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2679583003", @@ -421,7 +577,10 @@ "lat": 41.3154527, "lon": -81.6186942, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2679583027", @@ -429,7 +588,10 @@ "lat": 41.3196251, "lon": -81.6155058, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2679583028", @@ -437,7 +599,10 @@ "lat": 41.3181743, "lon": -81.6156821, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2679583062", @@ -445,7 +610,10 @@ "lat": 41.307817, "lon": -81.6020229, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2757357899", @@ -453,7 +621,10 @@ "lat": 41.3015754, "lon": -81.8033928, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2786496941", @@ -461,7 +632,10 @@ "lat": 41.3156644, "lon": -81.6010038, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2851907817", @@ -469,7 +643,10 @@ "lat": 41.2262941, "lon": -81.5152929, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "no", + "fee": null }, { "osm_id": "node2851910941", @@ -477,7 +654,10 @@ "lat": 41.2243049, "lon": -81.5104772, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": "no" }, { "osm_id": "node2851910954", @@ -485,7 +665,10 @@ "lat": 41.2320797, "lon": -81.5072738, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2867556015", @@ -493,7 +676,10 @@ "lat": 41.3863932, "lon": -81.5371677, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2867556025", @@ -501,7 +687,10 @@ "lat": 41.3846877, "lon": -81.5243936, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2867556036", @@ -509,7 +698,10 @@ "lat": 41.3732017, "lon": -81.5046475, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2937937111", @@ -517,7 +709,10 @@ "lat": 41.4237721, "lon": -81.4213917, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2937937160", @@ -525,7 +720,10 @@ "lat": 41.4185272, "lon": -81.4192953, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node2941979574", @@ -533,7 +731,10 @@ "lat": 41.4337199, "lon": -81.4177753, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2953596613", @@ -541,7 +742,10 @@ "lat": 41.4006065, "lon": -81.8864987, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2953596933", @@ -549,7 +753,10 @@ "lat": 41.4047691, "lon": -81.8840418, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2961881365", @@ -557,7 +764,10 @@ "lat": 41.4332255, "lon": -81.8448262, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2961881408", @@ -565,7 +775,10 @@ "lat": 41.4327047, "lon": -81.8485223, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986102859", @@ -573,7 +786,10 @@ "lat": 41.4901381, "lon": -81.9339643, "osm_name": null, - "park": "Huntington Reservation" + "park": "Huntington Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node2986102861", @@ -581,7 +797,10 @@ "lat": 41.4900261, "lon": -81.9310068, "osm_name": null, - "park": "Huntington Reservation" + "park": "Huntington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986102864", @@ -589,7 +808,10 @@ "lat": 41.486667, "lon": -81.9338194, "osm_name": null, - "park": "Huntington Reservation" + "park": "Huntington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986138404", @@ -597,7 +819,10 @@ "lat": 41.4425483, "lon": -81.7552954, "osm_name": null, - "park": "Big Creek Reservation" + "park": "Big Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986138410", @@ -605,7 +830,10 @@ "lat": 41.4020351, "lon": -81.7580542, "osm_name": null, - "park": "Big Creek Reservation" + "park": "Big Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986138417", @@ -613,7 +841,10 @@ "lat": 41.3804378, "lon": -81.8409555, "osm_name": "Mastadon Play Pit Play Area", - "park": "Big Creek Reservation" + "park": "Big Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986174403", @@ -621,7 +852,10 @@ "lat": 41.3635574, "lon": -81.8581176, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node2986174415", @@ -629,7 +863,10 @@ "lat": 41.3547407, "lon": -81.8546829, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986174419", @@ -637,7 +874,10 @@ "lat": 41.3552443, "lon": -81.8495652, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986236008", @@ -645,7 +885,10 @@ "lat": 41.3338914, "lon": -81.8335773, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986236013", @@ -653,7 +896,10 @@ "lat": 41.3341387, "lon": -81.8274293, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986519822", @@ -661,7 +907,10 @@ "lat": 41.4343864, "lon": -81.8443419, "osm_name": "Swingset", - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986519823", @@ -669,7 +918,10 @@ "lat": 41.4335579, "lon": -81.8443848, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986520656", @@ -677,7 +929,10 @@ "lat": 41.4791695, "lon": -81.832508, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986520658", @@ -685,7 +940,10 @@ "lat": 41.4780683, "lon": -81.8317462, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986687776", @@ -693,7 +951,10 @@ "lat": 41.2208544, "lon": -81.7203914, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986687811", @@ -701,7 +962,10 @@ "lat": 41.2204569, "lon": -81.6979976, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node2986687814", @@ -709,7 +973,10 @@ "lat": 41.2185362, "lon": -81.7030598, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986687817", @@ -717,7 +984,10 @@ "lat": 41.2114941, "lon": -81.70892, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986687822", @@ -725,7 +995,10 @@ "lat": 41.204207, "lon": -81.7262368, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node2986687832", @@ -733,7 +1006,10 @@ "lat": 41.2040133, "lon": -81.7269878, "osm_name": "Ledge Lake Bath House", - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node3195055708", @@ -741,7 +1017,10 @@ "lat": 41.3865764, "lon": -81.5953812, "osm_name": null, - "park": "Valley View Woods" + "park": "Valley View Woods", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node3195055710", @@ -749,7 +1028,10 @@ "lat": 41.3867434, "lon": -81.5956736, "osm_name": null, - "park": "Valley View Woods" + "park": "Valley View Woods", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node3195055711", @@ -757,7 +1039,10 @@ "lat": 41.3870272, "lon": -81.5929082, "osm_name": null, - "park": "Valley View Woods" + "park": "Valley View Woods", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node3445659035", @@ -765,7 +1050,10 @@ "lat": 41.4111826, "lon": -81.4140311, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node3618330016", @@ -773,7 +1061,10 @@ "lat": 41.2895578, "lon": -81.5640521, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4022750202", @@ -781,7 +1072,10 @@ "lat": 41.5598247, "lon": -81.5313771, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4035709934", @@ -789,7 +1083,10 @@ "lat": 41.4295271, "lon": -81.6060899, "osm_name": null, - "park": "Garfield Park Reservation" + "park": "Garfield Park Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4035709947", @@ -797,7 +1094,10 @@ "lat": 41.4294947, "lon": -81.6019106, "osm_name": null, - "park": "Garfield Park Reservation" + "park": "Garfield Park Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4035712675", @@ -805,7 +1105,10 @@ "lat": 41.4329632, "lon": -81.6051565, "osm_name": null, - "park": "Garfield Park Reservation" + "park": "Garfield Park Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4036690720", @@ -813,7 +1116,10 @@ "lat": 41.4286193, "lon": -81.60683, "osm_name": null, - "park": "Garfield Park Reservation" + "park": "Garfield Park Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4044801548", @@ -821,7 +1127,10 @@ "lat": 41.5699001, "lon": -81.4377953, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4064237415", @@ -829,7 +1138,10 @@ "lat": 41.4229027, "lon": -81.4168596, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4066048430", @@ -837,7 +1149,10 @@ "lat": 41.4322004, "lon": -81.604702, "osm_name": null, - "park": "Garfield Park Reservation" + "park": "Garfield Park Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4069224516", @@ -845,7 +1160,10 @@ "lat": 41.4134042, "lon": -81.4594332, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4127019880", @@ -853,7 +1171,10 @@ "lat": 41.2709841, "lon": -81.5558063, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4218284432", @@ -861,7 +1182,10 @@ "lat": 41.372215, "lon": -81.6137067, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4270946681", @@ -869,7 +1193,10 @@ "lat": 41.306772, "lon": -81.398587, "osm_name": null, - "park": "Liberty Park" + "park": "Liberty Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4351736404", @@ -877,7 +1204,10 @@ "lat": 41.1842838, "lon": -81.5826273, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "node4464194737", @@ -885,7 +1215,10 @@ "lat": 41.4901601, "lon": -81.9332669, "osm_name": null, - "park": "Huntington Reservation" + "park": "Huntington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4464194784", @@ -893,7 +1226,10 @@ "lat": 41.4895333, "lon": -81.9345944, "osm_name": null, - "park": "Huntington Reservation" + "park": "Huntington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4465446059", @@ -901,7 +1237,10 @@ "lat": 41.4336882, "lon": -81.6587505, "osm_name": null, - "park": "Ohio & Erie Canal Reservation" + "park": "Ohio & Erie Canal Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4465446844", @@ -909,7 +1248,10 @@ "lat": 41.4545856, "lon": -81.6592269, "osm_name": null, - "park": "Washington Reservation" + "park": "Washington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4529249945", @@ -917,7 +1259,10 @@ "lat": 41.561726, "lon": -81.4357488, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4531011957", @@ -925,7 +1270,10 @@ "lat": 41.3568005, "lon": -81.8241964, "osm_name": null, - "park": "Big Creek Reservation" + "park": "Big Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4531012608", @@ -933,7 +1281,10 @@ "lat": 41.380378, "lon": -81.8425807, "osm_name": null, - "park": "Big Creek Reservation" + "park": "Big Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4545860956", @@ -941,7 +1292,10 @@ "lat": 41.2216249, "lon": -81.7309028, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4545861521", @@ -949,7 +1303,10 @@ "lat": 41.203166, "lon": -81.7006004, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4636077527", @@ -957,7 +1314,10 @@ "lat": 41.3761302, "lon": -81.5742223, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4714314685", @@ -965,7 +1325,10 @@ "lat": 41.0125077, "lon": -81.3940918, "osm_name": null, - "park": "Springfield Bog Metro Park" + "park": "Springfield Bog Metro Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node4719518875", @@ -973,7 +1336,10 @@ "lat": 41.3629687, "lon": -81.8588522, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4731424491", @@ -981,7 +1347,10 @@ "lat": 41.3043636, "lon": -81.7537599, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4732830529", @@ -989,7 +1358,10 @@ "lat": 41.3023289, "lon": -81.7378319, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4884571736", @@ -997,7 +1369,10 @@ "lat": 41.2165105, "lon": -81.7145979, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4884571737", @@ -1005,7 +1380,10 @@ "lat": 41.2171251, "lon": -81.7144119, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4904842313", @@ -1013,7 +1391,10 @@ "lat": 41.3630752, "lon": -81.8546659, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4972122536", @@ -1021,7 +1402,10 @@ "lat": 41.1277701, "lon": -81.5397336, "osm_name": null, - "park": "Sand Run Metro Park" + "park": "Sand Run Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "node4974367973", @@ -1029,7 +1413,10 @@ "lat": 41.4133342, "lon": -81.4233188, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node4980291106", @@ -1037,7 +1424,10 @@ "lat": 41.2680072, "lon": -81.6392055, "osm_name": null, - "park": "Furnace Run Metro Park" + "park": "Furnace Run Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node5036948730", @@ -1045,7 +1435,10 @@ "lat": 41.4504556, "lon": -81.6580381, "osm_name": null, - "park": "Washington Reservation" + "park": "Washington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node5102173322", @@ -1053,7 +1446,10 @@ "lat": 41.0917526, "lon": -81.5186707, "osm_name": null, - "park": "Cascade Park" + "park": "Cascade Park", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "node5275328754", @@ -1061,7 +1457,10 @@ "lat": 41.2141827, "lon": -81.5309797, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node5747753898", @@ -1069,7 +1468,10 @@ "lat": 41.4996367, "lon": -81.7108324, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node5825507126", @@ -1077,7 +1479,10 @@ "lat": 41.0592966, "lon": -81.5425897, "osm_name": null, - "park": "Summit Lake Park" + "park": "Summit Lake Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node5982333359", @@ -1085,7 +1490,10 @@ "lat": 41.1378062, "lon": -81.5649645, "osm_name": null, - "park": "Sand Run Metro Park" + "park": "Sand Run Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node6003953365", @@ -1093,7 +1501,10 @@ "lat": 41.1334234, "lon": -81.596668, "osm_name": null, - "park": "Sand Run Metro Park" + "park": "Sand Run Metro Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node6011450296", @@ -1101,7 +1512,10 @@ "lat": 41.2611433, "lon": -81.683192, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node6214892937", @@ -1109,7 +1523,10 @@ "lat": 41.331648, "lon": -81.4091136, "osm_name": "Nature Play", - "park": "Liberty Park" + "park": "Liberty Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node6283260364", @@ -1117,7 +1534,10 @@ "lat": 41.1340915, "lon": -81.5600071, "osm_name": null, - "park": "Sand Run Metro Park" + "park": "Sand Run Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "node6311827098", @@ -1125,7 +1545,10 @@ "lat": 41.3903862, "lon": -81.5772039, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node6311827109", @@ -1133,7 +1556,10 @@ "lat": 41.389769, "lon": -81.5923124, "osm_name": null, - "park": "Valley View Woods" + "park": "Valley View Woods", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node6486880885", @@ -1141,7 +1567,10 @@ "lat": 41.0784253, "lon": -81.4557772, "osm_name": null, - "park": "Goodyear Heights Metro Park" + "park": "Goodyear Heights Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node6510003585", @@ -1149,7 +1578,10 @@ "lat": 41.1703681, "lon": -81.5902836, "osm_name": null, - "park": "O'Neil Woods Metro Park" + "park": "O'Neil Woods Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node6712076870", @@ -1157,7 +1589,10 @@ "lat": 41.448979, "lon": -81.7239299, "osm_name": null, - "park": "Brookside Reservation" + "park": "Brookside Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node6795730985", @@ -1165,7 +1600,10 @@ "lat": 41.1670844, "lon": -81.5670037, "osm_name": null, - "park": "Hampton Hills Metro Park" + "park": "Hampton Hills Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node8040270852", @@ -1173,7 +1611,10 @@ "lat": 41.2207808, "lon": -81.5116417, "osm_name": "Men's Toilets", - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "no", + "fee": null }, { "osm_id": "node8040276264", @@ -1181,7 +1622,10 @@ "lat": 41.2207497, "lon": -81.5112938, "osm_name": "Women's Bathroom", - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "no", + "fee": null }, { "osm_id": "node8279554267", @@ -1189,7 +1633,10 @@ "lat": 41.5606933, "lon": -81.5329362, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node8762263552", @@ -1197,7 +1644,10 @@ "lat": 41.4887874, "lon": -81.7382427, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": "no" }, { "osm_id": "node8762286830", @@ -1205,7 +1655,10 @@ "lat": 41.4865533, "lon": -81.743656, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": "no" }, { "osm_id": "node8762604693", @@ -1213,7 +1666,10 @@ "lat": 41.5834593, "lon": -81.568323, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node8762652383", @@ -1221,7 +1677,10 @@ "lat": 41.5829163, "lon": -81.5693881, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": "no" }, { "osm_id": "node8763018942", @@ -1229,7 +1688,10 @@ "lat": 41.0110472, "lon": -81.5176427, "osm_name": null, - "park": "Firestone Metro Park" + "park": "Firestone Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node8763018943", @@ -1237,7 +1699,10 @@ "lat": 41.012577, "lon": -81.5136469, "osm_name": null, - "park": "Firestone Metro Park" + "park": "Firestone Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node8815953337", @@ -1245,7 +1710,10 @@ "lat": 41.0168175, "lon": -81.5149407, "osm_name": null, - "park": "Firestone Metro Park" + "park": "Firestone Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node9230679589", @@ -1253,7 +1721,10 @@ "lat": 41.4092779, "lon": -81.8820007, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node9588942854", @@ -1261,7 +1732,10 @@ "lat": 41.4921596, "lon": -81.7359486, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node9741336929", @@ -1269,7 +1743,10 @@ "lat": 41.1293802, "lon": -81.5526594, "osm_name": null, - "park": "Sand Run Metro Park" + "park": "Sand Run Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "node9818859742", @@ -1277,7 +1754,10 @@ "lat": 41.4888053, "lon": -81.7382911, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node9854608444", @@ -1285,7 +1765,10 @@ "lat": 41.139266, "lon": -81.5649835, "osm_name": null, - "park": "Sand Run Metro Park" + "park": "Sand Run Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node9854608453", @@ -1293,7 +1776,10 @@ "lat": 41.1303178, "lon": -81.5680391, "osm_name": null, - "park": "Sand Run Metro Park" + "park": "Sand Run Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "node9910733104", @@ -1301,7 +1787,10 @@ "lat": 41.1227772, "lon": -81.5249043, "osm_name": null, - "park": "Cascade Valley Metro Park" + "park": "Cascade Valley Metro Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "node9935556868", @@ -1309,7 +1798,10 @@ "lat": 41.3608849, "lon": -81.8588261, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way1005349290", @@ -1317,7 +1809,10 @@ "lat": 41.4332349, "lon": -81.8448275, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1005349294", @@ -1325,7 +1820,10 @@ "lat": 41.4349193, "lon": -81.8442683, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1005349296", @@ -1333,7 +1831,10 @@ "lat": 41.4332898, "lon": -81.8441266, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1033100035", @@ -1341,7 +1842,10 @@ "lat": 41.4895403, "lon": -81.9345986, "osm_name": null, - "park": "Huntington Reservation" + "park": "Huntington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1038682275", @@ -1349,7 +1853,10 @@ "lat": 41.486458, "lon": -81.7460066, "osm_name": "The Lindsey Family Play Space", - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1044285011", @@ -1357,7 +1864,10 @@ "lat": 41.42995, "lon": -81.6657215, "osm_name": null, - "park": "Ohio & Erie Canal Reservation" + "park": "Ohio & Erie Canal Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1079665169", @@ -1365,7 +1875,10 @@ "lat": 41.582074, "lon": -81.4177858, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1082530189", @@ -1373,7 +1886,10 @@ "lat": 41.1201718, "lon": -81.5169127, "osm_name": null, - "park": "Cascade Valley Metro Park" + "park": "Cascade Valley Metro Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way1083291220", @@ -1381,7 +1897,10 @@ "lat": 41.1220865, "lon": -81.5227153, "osm_name": null, - "park": "Cascade Valley Metro Park" + "park": "Cascade Valley Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1083291222", @@ -1389,7 +1908,10 @@ "lat": 41.1195374, "lon": -81.5237149, "osm_name": null, - "park": "Cascade Valley Metro Park" + "park": "Cascade Valley Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1149973620", @@ -1397,7 +1919,10 @@ "lat": 41.2394779, "lon": -81.5378296, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1155071912", @@ -1405,7 +1930,10 @@ "lat": 41.219643, "lon": -81.575901, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1156484519", @@ -1413,7 +1941,10 @@ "lat": 41.1273396, "lon": -81.5458675, "osm_name": null, - "park": "Sand Run Metro Park" + "park": "Sand Run Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1157720751", @@ -1421,7 +1952,10 @@ "lat": 41.1208065, "lon": -81.4934425, "osm_name": null, - "park": "Gorge Metro Park" + "park": "Gorge Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1163505913", @@ -1429,7 +1963,10 @@ "lat": 41.3112209, "lon": -81.7846409, "osm_name": null, - "park": "Mill Stream Run Reservation" + "park": "Mill Stream Run Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1174428106", @@ -1437,7 +1974,10 @@ "lat": 41.2333892, "lon": -81.5693289, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1221204668", @@ -1445,7 +1985,10 @@ "lat": 41.229704, "lon": -81.5539495, "osm_name": null, - "park": "Deep Lock Quarry Metro Park" + "park": "Deep Lock Quarry Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1249928792", @@ -1453,7 +1996,10 @@ "lat": 41.4453405, "lon": -81.8293357, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1267521419", @@ -1461,7 +2007,10 @@ "lat": 41.3804303, "lon": -81.8409429, "osm_name": "Mastadon Play Pit Play Area", - "park": "Big Creek Reservation" + "park": "Big Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1267995343", @@ -1469,7 +2018,10 @@ "lat": 41.453983, "lon": -81.6621353, "osm_name": null, - "park": "Washington Reservation" + "park": "Washington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1286938353", @@ -1477,7 +2029,10 @@ "lat": 41.1509808, "lon": -81.550829, "osm_name": null, - "park": "Hampton Hills Mountain Bike Area" + "park": "Hampton Hills Mountain Bike Area", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1294767426", @@ -1485,7 +2040,10 @@ "lat": 41.1659651, "lon": -81.5365896, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1308288116", @@ -1493,7 +2051,10 @@ "lat": 41.1238763, "lon": -81.5310094, "osm_name": null, - "park": "Cascade Valley Metro Park" + "park": "Cascade Valley Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1330031009", @@ -1501,7 +2062,10 @@ "lat": 41.4902682, "lon": -81.9333607, "osm_name": "Karen's Way Play Space", - "park": "Huntington Reservation" + "park": "Huntington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1335708746", @@ -1509,7 +2073,10 @@ "lat": 41.1282915, "lon": -81.521784, "osm_name": null, - "park": "Cascade Valley Metro Park" + "park": "Cascade Valley Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1359965592", @@ -1517,7 +2084,10 @@ "lat": 41.4416124, "lon": -81.8349511, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1388871213", @@ -1525,7 +2095,10 @@ "lat": 41.2307395, "lon": -81.5232341, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1421600772", @@ -1533,7 +2106,10 @@ "lat": 41.2232298, "lon": -81.7116889, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1421600776", @@ -1541,7 +2117,10 @@ "lat": 41.2246356, "lon": -81.7081998, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1421600777", @@ -1549,7 +2128,10 @@ "lat": 41.2221404, "lon": -81.7129131, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1421600787", @@ -1557,7 +2139,10 @@ "lat": 41.217792, "lon": -81.7159193, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1421600795", @@ -1565,7 +2150,10 @@ "lat": 41.2266774, "lon": -81.7195273, "osm_name": null, - "park": "Hinckley Reservation" + "park": "Hinckley Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1422943492", @@ -1573,7 +2161,10 @@ "lat": 41.3014254, "lon": -81.5998556, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way1424147645", @@ -1581,7 +2172,10 @@ "lat": 41.3846824, "lon": -81.5394062, "osm_name": null, - "park": "Bedford Reservation" + "park": "Bedford Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "way1424841214", @@ -1589,7 +2183,10 @@ "lat": 41.2044367, "lon": -81.5816274, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1425465590", @@ -1597,7 +2194,10 @@ "lat": 41.3819678, "lon": -81.481892, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1425468558", @@ -1605,7 +2205,10 @@ "lat": 41.4203404, "lon": -81.4236848, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1427112920", @@ -1613,7 +2216,10 @@ "lat": 41.1306391, "lon": -81.4346757, "osm_name": null, - "park": "Munroe Falls Metro Park" + "park": "Munroe Falls Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1427123267", @@ -1621,7 +2227,10 @@ "lat": 41.1302572, "lon": -81.424582, "osm_name": null, - "park": "Munroe Falls Metro Park" + "park": "Munroe Falls Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1427125657", @@ -1629,7 +2238,10 @@ "lat": 41.1326473, "lon": -81.4252635, "osm_name": null, - "park": "Munroe Falls Metro Park" + "park": "Munroe Falls Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way1427238338", @@ -1637,7 +2249,10 @@ "lat": 41.3000021, "lon": -81.6072731, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way297209389", @@ -1645,7 +2260,10 @@ "lat": 41.1907638, "lon": -81.5597446, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way297209391", @@ -1653,7 +2271,10 @@ "lat": 41.190749, "lon": -81.5599941, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way297212149", @@ -1661,7 +2282,10 @@ "lat": 41.1918888, "lon": -81.5624295, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way297212150", @@ -1669,7 +2293,10 @@ "lat": 41.1920268, "lon": -81.5624016, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way310182539", @@ -1677,7 +2304,10 @@ "lat": 41.0829699, "lon": -81.4480869, "osm_name": null, - "park": "Goodyear Heights Metro Park" + "park": "Goodyear Heights Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way321927910", @@ -1685,7 +2315,10 @@ "lat": 41.1676295, "lon": -81.5362099, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way375405469", @@ -1693,7 +2326,10 @@ "lat": 41.4929316, "lon": -81.7341905, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way375610560", @@ -1701,7 +2337,10 @@ "lat": 41.4860415, "lon": -81.7468382, "osm_name": null, - "park": "Cleveland Lakefront Reservation" + "park": "Cleveland Lakefront Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way377646390", @@ -1709,7 +2348,10 @@ "lat": 41.4391244, "lon": -81.8462193, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way377646393", @@ -1717,7 +2359,10 @@ "lat": 41.4689982, "lon": -81.8329459, "osm_name": null, - "park": "Rocky River Reservation" + "park": "Rocky River Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "way422748570", @@ -1725,7 +2370,10 @@ "lat": 41.0755037, "lon": -81.4510398, "osm_name": null, - "park": "Goodyear Heights Metro Park" + "park": "Goodyear Heights Metro Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way425109411", @@ -1733,7 +2381,10 @@ "lat": 41.5480948, "lon": -81.528423, "osm_name": "Euclid Creek Playground", - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way437233917", @@ -1741,7 +2392,10 @@ "lat": 41.2122548, "lon": -81.5456137, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way462785361", @@ -1749,7 +2403,10 @@ "lat": 41.5859851, "lon": -81.5657686, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way462785367", @@ -1757,7 +2414,10 @@ "lat": 41.5875234, "lon": -81.5618468, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way462785368", @@ -1765,7 +2425,10 @@ "lat": 41.5875469, "lon": -81.56163, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way462785370", @@ -1773,7 +2436,10 @@ "lat": 41.58707, "lon": -81.5633549, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way462785375", @@ -1781,7 +2447,10 @@ "lat": 41.5829031, "lon": -81.5693631, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way478297268", @@ -1789,7 +2458,10 @@ "lat": 41.1860348, "lon": -81.5884168, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way491806317", @@ -1797,7 +2469,10 @@ "lat": 41.2629429, "lon": -81.5587285, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "no", + "fee": null }, { "osm_id": "way575122002", @@ -1805,7 +2480,10 @@ "lat": 41.4169457, "lon": -81.4153677, "osm_name": null, - "park": "South Chagrin Reservation" + "park": "South Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way610031851", @@ -1813,7 +2491,10 @@ "lat": 41.3014966, "lon": -81.5990664, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way622499187", @@ -1821,7 +2502,10 @@ "lat": 41.3166724, "lon": -81.4174869, "osm_name": null, - "park": "Liberty Park" + "park": "Liberty Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way622499200", @@ -1829,7 +2513,10 @@ "lat": 41.3173608, "lon": -81.4175533, "osm_name": null, - "park": "Liberty Park" + "park": "Liberty Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way713940619", @@ -1837,7 +2524,10 @@ "lat": 41.4500697, "lon": -81.7217981, "osm_name": null, - "park": "Brookside Reservation" + "park": "Brookside Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way714941822", @@ -1845,7 +2535,10 @@ "lat": 41.5745638, "lon": -81.4176246, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way714941824", @@ -1853,7 +2546,10 @@ "lat": 41.5751638, "lon": -81.4176432, "osm_name": null, - "park": "North Chagrin Reservation" + "park": "North Chagrin Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way746531257", @@ -1861,7 +2557,10 @@ "lat": 41.2006932, "lon": -81.5715733, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way749959910", @@ -1869,7 +2568,10 @@ "lat": 41.3043783, "lon": -81.753855, "osm_name": null, - "park": "Brecksville Reservation" + "park": "Brecksville Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way751089153", @@ -1877,7 +2579,10 @@ "lat": 41.1924006, "lon": -81.5611354, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way751089154", @@ -1885,7 +2590,10 @@ "lat": 41.1922441, "lon": -81.5611693, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": "yes", + "fee": null }, { "osm_id": "way817947652", @@ -1893,7 +2601,10 @@ "lat": 41.2431781, "lon": -81.5491636, "osm_name": null, - "park": "Cuyahoga Valley National Park" + "park": "Cuyahoga Valley National Park", + "opening_hours": null, + "wheelchair": null, + "fee": "no" }, { "osm_id": "way854646225", @@ -1901,7 +2612,10 @@ "lat": 41.5832467, "lon": -81.5683928, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null }, { "osm_id": "way891132942", @@ -1909,7 +2623,10 @@ "lat": 41.5604721, "lon": -81.5331986, "osm_name": null, - "park": "Euclid Creek Reservation" + "park": "Euclid Creek Reservation", + "opening_hours": null, + "wheelchair": "yes", + "fee": "no" }, { "osm_id": "way999320970", @@ -1917,6 +2634,9 @@ "lat": 41.4901637, "lon": -81.9341409, "osm_name": null, - "park": "Huntington Reservation" + "park": "Huntington Reservation", + "opening_hours": null, + "wheelchair": null, + "fee": null } ] diff --git a/backend/data/osm/poi-osm-matches.json b/backend/data/osm/poi-osm-matches.json new file mode 100644 index 00000000..2a26a953 --- /dev/null +++ b/backend/data/osm/poi-osm-matches.json @@ -0,0 +1,2978 @@ +[ + { + "poi_name": "Acacia Reservation", + "osm_id": "way297396089", + "opening_hours": "06:00-23:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Acacia Reservation", + "similarity": 1, + "distance_m": 90 + } + }, + { + "poi_name": "Akron Zoo", + "osm_id": "way243713543", + "opening_hours": "Mo-Su 11:00-16:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Akron Zoo", + "similarity": 1, + "distance_m": 79 + } + }, + { + "poi_name": "Boston Mill Visitor Center", + "osm_id": "way1056693999", + "opening_hours": "Mo-Su 09:30-17:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Boston Mill Visitor Center - Cuyahoga Valley NP", + "similarity": 0.85, + "distance_m": 15 + } + }, + { + "poi_name": "Boston Store", + "osm_id": "way491806320", + "opening_hours": "Mo-Su 09:30-18:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Boston Store Visitor Center", + "similarity": 0.85, + "distance_m": 2 + } + }, + { + "poi_name": "CanalWay Center", + "osm_id": "way98114746", + "opening_hours": "Mo-Su 09:30-17:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "CanalWay Center", + "similarity": 1, + "distance_m": 5 + } + }, + { + "poi_name": "Cleveland Metroparks Zoo", + "osm_id": "relation3961010", + "opening_hours": "Apr-Sep 10:00-17:00; Oct-Mar 10:00-16:00; Nov Th[4],Dec 25,Jan 01 off", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cleveland Metroparks Zoo", + "similarity": 1, + "distance_m": 89 + } + }, + { + "poi_name": "Creekside Bar & Restaurant", + "osm_id": "node5561316002", + "opening_hours": "Mo-Th 11:00-22:00; Fr-Sa 11:00-23:00; Su 08:00-21:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Creekside Restaurant & Bar", + "similarity": 1, + "distance_m": 22 + } + }, + { + "poi_name": "Hale Farm & Village", + "osm_id": "way578672338", + "opening_hours": "Mo-Su 10:00-16:00", + "wheelchair": null, + "fee": "yes", + "match": { + "osm_name": "Hale Farm & Village", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Hampton Hills Metro Park", + "osm_id": "way515714240", + "opening_hours": "Mo-Su 06:00-23:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Hampton Hills Metropark", + "similarity": 1, + "distance_m": 47 + } + }, + { + "poi_name": "Hampton Hills Mountain Bike Area", + "osm_id": "way458952457", + "opening_hours": "Mo-Su 06:00-23:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Hampton Hills Mountain Bike Area", + "similarity": 1, + "distance_m": 65 + } + }, + { + "poi_name": "Hampton Hills Mountain Bike Trailhead", + "osm_id": "way437398880", + "opening_hours": null, + "wheelchair": null, + "fee": "no", + "match": { + "osm_name": "Hampton Hills Mountain Bike Area Parking", + "similarity": 1, + "distance_m": 26 + } + }, + { + "poi_name": "Ira Road Trailhead", + "osm_id": "way1084532348", + "opening_hours": null, + "wheelchair": null, + "fee": "no", + "match": { + "osm_name": "Ira Trailhead", + "similarity": 0.85, + "distance_m": 5 + } + }, + { + "poi_name": "Purplebrown Farm Store", + "osm_id": "way662435089", + "opening_hours": "Tu-Su 09:00-19:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Purplebrown Farm Store", + "similarity": 1, + "distance_m": 5 + } + }, + { + "poi_name": "Sand Run Metro Park - Big Bend Area", + "osm_id": "way466833017", + "opening_hours": null, + "wheelchair": null, + "fee": "no", + "match": { + "osm_name": "Big Bend Trailhead Parking", + "similarity": 0.85, + "distance_m": 9 + } + }, + { + "poi_name": "Sand Run Metro Park - Revere Road Lot", + "osm_id": "way636715645", + "opening_hours": null, + "wheelchair": null, + "fee": "no", + "match": { + "osm_name": "Sand Run Metro Park Revere Road Lot", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Sand Run Metro Park - Treaty Line Area", + "osm_id": "node5972884372", + "opening_hours": "Mo-Su 06:00-21:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Treaty Line Area", + "similarity": 0.85, + "distance_m": 63 + } + }, + { + "poi_name": "West Creek Reservation", + "osm_id": "relation11228395", + "opening_hours": "06:00-23:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "West Creek Reservation", + "similarity": 1, + "distance_m": 1569 + } + }, + { + "poi_name": "West Creek Reservation", + "osm_id": "relation11228395", + "opening_hours": "06:00-23:00", + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "West Creek Reservation", + "similarity": 1, + "distance_m": 274 + } + }, + { + "poi_name": "303 & 8 Trailhead", + "osm_id": "way168918107", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "303 and 8 Trailhead", + "similarity": 1, + "distance_m": 8 + } + }, + { + "poi_name": "Akron Hebrew Cemetery", + "osm_id": "way470097973", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Akron Hebrew Cemetery", + "similarity": 1, + "distance_m": 20 + } + }, + { + "poi_name": "Alder Trail", + "osm_id": "way469653061", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Alder Pond", + "similarity": 0.85, + "distance_m": 161 + } + }, + { + "poi_name": "Averill Pond Connector Trail", + "osm_id": "way180853643", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Averill Pond", + "similarity": 0.85, + "distance_m": 60 + } + }, + { + "poi_name": "Bath Road Heronry", + "osm_id": "way1285790680", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Bath Road Heronry", + "similarity": 1, + "distance_m": 80 + } + }, + { + "poi_name": "Beaver Marsh", + "osm_id": "relation15433480", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Beaver Marsh", + "similarity": 1, + "distance_m": 94 + } + }, + { + "poi_name": "Bedford", + "osm_id": "relation182107", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Bedford", + "similarity": 1, + "distance_m": 110 + } + }, + { + "poi_name": "Bedford Reservation", + "osm_id": "relation15722681", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Bedford Reservation", + "similarity": 1, + "distance_m": 1710 + } + }, + { + "poi_name": "Bedford Reserve Mountain Bike Trailhead", + "osm_id": "relation182107", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Bedford", + "similarity": 0.85, + "distance_m": 677 + } + }, + { + "poi_name": "Blimp City Bike and Hike", + "osm_id": "way566171130", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Blimp City Bike & Hike", + "similarity": 1, + "distance_m": 10 + } + }, + { + "poi_name": "Blossom Music Center", + "osm_id": "way86578574", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Blossom Music Center", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Blue Hen Falls", + "osm_id": "node3639490710", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Blue Hen Falls Trailhead", + "similarity": 1, + "distance_m": 224 + } + }, + { + "poi_name": "Blue Hen Falls Spur", + "osm_id": "node3639490710", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Blue Hen Falls Trailhead", + "similarity": 0.85, + "distance_m": 515 + } + }, + { + "poi_name": "Boston Cemetery", + "osm_id": "way180853636", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Boston Cemetery", + "similarity": 1, + "distance_m": 10 + } + }, + { + "poi_name": "Boston Mill Pedestrian Bridge", + "osm_id": "way609638968", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Boston Trailhead", + "similarity": 0.85, + "distance_m": 76 + } + }, + { + "poi_name": "Boston Mill Ski Resort", + "osm_id": "way609638968", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Boston Trailhead", + "similarity": 0.85, + "distance_m": 508 + } + }, + { + "poi_name": "Boston Run Trail", + "osm_id": "node2916044185", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Boston Run Trailhead", + "similarity": 1, + "distance_m": 407 + } + }, + { + "poi_name": "Boston Ski Lodge", + "osm_id": "way609638968", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Boston Trailhead", + "similarity": 0.85, + "distance_m": 521 + } + }, + { + "poi_name": "Brandywine Falls", + "osm_id": "node1913071012", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brandywine Falls", + "similarity": 1, + "distance_m": 35 + } + }, + { + "poi_name": "Brandywine Falls Trailhead", + "osm_id": "way609638965", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brandywine Falls Metro Park", + "similarity": 1, + "distance_m": 35 + } + }, + { + "poi_name": "Brandywine Inn", + "osm_id": "node660062313", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Inn at Brandywine Falls", + "similarity": 0.85, + "distance_m": 10 + } + }, + { + "poi_name": "Brandywine Ski Resort", + "osm_id": "way391698033", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brandywine Ski Resort", + "similarity": 1, + "distance_m": 266 + } + }, + { + "poi_name": "Brecksville", + "osm_id": "relation182134", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brecksville", + "similarity": 1, + "distance_m": 324 + } + }, + { + "poi_name": "Brecksville Reservation", + "osm_id": "relation182134", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brecksville", + "similarity": 1, + "distance_m": 929 + } + }, + { + "poi_name": "Bridal Veil Falls", + "osm_id": "node2519251489", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Bridal Veil Falls Overlook", + "similarity": 0.85, + "distance_m": 51 + } + }, + { + "poi_name": "Bridal Veil Falls Scenic Overlook", + "osm_id": "node2519251489", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Bridal Veil Falls Overlook", + "similarity": 0.85, + "distance_m": 5 + } + }, + { + "poi_name": "Brookside Reservation", + "osm_id": "relation3956352", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brookside Reservation", + "similarity": 1, + "distance_m": 85 + } + }, + { + "poi_name": "Brushwood Lake", + "osm_id": "way86971609", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brushwood Lake", + "similarity": 1, + "distance_m": 8 + } + }, + { + "poi_name": "Buckeye trail", + "osm_id": "node13130126777", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Buckeye Trail Snowville Trailhead", + "similarity": 0.85, + "distance_m": 237 + } + }, + { + "poi_name": "Buckeye Trail", + "osm_id": "node13130126777", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Buckeye Trail Snowville Trailhead", + "similarity": 0.85, + "distance_m": 237 + } + }, + { + "poi_name": "Camp Butler", + "osm_id": "way1230727949", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Camp Butler", + "similarity": 1, + "distance_m": 353 + } + }, + { + "poi_name": "Camp Ledgewood", + "osm_id": "node3642999941", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Camp Ledgewood", + "similarity": 1, + "distance_m": 290 + } + }, + { + "poi_name": "Canal Basin Park", + "osm_id": "way1266663439", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Canal Basin Park", + "similarity": 1, + "distance_m": 12 + } + }, + { + "poi_name": "Canal Basin Park", + "osm_id": "way1266663439", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Canal Basin Park", + "similarity": 1, + "distance_m": 15 + } + }, + { + "poi_name": "Canal Exploration Center", + "osm_id": "way609638976", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Canal Exploration Center", + "similarity": 1, + "distance_m": 75 + } + }, + { + "poi_name": "Cascade Park", + "osm_id": "way464364020", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cascade Park", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Cascade Park", + "osm_id": "way464364020", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cascade Park", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Cascade Valley - Kayak Access Point", + "osm_id": "relation14962727", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cascade Valley Metro Park", + "similarity": 0.85, + "distance_m": 676 + } + }, + { + "poi_name": "Cascade Valley Metro Park", + "osm_id": "relation14962727", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cascade Valley Metro Park", + "similarity": 1, + "distance_m": 202 + } + }, + { + "poi_name": "Cascade Valley Metro Park", + "osm_id": "node357450378", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cascade Valley Metro Park", + "similarity": 1, + "distance_m": 227 + } + }, + { + "poi_name": "Cedar Grove Cemetery Peninsula", + "osm_id": "way479776135", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cedar Grove Cemetery", + "similarity": 0.85, + "distance_m": 19 + } + }, + { + "poi_name": "Century Cycles", + "osm_id": "way180851215", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Century Cycles", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Cherry Lane / Fernwood / Nuthatch Trail", + "osm_id": "relation17745791", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Nuthatch Trail", + "similarity": 0.85, + "distance_m": 159 + } + }, + { + "poi_name": "Chippewa Creek", + "osm_id": "way1383438145", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Chippewa Creek Condominiums", + "similarity": 0.85, + "distance_m": 421 + } + }, + { + "poi_name": "Chippewa Creek Gorge Scenic Overlook", + "osm_id": "node2765824033", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Chippewa Creek Gorge Overlook", + "similarity": 0.85, + "distance_m": 4 + } + }, + { + "poi_name": "City of Akron", + "osm_id": "relation182644", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Akron", + "similarity": 0.85, + "distance_m": 375 + } + }, + { + "poi_name": "Clayton-Stanford Trail", + "osm_id": "node10688617635", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Stanford Trailhead", + "similarity": 0.85, + "distance_m": 287 + } + }, + { + "poi_name": "Cleveland Grain Silos", + "osm_id": "relation182130", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cleveland", + "similarity": 0.85, + "distance_m": 584 + } + }, + { + "poi_name": "Cleveland Harbor West Pierhead Lighthouse", + "osm_id": "way414659281", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "West Pierhead", + "similarity": 0.85, + "distance_m": 1 + } + }, + { + "poi_name": "Cleveland Rowing Foundation", + "osm_id": "relation182130", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cleveland", + "similarity": 0.85, + "distance_m": 770 + } + }, + { + "poi_name": "Cleveland-Cliffs Bike Park", + "osm_id": "way1292838498", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cleveland-Cliffs Bike Park", + "similarity": 1, + "distance_m": 7 + } + }, + { + "poi_name": "Confluence Metro Park", + "osm_id": "way1183430028", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Confluence Metro Park", + "similarity": 1, + "distance_m": 22 + } + }, + { + "poi_name": "Connector Trail - Stanford to Towpath", + "osm_id": "node10688617635", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Stanford Trailhead", + "similarity": 0.85, + "distance_m": 206 + } + }, + { + "poi_name": "Conrad Botzum Farmstead", + "osm_id": "way1298135284", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "The Conrad Botzum Farmstead", + "similarity": 1, + "distance_m": 122 + } + }, + { + "poi_name": "County Line Saloon", + "osm_id": "way1018560522", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "County Line Saloon", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Crooked River Skatepark", + "osm_id": "way593865571", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Crooked River Skatepark", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Cuyahoga Falls", + "osm_id": "way321927904", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cuyahoga Falls Community Gardens at Keyser Park", + "similarity": 0.85, + "distance_m": 738 + } + }, + { + "poi_name": "Cuyahoga Heights", + "osm_id": "relation182126", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cuyahoga Heights", + "similarity": 1, + "distance_m": 779 + } + }, + { + "poi_name": "Cuyahoga Valley Scenic Railroad - Akron Northside Station", + "osm_id": "relation182644", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Akron", + "similarity": 0.85, + "distance_m": 592 + } + }, + { + "poi_name": "Cuyahoga Valley Scenic Railroad - Boston Mill Station", + "osm_id": "way609638968", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Boston Trailhead", + "similarity": 0.85, + "distance_m": 160 + } + }, + { + "poi_name": "Cuyahoga Valley Scenic Railroad - Brecksville Station", + "osm_id": "way609638972", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brecksville Station Trailhead", + "similarity": 0.85, + "distance_m": 147 + } + }, + { + "poi_name": "Cuyahoga Valley Scenic Railroad - Canal Exploration Center Station", + "osm_id": "way609638976", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Canal Exploration Center", + "similarity": 0.85, + "distance_m": 206 + } + }, + { + "poi_name": "Cuyahoga Valley Scenic Railroad - Peninsula Depot", + "osm_id": "relation181945", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Peninsula", + "similarity": 0.85, + "distance_m": 744 + } + }, + { + "poi_name": "Deep Lock Quarry", + "osm_id": "node11322675878", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Deep Lock Quarry Trailhead", + "similarity": 1, + "distance_m": 27 + } + }, + { + "poi_name": "Deep Lock Quarry Metro Park", + "osm_id": "way1118934213", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Deep Lock Quarry Metro Park", + "similarity": 1, + "distance_m": 25 + } + }, + { + "poi_name": "Deer Lick Cave", + "osm_id": "node1511399783", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Deer Lick Cave", + "similarity": 1, + "distance_m": 1 + } + }, + { + "poi_name": "Dogwood Trail", + "osm_id": "node9921222793", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Dogwood Trailhead", + "similarity": 1, + "distance_m": 485 + } + }, + { + "poi_name": "Egbert Picnic Area", + "osm_id": "way962742744", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Egbert Picnic Area and Trailhead", + "similarity": 1, + "distance_m": 89 + } + }, + { + "poi_name": "Everett Covered Bridge", + "osm_id": "way860501491", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Everett Covered Bridge", + "similarity": 1, + "distance_m": 1 + } + }, + { + "poi_name": "Everett Trailhead", + "osm_id": "node10774357846", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Everett Trailhead", + "similarity": 1, + "distance_m": 27 + } + }, + { + "poi_name": "F.A. Seiberling Nature Realm", + "osm_id": "way321864947", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "F.A. Seiberling Nature Realm", + "similarity": 1, + "distance_m": 32 + } + }, + { + "poi_name": "F.A. Seiberling Nature Realm", + "osm_id": "way321864947", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "F.A. Seiberling Nature Realm", + "similarity": 1, + "distance_m": 196 + } + }, + { + "poi_name": "F.A. Seiberling Nature Realm - Suspension Bridge", + "osm_id": "way321864947", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "F.A. Seiberling Nature Realm", + "similarity": 0.85, + "distance_m": 239 + } + }, + { + "poi_name": "F.A. Seiberling Nature Realm - Visitors Center", + "osm_id": "way614291127", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Visitors Center", + "similarity": 0.85, + "distance_m": 3 + } + }, + { + "poi_name": "Fernwood / Nuthatch Trail", + "osm_id": "relation17745791", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Nuthatch Trail", + "similarity": 0.85, + "distance_m": 117 + } + }, + { + "poi_name": "Firestone Metro Park", + "osm_id": "way279928717", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Firestone Metro Park", + "similarity": 1, + "distance_m": 535 + } + }, + { + "poi_name": "Firestone Metro Park", + "osm_id": "way279928717", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Firestone Metro Park", + "similarity": 1, + "distance_m": 31 + } + }, + { + "poi_name": "Frazee House", + "osm_id": "way205548623", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Frazee House", + "similarity": 1, + "distance_m": 4 + } + }, + { + "poi_name": "Furnace Run Metro Park", + "osm_id": "relation1290126", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Furnace Run Metro Park", + "similarity": 1, + "distance_m": 193 + } + }, + { + "poi_name": "Gardiner Trail", + "osm_id": "relation13168285", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Gardiner Trail", + "similarity": 1, + "distance_m": 99 + } + }, + { + "poi_name": "Garfield Park Reservation", + "osm_id": "relation19838009", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Garfield Park Reservation All Purpose Trail Loop", + "similarity": 0.85, + "distance_m": 88 + } + }, + { + "poi_name": "Garfield Park Reservation", + "osm_id": "relation3956380", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Garfield Park Reservation", + "similarity": 1, + "distance_m": 831 + } + }, + { + "poi_name": "Gear Up Velo", + "osm_id": "node9164112996", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Gear Up Velo", + "similarity": 1, + "distance_m": 6 + } + }, + { + "poi_name": "Glendale Cemetery", + "osm_id": "way279063127", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Glendale Cemetery", + "similarity": 1, + "distance_m": 37 + } + }, + { + "poi_name": "Glens Trail", + "osm_id": "way1230898998", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "The Glens", + "similarity": 1, + "distance_m": 802 + } + }, + { + "poi_name": "Goodyear Heights Metro Park", + "osm_id": "way422736187", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Goodyear Heights Metro Park", + "similarity": 1, + "distance_m": 27 + } + }, + { + "poi_name": "Gorge Metro Park", + "osm_id": "node10766608816", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Gorge Trailhead", + "similarity": 1, + "distance_m": 11 + } + }, + { + "poi_name": "Gorge Metro Park", + "osm_id": "way324814067", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Gorge Metro Park", + "similarity": 1, + "distance_m": 78 + } + }, + { + "poi_name": "Gorge Metro Park Dam", + "osm_id": "way324814067", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Gorge Metro Park", + "similarity": 0.85, + "distance_m": 156 + } + }, + { + "poi_name": "Gorge Trail", + "osm_id": "way324814067", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Gorge Metro Park", + "similarity": 1, + "distance_m": 490 + } + }, + { + "poi_name": "Greater Cleveland Acquarium", + "osm_id": "relation182130", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cleveland", + "similarity": 0.85, + "distance_m": 195 + } + }, + { + "poi_name": "Greenfield Trail", + "osm_id": "relation13168287", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Greenfield Trail", + "similarity": 1, + "distance_m": 50 + } + }, + { + "poi_name": "Hampton Hills - Archery Range", + "osm_id": "way1390859113", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Hampton Hills Archery Range", + "similarity": 1, + "distance_m": 55 + } + }, + { + "poi_name": "Harbor Hopper", + "osm_id": "way1417965572", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Harbor Hopper", + "similarity": 1, + "distance_m": 197 + } + }, + { + "poi_name": "Haskell Run Trail", + "osm_id": "node10767319986", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Haskell Run Trailhead", + "similarity": 1, + "distance_m": 67 + } + }, + { + "poi_name": "Hemlock Trail", + "osm_id": "relation19472719", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Hemlock Trail", + "similarity": 1, + "distance_m": 183 + } + }, + { + "poi_name": "Heritage Farms", + "osm_id": "node6351185586", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Heritage Farms", + "similarity": 1, + "distance_m": 0 + } + }, + { + "poi_name": "Hinckley Reservation", + "osm_id": "relation15741865", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Hinckley Hills Carriage Trail", + "similarity": 0.85, + "distance_m": 273 + } + }, + { + "poi_name": "Historic Coast Guard Station", + "osm_id": "way605955898", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Cleveland Coast Guard Station", + "similarity": 0.6, + "distance_m": 11 + } + }, + { + "poi_name": "Historic Viaduct", + "osm_id": "node2519265077", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Viaduct Park", + "similarity": 0.85, + "distance_m": 32 + } + }, + { + "poi_name": "Horseshoe Pond", + "osm_id": "way51472307", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Horseshoe Pond", + "similarity": 1, + "distance_m": 42 + } + }, + { + "poi_name": "Ice Box Cave", + "osm_id": "node9927508286", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Ice Box Cave", + "similarity": 1, + "distance_m": 4 + } + }, + { + "poi_name": "Indigo Lake", + "osm_id": "way86576736", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Indigo Lake", + "similarity": 1, + "distance_m": 8 + } + }, + { + "poi_name": "Ira Cemetery", + "osm_id": "way479772329", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Ira Cemetery", + "similarity": 1, + "distance_m": 7 + } + }, + { + "poi_name": "Jaite Mill Historic District", + "osm_id": "node6080047867", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Jaite Mill Historic District", + "similarity": 1, + "distance_m": 21 + } + }, + { + "poi_name": "John Brown House", + "osm_id": "way608649476", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "John Brown House;John Brown Home", + "similarity": 0.85, + "distance_m": 2 + } + }, + { + "poi_name": "John Brown Monument", + "osm_id": "node9298296247", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "John Brown Monument", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Kendall Lake CVNP", + "osm_id": "way86578820", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Kendall Lake", + "similarity": 0.85, + "distance_m": 65 + } + }, + { + "poi_name": "Kendall Lake Trailhead", + "osm_id": "node10707734911", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Kendall Lake Trailhead", + "similarity": 1, + "distance_m": 50 + } + }, + { + "poi_name": "Kennedy Park", + "osm_id": "way321515915", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Kennedy Park", + "similarity": 1, + "distance_m": 168 + } + }, + { + "poi_name": "Lake Plata Trail", + "osm_id": "way155050947", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Lake Plata", + "similarity": 1, + "distance_m": 39 + } + }, + { + "poi_name": "Lake Trail", + "osm_id": "node10707734911", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Kendall Lake Trailhead", + "similarity": 0.85, + "distance_m": 133 + } + }, + { + "poi_name": "Ledges Overlook", + "osm_id": "node7795340162", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Ledges Overlook", + "similarity": 1, + "distance_m": 4 + } + }, + { + "poi_name": "Ledges Trail", + "osm_id": "node2851910913", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Ledges Shelter", + "similarity": 0.85, + "distance_m": 240 + } + }, + { + "poi_name": "Liberty Park", + "osm_id": "way553214856", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Liberty Park Recreation", + "similarity": 0.85, + "distance_m": 137 + } + }, + { + "poi_name": "Liberty Park Nature Center", + "osm_id": "way553210214", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Liberty Park Nature Area", + "similarity": 1, + "distance_m": 350 + } + }, + { + "poi_name": "Liberty Park Trailhead", + "osm_id": "way553210214", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Liberty Park Nature Area", + "similarity": 0.85, + "distance_m": 239 + } + }, + { + "poi_name": "Lock 29 Peninsula", + "osm_id": "node11480703208", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Lock 29 Trailhead", + "similarity": 0.85, + "distance_m": 14 + } + }, + { + "poi_name": "Lock 39 Trailhead", + "osm_id": "way609638979", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Lock 39 Trailhead", + "similarity": 1, + "distance_m": 29 + } + }, + { + "poi_name": "Mater Dolorosa Cemetery", + "osm_id": "way1292193618", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Mater Dolorosa Cemetery", + "similarity": 1, + "distance_m": 8 + } + }, + { + "poi_name": "Meadowedge Trail", + "osm_id": "way86576729", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Meadowedge Pond", + "similarity": 0.85, + "distance_m": 169 + } + }, + { + "poi_name": "Meadows Trailhead Brecksville", + "osm_id": "relation182134", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Brecksville", + "similarity": 0.85, + "distance_m": 112 + } + }, + { + "poi_name": "Mill Stream Run Reservation", + "osm_id": "relation3951437", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Mill Stream Run Reservation", + "similarity": 1, + "distance_m": 987 + } + }, + { + "poi_name": "Missing Link Trail", + "osm_id": "node9910493624", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Missing Link Vista", + "similarity": 0.85, + "distance_m": 371 + } + }, + { + "poi_name": "Monarch Trail", + "osm_id": "way691839410", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Monarch Bluff Picnic Area", + "similarity": 0.85, + "distance_m": 107 + } + }, + { + "poi_name": "Morgana Run Trail", + "osm_id": "relation15521543", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Morgana Run Trail", + "similarity": 1, + "distance_m": 1596 + } + }, + { + "poi_name": "Mother of Sorrows Church", + "osm_id": "way1232206063", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Mother of Sorrows Church", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Mount Peace Cemetery", + "osm_id": "way256658690", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Mount Peace Cemetery", + "similarity": 1, + "distance_m": 50 + } + }, + { + "poi_name": "Mud Brook Greenway Trail", + "osm_id": "way1190178505", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Mud Brook Greenway Trail Parking", + "similarity": 1, + "distance_m": 415 + } + }, + { + "poi_name": "Munroe Falls Metro Park", + "osm_id": "way324817710", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Munroe Falls Metro Park", + "similarity": 1, + "distance_m": 683 + } + }, + { + "poi_name": "Munroe Falls Metro Park", + "osm_id": "way324817710", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Munroe Falls Metro Park", + "similarity": 1, + "distance_m": 5 + } + }, + { + "poi_name": "Mustill Store", + "osm_id": "way952525242", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Mustill Store Museum", + "similarity": 0.85, + "distance_m": 2 + } + }, + { + "poi_name": "My Mountain Trail", + "osm_id": "node4057487060", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "My Mountain Overlook", + "similarity": 0.85, + "distance_m": 232 + } + }, + { + "poi_name": "Newburgh Heights", + "osm_id": "relation182109", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Newburgh Heights", + "similarity": 1, + "distance_m": 39 + } + }, + { + "poi_name": "Noisy Oyster", + "osm_id": "node8951968628", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Noisy Oyster", + "similarity": 1, + "distance_m": 9 + } + }, + { + "poi_name": "North Chagrin Reservation", + "osm_id": "relation15699685", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "North Chagrin Reservation", + "similarity": 1, + "distance_m": 301 + } + }, + { + "poi_name": "Northampton Point", + "osm_id": "node13037793076", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Northampton Point River Access", + "similarity": 0.85, + "distance_m": 13 + } + }, + { + "poi_name": "Nuthatch / Seneca Trail", + "osm_id": "relation17745800", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Seneca Trail", + "similarity": 0.85, + "distance_m": 149 + } + }, + { + "poi_name": "Nuthatch Trail", + "osm_id": "relation17745791", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Nuthatch Trail", + "similarity": 1, + "distance_m": 98 + } + }, + { + "poi_name": "Nuthatch Trail Connector", + "osm_id": "relation17745791", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Nuthatch Trail", + "similarity": 0.85, + "distance_m": 464 + } + }, + { + "poi_name": "O'Neil Woods Metro Park", + "osm_id": "way323043456", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "O'Neil Woods Metropark", + "similarity": 1, + "distance_m": 182 + } + }, + { + "poi_name": "O’Neil Woods Metro Park", + "osm_id": "node10278271626", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "O'Neil Woods Trailhead", + "similarity": 1, + "distance_m": 39 + } + }, + { + "poi_name": "Oak Hill Trail", + "osm_id": "node2878973583", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Oak Hill Trailhead", + "similarity": 1, + "distance_m": 337 + } + }, + { + "poi_name": "Oak Hill Trailhead CVNP", + "osm_id": "way466935819", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Oak Hill Trailhead", + "similarity": 0.85, + "distance_m": 3 + } + }, + { + "poi_name": "Octagon Shelter CVNP", + "osm_id": "way441858075", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Octagon Shelter", + "similarity": 0.85, + "distance_m": 10 + } + }, + { + "poi_name": "Ohio & Erie Canal Mountain Bike Trailhead", + "osm_id": "way1292840660", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Canal Trail", + "similarity": 0.85, + "distance_m": 174 + } + }, + { + "poi_name": "Ohio & Erie Canal Reservation", + "osm_id": "way1292840660", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Canal Trail", + "similarity": 0.85, + "distance_m": 572 + } + }, + { + "poi_name": "Ohio City Bike Co-op", + "osm_id": "node3625076530", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Ohio City Bicycle Co-op", + "similarity": 0.67, + "distance_m": 10 + } + }, + { + "poi_name": "Old Carriage Trail", + "osm_id": "relation19383010", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Old Carriage Trail", + "similarity": 1, + "distance_m": 133 + } + }, + { + "poi_name": "Overlook Trail", + "osm_id": "node2335435034", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Overlook Deck", + "similarity": 0.85, + "distance_m": 193 + } + }, + { + "poi_name": "Oxbow Trail", + "osm_id": "node9927720490", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Oxbow Trailhead", + "similarity": 1, + "distance_m": 69 + } + }, + { + "poi_name": "Parma Heights Resevoir", + "osm_id": "way1423628359", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Resevoir Park", + "similarity": 0.85, + "distance_m": 161 + } + }, + { + "poi_name": "Pedego Electric Bikes", + "osm_id": "node10082314402", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Pedego Electric Bikes", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Peninsula Art Academy", + "osm_id": "relation181945", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Peninsula", + "similarity": 0.85, + "distance_m": 749 + } + }, + { + "poi_name": "Peninsula Coffee House & Market", + "osm_id": "way662436847", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Peninsula Coffee House & Market", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Peninsula Police Department", + "osm_id": "relation181945", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Peninsula", + "similarity": 0.85, + "distance_m": 651 + } + }, + { + "poi_name": "Peninsula United Methodist Church", + "osm_id": "way479776847", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Peninsula United Methodist Church", + "similarity": 1, + "distance_m": 5 + } + }, + { + "poi_name": "Pine Hollow Trailhead", + "osm_id": "way406599913", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Pine Hollow", + "similarity": 1, + "distance_m": 19 + } + }, + { + "poi_name": "Portal West Coffee", + "osm_id": "node12716428801", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Portal West Coffee", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Porthouse Theater", + "osm_id": "way325043658", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Porthouse Theater", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Prairie Trail", + "osm_id": "node2931873368", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Tallgrass Prairie", + "similarity": 0.85, + "distance_m": 20 + } + }, + { + "poi_name": "Prather Trail", + "osm_id": "node12115369026", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Prather Vista", + "similarity": 0.85, + "distance_m": 177 + } + }, + { + "poi_name": "Quarry Trail", + "osm_id": "node5825988904", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Deep Lock Quarry", + "similarity": 0.85, + "distance_m": 92 + } + }, + { + "poi_name": "Reagan-Huffman Mountain Bike Trailhead", + "osm_id": "way465205150", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Reagan Park", + "similarity": 0.85, + "distance_m": 459 + } + }, + { + "poi_name": "Red Lock Trailhead", + "osm_id": "way609638969", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Red Lock Trailhead", + "similarity": 1, + "distance_m": 33 + } + }, + { + "poi_name": "River Light Gallery", + "osm_id": "way662436846", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "River Light Gallery", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Rivergate Park", + "osm_id": "way1011021052", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Rivergate Park", + "similarity": 1, + "distance_m": 51 + } + }, + { + "poi_name": "Rivergate Park", + "osm_id": "way1011021052", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Rivergate Park", + "similarity": 1, + "distance_m": 58 + } + }, + { + "poi_name": "Rocky River Reservation", + "osm_id": "way1001929248", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Rocky River", + "similarity": 1, + "distance_m": 406 + } + }, + { + "poi_name": "Salt Run Trail", + "osm_id": "relation12471680", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Salt Run Trail", + "similarity": 1, + "distance_m": 83 + } + }, + { + "poi_name": "Sand Run Metro Park", + "osm_id": "way323083638", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Sand Run Metro Park", + "similarity": 1, + "distance_m": 282 + } + }, + { + "poi_name": "Sand Run Metro Park - Lone Spruce Area", + "osm_id": "node11644577965", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Lone Spruce Area", + "similarity": 0.85, + "distance_m": 41 + } + }, + { + "poi_name": "Sand Run Metro Park - North Hawkins Area", + "osm_id": "node11644577968", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "North Hawkins Area", + "similarity": 0.85, + "distance_m": 82 + } + }, + { + "poi_name": "Sand Run Metro Park - Old Portage Area", + "osm_id": "node11644577964", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Old Portage Area", + "similarity": 0.85, + "distance_m": 12 + } + }, + { + "poi_name": "Sand Run Metro Park - Shadowfield Area", + "osm_id": "node11644577967", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Shadowfield Area", + "similarity": 0.85, + "distance_m": 28 + } + }, + { + "poi_name": "Sand Run Metro Park - Vehicle Ford", + "osm_id": "way323083638", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Sand Run Metro Park", + "similarity": 0.85, + "distance_m": 536 + } + }, + { + "poi_name": "Sand Run Metro Park - Wadsworth Area", + "osm_id": "node11644577966", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Wadsworth Area", + "similarity": 0.85, + "distance_m": 27 + } + }, + { + "poi_name": "Sarah’s Vineyard", + "osm_id": "way1227238488", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Sarah's Vineyard", + "similarity": 1, + "distance_m": 34 + } + }, + { + "poi_name": "Schneider Park", + "osm_id": "way633129749", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Schneider Park", + "similarity": 1, + "distance_m": 5 + } + }, + { + "poi_name": "Schneider Park", + "osm_id": "way633129749", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Schneider Park", + "similarity": 1, + "distance_m": 1 + } + }, + { + "poi_name": "Schumacher / Valley Link Trail", + "osm_id": "node12421845396", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Schumacher Trailhead", + "similarity": 0.85, + "distance_m": 357 + } + }, + { + "poi_name": "Schumacher Trail", + "osm_id": "node12421845396", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Schumacher Trailhead", + "similarity": 1, + "distance_m": 593 + } + }, + { + "poi_name": "Second Sole Akron", + "osm_id": "node8951968622", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Second Sole", + "similarity": 0.85, + "distance_m": 7 + } + }, + { + "poi_name": "Seneca Trail", + "osm_id": "relation17745800", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Seneca Trail", + "similarity": 1, + "distance_m": 68 + } + }, + { + "poi_name": "Silver Creek Metro Park", + "osm_id": "way279929012", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Silver Creek Metro Park", + "similarity": 1, + "distance_m": 200 + } + }, + { + "poi_name": "Silver Creek Metro Park", + "osm_id": "way279929012", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Silver Creek Metro Park", + "similarity": 1, + "distance_m": 419 + } + }, + { + "poi_name": "Skyline Trail", + "osm_id": "node11215871518", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Skyline Overlook", + "similarity": 0.85, + "distance_m": 119 + } + }, + { + "poi_name": "Springfield Bog Metro Park", + "osm_id": "way279927827", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Springfield Bog Metro Park", + "similarity": 1, + "distance_m": 134 + } + }, + { + "poi_name": "Squire’s Castle", + "osm_id": "way1079665168", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Squire's Castle Shelter", + "similarity": 0.85, + "distance_m": 291 + } + }, + { + "poi_name": "Stan Hywet", + "osm_id": "way470099376", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Stan Hywet Hall & Gardens", + "similarity": 0.85, + "distance_m": 121 + } + }, + { + "poi_name": "Stanford House", + "osm_id": "way481072417", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Stanford House", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Stanford Trail", + "osm_id": "node10688617635", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Stanford Trailhead", + "similarity": 1, + "distance_m": 552 + } + }, + { + "poi_name": "Station Bridle Path", + "osm_id": "relation19472679", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Station Bridle Path", + "similarity": 1, + "distance_m": 453 + } + }, + { + "poi_name": "Stumpy Basin", + "osm_id": "way180851250", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Stumpy Basin", + "similarity": 1, + "distance_m": 18 + } + }, + { + "poi_name": "Summit County", + "osm_id": "relation911310", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Summit County", + "similarity": 1, + "distance_m": 464 + } + }, + { + "poi_name": "Summit Lake NorthShore Park", + "osm_id": "node357450445", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Summit Lake Park", + "similarity": 0.85, + "distance_m": 105 + } + }, + { + "poi_name": "Summit Lake Park", + "osm_id": "way472101121", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Summit Lake Park", + "similarity": 1, + "distance_m": 9 + } + }, + { + "poi_name": "Szalay’s Farm", + "osm_id": "way305206960", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Szalay's", + "similarity": 0.85, + "distance_m": 1 + } + }, + { + "poi_name": "Tamarack Trail", + "osm_id": "way782261998", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Tamarack Bog", + "similarity": 0.85, + "distance_m": 90 + } + }, + { + "poi_name": "Terminal & Valley Depot", + "osm_id": "node11817333996", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Terminal", + "similarity": 0.85, + "distance_m": 223 + } + }, + { + "poi_name": "Terra Vista Natural Study Area", + "osm_id": "node7633727920", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Terra Vista Natural Study Area", + "similarity": 1, + "distance_m": 17 + } + }, + { + "poi_name": "The Merchant Tavern", + "osm_id": "way630824653", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "The Merchant", + "similarity": 0.85, + "distance_m": 4 + } + }, + { + "poi_name": "The Rabbit Hole Akron", + "osm_id": "node7223210190", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "The Rabbit Hole", + "similarity": 0.85, + "distance_m": 3 + } + }, + { + "poi_name": "Tinker's Creek Gorge Scenic Overlook", + "osm_id": "node2141917791", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Tinker's Creek Gorge Scenic Overlook", + "similarity": 1, + "distance_m": 4 + } + }, + { + "poi_name": "Top O' the World Connector", + "osm_id": "way1227237226", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Top o' the World", + "similarity": 0.85, + "distance_m": 83 + } + }, + { + "poi_name": "Towpath Tennis Center", + "osm_id": "way1456804958", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Towpath Tennis Center", + "similarity": 1, + "distance_m": 2 + } + }, + { + "poi_name": "Trail Mix Peninsula", + "osm_id": "way662435088", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Trail Mix Peninsula", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Turner Trail", + "osm_id": "relation13168286", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Turner Trail", + "similarity": 1, + "distance_m": 158 + } + }, + { + "poi_name": "Valley Overlook at Camp Mueller", + "osm_id": "way1232699874", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Valley Overlook at Camp Mueller", + "similarity": 1, + "distance_m": 236 + } + }, + { + "poi_name": "Valley View Woods", + "osm_id": "relation18057126", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Valley View Woods", + "similarity": 1, + "distance_m": 86 + } + }, + { + "poi_name": "Valley View Woods Park", + "osm_id": "relation18057126", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Valley View Woods", + "similarity": 1, + "distance_m": 153 + } + }, + { + "poi_name": "Vertical Runner - Brecksville", + "osm_id": "way609351918", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Vertical Runner", + "similarity": 0.85, + "distance_m": 12 + } + }, + { + "poi_name": "Viaduct Park", + "osm_id": "node2519265077", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Viaduct Park", + "similarity": 1, + "distance_m": 3 + } + }, + { + "poi_name": "Viaduct Park Loop Trail", + "osm_id": "node2519265077", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Viaduct Park", + "similarity": 0.85, + "distance_m": 139 + } + }, + { + "poi_name": "Village of Peninsula", + "osm_id": "relation181945", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Peninsula", + "similarity": 0.85, + "distance_m": 152 + } + }, + { + "poi_name": "Village of Valley View", + "osm_id": "relation182083", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Valley View", + "similarity": 0.85, + "distance_m": 647 + } + }, + { + "poi_name": "Virginia Kendall Park", + "osm_id": "node357468346", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Virginia Kendall Park", + "similarity": 1, + "distance_m": 174 + } + }, + { + "poi_name": "Walton Hills", + "osm_id": "relation182082", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Walton Hills", + "similarity": 1, + "distance_m": 335 + } + }, + { + "poi_name": "Washington Reservation", + "osm_id": "relation3956422", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Washington Reservation", + "similarity": 1, + "distance_m": 697 + } + }, + { + "poi_name": "Water Works Family Aquatic Center", + "osm_id": "way321563943", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Water Works Park", + "similarity": 0.85, + "distance_m": 76 + } + }, + { + "poi_name": "water works walking path", + "osm_id": "way321563943", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Water Works Park", + "similarity": 0.85, + "distance_m": 475 + } + }, + { + "poi_name": "Wendy Park Cleveland Metroparks", + "osm_id": "way95024460", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Wendy Park", + "similarity": 0.85, + "distance_m": 47 + } + }, + { + "poi_name": "Wetmore Trail", + "osm_id": "node10025833140", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Wetmore Trailhead", + "similarity": 1, + "distance_m": 910 + } + }, + { + "poi_name": "Wetmore Trailhead", + "osm_id": "way437233918", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Wetmore Trailhead", + "similarity": 1, + "distance_m": 19 + } + }, + { + "poi_name": "Whipp's Ledges Loop Trail", + "osm_id": "relation19449933", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Whipp's Ledges Parking", + "similarity": 0.85, + "distance_m": 269 + } + }, + { + "poi_name": "White Oak Trail", + "osm_id": "relation19474655", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "White Oak Trail", + "similarity": 1, + "distance_m": 21 + } + }, + { + "poi_name": "Wildflower Loop Trail", + "osm_id": "relation19472720", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Wildflower Loop Trail", + "similarity": 1, + "distance_m": 58 + } + }, + { + "poi_name": "Wildlife Woods Trail", + "osm_id": "way1232467402", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Wildlife Woods Park", + "similarity": 1, + "distance_m": 200 + } + }, + { + "poi_name": "Wilson’s Feed Mill", + "osm_id": "way609638974", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Wilson Feed Mill", + "similarity": 0.85, + "distance_m": 5 + } + }, + { + "poi_name": "Winking Lizard Tavern", + "osm_id": "way662435087", + "opening_hours": null, + "wheelchair": null, + "fee": null, + "match": { + "osm_name": "Winking Lizard", + "similarity": 0.85, + "distance_m": 3 + } + } +] diff --git a/backend/migrations/067_osm_visitor_info.sql b/backend/migrations/067_osm_visitor_info.sql new file mode 100644 index 00000000..5c5273c6 --- /dev/null +++ b/backend/migrations/067_osm_visitor_info.sql @@ -0,0 +1,22 @@ +-- Migration 067: OSM-sourced visitor info fields (#7) +-- Adds operating hours, wheelchair accessibility, and fee to POIs. Column names +-- mirror the OpenStreetMap tag keys (opening_hours, wheelchair, fee) so the +-- provenance is obvious; the OSM amenity import populates them, and admins can +-- edit them on any POI. All optional — rows hide in the UI when unset. + +BEGIN; + +ALTER TABLE pois ADD COLUMN IF NOT EXISTS opening_hours TEXT; -- raw OSM opening_hours string, shown verbatim +ALTER TABLE pois ADD COLUMN IF NOT EXISTS wheelchair VARCHAR(12); -- yes | limited | no | designated +ALTER TABLE pois ADD COLUMN IF NOT EXISTS fee VARCHAR(12); -- yes | no | conditional + +-- Drop-before-add so the CHECK constraints re-apply cleanly on every deploy. +ALTER TABLE pois DROP CONSTRAINT IF EXISTS pois_wheelchair_check; +ALTER TABLE pois ADD CONSTRAINT pois_wheelchair_check + CHECK (wheelchair IS NULL OR wheelchair IN ('yes','limited','no','designated')); + +ALTER TABLE pois DROP CONSTRAINT IF EXISTS pois_fee_check; +ALTER TABLE pois ADD CONSTRAINT pois_fee_check + CHECK (fee IS NULL OR fee IN ('yes','no','conditional')); + +COMMIT; diff --git a/backend/migrations/apply-osm-matches.js b/backend/migrations/apply-osm-matches.js new file mode 100644 index 00000000..be4d337d --- /dev/null +++ b/backend/migrations/apply-osm-matches.js @@ -0,0 +1,86 @@ +/** + * Apply the curated-POI -> OpenStreetMap match snapshot (#7). + * + * Reads backend/data/osm/poi-osm-matches.json (produced by generate-osm-matches.js) + * and, for each matched POI, records the OSM id for provenance/future enrichment + * and fills opening_hours / wheelchair / fee where OSM has them. + * + * Idempotent and non-destructive: + * - Visitor-info fields use COALESCE, so an admin-entered (or prior) value is + * never overwritten by OSM, and a re-run is a no-op. + * - osm_id is set on one row per matched name, only when that row has no osm_id + * yet AND the id is not already claimed (the column is uniquely indexed). A + * name shared by two POIs (e.g. a park's point and boundary) enriches both + * rows but assigns the osm_id to just one. + * + * Run after the SQL migrations and after import-osm-amenities.js: + * + * node backend/migrations/apply-osm-matches.js # local + * node /app/migrations/apply-osm-matches.js # in container + * + * Refresh the snapshot with generate-osm-matches.js (see its header). + */ + +import { readFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; +import pkg from 'pg'; +const { Pool } = pkg; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const pool = new Pool({ + host: process.env.PGHOST || 'localhost', + port: parseInt(process.env.PGPORT || '5432'), + database: process.env.PGDATABASE || 'rotv', + user: process.env.PGUSER || 'postgres', + password: process.env.PGPASSWORD +}); + +const matches = JSON.parse( + readFileSync(join(__dirname, '..', 'data', 'osm', 'poi-osm-matches.json'), 'utf-8') +); + +console.log(`Applying ${matches.length} OSM matches...\n`); + +let linked = 0; // rows that gained an osm_id +let enriched = 0; // rows that gained at least one visitor-info value +let missing = 0; // matched names with no POI in this database + +for (const m of matches) { + try { + // Fill visitor-info on every row with this name; COALESCE preserves existing + // values (admin edits, prior runs). more_info_link is intentionally left + // alone so curated official links survive. + const fill = await pool.query( + `UPDATE pois SET + opening_hours = COALESCE(opening_hours, $2), + wheelchair = COALESCE(wheelchair, $3), + fee = COALESCE(fee, $4), + updated_at = CURRENT_TIMESTAMP + WHERE name = $1 AND deleted IS NOT TRUE`, + [m.poi_name, m.opening_hours, m.wheelchair, m.fee] + ); + if (fill.rowCount === 0) { missing++; continue; } + if (m.opening_hours || m.wheelchair || m.fee) enriched += fill.rowCount; + + // Claim the osm_id on a single still-unlinked row, only if no other POI + // already holds it (the column is uniquely indexed). + const link = await pool.query( + `UPDATE pois SET osm_id = $2, updated_at = CURRENT_TIMESTAMP + WHERE id = ( + SELECT id FROM pois + WHERE name = $1 AND osm_id IS NULL AND deleted IS NOT TRUE + ORDER BY id LIMIT 1 + ) + AND NOT EXISTS (SELECT 1 FROM pois WHERE osm_id = $2)`, + [m.poi_name, m.osm_id] + ); + linked += link.rowCount; + } catch (err) { + console.error(` ERROR ${m.poi_name} (${m.osm_id}) — ${err.message}`); + } +} + +console.log(`\nDone. linked=${linked} enriched_rows=${enriched} missing=${missing}`); +await pool.end(); diff --git a/backend/migrations/generate-osm-matches.js b/backend/migrations/generate-osm-matches.js new file mode 100644 index 00000000..05979715 --- /dev/null +++ b/backend/migrations/generate-osm-matches.js @@ -0,0 +1,178 @@ +/** + * Generate the curated-POI -> OpenStreetMap match snapshot (#7). + * + * Matches ROTV's hand-curated POIs (parks, trails, visitor centers, businesses) + * to OpenStreetMap features by name similarity + proximity, then records the + * OSM id and any visitor-info tags (opening_hours / wheelchair / fee). The + * result is written to backend/data/osm/poi-osm-matches.json, which is committed + * and reviewable, and consumed by apply-osm-matches.js at deploy time. + * + * Companion to import-osm-amenities.js: that seeds amenity POIs *from* OSM; this + * enriches POIs that already exist *with* OSM data. + * + * Run locally (needs internet for Overpass). It reads the POI list from a JSON + * dump rather than the DB, so it has no pg dependency and stays reproducible: + * + * # 1. Dump curated POIs (point lat/lon, else geometry centroid) from the DB: + * podman exec psql -h localhost -U postgres -d rotv -tAc " + * SELECT json_agg(json_build_object('name',name,'lat',lat,'lon',lon)) FROM ( + * SELECT name, + * COALESCE(latitude::float, ST_Y(ST_PointOnSurface(ST_GeomFromGeoJSON(geometry)))) lat, + * COALESCE(longitude::float, ST_X(ST_PointOnSurface(ST_GeomFromGeoJSON(geometry)))) lon + * FROM pois WHERE deleted IS NOT TRUE AND osm_id IS NULL + * AND (latitude IS NOT NULL OR geometry IS NOT NULL) + * ) s WHERE lat IS NOT NULL;" > /tmp/curated-pois.json + * + * # 2. Generate the match snapshot: + * node backend/migrations/generate-osm-matches.js /tmp/curated-pois.json + * + * Matching is deliberately high-precision: name token similarity gates every + * match, and the allowed distance scales with name confidence (a park or trail's + * OSM centroid can sit a kilometre from the curated point). Proximity alone is + * never enough — that is how a shoe store would otherwise inherit a neighbouring + * cafe's hours. + */ + +import { readFileSync, writeFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const OUT = join(__dirname, '..', 'data', 'osm', 'poi-osm-matches.json'); +const UA = 'rotv-osm-match/1.0 (rootsofthevalley.org)'; +// CVNP region bbox (S,W,N,E). Clamped to the park region so the central-Ohio +// "Ohio" state-boundary POI does not pull half the state into the candidate set. +const BBOX = '41.00,-81.85,41.65,-81.10'; + +// Generic tokens that should not drive a match (every park has "park", etc.). +const STOP = new Set(['the', 'of', 'and', 'a', 'at', 'park', 'metropark', 'metro', + 'reservation', 'area', 'trail', 'trailhead', 'center', 'centre', 'national', + 'valley', 'cuyahoga', 'lot', 'parking']); + +function tokens(name) { + return new Set((name || '').toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim() + .split(' ').filter(token => token && !STOP.has(token))); +} + +function jaccard(nameA, nameB) { + const setA = tokens(nameA), setB = tokens(nameB); + if (!setA.size || !setB.size) return 0; + let shared = 0; + for (const token of setA) if (setB.has(token)) shared++; + return shared / (setA.size + setB.size - shared); +} + +// True when one name's significant tokens are a subset of the other's, e.g. +// "Boston Store" vs "Boston Store Visitor Center". +function isContained(nameA, nameB) { + const setA = tokens(nameA), setB = tokens(nameB); + if (!setA.size || !setB.size) return false; + const [smaller, larger] = setA.size <= setB.size ? [setA, setB] : [setB, setA]; + for (const token of smaller) if (!larger.has(token)) return false; + return true; +} + +function distanceMeters(lat1, lon1, lat2, lon2) { + const R = 6371000, rad = Math.PI / 180; + const dLat = (lat2 - lat1) * rad, dLon = (lon2 - lon1) * rad; + const h = Math.sin(dLat / 2) ** 2 + + Math.cos(lat1 * rad) * Math.cos(lat2 * rad) * Math.sin(dLon / 2) ** 2; + return 2 * R * Math.asin(Math.sqrt(h)); +} + +// Allowed match radius grows with name confidence: an exact name match can be a +// large park whose centroid is far from the curated point; a weak name match +// must be nearly on top of the POI to count. +function maxDistance(similarity) { + if (similarity >= 0.9) return 2000; + if (similarity >= 0.7) return 800; + if (similarity >= 0.55) return 300; + return 0; +} + +async function fetchCandidates() { + const keys = ['leisure', 'tourism', 'historic', 'natural', 'boundary', + 'route', 'shop', 'amenity', 'landuse']; + const parts = []; + for (const t of ['node', 'way', 'relation']) + for (const k of keys) parts.push(`${t}["name"]["${k}"](${BBOX});`); + const ql = `[out:json][timeout:180];(${parts.join('')});out tags center;`; + + const res = await fetch('https://overpass-api.de/api/interpreter', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': UA }, + body: 'data=' + encodeURIComponent(ql) + }); + if (!res.ok) throw new Error(`Overpass HTTP ${res.status}: ${(await res.text()).slice(0, 200)}`); + const overpassResult = await res.json(); + + const FEE = new Set(['yes', 'no', 'conditional']); + const WC = new Set(['yes', 'limited', 'no', 'designated']); + return overpassResult.elements.map(e => { + const wc = (e.tags.wheelchair || '').toLowerCase(); + const fee = (e.tags.fee || '').toLowerCase(); + return { + osm_id: `${e.type}${e.id}`, + name: e.tags.name, + lat: e.lat ?? e.center?.lat, + lon: e.lon ?? e.center?.lon, + opening_hours: e.tags.opening_hours || null, + wheelchair: WC.has(wc) ? wc : null, + fee: FEE.has(fee) ? fee : null + }; + }).filter(c => c.lat && c.lon && c.name); +} + +const poisPath = process.argv[2]; +if (!poisPath) { + console.error('Usage: node generate-osm-matches.js '); + process.exit(1); +} + +const pois = JSON.parse(readFileSync(poisPath, 'utf-8')); +console.log(`Loaded ${pois.length} curated POIs. Querying Overpass...`); +const candidates = await fetchCandidates(); +console.log(`Fetched ${candidates.length} named OSM features in region.\n`); + +const matches = []; +let enriched = 0; +for (const poi of pois) { + let best = null; + for (const c of candidates) { + const j = jaccard(poi.name, c.name); + const similarity = isContained(poi.name, c.name) ? Math.max(j, 0.85) : j; + const limit = maxDistance(similarity); + if (limit === 0) continue; + const d = distanceMeters(poi.lat, poi.lon, c.lat, c.lon); + if (d > limit) continue; + const score = similarity - d / 5000; + if (!best || score > best.score) best = { ...c, distance: d, similarity, score }; + } + if (!best) continue; + const hasTag = !!(best.opening_hours || best.wheelchair || best.fee); + if (hasTag) enriched++; + matches.push({ + poi_name: poi.name, + osm_id: best.osm_id, + opening_hours: best.opening_hours, + wheelchair: best.wheelchair, + fee: best.fee, + match: { + osm_name: best.name, + similarity: Number(best.similarity.toFixed(2)), + distance_m: Math.round(best.distance) + } + }); +} + +// Stable ordering (enriched first, then by name) keeps the committed file's +// diffs readable across regenerations. +matches.sort((a, b) => { + const at = (a.opening_hours || a.wheelchair || a.fee) ? 0 : 1; + const bt = (b.opening_hours || b.wheelchair || b.fee) ? 0 : 1; + return at - bt || a.poi_name.localeCompare(b.poi_name); +}); + +writeFileSync(OUT, JSON.stringify(matches, null, 2) + '\n'); +console.log(`Wrote ${matches.length} matches (${enriched} carry visitor-info tags) to`); +console.log(` ${OUT}`); diff --git a/backend/migrations/import-osm-amenities.js b/backend/migrations/import-osm-amenities.js index ba4b71d3..f99f4f00 100644 --- a/backend/migrations/import-osm-amenities.js +++ b/backend/migrations/import-osm-amenities.js @@ -13,8 +13,13 @@ * node backend/migrations/import-osm-amenities.js # local * node /app/migrations/import-osm-amenities.js # in container * - * Refresh the snapshot by re-querying Overpass for the two tags in the region - * bbox and re-filtering to boundary_type='park' polygons. + * Each feature also carries the OSM visitor-info tags opening_hours, wheelchair, + * and fee (null when untagged), written to the matching pois columns (#7). On + * re-import these refresh via COALESCE so a present value is never nulled out. + * + * Refresh the snapshot by re-querying Overpass for the two amenity tags in the + * region bbox (with `out tags;` to capture opening_hours/wheelchair/fee) and + * re-filtering to boundary_type='park' polygons. */ import { readFileSync } from 'fs'; @@ -81,21 +86,27 @@ for (const feature of snapshot) { `INSERT INTO pois ( name, poi_roles, latitude, longitude, geom, primary_activities, brief_description, collection_tier, - osm_id, more_info_link, has_primary_image, created_at, updated_at + osm_id, more_info_link, opening_hours, wheelchair, fee, + has_primary_image, created_at, updated_at ) VALUES ( $1, ARRAY['point']::text[], $2::double precision, $3::double precision, ST_SetSRID(ST_MakePoint($3::double precision, $2::double precision), 4326), $4, $5, 'monthly', - $6, $7, FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP + $6, $7, $8, $9, $10, + FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP ) ON CONFLICT (osm_id) WHERE osm_id IS NOT NULL DO UPDATE SET latitude = EXCLUDED.latitude, longitude = EXCLUDED.longitude, geom = EXCLUDED.geom, primary_activities = EXCLUDED.primary_activities, + opening_hours = COALESCE(EXCLUDED.opening_hours, pois.opening_hours), + wheelchair = COALESCE(EXCLUDED.wheelchair, pois.wheelchair), + fee = COALESCE(EXCLUDED.fee, pois.fee), updated_at = CURRENT_TIMESTAMP RETURNING (xmax = 0) AS is_insert`, // xmax = 0 means a fresh INSERT; non-zero = ON CONFLICT UPDATE - [name, feature.lat, feature.lon, meta.activity, description, feature.osm_id, moreInfoLink] + [name, feature.lat, feature.lon, meta.activity, description, feature.osm_id, moreInfoLink, + feature.opening_hours || null, feature.wheelchair || null, feature.fee || null] ); if (upsert.rows[0].is_insert) inserted++; else updated++; diff --git a/backend/routes/admin.js b/backend/routes/admin.js index 89116f5f..4a0be725 100644 --- a/backend/routes/admin.js +++ b/backend/routes/admin.js @@ -167,7 +167,7 @@ export function createAdminRouter(pool, invalidateMosaicCache) { 'name', 'poi_roles', 'latitude', 'longitude', 'geometry', 'geometry_drive_file_id', 'navigation_latitude', 'navigation_longitude', 'property_owner', 'owner_id', 'brief_description', 'era_id', 'historical_description', - 'primary_activities', 'surface', 'pets', 'cell_signal', 'more_info_link', + 'primary_activities', 'surface', 'pets', 'cell_signal', 'opening_hours', 'wheelchair', 'fee', 'more_info_link', 'events_url', 'news_url', 'research_context', 'length_miles', 'difficulty', 'boundary_type', 'boundary_color', 'collection_tier', 'news_score_threshold', 'events_score_threshold' @@ -225,7 +225,7 @@ export function createAdminRouter(pool, invalidateMosaicCache) { 'name', 'latitude', 'longitude', 'navigation_latitude', 'navigation_longitude', 'property_owner', 'owner_id', 'brief_description', 'era', 'era_id', 'historical_description', 'primary_activities', 'surface', - 'pets', 'cell_signal', 'more_info_link', 'events_url', 'news_url', 'research_context', 'status_url', + 'pets', 'cell_signal', 'opening_hours', 'wheelchair', 'fee', 'more_info_link', 'events_url', 'news_url', 'research_context', 'status_url', 'collection_tier', 'news_score_threshold', 'events_score_threshold' ]; const updates = {}; @@ -296,7 +296,7 @@ export function createAdminRouter(pool, invalidateMosaicCache) { const allowedFields = [ 'navigation_latitude', 'navigation_longitude', 'property_owner', 'owner_id', 'brief_description', 'era_id', 'historical_description', - 'primary_activities', 'surface', 'pets', 'cell_signal', 'more_info_link', + 'primary_activities', 'surface', 'pets', 'cell_signal', 'opening_hours', 'wheelchair', 'fee', 'more_info_link', 'events_url', 'news_url', 'status_url', 'collection_tier', 'news_score_threshold', 'events_score_threshold' ]; diff --git a/backend/server.js b/backend/server.js index 3f5d56be..c9224f32 100644 --- a/backend/server.js +++ b/backend/server.js @@ -321,6 +321,11 @@ async function initDatabase() { cell_signal INTEGER, more_info_link TEXT, + -- OSM-sourced visitor info (#7); see migration 067 for CHECK constraints + opening_hours TEXT, + wheelchair VARCHAR(12), + fee VARCHAR(12), + -- Trail-specific fields length_miles DECIMAL(6, 2), difficulty VARCHAR(50), @@ -902,6 +907,7 @@ app.get('/api/pois', async (req, res) => { p.owner_id, o.name as owner_name, p.property_owner, p.brief_description, p.era_id, e.name as era_name, p.historical_description, p.primary_activities, p.surface, p.pets, p.cell_signal, p.more_info_link, + p.opening_hours, p.wheelchair, p.fee, p.length_miles, p.difficulty, p.has_primary_image, p.boundary_type, p.boundary_color, p.news_url, p.events_url, p.collection_tier, p.deleted, p.created_at, p.updated_at @@ -938,6 +944,7 @@ app.get('/api/pois/:id', async (req, res) => { p.owner_id, o.name as owner_name, p.property_owner, p.brief_description, p.era_id, e.name as era_name, p.historical_description, p.primary_activities, p.surface, p.pets, p.cell_signal, p.more_info_link, + p.opening_hours, p.wheelchair, p.fee, p.length_miles, p.difficulty, p.has_primary_image, p.boundary_type, p.boundary_color, p.news_url, p.events_url, p.collection_tier, p.deleted, p.created_at, p.updated_at @@ -1714,6 +1721,7 @@ app.get('/api/destinations', async (req, res) => { p.owner_id, o.name as owner_name, p.property_owner, p.brief_description, p.era_id, e.name as era_name, p.historical_description, p.primary_activities, p.surface, p.pets, p.cell_signal, p.more_info_link, + p.opening_hours, p.wheelchair, p.fee, p.has_primary_image, p.news_url, p.events_url, p.research_context, p.status_url, p.collection_tier, p.deleted, p.created_at, p.updated_at FROM pois p @@ -1739,6 +1747,7 @@ app.get('/api/destinations/:id', async (req, res) => { p.owner_id, o.name as owner_name, p.property_owner, p.brief_description, p.era_id, e.name as era_name, p.historical_description, p.primary_activities, p.surface, p.pets, p.cell_signal, p.more_info_link, + p.opening_hours, p.wheelchair, p.fee, p.has_primary_image, p.news_url, p.events_url, p.research_context, p.status_url, p.collection_tier, p.deleted, p.created_at, p.updated_at FROM pois p @@ -1766,6 +1775,7 @@ app.get('/api/linear-features', async (req, res) => { p.owner_id, o.name as owner_name, p.property_owner, p.brief_description, p.era_id, e.name as era_name, p.historical_description, p.primary_activities, p.surface, p.pets, p.cell_signal, p.more_info_link, + p.opening_hours, p.wheelchair, p.fee, p.length_miles, p.difficulty, p.has_primary_image, p.boundary_type, p.boundary_color, p.news_url, p.events_url, p.status_url, p.is_seasonal, p.is_ada_accessible, p.is_bike_friendly, p.live_tracker_url, p.stops, @@ -1793,6 +1803,7 @@ app.get('/api/linear-features/:id', async (req, res) => { p.owner_id, o.name as owner_name, p.property_owner, p.brief_description, p.era_id, e.name as era_name, p.historical_description, p.primary_activities, p.surface, p.pets, p.cell_signal, p.more_info_link, + p.opening_hours, p.wheelchair, p.fee, p.length_miles, p.difficulty, p.has_primary_image, p.boundary_type, p.boundary_color, p.news_url, p.events_url, p.status_url, p.is_seasonal, p.is_ada_accessible, p.is_bike_friendly, p.live_tracker_url, p.stops, diff --git a/frontend/src/components/sidebar/EditView.jsx b/frontend/src/components/sidebar/EditView.jsx index d505f13f..654442dd 100644 --- a/frontend/src/components/sidebar/EditView.jsx +++ b/frontend/src/components/sidebar/EditView.jsx @@ -452,6 +452,44 @@ function EditView({ destination, editedData, setEditedData, onSave, onCancel, on /> + +
+ + handleChange('opening_hours', e.target.value || null)} + placeholder="e.g. Mo-Su 06:00-22:00" + /> +
+ +
+
+ + +
+
+ + +
+
)} diff --git a/frontend/src/components/sidebar/ReadOnlyView.jsx b/frontend/src/components/sidebar/ReadOnlyView.jsx index 502468e6..ccb83293 100644 --- a/frontend/src/components/sidebar/ReadOnlyView.jsx +++ b/frontend/src/components/sidebar/ReadOnlyView.jsx @@ -3,7 +3,7 @@ import NavigateButton from '../NavigateButton'; import AddToTripButton from '../AddToTripButton'; import FavoriteToggle from '../FavoriteToggle'; import CellSignal from './CellSignal'; -import { getNavigationStops, getOwnerClass, formatCoordinate } from './helpers'; +import { getNavigationStops, getOwnerClass, formatCoordinate, WHEELCHAIR_LABELS, FEE_LABELS, humanizeOpeningHours } from './helpers'; function ReadOnlyView({ destination, isLinearFeature, isAdmin, editMode, onShare, moreInfoLink, trailStatus = null, onCollectStatus, boatPosition }) { // Fix: only honor http(s) tracker URLs so a stored javascript: URL can't run on click (PR #405 review) @@ -151,6 +151,24 @@ function ReadOnlyView({ destination, isLinearFeature, isAdmin, editMode, onShare )} + {destination.opening_hours && ( +
+ + {humanizeOpeningHours(destination.opening_hours)} +
+ )} + {destination.wheelchair && ( +
+ + {WHEELCHAIR_LABELS[destination.wheelchair] || destination.wheelchair} +
+ )} + {destination.fee && ( +
+ + {FEE_LABELS[destination.fee] || destination.fee} +
+ )} diff --git a/frontend/src/components/sidebar/helpers.js b/frontend/src/components/sidebar/helpers.js index f6b52f9d..f0067f9e 100644 --- a/frontend/src/components/sidebar/helpers.js +++ b/frontend/src/components/sidebar/helpers.js @@ -46,6 +46,84 @@ export function formatCoordinate(value, type) { } } +/** + * OSM visitor-info display labels (#7). Stored values mirror the OSM tag values + * (wheelchair, fee); these map them to public-facing text. opening_hours is + * shown verbatim and needs no mapping. + */ +export const WHEELCHAIR_LABELS = { + yes: 'Accessible', + designated: 'Designated accessible', + limited: 'Limited', + no: 'Not accessible' +}; + +export const FEE_LABELS = { + yes: 'Yes', + no: 'No', + conditional: 'Varies' +}; + +const OH_DAYS = { Mo: 'Mon', Tu: 'Tue', We: 'Wed', Th: 'Thu', Fr: 'Fri', Sa: 'Sat', Su: 'Sun' }; +const OH_MONTHS = { Jan: 'Jan', Feb: 'Feb', Mar: 'Mar', Apr: 'Apr', May: 'May', Jun: 'Jun', Jul: 'Jul', Aug: 'Aug', Sep: 'Sep', Oct: 'Oct', Nov: 'Nov', Dec: 'Dec' }; +const OH_DAY = 'Mo|Tu|We|Th|Fr|Sa|Su'; +const OH_MON = 'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec'; + +/** + * Render an OpenStreetMap opening_hours string as friendly text, e.g. + * "Mo-Su 09:30-17:00" -> "Daily 9:30am–5pm". Covers the grammar that appears in + * CVNP-region OSM data (day/month ranges, multiple rules, bare times, 24/7). The + * opening_hours spec is far larger than this; any rule it can't parse cleanly + * (e.g. holiday exceptions like "Nov Th[4],Dec 25 off") makes it return the raw + * string unchanged, so the visitor always sees something accurate. + */ +export function humanizeOpeningHours(raw) { + if (!raw || typeof raw !== 'string') return raw || null; + const text = raw.trim(); + if (text === '24/7') return 'Open 24/7'; + + const fmtTime = (t) => { + const m = /^(\d{1,2}):(\d{2})$/.exec(t); + if (!m) return null; + const h = +m[1], min = m[2]; + if (h === 24 && min === '00') return 'midnight'; + const meridiem = h < 12 || h === 24 ? 'am' : 'pm'; + const h12 = h % 12 === 0 ? 12 : h % 12; + return min === '00' ? `${h12}${meridiem}` : `${h12}:${min}${meridiem}`; + }; + const fmtDays = (spec) => spec.split(',').map((part) => { + const [from, to] = part.split('-'); + return to ? `${OH_DAYS[from]}–${OH_DAYS[to]}` : OH_DAYS[from]; + }).join(', '); + const fmtMonths = (spec) => { + const [from, to] = spec.split('-'); + return to ? `${OH_MONTHS[from]}–${OH_MONTHS[to]}` : OH_MONTHS[from]; + }; + + const out = []; + for (let rule of text.split(';').map((s) => s.trim()).filter(Boolean)) { + let prefix = ''; + const mon = new RegExp(`^((?:${OH_MON})(?:-(?:${OH_MON}))?)\\s+(.*)$`).exec(rule); + if (mon) { prefix = `${fmtMonths(mon[1])}: `; rule = mon[2]; } + + const day = new RegExp(`^((?:${OH_DAY})(?:[-,](?:${OH_DAY}))*)\\s+(.*)$`).exec(rule); + let dayLabel = 'Daily', times = rule; + if (day) { dayLabel = day[1] === 'Mo-Su' ? 'Daily' : fmtDays(day[1]); times = day[2]; } + + if (/^(off|closed)$/i.test(times.trim())) { out.push(`${prefix}${dayLabel}: Closed`); continue; } + + const spans = []; + for (const span of times.split(',').map((s) => s.trim())) { + const m = /^(\d{1,2}:\d{2})-(\d{1,2}:\d{2})$/.exec(span); + const from = m && fmtTime(m[1]), to = m && fmtTime(m[2]); + if (!from || !to) return raw; // unparseable rule -> safe fallback to the raw OSM string + spans.push(`${from}–${to}`); + } + out.push(`${prefix}${dayLabel} ${spans.join(', ')}`); + } + return out.join(' · '); +} + export function generateSlug(name) { if (!name) return ''; return name.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, ''); diff --git a/gourmand-exceptions.toml b/gourmand-exceptions.toml index 0f8736c8..169ac96e 100644 --- a/gourmand-exceptions.toml +++ b/gourmand-exceptions.toml @@ -310,6 +310,13 @@ check = "single_use_helpers" path = "backend/services/newsService.js" justification = "Flagged helpers include several false positives — resetJobUsage, createNewsCollectionJob, processNewsCollectionJob, getAllPoisForCollection, getPoisForTierCollection are all exported and called from routes/admin.js, server.js, or mcpServer.js (gourmand only sees internal call sites). isNoiseLink is re-exported and used by tests/deterministicLinks.experiment.js. Remaining internals (classifyPage, itemCount, buildEventPrompt, buildNewsPrompt, normalizeNewsTitle) are discrete LLM-prompt-construction phases whose names document which Gemini call they prepare" +# Single-use helpers - OSM POI match generator (discrete matching pipeline stages) + +[[exceptions]] +check = "single_use_helpers" +path = "backend/migrations/generate-osm-matches.js" +justification = "Flagged jaccard, isContained, distanceMeters, maxDistance, fetchCandidates are discrete, individually-reasoned stages of the curated-POI->OSM matcher (#7). jaccard (token-set similarity) and isContained (subset name match) are the two name-similarity primitives; distanceMeters is a standard haversine; maxDistance encodes the name-confidence->allowed-radius policy that prevents proximity-only false matches (a shoe store inheriting a neighbouring cafe's hours); fetchCandidates isolates the Overpass HTTP/QL I/O from the pure matching loop. Inlining them would fuse network I/O, geodesy, string similarity, and match policy into one opaque loop — the same discrete-stage rationale accepted for trailStatusService and newsService" + # Single-use helpers - Test utilities (legitimate test setup/teardown) [[exceptions]]