Illinois: the Illinois Tollway (point tolls at the plazas of its own GIS layer, prices from its calculator feed; trucks checked against the 2026 truck sheet) and the Chicago Skyway (by axles, peak / off-peak). Central times written in Eastern.
itw_plaza_prices (calculator feed getPlazaPrices) and the year's truck sheet; the feed also serves next year's prices (itw_plaza_prices_next_year). Fetch the feed on b100 (curl) with the URLs in urls.txt.skyway_toll_information (b100 Chrome; geo1 lacks its certificate chain).bash chain.sh IL.
itw_toll_rates_page, b100 cfpage.mjs) for cars. County Line (plaza 300): trucks from the truck sheet, cars from the same page ('County Line Road (opening soon)'; the builder asserts its truck row equals the sheet). Seven I-355 truck cells differ by $0.05 between sheet and feed (sheet used).Hosts: geo1 (192.168.50.220) holds the sources, builders, drafts, map and API; b100 (192.168.50.14) is the test client. All times are Eastern.
| what | where (geo1 unless said) |
|---|---|
| sources list | /home/geo1/maps/toll/IL/urls.txt (name <tab> URL) |
| archived sources | /home/geo1/maps/toll/IL/sources/<name>/<YYYY-MM-DD>/ (file + meta.json: url, fetched, sha256) |
| builder | /home/geo1/system/handbuilt/il_state.py; shared code toll_common.py |
| OpenStreetMap inputs | /home/geo1/system/handbuilt/osm/il_* (cut from /home/geo1/maps/osm/us-latest.osm.pbf) |
| output | draft /srv/toll/draft/IL/ (the builders write here); published /srv/toll/IL/ (copied from the draft by promote.py publish). The map and the API read the published page, or the draft while it is listed for review |
| toll engine | source /home/geo1/maps/web/tolls.js, served copy /srv/maps/tolls.js (the API runs the served copy) |
| API | /home/geo1/maps/api/server.mjs on 127.0.0.1:8090 behind nginx /api/; pid in logs/test.pid |
| regression trips | b100: ~/apitest/site/cases.json, runner ~/apitest/run.py, browser check ~/apitest/browser.mjs |
python3 /home/geo1/system/handbuilt/fetch_list.py IL [name ...] (no names = every line of urls.txt). A new source: add a line to urls.txt first, then fetch it by name.node ~/apitest/fetch_b100.mjs <out> <name>=<url> ..., then rsync -a <out>/ geo1@192.168.50.220:/home/geo1/maps/toll/IL/sources/. Its meta.json records that it came from b100.diff, pdftotext -layout for PDFs). Same content: nothing to do. Changed amounts or a new effective date: rebuild (step 2) and update the expected amounts of the affected regression trips from the operator's own figures.python3 /home/geo1/maps/toll/bin/tollup.py IL update fetches the adapter's sources (bin/adapters/il.py), stores a document only when its content changes, writes one rate file per version under /home/geo1/maps/toll/IL/rates/ and appends every price change to history.csv (every run to runs.log). TOLL_WEB=/home/geo1/maps/toll/corpus python3 /home/geo1/maps/toll/bin/publish.py IL writes the corpus /home/geo1/maps/toll/corpus/IL from it (DE: plain publish.py DE writes /srv/toll/DE). Never hand-edit either. Then rebuild the draft (step 2) so it picks up the new rates.
cd /home/geo1/system/handbuilt && python3 il_state.pybash /home/geo1/system/handbuilt/chain.sh IL (logs in /tmp/il1.log ... il6.log; it prints the points, any point on no road and the untied count). The builders written since October 2026 share state_kit.py (sources, booths, terms, rows, write) and own_state.py (keeps a state's untied list to toll nodes inside the state, by the local geocoder; cache osm/node_state.json).cd /home/geo1/system/handbuilt; H=$(ls osm/il_highways_*.geojsonseq); J=$(ls osm/il_junctions_*.geojsonseq)
python3 il_state.py && python3 osm_streets.py IL $H $J && python3 il_state.py && python3 osm_snap.py IL && python3 toll_ways.py IL && python3 il_state.pytoll_ways.py's output: nodes claimed by two points: {} and points on no road: [] must both be empty.OSM way <id>) needs that way in osm/il_lane_ways.json (the builder writes it). A point on a road priced entry to exit needs gantry in its location name, or toll_ways.py treats it as a position-only exit marker.osm/ny_not_toll_nodes.json (congestion-zone gantries that are not tolls); every state's untied list leaves those out, so rebuild NJ and PA after NY.tolls.js when it starts. Restart it: cd /home/geo1/maps/api && kill $(cat logs/test.pid); (nohup /home/geo1/maps/node/bin/node server.mjs > logs/server.log 2>&1 & echo $! > logs/test.pid) (it is started by hand, not a service).python3 ~/apitest/run.py ~/apitest/site/cases.json. Every trip must be OK. Add a trip for every rate or rule you change, with the amount taken from the operator's own source.tolls.js): edit /home/geo1/maps/web/tolls.js, check with /home/geo1/maps/node/bin/node --check, copy to /srv/maps/tolls.js with sudo install -o www-data -g www-data -m 644, restart the API, run the trips.The builders match toll points to the OSM way ids the router drives, so the extracts here must come from the same us-latest.osm.pbf the router (Valhalla, /home/geo1/maps/valhalla_data) was built from (now 2026-09-27). New OSM data means: rebuild the router tiles, then for each state cut the box, rebuild its OSM inputs and run the full chain, then compare untied_toll_nodes.csv and the estimated positions below. The box for IL and the cutting commands are in the state's procedure above; the toll-node and way index comes from python3 tollnode_ways.py IL.
A rebuild writes the draft (/srv/toll/draft/IL); the published page (/srv/toll/IL) does not change. python3 /home/geo1/maps/toll/bin/promote.py review IL lists the draft for review: the map and the API then read it instead of the published page. Run the regression trips from b100. After approval, python3 /home/geo1/maps/toll/bin/promote.py publish IL copies the draft to /srv/toll/IL (the previous page is kept under /home/geo1/maps/toll/IL/published/<time>/) and takes it off the review list. After a change, update the coverage line for IL in the API page (/api.html, generator /home/geo1/maps/api/doc/api_page.py) and rebuild this page: python3 /home/geo1/system/handbuilt/maintain_pages.py IL.
Each fetch is kept in its own dated folder under /home/geo1/maps/toll/IL/sources/<name>/; the builder always reads the newest one, so a new fetch takes effect at the next rebuild and the old one stays for comparison.
| source | fetched (newest) | fetches kept | how | listed in urls.txt | rows using it |
|---|---|---|---|---|---|
itw_calculator_jshttps://agency.illinoistollway.com/o/com.accenture.beirao.tripcalculator/js/main.js | 2026-10-09 | 1 | fetched on b100 (192.168.50.14) | yes | |
itw_plaza_priceshttps://agency.illinoistollway.com/toll-calculator?p_p_id=com_accenture_jamaica_tripcalcul | 2026-10-09 | 1 | fetched on b100 (192.168.50.14) | yes | 2967 |
itw_plaza_prices_next_yearhttps://agency.illinoistollway.com/toll-calculator?p_p_id=com_accenture_jamaica_tripcalcul | 2026-10-09 | 1 | fetched on b100 (192.168.50.14) | yes | |
itw_plazas_layerhttps://gis.illinoisvirtualtollway.com/arcgis/rest/services/IVT/IllinoisVirtualTollway/Map | 2026-10-09 | 1 | fetched on b100 (192.168.50.14) | yes | |
itw_proposed_2027https://agency.illinoistollway.com/documents/d/guest/2026-06_proposedrates | 2026-10-10 | 1 | fetch_list.py | yes | |
itw_rates_by_plaza_2026https://agency.illinoistollway.com/documents/d/guest/2026tollrateincrease-multipage_1125 | 2026-10-10 | 1 | fetch_list.py | yes | 324 |
itw_toll_calculatorhttps://agency.illinoistollway.com/toll-calculator | 2026-10-09 | 1 | fetched on b100 (192.168.50.14) | yes | |
itw_toll_rateshttps://www.illinoistollway.com/toll-rates | 2026-10-10 | 1 | fetch_list.py | yes | |
itw_toll_rates_pagehttps://agency.illinoistollway.com/toll-rates | 2026-10-10 | 1 | b100 (192.168.50.14), headless Chrome, rendered page: the site refuses scripts (Cloudflare) | yes | 12 |
skyway_the_skywayhttps://www.chicagoskyway.org/the-skyway/ | 2026-10-09 | 1 | b100 (192.168.50.14), headless Chrome, rendered page: the site refuses scripts (Cloudflare) | yes | |
skyway_toll_informationhttps://www.chicagoskyway.org/toll-information/ | 2026-10-09 | 1 | b100 (192.168.50.14), headless Chrome, rendered page: the site refuses scripts (Cloudflare) | yes | 13 |
| id | facility | operator | points | rate / trip rows | effective dates in the rows | source |
|---|---|---|---|---|---|---|
IL-ITW-90 | Jane Addams Memorial Tollway (I-90) | Illinois State Toll Highway Authority (Illinois Tollway) | 48 | 1008 | 2026-01-01, 2026-10-09_observed | itw_plaza_prices |
IL-ITW-294 | Tri-State Tollway (I-294) | Illinois State Toll Highway Authority (Illinois Tollway) | 31 | 651 | 2026-01-01, 2026-10-09_observed | itw_plaza_prices |
IL-ITW-94 | Tri-State Tollway (I-94) | Illinois State Toll Highway Authority (Illinois Tollway) | 10 | 210 | 2026-01-01, 2026-10-09_observed | itw_plaza_prices |
IL-ITW-88 | Reagan Memorial Tollway (I-88) | Illinois State Toll Highway Authority (Illinois Tollway) | 30 | 630 | 2026-01-01, 2026-10-09_observed | itw_plaza_prices |
IL-ITW-355 | Veterans Memorial Tollway (I-355) | Illinois State Toll Highway Authority (Illinois Tollway) | 25 | 525 | 2026-01-01, 2026-10-09_observed | itw_plaza_prices |
IL-ITW-390 | Illinois Route 390 Tollway | Illinois State Toll Highway Authority (Illinois Tollway) | 13 | 273 | 2026-01-01, 2026-10-09_observed | itw_plaza_prices |
IL-SKYWAY | Chicago Skyway | Skyway Concession Company (City of Chicago concession) | 1 | 12 | 2026-10-09_observed | skyway_toll_information |
None: every position comes from an official layer or a mapped toll node.
R1: 156, R2a: 1, R2b: 1, direction: 2, listed: 1, no: 1, not: 4, penalty,: 1, row: 1, sheet: 1, tied: 1, told: 1 (all in decisions.csv).
None.
Toll booths / gantries mapped in OpenStreetMap on or near this state's roads that no toll point claims; a route through one lists it under unpriced. After an OSM refresh, look at new ones here (untied_toll_nodes.csv): a new gantry on a priced road means a point is missing.
Run from b100 (never on geo1): python3 ~/apitest/run.py ~/apitest/site/cases.json. Every trip must come back OK; a changed amount is either a rate change (update the expected amount from the operator's own source) or a fault.
| trip | expected |
|---|---|
| IL Chicago Skyway, cash car ($8.10) | $8.10 |
| IL Chicago Skyway, E-ZPass 5-axle truck Wed 10:30 ET (peak, $47.20) | $47.20 |
| IL Tollway I-90 Rockford -> Elgin, I-PASS (ezpass) car ($2.80, calculator feed) | $2.80 |
| IL Tollway I-88 Aurora -> I-294, Pay By Plate car ($3.00, calculator feed) | $3.00 |
| IL Tollway I-294 southbound through Irving Park (Plaza 33, SB only), I-PASS car ($0.75) | $0.75 |
| IL Tollway I-294 northbound past Irving Park: not charged ($0) | $0.00 |
| IL Tollway I-355 Army Trail -> I-55, I-PASS 5-axle overnight ($6.35 + $6.35) | $12.70 |
| IL I-90 eastbound off at Genoa Road (Plaza 3 EB Exit), I-PASS car | $0.55 |
| IL I-90 eastbound off at Illinois 47 (Plaza 6 EB Exit), I-PASS car | $1.95 |
| IL I-90 westbound on at Illinois 47 (Plaza 6 WB On), Pay By Plate car | $0.90 |