From abe821a0472227e2006ea10812a4454d771c74f6 Mon Sep 17 00:00:00 2001 From: Home Assistant Version Control Date: Wed, 26 Aug 2026 17:38:07 +0000 Subject: [PATCH] 15 files --- custom_components/album_slideshow/__init__.py | 16 +- custom_components/album_slideshow/button.py | 25 +- custom_components/album_slideshow/camera.py | 584 +++++++++++++++--- .../album_slideshow/config_flow.py | 48 +- custom_components/album_slideshow/const.py | 5 + .../album_slideshow/google_scraper.py | 37 +- .../album_slideshow/manifest.json | 2 +- custom_components/album_slideshow/number.py | 33 + .../album_slideshow/services.yaml | 11 + custom_components/album_slideshow/store.py | 2 + .../album_slideshow/strings.json | 1 + .../album_slideshow/translations/en.json | 1 + .../www/album-slideshow-card.js | 15 +- .../multiple-entity-row.js | 2 +- .../multiple-entity-row.js.gz | Bin 25443 -> 27204 bytes 15 files changed, 654 insertions(+), 128 deletions(-) diff --git a/custom_components/album_slideshow/__init__.py b/custom_components/album_slideshow/__init__.py index 5647de81..db146623 100644 --- a/custom_components/album_slideshow/__init__.py +++ b/custom_components/album_slideshow/__init__.py @@ -10,7 +10,7 @@ from homeassistant.const import EVENT_HOMEASSISTANT_STARTED from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from .const import DOMAIN, SERVICE_NEXT_SLIDE, SERVICE_REFRESH_ALBUM, ATTR_ENTRY_ID +from .const import DOMAIN, SERVICE_NEXT_SLIDE, SERVICE_PREVIOUS_SLIDE, SERVICE_REFRESH_ALBUM, ATTR_ENTRY_ID from .store import SlideshowStore _LOGGER = logging.getLogger(__name__) @@ -392,6 +392,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if cam: await cam.async_force_next() + async def _previous_slide(call) -> None: + entry_id = call.data.get(ATTR_ENTRY_ID) + if not entry_id: + return + data = hass.data.get(DOMAIN, {}).get(entry_id) + if not data: + return + cam = data.get("camera") + if cam: + await cam.async_force_prev() + async def _refresh_album(call) -> None: entry_id = call.data.get(ATTR_ENTRY_ID) if not entry_id: @@ -406,6 +417,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if not hass.services.has_service(DOMAIN, SERVICE_NEXT_SLIDE): hass.services.async_register(DOMAIN, SERVICE_NEXT_SLIDE, _next_slide) + if not hass.services.has_service(DOMAIN, SERVICE_PREVIOUS_SLIDE): + hass.services.async_register(DOMAIN, SERVICE_PREVIOUS_SLIDE, _previous_slide) + if not hass.services.has_service(DOMAIN, SERVICE_REFRESH_ALBUM): hass.services.async_register(DOMAIN, SERVICE_REFRESH_ALBUM, _refresh_album) diff --git a/custom_components/album_slideshow/button.py b/custom_components/album_slideshow/button.py index 532cbfd3..ce4a81cd 100644 --- a/custom_components/album_slideshow/button.py +++ b/custom_components/album_slideshow/button.py @@ -5,7 +5,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .const import DOMAIN, SERVICE_NEXT_SLIDE, SERVICE_REFRESH_ALBUM, ATTR_ENTRY_ID +from .const import DOMAIN, SERVICE_REFRESH_ALBUM, ATTR_ENTRY_ID from .coordinator import AlbumCoordinator @@ -13,6 +13,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e coordinator: AlbumCoordinator = hass.data[DOMAIN][entry.entry_id]["coordinator"] async_add_entities( [ + PreviousSlideButton(hass, entry, coordinator), NextSlideButton(hass, entry, coordinator), RefreshAlbumButton(hass, entry, coordinator), ] @@ -36,6 +37,19 @@ class _BaseButton(ButtonEntity): } +class PreviousSlideButton(_BaseButton): + def __init__(self, hass: HomeAssistant, entry: ConfigEntry, coordinator: AlbumCoordinator) -> None: + super().__init__(hass, entry, coordinator) + self._attr_unique_id = f"{entry.entry_id}_previous_button" + self._attr_name = "Previous slide" + self._attr_icon = "mdi:skip-previous" + + async def async_press(self) -> None: + camera = self.hass.data[DOMAIN][self.entry.entry_id].get("camera") + if camera is not None: + await camera.async_force_prev() + + class NextSlideButton(_BaseButton): def __init__(self, hass: HomeAssistant, entry: ConfigEntry, coordinator: AlbumCoordinator) -> None: super().__init__(hass, entry, coordinator) @@ -44,12 +58,9 @@ class NextSlideButton(_BaseButton): self._attr_icon = "mdi:skip-next" async def async_press(self) -> None: - await self.hass.services.async_call( - DOMAIN, - SERVICE_NEXT_SLIDE, - {ATTR_ENTRY_ID: self.entry.entry_id}, - blocking=False, - ) + camera = self.hass.data[DOMAIN][self.entry.entry_id].get("camera") + if camera is not None: + await camera.async_force_next() class RefreshAlbumButton(_BaseButton): diff --git a/custom_components/album_slideshow/camera.py b/custom_components/album_slideshow/camera.py index e6b5bec6..fbf0d0a2 100644 --- a/custom_components/album_slideshow/camera.py +++ b/custom_components/album_slideshow/camera.py @@ -1,10 +1,13 @@ from __future__ import annotations import asyncio -from collections import OrderedDict +from collections import OrderedDict, deque +from dataclasses import dataclass +from datetime import datetime, timezone import logging import random from pathlib import Path +from typing import Any import async_timeout from PIL import Image @@ -46,18 +49,44 @@ _ACCEPTED_IMAGE_PREFIX = ("image/",) _PAIR_SEARCH_LIMIT = 12 _SKIP_SEARCH_LIMIT = 30 +_MAX_RENDER_ATTEMPTS = 10 + + +@dataclass(frozen=True, slots=True) +class _NavigationCursor: + """All mutable ordering state needed to render the following slide.""" + + index: int + random_order: tuple[int, ...] + random_pos: int + recent_urls: tuple[str, ...] + rng_state: Any + + +@dataclass(frozen=True, slots=True) +class _RenderedFrame: + """A complete slide that can be displayed without any further work.""" + + data: bytes + cursor: _NavigationCursor + meta: dict + def _ts_to_iso(ts_ms: int | None) -> str | None: """Convert epoch milliseconds to an ISO-8601 string in UTC, or None.""" if not isinstance(ts_ms, int): return None - from datetime import datetime, timezone try: return datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc).isoformat() except (OverflowError, OSError, ValueError): return None +def _utc_now_iso() -> str: + """Return the current time as an ISO-8601 UTC string.""" + return datetime.now(timezone.utc).isoformat() + + class _DownloadCache: """Byte-budget LRU cache for downloaded image data, O(1) per operation.""" @@ -155,22 +184,43 @@ class AlbumSlideshowCamera(Camera): self._frame_id: int = 0 self._interrupt_event: asyncio.Event = asyncio.Event() - self._force_next: bool = False + # Navigation runs directly in the button/service coroutine. The lock + # serialises rapid presses while buffered swaps remain independent of + # the background timer loop. + self._navigation_lock: asyncio.Lock = asyncio.Lock() + self._navigation_pending: int = 0 + # Rendered timeline around the current frame. Previous frames and future + # frames are final encoded JPEGs, so both navigation directions are an + # O(1) deque swap. The future deque is replenished in the background. + self._current_frame: _RenderedFrame | None = None + self._previous_frames: deque[_RenderedFrame] = deque() + self._next_frames: deque[_RenderedFrame] = deque() + self._timeline_generation: int = 0 + self._timeline_dirty: bool = False + self._next_ready_event: asyncio.Event = asyncio.Event() + self._preload_task: asyncio.Task | None = None + # Visible navigation diagnostics. These are state attributes rather + # than debug-only log messages so they remain observable when Home + # Assistant's UI filters debug logs. + self._last_nav_direction: str | None = None + self._last_nav_requested_at: str | None = None + self._last_nav_started_at: str | None = None + self._last_nav_committed_at: str | None = None + self._last_nav_outcome: str | None = None + self._last_nav_error: str | None = None self._consecutive_failures: int = 0 self._render_task: asyncio.Task | None = None def _on_coordinator_update() -> None: self._effective_cache = None - self._interrupt_event.set() - self.async_write_ha_state() + self._invalidate_timeline() coordinator.async_add_listener(_on_coordinator_update) def _on_store_change() -> None: self._download_cache.resize(self.store.image_cache_mb * 1024 * 1024) self._effective_cache = None - self._interrupt_event.set() - self.async_write_ha_state() + self._invalidate_timeline() store.add_listener(_on_store_change) @@ -193,12 +243,19 @@ class AlbumSlideshowCamera(Camera): ) async def async_will_remove_from_hass(self) -> None: + preload_task = self._preload_task + self._cancel_preload() if self._render_task is not None: self._render_task.cancel() try: await self._render_task except asyncio.CancelledError: pass + if preload_task is not None: + try: + await preload_task + except asyncio.CancelledError: + pass @property def device_info(self): @@ -258,6 +315,19 @@ class AlbumSlideshowCamera(Camera): "pair_divider_px": int(self.store.pair_divider_px), "pair_divider_color": self.store.pair_divider_color, "frame_id": self._frame_id, + "navigation_buffer_size": self._buffer_depth, + "previous_frames_cached": len(self._previous_frames), + "next_frames_preloaded": len(self._next_frames), + "navigation_preloading": bool( + self._preload_task is not None and not self._preload_task.done() + ), + "navigation_queue_size": self._navigation_pending, + "last_navigation_direction": self._last_nav_direction, + "last_navigation_requested_at": self._last_nav_requested_at, + "last_navigation_started_at": self._last_nav_started_at, + "last_navigation_committed_at": self._last_nav_committed_at, + "last_navigation_outcome": self._last_nav_outcome, + "last_navigation_error": self._last_nav_error, "pagination_debug": data.get("pagination_debug"), } @@ -331,10 +401,53 @@ class AlbumSlideshowCamera(Camera): return ordered async def async_force_next(self) -> None: - self._force_next = True + """Display the next buffered slide immediately.""" + await self._async_navigate(1) + + async def async_force_prev(self) -> None: + """Display the previous retained slide immediately.""" + await self._async_navigate(-1) + + async def _async_navigate(self, direction: int) -> None: + """Serialise a manual navigation request and execute it directly.""" + direction_name = "next" if direction > 0 else "previous" + self._navigation_pending += 1 + self._last_nav_direction = direction_name + self._last_nav_requested_at = _utc_now_iso() + self._last_nav_outcome = "pending" + self._last_nav_error = None + # Wake the timer loop so the manual frame starts a fresh interval. self._interrupt_event.set() self.async_write_ha_state() + try: + async with self._navigation_lock: + self._last_nav_started_at = _utc_now_iso() + if self._timeline_dirty: + await self._rebuild_current_frame() + changed = ( + await self._show_next_frame() + if direction > 0 + else await self._show_previous_frame() + ) + if changed: + self._last_nav_committed_at = _utc_now_iso() + self._last_nav_outcome = "displayed" + else: + self._last_nav_outcome = "not_available" + except Exception as err: + self._last_nav_outcome = "error" + self._last_nav_error = str(err) + _LOGGER.warning( + "Album Slideshow %s: manual %s navigation failed: %s", + self.entry.title, + direction_name, + err, + ) + finally: + self._navigation_pending -= 1 + self.async_write_ha_state() + async def async_force_refresh(self) -> None: await self.coordinator.async_request_refresh() @@ -373,123 +486,387 @@ class AlbumSlideshowCamera(Camera): async def async_handle_async_mjpeg_stream(self, request): return await self.handle_async_mjpeg_stream(request) - async def _wait_or_interrupt(self, timeout: float) -> bool: - """Wait up to ``timeout`` seconds, returning True if interrupted. + @property + def _buffer_depth(self) -> int: + """Configured number of rendered frames retained in each direction.""" + return min(10, max(0, int(self.store.navigation_buffer_size))) - Does NOT clear ``_interrupt_event`` - the render loop clears it once - per cycle, before rendering, so a signal that arrives while we're - rendering (a "next slide" press, a coordinator/store change) survives - until we get here instead of being wiped. + def _capture_cursor(self, source=None) -> _NavigationCursor: + """Snapshot ordering state from this camera or a private renderer.""" + source = source or self + return _NavigationCursor( + index=int(source._index), + random_order=tuple(source._random_order), + random_pos=int(source._random_pos), + recent_urls=tuple(source._recent_urls), + rng_state=source._rng.getstate(), + ) - A force-next that's already pending is honored immediately without - sleeping, so a press that landed during the last render (or right at - the loop boundary) isn't held until the full slide interval elapses. + def _make_renderer(self, cursor: _NavigationCursor): + """Create an isolated render context sharing only immutable services/cache. + + Composition helpers historically operate on ``self._index`` and random + ordering fields. A private camera-shaped context lets background + preloading reuse those mature helpers without ever mutating the live + entity's current frame or navigation cursor. """ - if self._force_next: + renderer = AlbumSlideshowCamera.__new__(AlbumSlideshowCamera) + renderer.hass = self.hass + renderer.entry = self.entry + renderer.coordinator = self.coordinator + renderer.store = self.store + renderer._download_cache = self._download_cache + renderer._index = cursor.index + renderer._random_order = list(cursor.random_order) + renderer._random_pos = cursor.random_pos + renderer._recent_urls = list(cursor.recent_urls) + renderer._rng = random.Random() + renderer._rng.setstate(cursor.rng_state) + return renderer + + async def _render_available_frame( + self, + cursor: _NavigationCursor, + items: list[MediaItem], + *, + advance: bool, + ) -> _RenderedFrame: + """Render the current or next usable slide from ``cursor``. + + Broken candidates are skipped, matching the old loop's retry behavior. + All state mutations occur on a private renderer. The returned JPEG and + cursor are therefore safe to place in the future buffer. + """ + if not items: + raise RuntimeError("No media available") + + attempts = min(len(items), _MAX_RENDER_ATTEMPTS) + last_error: Exception | None = None + should_advance = advance + + for _ in range(attempts): + renderer = self._make_renderer(cursor) + renderer._index %= len(items) + if should_advance: + renderer._do_advance(len(items), items) + + composed: Image.Image | None = None + try: + async with self._compose_semaphore: + composed, meta = await renderer._compose_for_index(items) + cursor = self._capture_cursor(renderer) + if composed is None: + raise RuntimeError("Image composition returned no frame") + encoded = await self.hass.async_add_executor_job( + ip.encode_image, composed + ) + return _RenderedFrame(encoded, cursor, meta or {}) + except asyncio.CancelledError: + raise + except Exception as err: + last_error = err + cursor = self._capture_cursor(renderer) + should_advance = True + _LOGGER.debug( + "Album Slideshow %s: skipping unrenderable buffered slide: %s", + self.entry.title, + err, + ) + finally: + ip.safe_close(composed) + + raise RuntimeError( + f"Could not render a usable slide after {attempts} attempts: {last_error}" + ) + + def _apply_frame(self, frame: _RenderedFrame) -> None: + """Make a rendered frame current and publish it to Home Assistant.""" + self._current_frame = frame + self._framebuffer = frame.data + self.store.last_frame = frame.data + self._index = frame.cursor.index + self._random_order = list(frame.cursor.random_order) + self._random_pos = frame.cursor.random_pos + self._recent_urls = list(frame.cursor.recent_urls) + self._rng.setstate(frame.cursor.rng_state) + + meta = frame.meta + self._last_is_portrait = meta.get("is_portrait") + self._last_captured_at_pair = meta.get("captured_at_pair") + self._last_pair_frames = meta.get("pair_frames") + self._last_pair_orientation = meta.get("pair_orientation") + self._frame_id += 1 + + _LOGGER.debug( + "Album Slideshow %s: displayed buffered frame_id=%d index=%d " + "previous=%d next=%d", + self.entry.title, + self._frame_id, + self._index, + len(self._previous_frames), + len(self._next_frames), + ) + self.async_write_ha_state() + + def _trim_timeline(self) -> None: + """Enforce the configured frame count on both sides of current.""" + depth = self._buffer_depth + while len(self._previous_frames) > depth: + self._previous_frames.popleft() + while len(self._next_frames) > depth: + self._next_frames.pop() + + def _cancel_preload(self) -> None: + task = self._preload_task + self._preload_task = None + if task is not None and not task.done(): + task.cancel() + self._next_ready_event.set() + + def _invalidate_timeline(self) -> None: + """Drop frames rendered from stale media/settings and wake the loop.""" + self._timeline_generation += 1 + self._timeline_dirty = True + self._previous_frames.clear() + self._next_frames.clear() + self._cancel_preload() + self._interrupt_event.set() + self.async_write_ha_state() + + def _schedule_preload(self) -> None: + """Start the single per-camera worker that fills future frames.""" + self._trim_timeline() + if ( + self._buffer_depth <= 0 + or self._current_frame is None + or len(self._next_frames) >= self._buffer_depth + ): + return + if self._preload_task is not None and not self._preload_task.done(): + return + + generation = self._timeline_generation + self._preload_task = self.hass.async_create_background_task( + self._preload_loop(generation), + name="album_slideshow_preload", + ) + + async def _preload_loop(self, generation: int) -> None: + """Render future slides sequentially until the configured buffer is full.""" + this_task = asyncio.current_task() + try: + while generation == self._timeline_generation: + self._trim_timeline() + if len(self._next_frames) >= self._buffer_depth: + return + + base = self._next_frames[-1] if self._next_frames else self._current_frame + if base is None: + return + items = self._effective_items() + if not items: + return + + frame = await self._render_available_frame( + base.cursor, + items, + advance=True, + ) + if generation != self._timeline_generation: + return + + # Navigation may have moved the base from future to current or + # vice versa while rendering. It is still valid if it remains + # the last frame in the known timeline. + current_tail = ( + self._next_frames[-1] + if self._next_frames + else self._current_frame + ) + if current_tail is not base: + continue + if len(self._next_frames) < self._buffer_depth: + self._next_frames.append(frame) + self._next_ready_event.set() + self.async_write_ha_state() + await asyncio.sleep(0) + except asyncio.CancelledError: + raise + except Exception as err: + _LOGGER.warning( + "Album Slideshow %s: could not fill navigation buffer: %s", + self.entry.title, + err, + ) + finally: + if self._preload_task is this_task: + self._preload_task = None + self._next_ready_event.set() + self.async_write_ha_state() + + async def _await_preloaded_frame(self) -> bool: + """Wait for the in-flight worker's first frame, without waiting for all X.""" + if self._next_frames: + return True + if self._buffer_depth <= 0: + return False + + self._schedule_preload() + while not self._next_frames: + task = self._preload_task + if task is None or task.done(): + return False + self._next_ready_event.clear() + if self._next_frames: + return True + waiter = asyncio.create_task(self._next_ready_event.wait()) + try: + await asyncio.wait( + {task, waiter}, + return_when=asyncio.FIRST_COMPLETED, + ) + finally: + waiter.cancel() + try: + await waiter + except asyncio.CancelledError: + pass + return True + + async def _show_next_frame(self) -> bool: + """Display the next buffered frame, rendering on demand only if empty.""" + if self._current_frame is None: + return await self._rebuild_current_frame() + + await self._await_preloaded_frame() + if self._next_frames: + frame = self._next_frames.popleft() + else: + items = self._effective_items() + frame = await self._render_available_frame( + self._current_frame.cursor, + items, + advance=True, + ) + + if self._buffer_depth > 0: + self._previous_frames.append(self._current_frame) + self._trim_timeline() + self._apply_frame(frame) + self._schedule_preload() + return True + + async def _show_previous_frame(self) -> bool: + """Restore the most recent retained frame without I/O or composition.""" + if not self._previous_frames: + return False + + frame = self._previous_frames.pop() + if self._current_frame is not None and self._buffer_depth > 0: + self._next_frames.appendleft(self._current_frame) + self._trim_timeline() + self._apply_frame(frame) + self._schedule_preload() + return True + + async def _rebuild_current_frame(self) -> bool: + """Render the current cursor after startup or playlist/settings changes.""" + generation = self._timeline_generation + self._timeline_dirty = False + items = self._effective_items() + if not items: + return False + + cursor = ( + self._current_frame.cursor + if self._current_frame is not None + else self._capture_cursor() + ) + frame = await self._render_available_frame(cursor, items, advance=False) + if generation != self._timeline_generation: + return False + self._previous_frames.clear() + self._next_frames.clear() + self._apply_frame(frame) + self._schedule_preload() + return True + + async def _wait_or_interrupt(self, timeout: float) -> bool: + """Wait for configuration/navigation or for the slide timer to expire.""" + if self._timeline_dirty: + return True + self._interrupt_event.clear() + # Close the clear/wait race: callbacks cannot run between these two + # synchronous statements without setting the event again. + if self._timeline_dirty: return True try: - await asyncio.wait_for(self._interrupt_event.wait(), timeout=timeout) + if self.store.paused: + await self._interrupt_event.wait() + else: + await asyncio.wait_for( + self._interrupt_event.wait(), + timeout=timeout, + ) return True except asyncio.TimeoutError: return False async def _render_loop(self, initial_delay: float = 0.0) -> None: - """Background task: render slides into _framebuffer, advance on timer or interrupt.""" + """Display buffered frames on command/timer and refill them in the background.""" if initial_delay > 0: + await asyncio.sleep(initial_delay) + + while self._current_frame is None: try: - await asyncio.sleep(initial_delay) - except asyncio.CancelledError: - raise - should_advance = False # Don't advance on the very first render - while True: - # Clear the wake signal before rendering. Anything that happens - # from here on (a "next slide" press, a coordinator/store change) - # re-sets it and is picked up after this frame commits, so no - # wake is lost while we're mid-render. - self._interrupt_event.clear() - try: - await self._render_cycle(advance=should_advance) - self._consecutive_failures = 0 + async with self._navigation_lock: + if self._current_frame is None: + await self._rebuild_current_frame() + if self._current_frame is not None: + self._consecutive_failures = 0 + break except asyncio.CancelledError: raise except Exception as err: self._consecutive_failures += 1 backoff = min(2 ** self._consecutive_failures, 60) _LOGGER.warning( - "Album Slideshow: render cycle failed (attempt %d), retrying in %ds: %s", - self._consecutive_failures, backoff, err, + "Album Slideshow: initial render failed (attempt %d), retrying in %ds: %s", + self._consecutive_failures, + backoff, + err, ) - try: - await asyncio.sleep(backoff) - except asyncio.CancelledError: - raise - should_advance = True # Skip the broken image on retry - continue + await asyncio.sleep(backoff) + if not self._effective_items(): + self._interrupt_event.clear() + if not self._effective_items(): + await self._interrupt_event.wait() - interrupted = await self._wait_or_interrupt(float(int(self.store.slide_interval))) - if self._force_next: - # Explicit "next slide" request: always advance. - should_advance = True - self._force_next = False - elif interrupted: - # A coordinator/store change woke us: re-render the current - # frame (new data or settings) without skipping ahead. - should_advance = False - else: - # Paused slideshows hold the current frame until the user - # un-pauses or hits "next slide" explicitly. - should_advance = not bool(self.store.paused) - - async def _render_cycle(self, advance: bool) -> None: - """Render one frame. - - The slideshow is just "advance index, compose, encode, broadcast". - Visible transitions are handled by the Lovelace card client-side, - so this path stays minimal: at most one PIL decode + encode per - slide change. - - Compose work is serialised across all albums via a domain-wide - semaphore so 4 cameras don't all decode + encode at once. - """ - items: list[MediaItem] = self._effective_items() - if not items: - return - - count = len(items) - if advance: - self._do_advance(count, items) - - async with self._compose_semaphore: - composed, meta = await self._compose_for_index(items) - if composed is None: - return + while True: try: - await self._commit_composed(composed, meta) - finally: - ip.safe_close(composed) + if self._timeline_dirty: + async with self._navigation_lock: + if self._timeline_dirty: + await self._rebuild_current_frame() + continue - async def _commit_composed(self, composed: Image.Image, meta: dict) -> None: - """Encode the composed slide into the framebuffer and broadcast. - - Encodes off the loop so the JPEG encode (30-80 ms at 1080p, more - at 4K) doesn't block HA. - """ - encoded = await self.hass.async_add_executor_job( - ip.encode_image, composed - ) - - self._framebuffer = encoded - self.store.last_frame = encoded - self._frame_id += 1 - if meta: - self._last_is_portrait = meta.get("is_portrait") - else: - self._last_is_portrait = None - self._last_captured_at_pair = meta.get("captured_at_pair") if meta else None - self._last_pair_frames = meta.get("pair_frames") if meta else None - self._last_pair_orientation = meta.get("pair_orientation") if meta else None - - self.async_write_ha_state() + interrupted = await self._wait_or_interrupt( + float(int(self.store.slide_interval)) + ) + if not interrupted and not self.store.paused: + async with self._navigation_lock: + if not self._timeline_dirty: + await self._show_next_frame() + self._consecutive_failures = 0 + except asyncio.CancelledError: + raise + except Exception as err: + self._consecutive_failures += 1 + _LOGGER.warning( + "Album Slideshow: buffered navigation/render failed (attempt %d): %s", + self._consecutive_failures, + err, + ) @property def _compose_semaphore(self) -> asyncio.Semaphore: @@ -849,6 +1226,7 @@ class AlbumSlideshowCamera(Camera): return None async def _http_get(self, url: str) -> bytes | None: + """Fetch one remote image with validation and a hard timeout.""" session = async_get_clientsession(self.hass) try: async with async_timeout.timeout(30): diff --git a/custom_components/album_slideshow/config_flow.py b/custom_components/album_slideshow/config_flow.py index 56a95624..5ec5d54e 100644 --- a/custom_components/album_slideshow/config_flow.py +++ b/custom_components/album_slideshow/config_flow.py @@ -1,6 +1,7 @@ from __future__ import annotations import json +import logging import re from typing import Any @@ -116,6 +117,15 @@ def _normalize_local_path(hass, path: str) -> str: ALBUM_URL_RE = re.compile(r"^https?://photos\.app\.goo\.gl/[^/]+/?$") +_LOGGER = logging.getLogger(__name__) + + +def _describe_error(err: BaseException) -> str: + """Render an exception for the log, including an HTTP status when known.""" + status = getattr(err, "status", None) + detail = str(err) or type(err).__name__ + return f"HTTP {status}: {detail}" if status else f"{type(err).__name__}: {detail}" + class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 @@ -318,13 +328,43 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): from . import immich as immich_api client = immich_api.ImmichClient(self.hass, url, key) + albums: list[dict[str, Any]] = [] + people: list[dict[str, Any]] = [] try: await client.async_validate() - albums = await client.async_list_albums() - people = await client.async_list_people() - except Exception: # noqa: BLE001 - any failure means bad URL/key - errors["base"] = "immich_cannot_connect" + except Exception as err: # noqa: BLE001 - any failure means bad URL/key + _LOGGER.warning( + "Immich validation failed for %s: %s", + client.base_url, + _describe_error(err), + ) + errors["base"] = ( + "immich_invalid_auth" + if getattr(err, "status", None) in (401, 403) + else "immich_cannot_connect" + ) else: + # A key with limited permissions can read the server but not + # albums or people; keep going with whatever it can see. + for label, call in ( + ("albums", client.async_list_albums), + ("people", client.async_list_people), + ): + try: + result = await call() + except Exception as err: # noqa: BLE001 + _LOGGER.warning( + "Immich %s listing failed for %s: %s", + label, + client.base_url, + _describe_error(err), + ) + else: + if label == "albums": + albums = result + else: + people = result + self._immich_url = client.base_url self._immich_key = key # id -> name maps for the two multi-select pickers. diff --git a/custom_components/album_slideshow/const.py b/custom_components/album_slideshow/const.py index d6021124..82b91ec7 100644 --- a/custom_components/album_slideshow/const.py +++ b/custom_components/album_slideshow/const.py @@ -254,6 +254,10 @@ DEFAULT_RECURSIVE = True # path. Users with one album and lots of RAM can bump this via the # Image cache size number entity. DEFAULT_IMAGE_CACHE_MB = 75 +# Number of fully rendered slides retained on each side of the current frame. +# Previous/Next can swap these JPEGs immediately without downloading, +# composing, or encoding during the button press. +DEFAULT_NAVIGATION_BUFFER_SIZE = 2 MAX_RESOLUTION_OPTIONS = ["480p", "720p", "1080p", "1440p", "4K (2160p)", "original"] DEFAULT_MAX_RESOLUTION = "1080p" @@ -269,5 +273,6 @@ MAX_RESOLUTION_SHORT_EDGE: dict[str, int | None] = { PUBLICALBUM_ENDPOINT = "https://www.publicalbum.org/api/v2/webapp/embed-player/jsonrpc" SERVICE_NEXT_SLIDE = "next_slide" +SERVICE_PREVIOUS_SLIDE = "previous_slide" SERVICE_REFRESH_ALBUM = "refresh_album" ATTR_ENTRY_ID = "entry_id" diff --git a/custom_components/album_slideshow/google_scraper.py b/custom_components/album_slideshow/google_scraper.py index 58f44623..37a077b7 100644 --- a/custom_components/album_slideshow/google_scraper.py +++ b/custom_components/album_slideshow/google_scraper.py @@ -194,6 +194,8 @@ def _extract_first_page_items(html: str) -> list[MediaItem]: items: list[MediaItem] = [] seen: set[str] = set() for raw in best: + if _is_video_item(raw): + continue item = _parse_album_item(raw) if item is None or item.url in seen: continue @@ -290,12 +292,39 @@ def _parse_batchexecute_album_page(body: str) -> tuple[list[MediaItem], str | No items: list[MediaItem] = [] for raw in raw_items: + if _is_video_item(raw): + continue item = _parse_album_item(raw) if item is not None: items.append(item) return items, next_page +def _is_video_item(raw: Any) -> bool: + """Return ``True`` when an album item carries a video duration. + + Google tags videos with key ``76647426`` (duration in ms) inside a metadata + dict. That dict is usually the item's last element, but its position moves + between responses, so scan every nested container instead of just ``[-1]``. + Live photos carry a duration too and are skipped along with videos, which + is what the photo-only slideshow wants (see #26). + """ + return _contains_key(raw, 0) + + +def _contains_key(node: Any, depth: int) -> bool: + if depth > 6: + return False + if isinstance(node, dict): + for key in node: + if key == _VIDEO_DURATION_KEY or key == str(_VIDEO_DURATION_KEY): + return True + return any(_contains_key(v, depth + 1) for v in node.values()) + if isinstance(node, list): + return any(_contains_key(v, depth + 1) for v in node) + return False + + def _parse_album_item(raw: Any) -> MediaItem | None: """Parse a single album item array. @@ -315,14 +344,6 @@ def _parse_album_item(raw: Any) -> MediaItem | None: width = visual[1] if isinstance(visual[1], int) else None height = visual[2] if isinstance(visual[2], int) else None - # Skip videos: their last element is a dict with key 76647426 (duration). - if raw and isinstance(raw[-1], dict): - if _VIDEO_DURATION_KEY in raw[-1] or "76647426" in raw[-1]: - # Note: live photos also carry a duration but are still images; - # we treat the presence of duration as "video". If a user reports - # missing live photos we can revisit by checking 146008172 too. - return None - captured_at = raw[2] if len(raw) > 2 and _looks_like_timestamp_ms(raw[2]) else None uploaded_at = raw[5] if len(raw) > 5 and _looks_like_timestamp_ms(raw[5]) else None diff --git a/custom_components/album_slideshow/manifest.json b/custom_components/album_slideshow/manifest.json index 25296c31..ac13cf93 100644 --- a/custom_components/album_slideshow/manifest.json +++ b/custom_components/album_slideshow/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "issue_tracker": "https://github.com/eyalgal/album_slideshow/issues", "requirements": ["Pillow"], - "version": "1.7.1" + "version": "1.8.1" } diff --git a/custom_components/album_slideshow/number.py b/custom_components/album_slideshow/number.py index 9fca2db8..e35ed7c7 100644 --- a/custom_components/album_slideshow/number.py +++ b/custom_components/album_slideshow/number.py @@ -20,6 +20,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e SlideIntervalNumber(entry, store), RefreshHoursNumber(entry, store, coordinator), PairDividerWidthNumber(entry, store), + NavigationBufferSizeNumber(entry, store), ImageCacheMbNumber(entry, store), ] ) @@ -143,6 +144,38 @@ class PairDividerWidthNumber(_BaseNumber): return +class NavigationBufferSizeNumber(_BaseNumber): + _attr_icon = "mdi:page-previous-outline" + _attr_native_min_value = 0 + _attr_native_max_value = 10 + _attr_native_step = 1 + + def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: + super().__init__(entry, store) + self._attr_unique_id = f"{entry.entry_id}_navigation_buffer_size" + self._attr_name = "Navigation buffer (slides)" + + @property + def native_value(self): + return int(self.store.navigation_buffer_size) + + async def async_set_native_value(self, value: float) -> None: + self.store.navigation_buffer_size = min(10, max(0, int(value))) + self.store.notify() + + async def async_added_to_hass(self) -> None: + await super().async_added_to_hass() + old = await self.async_get_last_state() + if old and old.state not in (None, "unknown", "unavailable"): + try: + self.store.navigation_buffer_size = min( + 10, max(0, int(float(old.state))) + ) + self.store.notify() + except Exception: + return + + class ImageCacheMbNumber(_BaseNumber): _attr_icon = "mdi:database-outline" _attr_native_min_value = 50 diff --git a/custom_components/album_slideshow/services.yaml b/custom_components/album_slideshow/services.yaml index 8a304a93..7d2bbca9 100644 --- a/custom_components/album_slideshow/services.yaml +++ b/custom_components/album_slideshow/services.yaml @@ -9,6 +9,17 @@ next_slide: selector: text: +previous_slide: + name: Previous slide + description: Go back to the previously shown image for a specific config entry. + fields: + entry_id: + name: Entry ID + description: The config entry id for the album slideshow instance. + required: true + selector: + text: + refresh_album: name: Refresh album description: Refresh the album list for a specific config entry. diff --git a/custom_components/album_slideshow/store.py b/custom_components/album_slideshow/store.py index fa8b5c0c..84e9d075 100644 --- a/custom_components/album_slideshow/store.py +++ b/custom_components/album_slideshow/store.py @@ -13,6 +13,7 @@ from .const import ( DEFAULT_PAIR_DIVIDER_PX, DEFAULT_PAIR_DIVIDER_COLOR, DEFAULT_IMAGE_CACHE_MB, + DEFAULT_NAVIGATION_BUFFER_SIZE, DEFAULT_MAX_RESOLUTION, DEFAULT_DATE_FILTER, DEFAULT_MISSING_DATE_MODE, @@ -33,6 +34,7 @@ class SlideshowStore: pair_divider_px: int = DEFAULT_PAIR_DIVIDER_PX pair_divider_color: str = DEFAULT_PAIR_DIVIDER_COLOR image_cache_mb: int = DEFAULT_IMAGE_CACHE_MB + navigation_buffer_size: int = DEFAULT_NAVIGATION_BUFFER_SIZE max_resolution: str = DEFAULT_MAX_RESOLUTION # Date filter mode (preset windows like this_year / on_this_day). diff --git a/custom_components/album_slideshow/strings.json b/custom_components/album_slideshow/strings.json index a9daf994..836a6681 100644 --- a/custom_components/album_slideshow/strings.json +++ b/custom_components/album_slideshow/strings.json @@ -129,6 +129,7 @@ "invalid_path": "Path is empty or invalid.", "invalid_media_source": "That does not look like a Media Source id (should start with media-source://).", "immich_cannot_connect": "Could not connect to Immich. Check the URL and API key.", + "immich_invalid_auth": "Immich rejected the API key. Check that it is valid and that its permissions include server.about, album.read and person.read.", "immich_no_content": "No albums or named people were found on this Immich server.", "immich_filter_required": "Custom search needs a JSON filter.", "immich_filter_invalid": "The filter must be a valid JSON object. See the README for examples.", diff --git a/custom_components/album_slideshow/translations/en.json b/custom_components/album_slideshow/translations/en.json index a9daf994..836a6681 100644 --- a/custom_components/album_slideshow/translations/en.json +++ b/custom_components/album_slideshow/translations/en.json @@ -129,6 +129,7 @@ "invalid_path": "Path is empty or invalid.", "invalid_media_source": "That does not look like a Media Source id (should start with media-source://).", "immich_cannot_connect": "Could not connect to Immich. Check the URL and API key.", + "immich_invalid_auth": "Immich rejected the API key. Check that it is valid and that its permissions include server.about, album.read and person.read.", "immich_no_content": "No albums or named people were found on this Immich server.", "immich_filter_required": "Custom search needs a JSON filter.", "immich_filter_invalid": "The filter must be a valid JSON object. See the README for examples.", diff --git a/custom_components/album_slideshow/www/album-slideshow-card.js b/custom_components/album_slideshow/www/album-slideshow-card.js index bb1a3ef2..c80ef8c1 100644 --- a/custom_components/album_slideshow/www/album-slideshow-card.js +++ b/custom_components/album_slideshow/www/album-slideshow-card.js @@ -26,7 +26,7 @@ * tap_action: none # none | more-info */ -const VERSION = "1.7.1"; +const VERSION = "1.8.1"; const ANIMATED_TRANSITIONS = [ "fade", @@ -974,6 +974,7 @@ const LIVE_SUFFIX = { slide_interval: "_interval", pair_divider_px: "_pair_divider_px", pair_divider_color: "_pair_divider_color", + previous_button: "_previous_button", next_button: "_next_button", refresh_button: "_refresh_button", }; @@ -1092,7 +1093,9 @@ function createAlbumSlideshowCardEditorClass(Base) { _hasActions() { return !!( this._siblings && - (this._siblings.next_button || this._siblings.refresh_button) + (this._siblings.previous_button || + this._siblings.next_button || + this._siblings.refresh_button) ); } @@ -1543,13 +1546,19 @@ function createAlbumSlideshowCardEditorClass(Base) { wrap.innerHTML = `
Actions
+ ${s.previous_button ? `` : ""} ${s.next_button ? `` : ""} ${s.refresh_button ? `` : ""}
`; + const actionEntities = { + previous: s.previous_button, + next: s.next_button, + refresh: s.refresh_button, + }; wrap.querySelectorAll("button.act").forEach((b) => { b.addEventListener("click", () => { - const id = b.dataset.act === "next" ? s.next_button : s.refresh_button; + const id = actionEntities[b.dataset.act]; if (id && this._hass) { this._hass.callService("button", "press", { entity_id: id }); } diff --git a/www/community/lovelace-multiple-entity-row/multiple-entity-row.js b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js index cd345a3d..5db8d09c 100644 --- a/www/community/lovelace-multiple-entity-row/multiple-entity-row.js +++ b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js @@ -1,2 +1,2 @@ /*! For license information please see multiple-entity-row.js.LICENSE.txt */ -(()=>{"use strict";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,n=Symbol(),i=new WeakMap;class r{constructor(t,e,i){if(this._$cssResult$=!0,i!==n)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const n=this.t;if(e&&void 0===t){const e=void 0!==n&&1===n.length;e&&(t=i.get(n)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&i.set(n,t))}return t}toString(){return this.cssText}}const o=(t,...e)=>{const i=1===t.length?t[0]:e.reduce((e,n,i)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+t[i+1],t[0]);return new r(i,t,n)},a=(n,i)=>{if(e)n.adoptedStyleSheets=i.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of i){const i=document.createElement("style"),r=t.litNonce;void 0!==r&&i.setAttribute("nonce",r),i.textContent=e.cssText,n.appendChild(i)}},s=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const n of t.cssRules)e+=n.cssText;return(t=>new r("string"==typeof t?t:t+"",void 0,n))(e)})(t):t,{is:c,defineProperty:l,getOwnPropertyDescriptor:u,getOwnPropertyNames:f,getOwnPropertySymbols:d,getPrototypeOf:h}=Object,p=globalThis,m=p.trustedTypes,y=m?m.emptyScript:"",v=p.reactiveElementPolyfillSupport,b=(t,e)=>t,g={toAttribute(t,e){switch(e){case Boolean:t=t?y:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let n=t;switch(e){case Boolean:n=null!==t;break;case Number:n=null===t?null:Number(t);break;case Object:case Array:try{n=JSON.parse(t)}catch(t){n=null}}return n}},_=(t,e)=>!c(t,e),w={attribute:!0,type:String,converter:g,reflect:!1,useDefault:!1,hasChanged:_};Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;class A extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=w){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(t,n,e);void 0!==i&&l(this.prototype,t,i)}}static getPropertyDescriptor(t,e,n){const{get:i,set:r}=u(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:i,set(e){const o=i?.call(this);r?.call(this,e),this.requestUpdate(t,o,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??w}static _$Ei(){if(this.hasOwnProperty(b("elementProperties")))return;const t=h(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(b("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(b("properties"))){const t=this.properties,e=[...f(t),...d(t)];for(const n of e)this.createProperty(n,t[n])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,n]of e)this.elementProperties.set(t,n)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const n=this._$Eu(t,e);void 0!==n&&this._$Eh.set(n,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const n=new Set(t.flat(1/0).reverse());for(const t of n)e.unshift(s(t))}else void 0!==t&&e.push(s(t));return e}static _$Eu(t,e){const n=e.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const n of e.keys())this.hasOwnProperty(n)&&(t.set(n,this[n]),delete this[n]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return a(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,n){this._$AK(t,n)}_$ET(t,e){const n=this.constructor.elementProperties.get(t),i=this.constructor._$Eu(t,n);if(void 0!==i&&!0===n.reflect){const r=(void 0!==n.converter?.toAttribute?n.converter:g).toAttribute(e,n.type);this._$Em=t,null==r?this.removeAttribute(i):this.setAttribute(i,r),this._$Em=null}}_$AK(t,e){const n=this.constructor,i=n._$Eh.get(t);if(void 0!==i&&this._$Em!==i){const t=n.getPropertyOptions(i),r="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:g;this._$Em=i;const o=r.fromAttribute(e,t.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(t,e,n,i=!1,r){if(void 0!==t){const o=this.constructor;if(!1===i&&(r=this[t]),n??=o.getPropertyOptions(t),!((n.hasChanged??_)(r,e)||n.useDefault&&n.reflect&&r===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,n))))return;this.C(t,e,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:n,reflect:i,wrapped:r},o){n&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,o??e??this[t]),!0!==r||void 0!==o)||(this._$AL.has(t)||(this.hasUpdated||n||(e=void 0),this._$AL.set(t,e)),!0===i&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,n]of t){const{wrapped:t}=n,i=this[e];!0!==t||this._$AL.has(e)||void 0===i||this.C(e,void 0,n,i)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}}A.elementStyles=[],A.shadowRootOptions={mode:"open"},A[b("elementProperties")]=new Map,A[b("finalized")]=new Map,v?.({ReactiveElement:A}),(p.reactiveElementVersions??=[]).push("2.1.2");const O=globalThis,S=t=>t,$=O.trustedTypes,j=$?$.createPolicy("lit-html",{createHTML:t=>t}):void 0,x="$lit$",k=`lit$${Math.random().toFixed(9).slice(2)}$`,E="?"+k,C=`<${E}>`,P=document,T=()=>P.createComment(""),M=t=>null===t||"object"!=typeof t&&"function"!=typeof t,I=Array.isArray,H=t=>I(t)||"function"==typeof t?.[Symbol.iterator],D="[ \t\n\f\r]",R=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,F=/-->/g,N=/>/g,U=RegExp(`>|${D}(?:([^\\s"'>=/]+)(${D}*=${D}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,V=/"/g,z=/^(?:script|style|textarea|title)$/i,B=t=>(e,...n)=>({_$litType$:t,strings:e,values:n}),W=B(1),q=(B(2),B(3),Symbol.for("lit-noChange")),Z=Symbol.for("lit-nothing"),J=new WeakMap,G=P.createTreeWalker(P,129);function K(t,e){if(!I(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==j?j.createHTML(e):e}const Y=(t,e)=>{const n=t.length-1,i=[];let r,o=2===e?"":3===e?"":"",a=R;for(let e=0;e"===c[0]?(a=r??R,l=-1):void 0===c[1]?l=-2:(l=a.lastIndex-c[2].length,s=c[1],a=void 0===c[3]?U:'"'===c[3]?V:L):a===V||a===L?a=U:a===F||a===N?a=R:(a=U,r=void 0);const f=a===U&&t[e+1].startsWith("/>")?" ":"";o+=a===R?n+C:l>=0?(i.push(s),n.slice(0,l)+x+n.slice(l)+k+f):n+k+(-2===l?e:f)}return[K(t,o+(t[n]||"")+(2===e?"":3===e?"":"")),i]};class Q{constructor({strings:t,_$litType$:e},n){let i;this.parts=[];let r=0,o=0;const a=t.length-1,s=this.parts,[c,l]=Y(t,e);if(this.el=Q.createElement(c,n),G.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(i=G.nextNode())&&s.length0){i.textContent=$?$.emptyScript:"";for(let n=0;n2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=Z}_$AI(t,e=this,n,i){const r=this.strings;let o=!1;if(void 0===r)t=X(this,t,e,0),o=!M(t)||t!==this._$AH&&t!==q,o&&(this._$AH=t);else{const i=t;let a,s;for(t=r[0],a=0;a{const i=n?.renderBefore??e;let r=i._$litPart$;if(void 0===r){const t=n?.renderBefore??null;i._$litPart$=r=new et(e.insertBefore(T(),t),t,void 0,n??{})}return r._$AI(t),r})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return q}}ut._$litElement$=!0,ut.finalized=!0,lt.litElementHydrateSupport?.({LitElement:ut});const ft=lt.litElementPolyfillSupport;ft?.({LitElement:ut}),(lt.litElementVersions??=[]).push("4.2.2");var dt=["unavailable","unknown"],ht="last-changed",pt="last-updated",mt=["relative","total","date","time","datetime"],yt=["entity-id","last-changed","last-updated","last-triggered","position","tilt-position","brightness"];function vt(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||bt(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function bt(t,e){if(t){if("string"==typeof t)return gt(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?gt(t,e):void 0}}function gt(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);n=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,a=!1;return{s:function(){e=e.call(t)},n:function(){var t=e.next();return o=t.done,t},e:function(t){a=!0,r=t},f:function(){try{o||null==e.return||e.return()}finally{if(a)throw r}}}}(wt);try{for(i.s();!(e=i.n()).done;){var r=vt(e.value,2),o=r[0],a=r[1];if(customElements.get(o))wt.delete(o);else try{customElements.define(o,a),n.push(o),wt.delete(o)}catch(t){console.warn("multiple-entity-row: re-defining ".concat(o," after registry swap failed"),t)}}}catch(t){i.e(t)}finally{i.f()}n.length&&console.info("multiple-entity-row: re-defined ".concat(n.join(", ")," after customElements registry swap, caught by ").concat(t," (frontend#52960)"))}catch(t){console.warn("multiple-entity-row: customElements registry check failed",t)}},$t=function(){wt.size&&(At>=30?wt.clear():(At+=1,setTimeout(function(){St("fallback poll"),$t()},1e3)))},jt=function(t,e){try{if(_t.get(t))return void console.warn("multiple-entity-row: ".concat(t," is already defined - a duplicate resource entry or stale cached copy loaded first"));_t.define(t,e)}catch(e){return void console.warn("multiple-entity-row: defining ".concat(t," failed"),e)}wt.set(t,e),Ot||(Ot=!0,_t.whenDefined("home-assistant").then(function(){return St("ha-boot signal")}).catch(function(){}),$t())},xt=new Set(["primary","accent","red","pink","purple","deep-purple","indigo","blue","light-blue","cyan","teal","green","light-green","lime","yellow","amber","orange","deep-orange","brown","light-grey","grey","dark-grey","blue-grey","black","white","primary-text","secondary-text","disabled"]),kt=function(t){return xt.has(t)?"var(--".concat(t,"-color)"):t},Et=function(t){var e,n=null!==(e=t.color)&&void 0!==e?e:void 0===t.state_color?void 0:t.state_color?"state":"none";return void 0===n?t.icon_color?{stateColor:!1}:{stateColor:!0}:"state"===n?{stateColor:!0}:"none"===n?{stateColor:!1}:{cssColor:kt(n)}},Ct=function(t){return t<10?"0".concat(t):t};function Pt(t){var e=Math.floor(t/3600),n=Math.floor(t%3600/60),i=Math.floor(t%3600%60);return e>0?"".concat(e,":").concat(Ct(n),":").concat(Ct(i)):n>0?"".concat(n,":").concat(Ct(i)):i>0?""+i:null}function Tt(t){return Tt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Tt(t)}function Mt(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function It(t,e,n){return(e=function(t){var e=function(t){if("object"!=Tt(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var n=e.call(t,"string");if("object"!=Tt(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==Tt(e)?e:e+""}(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var Ht=function(t,e,n){var i=e?function(t){switch(t.number_format){case"comma_decimal":return["en-US","en"];case"decimal_comma":return["de","es","it"];case"space_comma":return["fr","sv","cs"];case"system":return;default:return t.language}}(e):void 0;if(Number.isNaN=Number.isNaN||function t(e){return"number"==typeof e&&t(e)},"none"!==(null==e?void 0:e.number_format)&&!Number.isNaN(Number(t))&&Intl)try{return new Intl.NumberFormat(i,Dt(t,n)).format(Number(t))}catch(e){return console.error(e),new Intl.NumberFormat(void 0,Dt(t,n)).format(Number(t))}return"string"==typeof t?t:"".concat(function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:2;return Math.round(t*Math.pow(10,e))/Math.pow(10,e)}(t,null==n?void 0:n.maximumFractionDigits).toString()).concat("currency"===(null==n?void 0:n.style)?" ".concat(n.currency):"")},Dt=function(t,e){var n=function(t){for(var e=1;e-1?t.split(".")[1].length:0;n.minimumFractionDigits=i,n.maximumFractionDigits=i}return n};function Rt(t){return Rt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Rt(t)}var Ft=function(t){return"object"===Rt(t)&&!Array.isArray(t)&&!!t},Nt=function(t,e,n){var i=new Event(e,{bubbles:!0,composed:!0});i.detail=n,t.dispatchEvent(i)},Ut=function(t){return!t||dt.includes(t.state)},Lt=function(t,e,n){if(function(t,e){return e.hide_unavailable&&(Ut(t)||e.attribute&&![ht,pt].includes(e.attribute)&&void 0===t.attributes[e.attribute])}(t,e))return!0;if(void 0===e.hide_if)return!1;if("boolean"==typeof e.hide_if)return e.hide_if;var i;if(Ft(e.hide_if)&&(e.hide_if.entity||e.hide_if.attribute)){var r=e.hide_if.entity?null==n?void 0:n.states[e.hide_if.entity]:t;i=e.hide_if.attribute?null==r?void 0:r.attributes[e.hide_if.attribute]:null==r?void 0:r.state}else i=e.attribute?t.attributes[e.attribute]:t.state;var o=[];if(Ft(e.hide_if)){if(e.hide_if.below&&ie.hide_if.above)return!0;e.hide_if.value&&(o=o.concat(e.hide_if.value))}else o=o.concat(e.hide_if);return o.some(function(t){return"number"==typeof t?t===+i:t===i})},Vt=["formatEntityName","formatEntityState","formatEntityAttributeValue"];function zt(t){return zt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},zt(t)}function Bt(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function Wt(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,i=Array(e);n1&&a.every(function(t){return te.test(t)})){var s=r??0;return!isNaN(parseFloat(s))&&isFinite(s)?function(t,e,n,i){var r,o,a=parseFloat(e),s=Kt(e),c=!1,l=function(t){c||(s=void 0,r=t)},u=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!e){if(Array.isArray(t)||(e=Zt(t))){e&&(t=e);var n=0,i=function(){};return{s:i,n:function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,a=!1;return{s:function(){e=e.call(t)},n:function(){var t=e.next();return o=t.done,t},e:function(t){a=!0,r=t},f:function(){try{o||null==e.return||e.return()}finally{if(a)throw r}}}}(t);try{for(u.s();!(o=u.n()).done;){var f=o.value,d=Qt.exec(f);if(d&&"precision"===d[1])s=parseInt(d[2],10),r=void 0,c=!0;else if(d)a/={kilo:1e3,mega:1e6,milli:.001}[d[1]],void 0!==d[2]?(s=parseInt(d[2],10),r=void 0,c=!0):l(2);else switch(f){case"brightness":a=Math.round(a/255*100),n="%",l(0);break;case"percent":a*=100,n="%",l(2);break;case"invert":a=-a;break;case"position":a=100-a;break;case"celsius_to_fahrenheit":a=1.8*a+32,l(0);break;case"fahrenheit_to_celsius":a=5*(a-32)/9,l(1)}}}catch(t){u.e(t)}finally{u.f()}return"".concat(Ht(a,i,void 0!==s?{minimumFractionDigits:s,maximumFractionDigits:s}:void 0!==r?{maximumFractionDigits:r}:void 0)).concat(n?" ".concat(n):"")}(a,s,o,t.locale):"".concat(s).concat(o?" ".concat(o):"")}if(n.format&&!function(t){return Yt.some(function(e){return null==t?void 0:t.startsWith(e)})&&!Xt(t)}(n.format)){if(null==r&&(r=ee.includes(n.format)?"":0),ee.includes(n.format))return"".concat(function(t,e){switch(t){case"upper":return e.toUpperCase();case"lower":return e.toLowerCase();case"capitalize":return e.charAt(0).toUpperCase()+e.slice(1);case"title":return e.split(/(\s+)/).map(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}).join("")}}(n.format,String(r))).concat(o?" ".concat(o):"");if(isNaN(parseFloat(r))||!isFinite(r));else if("brightness"===n.format)r=Math.round(r/255*100),o="%";else if("percent"===n.format)r=Ht(100*r,t.locale,{maximumFractionDigits:2}),o="%";else if("duration"===n.format){var c;r=null!==(c=Pt(r))&&void 0!==c?c:"0",o=void 0}else if("duration-m"===n.format){var l;r=null!==(l=Pt(r/1e3))&&void 0!==l?l:"0",o=void 0}else if("duration-h"===n.format){var u;r=null!==(u=Pt(3600*r))&&void 0!==u?u:"0",o=void 0}else if(Xt(n.format)){var f=function(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||Zt(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}(Xt(n.format),3),d=f[1],h=f[2];if("precision"===d){var p=parseInt(h,10);r=Ht(parseFloat(r),t.locale,{minimumFractionDigits:p,maximumFractionDigits:p})}else r=function(t,e,n,i){if(void 0===n)return Ht(t/e,i,{maximumFractionDigits:2});var r=parseInt(n,10);return Ht(t/e,i,{minimumFractionDigits:r,maximumFractionDigits:r})}(r,{kilo:1e3,mega:1e6,milli:.001}[d],h,t.locale)}else if("invert"===n.format){var m=Kt(r);r=Ht(r-2*r,t.locale,void 0!==m?{minimumFractionDigits:m,maximumFractionDigits:m}:void 0)}else if("position"===n.format){var y=Kt(r);r=Ht(100-r,t.locale,void 0!==y?{minimumFractionDigits:y,maximumFractionDigits:y}:void 0)}else"celsius_to_fahrenheit"===n.format?r=Ht(1.8*r+32,t.locale,{maximumFractionDigits:0}):"fahrenheit_to_celsius"===n.format&&(r=Ht(5*(r-32)/9,t.locale,{maximumFractionDigits:1}));return"".concat(r).concat(o?" ".concat(o):"")}var v=Wt(Wt({},e),{},{attributes:Wt(Wt({},e.attributes),{},{unit_of_measurement:o})});if(void 0!==n.unit&&!n.attribute){if(!isNaN(parseFloat(r))&&isFinite(r)){var b,g=null===(b=t.entities)||void 0===b||null===(b=b[e.entity_id])||void 0===b?void 0:b.display_precision,_=Ht(r,t.locale,null!=g?{minimumFractionDigits:g,maximumFractionDigits:g}:void 0);return"".concat(_).concat(o?" ".concat(o):"")}return"".concat(t.formatEntityState(e)).concat(o?" ".concat(o):"")}if(n.attribute){if(void 0!==n.unit){var w=null==r?"":isNaN(r)?r:Ht(r,t.locale);return"".concat(w).concat(o?" ".concat(o):"")}return oe(t.formatEntityAttributeValue(v,n.attribute))}return oe(t.formatEntityState(v))},se=function(t){return Ft(null==t?void 0:t.styles)?Object.keys(t.styles).map(function(e){return"".concat(e,": ").concat(t.styles[e],";")}).join(""):""};function ce(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=me(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var i=0,r=function(){};return{s:r,n:function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function le(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,i=Array(e);n2&&void 0!==arguments[2]?arguments[2]:"";ge(t)&&n.push({template:i+t,entity:e})},r=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";i(t.name,e,n),i(t.icon,e,n),i(t.icon_color,e,n),i(t.color,e,n),i(t.template,e,n),i(we(t),e,n),xe.forEach(function(r){return ke(t[r],function(t){return i(t,e,n)})})},o=t.entity;if(r(t,o,je(Ee(t))),"string"==typeof t.secondary_info)i(t.secondary_info,o,je(Ee(t)));else if(Ft(t.secondary_info)){var a,s=t.secondary_info;r(s,null!==(a=s.entity)&&void 0!==a?a:o,je(Ee(t,s)))}return null===(e=t.entities)||void 0===e||e.forEach(function(e){if(Ft(e)){var n,i=e;r(i,null!==(n=i.entity)&&void 0!==n?n:o,je(Ee(t,i)))}}),n}(t).map(function(t){return[Se(t.template,t.entity),t]})),this.sync()}},{key:"setHass",value:function(t){var e,n=!(null===(e=this.hass)||void 0===e||!e.connection);this.hass=t,!n&&null!=t&&t.connection&&this.sync()}},{key:"connect",value:function(){this.connected=!0,this.sync()}},{key:"disconnect",value:function(){this.connected=!1,this.sync()}},{key:"sync",value:function(){var t,e,n=ce(this.unsubs);try{for(n.s();!(e=n.n()).done;){var i=pe(e.value,2),r=i[0],o=i[1];this.connected&&this.requests.has(r)||(this.unsubs.delete(r),this.requests.has(r)||(this.results.delete(r),this.errors.delete(r)),o.then(function(t){return null==t?void 0:t()}).catch(function(){}))}}catch(t){n.e(t)}finally{n.f()}if(this.connected&&null!==(t=this.hass)&&void 0!==t&&t.connection){var a,s=ce(this.requests);try{for(s.s();!(a=s.n()).done;){var c=pe(a.value,2),l=c[0],u=c[1];this.unsubs.has(l)||this.unsubs.set(l,this.subscribe(l,u))}}catch(t){s.e(t)}finally{s.f()}}}},{key:"subscribe",value:function(t,e){var n=this;return this.hass.connection.subscribeMessage(function(e){return n.onMessage(t,e)},{type:"render_template",template:e.template,variables:{entity:e.entity},report_errors:!0}).catch(function(t){return console.warn("multiple-entity-row: template subscription failed:",e.template,t),null})}},{key:"onMessage",value:function(t,e){this.unsubs.has(t)&&(void 0!==e.error?(this.errors.get(t)!==e.error&&(this.errors.set(t,e.error),console.warn("multiple-entity-row: template error:",e.error)),this.results.set(t,"")):(this.errors.delete(t),this.results.set(t,e.result)),this.notify(new Map(this.results)))}}])}();class Te{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,n){this._$Ct=t,this._$AM=e,this._$Ci=n}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}}const{I:Me}=st,Ie={},He=(t=>(...e)=>({_$litDirective$:t,values:e}))(class extends Te{constructor(){super(...arguments),this.key=Z}render(t,e){return this.key=t,e}update(t,[e,n]){return e!==this.key&&(((t,e=Ie)=>{t._$AH=e})(t),this.key=e),n}});var De,Re,Fe,Ne,Ue,Le,Ve,ze,Be,We,qe,Ze,Je,Ge,Ke,Ye,Qe,Xe="__custom__",tn=[{value:"",label:"No format"},{value:"brightness",label:"Brightness (0-255 → %)"},{value:"percent",label:"Percent (value × 100 → x %)"},{value:"duration",label:"Duration (seconds → h:mm:ss)"},{value:"duration-m",label:"Duration (milliseconds)"},{value:"duration-h",label:"Duration (hours)"},{value:"precision0",label:"Precision 0 decimals"},{value:"precision1",label:"Precision 1 decimal"},{value:"precision2",label:"Precision 2 decimals"},{value:"precision3",label:"Precision 3 decimals"},{value:"kilo",label:"Kilo (value / 1,000)"},{value:"mega",label:"Mega (value / 1,000,000)"},{value:"milli",label:"Milli (value × 1,000)"},{value:"invert",label:"Invert (value × -1)"},{value:"position",label:"Position (100 - value)"},{value:"celsius_to_fahrenheit",label:"°C → °F"},{value:"fahrenheit_to_celsius",label:"°F → °C"},{value:"upper",label:"Text: UPPERCASE"},{value:"lower",label:"Text: lowercase"},{value:"capitalize",label:"Text: Capitalize first letter"},{value:"title",label:"Text: Title Case"},{value:"relative",label:"Timestamp: relative"},{value:"total",label:"Timestamp: total"},{value:"date",label:"Timestamp: date"},{value:"time",label:"Timestamp: time"},{value:"datetime",label:"Timestamp: date + time"},{value:Xe,label:"Custom…"}],en=new Set(tn.map(function(t){return t.value}).filter(function(t){return t&&t!==Xe})),nn=[{name:"entity",required:!0,selector:{entity:{}}},{type:"grid",schema:[{name:"name",selector:{text:{}}},{name:"attribute",selector:{text:{}}}]},{type:"grid",schema:[{name:"unit",selector:{text:{}}},{name:"icon",selector:{icon:{}}}]},{name:"icon_color",selector:{text:{}}},{type:"grid",schema:[{name:"show_state",default:!0,selector:{boolean:{}}},{name:"color",selector:{ui_color:{include_state:!0,include_none:!0}}}]},{type:"grid",schema:[{name:"toggle",selector:{boolean:{}}},{name:"column",selector:{boolean:{}}}]},{type:"grid",schema:[{name:"show_state_first",selector:{boolean:{}}},{name:"hide_unavailable",selector:{boolean:{}}},{name:"wrap",selector:{boolean:{}}}]},{name:"state_header",selector:{text:{}}},{name:"image",selector:{text:{}}},{name:"format",selector:{select:{mode:"dropdown",options:tn}}}],rn=[{name:"tap_action",selector:{ui_action:{default_action:"more-info"}}},{name:"hold_action",selector:{ui_action:{default_action:"none"}}},{name:"double_tap_action",selector:{ui_action:{default_action:"none"}}}],on=[{name:"entity",selector:{entity:{}}},{type:"grid",schema:[{name:"name",selector:{text:{}}},{name:"attribute",selector:{text:{}}}]},{type:"grid",schema:[{name:"unit",selector:{text:{}}},{name:"icon",selector:{icon:{}}}]},{name:"icon_color",selector:{text:{}}},{type:"grid",schema:[{name:"color",selector:{ui_color:{include_state:!0,include_none:!0}}},{name:"toggle",selector:{boolean:{}}}]},{name:"hide_unavailable",selector:{boolean:{}}},{name:"format",selector:{select:{mode:"dropdown",options:tn}}}],an={entity:"Entity",attribute:"Attribute",name:"Name override (or false to hide)",unit:"Unit (or false to hide)",icon:"Icon",icon_color:"Icon color (CSS value, e.g. red, #ff0000, var(--my-color))",image:"Image URL",format:"Format",show_state:"Show main entity state",show_state_first:"State before entities",state_header:"State header label",color:"Icon color",state_color:"State color",column:"Column layout",wrap:"Wrap instead of overflowing",toggle:"Show as toggle",hide_unavailable:"Hide if unavailable",tap_action:"Tap action",hold_action:"Hold action",double_tap_action:"Double-tap action"};function sn(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}function cn(t){return function(t){if(Array.isArray(t))return _n(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||gn(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function ln(t,e){for(var n=0;n=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function bn(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||gn(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function gn(t,e){if(t){if("string"==typeof t)return _n(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_n(t,e):void 0}}function _n(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);ni.length&&(t._selectedTab=i.length),t._keys.clear(),t._updateConfig({entities:i.length?i:void 0})}}),mn(t,"_moveAdditional",function(e,n){var i;if(t._config){var r=cn(null!==(i=t._config.entities)&&void 0!==i?i:[]),o=e+n;if(!(o<0||o>=r.length)){var a=[r[o],r[e]];r[e]=a[0],r[o]=a[1],t._selectedTab=o+1,t._keys.clear(),t._updateConfig({entities:r})}}}),mn(t,"_copyAdditional",function(e){var n,i=null===(n=t._config)||void 0===n||null===(n=n.entities)||void 0===n?void 0:n[e];null!=i&&t._writeClipboard("string"==typeof i?{entity:i}:pn({},i))}),mn(t,"_cutAdditional",function(e){t._copyAdditional(e),t._deleteAdditional(e)}),mn(t,"_copyMainAsTemplate",function(){if(t._config){var e,n={},i=vn(Hn);try{for(i.s();!(e=i.n()).done;){var r=e.value,o=t._config[r];void 0!==o&&(n[r]=o)}}catch(t){i.e(t)}finally{i.f()}t._writeClipboard(n)}}),mn(t,"_pasteEntity",function(){var e;if(t._config){var n=t._readClipboard();if(n){var i=[].concat(cn(null!==(e=t._config.entities)&&void 0!==e?e:[]),[n]);t._selectedTab=i.length,t._keys.clear(),t._updateConfig({entities:i})}}}),mn(t,"_secondaryModeChanged",function(e){if(t._config){var n=e.detail.value.mode;if(n!==t._secondaryInfoMode()){var i;switch(n){case"none":i=void 0;break;case"text":i="";break;case"generic":i="last-changed";break;case"entity":i={entity:t._config.entity}}t._updateConfig({secondary_info:i})}}}),mn(t,"_secondaryTextChanged",function(e){t._updateConfig({secondary_info:e.detail.value.text})}),mn(t,"_secondaryTokenChanged",function(e){t._updateConfig({secondary_info:e.detail.value.token})}),mn(t,"_secondaryEntityChanged",function(e){var n,i=Ft(null===(n=t._config)||void 0===n?void 0:n.secondary_info)?t._config.secondary_info.format:void 0;t._updateConfig({secondary_info:t._formatFromForm("secondary",Mn(e.detail.value),i)})}),t._selectedTab=0,t._entitiesExpanded=!0,t._stateIconRowsMain=[],t._stateIconRowsAdditional=new Map,t._customFormatScopes=new Set,t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&dn(t,e)}(e,t),function(t,e,n){return e&&ln(t.prototype,e),n&&ln(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t}(e,[{key:"setConfig",value:function(t){var e,n,i,r=this;if(_e(t))throw new Error("This row uses templates - edit it in the code (YAML) editor.");this._config=t;var o,a=null!==(e=null===(n=t.entities)||void 0===n?void 0:n.length)&&void 0!==e?e:0;this._selectedTab>a&&(this._selectedTab=a),this._clipboardEntity=this._readClipboard(),this._stateIconRowsMatch(this._stateIconRowsMain,t.state_icon)||(this._stateIconRowsMain=Object.entries(null!==(o=t.state_icon)&&void 0!==o?o:{}));var s=new Map;null===(i=t.entities)||void 0===i||i.forEach(function(t,e){var n=Ft(t)?t.state_icon:void 0,i=r._stateIconRowsAdditional.get(e);i&&r._stateIconRowsMatch(i,n)?s.set(e,i):n&&s.set(e,Object.entries(n))}),this._stateIconRowsAdditional=s}},{key:"_stateIconRowsMatch",value:function(t,e){var n,i={},r=vn(t);try{for(r.s();!(n=r.n()).done;){var o=bn(n.value,2),a=o[0],s=o[1];a.trim()&&s.trim()&&(i[a.trim()]=s.trim())}}catch(t){r.e(t)}finally{r.f()}var c=null!=e?e:{},l=Object.keys(i);return l.length===Object.keys(c).length&&l.every(function(t){return i[t]===c[t]})}},{key:"_readClipboard",value:function(){try{var t=sessionStorage.getItem(In);if(!t)return;var e=JSON.parse(t);if(e&&"object"===wn(e))return e}catch(t){}}},{key:"_writeClipboard",value:function(t){try{sessionStorage.setItem(In,JSON.stringify(t)),this._clipboardEntity=t}catch(t){}}},{key:"_hasNativeTabs",get:function(){return!!customElements.get("ha-tab-group")&&!!customElements.get("ha-tab-group-tab")}},{key:"render",value:function(){return this.hass&&this._config?W(De||(De=sn(["\n \n ",'\n \n\n \n "])),"Entities",this._entitiesExpanded,this._onEntitiesExpandedChanged,this._renderEntitiesPanel(),"4.10.2","2026-08-16T17:39:39.571Z"):Z}},{key:"_isCustomFormat",value:function(t,e){return this._customFormatScopes.has(t)||!!e&&!en.has(e)}},{key:"_setCustomFormatScope",value:function(t,e){if(e!==this._customFormatScopes.has(t)){var n=new Set(this._customFormatScopes);e?n.add(t):n.delete(t),this._customFormatScopes=n}}},{key:"_formatToForm",value:function(t,e){return this._isCustomFormat(t,e.format)?pn(pn({},e),{},{format:Xe}):e}},{key:"_formatFromForm",value:function(t,e,n){if(e.format===Xe){this._setCustomFormatScope(t,!0);var i=pn({},e);return void 0!==n?i.format=n:delete i.format,i}return this._setCustomFormatScope(t,!1),e}},{key:"_renderCustomFormatField",value:function(t,e,n){return this._isCustomFormat(t,e)?W(Re||(Re=sn(["\n \n "])),this.hass,{custom_format:null!=e?e:""},[{name:"custom_format",selector:{text:{}}}],function(){return"Custom format (e.g. invert, precision3)"},function(t){var e,i=(null!==(e=t.detail.value.custom_format)&&void 0!==e?e:"").trim();n(i||void 0)}):Z}},{key:"_keyFor",value:function(t){return this._keys.has(t)||this._keys.set(t,"".concat(t,"-").concat(Math.random().toString(36).slice(2,10))),this._keys.get(t)}},{key:"_renderEntitiesPanel",value:function(){var t,e,n=this,i=null!==(t=null===(e=this._config)||void 0===e?void 0:e.entities)&&void 0!==t?t:[],r=Math.min(this._selectedTab,i.length);return W(Fe||(Fe=sn(['\n
\n
\n ','\n \n
\n\n
\n ',"\n
\n
\n "])),this._hasNativeTabs?W(Ne||(Ne=sn(['\n \n \n \n \n \n
\n
\n \n \n ','\n \n ','\n \n ',"\n \n "])),"Copy main as template",On,this._copyMainAsTemplate,"Paste as new entity",Sn,!this._clipboardEntity,this._pasteEntity,this.hass,this._mainFormData(),nn,this._computeLabel,this._mainValueChanged,this._renderCustomFormatField("main",null===(t=this._config)||void 0===t?void 0:t.format,function(t){return n._updateConfig({format:t})}),this.hass,this._mainFormData(),rn,this._computeLabel,this._mainValueChanged,this._renderSecondaryInfoBlock(),this._renderStateIconRows("main"),this._renderStylesBlock(null===(e=this._config)||void 0===e?void 0:e.styles,function(t){return n._mainStylesChanged(t)}))}},{key:"_renderStylesBlock",value:function(t,e){return W(Be||(Be=sn(['\n \n ','\n \n \n \n \n
\n
\n \n \n ','\n \n ',"\n \n "])),"Move before","M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z",0===t,function(){return i._moveAdditional(t,-1)},"Move after","M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z",t===a,function(){return i._moveAdditional(t,1)},"Copy entity",On,function(){return i._copyAdditional(t)},"Cut entity","M19,3L13,9L15,11L22,4V3M12,12.5A0.5,0.5 0 0,1 11.5,12A0.5,0.5 0 0,1 12,11.5A0.5,0.5 0 0,1 12.5,12A0.5,0.5 0 0,1 12,12.5M6,20A2,2 0 0,1 4,18C4,16.89 4.9,16 6,16A2,2 0 0,1 8,18C8,19.11 7.1,20 6,20M6,8A2,2 0 0,1 4,6C4,4.89 4.9,4 6,4A2,2 0 0,1 8,6C8,7.11 7.1,8 6,8M9.64,7.64C9.87,7.14 10,6.59 10,6A4,4 0 0,0 6,2A4,4 0 0,0 2,6A4,4 0 0,0 6,10C6.59,10 7.14,9.87 7.64,9.64L10,12L7.64,14.36C7.14,14.13 6.59,14 6,14A4,4 0 0,0 2,18A4,4 0 0,0 6,22A4,4 0 0,0 10,18C10,17.41 9.87,16.86 9.64,16.36L12,14L19,21H22V20L9.64,7.64Z",function(){return i._cutAdditional(t)},"Paste from clipboard",Sn,!this._clipboardEntity,this._pasteEntity,"Delete entity",An,function(){return i._deleteAdditional(t)},this.hass,this._formatToForm("sub-".concat(t),Tn(o)),on,this._computeLabel,function(e){return i._additionalValueChanged(e,t)},this._renderCustomFormatField("sub-".concat(t),o.format,function(e){return i._setAdditionalFormat(t,e)}),this.hass,this._formatToForm("sub-".concat(t),Tn(o)),rn,this._computeLabel,function(e){return i._additionalValueChanged(e,t)},this._renderStateIconRows(t),this._renderStylesBlock(o.styles,function(e){return i._additionalStylesChanged(e,t)}))}},{key:"_mainFormData",value:function(){return this._formatToForm("main",Tn(pn({show_state:!0},this._config)))}},{key:"_setAdditionalFormat",value:function(t,e){var n;if(this._config){var i=cn(null!==(n=this._config.entities)&&void 0!==n?n:[]),r=i[t],o="string"==typeof r?{entity:r}:pn({},r);e?o.format=e:delete o.format,i[t]=o,this._updateConfig({entities:i})}}},{key:"_secondaryInfoMode",value:function(){var t,e=null===(t=this._config)||void 0===t?void 0:t.secondary_info;return null==e?"none":"object"===wn(e)?"entity":yt.includes(e)?"generic":"text"}},{key:"_renderSecondaryInfoBlock",value:function(){var t,e=this,n=this._secondaryInfoMode(),i=null===(t=this._config)||void 0===t?void 0:t.secondary_info;return W(Je||(Je=sn(["\n
\n \n ","\n ","\n ","\n
\n "])),this.hass,{mode:n},$n,function(){return"Mode"},this._secondaryModeChanged,"text"===n?W(Ge||(Ge=sn(['
\n \n \n \n \n ',"\n
\n "])),ne(i.icon_color),this._hass,o,this.renderSecondaryInfo(),a,!1,[this.config.column?"entities-column":"entities-row",!this.config.column&&this.config.wrap?"wrap":"",null!==(t=ki[this.config.align])&&void 0!==t?t:"",a?"no-name":""].filter(Boolean).join(" "),this.config.show_state_first?W(Yn||(Yn=mi(["","",""])),this.renderMainEntity(),this.entities.map(function(t,n){return e.renderEntity(t.stateObj,t,n)})):W(Qn||(Qn=mi(["","",""])),this.entities.map(function(t,n){return e.renderEntity(t.stateObj,t,n)}),this.renderMainEntity()))}},{key:"renderSecondaryInfo",value:function(){var t=this.config.secondary_info;if(!t||function(t){return"string"==typeof t&&yt.includes(t)}(t))return null;if("string"==typeof t)return W(Xn||(Xn=mi(["",""])),ge(t)?Ce(this._templateResults,t,this.config.entity,Ee(this.config)):t);var e=this._resolved(t);if(Lt(this.info,e,this._hass))return null;var n=re(this.info,e);return W(ti||(ti=mi([""," ",""])),n,this.renderValue(this.info,e))}},{key:"renderMainEntity",value:function(){if(!1===this.config.show_state)return null;var t=this._resolved(this.config);if(Lt(this.stateObj,t,this._hass))return this.config.default?W(ei||(ei=mi(['
\n ',"\n
","
\n
"])),se(this.config),this.renderMainHeader(),this.config.default):null;var e=this.getGestureHandlers("main",this.config.entity,this.config);return W(ni||(ni=mi(['\n ',"\n
","
\n "])),se(this.config),null==e?void 0:e.onDown,null==e?void 0:e.onUp,null==e?void 0:e.onCancel,ji,ji,ji,ji,ji,ji,this.renderMainHeader(),this.renderValue(this.stateObj,t))}},{key:"renderEntity",value:function(t,e,n){var i,r,o;if(e=this._resolved(e),!t||Lt(t,e,this._hass))return e.default?W(ii||(ii=mi(['
\n ',"\n
","
\n
"])),se(e),null!==(r=xi(t?re(t,e):e.name))&&void 0!==r?r:this.headerPlaceholder(),e.default):t||e.hide_unavailable?null:W(ri||(ri=mi(['\n ','\n
\n '])),se(e),this._hass.localize("ui.panel.lovelace.warning.entity_not_found","entity",null!==(o=e.entity)&&void 0!==o?o:""),xi(e.name));var a=this.getGestureHandlers("sub-".concat(n),t.entity_id,e);return W(oi||(oi=mi(['\n ',"\n
\n ","\n
\n "])),se(e),null==a?void 0:a.onDown,null==a?void 0:a.onUp,null==a?void 0:a.onCancel,ji,ji,ji,ji,ji,ji,null!==(i=xi(re(t,e)))&&void 0!==i?i:function(t){return!0===t.toggle||!!t.icon||Ft(t.state_icon)}(e)?null:this.headerPlaceholder(),e.icon||Ft(e.state_icon)?this.renderIcon(t,e):this.renderValue(t,e))}},{key:"renderMainHeader",value:function(){var t,e=null!==(t=xi(this.config.state_header))&&void 0!==t?t:!0===this.config.toggle?null:this.headerPlaceholder();return e?W(ai||(ai=mi(["",""])),e):null}},{key:"headerPlaceholder",value:function(){return null!=xi(this.config.state_header)||this.entities.some(function(t){return!1!==(e=t).name&&null!==xi(e.name)&&!(!e.name&&!e.entity);var e})?" ":null}},{key:"renderValue",value:function(t,e){var n;if(!0===e.toggle)return this.renderToggle(t,e);if(void 0!==e.template){var i=ge(e.template)?"":e.template;return"".concat(i).concat(e.unit?" ".concat(e.unit):"")}if(!e.attribute&&null!==(n=t.entity_id)&&void 0!==n&&n.startsWith("timer."))return W(si||(si=mi([""])),this._hass,t);var r=e.attribute&&[ht,pt].includes(e.attribute);if(e.format&&mt.includes(e.format)){var o,a=r?t[e.attribute.replace("-","_")]:e.attribute?null!==(o=t.attributes[e.attribute])&&void 0!==o?o:t[e.attribute]:t.state,s=new Date(a);return s instanceof Date&&!isNaN(s.getTime())?W(ci||(ci=mi([""])),this._hass,s,e.format):a}return r?W(li||(li=mi([""])),this._hass,t[e.attribute.replace("-","_")]):ae(this._hass,t,e)}},{key:"renderToggle",value:function(t,e){var n,i=this,r=null===(n=e.tap_action)||void 0===n?void 0:n.confirmation,o=r?{handleEvent:function(n){var o,a,s;n.stopPropagation(),n.preventDefault();var c=Ft(r)&&(null===(o=r.exemptions)||void 0===o?void 0:o.some(function(t){var e;return t.user===(null===(e=i._hass.user)||void 0===e?void 0:e.id)})),l=Ft(r)&&r.text,u=ge(l)?Ce(i._templateResults,l,null!==(a=e.entity)&&void 0!==a?a:i.config.entity,Ee(i.config,e)):l||"Are you sure you want to toggle ".concat(null!==(s=re(t,e))&&void 0!==s?s:t.entity_id,"?");(c||confirm(u))&&i._hass.callService("homeassistant","toggle",{entity_id:t.entity_id})},capture:!0}:void 0;return W(ui||(ui=mi(["\n '])),ji,ji,ji,o,t,this._hass)}},{key:"renderIcon",value:function(t,e){var n,i,r=null!==(n=ie(t,e))&&void 0!==n?n:!0===e.icon?t.attributes.icon||null:e.icon,o="cssColor"in(i=Et(e))?{color:i.cssColor}:{stateColor:i.stateColor},a=o.stateColor,s=o.color,c=!(r||!t.attributes.entity_picture&&!t.attributes.entity_picture_local);return W(fi||(fi=mi([''])),c?" has-picture":"",ne(e.icon_color),this._hass,t,r,a,s)}},{key:"renderWarning",value:function(){return W(di||(di=mi(["\n ","\n "])),this._hass.localize("ui.panel.lovelace.warning.entity_not_found","entity",this.config.entity))}},{key:"getGestureHandlers",value:function(t,e,n){var i,r,o,a,s,c,l,u=this;return this._actionHandlers.has(t)||this._actionHandlers.set(t,(i=function(t,i){return u.dispatchAction(e,n,t,i)},r={hasHold:!!n.hold_action,hasDoubleTap:!!n.double_tap_action},s=r.hasHold,c=r.hasDoubleTap,l=!1,{onDown:function(){l=!1,s&&(o=setTimeout(function(){l=!0},500))},onUp:function(){if(clearTimeout(o),l)return l=!1,void i(!0,!1);c?a?(clearTimeout(a),a=void 0,i(!1,!0)):a=setTimeout(function(){a=void 0,i(!1,!1)},250):i(!1,!1)},onCancel:function(){clearTimeout(o)}})),this._actionHandlers.get(t)}},{key:"dispatchAction",value:function(t,e,n,i){var r,o,a=i?e.double_tap_action:n?e.hold_action:null!==(r=e.tap_action)&&void 0!==r?r:{action:"more-info"};if(a&&"none"!==a.action){var s,c,l,u,f,d,h=(s=a,c=this._templateResults,l=null!==(o=e.entity)&&void 0!==o?o:this.config.entity,u=Ee(this.config,e),f=je(u),d=function(t){if(ge(t)){var e=c.get(Se(f+t,l));return void 0===e?"":e}return Array.isArray(t)?t.map(d):Ft(t)?Object.fromEntries(Object.entries(t).map(function(t){var e=pe(t,2),n=e[0],i=e[1];return[n,d(i)]})):t},d(s)),p=i?"double_tap":n?"hold":"tap";Nt(this,"hass-action",{config:bi({entity:h.entity||t},"".concat(p,"_action"),h),action:p})}}}],[{key:"getConfigElement",value:function(){return document.createElement("multiple-entity-row-editor")}},{key:"getStubConfig",value:function(t,e){var n,i,r=null!==(n=null!==(i=null==e?void 0:e.find(function(t){return t.startsWith("sensor.")}))&&void 0!==i?i:null==e?void 0:e[0])&&void 0!==n?n:"";return{entity:r}}},{key:"properties",get:function(){return{_hass:Object,config:Object,stateObj:Object,_templateResults:Object}}},{key:"styles",get:function(){return o(be||(be=function(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}(["\n /* state-badge is a fixed 40px box, which leaves an odd gap under a headered icon - let it\n shrink to the icon's natural size instead (see #425). */\n .icon-small {\n width: auto;\n height: auto;\n }\n /* ...except when it is showing a picture: state-badge then hides the icon and paints the\n image as a background, so the host has no in-flow content and would collapse to nothing.\n The class is set in renderIcon rather than reusing state-badge's own has-image. */\n .icon-small.has-picture {\n width: 40px;\n height: 40px;\n }\n .entity {\n text-align: center;\n cursor: pointer;\n }\n /* Marker for an entity id that resolves to nothing (see #364). */\n .entity .missing {\n color: var(--error-color, #db4437);\n }\n .entity span {\n font-size: 10px;\n color: var(--multiple-entity-row-header-color, var(--secondary-text-color));\n }\n .entities-row {\n flex-direction: row;\n display: inline-flex;\n justify-content: space-between;\n align-items: center;\n }\n /* HA's name box is what pushes the entities to the right: it grows at flex: 1 1 30%. Hiding\n it removes that push too, leaving them against the icon, so take over the job here - the\n point of hiding the name is more room, not a different alignment (see #341, #365). */\n .entities-row.no-name,\n .entities-column.no-name {\n margin-left: auto;\n }\n /* The 'styles' option reaches one entity's div, which is a flex item - so vertical-align\n there does nothing and alignment has to be set on the container instead (see #261). */\n .entities-row.align-top,\n .entities-column.align-top {\n align-items: flex-start;\n }\n .entities-row.align-bottom,\n .entities-column.align-bottom {\n align-items: flex-end;\n }\n /* The 16px gap must be margin, not padding: users tune spacing with their own margins in\n the 'styles' option, which replace this margin but would stack on top of a padding - 4.10.1 did\n padding and widened every tuned row into overflowing on phones (see #432). The gap still\n has to be clickable though: the row's cursor:pointer inherits into it, but HA stops\n slotted clicks at the bare slot (catchInteraction=false), so bare margin is dead space\n that looks clickable. The ::after extension puts the gap inside the entity's hit area\n without affecting layout. position:relative on every entity keeps hit-testing fair: a\n positioned later sibling beats its neighbor's ::after wherever a user's zero/negative\n margin makes them overlap, so no entity steals its neighbor's clicks. */\n .entities-row .entity {\n margin-right: 16px;\n position: relative;\n }\n .entities-row .entity:last-of-type {\n margin-right: 0;\n }\n .entities-row .entity:not(:last-of-type)::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n right: -16px;\n width: 16px;\n }\n /* HA's ha-entity-toggle host is display:flex with no horizontal alignment, so in a slot\n wider than the switch it hugs the left edge while everything else centers. Outer styles\n out-rank :host rules, so it can be centered from here; keeping the host's flex box (vs\n display:contents) preserves the full-width tap strip and HA's box assumptions (#436). */\n .entity ha-entity-toggle {\n justify-content: center;\n }\n /* Opt-in, because it trades a taller row for not overflowing: nothing between HA's .row and\n our entities can shrink, so a row needing more width than the card has just spills past\n the edge (worst on narrow phone screens - see #411). Wrapping reflows instead. */\n .entities-row.wrap {\n flex-wrap: wrap;\n justify-content: flex-end;\n row-gap: 4px;\n }\n .entities-column {\n flex-direction: column;\n display: flex;\n align-items: flex-end;\n justify-content: space-evenly;\n }\n .entities-column .entity div {\n display: inline-block;\n vertical-align: middle;\n }\n"])))}}])}(ut);jt("multiple-entity-row",Ei),window.customCards=window.customCards||[],window.customCards.some(function(t){return"multiple-entity-row"===t.type})||window.customCards.push({type:"multiple-entity-row",name:"Multiple Entity Row",description:"Show multiple entity states and attributes on a single entity row"})})(); \ No newline at end of file +(()=>{"use strict";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,n=Symbol(),i=new WeakMap;class r{constructor(t,e,i){if(this._$cssResult$=!0,i!==n)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const n=this.t;if(e&&void 0===t){const e=void 0!==n&&1===n.length;e&&(t=i.get(n)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&i.set(n,t))}return t}toString(){return this.cssText}}const o=(t,...e)=>{const i=1===t.length?t[0]:e.reduce((e,n,i)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+t[i+1],t[0]);return new r(i,t,n)},a=(n,i)=>{if(e)n.adoptedStyleSheets=i.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of i){const i=document.createElement("style"),r=t.litNonce;void 0!==r&&i.setAttribute("nonce",r),i.textContent=e.cssText,n.appendChild(i)}},s=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const n of t.cssRules)e+=n.cssText;return(t=>new r("string"==typeof t?t:t+"",void 0,n))(e)})(t):t,{is:c,defineProperty:l,getOwnPropertyDescriptor:u,getOwnPropertyNames:f,getOwnPropertySymbols:d,getPrototypeOf:h}=Object,p=globalThis,m=p.trustedTypes,y=m?m.emptyScript:"",v=p.reactiveElementPolyfillSupport,b=(t,e)=>t,g={toAttribute(t,e){switch(e){case Boolean:t=t?y:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let n=t;switch(e){case Boolean:n=null!==t;break;case Number:n=null===t?null:Number(t);break;case Object:case Array:try{n=JSON.parse(t)}catch(t){n=null}}return n}},_=(t,e)=>!c(t,e),w={attribute:!0,type:String,converter:g,reflect:!1,useDefault:!1,hasChanged:_};Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;class O extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=w){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(t,n,e);void 0!==i&&l(this.prototype,t,i)}}static getPropertyDescriptor(t,e,n){const{get:i,set:r}=u(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:i,set(e){const o=i?.call(this);r?.call(this,e),this.requestUpdate(t,o,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??w}static _$Ei(){if(this.hasOwnProperty(b("elementProperties")))return;const t=h(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(b("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(b("properties"))){const t=this.properties,e=[...f(t),...d(t)];for(const n of e)this.createProperty(n,t[n])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,n]of e)this.elementProperties.set(t,n)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const n=this._$Eu(t,e);void 0!==n&&this._$Eh.set(n,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const n=new Set(t.flat(1/0).reverse());for(const t of n)e.unshift(s(t))}else void 0!==t&&e.push(s(t));return e}static _$Eu(t,e){const n=e.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const n of e.keys())this.hasOwnProperty(n)&&(t.set(n,this[n]),delete this[n]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return a(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,n){this._$AK(t,n)}_$ET(t,e){const n=this.constructor.elementProperties.get(t),i=this.constructor._$Eu(t,n);if(void 0!==i&&!0===n.reflect){const r=(void 0!==n.converter?.toAttribute?n.converter:g).toAttribute(e,n.type);this._$Em=t,null==r?this.removeAttribute(i):this.setAttribute(i,r),this._$Em=null}}_$AK(t,e){const n=this.constructor,i=n._$Eh.get(t);if(void 0!==i&&this._$Em!==i){const t=n.getPropertyOptions(i),r="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:g;this._$Em=i;const o=r.fromAttribute(e,t.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(t,e,n,i=!1,r){if(void 0!==t){const o=this.constructor;if(!1===i&&(r=this[t]),n??=o.getPropertyOptions(t),!((n.hasChanged??_)(r,e)||n.useDefault&&n.reflect&&r===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,n))))return;this.C(t,e,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:n,reflect:i,wrapped:r},o){n&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,o??e??this[t]),!0!==r||void 0!==o)||(this._$AL.has(t)||(this.hasUpdated||n||(e=void 0),this._$AL.set(t,e)),!0===i&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,n]of t){const{wrapped:t}=n,i=this[e];!0!==t||this._$AL.has(e)||void 0===i||this.C(e,void 0,n,i)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}}O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[b("elementProperties")]=new Map,O[b("finalized")]=new Map,v?.({ReactiveElement:O}),(p.reactiveElementVersions??=[]).push("2.1.2");const S=globalThis,A=t=>t,j=S.trustedTypes,$=j?j.createPolicy("lit-html",{createHTML:t=>t}):void 0,x="$lit$",k=`lit$${Math.random().toFixed(9).slice(2)}$`,E="?"+k,C=`<${E}>`,P=document,T=()=>P.createComment(""),M=t=>null===t||"object"!=typeof t&&"function"!=typeof t,I=Array.isArray,R=t=>I(t)||"function"==typeof t?.[Symbol.iterator],H="[ \t\n\f\r]",D=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,F=/-->/g,N=/>/g,U=RegExp(`>|${H}(?:([^\\s"'>=/]+)(${H}*=${H}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,V=/"/g,z=/^(?:script|style|textarea|title)$/i,B=t=>(e,...n)=>({_$litType$:t,strings:e,values:n}),W=B(1),q=(B(2),B(3),Symbol.for("lit-noChange")),Z=Symbol.for("lit-nothing"),G=new WeakMap,J=P.createTreeWalker(P,129);function K(t,e){if(!I(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==$?$.createHTML(e):e}const Y=(t,e)=>{const n=t.length-1,i=[];let r,o=2===e?"":3===e?"":"",a=D;for(let e=0;e"===c[0]?(a=r??D,l=-1):void 0===c[1]?l=-2:(l=a.lastIndex-c[2].length,s=c[1],a=void 0===c[3]?U:'"'===c[3]?V:L):a===V||a===L?a=U:a===F||a===N?a=D:(a=U,r=void 0);const f=a===U&&t[e+1].startsWith("/>")?" ":"";o+=a===D?n+C:l>=0?(i.push(s),n.slice(0,l)+x+n.slice(l)+k+f):n+k+(-2===l?e:f)}return[K(t,o+(t[n]||"")+(2===e?"":3===e?"":"")),i]};class Q{constructor({strings:t,_$litType$:e},n){let i;this.parts=[];let r=0,o=0;const a=t.length-1,s=this.parts,[c,l]=Y(t,e);if(this.el=Q.createElement(c,n),J.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(i=J.nextNode())&&s.length0){i.textContent=j?j.emptyScript:"";for(let n=0;n2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=Z}_$AI(t,e=this,n,i){const r=this.strings;let o=!1;if(void 0===r)t=X(this,t,e,0),o=!M(t)||t!==this._$AH&&t!==q,o&&(this._$AH=t);else{const i=t;let a,s;for(t=r[0],a=0;a{const i=n?.renderBefore??e;let r=i._$litPart$;if(void 0===r){const t=n?.renderBefore??null;i._$litPart$=r=new et(e.insertBefore(T(),t),t,void 0,n??{})}return r._$AI(t),r})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return q}}ut._$litElement$=!0,ut.finalized=!0,lt.litElementHydrateSupport?.({LitElement:ut});const ft=lt.litElementPolyfillSupport;ft?.({LitElement:ut}),(lt.litElementVersions??=[]).push("4.2.2");var dt=["unavailable","unknown"],ht="last-changed",pt="last-updated",mt=["relative","total","date","time","datetime"],yt=["entity-id","last-changed","last-updated","last-triggered","position","tilt-position","brightness"];function vt(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||bt(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function bt(t,e){if(t){if("string"==typeof t)return gt(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?gt(t,e):void 0}}function gt(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);n=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,a=!1;return{s:function(){e=e.call(t)},n:function(){var t=e.next();return o=t.done,t},e:function(t){a=!0,r=t},f:function(){try{o||null==e.return||e.return()}finally{if(a)throw r}}}}(wt);try{for(i.s();!(e=i.n()).done;){var r=vt(e.value,2),o=r[0],a=r[1];if(customElements.get(o))wt.delete(o);else try{customElements.define(o,a),n.push(o),wt.delete(o)}catch(t){console.warn("multiple-entity-row: re-defining ".concat(o," after registry swap failed"),t)}}}catch(t){i.e(t)}finally{i.f()}n.length&&console.info("multiple-entity-row: re-defined ".concat(n.join(", ")," after customElements registry swap, caught by ").concat(t," (frontend#52960)"))}catch(t){console.warn("multiple-entity-row: customElements registry check failed",t)}},jt=function(){wt.size&&(Ot>=30?wt.clear():(Ot+=1,setTimeout(function(){At("fallback poll"),jt()},1e3)))},$t=function(t,e){try{if(_t.get(t))return void console.warn("multiple-entity-row: ".concat(t," is already defined - a duplicate resource entry or stale cached copy loaded first"));_t.define(t,e)}catch(e){return void console.warn("multiple-entity-row: defining ".concat(t," failed"),e)}wt.set(t,e),St||(St=!0,_t.whenDefined("home-assistant").then(function(){return At("ha-boot signal")}).catch(function(){}),jt())};function xt(t){return xt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},xt(t)}var kt=function(t){return"object"===xt(t)&&!Array.isArray(t)&&!!t},Et=function(t,e){if(kt(t)&&void 0!==e&&Object.prototype.hasOwnProperty.call(t,e)){var n=t[e];return null==n||""===n?void 0:n}},Ct=function(t,e,n){var i=new Event(e,{bubbles:!0,composed:!0});i.detail=n,t.dispatchEvent(i)},Pt=function(t){return!t||dt.includes(t.state)},Tt=function(t,e,n){if(function(t,e){return e.hide_unavailable&&(Pt(t)||e.attribute&&![ht,pt].includes(e.attribute)&&void 0===t.attributes[e.attribute])}(t,e))return!0;if(void 0===e.hide_if)return!1;if("boolean"==typeof e.hide_if)return e.hide_if;var i;if(kt(e.hide_if)&&(e.hide_if.entity||e.hide_if.attribute)){var r=e.hide_if.entity?null==n?void 0:n.states[e.hide_if.entity]:t;i=e.hide_if.attribute?null==r?void 0:r.attributes[e.hide_if.attribute]:null==r?void 0:r.state}else i=e.attribute?t.attributes[e.attribute]:t.state;var o=[];if(kt(e.hide_if)){if(e.hide_if.below&&ie.hide_if.above)return!0;e.hide_if.value&&(o=o.concat(e.hide_if.value))}else o=o.concat(e.hide_if);return o.some(function(t){return"number"==typeof t?t===+i:t===i})},Mt=["formatEntityName","formatEntityState","formatEntityAttributeValue"],It=new Set(["primary","accent","red","pink","purple","deep-purple","indigo","blue","light-blue","cyan","teal","green","light-green","lime","yellow","amber","orange","deep-orange","brown","light-grey","grey","dark-grey","blue-grey","black","white","primary-text","secondary-text","disabled"]),Rt=function(t){return It.has(t)?"var(--".concat(t,"-color)"):t},Ht=function(t,e){var n=Et(t.state_color,e);return void 0===n?void 0:Rt(String(n))},Dt=function(t){var e;return null!==(e=t.color)&&void 0!==e?e:"boolean"==typeof t.state_color?t.state_color?"state":"none":void 0},Ft=function(t,e,n){var i;if(void 0!==Ht(t,n))return{stateColor:!1};var r=null!==(i=Dt(t))&&void 0!==i?i:t.icon_color||!e?void 0:Dt(e);return void 0===r?t.icon_color?{stateColor:!1}:{stateColor:!0}:"state"===r?{stateColor:!0}:"none"===r?{stateColor:!1}:{cssColor:Rt(r)}},Nt=function(t){return t<10?"0".concat(t):t};function Ut(t){var e=Math.floor(t/3600),n=Math.floor(t%3600/60),i=Math.floor(t%3600%60);return e>0?"".concat(e,":").concat(Nt(n),":").concat(Nt(i)):n>0?"".concat(n,":").concat(Nt(i)):i>0?""+i:null}function Lt(t){return Lt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Lt(t)}function Vt(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function zt(t,e,n){return(e=function(t){var e=function(t){if("object"!=Lt(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var n=e.call(t,"string");if("object"!=Lt(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==Lt(e)?e:e+""}(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var Bt=function(t,e,n){var i=e?function(t){switch(t.number_format){case"comma_decimal":return["en-US","en"];case"decimal_comma":return["de","es","it"];case"space_comma":return["fr","sv","cs"];case"system":return;default:return t.language}}(e):void 0;if(Number.isNaN=Number.isNaN||function t(e){return"number"==typeof e&&t(e)},"none"!==(null==e?void 0:e.number_format)&&!Number.isNaN(Number(t))&&Intl)try{return new Intl.NumberFormat(i,Wt(t,n)).format(Number(t))}catch(e){return console.error(e),new Intl.NumberFormat(void 0,Wt(t,n)).format(Number(t))}return"string"==typeof t?t:"".concat(function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:2;return Math.round(t*Math.pow(10,e))/Math.pow(10,e)}(t,null==n?void 0:n.maximumFractionDigits).toString()).concat("currency"===(null==n?void 0:n.style)?" ".concat(n.currency):"")},Wt=function(t,e){var n=function(t){for(var e=1;e-1?t.split(".")[1].length:0;n.minimumFractionDigits=i,n.maximumFractionDigits=i}return n};function qt(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=Xt(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var i=0,r=function(){};return{s:r,n:function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function Zt(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,i=Array(e);n2&&void 0!==arguments[2]?arguments[2]:"";ne(t)&&n.push({template:i+t,entity:e})},r=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";i(t.name,e,n),i(t.icon,e,n),i(t.icon_color,e,n),i(t.color,e,n),i(t.template,e,n),i(re(t),e,n),kt(t.styles)&&fe(t.styles,function(t){return i(t,e,n)}),ue.forEach(function(r){return fe(t[r],function(t){return i(t,e,n)})})},o=t.entity;if(r(t,o,le(de(t))),"string"==typeof t.secondary_info)i(t.secondary_info,o,le(de(t)));else if(kt(t.secondary_info)){var a,s=t.secondary_info;r(s,null!==(a=s.entity)&&void 0!==a?a:o,le(de(t,s)))}return null===(e=t.entities)||void 0===e||e.forEach(function(e){if(kt(e)){var n,i=e;r(i,null!==(n=i.entity)&&void 0!==n?n:o,le(de(t,i)))}}),n}(t).map(function(t){return[se(t.template,t.entity),t]})),this.sync()}},{key:"setHass",value:function(t){var e,n=!(null===(e=this.hass)||void 0===e||!e.connection);this.hass=t,!n&&null!=t&&t.connection&&this.sync()}},{key:"connect",value:function(){this.connected=!0,this.sync()}},{key:"disconnect",value:function(){this.connected=!1,this.sync()}},{key:"sync",value:function(){var t,e,n=qt(this.unsubs);try{for(n.s();!(e=n.n()).done;){var i=Qt(e.value,2),r=i[0],o=i[1];this.connected&&this.requests.has(r)||(this.unsubs.delete(r),this.requests.has(r)||(this.results.delete(r),this.errors.delete(r)),o.then(function(t){return null==t?void 0:t()}).catch(function(){}))}}catch(t){n.e(t)}finally{n.f()}if(this.connected&&null!==(t=this.hass)&&void 0!==t&&t.connection){var a,s=qt(this.requests);try{for(s.s();!(a=s.n()).done;){var c=Qt(a.value,2),l=c[0],u=c[1];this.unsubs.has(l)||this.unsubs.set(l,this.subscribe(l,u))}}catch(t){s.e(t)}finally{s.f()}}}},{key:"subscribe",value:function(t,e){var n=this;return this.hass.connection.subscribeMessage(function(e){return n.onMessage(t,e)},{type:"render_template",template:e.template,variables:{entity:e.entity},report_errors:!0}).catch(function(t){return console.warn("multiple-entity-row: template subscription failed:",e.template,t),null})}},{key:"onMessage",value:function(t,e){this.unsubs.has(t)&&(void 0!==e.error?(this.errors.get(t)!==e.error&&(this.errors.set(t,e.error),console.warn("multiple-entity-row: template error:",e.error)),this.results.set(t,"")):(this.errors.delete(t),this.results.set(t,e.result)),this.notify(new Map(this.results)))}}])}();function me(t){return me="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},me(t)}function ye(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function ve(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,i=Array(e);n1&&a.every(function(t){return xe.test(t)})){var s=r??0;return!isNaN(parseFloat(s))&&isFinite(s)?function(t,e,n,i){var r,o,a=parseFloat(e),s=Se(e),c=!1,l=function(t){c||(s=void 0,r=t)},u=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!e){if(Array.isArray(t)||(e=ge(t))){e&&(t=e);var n=0,i=function(){};return{s:i,n:function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,a=!1;return{s:function(){e=e.call(t)},n:function(){var t=e.next();return o=t.done,t},e:function(t){a=!0,r=t},f:function(){try{o||null==e.return||e.return()}finally{if(a)throw r}}}}(t);try{for(u.s();!(o=u.n()).done;){var f=o.value,d=je.exec(f);if(d&&"precision"===d[1])s=parseInt(d[2],10),r=void 0,c=!0;else if(d)a/={kilo:1e3,mega:1e6,milli:.001}[d[1]],void 0!==d[2]?(s=parseInt(d[2],10),r=void 0,c=!0):l(2);else switch(f){case"brightness":a=Math.round(a/255*100),n="%",l(0);break;case"percent":a*=100,n="%",l(2);break;case"invert":a=-a;break;case"position":a=100-a;break;case"celsius_to_fahrenheit":a=1.8*a+32,l(0);break;case"fahrenheit_to_celsius":a=5*(a-32)/9,l(1)}}}catch(t){u.e(t)}finally{u.f()}return"".concat(Bt(a,i,void 0!==s?{minimumFractionDigits:s,maximumFractionDigits:s}:void 0!==r?{maximumFractionDigits:r}:void 0)).concat(n?" ".concat(n):"")}(a,s,o,t.locale):"".concat(s).concat(o?" ".concat(o):"")}if(n.format&&!function(t){return Ae.some(function(e){return null==t?void 0:t.startsWith(e)})&&!$e(t)}(n.format)){if(null==r&&(r=ke.includes(n.format)?"":0),ke.includes(n.format))return"".concat(function(t,e){switch(t){case"upper":return e.toUpperCase();case"lower":return e.toLowerCase();case"capitalize":return e.charAt(0).toUpperCase()+e.slice(1);case"title":return e.split(/(\s+)/).map(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}).join("")}}(n.format,String(r))).concat(o?" ".concat(o):"");if(isNaN(parseFloat(r))||!isFinite(r));else if("brightness"===n.format)r=Math.round(r/255*100),o="%";else if("percent"===n.format)r=Bt(100*r,t.locale,{maximumFractionDigits:2}),o="%";else if("duration"===n.format){var c;r=null!==(c=Ut(r))&&void 0!==c?c:"0",o=void 0}else if("duration-m"===n.format){var l;r=null!==(l=Ut(r/1e3))&&void 0!==l?l:"0",o=void 0}else if("duration-h"===n.format){var u;r=null!==(u=Ut(3600*r))&&void 0!==u?u:"0",o=void 0}else if($e(n.format)){var f=function(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||ge(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}($e(n.format),3),d=f[1],h=f[2];if("precision"===d){var p=parseInt(h,10);r=Bt(parseFloat(r),t.locale,{minimumFractionDigits:p,maximumFractionDigits:p})}else r=function(t,e,n,i){if(void 0===n)return Bt(t/e,i,{maximumFractionDigits:2});var r=parseInt(n,10);return Bt(t/e,i,{minimumFractionDigits:r,maximumFractionDigits:r})}(r,{kilo:1e3,mega:1e6,milli:.001}[d],h,t.locale)}else if("invert"===n.format){var m=Se(r);r=Bt(r-2*r,t.locale,void 0!==m?{minimumFractionDigits:m,maximumFractionDigits:m}:void 0)}else if("position"===n.format){var y=Se(r);r=Bt(100-r,t.locale,void 0!==y?{minimumFractionDigits:y,maximumFractionDigits:y}:void 0)}else"celsius_to_fahrenheit"===n.format?r=Bt(1.8*r+32,t.locale,{maximumFractionDigits:0}):"fahrenheit_to_celsius"===n.format&&(r=Bt(5*(r-32)/9,t.locale,{maximumFractionDigits:1}));return"".concat(r).concat(o?" ".concat(o):"")}var v=ve(ve({},e),{},{attributes:ve(ve({},e.attributes),{},{unit_of_measurement:o})});if(void 0!==n.unit&&!n.attribute){if(!isNaN(parseFloat(r))&&isFinite(r)){var b,g=null===(b=t.entities)||void 0===b||null===(b=b[e.entity_id])||void 0===b?void 0:b.display_precision,_=Bt(r,t.locale,null!=g?{minimumFractionDigits:g,maximumFractionDigits:g}:void 0);return"".concat(_).concat(o?" ".concat(o):"")}return"".concat(t.formatEntityState(e)).concat(o?" ".concat(o):"")}if(n.attribute){if(void 0!==n.unit){var w=null==r?"":isNaN(r)?r:Bt(r,t.locale);return"".concat(w).concat(o?" ".concat(o):"")}return Me(t.formatEntityAttributeValue(v,n.attribute))}return Me(t.formatEntityState(v))},Re=function(t){return kt(null==t?void 0:t.styles)?Object.keys(t.styles).filter(function(e){return""!==t.styles[e]&&null!=t.styles[e]}).map(function(e){return"".concat(e,": ").concat(t.styles[e],";")}).join(""):""};class He{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,n){this._$Ct=t,this._$AM=e,this._$Ci=n}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}}const{I:De}=st,Fe={},Ne=(t=>(...e)=>({_$litDirective$:t,values:e}))(class extends He{constructor(){super(...arguments),this.key=Z}render(t,e){return this.key=t,e}update(t,[e,n]){return e!==this.key&&(((t,e=Fe)=>{t._$AH=e})(t),this.key=e),n}});var Ue,Le,Ve,ze,Be,We,qe,Ze,Ge,Je,Ke,Ye,Qe,Xe,tn,en,nn,rn="__custom__",on=[{value:"",label:"No format"},{value:"brightness",label:"Brightness (0-255 → %)"},{value:"percent",label:"Percent (value × 100 → x %)"},{value:"duration",label:"Duration (seconds → h:mm:ss)"},{value:"duration-m",label:"Duration (milliseconds)"},{value:"duration-h",label:"Duration (hours)"},{value:"precision0",label:"Precision 0 decimals"},{value:"precision1",label:"Precision 1 decimal"},{value:"precision2",label:"Precision 2 decimals"},{value:"precision3",label:"Precision 3 decimals"},{value:"kilo",label:"Kilo (value / 1,000)"},{value:"mega",label:"Mega (value / 1,000,000)"},{value:"milli",label:"Milli (value × 1,000)"},{value:"invert",label:"Invert (value × -1)"},{value:"position",label:"Position (100 - value)"},{value:"celsius_to_fahrenheit",label:"°C → °F"},{value:"fahrenheit_to_celsius",label:"°F → °C"},{value:"upper",label:"Text: UPPERCASE"},{value:"lower",label:"Text: lowercase"},{value:"capitalize",label:"Text: Capitalize first letter"},{value:"title",label:"Text: Title Case"},{value:"relative",label:"Timestamp: relative"},{value:"total",label:"Timestamp: total"},{value:"date",label:"Timestamp: date"},{value:"time",label:"Timestamp: time"},{value:"datetime",label:"Timestamp: date + time"},{value:rn,label:"Custom…"}],an=new Set(on.map(function(t){return t.value}).filter(function(t){return t&&t!==rn})),sn=[{name:"entity",required:!0,selector:{entity:{}}},{type:"grid",schema:[{name:"name",selector:{text:{}}},{name:"attribute",selector:{text:{}}}]},{type:"grid",schema:[{name:"unit",selector:{text:{}}},{name:"icon",selector:{icon:{}}}]},{name:"icon_color",selector:{text:{}}},{name:"name_gap",selector:{text:{}}},{type:"grid",schema:[{name:"show_state",default:!0,selector:{boolean:{}}},{name:"color",selector:{ui_color:{include_state:!0,include_none:!0}}}]},{type:"grid",schema:[{name:"toggle",selector:{boolean:{}}},{name:"column",selector:{boolean:{}}}]},{type:"grid",schema:[{name:"show_state_first",selector:{boolean:{}}},{name:"hide_unavailable",selector:{boolean:{}}},{name:"wrap",selector:{boolean:{}}}]},{name:"state_header",selector:{text:{}}},{name:"image",selector:{text:{}}},{name:"format",selector:{select:{mode:"dropdown",options:on}}}],cn=[{name:"tap_action",selector:{ui_action:{default_action:"more-info"}}},{name:"hold_action",selector:{ui_action:{default_action:"none"}}},{name:"double_tap_action",selector:{ui_action:{default_action:"none"}}}],ln=[{name:"entity",selector:{entity:{}}},{type:"grid",schema:[{name:"name",selector:{text:{}}},{name:"attribute",selector:{text:{}}}]},{type:"grid",schema:[{name:"unit",selector:{text:{}}},{name:"icon",selector:{icon:{}}}]},{name:"icon_color",selector:{text:{}}},{type:"grid",schema:[{name:"color",selector:{ui_color:{include_state:!0,include_none:!0}}},{name:"toggle",selector:{boolean:{}}}]},{name:"hide_unavailable",selector:{boolean:{}}},{name:"format",selector:{select:{mode:"dropdown",options:on}}}],un={entity:"Entity",attribute:"Attribute",name:"Name override (or false to hide)",unit:"Unit (or false to hide)",icon:"Icon",icon_color:"Icon color (CSS value, e.g. red, #ff0000, var(--my-color))",name_gap:"Icon → name gap (CSS length, e.g. 8px; default 16px)",image:"Image URL",format:"Format",show_state:"Show main entity state",show_state_first:"State before entities",state_header:"State header label",color:"Icon color",state_color:"State color",column:"Column layout",wrap:"Wrap instead of overflowing",toggle:"Show as toggle",hide_unavailable:"Hide if unavailable",tap_action:"Tap action",hold_action:"Hold action",double_tap_action:"Double-tap action"};function fn(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}function dn(t){return function(t){if(Array.isArray(t))return An(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||Sn(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function hn(t,e){for(var n=0;n=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function On(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||Sn(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Sn(t,e){if(t){if("string"==typeof t)return An(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?An(t,e):void 0}}function An(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);ni.length&&(t._selectedTab=i.length),t._keys.clear(),t._updateConfig({entities:i.length?i:void 0})}}),gn(t,"_moveAdditional",function(e,n){var i;if(t._config){var r=dn(null!==(i=t._config.entities)&&void 0!==i?i:[]),o=e+n;if(!(o<0||o>=r.length)){var a=[r[o],r[e]];r[e]=a[0],r[o]=a[1],t._selectedTab=o+1,t._keys.clear(),t._updateConfig({entities:r})}}}),gn(t,"_copyAdditional",function(e){var n,i=null===(n=t._config)||void 0===n||null===(n=n.entities)||void 0===n?void 0:n[e];null!=i&&t._writeClipboard("string"==typeof i?{entity:i}:bn({},i))}),gn(t,"_cutAdditional",function(e){t._copyAdditional(e),t._deleteAdditional(e)}),gn(t,"_copyMainAsTemplate",function(){if(t._config){var e,n={},i=wn(Nn);try{for(i.s();!(e=i.n()).done;){var r=e.value,o=t._config[r];void 0!==o&&(n[r]=o)}}catch(t){i.e(t)}finally{i.f()}t._writeClipboard(n)}}),gn(t,"_pasteEntity",function(){var e;if(t._config){var n=t._readClipboard();if(n){var i=[].concat(dn(null!==(e=t._config.entities)&&void 0!==e?e:[]),[n]);t._selectedTab=i.length,t._keys.clear(),t._updateConfig({entities:i})}}}),gn(t,"_secondaryModeChanged",function(e){if(t._config){var n=e.detail.value.mode;if(n!==t._secondaryInfoMode()){var i;switch(n){case"none":i=void 0;break;case"text":i="";break;case"generic":i="last-changed";break;case"entity":i={entity:t._config.entity}}t._updateConfig({secondary_info:i})}}}),gn(t,"_secondaryTextChanged",function(e){t._updateConfig({secondary_info:e.detail.value.text})}),gn(t,"_secondaryTokenChanged",function(e){t._updateConfig({secondary_info:e.detail.value.token})}),gn(t,"_secondaryEntityChanged",function(e){var n,i=kt(null===(n=t._config)||void 0===n?void 0:n.secondary_info)?t._config.secondary_info.format:void 0;t._updateConfig({secondary_info:t._formatFromForm("secondary",Dn(e.detail.value),i)})}),t._selectedTab=0,t._entitiesExpanded=!0,t._stateIconRowsMain=[],t._stateIconRowsAdditional=new Map,t._customFormatScopes=new Set,t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&yn(t,e)}(e,t),function(t,e,n){return e&&hn(t.prototype,e),n&&hn(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t}(e,[{key:"setConfig",value:function(t){var e,n,i,r=this;if(ie(t))throw new Error("This row uses templates - edit it in the code (YAML) editor.");this._config=t;var o,a=null!==(e=null===(n=t.entities)||void 0===n?void 0:n.length)&&void 0!==e?e:0;this._selectedTab>a&&(this._selectedTab=a),this._clipboardEntity=this._readClipboard(),this._stateIconRowsMatch(this._stateIconRowsMain,t.state_icon)||(this._stateIconRowsMain=Object.entries(null!==(o=t.state_icon)&&void 0!==o?o:{}));var s=new Map;null===(i=t.entities)||void 0===i||i.forEach(function(t,e){var n=kt(t)?t.state_icon:void 0,i=r._stateIconRowsAdditional.get(e);i&&r._stateIconRowsMatch(i,n)?s.set(e,i):n&&s.set(e,Object.entries(n))}),this._stateIconRowsAdditional=s}},{key:"_stateIconRowsMatch",value:function(t,e){var n,i={},r=wn(t);try{for(r.s();!(n=r.n()).done;){var o=On(n.value,2),a=o[0],s=o[1];a.trim()&&s.trim()&&(i[a.trim()]=s.trim())}}catch(t){r.e(t)}finally{r.f()}var c=null!=e?e:{},l=Object.keys(i);return l.length===Object.keys(c).length&&l.every(function(t){return i[t]===c[t]})}},{key:"_readClipboard",value:function(){try{var t=sessionStorage.getItem(Fn);if(!t)return;var e=JSON.parse(t);if(e&&"object"===jn(e))return e}catch(t){}}},{key:"_writeClipboard",value:function(t){try{sessionStorage.setItem(Fn,JSON.stringify(t)),this._clipboardEntity=t}catch(t){}}},{key:"_hasNativeTabs",get:function(){return!!customElements.get("ha-tab-group")&&!!customElements.get("ha-tab-group-tab")}},{key:"render",value:function(){return this.hass&&this._config?W(Ue||(Ue=fn(["\n \n ",'\n \n\n \n "])),"Entities",this._entitiesExpanded,this._onEntitiesExpandedChanged,this._renderEntitiesPanel(),"4.11.0","2026-08-26T14:27:18.177Z"):Z}},{key:"_isCustomFormat",value:function(t,e){return this._customFormatScopes.has(t)||!!e&&!an.has(e)}},{key:"_setCustomFormatScope",value:function(t,e){if(e!==this._customFormatScopes.has(t)){var n=new Set(this._customFormatScopes);e?n.add(t):n.delete(t),this._customFormatScopes=n}}},{key:"_formatToForm",value:function(t,e){return this._isCustomFormat(t,e.format)?bn(bn({},e),{},{format:rn}):e}},{key:"_formatFromForm",value:function(t,e,n){if(e.format===rn){this._setCustomFormatScope(t,!0);var i=bn({},e);return void 0!==n?i.format=n:delete i.format,i}return this._setCustomFormatScope(t,!1),e}},{key:"_renderCustomFormatField",value:function(t,e,n){return this._isCustomFormat(t,e)?W(Le||(Le=fn(["\n \n "])),this.hass,{custom_format:null!=e?e:""},[{name:"custom_format",selector:{text:{}}}],function(){return"Custom format (e.g. invert, precision3)"},function(t){var e,i=(null!==(e=t.detail.value.custom_format)&&void 0!==e?e:"").trim();n(i||void 0)}):Z}},{key:"_keyFor",value:function(t){return this._keys.has(t)||this._keys.set(t,"".concat(t,"-").concat(Math.random().toString(36).slice(2,10))),this._keys.get(t)}},{key:"_renderEntitiesPanel",value:function(){var t,e,n=this,i=null!==(t=null===(e=this._config)||void 0===e?void 0:e.entities)&&void 0!==t?t:[],r=Math.min(this._selectedTab,i.length);return W(Ve||(Ve=fn(['\n
\n
\n ','\n \n
\n\n
\n ',"\n
\n
\n "])),this._hasNativeTabs?W(ze||(ze=fn(['\n \n \n \n \n \n
\n
\n \n \n ','\n \n ','\n \n ',"\n \n "])),"Copy main as template",xn,this._copyMainAsTemplate,"Paste as new entity",kn,!this._clipboardEntity,this._pasteEntity,this.hass,this._mainFormData(),sn,this._computeLabel,this._mainValueChanged,this._renderCustomFormatField("main",null===(t=this._config)||void 0===t?void 0:t.format,function(t){return n._updateConfig({format:t})}),this.hass,this._mainFormData(),cn,this._computeLabel,this._mainValueChanged,this._renderSecondaryInfoBlock(),this._renderStateIconRows("main"),this._renderStylesBlock(null===(e=this._config)||void 0===e?void 0:e.styles,function(t){return n._mainStylesChanged(t)}))}},{key:"_renderStylesBlock",value:function(t,e){return W(Ge||(Ge=fn(['\n \n ','\n \n \n \n \n
\n
\n \n \n ','\n \n ',"\n \n "])),"Move before","M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z",0===t,function(){return i._moveAdditional(t,-1)},"Move after","M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z",t===a,function(){return i._moveAdditional(t,1)},"Copy entity",xn,function(){return i._copyAdditional(t)},"Cut entity","M19,3L13,9L15,11L22,4V3M12,12.5A0.5,0.5 0 0,1 11.5,12A0.5,0.5 0 0,1 12,11.5A0.5,0.5 0 0,1 12.5,12A0.5,0.5 0 0,1 12,12.5M6,20A2,2 0 0,1 4,18C4,16.89 4.9,16 6,16A2,2 0 0,1 8,18C8,19.11 7.1,20 6,20M6,8A2,2 0 0,1 4,6C4,4.89 4.9,4 6,4A2,2 0 0,1 8,6C8,7.11 7.1,8 6,8M9.64,7.64C9.87,7.14 10,6.59 10,6A4,4 0 0,0 6,2A4,4 0 0,0 2,6A4,4 0 0,0 6,10C6.59,10 7.14,9.87 7.64,9.64L10,12L7.64,14.36C7.14,14.13 6.59,14 6,14A4,4 0 0,0 2,18A4,4 0 0,0 6,22A4,4 0 0,0 10,18C10,17.41 9.87,16.86 9.64,16.36L12,14L19,21H22V20L9.64,7.64Z",function(){return i._cutAdditional(t)},"Paste from clipboard",kn,!this._clipboardEntity,this._pasteEntity,"Delete entity",$n,function(){return i._deleteAdditional(t)},this.hass,this._formatToForm("sub-".concat(t),Hn(o)),ln,this._computeLabel,function(e){return i._additionalValueChanged(e,t)},this._renderCustomFormatField("sub-".concat(t),o.format,function(e){return i._setAdditionalFormat(t,e)}),this.hass,this._formatToForm("sub-".concat(t),Hn(o)),cn,this._computeLabel,function(e){return i._additionalValueChanged(e,t)},this._renderStateIconRows(t),this._renderStylesBlock(o.styles,function(e){return i._additionalStylesChanged(e,t)}))}},{key:"_mainFormData",value:function(){return this._formatToForm("main",Hn(bn({show_state:!0},this._config)))}},{key:"_setAdditionalFormat",value:function(t,e){var n;if(this._config){var i=dn(null!==(n=this._config.entities)&&void 0!==n?n:[]),r=i[t],o="string"==typeof r?{entity:r}:bn({},r);e?o.format=e:delete o.format,i[t]=o,this._updateConfig({entities:i})}}},{key:"_secondaryInfoMode",value:function(){var t,e=null===(t=this._config)||void 0===t?void 0:t.secondary_info;return null==e?"none":"object"===jn(e)?"entity":yt.includes(e)?"generic":"text"}},{key:"_renderSecondaryInfoBlock",value:function(){var t,e=this,n=this._secondaryInfoMode(),i=null===(t=this._config)||void 0===t?void 0:t.secondary_info;return W(Qe||(Qe=fn(["\n
\n \n ","\n ","\n ","\n
\n "])),this.hass,{mode:n},En,function(){return"Mode"},this._secondaryModeChanged,"text"===n?W(Xe||(Xe=fn(['
\n \n \n 3?(r=p===i)&&(c=o[(s=o[4])?5:(s=3,3)],o[4]=o[5]=t):o[0]<=h&&((r=n<2&&hi||i>p)&&(o[4]=n,o[5]=i,d.n=p,s=0))}if(r||n>1)return a;throw f=!0,i}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(f&&1===u&&h(u,p),s=u,c=p;(e=s<2?t:c)||!f;){o||(s?s<3?(s>1&&(d.n=-1),h(s,c)):d.n=c:d.v=c);try{if(l=2,o){if(s||(r="next"),e=o[r]){if(!(e=e.call(o,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=o.return)&&e.call(o),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);o=t}else if((e=(f=d.n<0)?c:n.call(i,d))!==a)break}catch(e){o=t,s=1,c=e}finally{l=1}}return{value:e,done:f}}}(n,r,o),!0),l}var a={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][i]?e(e([][i]())):(_i(e={},i,function(){return this}),e),f=l.prototype=s.prototype=Object.create(u);function d(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,_i(t,r,"GeneratorFunction")),t.prototype=Object.create(f),t}return c.prototype=l,_i(f,"constructor",l),_i(l,"constructor",c),c.displayName="GeneratorFunction",_i(l,r,"GeneratorFunction"),_i(f),_i(f,r,"Generator"),_i(f,i,function(){return this}),_i(f,"toString",function(){return"[object Generator]"}),(gi=function(){return{w:o,m:d}})()}function _i(t,e,n,i){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}_i=function(t,e,n,i){function o(e,n){_i(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!i,configurable:!i,writable:!i}):t[e]=n:(o("next",0),o("throw",1),o("return",2))},_i(t,e,n,i)}function wi(t,e,n,i,r,o,a){try{var s=t[o](a),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(i,r)}function Oi(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}function Si(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function Ai(t){for(var e=1;e\n \n ',"\n
\n "])),u?"main-icon-painted":"",(s=u)?"--multiple-entity-row-main-icon-color: ".concat(s,";"):"",Ce(i.name_gap),this._hass,c,this.renderSecondaryInfo(),l,!1,[this.config.column?"entities-column":"entities-row",!this.config.column&&this.config.wrap?"wrap":"",null!==(e=Hi[this.config.align])&&void 0!==e?e:"",l?"no-name":""].filter(Boolean).join(" "),this.config.show_state_first?W(ei||(ei=Oi(["","",""])),this.renderMainEntity(),this.entities.map(function(t,e){return n.renderEntity(t.stateObj,t,e)})):W(ni||(ni=Oi(["","",""])),this.entities.map(function(t,e){return n.renderEntity(t.stateObj,t,e)}),this.renderMainEntity()))}},{key:"updated",value:function(t){var n;null===(n=Ei(e,"updated",this,3))||void 0===n||n([t]),this.syncRowStyles()}},{key:"syncRowStyles",value:function(){var t,e,n=Ce(null===(t=this.config)||void 0===t?void 0:t.name_gap);if(n||this._mainPainted){var i=null===(e=this.renderRoot)||void 0===e?void 0:e.querySelector("hui-generic-entity-row");i&&(n&&this.injectRowStyle(i,"data-mer-name-gap",":host .info{padding-inline-start:var(--multiple-entity-row-name-gap,16px)}"),i.classList.contains("main-icon-painted")&&this.injectRowStyle(i,"data-mer-main-icon",Ii))}}},{key:"injectRowStyle",value:(n=function(t){return function(){var e=this,n=arguments;return new Promise(function(i,r){var o=t.apply(e,n);function a(t){wi(o,i,r,a,s,"next",t)}function s(t){wi(o,i,r,a,s,"throw",t)}a(void 0)})}}(gi().m(function t(e,n,i){var r,o;return gi().w(function(t){for(;;)switch(t.p=t.n){case 0:if(!this._injected.has(n)){t.n=1;break}return t.a(2);case 1:return t.p=1,t.n=2,e.updateComplete;case 2:t.n=4;break;case 3:return t.p=3,t.v,t.a(2);case 4:if(r=e.shadowRoot){t.n=5;break}return t.a(2);case 5:r.querySelector("style[".concat(n,"]"))||((o=document.createElement("style")).setAttribute(n,""),o.textContent=i,r.appendChild(o)),this._injected.add(n);case 6:return t.a(2)}},t,this,[[1,3]])})),function(t,e,i){return n.apply(this,arguments)})},{key:"renderSecondaryInfo",value:function(){var t=this.config.secondary_info;if(!t||function(t){return"string"==typeof t&&yt.includes(t)}(t))return null;if("string"==typeof t)return W(ii||(ii=Oi(["",""])),ne(t)?he(this._templateResults,t,this.config.entity,de(this.config)):t);var e=this._resolved(t);if(Tt(this.info,e,this._hass))return null;var n=Te(this.info,e);return W(ri||(ri=Oi([''," ",""])),Re(e),n,this.renderValue(this.info,e))}},{key:"renderMainEntity",value:function(){var t;if(!1===this.config.show_state)return null;var e=null!==(t=this._rowScope)&&void 0!==t?t:this._resolved(this.config);if(Tt(this.stateObj,e,this._hass))return this.config.default?W(oi||(oi=Oi(['
\n ',"\n
","
\n
"])),Re(e),this.renderMainHeader(),this.config.default):null;var n=this.getGestureHandlers("main",this.config.entity,this.config);return W(ai||(ai=Oi(['\n ',"\n
","
\n "])),Re(e),null==n?void 0:n.onDown,null==n?void 0:n.onUp,null==n?void 0:n.onCancel,Mi,Mi,Mi,Mi,Mi,Mi,this.renderMainHeader(),this.renderValue(this.stateObj,e))}},{key:"renderEntity",value:function(t,e,n){var i,r,o;if(e=this._resolved(e),!t||Tt(t,e,this._hass))return e.default?W(si||(si=Oi(['
\n ',"\n
","
\n
"])),Re(e),null!==(r=Ri(t?Te(t,e):e.name))&&void 0!==r?r:this.headerPlaceholder(),e.default):t||e.hide_unavailable?null:W(ci||(ci=Oi(['\n ','\n
\n '])),Re(e),this._hass.localize("ui.panel.lovelace.warning.entity_not_found","entity",null!==(o=e.entity)&&void 0!==o?o:""),Ri(e.name));var a=this.getGestureHandlers("sub-".concat(n),t.entity_id,e);return W(li||(li=Oi(['\n ',"\n
\n ","\n
\n "])),Re(e),null==a?void 0:a.onDown,null==a?void 0:a.onUp,null==a?void 0:a.onCancel,Mi,Mi,Mi,Mi,Mi,Mi,null!==(i=Ri(Te(t,e)))&&void 0!==i?i:function(t){return!0===t.toggle||!!t.icon||kt(t.state_icon)}(e)?null:this.headerPlaceholder(),e.icon||kt(e.state_icon)?this.renderIcon(t,e):this.renderValue(t,e))}},{key:"renderMainHeader",value:function(){var t,e=null!==(t=Ri(this.config.state_header))&&void 0!==t?t:!0===this.config.toggle?null:this.headerPlaceholder();return e?W(ui||(ui=Oi(["",""])),e):null}},{key:"headerPlaceholder",value:function(){return null!=Ri(this.config.state_header)||this.entities.some(function(t){return!1!==(e=t).name&&null!==Ri(e.name)&&!(!e.name&&!e.entity);var e})?" ":null}},{key:"renderValue",value:function(t,e){var n;if(!0===e.toggle)return this.renderToggle(t,e);if(void 0!==e.template){var i=ne(e.template)?"":e.template;return"".concat(i).concat(e.unit?" ".concat(e.unit):"")}if(!e.attribute&&null!==(n=t.entity_id)&&void 0!==n&&n.startsWith("timer."))return W(fi||(fi=Oi([""])),this._hass,t);var r=e.attribute&&[ht,pt].includes(e.attribute);if(e.format&&mt.includes(e.format)){var o,a=r?t[e.attribute.replace("-","_")]:e.attribute?null!==(o=t.attributes[e.attribute])&&void 0!==o?o:t[e.attribute]:t.state,s=new Date(a);return s instanceof Date&&!isNaN(s.getTime())?W(di||(di=Oi([""])),this._hass,s,e.format):a}return r?W(hi||(hi=Oi([""])),this._hass,t[e.attribute.replace("-","_")]):Ie(this._hass,t,e)}},{key:"renderToggle",value:function(t,e){var n,i=this,r=null===(n=e.tap_action)||void 0===n?void 0:n.confirmation,o=r?{handleEvent:function(n){var o,a,s;n.stopPropagation(),n.preventDefault();var c=kt(r)&&(null===(o=r.exemptions)||void 0===o?void 0:o.some(function(t){var e;return t.user===(null===(e=i._hass.user)||void 0===e?void 0:e.id)})),l=kt(r)&&r.text,u=ne(l)?he(i._templateResults,l,null!==(a=e.entity)&&void 0!==a?a:i.config.entity,de(i.config,e)):l||"Are you sure you want to toggle ".concat(null!==(s=Te(t,e))&&void 0!==s?s:t.entity_id,"?");(c||confirm(u))&&i._hass.callService("homeassistant","toggle",{entity_id:t.entity_id})},capture:!0}:void 0;return W(pi||(pi=Oi(["\n '])),Mi,Mi,Mi,o,t,this._hass)}},{key:"renderIcon",value:function(t,e){var n,i,r,o,a=null!==(n=Pe(t,e))&&void 0!==n?n:!0===e.icon?t.attributes.icon||null:e.icon,s=null!==(i=this._rowScope)&&void 0!==i?i:this._resolved(this.config),c="cssColor"in(o=Ft(e,s,t.state))?{color:o.cssColor}:{stateColor:o.stateColor},l=c.stateColor,u=c.color,f=!(a||!t.attributes.entity_picture&&!t.attributes.entity_picture_local);return W(mi||(mi=Oi([''])),f?" has-picture":"",Ee(null!==(r=Ht(e,t.state))&&void 0!==r?r:e.icon_color),this._hass,t,a,l,u)}},{key:"renderWarning",value:function(){return W(yi||(yi=Oi(["\n ","\n "])),this._hass.localize("ui.panel.lovelace.warning.entity_not_found","entity",this.config.entity))}},{key:"getGestureHandlers",value:function(t,e,n){var i,r,o,a,s,c,l,u=this;return this._actionHandlers.has(t)||this._actionHandlers.set(t,(i=function(t,i){return u.dispatchAction(e,n,t,i)},r={hasHold:!!n.hold_action,hasDoubleTap:!!n.double_tap_action},s=r.hasHold,c=r.hasDoubleTap,l=!1,{onDown:function(){l=!1,s&&(o=setTimeout(function(){l=!0},500))},onUp:function(){if(clearTimeout(o),l)return l=!1,void i(!0,!1);c?a?(clearTimeout(a),a=void 0,i(!1,!0)):a=setTimeout(function(){a=void 0,i(!1,!1)},250):i(!1,!1)},onCancel:function(){clearTimeout(o)}})),this._actionHandlers.get(t)}},{key:"dispatchAction",value:function(t,e,n,i){var r,o,a=i?e.double_tap_action:n?e.hold_action:null!==(r=e.tap_action)&&void 0!==r?r:{action:"more-info"};if(a&&"none"!==a.action){var s,c,l,u,f,d,h=(s=a,c=this._templateResults,l=null!==(o=e.entity)&&void 0!==o?o:this.config.entity,u=de(this.config,e),f=le(u),d=function(t){if(ne(t)){var e=c.get(se(f+t,l));return void 0===e?"":e}return Array.isArray(t)?t.map(d):kt(t)?Object.fromEntries(Object.entries(t).map(function(t){var e=Qt(t,2),n=e[0],i=e[1];return[n,d(i)]})):t},d(s)),p=i?"double_tap":n?"hold":"tap";Ct(this,"hass-action",{config:ji({entity:h.entity||t},"".concat(p,"_action"),h),action:p})}}}],[{key:"getConfigElement",value:function(){return document.createElement("multiple-entity-row-editor")}},{key:"getStubConfig",value:function(t,e){var n,i,r=null!==(n=null!==(i=null==e?void 0:e.find(function(t){return t.startsWith("sensor.")}))&&void 0!==i?i:null==e?void 0:e[0])&&void 0!==n?n:"";return{entity:r}}},{key:"properties",get:function(){return{_hass:Object,config:Object,stateObj:Object,_templateResults:Object}}},{key:"styles",get:function(){return o(we||(we=function(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}(["\n /* state-badge is a fixed 40px box, which leaves an odd gap under a headered icon - let it\n shrink to the icon's natural size instead (see #425). */\n .icon-small {\n width: auto;\n height: auto;\n }\n /* ...except when it is showing a picture: state-badge then hides the icon and paints the\n image as a background, so the host has no in-flow content and would collapse to nothing.\n The class is set in renderIcon rather than reusing state-badge's own has-image. */\n .icon-small.has-picture {\n width: 40px;\n height: 40px;\n }\n .entity {\n text-align: center;\n cursor: pointer;\n }\n /* Marker for an entity id that resolves to nothing (see #364). */\n .entity .missing {\n color: var(--error-color, #db4437);\n }\n .entity span {\n font-size: 10px;\n color: var(--multiple-entity-row-header-color, var(--secondary-text-color));\n }\n .entities-row {\n flex-direction: row;\n display: inline-flex;\n justify-content: space-between;\n align-items: center;\n }\n /* HA's name box is what pushes the entities to the right: it grows at flex: 1 1 30%. Hiding\n it removes that push too, leaving them against the icon, so take over the job here - the\n point of hiding the name is more room, not a different alignment (see #341, #365). */\n .entities-row.no-name,\n .entities-column.no-name {\n margin-left: auto;\n }\n /* The 'styles' option reaches one entity's div, which is a flex item - so vertical-align\n there does nothing and alignment has to be set on the container instead (see #261). */\n .entities-row.align-top,\n .entities-column.align-top {\n align-items: flex-start;\n }\n .entities-row.align-bottom,\n .entities-column.align-bottom {\n align-items: flex-end;\n }\n /* The 16px gap must be margin, not padding: users tune spacing with their own margins in\n the 'styles' option, which replace this margin but would stack on top of a padding - 4.10.1 did\n padding and widened every tuned row into overflowing on phones (see #432). The gap still\n has to be clickable though: the row's cursor:pointer inherits into it, but HA stops\n slotted clicks at the bare slot (catchInteraction=false), so bare margin is dead space\n that looks clickable. The ::after extension puts the gap inside the entity's hit area\n without affecting layout. position:relative on every entity keeps hit-testing fair: a\n positioned later sibling beats its neighbor's ::after wherever a user's zero/negative\n margin makes them overlap, so no entity steals its neighbor's clicks. */\n .entities-row .entity {\n margin-right: 16px;\n position: relative;\n }\n .entities-row .entity:last-of-type {\n margin-right: 0;\n }\n .entities-row .entity:not(:last-of-type)::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n right: -16px;\n width: 16px;\n }\n /* HA's ha-entity-toggle host is display:flex with no horizontal alignment, so in a slot\n wider than the switch it hugs the left edge while everything else centers. Outer styles\n out-rank :host rules, so it can be centered from here; keeping the host's flex box (vs\n display:contents) preserves the full-width tap strip and HA's box assumptions (#436). */\n .entity ha-entity-toggle {\n justify-content: center;\n }\n /* Opt-in, because it trades a taller row for not overflowing: nothing between HA's .row and\n our entities can shrink, so a row needing more width than the card has just spills past\n the edge (worst on narrow phone screens - see #411). Wrapping reflows instead. */\n .entities-row.wrap {\n flex-wrap: wrap;\n justify-content: flex-end;\n row-gap: 4px;\n }\n .entities-column {\n flex-direction: column;\n display: flex;\n align-items: flex-end;\n justify-content: space-evenly;\n }\n .entities-column .entity div {\n display: inline-block;\n vertical-align: middle;\n }\n"])))}}]);var n}(ut);$t("multiple-entity-row",Di),window.customCards=window.customCards||[],window.customCards.some(function(t){return"multiple-entity-row"===t.type})||window.customCards.push({type:"multiple-entity-row",name:"Multiple Entity Row",description:"Show multiple entity states and attributes on a single entity row"})})(); \ No newline at end of file diff --git a/www/community/lovelace-multiple-entity-row/multiple-entity-row.js.gz b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js.gz index 277906211aa1e7415571a2db313b42330a3766e9..6ba3631a60f3d21665146436020c705d9d8d46e1 100644 GIT binary patch literal 27204 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 XJ$DbXDJGPd%|HJOOrCe5iIf2V8(QH> literal 25443 zcmV(-K-|9{iwFqp`GRT!|7~?_bZKyGWi4fHbZK;XEpl&nE^2cC?Y&ET+(xn}xSwAE zqGbv&vmh4ru#6H^O;eI3w_X1EZeRED5exaw$jFGuh{(umU#>Y1vfP;_W1be=Nz%hCpT%X8rOtfH zV@N7EcV>%enZS3Cr)5%}_VVl`_^AjUKiawfboYKxekh$Uul;YH=SO$X+yz!D^JHAQ zgK?G?rBg;n)9fIgzC2C}#-lRWJ&q^Y$%`y2*Vn!GSu$}pqe!No?(FWKpPS!73d4EN zMHPR2-G#sNl23Na({P5(VWkx@t9*iv}9_SLM)AT zPiF_&)bm*qrToNs!{c{P;`v}ajf=v`&u9wyVq9jqS2E5L|13H5N|;Kpe`Q=0FL(ja zxe~2yvSclaQolR~@HqGL94ffbttj9mg_CBbqnnElraW+70kHnLNQ?N8L(zXauonM> zM*j&bQItHM1g<}zz98`>|4>FHqt7zp%OhR_pw*l_|7^+;)|8(~(5K?F9Ke_XA_msJ zn3%&Ok%mKGU++U!8ccb5R2~nYyjMm^0R4EW?=w>wG6V#&s3f3Opz8+`?z^Yy*t19P zGiWmj3T%*-zQ4?QxyVzeT$b4`piFuMvruVPz2#C2Hj7{hf*|0CXd)?z`h+@S%)@eT za};tIz+^Gzo(Jm-3l`nw8!(f*xNvI%)9j`5RgbDW1eTjFW(PcXp)jCHcIcG4*r2k) zujA>0J99u5K5@#-xeAS3bq*Kln0C=@0fRi?PF&B(sq@frH_8oHAi`CR2v@NsY!h%M z?M;)C=ke5ek6jhaIat6t$M3i^j&qJBVec+-9K;ds*YP5UO$wN^^kLmL%DrTxKVk?O ze<0_8YnFQnD_QCJt?Wyd*>OMZXK@ym0m3D;*iE^AUg&7iM=#?oA3&~^z31CZdbR9M1g zIc(veg!S9W(h^#VxLQyKQ<~3tI@vi+rV}smmrGVee2CKtSI>#?1~(RuTz6n5lj39u zV_qz#yzu!3Y#fC@0?Jrb0NO1Gxh-TuSZ%nj+*7a$J^&uptMtQ?oh3y$W)psxr2KiF z&3Rs)hEoRn@YzYK67KP0oF{W2OW~rH^)#OGB0Q|63OZMW6HI@u2;j5B@OT+LJNSu@ zOE$L&^(>kPK&gNXOGyV?$EQ#Z%K&5nq~Gm6dm0E>Cx@p1OhaJUVV=!uJ>#+hfgE&a` zJRB-^=&B^xh;!VA3XPtaqD^+W?Ew12J}aDuFP}V?_;3bWt4zjDJefR7lQM~?$u9(| zGs#8oC%}CLqnJXodm}%XFA4<7QdUJ)mmL&5f6pg+5sMnLfbBv}Lu0Dp}p|fgF$r8s5=b-!z@5ZnP{B0BEiK2E#`_$>rvfR1UDr z4^DCQ*H6rjp3xqWUIPly?8?Nt5K|%}1$8w6Ljlp`!fCr)+Mw=rd zWDcgIF0`R7`2-ntGf!_O)60s1t3nfNz^b&)L!q~^ADV5=E3-dS^H!K6^I-4c^q>zP zWxNUe9n~2w_k~zk-L@c0?xiDtX*axAqiiD_y`twv_-!Fih{n_)xtN{4CKCXfYX_BcD?`A&=@4@LE* zef$GiWdTcM@t3(gJ&A;*5R~XSa6o7s*oEE^B4eVHpze&gz5aaf`AhLfv&CHkF5ty1 zK}i7wC|ckYNf|YWos@bs+m98Z=|=axR!S)ot+@f?4PdG6$0&(FM}j2zOW@fkP3PHk zDpV@If)$wq_YcpXr3>;*>Ap18t?i3;6_6g5#_xb;2<4P+FU1?|HRD z(_b(F+%8FE5>wNZL`|DVjd?XTSA(QTnZR!&UMaHhQtdD#D?n$M7>A?2fp8bFb?$B| zI!%ayf*p~m7a9y+jrJ8<4Kf^30$?&MfKYXKjj5R8l40rX5ql-;nz`7~u;Pfy0@gdg zNDt!iJB4aypS*+yRYkO`34j!A zbwg5aQTyX>f-Xb5FRL`Leg5`_ge2q0x*nE zHq6%AdSBM7SB^!1erP06dCS^2DOuZEwN4RhH9(t#$mLlPGFktuU81Hux%?3y)TOm5 ztX4}4I55fHtup`@X8^U4&lJX%%P5sR0*<%?LcH?)yozeLGqo-~k-0lSca$=a4&*|a zzt$fpL0mUNn4v|8Y%!fk*yFKyDByUKOs7`r3U(?=5hE4l7OI-$8c^?vr?gZY@fEe- zr7g-rKI6+$?}F|7sLiy-fUKU9%hkMH;)69BdpCLwX<7>2he@vM;s&!PGLiD)6C+mC z1?8sPPPP?MeNo9|s%9)%!#C9GLA8Qk-hJn(EkTD5}-H6?b z+&$;V^2hYY!yogJ%U(p+?s&t{TkG}Cf4sK$kGS{CcJJ-TKlgsTHr$h6d;hrmV=?+t zBwq3TYe(!sbgkFB3qPJl*YMA)=mkHz|6%U^^X~bTvwKTybMGHN{#dwI??%@~8@`9B zUqmNBC$3*LG$$!c0T8(4Kzg7DN6yWO5j$Kh z0caWMr{Pb5*#tnZLoWH^56b3X4gu1<+Uo;z+Zzp#H{~pgwg6}O(7jW9Av2jTce@( zOHhIg@8O3}GPuNL_s%tU15*hbeQ5ucZ`Zv(!f|3E_WWw--WC0BLYpz1%!V&$f~t-h z6Qpg0-qap?4||bwX9X35-mGfZN5fa)Rrjj;cpW|#y}mv_$3Kr@Uau(Ofk=1?2`@q% z9UQo%G%IQ8VMN0P*1g9!`Xe-Zir2{+l)-}tbhKH=lt#-Sgk@W<;RvP_3OJXBV>Jw)|v!$ajQ5Uo2y=x)PPICZUx zRM#|C0qm2}QW~7TulQ%2sSRB+YoGHaDghA75+MrCaf%v`qfNl%O$m0AtL+)(d}0`$cX9FNwYlQXqtw2U67fdLbutCms-4q0?oMLNU-J7#)zd+wIa~7pqRtLc<*onUGw&W;a^Ao z&1c$|LXwXpDB~l9lV$IyI42l5a0}(gO$SaI zXH`cAlw_)QcTHAPK;85XAEZE56Y1qZJBqzT8QR7LR+-I~oXy4t%x7R#<)Z3xDS!ea zx?RN>LKw7^K=OURwNY#mYfG0Tm>A(`ua6jtkRU?~m3?;Ty<_D@AHY{_>njV~Q z18JFWY%Hr5T($Wss;lR9#}dUG4L3|-3@Oi%1ELabxzud6--Y6sg*T?2Sk|eB{?Ud_lg<`+BXd)LmdS&pCO)B;GpE8 zy8*mNGsWdUA9mQlmyImt%}_t6YxO?g%GNE$t!% z0wEYdB$bT=)Ap0VFsfS_#x%SeIa3vAbbEd=4sVCf2h^nxAn!4@SUx(_)mBrm-jz>h8O zCI?gW>L81E>4*J#*&-m|=diDlHnKvxz7)F3EnS6{7AwWrfy_4=t=D4Xai1ozu@R4! z84i3XhD&l#b-qAul%Gl!JkMFOoZ~Vmp|9>UrMmQOYo@Iem$ML9yZuNyF);G5l6i_2 zZ26%o1au1#6iI`?QBJN3UHC#f>y=jQ?z~^t9X)Xu38Y2PHur_)+=<;-+oGW%deRW~Vg380r5$QAPR^a&Y6eY2 z!lg9MJ2vAs6#zETp8d^Iu9p}JKo6-2;TkUB6ZD-ZVH9uA&!x{6h%OKW2v!f4+b zMbZnS?nAiyVY#L?*V_-F9DM$)ilg_OWfL$WpjhQAwR{B$k^2&JAJP!<^BuY3sb-hY z>dqmxHGq9mz}f5@4%p5;3kCe;OG~9g)3emWwfWJnXQU$Duh#;gJTXx6hh`KOu@G#z z4CRdUaZ_zvd(T66%PWRn$`dfRC1)g;Kqec$u&M5S2f<`qxKj{dVRmVoVEi|qB_FwUARUra%OE<>wFdMh9vJQE zFXap*t@=(FLKKmyotY!rM&AkDzb3VUs(w$9T=&v23cCAf&} zRgD>WdxeoCRYn3QBe@uNw~(G94}~qJf5Oqn!a?D{lWJkw571TDBNG*&v_v3@-%+Zq z065|*ffp=NnYHa|gvc3MFSOkgmL~UYhQKyaY+8FlO0G7t&N2%ZVY^l~e-f3{Nz8;t zM;YZXX_UbR@txcpsA3RQ3e{_}mx5>mUB@Ws5a;j;)9+pkgef~e$3Yb^sKOo;WKx~C zz{1`V8+wbw+lahkICNcqBj1ZR`Xh_LK#iza!X(y|eefq_B|i~m7cJRH);LhA#g{9f z%2llRx)3XA6bh}AQhVa2Rasp*F$F;o=SQTSF65vIL$AvLT3znxUPh4^xIBH7s=NG? zySvfsE-163qiGu?*xFhtkmIeMY1Y}bwE@K#OoBCln{}ZDFxIQ#>2Ubgx6XfqntR^% zL$vutgc0c)$v0&%j^|L83oj4x80;S;(Ou$8LxRd~UlsHsH zm;3MG_v54h0Px(#2HKu*Y^&9ZCzF*`$|{3Aj?>9hbb_nYW?0ZH+c0YFsH~;8e_9)~fdlF4SrlyB@&*X}j3ezGx>Eqzkh>wlBLeg%Ms`0dehU zsg??y_cCos?{;yc=3C770~^|vuH=^xqS5|u=|JIdVhp4e!AVr|q(4;CUR>?MI%h?7 zr$k^1G-lnAHD6C+pLOvp9o7b{)Iy0kdOU}7)Rh_oG@@(0GTn5sYeu<}?rNutmnZ|l zf7)MQI6PbG(|9h=!?5?4zQD(x-HDOqO_fI>})@)fc?zq7{Hk z+>DzTYq&7Lq7AEV;|319=l=Dt>f5!h0i>dN5C>SsK#auW*_ep0wtfZU2N;*IX5`Fh^u;z`?DwByuQfOq7rQEVEBtprG`gtL?(uD(T zX44-Sm#-;~4J3mlVfys+Ob&5v3{r=fQ6NS@hDh}R8%&Ne#!GgHX;K%e) z>SQ_WaV&oTIkE_&3S_)?giAyr?$RE|@9{QmW2HUcnep;C!zN_o$M(C%y*sB6gz0iHcR)(#`C;6?CBIJ4IK8fd40S;-q zT+|(kje)+Xs8eyb6;qZ4$=%^qa{kB%5os9SKJVW;zrN+e&z)&Jn*;X}EnK-KEKsRG zl+#gH84O5d#+fH}7RaIet};UTq$<{5bhr}m*aRt8>{S zKn~#q@?Z@xv7(Ov8JkuCN@Ysn%q39-gxBQJCWNsegg^jKN}u=uZh<5yU=VA714#gt z1Q8#IQRdNm6w+wf*cNIvq%I=g>k~><@tL%YneU&J>PAZ@@5*CmwXy=6y$n?rso)ox z&+Mv(Lm;8araU-_VP0-a(2mf_d5>BIn&!AjnV>Q>?mF=yEFokc!ND*;b&8XC?i_-Q zf_{8-^fBEe0h!D-*n&dr!0YCGY2|UjYtwiAj{{Oyuj6Arey5;9Kw(!(d*h!7S79Iy+vVNp z`sNT4##0`H02@NmM%2ekt}j6@%NC_)RopE-_fSg2&ODn=0R~q9>zAz0uLHqZvY%{1 zN#<5TD)&q2z3Pt-0wIPG=l>92zv&m2}Gr=sOkIz8m? zR1%KB{097lzbD5D9X8}td+4hIp9O~nnpg>N;6pAlaYsITSLO5))*niF`(o$dVra@XNC8vY3+Y+=718Gqh+jYy+W`|CeD~ zrtNs$=&mBx!#e8pHTByBMHs5Fg}OsVGcyx?QrZVz88Lz`riv?eGNm=5i#*3htIA+A z$d?ijUk>3E&vQe`3`uTnp&AFm4@@|PrLSZX^d6g@QWPN*y+lv$QK?k7Qs&|L~oMk9)UGQCn2E#~o<*9#sZ|0>=i11xmG z(*jO4s?1;_?+@x2UQ^(2i};8y5uTFz<6?^dJ#e6V8b6Kf52M*|O0yRlJ`b>aFnh@a z=|-L-&lJYDuL`X7^)``Ltq95*-M2Wg&LppU>m%G!tVP_i$rk8@`XznL zvlFk6o&x^0>No191n_m3hcuYQAClQ(_8^aGVE2-vq%8cvM3&P$#})o+<5Oh7UZWwp zOhS(D=4_&B_~?MX1n5O=ib@+ON^ioW{(#@914mqgFzU@U3qst65FdqS%K`slYX~et zs~gcRQC|qN3ArM*=nV&3{{n(uw330vsGF8u#B9*%&tF<0yu7p4 zB@VZi(j{M^>{>&yCvKf`;37Pj!D*t=2<%nffkBc!mfBs}1@eBk*B>e$Zu|yJmMa@> z4$}5MqJ(u|X_OeQX(YH8w(#@fk0kui%!nO5XcKJ}U&i|;@?v^j8wW{i(9qK^Zici^ zSd)Qi9xM)k85V+5&gNOcC&U>C3E*W32TA0PXq}oPNfp&VkYTUd2Db(W%n2gHc)FP2 zP7x;vDE_!P7{IzJols(QaGXr|zGVjj+3b}NbgY0jFw4E;lFiGJ>Cejc?SP&p8Hk4Y z82Lhx@2h*J6@#Q4M{=mL$zjJm5E1Y!=2t6c5=a(Hu+{_AfvI8?I8A;8;xvylQz>Q& zN`qD}J!~P%v6x%6;3zByNz~HxP{qWME#y@QHOh~|Mg{6pUW2d$4GlY?tqzm~mP`gu zsz64Dms8yza5$~6ucQB6C8@Gr)@Tp1_ZUOjimxc`NjHe=IBXcU@NK?|yeH^tWXL#~V-wnod_xe1m}!`vfa;9^I37=>-B} z5cdP_98BZ%UEp?{J3w%IKt`FaMg{s<(ZPkqme;$?a+M}F4x%~xTdUCAGBZm|#Y0Nh ziAAmq`vJN2Jm=%25dJ;yk||mwX8b6|Kgo2OxFhy`iLn=SxpORaj%CiNgzx=0+3<%~ zuCc$jsO+QfOL5UxZ%sUwS-qlE3S+ZGTaNeg$@hmZS;?_;<9KuqI~A=g=LtpmI#=FF z=VOp;l0~s!X8VWnF&y5Hc~YL6pO_)b&&4p@)T2f*Em+-dpoI8CIqk zEfRH8@f`L(`ks-CR5?YjtCY9u?1yfzH;>)6#R=5MUiVnztLMlN%FR^43s6| z>12AkFH0e566N-j2~f7h0pPKhRu0=6eV=4=UzqU)VO+9|Uuqi+_3e4@8la~C#Wm($ z>Hqit_&>f7hNYOd9ot?Zn=mf}Gz3;p66l2GQEHtGxP3B6?UR87FZx4>XBHM|QmV6t zb^Xygz)+D;{HYua3rgD04)n`+MsjVOgce=yAeVGGoXCdGpU z=EdP_SX~pmXd>N7V47Avy0ZE=`ip*dY+AvIF<@Ase8F>!$;lR<-)rdYpI$@%3waG$ zPD2anG?Yb)hSSg?oVkU^&_wgZLlP$@Ad*!0;RN`hUkI#!1aj8|gJASGeI3k&{8k4l zT*JhVuSI9b)51Q#&XB3Wk6VnmS{Q6@_LqCuS&Lr2s+-)Fgvl#C^-IQ|OABT`?0C z(Ro_(6A*D*=>897OdHIwKF7a^vGT-!1{$s*P@N zd6?_V%0hlL^#scX!KK*nudQI)UG0~;ePHRr!wzo=Y6vlTTF!lc)ygAXYVd5RbAG<2 znKpcC8f4Q05_aTz>|MrplKMtp*d2%YS5b*9{-&d^gSRZ9k3(yq?&i2ltTCzjukBXK%L02$iW^rnxj#rn36FM$f!S! zPxm$1VEcr~2FQX8A9Z2RQ3v)MY3yk%#s12rsF!ZnEnO^ySD{>62LaNPNLjQ&LKe%A z`@=k}0H8VklS_=>$#`w#RgX1id9slR%K-4 z&{y$VwpFFFA_hK0rKu$+qyE&Gp2yr4aDEG&QQD<5N~0MCYdSwix5M@Irm0<7M(}wA zuLSNRw2={t8|_M^yj7``Tu!N!T%c6S{{xgts5xB25Pcm=B}-^*RVt-5rBd9fR4TBa ztW~KLD-xD!rBd3eR4Sx=m!VQg#SQiDjFQ><>7%^;r_w zR!khTOY4pACFA=eNuaEn^ipA$jr5p9N!Wuvy<4D%y5N6c2ZlrbyErfa%r16dnDEc) zz+jK*^Eoi6Nm>pJ$Nck|>yP;*+$7%f-``CF`uLZ)NxbKln}i0-od2mN_~WPvX8b=q zw1b?$Wt?hG`5(%uMoy>cR3kHfC#M<{H`HCn#)Qd-V?W z&k!559JcLZfeMvwmDg$7C1e}DVF1$N+A-eeBCnyoJ7UjTN1~`b97io5e}ee1@pgM? z7!=!WcRsN$l@gW2`@SxW;M_XhLG3H(GxX!xk7pjfL^E9barxuY-}}eN|I){wSFW+2 zx{jWuK4jv>_e4OvZiEp`pLpYzJ{?rY+eVu>!Cbk(r_mKIpFog47$!>n5D>^Icv-yy zA6bW34D%_gLCzOTJiE5l!5r%x3`Hvn8V~2CG}(fbegKQ3GJ%ABcb-t7x$kr|40MOc+?d4EqTG>G2~TsnC=Y5epQM1&X;$z00VRb#ytG;e!b}T|UeS zRn*&&CU23V&skdzU8HQy$$7Duwl@cpflXk>CgN*SV#Jqh?+i}Bp)2Ct!HL9`8kVYB z#XQ(-UUY8@eoza7q{Ql^c^7l5^)BX?eG1(g;kzQVr!eZXe2GKR{A2@~Cyiam5mWQl z3y`1QZ-RG?F$^gpHN!7-L#%#@xCX#Rr6#D{9v#4N z{7a~8;)}upu(ed3%t|S8%3?C!Zf!s^zcC=W*)`qLFIv{>o5-1$XrkW^6ZmYYOsY+K z>1HegEenEZoY+zw`6_KVu_Y+=Sdp*tC_$E=!JqzUP#u_rj3R6l_a)Z>@8rp8sO%xufZ7CAU10-rAO!3f*y_=*uX^~q7${9hJll&5@FzboF@ky5*C$- z7uAUuH1VZDEmg6(;S6iQE-Ima5iAxMO!rTCQN%~>K4d|bs%#R%n0PD76>(zs^$Sl- zGcImO2Mi>M=_c@*Vr7z;pnE&Uc-3oC+FnP(WqtmZ;%OhKzcmsx`< z#T$l8vs3jH+re31QF;N}C>F&okRku&jt~*TOsf6Exvzcr>s6x zrQhmFqI9X=#;Ufr(67GxOY8SpGukzV+~z8n_}QcI313D<$sX|tP7Dt@(v7>KjDE1x zycZUh>a9|=Re18LBN^elHv1JJz5&sqw<@}FW1N@^iDn-3;I%nLsCN;d9H0_~#*QA* zi=m~691mmDi;In6G?JzCd%4Hi3(g*J_LQ?%oIU33HD|wY_6=umIQyBix14>)*|(hi zjk6y(`<}DE^T^%b7h(DK_hEB`=qnZdaNM892Yed3Pcugtmf?7*GA%DeRqPv`jL z%|hS_Ej4?ymb&D>BO7R~blg(uI9ueE(%J=L(@abyIh&4*)l;<9=(p79s~T+;wpuD| zt?c4@OO5MoHN>4XS@v)6p_b*E(`TEToA#8&#Wh*>34GMbHp_x8^mp)Uf z{3H6bD)jml`0KdYYN9g1L7yh4Ck!-pjdqVDRsFyI=MG`hfBnw~R-JZ-BU9&rtg~a) zkr&!z8GI}%bY4Awe*eYJ_U?VFoV@T>DMxAKxonNwx)4_>yrVNjlt>4-KnYEns>1!b zTI(gIIXl%pOaydQHkpCU6wl@uUR35;?TRSr&9WlH+EXMwG|N%CJRbq zoQ+zIzjIY`hp63u|BwI2U5?=7tpiM!X}1$NwPCJqwd>AN5&m~!=teS1&#KD!@Ge8q z6L<~AM_~mpX?kE)NlRxW@(F?KD92dx#rT-d;!w4cQgjDX55qvpTB3mV2x=`gTHQK2 zHmz(Obp&<+{MHSdB0`PO(b9_ki{tEMU&M4|D(qMVOfqarWlW8}7K!K|h9}GeqDgE? zC8W{~=R$~xhjQGDhp?EXU8P2so%Fs4?0P|G^|&?{l|RYj`KqDGQP2R6c|76yY804} z+`OWMlo6~V;#YV!%O<#G^K3q$(5UjMn6ON7EG##>#a3KbR#qg2XA(Wsw>!&n-a}Q5 zYlF(xcwed+(zjbJG_~X(*AAT2n|-sjWKt=p3h!T3{KJz-4-! zLU-FNndk^3_c$3yH~=H=cv%joS&CVnIXGtDWpr8DeFguvX4A5`k7%*XdWaNrCP296q()GJMW%U8Cj*`4Sfw7QG7>1(6YVb1w4%E7G7MeQt)PeLgi zRqNmp+P9oR#P^z3kGd?&5c;2=pSp5N*g6YTHPl=k<} z&s!^#GX!;R`B_#s>g0ma6c>!f)+CwnMC2nayRw`t(?76>@cj3Q0t+y^*h6@hepU}* zdrY6tLwJ@pJcLiv&*ve0dYM3KC+Y9+Aq;)|OFV>6(l!s__vvT6Btz`;&r33YUXrO^ zk~#SEGW#FMOZ_PQ5BE|(N-yoDzMuY~ywv4%nqKNM3zV)#G^^;qy|Mm73+j2IYO}6RWW?TJ- z{aaQ_|2C9({nf);ulrxWb=fo7EEKy9sn7y^+Pfk3_OKI>E6zSFujg)2vkw7Kx3_lS-y3W*xP1ef39jS#w%F!Qe>3iYIF{RV8 z!=NSmFJ;H&5`AQ#vkz8hG}F39mt0n+i8i9JcUWVUkwfYMKS{?tV)xVbTO#uHFX7la z6uLiGwq>Q0N;DK-OSY4?1SkX%6&bDO6C%Dm`dp&Ct>QZVnBud0^%pDC))y;N!Sm&v z0di+uUti1Zpj_@>TP8Y-R@hj9Fd|IU`^-v$59=r?CBX~oeWs>G}%d-4gr z$VM*cYOQa2c?8r{IdX~p`yxBpnI`jtEY4v+JWTZ);R*oEw%RDrh;2|Yr?@6)to~40 zN-f=D)zF5E>MalviUFX1ulAabV(DC+G&=9u{N@)AKwd&!LnBJ8!k*|5Pr|G*5L7*x zYff}r263w?6PP%&yruzY9r!&U-0!(~I#UV|Aeo|+nodvEv0ikG;iJuIrR8c;HH48J z1N#L(J=dYqHmF2#emfu#4NywBu2j^d@EEqn)#Iy2wJ;aI$)txj|$mgQ_TuM zJwHbsD-O(-kNl8JT^l`FWtPR=M{S{X4TE$-?tYfumo}UGALcOtV6vm0ySKGcO1}c6 z=7^Vr#{8t@uKmK;={DA2Of}ueW8d`tMfz=H#GzGa>-zAQ%nu22wL(0PA+Kn z^IYr(u!8BV?=kH@!r{T1VT*} zsnl!JIAkON>XqdcQ>ZSTSo&?ffGzu{Wh#liWa$MHz?&{Gfq@9S4Xm8AJ`K>C$lXLg zn_b^GD#!nbIjTBg;*L0*woU*9z%s(+f^w;P+>X)NlWpp zzmLWQuH~(!0w@_OUyNiK3VN6LHVavlUBjor+OtDh1QP2QPBC_Ecsv0jxm~=}HzusD z+{6OBAcTX$^TxxpdC1_chYWQyC^I14%SQu^E*UDQASKHDi$wJ%5K|ks=W$W;k0MHt zfEIMq9-V6R19HEPW~EJ%m3%zON~%b#Fa14%lk}w-XqC#WRlKMQvwIq0!bHIOX}%{+No>PBm$BKOgMz? z0_Ed{a;9eGvNKwPKBui&@fsu{=s20};vvX^6F|-jy1+p80-lt|9HWVlgpWru`;0lT zF5@d_hB0gqi~_m7&aIpJ_SK$H>&7fIb=`!Go8lAh_M>1dJvBVKp4N5lU0+8hplU3E zR3ze^>rV?Sz%O-0Ua};HudmR>LRhhV-umFuOFXz@+M?ivzPMJvnUw>wIQSpldP1i> z^lSWK`^jUUva%eXcM=!B1Y{#&y+;$N;RyETTP+kA`$mOfY|1`tu`pIQ^eX!!mN%;Q z$BJnQ`XDZ2)!CUWTiZCqW7{$kJT6(!0jayTEjzCk5kvkprm;Q`A0+ zulm$UNNa(UMTrW1v9qPG6*p#K4rdr=0X4iv;L5dDH*W}BS#$uhin$3KM;VIL1^nrc z2C>w@;$+k>FWFPcqevy&vRGb~#d4Cx#I0i!atDSvt+;O`TIVyBNDr%N7a05c+%xTd zL@3!SM^JIRhd2EV6f1b%b{}55`W1o>@4{Y=k2tRTBOn0Yqtvgc)1^-i#jzokhx9)K z3TK5WA_bn-)LE{7W@J?fwKcW}jIB1RLXV0yVjy*H_}1=^C+HgJ^0I~)dKjxKsaDWE_0ii*`h={(4?6&REoOxihotvN^ETw zyW6bgva7WjTx(7N>eUKOlJ`OZ9l3{Dh8N=QzQ4*`=fD16XwkiM4f3td+!2Nvxv!nl z1w89wlT7Z^gfhi5aNSgy=Quu$Aax_?Zw6b?`PSyvt={JCUjNq1{#W7kui?Mo=2!i< zt{=WNh?f*QmW}we3+Ls8?(63b(GhqTJn;cJ5IZ z>pF`21AK`so=ngyBCTItZlnJLSFAs z3F2*C$`|fb%Mo4&R5#z-fDCoe5lF`SkV8-e-colZs=+jrnpKs;^!xU!d+CGpY14Vc zO}pTOgij}3Q@Q|-KG2#MNNZkn(i$9W8-byn*+wM-I1|MkS;EBJk!hO*ItUO=as~Av z(t;zdlLk#{;lvE+q$}wvT4JDdwQ;Q<_MjfpyBzI+89x`?%kqIhO3tZH4;^*qj!CTc- z<**Fl^eo?Enk8xTtiiPUS#9(;-UHk{55(@d+Reg<$@O4RCB{%_;gWV?kRl2UDbiLB z|97>{QSJRoPoEwv$}&sa3*rB)j`q=V;dU1d$k8Oa%2t(`1I*gDtlqjHt&QJBZr9Mo z*0l!T1|!MzJD`^UMVRrN#4&=m3rE~3r)i4sPI$WAovlhUq@^lm0#$vAc=5CqFWT2l z3z7EXxXxcsL>5}(U=gm~y{N55d-%&Krdb)eY5d;B#Y)A3IzdeFQ*h-j)h_-I54)Ed z!?pS#F4e_KBx-AUWvkW#X{#{XBv;`ac5~Im%9153{MLxDbvI^nx)Ba$j#y&OLM4m6^Z)_)>p zXwvK!e8vTG+zpS&z>x5EW89ez}^WyvF_V`co*%$6@-f z!uU_d{7>Hjzj`P9raR)(cE(5VkWZ%MAF*K?_%3O93&xwAkHdMWvs5gBx!aS8qx~h( zp}c?nVgLH;{?`xt{nzmO=IeeRf8L~2`1v)YzE#Q^?LfmG%8-xp*n*)f#g??yGe~1# z2%aC>sYb<&c{w`3HclC`=7r}ABjo>rTlbd>h5YexGM)5<+h)-!M(igu~!%|b@6G+8P=k%#@GX7e7Pk%w{Ibms;wtfIDeYDMqg(5-6MS*cr?UQNN9UHV?I!IuU?wW+;T zfbyz8XS9R9I~A`i>4#GD^rGfN+j!5F@&4}SkXw$%dRWFU{(`}=im!EJkV(rRSzhzO zwrZ_%!zRypj-K-k=i5v>-)74BHuDEne+Dz-SnlyCQC2RM!h{zyYXf7=F}c+tq{D1s zUlI|tipXz=b53ZPR#v&CNV7!Kd$nS4tx(ENW2+gJ-{msI>1hkg;;JKgcMZ@Vq$(cx zMIJWkQpQn0hnWl=X1H;f$)v*!20*Ag%*41c6XP&b2p{w@IiL@Wo6Oia%;bB8c9Wy(&*%&R1x^r&`3t8HR?++*jygA*z zL5BI}!qY9aAx>R6_Izmpbk#xf5=yFO_uU4oRa%=4oymrSY71(;%?Na<119m-S_op; zd6rP}Gs5`i3zdJ}@V-bXzWV638lG715^AUm&Tk)amiwr4-6x#!KK7t|>9gM_8Cx%_ zH2Fx2>SYu@AFKSij3Ql_grqZt2qH@F+YrIUCvKMPUCQpKM&3`9CuUL+ThL>;MPV-e zJO}zFF>3zyjBt|)B3c(`T$h;(Sy@o`w#7?Wt~>I*>>8Z z{A{n6Hf3Qu$S3rjFMZ+Kf7vFh_iTK&w}%fnx}y=bQ{x8}mFG&oaKRJucD{!UE^9Kl zTr;?Q8RoELUaOaP$06{e?uT`_g7^Ji-!QAUNJ!uQXQ*O7M$P#L(boPOPvg%q{)rBM z8W{dGF#Jaw82;@|0Z%}Dk}=}R2z)cR(P#Zz!Oh!``#V=^SR{T0|2*#BV7DIM zroI=sUh--_$i3L6jlmS=wH;b}PN4ii@&pHop#|WnTjxYm41@ zeI4Vw^|ykX+nd2n2LG=Exxr_DtDXvF`^~ajU1cHT$t`9DZtFX^7&|u*7`MN6ZUhJx z2OxFJDsmf(V0^rw-*>(WFs_?}tw2+^D=poEhHj{KZa|qEl~!&+BVVaDZbSC%CtnA* zZa~_t8#`YIx4**N8xF1(tPlO&h6Z)Ky)El&tCrW_+_^=Ix{0mdVA!044KwV5mVN6n zefMt!*Kh4mA^6$9?udFg-2RP95B=NK?(O~wk9P21#4v|Ok1)LD(3IfkbwD|21Nx>g zf?Hd!w>BT^`Mz~K(8dmRAh1T*&oD5hGd7p2KE{CN-V<6Wg?rl_INJ!Cfc@9)RQ8pQ zT4}?$#R;_N-qiuJyEsq!6VXJ{fm`h)Zt2x$NBWs&WRyis9)tgN9Mfe2U z$fub>@P*z>9Djv=H^;kA3Zo*fbh{eI=z?apTCbZ_4IcG)6Wy*!(MK7f>n~#4ul(|% zj9yW{%{kNoC{D{jzTHz$x{h8UqFXc+(+v~zig{Gk)6IYzR_vKyG1WKTcc?G;uKjk? zr^}e`f4*?;erjU(B?zGsq>!fRl3i(GCoW;Pq5^HPTbRHtQVhNEzQxu1R%&}{;;X3I zLmEs9?3L=;%c{pOt>eD5hWjJ*+aImn{y5$CB{bV&ZR;yam)>OLCQ_p=*@v|I{+o=d zTU%o*@{Aw8Wty1CmHr#9^xytm>3{J`W6&MoPVA?)^|j(5x2&%f_=gr)auK<{Kj8ZQ z@aOt|uJygZxx97xTSZ(GvgjpRa=L{08a7m7G+ijJn?8~ij&uBifJ^!=cv86wPJVTG zW$CRYZQ2c8%0I}wStP>>+qq1H;jei~l^BmdX*~XwlYa#UtlSa~IGgBzlcRHm7Hs07 zlq&gNHVQd~|64v4*YUdpadH_8Tm}o8>ov%-R98+F-*&r!&_a3aYI)A`DpB2nB!XEno#^sdq2cA(UC>eUF6b`-VW+3`yaf zRX5KhDdyAoG;|J7v>jA4XK{X%q`fkmhfaTM{=v##nx8@C8gRXXIUdc@Bhi4f+0lf$ z9Nam)!zuqz8(ln2j_93_SrIz;YCF$sC5~bk_>FnJ;sHGZ(mTjX05%K^##LnaoQQaJ z5@<+*`4rlkIe+1s_zJs?c#LUS~WQ zwwC||?@jq(*~{ZevM5&I43^B3qvKUYPmTd6doZLi$4>E$&-xVUg;0rZMpQr%Q$BcF z?;U`N7?e)J74toW9T+-EdJH0H`B7`6?oHL#%I;T;b_}GiXOcUHD}Ys*W@T6Ts{n$p zly!rnPBrMJfBT-=g#TNCt`%$gXCXWq^=}|4?4}vDp;fJRd&*Kds*gDXltZ56Yz8;# zJ&VoM^sIXD6#DMkT-aBefW*|{A>khqV8 zi^S$OT2>WhK9!K$aP6-~(@O)6NL%QTaMc6`p6TI~{!{7c$8E%ArBfsy$|;52lka}M zNZEswJx%M+wU&WC78XIy(WC=_5;q&<&2f6?Lil1zpL4v!a1W#OR%#zYRoLRieq8!^ z!{TK!S39=hxY$evRn*tmp)2khi8ncX zACA@=w>G~_;cUH;?rn|KRUz{v`zu?)@am8B7~ZSulh%(v|J(Dg{|#S5|E2vk^j|LX zZt<(n@NV&|f6=?euUg+N{^m12693I*9*KV=0~<2^8qd$E_crzV>&egxx*e82g+Ej@ zW@|lZ-D|CTHrG#>1FXW_bpEqt_Wrs38D|NB^>qabAa_ISciY?W`kj%eYUdWu)SfL- zH)}lut`G0i-d{gw7R*N0`8`e80m zV7X*JrwVW|DyGX@tM}Fh^IIJwQ|o6hh~^oY7=mVj0XGrwDSA==jW}J$zkPf zl^%XqrH9{LFq-0m(bzFd&3Gbu;aPS?7v8>2+22z3L(0BS+1~-f0Okox6P6?_Pgs_) zIAKM?#tEAyY>}|TgiR85oOHkY_BmgC>wN6(?PVT&d-dmIZ|bqPZ&p9{_V$vGz1h3$ z&o>)d-fZ~pl5aM=ZhN!g^>6cLg8;${GJd^)L&|DjDs7?y7^Gx$*-=sQn)Tk`GgWOR z2|cd+9y&Ma8=!efF4oYBXDnfpq_})f?S-42(JMYJot-4p=_|6lwT6MG(6i!VBETF& zuCE?@wV$@2_af}EEC9r)IQ$7qA2n{9q`cj~v-++;GPsmsBfpVPfDErm;yu`n}|o1`bBLgbOT68OCIpw~^m zaVc=qRnqW0Uf}c1rl+9^Lykk$ReufJuI{scA_G9sBV!zg6$3GAcY_y8$Vrqpt zDXc1k&7k0wz#+PRGu6!WqQd|V(K>@K>4N)wQ5@^jQKDsz)J*O@A&zmD=nwdv`q5#) z)yY4V`%{;|mz(X6@N7BYUu+ElW@5m28y3#@%?EH`W(SEN9Z(O$pIyN!T^N$ zl6C~A6x01t^6#h9f%&)TboP@==yZr2{LVTZ=;L3a)0ro2I-Qf`^XYU>l1u1xwv)O} z=UL+ICZ9*A^DHp}%d_O)OQ*A&{L6JZ&ytIDI=i-{u$z2doz8BRnO~_g^DD{kr_+&L zExXJtWimtA_&5=Q=ucGzj&8LmvpKF>d=!gKvSc6HiZ<@0ppYaCFe2L05Em$ffxSzj zGqhK^!T=6GT_(+bGD&>7%K>g_*vbJqPkQbbW9P}M$1fi}e|*1p|LMy|FMsI0c=pDD zWGw@m7myr}9D%L4Y~7C{F_%@!O*Rj1+`bLTJ|yGmm26<+(>NVe?4$=%_!v}ek3iTa z16Nm?#QD1ez|?9*@+xYrC>G=X3T+w@#lh#)sli6?RIBYKmr$z_ng3I*hQtwh+X}TB zk&8>H)j*uvS5Zt~@B+4XVLzR!pUb4g=iIBka$B#;Ng?#7ey&A7r^x6<`Z*Lk8~Qnt zMSlbR+$GdsAfsGX(WbE@ki|b<*(Q3stg_8?Xlht}Ui@UNc=i#6VEMds^S#*TAn_I4 z5g-P%qFBG8Fuez>Z&%_0UHxu(rBtu!xAgoIK6YGn;$L6Kocfc@Vy2?MN0TDzc=cA& zgFQ75W<{wDj*|)BPYzeT2xTguqd{#9?IDY5^^%qK5)%yx59ci-N>s~E&bDbFpcN}2ff+QVcr z;c2wiC*cNDM5cUf_YESvjE zZz0bbinYUzv&D4Mt=I0N{9Nd}MRTs=)oT>;Qs&ipNk=Kv0lL09kJ7`WGF2}6T8gho zz6SKnX1q-yglZFf292JwLfy*}-+(iluDha8Zx)sMCQWNGfba_bYQ6hLLu7@m*lc^q z+S6}r6;au?JP#pYC@O`re{(35ph7QP%3$+1u$-C9Iy-R5W%z*Vo(mGUWRCO0~&SvB|VLS<$=(bfOgl;8n9h^Jfw+Cjn36)b72#kWDWSQXsLR3HsfRSjULoUdJFCq`8OBP2z zaX2xvB5J)4geXs6jEbaa5>; z0aU~vDsKE3s^EzY{z|pY7Xu}(YEOK+tg)8U;S}F;(M{T|EvPlq zP*)oZJXXrUw<0`%zof?0ZW92pLi`J$=xq6%`C)Xztr)Y1R7)}wx8-i%8l4i(&->y} z+i`cBn_vX$)Eku9{%7Dmq zu@$Uh3?vCl(=ZgZEGngA6?}`9pl{P?mMBY*si^6MZCw+czln1+>3A{{x{UJ}=xtWv zS{UnsSE(Z2m&_z*75g3%^5Gc;^vsv|NIl5DMX^IjlcYe2?qeW!e|RR&;c1|9m(s4Z zuQKRMWZ~26bw0nozSd1QO%R8_Az=O{0CV-u@gnKT+vAqXrRpe4_x&RGD!W>{0xRP; zv}8yLqb;j)iM_p5!0o3nt>%T}fV84kaI$~WhLW9&* z*1e1FMJsl-JZ)Z1$!Uk65oQkGief`{mPRc@Q2&lF`@01*1Q_x&f4HOG7^^dgl3mCE zU_DBIV8X21q?Snb2Aj9Xi%I(i|L<=if8#bqzyya@m3(K~7esl8YfHmcG>eZ|aj zwk#K}265e1#BU6@T*X`LsaxpPGJU(Z2|tVh^02!&PM9Z>%-2Jqt2kvgZU2}DeRaqm z0Apu-NfQ>Ks4jVZe>~*z1QnC4Wh#EC;Uy6SWXx}Q0aNGd=&Pb+wIEvsq#7Gi1WsxJ zr*@U31yYw}iGP)MpC;K!x+;G$UzIyXrTDb9#4JOa)^W+$S9$DY z_i-{sm9?<#z43AcT;53mYLuXr23$xB^hL9z>@KisRRH!^1?*QrSp|4jgPkQsflQo& z+QR1~31gs=WpAA1<0Zm_Emgn;g#iQco=ztVsKk#UWTsF4A)MQlSOii_c~)BnHC)NmdY78Al~uGmc7XC*v?GOh8yk zx*E>0U7DJp%#M!8i)&3Nsm{+Il9#HS(ip^0{rWjl%-kw1V6b|Q`V|vkd@=6gSjzK)Sh@j#qHZvl8(UL-W~qWH8bGDLh!DNr`5pYKpIP zt1w~hRBgPq(#WFSl@PN~CLn57yh+Mq&n3^GKpS#^x)+ESg~E$YZ=$YOBwM4r8Iwob zBaxkbSP|ib%BNJ0^p#of9hYogj;!dgCf65+DPc@oU!U1AWR?9*z6XS1&xYlmRT)-! zj@a(GJs9`C>yJV!cW4-}eGlAjU{vSGmF7q4LIf+!UG-RR(!zG`!8}0kq<9)X^$K%u z-G`k##uXc@6+?9zLJz9W<~o@u@U+BT%d;ucJ=NEj;z zl^o_b#raM3{Ni2?G7@^AQllR?HMELit&g8Wt=lGUuErdg6Zh=m=x9=V3cpeAuz>42T~0ImIEmCk_Zw z#XpXKW9Dd)RHK4E0{#K08-+o#N0q5jWle%#v9*-}h-c;oYPxs2Wdiz`^5^Vu%X-{S=l_ZUD5i3w7T z67a5+2z91gvs+&JO9lv!X8`n?QZHO;MzFwbx3C3-RU$iEA+WOx#C6soj<2#zV1z`$ zE+lj<9)qH^ZCVlAw^FrmLZKpmWOX`Y!%FJD_lq_7eMaEF?Qn)}F zb65!^BE(P<;S%Z*h zGEc^cAZQuu&fTYztaU;>MASJ{C&WTN6EivDttUkaR#eOYlbdIx3oK`ihh=J5P|L(% zNO>}$XrAq+H4UE*qg+c4V3##Rfk$Hy*PlOz~8)SGfg|XizTDVR4Su(QWO?!LYy*A1#K4AHta@Tw6;6Jp9PE8KmFK76()Q zGM-cBgueC-Q(nSO%L7>-_8R@xb%0f^_1T#?N81Zb=>;&=3@^u`u$L`LuUcSp$!>0L z0(2Rkw`+D3y6dazWxx}ah)*pOB}(9c!`Ax#U_6Y6)e14%$K`cjDAvboZXm*RjHOl- zA0XPgx#@@IQyu;7LDoiy_YzzE^5i?%w%@9?PVM-ky>k$MqGZUM3lpZ0YOQ5x6sQ%U zs-`$Slcn8Rmh&DOxm@zniPzVKj|xf*fvihokl4!(*@PV<*N*`W+Rc5_=whv2i;ZRx z)qFzGPapk^7W7(l)eoL5j_NAfSUDUWZj^u`nuc4#6`oa2IlbQsfBGZkLz}V*oQl!66K|DFyaG^V z4$JDARfR+T(8cA%2SMO-paWDRQIjz_O?2vm#8b{@#}bS{HkQns!sj5k%UV7=hW#Mc zeO?V~eWbiG?@u}2M(U>3lWa`)m874$EWa`?T7_=zmWzWf-{~&V!>H97R-8k;VAOF9 z$mjL8 z-P)6rc?Wpc`hZ96ujc-K_po);?`vN=mK5P6bU`Qiz$ea)&G`rCAp5}ZD$)4Z0jl|) zLpBV1GQqf^boT|XR|wUbe2mZOVZcHsDK*YaLnf=ObBn-lsH?o z@`GT37fglB6jtC-Vo5Yb6?*Uhfr&GZ;Uqz6y7OcfLj}6wWbR=xrx4RV&WaL6Gbhbp zx;>1J?WhRo*x(6zPh%*=X*@4D0t;lEV-$IG2QQ%+ag7ScjWA9fb1rc5m@dAQaL9(_ z1zM8qsQ}D@)su8cBW;CnUc&_AHN!)Ey&ZqtsRaik}Ry(hSC7)L?wD>Vg0ByxdR zutkq3Y%-LVk%Qs?u5W%3I1dvHS!y;Pq5-~0SqPlKwxO|%5!u4UhGu6@d=w+C(R*2J z&-fjukoA=OQ+5D|4d~yi>~6wLCp$!9Ae$32g4v)%2GGrB4Dk>4|0Fr2>wTqw4)R-t zkvIAb@$zN^FXaLT(nXKe^Mp&F%C^^8Mt8-4^c|EBDaTd8imo~tsmB0Z@fg7mqNChU zutt;Qy(0I569CX1TwA<@m^tr}!N4I+>|;HGlHfJTc%k{ar=b*tYA9DSX)3p~1j4WJ5&(yky;W5qTK>`TI{`x0eVcLzkebxkl9FL6@3 zxd`A9ODWJu$CyUFBfxI~3ngO!13fN}5r|1nL|s%v#l5{I^(9v;D|N(ll9g4RgGDJ> z5P)X2eWfdC57&F4N~$;9jnnMphh_+$!V00%rdr2$Wn=)kaG@zt9USQumL z90TGNisN73f+a_YATWUNOsBd7gFB?1Lst+OdA2wLeng}qI|0O%3`Ft|6|1@sT_+`@ z2|nC*P`g|h$z%$Phj)FkWuh|J;z119j9HG?@LE2Mrv)5xa5GRb2|fVi1TmP1q_qan z;xx;kX+3r^%`l|bc^x3?oE}>Nf+fTWf&i=~fYMM#+?vNg;-JS^w~jafCs-#2S_6Xv zumU-UgaBw&L660R%5s1J7mFg<);rGU)Fkkgg6bZ|32>*_qIaSVfDX#HaGFdGrdaR* z4iNxX`2Q5y|3Q|+;M9ChkP^Hnp%Aeaa(>}?b}i*cG!EUm1ltTKZy_i%q6dgR1X&P~ z6nh1_Fm3cEmaBtCw85(dwc*w(4w?shf~0AJ4(3?0_=zF-CmD`ImW&C!H9EHk|_K5KB?!Ms{S;?@+UO zDGrLk2Ur}YVu3n0k{!ZUoCFElu_G>5bK)K(K}o2nmB;rwi2CD%fU*KpC>(sbxx(WJ z54@8sFG#RR;~d*1?&1_8t77bV(+`I;2JN)%Zk<)gKAdV0b56fUCg>RI=>qW(@; zRfY_mSu&YSEt0EZ|H)u{9ie4hc0chMAmapZQ*glJEH(i?W3g|+U^sXWSk;W?(QA~_No>P7sOkpLZ;TXFvNBs zoq)-vAa;fKPCb9{{{!i{HNwAt0RW3?ah>Ilx3_-3pSSbN8DBK7uP;PAN-o;Nd6p;V z2T?l8+Ov5!X_9G&xC_;^0e#caxh2XQX)%iwu( z5wa1_hN+n4B8hw9i%D`3oX@AZm`!=W<6PvIL6%23&w?l(1yP=-;&h(#EJ)%Y3NjI& eO?klMT;!KQnp}j7=AzkX?*D)3xi!MSe*pk%J3pKN