kpi-dashboard/app_stats/index.html
Iliyas 5b78a24439 feat(Метрики МП): daily scrollable charts, MAU max/month, DAU avg, iOS+Android lines
- updater: monthly MAU = MAX over month, monthly DAU = AVG; add monthly
  iOS/Android series + daily series (last 540 days) to top{} JSON
- modal: monthly chart + scrollable daily chart (scrolls to latest); downloads
  show Всего + semi-transparent iOS/Android lines (both monthly & daily)
2026-06-17 14:07:48 +05:00

5228 lines
108 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Метрики МП — Казахтелеком 2026</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js"></script>
<style>
:root {
--color-bg: #F4F6F9;
--color-surface: #FFFFFF;
--color-border: #E5E7EB;
--color-text-primary: #111827;
--color-text-secondary: #6B7280;
--color-brand: #0052CC;
--color-brand-light: #EFF6FF;
--color-green: #10B981;
--color-green-bg: #ECFDF5;
--color-yellow: #F59E0B;
--color-yellow-bg: #FFFBEB;
--color-red: #EF4444;
--color-red-bg: #FEF2F2;
--color-purple: #8B5CF6;
--color-purple-bg: #F5F3FF;
--radius-card: 12px;
--radius-btn: 8px;
--shadow-card: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04);
--shadow-card-hover: 0 4px 12px rgba(0,0,0,0.1);
--font-base: 'Inter', system-ui, sans-serif;
--font-mono: 'Roboto Mono', monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: var(--font-base); background: var(--color-bg); color: var(--color-text-primary); font-size: 14px; line-height: 1.5; }
@keyframes spin { to { transform: rotate(360deg); } }
/* LOGIN */
#login-screen { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #0052CC 0%, #0070F3 100%); }
.login-box { background: #fff; border-radius: 20px; padding: 48px 56px; text-align: center; max-width: 420px; width: 90%; box-shadow: 0 20px 60px rgba(0,0,0,0.15); }
.login-logo { display: inline-flex; align-items: center; justify-content: center; width: 64px; height: 64px; background: var(--color-brand); color: #fff; font-size: 24px; font-weight: 700; border-radius: 16px; margin-bottom: 20px; }
.login-box h1 { font-size: 22px; font-weight: 700; margin-bottom: 4px; }
.login-box > p { color: var(--color-text-secondary); margin-bottom: 28px; font-size: 14px; }
.txt-input { width: 100%; padding: 11px 14px; border: 1px solid var(--color-border); border-radius: var(--radius-btn); font-size: 15px; font-family: var(--font-base); outline: none; transition: border-color 0.15s; }
.txt-input:focus { border-color: var(--color-brand); }
.btn-primary { padding: 11px 40px; background: var(--color-brand); color: #fff; border: none; border-radius: var(--radius-btn); font-size: 14px; font-weight: 600; cursor: pointer; font-family: var(--font-base); transition: background 0.15s; }
.btn-primary:hover { background: #003fa3; }
#login-error { color: var(--color-red); font-size: 13px; margin-top: 10px; min-height: 18px; }
/* HEADER */
#app { display: none; }
.header { background: var(--color-brand); color: #fff; padding: 0 24px; height: 64px; display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 100; box-shadow: 0 2px 8px rgba(0,82,204,0.3); }
.header-left { display: flex; align-items: center; gap: 14px; }
.header-logo { width: 40px; height: 40px; background: rgba(255,255,255,0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 14px; flex-shrink: 0; }
.header-left h1 { font-size: 16px; font-weight: 700; line-height: 1.2; }
.header-left p { font-size: 12px; opacity: 0.75; }
.header-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
#generated-at { font-size: 12px; opacity: 0.85; }
.btn { padding: 7px 14px; border-radius: var(--radius-btn); font-size: 13px; font-weight: 500; cursor: pointer; border: none; font-family: var(--font-base); transition: all 0.15s; text-decoration: none; display: inline-block; }
.btn-ghost { background: rgba(255,255,255,0.15); color: #fff; }
.btn-ghost:hover { background: rgba(255,255,255,0.25); }
/* SUMMARY */
.wrap { padding: 20px 24px 40px; max-width: 1400px; margin: 0 auto; }
.summary-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 22px; }
.sum-card { background: var(--color-surface); border-radius: var(--radius-card); padding: 16px 18px; box-shadow: var(--shadow-card); border-top: 4px solid var(--color-brand); }
.sum-card.accent-green { border-top-color: var(--color-green); }
.sum-card.accent-purple { border-top-color: var(--color-purple); }
.sum-card.accent-yellow { border-top-color: var(--color-yellow); }
.sum-label { font-size: 11px; font-weight: 600; color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 8px; }
.sum-value { font-size: 26px; font-weight: 700; font-family: var(--font-mono); line-height: 1.1; }
.sum-sub { font-size: 12px; color: var(--color-text-secondary); margin-top: 4px; }
/* CONTROLS */
.controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 18px; }
.controls .grow { flex: 1 1 220px; }
.controls label { font-size: 13px; color: var(--color-text-secondary); display: flex; align-items: center; gap: 6px; cursor: pointer; }
select.txt-input, input.txt-input { font-size: 13px; padding: 9px 12px; }
select.txt-input { cursor: pointer; background: #fff; }
/* METRIC CARDS */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.card { background: var(--color-surface); border-radius: var(--radius-card); padding: 16px 18px; box-shadow: var(--shadow-card); border-left: 4px solid var(--color-border); transition: box-shadow 0.2s, transform 0.2s; }
.card:hover { box-shadow: var(--shadow-card-hover); transform: translateY(-2px); }
.card.up { border-left-color: var(--color-green); }
.card.down { border-left-color: var(--color-red); }
.card.flat { border-left-color: var(--color-yellow); }
.card.new { border-left-color: var(--color-purple); }
.card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; margin-bottom: 12px; }
.card-title { font-size: 13px; font-weight: 600; line-height: 1.35; }
.badge { font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 20px; white-space: nowrap; flex-shrink: 0; }
.badge.up { background: var(--color-green-bg); color: var(--color-green); }
.badge.down { background: var(--color-red-bg); color: var(--color-red); }
.badge.flat { background: var(--color-yellow-bg); color: #92400E; }
.badge.new { background: var(--color-purple-bg); color: var(--color-purple); }
.card-value { font-size: 30px; font-weight: 700; font-family: var(--font-mono); line-height: 1; }
.card-value-year { font-size: 11px; color: var(--color-text-secondary); font-weight: 600; margin-left: 2px; }
.card-sub { font-size: 11px; color: var(--color-text-secondary); margin-top: 2px; }
/* накопительный мини-график (нарастающим итогом по месяцам) */
.spark { width: 100%; height: 52px; display: block; margin-top: 12px; overflow: visible; }
.spark polyline { fill: none; stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linecap: round; stroke-linejoin: round; }
.spark .sp-cur { stroke: var(--color-brand); }
.spark .sp-prev { stroke: #C7D2E8; stroke-dasharray: 3 3; }
.spark .dot-cur { fill: var(--color-brand); }
.spark-x { display: flex; justify-content: space-between; font-size: 9px; color: var(--color-text-secondary); font-family: var(--font-mono); margin-top: 2px; }
.legend { display: flex; gap: 14px; margin-top: 10px; font-size: 11px; }
.legend span { display: flex; align-items: center; gap: 5px; color: var(--color-text-secondary); }
.legend b { font-family: var(--font-mono); color: var(--color-text-primary); font-weight: 600; }
.legend .dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.legend .dot.cur { background: var(--color-brand); }
.legend .dot.prev { background: #C7D2E8; }
.empty-note { text-align: center; color: var(--color-text-secondary); padding: 40px; grid-column: 1 / -1; }
/* ── TOP KPI CARDS ── */
.section-title { font-size: 13px; font-weight: 700; color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.04em; margin: 4px 0 12px; }
.top-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 24px; }
.kpi-stat { background: var(--color-surface); border-radius: var(--radius-card); padding: 16px 18px; box-shadow: var(--shadow-card); border-top: 4px solid var(--color-brand); cursor: pointer; transition: box-shadow 0.2s, transform 0.2s; }
.kpi-stat:hover { box-shadow: var(--shadow-card-hover); transform: translateY(-2px); }
.kpi-stat.accent-green { border-top-color: var(--color-green); }
.kpi-stat.accent-purple { border-top-color: var(--color-purple); }
.kpi-stat.accent-yellow { border-top-color: var(--color-orange); }
.kpi-stat-value { font-size: 26px; font-weight: 700; font-family: var(--font-mono); line-height: 1.1; margin-top: 2px; }
.kpi-stat-sub { font-size: 12px; color: var(--color-text-secondary); margin-top: 4px; min-height: 16px; }
/* ── VIEW TOGGLE ── */
.view-toggle { display: flex; gap: 4px; }
.view-toggle button { padding: 8px 11px; border: 1px solid var(--color-border); background: #fff; cursor: pointer; border-radius: var(--radius-btn); color: var(--color-text-secondary); font-family: var(--font-base); font-size: 14px; line-height: 1; transition: all 0.15s; }
.view-toggle button:hover { border-color: var(--color-brand); color: var(--color-brand); }
.view-toggle button.active { background: var(--color-brand); color: #fff; border-color: var(--color-brand); }
/* ── LIST VIEW ── */
.card { cursor: pointer; }
.cards.list { grid-template-columns: 1fr; }
.cards.list .card { display: grid; grid-template-columns: minmax(190px, 1.1fr) 130px minmax(160px, 2fr) minmax(150px, auto); align-items: center; gap: 22px; }
.cards.list .card-head { margin-bottom: 0; }
.cards.list .card-value { font-size: 24px; }
.cards.list .spark { margin-top: 0; height: 44px; }
.cards.list .spark-x { display: none; }
.cards.list .legend { margin-top: 0; flex-direction: column; gap: 5px; }
/* ── MODAL ── */
.modal-overlay { position: fixed; inset: 0; background: rgba(17,24,39,0.55); display: none; align-items: center; justify-content: center; z-index: 1000; padding: 20px; }
.modal-overlay.open { display: flex; }
.modal-box { background: #fff; border-radius: 16px; max-width: 880px; width: 100%; max-height: 90vh; overflow-y: auto; box-shadow: 0 20px 60px rgba(0,0,0,0.25); }
.modal-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; padding: 20px 24px; border-bottom: 1px solid var(--color-border); position: sticky; top: 0; background: #fff; z-index: 1; }
.modal-title { font-size: 18px; font-weight: 700; }
.modal-sub { font-size: 12px; color: var(--color-text-secondary); margin-top: 3px; }
.modal-close { background: var(--color-bg); border: none; width: 32px; height: 32px; border-radius: 8px; cursor: pointer; font-size: 16px; color: var(--color-text-secondary); flex-shrink: 0; }
.modal-close:hover { background: var(--color-border); }
.modal-body { padding: 20px 24px; }
.modal-section { font-size: 11px; font-weight: 700; color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.04em; margin: 4px 0 8px; }
.modal-section .hint { font-weight: 500; text-transform: none; letter-spacing: 0; opacity: 0.8; }
.modal-chart-wrap { position: relative; height: 280px; margin-bottom: 18px; }
.daily-scroll { overflow-x: auto; overflow-y: hidden; margin-bottom: 20px; border: 1px solid var(--color-border); border-radius: 8px; padding: 8px 4px 4px; }
.daily-inner { height: 240px; position: relative; }
.daily-scroll::-webkit-scrollbar { height: 8px; }
.daily-scroll::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 8px; }
.daily-scroll::-webkit-scrollbar-thumb:hover { background: #cbd2dc; }
.mtable { width: 100%; border-collapse: collapse; font-size: 13px; }
.mtable th, .mtable td { padding: 7px 10px; text-align: right; border-bottom: 1px solid var(--color-border); font-family: var(--font-mono); white-space: nowrap; }
.mtable th:first-child, .mtable td:first-child { text-align: left; font-family: var(--font-base); }
.mtable th { font-weight: 600; color: var(--color-text-secondary); font-size: 11px; text-transform: uppercase; letter-spacing: 0.02em; }
.mtable tbody tr:last-child td { font-weight: 700; }
/* loading / error */
#status-msg { text-align:center; padding: 60px 20px; color: var(--color-text-secondary); }
@media (max-width: 900px) { .summary-grid, .top-grid { grid-template-columns: repeat(2,1fr); } .cards.list .card { grid-template-columns: 1fr; gap: 10px; } }
@media (max-width: 560px) { .summary-grid, .top-grid { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<!-- LOGIN -->
<div id="login-screen">
<div class="login-box">
<div class="login-logo">KT</div>
<h1>Метрики МП</h1>
<p>Казахтелеком · 2026</p>
<input type="password" id="login-password" class="txt-input" placeholder="Введите пароль" style="text-align:center;margin-bottom:12px;">
<button class="btn-primary" id="btn-login">Войти</button>
<p id="login-error"></p>
</div>
</div>
<!-- APP -->
<div id="app">
<header class="header">
<div class="header-left">
<div class="header-logo">KT</div>
<div>
<h1>📱 Метрики МП</h1>
<p>Использование функций МП · нарастающим итогом, год к году</p>
</div>
</div>
<div class="header-right">
<span id="generated-at"></span>
<a class="btn btn-ghost" href="../index.html">← KPI Dashboard</a>
</div>
</header>
<div class="wrap">
<div id="status-msg">Загрузка данных…</div>
<div id="content" style="display:none">
<div class="section-title">Ключевые показатели приложения</div>
<div class="top-grid" id="top-grid"></div>
<div class="section-title">Сравнение функций · год к году</div>
<div class="summary-grid" id="summary-grid"></div>
<div class="controls">
<input type="text" id="search" class="txt-input grow" placeholder="🔍 Поиск метрики…">
<select id="sort" class="txt-input">
<option value="cur">Сортировка: по использованию ↓</option>
<option value="growth">по приросту ↓</option>
<option value="label">по названию (А→Я)</option>
</select>
<label><input type="checkbox" id="only-new"> только новые</label>
<div class="view-toggle">
<button data-view="grid" title="Сетка"></button>
<button data-view="list" title="Список"></button>
</div>
</div>
<div class="cards" id="cards"></div>
</div>
</div>
</div>
<!-- MODAL -->
<div class="modal-overlay" id="modal">
<div class="modal-box">
<div class="modal-head">
<div>
<div class="modal-title" id="modal-title"></div>
<div class="modal-sub" id="modal-sub"></div>
</div>
<button class="modal-close" id="modal-close" title="Закрыть"></button>
</div>
<div class="modal-body" id="modal-body"></div>
</div>
</div>
<script>
const LOGIN_PASSWORD = 'KTdash1';
const DATA_URL = 'app_metrics.json';
// Резервные данные (на случай file:// или недоступности файла). Обновляются скриптом updater.
const EMBEDDED_METRICS = /*__DATA__*/{
"generated_at": "2026-06-17T14:04:10",
"cur_year": 2026,
"prev_year": 2025,
"period_label": "с 1 января по 16 июня",
"range": {
"start": "2026-01-01",
"end": "2026-06-16"
},
"months": [
1,
2,
3,
4,
5,
6
],
"month_labels": [
"Янв",
"Фев",
"Мар",
"Апр",
"Май",
"Июн"
],
"cumulative": true,
"metrics": [
{
"key": "my_services",
"label": "Мои услуги",
"cur": 1796228,
"prev": 1472562,
"growth": 0.21979787608263693,
"is_new": false,
"cur_cum": [
321989,
621597,
980877,
1327890,
1676682,
1796228
],
"prev_cum": [
308264,
594530,
857453,
1108674,
1341165,
1472562
]
},
{
"key": "traffic",
"label": "Детализация трафика",
"cur": 1290610,
"prev": 1089617,
"growth": 0.18446206327544448,
"is_new": false,
"cur_cum": [
246604,
463349,
727262,
978030,
1179069,
1290610
],
"prev_cum": [
214948,
425004,
634594,
827602,
1001634,
1089617
]
},
{
"key": "payments",
"label": "Платежи",
"cur": 741888,
"prev": 557497,
"growth": 0.3307479681505013,
"is_new": false,
"cur_cum": [
111523,
203960,
358189,
523890,
653416,
741888
],
"prev_cum": [
120062,
232395,
331976,
427765,
512345,
557497
]
},
{
"key": "orders",
"label": "Заявки",
"cur": 845340,
"prev": 642020,
"growth": 0.31668795364630387,
"is_new": false,
"cur_cum": [
173075,
312944,
461361,
601613,
742794,
845340
],
"prev_cum": [
153918,
301147,
409051,
500862,
587480,
642020
]
},
{
"key": "loyalty",
"label": "Лояльность",
"cur": 474289,
"prev": 466803,
"growth": 0.016036743551348213,
"is_new": false,
"cur_cum": [
86429,
152587,
264979,
351823,
432724,
474289
],
"prev_cum": [
88583,
196751,
284932,
371536,
431175,
466803
]
},
{
"key": "pay",
"label": "Оплата",
"cur": 341470,
"prev": 305025,
"growth": 0.11948200967133842,
"is_new": false,
"cur_cum": [
73119,
141842,
198550,
248839,
304810,
341470
],
"prev_cum": [
50344,
101847,
150536,
205493,
269251,
305025
]
},
{
"key": "billing_detail",
"label": "Детали счета",
"cur": 502390,
"prev": 359719,
"growth": 0.39661791565082744,
"is_new": false,
"cur_cum": [
81176,
147137,
241789,
343225,
431112,
502390
],
"prev_cum": [
62482,
134395,
200427,
260559,
315518,
359719
]
},
{
"key": "viktorina",
"label": "Викторина KT Club",
"cur": 213879,
"prev": 298475,
"growth": -0.28342742273222216,
"is_new": false,
"cur_cum": [
0,
1,
118526,
213879,
213879,
213879
],
"prev_cum": [
0,
0,
49414,
298475,
298475,
298475
]
},
{
"key": "partners",
"label": "Акции партнеров",
"cur": 197777,
"prev": 95016,
"growth": 1.0815125873537088,
"is_new": false,
"cur_cum": [
40566,
65001,
117646,
149940,
185907,
197777
],
"prev_cum": [
27730,
49011,
65023,
75359,
89282,
95016
]
},
{
"key": "tv_plus",
"label": "TV+",
"cur": 65461,
"prev": 96208,
"growth": -0.31958880758356895,
"is_new": false,
"cur_cum": [
11947,
20939,
33969,
45372,
56326,
65461
],
"prev_cum": [
24830,
44479,
61671,
76824,
90692,
96208
]
},
{
"key": "boosters",
"label": "Бустеры",
"cur": 123015,
"prev": 54525,
"growth": 1.256121045392022,
"is_new": false,
"cur_cum": [
15882,
33486,
61530,
88555,
114328,
123015
],
"prev_cum": [
7244,
12487,
18093,
31284,
49552,
54525
]
},
{
"key": "roaming",
"label": "Роуминг",
"cur": 22826,
"prev": 39835,
"growth": -0.4269863185640768,
"is_new": false,
"cur_cum": [
2924,
5494,
8974,
11894,
18923,
22826
],
"prev_cum": [
6678,
13021,
19649,
27201,
35474,
39835
]
},
{
"key": "pereoform",
"label": "Переоформление",
"cur": 35385,
"prev": 23802,
"growth": 0.48663977816990167,
"is_new": false,
"cur_cum": [
7556,
12691,
18718,
24711,
30988,
35385
],
"prev_cum": [
4876,
9244,
13556,
17422,
21572,
23802
]
},
{
"key": "aitu_music",
"label": "Aitu Music",
"cur": 8872,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
1048,
4000,
5553,
7271,
8872
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "online_booking",
"label": "Онлайн очередь",
"cur": 22529,
"prev": 5523,
"growth": 3.0791236646749955,
"is_new": false,
"cur_cum": [
5636,
10095,
13892,
17262,
20514,
22529
],
"prev_cum": [
0,
0,
0,
1848,
4407,
5523
]
},
{
"key": "my_docs",
"label": "Мои документы",
"cur": 54148,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
14980,
24658,
33590,
41765,
49555,
54148
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "dz_statement",
"label": "Справка о ДЗ",
"cur": 134463,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
35454,
64672,
85004,
100575,
119914,
134463
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "new_boosters_roaming_kcell",
"label": "Новая линейка бустеров и роумингов Кселл",
"cur": 28858,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
1927,
4523,
13318,
21056,
28240,
28858
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "adsl",
"label": "ADSL отключение услуги",
"cur": 69,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
20,
33,
44,
55,
65,
69
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "law_and_order",
"label": "Закон и порядок",
"cur": 1598,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
232,
671,
1034,
1377,
1598
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "acs",
"label": "ACS",
"cur": 9447,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
2329,
7499,
7800,
8174,
9447
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "kaspi_freedom_pay",
"label": "Прием платежей через Freedom и Kaspi",
"cur": 62724,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
8427,
24816,
39893,
53445,
62724
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "csat",
"label": "CSAT",
"cur": 4057,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
0,
0,
0,
0,
4057
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "multicustomer",
"label": "Мультикастомер",
"cur": 169,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
0,
0,
0,
99,
169
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "tv_plus_setup",
"label": "Настройка TV+",
"cur": 4908,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
0,
0,
0,
2630,
4908
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "static_ip",
"label": "Статический IP",
"cur": 119,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
0,
0,
35,
75,
119
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "turbo_button",
"label": "Turbo кнопка",
"cur": 4638,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
0,
0,
498,
2789,
4638
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
},
{
"key": "real_estate_docs",
"label": "Справка о недвижимости",
"cur": 79,
"prev": 0,
"growth": null,
"is_new": true,
"cur_cum": [
0,
23,
44,
52,
70,
79
],
"prev_cum": [
0,
0,
0,
0,
0,
0
]
}
],
"top": {
"as_of": "2026-06-16",
"registered_total": 1078231,
"installs_total": 2307490,
"installs_ios": 924083,
"installs_android": 1383407,
"mau": 185155,
"dau": 17757,
"trend_labels": [
"Июн 25",
"Июл 25",
"Авг 25",
"Сен 25",
"Окт 25",
"Ноя 25",
"Дек 25",
"Янв 26",
"Фев 26",
"Мар 26",
"Апр 26",
"Май 26",
"Июн 26"
],
"registered_series": [
925945,
937312,
949404,
961772,
973331,
985194,
1000768,
1016923,
1030968,
1043887,
1056398,
1068794,
1078231
],
"installs_series": [
1485273,
1519017,
1552922,
1722057,
1803173,
1879957,
1973234,
2053773,
2131472,
2176215,
2215453,
2260248,
2307490
],
"installs_ios_series": [
454805,
467042,
479578,
628159,
685235,
713652,
756819,
804216,
855390,
877708,
896277,
914383,
924083
],
"installs_android_series": [
1030468,
1051975,
1073344,
1093898,
1117938,
1166305,
1216415,
1249557,
1276082,
1298507,
1319176,
1345865,
1383407
],
"mau_series": [
259010,
217943,
221886,
192462,
146096,
148208,
193675,
259426,
256194,
274991,
263556,
252238,
185155
],
"dau_series": [
35538,
18569,
19517,
15670,
11862,
12247,
17946,
27955,
28326,
29972,
28007,
25391,
26288
],
"daily": {
"labels": [
"2024-12-24",
"2024-12-25",
"2024-12-26",
"2024-12-27",
"2024-12-28",
"2024-12-29",
"2024-12-30",
"2024-12-31",
"2025-01-01",
"2025-01-02",
"2025-01-03",
"2025-01-04",
"2025-01-05",
"2025-01-06",
"2025-01-07",
"2025-01-08",
"2025-01-09",
"2025-01-10",
"2025-01-11",
"2025-01-12",
"2025-01-13",
"2025-01-14",
"2025-01-15",
"2025-01-16",
"2025-01-17",
"2025-01-18",
"2025-01-19",
"2025-01-20",
"2025-01-21",
"2025-01-22",
"2025-01-23",
"2025-01-24",
"2025-01-25",
"2025-01-26",
"2025-01-27",
"2025-01-28",
"2025-01-29",
"2025-01-30",
"2025-01-31",
"2025-02-01",
"2025-02-02",
"2025-02-03",
"2025-02-04",
"2025-02-05",
"2025-02-06",
"2025-02-07",
"2025-02-08",
"2025-02-09",
"2025-02-10",
"2025-02-11",
"2025-02-12",
"2025-02-13",
"2025-02-14",
"2025-02-15",
"2025-02-16",
"2025-02-17",
"2025-02-18",
"2025-02-19",
"2025-02-20",
"2025-02-21",
"2025-02-22",
"2025-02-23",
"2025-02-24",
"2025-02-25",
"2025-02-26",
"2025-02-27",
"2025-02-28",
"2025-03-01",
"2025-03-02",
"2025-03-03",
"2025-03-04",
"2025-03-05",
"2025-03-06",
"2025-03-07",
"2025-03-08",
"2025-03-09",
"2025-03-10",
"2025-03-11",
"2025-03-12",
"2025-03-13",
"2025-03-14",
"2025-03-15",
"2025-03-16",
"2025-03-17",
"2025-03-18",
"2025-03-19",
"2025-03-20",
"2025-03-21",
"2025-03-22",
"2025-03-23",
"2025-03-24",
"2025-03-25",
"2025-03-26",
"2025-03-27",
"2025-03-28",
"2025-03-29",
"2025-03-30",
"2025-03-31",
"2025-04-01",
"2025-04-02",
"2025-04-03",
"2025-04-04",
"2025-04-05",
"2025-04-06",
"2025-04-07",
"2025-04-08",
"2025-04-09",
"2025-04-10",
"2025-04-11",
"2025-04-12",
"2025-04-13",
"2025-04-14",
"2025-04-15",
"2025-04-16",
"2025-04-17",
"2025-04-18",
"2025-04-19",
"2025-04-20",
"2025-04-21",
"2025-04-22",
"2025-04-23",
"2025-04-24",
"2025-04-25",
"2025-04-26",
"2025-04-27",
"2025-04-28",
"2025-04-29",
"2025-04-30",
"2025-05-01",
"2025-05-02",
"2025-05-03",
"2025-05-04",
"2025-05-05",
"2025-05-06",
"2025-05-07",
"2025-05-08",
"2025-05-09",
"2025-05-10",
"2025-05-11",
"2025-05-12",
"2025-05-13",
"2025-05-14",
"2025-05-15",
"2025-05-16",
"2025-05-17",
"2025-05-18",
"2025-05-19",
"2025-05-20",
"2025-05-21",
"2025-05-22",
"2025-05-23",
"2025-05-24",
"2025-05-25",
"2025-05-26",
"2025-05-27",
"2025-05-28",
"2025-05-29",
"2025-05-30",
"2025-05-31",
"2025-06-01",
"2025-06-02",
"2025-06-03",
"2025-06-04",
"2025-06-05",
"2025-06-06",
"2025-06-07",
"2025-06-08",
"2025-06-09",
"2025-06-10",
"2025-06-11",
"2025-06-12",
"2025-06-13",
"2025-06-14",
"2025-06-15",
"2025-06-16",
"2025-06-17",
"2025-06-18",
"2025-06-19",
"2025-06-20",
"2025-06-21",
"2025-06-22",
"2025-06-23",
"2025-06-24",
"2025-06-25",
"2025-06-26",
"2025-06-27",
"2025-06-28",
"2025-06-29",
"2025-06-30",
"2025-07-01",
"2025-07-02",
"2025-07-03",
"2025-07-04",
"2025-07-05",
"2025-07-06",
"2025-07-07",
"2025-07-08",
"2025-07-09",
"2025-07-10",
"2025-07-11",
"2025-07-12",
"2025-07-13",
"2025-07-14",
"2025-07-15",
"2025-07-16",
"2025-07-17",
"2025-07-18",
"2025-07-19",
"2025-07-20",
"2025-07-21",
"2025-07-22",
"2025-07-23",
"2025-07-24",
"2025-07-25",
"2025-07-26",
"2025-07-27",
"2025-07-28",
"2025-07-29",
"2025-07-30",
"2025-07-31",
"2025-08-01",
"2025-08-02",
"2025-08-03",
"2025-08-04",
"2025-08-05",
"2025-08-06",
"2025-08-07",
"2025-08-08",
"2025-08-09",
"2025-08-10",
"2025-08-11",
"2025-08-12",
"2025-08-13",
"2025-08-14",
"2025-08-15",
"2025-08-16",
"2025-08-17",
"2025-08-18",
"2025-08-19",
"2025-08-20",
"2025-08-21",
"2025-08-22",
"2025-08-23",
"2025-08-24",
"2025-08-25",
"2025-08-26",
"2025-08-27",
"2025-08-28",
"2025-08-29",
"2025-08-30",
"2025-08-31",
"2025-09-01",
"2025-09-02",
"2025-09-03",
"2025-09-04",
"2025-09-05",
"2025-09-06",
"2025-09-07",
"2025-09-08",
"2025-09-09",
"2025-09-10",
"2025-09-11",
"2025-09-12",
"2025-09-13",
"2025-09-14",
"2025-09-15",
"2025-09-16",
"2025-09-17",
"2025-09-18",
"2025-09-19",
"2025-09-20",
"2025-09-21",
"2025-09-22",
"2025-09-23",
"2025-09-24",
"2025-09-25",
"2025-09-26",
"2025-09-27",
"2025-09-28",
"2025-09-29",
"2025-09-30",
"2025-10-01",
"2025-10-02",
"2025-10-03",
"2025-10-04",
"2025-10-05",
"2025-10-06",
"2025-10-07",
"2025-10-08",
"2025-10-09",
"2025-10-10",
"2025-10-11",
"2025-10-12",
"2025-10-13",
"2025-10-14",
"2025-10-15",
"2025-10-16",
"2025-10-17",
"2025-10-18",
"2025-10-19",
"2025-10-20",
"2025-10-21",
"2025-10-22",
"2025-10-23",
"2025-10-24",
"2025-10-25",
"2025-10-26",
"2025-10-27",
"2025-10-28",
"2025-10-29",
"2025-10-30",
"2025-10-31",
"2025-11-01",
"2025-11-02",
"2025-11-03",
"2025-11-04",
"2025-11-05",
"2025-11-06",
"2025-11-07",
"2025-11-08",
"2025-11-09",
"2025-11-10",
"2025-11-11",
"2025-11-12",
"2025-11-13",
"2025-11-14",
"2025-11-15",
"2025-11-16",
"2025-11-17",
"2025-11-18",
"2025-11-19",
"2025-11-20",
"2025-11-21",
"2025-11-22",
"2025-11-23",
"2025-11-24",
"2025-11-25",
"2025-11-26",
"2025-11-27",
"2025-11-28",
"2025-11-29",
"2025-11-30",
"2025-12-01",
"2025-12-02",
"2025-12-03",
"2025-12-04",
"2025-12-05",
"2025-12-06",
"2025-12-07",
"2025-12-08",
"2025-12-09",
"2025-12-10",
"2025-12-11",
"2025-12-12",
"2025-12-13",
"2025-12-14",
"2025-12-15",
"2025-12-16",
"2025-12-17",
"2025-12-18",
"2025-12-19",
"2025-12-20",
"2025-12-21",
"2025-12-22",
"2025-12-23",
"2025-12-24",
"2025-12-25",
"2025-12-26",
"2025-12-27",
"2025-12-28",
"2025-12-29",
"2025-12-30",
"2025-12-31",
"2026-01-01",
"2026-01-02",
"2026-01-03",
"2026-01-04",
"2026-01-05",
"2026-01-06",
"2026-01-07",
"2026-01-08",
"2026-01-09",
"2026-01-10",
"2026-01-11",
"2026-01-12",
"2026-01-13",
"2026-01-14",
"2026-01-15",
"2026-01-16",
"2026-01-17",
"2026-01-18",
"2026-01-19",
"2026-01-20",
"2026-01-21",
"2026-01-22",
"2026-01-23",
"2026-01-24",
"2026-01-25",
"2026-01-26",
"2026-01-27",
"2026-01-28",
"2026-01-29",
"2026-01-30",
"2026-01-31",
"2026-02-01",
"2026-02-02",
"2026-02-03",
"2026-02-04",
"2026-02-05",
"2026-02-06",
"2026-02-07",
"2026-02-08",
"2026-02-09",
"2026-02-10",
"2026-02-11",
"2026-02-12",
"2026-02-13",
"2026-02-14",
"2026-02-15",
"2026-02-16",
"2026-02-17",
"2026-02-18",
"2026-02-19",
"2026-02-20",
"2026-02-21",
"2026-02-22",
"2026-02-23",
"2026-02-24",
"2026-02-25",
"2026-02-26",
"2026-02-27",
"2026-02-28",
"2026-03-01",
"2026-03-02",
"2026-03-03",
"2026-03-04",
"2026-03-05",
"2026-03-06",
"2026-03-07",
"2026-03-08",
"2026-03-09",
"2026-03-10",
"2026-03-11",
"2026-03-12",
"2026-03-13",
"2026-03-14",
"2026-03-15",
"2026-03-16",
"2026-03-17",
"2026-03-18",
"2026-03-19",
"2026-03-20",
"2026-03-21",
"2026-03-22",
"2026-03-23",
"2026-03-24",
"2026-03-25",
"2026-03-26",
"2026-03-27",
"2026-03-28",
"2026-03-29",
"2026-03-30",
"2026-03-31",
"2026-04-01",
"2026-04-02",
"2026-04-03",
"2026-04-04",
"2026-04-05",
"2026-04-06",
"2026-04-07",
"2026-04-08",
"2026-04-09",
"2026-04-10",
"2026-04-11",
"2026-04-12",
"2026-04-13",
"2026-04-14",
"2026-04-15",
"2026-04-16",
"2026-04-17",
"2026-04-18",
"2026-04-19",
"2026-04-20",
"2026-04-21",
"2026-04-22",
"2026-04-23",
"2026-04-24",
"2026-04-25",
"2026-04-26",
"2026-04-27",
"2026-04-28",
"2026-04-29",
"2026-04-30",
"2026-05-01",
"2026-05-02",
"2026-05-03",
"2026-05-04",
"2026-05-05",
"2026-05-06",
"2026-05-07",
"2026-05-08",
"2026-05-09",
"2026-05-10",
"2026-05-11",
"2026-05-12",
"2026-05-13",
"2026-05-14",
"2026-05-15",
"2026-05-16",
"2026-05-17",
"2026-05-18",
"2026-05-19",
"2026-05-20",
"2026-05-21",
"2026-05-22",
"2026-05-23",
"2026-05-24",
"2026-05-25",
"2026-05-26",
"2026-05-27",
"2026-05-28",
"2026-05-29",
"2026-05-30",
"2026-05-31",
"2026-06-01",
"2026-06-02",
"2026-06-03",
"2026-06-04",
"2026-06-05",
"2026-06-06",
"2026-06-07",
"2026-06-08",
"2026-06-09",
"2026-06-10",
"2026-06-11",
"2026-06-12",
"2026-06-13",
"2026-06-14",
"2026-06-15",
"2026-06-16"
],
"registered": [
826351,
827942,
829331,
830529,
831575,
832425,
833574,
834185,
834433,
834773,
835122,
835560,
836506,
837447,
837913,
838832,
839794,
840743,
841350,
841717,
842675,
843692,
844670,
845759,
846754,
847482,
847907,
848856,
849839,
850846,
851834,
852666,
853417,
853867,
854913,
855904,
856917,
857893,
858819,
859669,
860092,
861011,
861907,
862805,
863679,
864470,
865006,
865372,
866296,
867254,
868162,
869005,
869768,
870336,
870682,
871616,
872418,
873182,
873864,
874499,
874943,
875199,
876074,
876918,
877704,
878432,
879182,
879778,
880137,
880852,
881479,
882002,
882499,
882891,
883099,
883265,
883588,
884156,
884726,
885236,
885659,
885990,
886216,
886733,
887173,
887659,
888211,
888479,
888674,
888867,
889124,
889456,
890127,
890800,
891391,
891772,
892034,
892664,
893276,
893817,
894312,
894747,
895016,
895171,
895549,
895984,
896351,
896737,
897085,
897302,
897445,
897842,
898222,
898588,
898969,
899288,
899516,
899673,
900137,
900558,
900976,
901589,
901983,
902254,
902433,
902950,
903415,
903980,
904327,
904927,
905183,
905379,
905867,
906299,
906474,
906899,
907094,
907297,
907460,
907990,
908448,
908883,
909288,
909614,
909792,
909956,
910364,
910744,
911169,
911546,
912008,
912327,
912530,
913050,
913512,
913896,
914325,
914763,
915135,
915361,
915891,
916405,
916877,
917279,
917423,
917607,
917718,
918172,
918616,
919049,
919429,
919798,
920038,
920202,
920656,
921027,
921418,
921805,
922193,
922411,
922580,
923027,
923598,
924088,
924515,
924897,
925191,
925364,
925945,
926501,
926951,
927373,
927774,
928000,
928148,
928322,
928756,
929194,
929613,
930038,
930270,
930417,
930817,
931216,
931654,
931997,
932323,
932541,
932707,
933165,
933639,
934050,
934611,
935069,
935326,
935491,
935949,
936380,
936817,
937312,
937879,
938165,
938357,
938874,
939362,
939817,
940234,
940621,
940855,
941003,
941474,
941813,
942315,
942736,
943118,
943349,
943520,
943978,
944402,
944806,
945231,
945660,
946034,
946260,
946844,
947389,
947902,
948407,
948867,
949145,
949404,
949805,
950387,
950946,
951439,
952005,
952281,
952456,
952915,
953427,
953890,
954337,
954737,
955000,
955184,
955613,
956038,
956436,
956861,
957295,
957539,
957711,
958196,
958613,
959144,
959645,
960103,
960389,
960590,
961126,
961772,
962334,
962757,
963144,
963408,
963605,
964039,
964393,
964765,
965217,
965629,
965911,
966095,
966542,
966983,
967372,
967779,
968153,
968414,
968594,
968999,
969440,
969873,
970268,
970666,
970890,
971073,
971357,
971890,
972370,
972880,
973331,
973707,
973937,
974493,
974927,
975357,
975717,
976119,
976408,
976605,
977074,
977514,
978008,
978436,
978785,
979010,
979177,
979606,
979999,
980423,
980805,
981190,
981460,
981654,
982232,
982764,
983352,
983897,
984449,
984853,
985194,
986013,
986639,
987182,
987702,
988149,
988467,
988699,
989274,
989831,
990379,
990951,
991441,
991739,
991997,
992541,
992790,
993461,
994016,
994451,
994758,
995014,
995670,
996241,
996886,
997534,
998111,
998500,
998837,
999556,
1000258,
1000768,
1001225,
1001752,
1002141,
1002457,
1003254,
1003932,
1004267,
1004939,
1005602,
1006054,
1006354,
1007014,
1007586,
1008137,
1008639,
1009126,
1009440,
1009670,
1010243,
1010783,
1011317,
1011909,
1012499,
1012923,
1013247,
1013885,
1014519,
1015139,
1015745,
1016431,
1016923,
1017352,
1018099,
1018798,
1019385,
1019954,
1020456,
1020799,
1021034,
1021629,
1022264,
1022915,
1023527,
1024080,
1024356,
1024576,
1025060,
1025487,
1026003,
1026456,
1026962,
1027336,
1027537,
1028055,
1028704,
1029313,
1029916,
1030502,
1030968,
1031336,
1032037,
1032626,
1033165,
1033639,
1034043,
1034335,
1034510,
1034770,
1035389,
1035954,
1036446,
1036968,
1037271,
1037450,
1037938,
1038394,
1038814,
1039289,
1039701,
1039912,
1040067,
1040286,
1040608,
1040941,
1041553,
1042107,
1042414,
1042635,
1043213,
1043887,
1044564,
1045103,
1045603,
1045861,
1046022,
1046510,
1046967,
1047421,
1047856,
1048274,
1048505,
1048668,
1049114,
1049550,
1049971,
1050387,
1050775,
1051034,
1051231,
1051718,
1052161,
1052585,
1053041,
1053568,
1053910,
1054127,
1054773,
1055339,
1055832,
1056398,
1056755,
1057008,
1057206,
1057747,
1058238,
1058692,
1058906,
1059343,
1059531,
1059740,
1060033,
1060625,
1061182,
1061691,
1062130,
1062397,
1062577,
1063027,
1063492,
1063999,
1064507,
1064995,
1065296,
1065568,
1066083,
1066630,
1066923,
1067531,
1068103,
1068492,
1068794,
1069597,
1070275,
1070862,
1071482,
1072019,
1072336,
1072641,
1073315,
1074069,
1074823,
1075511,
1076154,
1076503,
1076728,
1077494,
1078231
],
"installs": [
1209021,
1212591,
1215811,
1218639,
1221008,
1222981,
1225511,
1227071,
1228216,
1229503,
1230788,
1232222,
1234433,
1236308,
1237744,
1240121,
1242838,
1245252,
1246884,
1248110,
1250589,
1252986,
1255571,
1258215,
1260585,
1262237,
1263446,
1265885,
1268304,
1271085,
1273676,
1275997,
1277665,
1278930,
1281564,
1284124,
1286680,
1289212,
1291912,
1294137,
1295456,
1298293,
1300980,
1303921,
1306491,
1309075,
1310530,
1311684,
1314270,
1316706,
1318851,
1321001,
1322992,
1324517,
1325796,
1328267,
1330466,
1332627,
1334569,
1336397,
1337734,
1338774,
1341105,
1343323,
1345423,
1347508,
1349436,
1351170,
1352367,
1354368,
1356145,
1357652,
1359133,
1360402,
1361244,
1362091,
1363469,
1363500,
1364950,
1366395,
1367640,
1368675,
1369490,
1370861,
1372136,
1373576,
1375189,
1376238,
1377094,
1377977,
1379043,
1380272,
1382065,
1383728,
1385215,
1386338,
1387246,
1388921,
1390612,
1392050,
1393308,
1394641,
1395633,
1396387,
1397600,
1398757,
1399861,
1400940,
1401930,
1402647,
1403269,
1404428,
1405516,
1406624,
1407664,
1408721,
1409556,
1410231,
1411512,
1412806,
1414049,
1415584,
1416745,
1417655,
1418428,
1419798,
1421023,
1422530,
1423753,
1425288,
1426232,
1427040,
1428464,
1429612,
1430372,
1431556,
1432255,
1433077,
1433819,
1435211,
1436553,
1437759,
1438897,
1439874,
1440575,
1441283,
1442423,
1443568,
1444776,
1445824,
1447040,
1447963,
1448742,
1450023,
1451121,
1452185,
1453386,
1454543,
1455798,
1456627,
1458075,
1459456,
1460457,
1460934,
1461531,
1462156,
1462770,
1464107,
1465390,
1466632,
1467559,
1468406,
1469061,
1469590,
1470574,
1471401,
1472334,
1473311,
1474197,
1474898,
1475513,
1476843,
1478365,
1479725,
1480963,
1482098,
1482957,
1483665,
1485273,
1486877,
1488187,
1489354,
1490437,
1491189,
1491813,
1492500,
1493706,
1494959,
1496173,
1497417,
1498117,
1498775,
1499930,
1501139,
1502285,
1503363,
1504413,
1505127,
1505730,
1507063,
1508465,
1509717,
1511203,
1512580,
1513388,
1514046,
1515207,
1516415,
1517651,
1519017,
1520793,
1521730,
1522386,
1523890,
1525146,
1526440,
1527597,
1528731,
1529528,
1530212,
1531598,
1533068,
1534502,
1535692,
1535717,
1536508,
1537145,
1538355,
1539545,
1540828,
1542137,
1543364,
1544425,
1545269,
1546871,
1548424,
1548450,
1549792,
1551080,
1551984,
1552922,
1554139,
1561192,
1581261,
1597195,
1611966,
1619158,
1626939,
1634294,
1642694,
1649141,
1655004,
1660395,
1663124,
1666282,
1670614,
1675038,
1679166,
1683377,
1687511,
1689558,
1691591,
1695776,
1699981,
1703851,
1707256,
1710303,
1711727,
1713199,
1717613,
1722057,
1725716,
1728866,
1731481,
1732852,
1734385,
1738088,
1741270,
1744419,
1747306,
1749990,
1751527,
1753041,
1756577,
1759781,
1762843,
1766090,
1768985,
1770579,
1772041,
1775731,
1778755,
1781911,
1785016,
1788457,
1789814,
1790917,
1792897,
1796062,
1798786,
1801197,
1803173,
1804363,
1805362,
1807848,
1809954,
1812437,
1815524,
1818556,
1820732,
1823007,
1827390,
1830980,
1834269,
1837570,
1840052,
1842005,
1843965,
1847348,
1850066,
1852535,
1854814,
1857084,
1858796,
1860625,
1863626,
1866234,
1869546,
1872820,
1875687,
1877811,
1879957,
1883888,
1887472,
1890891,
1894204,
1897478,
1899732,
1901871,
1905491,
1909061,
1913163,
1917352,
1921480,
1924179,
1926278,
1929983,
1932149,
1935435,
1938171,
1940856,
1942485,
1943875,
1944067,
1947384,
1951239,
1954826,
1958607,
1961320,
1963770,
1967626,
1970818,
1973234,
1975739,
1978401,
1980407,
1982298,
1985858,
1988818,
1990569,
1993532,
1996225,
1998232,
1999938,
2002875,
2005401,
2007880,
2010333,
2012635,
2014458,
2016685,
2020882,
2023857,
2026758,
2029630,
2032481,
2034309,
2036206,
2039971,
2043018,
2045903,
2048858,
2051828,
2053773,
2055865,
2059037,
2061044,
2064338,
2067096,
2069535,
2071061,
2072476,
2075553,
2078489,
2081405,
2084066,
2086712,
2088942,
2091078,
2095924,
2099606,
2102697,
2105285,
2108038,
2109619,
2111053,
2115406,
2119731,
2123080,
2126230,
2129561,
2131472,
2133425,
2136287,
2137864,
2139381,
2140832,
2142174,
2143321,
2144237,
2145508,
2147469,
2149230,
2150849,
2152358,
2153544,
2154484,
2155979,
2157368,
2158719,
2160442,
2161737,
2162738,
2163554,
2164473,
2165697,
2166886,
2168748,
2170450,
2171623,
2172654,
2174394,
2176215,
2178368,
2180003,
2181473,
2182473,
2183329,
2184755,
2186197,
2187576,
2188886,
2190174,
2191115,
2191910,
2193180,
2194533,
2195797,
2197062,
2198365,
2199313,
2200130,
2201510,
2202837,
2204161,
2205621,
2207162,
2208305,
2209227,
2210899,
2212477,
2213941,
2215453,
2216629,
2217603,
2218463,
2220087,
2221607,
2222895,
2223767,
2225068,
2225849,
2226728,
2227822,
2229495,
2230923,
2232358,
2233600,
2234533,
2235298,
2236784,
2238195,
2239830,
2240938,
2241775,
2242465,
2243155,
2244432,
2246401,
2248212,
2251588,
2255522,
2258149,
2260248,
2264657,
2268788,
2272436,
2276286,
2279671,
2282217,
2285248,
2288824,
2292666,
2297811,
2297885,
2301420,
2301471,
2304017,
2304061,
2307490
],
"installs_ios": [
360743,
361953,
362992,
363895,
364806,
365585,
366552,
367113,
367521,
367991,
368442,
368994,
369796,
370444,
370992,
371757,
372607,
373349,
373985,
374446,
375278,
376027,
376809,
377614,
378355,
378948,
379424,
380177,
380959,
381883,
382710,
383333,
383874,
384285,
384949,
385710,
386523,
387371,
388205,
389087,
389603,
390413,
391169,
391857,
392582,
393199,
393667,
394045,
394719,
395425,
396092,
396779,
397399,
397951,
398439,
399193,
399931,
400612,
401156,
401681,
402184,
402575,
403377,
404133,
404837,
405564,
406222,
406897,
407365,
408042,
408659,
409181,
409626,
409990,
410276,
410604,
411092,
411102,
411615,
412076,
412525,
412849,
413134,
413640,
414090,
414610,
415196,
415553,
415870,
416213,
416615,
417070,
417707,
418303,
418819,
419215,
419562,
420190,
420816,
421345,
421819,
422300,
422654,
422935,
423395,
423804,
424214,
424561,
424927,
425185,
425418,
425860,
426246,
426650,
427043,
427416,
427736,
428014,
428484,
428973,
429425,
430046,
430471,
430788,
431076,
431595,
432112,
432662,
433122,
433713,
434066,
434375,
434886,
435286,
435553,
435969,
436205,
436503,
436786,
437327,
437805,
438238,
438631,
438992,
439257,
439534,
439947,
440387,
440849,
441236,
441723,
442076,
442384,
442882,
443291,
443689,
444131,
444554,
445059,
445386,
445919,
446423,
446772,
446936,
447153,
447399,
447651,
448123,
448622,
449054,
449248,
449421,
449578,
449721,
449947,
450167,
450387,
450607,
450815,
451014,
451155,
451567,
452242,
452750,
453189,
453611,
453948,
454230,
454805,
455406,
455896,
456302,
456683,
456959,
457184,
457440,
457907,
458338,
458827,
459302,
459543,
459800,
460212,
460647,
461082,
461493,
461830,
462089,
462298,
462766,
463282,
463719,
464309,
464774,
465059,
465256,
465640,
466083,
466535,
467042,
467688,
468015,
468268,
468791,
469251,
469694,
470116,
470503,
470783,
471025,
471545,
472125,
472643,
473081,
473085,
473360,
473589,
473984,
474433,
474905,
475418,
475871,
476286,
476607,
477207,
477850,
477852,
478357,
478843,
479213,
479578,
480084,
486168,
505618,
521116,
534910,
541535,
548853,
555671,
563323,
569155,
574300,
578910,
581075,
583808,
587603,
591513,
595094,
598583,
601902,
603420,
605035,
608581,
611996,
614905,
617446,
619625,
620466,
621483,
625034,
628159,
630713,
633001,
634827,
635664,
636757,
639695,
642137,
644472,
646568,
648404,
649239,
650177,
652817,
655101,
657318,
659775,
661796,
662766,
663707,
666602,
668695,
670984,
673302,
675824,
676605,
677166,
678564,
680766,
682586,
684121,
685235,
685626,
686099,
687652,
688960,
690167,
691740,
693112,
693578,
694100,
696032,
697468,
698647,
699832,
700764,
701269,
701808,
703504,
704662,
705388,
706001,
706580,
706826,
707166,
708123,
709151,
710388,
711611,
712617,
713104,
713652,
715217,
716745,
718167,
719594,
720927,
721474,
722027,
723699,
725341,
727347,
729372,
731506,
732476,
733127,
734969,
735762,
737716,
739317,
740853,
741528,
742098,
742218,
744384,
746547,
748417,
750404,
751602,
752570,
754291,
755823,
756819,
757906,
759046,
760006,
760920,
762867,
764472,
765352,
766917,
768319,
769279,
770142,
771804,
773193,
774542,
775942,
777327,
778394,
779948,
783071,
785097,
787008,
788810,
790669,
791662,
792844,
795543,
797534,
799331,
801301,
803174,
804216,
805359,
807250,
808086,
810330,
812079,
813545,
814321,
815096,
817055,
818825,
820613,
822210,
823845,
825337,
826802,
830622,
833248,
835375,
837098,
838927,
839776,
840635,
844101,
847312,
849708,
851917,
854304,
855390,
856576,
858450,
859168,
859828,
860492,
861099,
861686,
862143,
862733,
863681,
864540,
865375,
866089,
866694,
867163,
867851,
868501,
869115,
870054,
870682,
871206,
871607,
872073,
872674,
873277,
874092,
874910,
875474,
875983,
876828,
877708,
878747,
879547,
880281,
880777,
881210,
881889,
882559,
883185,
883832,
884389,
884838,
885227,
885851,
886473,
887044,
887672,
888262,
888701,
889099,
889758,
890372,
890986,
891699,
892427,
892963,
893397,
894139,
894863,
895551,
896277,
896840,
897343,
897741,
898496,
899201,
899786,
900195,
900782,
901178,
901579,
902113,
902842,
903508,
904169,
904738,
905214,
905554,
906246,
906906,
907650,
908327,
908933,
909444,
909946,
910614,
911297,
911783,
912485,
913290,
913844,
914383,
915304,
916185,
916906,
917660,
918357,
918884,
919535,
920338,
921238,
922114,
922114,
922829,
922829,
923271,
923271,
924083
],
"installs_android": [
848278,
850638,
852819,
854744,
856202,
857396,
858959,
859958,
860695,
861512,
862346,
863228,
864637,
865864,
866752,
868364,
870231,
871903,
872899,
873664,
875311,
876959,
878762,
880601,
882230,
883289,
884022,
885708,
887345,
889202,
890966,
892664,
893791,
894645,
896615,
898414,
900157,
901841,
903707,
905050,
905853,
907880,
909811,
912064,
913909,
915876,
916863,
917639,
919551,
921281,
922759,
924222,
925593,
926566,
927357,
929074,
930535,
932015,
933413,
934716,
935550,
936199,
937728,
939190,
940586,
941944,
943214,
944273,
945002,
946326,
947486,
948471,
949507,
950412,
950968,
951487,
952377,
952398,
953335,
954319,
955115,
955826,
956356,
957221,
958046,
958966,
959993,
960685,
961224,
961764,
962428,
963202,
964358,
965425,
966396,
967123,
967684,
968731,
969796,
970705,
971489,
972341,
972979,
973452,
974205,
974953,
975647,
976379,
977003,
977462,
977851,
978568,
979270,
979974,
980621,
981305,
981820,
982217,
983028,
983833,
984624,
985538,
986274,
986867,
987352,
988203,
988911,
989868,
990631,
991575,
992166,
992665,
993578,
994326,
994819,
995587,
996050,
996574,
997033,
997884,
998748,
999521,
1000266,
1000882,
1001318,
1001749,
1002476,
1003181,
1003927,
1004588,
1005317,
1005887,
1006358,
1007141,
1007830,
1008496,
1009255,
1009989,
1010739,
1011241,
1012156,
1013033,
1013685,
1013998,
1014378,
1014757,
1015119,
1015984,
1016768,
1017578,
1018311,
1018985,
1019483,
1019869,
1020627,
1021234,
1021947,
1022704,
1023382,
1023884,
1024358,
1025276,
1026123,
1026975,
1027774,
1028487,
1029009,
1029435,
1030468,
1031471,
1032291,
1033052,
1033754,
1034230,
1034629,
1035060,
1035799,
1036621,
1037346,
1038115,
1038574,
1038975,
1039718,
1040492,
1041203,
1041870,
1042583,
1043038,
1043432,
1044297,
1045183,
1045998,
1046894,
1047806,
1048329,
1048790,
1049567,
1050332,
1051116,
1051975,
1053105,
1053715,
1054118,
1055099,
1055895,
1056746,
1057481,
1058228,
1058745,
1059187,
1060053,
1060943,
1061859,
1062611,
1062632,
1063148,
1063556,
1064371,
1065112,
1065923,
1066719,
1067493,
1068139,
1068662,
1069664,
1070574,
1070598,
1071435,
1072237,
1072771,
1073344,
1074055,
1075024,
1075643,
1076079,
1077056,
1077623,
1078086,
1078623,
1079371,
1079986,
1080704,
1081485,
1082049,
1082474,
1083011,
1083525,
1084072,
1084794,
1085609,
1086138,
1086556,
1087195,
1087985,
1088946,
1089810,
1090678,
1091261,
1091716,
1092579,
1093898,
1095003,
1095865,
1096654,
1097188,
1097628,
1098393,
1099133,
1099947,
1100738,
1101586,
1102288,
1102864,
1103760,
1104680,
1105525,
1106315,
1107189,
1107813,
1108334,
1109129,
1110060,
1110927,
1111714,
1112633,
1113209,
1113751,
1114333,
1115296,
1116200,
1117076,
1117938,
1118737,
1119263,
1120196,
1120994,
1122270,
1123784,
1125444,
1127154,
1128907,
1131358,
1133512,
1135622,
1137738,
1139288,
1140736,
1142157,
1143844,
1145404,
1147147,
1148813,
1150504,
1151970,
1153459,
1155503,
1157083,
1159158,
1161209,
1163070,
1164707,
1166305,
1168671,
1170727,
1172724,
1174610,
1176551,
1178258,
1179844,
1181792,
1183720,
1185816,
1187980,
1189974,
1191703,
1193151,
1195014,
1196387,
1197719,
1198854,
1200003,
1200957,
1201777,
1201849,
1203000,
1204692,
1206409,
1208203,
1209718,
1211200,
1213335,
1214995,
1216415,
1217833,
1219355,
1220401,
1221378,
1222991,
1224346,
1225217,
1226615,
1227906,
1228953,
1229796,
1231071,
1232208,
1233338,
1234391,
1235308,
1236064,
1236737,
1237811,
1238760,
1239750,
1240820,
1241812,
1242647,
1243362,
1244428,
1245484,
1246572,
1247557,
1248654,
1249557,
1250506,
1251787,
1252958,
1254008,
1255017,
1255990,
1256740,
1257380,
1258498,
1259664,
1260792,
1261856,
1262867,
1263605,
1264276,
1265302,
1266358,
1267322,
1268187,
1269111,
1269843,
1270418,
1271305,
1272419,
1273372,
1274313,
1275257,
1276082,
1276849,
1277837,
1278696,
1279553,
1280340,
1281075,
1281635,
1282094,
1282775,
1283788,
1284690,
1285474,
1286269,
1286850,
1287321,
1288128,
1288867,
1289604,
1290388,
1291055,
1291532,
1291947,
1292400,
1293023,
1293609,
1294656,
1295540,
1296149,
1296671,
1297566,
1298507,
1299621,
1300456,
1301192,
1301696,
1302119,
1302866,
1303638,
1304391,
1305054,
1305785,
1306277,
1306683,
1307329,
1308060,
1308753,
1309390,
1310103,
1310612,
1311031,
1311752,
1312465,
1313175,
1313922,
1314735,
1315342,
1315830,
1316760,
1317614,
1318390,
1319176,
1319789,
1320260,
1320722,
1321591,
1322406,
1323109,
1323572,
1324286,
1324671,
1325149,
1325709,
1326653,
1327415,
1328189,
1328862,
1329319,
1329744,
1330538,
1331289,
1332180,
1332611,
1332842,
1333021,
1333209,
1333818,
1335104,
1336429,
1339103,
1342232,
1344305,
1345865,
1349353,
1352603,
1355530,
1358626,
1361314,
1363333,
1365713,
1368486,
1371428,
1375697,
1375771,
1378591,
1378642,
1380746,
1380790,
1383407
],
"mau": [
254095,
259526,
264649,
269014,
272710,
275800,
280165,
282980,
14537,
25341,
34423,
43042,
54188,
65126,
72455,
84401,
94496,
128152,
137239,
142114,
150480,
156543,
166481,
173155,
178304,
182475,
185854,
191155,
196186,
202391,
213774,
219289,
222932,
225829,
230631,
234859,
239224,
243458,
247874,
21035,
32059,
47044,
58317,
75925,
86201,
94244,
100339,
105590,
136123,
150415,
157629,
164155,
170000,
177431,
183795,
190472,
196396,
201847,
206834,
211120,
215960,
219079,
228111,
233660,
238841,
243540,
247842,
19564,
30647,
45488,
60130,
72402,
82010,
90468,
95574,
100830,
107262,
114982,
121276,
146790,
154892,
159122,
162731,
168421,
174547,
180182,
186572,
190726,
193740,
196590,
204235,
209093,
214902,
220404,
224925,
227992,
230550,
235195,
28112,
46060,
58053,
70728,
79251,
85923,
95312,
104995,
112083,
132445,
142722,
147259,
151746,
158990,
164097,
169353,
174116,
178762,
182175,
185385,
190531,
195334,
199397,
207755,
211494,
214193,
216546,
220218,
224014,
228398,
18569,
35006,
45555,
53439,
63207,
71456,
77315,
85680,
96739,
115804,
125382,
132489,
138466,
143861,
149271,
161214,
165932,
170337,
176005,
181823,
188353,
195758,
205462,
221274,
236484,
246901,
251137,
254513,
257675,
260017,
262728,
112716,
125573,
139148,
146418,
158660,
162431,
165577,
172344,
177661,
190632,
197608,
201014,
203991,
206303,
208347,
211429,
214224,
217608,
220965,
223635,
226898,
228673,
232031,
238850,
243573,
246987,
249992,
253183,
255270,
259010,
20676,
33149,
45867,
54699,
62088,
69239,
74708,
81892,
89247,
110874,
125209,
129373,
132908,
137557,
142942,
149640,
153873,
157672,
162409,
165176,
169122,
174539,
179770,
190109,
195835,
199251,
201957,
205365,
209452,
213653,
217943,
27137,
40318,
50890,
60587,
69144,
81071,
92145,
101783,
109990,
124026,
135153,
142780,
149386,
153842,
155034,
158697,
162618,
167508,
172354,
177307,
182428,
187497,
192010,
198188,
202624,
207978,
208449,
213163,
216661,
219505,
221886,
17328,
30811,
38826,
49943,
63889,
74420,
80212,
85885,
93497,
100748,
106754,
112914,
119882,
124304,
129827,
134274,
138384,
143544,
148994,
154753,
157717,
161093,
164869,
174395,
178582,
182003,
184044,
185771,
188375,
192462,
14934,
22763,
29685,
35090,
39261,
44594,
49518,
54077,
58969,
75229,
85423,
88473,
92121,
95557,
99419,
102403,
105670,
107977,
110012,
112794,
117250,
120504,
123204,
129111,
131401,
133229,
135164,
138477,
141033,
143536,
146096,
12491,
18777,
26440,
33238,
39080,
44257,
51261,
55231,
60244,
77274,
86920,
90982,
94564,
97741,
100462,
102764,
105806,
108701,
111433,
114273,
116863,
120531,
122750,
129224,
132179,
138302,
141330,
144004,
146203,
148208,
15862,
24229,
38586,
47844,
57568,
61897,
67792,
75794,
80948,
95160,
104346,
109492,
112375,
115633,
121130,
125337,
129530,
133231,
137610,
141367,
143910,
148601,
152946,
160235,
164168,
169438,
172686,
176101,
181871,
188143,
193675,
40514,
57924,
68670,
77581,
90190,
101423,
108385,
117521,
126183,
145488,
156727,
165193,
171888,
177781,
185429,
190394,
194886,
198397,
203648,
208147,
212863,
217987,
223616,
230376,
233909,
238683,
243198,
247524,
252451,
256358,
259426,
28358,
47224,
60896,
71878,
82147,
91661,
99106,
105360,
120553,
145228,
162956,
170163,
176346,
180700,
184777,
189847,
196024,
202179,
207489,
212348,
216324,
220060,
224823,
235424,
241368,
246780,
251971,
256194,
28799,
53802,
67500,
81687,
98645,
108155,
119098,
124654,
132541,
152758,
168266,
175996,
182319,
186990,
190884,
196219,
202467,
208135,
214530,
220946,
224649,
227519,
231112,
239707,
244457,
250824,
256357,
260409,
264072,
269639,
274991,
42722,
63604,
79295,
90401,
100586,
109726,
119398,
128489,
136389,
160248,
166231,
170598,
177064,
183456,
189815,
194879,
200521,
204495,
207925,
213877,
219162,
224701,
230198,
237380,
241217,
244324,
249842,
254495,
258745,
263556,
26257,
39217,
48787,
62115,
78763,
88442,
95058,
104405,
109709,
135456,
142383,
152507,
160370,
167119,
173448,
177589,
181195,
186991,
192258,
198068,
203863,
208789,
212581,
219419,
225031,
230307,
234125,
239256,
244488,
248517,
252238,
31457,
54418,
68224,
79578,
90270,
97467,
107233,
115531,
124604,
149519,
158694,
165229,
169646,
173419,
179868,
185155
],
"dau": [
25867,
22137,
24481,
18305,
15282,
13931,
19466,
14330,
14537,
13794,
13210,
13679,
18152,
18097,
13473,
21656,
19826,
58834,
20456,
12932,
22379,
16477,
31695,
20634,
15844,
12963,
11666,
17941,
16588,
21181,
47272,
25134,
14682,
12875,
21850,
16970,
17333,
17079,
19464,
21035,
14563,
20595,
18011,
27477,
19047,
16213,
12957,
11807,
58453,
34344,
20278,
18595,
17735,
26326,
25517,
22673,
20309,
18804,
18480,
15696,
25259,
13596,
40238,
22903,
21871,
19152,
18706,
19564,
14308,
20142,
21594,
20052,
17489,
16680,
11123,
11533,
13858,
17330,
15256,
54180,
22414,
13022,
11290,
18736,
20908,
18823,
22200,
16088,
11493,
11560,
32304,
22222,
25014,
25267,
21393,
14485,
13085,
23717,
28112,
24186,
20267,
21793,
17194,
14513,
20853,
22725,
18535,
46663,
29288,
16299,
16111,
27027,
19037,
20296,
19641,
19224,
15428,
15401,
22928,
20884,
18186,
37101,
17569,
12681,
11958,
18136,
21327,
23625,
18569,
20984,
16119,
13488,
17396,
16051,
12665,
17650,
24166,
40649,
23771,
19947,
18709,
18476,
19534,
41939,
21599,
22310,
27950,
30176,
34512,
40793,
53811,
89914,
102751,
122975,
126409,
129395,
150135,
127664,
122970,
112716,
98970,
87013,
95651,
105877,
88416,
64807,
20564,
15168,
42577,
24839,
13211,
11910,
10090,
9254,
12408,
12281,
16400,
16371,
12773,
20384,
10420,
14543,
35190,
28004,
17337,
15117,
21458,
12534,
19857,
20676,
16905,
18372,
14648,
12927,
12704,
10896,
14396,
15327,
40947,
31794,
12135,
10504,
13601,
15655,
22429,
14371,
13131,
19105,
10559,
14115,
20971,
21929,
39880,
25281,
17894,
14247,
15007,
20824,
21826,
22581,
27137,
18189,
16609,
15913,
15025,
22551,
22923,
21688,
19927,
33739,
30138,
24141,
21708,
14013,
4471,
11808,
15577,
18659,
19344,
20107,
20977,
22294,
20606,
30715,
19588,
24895,
2588,
23753,
16666,
16317,
12948,
17328,
17279,
12418,
16637,
21996,
19284,
11820,
12226,
16468,
16784,
15104,
15795,
18393,
12454,
16982,
13729,
13100,
16142,
18081,
20251,
11333,
12872,
14462,
32678,
16836,
14248,
9209,
7922,
11779,
16484,
14934,
10702,
10349,
8590,
7249,
9661,
9542,
9340,
10079,
29408,
21344,
8181,
10000,
9903,
12052,
9674,
10613,
7854,
7131,
9554,
17755,
11900,
10391,
23767,
10298,
7910,
8333,
15014,
11146,
11127,
13907,
12491,
8377,
10724,
10644,
9936,
9353,
12726,
8198,
10514,
31166,
20511,
10854,
10166,
9432,
8841,
7249,
9629,
8957,
8714,
8693,
8662,
15304,
8401,
24247,
11890,
27654,
12968,
11395,
10235,
9487,
15862,
11606,
19657,
15139,
17341,
9133,
13511,
17569,
12634,
35053,
27930,
18112,
10849,
14790,
22792,
19119,
18583,
17462,
20104,
15273,
9987,
19078,
18866,
33400,
16461,
25120,
12840,
12195,
17415,
19422,
19020,
40514,
25411,
20241,
18970,
26211,
26573,
20043,
24860,
24812,
50089,
34081,
30203,
27076,
24595,
33610,
23832,
24123,
19063,
26617,
23818,
26526,
27876,
30555,
40500,
22877,
28666,
29207,
29971,
34401,
27911,
23367,
28358,
27616,
26157,
24569,
24844,
24301,
21292,
19399,
35850,
56390,
50682,
26993,
25206,
20728,
20143,
23356,
28445,
28597,
26038,
23711,
20712,
21843,
24191,
50978,
30029,
27929,
29532,
25227,
28799,
34203,
26234,
28596,
35661,
25163,
30271,
19516,
24194,
51431,
46677,
29221,
25260,
20931,
19433,
23381,
29273,
28140,
30119,
34055,
20963,
18086,
21379,
47204,
29896,
35994,
33235,
29967,
28552,
37806,
35506,
42722,
33680,
32237,
27525,
27364,
25194,
26792,
27362,
25702,
62215,
24439,
19675,
26442,
26034,
26954,
23022,
26472,
20501,
19294,
27188,
26844,
28320,
28450,
36586,
21832,
19733,
28722,
25218,
24755,
28949,
26257,
19724,
18640,
25069,
31577,
23684,
19007,
24576,
17634,
55444,
22678,
31193,
28412,
25240,
24464,
19148,
18124,
25033,
22899,
24333,
25196,
22974,
19838,
35436,
28180,
27227,
22668,
27002,
27836,
23907,
23734,
31457,
32944,
26370,
24519,
25088,
19975,
24496,
23874,
26306,
60764,
29798,
22988,
17052,
15103,
22115,
17757
]
}
}
};
const App = { data: null };
// ───────── helpers ─────────
const fmtInt = n => (n || 0).toLocaleString('ru-RU');
function fmtPct(g) {
if (g === null || g === undefined) return '';
const s = (g * 100);
return (s >= 0 ? '+' : '') + s.toFixed(1) + '%';
}
function classify(m) {
if (m.is_new) return 'new';
if (m.growth === null) return 'flat';
if (m.growth > 0.0005) return 'up';
if (m.growth < -0.0005) return 'down';
return 'flat';
}
function badgeText(m, cls) {
if (cls === 'new') return 'NEW';
if (cls === 'flat') return '≈ 0%';
return fmtPct(m.growth);
}
// ───────── render ─────────
function renderSummary() {
const d = App.data;
const totCur = d.metrics.reduce((s, m) => s + m.cur, 0);
const totPrev = d.metrics.reduce((s, m) => s + m.prev, 0);
const overall = totPrev > 0 ? (totCur - totPrev) / totPrev : null;
const nNew = d.metrics.filter(m => m.is_new).length;
const nUp = d.metrics.filter(m => !m.is_new && m.growth > 0).length;
const nDown = d.metrics.filter(m => !m.is_new && m.growth < 0).length;
const cards = [
{ cls: '', label: 'Период', value: d.cur_year + ' / ' + d.prev_year, sub: d.period_label },
{ cls: 'accent-green', label: 'Обращений · ' + d.cur_year, value: fmtInt(totCur),
sub: 'против ' + fmtInt(totPrev) + ' в ' + d.prev_year + (overall !== null ? ' · ' + fmtPct(overall) : '') },
{ cls: 'accent-yellow', label: 'Динамика', value: '▲ ' + nUp + ' ▼ ' + nDown,
sub: nUp + ' выросли, ' + nDown + ' снизились' },
{ cls: 'accent-purple', label: 'Новых функций', value: String(nNew),
sub: 'появились в ' + d.cur_year + ' году' },
];
document.getElementById('summary-grid').innerHTML = cards.map(c => `
<div class="sum-card ${c.cls}">
<div class="sum-label">${c.label}</div>
<div class="sum-value">${c.value}</div>
<div class="sum-sub">${c.sub}</div>
</div>`).join('');
}
function renderCards() {
const d = App.data;
const q = document.getElementById('search').value.trim().toLowerCase();
const sort = document.getElementById('sort').value;
const onlyNew = document.getElementById('only-new').checked;
let list = d.metrics.slice();
if (onlyNew) list = list.filter(m => m.is_new);
if (q) list = list.filter(m => m.label.toLowerCase().includes(q));
list.sort((a, b) => {
if (sort === 'label') return a.label.localeCompare(b.label, 'ru');
if (sort === 'growth') {
// новые — в конце при сортировке по приросту (у них нет базы сравнения)
const ga = a.is_new ? -Infinity : (a.growth ?? -Infinity);
const gb = b.is_new ? -Infinity : (b.growth ?? -Infinity);
return gb - ga;
}
return b.cur - a.cur; // по использованию
});
const el = document.getElementById('cards');
if (!list.length) { el.innerHTML = '<div class="empty-note">Ничего не найдено</div>'; return; }
const labels = d.month_labels || [];
el.innerHTML = list.map(m => {
const cls = classify(m);
const curCum = m.cur_cum || [m.cur];
const prevCum = m.prev_cum || [m.prev];
return `
<div class="card ${cls}" data-key="${m.key}">
<div class="card-head">
<div>
<div class="card-title">${m.label}</div>
<div class="card-sub">нарастающим итогом · ${d.cur_year} vs ${d.prev_year}</div>
</div>
<span class="badge ${cls}">${badgeText(m, cls)}</span>
</div>
<div class="card-value">${fmtInt(m.cur)}<span class="card-value-year"> · ${d.cur_year}</span></div>
${sparkline(curCum, prevCum)}
<div class="spark-x"><span>${labels[0] || ''}</span><span>${labels[labels.length - 1] || ''}</span></div>
<div class="legend">
<span><i class="dot cur"></i>${d.cur_year}: <b>${fmtInt(m.cur)}</b></span>
<span><i class="dot prev"></i>${d.prev_year}: <b>${fmtInt(m.prev)}</b></span>
</div>
</div>`;
}).join('');
}
// Накопительный мини-график: две кривые (пунктир — прошлый год, сплошная — текущий)
function sparkline(curCum, prevCum) {
const W = 100, H = 34, pad = 3;
const n = Math.max(curCum.length, prevCum.length, 1);
const max = Math.max(1, ...curCum, ...prevCum);
const x = i => n <= 1 ? W / 2 : pad + i * (W - 2 * pad) / (n - 1);
const y = v => H - pad - (v / max) * (H - 2 * pad);
const pts = arr => arr.map((v, i) => `${x(i).toFixed(1)},${y(v).toFixed(1)}`).join(' ');
const lastI = curCum.length - 1;
return `<svg class="spark" viewBox="0 0 ${W} ${H}" preserveAspectRatio="none">
<polyline class="sp-prev" points="${pts(prevCum)}"/>
<polyline class="sp-cur" points="${pts(curCum)}"/>
<circle class="dot-cur" cx="${x(lastI).toFixed(1)}" cy="${y(curCum[lastI] || 0).toFixed(1)}" r="2.2"/>
</svg>`;
}
// ───────── верхние KPI ─────────
const ACCENT_COLOR = { '': '#0052CC', 'accent-green': '#10B981', 'accent-purple': '#8B5CF6', 'accent-yellow': '#F97316' };
function fmtDate(s) {
if (!s) return '—';
const p = String(s).slice(0, 10).split('-');
return p.length === 3 ? `${p[2]}.${p[1]}.${p[0]}` : s;
}
function delta(cum) { return cum.map((v, i) => i === 0 ? v : v - cum[i - 1]); }
// одиночный мини-график (одна линия)
function miniline(series, color) {
if (!series || !series.length) return '';
const W = 100, H = 30, pad = 3, n = series.length;
const max = Math.max(...series), min = Math.min(...series), span = (max - min) || 1;
const x = i => n <= 1 ? W / 2 : pad + i * (W - 2 * pad) / (n - 1);
const y = v => H - pad - ((v - min) / span) * (H - 2 * pad);
const pts = series.map((v, i) => `${x(i).toFixed(1)},${y(v).toFixed(1)}`).join(' ');
return `<svg class="spark" viewBox="0 0 ${W} ${H}" preserveAspectRatio="none">
<polyline points="${pts}" style="fill:none;stroke:${color};stroke-width:2;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round"/></svg>`;
}
function renderTop() {
const t = App.data.top;
const grid = document.getElementById('top-grid');
const title = grid.previousElementSibling;
if (!t) { grid.style.display = 'none'; if (title) title.style.display = 'none'; return; }
const cards = [
{ key: 'registered', accent: '', label: 'Регистрации', value: fmtInt(t.registered_total), sub: 'всего зарегистрировано', series: t.registered_series },
{ key: 'installs', accent: 'accent-green', label: 'Скачивания', value: fmtInt(t.installs_total), sub: `iOS ${fmtInt(t.installs_ios)} · Android ${fmtInt(t.installs_android)}`, series: t.installs_series },
{ key: 'mau', accent: 'accent-purple', label: 'MAU', value: fmtInt(t.mau), sub: 'на ' + fmtDate(t.as_of), series: t.mau_series },
{ key: 'dau', accent: 'accent-yellow', label: 'DAU', value: fmtInt(t.dau), sub: 'на ' + fmtDate(t.as_of), series: t.dau_series },
];
grid.innerHTML = cards.map(c => `
<div class="kpi-stat ${c.accent}" data-top="${c.key}">
<div class="sum-label">${c.label}</div>
<div class="kpi-stat-value">${c.value}</div>
<div class="kpi-stat-sub">${c.sub}</div>
${miniline(c.series, ACCENT_COLOR[c.accent])}
</div>`).join('');
}
// ───────── вид: сетка / список ─────────
function setView(v) {
App.view = v;
try { localStorage.setItem('mp_view', v); } catch (e) {}
document.getElementById('cards').classList.toggle('list', v === 'list');
document.querySelectorAll('.view-toggle button').forEach(b => b.classList.toggle('active', b.dataset.view === v));
}
// ───────── модалка ─────────
let modalCharts = [];
function destroyCharts() { modalCharts.forEach(c => c && c.destroy()); modalCharts = []; }
function closeModal() { document.getElementById('modal').classList.remove('open'); destroyCharts(); }
function openModal(title, sub, bodyHTML) {
document.getElementById('modal-title').textContent = title;
document.getElementById('modal-sub').textContent = sub;
document.getElementById('modal-body').innerHTML = bodyHTML;
document.getElementById('modal').classList.add('open');
}
// universal line-chart builder
function makeChart(canvasId, labels, datasets, opts) {
if (typeof Chart === 'undefined') return null;
const ctx = document.getElementById(canvasId);
if (!ctx) return null;
opts = opts || {};
const ch = new Chart(ctx, {
type: 'line',
data: { labels, datasets: datasets.map(s => ({
label: s.label, data: s.data, borderColor: s.color, backgroundColor: s.color,
borderWidth: s.width || 2.4, tension: 0.3,
pointRadius: opts.points === false ? 0 : (s.pr ?? 3), pointHoverRadius: 5,
fill: false, borderDash: s.dash || [], spanGaps: true,
})) },
options: {
responsive: true, maintainAspectRatio: false,
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { display: opts.legend !== false, position: 'bottom', labels: { usePointStyle: true, boxWidth: 8 } },
tooltip: { callbacks: { label: (c) => {
const base = `${c.dataset.label}: ${fmtInt(c.parsed.y)}`;
const mo = opts.monthlyMap && opts.monthlyMap[c.dataset.label];
return mo ? `${base} (за месяц +${fmtInt(mo[c.dataIndex])})` : base;
} } },
},
scales: {
y: { ticks: { callback: v => fmtInt(v) }, grid: { color: '#F0F2F5' } },
x: { grid: { display: false }, ticks: { maxRotation: 0, autoSkip: true, maxTicksLimit: opts.maxTicks || 12 } },
},
},
});
modalCharts.push(ch);
return ch;
}
// прокрутка дневного графика к последним данным
function scrollDailyToEnd() {
const sc = document.querySelector('.daily-scroll');
if (sc) sc.scrollLeft = sc.scrollWidth;
}
function tableHTML(headers, labels, columns) {
let rows = '';
for (let i = 0; i < labels.length; i++) {
rows += '<tr><td>' + labels[i] + '</td>' + columns.map(col => `<td>${fmtInt(col[i])}</td>`).join('') + '</tr>';
}
return `<table class="mtable"><thead><tr>${headers.map(h => `<th>${h}</th>`).join('')}</tr></thead><tbody>${rows}</tbody></table>`;
}
function openMetricModal(key) {
const d = App.data, m = d.metrics.find(x => x.key === key);
if (!m) return;
const labels = d.month_labels || [];
const curCum = m.cur_cum || [m.cur], prevCum = m.prev_cum || [m.prev];
const curMo = delta(curCum), prevMo = delta(prevCum);
const cy = String(d.cur_year), py = String(d.prev_year);
let rows = '';
for (let i = 0; i < labels.length; i++) {
rows += `<tr><td>${labels[i]}</td><td>${fmtInt(curCum[i])}</td><td>+${fmtInt(curMo[i])}</td><td>${fmtInt(prevCum[i])}</td><td>+${fmtInt(prevMo[i])}</td></tr>`;
}
const body = `
<div class="modal-section">По месяцам <span class="hint">· нарастающим итогом</span></div>
<div class="modal-chart-wrap"><canvas id="modal-canvas"></canvas></div>
<table class="mtable">
<thead><tr><th>Месяц</th><th>${cy} ∑</th><th>${cy} /мес</th><th>${py} ∑</th><th>${py} /мес</th></tr></thead>
<tbody>${rows}</tbody>
</table>`;
openModal(m.label, `Нарастающим итогом · ${d.period_label}`, body);
makeChart('modal-canvas', labels, [
{ label: cy, data: curCum, color: '#0052CC' },
{ label: py, data: prevCum, color: '#9CB4D9', dash: [5, 4] },
], { monthlyMap: { [cy]: curMo, [py]: prevMo } });
}
function openTopModal(key) {
const t = App.data.top;
if (!t) return;
const ios = 'rgba(0,82,204,0.55)', andr = 'rgba(249,115,22,0.6)';
const conf = {
registered: { title: 'Регистрации', note: 'Накопительно — всего зарегистрировано',
monthly: [{ label: 'Регистрации', data: t.registered_series, color: '#0052CC' }],
daily: [{ label: 'Регистрации', data: t.daily.registered, color: '#0052CC' }] },
installs: { title: 'Скачивания', note: `Накопительно · iOS ${fmtInt(t.installs_ios)} · Android ${fmtInt(t.installs_android)}`,
monthly: [
{ label: 'Всего', data: t.installs_series, color: '#10B981', width: 2.6 },
{ label: 'iOS', data: t.installs_ios_series, color: ios, width: 1.8 },
{ label: 'Android', data: t.installs_android_series, color: andr, width: 1.8 }],
daily: [
{ label: 'Всего', data: t.daily.installs, color: '#10B981', width: 2.2 },
{ label: 'iOS', data: t.daily.installs_ios, color: ios, width: 1.6 },
{ label: 'Android', data: t.daily.installs_android, color: andr, width: 1.6 }] },
mau: { title: 'MAU', note: 'Максимум за месяц · по дням — фактический MAU',
monthly: [{ label: 'MAU (max/мес)', data: t.mau_series, color: '#8B5CF6' }],
daily: [{ label: 'MAU', data: t.daily.mau, color: '#8B5CF6' }] },
dau: { title: 'DAU', note: 'Среднее за месяц · по дням — фактический DAU',
monthly: [{ label: 'DAU (avg/мес)', data: t.dau_series, color: '#F97316' }],
daily: [{ label: 'DAU', data: t.daily.dau, color: '#F97316' }] },
}[key];
if (!conf) return;
const mLabels = t.trend_labels || [];
const dLabels = (t.daily && t.daily.labels || []).map(fmtDate);
const dN = dLabels.length;
const dWidth = Math.max(800, dN * 6);
const tblHeaders = ['Месяц', ...conf.monthly.map(s => s.label)];
const tblCols = conf.monthly.map(s => s.data);
const body = `
<div class="modal-section">По месяцам</div>
<div class="modal-chart-wrap"><canvas id="modal-canvas"></canvas></div>
<div class="modal-section">По дням <span class="hint">· прокрутите для более старых дат →</span></div>
<div class="daily-scroll"><div class="daily-inner" style="min-width:${dWidth}px"><canvas id="modal-canvas-daily"></canvas></div></div>
${tableHTML(tblHeaders, mLabels, tblCols)}`;
openModal(conf.title, conf.note + ' · по ' + fmtDate(t.as_of), body);
makeChart('modal-canvas', mLabels, conf.monthly, { legend: conf.monthly.length > 1 });
makeChart('modal-canvas-daily', dLabels, conf.daily, { points: false, legend: conf.daily.length > 1, maxTicks: 16 });
scrollDailyToEnd();
}
function renderAll() {
document.getElementById('status-msg').style.display = 'none';
document.getElementById('content').style.display = 'block';
const gen = App.data.generated_at ? new Date(App.data.generated_at) : null;
document.getElementById('generated-at').textContent =
'Обновлено: ' + (gen ? gen.toLocaleDateString('ru-RU') : '—');
renderTop();
renderSummary();
let v = 'grid';
try { v = localStorage.getItem('mp_view') || 'grid'; } catch (e) {}
setView(v);
renderCards();
}
// ───────── load ─────────
async function loadData() {
if (window.location.protocol !== 'file:') {
try {
const r = await fetch(DATA_URL, { cache: 'no-cache' });
if (r.ok) { App.data = await r.json(); renderAll(); return; }
} catch (e) { /* fall through */ }
}
if (EMBEDDED_METRICS && EMBEDDED_METRICS.metrics) {
App.data = EMBEDDED_METRICS; renderAll(); return;
}
document.getElementById('status-msg').textContent =
'Не удалось загрузить данные (app_metrics.json).';
}
document.addEventListener('input', e => {
if (['search', 'sort', 'only-new'].includes(e.target.id)) renderCards();
});
// переключатель вида
document.addEventListener('click', e => {
const vb = e.target.closest('.view-toggle button');
if (vb) { setView(vb.dataset.view); return; }
// клик по карточке метрики или верхней KPI
const top = e.target.closest('.kpi-stat');
if (top) { openTopModal(top.dataset.top); return; }
const card = e.target.closest('.card[data-key]');
if (card) { openMetricModal(card.dataset.key); return; }
});
// закрытие модалки
document.getElementById('modal-close').addEventListener('click', closeModal);
document.getElementById('modal').addEventListener('click', e => { if (e.target.id === 'modal') closeModal(); });
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeModal(); });
// ───────── login ─────────
function showApp() {
document.getElementById('login-screen').style.display = 'none';
document.getElementById('app').style.display = 'block';
loadData();
}
function handleLogin() {
const inp = document.getElementById('login-password');
if (inp.value === LOGIN_PASSWORD) {
if (window.sessionStorage) sessionStorage.setItem('kpi_auth', '1');
showApp();
} else {
document.getElementById('login-error').textContent = 'Неверный пароль';
inp.value = '';
}
}
document.getElementById('btn-login').addEventListener('click', handleLogin);
document.getElementById('login-password').addEventListener('keydown', e => { if (e.key === 'Enter') handleLogin(); });
document.addEventListener('DOMContentLoaded', () => {
if (window.sessionStorage && sessionStorage.getItem('kpi_auth') === '1') showApp();
});
</script>
</body>
</html>