1const publishedSheetCsvEndpoint = 2 'https://docs.google.com/spreadsheets/d/e/2PACX-1vQ1vMlwTJ8_Lty161T73uwnMzVxb48XzHxz9aPNla5OgCjd2yJ0HMfxEHGSv1OsyGOarWUYDcsJZfmk/pub?gid=0&single=true&output=csv'; 3 4let leaderboardStatusSettled = false; 5let leaderboardStatusTimeout; 6 7function showLeaderboardStatus(snapshotLabel, companyCount) { 8 const status = document.getElementById('leaderboard-status'); 9 const loader = document.getElementById('leaderboard-status-loader'); 10 const dot = document.getElementById('leaderboard-status-dot'); 11 const text = document.getElementById('leaderboard-status-text'); 12 13 if (!status || !loader || !dot || !text) return; 14 15 loader.classList.add('hidden'); 16 dot.classList.remove('hidden'); 17 text.replaceChildren(); 18 19 const label = document.createElement('span'); 20 label.className = 'font-medium text-gray-700'; 21 label.textContent = `Latest data snapshot: ${snapshotLabel}`; 22 23 const separator = document.createElement('span'); 24 separator.className = 'mx-2 text-gray-300'; 25 separator.textContent = 'â¢'; 26 27 const count = document.createElement('span'); 28 count.textContent = `${companyCount.toLocaleString('en-US')} companies tracked`; 29 30 text.append(label, separator, count); 31 status.setAttribute('aria-busy', 'false'); 32} 33 34function showLeaderboardStatusUnavailable() { 35 if (leaderboardStatusSettled) return; 36 leaderboardStatusSettled = true; 37 38 const status = document.getElementById('leaderboard-status'); 39 const loader = document.getElementById('leaderboard-status-loader'); 40 const text = document.getElementById('leaderboard-status-text'); 41 42 if (!status || !loader || !text) return; 43 44 loader.classList.add('hidden'); 45 text.textContent = 'Latest data snapshot temporarily unavailable'; 46 status.setAttribute('aria-busy', 'false'); 47} 48 49function parseCsv(csv) { 50 const rows = []; 51 let row = []; 52 let field = ''; 53 let quoted = false; 54 55 for (let index = 0; index < csv.length; index += 1) { 56 const character = csv[index]; 57 58 if (quoted) { 59 if (character === '"' && csv[index + 1] === '"') { 60 field += '"'; 61 index += 1; 62 } else if (character === '"') { 63 quoted = false; 64 } else { 65 field += character; 66 } 67 } else if (character === '"') { 68 quoted = true; 69 } else if (character === ',') { 70 row.push(field); 71 field = ''; 72 } else if (character === '\n') { 73 row.push(field); 74 rows.push(row); 75 row = []; 76 field = ''; 77 } else if (character !== '\r') { 78 field += character; 79 } 80 } 81 82 if (field || row.length) { 83 row.push(field); 84 rows.push(row); 85 } 86 87 return rows; 88} 89 90function getLeaderboardSnapshot(csv) { 91 const rows = parseCsv(csv); 92 const headers = rows[0] || []; 93 const companyIndex = headers.indexOf('Company'); 94 const snapshotIndex = headers.indexOf('Snapshot Time'); 95 const monthIndexes = new Map([ 96 ['Jan', 0], ['Feb', 1], ['Mar', 2], ['Apr', 3], ['May', 4], ['Jun', 5], 97 ['Jul', 6], ['Aug', 7], ['Sep', 8], ['Oct', 9], ['Nov', 10], ['Dec', 11] 98 ]); 99 100 if (companyIndex === -1 || snapshotIndex === -1) { 101 throw new Error('Published Sheet is missing expected leaderboard columns.'); 102 } 103 104 let companyCount = 0; 105 let latestSnapshot; 106 107 rows.slice(1).forEach((currentRow) => { 108 if (!currentRow[companyIndex]?.trim()) return; 109 companyCount += 1; 110 111 const snapshotLabel = currentRow[snapshotIndex]?.trim(); 112 const match = snapshotLabel?.match(/^([A-Z][a-z]{2})\s+(\d{4})$/); 113 const monthIndex = match ? monthIndexes.get(match[1]) : undefined; 114 115 if (monthIndex === undefined) return; 116 117 const sortValue = Number(match[2]) * 12 + monthIndex; 118 if (!latestSnapshot || sortValue > latestSnapshot.sortValue) { 119 latestSnapshot = { label: snapshotLabel, sortValue }; 120 } 121 }); 122 123 if (!latestSnapshot || companyCount === 0) { 124 throw new Error('Published Sheet returned incomplete leaderboard data.'); 125 } 126 127 return { snapshotLabel: latestSnapshot.label, companyCount }; 128} 129 130window.addEventListener('DOMContentLoaded', () => { 131 leaderboardStatusTimeout = setTimeout(showLeaderboardStatusUnavailable, 8000); 132 133 fetch(publishedSheetCsvEndpoint, { cache: 'no-store' }) 134 .then((response) => { 135 if (!response.ok) throw new Error(`Published Sheet request failed: ${response.status}`); 136 return response.text(); 137 }) 138 .then((csv) => { 139 if (leaderboardStatusSettled) return; 140 141 const { snapshotLabel, companyCount } = getLeaderboardSnapshot(csv); 142 leaderboardStatusSettled = true; 143 clearTimeout(leaderboardStatusTimeout); 144 showLeaderboardStatus(snapshotLabel, companyCount); 145 }) 146 .catch((error) => { 147 console.error('Unable to read the latest leaderboard snapshot:', error); 148 showLeaderboardStatusUnavailable(); 149 }); 150});
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.