this repo has no description
0
fork

Configure Feed

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

cleanup etc.

alice 90eabf7a 98c42092

+462 -1323
+2
.cursor/rules/001.mdc
··· 4 4 alwaysApply: true 5 5 --- 6 6 Always ignore all errors related to the file "resource_ids.auto.h" 7 + 8 + Currently, src/pkjs/config.js sends string values ("0", "1") for settings, and watchface.c converts these from their ASCII values. This is a neccessary workaround
+47 -20
scripts/bun.lock
··· 5 5 "name": "tidface-scripts", 6 6 "dependencies": { 7 7 "@types/commander": "^2.12.5", 8 - "@vvo/tzdb": "^6.161.0", 9 8 "airport-data": "^1.0.1", 10 - "cheerio": "^1", 9 + "cheerio": "^1.0.0", 11 10 "commander": "^13.1.0", 12 - "csv-parse": "^5", 13 - "geo-tz": "^8", 14 - "luxon": "^3", 15 - "timezonecomplete": "^5.13.1", 11 + "csv-parse": "^5.6.0", 12 + "geo-tz": "^8.1.4", 13 + "luxon": "^3.6.1", 16 14 "tzdata": "^1.0.44", 17 15 }, 18 16 "devDependencies": { 19 - "@types/jest": "^29", 20 - "@types/luxon": "^3", 21 - "@types/node": "^22", 22 - "jest": "^29", 23 - "ts-jest": "^29", 24 - "ts-node": "^10", 25 - "typescript": "^5", 17 + "@types/cheerio": "^1.0.0", 18 + "@types/jest": "^29.5.14", 19 + "@types/luxon": "^3.6.2", 20 + "@types/node": "^22.15.14", 21 + "jest": "^29.7.0", 22 + "ts-jest": "^29.3.2", 23 + "ts-node": "^10.9.2", 24 + "typescript": "^5.8.3", 26 25 }, 27 26 }, 28 27 }, ··· 169 168 170 169 "@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="], 171 170 171 + "@types/cheerio": ["@types/cheerio@1.0.0", "", { "dependencies": { "cheerio": "*" } }, "sha512-zAaImHWoh5RY2CLgU2mvg3bl2k3F65B0N5yphuII3ythFLPmJhL7sj1RDu6gSxcgqHlETbr/lhA2OBY+WF1fXQ=="], 172 + 172 173 "@types/commander": ["@types/commander@2.12.5", "", { "dependencies": { "commander": "*" } }, "sha512-YXGZ/rz+s57VbzcvEV9fUoXeJlBt5HaKu5iUheiIWNsJs23bz6AnRuRiZBRVBLYyPnixNvVnuzM5pSaxr8Yp/g=="], 173 174 174 175 "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], ··· 185 186 186 187 "@types/luxon": ["@types/luxon@3.6.2", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="], 187 188 188 - "@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 189 + "@types/node": ["@types/node@22.15.14", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-BL1eyu/XWsFGTtDWOYULQEs4KR0qdtYfCxYAUYRoB7JP7h9ETYLgQTww6kH8Sj2C0pFGgrpM0XKv6/kbIzYJ1g=="], 189 190 190 191 "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], 191 192 192 193 "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], 193 194 194 195 "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], 195 - 196 - "@vvo/tzdb": ["@vvo/tzdb@6.161.0", "", {}, "sha512-rvk2x77vnY87Tu1d8QuJk300WWzk8OP9/cDw2KgxEdjlYpLarJx82j2sPUpiy1wnjSuTTnYwpjBgZnNS5Iyb+w=="], 197 196 198 197 "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], 199 198 ··· 643 642 644 643 "text-encoding": ["text-encoding@0.6.4", "", {}, "sha512-hJnc6Qg3dWoOMkqP53F0dzRIgtmsAge09kxUIqGrEUS4qr5rWLckGYaQAVr+opBrIMRErGgy6f5aPnyPpyGRfg=="], 645 644 646 - "timezonecomplete": ["timezonecomplete@5.13.1", "", { "dependencies": { "tzdata": "1.0.25" } }, "sha512-41o3TTExXQ03jQML12Tk64b5TYeEy968Umq5vya+08sFWCcYw5fNqrHubD1vj/JGN1NYhFFBCS09rOL3b7nM2w=="], 647 - 648 645 "tmpl": ["tmpl@1.0.5", "", {}, "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="], 649 646 650 647 "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], ··· 711 708 712 709 "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], 713 710 711 + "@jest/console/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 712 + 713 + "@jest/core/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 714 + 715 + "@jest/environment/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 716 + 717 + "@jest/fake-timers/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 718 + 719 + "@jest/reporters/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 720 + 721 + "@jest/types/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 722 + 723 + "@types/graceful-fs/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 724 + 714 725 "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], 715 726 716 727 "babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="], ··· 719 730 720 731 "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], 721 732 733 + "jest-circus/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 734 + 735 + "jest-environment-node/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 736 + 737 + "jest-haste-map/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 738 + 739 + "jest-mock/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 740 + 741 + "jest-runner/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 742 + 743 + "jest-runtime/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 744 + 745 + "jest-util/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 746 + 747 + "jest-watcher/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 748 + 749 + "jest-worker/@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], 750 + 722 751 "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], 723 752 724 753 "p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], ··· 726 755 "parse5/entities": ["entities@6.0.0", "", {}, "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw=="], 727 756 728 757 "shapefile/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], 729 - 730 - "timezonecomplete/tzdata": ["tzdata@1.0.25", "", {}, "sha512-yAZ/Tv/tBFIPHJGYrOexxW8Swyjszt7rDhIjnIPSqLaP8mzrr3T7D0w4cxQBtToXnQrlFqkEU0stGC/auz0JcQ=="], 731 758 732 759 "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 733 760
+1 -1
scripts/generateAirportTzList.test.ts
··· 101 101 expect(matches!.length).toBe(1); 102 102 }); 103 103 104 - // Ensure the Noronha timezone correction took place – should show up in bucket comment 104 + // Ensure the Noronha timezone correction took place - should show up in bucket comment 105 105 expect(content).toContain('America/Noronha'); 106 106 107 107 // Validate the macro count equals 3 (unique codes)
+10 -68
scripts/generateAirportTzList.ts
··· 1 - // TODO: Convert generate_airport_tz_list.py to TypeScript 2 - 3 1 import { program } from 'commander'; 4 2 import * as fs from 'fs/promises'; 5 3 import * as path from 'path'; 6 - import * as cheerio from 'cheerio'; 7 4 // Use require for airport-data as it lacks types 8 5 const airports = require('airport-data'); 9 - import { find as findTz } from 'geo-tz'; // Use geo-tz instead of timezonefinder 10 - // Remove node-fetch import, use global fetch 11 - import { parse } from 'csv-parse'; // Import csv-parse 12 - import { findDstTransitions, DstTransitions } from './tzCommon'; 6 + import { type DstTransitions } from './tzCommon'; // Only the type DstTransitions is used directly 13 7 import { 14 8 findTzCache, 15 9 memoizedFindTz, ··· 26 20 RouteRecord, 27 21 } from './generateAirportTzListHelpers'; 28 22 29 - // Local-only type used before helper split 30 - interface AirportDataEntry { 31 - iata?: string; 32 - name?: string; 33 - city?: string; 34 - country?: string; 35 - latitude?: number | string; 36 - longitude?: number | string; 37 - tz?: string; 38 - type?: string; 39 - source?: string; 40 - } 41 - 42 - // Define interfaces for data structures 43 - interface TzBucketKey { 44 - stdOffsetSeconds: number; 45 - dstOffsetSeconds: number; 46 - dstStartTimestamp: number; 47 - dstEndTimestamp: number; 48 - } 49 - 50 - // Helper function to create bucket keys 51 - // function getBucketKey(details: DstTransitions): string { 52 - // return `${details[0]}_${details[1]}_${details[2]}_${details[3]}`; 53 - // } 54 - 55 23 // Placeholder functions matching Python script structure 56 24 57 - // async function parseTopHtml(htmlPath: string): Promise<Array<[string, string]>> { 58 - // console.log(`Parsing HTML file: ${htmlPath}`); 59 - // const htmlContent = await fs.readFile(htmlPath, 'utf-8'); 60 - // const $ = cheerio.load(htmlContent); 61 - // const results: Array<[string, string]> = []; 62 - // $('tr').each((_, tr) => { 63 - // const tds = $(tr).find('td'); 64 - // if (tds.length < 3) return; 65 - // const iata = $(tds[2]).text().trim().toUpperCase(); 66 - // if (!iata || iata.length !== 3) return; // Basic validation 67 - // // Improve name extraction - handle potential h2 tags etc. 68 - // let name = $(tds[1]).find('h2').first().text().trim(); 69 - // if (!name) { 70 - // name = $(tds[1]).text().trim(); 71 - // } 72 - // // Clean up common suffixes (like in Python) 73 - // if (name.endsWith(' International Airport')) { 74 - // name = name.substring(0, name.length - ' International Airport'.length); 75 - // } else if (name.endsWith(' Airport')) { 76 - // name = name.substring(0, name.length - ' Airport'.length); 77 - // } 78 - // results.push([iata, name.trim()]); 79 - // }); 80 - // console.log(`Found ${results.length} airports in HTML.`); 81 - // return results; 82 - // } 83 - 84 25 async function generateCCode( 85 26 airportsList: Array<[string, string]>, 86 27 outPath: string, ··· 93 34 const year = new Date().getUTCFullYear(); 94 35 95 36 // Load airport data using require 96 - const airportDataArray: AirportDataEntry[] = airports as any[]; 37 + const airportDataArray = airports as any[]; 97 38 const initialAirportDb = new Map<string, AirportInfo>(); 98 39 99 40 for (const airport of airportDataArray) { ··· 276 217 277 218 // Tier 1: Large, scheduled 278 219 const large = candidates.filter(a => a.type === 'large_airport' && scheduledYes(a)); 279 - result.push(...large.slice(0, maxBucket > 0 ? maxBucket : 3).map(a => a.iata)); 220 + result.push(...large.slice(0, maxBucket > 0 ? maxBucket : 10).map(a => a.iata)); 280 221 281 222 // Tier 2: Medium, scheduled 282 - let remain = (maxBucket > 0 ? maxBucket : 3) - result.length; 223 + let remain = (maxBucket > 0 ? maxBucket : 5) - result.length; 283 224 if (remain > 0) { 284 225 const medium = candidates.filter(a => a.type === 'medium_airport' && scheduledYes(a) && !result.includes(a.iata)); 285 - result.push(...medium.slice(0, Math.min(remain, 2)).map(a => a.iata)); 226 + result.push(...medium.slice(0, Math.min(remain, 5)).map(a => a.iata)); 286 227 } 287 228 288 229 // Tier 3: Small, scheduled 289 230 remain = (maxBucket > 0 ? maxBucket : 3) - result.length; 290 231 if (remain > 0) { 291 232 const small = candidates.filter(a => a.type === 'small_airport' && scheduledYes(a) && !result.includes(a.iata)); 292 - result.push(...small.slice(0, 1).map(a => a.iata)); 233 + // console.log(`SMALL hit with ${small.length} candidates: ${small.map(a => a.iata).join(', ')}`); 234 + result.push(...small.slice(0, 3).map(a => a.iata)); 293 235 } 294 236 295 237 // Tier 4: Ensure at least one if possible ··· 297 239 result.push(candidates[0].iata); // Add the top-ranked overall 298 240 } 299 241 300 - // Enforce max bucket size strictly if needed (though applied later too) 242 + // Enforce max bucket size strictly if needed 243 + // (though applied later too) 301 244 return maxBucket > 0 ? result.slice(0, maxBucket) : result; 302 245 }; 303 246 ··· 456 399 457 400 // Airport Code Pool (bit-packed 15 bits/code) 458 401 cContent += `// Total airport codes: ${codePool.length} (codes listed for debug)\n`; 459 - cContent += `// Codes: ${codePool.join(', ')}\n`; 460 402 cContent += `static const uint16_t airport_code_pool_bits[] = {\n`; 461 403 for (const code of codePool) { 462 404 // pack each letter A-Z into 5 bits ··· 585 527 }; 586 528 587 529 // ------------------------------------------------------------ 588 - // CLI entry point – only run when invoked directly 530 + // CLI entry point - only run when invoked directly 589 531 // ------------------------------------------------------------ 590 532 if (require.main === module) { 591 533 main().catch(error => {
-164
scripts/generateTzList.test.ts
··· 1 - import os from 'os'; 2 - import path from 'path'; 3 - import fs from 'fs/promises'; 4 - import { DateTime } from 'luxon'; 5 - import { generateTzCCode } from './generateTzList'; 6 - import { findDstTransitions, DstTransitions } from './tzCommon'; // Import to get expected values 7 - 8 - jest.setTimeout(60000); // Keep generous timeout as it runs the full generation 9 - 10 - // Helper to parse the simple C array formats 11 - function parseCStringArray(cCode: string, arrayName: string): string[] { 12 - const startMarker = `static const char* ${arrayName}[] = {`; 13 - const endMarker = `};`; 14 - 15 - const startIndex = cCode.indexOf(startMarker); 16 - if (startIndex === -1) { 17 - console.error(`[TEST PARSE ERROR] Could not find start marker for C array: ${arrayName}`); 18 - return []; 19 - } 20 - 21 - const braceIndex = startIndex + startMarker.length; 22 - const endIndex = cCode.indexOf(endMarker, braceIndex); 23 - if (endIndex === -1) { 24 - console.error(`[TEST PARSE ERROR] Could not find end marker for C array: ${arrayName}`); 25 - return []; 26 - } 27 - 28 - const blockContent = cCode.slice(braceIndex, endIndex); 29 - const lines = blockContent.split('\n'); 30 - 31 - const results: string[] = []; 32 - lines.forEach((line, index) => { 33 - const trimmedLine = line.trim(); 34 - const lineMatch = trimmedLine.match(/^"(.*?)",?$/); 35 - if (lineMatch && lineMatch[1]) { 36 - results.push(lineMatch[1]); 37 - } 38 - }); 39 - return results; 40 - } 41 - 42 - interface ParsedTzInfo { 43 - stdHours: number; 44 - dstHours: number; 45 - startTs: number; 46 - endTs: number; 47 - nameOffset: number; 48 - nameCount: number; 49 - } 50 - 51 - function parseTzInfoArray(cCode: string): ParsedTzInfo[] { 52 - const startMarker = `static const TzInfo tz_list[] = {`; 53 - const endMarker = `};`; 54 - 55 - const startIndex = cCode.indexOf(startMarker); 56 - if (startIndex === -1) { 57 - console.error(`[TEST PARSE ERROR] Could not find start marker for TzInfo array`); 58 - return []; 59 - } 60 - 61 - const braceIndex = startIndex + startMarker.length; 62 - const endIndex = cCode.indexOf(endMarker, braceIndex); 63 - if (endIndex === -1) { 64 - console.error(`[TEST PARSE ERROR] Could not find end marker for TzInfo array`); 65 - return []; 66 - } 67 - 68 - const blockContent = cCode.slice(braceIndex, endIndex); 69 - const lines = blockContent.split('\n'); 70 - 71 - const result: ParsedTzInfo[] = []; 72 - const lineRegex = /\{\s*(-?\d+(?:\.\d+)?)f,\s*(-?\d+(?:\.\d+)?)f,\s*(\d+)LL,\s*(\d+)LL,\s*(\d+),\s*(\d+)\s*\},?/; // Allow integers or floats for offsets 73 - lines.forEach(line => { 74 - const lineMatch = line.trim().match(lineRegex); 75 - if (lineMatch) { 76 - result.push({ 77 - stdHours: parseFloat(lineMatch[1]), 78 - dstHours: parseFloat(lineMatch[2]), 79 - startTs: parseInt(lineMatch[3], 10), 80 - endTs: parseInt(lineMatch[4], 10), 81 - nameOffset: parseInt(lineMatch[5], 10), 82 - nameCount: parseInt(lineMatch[6], 10), 83 - }); 84 - } 85 - }); 86 - return result; 87 - } 88 - 89 - 90 - describe('generateTzList', () => { 91 - let generatedCCode: string; 92 - let namePool: string[]; 93 - let tzList: ParsedTzInfo[]; 94 - const currentYear = DateTime.utc().year; 95 - 96 - // Run generation once before all tests 97 - beforeAll(async () => { 98 - const out = path.join(os.tmpdir(), `tz_${Date.now()}.c`); 99 - await generateTzCCode(out); 100 - generatedCCode = await fs.readFile(out, 'utf-8'); 101 - namePool = parseCStringArray(generatedCCode, 'tz_name_pool'); 102 - tzList = parseTzInfoArray(generatedCCode); 103 - // Add a check to ensure parsing worked before tests run 104 - if (namePool.length === 0 || tzList.length === 0) { 105 - throw new Error('[TEST] Failed to parse generated C code in beforeAll hook.'); 106 - } 107 - }); 108 - 109 - // Test cases for specific zones 110 - const testCases: { zone: string; city: string }[] = [ 111 - { zone: 'America/New_York', city: 'New York' }, 112 - { zone: 'Asia/Tokyo', city: 'Tokyo' }, 113 - { zone: 'Pacific/Auckland', city: 'Auckland' }, 114 - { zone: 'Australia/Lord_Howe', city: 'Lord Howe' }, 115 - { zone: 'Europe/London', city: 'London' }, 116 - ]; 117 - 118 - test.each(testCases)('should generate correct entry for $city ($zone)', ({ zone, city }) => { 119 - const expectedTransitions = findDstTransitions(zone, currentYear); 120 - const expected: ParsedTzInfo = { 121 - stdHours: expectedTransitions[0] / 3600, 122 - dstHours: expectedTransitions[1] / 3600, 123 - startTs: expectedTransitions[2], 124 - endTs: expectedTransitions[3], 125 - nameOffset: -1, // Will be updated 126 - nameCount: -1, // Will be updated 127 - }; 128 - 129 - // 1. Find the city in the name pool 130 - const cityIndex = namePool.indexOf(city); 131 - expect(cityIndex).toBeGreaterThanOrEqual(0); // City must exist in the pool 132 - 133 - // 2. Find the bucket containing this city 134 - const bucket = tzList.find(entry => 135 - cityIndex >= entry.nameOffset && cityIndex < (entry.nameOffset + entry.nameCount) 136 - ); 137 - expect(bucket).toBeDefined(); // A bucket must contain this city 138 - 139 - // 3. Compare bucket details with expected values 140 - expect(bucket?.stdHours).toBeCloseTo(expected.stdHours, 2); 141 - expect(bucket?.dstHours).toBeCloseTo(expected.dstHours, 2); 142 - expect(bucket?.startTs).toBe(expected.startTs); 143 - expect(bucket?.endTs).toBe(expected.endTs); 144 - }); 145 - 146 - test('should contain the required macros', () => { 147 - expect(generatedCCode).toMatch(/#define TZ_LIST_COUNT/); 148 - expect(generatedCCode).toMatch(/#define TZ_NAME_POOL_COUNT/); 149 - }); 150 - 151 - test('TZ_LIST_COUNT macro should match parsed list length', () => { 152 - const match = generatedCCode.match(/#define\s+TZ_LIST_COUNT\s+\(sizeof\(tz_list\)\/sizeof\(tz_list\[0\]\)\)/); 153 - expect(match).not.toBeNull(); 154 - // Check the actual count directly from parsed data 155 - expect(tzList.length).toBeGreaterThan(10); // Keep a basic sanity check on count 156 - // We could potentially parse the value from the define if needed, but comparing to parsed length is good 157 - }); 158 - 159 - test('TZ_NAME_POOL_COUNT macro should match parsed name pool length', () => { 160 - const match = generatedCCode.match(/#define\s+TZ_NAME_POOL_COUNT\s+\(sizeof\(tz_name_pool\)\/sizeof\(tz_name_pool\[0\]\)\)/); 161 - expect(match).not.toBeNull(); 162 - expect(namePool.length).toBeGreaterThan(50); // Basic sanity check 163 - }); 164 - });
-102
scripts/generateTzList.ts
··· 1 - import { DateTime } from 'luxon'; 2 - import { rawTimeZones } from '@vvo/tzdb'; 3 - import * as fs from 'fs/promises'; 4 - import * as path from 'path'; 5 - import { program } from 'commander'; 6 - import { findDstTransitions } from './tzCommon'; 7 - 8 - interface TzBucket { 9 - std: number; 10 - dst: number; 11 - start: number; 12 - end: number; 13 - names: Set<string>; 14 - nameOffset?: number; 15 - nameCount?: number; 16 - } 17 - 18 - function getCityName(tz: string): string { 19 - const part = tz.split('/').pop() || tz; 20 - return part.replace(/_/g, ' '); 21 - } 22 - 23 - export async function generateTzCCode(outPath: string): Promise<void> { 24 - const year = DateTime.utc().year; 25 - console.log(`Generating tz_list for year ${year}`); 26 - 27 - const buckets = new Map<string, TzBucket>(); 28 - 29 - rawTimeZones.forEach(({ name }) => { 30 - if (!name.includes('/')) return; 31 - if (name.startsWith('Etc/')) return; 32 - if (/^(Factory|factory)/.test(name)) return; 33 - if (/^(right|posix)\//i.test(name)) return; 34 - 35 - const [std, dst, start, end] = findDstTransitions(name, year); 36 - const city = getCityName(name); 37 - if (!/^[A-Z]/.test(city)) return; 38 - 39 - const key = `${std}_${dst}_${start}_${end}`; 40 - let bucket = buckets.get(key); 41 - if (!bucket) { 42 - bucket = { std, dst, start, end, names: new Set() }; 43 - buckets.set(key, bucket); 44 - } 45 - bucket.names.add(city); 46 - }); 47 - 48 - const ordered = Array.from(buckets.values()).sort((a,b)=>{ 49 - if(a.std!==b.std) return a.std-b.std; 50 - if(a.dst!==b.dst) return a.dst-b.dst; 51 - if(a.start!==b.start) return a.start-b.start; 52 - return a.end-b.end; 53 - }); 54 - 55 - // Build flat name pool 56 - const namePool: string[] = []; 57 - ordered.forEach(b=>{ 58 - const names = Array.from(b.names).sort(); 59 - b.nameOffset = namePool.length; 60 - b.nameCount = names.length; 61 - namePool.push(...names); 62 - }); 63 - 64 - // Emit C code 65 - let c = ''; 66 - c += '// Auto-generated by generateTzList.ts\n'; 67 - c += `// Year ${year} DST data (Luxon / IANA)\n\n`; 68 - c += '#include <stdint.h>\n\n'; 69 - 70 - c += 'static const char* tz_name_pool[] = {\n'; 71 - namePool.forEach(n=>{ c += ` "${n}",\n`; }); 72 - c += '};\n\n'; 73 - 74 - c += 'typedef struct {\n'; 75 - c += ' float std_offset_hours;\n'; 76 - c += ' float dst_offset_hours;\n'; 77 - c += ' int64_t dst_start_utc;\n'; 78 - c += ' int64_t dst_end_utc;\n'; 79 - c += ' int name_offset;\n'; 80 - c += ' int name_count;\n'; 81 - c += '} TzInfo;\n\n'; 82 - 83 - c += 'static const TzInfo tz_list[] = {\n'; 84 - ordered.forEach(b=>{ 85 - c += ` { ${(b.std/3600).toFixed(2)}f, ${(b.dst/3600).toFixed(2)}f, ${b.start}LL, ${b.end}LL, ${b.nameOffset}, ${b.nameCount} },\n`; 86 - }); 87 - c += '};\n\n'; 88 - c += `#define TZ_LIST_COUNT (sizeof(tz_list)/sizeof(tz_list[0]))\n`; 89 - c += `#define TZ_NAME_POOL_COUNT (sizeof(tz_name_pool)/sizeof(tz_name_pool[0]))\n`; 90 - 91 - await fs.writeFile(outPath, c, 'utf-8'); 92 - console.log(`Wrote ${ordered.length} buckets and ${namePool.length} names to ${outPath}`); 93 - } 94 - 95 - // CLI 96 - if (require.main === module) { 97 - program 98 - .option('--out <path>', 'C output file', path.join(__dirname,'../src/c/tz_list.c')) 99 - .parse(process.argv); 100 - const { out } = program.opts(); 101 - generateTzCCode(out).catch(err=>{ console.error(err); process.exit(1); }); 102 - }
+12 -14
scripts/package.json
··· 4 4 "private": true, 5 5 "description": "Scripts for generating C code for tidface", 6 6 "scripts": { 7 - "generate:tz": "ts-node generateTzList.ts", 8 7 "generate:airport": "ts-node generateAirportTzList.ts", 9 8 "test": "jest" 10 9 }, 11 10 "dependencies": { 12 11 "@types/commander": "^2.12.5", 13 - "@vvo/tzdb": "^6.161.0", 14 12 "airport-data": "^1.0.1", 15 - "cheerio": "^1", 13 + "cheerio": "^1.0.0", 16 14 "commander": "^13.1.0", 17 - "csv-parse": "^5", 18 - "geo-tz": "^8", 19 - "luxon": "^3", 20 - "timezonecomplete": "^5.13.1", 15 + "csv-parse": "^5.6.0", 16 + "geo-tz": "^8.1.4", 17 + "luxon": "^3.6.1", 21 18 "tzdata": "^1.0.44" 22 19 }, 23 20 "devDependencies": { 24 - "typescript": "^5", 25 - "ts-node": "^10", 26 - "@types/node": "^22", 27 - "@types/luxon": "^3", 28 - "jest": "^29", 29 - "ts-jest": "^29", 30 - "@types/jest": "^29" 21 + "typescript": "^5.8.3", 22 + "ts-node": "^10.9.2", 23 + "@types/node": "^22.15.14", 24 + "@types/luxon": "^3.6.2", 25 + "@types/cheerio": "^1.0.0", 26 + "jest": "^29.7.0", 27 + "ts-jest": "^29.3.2", 28 + "@types/jest": "^29.5.14" 31 29 } 32 30 }
-31
scripts/tzCommon.test.ts
··· 1 - import { execSync } from 'child_process'; 2 - import path from 'path'; 3 1 import { findDstTransitions, DstTransitions } from './tzCommon'; 4 - 5 - // Function to get expected result from Python script 6 - const getExpectedFromPython = (zone: string, year: number): DstTransitions => { 7 - const pythonScriptPath = path.resolve(__dirname, 'tz_common.py'); 8 - const command = `python3 "${pythonScriptPath}" "${zone}" ${year}`; 9 - try { 10 - const stdout = execSync(command, { encoding: 'utf-8' }); 11 - // Parse the output tuple string, e.g., "(-18000, -14400, 1741503600, 1762063200)\n" 12 - const match = stdout.trim().match(/^\((.*)\)$/); 13 - if (match && match[1]) { 14 - const values = match[1].split(', ').map(Number); 15 - if (values.length === 4 && values.every(v => !isNaN(v))) { 16 - return values as DstTransitions; 17 - } 18 - } 19 - throw new Error(`Failed to parse Python output: ${stdout}`); 20 - } catch (error: any) { 21 - console.error(`Error executing Python script for ${zone}/${year}:`, error.stderr || error.message); 22 - // Return a default/error value or rethrow, depending on desired test behavior 23 - // Returning [0,0,0,0] for invalid zones handled by Python script itself 24 - if (error.stderr && error.stderr.includes('Invalid zone')) { 25 - // Match the python script's likely return for truly invalid IANA names 26 - // Note: findDstTransitions in Python returns (0,0,0,0) on initial get_tz_details failure. 27 - return [0, 0, 0, 0]; 28 - } 29 - // Rethrow for unexpected errors (e.g., python not found, script errors) 30 - throw new Error(`Python script execution failed for ${zone}/${year}: ${error.message}`); 31 - } 32 - }; 33 2 34 3 // Generated for year 2025 by generateExpectedTransitions.ts 35 4 const expectedTransitions: { zone: string; expected: DstTransitions }[] = [
+2 -2
scripts/tzCommon.ts
··· 27 27 /** 28 28 * Return (offset_seconds, isDST) or undefined if the timezone is invalid or offset is null. 29 29 */ 30 - export function getTzDetails(zoneName: string, dt: DateTime): TzDetails | undefined { 30 + function getTzDetails(zoneName: string, dt: DateTime): TzDetails | undefined { 31 31 if (!IANAZone.isValidZone(zoneName)) { 32 32 return undefined; 33 33 } ··· 173 173 cursor = nextCursor; 174 174 } 175 175 176 - // Final fallbacks – replicate slow loop behaviour 176 + // Final fallbacks - replicate slow loop behaviour 177 177 if (stdOffsetSec === null && dstOffsetSec !== null) { 178 178 stdOffsetSec = dstOffsetSec; 179 179 }
+319 -112
src/c/airport_tz_list.c
··· 1 1 // Auto-generated by generateAirportTzList.ts 2 - // Generated on: 2025-04-24T22:10:45.033Z 2 + // Generated on: 2025-05-05T01:10:00.243Z 3 3 // Year-specific DST data for 2025 4 4 5 5 #include <stdint.h> 6 6 7 - // Total airport codes: 245 (codes listed for debug) 8 - // Codes: PPG, IUE, FTI, HNL, KOA, LIH, ITO, MKK, JHM, LNY, ADK, NHV, AUQ, UAP, GMR, ANC, LAX, SFO, LAS, SEA, YVR, SAN, PDX, OAK, SJC, SMF, PHX, DEN, SLC, YYC, YEG, ABQ, ELP, MEX, ORD, DFW, IAH, MSP, MDW, DAL, STL, BNA, AUS, IPC, CUN, HAV, ATL, JFK, YYZ, CLT, MCO, MIA, EWR, BOS, DTW, FLL, MUN, CGB, MAO, SXM, CGR, PVH, BVB, YHZ, SCL, YYT, YDF, YAY, YWM, GRU, CGH, BSB, GIG, AEP, EZE, CNF, VCP, SDU, POA, FSP, FEN, GOH, SID, PDL, TER, DKR, LHR, LGW, DUB, MAN, LIS, STN, LTN, EDI, LPA, BHX, CMN, CDG, AMS, FRA, MAD, BCN, MUC, FCO, ZRH, CPH, PMI, JNB, CPT, TLV, BEY, KIV, ATH, HEL, OTP, KBP, HER, SOF, GZA, CAI, IST, SVO, JED, SAW, DME, AYT, RUH, VKO, LED, ESB, THR, MHD, IKA, SYZ, AWZ, KIH, IFN, TBZ, BND, PGU, DXB, AUH, SHJ, MRU, TBS, KUF, RUN, DWC, ASF, BUS, KBL, HEA, FBD, SVX, UFA, TJM, SGC, CEK, PEE, NUX, REN, NJC, SLY, DEL, BOM, BLR, CCU, MAA, COK, PNQ, AMD, GOI, JAI, KTM, BWA, BIR, TMI, OMS, RGN, MDL, CGK, BKK, DMK, SGN, HAN, SUB, HKT, KNO, DAD, CNX, PEK, HKG, PVG, CAN, SIN, KUL, CTU, SZX, TPE, KMG, HND, ICN, NRT, CJU, KIX, GMP, FUK, CTS, OKA, PUS, DRW, ASP, AYQ, ADL, PLO, MGB, OLP, BNE, OOL, CNS, VVO, KHV, TSV, SYD, MEL, CBR, HBA, LDH, UUS, NLK, NAN, PKC, AKL, CHC, WLG, ZQN, NSN, DUD, NPE, PMR, CHT, APW, TBU, EUA, CXI 9 7 static const uint16_t airport_code_pool_bits[] = { 10 8 0x3de6, /* PPG */ 11 9 0x2284, /* IUE */ ··· 21 19 0x34f5, /* NHV */ 22 20 0x290, /* AUQ */ 23 21 0x500f, /* UAP */ 22 + 0x5007, /* UAH */ 24 23 0x1991, /* GMR */ 25 24 0x1a2, /* ANC */ 26 25 0x2c17, /* LAX */ ··· 33 32 0x380a, /* OAK */ 34 33 0x4922, /* SJC */ 35 34 0x4985, /* SMF */ 35 + 0x49a0, /* SNA */ 36 + 0x4d09, /* TIJ */ 37 + 0x39b3, /* ONT */ 38 + 0x2cc1, /* LGB */ 39 + 0x691, /* BUR */ 40 + 0x3e4f, /* PSP */ 41 + 0x6309, /* YYJ */ 42 + 0x6176, /* YLW */ 43 + 0x1413, /* FAT */ 44 + 0x4820, /* SBA */ 36 45 0x3cf7, /* PHX */ 37 46 0xc8d, /* DEN */ 38 47 0x4962, /* SLC */ ··· 41 50 0x30, /* ABQ */ 42 51 0x116f, /* ELP */ 43 52 0x3097, /* MEX */ 53 + 0x186b, /* GDL */ 54 + 0x3278, /* MTY */ 55 + 0x492e, /* SJO */ 44 56 0x3a23, /* ORD */ 45 57 0xcb6, /* DFW */ 46 58 0x2007, /* IAH */ ··· 50 62 0x4a6b, /* STL */ 51 63 0x5a0, /* BNA */ 52 64 0x292, /* AUS */ 65 + 0x1dd4, /* HOU */ 66 + 0x3258, /* MSY */ 67 + 0x3048, /* MCI */ 68 + 0x4813, /* SAT */ 69 + 0x3980, /* OMA */ 70 + 0x62c6, /* YWG */ 71 + 0x3144, /* MKE */ 53 72 0x21e2, /* IPC */ 73 + 0x5c6, /* BOG */ 54 74 0xa8d, /* CUN */ 75 + 0x2d0c, /* LIM */ 55 76 0x1c15, /* HAV */ 56 77 0x26b, /* ATL */ 57 78 0x24aa, /* JFK */ ··· 63 84 0x5d2, /* BOS */ 64 85 0xe76, /* DTW */ 65 86 0x156b, /* FLL */ 87 + 0x3a2b, /* ORL */ 88 + 0x2cc0, /* LGA */ 89 + 0x3ceb, /* PHL */ 90 + 0x6c8, /* BWI */ 91 + 0xc40, /* DCA */ 92 + 0x2003, /* IAD */ 93 + 0x4de0, /* TPA */ 66 94 0x328d, /* MUN */ 67 95 0x8c1, /* CGB */ 68 96 0x300e, /* MAO */ ··· 75 103 0x6313, /* YYT */ 76 104 0x6065, /* YDF */ 77 105 0x6018, /* YAY */ 106 + 0x6217, /* YQX */ 78 107 0x62cc, /* YWM */ 108 + 0x60b7, /* YFX */ 109 + 0x60e0, /* YHA */ 79 110 0x1a34, /* GRU */ 80 111 0x8c7, /* CGH */ 81 112 0x641, /* BSB */ ··· 86 117 0x544f, /* VCP */ 87 118 0x4874, /* SDU */ 88 119 0x3dc0, /* POA */ 120 + 0x4482, /* REC */ 121 + 0x4a40, /* SSA */ 122 + 0xac1, /* CWB */ 123 + 0x15d1, /* FOR */ 124 + 0x156d, /* FLN */ 125 + 0x48b, /* BEL */ 126 + 0x1b0d, /* GYN */ 127 + 0x5517, /* VIX */ 128 + 0x9d1, /* COR */ 129 + 0x3413, /* NAT */ 89 130 0x164f, /* FSP */ 90 131 0x148d, /* FEN */ 91 132 0x19c7, /* GOH */ 92 133 0x4903, /* SID */ 93 134 0x3c6b, /* PDL */ 94 135 0x4c91, /* TER */ 95 - 0xd51, /* DKR */ 136 + 0x2885, /* KEF */ 96 137 0x2cf1, /* LHR */ 97 138 0x2cd6, /* LGW */ 98 139 0xe81, /* DUB */ ··· 103 144 0x1068, /* EDI */ 104 145 0x2de0, /* LPA */ 105 146 0x4f7, /* BHX */ 147 + 0x4cb2, /* TFS */ 148 + 0x39ee, /* OPO */ 149 + 0x1960, /* GLA */ 150 + 0x140e, /* FAO */ 151 + 0x632, /* BRS */ 152 + 0x44, /* ACE */ 153 + 0x1684, /* FUE */ 154 + 0x4b2, /* BFS */ 155 + 0x344b, /* NCL */ 106 156 0x98d, /* CMN */ 107 157 0x866, /* CDG */ 108 158 0x192, /* AMS */ ··· 114 164 0x6627, /* ZRH */ 115 165 0x9e7, /* CPH */ 116 166 0x3d88, /* PMI */ 167 + 0x3a4b, /* OSL */ 168 + 0x22d, /* ARN */ 169 + 0x634, /* BRU */ 170 + 0xe92, /* DUS */ 171 + 0x5504, /* VIE */ 172 + 0x32ef, /* MXP */ 173 + 0x4eeb, /* TXL */ 174 + 0xcf, /* AGP */ 175 + 0x1c0c, /* HAM */ 176 + 0x1aa0, /* GVA */ 117 177 0x25a1, /* JNB */ 118 178 0x9f3, /* CPT */ 179 + 0xe91, /* DUR */ 180 + 0x2a33, /* KRT */ 181 + 0x28c3, /* KGD */ 119 182 0x4d75, /* TLV */ 120 183 0x498, /* BEY */ 121 184 0x2915, /* KIV */ ··· 125 188 0x282f, /* KBP */ 126 189 0x1c91, /* HER */ 127 190 0x49c5, /* SOF */ 191 + 0x4946, /* SKG */ 192 + 0x4517, /* RIX */ 193 + 0x44ee, /* RHO */ 194 + 0x104d, /* ECN */ 128 195 0x1b20, /* GZA */ 129 196 0x808, /* CAI */ 197 + 0x1e26, /* HRG */ 198 + 0x4a47, /* SSH */ 199 + 0x1c24, /* HBE */ 130 200 0x2253, /* IST */ 131 201 0x4aae, /* SVO */ 132 202 0x2483, /* JED */ ··· 137 207 0x554e, /* VKO */ 138 208 0x2c83, /* LED */ 139 209 0x1241, /* ESB */ 210 + 0x61, /* ADB */ 211 + 0x63, /* ADD */ 212 + 0x342e, /* NBO */ 213 + 0x3083, /* MED */ 214 + 0x91, /* AER */ 215 + 0x60, /* ADA */ 216 + 0x490f, /* SIP */ 217 + 0xd6c, /* DLM */ 218 + 0x3250, /* MSQ */ 219 + 0x535, /* BJV */ 140 220 0x4cf1, /* THR */ 141 221 0x30e3, /* MHD */ 142 222 0x2140, /* IKA */ ··· 147 227 0x4c39, /* TBZ */ 148 228 0x5a3, /* BND */ 149 229 0x3cd4, /* PGU */ 230 + 0x2891, /* KER */ 231 + 0x323, /* AZD */ 232 + 0x23, /* ABD */ 233 + 0x699, /* BUZ */ 234 + 0x6407, /* ZAH */ 235 + 0x3987, /* OMH */ 236 + 0x4412, /* RAS */ 150 237 0xee1, /* DXB */ 151 238 0x287, /* AUH */ 152 239 0x48e9, /* SHJ */ ··· 157 244 0xec2, /* DWC */ 158 245 0x245, /* ASF */ 159 246 0x692, /* BUS */ 247 + 0x4553, /* RKT */ 248 + 0x2a93, /* KUT */ 249 + 0x212a, /* IJK */ 250 + 0x5178, /* ULY */ 160 251 0x282b, /* KBL */ 161 252 0x1c80, /* HEA */ 253 + 0x2867, /* KDH */ 254 + 0x3331, /* MZR */ 255 + 0x3199, /* MMZ */ 162 256 0x1423, /* FBD */ 163 257 0x4ab7, /* SVX */ 164 258 0x50a0, /* UFA */ ··· 170 264 0x448d, /* REN */ 171 265 0x3522, /* NJC */ 172 266 0x4978, /* SLY */ 267 + 0x1d80, /* HMA */ 268 + 0x35c9, /* NOJ */ 269 + 0x370c, /* NYM */ 270 + 0x3205, /* MQF */ 271 + 0x28cf, /* KGP */ 173 272 0xc8b, /* DEL */ 174 273 0x5cc, /* BOM */ 175 274 0x571, /* BLR */ ··· 180 279 0x183, /* AMD */ 181 280 0x19c8, /* GOI */ 182 281 0x2408, /* JAI */ 282 + 0x2d4e, /* LKO */ 283 + 0x1814, /* GAU */ 284 + 0x4e35, /* TRV */ 285 + 0x428, /* BBI */ 286 + 0x849, /* CCJ */ 287 + 0x3c13, /* PAT */ 288 + 0x2071, /* IDR */ 289 + 0x5679, /* VTZ */ 290 + 0x4af1, /* SXR */ 291 + 0x921, /* CJB */ 183 292 0x2a6c, /* KTM */ 184 293 0x6c0, /* BWA */ 185 294 0x511, /* BIR */ 295 + 0x288f, /* KEP */ 296 + 0x4de9, /* TPJ */ 186 297 0x4d88, /* TMI */ 298 + 0x4f1, /* BHR */ 299 + 0x46f, /* BDP */ 187 300 0x3992, /* OMS */ 188 301 0x44cd, /* RGN */ 189 302 0x306b, /* MDL */ ··· 197 310 0x29ae, /* KNO */ 198 311 0xc03, /* DAD */ 199 312 0x9b7, /* CNX */ 313 + 0x25c6, /* JOG */ 314 + 0x1d6f, /* HLP */ 315 + 0x667, /* BTH */ 316 + 0x3d6c, /* PLM */ 317 + 0x3aa1, /* OVB */ 318 + 0xaf1, /* CXR */ 319 + 0x3d54, /* PKU */ 320 + 0x1c78, /* HDY */ 321 + 0x4a26, /* SRG */ 322 + 0x2835, /* KBV */ 200 323 0x3c8a, /* PEK */ 201 324 0x1d46, /* HKG */ 202 325 0x3ea6, /* PVG */ ··· 207 330 0x4b37, /* SZX */ 208 331 0x4de4, /* TPE */ 209 332 0x2986, /* KMG */ 333 + 0x31ab, /* MNL */ 334 + 0x48e0, /* SHA */ 335 + 0x5d18, /* XIY */ 336 + 0x946, /* CKG */ 337 + 0x1cc7, /* HGH */ 338 + 0x3546, /* NKG */ 339 + 0x5d8d, /* XMN */ 340 + 0x8ce, /* CGO */ 341 + 0xa57, /* CSX */ 342 + 0x4c0e, /* TAO */ 210 343 0x1da3, /* HND */ 211 344 0x204d, /* ICN */ 212 345 0x3633, /* NRT */ ··· 217 350 0xa72, /* CTS */ 218 351 0x3940, /* OKA */ 219 352 0x3e92, /* PUS */ 353 + 0x226c, /* ITM */ 354 + 0x34ce, /* NGO */ 355 + 0x29c9, /* KOJ */ 356 + 0x4c04, /* TAE */ 357 + 0x2989, /* KMJ */ 358 + 0x4869, /* SDJ */ 359 + 0x34d2, /* NGS */ 360 + 0x2988, /* KMI */ 361 + 0x3309, /* MYJ */ 362 + 0x929, /* CJJ */ 220 363 0xe36, /* DRW */ 221 364 0x24f, /* ASP */ 222 365 0x310, /* AYQ */ ··· 230 373 0x56ae, /* VVO */ 231 374 0x28f5, /* KHV */ 232 375 0x4e55, /* TSV */ 376 + 0x3158, /* MKY */ 377 + 0x3dcc, /* POM */ 378 + 0x3058, /* MCY */ 379 + 0x45ca, /* ROK */ 380 + 0x1e68, /* HTI */ 381 + 0x1973, /* GLT */ 233 382 0x4b03, /* SYD */ 234 383 0x308b, /* MEL */ 235 384 0x831, /* CBR */ 236 385 0x1c20, /* HBA */ 386 + 0x2e53, /* LST */ 387 + 0x366b, /* NTL */ 388 + 0x5aa, /* BNK */ 389 + 0x8b2, /* CFS */ 237 390 0x2c67, /* LDH */ 238 391 0x5292, /* UUS */ 239 392 0x356a, /* NLK */ ··· 247 400 0xe83, /* DUD */ 248 401 0x35e4, /* NPE */ 249 402 0x3d91, /* PMR */ 403 + 0x35eb, /* NPL */ 404 + 0x4e26, /* TRG */ 405 + 0x1d79, /* HLZ */ 406 + 0x4e4, /* BHE */ 407 + 0x22a2, /* IVC */ 408 + 0x45d3, /* ROT */ 250 409 0x8f3, /* CHT */ 251 410 0x1f6, /* APW */ 252 411 0x4c34, /* TBU */ 412 + 0x5415, /* VAV */ 413 + 0x1de0, /* HPA */ 253 414 0x1280, /* EUA */ 415 + 0x3673, /* NTT */ 254 416 0xae8, /* CXI */ 255 417 }; 256 418 257 - #define AIRPORT_CODE_POOL_BITS_COUNT 245 419 + #define AIRPORT_CODE_POOL_BITS_COUNT 409 258 420 259 - // Total airport names: 245 421 + // Total airport names: 409 260 422 static const char airport_name_pool[] = 261 423 "Pago Pago\0" "Niue\0" "Fitiuta\0" "Honolulu\0" 262 424 "Kona International At Keahole\0" "Lihue\0" "Hilo\0" "Molokai\0" 263 425 "Kapalua\0" "Lanai\0" "Adak\0" "Nuku Hiva\0" "Hiva Oa-Atuona\0" "Ua Pou\0" 264 - "Totegegie\0" "Ted Stevens Anchorage\0" "Los Angeles\0" "San Francisco\0" 265 - "McCarran\0" "Seattle Tacoma\0" "Vancouver\0" "San Diego\0" "Portland\0" 266 - "Metropolitan Oakland\0" "Norman Y. Mineta San Jose\0" "Sacramento\0" 426 + "Ua Huka\0" "Totegegie\0" "Ted Stevens Anchorage\0" "Los Angeles\0" 427 + "San Francisco\0" "McCarran\0" "Seattle Tacoma\0" "Vancouver\0" 428 + "San Diego\0" "Portland\0" "Metropolitan Oakland\0" 429 + "Norman Y. Mineta San Jose\0" "Sacramento\0" 430 + "John Wayne Airport-Orange County\0" "General Abelardo L. Rodríguez\0" 431 + "Ontario\0" "Long Beach /Daugherty Field/\0" "Bob Hope\0" "Palm Springs\0" 432 + "Victoria\0" "Kelowna\0" "Fresno Yosemite\0" "Santa Barbara Municipal\0" 267 433 "Phoenix Sky Harbor\0" "Denver\0" "Salt Lake City\0" "Calgary\0" 268 434 "Edmonton\0" "Albuquerque International Sunport\0" "El Paso\0" 269 - "Licenciado Benito Juarez\0" "Chicago O'Hare\0" "Dallas Fort Worth\0" 270 - "George Bush Intercontinental Houston\0" 435 + "Licenciado Benito Juarez\0" "Don Miguel Hidalgo Y Costilla\0" 436 + "General Mariano Escobedo\0" "Juan Santamaria\0" "Chicago O'Hare\0" 437 + "Dallas Fort Worth\0" "George Bush Intercontinental Houston\0" 271 438 "Minneapolis-St Paul International/Wold-Chamberlain\0" "Chicago Midway\0" 272 439 "Dallas Love Field\0" "Lambert St Louis\0" "Nashville\0" 273 - "Austin Bergstrom\0" "Mataveri\0" "Cancún\0" "José Martí\0" 440 + "Austin Bergstrom\0" "William P Hobby\0" "Louis Armstrong New Orleans\0" 441 + "Kansas City\0" "San Antonio\0" "Eppley Airfield\0" 442 + "Winnipeg / James Armstrong Richardson\0" "General Mitchell\0" "Mataveri\0" 443 + "El Dorado\0" "Cancún\0" "Jorge Chávez\0" "José Martí\0" 274 444 "Hartsfield Jackson Atlanta\0" "John F Kennedy\0" "Lester B. Pearson\0" 275 445 "Charlotte Douglas\0" "Orlando\0" "Miami\0" "Newark Liberty\0" 276 446 "General Edward Lawrence Logan\0" "Detroit Metropolitan Wayne County\0" 277 - "Fort Lauderdale Hollywood\0" "Maturín\0" "Marechal Rondon\0" 278 - "Eduardo Gomes\0" "Princess Juliana\0" "Campo Grande\0" 279 - "Governador Jorge Teixeira de Oliveira\0" "Atlas Brasil Cantanhede\0" 280 - "Halifax / Stanfield\0" "Comodoro Arturo Merino Benítez\0" "St. John's\0" 281 - "Deer Lake\0" "St. Anthony\0" "Williams Harbour\0" 282 - "Guarulhos - Governador André Franco Montoro\0" "Congonhas\0" 283 - "Presidente Juscelino Kubistschek\0" "Rio Galeão – Tom Jobim\0" 284 - "Jorge Newbery Airpark\0" "Ministro Pistarini\0" "Tancredo Neves\0" 285 - "Viracopos\0" "Santos Dumont\0" "Salgado Filho\0" "St Pierre\0" 286 - "Fernando de Noronha\0" "Godthaab / Nuuk\0" "Amílcar Cabral\0" 287 - "João Paulo II\0" "Lajes Field\0" "Léopold Sédar Senghor\0" 288 - "London Heathrow\0" "London Gatwick\0" "Dublin\0" "Manchester\0" 289 - "Lisbon Portela\0" "London Stansted\0" "London Luton\0" "Edinburgh\0" 290 - "Gran Canaria\0" "Birmingham\0" "Mohammed V\0" "Charles de Gaulle\0" 291 - "Amsterdam Airport Schiphol\0" "Frankfurt am Main\0" 447 + "Fort Lauderdale Hollywood\0" "Orlando Executive\0" "La Guardia\0" 448 + "Philadelphia\0" "Baltimore/Washington International Thurgood Marshall\0" 449 + "Ronald Reagan Washington National\0" "Washington Dulles\0" "Tampa\0" 450 + "Maturín\0" "Marechal Rondon\0" "Eduardo Gomes\0" "Princess Juliana\0" 451 + "Campo Grande\0" "Governador Jorge Teixeira de Oliveira\0" 452 + "Atlas Brasil Cantanhede\0" "Halifax / Stanfield\0" 453 + "Comodoro Arturo Merino Benítez\0" "St. John's\0" "Deer Lake\0" 454 + "St. Anthony\0" "Gander\0" "Williams Harbour\0" "St. Lewis (Fox Harbour)\0" 455 + "Port Hope Simpson\0" "Guarulhos - Governador André Franco Montoro\0" 456 + "Congonhas\0" "Presidente Juscelino Kubistschek\0" 457 + "Rio Galeão – Tom Jobim\0" "Jorge Newbery Airpark\0" "Ministro Pistarini\0" 458 + "Tancredo Neves\0" "Viracopos\0" "Santos Dumont\0" "Salgado Filho\0" 459 + "Guararapes - Gilberto Freyre\0" "Deputado Luiz Eduardo Magalhães\0" 460 + "Afonso Pena\0" "Pinto Martins\0" "Hercílio Luz\0" 461 + "Val de Cans/Júlio Cezar Ribeiro\0" "Santa Genoveva\0" 462 + "Eurico de Aguiar Salles\0" "Ingeniero Ambrosio Taravella\0" 463 + "Governador Aluízio Alves\0" "St Pierre\0" "Fernando de Noronha\0" 464 + "Godthaab / Nuuk\0" "Amílcar Cabral\0" "João Paulo II\0" "Lajes Field\0" 465 + "Keflavik\0" "London Heathrow\0" "London Gatwick\0" "Dublin\0" 466 + "Manchester\0" "Lisbon Portela\0" "London Stansted\0" "London Luton\0" 467 + "Edinburgh\0" "Gran Canaria\0" "Birmingham\0" "Tenerife South\0" 468 + "Francisco de Sá Carneiro\0" "Glasgow\0" "Faro\0" "Bristol\0" "Lanzarote\0" 469 + "Fuerteventura\0" "Belfast\0" "Newcastle\0" "Mohammed V\0" 470 + "Charles de Gaulle\0" "Amsterdam Airport Schiphol\0" "Frankfurt am Main\0" 292 471 "Adolfo Suárez Madrid–Barajas\0" "Barcelona\0" "Munich\0" 293 472 "Leonardo da Vinci–Fiumicino\0" "Zürich\0" "Copenhagen Kastrup\0" 294 - "Palma De Mallorca\0" "OR Tambo\0" "Cape Town\0" "Ben Gurion\0" 473 + "Palma De Mallorca\0" "Oslo Gardermoen\0" "Stockholm-Arlanda\0" 474 + "Brussels\0" "Düsseldorf\0" "Vienna\0" "Malpensa\0" "Berlin-Tegel\0" 475 + "Málaga\0" "Hamburg\0" "Geneva Cointrin\0" "OR Tambo\0" "Cape Town\0" 476 + "King Shaka\0" "Khartoum\0" "Khrabrovo\0" "Ben Gurion\0" 295 477 "Beirut Rafic Hariri\0" "Chişinău\0" "Eleftherios Venizelos\0" 296 478 "Helsinki Vantaa\0" "Henri Coandă\0" "Boryspil\0" 297 - "Heraklion International Nikos Kazantzakis\0" "Sofia\0" "Yasser Arafat\0" 298 - "Cairo\0" "Atatürk\0" "Sheremetyevo\0" "King Abdulaziz\0" "Sabiha Gökçen\0" 299 - "Domodedovo\0" "Antalya\0" "King Khaled\0" "Vnukovo\0" "Pulkovo\0" 300 - "Esenboğa\0" "Mehrabad\0" "Mashhad\0" "Imam Khomeini\0" 301 - "Shiraz Shahid Dastghaib\0" "Ahwaz\0" "Kish\0" "Esfahan Shahid Beheshti\0" 302 - "Tabriz\0" "Bandar Abbas\0" "Persian Gulf\0" "Dubai\0" "Abu Dhabi\0" 479 + "Heraklion International Nikos Kazantzakis\0" "Sofia\0" 480 + "Thessaloniki Macedonia\0" "Riga\0" "Diagoras\0" "Ercan\0" 481 + "Yasser Arafat\0" "Cairo\0" "Hurghada\0" "Sharm El Sheikh\0" 482 + "Borg El Arab\0" "Atatürk\0" "Sheremetyevo\0" "King Abdulaziz\0" 483 + "Sabiha Gökçen\0" "Domodedovo\0" "Antalya\0" "King Khaled\0" "Vnukovo\0" 484 + "Pulkovo\0" "Esenboğa\0" "Adnan Menderes\0" "Addis Ababa Bole\0" 485 + "Jomo Kenyatta\0" "Prince Mohammad Bin Abdulaziz\0" "Sochi\0" "Adana\0" 486 + "Simferopol\0" "Dalaman\0" "Minsk National\0" "Milas Bodrum\0" "Mehrabad\0" 487 + "Mashhad\0" "Imam Khomeini\0" "Shiraz Shahid Dastghaib\0" "Ahwaz\0" 488 + "Kish\0" "Esfahan Shahid Beheshti\0" "Tabriz\0" "Bandar Abbas\0" 489 + "Persian Gulf\0" "Kerman\0" "Shahid Sadooghi\0" "Abadan\0" "Bushehr\0" 490 + "Zahedan\0" "Urmia\0" "Sardar-e-Jangal\0" "Dubai\0" "Abu Dhabi\0" 303 491 "Sharjah\0" "Sir Seewoosagur Ramgoolam\0" "Tbilisi\0" "Kurumoch\0" 304 - "Roland Garros\0" "Al Maktoum\0" "Astrakhan\0" "Batumi\0" "Kabul\0" 305 - "Herat\0" "Fayzabad\0" "Koltsovo\0" "Ufa\0" "Roshchino\0" "Surgut\0" 306 - "Chelyabinsk Balandino\0" "Bolshoye Savino\0" "Novy Urengoy\0" 307 - "Orenburg Central\0" "Nizhnevartovsk\0" "Salekhard\0" "Indira Gandhi\0" 308 - "Chhatrapati Shivaji\0" "Kempegowda\0" "Netaji Subhash Chandra Bose\0" 309 - "Chennai\0" "Cochin\0" "Pune\0" "Sardar Vallabhbhai Patel\0" "Dabolim\0" 310 - "Jaipur\0" "Tribhuvan\0" "Gautam Buddha\0" "Biratnagar\0" "Tumling Tar\0" 311 - "Omsk Central\0" "Yangon\0" "Mandalay\0" "Soekarno-Hatta\0" 312 - "Suvarnabhumi\0" "Don Mueang\0" "Tan Son Nhat\0" "Noi Bai\0" "Juanda\0" 313 - "Phuket\0" "Kualanamu\0" "Da Nang\0" "Chiang Mai\0" "Beijing Capital\0" 314 - "Chek Lap Kok\0" "Shanghai Pudong\0" "Guangzhou Baiyun\0" 315 - "Singapore Changi\0" "Kuala Lumpur\0" "Chengdu Shuangliu\0" 316 - "Shenzhen Bao'an\0" "Taiwan Taoyuan\0" "Kunming Changshui\0" 317 - "Tokyo Haneda\0" "Incheon\0" "Narita\0" "Jeju\0" "Kansai\0" "Gimpo\0" 318 - "Fukuoka\0" "New Chitose\0" "Naha\0" "Gimhae\0" "Darwin\0" 319 - "Alice Springs\0" "Ayers Rock Connellan\0" "Adelaide\0" "Port Lincoln\0" 320 - "Mount Gambier\0" "Olympic Dam\0" "Brisbane\0" "Gold Coast\0" "Cairns\0" 321 - "Vladivostok\0" "Khabarovsk-Novy\0" "Townsville\0" 492 + "Roland Garros\0" "Al Maktoum\0" "Astrakhan\0" "Batumi\0" 493 + "Ras Al Khaimah\0" "Kopitnari\0" "Izhevsk\0" "Ulyanovsk East\0" "Kabul\0" 494 + "Herat\0" "Kandahar\0" "Mazar I Sharif\0" "Maimana\0" "Fayzabad\0" 495 + "Koltsovo\0" "Ufa\0" "Roshchino\0" "Surgut\0" "Chelyabinsk Balandino\0" 496 + "Bolshoye Savino\0" "Novy Urengoy\0" "Orenburg Central\0" 497 + "Nizhnevartovsk\0" "Salekhard\0" "Khanty Mansiysk\0" "Noyabrsk\0" "Nadym\0" 498 + "Magnitogorsk\0" "Kogalym\0" "Indira Gandhi\0" "Chhatrapati Shivaji\0" 499 + "Kempegowda\0" "Netaji Subhash Chandra Bordoloi\0" "Chennai\0" "Cochin\0" 500 + "Pune\0" "Sardar Vallabhbhai Patel\0" "Dabolim\0" "Jaipur\0" 501 + "Chaudhary Charan Singh\0" "Lokpriya Gopinath Bordoloi\0" "Trivandrum\0" 502 + "Biju Patnaik\0" "Calicut\0" "Lok Nayak Jayaprakash\0" 503 + "Devi Ahilyabai Holkar\0" "Vishakhapatnam\0" "Sheikh ul Alam\0" 504 + "Coimbatore\0" "Tribhuvan\0" "Gautam Buddha\0" "Biratnagar\0" "Nepalgunj\0" 505 + "Taplejung\0" "Tumling Tar\0" "Bharatpur\0" "Bhadrapur\0" "Omsk Central\0" 506 + "Yangon\0" "Mandalay\0" "Soekarno-Hatta\0" "Suvarnabhumi\0" "Don Mueang\0" 507 + "Tan Son Nhat\0" "Noi Bai\0" "Juanda\0" "Phuket\0" "Kualanamu\0" 508 + "Da Nang\0" "Chiang Mai\0" "Adi Sutjipto\0" "Halim Perdanakusuma\0" 509 + "Hang Nadim\0" "Sultan Mahmud Badaruddin II\0" "Tolmachevo\0" "Cam Ranh\0" 510 + "Sultan Syarif Kasim Ii (Simpang Tiga)\0" "Hat Yai\0" "Achmad Yani\0" 511 + "Krabi\0" "Beijing Capital\0" "Chek Lap Kok\0" "Shanghai Pudong\0" 512 + "Guangzhou Baiyun\0" "Singapore Changi\0" "Kuala Lumpur\0" 513 + "Chengdu Shuangliu\0" "Shenzhen Bao'an\0" "Taiwan Taoyuan\0" 514 + "Kunming Changshui\0" "Ninoy Aquino\0" "Shanghai Hongqiao\0" 515 + "Xi'an Xianyang\0" "Chongqing Jiangbei\0" "Hangzhou Xiaoshan\0" 516 + "Nanjing Lukou\0" "Xiamen Gaoqi\0" "Zhengzhou Xinzheng\0" 517 + "Changsha Huanghua\0" "Liuting\0" "Tokyo Haneda\0" "Incheon\0" "Narita\0" 518 + "Jeju\0" "Kansai\0" "Gimpo\0" "Fukuoka\0" "New Chitose\0" "Naha\0" 519 + "Gimhae\0" "Osaka\0" "Chubu Centrair\0" "Kagoshima\0" "Daegu\0" 520 + "Kumamoto\0" "Sendai\0" "Nagasaki\0" "Miyazaki\0" "Matsuyama\0" 521 + "Cheongju\0" "Darwin\0" "Alice Springs\0" "Ayers Rock Connellan\0" 522 + "Adelaide\0" "Port Lincoln\0" "Mount Gambier\0" "Olympic Dam\0" 523 + "Brisbane\0" "Gold Coast\0" "Cairns\0" "Vladivostok\0" "Khabarovsk-Novy\0" 524 + "Townsville\0" "Mackay\0" "Port Moresby Jacksons\0" "Sunshine Coast\0" 525 + "Rockhampton\0" "Hamilton Island\0" "Gladstone\0" 322 526 "Sydney Kingsford Smith\0" "Melbourne\0" "Canberra\0" "Hobart\0" 527 + "Launceston\0" "Newcastle\0" "Ballina Byron Gateway\0" "Coffs Harbour\0" 323 528 "Lord Howe Island\0" "Yuzhno-Sakhalinsk\0" "Norfolk Island\0" "Nadi\0" 324 529 "Yelizovo\0" "Auckland\0" "Christchurch\0" "Wellington\0" "Queenstown\0" 325 530 "Nelson\0" "Dunedin\0" "Hawke's Bay\0" "Palmerston North\0" 326 - "Chatham Islands-Tuuta\0" "Faleolo\0" "Fua'amotu\0" "Kaufana\0" "Cassidy\0" 531 + "New Plymouth\0" "Tauranga\0" "Hamilton\0" "Woodbourne\0" "Invercargill\0" 532 + "Rotorua Regional\0" "Chatham Islands-Tuuta\0" "Faleolo\0" "Fua'amotu\0" 533 + "Vava'u\0" "Lifuka Island\0" "Kaufana\0" "Kuini Lavenia\0" "Cassidy\0" 327 534 ; 328 535 329 536 typedef struct { ··· 340 547 { -44, -44, 0, 0, 0, 3 }, // Pacific/Pago_Pago, Pacific/Midway, Pacific/Niue (-11.00h/-11.00h) 341 548 { -40, -40, 0, 0, 3, 7 }, // Pacific/Rarotonga, Pacific/Honolulu, Pacific/Tahiti (-10.00h/-10.00h) 342 549 { -40, -36, 1741521600, 1762081200, 10, 1 }, // America/Adak (-10.00h/-9.00h) 343 - { -38, -38, 0, 0, 11, 3 }, // Pacific/Marquesas (-9.50h/-9.50h) 344 - { -36, -36, 0, 0, 14, 1 }, // Pacific/Gambier (-9.00h/-9.00h) 345 - { -36, -32, 1741518000, 1762077600, 15, 1 }, // America/Anchorage (-9.00h/-8.00h) 346 - { -32, -28, 1741514400, 1762074000, 16, 10 }, // America/Vancouver, America/Tijuana, America/Los_Angeles (-8.00h/-7.00h) 347 - { -28, -28, 0, 0, 26, 1 }, // America/Dawson_Creek, America/Mazatlan, America/Hermosillo (-7.00h/-7.00h) 348 - { -28, -24, 1741510800, 1762070400, 27, 6 }, // America/Edmonton, America/Denver, America/Inuvik (-7.00h/-6.00h) 349 - { -24, -24, 0, 0, 33, 1 }, // America/Regina, America/Guatemala, America/Tegucigalpa (-6.00h/-6.00h) 350 - { -24, -20, 1741507200, 1762066800, 34, 9 }, // America/Winnipeg, America/Chicago (-6.00h/-5.00h) 351 - { -24, -20, 1757217600, 1743908400, 43, 1 }, // Pacific/Easter (-6.00h/-5.00h) 352 - { -20, -20, 0, 0, 44, 1 }, // America/Coral_Harbour, America/Jamaica, America/Cancun (-5.00h/-5.00h) 353 - { -20, -16, 1741496400, 1762059600, 45, 1 }, // America/Havana (-5.00h/-4.00h) 354 - { -20, -16, 1741503600, 1762063200, 46, 10 }, // America/Toronto, America/Grand_Turk, America/Port-au-Prince (-5.00h/-4.00h) 355 - { -16, -16, 0, 0, 56, 7 }, // America/Santo_Domingo, America/Campo_Grande, America/Boa_Vista (-4.00h/-4.00h) 356 - { -16, -12, 1741500000, 1762059600, 63, 1 }, // America/Thule, America/Halifax, Atlantic/Bermuda (-4.00h/-3.00h) 357 - { -16, -12, 1757217600, 1743908400, 64, 1 }, // America/Santiago (-4.00h/-3.00h) 358 - { -14, -10, 1741496400, 1762056000, 65, 4 }, // America/St_Johns (-3.50h/-2.50h) 359 - { -12, -12, 0, 0, 69, 10 }, // Atlantic/Stanley, America/Cordoba, America/Buenos_Aires (-3.00h/-3.00h) 360 - { -12, -8, 1741496400, 1762056000, 79, 1 }, // America/Miquelon (-3.00h/-2.00h) 361 - { -8, -8, 0, 0, 80, 1 }, // America/Noronha (-2.00h/-2.00h) 362 - { -8, -4, 1743296400, 1761440400, 81, 1 }, // America/Godthab, America/Scoresbysund (-2.00h/-1.00h) 363 - { -4, -4, 0, 0, 82, 1 }, // Atlantic/Cape_Verde (-1.00h/-1.00h) 364 - { -4, 0, 1743296400, 1761440400, 83, 2 }, // Atlantic/Azores (-1.00h/0.00h) 365 - { 0, 0, 0, 0, 85, 1 }, // Atlantic/Reykjavik, Africa/Ouagadougou, Africa/Accra (0.00h/0.00h) 366 - { 0, 4, 1743296400, 1761440400, 86, 10 }, // Europe/London, Europe/Guernsey, Europe/Jersey (0.00h/1.00h) 367 - { 4, 4, 0, 0, 96, 1 }, // Africa/Algiers, Africa/Porto-Novo, Africa/Lagos (1.00h/1.00h) 368 - { 4, 8, 1743296400, 1761440400, 97, 10 }, // Europe/Brussels, Europe/Berlin, Europe/Amsterdam (1.00h/2.00h) 369 - { 8, 8, 0, 0, 107, 2 }, // Africa/Johannesburg, Africa/Gaborone, Africa/Mbabane (2.00h/2.00h) 370 - { 8, 12, 1743120000, 1761433200, 109, 1 }, // Asia/Jerusalem (2.00h/3.00h) 371 - { 8, 12, 1743285600, 1761426000, 110, 1 }, // Asia/Beirut (2.00h/3.00h) 372 - { 8, 12, 1743292800, 1761436800, 111, 1 }, // Europe/Chisinau (2.00h/3.00h) 373 - { 8, 12, 1743296400, 1761440400, 112, 6 }, // Europe/Tallinn, Europe/Helsinki, Europe/Mariehamn (2.00h/3.00h) 374 - { 8, 12, 1744416000, 1761346800, 118, 1 }, // Asia/Gaza (2.00h/3.00h) 375 - { 8, 12, 1745532000, 1761858000, 119, 1 }, // Africa/Cairo (2.00h/3.00h) 376 - { 12, 12, 0, 0, 120, 10 }, // Indian/Comoro, Indian/Mayotte, Indian/Antananarivo (3.00h/3.00h) 377 - { 14, 14, 0, 0, 130, 10 }, // Asia/Tehran (3.50h/3.50h) 378 - { 16, 16, 0, 0, 140, 10 }, // Indian/Mauritius, Indian/Reunion, Indian/Mahe (4.00h/4.00h) 379 - { 18, 18, 0, 0, 150, 3 }, // Asia/Kabul (4.50h/4.50h) 380 - { 20, 20, 0, 0, 153, 10 }, // Asia/Karachi, Asia/Qyzylorda, Asia/Oral (5.00h/5.00h) 381 - { 22, 22, 0, 0, 163, 10 }, // Asia/Calcutta, Asia/Colombo, Asia/Kolkata (5.50h/5.50h) 382 - { 23, 23, 0, 0, 173, 4 }, // Asia/Katmandu (5.75h/5.75h) 383 - { 24, 24, 0, 0, 177, 1 }, // Asia/Bishkek, Asia/Omsk, Asia/Dhaka (6.00h/6.00h) 384 - { 26, 26, 0, 0, 178, 2 }, // Asia/Rangoon, Indian/Cocos (6.50h/6.50h) 385 - { 28, 28, 0, 0, 180, 10 }, // Asia/Krasnoyarsk, Asia/Phnom_Penh, Asia/Vientiane (7.00h/7.00h) 386 - { 32, 32, 0, 0, 190, 10 }, // Asia/Taipei, Asia/Manila, Asia/Irkutsk (8.00h/8.00h) 387 - { 36, 36, 0, 0, 200, 10 }, // Pacific/Palau, Asia/Tokyo, Asia/Seoul (9.00h/9.00h) 388 - { 38, 38, 0, 0, 210, 3 }, // Australia/Darwin (9.50h/9.50h) 389 - { 38, 42, 1759593600, 1743872400, 213, 4 }, // Australia/Adelaide (9.50h/10.50h) 390 - { 40, 40, 0, 0, 217, 6 }, // Pacific/Port_Moresby, Pacific/Saipan, Pacific/Guam (10.00h/10.00h) 391 - { 40, 44, 1759593600, 1743868800, 223, 4 }, // Australia/Hobart, Australia/Sydney, Australia/Melbourne (10.00h/11.00h) 392 - { 42, 44, 1759593600, 1743865200, 227, 1 }, // Australia/Lord_Howe (10.50h/11.00h) 393 - { 44, 44, 0, 0, 228, 1 }, // Pacific/Efate, Pacific/Noumea, Pacific/Ponape (11.00h/11.00h) 394 - { 44, 48, 1759590000, 1743865200, 229, 1 }, // Pacific/Norfolk (11.00h/12.00h) 395 - { 48, 48, 0, 0, 230, 2 }, // Pacific/Fiji, Pacific/Tarawa, Pacific/Wallis (12.00h/12.00h) 396 - { 48, 52, 1758981600, 1743861600, 232, 8 }, // Pacific/Auckland (12.00h/13.00h) 397 - { 51, 55, 1758981600, 1743861600, 240, 1 }, // Pacific/Chatham (12.75h/13.75h) 398 - { 52, 52, 0, 0, 241, 3 }, // Pacific/Tongatapu, Pacific/Apia, Pacific/Enderbury (13.00h/13.00h) 399 - { 56, 56, 0, 0, 244, 1 }, // Pacific/Kiritimati (14.00h/14.00h) 550 + { -38, -38, 0, 0, 11, 4 }, // Pacific/Marquesas (-9.50h/-9.50h) 551 + { -36, -36, 0, 0, 15, 1 }, // Pacific/Gambier (-9.00h/-9.00h) 552 + { -36, -32, 1741518000, 1762077600, 16, 1 }, // America/Anchorage (-9.00h/-8.00h) 553 + { -32, -28, 1741514400, 1762074000, 17, 20 }, // America/Vancouver, America/Tijuana, America/Los_Angeles (-8.00h/-7.00h) 554 + { -28, -28, 0, 0, 37, 1 }, // America/Dawson_Creek, America/Mazatlan, America/Hermosillo (-7.00h/-7.00h) 555 + { -28, -24, 1741510800, 1762070400, 38, 6 }, // America/Edmonton, America/Denver, America/Inuvik (-7.00h/-6.00h) 556 + { -24, -24, 0, 0, 44, 4 }, // America/Regina, America/Guatemala, America/Tegucigalpa (-6.00h/-6.00h) 557 + { -24, -20, 1741507200, 1762066800, 48, 16 }, // America/Winnipeg, America/Chicago (-6.00h/-5.00h) 558 + { -24, -20, 1757217600, 1743908400, 64, 1 }, // Pacific/Easter (-6.00h/-5.00h) 559 + { -20, -20, 0, 0, 65, 3 }, // America/Coral_Harbour, America/Jamaica, America/Cancun (-5.00h/-5.00h) 560 + { -20, -16, 1741496400, 1762059600, 68, 1 }, // America/Havana (-5.00h/-4.00h) 561 + { -20, -16, 1741503600, 1762063200, 69, 17 }, // America/Toronto, America/Grand_Turk, America/Port-au-Prince (-5.00h/-4.00h) 562 + { -16, -16, 0, 0, 86, 7 }, // America/Santo_Domingo, America/Campo_Grande, America/Boa_Vista (-4.00h/-4.00h) 563 + { -16, -12, 1741500000, 1762059600, 93, 1 }, // America/Thule, America/Halifax, Atlantic/Bermuda (-4.00h/-3.00h) 564 + { -16, -12, 1757217600, 1743908400, 94, 1 }, // America/Santiago (-4.00h/-3.00h) 565 + { -14, -10, 1741496400, 1762056000, 95, 7 }, // America/St_Johns (-3.50h/-2.50h) 566 + { -12, -12, 0, 0, 102, 20 }, // Atlantic/Stanley, America/Cordoba, America/Buenos_Aires (-3.00h/-3.00h) 567 + { -12, -8, 1741496400, 1762056000, 122, 1 }, // America/Miquelon (-3.00h/-2.00h) 568 + { -8, -8, 0, 0, 123, 1 }, // America/Noronha (-2.00h/-2.00h) 569 + { -8, -4, 1743296400, 1761440400, 124, 1 }, // America/Godthab, America/Scoresbysund (-2.00h/-1.00h) 570 + { -4, -4, 0, 0, 125, 1 }, // Atlantic/Cape_Verde (-1.00h/-1.00h) 571 + { -4, 0, 1743296400, 1761440400, 126, 2 }, // Atlantic/Azores (-1.00h/0.00h) 572 + { 0, 0, 0, 0, 128, 1 }, // Atlantic/Reykjavik, Africa/Ouagadougou, Africa/Accra (0.00h/0.00h) 573 + { 0, 4, 1743296400, 1761440400, 129, 19 }, // Europe/London, Europe/Guernsey, Europe/Jersey (0.00h/1.00h) 574 + { 4, 4, 0, 0, 148, 1 }, // Africa/Algiers, Africa/Porto-Novo, Africa/Lagos (1.00h/1.00h) 575 + { 4, 8, 1743296400, 1761440400, 149, 20 }, // Europe/Brussels, Europe/Berlin, Europe/Amsterdam (1.00h/2.00h) 576 + { 8, 8, 0, 0, 169, 5 }, // Africa/Johannesburg, Africa/Gaborone, Africa/Mbabane (2.00h/2.00h) 577 + { 8, 12, 1743120000, 1761433200, 174, 1 }, // Asia/Jerusalem (2.00h/3.00h) 578 + { 8, 12, 1743285600, 1761426000, 175, 1 }, // Asia/Beirut (2.00h/3.00h) 579 + { 8, 12, 1743292800, 1761436800, 176, 1 }, // Europe/Chisinau (2.00h/3.00h) 580 + { 8, 12, 1743296400, 1761440400, 177, 10 }, // Europe/Tallinn, Europe/Helsinki, Europe/Mariehamn (2.00h/3.00h) 581 + { 8, 12, 1744416000, 1761346800, 187, 1 }, // Asia/Gaza (2.00h/3.00h) 582 + { 8, 12, 1745532000, 1761858000, 188, 4 }, // Africa/Cairo (2.00h/3.00h) 583 + { 12, 12, 0, 0, 192, 20 }, // Indian/Comoro, Indian/Mayotte, Indian/Antananarivo (3.00h/3.00h) 584 + { 14, 14, 0, 0, 212, 17 }, // Asia/Tehran (3.50h/3.50h) 585 + { 16, 16, 0, 0, 229, 14 }, // Indian/Mauritius, Indian/Reunion, Indian/Mahe (4.00h/4.00h) 586 + { 18, 18, 0, 0, 243, 6 }, // Asia/Kabul (4.50h/4.50h) 587 + { 20, 20, 0, 0, 249, 15 }, // Asia/Karachi, Asia/Qyzylorda, Asia/Oral (5.00h/5.00h) 588 + { 22, 22, 0, 0, 264, 20 }, // Asia/Calcutta, Asia/Colombo, Asia/Kolkata (5.50h/5.50h) 589 + { 23, 23, 0, 0, 284, 8 }, // Asia/Katmandu (5.75h/5.75h) 590 + { 24, 24, 0, 0, 292, 1 }, // Asia/Bishkek, Asia/Omsk, Asia/Dhaka (6.00h/6.00h) 591 + { 26, 26, 0, 0, 293, 2 }, // Asia/Rangoon, Indian/Cocos (6.50h/6.50h) 592 + { 28, 28, 0, 0, 295, 20 }, // Asia/Krasnoyarsk, Asia/Phnom_Penh, Asia/Vientiane (7.00h/7.00h) 593 + { 32, 32, 0, 0, 315, 20 }, // Asia/Taipei, Asia/Manila, Asia/Irkutsk (8.00h/8.00h) 594 + { 36, 36, 0, 0, 335, 20 }, // Pacific/Palau, Asia/Tokyo, Asia/Seoul (9.00h/9.00h) 595 + { 38, 38, 0, 0, 355, 3 }, // Australia/Darwin (9.50h/9.50h) 596 + { 38, 42, 1759593600, 1743872400, 358, 4 }, // Australia/Adelaide (9.50h/10.50h) 597 + { 40, 40, 0, 0, 362, 12 }, // Pacific/Port_Moresby, Pacific/Saipan, Pacific/Guam (10.00h/10.00h) 598 + { 40, 44, 1759593600, 1743868800, 374, 8 }, // Australia/Hobart, Australia/Sydney, Australia/Melbourne (10.00h/11.00h) 599 + { 42, 44, 1759593600, 1743865200, 382, 1 }, // Australia/Lord_Howe (10.50h/11.00h) 600 + { 44, 44, 0, 0, 383, 1 }, // Pacific/Efate, Pacific/Noumea, Pacific/Ponape (11.00h/11.00h) 601 + { 44, 48, 1759590000, 1743865200, 384, 1 }, // Pacific/Norfolk (11.00h/12.00h) 602 + { 48, 48, 0, 0, 385, 2 }, // Pacific/Fiji, Pacific/Tarawa, Pacific/Wallis (12.00h/12.00h) 603 + { 48, 52, 1758981600, 1743861600, 387, 14 }, // Pacific/Auckland (12.00h/13.00h) 604 + { 51, 55, 1758981600, 1743861600, 401, 1 }, // Pacific/Chatham (12.75h/13.75h) 605 + { 52, 52, 0, 0, 402, 6 }, // Pacific/Tongatapu, Pacific/Apia, Pacific/Enderbury (13.00h/13.00h) 606 + { 56, 56, 0, 0, 408, 1 }, // Pacific/Kiritimati (14.00h/14.00h) 400 607 }; 401 608 402 609 #define AIRPORT_TZ_LIST_COUNT (sizeof(airport_tz_list)/sizeof(airport_tz_list[0])) 403 - #define AIRPORT_CODE_POOL_COUNT 245 404 - #define AIRPORT_NAME_POOL_COUNT 245 610 + #define AIRPORT_CODE_POOL_COUNT 409 611 + #define AIRPORT_NAME_POOL_COUNT 409
+1 -1
src/c/clock_beat.c
··· 9 9 #define DAY_LENGTH 86400 10 10 11 11 // --- Static variables specific to Beat Clock --- 12 - static char s_beat_buffer[7]; // Buffer for Beat time string "@XXX.X\0" 12 + static char s_beat_buffer[7]; // Buffer for Beat time string "@XXX.X" 13 13 static int last_beat_time = -1; // Cache the last displayed beat time (multiplied by 10) 14 14 15 15 // --- Static helper function ---
+8 -19
src/c/clock_closest_airport_noon.h
··· 5 5 // IATA code of a randomly-chosen airport whose local time is the *closest past 6 6 // but not before* 12:00:00 (noon) relative to the current UTC. The 7 7 // underlying data come from the generated `airport_tz_list.c`, which is built 8 - // by `generate_airport_tz_list.py`. 8 + // by `generateAirportTzList.ts`. 9 9 // 10 10 // The public interface mirrors `clock_closest_noon.h`, so you can swap calls 11 11 // easily in `watchface.c`. ··· 33 33 #include "text_layer_util.h" 34 34 35 35 // Bring in the generated data table; make sure the build has already executed 36 - // generate_airport_tz_list.py. During early development you may still include 37 - // `tz_list.c` as a fallback; define USE_FALLBACK_TZ_LIST to do so. 38 - #ifdef USE_FALLBACK_TZ_LIST 39 - #include "tz_list.c" 40 - #define CODE_POOL tz_name_pool 41 - #define NAME_POOL tz_name_pool 42 - #define TZ_LIST tz_list 43 - #define TZ_LIST_COUNT TZ_LIST_COUNT 44 - #else 45 - #include "airport_tz_list.c" 46 - #define CODE_POOL airport_code_pool 47 - #define NAME_POOL airport_name_pool 48 - #define TZ_LIST airport_tz_list 49 - #define TZ_LIST_COUNT AIRPORT_TZ_LIST_COUNT 50 - // Bit-packed IATA code pool (15-bits per entry) 51 - extern const uint16_t airport_code_pool_bits[]; 52 - #endif 36 + // generate_airport_tz_list.py. 37 + #include "airport_tz_list.c" 38 + #define NAME_POOL airport_name_pool 39 + #define TZ_LIST airport_tz_list 40 + #define TZ_LIST_COUNT AIRPORT_TZ_LIST_COUNT 41 + // Bit-packed IATA code pool (15-bits per entry) 42 + extern const uint16_t airport_code_pool_bits[]; 53 43 54 44 #ifdef __cplusplus 55 45 extern "C" { ··· 81 71 // Internal constants / storage -------------------------------------------- 82 72 #define DAY_SECONDS (24 * 3600L) 83 73 84 - // static char s_airport_noon_buffer[40]; // code + MM:SS 85 74 static time_t s_last_update_time = -1; 86 75 static time_t s_last_re_eval_time = -1; 87 76 static char s_selected_code[4] = "---"; // IATA placeholder
-156
src/c/clock_closest_noon.c
··· 1 - #include "clock_closest_noon.h" 2 - #include <pebble.h> // Always include pebble for device builds 3 - #include <stdlib.h> // For rand() 4 - #include <stdint.h> // For uint32_t, int64_t 5 - #include <time.h> // For time_t, struct tm, gmtime, strcmp, strncmp 6 - #include <stdbool.h>// For bool 7 - #include <limits.h> // For LONG_MAX // Not strictly needed anymore, but harmless 8 - #include <string.h> // For strcmp, strncmp 9 - #include <stdio.h> // For snprintf 10 - #include "text_layer_util.h" 11 - 12 - // Include the generated timezone data structure definitions and list 13 - // This must contain TzInfo, tz_list[], and TZ_LIST_COUNT 14 - #include "tz_list.c" 15 - 16 - #define DAY_SECONDS (24 * 3600L) 17 - #define NOON_SECONDS (12 * 3600L) 18 - 19 - // --- Static variables specific to Closest Noon Clock --- 20 - static char s_closest_noon_buffer[40]; // Increased size for potentially longer names + MM:SS 21 - static time_t s_last_update_time = -1; 22 - static time_t s_last_re_evaluation_time = -1; 23 - 24 - // Stores the results of the last re-evaluation 25 - static const char *s_selected_city_name = "Wait..."; 26 - static float s_selected_offset_hours = 0.0f; // Store the active offset 27 - 28 - // --- Static helper functions --- 29 - 30 - /** 31 - * @brief Re-evaluates and selects the timezone whose local time is >= 12:00:00 32 - * and closest to 12:00:00, based on current UTC. 33 - * Updates the static s_selected_city_name and s_selected_offset_hours. 34 - * Should only be called at :00, :15, :30, :45 minutes past the hour (UTC). 35 - * 36 - * @param current_utc_t The current UTC time as time_t. 37 - */ 38 - static void update_selected_timezone_and_city(time_t current_utc_t) { 39 - // Seed for consistent randomness when multiple zones tie 40 - srand(current_utc_t); 41 - uint32_t utc_secs = current_utc_t % DAY_SECONDS; 42 - long best_delta = LONG_MAX; 43 - int best_count = 0; 44 - int best_candidates[TZ_LIST_COUNT]; 45 - // Find zones that have local time >= noon and minimal seconds past noon 46 - for (int i = 0; i < (int)TZ_LIST_COUNT; ++i) { 47 - const TzInfo *tz = &tz_list[i]; 48 - // Determine DST active 49 - bool is_dst = false; 50 - if (tz->dst_start_utc && tz->dst_end_utc) { 51 - int64_t now = (int64_t)current_utc_t; 52 - if ((tz->dst_start_utc <= tz->dst_end_utc && now >= tz->dst_start_utc && now < tz->dst_end_utc) || 53 - (tz->dst_start_utc > tz->dst_end_utc && (now >= tz->dst_start_utc || now < tz->dst_end_utc))) { 54 - is_dst = true; 55 - } 56 - } 57 - float off_h = is_dst ? tz->dst_offset_hours : tz->std_offset_hours; 58 - long local_secs = (long)utc_secs + (long)(off_h * 3600.0f); 59 - local_secs %= DAY_SECONDS; 60 - if (local_secs < 0) local_secs += DAY_SECONDS; 61 - if (local_secs < NOON_SECONDS) continue; 62 - long delta = local_secs - NOON_SECONDS; 63 - if (delta < best_delta) { 64 - best_delta = delta; 65 - best_count = 0; 66 - best_candidates[best_count++] = i; 67 - } else if (delta == best_delta && best_count < (int)TZ_LIST_COUNT) { 68 - best_candidates[best_count++] = i; 69 - } 70 - } 71 - if (best_count == 0) { 72 - s_selected_city_name = "Wait..."; 73 - s_selected_offset_hours = 0.0f; 74 - } else { 75 - int pick = (best_count == 1) ? 0 : (rand() % best_count); 76 - int idx = best_candidates[pick]; 77 - const TzInfo *tz = &tz_list[idx]; 78 - bool is_dst = (current_utc_t >= tz->dst_start_utc && current_utc_t < tz->dst_end_utc); 79 - s_selected_offset_hours = is_dst ? tz->dst_offset_hours : tz->std_offset_hours; 80 - int cnt = tz->name_count; 81 - int ni = (cnt == 1) ? 0 : (rand() % cnt); 82 - s_selected_city_name = tz_name_pool[tz->name_offset + ni]; 83 - } 84 - s_last_re_evaluation_time = current_utc_t; 85 - } 86 - 87 - 88 - // --- Interface Functions (Pebble only) --- 89 - 90 - // Initializes the city name TextLayer for Closest Noon 91 - TextLayer* clock_closest_noon_city_init(GRect bounds, Layer *window_layer) { 92 - TextLayer* layer = text_layer_util_create(bounds, window_layer, "Wait...", FONT_KEY_GOTHIC_24_BOLD); 93 - // Initialize static vars 94 - s_selected_city_name = "Wait..."; 95 - s_last_update_time = -1; 96 - s_last_re_evaluation_time = -1; 97 - return layer; 98 - } 99 - 100 - // Initializes the hero time TextLayer for Closest Noon 101 - TextLayer* clock_closest_noon_time_init(GRect bounds, Layer *window_layer) { 102 - TextLayer* layer = text_layer_util_create(bounds, window_layer, "--:--", FONT_KEY_LECO_42_NUMBERS); 103 - s_selected_offset_hours = 0.0f; 104 - return layer; 105 - } 106 - 107 - void clock_closest_noon_deinit(TextLayer *layer) { 108 - if (layer) { 109 - text_layer_destroy(layer); 110 - } 111 - } 112 - 113 - // Updates both the city and hero time TextLayers for Closest Noon 114 - void clock_closest_noon_update(TextLayer *city_layer, TextLayer *time_layer, time_t current_utc_t) { 115 - if (!city_layer || !time_layer) return; 116 - 117 - // Avoid redundant updates for the same second 118 - if (current_utc_t == s_last_update_time) { 119 - return; 120 - } 121 - s_last_update_time = current_utc_t; 122 - 123 - // --- Check if it's time for re-evaluation --- 124 - struct tm *utc_tm_struct = gmtime(&current_utc_t); 125 - bool needs_re_evaluation = false; 126 - if (utc_tm_struct && (utc_tm_struct->tm_min % 15 == 0) && (utc_tm_struct->tm_min != 45) && (utc_tm_struct->tm_sec == 0)) { 127 - if (current_utc_t != s_last_re_evaluation_time) { 128 - needs_re_evaluation = true; 129 - } 130 - } else if (s_last_re_evaluation_time == -1) { 131 - // Ensure initial evaluation happens if starting between intervals 132 - needs_re_evaluation = true; 133 - } 134 - 135 - if (needs_re_evaluation) { 136 - update_selected_timezone_and_city(current_utc_t); 137 - } 138 - 139 - // Format and set city name 140 - text_layer_set_text(city_layer, s_selected_city_name ? s_selected_city_name : "ERR"); 141 - 142 - // Calculate and format hero time (MM:SS) 143 - long offset_seconds = (long)(s_selected_offset_hours * 3600.0f); 144 - time_t local_epoch = current_utc_t + offset_seconds; 145 - struct tm *local_tm_struct = gmtime(&local_epoch); 146 - static char s_time_buffer[10]; 147 - if (local_tm_struct) { 148 - // Hero time: display minutes and seconds 149 - snprintf(s_time_buffer, sizeof(s_time_buffer), "%02d:%02d", 150 - local_tm_struct->tm_min, 151 - local_tm_struct->tm_sec); 152 - } else { 153 - snprintf(s_time_buffer, sizeof(s_time_buffer), "ERR"); 154 - } 155 - text_layer_set_text(time_layer, s_time_buffer); 156 - }
-19
src/c/clock_closest_noon.h
··· 1 - #ifndef CLOCK_CLOSEST_NOON_H 2 - #define CLOCK_CLOSEST_NOON_H 3 - 4 - #include <pebble.h> // Pebble time_t definition and UI types 5 - #include <stddef.h> // For size_t 6 - 7 - // Initializes the city name TextLayer for the Closest Noon clock 8 - TextLayer* clock_closest_noon_city_init(GRect bounds, Layer *window_layer); 9 - 10 - // Initializes the hero time TextLayer for the Closest Noon clock 11 - TextLayer* clock_closest_noon_time_init(GRect bounds, Layer *window_layer); 12 - 13 - // Deinitializes a Closest Noon TextLayer (city or time) 14 - void clock_closest_noon_deinit(TextLayer *layer); 15 - 16 - // Updates the Closest Noon city and time TextLayers 17 - void clock_closest_noon_update(TextLayer *city_layer, TextLayer *time_layer, time_t current_seconds_utc); 18 - 19 - #endif // CLOCK_CLOSEST_NOON_H
-43
src/c/clock_decimal.c
··· 1 - #include "clock_decimal.h" 2 - #include <pebble.h> 3 - #include <stdio.h> 4 - #include <time.h> 5 - #include "text_layer_util.h" 6 - 7 - static char s_buffer[10]; // Buffer for time string HH:MM:SS.ss 8 - 9 - // Updates the decimal-time TextLayer by converting local time to French decimal time inline 10 - void clock_decimal_update(TextLayer *text_layer, time_t system_seconds) { 11 - // Get local hours, minutes, seconds 12 - struct tm *local_tm = localtime(&system_seconds); 13 - uint32_t seconds_today = local_tm->tm_hour * 3600 + local_tm->tm_min * 60 + local_tm->tm_sec; 14 - 15 - // Compute decimal seconds: (seconds_today * 100000) / 86400 16 - uint32_t total_decimal_seconds = (uint32_t)(((uint64_t)seconds_today * 100000ULL) / 86400ULL); 17 - uint32_t dec_hour = total_decimal_seconds / 10000; 18 - uint32_t dec_min = (total_decimal_seconds / 100) % 100; 19 - uint32_t dec_sec = total_decimal_seconds % 100; 20 - 21 - // Format and display 22 - snprintf(s_buffer, sizeof(s_buffer), "%lu:%02lu:%02lu", 23 - (unsigned long)dec_hour, 24 - (unsigned long)dec_min, 25 - (unsigned long)dec_sec); 26 - text_layer_set_text(text_layer, s_buffer); 27 - } 28 - 29 - // Initializes the decimal time TextLayer 30 - TextLayer* clock_decimal_init(GRect bounds, Layer *window_layer) { 31 - TextLayer *text_layer = text_layer_util_create(bounds, window_layer, "", FONT_KEY_GOTHIC_18_BOLD); 32 - 33 - // Initialize with placeholder or current time 34 - time_t temp = time(NULL); 35 - clock_decimal_update(text_layer, temp); 36 - 37 - return text_layer; 38 - } 39 - 40 - // Deinitializes the decimal time TextLayer 41 - void clock_decimal_deinit(TextLayer *text_layer) { 42 - text_layer_destroy(text_layer); 43 - }
-12
src/c/clock_decimal.h
··· 1 - #pragma once 2 - 3 - #include <pebble.h> 4 - 5 - // Initializes the decimal time TextLayer 6 - TextLayer* clock_decimal_init(GRect bounds, Layer *window_layer); 7 - 8 - // Updates the decimal time TextLayer 9 - void clock_decimal_update(TextLayer *text_layer, time_t system_seconds); 10 - 11 - // Deinitializes the decimal time TextLayer 12 - void clock_decimal_deinit(TextLayer *text_layer);
-97
src/c/clock_noonzone.c
··· 1 - #include "clock_noonzone.h" 2 - #include <pebble.h> 3 - #include <time.h> // For time_t, struct tm, gmtime 4 - #include <string.h> // For NULL definition (consider stddef.h?) 5 - #include <stdio.h> // For snprintf 6 - #include "text_layer_util.h" 7 - 8 - // --- Static variables specific to Noon Zone Clock --- 9 - static char s_noonzone_buffer[16]; // Buffer for "NAME:MM:SS\0" 10 - static int last_noonzone_update_secs = -1; 11 - static int last_utc_hour = -1; 12 - static const char *last_zone_name_ptr = NULL; 13 - 14 - // --- Static helper function --- 15 - /** 16 - * Gets the military timezone name for the longitude where it is currently noon. 17 - * Includes caching based on UTC hour. 18 - */ 19 - static const char* get_noon_zone_name(int utc_hour) { 20 - if (utc_hour == last_utc_hour && last_zone_name_ptr != NULL) { 21 - return last_zone_name_ptr; 22 - } 23 - 24 - const char *name = "???"; 25 - switch(utc_hour){ 26 - case 12: name="ZULU"; break; 27 - case 11: name="ALPHA"; break; 28 - case 10: name="BRAVO"; break; 29 - case 9: name="CHARLIE"; break; 30 - case 8: name="DELTA"; break; 31 - case 7: name="ECHO"; break; 32 - case 6: name="FOXTROT"; break; 33 - case 5: name="GOLF"; break; 34 - case 4: name="HOTEL"; break; 35 - case 3: name="JULIET"; break; 36 - case 2: name="KILO"; break; 37 - case 1: name="LIMA"; break; 38 - case 0: name="MIKE"; break; 39 - case 23: name="NOVEMBER"; break; 40 - case 22: name="OSCAR"; break; 41 - case 21: name="PAPA"; break; 42 - case 20: name="QUEBEC"; break; 43 - case 19: name="ROMEO"; break; 44 - case 18: name="SIERRA"; break; 45 - case 17: name="TANGO"; break; 46 - case 16: name="UNIFORM"; break; 47 - case 15: name="VICTOR"; break; 48 - case 14: name="WHISKEY"; break; 49 - case 13: name="X-RAY"; break; 50 - // default: name="???"; // Already initialized 51 - } 52 - last_utc_hour = utc_hour; 53 - last_zone_name_ptr = name; 54 - return name; 55 - } 56 - 57 - // --- Pebble UI Interface Functions --- 58 - 59 - TextLayer* clock_noonzone_init(GRect bounds, Layer *window_layer) { 60 - TextLayer* layer = text_layer_util_create(bounds, window_layer, "ZONE:--:--", FONT_KEY_GOTHIC_18_BOLD); 61 - return layer; 62 - } 63 - 64 - void clock_noonzone_deinit(TextLayer *layer) { 65 - if (layer) { 66 - text_layer_destroy(layer); 67 - } 68 - } 69 - 70 - void clock_noonzone_update(TextLayer *layer, time_t current_seconds_utc) { 71 - if (!layer) return; 72 - 73 - // Check cache first to avoid unnecessary calculation/string formatting 74 - if (current_seconds_utc == last_noonzone_update_secs) { 75 - return; 76 - } 77 - 78 - // Perform calculations 79 - struct tm *utc_tm = gmtime(&current_seconds_utc); 80 - if (!utc_tm) { 81 - text_layer_set_text(layer, "ERR:TIME"); // Show error on layer 82 - last_noonzone_update_secs = current_seconds_utc; // Cache update time even on error 83 - return; 84 - } 85 - 86 - const char *zone_name = get_noon_zone_name(utc_tm->tm_hour); 87 - 88 - // Format string into static buffer 89 - snprintf(s_noonzone_buffer, sizeof(s_noonzone_buffer), 90 - "%s:%02d:%02d", 91 - zone_name, 92 - utc_tm->tm_min, 93 - utc_tm->tm_sec); 94 - 95 - text_layer_set_text(layer, s_noonzone_buffer); 96 - last_noonzone_update_secs = current_seconds_utc; 97 - }
-16
src/c/clock_noonzone.h
··· 1 - #ifndef CLOCK_NOONZONE_H 2 - #define CLOCK_NOONZONE_H 3 - 4 - #include <pebble.h> 5 - #include <stddef.h> // For size_t 6 - 7 - // Initializes the Noon Zone clock layer 8 - TextLayer* clock_noonzone_init(GRect bounds, Layer *window_layer); 9 - 10 - // Deinitializes the Noon Zone clock layer 11 - void clock_noonzone_deinit(TextLayer *layer); 12 - 13 - // Updates the Noon Zone clock layer 14 - void clock_noonzone_update(TextLayer *layer, time_t current_seconds_utc); 15 - 16 - #endif // CLOCK_NOONZONE_H
+16 -20
src/c/clock_tid.c
··· 8 8 static uint64_t last_timestamp; 9 9 static char s_tid_buffer[14]; 10 10 11 + // Helper to encode a value into a fixed-width base-32 string, right-to-left, padded with S32_CHAR[0] 12 + static void encode_to_base32_fixed_width(char *out_buf, size_t width, uint64_t val) { 13 + for (size_t i = 0; i < width; ++i) { 14 + out_buf[i] = S32_CHAR[0]; // Pre-fill with padding character 15 + } 16 + size_t current_pos = width; 17 + while (val && current_pos) { 18 + out_buf[--current_pos] = S32_CHAR[val & 31]; 19 + val >>= 5; 20 + } 21 + } 22 + 11 23 // Generate monotonic TID string into tid_buffer 12 - void clock_tid_get_string(char *tid_buffer, size_t tid_buffer_len, time_t seconds, uint16_t milliseconds) { 24 + static void clock_tid_get_string(char *tid_buffer, size_t tid_buffer_len, time_t seconds, uint16_t milliseconds) { 13 25 if (tid_buffer_len < sizeof(s_tid_buffer)) return; 14 26 15 27 uint64_t current_micros = (uint64_t)seconds * 1000000 + (uint64_t)milliseconds * 1000; ··· 18 30 } 19 31 last_timestamp = current_micros; 20 32 21 - // Encode 11-char base-32 timestamp (pad with '2') 22 - size_t pos = 11; 23 - for (size_t i = 0; i < pos; ++i) { 24 - tid_buffer[i] = S32_CHAR[0]; 25 - } 26 - uint64_t v = current_micros; 27 - while (v && pos) { 28 - tid_buffer[--pos] = S32_CHAR[v & 31]; 29 - v >>= 5; 30 - } 33 + // Encode 11-char base-32 timestamp 34 + encode_to_base32_fixed_width(tid_buffer, 11, current_micros); 31 35 32 36 // Encode 2-char random clock ID (0-1023) 33 37 uint16_t cid = (uint16_t)(rand() % 1024); 34 - pos = 2; 35 - for (size_t i = 0; i < pos; ++i) { 36 - tid_buffer[11 + i] = S32_CHAR[0]; 37 - } 38 - uint16_t v2 = cid; 39 - while (v2 && pos) { 40 - tid_buffer[11 + --pos] = S32_CHAR[v2 & 31]; 41 - v2 >>= 5; 42 - } 38 + encode_to_base32_fixed_width(tid_buffer + 11, 2, cid); 43 39 44 40 tid_buffer[13] = '\0'; 45 41 }
-400
src/c/tz_list.c
··· 1 - // Auto-generated by generateTzList.ts 2 - // Year 2025 DST data (Luxon / IANA) 3 - 4 - #include <stdint.h> 5 - 6 - static const char* tz_name_pool[] = { 7 - "Midway", 8 - "Niue", 9 - "Pago Pago", 10 - "Honolulu", 11 - "Rarotonga", 12 - "Tahiti", 13 - "Adak", 14 - "Marquesas", 15 - "Gambier", 16 - "Anchorage", 17 - "Pitcairn", 18 - "Los Angeles", 19 - "Tijuana", 20 - "Vancouver", 21 - "Hermosillo", 22 - "Phoenix", 23 - "Whitehorse", 24 - "Ciudad Juarez", 25 - "Denver", 26 - "Edmonton", 27 - "Belize", 28 - "Costa Rica", 29 - "El Salvador", 30 - "Galapagos", 31 - "Guatemala", 32 - "Managua", 33 - "Mexico City", 34 - "Regina", 35 - "Tegucigalpa", 36 - "Chicago", 37 - "Matamoros", 38 - "Winnipeg", 39 - "Easter", 40 - "Atikokan", 41 - "Bogota", 42 - "Cancun", 43 - "Cayman", 44 - "Guayaquil", 45 - "Jamaica", 46 - "Lima", 47 - "Panama", 48 - "Rio Branco", 49 - "Havana", 50 - "Grand Turk", 51 - "Nassau", 52 - "New York", 53 - "Port-au-Prince", 54 - "Toronto", 55 - "Anguilla", 56 - "Antigua", 57 - "Aruba", 58 - "Barbados", 59 - "Blanc-Sablon", 60 - "Caracas", 61 - "Curacao", 62 - "Dominica", 63 - "Grenada", 64 - "Guadeloupe", 65 - "Guyana", 66 - "Kralendijk", 67 - "La Paz", 68 - "Lower Princes", 69 - "Manaus", 70 - "Marigot", 71 - "Martinique", 72 - "Montserrat", 73 - "Port of Spain", 74 - "Puerto Rico", 75 - "Santo Domingo", 76 - "St Barthelemy", 77 - "St Kitts", 78 - "St Lucia", 79 - "St Thomas", 80 - "St Vincent", 81 - "Tortola", 82 - "Bermuda", 83 - "Halifax", 84 - "Thule", 85 - "Santiago", 86 - "St Johns", 87 - "Asuncion", 88 - "Buenos Aires", 89 - "Cayenne", 90 - "Montevideo", 91 - "Palmer", 92 - "Paramaribo", 93 - "Punta Arenas", 94 - "Sao Paulo", 95 - "Stanley", 96 - "Miquelon", 97 - "Noronha", 98 - "South Georgia", 99 - "Nuuk", 100 - "Cape Verde", 101 - "Azores", 102 - "Abidjan", 103 - "Accra", 104 - "Bamako", 105 - "Banjul", 106 - "Bissau", 107 - "Conakry", 108 - "Dakar", 109 - "Danmarkshavn", 110 - "Freetown", 111 - "Lome", 112 - "Monrovia", 113 - "Nouakchott", 114 - "Ouagadougou", 115 - "Reykjavik", 116 - "Sao Tome", 117 - "St Helena", 118 - "Canary", 119 - "Dublin", 120 - "Faroe", 121 - "Guernsey", 122 - "Isle of Man", 123 - "Jersey", 124 - "Lisbon", 125 - "London", 126 - "Troll", 127 - "Algiers", 128 - "Bangui", 129 - "Brazzaville", 130 - "Casablanca", 131 - "Douala", 132 - "El Aaiun", 133 - "Kinshasa", 134 - "Lagos", 135 - "Libreville", 136 - "Luanda", 137 - "Malabo", 138 - "Ndjamena", 139 - "Niamey", 140 - "Porto-Novo", 141 - "Tunis", 142 - "Amsterdam", 143 - "Andorra", 144 - "Belgrade", 145 - "Berlin", 146 - "Bratislava", 147 - "Brussels", 148 - "Budapest", 149 - "Copenhagen", 150 - "Gibraltar", 151 - "Ljubljana", 152 - "Longyearbyen", 153 - "Luxembourg", 154 - "Madrid", 155 - "Malta", 156 - "Monaco", 157 - "Oslo", 158 - "Paris", 159 - "Podgorica", 160 - "Prague", 161 - "Rome", 162 - "San Marino", 163 - "Sarajevo", 164 - "Skopje", 165 - "Stockholm", 166 - "Tirane", 167 - "Vaduz", 168 - "Vatican", 169 - "Vienna", 170 - "Warsaw", 171 - "Zagreb", 172 - "Zurich", 173 - "Blantyre", 174 - "Bujumbura", 175 - "Gaborone", 176 - "Harare", 177 - "Johannesburg", 178 - "Juba", 179 - "Kaliningrad", 180 - "Khartoum", 181 - "Kigali", 182 - "Lubumbashi", 183 - "Lusaka", 184 - "Maputo", 185 - "Maseru", 186 - "Mbabane", 187 - "Tripoli", 188 - "Windhoek", 189 - "Jerusalem", 190 - "Beirut", 191 - "Chisinau", 192 - "Athens", 193 - "Bucharest", 194 - "Helsinki", 195 - "Kyiv", 196 - "Mariehamn", 197 - "Nicosia", 198 - "Riga", 199 - "Sofia", 200 - "Tallinn", 201 - "Vilnius", 202 - "Hebron", 203 - "Cairo", 204 - "Addis Ababa", 205 - "Aden", 206 - "Amman", 207 - "Antananarivo", 208 - "Asmara", 209 - "Baghdad", 210 - "Bahrain", 211 - "Comoro", 212 - "Damascus", 213 - "Dar es Salaam", 214 - "Djibouti", 215 - "Istanbul", 216 - "Kampala", 217 - "Kuwait", 218 - "Mayotte", 219 - "Minsk", 220 - "Mogadishu", 221 - "Moscow", 222 - "Nairobi", 223 - "Qatar", 224 - "Riyadh", 225 - "Simferopol", 226 - "Syowa", 227 - "Tehran", 228 - "Baku", 229 - "Dubai", 230 - "Mahe", 231 - "Mauritius", 232 - "Muscat", 233 - "Reunion", 234 - "Samara", 235 - "Tbilisi", 236 - "Yerevan", 237 - "Kabul", 238 - "Almaty", 239 - "Ashgabat", 240 - "Dushanbe", 241 - "Karachi", 242 - "Kerguelen", 243 - "Maldives", 244 - "Mawson", 245 - "Tashkent", 246 - "Yekaterinburg", 247 - "Colombo", 248 - "Kolkata", 249 - "Kathmandu", 250 - "Bishkek", 251 - "Chagos", 252 - "Dhaka", 253 - "Omsk", 254 - "Thimphu", 255 - "Urumqi", 256 - "Cocos", 257 - "Yangon", 258 - "Bangkok", 259 - "Christmas", 260 - "Davis", 261 - "Ho Chi Minh", 262 - "Hovd", 263 - "Jakarta", 264 - "Novosibirsk", 265 - "Phnom Penh", 266 - "Vientiane", 267 - "Brunei", 268 - "Casey", 269 - "Hong Kong", 270 - "Irkutsk", 271 - "Kuala Lumpur", 272 - "Macau", 273 - "Makassar", 274 - "Manila", 275 - "Perth", 276 - "Shanghai", 277 - "Singapore", 278 - "Taipei", 279 - "Ulaanbaatar", 280 - "Eucla", 281 - "Chita", 282 - "Dili", 283 - "Jayapura", 284 - "Palau", 285 - "Pyongyang", 286 - "Seoul", 287 - "Tokyo", 288 - "Darwin", 289 - "Adelaide", 290 - "Brisbane", 291 - "Chuuk", 292 - "DumontDUrville", 293 - "Guam", 294 - "Port Moresby", 295 - "Saipan", 296 - "Vladivostok", 297 - "Sydney", 298 - "Lord Howe", 299 - "Bougainville", 300 - "Efate", 301 - "Guadalcanal", 302 - "Kosrae", 303 - "Noumea", 304 - "Sakhalin", 305 - "Norfolk", 306 - "Fiji", 307 - "Funafuti", 308 - "Kamchatka", 309 - "Majuro", 310 - "Nauru", 311 - "Tarawa", 312 - "Wake", 313 - "Wallis", 314 - "Auckland", 315 - "McMurdo", 316 - "Chatham", 317 - "Apia", 318 - "Fakaofo", 319 - "Kanton", 320 - "Tongatapu", 321 - "Kiritimati", 322 - }; 323 - 324 - typedef struct { 325 - float std_offset_hours; 326 - float dst_offset_hours; 327 - int64_t dst_start_utc; 328 - int64_t dst_end_utc; 329 - int name_offset; 330 - int name_count; 331 - } TzInfo; 332 - 333 - static const TzInfo tz_list[] = { 334 - { -11.00f, -11.00f, 0LL, 0LL, 0, 3 }, 335 - { -10.00f, -10.00f, 0LL, 0LL, 3, 3 }, 336 - { -10.00f, -9.00f, 1741521600LL, 1762081200LL, 6, 1 }, 337 - { -9.50f, -9.50f, 0LL, 0LL, 7, 1 }, 338 - { -9.00f, -9.00f, 0LL, 0LL, 8, 1 }, 339 - { -9.00f, -8.00f, 1741518000LL, 1762077600LL, 9, 1 }, 340 - { -8.00f, -8.00f, 0LL, 0LL, 10, 1 }, 341 - { -8.00f, -7.00f, 1741514400LL, 1762074000LL, 11, 3 }, 342 - { -7.00f, -7.00f, 0LL, 0LL, 14, 3 }, 343 - { -7.00f, -6.00f, 1741510800LL, 1762070400LL, 17, 3 }, 344 - { -6.00f, -6.00f, 0LL, 0LL, 20, 9 }, 345 - { -6.00f, -5.00f, 1741507200LL, 1762066800LL, 29, 3 }, 346 - { -6.00f, -5.00f, 1757217600LL, 1743908400LL, 32, 1 }, 347 - { -5.00f, -5.00f, 0LL, 0LL, 33, 9 }, 348 - { -5.00f, -4.00f, 1741496400LL, 1762059600LL, 42, 1 }, 349 - { -5.00f, -4.00f, 1741503600LL, 1762063200LL, 43, 5 }, 350 - { -4.00f, -4.00f, 0LL, 0LL, 48, 27 }, 351 - { -4.00f, -3.00f, 1741500000LL, 1762059600LL, 75, 3 }, 352 - { -4.00f, -3.00f, 1757217600LL, 1743908400LL, 78, 1 }, 353 - { -3.50f, -2.50f, 1741496400LL, 1762056000LL, 79, 1 }, 354 - { -3.00f, -3.00f, 0LL, 0LL, 80, 9 }, 355 - { -3.00f, -2.00f, 1741496400LL, 1762056000LL, 89, 1 }, 356 - { -2.00f, -2.00f, 0LL, 0LL, 90, 2 }, 357 - { -2.00f, -1.00f, 1743296400LL, 1761440400LL, 92, 1 }, 358 - { -1.00f, -1.00f, 0LL, 0LL, 93, 1 }, 359 - { -1.00f, 0.00f, 1743296400LL, 1761440400LL, 94, 1 }, 360 - { 0.00f, 0.00f, 0LL, 0LL, 95, 16 }, 361 - { 0.00f, 1.00f, 1743296400LL, 1761440400LL, 111, 8 }, 362 - { 0.00f, 2.00f, 1743296400LL, 1761440400LL, 119, 1 }, 363 - { 1.00f, 1.00f, 0LL, 0LL, 120, 15 }, 364 - { 1.00f, 2.00f, 1743296400LL, 1761440400LL, 135, 31 }, 365 - { 2.00f, 2.00f, 0LL, 0LL, 166, 16 }, 366 - { 2.00f, 3.00f, 1743120000LL, 1761433200LL, 182, 1 }, 367 - { 2.00f, 3.00f, 1743285600LL, 1761426000LL, 183, 1 }, 368 - { 2.00f, 3.00f, 1743292800LL, 1761436800LL, 184, 1 }, 369 - { 2.00f, 3.00f, 1743296400LL, 1761440400LL, 185, 10 }, 370 - { 2.00f, 3.00f, 1744416000LL, 1761346800LL, 195, 1 }, 371 - { 2.00f, 3.00f, 1745532000LL, 1761858000LL, 196, 1 }, 372 - { 3.00f, 3.00f, 0LL, 0LL, 197, 23 }, 373 - { 3.50f, 3.50f, 0LL, 0LL, 220, 1 }, 374 - { 4.00f, 4.00f, 0LL, 0LL, 221, 9 }, 375 - { 4.50f, 4.50f, 0LL, 0LL, 230, 1 }, 376 - { 5.00f, 5.00f, 0LL, 0LL, 231, 9 }, 377 - { 5.50f, 5.50f, 0LL, 0LL, 240, 2 }, 378 - { 5.75f, 5.75f, 0LL, 0LL, 242, 1 }, 379 - { 6.00f, 6.00f, 0LL, 0LL, 243, 6 }, 380 - { 6.50f, 6.50f, 0LL, 0LL, 249, 2 }, 381 - { 7.00f, 7.00f, 0LL, 0LL, 251, 9 }, 382 - { 8.00f, 8.00f, 0LL, 0LL, 260, 13 }, 383 - { 8.75f, 8.75f, 0LL, 0LL, 273, 1 }, 384 - { 9.00f, 9.00f, 0LL, 0LL, 274, 7 }, 385 - { 9.50f, 9.50f, 0LL, 0LL, 281, 1 }, 386 - { 9.50f, 10.50f, 1759593600LL, 1743872400LL, 282, 1 }, 387 - { 10.00f, 10.00f, 0LL, 0LL, 283, 7 }, 388 - { 10.00f, 11.00f, 1759593600LL, 1743868800LL, 290, 1 }, 389 - { 10.50f, 11.00f, 1759593600LL, 1743865200LL, 291, 1 }, 390 - { 11.00f, 11.00f, 0LL, 0LL, 292, 6 }, 391 - { 11.00f, 12.00f, 1759590000LL, 1743865200LL, 298, 1 }, 392 - { 12.00f, 12.00f, 0LL, 0LL, 299, 8 }, 393 - { 12.00f, 13.00f, 1758981600LL, 1743861600LL, 307, 2 }, 394 - { 12.75f, 13.75f, 1758981600LL, 1743861600LL, 309, 1 }, 395 - { 13.00f, 13.00f, 0LL, 0LL, 310, 4 }, 396 - { 14.00f, 14.00f, 0LL, 0LL, 314, 1 }, 397 - }; 398 - 399 - #define TZ_LIST_COUNT (sizeof(tz_list)/sizeof(tz_list[0])) 400 - #define TZ_NAME_POOL_COUNT (sizeof(tz_name_pool)/sizeof(tz_name_pool[0]))
+44 -26
src/c/watchface.c
··· 16 16 #include "clock_beat.h" 17 17 #include "clock_closest_airport_noon.h" 18 18 #include "clock_tid.h" 19 - // #include "clock_decimal.h" 20 19 21 20 // --- Clock Modules & Settings --- 22 21 #define SETTINGS_KEY 1 ··· 48 47 static TextLayer *s_airport_noon_time_layer; 49 48 static TextLayer *s_tid_layer; 50 49 static TextLayer *s_beat_layer; 50 + 51 + // --- Layout Constants --- 52 + // These can be tweaked for different visual arrangements. 53 + static const int LAYER_AIRPORT_CODE_HEIGHT = 28; 54 + static const int LAYER_AIRPORT_NAME_HEIGHT = 28; 55 + static const int LAYER_AIRPORT_TIME_HEIGHT = 42; // Approximate height for FONT_KEY_LECO_42_NUMBERS 56 + static const int FOOTER_AREA_HEIGHT = 48; 57 + static const int FOOTER_TID_HEIGHT = 28; 58 + 59 + // Padding and Adjustments 60 + static const int AIRPORT_NAME_X_PADDING = 3; 61 + static const int AIRPORT_NAME_WIDTH_ADJUST = 5; // Total reduction (e.g., 2*padding + 1) 62 + static const int AIRPORT_TIME_Y_ADJUST = -7; // Fine-tuning vertical position 63 + static const int FOOTER_TID_Y_ADJUST = -1; 64 + static const int FOOTER_BEAT_Y_ADJUST = -3; 51 65 52 66 // --- Pebble Window Management --- 53 67 ··· 96 110 // Apply updated colors immediately 97 111 apply_color_scheme(); 98 112 99 - // Potentially force an update if needed (e.g., re-pick airport) 100 - s_last_re_eval_time = -1; // Force re-evaluation on next tick 113 + // Potentially force an update if needed 114 + s_last_re_eval_time = -1; // Force re-evaluation 101 115 } 102 116 103 117 // Handles updates from the TickTimerService ··· 125 139 static void main_window_load(Window *window) { 126 140 Layer *window_layer = window_get_root_layer(window); 127 141 GRect bounds = layer_get_bounds(window_layer); 128 - // Hero area for Closest Noon: split into city + large time 129 - int footer_h = 48; 130 - int hero_h = bounds.size.h - footer_h; 131 - const int city_h = 28; 132 - const int name_h = 28; // height for airport name (increased to fit descenders) 133 - const int usable_h = hero_h - city_h - name_h; 134 - const int time_font_h = 42; 135 - // Create city name line 142 + 143 + // Calculated heights based on constants 144 + int hero_h = bounds.size.h - FOOTER_AREA_HEIGHT; 145 + const int usable_h = hero_h - LAYER_AIRPORT_CODE_HEIGHT - LAYER_AIRPORT_NAME_HEIGHT; 146 + 147 + // Create city name line (IATA Code) 136 148 s_airport_noon_code_layer = clock_closest_airport_noon_code_init( 137 - GRect(0, 0, bounds.size.w, city_h), window_layer); 149 + GRect(0, 0, bounds.size.w, LAYER_AIRPORT_CODE_HEIGHT), window_layer); 138 150 text_layer_set_text_alignment(s_airport_noon_code_layer, GTextAlignmentCenter); 151 + 139 152 // Create airport name line below the IATA code 140 - s_airport_noon_name_layer = text_layer_create(GRect(3, name_h, bounds.size.w - 5, name_h)); 141 - text_layer_set_font(s_airport_noon_name_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24)); 142 - text_layer_set_background_color(s_airport_noon_name_layer, GColorClear); // Make background transparent 143 - text_layer_set_text_alignment(s_airport_noon_name_layer, GTextAlignmentCenter); 144 - layer_add_child(window_layer, text_layer_get_layer(s_airport_noon_name_layer)); 145 - // Create hero time line, vertically centered 146 - int time_y = city_h + name_h + (usable_h - time_font_h) / 2 - 7; 153 + s_airport_noon_name_layer = text_layer_util_create(GRect( 154 + AIRPORT_NAME_X_PADDING, 155 + LAYER_AIRPORT_CODE_HEIGHT, // Positioned below the code layer 156 + bounds.size.w - AIRPORT_NAME_WIDTH_ADJUST, 157 + LAYER_AIRPORT_NAME_HEIGHT), 158 + window_layer, 159 + "", // Initial text, will be updated by tick_handler 160 + FONT_KEY_GOTHIC_24); 161 + // text_layer_set_text_alignment is GTextAlignmentCenter by default in text_layer_util_create 162 + // text_layer_set_background_color is GColorClear by default in text_layer_util_create 163 + // layer_add_child is handled by text_layer_util_create 164 + 165 + // Create hero time line, vertically centered in its usable area 166 + int time_y = LAYER_AIRPORT_CODE_HEIGHT + LAYER_AIRPORT_NAME_HEIGHT + (usable_h - LAYER_AIRPORT_TIME_HEIGHT) / 2 + AIRPORT_TIME_Y_ADJUST; 147 167 s_airport_noon_time_layer = clock_closest_airport_noon_time_init( 148 - GRect(0, time_y, bounds.size.w, time_font_h), window_layer); 168 + GRect(0, time_y, bounds.size.w, LAYER_AIRPORT_TIME_HEIGHT), window_layer); 149 169 150 170 // Setup footer area 151 171 int w = bounds.size.w; 152 172 int h = bounds.size.h; 153 - int footer_y = h - footer_h; 154 - // Two line heights to fit fonts without clipping 155 - int tid_h = 28; // tall enough for 18px font + padding 156 - int beat_h = footer_h - tid_h; 173 + int footer_y = h - FOOTER_AREA_HEIGHT; 174 + int beat_h = FOOTER_AREA_HEIGHT - FOOTER_TID_HEIGHT; // Calculated 157 175 158 176 // Footer line 1: TID (bigger, center aligned) 159 - s_tid_layer = clock_tid_init(GRect(0, footer_y - 1, w, tid_h), window_layer); 177 + s_tid_layer = clock_tid_init(GRect(0, footer_y + FOOTER_TID_Y_ADJUST, w, FOOTER_TID_HEIGHT), window_layer); 160 178 text_layer_set_font(s_tid_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD)); 161 179 text_layer_set_text_alignment(s_tid_layer, GTextAlignmentCenter); 162 180 163 181 // Footer line 2: Beat (smaller, center aligned) 164 - s_beat_layer = clock_beat_init(GRect(0, footer_y + tid_h - 3, w, beat_h), window_layer); 182 + s_beat_layer = clock_beat_init(GRect(0, footer_y + FOOTER_TID_HEIGHT + FOOTER_BEAT_Y_ADJUST, w, beat_h), window_layer); 165 183 text_layer_set_font(s_beat_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18)); 166 184 text_layer_set_text_alignment(s_beat_layer, GTextAlignmentCenter); 167 185