/* chem7_ch1_widgets.js — интерактивы главы 1 «Первоначальные химические понятия» (Химия 7). * Монтируются движком chem8_engine.js: window.CHEM8_WIDGETS[id] / window.FLAG_MOUNTS[id]. * Используют window.Chem8 (chem8_svg.js): molarMass, elementCounts, arOf, fmt, equationBalancer. * Без эмоджи; KaTeX-рендер — через window.chem8RenderMath. */ (function (W) { 'use strict'; function C() { return W.Chem8 || {}; } function $(id) { return document.getElementById(id); } function esc(s){ return String(s).replace(/&/g,'&').replace(//g,'>'); } /* ── общий мини-классификатор: чипы → 2 корзины ──────────────────── */ function classifier(mount, opts) { if (!mount || mount._built) return; mount._built = 1; var items = opts.items.slice(); // {t, b} t=подпись, b=индекс корзины var buckets = opts.buckets; // [name0, name1] var placed = {}; // idx -> bucket var pool = items.map(function (it, i) { return i; }); function colorOf(ok){ return ok ? '#059669' : '#dc2626'; } function render() { var chips = pool.map(function (i) { return ''; }).join('') || 'Все карточки распределены.'; var cols = buckets.map(function (name, bi) { var inb = Object.keys(placed).filter(function (k) { return placed[k] === bi; }); var cells = inb.map(function (k) { var ok = items[k].b === bi; return '
' + esc(items[k].t) + (ok ? ' ✓' : ' ✗') + '
'; }).join('') || '
перетащите сюда…
'; return '
' + esc(name) + '
' + cells + '
'; }).join(''); mount.innerHTML = '
' + chips + '
' + cols + '
' + '
Кликни карточку, затем — корзину. Зелёный — верно, красный — ошибка.
'; bind(); } var sel = null; function bind() { mount.querySelectorAll('.c7-chip').forEach(function (b) { b.addEventListener('click', function () { mount.querySelectorAll('.c7-chip').forEach(function (x) { x.style.outline = ''; }); sel = +b.dataset.i; b.style.outline = '2px solid var(--pri)'; }); }); mount.querySelectorAll('.c7-bucket').forEach(function (col) { col.addEventListener('click', function () { if (sel == null) return; placed[sel] = +col.dataset.b; pool = pool.filter(function (x) { return x !== sel; }); sel = null; render(); }); }); } render(); } /* §1 — классификатор «тело / вещество» */ function mount_p1() { var m = $('p1-cls'); if (!m) return; classifier(m, { buckets: ['Физическое тело', 'Вещество'], items: [ { t: 'стакан', b: 0 }, { t: 'вода', b: 1 }, { t: 'гвоздь', b: 0 }, { t: 'железо', b: 1 }, { t: 'ложка', b: 0 }, { t: 'сахар', b: 1 }, { t: 'медь', b: 1 }, { t: 'линейка', b: 0 } ] }); } /* §2 / ПР1 — разделитель смесей: выбери метод для смеси */ var MIX = [ { mix: 'Песок и вода', method: 'Фильтрование', kind: 'filter', why: 'Песок не растворяется — задерживается фильтром, вода проходит.' }, { mix: 'Соль и вода', method: 'Выпаривание', kind: 'evaporate', why: 'Вода испаряется, соль остаётся на дне.' }, { mix: 'Железные опилки и сера', method: 'Магнит', kind: 'magnet', why: 'Железо притягивается магнитом, сера — нет.' }, { mix: 'Вода и растительное масло', method: 'Отстаивание (делительная воронка)', kind: 'settle', why: 'Масло легче воды и не смешивается — слои разделяют.' }, { mix: 'Спирт и вода', method: 'Перегонка (дистилляция)', kind: 'distill', why: 'У спирта и воды разные температуры кипения.' } ]; var METHODS = ['Фильтрование', 'Выпаривание', 'Магнит', 'Отстаивание (делительная воронка)', 'Перегонка (дистилляция)']; function mount_sep(mountId) { var m = $(mountId); if (!m || m._built) return; m._built = 1; var idx = 0, anim = null; function stopAnim() { if (anim) { anim.stop(); anim = null; } } function render() { stopAnim(); var cur = MIX[idx]; m.innerHTML = '
' + '
Каким способом разделить смесь «' + esc(cur.mix) + '»?
' + '
' + METHODS.map(function (mt) { return ''; }).join('') + '
' + '
Выбери способ разделения — при верном ответе увидишь анимацию.
' + '
'; $(mountId + '-pick').addEventListener('change', function (e) { idx = +e.target.value; render(); }); var out = $(mountId + '-out'); m.querySelectorAll('.c7-m').forEach(function (b) { b.addEventListener('click', function () { var ok = b.dataset.m === cur.method; out.className = 'out ' + (ok ? 'ok' : 'bad'); out.innerHTML = ok ? 'Верно! ' + esc(cur.method) + '. ' + esc(cur.why) : 'Не подходит. Подумай, чем различаются вещества в смеси (растворимость, магнитные свойства, температура кипения, плотность).'; stopAnim(); var host = $(mountId + '-anim'); if (ok && W.Chem7Anim && host) anim = W.Chem7Anim.separation(host, cur.kind); else if (host) host.innerHTML = ''; }); }); } render(); } function mount_p2() { mount_sep('p2-sep'); } function mount_pr1() { mount_sep('pr1-sep'); } /* §3 — каталог элементов + тренажёр «символ ↔ название» */ var EL = { H: [1, 'Водород'], He: [2, 'Гелий'], Li: [3, 'Литий'], C: [6, 'Углерод'], N: [7, 'Азот'], O: [8, 'Кислород'], F: [9, 'Фтор'], Na: [11, 'Натрий'], Mg: [12, 'Магний'], Al: [13, 'Алюминий'], Si: [14, 'Кремний'], P: [15, 'Фосфор'], S: [16, 'Сера'], Cl: [17, 'Хлор'], K: [19, 'Калий'], Ca: [20, 'Кальций'], Fe: [26, 'Железо'], Cu: [29, 'Медь'], Zn: [30, 'Цинк'], Ag: [47, 'Серебро'] }; function mount_p3() { var grid = $('p3-el'), info = $('p3-elinfo'); if (grid && !grid._built) { grid._built = 1; Object.keys(EL).forEach(function (s) { var ar = C().arOf ? C().arOf(s) : ''; var c = document.createElement('div'); c.className = 'el-cell'; c.innerHTML = '' + EL[s][0] + '' + s + '' + ar + ''; c.addEventListener('click', function () { grid.querySelectorAll('.el-cell').forEach(function (x) { x.classList.remove('on'); }); c.classList.add('on'); if (info) info.innerHTML = '' + EL[s][1] + ' (' + s + ') · порядковый номер Z = ' + EL[s][0] + ' · A_r = ' + ar; }); grid.appendChild(c); }); } /* drill: дан символ → выбери название */ var d = $('p3-drill'); if (d && !d._built) { d._built = 1; var keys = Object.keys(EL), order = keys.slice(), qi = 0, score = 0, total = 0; function nextQ() { var sym = order[qi % order.length]; var correct = EL[sym][1]; var opts = [correct]; while (opts.length < 4) { var r = EL[keys[(qi * 7 + opts.length * 13 + 3) % keys.length]][1]; if (opts.indexOf(r) < 0) opts.push(r); } // детерминированная перестановка opts = opts.sort(function (a, b) { return ((a.length + qi) % 3) - ((b.length + qi) % 3); }); d.innerHTML = '
Какому элементу соответствует символ ' + sym + '?
' + '
' + opts.map(function (o) { return ''; }).join('') + '
' + '
Счёт: ' + score + ' из ' + total + '
'; var out = $('p3-drill-out'); d.querySelectorAll('.c7-d').forEach(function (b) { b.addEventListener('click', function () { total++; var ok = b.dataset.o === correct; if (ok) score++; out.className = 'out ' + (ok ? 'ok' : 'bad'); out.innerHTML = (ok ? 'Верно! ' : 'Нет. ') + sym + ' — это ' + correct + '. Счёт: ' + score + ' из ' + total; qi++; setTimeout(nextQ, 850); }); }); } nextQ(); } } /* ── Волна 2 ── */ /* §4 — «весы атомов»: во сколько раз один атом тяжелее другого */ var ABEL = ['H','C','N','O','Na','Mg','Al','S','Cl','Ca','Fe','Cu','Zn','Ag']; function mount_p4() { var m = $('p4-bal'); if (!m || m._built) return; m._built = 1; function opts(sel){ return ABEL.map(function(e){ var ar=C().arOf?C().arOf(e):''; return ''; }).join(''); } m.innerHTML = '
' +'
'; function upd(){ var a=$('p4-a').value, b=$('p4-b').value, ara=+C().arOf(a), arb=+C().arOf(b); var out=$('p4-out'); if(!ara||!arb){ out.textContent='—'; return; } var big=Math.max(ara,arb), sm=Math.min(ara,arb), k=big/sm; var heavier=ara>=arb?a:b, lighter=ara>=arb?b:a; out.className='out ok'; out.innerHTML='A_r('+a+')='+ara+', A_r('+b+')='+arb+'
' +(ara===arb?('Атомы '+a+' и '+b+' имеют одинаковую массу.') :('Атом '+heavier+' тяжелее атома '+lighter+' в '+(Math.round(k*100)/100).toString().replace('.',',')+' раз.'))+'
'; } $('p4-a').addEventListener('change',upd); $('p4-b').addEventListener('change',upd); upd(); } /* рисуем молекулу как набор шариков-атомов */ var COL = { H:'#cbd5e1', O:'#ef4444', N:'#3b82f6', C:'#334155', S:'#eab308', Cl:'#22c55e', Fe:'#b45309', Na:'#a78bfa' }; var RAD = { H:11, O:16, N:15, C:16, S:18, Cl:17, Fe:18, Na:17 }; function molBalls(atoms) { // atoms: [[el,n],...]; рисуем в ряд var balls = [], cx = 26; atoms.forEach(function(pair){ for(var i=0;i' + ''+el+''; x += r + 8; }); return ''+svg+''; } function molCard(name, formula, atoms, note) { return '
' +'
'+esc(name)+' · '+(C().formula?C().formula(formula):formula)+'
' + molBalls(atoms) +'
'+esc(note)+'
'; } /* 3D-модели молекул для §5/§6 (через Chem7Anim.molecule3d) */ var MOL = { H2: { atoms:[{el:'H',x:-0.7,y:0,z:0},{el:'H',x:0.7,y:0,z:0}], bonds:[[0,1]] }, O2: { atoms:[{el:'O',x:-0.75,y:0,z:0},{el:'O',x:0.75,y:0,z:0}], bonds:[[0,1]] }, O3: { atoms:[{el:'O',x:0,y:0.45,z:0},{el:'O',x:-1.05,y:-0.4,z:0},{el:'O',x:1.05,y:-0.4,z:0}], bonds:[[0,1],[0,2]] }, N2: { atoms:[{el:'N',x:-0.7,y:0,z:0},{el:'N',x:0.7,y:0,z:0}], bonds:[[0,1]] }, H2O: { atoms:[{el:'O',x:0,y:0,z:0},{el:'H',x:-0.78,y:0.6,z:0},{el:'H',x:0.78,y:0.6,z:0}], bonds:[[0,1],[0,2]] }, CO2: { atoms:[{el:'C',x:0,y:0,z:0},{el:'O',x:-1.15,y:0,z:0},{el:'O',x:1.15,y:0,z:0}], bonds:[[0,1],[0,2]] }, CH4: { atoms:[{el:'C',x:0,y:0,z:0},{el:'H',x:0.63,y:0.63,z:0.63},{el:'H',x:-0.63,y:-0.63,z:0.63},{el:'H',x:-0.63,y:0.63,z:-0.63},{el:'H',x:0.63,y:-0.63,z:-0.63}], bonds:[[0,1],[0,2],[0,3],[0,4]] }, NH3: { atoms:[{el:'N',x:0,y:0.32,z:0},{el:'H',x:0.94,y:-0.3,z:0},{el:'H',x:-0.47,y:-0.3,z:0.82},{el:'H',x:-0.47,y:-0.3,z:-0.82}], bonds:[[0,1],[0,2],[0,3]] } }; function fmlName(k) { return C().formula ? C().formula(k) : k; } function molViewer(host, keys, caption) { if (!host || host._built) return; host._built = 1; var A = W.Chem7Anim; if (!A || !A.molecule3d) { host.innerHTML = '
3D-модели недоступны.
'; return; } var cur = keys[0], handle = null; function render() { if (handle) handle.stop(); host.innerHTML = '
' + keys.map(function (k) { return ''; }).join('') + '
' + '
' + '
' + caption + ' Перетаскивай модель мышью, чтобы повернуть.
'; handle = A.molecule3d($(host.id + '-stage'), MOL[cur]); host.querySelectorAll('.mv-b').forEach(function (b) { b.addEventListener('click', function () { cur = b.dataset.k; render(); }); }); } render(); } /* §5 — 3D-модели простых веществ */ function mount_p5() { molViewer($('p5-gal'), ['H2', 'O2', 'O3', 'N2'], 'Простое вещество — атомы одного элемента.'); } /* §6 — классификатор простое/сложное + 3D-модели сложных веществ */ function mount_p6() { var c = $('p6-cls'); if (c) classifier(c, { buckets: ['Простое вещество', 'Сложное вещество'], items: [ { t:'O₂', b:0 }, { t:'H₂O', b:1 }, { t:'Fe', b:0 }, { t:'CO₂', b:1 }, { t:'N₂', b:0 }, { t:'NH₃', b:1 }, { t:'S', b:0 }, { t:'CH₄', b:1 } ] }); molViewer($('p6-gal'), ['H2O', 'CO2', 'CH4', 'NH3'], 'Сложное вещество — атомы разных элементов.'); } /* ── Волна 3 ── */ /* §7 — разбор химической формулы на состав */ function mount_p7() { var inp = $('p7-in'), out = $('p7-out'), go = $('p7-go'); if (!inp || inp._built) return; inp._built = 1; function calc() { var f = inp.value.trim(), cnt = C().elementCounts ? C().elementCounts(f) : null; if (!cnt || !Object.keys(cnt).length) { out.className = 'out bad'; out.textContent = 'Не удалось разобрать формулу. Проверь символы элементов (например, H2SO4).'; return; } var els = Object.keys(cnt), tot = els.reduce(function (s, e) { return s + cnt[e]; }, 0); out.className = 'out ok'; out.innerHTML = '' + (C().formula ? C().formula(f) : f) + '
' + 'Элементов: ' + els.length + ' (' + (els.length === 1 ? 'простое' : 'сложное') + ' вещество)
' + els.map(function (e) { return e + ': ' + cnt[e] + ' ' + (cnt[e] === 1 ? 'атом' : 'атома(ов)'); }).join('
') + '
Всего атомов в формуле: ' + tot + '
'; } go.addEventListener('click', calc); inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); }); document.querySelectorAll('.p7-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); }); calc(); } /* §8 — калькулятор относительной молекулярной массы M_r */ function mount_p8() { var inp = $('p8-in'), out = $('p8-out'), go = $('p8-go'); if (!inp || inp._built) return; inp._built = 1; function calc() { var f = inp.value.trim(), cnt = C().elementCounts ? C().elementCounts(f) : null, mr = C().molarMass ? C().molarMass(f) : NaN; if (!cnt || isNaN(mr)) { out.className = 'out bad'; out.textContent = 'Не удалось разобрать формулу.'; return; } out.className = 'out ok'; out.innerHTML = 'M_r(' + f + ') = ' + C().fmt(mr) + '
' + Object.keys(cnt).map(function (e) { return e + ': A_r=' + (C().arOf ? C().arOf(e) : '?') + ' × ' + cnt[e]; }).join('  |  ') + '
Σ = ' + Object.keys(cnt).map(function (e) { return (C().arOf ? C().arOf(e) : '?') + '·' + cnt[e]; }).join(' + ') + ' = ' + C().fmt(mr) + '
'; } go.addEventListener('click', calc); inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); }); document.querySelectorAll('.p8-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); }); calc(); } /* §9 — конструктор формулы по валентности (НОК индексов) */ function gcd(a, b) { return b ? gcd(b, a % b) : a; } var VA = [ ['Na', 1], ['K', 1], ['H', 1], ['Mg', 2], ['Ca', 2], ['Zn', 2], ['Cu', 2], ['Al', 3], ['C', 4] ]; var VB = [ ['O', 2], ['Cl', 1], ['S', 2] ]; var BCOL = { O:'#ef4444', Cl:'#22c55e', S:'#eab308' }; function mount_p9() { var m = $('p9-bld'); if (!m || m._built) return; m._built = 1; var vanim = null; function optA(){ return VA.map(function(e,i){ return ''; }).join(''); } function optB(){ return VB.map(function(e,i){ return ''; }).join(''); } m.innerHTML = '
' +'
' +'
' +'
'; function upd() { var a = VA[+$('p9-a').value], b = VB[+$('p9-b').value]; var lcm = a[1] * b[1] / gcd(a[1], b[1]); var ia = lcm / a[1], ib = lcm / b[1]; var raw = a[0] + (ia > 1 ? ia : '') + b[0] + (ib > 1 ? ib : ''); if (vanim) { vanim.stop(); vanim = null; } if (W.Chem7Anim) vanim = W.Chem7Anim.valenceLink($('p9-vis'), { a: { el:a[0], val:a[1], n:ia, color:'#6366f1' }, b: { el:b[0], val:b[1], n:ib, color:BCOL[b[0]] || '#ef4444' } }); var out = $('p9-bout'); out.className = 'out ok'; out.innerHTML = 'Валентности: ' + a[0] + ' = ' + 'I'.repeat(a[1]).replace('IIII','IV') + ', ' + b[0] + ' = ' + 'I'.repeat(b[1]) + '
' + 'Каждая чёрточка-связь соединена — все валентности заняты.
' + 'НОК валентностей = ' + lcm + '; индексы: ' + a[0] + ' → ' + ia + ', ' + b[0] + ' → ' + ib + '
' + 'Формула: ' + (C().formula ? C().formula(raw) : raw) + '
'; } $('p9-a').addEventListener('change', upd); $('p9-b').addEventListener('change', upd); upd(); } /* ── Волна 4 ── */ /* §10 / ЛО1 — детектор признаков химической реакции */ var DEMOS = [ { name: 'Нагревание малахита', signs: ['изменение цвета: зелёный → чёрный', 'выделение газа (водяной пар и углекислый газ)'] }, { name: 'Сливание растворов CuSO₄ и NaOH', signs: ['образование осадка (голубой)', 'изменение цвета раствора'] }, { name: 'Горение серы', signs: ['выделение света и тепла (пламя)', 'появление резкого запаха'] }, { name: 'Добавление соды в уксус', signs: ['выделение газа (пузырьки)'] } ]; // анимация на каждый опыт (через Chem7Anim, CSS-хелперы) function demoAnim(idx, host) { var A = W.Chem7Anim; if (!A || !host) return null; if (idx === 0) return A.colorBlock(host, '#16a34a', '#1f2937', 'малахит → CuO + газы', 2000); // зелёный → чёрный if (idx === 1) return A.precipField(host, { color: '#38bdf8' }); // голубой осадок if (idx === 2) return A.flameBox(host, { color: '#3b82f6', sparks: true }); // синее пламя серы return A.bubbleField(host, { color: 'rgba(255,255,255,.85)' }); // пузырьки газа } function mount_signs(mountId) { var m = $(mountId); if (!m || m._built) return; m._built = 1; var idx = 0, anim = null; function stopAnim() { if (anim) { anim.stop(); anim = null; } } function render() { stopAnim(); m.innerHTML = '
' + '
' + '
' + '
Выбери опыт и нажми «Провести опыт».
'; $(mountId + '-pick').addEventListener('change', function (e) { idx = +e.target.value; render(); }); $(mountId + '-go').addEventListener('click', function () { var d = DEMOS[idx], out = $(mountId + '-out'); stopAnim(); anim = demoAnim(idx, $(mountId + '-stage')); out.className = 'out ok'; out.innerHTML = 'Наблюдаемые признаки реакции:
' + d.signs.map(function (s) { return '
✓ ' + esc(s) + '
'; }).join('') + '
Эти признаки указывают, что произошла химическая реакция — образовались новые вещества.
'; }); } render(); } function mount_p10() { mount_signs('p10-signs'); } function mount_lo1() { mount_signs('lo1-signs'); } /* §11 — весы сохранения массы */ function mount_p11() { var m = $('p11-bal'); if (!m || m._built) return; m._built = 1; var mixed = false; function scale(level) { // level: 0 = равновесие return '' + '' + '' + '' + '' + '' + '' + '' + '100 г' + '100 г' + '' + (mixed ? 'продукты' : 'реагенты') + '' + '' + (mixed ? 'продукты' : 'реагенты') + '' + ''; } var anim = null; function render() { if (anim) { anim.stop(); anim = null; } m.innerHTML = scale() + '
' + (mixed ? 'После реакции: осадок Cu(OH)₂ + раствор Na₂SO₄. Стрелка весов не сдвинулась — масса сохранилась (100 г = 100 г).' : 'До реакции: раствор CuSO₄ + раствор NaOH, общая масса 100 г.') + '
' + '
' + ''; if (mixed && W.Chem7Anim) anim = W.Chem7Anim.precipField($('p11-stage'), { color: '#38bdf8', h: 96 }); $('p11-mix').addEventListener('click', function () { mixed = !mixed; render(); }); } render(); } /* §12 — балансировщик + анимированный подсчёт атомов (слева/справа) */ var ELC = { H:'#cbd5e1', O:'#ef4444', C:'#334155', N:'#3b82f6', S:'#eab308', Fe:'#b45309', P:'#f97316', Cl:'#22c55e', Mg:'#22c55e', Ca:'#a78bfa', Na:'#a78bfa', Cu:'#ea580c', Zn:'#64748b', Al:'#6366f1', K:'#a78bfa' }; function mount_p12() { var pick = $('p12-pick'), mount = $('p12-mount'); if (!pick || pick._built || !C().equationBalancer) return; pick._built = 1; if (!$('p12-tally')) mount.insertAdjacentHTML('afterend', '
'); function sumSide(list, coeffs, off) { var tot = {}; list.forEach(function (sp, i) { var cnt = C().elementCounts ? C().elementCounts(sp) : {}; var co = coeffs[off + i] || 1; for (var e in cnt) tot[e] = (tot[e] || 0) + cnt[e] * co; }); return tot; } function dots(el, n) { var s = ''; for (var i = 0; i < n; i++) s += ''; return s; } function col(title, tot) { return '
' + title + '
' + Object.keys(tot).map(function (e) { return '
' + e + '' + dots(e, tot[e]) + '× ' + tot[e] + '
'; }).join('') + '
'; } function tally(skeleton, coeffs) { var t = $('p12-tally'); if (!t) return; var sides = skeleton.split(/->|=/); var L = sides[0].split('+').map(function (s) { return s.trim(); }); var Rr = (sides[1] || '').split('+').map(function (s) { return s.trim(); }); var left = sumSide(L, coeffs, 0), right = sumSide(Rr, coeffs, L.length); var ok = Object.keys(left).every(function (e) { return left[e] === right[e]; }) && Object.keys(right).every(function (e) { return left[e] === right[e]; }); t.innerHTML = '
' + col('Реагенты — атомы', left) + col('Продукты — атомы', right) + '
' + '
' + (ok ? '✓ Число атомов каждого элемента слева и справа совпадает — уравнение сбалансировано.' : 'Атомы не уравнены.') + '
'; if (W.Chem7Anim && !W.Chem7Anim.HEADLESS) { var a = t.querySelectorAll('.c7-atom'); a.forEach(function (d, i) { d.style.transitionDelay = (i * 28) + 'ms'; }); W.requestAnimationFrame(function () { W.requestAnimationFrame(function () { a.forEach(function (d) { d.style.transform = 'scale(1)'; d.style.opacity = '1'; }); }); }); } } function build() { var parts = pick.value.split('|'); var coeffs = parts[1].split(',').map(Number); C().equationBalancer(mount, { skeleton: parts[0], solution: coeffs }); tally(parts[0], coeffs); } pick.addEventListener('change', build); build(); } W.CHEM8_WIDGETS = Object.assign(W.CHEM8_WIDGETS || {}, { p1: mount_p1, p2: mount_p2, pr1: mount_pr1, p3: mount_p3, p4: mount_p4, p5: mount_p5, p6: mount_p6, p7: mount_p7, p8: mount_p8, p9: mount_p9, p10: mount_p10, lo1: mount_lo1, p11: mount_p11 }); W.FLAG_MOUNTS = Object.assign(W.FLAG_MOUNTS || {}, { p12: mount_p12 }); })(window);