this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

tweaks. my head figuratively hurts

alice 1fb58d4c f812dcb1

+161 -88
+1 -1
.gitignore
··· 1 1 build/ 2 2 .lock* 3 3 .clangd 4 - __pycache__ 4 + scripts/__pycache__/
+1
requirements.txt
··· 3 3 pandas 4 4 requests 5 5 pyarrow 6 + timezonefinder
+3 -1
run.sh
··· 43 43 install_project 44 44 ;; 45 45 debug) 46 - echo "Running debug (build and install)..." 46 + echo "Running debug (build, install, and tail logs)..." 47 47 build_project 48 48 install_project 49 + # Stream verbose emulator logs for live debugging 50 + rebble logs --emulator basalt -v 49 51 ;; 50 52 *) 51 53 echo "Usage: ./run.sh {generate|build|install|debug}"
+71 -28
scripts/generate_airport_tz_list.py
··· 26 26 from tz_common import find_dst_transitions as _find_dst_transitions 27 27 from bs4 import BeautifulSoup # type: ignore 28 28 import airportsdata 29 + from timezonefinder import TimezoneFinder 29 30 import pandas as pd 30 31 31 32 # --------------------------------------------------------------------------- ··· 117 118 """ 118 119 year = datetime.now(timezone.utc).year 119 120 airport_db = airportsdata.load("IATA") 121 + 120 122 # Ensure unique HTML airport entries by IATA code 121 123 seen_iatas: set[str] = set() 122 124 unique_airports: List[Tuple[str, str]] = [] ··· 130 132 if 'iata' in df_all.columns: 131 133 df_all = df_all.drop(columns=['iata']) 132 134 df_all = df_all.reset_index().rename(columns={'index': 'iata'}) 135 + # Recompute tz field from lat/lon to correct misclassified zones _before_ we 136 + # derive any offset‑related columns (important for DUT / America/Adak etc.) 137 + tf = TimezoneFinder() 138 + df_all['tz'] = df_all.apply( 139 + lambda row: tf.timezone_at(lat=row.get('lat'), lng=row.get('lon')) or row.get('tz'), 140 + axis=1, 141 + ) 142 + 133 143 # Merge OurAirports classification 134 144 try: 135 145 oa = pd.read_csv("https://ourairports.com/data/airports.csv", usecols=["iata_code","type","scheduled_service"]) # type: ignore ··· 143 153 traffic_dict = traffic_counts.to_dict() 144 154 # Map route hits using apply to ensure a Series 145 155 df_all['route_hits'] = df_all['iata'].apply(lambda x: traffic_dict.get(x, 0)).astype(int) 146 - # Compute standard offset seconds for each record 156 + # Compute standard offset seconds for each record (now that tz is fixed) 147 157 df_all['std_offset_s'] = df_all['tz'].apply(lambda tz: _find_dst_transitions(tz, year)[0]) 148 158 149 159 # Fallback selector for a given std_offset ··· 192 202 std_s, dst_s, start_ts, end_ts = _find_dst_transitions(tz_name, year) 193 203 key = (std_s, dst_s, start_ts, end_ts) 194 204 if key not in full_buckets: 195 - full_buckets[key] = { 'std': std_s, 'dst': dst_s, 'start': start_ts, 'end': end_ts } 205 + full_buckets[key] = { 206 + 'std': std_s, 207 + 'dst': dst_s, 208 + 'start': start_ts, 209 + 'end': end_ts, 210 + 'tz_names': [tz_name], 211 + } 196 212 group_keys.setdefault(std_s, []).append(key) 213 + else: 214 + full_buckets[key]['tz_names'].append(tz_name) 197 215 198 216 # 2) Collect codes from HTML for each std_offset (popular timezones) 199 217 group_codes: Dict[int, List[str]] = {} ··· 216 234 if not group_codes.get(std_s): 217 235 group_codes[std_s] = _fallback_codes(std_s) 218 236 219 - # 4) Assign popular codes to their actual DST buckets, then fallback for empty 237 + # 4) Assign popular & fallback codes to their actual DST buckets 220 238 # initialize codes list for each bucket 221 - for key, meta in full_buckets.items(): 239 + for bucket_key, meta in full_buckets.items(): 222 240 meta['codes'] = [] 223 - # populate HTML-based codes into their real tz variant buckets 241 + used_codes: set[str] = set() 242 + 243 + def _assign_to_bucket(iata_code: str): 244 + if iata_code in used_codes: 245 + return False 246 + rec = airport_db.get(iata_code) 247 + if rec and rec.get('tz'): 248 + std2, dst2, st2, ed2 = _find_dst_transitions(rec['tz'], year) 249 + key = (std2, dst2, st2, ed2) 250 + if key in full_buckets: 251 + full_buckets[key]['codes'].append(iata_code) 252 + used_codes.add(iata_code) 253 + return True 254 + return False 255 + 224 256 for std_s, codes in group_codes.items(): 225 257 for iata in codes: 226 - rec = airport_db.get(iata) 227 - if rec and rec.get('tz'): 228 - std2, dst2, st2, ed2 = _find_dst_transitions(rec['tz'], year) 229 - bucket_key = (std2, dst2, st2, ed2) 230 - if bucket_key in full_buckets: 231 - full_buckets[bucket_key]['codes'].append(iata) 258 + _assign_to_bucket(iata) 259 + 232 260 # fallback for buckets still empty: only populate the first empty bucket per std-offset 233 261 for std_s, keys in group_keys.items(): 234 - # track HTML-derived codes for this std-offset 235 262 assigned = set(group_codes.get(std_s, [])) 236 - # prepare a one-time fallback candidate list, filtered of already assigned 237 - fallback_candidates = [c for c in _fallback_codes(std_s) if c not in assigned] 238 - fallback_used = False 263 + fallback_candidates = [c for c in group_codes.get(std_s, []) if c not in used_codes] 264 + # track if we've used fallback for this std-offset 265 + used = False 239 266 for bucket_key in keys: 240 267 codes_list = full_buckets[bucket_key].get('codes', []) 241 - if not codes_list and not fallback_used and fallback_candidates: 242 - # assign up to max_bucket fallback codes to first empty bucket 243 - if max_bucket > 0: 244 - codes_list = fallback_candidates[:max_bucket] 268 + if not codes_list and not used: 269 + # pick first unassigned fallback candidates 270 + fallback_pool = [c for c in group_codes.get(std_s, []) if c not in used_codes] 271 + for candidate in fallback_pool: 272 + if _assign_to_bucket(candidate): 273 + codes_list = [candidate] 274 + break 245 275 else: 246 - codes_list = fallback_candidates[:] 247 - fallback_used = True 248 - # cap any list to max_bucket if needed 249 - if codes_list and max_bucket > 0: 250 - codes_list = codes_list[:max_bucket] 276 + codes_list = [] 277 + used = True 251 278 full_buckets[bucket_key]['codes'] = codes_list 252 - # record assigned codes so we don't reuse them (though fallback is one-shot) 253 - assigned.update(codes_list) 279 + 280 + # FINAL safety pass: if a bucket is still empty try to grab 1 airport that 281 + # actually sits in *this* timezone (e.g. DUT for America/Adak). This never 282 + # duplicates because we consult used_codes. 283 + for bucket_key, meta in full_buckets.items(): 284 + if meta['codes']: 285 + continue 286 + tz_names = meta.get('tz_names', []) 287 + if not tz_names: 288 + continue 289 + seg = df_all[df_all['tz'].isin(tz_names)].sort_values('route_hits', ascending=False) 290 + for code in seg['iata']: 291 + if _assign_to_bucket(code): 292 + meta['codes'] = [code] 293 + break 254 294 255 295 # build ordered bucket list 256 296 buckets_list = [ ··· 263 303 264 304 # 5) Build flat pool and offsets 265 305 code_pool = [] 306 + seen_for_pool: set[str] = set() 266 307 for b in buckets_list: 308 + unique_codes = [c for c in b.get('codes', []) if c not in seen_for_pool] 267 309 b['offset'] = len(code_pool) 268 - b['count'] = len(b.get('codes', [])) 269 - code_pool.extend(b.get('codes', [])) 310 + b['count'] = len(unique_codes) 311 + code_pool.extend(unique_codes) 312 + seen_for_pool.update(unique_codes) 270 313 271 314 # Build name pool parallel to code_pool 272 315 name_pool = []
+85 -58
src/c/airport_tz_list.c
··· 12 12 "MKK", 13 13 "JHM", 14 14 "LNY", 15 + "AKB", 15 16 "NHV", 17 + "GMR", 16 18 "ANC", 17 19 "LAX", 18 20 "SFO", ··· 41 43 "STL", 42 44 "BNA", 43 45 "AUS", 46 + "IPC", 47 + "CUN", 48 + "HAV", 44 49 "ATL", 45 50 "JFK", 46 51 "YYZ", ··· 71 76 "VCP", 72 77 "SDU", 73 78 "POA", 79 + "FEN", 80 + "FSP", 74 81 "GOH", 75 82 "SID", 76 83 "PDL", 77 84 "TER", 85 + "DKR", 78 86 "LHR", 79 87 "LGW", 80 88 "DUB", ··· 85 93 "EDI", 86 94 "LPA", 87 95 "BHX", 96 + "CMN", 97 + "ALG", 88 98 "CDG", 89 99 "AMS", 90 100 "FRA", ··· 98 108 "JNB", 99 109 "CPT", 100 110 "TLV", 111 + "BEY", 112 + "BZY", 101 113 "ATH", 102 114 "HEL", 103 115 "OTP", ··· 210 222 "HBA", 211 223 "LDH", 212 224 "VLI", 225 + "NLK", 213 226 "NAN", 214 227 "PKC", 215 228 "AKL", ··· 234 247 "Molokai", 235 248 "Kapalua", 236 249 "Lanai", 250 + "Atka", 237 251 "Nuku Hiva", 252 + "Totegegie", 238 253 "Ted Stevens Anchorage", 239 254 "Los Angeles", 240 255 "San Francisco", ··· 263 278 "St Louis Lambert", 264 279 "Nashville", 265 280 "Austin-Bergstrom", 281 + "Mataveri", 282 + "Cancun", 283 + "Jose Marti", 266 284 "Hartsfield - Jackson Atlanta", 267 285 "John F Kennedy", 268 286 "Toronto Pearson", ··· 293 311 "Viracopos", 294 312 "Santos Dumont", 295 313 "Salgado Filho", 314 + "Fernando de Noronha", 315 + "St Pierre", 296 316 "Godthaab / Nuuk", 297 317 "Amilcar Cabral", 298 318 "João Paulo II", 299 319 "Lajes Field", 320 + "Leopold Sedar Senghor", 300 321 "London Heathrow", 301 322 "London Gatwick", 302 323 "Dublin", ··· 307 328 "Edinburgh", 308 329 "Gran Canaria", 309 330 "Birmingham", 331 + "Mohammed V", 332 + "Houari Boumediene", 310 333 "Charles de Gaulle", 311 334 "Amsterdam Airport Schiphol", 312 335 "Frankfurt am Main", ··· 320 343 "O. R. Tambo", 321 344 "Cape Town", 322 345 "Ben Gurion", 346 + "Beirut Rafic Hariri", 347 + "Balti", 323 348 "Eleftherios Venizelos", 324 349 "Helsinki Vantaa", 325 350 "Henri Coanda", ··· 432 457 "Hobart", 433 458 "Lord Howe Island", 434 459 "Port Vila Bauerfield", 460 + "Norfolk Island", 435 461 "Nadi", 436 462 "Yelizovo", 437 463 "Auckland", ··· 459 485 static const TzInfo airport_tz_list[] = { 460 486 { -11.00f, -11.00f, 0LL, 0LL, 0, 1 }, 461 487 { -10.00f, -10.00f, 0LL, 0LL, 1, 7 }, 462 - { -10.00f, -9.00f, 1741489200LL, 1762048800LL, 8, 0 }, 463 - { -9.50f, -9.50f, 0LL, 0LL, 8, 1 }, 464 - { -9.00f, -9.00f, 0LL, 0LL, 9, 0 }, 465 - { -9.00f, -8.00f, 1741489200LL, 1762048800LL, 9, 1 }, 466 - { -8.00f, -7.00f, 1741489200LL, 1762048800LL, 10, 10 }, 467 - { -7.00f, -7.00f, 0LL, 0LL, 20, 1 }, 468 - { -7.00f, -6.00f, 1741489200LL, 1762048800LL, 21, 6 }, 469 - { -6.00f, -6.00f, 0LL, 0LL, 27, 1 }, 470 - { -6.00f, -5.00f, 1741489200LL, 1762048800LL, 28, 9 }, 471 - { -6.00f, -5.00f, 1757199600LL, 1743890400LL, 37, 0 }, 472 - { -5.00f, -5.00f, 0LL, 0LL, 37, 0 }, 473 - { -5.00f, -4.00f, 1741482000LL, 1762045200LL, 37, 0 }, 474 - { -5.00f, -4.00f, 1741489200LL, 1762048800LL, 37, 10 }, 475 - { -4.00f, -4.00f, 0LL, 0LL, 47, 7 }, 476 - { -4.00f, -3.00f, 1741489200LL, 1762048800LL, 54, 1 }, 477 - { -4.00f, -3.00f, 1757206800LL, 1743897600LL, 55, 1 }, 478 - { -3.50f, -2.50f, 1741489200LL, 1762048800LL, 56, 1 }, 479 - { -3.00f, -3.00f, 0LL, 0LL, 57, 10 }, 480 - { -3.00f, -2.00f, 1741489200LL, 1762048800LL, 67, 0 }, 481 - { -2.00f, -1.00f, 1743292800LL, 1761436800LL, 67, 1 }, 482 - { -1.00f, -1.00f, 0LL, 0LL, 68, 1 }, 483 - { -1.00f, 0.00f, 1743296400LL, 1761440400LL, 69, 2 }, 484 - { 0.00f, 0.00f, 0LL, 0LL, 71, 0 }, 485 - { 0.00f, 1.00f, 1743300000LL, 1761444000LL, 71, 10 }, 486 - { 0.00f, 1.00f, 1743908400LL, 1740279600LL, 81, 0 }, 487 - { 1.00f, 1.00f, 0LL, 0LL, 81, 0 }, 488 - { 1.00f, 2.00f, 1743303600LL, 1761447600LL, 81, 10 }, 489 - { 2.00f, 2.00f, 0LL, 0LL, 91, 2 }, 490 - { 2.00f, 3.00f, 1743130800LL, 1761444000LL, 93, 1 }, 491 - { 2.00f, 3.00f, 1743296400LL, 1761436800LL, 94, 0 }, 492 - { 2.00f, 3.00f, 1743303600LL, 1761447600LL, 94, 0 }, 493 - { 2.00f, 3.00f, 1743307200LL, 1761451200LL, 94, 6 }, 494 - { 2.00f, 3.00f, 1745542800LL, 1761868800LL, 100, 1 }, 495 - { 3.00f, 3.00f, 0LL, 0LL, 101, 10 }, 496 - { 3.50f, 3.50f, 0LL, 0LL, 111, 10 }, 497 - { 4.00f, 4.00f, 0LL, 0LL, 121, 10 }, 498 - { 4.50f, 4.50f, 0LL, 0LL, 131, 1 }, 499 - { 5.00f, 5.00f, 0LL, 0LL, 132, 10 }, 500 - { 5.50f, 5.50f, 0LL, 0LL, 142, 10 }, 501 - { 5.75f, 5.75f, 0LL, 0LL, 152, 1 }, 502 - { 6.00f, 6.00f, 0LL, 0LL, 153, 1 }, 503 - { 6.50f, 6.50f, 0LL, 0LL, 154, 2 }, 504 - { 7.00f, 7.00f, 0LL, 0LL, 156, 10 }, 505 - { 8.00f, 8.00f, 0LL, 0LL, 166, 10 }, 506 - { 8.75f, 8.75f, 0LL, 0LL, 176, 1 }, 507 - { 9.00f, 9.00f, 0LL, 0LL, 177, 10 }, 508 - { 9.50f, 9.50f, 0LL, 0LL, 187, 3 }, 509 - { 9.50f, 10.50f, 1759633200LL, 1743908400LL, 190, 4 }, 510 - { 10.00f, 10.00f, 0LL, 0LL, 194, 6 }, 511 - { 10.00f, 11.00f, 1759633200LL, 1743908400LL, 200, 4 }, 512 - { 10.50f, 11.00f, 1759633200LL, 1743904800LL, 204, 1 }, 513 - { 11.00f, 11.00f, 0LL, 0LL, 205, 1 }, 514 - { 11.00f, 12.00f, 1759633200LL, 1743908400LL, 206, 0 }, 515 - { 12.00f, 12.00f, 0LL, 0LL, 206, 2 }, 516 - { 12.00f, 13.00f, 1759028400LL, 1743908400LL, 208, 8 }, 517 - { 12.75f, 13.75f, 1759032000LL, 1743912000LL, 216, 1 }, 518 - { 13.00f, 13.00f, 0LL, 0LL, 217, 1 }, 519 - { 14.00f, 14.00f, 0LL, 0LL, 218, 1 }, 488 + { -10.00f, -9.00f, 1741489200LL, 1762048800LL, 8, 1 }, 489 + { -9.50f, -9.50f, 0LL, 0LL, 9, 1 }, 490 + { -9.00f, -9.00f, 0LL, 0LL, 10, 1 }, 491 + { -9.00f, -8.00f, 1741489200LL, 1762048800LL, 11, 1 }, 492 + { -8.00f, -7.00f, 1741489200LL, 1762048800LL, 12, 10 }, 493 + { -7.00f, -7.00f, 0LL, 0LL, 22, 1 }, 494 + { -7.00f, -6.00f, 1741489200LL, 1762048800LL, 23, 6 }, 495 + { -6.00f, -6.00f, 0LL, 0LL, 29, 1 }, 496 + { -6.00f, -5.00f, 1741489200LL, 1762048800LL, 30, 9 }, 497 + { -6.00f, -5.00f, 1757199600LL, 1743890400LL, 39, 1 }, 498 + { -5.00f, -5.00f, 0LL, 0LL, 40, 1 }, 499 + { -5.00f, -4.00f, 1741482000LL, 1762045200LL, 41, 1 }, 500 + { -5.00f, -4.00f, 1741489200LL, 1762048800LL, 42, 10 }, 501 + { -4.00f, -4.00f, 0LL, 0LL, 52, 7 }, 502 + { -4.00f, -3.00f, 1741489200LL, 1762048800LL, 59, 1 }, 503 + { -4.00f, -3.00f, 1757206800LL, 1743897600LL, 60, 1 }, 504 + { -3.50f, -2.50f, 1741489200LL, 1762048800LL, 61, 1 }, 505 + { -3.00f, -3.00f, 0LL, 0LL, 62, 11 }, 506 + { -3.00f, -2.00f, 1741489200LL, 1762048800LL, 73, 1 }, 507 + { -2.00f, -2.00f, 0LL, 0LL, 74, 0 }, 508 + { -2.00f, -1.00f, 1743292800LL, 1761436800LL, 74, 1 }, 509 + { -1.00f, -1.00f, 0LL, 0LL, 75, 1 }, 510 + { -1.00f, 0.00f, 1743296400LL, 1761440400LL, 76, 2 }, 511 + { 0.00f, 0.00f, 0LL, 0LL, 78, 1 }, 512 + { 0.00f, 1.00f, 1743300000LL, 1761444000LL, 79, 10 }, 513 + { 0.00f, 1.00f, 1743908400LL, 1740279600LL, 89, 1 }, 514 + { 1.00f, 1.00f, 0LL, 0LL, 90, 1 }, 515 + { 1.00f, 2.00f, 1743303600LL, 1761447600LL, 91, 10 }, 516 + { 2.00f, 2.00f, 0LL, 0LL, 101, 2 }, 517 + { 2.00f, 3.00f, 1743130800LL, 1761444000LL, 103, 1 }, 518 + { 2.00f, 3.00f, 1743296400LL, 1761436800LL, 104, 1 }, 519 + { 2.00f, 3.00f, 1743303600LL, 1761447600LL, 105, 1 }, 520 + { 2.00f, 3.00f, 1743307200LL, 1761451200LL, 106, 6 }, 521 + { 2.00f, 3.00f, 1745542800LL, 1761868800LL, 112, 1 }, 522 + { 3.00f, 3.00f, 0LL, 0LL, 113, 10 }, 523 + { 3.50f, 3.50f, 0LL, 0LL, 123, 10 }, 524 + { 4.00f, 4.00f, 0LL, 0LL, 133, 10 }, 525 + { 4.50f, 4.50f, 0LL, 0LL, 143, 1 }, 526 + { 5.00f, 5.00f, 0LL, 0LL, 144, 10 }, 527 + { 5.50f, 5.50f, 0LL, 0LL, 154, 10 }, 528 + { 5.75f, 5.75f, 0LL, 0LL, 164, 1 }, 529 + { 6.00f, 6.00f, 0LL, 0LL, 165, 1 }, 530 + { 6.50f, 6.50f, 0LL, 0LL, 166, 2 }, 531 + { 7.00f, 7.00f, 0LL, 0LL, 168, 10 }, 532 + { 8.00f, 8.00f, 0LL, 0LL, 178, 10 }, 533 + { 8.75f, 8.75f, 0LL, 0LL, 188, 1 }, 534 + { 9.00f, 9.00f, 0LL, 0LL, 189, 10 }, 535 + { 9.50f, 9.50f, 0LL, 0LL, 199, 3 }, 536 + { 9.50f, 10.50f, 1759633200LL, 1743908400LL, 202, 4 }, 537 + { 10.00f, 10.00f, 0LL, 0LL, 206, 6 }, 538 + { 10.00f, 11.00f, 1759633200LL, 1743908400LL, 212, 4 }, 539 + { 10.50f, 11.00f, 1759633200LL, 1743904800LL, 216, 1 }, 540 + { 11.00f, 11.00f, 0LL, 0LL, 217, 1 }, 541 + { 11.00f, 12.00f, 1759633200LL, 1743908400LL, 218, 1 }, 542 + { 12.00f, 12.00f, 0LL, 0LL, 219, 2 }, 543 + { 12.00f, 13.00f, 1759028400LL, 1743908400LL, 221, 8 }, 544 + { 12.75f, 13.75f, 1759032000LL, 1743912000LL, 229, 1 }, 545 + { 13.00f, 13.00f, 0LL, 0LL, 230, 1 }, 546 + { 14.00f, 14.00f, 0LL, 0LL, 231, 1 }, 520 547 }; 521 548 522 549 #define AIRPORT_TZ_LIST_COUNT (sizeof(airport_tz_list)/sizeof(airport_tz_list[0]))