/* Comparison of two finished runs: renders the comparison embedded as JSON in #analytics-data (the groups of addresses, the dynamics of the seven indicators, the verdict transitions) and opens the address list behind each number in the shared dialog (analytics-dialog.js). The state of the page is its address: ?base=A&target=B. */ (function () { 'use strict'; var D = JSON.parse(document.getElementById('analytics-data').textContent); var R = D.report, M = D.meta, G = R.groups, T = R.transitions; var A = window.AnalyticsDialog, $ = A.$, fmt = A.fmt, esc = A.esc, tipAttr = A.tipAttr; function pct(a, b) { return b ? Math.round(a / b * 100) : 0; } var NAME = {}; R.indicators.forEach(function (d) { NAME[d.key] = d.name; }); /* ---- what each list says about itself ---- */ var GROUP = { new: ['Новые адреса', 'Есть в запуске B, в A их не было: прибыли в проект и подключились к анализу. Столбцы показывают состояние в B.'], left: ['Выбывшие адреса', 'Были в запуске A, в B их нет: вышли из состава проекта. Столбцы показывают состояние в A.'], common: ['Общие адреса', 'Есть в обоих запусках. Столбцы показывают состояние в A → B.'], changed: ['Изменившиеся адреса', 'Есть в обоих запусках, принадлежность хотя бы к одному из семи индикаторов в A и в B разная.'], same: ['Адреса без изменений', 'Есть в обоих запусках, принадлежность ко всем индикаторам та же. Другой набор проваленных целей или площадок изменением не считается.'], entered: ['Вошли в индикатор', 'Общие адреса, которые в A не входили в этот индикатор, а в B входят.'], exited: ['Вышли из индикатора', 'Общие адреса, которые в A входили в этот индикатор, а в B не входят.'] }; var HINT_ONE = { 2: 'Вердикт адреса, который система выставила при агрегации, а не итог всех проверок.', 3: 'Сколько egress-проверок адреса успешно из всех записанных в последнем цикле запуска. «—» — egress-проверок нет.', 4: 'Сколько ingress-проверок адреса успешно из всех записанных в последнем цикле запуска. «—» — ingress-проверок нет.', 5: 'Индикаторы страницы «Аналитика», в которые входит адрес. Один адрес может входить в несколько; вердикт — ровно в один из трёх.' }; var HINT_PAIR = { 2: 'Вердикт адреса в запуске A и в запуске B.', 3: 'Сколько egress-проверок адреса успешно из всех записанных в последнем цикле: в A → в B.', 4: 'Сколько ingress-проверок адреса успешно из всех записанных в последнем цикле: в A → в B.', 5: 'Что изменилось между запусками, по шагам: вердикт, вход в индикатор и выход из него, проваленные цели https и площадки ssh, валидатор. У адреса без изменений в индикаторах — «без изменений», даже если набор проваленных целей другой.' }; function describe(f) { var g = GROUP[f.group], ind = f.ind ? '«' + (NAME[f.ind] || f.ind) + '»' : ''; var title = g[0] + (f.ind ? ': ' + (NAME[f.ind] || f.ind) : '') + (f.from ? ' · вердикт ' + f.from + ' → ' + f.to : ''); var note = g[1]; if (f.ind && f.group === 'new') note += ' Только входящие в индикатор ' + ind + ' в запуске B.'; if (f.ind && f.group === 'left') note += ' Только входившие в индикатор ' + ind + ' в запуске A.'; if (f.ind && (f.group === 'common' || f.group === 'changed' || f.group === 'same')) note += ' Только входящие в индикатор ' + ind + ' хотя бы в одном из запусков.'; if (f.from) note += ' Только адреса с вердиктом ' + f.from + ' в A и ' + f.to + ' в B.'; return { title: title, note: note, hints: f.group === 'new' || f.group === 'left' ? HINT_ONE : HINT_PAIR }; } function listURL(root, f) { return root + encodeURIComponent(f.group) + '?base=' + M.base.id + '&target=' + M.target.id + (f.ind ? '&indicator=' + encodeURIComponent(f.ind) : '') + (f.from ? '&from=' + encodeURIComponent(f.from) + '&to=' + encodeURIComponent(f.to) : ''); } function openList(f) { var t = describe(f); A.load(listURL(M.list_url, f), t.title).then(function (l) { if (!l) return; A.fill({ title: t.title, note: t.note, hints: t.hints, scope: 'Запуски', runLabel: 'A — ' + M.base.label + '; B — ' + M.target.label, cols: l.columns, rows: l.rows, csvURL: listURL(M.csv_url, f) }); }); } /* ---- the page ---- */ function renderNote() { function line(name, m, r, cancelled) { return '