1// Single source of truth for the release. Bump VERSION on a new release and 2// every download URL below is rebuilt automatically. 3const VERSION = "4.1.0"; 4const TAG = "v" + VERSION; 5const RELEASE_BASE = "https://github.com/Serial-Studio/Serial-Studio/releases/download/" + TAG; 6const asset = (suffix) => `${RELEASE_BASE}/Serial-Studio-Pro-${VERSION}-${suffix}`; 7 8const config = { 9 version: { 10 latest: TAG, 11 windows: TAG, 12 macos: TAG, 13 linux: TAG 14 }, 15 16 downloads: { 17 // Windows 18 windows: asset("Windows.msi"), 19 windowsPortable: asset("Windows-Portable.zip"), 20 microsoftStore: "https://apps.microsoft.com/detail/9N5PZLKJCDP7", 21 22 // macOS (universal) 23 macos: asset("macOS.dmg"), 24 25 // Linux â x64 26 linux: asset("Linux-x64.AppImage"), 27 linuxX64AppImage: asset("Linux-x64.AppImage"), 28 linuxX64Deb: asset("Linux-x64.deb"), 29 linuxX64Rpm: asset("Linux-x64.rpm"), 30 31 // Linux â ARM64 (Raspberry Pi etc.) 32 linuxArm64AppImage: asset("Linux-arm64.AppImage"), 33 linuxArm64Deb: asset("Linux-arm64.deb"), 34 linuxArm64Rpm: asset("Linux-arm64.rpm"), 35 36 flathub: "https://flathub.org/apps/com.serial_studio.Serial-Studio" 37 }, 38 39 links: { 40 github: "https://github.com/Serial-Studio/Serial-Studio", 41 wiki: "https://github.com/Serial-Studio/Serial-Studio/wiki", 42 examples: "https://github.com/Serial-Studio/Serial-Studio/tree/master/examples", 43 faq: "https://serial-studio.com/help#faq", 44 releases: "https://github.com/Serial-Studio/Serial-Studio/releases", 45 license: "https://github.com/Serial-Studio/Serial-Studio/blob/master/LICENSE.md", 46 gpl: "https://github.com/Serial-Studio/Serial-Studio/blob/master/LICENSES/GPL-3.0-only.txt", 47 store: "https://store.serial-studio.com/checkout/buy/e33e6d04-639f-46b7-bd68-b46d341c5b16", 48 instagram: "https://instagram.com/serialstudio.app", 49 youtube: "https://www.youtube.com/@serial-studio-app" 50 }, 51 52 contact: { 53 email: "[email protected]", 54 formspree: "https://formspree.io/f/xbdjodnk" 55 }, 56 57 // Rendered into the "Trusted by" carousel on index.html (see applyConfig). 58 // To add a client: drop a logo in images/clients/ and add an entry here. 59 companies: [ 60 { name: "Teledyne", url: "https://www.teledyne.com/", logo: "images/clients/teledyne.png" }, 61 { name: "Bonnel", url: "https://bonnel.cz/", logo: "images/clients/bonnel.png" }, 62 { name: "Harvard University", url: "https://www.harvard.edu/", logo: "images/clients/harvard.png" }, 63 { name: "Windracers", url: "https://windracers.com/", logo: "images/clients/windracers.png" }, 64 { name: "Kemper", url: "https://kemper.eu/", logo: "images/clients/kemper.png" }, 65 { name: "Spectrum Medical", url: "https://www.spectrummedical.com/", logo: "images/clients/spectrum-medical.png" }, 66 { name: "Terranova", url: "https://www.terranova.inc/", logo: "images/clients/terranova.png" }, 67 { name: "NXP Semiconductors", url: "https://www.nxp.com/", logo: "images/clients/nxp.png" }, 68 { name: "Aether Space", url: "https://aetherspace.be/", logo: "images/clients/aether.png" }, 69 { name: "Newbury Innovation", url: "https://www.newburyelectronics.co.uk/innovation/", logo: "images/clients/newbury.png" }, 70 { name: "Sorcerer", url: "https://www.sorcerer.earth/", logo: "images/clients/sorcerer.png" }, 71 { name: "University of Bath", url: "https://www.bath.ac.uk/", logo: "images/clients/bath.png" }, 72 { name: "Spherie", url: "https://www.spherie.com/", logo: "images/clients/spherie.png" }, 73 { name: "Critical Software", url: "https://criticalsoftware.com/", logo: "images/clients/critical.png" }, 74 { name: "Redlite", url: "https://redlite.nz/", logo: "images/clients/redlite.png" }, 75 { name: "NJIT Baja Racing", url: "https://baja.njit.edu/", logo: "images/clients/njit.png" }, 76 { name: "Marco Beverage Systems", url: "https://marcobeveragesystems.com/us/", logo: "images/clients/marco.png" }, 77 { name: "Grinn Global", url: "https://grinn-global.com/", logo: "images/clients/grinn.png" }, 78 { name: "Spectra Ingenuity", url: "https://spectra-ingenuity.com.au/", logo: "images/clients/spectra.png" }, 79 { name: "ThoraTech", url: "https://thoratech.de/de/", logo: "images/clients/thoratech.png" }, 80 { name: "CUNY - City University of New York", url: "https://www.cuny.edu/", logo: "images/clients/cuny.png" }, 81 { name: "Vitabyte / Wolffsohn Research", url: "https://www.wolffsohnresearch.com/", logo: "images/clients/vitabyte.png" }, 82 { name: "White River Technologies", url: "https://whiterivertech.com/", logo: "images/clients/whiteriver.png" } 83 ] 84}; 85 86document.addEventListener('DOMContentLoaded', () => { 87 applyConfig(); 88}); 89 90function applyConfig() { 91 const downloadLinks = { 92 'windows-download': config.downloads.windows, 93 'macos-download': config.downloads.macos, 94 'linux-download': config.downloads.linux 95 }; 96
97 Object.entries(downloadLinks).forEach(([id, url]) => { 98 const element = document.getElementById(id); 99 if (element) element.href = url; 100 }); 101 102 applyOsDownloadHint(); 103 104 document.querySelectorAll('a[data-config]').forEach(link => { 105 const configKey = link.getAttribute('data-config'); 106 const keys = configKey.split('.'); 107 let value = config; 108 109 keys.forEach(key => { 110 value = value[key]; 111 }); 112 113 if (value) link.href = value; 114 }); 115 116 populateTrustedBy(); 117} 118 119// OS-aware quick download hint in the index.html hero (#hero-os-download). 120// The anchor ships hidden; when the visitor is on a desktop OS we can serve, 121// point it at the right installer (URL + version from this file's SSOT) and 122// reveal it. Unrecognized platforms (Android, iOS, ChromeOS, ...) get a 123// "See all downloads" variant pointing at the #download grid; no-JS visitors 124// keep it hidden â the primary CTA still leads to #download. 125function applyOsDownloadHint() { 126 const osHint = document.getElementById('hero-os-download'); 127 if (!osHint) return; 128 129 const installers = { 130 windows: { name: 'Windows', url: config.downloads.windows, pkg: '.msi installer' }, 131 macos: { name: 'macOS', url: config.downloads.macos, pkg: '.dmg universal' }, 132 linux: { name: 'Linux', url: config.downloads.linux, pkg: 'AppImage x64' } 133 }; 134 const installer = installers[detectDesktopOS()]; 135 136 if (installer) { 137 osHint.href = installer.url; 138 osHint.target = '_blank'; 139 osHint.rel = 'noopener'; 140 // OS name goes in a translate="no" span so page translation doesn't 141 // localize it ("Windows" -> "Ventanas" in Spanish, etc.). 142 const label = osHint.querySelector('.hero-os-hint-label'); 143 label.textContent = 'Download for '; 144 const osName = document.createElement('span'); 145 osName.setAttribute('translate', 'no'); 146 osName.className = 'notranslate'; 147 osName.textContent = installer.name; 148 label.appendChild(osName); 149 osHint.querySelector('.hero-os-hint-meta').textContent = 150 TAG + ' · ' + installer.pkg; 151 } else { 152 // Unrecognized platform (Android, iOS, ChromeOS, BSD, ...): never guess 153 // an installer â keep the default #download href and offer the grid. 154 osHint.querySelector('.hero-os-hint-label').textContent = 155 'See all downloads'; 156 osHint.querySelector('.hero-os-hint-meta').textContent = 157 TAG + ' · all platforms'; 158 } 159 osHint.hidden = false; 160} 161 162// Best-effort desktop OS detection for the hero quick-download hint. Returns 163// 'windows' | 'macos' | 'linux', or null for anything we don't ship a 164// one-click installer for. Mobile and ChromeOS checks run first because their 165// platform strings masquerade as desktop ones (Android reports "Linux armv8l", 166// iPadOS reports "MacIntel", ChromeOS reports "Linux x86_64"). 167function detectDesktopOS() { 168 const uaData = navigator.userAgentData; 169 const platform = (uaData && uaData.platform) || navigator.platform || ''; 170 const ua = navigator.userAgent || ''; 171 const probe = platform + ' ' + ua; 172 173 if (uaData && uaData.mobile) return null; 174 if (/Android|iPhone|iPad|iPod|CrOS|Chrome OS/i.test(probe)) return null; 175 if (/Mac/i.test(platform)) return navigator.maxTouchPoints > 1 ? null : 'macos'; 176 if (/Win/i.test(platform)) return 'windows'; 177 if (/Linux|X11/i.test(platform)) return 'linux'; 178 return null; 179} 180 181function populateTrustedBy() { 182 const trustedTrack = document.querySelector('.trusted-by .carousel-track'); 183 if (trustedTrack) { 184 config.companies.forEach(company => { 185 const card = document.createElement('a'); 186 card.href = company.url; 187 card.target = '_blank'; 188 card.rel = 'noopener'; 189 card.className = 'logo-card'; 190 191 const img = document.createElement('img'); 192 img.src = company.logo; 193 img.alt = company.name; 194 img.loading = 'lazy'; 195 196 card.appendChild(img); 197 trustedTrack.appendChild(card); 198 }); 199 } 200}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.