3 этап
Дата проведения: 2026г.
Место проведения:
Мероприятие задействует объект экстрим-локации: ПАМП-ТРЕК

Данные из таблицы

Загрузка…
Загрузка данных из Google Таблицы…
', changedKeys: [] }; } var html = '
'; displayHeaders.forEach(function (h, hi) { var cls = ''; if (hi === 0) cls = 'is-name'; else if (qualSources.length) { var qi = hi - 1; if (qi >= 0 && qi < qualSources.length) { cls = 'is-time'; if (qi % 2 === 1) cls += ' is-time--alt'; } } html += ''; }); html += ''; tableRows.forEach(function (row, ri) { var key = 'r' + ri; var prev = prevRows ? prevRows[ri] : null; var changed = false; html += ''; row.forEach(function (cell, ci) { if (prev && String(prev[ci]) !== String(cell)) changed = true; var cls = ''; if (ci === 0) cls = 'is-name'; else if (qualSources.length) { var qi = ci - 1; if (qi >= 0 && qi < qualSources.length) { cls = 'is-time'; if (qi % 2 === 1) cls += ' is-time--alt'; } } html += ''; }); html += ''; if (changed) changedKeys.push(key); }); html += '
' + esc(h) + '
' + esc(cell) + '
'; return { html: html, changedKeys: changedKeys }; } function renderLegend(qualSources) { if (!qualSources.length) return ''; var items = qualSources.map(function (q) { var src = q.sourceIdx === -1 ? '—' : colLetter(q.sourceIdx); return '' + '' + esc(q.label) + '' + '' + 'столбец ' + src + '' + ''; }).join(''); return '
' + items + '
'; } function render(headers, rows) { if (!headers.length) { container.innerHTML = '
' + '
Таблица пуста
' + '
'; if (rowCountEl) rowCountEl.textContent = ''; return; } var mapping = buildMapping(headers); if (mapping.rideIdxs.length === 0) { container.innerHTML = '
' + '
' + '

' + ' !' + ' Квалификации' + '

' + '
' + '
В шапке не найдена колонка «' + esc(RIDE_COLUMN) + '».
' + '
'; if (rowCountEl) rowCountEl.textContent = ''; prevRows = null; return; } if (mapping.qualIdxs.length === 0) { container.innerHTML = '
' + '
' + '

' + ' !' + ' Квалификации' + '

' + '
' + '
Колонка «' + esc(RIDE_COLUMN) + '» найдена, но в шапке нет меток «Квал N».
' + '
'; if (rowCountEl) rowCountEl.textContent = ''; prevRows = null; return; } var qualSources = resolveQualSources(mapping); var tableData = buildTableData(rows, qualSources); var rendered = renderTable(tableData.headers, tableData.rows, tableData.qualSources); var html = '
'; html += '
'; html += '

'; html += ' '; html += ' Квалификации'; html += '

'; html += ' ' + tableData.rows.length + ' ' + plural(tableData.rows.length, 'запись', 'записи', 'записей') + ''; html += '
'; html += renderLegend(qualSources); html += rendered.html; html += '
'; container.innerHTML = html; var card = container.querySelector('.hp-sheet__card'); rendered.changedKeys.forEach(function (k) { var tr = card && card.querySelector('tr[data-key="' + k + '"]'); if (tr) tr.classList.add('is-updated'); }); prevRows = tableData.rows; if (rowCountEl) rowCountEl.textContent = 'Всего: ' + rows.length + ' (' + plural(rows.length, 'запись', 'записи', 'записей') + ')' + ' · Квал-колонок: ' + qualSources.length; } function renderError(msg, hint) { var h = hint ? '
' + esc(hint) + '
' : ''; container.innerHTML = '
' + '
' + esc(msg) + '
' + h + '' + '
'; if (rowCountEl) rowCountEl.textContent = ''; var r = document.getElementById('hsRetry'); if (r) r.addEventListener('click', fetchData); } // === ТОЛЬКО JSONP — никаких fetch, никаких CORS === function fetchData() { if (isLoading) return; setStatus('loading'); setLoading(true); // Чистим предыдущий скрипт, если остался if (currentScript && currentScript.parentNode) { currentScript.parentNode.removeChild(currentScript); currentScript = null; } jsonpCounter++; var cbName = '_hsCb_' + Date.now() + '_' + jsonpCounter + '_' + Math.floor(Math.random() * 100000); var done = false; var timer = null; function cleanup() { if (timer) clearTimeout(timer); if (currentScript && currentScript.parentNode) { currentScript.parentNode.removeChild(currentScript); } currentScript = null; try { delete window[cbName]; } catch (e) { window[cbName] = undefined; } } window[cbName] = function (response) { if (done) return; done = true; cleanup(); try { var table = response.table; var headers = (table.cols || []).map(function (c) { return c.label || ''; }); var rows = (table.rows || []).map(function (r) { return (r.c || []).map(function (cell) { if (!cell) return ''; return cell.f !== undefined ? cell.f : (cell.v !== undefined ? cell.v : ''); }); }); render(headers, rows); setStatus('ok'); } catch (e) { console.error('[hp-sheet] parse error:', e); renderError('Ошибка обработки данных', e.message); setStatus('error'); } setLoading(false); resetCountdown(); }; var script = document.createElement('script'); script.src = 'https://docs.google.com/spreadsheets/d/' + SHEET_ID + '/gviz/tq?tqx=responseHandler:' + cbName; script.onerror = function () { if (done) return; done = true; cleanup(); renderError( 'Не удалось загрузить данные из Google Таблицы.', 'Проверьте доступ: откройте таблицу, нажмите «Настройки доступа» → «Все, у кого есть ссылка».' ); setStatus('error'); setLoading(false); resetCountdown(); }; timer = setTimeout(function () { if (done) return; done = true; cleanup(); renderError('Превышено время ожидания ответа от Google.', 'Попробуйте обновить страницу.'); setStatus('error'); setLoading(false); resetCountdown(); }, 15000); currentScript = script; document.head.appendChild(script); } function resetCountdown() { if (countdownId) clearInterval(countdownId); countdown = REFRESH_INTERVAL; if (timerEl) timerEl.textContent = 'Авто-обновление через ' + countdown + ' с'; countdownId = setInterval(function () { countdown--; if (countdown <= 0) { if (timerEl) timerEl.textContent = 'Обновление…'; clearInterval(countdownId); fetchData(); } else { if (timerEl) timerEl.textContent = 'Авто-обновление через ' + countdown + ' с'; } }, 1000); } if (refreshBtn) refreshBtn.addEventListener('click', fetchData); fetchData(); })();
ПАРТНЁРЫ
При поддержке
Генеральные партнёры
Партнёры