diff --git a/frontend/js/flagships/phys9_flag_F3_dashboard.js b/frontend/js/flagships/phys9_flag_F3_dashboard.js
new file mode 100644
index 0000000..9069042
--- /dev/null
+++ b/frontend/js/flagships/phys9_flag_F3_dashboard.js
@@ -0,0 +1,210 @@
+// F3. Тахометр + спидометр + одометр (§11-13) — игра в автогонщика.
+(function(){
+'use strict';
+const B = () => window.PHYS9_FLAG_BASE;
+const C = () => window.PHYS9_COLORS || {};
+
+function init(secId){
+ if (!B()) return false;
+ const body = ''
+ + '
'
+ + ''
+ + ''
+ + ''
+ + '
'
+ + ''
+ + ''
+ + ''
+ + ''
+ + ''
+ + ''
+ + '
'
+ + ''
+ + '
Время0 с
'
+ + '
$v$ (спидометр)0 м/с
'
+ + '
$a$ (тахометр)0 м/с²
'
+ + '
$\\Delta x$ (одометр)0 м
'
+ + '
Рекорд скорости0 м/с
'
+ + '
'
+ + '';
+
+ const card = B().makeCard(secId,
+ 'F3. Тахометр + спидометр + одометр',
+ 'Управляй автомобилем кнопками. Тахометр (a), спидометр (v) и одометр (Δx) — связаны. Разгонись до цели и затормози.',
+ body);
+ if (!card) return false;
+
+ const cv = document.getElementById('F3-cv');
+ const ctx = cv.getContext('2d');
+ const W = cv.width, H = cv.height;
+
+ let st = { t: 0, v: 0, x: 0, a: 0, mode: 'coast', history: [], targetHit: false };
+
+ function readSliders(){
+ document.getElementById('F3-gv').textContent = (+document.getElementById('F3-g').value).toFixed(1);
+ document.getElementById('F3-bv').textContent = (+document.getElementById('F3-b').value).toFixed(1);
+ document.getElementById('F3-tv').textContent = (+document.getElementById('F3-t').value).toFixed(1);
+ }
+
+ function reset(){
+ st = { t: 0, v: 0, x: 0, a: 0, mode: 'coast', history: [], targetHit: false };
+ document.getElementById('F3-fb').className = 'flag-feedback';
+ }
+
+ function tick(dt){
+ const gas = +document.getElementById('F3-g').value;
+ const brake = +document.getElementById('F3-b').value;
+ const target = +document.getElementById('F3-t').value;
+ if (st.mode === 'gas') st.a = gas;
+ else if (st.mode === 'brake') st.a = st.v > 0.1 ? -brake : 0;
+ else /* coast */ st.a = st.v > 0.05 ? -0.5 : 0; /* лёгкое торможение от трения */
+ st.v = Math.max(0, st.v + st.a * dt);
+ st.x += st.v * dt;
+ st.t += dt;
+ st.history.push({ t: st.t, v: st.v, a: st.a });
+ if (st.history.length > 600) st.history.shift();
+ /* Цель достигнута? */
+ if (!st.targetHit && Math.abs(st.v - target) < 0.5){
+ st.targetHit = true;
+ const fb = document.getElementById('F3-fb');
+ fb.className = 'flag-feedback ok show';
+ fb.innerHTML = '✓ Цель достигнута! Скорость '+st.v.toFixed(1)+' м/с (~'+(st.v*3.6).toFixed(0)+' км/ч). Теперь затормози.';
+ }
+ /* Рекорд */
+ const rec = B().saveRecord('F3_max_v', st.v);
+ document.getElementById('F3-rec').textContent = rec.toFixed(1) + ' м/с';
+ /* UI */
+ document.getElementById('F3-t-st').textContent = st.t.toFixed(1) + ' с';
+ document.getElementById('F3-v').textContent = st.v.toFixed(1) + ' м/с';
+ document.getElementById('F3-a').textContent = st.a.toFixed(1) + ' м/с²';
+ document.getElementById('F3-x').textContent = st.x.toFixed(1) + ' м';
+ draw();
+ }
+
+ function drawGauge(cx, cy, r, val, min, max, label, unit, color){
+ const col = C();
+ /* фон */
+ ctx.fillStyle = col.bgSubtle || '#f8fafc';
+ ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI*2); ctx.fill();
+ ctx.strokeStyle = col.axis || '#1e293b';
+ ctx.lineWidth = 2;
+ ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI*2); ctx.stroke();
+ /* шкала */
+ const a0 = Math.PI*0.75, a1 = Math.PI*2.25;
+ ctx.strokeStyle = col.text || '#0f172a';
+ ctx.lineWidth = 2;
+ for (let i = 0; i <= 10; i++){
+ const a = a0 + (a1 - a0) * (i/10);
+ const x1 = cx + (r-10) * Math.cos(a), y1 = cy + (r-10) * Math.sin(a);
+ const x2 = cx + r * Math.cos(a), y2 = cy + r * Math.sin(a);
+ ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke();
+ }
+ /* стрелка */
+ const norm = Math.max(0, Math.min(1, (val - min)/(max - min)));
+ const a = a0 + (a1 - a0) * norm;
+ const tipX = cx + (r-15) * Math.cos(a), tipY = cy + (r-15) * Math.sin(a);
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 4;
+ ctx.lineCap = 'round';
+ ctx.beginPath(); ctx.moveTo(cx, cy); ctx.lineTo(tipX, tipY); ctx.stroke();
+ ctx.fillStyle = color;
+ ctx.beginPath(); ctx.arc(cx, cy, 5, 0, Math.PI*2); ctx.fill();
+ /* подписи */
+ ctx.fillStyle = col.text || '#0f172a';
+ ctx.font = 'bold 11px Inter,sans-serif';
+ ctx.textAlign = 'center';
+ ctx.fillText(label, cx, cy - r - 6);
+ ctx.font = 'bold 18px Inter,sans-serif';
+ ctx.fillText(val.toFixed(1), cx, cy + r/2);
+ ctx.font = '11px Inter,sans-serif';
+ ctx.fillText(unit, cx, cy + r/2 + 14);
+ ctx.textAlign = 'left';
+ }
+
+ function draw(){
+ const col = C();
+ ctx.fillStyle = col.bg || '#fafafa';
+ ctx.fillRect(0, 0, W, H);
+ /* 3 прибора в верху */
+ drawGauge(110, 80, 55, st.a, -10, 8, 'ТАХОМЕТР (a)', 'м/с²', col.acceleration || '#ea580c');
+ drawGauge(320, 80, 55, st.v, 0, 35, 'СПИДОМЕТР (v)', 'м/с', col.velocity || '#0891b2');
+ drawGauge(530, 80, 55, st.x % 1000, 0, 1000, 'ОДОМЕТР (Δx)', 'м', col.displacement || '#2563eb');
+ /* график v(t) и a(t) внизу */
+ const gx = 20, gy = 180, gw = W - 40, gh = 180;
+ ctx.fillStyle = col.bgSubtle || '#f8fafc';
+ ctx.fillRect(gx, gy, gw, gh);
+ ctx.strokeStyle = col.axis || '#1e293b';
+ ctx.lineWidth = 1.5;
+ ctx.beginPath();
+ ctx.moveTo(gx, gy + gh/2); ctx.lineTo(gx + gw, gy + gh/2); /* ось t для a */
+ ctx.moveTo(gx, gy + gh); ctx.lineTo(gx + gw, gy + gh); /* ось t для v */
+ ctx.stroke();
+ /* сетка */
+ ctx.strokeStyle = col.grid || '#e5e7eb';
+ ctx.lineWidth = 1;
+ const tMax = Math.max(20, st.t);
+ for (let i = 0; i <= 10; i++){
+ const px = gx + (i/10)*gw;
+ ctx.beginPath(); ctx.moveTo(px, gy); ctx.lineTo(px, gy+gh); ctx.stroke();
+ }
+ /* подписи */
+ ctx.fillStyle = col.textMuted || '#64748b';
+ ctx.font = '10px Inter,sans-serif';
+ ctx.fillText('v(t)', gx + 4, gy + gh - 4);
+ ctx.fillText('a(t)', gx + 4, gy + gh/2 - 4);
+ ctx.fillText('t, с', gx + gw - 24, gy + gh + 12);
+ /* линии */
+ if (st.history.length > 1){
+ ctx.strokeStyle = col.velocity || '#0891b2';
+ ctx.lineWidth = 2.5;
+ ctx.beginPath();
+ for (let i = 0; i < st.history.length; i++){
+ const p = st.history[i];
+ const px = gx + (p.t / tMax) * gw;
+ const py = gy + gh - (p.v / 35) * (gh/2);
+ if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py);
+ }
+ ctx.stroke();
+ ctx.strokeStyle = col.acceleration || '#ea580c';
+ ctx.beginPath();
+ for (let i = 0; i < st.history.length; i++){
+ const p = st.history[i];
+ const px = gx + (p.t / tMax) * gw;
+ const py = gy + gh/2 - (p.a / 12) * (gh/4);
+ if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py);
+ }
+ ctx.stroke();
+ }
+ /* цель скорости — горизонталь */
+ const target = +document.getElementById('F3-t').value;
+ ctx.strokeStyle = '#fbbf24';
+ ctx.setLineDash([6, 4]);
+ ctx.lineWidth = 2;
+ const targetY = gy + gh - (target / 35) * (gh/2);
+ ctx.beginPath(); ctx.moveTo(gx, targetY); ctx.lineTo(gx + gw, targetY); ctx.stroke();
+ ctx.setLineDash([]);
+ ctx.fillStyle = '#92400e';
+ ctx.font = 'bold 11px Inter,sans-serif';
+ ctx.fillText('★ цель '+target.toFixed(1)+' м/с', gx + gw - 110, targetY - 4);
+ }
+
+ document.getElementById('F3-gas').addEventListener('mousedown', ()=>{ st.mode = 'gas'; });
+ document.getElementById('F3-gas').addEventListener('mouseup', ()=>{ st.mode = 'coast'; });
+ document.getElementById('F3-brake').addEventListener('mousedown', ()=>{ st.mode = 'brake'; });
+ document.getElementById('F3-brake').addEventListener('mouseup', ()=>{ st.mode = 'coast'; });
+ document.getElementById('F3-coast').addEventListener('click', ()=>{ st.mode = 'coast'; });
+ document.getElementById('F3-reset').addEventListener('click', reset);
+ ['F3-g','F3-b','F3-t'].forEach(id => document.getElementById(id).addEventListener('input', readSliders));
+
+ readSliders();
+ draw();
+ B().startLoop('F3', cv, tick);
+ return true;
+}
+
+if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F3', { init: init, cleanup: function(){} });
+else document.addEventListener('DOMContentLoaded', ()=>{
+ if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F3', { init: init, cleanup: function(){} });
+});
+
+})();
diff --git a/frontend/js/flagships/phys9_flag_F4_orbit.js b/frontend/js/flagships/phys9_flag_F4_orbit.js
new file mode 100644
index 0000000..bc1bd19
--- /dev/null
+++ b/frontend/js/flagships/phys9_flag_F4_orbit.js
@@ -0,0 +1,230 @@
+// F4. Орбитальный конструктор (§17-18) — запусти спутник, увидь орбиту.
+(function(){
+'use strict';
+const B = () => window.PHYS9_FLAG_BASE;
+const C = () => window.PHYS9_COLORS || {};
+
+function init(secId){
+ if (!B()) return false;
+ const body = ''
+ + ''
+ + ''
+ + ''
+ + ''
+ + '
'
+ + ''
+ + ''
+ + ''
+ + ''
+ + ''
+ + '
'
+ + ''
+ + '
Тип орбиты—
'
+ + '
$T$ (период, если эллипс)—
'
+ + '
$|r|$ от центра200 px
'
+ + '
$|v|$120 px/с
'
+ + '
'
+ + '';
+
+ const card = B().makeCard(secId,
+ 'F4. Орбитальный конструктор',
+ 'Запусти спутник с разной начальной скоростью. Слишком мало — упадёт. Точно — круговая. Чуть больше — эллипс. Слишком много — улетит навсегда.',
+ body);
+ if (!card) return false;
+
+ const cv = document.getElementById('F4-cv');
+ const ctx = cv.getContext('2d');
+ const W = cv.width, H = cv.height;
+ const cx = W/2, cy = H/2;
+ const planetR = 30;
+ const startR = 200; /* начальное расстояние от центра */
+
+ let st = {
+ x: cx + startR, y: cy,
+ vx: 0, vy: -120,
+ trail: [],
+ running: false,
+ crashed: false,
+ escaped: false,
+ /* для определения периода — фиксируем угол при старте */
+ lastAngle: 0,
+ revolutions: 0,
+ tStart: 0,
+ t: 0
+ };
+
+ function readSliders(){
+ document.getElementById('F4-Mv').textContent = (+document.getElementById('F4-M').value).toFixed(0);
+ document.getElementById('F4-v0v').textContent = (+document.getElementById('F4-v0').value).toFixed(0);
+ document.getElementById('F4-anv').textContent = (+document.getElementById('F4-an').value).toFixed(0);
+ }
+
+ function reset(){
+ const v0 = +document.getElementById('F4-v0').value;
+ const an = +document.getElementById('F4-an').value;
+ st.x = cx + startR; st.y = cy;
+ st.vx = v0 * Math.cos(an*Math.PI/180);
+ st.vy = -v0 * Math.sin(an*Math.PI/180);
+ st.trail = [];
+ st.crashed = false; st.escaped = false;
+ st.running = false;
+ st.t = 0; st.revolutions = 0; st.tStart = 0;
+ st.lastAngle = Math.atan2(st.y - cy, st.x - cx);
+ document.getElementById('F4-fb').className = 'flag-feedback';
+ document.getElementById('F4-go').textContent = 'Запустить';
+ draw();
+ }
+
+ function setCircular(){
+ /* для круговой v = sqrt(G*M/r) — у нас G=1, M из slider'a */
+ const M = +document.getElementById('F4-M').value;
+ const vCirc = Math.sqrt(M / startR);
+ document.getElementById('F4-v0').value = Math.round(vCirc);
+ document.getElementById('F4-an').value = 90;
+ readSliders();
+ reset();
+ }
+
+ function tick(dt){
+ if (!st.running || st.crashed || st.escaped) { draw(); return; }
+ /* Гравитация: F = G*M*m/r², a = G*M/r² к центру */
+ const M = +document.getElementById('F4-M').value;
+ /* RK4 was bы лучше но Эйлер с малым шагом норм */
+ const N = 8;
+ const ddt = dt / N;
+ for (let i = 0; i < N; i++){
+ const dx = cx - st.x, dy = cy - st.y;
+ const r2 = dx*dx + dy*dy;
+ const r = Math.sqrt(r2);
+ if (r < planetR){ st.crashed = true; break; }
+ if (r > 2000){ st.escaped = true; break; }
+ const aMag = M / r2;
+ const ax = aMag * dx / r, ay = aMag * dy / r;
+ st.vx += ax * ddt;
+ st.vy += ay * ddt;
+ st.x += st.vx * ddt;
+ st.y += st.vy * ddt;
+ st.t += ddt;
+ /* trail */
+ if (i === N-1) st.trail.push({ x: st.x, y: st.y });
+ if (st.trail.length > 1500) st.trail.shift();
+ /* определение периода — переход через ось x */
+ const ang = Math.atan2(st.y - cy, st.x - cx);
+ if (st.lastAngle > Math.PI*0.9 && ang < -Math.PI*0.9 || st.lastAngle < -Math.PI*0.9 && ang > Math.PI*0.9){
+ /* skip — wrap */
+ } else if (st.lastAngle < 0 && ang >= 0){
+ st.revolutions++;
+ if (st.revolutions === 1) st.tStart = st.t;
+ }
+ st.lastAngle = ang;
+ }
+ const fb = document.getElementById('F4-fb');
+ if (st.crashed){
+ st.running = false;
+ document.getElementById('F4-go').textContent = 'Запустить';
+ fb.className = 'flag-feedback fail show';
+ fb.innerHTML = '✗ Спутник упал на планету! Нужна бо́льшая начальная скорость.';
+ } else if (st.escaped){
+ st.running = false;
+ document.getElementById('F4-go').textContent = 'Запустить';
+ fb.className = 'flag-feedback warn show';
+ fb.innerHTML = 'Спутник улетел! Это вторая космическая (~$\\sqrt 2 v_{круг}$). Уменьши скорость.';
+ }
+ /* статистика */
+ const dx = st.x - cx, dy = st.y - cy;
+ const r = Math.sqrt(dx*dx + dy*dy);
+ const v = Math.sqrt(st.vx*st.vx + st.vy*st.vy);
+ document.getElementById('F4-r').textContent = r.toFixed(0) + ' px';
+ document.getElementById('F4-v').textContent = v.toFixed(0) + ' px/с';
+ /* классификация */
+ const Mclassify = +document.getElementById('F4-M').value;
+ const vCirc = Math.sqrt(Mclassify / startR);
+ const ratio = +document.getElementById('F4-v0').value / vCirc;
+ let type;
+ if (st.crashed) type = '✗ падение';
+ else if (st.escaped) type = '↗ убегание';
+ else if (Math.abs(ratio - 1) < 0.05) type = '○ круговая';
+ else if (ratio < 0.95) type = '⬭ эллипс (ближе к планете)';
+ else if (ratio < 1.41) type = '⬮ эллипс (дальше)';
+ else type = '↗ убегание';
+ document.getElementById('F4-type').textContent = type;
+ if (st.revolutions >= 2 && st.tStart > 0){
+ const T = (st.t - st.tStart) / (st.revolutions - 1);
+ document.getElementById('F4-T').textContent = T.toFixed(2) + ' с';
+ }
+ draw();
+ }
+
+ function draw(){
+ const col = C();
+ ctx.fillStyle = col.bg || '#fafafa';
+ ctx.fillRect(0, 0, W, H);
+ /* звёзды для красоты */
+ ctx.fillStyle = col.textMuted || '#94a3b8';
+ for (let i = 0; i < 60; i++){
+ const sx = (i * 37 + 17) % W;
+ const sy = (i * 61 + 23) % H;
+ ctx.fillRect(sx, sy, 1, 1);
+ }
+ /* планета (Земля) */
+ ctx.fillStyle = col.forceGravity || '#2563eb';
+ ctx.beginPath(); ctx.arc(cx, cy, planetR, 0, Math.PI*2); ctx.fill();
+ ctx.strokeStyle = '#fff';
+ ctx.lineWidth = 1.5;
+ ctx.stroke();
+ ctx.fillStyle = '#fff';
+ ctx.font = 'bold 12px Inter,sans-serif';
+ ctx.textAlign = 'center';
+ ctx.fillText('M', cx, cy + 4);
+ ctx.textAlign = 'left';
+ /* trail */
+ if (st.trail.length > 1){
+ ctx.strokeStyle = col.velocity || '#0891b2';
+ ctx.lineWidth = 1.8;
+ ctx.beginPath();
+ ctx.moveTo(st.trail[0].x, st.trail[0].y);
+ for (let i = 1; i < st.trail.length; i++) ctx.lineTo(st.trail[i].x, st.trail[i].y);
+ ctx.stroke();
+ }
+ /* спутник */
+ ctx.fillStyle = st.crashed ? col.fail : (col.acceleration || '#ea580c');
+ ctx.beginPath(); ctx.arc(st.x, st.y, 7, 0, Math.PI*2); ctx.fill();
+ ctx.strokeStyle = '#fff'; ctx.lineWidth = 1.2; ctx.stroke();
+ /* вектор v */
+ if (st.running || st.t === 0){
+ const v = Math.sqrt(st.vx*st.vx + st.vy*st.vy);
+ const k = v > 0 ? 40 / v : 0;
+ B().arrow(ctx, st.x, st.y, st.x + st.vx*k, st.y + st.vy*k, col.velocity || '#0891b2', 2);
+ }
+ }
+
+ document.getElementById('F4-go').addEventListener('click', ()=>{
+ if (st.crashed || st.escaped) reset();
+ if (!st.running) {
+ reset();
+ st.running = true;
+ document.getElementById('F4-go').textContent = 'Пауза';
+ } else {
+ st.running = false;
+ document.getElementById('F4-go').textContent = 'Запустить';
+ }
+ });
+ document.getElementById('F4-reset').addEventListener('click', reset);
+ document.getElementById('F4-circle').addEventListener('click', setCircular);
+ ['F4-M','F4-v0','F4-an'].forEach(id => document.getElementById(id).addEventListener('input', ()=>{
+ readSliders();
+ if (!st.running) reset();
+ }));
+
+ readSliders();
+ reset();
+ B().startLoop('F4', cv, tick);
+ return true;
+}
+
+if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F4', { init: init, cleanup: function(){} });
+else document.addEventListener('DOMContentLoaded', ()=>{
+ if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F4', { init: init, cleanup: function(){} });
+});
+
+})();
diff --git a/frontend/textbooks/physics_9_ch1.html b/frontend/textbooks/physics_9_ch1.html
index 52b1e76..d995959 100644
--- a/frontend/textbooks/physics_9_ch1.html
+++ b/frontend/textbooks/physics_9_ch1.html
@@ -806,7 +806,7 @@ function _injectTasks(id){
var body = document.getElementById(id + '-body');
if(!body || body.querySelector('.legacy-tasks')) return;
body.insertAdjacentHTML('beforeend', _makeTaskBlock(id));
- setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_FINALS_INIT && /^final\d+$/.test(id)) window.PHYS9_FINALS_INIT(id); } catch(e){ console.warn("phys9 final init:", e.message); } try { if(window.PHYS9_CH1_WIDGETS && window.PHYS9_CH1_WIDGETS[id]) window.PHYS9_CH1_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } try { if(window.PHYS9_FLAG_BASE){ if(id==='p5') window.PHYS9_FLAG_BASE.mount('F1','p5'); else if(id==='p9') window.PHYS9_FLAG_BASE.mount('F2','p9'); } } catch(e){ console.warn('phys9 flag init:', e.message); } }, 60);
+ setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_FINALS_INIT && /^final\d+$/.test(id)) window.PHYS9_FINALS_INIT(id); } catch(e){ console.warn("phys9 final init:", e.message); } try { if(window.PHYS9_CH1_WIDGETS && window.PHYS9_CH1_WIDGETS[id]) window.PHYS9_CH1_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } try { if(window.PHYS9_FLAG_BASE){ if(id==='p5') window.PHYS9_FLAG_BASE.mount('F1','p5'); else if(id==='p9') window.PHYS9_FLAG_BASE.mount('F2','p9'); else if(id==='p11') window.PHYS9_FLAG_BASE.mount('F3','p11'); } } catch(e){ console.warn('phys9 flag init:', e.message); } }, 60);
}
var _origEnsureBuilt = ensureBuilt;
ensureBuilt = function(id){ _origEnsureBuilt(id); _injectTasks(id); };
diff --git a/frontend/textbooks/physics_9_ch2.html b/frontend/textbooks/physics_9_ch2.html
index 7e01b8a..409ee91 100644
--- a/frontend/textbooks/physics_9_ch2.html
+++ b/frontend/textbooks/physics_9_ch2.html
@@ -9,6 +9,7 @@
+
@@ -789,7 +790,7 @@ function _injectTasks(id){
var body = document.getElementById(id + '-body');
if(!body || body.querySelector('.legacy-tasks')) return;
body.insertAdjacentHTML('beforeend', _makeTaskBlock(id));
- setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_FINALS_INIT && /^final\d+$/.test(id)) window.PHYS9_FINALS_INIT(id); } catch(e){ console.warn("phys9 final init:", e.message); } try { if(window.PHYS9_CH2_WIDGETS && window.PHYS9_CH2_WIDGETS[id]) window.PHYS9_CH2_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } }, 60);
+ setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_FINALS_INIT && /^final\d+$/.test(id)) window.PHYS9_FINALS_INIT(id); } catch(e){ console.warn("phys9 final init:", e.message); } try { if(window.PHYS9_CH2_WIDGETS && window.PHYS9_CH2_WIDGETS[id]) window.PHYS9_CH2_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } try { if(window.PHYS9_FLAG_BASE){ if(id==='p17') window.PHYS9_FLAG_BASE.mount('F4','p17'); } } catch(e){ console.warn('phys9 flag init:', e.message); } }, 60);
}
var _origEnsureBuilt = ensureBuilt;
ensureBuilt = function(id){ _origEnsureBuilt(id); _injectTasks(id); };