mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
282 lines
31 KiB
Markdown
282 lines
31 KiB
Markdown
# Changelog
|
||
|
||
## v1.9.3 — 2026-07-05 (аудит + рефакторинг + тесты)
|
||
- Чистые функции `fitView` (contain-прямоугольник вьюпорта) и `declump` (расталкивание значков)
|
||
вынесены из карточки в `logic.ts` — покрыты юнит-тестами (было 9 → стало 14 тестов).
|
||
- `_lqiFor` и `_roomLqi` теперь используют общую `averageLqi` (убрано дублирование усреднения).
|
||
- Удалён мёртвый код после отказа от отдельного режима правки: поле `_edit` (писалось, но не
|
||
читалось), методы `_renderEditbar` и `_applyXY` (не вызывались).
|
||
- Поведение не изменилось — только структура и покрытие тестами. Проверено: tsc, сборка,
|
||
14 фронт-тестов + 10 бэк-тестов зелёные, headless-дымтест (рендер/зум/устройства/declump) чист.
|
||
|
||
## v1.9.2 — 2026-07-05 (сетка вдвое мельче)
|
||
- Шаг сетки разметки/привязки уменьшен вдвое: `GRID_N` 120 → 240. Позиции устройств и контуры
|
||
комнат НЕ пересчитываются и не сдвигаются: координаты хранятся нормированными долями и снапятся
|
||
к узлам сетки, а старые узлы (кратные 1/120) — точное подмножество новых (кратных 1/240).
|
||
Проверено на живой раскладке (65 позиций — все уже на новой сетке). Перетаскивание теперь
|
||
позволяет более точное позиционирование.
|
||
|
||
## v1.9.1 — 2026-07-05 (сигнал Zigbee: чтение из атрибута + ZHA)
|
||
- Уровень сигнала теперь берётся не только из выделенного сенсора `*_linkquality` (Z2M), но и:
|
||
из сенсоров `*_lqi` (ZHA), и из АТРИБУТА `linkquality`/`lqi` на любой сущности устройства.
|
||
Это покрывает устройства, у которых отдельный сенсор сигнала отключён, но значение есть в атрибуте.
|
||
- ПРИМЕЧАНИЕ: если у устройства сенсор `*_linkquality` отключён (disabled_by=integration) И значение
|
||
нигде не публикуется как атрибут — сигнал показать нельзя, нужно включить сенсор в реестре HA.
|
||
|
||
## v1.9.0 — 2026-07-05 (UX: перетаскивание всегда, расталкивание, показать все, адаптив)
|
||
- **Перетаскивание значков доступно всегда** — отдельный «режим правки» убран (кнопка ✥ удалена).
|
||
Клик по значку открывает карточку устройства (правка метаданных — через кнопку «Редактировать»
|
||
в ней), перетаскивание работает в любой момент. `_pointerDown` больше не требует `_edit`.
|
||
- **Значки не скучиваются** (`_declump`): после авто-раскладки по сетке выполняется расталкивание
|
||
в пределах комнаты, чтобы иконки не налезали друг на друга.
|
||
- **Позиции фиксируются при сохранении комнаты**: авто-позиции устройств зоны один раз пишутся
|
||
в раскладку, поэтому при смене порядка в реестре HA значки не перетасовываются.
|
||
- **Дубли не скрываются, а нумеруются**: устройства с одинаковым «имя|зона» получают суффикс
|
||
(« 2», « 3»…) вместо тихого исчезновения.
|
||
- **Кнопка 👁 «Показать все устройства»** в шапке: временно отключает курирование и показывает
|
||
все устройства зоны (мосты, служебные, дубли) — на случай, если нужное скрыто. Флаг `show_all`
|
||
в настройках конфига.
|
||
- **Подсказка продолжения разметки**: после сохранения комнаты тост показывает счётчик комнат и
|
||
предлагает обвести следующую или выйти из разметки.
|
||
- **Адаптивная шапка**: тулбар переносится и ужимается на узких экранах (media-query ≤620px).
|
||
|
||
## v1.8.4 — 2026-07-04 (онбординг: обязательные поля + ведение пользователя)
|
||
- Первичная инициализация приведена к целевому сценарию: установка → диалог пространства →
|
||
комнаты → авто-значки устройств.
|
||
- **Подложка обязательна** при создании пространства: «Сохранить» неактивна без загруженного
|
||
плана (раньше требовалось только название — можно было создать пустое пространство).
|
||
- **Зона комнаты обязательна** с явным выходом: основная «Сохранить» требует привязку к зоне HA;
|
||
для декоративных комнат без устройств (холл, сауна) есть отдельная кнопка «Без зоны»
|
||
(нужно только имя). Раньше сохранить можно было по «имя ИЛИ зона».
|
||
- **Ведение пользователя:** на пустом серверном конфиге диалог пространства открывается
|
||
автоматически; после добавления первого пространства карточка сама входит в режим разметки
|
||
комнат с подсказкой «обведите комнаты».
|
||
- При сохранении комнаты с зоной значки устройств этой зоны авто-расставляются внутри контура
|
||
(курируемый набор: без мостов/служебных/дублей/одиночных ламп из групп), тост показывает,
|
||
сколько устройств добавлено.
|
||
|
||
## v1.8.3 — 2026-07-04 (мгновенный старт: кэш конфига, данные в фоне)
|
||
- Иконки и план появлялись с задержкой — карточка ждала ответа сервера (WS `config/get`
|
||
+ ретраи прогрева соединения), до этого модель пространств была пуста.
|
||
- Внедрён кэш «stale-while-revalidate»: снимок серверного конфига + rev + раскладки
|
||
сохраняется в `localStorage['houseplan_card_cfg_v1']`. В `setConfig` (синхронно, до прихода
|
||
hass) он восстанавливается — план и значки рисуются сразу из кэша (проверено: setConfig
|
||
наполняет модель за 0.2 мс без сервера), а свежие данные догружаются в фоне и обновляют
|
||
карточку. Живые состояния/температуры/сигнал подтягиваются по мере прогрева hass.
|
||
- Кэш обновляется после каждой успешной загрузки, live-ресинка и сохранения позиций иконок,
|
||
поэтому при следующем открытии виден актуальный снимок. При недоступном сервере показывается
|
||
последний известный план вместо пустого онбординга.
|
||
|
||
## v1.8.2 — 2026-07-04 (векторно-чёткий зум через viewBox + полная ширина сцены)
|
||
- Зум переведён с CSS `transform: scale()` на манипуляцию `viewBox` SVG. Раньше слой
|
||
растрировался и потом масштабировался — при приближении всё «мылилось». Теперь браузер
|
||
перерисовывает вектор в целевом разрешении: иконки, подписи комнат, линии, штриховка и
|
||
векторная подложка остаются чёткими на любом масштабе (проверено на 274%).
|
||
- Слой иконок (HTML) позиционируется и масштабируется по тому же `view`, а не общим
|
||
transform — иконки чёткие и растут вместе с планом.
|
||
- Сцена теперь занимает всю ширину вьюпорта (модель «contain» по аспекту сцены): при
|
||
зум-ине контент заполняет ширину без чёрных полей по бокам. При полном отдалении виден
|
||
весь план (по ширине и высоте), поля вокруг залиты фоном карточки, а не чёрным.
|
||
- Вся координатная математика (клик разметки `_svgPoint`, drag иконок, pan, pinch) переписана
|
||
в единых `view`-координатах — редактирование корректно на любом зуме. ResizeObserver сцены
|
||
пересчитывает `view` при изменении размеров (сайдбар, поворот). Пан/зум ограничены `fit`.
|
||
|
||
## v1.8.1 — 2026-07-04 (fit-to-viewport + сохранение зума по пространствам)
|
||
- Уменьшение масштаба до полного вида: нижний предел зума = 100% совпадает с полностью
|
||
видимым планом. `.stage` теперь ограничена по высоте вьюпорта
|
||
(`width:min(100%, calc((100dvh − 118px) × aspect))`, `max-width:100%`, центрирование),
|
||
поэтому при сбросе/зум-ауте вся схема видна и по ширине, и по высоте без обрезки.
|
||
- Масштаб запоминается для каждого пространства отдельно и локально на устройстве
|
||
(`localStorage['houseplan_card_zoom_v1']`, `_zoomBySpace`): переключение этажей
|
||
восстанавливает свой зум; при возврате пан центрируется и ограничивается.
|
||
- Проверено на живом HA: f1→196%, f2→140%, двор нетронут — после переключений
|
||
значения восстанавливаются; сброс даёт 100% и полный план (874≤992 px по высоте).
|
||
|
||
|
||
## v1.8.0 — 2026-07-04 (зумирование плана)
|
||
- Зум и панорама схемы: колёсико мыши (к курсору), щипок двумя пальцами (pinch) на тач-экране,
|
||
перетаскивание фона одним пальцем при увеличении, кнопки −/сброс/+ в тулбаре, бейдж масштаба.
|
||
- Реализовано через CSS-transform на `.zoomwrap` (translate+scale); координатная математика
|
||
(клик разметки, drag иконок, тултипы) пересчитана с учётом зума/пана — редактирование
|
||
работает и при увеличении. Пан ограничен, чтобы контент всегда покрывал сцену. Зум 100–800%.
|
||
- `.stage`: overflow hidden + touch-action none (свои жесты вместо браузерных).
|
||
|
||
## v1.7.4 — 2026-07-04 (PDF по HTTP вместо WebSocket)
|
||
- КОРНЕВАЯ ПРИЧИНА невозможности загрузить PDF: файл слался как base64 одним WebSocket-сообщением,
|
||
а у WS есть лимит размера — реальный мануал (>2–3 МБ) превышал его, соединение рвалось
|
||
(«Connection lost»), из-за чего и падала загрузка, и закрывался диалог (обрыв WS → переподключение
|
||
→ ре-рендер). Подтверждено тестом: 1 МБ по WS ок, 3 МБ → Connection lost.
|
||
- Файлы-инструкции теперь грузятся через HTTP-эндпоинт `POST /api/houseplan/upload` (multipart,
|
||
HomeAssistantView, requires_auth, admin_only-проверка) — как медиа в самом HA. Проверено:
|
||
3 МБ (182мс) и 10 МБ (446мс) загружаются на ура.
|
||
- Читаемые ошибки везде (`_errText`): больше никаких «[object Object]»; понятные тексты для
|
||
too_large / bad_ext / unauthorized.
|
||
- WS-команда houseplan/file/set оставлена для совместимости, но фронт использует HTTP.
|
||
|
||
|
||
## v1.7.3 — 2026-07-04 (фиксы диалога устройства)
|
||
- PDF-инструкции не загружались: ручной base64 (`btoa(String.fromCharCode(...subarray))`) падал
|
||
на реальных файлах (RangeError при спреде больших массивов), а при закрытии диалога во время
|
||
await бросал null-доступ. Заменено на `FileReader.readAsDataURL` (надёжно для любого размера),
|
||
результаты аккумулируются и добавляются, только если диалог ещё открыт (без исключений).
|
||
- Диалог редактирования устройства/пространства/комнаты закрывался по клику мимо и «сам»
|
||
(случайный клик по фон-оверлею, в т.ч. после закрытия системного выбора файла). Убрано
|
||
закрытие по клику на фон у диалогов-редакторов — только явные Отмена/Сохранить/Esc.
|
||
Инфо-карточка (только чтение) по-прежнему закрывается кликом мимо.
|
||
- Проверено на живом HA: PDF прикрепляется; клик по фону и обновление данных диалог не закрывают.
|
||
|
||
## v1.7.2 — 2026-07-04 (фикс мобильного «ошибка конфигурации»)
|
||
- ПРИЧИНА: карточка подключалась только через `add_extra_js_url` (extra_module_url), загрузку
|
||
которого фронтенд НЕ дожидается — на холодном старте мобильного приложения дашборд рисовался
|
||
раньше регистрации элемента → «ошибка конфигурации». (Все рабочие HACS-карточки — Lovelace-ресурсы.)
|
||
- ФИКС 1: интеграция регистрирует карточку как **Lovelace-ресурс** (module) — их фронтенд ждёт
|
||
перед рендером. Идемпотентно (обновляет URL при смене версии, без дублей); фолбэк на
|
||
extra_module_url для YAML-режима Lovelace. `_register_lovelace_resource` в __init__.py.
|
||
- ФИКС 2: `_loadFromServer` ретраит (до 8 попыток по обновлениям hass) — если hass пришёл раньше
|
||
готовности WS, карточка не застревает на онбординге, а дожидается конфига.
|
||
- Проверено: ресурс houseplan-card.js зарегистрирован, extra_module_url пуст (единый чистый
|
||
модуль), карточка рендерит план на свежей вкладке без ошибки.
|
||
|
||
## v1.7.0 — 2026-07-04 (аудит + рефакторинг + тесты)
|
||
- Удалён вшитый в бандл дом-образец (дача, ~245 КБ base64 планов + ROOMS/FLOOR_*): бандл
|
||
293 КБ → 83 КБ. Свежая установка показывает онбординг «Добавить пространство», а не чужой дом.
|
||
- Удалён код миграции legacy→сервер (дача уже на server config) и мёртвые пути
|
||
device_overrides/virtual_devices (заменены markers[]).
|
||
- Чистая логика вынесена в src/logic.ts (lqiColor, snapToGrid, segKey, pointInPolygon,
|
||
markerIdForBinding, averageLqi) — покрыта юнит-тестами (node:test, 9 тестов + iconFor).
|
||
- Бэкенд: валидация/санитайзеры вынесены в validation.py (без HA-импортов) — pytest, 10 тестов.
|
||
- БЕЗОПАСНОСТЬ: тест выявил, что санитайзер имён файлов/маркеров сохранял ведущие точки
|
||
(риск обхода каталогов через «..»); добавлено срезание ведущих точек, пустое → misc/file.
|
||
- Исправлены реальные баги, ранее замаскированные обрезанным rules.ts: DOMAIN_PRIORITY был
|
||
усечён (ломало выбор more-info-сущности); _defaultPositions падал на полигон-комнатах
|
||
(теперь bbox). tsc --noEmit добавлен в сборку и CI — строгая типизация проходит.
|
||
- Убраны дубли-мусор src/data/{editor,rules}.ts; версии синхронизированы (manifest застрял на 1.4.0).
|
||
- CI: добавлены typecheck, юнит-тесты фронта и бэка.
|
||
|
||
## v1.6.2 — 2026-07-04
|
||
- Поле «Комната» в диалоге устройства теперь для ВСЕХ значков (не только виртуальных):
|
||
для привязанных — «переопределить размещение» (по умолчанию по зоне устройства); смена
|
||
комнаты переставляет значок в её центр. Сохраняется в marker.space/area и выигрывает у зоны HA.
|
||
- В инфо-карточке добавлена кнопка «Редактировать» — открывает диалог редактирования устройства.
|
||
|
||
## v1.6.0 — 2026-07-04 (Фаза 3: редактор устройств)
|
||
- Модель «маркеров» (config.markers[]): гибрид — авто-устройства HA появляются сами, маркеры
|
||
правят/перепривязывают/дополняют их и описывают ручные/виртуальные значки. id маркера
|
||
сохраняет позицию (device→device_id, entity→lg_<eid>, virtual→v_<rand>).
|
||
- Клик по значку: обычный режим → инфо-карточка (имя, модель, состояние, ссылка, описание,
|
||
PDF-инструкции, кнопка «Открыть в HA»); режим правки → диалог редактирования.
|
||
- Диалог устройства: имя, привязка (пикер всех устройств/групп HA+Z2M+хелперов с текстовым
|
||
фильтром, минус уже размещённые и дубли по имя|area, + «Виртуальное устройство»), MDI-иконка
|
||
(ha-icon-picker), модель, ссылка, описание, прикрепление файлов-инструкций (PDF на сервер),
|
||
комната (для виртуальных), Убрать/Отмена/Сохранить.
|
||
- Тулбар: кнопка «+» (тултип «Добавить устройство») — пустой диалог.
|
||
- Бэкенд: MARKER_SCHEMA в config; WS houseplan/file/set (файлы в /config/houseplan/files/,
|
||
≤25 МБ, отдача /houseplan_files/files/); статика files зарегистрирована.
|
||
- Виртуальные значки теперь перетаскиваются и позиционируются как обычные (layout по id).
|
||
|
||
## v1.6.1 — 2026-07-04
|
||
- Пикер привязки прячет дубли устройств по «имя|area» (Tuya/LocalTuya), как дедуп на плане.
|
||
|
||
## v1.5.1 — 2026-07-04 (управление пространствами)
|
||
- Иконка-карандаш справа от названия каждого пространства в верхнем тулбаре + кнопка «+»
|
||
(только при server config).
|
||
- Диалог пространства: поле «Название», превью текущей подложки + «Загрузить/Заменить…»
|
||
(SVG/PNG/JPG/WebP, base64 → houseplan/plan/set, пропорции определяются из файла),
|
||
кнопки Удалить / Отмена / Сохранить. Создание пустого пространства и удаление (со всеми
|
||
комнатами и разметкой, с подтверждением). Сохранение через config/set с ревизией.
|
||
|
||
## v1.5.0 — 2026-07-04 (группы света = сущности)
|
||
- Лампы заменены сущностями групп: HA light-groups (platform=group, area из реестра сущности)
|
||
и Z2M-группы (device model=Group) рендерятся иконкой mdi:lightbulb-group; клик → more-info
|
||
группы (управление всей группой и участниками штатно в HA).
|
||
- Одиночные лампы скрываются в комнатах, где есть группа света (settings.group_lights=false
|
||
возвращает поштучный режим).
|
||
- Выпилена старая визуальная группировка и кастомное меню участников (упрощение кода).
|
||
- Позиции старых групп (grp_<area>) перенесены на новые id (lg_<entity_id>) в раскладке дачи.
|
||
|
||
## v1.4.4 — 2026-07-04 (КРИТИЧЕСКИЙ фикс: гонка конфигураций)
|
||
- ИНЦИДЕНТ: config сохранялся целиком по принципу last-writer-wins — открытый клиент со
|
||
старой копией затирал чужие правки (потеряна первая итерация пользовательской разметки).
|
||
- Фикс: оптимистичная блокировка — конфиг несёт `rev`; `config/set` принимает `expected_rev`
|
||
и возвращает ошибку `conflict` при несовпадении; клиент перечитывает конфиг.
|
||
- Live-синхронизация: `config/set` рассылает событие `houseplan_config_updated`; все открытые
|
||
карточки подписаны и перечитывают конфиг автоматически (окна больше не расходятся).
|
||
- Позиции при drag сохраняются точечно через `layout/update` (dirty-set), а не полным
|
||
`layout/set` — раскладка тоже больше не затирается между окнами.
|
||
- Бэкап конфига перед деплоем: .storage/houseplan.config.bak-*.
|
||
|
||
## v1.4.3 — 2026-07-04
|
||
- Иконки устройств привязываются к той же сетке, что и разметка (центр иконки = узел, снап
|
||
при перетаскивании и вводе X/Y). Существующие 57 позиций в БД дачи снапнуты к узлам.
|
||
|
||
## v1.4.2 — 2026-07-04 (сетка разметки)
|
||
- Шаг сетки уменьшен в 2 раза: GRID_N 60 → 120 (шаг 8.33 рендер-ед. ≈ 0.83% ширины плана).
|
||
- Точки сетки рендерятся ПОВЕРХ плана и комнат (grid-rect перенесён из под-плана в верхний
|
||
markup-слой); точки контрастнее (r=0.14g, обводка).
|
||
- Данные дачи: границы всех 13 комнат привязаны к узлам сетки (снап рёбер, сдвиги ≤ полшага;
|
||
правка только конфига инстанса через houseplan/config/set, код не менялся).
|
||
- Кэш карточки: URL модуля ?v= берётся из const.VERSION — при обновлении фронтенда бампать
|
||
const.py и рестартовать HA, иначе браузеры держат старый модуль в memory-cache.
|
||
|
||
## v1.4.1 — 2026-07-04 (UX разметки)
|
||
- Esc / Ctrl+Z при рисовании убирают последнюю точку (и её линию, если она была добавлена
|
||
этим шагом; переиспользованные чужие стены не трогаются).
|
||
- Панель редактирования (разметка и правка раскладки) перенесена наверх под шапку карточки
|
||
и закреплена вместе с ней (общий sticky-контейнер .hdr).
|
||
- Замыкание контура автоматически открывает модальный диалог «Новая комната»: отображаемое
|
||
имя, выпадающий список ТОЛЬКО свободных зон HA (не назначенных ни одной комнате конфига),
|
||
Сохранить/Отмена. Отмена (или Esc) снимает замыкающую точку — контур можно продолжить.
|
||
Выбор зоны при пустом имени подставляет название зоны.
|
||
|
||
## v1.4.0 — 2026-07-04 (Фаза 2: редактор разметки комнат)
|
||
- Режим «Разметка» в карточке (кнопка mdi:vector-square-edit, только при server config):
|
||
сетка точек (60 узлов по ширине), линии парами кликов со снапом к узлам, полилиния-превью.
|
||
- Замкнутый контур (клик по первой точке) активирует «Сохранить»: выбор зоны HA из
|
||
выпадающего списка + название; комната сохраняется полигоном (poly, нормированные вершины).
|
||
- Инструменты: Добавить (рисование), Стереть линию (клик по линии), Удалить комнату
|
||
(клик внутри + confirm). Линии-«стены» хранятся в space.segments и переиспользуются
|
||
соседними комнатами (общие стены — кликами по существующим узлам).
|
||
- Рендер комнат: полигоны наравне с прямоугольниками (hover, клик в зону, LQI-тултип,
|
||
подпись в центроиде); в режиме разметки контуры и названия всех комнат видимы.
|
||
- Бэкенд: ROOM_SCHEMA принимает poly (≥3 вершин) или x/y/w/h; SPACE_SCHEMA — segments.
|
||
|
||
## v1.3.0 — 2026-07-04 (Фаза 1: серверная конфигурация)
|
||
- Store `houseplan.config`: spaces (план, aspect, view_box, комнаты), device_overrides
|
||
(hidden/icon/name), virtual_devices, settings (exclude_integrations, group_lights).
|
||
- WS: `houseplan/config/get|set`, `houseplan/plan/set` (загрузка файла плана base64 →
|
||
`<config>/houseplan/plans/`, отдача через /houseplan_files/plans/).
|
||
- Карточка: резолв-модель — server config (координаты НОРМИРОВАННЫЕ 0..1, рендер 1000×1000/aspect)
|
||
или legacy-бандл (холст 1489×1053). Раскладка v2: {device_id: {s, x, y}} нормированная.
|
||
- Кнопка «На сервер» в режиме правки — миграция legacy-конфига в один клик (планы, комнаты,
|
||
view_box, раскладка). Выполнена на даче: .storage/houseplan.config + plans/f1.svg,f2.svg.
|
||
- Read-side поддержка оверрайдов устройств и виртуальных устройств (UI управления — фазы 3–4).
|
||
|
||
## v1.2.2 — 2026-07-04
|
||
- Тулбар карточки (вкладки этажей) закрепляется при скролле под шапкой HA
|
||
(`position: sticky; top: var(--header-height)`; ha-card overflow: visible).
|
||
- Инцидент: промежуточная сборка на нестабильном mount дала битый бандл, роняющий рендер
|
||
дашбордов; правило «собирать только в /tmp + md5-контроль» закреплено в DEVELOPMENT.md.
|
||
|
||
## v1.2.1 — 2026-07-04
|
||
- Иконки не увеличиваются при наведении/перетаскивании (убран transform: scale).
|
||
|
||
## v1.2.0 — 2026-07-03
|
||
- Границы комнат сняппены к стенам векторного плана.
|
||
- Zigbee LQI: значение под иконкой, среднее по комнате в тултипе, градиент красный→зелёный,
|
||
опция show_signal.
|
||
- `mdi:lock` для любых устройств с сущностью lock.* (TTLock).
|
||
- Выключатель прихожей: исправлена зона устройства в реестре HA (был в detskaia_elina).
|
||
|
||
## v1.1.0 — 2026-07-03
|
||
- Векторные подложки (SVG РЕМПЛАННЕР), автосовмещение масштаба/сдвига растровой корреляцией.
|
||
- Размер иконок в % ширины плана (container queries, дефолт 2.5%).
|
||
|
||
## v1.0.1 — 2026-07-03
|
||
- fix: вложенные SVG-фрагменты через lit svg`` (подложка/комнаты не рендерились).
|
||
- fix: версия из const вместо блокирующего чтения manifest.json в event loop.
|
||
|
||
## v1.0.0 — 2026-07-03
|
||
- Первый релиз: Lovelace-карточка (TS+Lit, без токена, от hass) + интеграция houseplan
|
||
(WS-хранилище раскладки, раздача JS). Перенос модели прототипа: курирование, группы ламп,
|
||
iconFor, температура, more-info, навигация в зоны, drag-раскладка.
|